diff options
Diffstat (limited to 'src/state')
-rw-r--r-- | src/state/models/content/feed-source.ts | 2 | ||||
-rw-r--r-- | src/state/models/ui/preferences.ts | 18 | ||||
-rw-r--r-- | src/state/queries/feed.ts | 132 | ||||
-rw-r--r-- | src/state/queries/preferences/types.ts | 5 |
4 files changed, 128 insertions, 29 deletions
diff --git a/src/state/models/content/feed-source.ts b/src/state/models/content/feed-source.ts index 156e3be3b..cd8c08b56 100644 --- a/src/state/models/content/feed-source.ts +++ b/src/state/models/content/feed-source.ts @@ -61,7 +61,7 @@ export class FeedSourceModel { } get isPinned() { - return this.rootStore.preferences.isPinnedFeed(this.uri) + return false } get isLiked() { diff --git a/src/state/models/ui/preferences.ts b/src/state/models/ui/preferences.ts index 4f43487e7..1068ac651 100644 --- a/src/state/models/ui/preferences.ts +++ b/src/state/models/ui/preferences.ts @@ -4,7 +4,6 @@ import { BskyFeedViewPreference, BskyThreadViewPreference, } from '@atproto/api' -import AwaitLock from 'await-lock' import {isObj, hasProp} from 'lib/type-guards' import {RootStoreModel} from '../root-store' import {ModerationOpts} from '@atproto/api' @@ -33,30 +32,17 @@ export class LabelPreferencesModel { } export class PreferencesModel { - adultContentEnabled = false contentLabels = new LabelPreferencesModel() savedFeeds: string[] = [] pinnedFeeds: string[] = [] - birthDate: Date | undefined = undefined - homeFeed: FeedViewPreference = { - hideReplies: false, - hideRepliesByUnfollowed: false, - hideRepliesByLikeCount: 0, - hideReposts: false, - hideQuotePosts: false, - lab_mergeFeedEnabled: false, // experimental - } thread: ThreadViewPreference = { sort: 'oldest', prioritizeFollowedUsers: true, lab_treeViewEnabled: false, // experimental } - // used to linearize async modifications to state - lock = new AwaitLock() - constructor(public rootStore: RootStoreModel) { - makeAutoObservable(this, {lock: false}, {autoBind: true}) + makeAutoObservable(this, {}, {autoBind: true}) } serialize() { @@ -106,7 +92,7 @@ export class PreferencesModel { get moderationOpts(): ModerationOpts { return { userDid: this.rootStore.session.currentSession?.did || '', - adultContentEnabled: this.adultContentEnabled, + adultContentEnabled: false, labels: { // TEMP translate old settings until this UI can be migrated -prf porn: tempfixLabelPref(this.contentLabels.nsfw), diff --git a/src/state/queries/feed.ts b/src/state/queries/feed.ts index 5754d2c70..dde37315d 100644 --- a/src/state/queries/feed.ts +++ b/src/state/queries/feed.ts @@ -1,9 +1,11 @@ +import React from 'react' import { useQuery, useInfiniteQuery, InfiniteData, QueryKey, useMutation, + useQueryClient, } from '@tanstack/react-query' import { AtUri, @@ -13,16 +15,22 @@ import { AppBskyUnspeccedGetPopularFeedGenerators, } from '@atproto/api' +import {router} from '#/routes' import {sanitizeDisplayName} from '#/lib/strings/display-names' import {sanitizeHandle} from '#/lib/strings/handles' import {useSession} from '#/state/session' +import {usePreferencesQuery} from '#/state/queries/preferences' -type FeedSourceInfo = +export type FeedSourceInfo = | { type: 'feed' uri: string + route: { + href: string + name: string + params: Record<string, string> + } cid: string - href: string avatar: string | undefined displayName: string description: RichText @@ -34,8 +42,12 @@ type FeedSourceInfo = | { type: 'list' uri: string + route: { + href: string + name: string + params: Record<string, string> + } cid: string - href: string avatar: string | undefined displayName: string description: RichText @@ -43,7 +55,7 @@ type FeedSourceInfo = creatorHandle: string } -export const useFeedSourceInfoQueryKey = ({uri}: {uri: string}) => [ +export const feedSourceInfoQueryKey = ({uri}: {uri: string}) => [ 'getFeedSourceInfo', uri, ] @@ -53,19 +65,24 @@ const feedSourceNSIDs = { list: 'app.bsky.graph.list', } -function hydrateFeedGenerator( +export function hydrateFeedGenerator( view: AppBskyFeedDefs.GeneratorView, ): FeedSourceInfo { const urip = new AtUri(view.uri) const collection = urip.collection === 'app.bsky.feed.generator' ? 'feed' : 'lists' const href = `/profile/${urip.hostname}/${collection}/${urip.rkey}` + const route = router.matchPath(href) return { type: 'feed', uri: view.uri, cid: view.cid, - href, + route: { + href, + name: route[0], + params: route[1], + }, avatar: view.avatar, displayName: view.displayName ? sanitizeDisplayName(view.displayName) @@ -81,17 +98,22 @@ function hydrateFeedGenerator( } } -function hydrateList(view: AppBskyGraphDefs.ListView): FeedSourceInfo { +export function hydrateList(view: AppBskyGraphDefs.ListView): FeedSourceInfo { const urip = new AtUri(view.uri) const collection = urip.collection === 'app.bsky.feed.generator' ? 'feed' : 'lists' const href = `/profile/${urip.hostname}/${collection}/${urip.rkey}` + const route = router.matchPath(href) return { type: 'list', uri: view.uri, + route: { + href, + name: route[0], + params: route[1], + }, cid: view.cid, - href, avatar: view.avatar, description: new RichText({ text: view.description || '', @@ -105,13 +127,17 @@ function hydrateList(view: AppBskyGraphDefs.ListView): FeedSourceInfo { } } +export function getFeedTypeFromUri(uri: string) { + const {pathname} = new AtUri(uri) + return pathname.includes(feedSourceNSIDs.feed) ? 'feed' : 'list' +} + export function useFeedSourceInfoQuery({uri}: {uri: string}) { const {agent} = useSession() - const {pathname} = new AtUri(uri) - const type = pathname.includes(feedSourceNSIDs.feed) ? 'feed' : 'list' + const type = getFeedTypeFromUri(uri) return useQuery({ - queryKey: useFeedSourceInfoQueryKey({uri}), + queryKey: feedSourceInfoQueryKey({uri}), queryFn: async () => { let view: FeedSourceInfo @@ -170,3 +196,87 @@ export function useSearchPopularFeedsMutation() { }, }) } + +const FOLLOWING_FEED_STUB: FeedSourceInfo = { + type: 'feed', + displayName: 'Following', + uri: '', + route: { + href: '/', + name: 'Home', + params: {}, + }, + cid: '', + avatar: '', + description: new RichText({text: ''}), + creatorDid: '', + creatorHandle: '', + likeCount: 0, + likeUri: '', +} + +export function usePinnedFeedsInfos(): FeedSourceInfo[] { + const {agent} = useSession() + const queryClient = useQueryClient() + const [tabs, setTabs] = React.useState<FeedSourceInfo[]>([ + FOLLOWING_FEED_STUB, + ]) + const {data: preferences} = usePreferencesQuery() + const pinnedFeedsKey = JSON.stringify(preferences?.feeds?.pinned) + + React.useEffect(() => { + if (!preferences?.feeds?.pinned) return + const uris = preferences.feeds.pinned + + async function fetchFeedInfo() { + const reqs = [] + + for (const uri of uris) { + const cached = queryClient.getQueryData<FeedSourceInfo>( + feedSourceInfoQueryKey({uri}), + ) + + if (cached) { + reqs.push(cached) + } else { + reqs.push( + queryClient.fetchQuery({ + queryKey: feedSourceInfoQueryKey({uri}), + queryFn: async () => { + const type = getFeedTypeFromUri(uri) + + if (type === 'feed') { + const res = await agent.app.bsky.feed.getFeedGenerator({ + feed: uri, + }) + return hydrateFeedGenerator(res.data.view) + } else { + const res = await agent.app.bsky.graph.getList({ + list: uri, + limit: 1, + }) + return hydrateList(res.data.list) + } + }, + }), + ) + } + } + + const views = await Promise.all(reqs) + + setTabs([FOLLOWING_FEED_STUB].concat(views)) + } + + fetchFeedInfo() + }, [ + agent, + queryClient, + setTabs, + preferences?.feeds?.pinned, + // ensure we react to re-ordering + pinnedFeedsKey, + ]) + + return tabs +} diff --git a/src/state/queries/preferences/types.ts b/src/state/queries/preferences/types.ts index 9f4c30e53..2b04b725f 100644 --- a/src/state/queries/preferences/types.ts +++ b/src/state/queries/preferences/types.ts @@ -2,6 +2,7 @@ import { BskyPreferences, LabelPreference, BskyThreadViewPreference, + BskyFeedViewPreference, } from '@atproto/api' export type ConfigurableLabelGroup = @@ -29,7 +30,9 @@ export type UsePreferencesQueryResponse = Omit< * we clean up the data in `usePreferencesQuery`. */ contentLabels: Record<ConfigurableLabelGroup, LabelPreference> - feedViewPrefs: BskyPreferences['feedViewPrefs']['home'] + feedViewPrefs: BskyFeedViewPreference & { + lab_mergeFeedEnabled: boolean + } /** * User thread-view prefs, including newer fields that may not be typed yet. */ |