Sync prefs, add background task provider
This commit is contained in:
@@ -35,6 +35,7 @@ import {
|
|||||||
} from 'state/session'
|
} from 'state/session'
|
||||||
import {Provider as UnreadNotifsProvider} from 'state/queries/notifications/unread'
|
import {Provider as UnreadNotifsProvider} from 'state/queries/notifications/unread'
|
||||||
import * as persisted from '#/state/persisted'
|
import * as persisted from '#/state/persisted'
|
||||||
|
import {AccountBackgroundTaskProvider} from '#/state/AccountBackgroundTaskProvider'
|
||||||
|
|
||||||
SplashScreen.preventAutoHideAsync()
|
SplashScreen.preventAutoHideAsync()
|
||||||
|
|
||||||
@@ -69,6 +70,9 @@ function InnerApp() {
|
|||||||
<React.Fragment
|
<React.Fragment
|
||||||
// Resets the entire tree below when it changes:
|
// Resets the entire tree below when it changes:
|
||||||
key={currentAccount?.did}>
|
key={currentAccount?.did}>
|
||||||
|
{/* Must live inside the tree reset above */}
|
||||||
|
<AccountBackgroundTaskProvider />
|
||||||
|
|
||||||
<LoggedOutViewProvider>
|
<LoggedOutViewProvider>
|
||||||
<UnreadNotifsProvider>
|
<UnreadNotifsProvider>
|
||||||
<ThemeProvider theme={colorMode}>
|
<ThemeProvider theme={colorMode}>
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ import {
|
|||||||
} from 'state/session'
|
} from 'state/session'
|
||||||
import {Provider as UnreadNotifsProvider} from 'state/queries/notifications/unread'
|
import {Provider as UnreadNotifsProvider} from 'state/queries/notifications/unread'
|
||||||
import * as persisted from '#/state/persisted'
|
import * as persisted from '#/state/persisted'
|
||||||
|
import {AccountBackgroundTaskProvider} from '#/state/AccountBackgroundTaskProvider'
|
||||||
|
|
||||||
function InnerApp() {
|
function InnerApp() {
|
||||||
const {isInitialLoad, currentAccount} = useSession()
|
const {isInitialLoad, currentAccount} = useSession()
|
||||||
@@ -56,6 +57,9 @@ function InnerApp() {
|
|||||||
<React.Fragment
|
<React.Fragment
|
||||||
// Resets the entire tree below when it changes:
|
// Resets the entire tree below when it changes:
|
||||||
key={currentAccount?.did}>
|
key={currentAccount?.did}>
|
||||||
|
{/* Must live inside the tree reset above */}
|
||||||
|
<AccountBackgroundTaskProvider />
|
||||||
|
|
||||||
<LoggedOutViewProvider>
|
<LoggedOutViewProvider>
|
||||||
<UnreadNotifsProvider>
|
<UnreadNotifsProvider>
|
||||||
<ThemeProvider theme={colorMode}>
|
<ThemeProvider theme={colorMode}>
|
||||||
|
|||||||
@@ -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<NodeJS.Timeout | undefined>(
|
||||||
|
undefined,
|
||||||
|
)
|
||||||
|
|
||||||
|
React.useEffect(() => {
|
||||||
|
if (!currentAccount) return
|
||||||
|
preferencesSyncInterval.current = setInterval(syncPreferences, 15e3)
|
||||||
|
return () => clearInterval(preferencesSyncInterval.current)
|
||||||
|
}, [currentAccount, syncPreferences])
|
||||||
|
|
||||||
|
return null
|
||||||
|
}
|
||||||
@@ -1,6 +1,10 @@
|
|||||||
import {useMemo} from 'react'
|
import {useMemo, useCallback} from 'react'
|
||||||
import {useQuery, useMutation, useQueryClient} from '@tanstack/react-query'
|
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 {track} from '#/lib/analytics/analytics'
|
||||||
import {getAge} from '#/lib/strings/time'
|
import {getAge} from '#/lib/strings/time'
|
||||||
@@ -26,6 +30,56 @@ export * from '#/state/queries/preferences/const'
|
|||||||
|
|
||||||
export const preferencesQueryKey = ['getPreferences']
|
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() {
|
export function usePreferencesQuery() {
|
||||||
return useQuery({
|
return useQuery({
|
||||||
staleTime: STALE.MINUTES.ONE,
|
staleTime: STALE.MINUTES.ONE,
|
||||||
@@ -37,58 +91,24 @@ export function usePreferencesQuery() {
|
|||||||
return DEFAULT_LOGGED_OUT_PREFERENCES
|
return DEFAULT_LOGGED_OUT_PREFERENCES
|
||||||
} else {
|
} else {
|
||||||
const res = await agent.getPreferences()
|
const res = await agent.getPreferences()
|
||||||
const preferences: UsePreferencesQueryResponse = {
|
const preferences = mergePreferencesResponseWithDefaults(res)
|
||||||
...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,
|
|
||||||
}
|
|
||||||
return preferences
|
return preferences
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function useSyncPreferences() {
|
||||||
|
const queryClient = useQueryClient()
|
||||||
|
|
||||||
|
return useCallback(async () => {
|
||||||
|
queryClient.invalidateQueries({
|
||||||
|
queryKey: preferencesQueryKey,
|
||||||
|
refetchType: 'none',
|
||||||
|
})
|
||||||
|
}, [queryClient])
|
||||||
|
}
|
||||||
|
|
||||||
export function useModerationOpts() {
|
export function useModerationOpts() {
|
||||||
const {currentAccount} = useSession()
|
const {currentAccount} = useSession()
|
||||||
const prefs = usePreferencesQuery()
|
const prefs = usePreferencesQuery()
|
||||||
|
|||||||
Reference in New Issue
Block a user