add shadow filter to post feeds (#9406)
This commit is contained in:
Vendored
+79
-1
@@ -13,7 +13,10 @@ import {findAllProfilesInQueryData as findAllProfilesInListConvosQueryData} from
|
|||||||
import {findAllProfilesInQueryData as findAllProfilesInMyBlockedAccountsQueryData} from '#/state/queries/my-blocked-accounts'
|
import {findAllProfilesInQueryData as findAllProfilesInMyBlockedAccountsQueryData} from '#/state/queries/my-blocked-accounts'
|
||||||
import {findAllProfilesInQueryData as findAllProfilesInMyMutedAccountsQueryData} from '#/state/queries/my-muted-accounts'
|
import {findAllProfilesInQueryData as findAllProfilesInMyMutedAccountsQueryData} from '#/state/queries/my-muted-accounts'
|
||||||
import {findAllProfilesInQueryData as findAllProfilesInNotifsQueryData} from '#/state/queries/notifications/feed'
|
import {findAllProfilesInQueryData as findAllProfilesInNotifsQueryData} from '#/state/queries/notifications/feed'
|
||||||
import {findAllProfilesInQueryData as findAllProfilesInFeedsQueryData} from '#/state/queries/post-feed'
|
import {
|
||||||
|
type FeedPage,
|
||||||
|
findAllProfilesInQueryData as findAllProfilesInFeedsQueryData,
|
||||||
|
} from '#/state/queries/post-feed'
|
||||||
import {findAllProfilesInQueryData as findAllProfilesInPostLikedByQueryData} from '#/state/queries/post-liked-by'
|
import {findAllProfilesInQueryData as findAllProfilesInPostLikedByQueryData} from '#/state/queries/post-liked-by'
|
||||||
import {findAllProfilesInQueryData as findAllProfilesInPostQuotesQueryData} from '#/state/queries/post-quotes'
|
import {findAllProfilesInQueryData as findAllProfilesInPostQuotesQueryData} from '#/state/queries/post-quotes'
|
||||||
import {findAllProfilesInQueryData as findAllProfilesInPostRepostedByQueryData} from '#/state/queries/post-reposted-by'
|
import {findAllProfilesInQueryData as findAllProfilesInPostRepostedByQueryData} from '#/state/queries/post-reposted-by'
|
||||||
@@ -110,6 +113,81 @@ export function useMaybeProfileShadow<
|
|||||||
}, [profile, shadow])
|
}, [profile, shadow])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Takes a list of posts, and returns a list of DIDs that should be filtered out
|
||||||
|
*
|
||||||
|
* Note: it doesn't retroactively scan the cache, but only listens to new updates.
|
||||||
|
* The use case here is intended for removing a post from a feed after you mute the author
|
||||||
|
*/
|
||||||
|
export function usePostAuthorShadowFilter(data?: FeedPage[]) {
|
||||||
|
const [trackedDids, setTrackedDids] = useState<string[]>(
|
||||||
|
() =>
|
||||||
|
data?.flatMap(page =>
|
||||||
|
page.slices.flatMap(slice =>
|
||||||
|
slice.items.map(item => item.post.author.did),
|
||||||
|
),
|
||||||
|
) ?? [],
|
||||||
|
)
|
||||||
|
const [authors, setAuthors] = useState(
|
||||||
|
new Map<string, {muted: boolean; blocked: boolean}>(),
|
||||||
|
)
|
||||||
|
|
||||||
|
const [prevData, setPrevData] = useState(data)
|
||||||
|
if (data !== prevData) {
|
||||||
|
const newAuthors = new Set(trackedDids)
|
||||||
|
let hasNew = false
|
||||||
|
for (const slice of data?.flatMap(page => page.slices) ?? []) {
|
||||||
|
for (const item of slice.items) {
|
||||||
|
const author = item.post.author
|
||||||
|
if (!newAuthors.has(author.did)) {
|
||||||
|
hasNew = true
|
||||||
|
newAuthors.add(author.did)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (hasNew) setTrackedDids([...newAuthors])
|
||||||
|
setPrevData(data)
|
||||||
|
}
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const unsubs: Array<() => void> = []
|
||||||
|
|
||||||
|
for (const did of trackedDids) {
|
||||||
|
function onUpdate(value: Partial<ProfileShadow>) {
|
||||||
|
setAuthors(prev => {
|
||||||
|
const prevValue = prev.get(did)
|
||||||
|
const next = new Map(prev)
|
||||||
|
next.set(did, {
|
||||||
|
blocked: Boolean(value.blockingUri ?? prevValue?.blocked ?? false),
|
||||||
|
muted: Boolean(value.muted ?? prevValue?.muted ?? false),
|
||||||
|
})
|
||||||
|
return next
|
||||||
|
})
|
||||||
|
}
|
||||||
|
emitter.addListener(did, onUpdate)
|
||||||
|
unsubs.push(() => {
|
||||||
|
emitter.removeListener(did, onUpdate)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
unsubs.map(fn => fn())
|
||||||
|
}
|
||||||
|
}, [trackedDids])
|
||||||
|
|
||||||
|
return useMemo(() => {
|
||||||
|
const dids: Array<string> = []
|
||||||
|
|
||||||
|
for (const [did, value] of authors.entries()) {
|
||||||
|
if (value.blocked || value.muted) {
|
||||||
|
dids.push(did)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return dids
|
||||||
|
}, [authors])
|
||||||
|
}
|
||||||
|
|
||||||
export function updateProfileShadow(
|
export function updateProfileShadow(
|
||||||
queryClient: QueryClient,
|
queryClient: QueryClient,
|
||||||
did: string,
|
did: string,
|
||||||
|
|||||||
@@ -35,6 +35,7 @@ import {logEvent} from '#/lib/statsig/statsig'
|
|||||||
import {isNetworkError} from '#/lib/strings/errors'
|
import {isNetworkError} from '#/lib/strings/errors'
|
||||||
import {logger} from '#/logger'
|
import {logger} from '#/logger'
|
||||||
import {isIOS, isNative, isWeb} from '#/platform/detection'
|
import {isIOS, isNative, isWeb} from '#/platform/detection'
|
||||||
|
import {usePostAuthorShadowFilter} from '#/state/cache/profile-shadow'
|
||||||
import {listenPostCreated} from '#/state/events'
|
import {listenPostCreated} from '#/state/events'
|
||||||
import {useFeedFeedbackContext} from '#/state/feed-feedback'
|
import {useFeedFeedbackContext} from '#/state/feed-feedback'
|
||||||
import {useTrendingSettings} from '#/state/preferences/trending'
|
import {useTrendingSettings} from '#/state/preferences/trending'
|
||||||
@@ -363,6 +364,11 @@ let PostFeed = ({
|
|||||||
*/
|
*/
|
||||||
const [isCurrentFeedAtStartupSelected] = useState(selectedFeed === feed)
|
const [isCurrentFeedAtStartupSelected] = useState(selectedFeed === feed)
|
||||||
|
|
||||||
|
const blockedOrMutedAuthors = usePostAuthorShadowFilter(
|
||||||
|
// author feeds have their own handling
|
||||||
|
feed.startsWith('author|') ? undefined : data?.pages,
|
||||||
|
)
|
||||||
|
|
||||||
const feedItems: FeedRow[] = useMemo(() => {
|
const feedItems: FeedRow[] = useMemo(() => {
|
||||||
// wraps a slice item, and replaces it with a showLessFollowup item
|
// wraps a slice item, and replaces it with a showLessFollowup item
|
||||||
// if the user has pressed show less on it
|
// if the user has pressed show less on it
|
||||||
@@ -423,7 +429,11 @@ let PostFeed = ({
|
|||||||
// eslint-disable-next-line @typescript-eslint/no-shadow
|
// eslint-disable-next-line @typescript-eslint/no-shadow
|
||||||
item => item.uri === slice.feedPostUri,
|
item => item.uri === slice.feedPostUri,
|
||||||
)
|
)
|
||||||
if (item && AppBskyEmbedVideo.isView(item.post.embed)) {
|
if (
|
||||||
|
item &&
|
||||||
|
AppBskyEmbedVideo.isView(item.post.embed) &&
|
||||||
|
!blockedOrMutedAuthors.includes(item.post.author.did)
|
||||||
|
) {
|
||||||
videos.push({
|
videos.push({
|
||||||
item,
|
item,
|
||||||
feedContext: slice.feedContext,
|
feedContext: slice.feedContext,
|
||||||
@@ -541,6 +551,12 @@ let PostFeed = ({
|
|||||||
key:
|
key:
|
||||||
'sliceFallbackMarker-' + sliceIndex + '-' + lastFetchedAt,
|
'sliceFallbackMarker-' + sliceIndex + '-' + lastFetchedAt,
|
||||||
})
|
})
|
||||||
|
} else if (
|
||||||
|
slice.items.some(item =>
|
||||||
|
blockedOrMutedAuthors.includes(item.post.author.did),
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
// skip
|
||||||
} else if (slice.isIncompleteThread && slice.items.length >= 3) {
|
} else if (slice.isIncompleteThread && slice.items.length >= 3) {
|
||||||
const beforeLast = slice.items.length - 2
|
const beforeLast = slice.items.length - 2
|
||||||
const last = slice.items.length - 1
|
const last = slice.items.length - 1
|
||||||
@@ -636,6 +652,7 @@ let PostFeed = ({
|
|||||||
hasPressedShowLessUris,
|
hasPressedShowLessUris,
|
||||||
ageAssuranceBannerState,
|
ageAssuranceBannerState,
|
||||||
isCurrentFeedAtStartupSelected,
|
isCurrentFeedAtStartupSelected,
|
||||||
|
blockedOrMutedAuthors,
|
||||||
])
|
])
|
||||||
|
|
||||||
// events
|
// events
|
||||||
|
|||||||
Reference in New Issue
Block a user