diff options
Diffstat (limited to 'src/state')
-rw-r--r-- | src/state/persisted/legacy.ts | 1 | ||||
-rw-r--r-- | src/state/persisted/schema.ts | 2 | ||||
-rw-r--r-- | src/state/preferences/hidden-posts.tsx | 64 | ||||
-rw-r--r-- | src/state/preferences/index.tsx | 6 | ||||
-rw-r--r-- | src/state/queries/actor-autocomplete.ts | 5 | ||||
-rw-r--r-- | src/state/queries/feed.ts | 5 | ||||
-rw-r--r-- | src/state/queries/notifications/unread.tsx | 3 | ||||
-rw-r--r-- | src/state/queries/notifications/util.ts | 6 | ||||
-rw-r--r-- | src/state/queries/post-feed.ts | 8 | ||||
-rw-r--r-- | src/state/queries/preferences/index.ts | 11 |
10 files changed, 97 insertions, 14 deletions
diff --git a/src/state/persisted/legacy.ts b/src/state/persisted/legacy.ts index f689c3d06..cdb542f5a 100644 --- a/src/state/persisted/legacy.ts +++ b/src/state/persisted/legacy.ts @@ -108,6 +108,7 @@ export function transform(legacy: Partial<LegacySchema>): Schema { onboarding: { step: legacy.onboarding?.step || defaults.onboarding.step, }, + hiddenPosts: defaults.hiddenPosts, } } diff --git a/src/state/persisted/schema.ts b/src/state/persisted/schema.ts index 5ed8e01f3..27b1f26bd 100644 --- a/src/state/persisted/schema.ts +++ b/src/state/persisted/schema.ts @@ -37,6 +37,7 @@ export const schema = z.object({ onboarding: z.object({ step: z.string(), }), + hiddenPosts: z.array(z.string()).optional(), // should move to server }) export type Schema = z.infer<typeof schema> @@ -66,4 +67,5 @@ export const defaults: Schema = { onboarding: { step: 'Home', }, + hiddenPosts: [], } diff --git a/src/state/preferences/hidden-posts.tsx b/src/state/preferences/hidden-posts.tsx new file mode 100644 index 000000000..11119ce75 --- /dev/null +++ b/src/state/preferences/hidden-posts.tsx @@ -0,0 +1,64 @@ +import React from 'react' +import * as persisted from '#/state/persisted' + +type SetStateCb = ( + s: persisted.Schema['hiddenPosts'], +) => persisted.Schema['hiddenPosts'] +type StateContext = persisted.Schema['hiddenPosts'] +type ApiContext = { + hidePost: ({uri}: {uri: string}) => void + unhidePost: ({uri}: {uri: string}) => void +} + +const stateContext = React.createContext<StateContext>( + persisted.defaults.hiddenPosts, +) +const apiContext = React.createContext<ApiContext>({ + hidePost: () => {}, + unhidePost: () => {}, +}) + +export function Provider({children}: React.PropsWithChildren<{}>) { + const [state, setState] = React.useState(persisted.get('hiddenPosts')) + + const setStateWrapped = React.useCallback( + (fn: SetStateCb) => { + const s = fn(persisted.get('hiddenPosts')) + setState(s) + persisted.write('hiddenPosts', s) + }, + [setState], + ) + + const api = React.useMemo( + () => ({ + hidePost: ({uri}: {uri: string}) => { + setStateWrapped(s => [...(s || []), uri]) + }, + unhidePost: ({uri}: {uri: string}) => { + setStateWrapped(s => (s || []).filter(u => u !== uri)) + }, + }), + [setStateWrapped], + ) + + React.useEffect(() => { + return persisted.onUpdate(() => { + setState(persisted.get('hiddenPosts')) + }) + }, [setStateWrapped]) + + return ( + <stateContext.Provider value={state}> + <apiContext.Provider value={api}>{children}</apiContext.Provider> + </stateContext.Provider> + ) +} + +export function useHiddenPosts() { + return React.useContext(stateContext) +} + +export function useHiddenPostsApi() { + return React.useContext(apiContext) +} diff --git a/src/state/preferences/index.tsx b/src/state/preferences/index.tsx index 1f4348cfc..5ec659031 100644 --- a/src/state/preferences/index.tsx +++ b/src/state/preferences/index.tsx @@ -1,17 +1,21 @@ import React from 'react' import {Provider as LanguagesProvider} from './languages' import {Provider as AltTextRequiredProvider} from '../preferences/alt-text-required' +import {Provider as HiddenPostsProvider} from '../preferences/hidden-posts' export {useLanguagePrefs, useLanguagePrefsApi} from './languages' export { useRequireAltTextEnabled, useSetRequireAltTextEnabled, } from './alt-text-required' +export * from './hidden-posts' export function Provider({children}: React.PropsWithChildren<{}>) { return ( <LanguagesProvider> - <AltTextRequiredProvider>{children}</AltTextRequiredProvider> + <AltTextRequiredProvider> + <HiddenPostsProvider>{children}</HiddenPostsProvider> + </AltTextRequiredProvider> </LanguagesProvider> ) } diff --git a/src/state/queries/actor-autocomplete.ts b/src/state/queries/actor-autocomplete.ts index fe207371d..785e29765 100644 --- a/src/state/queries/actor-autocomplete.ts +++ b/src/state/queries/actor-autocomplete.ts @@ -11,6 +11,7 @@ import { getModerationOpts, useModerationOpts, } from './preferences' +import {isInvalidHandle} from '#/lib/strings/handles' const DEFAULT_MOD_OPTS = getModerationOpts({ userDid: '', @@ -111,7 +112,7 @@ function computeSuggestions( } return items.filter(profile => { const mod = moderateProfile(profile, moderationOpts) - return !mod.account.filter + return !mod.account.filter && mod.account.cause?.type !== 'muted' }) } @@ -119,7 +120,7 @@ function prefixMatch( prefix: string, info: AppBskyActorDefs.ProfileViewBasic, ): boolean { - if (info.handle.includes(prefix)) { + if (!isInvalidHandle(info.handle) && info.handle.includes(prefix)) { return true } if (info.displayName?.toLocaleLowerCase().includes(prefix)) { diff --git a/src/state/queries/feed.ts b/src/state/queries/feed.ts index c87e95f03..7a55b4e18 100644 --- a/src/state/queries/feed.ts +++ b/src/state/queries/feed.ts @@ -218,11 +218,13 @@ const FOLLOWING_FEED_STUB: FeedSourceInfo = { export function usePinnedFeedsInfos(): { feeds: FeedSourceInfo[] hasPinnedCustom: boolean + isLoading: boolean } { const queryClient = useQueryClient() const [tabs, setTabs] = React.useState<FeedSourceInfo[]>([ FOLLOWING_FEED_STUB, ]) + const [isLoading, setLoading] = React.useState(true) const {data: preferences} = usePreferencesQuery() const hasPinnedCustom = React.useMemo<boolean>(() => { @@ -284,10 +286,11 @@ export function usePinnedFeedsInfos(): { ) as FeedSourceInfo[] setTabs([FOLLOWING_FEED_STUB].concat(views)) + setLoading(false) } fetchFeedInfo() }, [queryClient, setTabs, preferences?.feeds?.pinned]) - return {feeds: tabs, hasPinnedCustom} + return {feeds: tabs, hasPinnedCustom, isLoading} } diff --git a/src/state/queries/notifications/unread.tsx b/src/state/queries/notifications/unread.tsx index a189f20e4..abaabbf0e 100644 --- a/src/state/queries/notifications/unread.tsx +++ b/src/state/queries/notifications/unread.tsx @@ -89,6 +89,9 @@ export function Provider({children}: React.PropsWithChildren<{}>) { // update & broadcast setNumUnread('') broadcast.postMessage({event: ''}) + if (isNative) { + Notifications.setBadgeCountAsync(0) + } }, async checkUnread({invalidate}: {invalidate?: boolean} = {}) { diff --git a/src/state/queries/notifications/util.ts b/src/state/queries/notifications/util.ts index cc5943163..411a0f791 100644 --- a/src/state/queries/notifications/util.ts +++ b/src/state/queries/notifications/util.ts @@ -2,12 +2,12 @@ import { AppBskyNotificationListNotifications, ModerationOpts, moderateProfile, - moderatePost, AppBskyFeedDefs, AppBskyFeedPost, AppBskyFeedRepost, AppBskyFeedLike, } from '@atproto/api' +import {moderatePost_wrapped as moderatePost} from '#/lib/moderatePost_wrapped' import chunk from 'lodash.chunk' import {QueryClient} from '@tanstack/react-query' import {getAgent} from '../../session' @@ -156,7 +156,7 @@ async function fetchSubjects( ): Promise<Map<string, AppBskyFeedDefs.PostView>> { const uris = new Set<string>() for (const notif of groupedNotifs) { - if (notif.subjectUri) { + if (notif.subjectUri && !notif.subjectUri.includes('feed.generator')) { uris.add(notif.subjectUri) } } @@ -216,6 +216,8 @@ function getSubjectUri( ? notif.record.subject?.uri : undefined } + } else if (type === 'feedgen-like') { + return notif.reasonSubject } } diff --git a/src/state/queries/post-feed.ts b/src/state/queries/post-feed.ts index b91af372f..0e943622a 100644 --- a/src/state/queries/post-feed.ts +++ b/src/state/queries/post-feed.ts @@ -1,10 +1,5 @@ import React, {useCallback, useEffect, useRef} from 'react' -import { - AppBskyFeedDefs, - AppBskyFeedPost, - moderatePost, - PostModeration, -} from '@atproto/api' +import {AppBskyFeedDefs, AppBskyFeedPost, PostModeration} from '@atproto/api' import { useInfiniteQuery, InfiniteData, @@ -12,6 +7,7 @@ import { QueryClient, useQueryClient, } from '@tanstack/react-query' +import {moderatePost_wrapped as moderatePost} from '#/lib/moderatePost_wrapped' import {useFeedTuners} from '../preferences/feed-tuners' import {FeedTuner, FeedTunerFn, NoopFeedTuner} from 'lib/api/feed-manip' import {FeedAPI, ReasonFeedSource} from 'lib/api/feed/types' diff --git a/src/state/queries/preferences/index.ts b/src/state/queries/preferences/index.ts index 872bb21af..a9aa7f26e 100644 --- a/src/state/queries/preferences/index.ts +++ b/src/state/queries/preferences/index.ts @@ -19,6 +19,7 @@ import { } from '#/state/queries/preferences/const' import {getModerationOpts} from '#/state/queries/preferences/moderation' import {STALE} from '#/state/queries' +import {useHiddenPosts} from '#/state/preferences/hidden-posts' export * from '#/state/queries/preferences/types' export * from '#/state/queries/preferences/moderation' @@ -94,15 +95,21 @@ export function usePreferencesQuery() { export function useModerationOpts() { const {currentAccount} = useSession() const prefs = usePreferencesQuery() + const hiddenPosts = useHiddenPosts() const opts = useMemo(() => { if (!prefs.data) { return } - return getModerationOpts({ + const moderationOpts = getModerationOpts({ userDid: currentAccount?.did || '', preferences: prefs.data, }) - }, [currentAccount?.did, prefs.data]) + + return { + ...moderationOpts, + hiddenPosts, + } + }, [currentAccount?.did, prefs.data, hiddenPosts]) return opts } |