merge main
This commit is contained in:
Vendored
+2
@@ -5,6 +5,7 @@ import EventEmitter from 'eventemitter3'
|
||||
|
||||
import {batchedUpdates} from '#/lib/batchedUpdates'
|
||||
import {findAllProfilesInQueryData as findAllProfilesInActorSearchQueryData} from '../queries/actor-search'
|
||||
import {findAllProfilesInQueryData as findAllProfilesInKnownFollowersQueryData} from '../queries/known-followers'
|
||||
import {findAllProfilesInQueryData as findAllProfilesInListMembersQueryData} from '../queries/list-members'
|
||||
import {findAllProfilesInQueryData as findAllProfilesInListConvosQueryData} from '../queries/messages/list-converations'
|
||||
import {findAllProfilesInQueryData as findAllProfilesInMyBlockedAccountsQueryData} from '../queries/my-blocked-accounts'
|
||||
@@ -111,4 +112,5 @@ function* findProfilesInCache(
|
||||
yield* findAllProfilesInListConvosQueryData(queryClient, did)
|
||||
yield* findAllProfilesInFeedsQueryData(queryClient, did)
|
||||
yield* findAllProfilesInPostThreadQueryData(queryClient, did)
|
||||
yield* findAllProfilesInKnownFollowersQueryData(queryClient, did)
|
||||
}
|
||||
|
||||
+124
-4
@@ -1,3 +1,4 @@
|
||||
import {useCallback, useEffect, useMemo, useRef} from 'react'
|
||||
import {
|
||||
AppBskyActorDefs,
|
||||
AppBskyFeedDefs,
|
||||
@@ -171,18 +172,54 @@ export function useFeedSourceInfoQuery({uri}: {uri: string}) {
|
||||
})
|
||||
}
|
||||
|
||||
export const useGetPopularFeedsQueryKey = ['getPopularFeeds']
|
||||
// HACK
|
||||
// the protocol doesn't yet tell us which feeds are personalized
|
||||
// this list is used to filter out feed recommendations from logged out users
|
||||
// for the ones we know need it
|
||||
// -prf
|
||||
export const KNOWN_AUTHED_ONLY_FEEDS = [
|
||||
'at://did:plc:z72i7hdynmk6r22z27h6tvur/app.bsky.feed.generator/with-friends', // popular with friends, by bsky.app
|
||||
'at://did:plc:tenurhgjptubkk5zf5qhi3og/app.bsky.feed.generator/mutuals', // mutuals, by skyfeed
|
||||
'at://did:plc:tenurhgjptubkk5zf5qhi3og/app.bsky.feed.generator/only-posts', // only posts, by skyfeed
|
||||
'at://did:plc:wzsilnxf24ehtmmc3gssy5bu/app.bsky.feed.generator/mentions', // mentions, by flicknow
|
||||
'at://did:plc:q6gjnaw2blty4crticxkmujt/app.bsky.feed.generator/bangers', // my bangers, by jaz
|
||||
'at://did:plc:z72i7hdynmk6r22z27h6tvur/app.bsky.feed.generator/mutuals', // mutuals, by bluesky
|
||||
'at://did:plc:q6gjnaw2blty4crticxkmujt/app.bsky.feed.generator/my-followers', // followers, by jaz
|
||||
'at://did:plc:vpkhqolt662uhesyj6nxm7ys/app.bsky.feed.generator/followpics', // the gram, by why
|
||||
]
|
||||
|
||||
export function useGetPopularFeedsQuery(limit: number = 10) {
|
||||
type GetPopularFeedsOptions = {limit?: number}
|
||||
|
||||
export function createGetPopularFeedsQueryKey(
|
||||
options?: GetPopularFeedsOptions,
|
||||
) {
|
||||
return ['getPopularFeeds', options]
|
||||
}
|
||||
|
||||
export function useGetPopularFeedsQuery(options?: GetPopularFeedsOptions) {
|
||||
const {hasSession} = useSession()
|
||||
const agent = useAgent()
|
||||
return useInfiniteQuery<
|
||||
const limit = options?.limit || 10
|
||||
const {data: preferences} = usePreferencesQuery()
|
||||
|
||||
// Make sure this doesn't invalidate unless really needed.
|
||||
const selectArgs = useMemo(
|
||||
() => ({
|
||||
hasSession,
|
||||
savedFeeds: preferences?.savedFeeds || [],
|
||||
}),
|
||||
[hasSession, preferences?.savedFeeds],
|
||||
)
|
||||
const lastPageCountRef = useRef(0)
|
||||
|
||||
const query = useInfiniteQuery<
|
||||
AppBskyUnspeccedGetPopularFeedGenerators.OutputSchema,
|
||||
Error,
|
||||
InfiniteData<AppBskyUnspeccedGetPopularFeedGenerators.OutputSchema>,
|
||||
QueryKey,
|
||||
string | undefined
|
||||
>({
|
||||
queryKey: useGetPopularFeedsQueryKey,
|
||||
queryKey: createGetPopularFeedsQueryKey(options),
|
||||
queryFn: async ({pageParam}) => {
|
||||
const res = await agent.app.bsky.unspecced.getPopularFeedGenerators({
|
||||
limit,
|
||||
@@ -192,7 +229,62 @@ export function useGetPopularFeedsQuery(limit: number = 10) {
|
||||
},
|
||||
initialPageParam: undefined,
|
||||
getNextPageParam: lastPage => lastPage.cursor,
|
||||
select: useCallback(
|
||||
(
|
||||
data: InfiniteData<AppBskyUnspeccedGetPopularFeedGenerators.OutputSchema>,
|
||||
) => {
|
||||
const {savedFeeds, hasSession: hasSessionInner} = selectArgs
|
||||
data?.pages.map(page => {
|
||||
page.feeds = page.feeds.filter(feed => {
|
||||
if (
|
||||
!hasSessionInner &&
|
||||
KNOWN_AUTHED_ONLY_FEEDS.includes(feed.uri)
|
||||
) {
|
||||
return false
|
||||
}
|
||||
const alreadySaved = Boolean(
|
||||
savedFeeds?.find(f => {
|
||||
return f.value === feed.uri
|
||||
}),
|
||||
)
|
||||
return !alreadySaved
|
||||
})
|
||||
|
||||
return page
|
||||
})
|
||||
|
||||
return data
|
||||
},
|
||||
[selectArgs /* Don't change. Everything needs to go into selectArgs. */],
|
||||
),
|
||||
})
|
||||
|
||||
useEffect(() => {
|
||||
const {isFetching, hasNextPage, data} = query
|
||||
if (isFetching || !hasNextPage) {
|
||||
return
|
||||
}
|
||||
|
||||
// avoid double-fires of fetchNextPage()
|
||||
if (
|
||||
lastPageCountRef.current !== 0 &&
|
||||
lastPageCountRef.current === data?.pages?.length
|
||||
) {
|
||||
return
|
||||
}
|
||||
|
||||
// fetch next page if we haven't gotten a full page of content
|
||||
let count = 0
|
||||
for (const page of data?.pages || []) {
|
||||
count += page.feeds.length
|
||||
}
|
||||
if (count < limit && (data?.pages.length || 0) < 6) {
|
||||
query.fetchNextPage()
|
||||
lastPageCountRef.current = data?.pages?.length || 0
|
||||
}
|
||||
}, [query, limit])
|
||||
|
||||
return query
|
||||
}
|
||||
|
||||
export function useSearchPopularFeedsMutation() {
|
||||
@@ -209,6 +301,34 @@ export function useSearchPopularFeedsMutation() {
|
||||
})
|
||||
}
|
||||
|
||||
const popularFeedsSearchQueryKeyRoot = 'popularFeedsSearch'
|
||||
export const createPopularFeedsSearchQueryKey = (query: string) => [
|
||||
popularFeedsSearchQueryKeyRoot,
|
||||
query,
|
||||
]
|
||||
|
||||
export function usePopularFeedsSearch({
|
||||
query,
|
||||
enabled,
|
||||
}: {
|
||||
query: string
|
||||
enabled?: boolean
|
||||
}) {
|
||||
const agent = useAgent()
|
||||
return useQuery({
|
||||
enabled,
|
||||
queryKey: createPopularFeedsSearchQueryKey(query),
|
||||
queryFn: async () => {
|
||||
const res = await agent.app.bsky.unspecced.getPopularFeedGenerators({
|
||||
limit: 10,
|
||||
query: query,
|
||||
})
|
||||
|
||||
return res.data.feeds
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
export type SavedFeedSourceInfo = FeedSourceInfo & {
|
||||
savedFeed: AppBskyActorDefs.SavedFeed
|
||||
}
|
||||
|
||||
@@ -1,5 +1,10 @@
|
||||
import {AppBskyGraphGetKnownFollowers} from '@atproto/api'
|
||||
import {InfiniteData, QueryKey, useInfiniteQuery} from '@tanstack/react-query'
|
||||
import {AppBskyActorDefs, AppBskyGraphGetKnownFollowers} from '@atproto/api'
|
||||
import {
|
||||
InfiniteData,
|
||||
QueryClient,
|
||||
QueryKey,
|
||||
useInfiniteQuery,
|
||||
} from '@tanstack/react-query'
|
||||
|
||||
import {useAgent} from '#/state/session'
|
||||
|
||||
@@ -32,3 +37,26 @@ export function useProfileKnownFollowersQuery(did: string | undefined) {
|
||||
enabled: !!did,
|
||||
})
|
||||
}
|
||||
|
||||
export function* findAllProfilesInQueryData(
|
||||
queryClient: QueryClient,
|
||||
did: string,
|
||||
): Generator<AppBskyActorDefs.ProfileView, void> {
|
||||
const queryDatas = queryClient.getQueriesData<
|
||||
InfiniteData<AppBskyGraphGetKnownFollowers.OutputSchema>
|
||||
>({
|
||||
queryKey: [RQKEY_ROOT],
|
||||
})
|
||||
for (const [_queryKey, queryData] of queryDatas) {
|
||||
if (!queryData?.pages) {
|
||||
continue
|
||||
}
|
||||
for (const page of queryData?.pages) {
|
||||
for (const follow of page.followers) {
|
||||
if (follow.did === did) {
|
||||
yield follow
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,7 +23,10 @@ import {useAgent, useSession} from '#/state/session'
|
||||
import {useModerationOpts} from '../preferences/moderation-opts'
|
||||
|
||||
const suggestedFollowsQueryKeyRoot = 'suggested-follows'
|
||||
const suggestedFollowsQueryKey = [suggestedFollowsQueryKeyRoot]
|
||||
const suggestedFollowsQueryKey = (options?: SuggestedFollowsOptions) => [
|
||||
suggestedFollowsQueryKeyRoot,
|
||||
options,
|
||||
]
|
||||
|
||||
const suggestedFollowsByActorQueryKeyRoot = 'suggested-follows-by-actor'
|
||||
const suggestedFollowsByActorQueryKey = (did: string) => [
|
||||
@@ -31,7 +34,9 @@ const suggestedFollowsByActorQueryKey = (did: string) => [
|
||||
did,
|
||||
]
|
||||
|
||||
export function useSuggestedFollowsQuery() {
|
||||
type SuggestedFollowsOptions = {limit?: number}
|
||||
|
||||
export function useSuggestedFollowsQuery(options?: SuggestedFollowsOptions) {
|
||||
const {currentAccount} = useSession()
|
||||
const agent = useAgent()
|
||||
const moderationOpts = useModerationOpts()
|
||||
@@ -46,12 +51,12 @@ export function useSuggestedFollowsQuery() {
|
||||
>({
|
||||
enabled: !!moderationOpts && !!preferences,
|
||||
staleTime: STALE.HOURS.ONE,
|
||||
queryKey: suggestedFollowsQueryKey,
|
||||
queryKey: suggestedFollowsQueryKey(options),
|
||||
queryFn: async ({pageParam}) => {
|
||||
const contentLangs = getContentLanguages().join(',')
|
||||
const res = await agent.app.bsky.actor.getSuggestions(
|
||||
{
|
||||
limit: 25,
|
||||
limit: options?.limit || 25,
|
||||
cursor: pageParam,
|
||||
},
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user