Skip to content

Commit a5345dc

Browse files
committed
fix(visibility): watch document visibility and refresh view when active
1 parent f90020b commit a5345dc

16 files changed

+121
-26
lines changed

src/components/views/calendar/CalendarComponent.vue

+6-2
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,8 @@ import { useActivityStore } from '~/stores/data/activity.store';
1212
import { useCalendarStore, useCalendarStoreRefs } from '~/stores/data/calendar.store';
1313
import { useCalendar, useCenterButton } from '~/utils/calendar.utils';
1414
import { useI18n } from '~/utils/i18n.utils';
15-
import { watchUserChange } from '~/utils/store.utils';
16-
import { useWatchActivated } from '~/utils/watching.utils';
15+
import { useActiveAndDocumentVisible, watchUserChange } from '~/utils/store.utils';
16+
import { useWatchActivated } from '~/utils/vue.utils';
1717
1818
const i18n = useI18n('calendar');
1919
@@ -59,6 +59,10 @@ watchUserChange({
5959
},
6060
});
6161
62+
useActiveAndDocumentVisible({
63+
onVisible: fetchCalendar,
64+
});
65+
6266
const { onItemClick } = usePanelItem();
6367
</script>
6468

src/components/views/history/HistoryComponent.vue

+6-2
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,8 @@ import { useActivityStore } from '~/stores/data/activity.store';
1616
import { useHistoryStore, useHistoryStoreRefs } from '~/stores/data/history.store';
1717
import { useWatchingStoreRefs } from '~/stores/data/watching.store';
1818
import { useI18n } from '~/utils/i18n.utils';
19-
import { watchUserChange } from '~/utils/store.utils';
20-
import { useWatchActivated } from '~/utils/watching.utils';
19+
import { useActiveAndDocumentVisible, watchUserChange } from '~/utils/store.utils';
20+
import { useWatchActivated } from '~/utils/vue.utils';
2121
2222
const { footerOpen, panelOpen, panelDirty } = useAppStateStoreRefs();
2323
@@ -66,6 +66,10 @@ onMounted(() => {
6666
await fetchHistory();
6767
});
6868
});
69+
70+
useActiveAndDocumentVisible({
71+
onVisible: fetchHistory,
72+
});
6973
</script>
7074

7175
<template>

src/components/views/progress/ProgressComponent.vue

+6-2
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,9 @@ import { useProgressStore, useProgressStoreRefs } from '~/stores/data/progress.s
1717
import { useWatchingStoreRefs } from '~/stores/data/watching.store';
1818
import { useAuthSettingsStoreRefs } from '~/stores/settings/auth.store';
1919
import { useI18n } from '~/utils/i18n.utils';
20-
import { watchUserChange } from '~/utils/store.utils';
20+
import { useActiveAndDocumentVisible, watchUserChange } from '~/utils/store.utils';
2121
import { getSessionUser } from '~/utils/trakt-service.utils';
22-
import { useWatchActivated } from '~/utils/watching.utils';
22+
import { useWatchActivated } from '~/utils/vue.utils';
2323
2424
const i18n = useI18n('progress');
2525
@@ -78,6 +78,10 @@ watchUserChange({
7878
notification.value?.destroy();
7979
},
8080
});
81+
82+
useActiveAndDocumentVisible({
83+
onVisible: fetchProgress,
84+
});
8185
</script>
8286

8387
<template>

src/components/views/releases/ReleasesComponent.vue

+5-1
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ import { useAppStateStoreRefs } from '~/stores/app-state.store';
1414
import { useReleasesStore, useReleasesStoreRefs } from '~/stores/data/releases.store';
1515
import { useCalendar, useCenterButton } from '~/utils/calendar.utils';
1616
import { useI18n } from '~/utils/i18n.utils';
17-
import { watchUserChange } from '~/utils/store.utils';
17+
import { useActiveAndDocumentVisible, watchUserChange } from '~/utils/store.utils';
1818
1919
const i18n = useI18n('releases');
2020
@@ -47,6 +47,10 @@ watchUserChange({
4747
},
4848
});
4949
50+
useActiveAndDocumentVisible({
51+
onVisible: fetchReleases,
52+
});
53+
5054
const { onItemClick } = usePanelItem();
5155
5256
const onMovieClick = async ({ item }: { item: ListScrollItem }) => {

src/components/views/releases/ReleasesNavbar.vue

+5
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import IconCalendar from '~/components/icons/IconCalendar.vue';
88
import IconChevron from '~/components/icons/IconChevronDownSmall.vue';
99
import { useReleasesStore, useReleasesStoreRefs } from '~/stores/data/releases.store';
1010
import { useI18n } from '~/utils/i18n.utils';
11+
import { useActiveAndDocumentVisible } from '~/utils/store.utils';
1112
1213
defineProps({
1314
parentElement: {
@@ -48,6 +49,10 @@ const regionOptions = computed<SelectOption[]>(() =>
4849
const open = ref(false);
4950
5051
onActivated(() => fetchRegions());
52+
53+
useActiveAndDocumentVisible({
54+
onVisible: fetchRegions,
55+
});
5156
</script>
5257

5358
<template>

src/components/views/search/SearchComponent.vue

+5
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import {
1717
useSearchStoreRefs,
1818
} from '~/stores/data/search.store';
1919
import { useI18n } from '~/utils/i18n.utils';
20+
import { useActiveAndDocumentVisible } from '~/utils/store.utils';
2021
2122
const i18n = useI18n('search');
2223
@@ -29,6 +30,10 @@ onActivated(async () => {
2930
await fetchSearchResults();
3031
});
3132
33+
useActiveAndDocumentVisible({
34+
onVisible: fetchSearchResults,
35+
});
36+
3237
const list = useListScroll<SearchResult>(searchResults);
3338
3439
const { onScroll } = useListScrollEvents(fetchSearchResults, {

src/components/views/settings/SettingsAccount.vue

+1-1
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ import {
2323
} from '~/stores/settings/user.store';
2424
2525
import { useI18n } from '~/utils/i18n.utils';
26-
import { useWatchActivated } from '~/utils/watching.utils';
26+
import { useWatchActivated } from '~/utils/vue.utils';
2727
2828
const i18n = useI18n('settings', 'account');
2929

src/components/views/settings/SettingsConnect.vue

+1-1
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ import { useAuthSettingsStoreRefs } from '~/stores/settings/auth.store';
1717
import { useLinksStore } from '~/stores/settings/links.store';
1818
import { defaultUser } from '~/stores/settings/user.store';
1919
import { useI18n } from '~/utils/i18n.utils';
20-
import { useWatchActivated } from '~/utils/watching.utils';
20+
import { useWatchActivated } from '~/utils/vue.utils';
2121
2222
const i18n = useI18n('settings', 'connect');
2323

src/components/views/settings/SettingsTabs.vue

+1-1
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ import {
3737
} from '~/stores/settings/extension.store';
3838
import { defaultUser } from '~/stores/settings/user.store';
3939
import { useI18n } from '~/utils/i18n.utils';
40-
import { useWatchActivated } from '~/utils/watching.utils';
40+
import { useWatchActivated } from '~/utils/vue.utils';
4141
4242
const i18n = useI18n('settings', 'tabs');
4343

src/components/views/watchlist/WatchlistComponent.vue

+6-2
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,8 @@ import {
2323
useListStoreRefs,
2424
} from '~/stores/data/list.store';
2525
import { useI18n } from '~/utils/i18n.utils';
26-
import { watchUserChange } from '~/utils/store.utils';
27-
import { useWatchActivated } from '~/utils/watching.utils';
26+
import { useActiveAndDocumentVisible, watchUserChange } from '~/utils/store.utils';
27+
import { useWatchActivated } from '~/utils/vue.utils';
2828
2929
const i18n = useI18n('list');
3030
@@ -80,6 +80,10 @@ onMounted(() => {
8080
});
8181
watch(activeList, () => onClick());
8282
});
83+
84+
useActiveAndDocumentVisible({
85+
onVisible: fetchListItems,
86+
});
8387
</script>
8488

8589
<template>

src/components/views/watchlist/WatchlistNavbar.vue

+9-1
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,11 @@ import {
1717
} from '~/stores/data/list.store';
1818
import { useAuthSettingsStoreRefs } from '~/stores/settings/auth.store';
1919
import { useI18n } from '~/utils/i18n.utils';
20-
import { useDebouncedSearch, watchUserChange } from '~/utils/store.utils';
20+
import {
21+
useActiveAndDocumentVisible,
22+
useDebouncedSearch,
23+
watchUserChange,
24+
} from '~/utils/store.utils';
2125
2226
const i18n = useI18n('navbar', 'list');
2327
@@ -86,6 +90,10 @@ watchUserChange({
8690
},
8791
});
8892
93+
useActiveAndDocumentVisible({
94+
onVisible: fetchLists,
95+
});
96+
8997
const open = ref(false);
9098
9199
const renderLabel = (option: ListOption) => [

src/stores/data/activity.store.ts

+3
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import { useAuthSettingsStoreRefs } from '~/stores/settings/auth.store';
1616
import { useUserSettingsStore } from '~/stores/settings/user.store';
1717
import { storage } from '~/utils/browser/browser-storage.utils';
1818
import { debounce } from '~/utils/debounce.utils';
19+
import { useDocumentVisible } from '~/utils/store.utils';
1920

2021
type Evicted = Record<Route, boolean>;
2122
const defaultEvicted: Evicted = Object.fromEntries(Object.values(Route).map(route => [route, false])) as Evicted;
@@ -209,6 +210,8 @@ export const useActivityStore = defineStore(ActivityStoreConstants.Store, () =>
209210
await fetchActivity();
210211
});
211212

213+
useDocumentVisible({ onVisible: fetchActivity });
214+
212215
if (polling.value || !isAuthenticated.value) return;
213216
return fetchActivity();
214217
};

src/stores/data/watching.store.ts

+3
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import { TraktService } from '~/services/trakt.service';
1212
import { useAuthSettingsStoreRefs } from '~/stores/settings/auth.store';
1313
import { storage } from '~/utils/browser/browser-storage.utils';
1414
import { useI18n } from '~/utils/i18n.utils';
15+
import { useDocumentVisible } from '~/utils/store.utils';
1516

1617
const WatchingStoreConstants = {
1718
Store: 'data.watching',
@@ -170,6 +171,8 @@ export const useWatchingStore = defineStore(WatchingStoreConstants.Store, () =>
170171
if (!isAuthenticated.value) return;
171172
await fetchWatching();
172173
});
174+
175+
useDocumentVisible({ onVisible: fetchWatching });
173176
};
174177

175178
return {

src/utils/store.utils.ts

+51
Original file line numberDiff line numberDiff line change
@@ -168,3 +168,54 @@ export const useWaitReady = () => {
168168

169169
return { waitReady, setReady, isReady };
170170
};
171+
172+
export const useDocumentVisible = ({
173+
onHidden,
174+
onVisible,
175+
onVisibilityChange,
176+
}: {
177+
onHidden?: () => void;
178+
onVisible?: () => void;
179+
onVisibilityChange?: (visible: boolean) => void;
180+
} = {}) => {
181+
const listener = () => {
182+
const isVisible = !document.hidden;
183+
onVisibilityChange?.(isVisible);
184+
if (!isVisible) return onHidden?.();
185+
onVisible?.();
186+
};
187+
188+
document.addEventListener('visibilitychange', listener);
189+
190+
return () => document.removeEventListener('visibilitychange', listener);
191+
};
192+
193+
export const useActiveAndDocumentVisible = ({
194+
visible = ref(!document.hidden),
195+
onHidden,
196+
onVisible,
197+
onVisibilityChange,
198+
}: {
199+
visible?: Ref<boolean>;
200+
onHidden?: () => void;
201+
onVisible?: () => void;
202+
onVisibilityChange?: (visible: boolean) => void;
203+
} = {}) => {
204+
const listener = () => {
205+
visible.value = !document.hidden;
206+
};
207+
const sub = ref<() => void>();
208+
onActivated(() => {
209+
document.addEventListener('visibilitychange', listener);
210+
sub.value = watch(visible, _visible => {
211+
onVisibilityChange?.(_visible);
212+
if (!visible.value) return onHidden?.();
213+
onVisible?.();
214+
});
215+
});
216+
onDeactivated(() => {
217+
document.removeEventListener('visibilitychange', listener);
218+
sub.value?.();
219+
});
220+
return visible;
221+
};

src/utils/vue.utils.ts

+12-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { ref, type Ref, type UnwrapRef, watch, type WatchOptions } from 'vue';
1+
import { onActivated, onDeactivated, ref, type Ref, type UnwrapRef, watch, type WatchOptions } from 'vue';
22

33
import { debounce } from '~/utils/debounce.utils';
44

@@ -53,3 +53,14 @@ export const useDebounceRef = <T>(outerRef: Ref<T>, delay = 100, options?: Watch
5353
const unSubscribe = watch(outerRef, setValue, options);
5454
return { value: innerRef, unSubscribe, setValue };
5555
};
56+
57+
export const useWatchActivated = (_sub: ReturnType<typeof watch>) => {
58+
const sub = ref<() => void>();
59+
onActivated(() => {
60+
sub.value = _sub;
61+
});
62+
onDeactivated(() => {
63+
sub.value?.();
64+
});
65+
return { sub };
66+
};

src/utils/watching.utils.ts

+1-12
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import { elapsedTime } from '@dvcol/common-utils/common/date';
22

33
import { useDialog } from 'naive-ui';
44

5-
import { computed, onActivated, onBeforeMount, onDeactivated, ref, watch } from 'vue';
5+
import { computed, onBeforeMount, ref, watch } from 'vue';
66

77
import type { TraktWatching } from '@dvcol/trakt-http-client/models';
88
import type { Ref } from 'vue';
@@ -94,14 +94,3 @@ export const useCancelWatching = (cancel: () => unknown, action: TraktWatching['
9494
});
9595
return { onCancel };
9696
};
97-
98-
export const useWatchActivated = (_sub: ReturnType<typeof watch>) => {
99-
const sub = ref<() => void>();
100-
onActivated(() => {
101-
sub.value = _sub;
102-
});
103-
onDeactivated(() => {
104-
sub.value?.();
105-
});
106-
return { sub };
107-
};

0 commit comments

Comments
 (0)