Improve moderation behaviors: show alert/inform sources and improve UX around threads (#3677)

* Dont show account or profile alerts and informs on posts

* Sort threads to put blurred items at bottom

* Group blurred replies under a single 'show hidden replies' control

* Distinguish between muted and hidden replies in the thread view

* Fix types

* Modify the label alerts with some minor aesthetic updates and to show the source of a label

* Tune when an account-level alert is shown on a post

* Revert: show account-level alerts on posts again

* Rm unused import

* Fix to showing hidden replies when viewing a blurred item

* Go ahead and uncover replies when 'show hidden posts' is clicked

---------

Co-authored-by: dan <dan.abramov@gmail.com>
This commit is contained in:
Paul Frazee 2024-05-23 16:39:39 -07:00 committed by GitHub
parent d2c42cf169
commit f7ee532a85
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
9 changed files with 311 additions and 67 deletions

View file

@ -3,9 +3,12 @@ import {
AppBskyFeedDefs,
AppBskyFeedGetPostThread,
AppBskyFeedPost,
ModerationDecision,
ModerationOpts,
} from '@atproto/api'
import {QueryClient, useQuery, useQueryClient} from '@tanstack/react-query'
import {moderatePost_wrapped as moderatePost} from '#/lib/moderatePost_wrapped'
import {UsePreferencesQueryResponse} from '#/state/queries/preferences/types'
import {useAgent} from '#/state/session'
import {findAllPostsInQueryData as findAllPostsInSearchQueryData} from 'state/queries/search-posts'
@ -21,8 +24,6 @@ export interface ThreadCtx {
depth: number
isHighlightedPost?: boolean
hasMore?: boolean
showChildReplyLine?: boolean
showParentReplyLine?: boolean
isParentLoading?: boolean
isChildLoading?: boolean
}
@ -63,6 +64,8 @@ export type ThreadNode =
| ThreadBlocked
| ThreadUnknown
export type ThreadModerationCache = WeakMap<ThreadNode, ModerationDecision>
export function usePostThreadQuery(uri: string | undefined) {
const queryClient = useQueryClient()
const {getAgent} = useAgent()
@ -92,9 +95,28 @@ export function usePostThreadQuery(uri: string | undefined) {
})
}
export function fillThreadModerationCache(
cache: ThreadModerationCache,
node: ThreadNode,
moderationOpts: ModerationOpts,
) {
if (node.type === 'post') {
cache.set(node, moderatePost(node.post, moderationOpts))
if (node.parent) {
fillThreadModerationCache(cache, node.parent, moderationOpts)
}
if (node.replies) {
for (const reply of node.replies) {
fillThreadModerationCache(cache, reply, moderationOpts)
}
}
}
}
export function sortThread(
node: ThreadNode,
opts: UsePreferencesQueryResponse['threadViewPrefs'],
modCache: ThreadModerationCache,
): ThreadNode {
if (node.type !== 'post') {
return node
@ -117,6 +139,18 @@ export function sortThread(
} else if (bIsByOp) {
return 1 // op's own reply
}
const aBlur = Boolean(modCache.get(a)?.ui('contentList').blur)
const bBlur = Boolean(modCache.get(b)?.ui('contentList').blur)
if (aBlur !== bBlur) {
if (aBlur) {
return 1
}
if (bBlur) {
return -1
}
}
if (opts.prioritizeFollowedUsers) {
const af = a.post.author.viewer?.following
const bf = b.post.author.viewer?.following
@ -126,6 +160,7 @@ export function sortThread(
return 1
}
}
if (opts.sort === 'oldest') {
return a.post.indexedAt.localeCompare(b.post.indexedAt)
} else if (opts.sort === 'newest') {
@ -141,7 +176,7 @@ export function sortThread(
}
return b.post.indexedAt.localeCompare(a.post.indexedAt)
})
node.replies.forEach(reply => sortThread(reply, opts))
node.replies.forEach(reply => sortThread(reply, opts, modCache))
}
return node
}
@ -188,12 +223,6 @@ function responseToThreadNodes(
isHighlightedPost: depth === 0,
hasMore:
direction === 'down' && !node.replies?.length && !!node.replyCount,
showChildReplyLine:
direction === 'up' ||
(direction === 'down' && !!node.replies?.length),
showParentReplyLine:
(direction === 'up' && !!node.parent) ||
(direction === 'down' && depth !== 1),
},
}
} else if (AppBskyFeedDefs.isBlockedPost(node)) {
@ -296,8 +325,6 @@ function threadNodeToPlaceholderThread(
depth: 0,
isHighlightedPost: true,
hasMore: false,
showChildReplyLine: false,
showParentReplyLine: false,
isParentLoading: !!node.record.reply,
isChildLoading: !!node.post.replyCount,
},
@ -319,8 +346,6 @@ function postViewToPlaceholderThread(
depth: 0,
isHighlightedPost: true,
hasMore: false,
showChildReplyLine: false,
showParentReplyLine: false,
isParentLoading: !!(post.record as AppBskyFeedPost.Record).reply,
isChildLoading: true, // assume yes (show the spinner) just in case
},
@ -342,8 +367,6 @@ function embedViewRecordToPlaceholderThread(
depth: 0,
isHighlightedPost: true,
hasMore: false,
showChildReplyLine: false,
showParentReplyLine: false,
isParentLoading: !!(record.value as AppBskyFeedPost.Record).reply,
isChildLoading: true, // not available, so assume yes (to show the spinner)
},