From 250fbc89e2f003dc672efbd86b7b73e59a039409 Mon Sep 17 00:00:00 2001 From: Eric Bailey Date: Wed, 6 Dec 2023 10:59:02 -0600 Subject: [PATCH] Sync prefs, add background task provider --- src/App.native.tsx | 4 + src/App.web.tsx | 4 + src/state/AccountBackgroundTaskProvider.tsx | 24 ++++ src/state/queries/preferences/index.ts | 116 ++++++++++++-------- 4 files changed, 100 insertions(+), 48 deletions(-) create mode 100644 src/state/AccountBackgroundTaskProvider.tsx diff --git a/src/App.native.tsx b/src/App.native.tsx index 5ffbb6a828..7d1a9e19eb 100644 --- a/src/App.native.tsx +++ b/src/App.native.tsx @@ -35,6 +35,7 @@ import { } from 'state/session' import {Provider as UnreadNotifsProvider} from 'state/queries/notifications/unread' import * as persisted from '#/state/persisted' +import {AccountBackgroundTaskProvider} from '#/state/AccountBackgroundTaskProvider' SplashScreen.preventAutoHideAsync() @@ -69,6 +70,9 @@ function InnerApp() { + {/* Must live inside the tree reset above */} + + diff --git a/src/App.web.tsx b/src/App.web.tsx index 74702dca2d..3b407cd13c 100644 --- a/src/App.web.tsx +++ b/src/App.web.tsx @@ -29,6 +29,7 @@ import { } from 'state/session' import {Provider as UnreadNotifsProvider} from 'state/queries/notifications/unread' import * as persisted from '#/state/persisted' +import {AccountBackgroundTaskProvider} from '#/state/AccountBackgroundTaskProvider' function InnerApp() { const {isInitialLoad, currentAccount} = useSession() @@ -56,6 +57,9 @@ function InnerApp() { + {/* Must live inside the tree reset above */} + + diff --git a/src/state/AccountBackgroundTaskProvider.tsx b/src/state/AccountBackgroundTaskProvider.tsx new file mode 100644 index 0000000000..d66ebedcb2 --- /dev/null +++ b/src/state/AccountBackgroundTaskProvider.tsx @@ -0,0 +1,24 @@ +import React from 'react' + +import {useSession} from '#/state/session' +import {useSyncPreferences} from '#/state/queries/preferences' + +/** + * Must live inside our "tree-reset" fragment in App.tsx, so that when the + * current user changes, we clean up the intervals. + */ +export function AccountBackgroundTaskProvider() { + const {currentAccount} = useSession() + const syncPreferences = useSyncPreferences() + const preferencesSyncInterval = React.useRef( + undefined, + ) + + React.useEffect(() => { + if (!currentAccount) return + preferencesSyncInterval.current = setInterval(syncPreferences, 15e3) + return () => clearInterval(preferencesSyncInterval.current) + }, [currentAccount, syncPreferences]) + + return null +} diff --git a/src/state/queries/preferences/index.ts b/src/state/queries/preferences/index.ts index afdec267d1..000a3fa3e2 100644 --- a/src/state/queries/preferences/index.ts +++ b/src/state/queries/preferences/index.ts @@ -1,6 +1,10 @@ -import {useMemo} from 'react' +import {useMemo, useCallback} from 'react' import {useQuery, useMutation, useQueryClient} from '@tanstack/react-query' -import {LabelPreference, BskyFeedViewPreference} from '@atproto/api' +import { + LabelPreference, + BskyFeedViewPreference, + BskyPreferences, +} from '@atproto/api' import {track} from '#/lib/analytics/analytics' import {getAge} from '#/lib/strings/time' @@ -26,6 +30,56 @@ export * from '#/state/queries/preferences/const' export const preferencesQueryKey = ['getPreferences'] +function mergePreferencesResponseWithDefaults( + res: BskyPreferences, +): UsePreferencesQueryResponse { + return { + ...res, + feeds: { + saved: res.feeds?.saved || [], + pinned: res.feeds?.pinned || [], + unpinned: + res.feeds.saved?.filter(f => { + return !res.feeds.pinned?.includes(f) + }) || [], + }, + // labels are undefined until set by user + contentLabels: { + nsfw: temp__migrateLabelPref( + res.contentLabels?.nsfw || DEFAULT_LABEL_PREFERENCES.nsfw, + ), + nudity: temp__migrateLabelPref( + res.contentLabels?.nudity || DEFAULT_LABEL_PREFERENCES.nudity, + ), + suggestive: temp__migrateLabelPref( + res.contentLabels?.suggestive || DEFAULT_LABEL_PREFERENCES.suggestive, + ), + gore: temp__migrateLabelPref( + res.contentLabels?.gore || DEFAULT_LABEL_PREFERENCES.gore, + ), + hate: temp__migrateLabelPref( + res.contentLabels?.hate || DEFAULT_LABEL_PREFERENCES.hate, + ), + spam: temp__migrateLabelPref( + res.contentLabels?.spam || DEFAULT_LABEL_PREFERENCES.spam, + ), + impersonation: temp__migrateLabelPref( + res.contentLabels?.impersonation || + DEFAULT_LABEL_PREFERENCES.impersonation, + ), + }, + feedViewPrefs: { + ...DEFAULT_HOME_FEED_PREFS, + ...(res.feedViewPrefs.home || {}), + }, + threadViewPrefs: { + ...DEFAULT_THREAD_VIEW_PREFS, + ...(res.threadViewPrefs ?? {}), + }, + userAge: res.birthDate ? getAge(res.birthDate) : undefined, + } +} + export function usePreferencesQuery() { return useQuery({ staleTime: STALE.MINUTES.ONE, @@ -37,58 +91,24 @@ export function usePreferencesQuery() { return DEFAULT_LOGGED_OUT_PREFERENCES } else { const res = await agent.getPreferences() - const preferences: UsePreferencesQueryResponse = { - ...res, - feeds: { - saved: res.feeds?.saved || [], - pinned: res.feeds?.pinned || [], - unpinned: - res.feeds.saved?.filter(f => { - return !res.feeds.pinned?.includes(f) - }) || [], - }, - // labels are undefined until set by user - contentLabels: { - nsfw: temp__migrateLabelPref( - res.contentLabels?.nsfw || DEFAULT_LABEL_PREFERENCES.nsfw, - ), - nudity: temp__migrateLabelPref( - res.contentLabels?.nudity || DEFAULT_LABEL_PREFERENCES.nudity, - ), - suggestive: temp__migrateLabelPref( - res.contentLabels?.suggestive || - DEFAULT_LABEL_PREFERENCES.suggestive, - ), - gore: temp__migrateLabelPref( - res.contentLabels?.gore || DEFAULT_LABEL_PREFERENCES.gore, - ), - hate: temp__migrateLabelPref( - res.contentLabels?.hate || DEFAULT_LABEL_PREFERENCES.hate, - ), - spam: temp__migrateLabelPref( - res.contentLabels?.spam || DEFAULT_LABEL_PREFERENCES.spam, - ), - impersonation: temp__migrateLabelPref( - res.contentLabels?.impersonation || - DEFAULT_LABEL_PREFERENCES.impersonation, - ), - }, - feedViewPrefs: { - ...DEFAULT_HOME_FEED_PREFS, - ...(res.feedViewPrefs.home || {}), - }, - threadViewPrefs: { - ...DEFAULT_THREAD_VIEW_PREFS, - ...(res.threadViewPrefs ?? {}), - }, - userAge: res.birthDate ? getAge(res.birthDate) : undefined, - } + const preferences = mergePreferencesResponseWithDefaults(res) return preferences } }, }) } +export function useSyncPreferences() { + const queryClient = useQueryClient() + + return useCallback(async () => { + queryClient.invalidateQueries({ + queryKey: preferencesQueryKey, + refetchType: 'none', + }) + }, [queryClient]) +} + export function useModerationOpts() { const {currentAccount} = useSession() const prefs = usePreferencesQuery()