diff options
Diffstat (limited to 'src/state/queries/feed.ts')
-rw-r--r-- | src/state/queries/feed.ts | 139 |
1 files changed, 139 insertions, 0 deletions
diff --git a/src/state/queries/feed.ts b/src/state/queries/feed.ts index 83d6a7634..972dbf995 100644 --- a/src/state/queries/feed.ts +++ b/src/state/queries/feed.ts @@ -9,20 +9,24 @@ import { } from '@atproto/api' import { InfiniteData, + QueryClient, QueryKey, useInfiniteQuery, useMutation, useQuery, + useQueryClient, } from '@tanstack/react-query' import {DISCOVER_FEED_URI, DISCOVER_SAVED_FEED} from '#/lib/constants' import {sanitizeDisplayName} from '#/lib/strings/display-names' import {sanitizeHandle} from '#/lib/strings/handles' import {STALE} from '#/state/queries' +import {RQKEY as listQueryKey} from '#/state/queries/list' import {usePreferencesQuery} from '#/state/queries/preferences' import {useAgent, useSession} from '#/state/session' import {router} from '#/routes' import {FeedDescriptor} from './post-feed' +import {precacheResolvedUri} from './resolve-uri' export type FeedSourceFeedInfo = { type: 'feed' @@ -201,6 +205,7 @@ export function useGetPopularFeedsQuery(options?: GetPopularFeedsOptions) { const agent = useAgent() const limit = options?.limit || 10 const {data: preferences} = usePreferencesQuery() + const queryClient = useQueryClient() // Make sure this doesn't invalidate unless really needed. const selectArgs = useMemo( @@ -225,6 +230,13 @@ export function useGetPopularFeedsQuery(options?: GetPopularFeedsOptions) { limit, cursor: pageParam, }) + + // precache feeds + for (const feed of res.data.feeds) { + const hydratedFeed = hydrateFeedGenerator(feed) + precacheFeed(queryClient, hydratedFeed) + } + return res.data }, initialPageParam: undefined, @@ -449,3 +461,130 @@ export function usePinnedFeedsInfos() { }, }) } + +export type SavedFeedItem = + | { + type: 'feed' + config: AppBskyActorDefs.SavedFeed + view: AppBskyFeedDefs.GeneratorView + } + | { + type: 'list' + config: AppBskyActorDefs.SavedFeed + view: AppBskyGraphDefs.ListView + } + | { + type: 'timeline' + config: AppBskyActorDefs.SavedFeed + view: undefined + } + +export function useSavedFeeds() { + const agent = useAgent() + const {data: preferences, isLoading: isLoadingPrefs} = usePreferencesQuery() + const savedItems = preferences?.savedFeeds ?? [] + const queryClient = useQueryClient() + + return useQuery({ + staleTime: STALE.INFINITY, + enabled: !isLoadingPrefs, + queryKey: [pinnedFeedInfosQueryKeyRoot, ...savedItems], + placeholderData: previousData => { + return ( + previousData || { + count: savedItems.length, + feeds: [], + } + ) + }, + queryFn: async () => { + const resolvedFeeds = new Map<string, AppBskyFeedDefs.GeneratorView>() + const resolvedLists = new Map<string, AppBskyGraphDefs.ListView>() + + const savedFeeds = savedItems.filter(feed => feed.type === 'feed') + const savedLists = savedItems.filter(feed => feed.type === 'list') + + let feedsPromise = Promise.resolve() + if (savedFeeds.length > 0) { + feedsPromise = agent.app.bsky.feed + .getFeedGenerators({ + feeds: savedFeeds.map(f => f.value), + }) + .then(res => { + res.data.feeds.forEach(f => { + resolvedFeeds.set(f.uri, f) + }) + }) + } + + const listsPromises = savedLists.map(list => + agent.app.bsky.graph + .getList({ + list: list.value, + limit: 1, + }) + .then(res => { + const listView = res.data.list + resolvedLists.set(listView.uri, listView) + }), + ) + + await Promise.allSettled([feedsPromise, ...listsPromises]) + + resolvedFeeds.forEach(feed => { + const hydratedFeed = hydrateFeedGenerator(feed) + precacheFeed(queryClient, hydratedFeed) + }) + resolvedLists.forEach(list => { + precacheList(queryClient, list) + }) + + const res: SavedFeedItem[] = savedItems.map(s => { + if (s.type === 'timeline') { + return { + type: 'timeline', + config: s, + view: undefined, + } + } + + return { + type: s.type, + config: s, + view: + s.type === 'feed' + ? resolvedFeeds.get(s.value) + : resolvedLists.get(s.value), + } + }) as SavedFeedItem[] + + return { + count: savedItems.length, + feeds: res, + } + }, + }) +} + +function precacheFeed(queryClient: QueryClient, hydratedFeed: FeedSourceInfo) { + precacheResolvedUri( + queryClient, + hydratedFeed.creatorHandle, + hydratedFeed.creatorDid, + ) + queryClient.setQueryData<FeedSourceInfo>( + feedSourceInfoQueryKey({uri: hydratedFeed.uri}), + hydratedFeed, + ) +} + +function precacheList( + queryClient: QueryClient, + list: AppBskyGraphDefs.ListView, +) { + precacheResolvedUri(queryClient, list.creator.handle, list.creator.did) + queryClient.setQueryData<AppBskyGraphDefs.ListView>( + listQueryKey(list.uri), + list, + ) +} |