Performance improvements: structural sharing & moderation opts context (#3785)
* Fix: correctly apply structural sharing to preferences object * Move moderation opts into a context * Fix import * Remove log * Pass userdid directly * Pass moderationPrefs directlyzio/stable
parent
39807a8630
commit
31cb3e5422
|
@ -18,6 +18,7 @@ import {useQueryClient} from '@tanstack/react-query'
|
||||||
import {Provider as StatsigProvider} from '#/lib/statsig/statsig'
|
import {Provider as StatsigProvider} from '#/lib/statsig/statsig'
|
||||||
import {init as initPersistedState} from '#/state/persisted'
|
import {init as initPersistedState} from '#/state/persisted'
|
||||||
import {Provider as LabelDefsProvider} from '#/state/preferences/label-defs'
|
import {Provider as LabelDefsProvider} from '#/state/preferences/label-defs'
|
||||||
|
import {Provider as ModerationOptsProvider} from '#/state/preferences/moderation-opts'
|
||||||
import {readLastActiveAccount} from '#/state/session/util'
|
import {readLastActiveAccount} from '#/state/session/util'
|
||||||
import {useIntentHandler} from 'lib/hooks/useIntentHandler'
|
import {useIntentHandler} from 'lib/hooks/useIntentHandler'
|
||||||
import {useNotificationsListener} from 'lib/notifications/notifications'
|
import {useNotificationsListener} from 'lib/notifications/notifications'
|
||||||
|
@ -79,23 +80,25 @@ function InnerApp() {
|
||||||
<QueryProvider currentDid={currentAccount?.did}>
|
<QueryProvider currentDid={currentAccount?.did}>
|
||||||
<PushNotificationsListener>
|
<PushNotificationsListener>
|
||||||
<StatsigProvider>
|
<StatsigProvider>
|
||||||
<LabelDefsProvider>
|
<ModerationOptsProvider>
|
||||||
<LoggedOutViewProvider>
|
<LabelDefsProvider>
|
||||||
<SelectedFeedProvider>
|
<LoggedOutViewProvider>
|
||||||
<UnreadNotifsProvider>
|
<SelectedFeedProvider>
|
||||||
<ThemeProvider theme={theme}>
|
<UnreadNotifsProvider>
|
||||||
{/* All components should be within this provider */}
|
<ThemeProvider theme={theme}>
|
||||||
<RootSiblingParent>
|
{/* All components should be within this provider */}
|
||||||
<GestureHandlerRootView style={s.h100pct}>
|
<RootSiblingParent>
|
||||||
<TestCtrls />
|
<GestureHandlerRootView style={s.h100pct}>
|
||||||
<Shell />
|
<TestCtrls />
|
||||||
</GestureHandlerRootView>
|
<Shell />
|
||||||
</RootSiblingParent>
|
</GestureHandlerRootView>
|
||||||
</ThemeProvider>
|
</RootSiblingParent>
|
||||||
</UnreadNotifsProvider>
|
</ThemeProvider>
|
||||||
</SelectedFeedProvider>
|
</UnreadNotifsProvider>
|
||||||
</LoggedOutViewProvider>
|
</SelectedFeedProvider>
|
||||||
</LabelDefsProvider>
|
</LoggedOutViewProvider>
|
||||||
|
</LabelDefsProvider>
|
||||||
|
</ModerationOptsProvider>
|
||||||
</StatsigProvider>
|
</StatsigProvider>
|
||||||
</PushNotificationsListener>
|
</PushNotificationsListener>
|
||||||
</QueryProvider>
|
</QueryProvider>
|
||||||
|
|
|
@ -8,6 +8,7 @@ import {SafeAreaProvider} from 'react-native-safe-area-context'
|
||||||
import {Provider as StatsigProvider} from '#/lib/statsig/statsig'
|
import {Provider as StatsigProvider} from '#/lib/statsig/statsig'
|
||||||
import {init as initPersistedState} from '#/state/persisted'
|
import {init as initPersistedState} from '#/state/persisted'
|
||||||
import {Provider as LabelDefsProvider} from '#/state/preferences/label-defs'
|
import {Provider as LabelDefsProvider} from '#/state/preferences/label-defs'
|
||||||
|
import {Provider as ModerationOptsProvider} from '#/state/preferences/moderation-opts'
|
||||||
import {readLastActiveAccount} from '#/state/session/util'
|
import {readLastActiveAccount} from '#/state/session/util'
|
||||||
import {useIntentHandler} from 'lib/hooks/useIntentHandler'
|
import {useIntentHandler} from 'lib/hooks/useIntentHandler'
|
||||||
import {QueryProvider} from 'lib/react-query'
|
import {QueryProvider} from 'lib/react-query'
|
||||||
|
@ -56,23 +57,25 @@ function InnerApp() {
|
||||||
key={currentAccount?.did}>
|
key={currentAccount?.did}>
|
||||||
<QueryProvider currentDid={currentAccount?.did}>
|
<QueryProvider currentDid={currentAccount?.did}>
|
||||||
<StatsigProvider>
|
<StatsigProvider>
|
||||||
<LabelDefsProvider>
|
<ModerationOptsProvider>
|
||||||
<LoggedOutViewProvider>
|
<LabelDefsProvider>
|
||||||
<SelectedFeedProvider>
|
<LoggedOutViewProvider>
|
||||||
<UnreadNotifsProvider>
|
<SelectedFeedProvider>
|
||||||
<ThemeProvider theme={theme}>
|
<UnreadNotifsProvider>
|
||||||
{/* All components should be within this provider */}
|
<ThemeProvider theme={theme}>
|
||||||
<RootSiblingParent>
|
{/* All components should be within this provider */}
|
||||||
<SafeAreaProvider>
|
<RootSiblingParent>
|
||||||
<Shell />
|
<SafeAreaProvider>
|
||||||
</SafeAreaProvider>
|
<Shell />
|
||||||
</RootSiblingParent>
|
</SafeAreaProvider>
|
||||||
<ToastContainer />
|
</RootSiblingParent>
|
||||||
</ThemeProvider>
|
<ToastContainer />
|
||||||
</UnreadNotifsProvider>
|
</ThemeProvider>
|
||||||
</SelectedFeedProvider>
|
</UnreadNotifsProvider>
|
||||||
</LoggedOutViewProvider>
|
</SelectedFeedProvider>
|
||||||
</LabelDefsProvider>
|
</LoggedOutViewProvider>
|
||||||
|
</LabelDefsProvider>
|
||||||
|
</ModerationOptsProvider>
|
||||||
</StatsigProvider>
|
</StatsigProvider>
|
||||||
</QueryProvider>
|
</QueryProvider>
|
||||||
</React.Fragment>
|
</React.Fragment>
|
||||||
|
|
|
@ -9,7 +9,7 @@ import {makeProfileLink} from '#/lib/routes/links'
|
||||||
import {sanitizeDisplayName} from '#/lib/strings/display-names'
|
import {sanitizeDisplayName} from '#/lib/strings/display-names'
|
||||||
import {sanitizeHandle} from '#/lib/strings/handles'
|
import {sanitizeHandle} from '#/lib/strings/handles'
|
||||||
import {pluralize} from '#/lib/strings/helpers'
|
import {pluralize} from '#/lib/strings/helpers'
|
||||||
import {useModerationOpts} from '#/state/queries/preferences'
|
import {useModerationOpts} from '#/state/preferences/moderation-opts'
|
||||||
import {usePrefetchProfileQuery, useProfileQuery} from '#/state/queries/profile'
|
import {usePrefetchProfileQuery, useProfileQuery} from '#/state/queries/profile'
|
||||||
import {useSession} from '#/state/session'
|
import {useSession} from '#/state/session'
|
||||||
import {useProfileShadow} from 'state/cache/profile-shadow'
|
import {useProfileShadow} from 'state/cache/profile-shadow'
|
||||||
|
|
|
@ -8,7 +8,7 @@ import {useLingui} from '@lingui/react'
|
||||||
import {sanitizeDisplayName} from '#/lib/strings/display-names'
|
import {sanitizeDisplayName} from '#/lib/strings/display-names'
|
||||||
import {sanitizeHandle} from '#/lib/strings/handles'
|
import {sanitizeHandle} from '#/lib/strings/handles'
|
||||||
import {isWeb} from '#/platform/detection'
|
import {isWeb} from '#/platform/detection'
|
||||||
import {useModerationOpts} from '#/state/queries/preferences'
|
import {useModerationOpts} from '#/state/preferences/moderation-opts'
|
||||||
import {useActorAutocompleteQuery} from 'state/queries/actor-autocomplete'
|
import {useActorAutocompleteQuery} from 'state/queries/actor-autocomplete'
|
||||||
import {FAB} from '#/view/com/util/fab/FAB'
|
import {FAB} from '#/view/com/util/fab/FAB'
|
||||||
import * as Toast from '#/view/com/util/Toast'
|
import * as Toast from '#/view/com/util/Toast'
|
||||||
|
|
|
@ -9,3 +9,90 @@ export function dedupArray<T>(arr: T[]): T[] {
|
||||||
const s = new Set(arr)
|
const s = new Set(arr)
|
||||||
return [...s]
|
return [...s]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Taken from @tanstack/query-core utils.ts
|
||||||
|
* Modified to support Date object comparisons
|
||||||
|
*
|
||||||
|
* This function returns `a` if `b` is deeply equal.
|
||||||
|
* If not, it will replace any deeply equal children of `b` with those of `a`.
|
||||||
|
* This can be used for structural sharing between JSON values for example.
|
||||||
|
*/
|
||||||
|
export function replaceEqualDeep(a: any, b: any): any {
|
||||||
|
if (a === b) {
|
||||||
|
return a
|
||||||
|
}
|
||||||
|
|
||||||
|
if (a instanceof Date && b instanceof Date) {
|
||||||
|
return a.getTime() === b.getTime() ? a : b
|
||||||
|
}
|
||||||
|
|
||||||
|
const array = isPlainArray(a) && isPlainArray(b)
|
||||||
|
|
||||||
|
if (array || (isPlainObject(a) && isPlainObject(b))) {
|
||||||
|
const aItems = array ? a : Object.keys(a)
|
||||||
|
const aSize = aItems.length
|
||||||
|
const bItems = array ? b : Object.keys(b)
|
||||||
|
const bSize = bItems.length
|
||||||
|
const copy: any = array ? [] : {}
|
||||||
|
|
||||||
|
let equalItems = 0
|
||||||
|
|
||||||
|
for (let i = 0; i < bSize; i++) {
|
||||||
|
const key = array ? i : bItems[i]
|
||||||
|
if (
|
||||||
|
!array &&
|
||||||
|
a[key] === undefined &&
|
||||||
|
b[key] === undefined &&
|
||||||
|
aItems.includes(key)
|
||||||
|
) {
|
||||||
|
copy[key] = undefined
|
||||||
|
equalItems++
|
||||||
|
} else {
|
||||||
|
copy[key] = replaceEqualDeep(a[key], b[key])
|
||||||
|
if (copy[key] === a[key] && a[key] !== undefined) {
|
||||||
|
equalItems++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return aSize === bSize && equalItems === aSize ? a : copy
|
||||||
|
}
|
||||||
|
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
|
||||||
|
export function isPlainArray(value: unknown) {
|
||||||
|
return Array.isArray(value) && value.length === Object.keys(value).length
|
||||||
|
}
|
||||||
|
|
||||||
|
// Copied from: https://github.com/jonschlinkert/is-plain-object
|
||||||
|
export function isPlainObject(o: any): o is Object {
|
||||||
|
if (!hasObjectPrototype(o)) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// If has no constructor
|
||||||
|
const ctor = o.constructor
|
||||||
|
if (ctor === undefined) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// If has modified prototype
|
||||||
|
const prot = ctor.prototype
|
||||||
|
if (!hasObjectPrototype(prot)) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// If constructor does not have an Object-specific method
|
||||||
|
if (!prot.hasOwnProperty('isPrototypeOf')) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// Most likely a plain Object
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
function hasObjectPrototype(o: any): boolean {
|
||||||
|
return Object.prototype.toString.call(o) === '[object Object]'
|
||||||
|
}
|
||||||
|
|
|
@ -2,13 +2,13 @@ import React from 'react'
|
||||||
import {View, ViewStyle} from 'react-native'
|
import {View, ViewStyle} from 'react-native'
|
||||||
import {AppBskyActorDefs, moderateProfile} from '@atproto/api'
|
import {AppBskyActorDefs, moderateProfile} from '@atproto/api'
|
||||||
|
|
||||||
import {useTheme, atoms as a, flatten} from '#/alf'
|
import {useModerationOpts} from '#/state/preferences/moderation-opts'
|
||||||
import {Text} from '#/components/Typography'
|
import {UserAvatar} from '#/view/com/util/UserAvatar'
|
||||||
|
import {atoms as a, flatten, useTheme} from '#/alf'
|
||||||
import {useItemContext} from '#/components/forms/Toggle'
|
import {useItemContext} from '#/components/forms/Toggle'
|
||||||
import {Check_Stroke2_Corner0_Rounded as Check} from '#/components/icons/Check'
|
import {Check_Stroke2_Corner0_Rounded as Check} from '#/components/icons/Check'
|
||||||
import {UserAvatar} from '#/view/com/util/UserAvatar'
|
|
||||||
import {useModerationOpts} from '#/state/queries/preferences'
|
|
||||||
import {RichText} from '#/components/RichText'
|
import {RichText} from '#/components/RichText'
|
||||||
|
import {Text} from '#/components/Typography'
|
||||||
|
|
||||||
export function SuggestedAccountCard({
|
export function SuggestedAccountCard({
|
||||||
profile,
|
profile,
|
||||||
|
|
|
@ -7,7 +7,7 @@ import {useLingui} from '@lingui/react'
|
||||||
import {useAnalytics} from '#/lib/analytics/analytics'
|
import {useAnalytics} from '#/lib/analytics/analytics'
|
||||||
import {logEvent} from '#/lib/statsig/statsig'
|
import {logEvent} from '#/lib/statsig/statsig'
|
||||||
import {capitalize} from '#/lib/strings/capitalize'
|
import {capitalize} from '#/lib/strings/capitalize'
|
||||||
import {useModerationOpts} from '#/state/queries/preferences'
|
import {useModerationOpts} from '#/state/preferences/moderation-opts'
|
||||||
import {useProfilesQuery} from '#/state/queries/profile'
|
import {useProfilesQuery} from '#/state/queries/profile'
|
||||||
import {
|
import {
|
||||||
DescriptionText,
|
DescriptionText,
|
||||||
|
|
|
@ -0,0 +1,61 @@
|
||||||
|
import React, {createContext, useContext, useMemo} from 'react'
|
||||||
|
import {BSKY_LABELER_DID, ModerationOpts} from '@atproto/api'
|
||||||
|
|
||||||
|
import {useHiddenPosts, useLabelDefinitions} from '#/state/preferences'
|
||||||
|
import {DEFAULT_LOGGED_OUT_LABEL_PREFERENCES} from '#/state/queries/preferences/moderation'
|
||||||
|
import {useSession} from '#/state/session'
|
||||||
|
import {usePreferencesQuery} from '../queries/preferences'
|
||||||
|
|
||||||
|
export const moderationOptsContext = createContext<ModerationOpts | undefined>(
|
||||||
|
undefined,
|
||||||
|
)
|
||||||
|
|
||||||
|
// used in the moderation state devtool
|
||||||
|
export const moderationOptsOverrideContext = createContext<
|
||||||
|
ModerationOpts | undefined
|
||||||
|
>(undefined)
|
||||||
|
|
||||||
|
export function useModerationOpts() {
|
||||||
|
return useContext(moderationOptsContext)
|
||||||
|
}
|
||||||
|
|
||||||
|
export function Provider({children}: React.PropsWithChildren<{}>) {
|
||||||
|
const override = useContext(moderationOptsOverrideContext)
|
||||||
|
const {currentAccount} = useSession()
|
||||||
|
const prefs = usePreferencesQuery()
|
||||||
|
const {labelDefs} = useLabelDefinitions()
|
||||||
|
const hiddenPosts = useHiddenPosts() // TODO move this into pds-stored prefs
|
||||||
|
|
||||||
|
const userDid = currentAccount?.did
|
||||||
|
const moderationPrefs = prefs.data?.moderationPrefs
|
||||||
|
const value = useMemo<ModerationOpts | undefined>(() => {
|
||||||
|
if (override) {
|
||||||
|
return override
|
||||||
|
}
|
||||||
|
if (!moderationPrefs) {
|
||||||
|
return undefined
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
userDid,
|
||||||
|
prefs: {
|
||||||
|
...moderationPrefs,
|
||||||
|
labelers: moderationPrefs.labelers.length
|
||||||
|
? moderationPrefs.labelers
|
||||||
|
: [
|
||||||
|
{
|
||||||
|
did: BSKY_LABELER_DID,
|
||||||
|
labels: DEFAULT_LOGGED_OUT_LABEL_PREFERENCES,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
hiddenPosts: hiddenPosts || [],
|
||||||
|
},
|
||||||
|
labelDefs,
|
||||||
|
}
|
||||||
|
}, [override, userDid, labelDefs, moderationPrefs, hiddenPosts])
|
||||||
|
|
||||||
|
return (
|
||||||
|
<moderationOptsContext.Provider value={value}>
|
||||||
|
{children}
|
||||||
|
</moderationOptsContext.Provider>
|
||||||
|
)
|
||||||
|
}
|
|
@ -6,7 +6,8 @@ import {isJustAMute} from '#/lib/moderation'
|
||||||
import {logger} from '#/logger'
|
import {logger} from '#/logger'
|
||||||
import {STALE} from '#/state/queries'
|
import {STALE} from '#/state/queries'
|
||||||
import {useAgent} from '#/state/session'
|
import {useAgent} from '#/state/session'
|
||||||
import {DEFAULT_LOGGED_OUT_PREFERENCES, useModerationOpts} from './preferences'
|
import {useModerationOpts} from '../preferences/moderation-opts'
|
||||||
|
import {DEFAULT_LOGGED_OUT_PREFERENCES} from './preferences'
|
||||||
|
|
||||||
const DEFAULT_MOD_OPTS = {
|
const DEFAULT_MOD_OPTS = {
|
||||||
userDid: undefined,
|
userDid: undefined,
|
||||||
|
|
|
@ -28,8 +28,8 @@ import {
|
||||||
|
|
||||||
import {useMutedThreads} from '#/state/muted-threads'
|
import {useMutedThreads} from '#/state/muted-threads'
|
||||||
import {useAgent} from '#/state/session'
|
import {useAgent} from '#/state/session'
|
||||||
|
import {useModerationOpts} from '../../preferences/moderation-opts'
|
||||||
import {STALE} from '..'
|
import {STALE} from '..'
|
||||||
import {useModerationOpts} from '../preferences'
|
|
||||||
import {embedViewRecordToPostView, getEmbeddedPost} from '../util'
|
import {embedViewRecordToPostView, getEmbeddedPost} from '../util'
|
||||||
import {FeedPage} from './types'
|
import {FeedPage} from './types'
|
||||||
import {useUnreadNotificationsApi} from './unread'
|
import {useUnreadNotificationsApi} from './unread'
|
||||||
|
|
|
@ -13,7 +13,7 @@ import {logger} from '#/logger'
|
||||||
import {isNative} from '#/platform/detection'
|
import {isNative} from '#/platform/detection'
|
||||||
import {useMutedThreads} from '#/state/muted-threads'
|
import {useMutedThreads} from '#/state/muted-threads'
|
||||||
import {useAgent, useSession} from '#/state/session'
|
import {useAgent, useSession} from '#/state/session'
|
||||||
import {useModerationOpts} from '../preferences'
|
import {useModerationOpts} from '../../preferences/moderation-opts'
|
||||||
import {truncateAndInvalidate} from '../util'
|
import {truncateAndInvalidate} from '../util'
|
||||||
import {RQKEY as RQKEY_NOTIFS} from './feed'
|
import {RQKEY as RQKEY_NOTIFS} from './feed'
|
||||||
import {CachedFeedPage, FeedPage} from './types'
|
import {CachedFeedPage, FeedPage} from './types'
|
||||||
|
|
|
@ -32,7 +32,8 @@ import {FeedTuner, FeedTunerFn, NoopFeedTuner} from 'lib/api/feed-manip'
|
||||||
import {BSKY_FEED_OWNER_DIDS} from 'lib/constants'
|
import {BSKY_FEED_OWNER_DIDS} from 'lib/constants'
|
||||||
import {KnownError} from '#/view/com/posts/FeedErrorMessage'
|
import {KnownError} from '#/view/com/posts/FeedErrorMessage'
|
||||||
import {useFeedTuners} from '../preferences/feed-tuners'
|
import {useFeedTuners} from '../preferences/feed-tuners'
|
||||||
import {useModerationOpts, usePreferencesQuery} from './preferences'
|
import {useModerationOpts} from '../preferences/moderation-opts'
|
||||||
|
import {usePreferencesQuery} from './preferences'
|
||||||
import {embedViewRecordToPostView, getEmbeddedPost} from './util'
|
import {embedViewRecordToPostView, getEmbeddedPost} from './util'
|
||||||
|
|
||||||
type ActorDid = string
|
type ActorDid = string
|
||||||
|
|
|
@ -1,28 +1,24 @@
|
||||||
import {createContext, useContext, useMemo} from 'react'
|
|
||||||
import {
|
import {
|
||||||
AppBskyActorDefs,
|
AppBskyActorDefs,
|
||||||
BSKY_LABELER_DID,
|
|
||||||
BskyFeedViewPreference,
|
BskyFeedViewPreference,
|
||||||
LabelPreference,
|
LabelPreference,
|
||||||
ModerationOpts,
|
|
||||||
} from '@atproto/api'
|
} from '@atproto/api'
|
||||||
import {useMutation, useQuery, useQueryClient} from '@tanstack/react-query'
|
import {useMutation, useQuery, useQueryClient} from '@tanstack/react-query'
|
||||||
|
|
||||||
import {track} from '#/lib/analytics/analytics'
|
import {track} from '#/lib/analytics/analytics'
|
||||||
|
import {replaceEqualDeep} from '#/lib/functions'
|
||||||
import {getAge} from '#/lib/strings/time'
|
import {getAge} from '#/lib/strings/time'
|
||||||
import {useHiddenPosts, useLabelDefinitions} from '#/state/preferences'
|
|
||||||
import {STALE} from '#/state/queries'
|
import {STALE} from '#/state/queries'
|
||||||
import {
|
import {
|
||||||
DEFAULT_HOME_FEED_PREFS,
|
DEFAULT_HOME_FEED_PREFS,
|
||||||
DEFAULT_LOGGED_OUT_PREFERENCES,
|
DEFAULT_LOGGED_OUT_PREFERENCES,
|
||||||
DEFAULT_THREAD_VIEW_PREFS,
|
DEFAULT_THREAD_VIEW_PREFS,
|
||||||
} from '#/state/queries/preferences/const'
|
} from '#/state/queries/preferences/const'
|
||||||
import {DEFAULT_LOGGED_OUT_LABEL_PREFERENCES} from '#/state/queries/preferences/moderation'
|
|
||||||
import {
|
import {
|
||||||
ThreadViewPreferences,
|
ThreadViewPreferences,
|
||||||
UsePreferencesQueryResponse,
|
UsePreferencesQueryResponse,
|
||||||
} from '#/state/queries/preferences/types'
|
} from '#/state/queries/preferences/types'
|
||||||
import {useAgent, useSession} from '#/state/session'
|
import {useAgent} from '#/state/session'
|
||||||
import {saveLabelers} from '#/state/session/agent-config'
|
import {saveLabelers} from '#/state/session/agent-config'
|
||||||
|
|
||||||
export * from '#/state/queries/preferences/const'
|
export * from '#/state/queries/preferences/const'
|
||||||
|
@ -36,7 +32,7 @@ export function usePreferencesQuery() {
|
||||||
const {getAgent} = useAgent()
|
const {getAgent} = useAgent()
|
||||||
return useQuery({
|
return useQuery({
|
||||||
staleTime: STALE.SECONDS.FIFTEEN,
|
staleTime: STALE.SECONDS.FIFTEEN,
|
||||||
structuralSharing: true,
|
structuralSharing: replaceEqualDeep,
|
||||||
refetchOnWindowFocus: true,
|
refetchOnWindowFocus: true,
|
||||||
queryKey: preferencesQueryKey,
|
queryKey: preferencesQueryKey,
|
||||||
queryFn: async () => {
|
queryFn: async () => {
|
||||||
|
@ -79,44 +75,6 @@ export function usePreferencesQuery() {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// used in the moderation state devtool
|
|
||||||
export const moderationOptsOverrideContext = createContext<
|
|
||||||
ModerationOpts | undefined
|
|
||||||
>(undefined)
|
|
||||||
|
|
||||||
export function useModerationOpts() {
|
|
||||||
const override = useContext(moderationOptsOverrideContext)
|
|
||||||
const {currentAccount} = useSession()
|
|
||||||
const prefs = usePreferencesQuery()
|
|
||||||
const {labelDefs} = useLabelDefinitions()
|
|
||||||
const hiddenPosts = useHiddenPosts() // TODO move this into pds-stored prefs
|
|
||||||
const opts = useMemo<ModerationOpts | undefined>(() => {
|
|
||||||
if (override) {
|
|
||||||
return override
|
|
||||||
}
|
|
||||||
if (!prefs.data) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
return {
|
|
||||||
userDid: currentAccount?.did,
|
|
||||||
prefs: {
|
|
||||||
...prefs.data.moderationPrefs,
|
|
||||||
labelers: prefs.data.moderationPrefs.labelers.length
|
|
||||||
? prefs.data.moderationPrefs.labelers
|
|
||||||
: [
|
|
||||||
{
|
|
||||||
did: BSKY_LABELER_DID,
|
|
||||||
labels: DEFAULT_LOGGED_OUT_LABEL_PREFERENCES,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
hiddenPosts: hiddenPosts || [],
|
|
||||||
},
|
|
||||||
labelDefs,
|
|
||||||
}
|
|
||||||
}, [override, currentAccount, labelDefs, prefs.data, hiddenPosts])
|
|
||||||
return opts
|
|
||||||
}
|
|
||||||
|
|
||||||
export function useClearPreferencesMutation() {
|
export function useClearPreferencesMutation() {
|
||||||
const queryClient = useQueryClient()
|
const queryClient = useQueryClient()
|
||||||
const {getAgent} = useAgent()
|
const {getAgent} = useAgent()
|
||||||
|
|
|
@ -18,11 +18,9 @@ import {
|
||||||
} from '#/lib/api/feed/utils'
|
} from '#/lib/api/feed/utils'
|
||||||
import {getContentLanguages} from '#/state/preferences/languages'
|
import {getContentLanguages} from '#/state/preferences/languages'
|
||||||
import {STALE} from '#/state/queries'
|
import {STALE} from '#/state/queries'
|
||||||
import {
|
import {usePreferencesQuery} from '#/state/queries/preferences'
|
||||||
useModerationOpts,
|
|
||||||
usePreferencesQuery,
|
|
||||||
} from '#/state/queries/preferences'
|
|
||||||
import {useAgent, useSession} from '#/state/session'
|
import {useAgent, useSession} from '#/state/session'
|
||||||
|
import {useModerationOpts} from '../preferences/moderation-opts'
|
||||||
|
|
||||||
const suggestedFollowsQueryKeyRoot = 'suggested-follows'
|
const suggestedFollowsQueryKeyRoot = 'suggested-follows'
|
||||||
const suggestedFollowsQueryKey = [suggestedFollowsQueryKeyRoot]
|
const suggestedFollowsQueryKey = [suggestedFollowsQueryKeyRoot]
|
||||||
|
|
|
@ -1,21 +1,22 @@
|
||||||
import React from 'react'
|
import React from 'react'
|
||||||
import {CenteredView} from '../util/Views'
|
|
||||||
import {ActivityIndicator, StyleSheet, View} from 'react-native'
|
import {ActivityIndicator, StyleSheet, View} from 'react-native'
|
||||||
import {FeedItem} from './FeedItem'
|
import {msg} from '@lingui/macro'
|
||||||
import {NotificationFeedLoadingPlaceholder} from '../util/LoadingPlaceholder'
|
import {useLingui} from '@lingui/react'
|
||||||
import {ErrorMessage} from '../util/error/ErrorMessage'
|
|
||||||
import {LoadMoreRetryBtn} from '../util/LoadMoreRetryBtn'
|
import {usePalette} from '#/lib/hooks/usePalette'
|
||||||
import {EmptyState} from '../util/EmptyState'
|
import {cleanError} from '#/lib/strings/errors'
|
||||||
import {s} from 'lib/styles'
|
import {logger} from '#/logger'
|
||||||
|
import {useModerationOpts} from '#/state/preferences/moderation-opts'
|
||||||
import {useNotificationFeedQuery} from '#/state/queries/notifications/feed'
|
import {useNotificationFeedQuery} from '#/state/queries/notifications/feed'
|
||||||
import {useUnreadNotificationsApi} from '#/state/queries/notifications/unread'
|
import {useUnreadNotificationsApi} from '#/state/queries/notifications/unread'
|
||||||
import {logger} from '#/logger'
|
import {s} from 'lib/styles'
|
||||||
import {cleanError} from '#/lib/strings/errors'
|
import {EmptyState} from '../util/EmptyState'
|
||||||
import {useModerationOpts} from '#/state/queries/preferences'
|
import {ErrorMessage} from '../util/error/ErrorMessage'
|
||||||
import {List, ListRef} from '../util/List'
|
import {List, ListRef} from '../util/List'
|
||||||
import {useLingui} from '@lingui/react'
|
import {NotificationFeedLoadingPlaceholder} from '../util/LoadingPlaceholder'
|
||||||
import {msg} from '@lingui/macro'
|
import {LoadMoreRetryBtn} from '../util/LoadMoreRetryBtn'
|
||||||
import {usePalette} from '#/lib/hooks/usePalette'
|
import {CenteredView} from '../util/Views'
|
||||||
|
import {FeedItem} from './FeedItem'
|
||||||
|
|
||||||
const EMPTY_FEED_ITEM = {_reactKey: '__empty__'}
|
const EMPTY_FEED_ITEM = {_reactKey: '__empty__'}
|
||||||
const LOAD_MORE_ERROR_ITEM = {_reactKey: '__load_more_error__'}
|
const LOAD_MORE_ERROR_ITEM = {_reactKey: '__load_more_error__'}
|
||||||
|
|
|
@ -8,6 +8,7 @@ import {useLingui} from '@lingui/react'
|
||||||
import {moderatePost_wrapped as moderatePost} from '#/lib/moderatePost_wrapped'
|
import {moderatePost_wrapped as moderatePost} from '#/lib/moderatePost_wrapped'
|
||||||
import {ScrollProvider} from '#/lib/ScrollContext'
|
import {ScrollProvider} from '#/lib/ScrollContext'
|
||||||
import {isAndroid, isNative, isWeb} from '#/platform/detection'
|
import {isAndroid, isNative, isWeb} from '#/platform/detection'
|
||||||
|
import {useModerationOpts} from '#/state/preferences/moderation-opts'
|
||||||
import {
|
import {
|
||||||
sortThread,
|
sortThread,
|
||||||
ThreadBlocked,
|
ThreadBlocked,
|
||||||
|
@ -16,10 +17,7 @@ import {
|
||||||
ThreadPost,
|
ThreadPost,
|
||||||
usePostThreadQuery,
|
usePostThreadQuery,
|
||||||
} from '#/state/queries/post-thread'
|
} from '#/state/queries/post-thread'
|
||||||
import {
|
import {usePreferencesQuery} from '#/state/queries/preferences'
|
||||||
useModerationOpts,
|
|
||||||
usePreferencesQuery,
|
|
||||||
} from '#/state/queries/preferences'
|
|
||||||
import {useSession} from '#/state/session'
|
import {useSession} from '#/state/session'
|
||||||
import {useInitialNumToRender} from 'lib/hooks/useInitialNumToRender'
|
import {useInitialNumToRender} from 'lib/hooks/useInitialNumToRender'
|
||||||
import {usePalette} from 'lib/hooks/usePalette'
|
import {usePalette} from 'lib/hooks/usePalette'
|
||||||
|
|
|
@ -15,8 +15,8 @@ import {moderatePost_wrapped as moderatePost} from '#/lib/moderatePost_wrapped'
|
||||||
import {POST_TOMBSTONE, Shadow, usePostShadow} from '#/state/cache/post-shadow'
|
import {POST_TOMBSTONE, Shadow, usePostShadow} from '#/state/cache/post-shadow'
|
||||||
import {useLanguagePrefs} from '#/state/preferences'
|
import {useLanguagePrefs} from '#/state/preferences'
|
||||||
import {useOpenLink} from '#/state/preferences/in-app-browser'
|
import {useOpenLink} from '#/state/preferences/in-app-browser'
|
||||||
|
import {useModerationOpts} from '#/state/preferences/moderation-opts'
|
||||||
import {ThreadPost} from '#/state/queries/post-thread'
|
import {ThreadPost} from '#/state/queries/post-thread'
|
||||||
import {useModerationOpts} from '#/state/queries/preferences'
|
|
||||||
import {useComposerControls} from '#/state/shell/composer'
|
import {useComposerControls} from '#/state/shell/composer'
|
||||||
import {MAX_POST_LINES} from 'lib/constants'
|
import {MAX_POST_LINES} from 'lib/constants'
|
||||||
import {usePalette} from 'lib/hooks/usePalette'
|
import {usePalette} from 'lib/hooks/usePalette'
|
||||||
|
|
|
@ -14,7 +14,7 @@ import {useQueryClient} from '@tanstack/react-query'
|
||||||
|
|
||||||
import {moderatePost_wrapped as moderatePost} from '#/lib/moderatePost_wrapped'
|
import {moderatePost_wrapped as moderatePost} from '#/lib/moderatePost_wrapped'
|
||||||
import {POST_TOMBSTONE, Shadow, usePostShadow} from '#/state/cache/post-shadow'
|
import {POST_TOMBSTONE, Shadow, usePostShadow} from '#/state/cache/post-shadow'
|
||||||
import {useModerationOpts} from '#/state/queries/preferences'
|
import {useModerationOpts} from '#/state/preferences/moderation-opts'
|
||||||
import {useComposerControls} from '#/state/shell/composer'
|
import {useComposerControls} from '#/state/shell/composer'
|
||||||
import {MAX_POST_LINES} from 'lib/constants'
|
import {MAX_POST_LINES} from 'lib/constants'
|
||||||
import {usePalette} from 'lib/hooks/usePalette'
|
import {usePalette} from 'lib/hooks/usePalette'
|
||||||
|
|
|
@ -12,7 +12,7 @@ import {useQueryClient} from '@tanstack/react-query'
|
||||||
import {useModerationCauseDescription} from '#/lib/moderation/useModerationCauseDescription'
|
import {useModerationCauseDescription} from '#/lib/moderation/useModerationCauseDescription'
|
||||||
import {useProfileShadow} from '#/state/cache/profile-shadow'
|
import {useProfileShadow} from '#/state/cache/profile-shadow'
|
||||||
import {Shadow} from '#/state/cache/types'
|
import {Shadow} from '#/state/cache/types'
|
||||||
import {useModerationOpts} from '#/state/queries/preferences'
|
import {useModerationOpts} from '#/state/preferences/moderation-opts'
|
||||||
import {useSession} from '#/state/session'
|
import {useSession} from '#/state/session'
|
||||||
import {usePalette} from 'lib/hooks/usePalette'
|
import {usePalette} from 'lib/hooks/usePalette'
|
||||||
import {getModerationCauseKey, isJustAMute} from 'lib/moderation'
|
import {getModerationCauseKey, isJustAMute} from 'lib/moderation'
|
||||||
|
|
|
@ -9,7 +9,7 @@ import {msg, Trans} from '@lingui/macro'
|
||||||
import {useLingui} from '@lingui/react'
|
import {useLingui} from '@lingui/react'
|
||||||
|
|
||||||
import {useProfileShadow} from '#/state/cache/profile-shadow'
|
import {useProfileShadow} from '#/state/cache/profile-shadow'
|
||||||
import {useModerationOpts} from '#/state/queries/preferences'
|
import {useModerationOpts} from '#/state/preferences/moderation-opts'
|
||||||
import {useProfileFollowMutationQueue} from '#/state/queries/profile'
|
import {useProfileFollowMutationQueue} from '#/state/queries/profile'
|
||||||
import {useSuggestedFollowsByActorQuery} from '#/state/queries/suggested-follows'
|
import {useSuggestedFollowsByActorQuery} from '#/state/queries/suggested-follows'
|
||||||
import {useAnalytics} from 'lib/analytics/analytics'
|
import {useAnalytics} from 'lib/analytics/analytics'
|
||||||
|
|
|
@ -25,7 +25,7 @@ import {useQueryClient} from '@tanstack/react-query'
|
||||||
|
|
||||||
import {HITSLOP_20} from '#/lib/constants'
|
import {HITSLOP_20} from '#/lib/constants'
|
||||||
import {s} from '#/lib/styles'
|
import {s} from '#/lib/styles'
|
||||||
import {useModerationOpts} from '#/state/queries/preferences'
|
import {useModerationOpts} from '#/state/preferences/moderation-opts'
|
||||||
import {usePalette} from 'lib/hooks/usePalette'
|
import {usePalette} from 'lib/hooks/usePalette'
|
||||||
import {InfoCircleIcon} from 'lib/icons'
|
import {InfoCircleIcon} from 'lib/icons'
|
||||||
import {makeProfileLink} from 'lib/routes/links'
|
import {makeProfileLink} from 'lib/routes/links'
|
||||||
|
|
|
@ -20,12 +20,12 @@ import {msg} from '@lingui/macro'
|
||||||
import {useLingui} from '@lingui/react'
|
import {useLingui} from '@lingui/react'
|
||||||
|
|
||||||
import {useGlobalLabelStrings} from '#/lib/moderation/useGlobalLabelStrings'
|
import {useGlobalLabelStrings} from '#/lib/moderation/useGlobalLabelStrings'
|
||||||
|
import {moderationOptsOverrideContext} from '#/state/preferences/moderation-opts'
|
||||||
import {FeedNotification} from '#/state/queries/notifications/types'
|
import {FeedNotification} from '#/state/queries/notifications/types'
|
||||||
import {
|
import {
|
||||||
groupNotifications,
|
groupNotifications,
|
||||||
shouldFilterNotif,
|
shouldFilterNotif,
|
||||||
} from '#/state/queries/notifications/util'
|
} from '#/state/queries/notifications/util'
|
||||||
import {moderationOptsOverrideContext} from '#/state/queries/preferences'
|
|
||||||
import {useSession} from '#/state/session'
|
import {useSession} from '#/state/session'
|
||||||
import {CommonNavigatorParams, NativeStackScreenProps} from 'lib/routes/types'
|
import {CommonNavigatorParams, NativeStackScreenProps} from 'lib/routes/types'
|
||||||
import {CenteredView, ScrollView} from '#/view/com/util/Views'
|
import {CenteredView, ScrollView} from '#/view/com/util/Views'
|
||||||
|
|
|
@ -13,9 +13,9 @@ import {useQueryClient} from '@tanstack/react-query'
|
||||||
|
|
||||||
import {cleanError} from '#/lib/strings/errors'
|
import {cleanError} from '#/lib/strings/errors'
|
||||||
import {useProfileShadow} from '#/state/cache/profile-shadow'
|
import {useProfileShadow} from '#/state/cache/profile-shadow'
|
||||||
|
import {useModerationOpts} from '#/state/preferences/moderation-opts'
|
||||||
import {useLabelerInfoQuery} from '#/state/queries/labeler'
|
import {useLabelerInfoQuery} from '#/state/queries/labeler'
|
||||||
import {resetProfilePostsQueries} from '#/state/queries/post-feed'
|
import {resetProfilePostsQueries} from '#/state/queries/post-feed'
|
||||||
import {useModerationOpts} from '#/state/queries/preferences'
|
|
||||||
import {useProfileQuery} from '#/state/queries/profile'
|
import {useProfileQuery} from '#/state/queries/profile'
|
||||||
import {useResolveDidQuery} from '#/state/queries/resolve-uri'
|
import {useResolveDidQuery} from '#/state/queries/resolve-uri'
|
||||||
import {useAgent, useSession} from '#/state/session'
|
import {useAgent, useSession} from '#/state/session'
|
||||||
|
|
|
@ -27,9 +27,9 @@ import {s} from '#/lib/styles'
|
||||||
import {logger} from '#/logger'
|
import {logger} from '#/logger'
|
||||||
import {isIOS, isNative, isWeb} from '#/platform/detection'
|
import {isIOS, isNative, isWeb} from '#/platform/detection'
|
||||||
import {listenSoftReset} from '#/state/events'
|
import {listenSoftReset} from '#/state/events'
|
||||||
|
import {useModerationOpts} from '#/state/preferences/moderation-opts'
|
||||||
import {useActorAutocompleteQuery} from '#/state/queries/actor-autocomplete'
|
import {useActorAutocompleteQuery} from '#/state/queries/actor-autocomplete'
|
||||||
import {useActorSearch} from '#/state/queries/actor-search'
|
import {useActorSearch} from '#/state/queries/actor-search'
|
||||||
import {useModerationOpts} from '#/state/queries/preferences'
|
|
||||||
import {useSearchPostsQuery} from '#/state/queries/search-posts'
|
import {useSearchPostsQuery} from '#/state/queries/search-posts'
|
||||||
import {useSuggestedFollowsQuery} from '#/state/queries/suggested-follows'
|
import {useSuggestedFollowsQuery} from '#/state/queries/suggested-follows'
|
||||||
import {useSession} from '#/state/session'
|
import {useSession} from '#/state/session'
|
||||||
|
|
|
@ -21,8 +21,8 @@ import {makeProfileLink} from '#/lib/routes/links'
|
||||||
import {sanitizeDisplayName} from '#/lib/strings/display-names'
|
import {sanitizeDisplayName} from '#/lib/strings/display-names'
|
||||||
import {sanitizeHandle} from '#/lib/strings/handles'
|
import {sanitizeHandle} from '#/lib/strings/handles'
|
||||||
import {s} from '#/lib/styles'
|
import {s} from '#/lib/styles'
|
||||||
|
import {useModerationOpts} from '#/state/preferences/moderation-opts'
|
||||||
import {useActorAutocompleteQuery} from '#/state/queries/actor-autocomplete'
|
import {useActorAutocompleteQuery} from '#/state/queries/actor-autocomplete'
|
||||||
import {useModerationOpts} from '#/state/queries/preferences'
|
|
||||||
import {usePalette} from 'lib/hooks/usePalette'
|
import {usePalette} from 'lib/hooks/usePalette'
|
||||||
import {MagnifyingGlassIcon2} from 'lib/icons'
|
import {MagnifyingGlassIcon2} from 'lib/icons'
|
||||||
import {NavigationProp} from 'lib/routes/types'
|
import {NavigationProp} from 'lib/routes/types'
|
||||||
|
|
Loading…
Reference in New Issue