Skip to content

Commit 0a8f4a5

Browse files
committed
feat(panel): load selected lists on show panel open
1 parent 253b480 commit 0a8f4a5

File tree

9 files changed

+194
-61
lines changed

9 files changed

+194
-61
lines changed

src/components/views/panel/ShowPanel.vue

+28-5
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import {
2323
useListStore,
2424
} from '~/stores/data/list.store';
2525
import { useShowStore } from '~/stores/data/show.store';
26+
import { useExtensionSettingsStoreRefs } from '~/stores/settings/extension.store';
2627
import { useLinksStore } from '~/stores/settings/links.store';
2728
import { useI18n } from '~/utils/i18n.utils';
2829
@@ -163,9 +164,20 @@ const collectionProgressEntity = computed(() => {
163164
return collectionProgress.value;
164165
});
165166
166-
const { lists } = useListsStoreRefs();
167-
const { isListTypeLoading, isItemInList, addToOrRemoveFromList, isItemListLoading } =
168-
useListStore();
167+
const { myLists } = useListsStoreRefs();
168+
const {
169+
isListTypeLoading,
170+
isItemInList,
171+
addToOrRemoveFromList,
172+
isItemListLoading,
173+
fetchAll,
174+
} = useListStore();
175+
const { loadLists, loadListsPageSize } = useExtensionSettingsStoreRefs();
176+
177+
const shouldFetchLists = computed(() => {
178+
if (!myLists.value?.length) return false;
179+
return loadLists.value;
180+
});
169181
170182
const listLoading = computed(
171183
() =>
@@ -208,7 +220,7 @@ const activeLists = computed(() => {
208220
const _id = activeItem?.value?.ids?.trakt;
209221
const _type = panelType.value;
210222
if (_id === undefined || !_type) return;
211-
return lists.value
223+
return myLists.value
212224
?.filter(list => isItemInList(list.id, _type, _id).value)
213225
.map(list => list.id);
214226
});
@@ -231,7 +243,7 @@ const releaseDate = computed(() => activeItem.value?.first_aired);
231243
232244
const onListUpdate = async (value: ListEntity['id'], remove: boolean) => {
233245
if (!panelType.value || !activeItem.value?.ids) return;
234-
const _list = lists.value.find(list => list.id === value);
246+
const _list = myLists.value.find(list => list.id === value);
235247
if (!_list) return;
236248
237249
await addToOrRemoveFromList({
@@ -302,6 +314,17 @@ onMounted(() => {
302314
fetchShowEpisode(_showId, _seasonNb, _episodeNb);
303315
}
304316
}
317+
318+
if (shouldFetchLists.value) {
319+
fetchAll(
320+
myLists.value.filter(
321+
_active => loadLists.value?.find(_list => _list.id === _active.id),
322+
),
323+
{
324+
limit: loadListsPageSize.value,
325+
},
326+
);
327+
}
305328
},
306329
{ immediate: true },
307330
);

src/components/views/panel/ShowPanelButtons.vue

+8-10
Original file line numberDiff line numberDiff line change
@@ -179,23 +179,21 @@ const collectionOptions = computed(() => {
179179
return _options;
180180
});
181181
182-
const { lists, listsLoading } = useListsStoreRefs();
182+
const { myLists, listsLoading } = useListsStoreRefs();
183183
const { fetchLists, getIcon } = useListsStore();
184184
185185
const listLoading = computed(() => {
186186
return listsLoading.value || activeLoading.value;
187187
});
188188
189189
const listOptions = computed(() => {
190-
return lists.value
191-
?.filter(list => [ListType.List, ListType.Watchlist].map(String).includes(list.type))
192-
.map(list => {
193-
return {
194-
label: list.type === ListType.Watchlist ? i18n(list.name) : list.name,
195-
value: list.id,
196-
icon: getIcon(list),
197-
};
198-
});
190+
return myLists.value?.map(list => {
191+
return {
192+
label: list.type === ListType.Watchlist ? i18n(list.name) : list.name,
193+
value: list.id,
194+
icon: getIcon(list),
195+
};
196+
});
199197
});
200198
201199
onMounted(() => {

src/components/views/settings/SettingsTabs.vue

+83-7
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,19 @@
11
<script lang="ts" setup>
2-
import { NSelect, NSwitch } from 'naive-ui';
2+
import { NIcon, NSelect, NSwitch, type SelectOption } from 'naive-ui';
33
4-
import { computed, ref } from 'vue';
4+
import { type Component, computed, h, onBeforeMount, ref } from 'vue';
55
66
import SettingsFormItem from '~/components/views/settings/SettingsFormItem.vue';
77
import { pageSizeOptions } from '~/models/page-size.model';
88
import { Route } from '~/models/router.model';
99
import { useHistoryStoreRefs } from '~/stores/data/history.store';
10-
import { useListStoreRefs } from '~/stores/data/list.store';
10+
import {
11+
type ListEntity,
12+
ListType,
13+
useListsStore,
14+
useListsStoreRefs,
15+
useListStoreRefs,
16+
} from '~/stores/data/list.store';
1117
import { useSearchStoreRefs } from '~/stores/data/search.store';
1218
import {
1319
useExtensionSettingsStore,
@@ -17,10 +23,53 @@ import { useI18n } from '~/utils/i18n.utils';
1723
1824
const i18n = useI18n('settings', 'tabs');
1925
20-
const { enabledTabs, restoreRoute, routeDictionary, restorePanel, defaultTab } =
21-
useExtensionSettingsStoreRefs();
2226
const { toggleTab } = useExtensionSettingsStore();
2327
28+
const {
29+
enabledTabs,
30+
restoreRoute,
31+
routeDictionary,
32+
restorePanel,
33+
defaultTab,
34+
loadLists,
35+
loadListsPageSize,
36+
} = useExtensionSettingsStoreRefs();
37+
38+
const { getIcon, fetchLists } = useListsStore();
39+
const { myLists, listsLoading } = useListsStoreRefs();
40+
41+
const selectedLists = computed({
42+
get: () => loadLists.value.map(({ id }) => id),
43+
set: selected => {
44+
loadLists.value = myLists.value.filter(({ id }) => selected.includes(id));
45+
},
46+
});
47+
48+
type ListOption = SelectOption & { source: ListEntity; icon: Component };
49+
const listOptions = computed<ListOption[]>(() =>
50+
myLists.value.map((list, i) => ({
51+
label: list.type === ListType.Watchlist ? i18n(list.name, 'list') : list.name,
52+
value: list.id,
53+
source: list,
54+
icon: getIcon(list),
55+
})),
56+
);
57+
58+
const renderLabel = (option: ListOption) => [
59+
h(NIcon, {
60+
style: {
61+
verticalAlign: '-0.2em',
62+
marginRight: '0.7em',
63+
},
64+
component: option.icon,
65+
}),
66+
option.label?.toString(),
67+
];
68+
69+
onBeforeMount(() => {
70+
fetchLists();
71+
});
72+
2473
const { pageSize: historyPageSize } = useHistoryStoreRefs();
2574
const { pageSize: listPageSize } = useListStoreRefs();
2675
const { pageSize: searchPageSize } = useSearchStoreRefs();
@@ -52,6 +101,22 @@ const container = ref();
52101
/>
53102
</SettingsFormItem>
54103

104+
<!-- Load lists in panel -->
105+
<SettingsFormItem :label="i18n('label_load_lists')">
106+
<NSelect
107+
v-model:value="selectedLists"
108+
class="list-select"
109+
:to="container"
110+
:options="listOptions"
111+
:loading="listsLoading"
112+
:disabled="listsLoading"
113+
:render-label="renderLabel"
114+
:max-tag-count="1"
115+
:ellipsis-tag-popover-props="{ disabled: true }"
116+
multiple
117+
/>
118+
</SettingsFormItem>
119+
55120
<!-- Restore tab -->
56121
<SettingsFormItem :label="i18n('label_restore_tab')">
57122
<NSwitch v-model:value="restoreRoute" class="form-switch">
@@ -91,6 +156,16 @@ const container = ref();
91156
</SettingsFormItem>
92157

93158
<!-- Page Size -->
159+
<SettingsFormItem :label="i18n('label_load_lists_page_size')">
160+
<NSelect
161+
v-model:value="loadListsPageSize"
162+
:disabled="!loadLists.length"
163+
class="form-select"
164+
:to="container"
165+
:options="pageSizeOptions"
166+
/>
167+
</SettingsFormItem>
168+
94169
<SettingsFormItem :label="i18n('label_history_page_size')">
95170
<NSelect
96171
v-model:value="historyPageSize"
@@ -143,7 +218,8 @@ const container = ref();
143218
min-width: 5.5rem;
144219
}
145220
146-
.default-tab {
147-
min-width: 7rem;
221+
.default-tab,
222+
.list-select {
223+
width: 12.5rem;
148224
}
149225
</style>

src/components/views/watchlist/WatchlistNavbar.vue

+2-2
Original file line numberDiff line numberDiff line change
@@ -49,12 +49,12 @@ const listOptions = computed<ListOption[]>(() =>
4949
label: [ListType.Collection, ListType.Watchlist, ListType.Favorites]
5050
.map(String)
5151
.includes(list.type)
52-
? i18n(list.name)
52+
? i18n(list.name, 'list')
5353
: list.name,
5454
value: list.id,
5555
source: list,
5656
icon: getIcon(list),
57-
disabled: listLoading.value || listLoading.value,
57+
disabled: listLoading.value,
5858
})),
5959
);
6060

src/i18n/en/list/list.json

+16
Original file line numberDiff line numberDiff line change
@@ -22,5 +22,21 @@
2222
"list__item__placeholder_empty": {
2323
"message": "Nothing on this day.",
2424
"description": "Empty placeholder for list item."
25+
},
26+
"list__list_type__watchlist": {
27+
"message": "Watchlist",
28+
"description": "Label for the watchlist list type"
29+
},
30+
"list__list_type__favorites": {
31+
"message": "Favorites",
32+
"description": "Label for the favorites list type"
33+
},
34+
"list__list_type__collection_movie": {
35+
"message": "Movie collection",
36+
"description": "Label for the movie collection list type"
37+
},
38+
"list__list_type__collection_show": {
39+
"message": "Show collection",
40+
"description": "Label for the show collection list type"
2541
}
2642
}

src/i18n/en/navbar/navbar-list.json

-18
This file was deleted.

src/i18n/en/settings/settings-tabs.json

+8
Original file line numberDiff line numberDiff line change
@@ -46,5 +46,13 @@
4646
"settings__tabs__label_search_page_size": {
4747
"message": "Search page size",
4848
"description": "Label for the 'Search page size' setting"
49+
},
50+
"settings__tabs__label_load_lists": {
51+
"message": "Lists to load when opening panels",
52+
"description": "Label for the 'Load lists' setting"
53+
},
54+
"settings__tabs__label_load_lists_page_size": {
55+
"message": "Page size for lists",
56+
"description": "Label for the 'Page size for lists' setting"
4957
}
5058
}

src/stores/data/list.store.ts

+24-13
Original file line numberDiff line numberDiff line change
@@ -185,6 +185,13 @@ export const useListsStore = defineStore(ListsStoreConstants.Store, () => {
185185
}
186186
};
187187

188+
/** Filter favorites and collections out */
189+
const myLists = computed(() => {
190+
return lists.value?.filter(list => {
191+
return [ListType.List, ListType.Watchlist].map(String).includes(list.type);
192+
});
193+
});
194+
188195
const initListsStore = async () => {
189196
await restoreState();
190197

@@ -193,7 +200,7 @@ export const useListsStore = defineStore(ListsStoreConstants.Store, () => {
193200
});
194201
};
195202

196-
return { listsLoading: loading, lists, activeList, fetchLists, clearState, initListsStore, getIcon };
203+
return { listsLoading: loading, lists, myLists, activeList, fetchLists, clearState, initListsStore, getIcon };
197204
});
198205

199206
export const useListsStoreRefs = () => storeToRefs(useListsStore());
@@ -209,6 +216,9 @@ type ListErrorDictionary = Partial<Record<ListEntity['type'], ErrorDictionary>>;
209216
type ListTypeLoading = Partial<Record<ListTypes, boolean>>;
210217
type ListDictionaryItemLoading = Partial<Record<ListTypes, Partial<Record<ListItemTypes, Record<string, boolean>>>>>;
211218

219+
type ListItemQuery = TraktWatchlistGetQuery | TraktFavoriteGetQuery | TraktCollectionGetQuery | TraktListItemsGetQuery;
220+
type ListQuery = { page?: number; limit?: number; list?: ListEntity };
221+
212222
const ListStoreConstants = {
213223
Store: 'data.list',
214224
LocalPageSize: 'data.list.page-size',
@@ -280,10 +290,7 @@ export const useListStore = defineStore(ListStoreConstants.Store, () => {
280290

281291
const { user } = useUserSettingsStoreRefs();
282292

283-
const fetchItems = async (
284-
list: ListEntity,
285-
query: TraktWatchlistGetQuery | TraktFavoriteGetQuery | TraktCollectionGetQuery | TraktListItemsGetQuery,
286-
) => {
293+
const fetchItems = async (list: ListEntity, query: ListItemQuery = {}) => {
287294
let _query = { ...query };
288295
let response;
289296

@@ -314,20 +321,16 @@ export const useListStore = defineStore(ListStoreConstants.Store, () => {
314321
return response;
315322
};
316323

317-
const fetchListItems = async ({
318-
page,
319-
limit = pageSize.value,
320-
list = activeList.value,
321-
}: { page?: number; limit?: number; list?: ListEntity } = {}) => {
322-
if (!firstLoad.value && loading.value) {
324+
const fetchListItems = async ({ page, limit = pageSize.value, list = activeList.value }: ListQuery = {}, parallel = false) => {
325+
if (!firstLoad.value && !parallel && loading.value) {
323326
logger.warn('Already fetching list');
324327
return;
325328
}
326329
if (firstLoad.value) firstLoad.value = false;
327330

328331
logger.debug('Fetching List', { list, page, limit });
329332

330-
loading.value = true;
333+
if (!parallel) loading.value = true;
331334
typeLoading[list.type] = true;
332335
listDictionaryLoading[list.id.toString()] = true;
333336
const timeout = debounceLoading(listItems, loadingPlaceholder, !page);
@@ -348,12 +351,19 @@ export const useListStore = defineStore(ListStoreConstants.Store, () => {
348351
throw e;
349352
} finally {
350353
clearTimeout(timeout);
351-
loading.value = false;
354+
if (!parallel) loading.value = false;
352355
typeLoading[list.type] = false;
353356
listDictionaryLoading[list.id.toString()] = false;
354357
}
355358
};
356359

360+
const fetchAll = async (lists: ListEntity[], query?: Omit<ListQuery, 'list'>) => {
361+
if (!lists.length) return;
362+
loading.value = true;
363+
await Promise.all(lists.map(list => fetchListItems({ list, ...query }, true)));
364+
loading.value = false;
365+
};
366+
357367
const i18n = useI18n('common', 'notification');
358368

359369
const { fetchActivity } = useActivityStore();
@@ -475,6 +485,7 @@ export const useListStore = defineStore(ListStoreConstants.Store, () => {
475485
belowThreshold,
476486
loadingPlaceholder,
477487
fetchListItems,
488+
fetchAll,
478489
filteredListItems,
479490
initListStore,
480491
isListLoading,

0 commit comments

Comments
 (0)