Optimistic hidden replies (#4977)
This commit is contained in:
parent
5ec8761b29
commit
425dd5f27f
9 changed files with 70 additions and 129 deletions
|
@ -3,12 +3,7 @@ import {StyleSheet, useWindowDimensions, View} from 'react-native'
|
|||
import {runOnJS} from 'react-native-reanimated'
|
||||
import Animated from 'react-native-reanimated'
|
||||
import {useSafeAreaInsets} from 'react-native-safe-area-context'
|
||||
import {
|
||||
AppBskyFeedDefs,
|
||||
AppBskyFeedPost,
|
||||
AppBskyFeedThreadgate,
|
||||
AtUri,
|
||||
} from '@atproto/api'
|
||||
import {AppBskyFeedDefs, AppBskyFeedThreadgate} from '@atproto/api'
|
||||
import {msg, Trans} from '@lingui/macro'
|
||||
import {useLingui} from '@lingui/react'
|
||||
|
||||
|
@ -28,9 +23,9 @@ import {
|
|||
usePostThreadQuery,
|
||||
} from '#/state/queries/post-thread'
|
||||
import {usePreferencesQuery} from '#/state/queries/preferences'
|
||||
import {useThreadgateRecordQuery} from '#/state/queries/threadgate'
|
||||
import {useSession} from '#/state/session'
|
||||
import {useComposerControls} from '#/state/shell'
|
||||
import {useMergedThreadgateHiddenReplies} from '#/state/threadgate-hidden-replies'
|
||||
import {useInitialNumToRender} from 'lib/hooks/useInitialNumToRender'
|
||||
import {useMinimalShellFabTransform} from 'lib/hooks/useMinimalShellTransform'
|
||||
import {useSetTitle} from 'lib/hooks/useSetTitle'
|
||||
|
@ -108,7 +103,7 @@ export function PostThread({uri}: {uri: string | undefined}) {
|
|||
isError: isThreadError,
|
||||
error: threadError,
|
||||
refetch,
|
||||
data: thread,
|
||||
data: {thread, threadgate} = {},
|
||||
} = usePostThreadQuery(uri)
|
||||
|
||||
const treeView = React.useMemo(
|
||||
|
@ -119,26 +114,11 @@ export function PostThread({uri}: {uri: string | undefined}) {
|
|||
)
|
||||
const rootPost = thread?.type === 'post' ? thread.post : undefined
|
||||
const rootPostRecord = thread?.type === 'post' ? thread.record : undefined
|
||||
const replyRef =
|
||||
rootPostRecord && AppBskyFeedPost.isRecord(rootPostRecord)
|
||||
? rootPostRecord.reply
|
||||
: undefined
|
||||
const rootPostUri = replyRef ? replyRef.root.uri : rootPost?.uri
|
||||
|
||||
const isOP =
|
||||
currentAccount &&
|
||||
rootPostUri &&
|
||||
currentAccount?.did === new AtUri(rootPostUri).host
|
||||
const initialThreadgateRecord = rootPost?.threadgate?.record as
|
||||
const threadgateRecord = threadgate?.record as
|
||||
| AppBskyFeedThreadgate.Record
|
||||
| undefined
|
||||
const {data: threadgateRecord} = useThreadgateRecordQuery({
|
||||
/**
|
||||
* If the user is the OP and we have a root post, fetch the threadgate.
|
||||
*/
|
||||
enabled: Boolean(isOP && rootPostUri),
|
||||
postUri: rootPostUri,
|
||||
initialData: initialThreadgateRecord,
|
||||
const threadgateHiddenReplies = useMergedThreadgateHiddenReplies({
|
||||
threadgateRecord,
|
||||
})
|
||||
|
||||
const moderationOpts = useModerationOpts()
|
||||
|
@ -194,9 +174,6 @@ export function PostThread({uri}: {uri: string | undefined}) {
|
|||
const skeleton = React.useMemo(() => {
|
||||
const threadViewPrefs = preferences?.threadViewPrefs
|
||||
if (!threadViewPrefs || !thread) return null
|
||||
const threadgateRecordHiddenReplies = new Set<string>(
|
||||
threadgateRecord?.hiddenReplies || [],
|
||||
)
|
||||
|
||||
return createThreadSkeleton(
|
||||
sortThread(
|
||||
|
@ -205,13 +182,13 @@ export function PostThread({uri}: {uri: string | undefined}) {
|
|||
threadModerationCache,
|
||||
currentDid,
|
||||
justPostedUris,
|
||||
threadgateRecordHiddenReplies,
|
||||
threadgateHiddenReplies,
|
||||
),
|
||||
currentDid,
|
||||
treeView,
|
||||
threadModerationCache,
|
||||
hiddenRepliesState !== HiddenRepliesState.Hide,
|
||||
threadgateRecordHiddenReplies,
|
||||
threadgateHiddenReplies,
|
||||
)
|
||||
}, [
|
||||
thread,
|
||||
|
@ -221,7 +198,7 @@ export function PostThread({uri}: {uri: string | undefined}) {
|
|||
threadModerationCache,
|
||||
hiddenRepliesState,
|
||||
justPostedUris,
|
||||
threadgateRecord,
|
||||
threadgateHiddenReplies,
|
||||
])
|
||||
|
||||
const error = React.useMemo(() => {
|
||||
|
|
|
@ -17,6 +17,7 @@ import {useLanguagePrefs} from '#/state/preferences'
|
|||
import {useOpenLink} from '#/state/preferences/in-app-browser'
|
||||
import {ThreadPost} from '#/state/queries/post-thread'
|
||||
import {useComposerControls} from '#/state/shell/composer'
|
||||
import {useMergedThreadgateHiddenReplies} from '#/state/threadgate-hidden-replies'
|
||||
import {MAX_POST_LINES} from 'lib/constants'
|
||||
import {usePalette} from 'lib/hooks/usePalette'
|
||||
import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries'
|
||||
|
@ -206,24 +207,22 @@ let PostThreadItemLoaded = ({
|
|||
return makeProfileLink(post.author, 'post', urip.rkey, 'reposted-by')
|
||||
}, [post.uri, post.author])
|
||||
const repostsTitle = _(msg`Reposts of this post`)
|
||||
const threadgateHiddenReplies = useMergedThreadgateHiddenReplies({
|
||||
threadgateRecord,
|
||||
})
|
||||
const additionalPostAlerts: AppModerationCause[] = React.useMemo(() => {
|
||||
const isPostHiddenByThreadgate = threadgateRecord?.hiddenReplies?.includes(
|
||||
post.uri,
|
||||
)
|
||||
const isControlledByViewer =
|
||||
threadgateRecord &&
|
||||
new AtUri(threadgateRecord.post).host === currentAccount?.did
|
||||
if (!isControlledByViewer) return []
|
||||
return threadgateRecord && isPostHiddenByThreadgate
|
||||
const isPostHiddenByThreadgate = threadgateHiddenReplies.has(post.uri)
|
||||
const isControlledByViewer = new AtUri(rootUri).host === currentAccount?.did
|
||||
return isControlledByViewer && isPostHiddenByThreadgate
|
||||
? [
|
||||
{
|
||||
type: 'reply-hidden',
|
||||
source: {type: 'user', did: new AtUri(threadgateRecord.post).host},
|
||||
source: {type: 'user', did: currentAccount?.did},
|
||||
priority: 6,
|
||||
},
|
||||
]
|
||||
: []
|
||||
}, [post, threadgateRecord, currentAccount?.did])
|
||||
}, [post, currentAccount?.did, threadgateHiddenReplies, rootUri])
|
||||
const quotesHref = React.useMemo(() => {
|
||||
const urip = new AtUri(post.uri)
|
||||
return makeProfileLink(post.author, 'post', urip.rkey, 'quotes')
|
||||
|
|
|
@ -22,7 +22,7 @@ import {POST_TOMBSTONE, Shadow, usePostShadow} from '#/state/cache/post-shadow'
|
|||
import {useFeedFeedbackContext} from '#/state/feed-feedback'
|
||||
import {useSession} from '#/state/session'
|
||||
import {useComposerControls} from '#/state/shell/composer'
|
||||
import {useThreadgateHiddenReplyUris} from '#/state/threadgate-hidden-replies'
|
||||
import {useMergedThreadgateHiddenReplies} from '#/state/threadgate-hidden-replies'
|
||||
import {isReasonFeedSource, ReasonFeedSource} from 'lib/api/feed/types'
|
||||
import {MAX_POST_LINES} from 'lib/constants'
|
||||
import {usePalette} from 'lib/hooks/usePalette'
|
||||
|
@ -227,6 +227,10 @@ let FeedItemInner = ({
|
|||
AppBskyFeedDefs.isReasonRepost(reason) &&
|
||||
reason.by.did === currentAccount?.did
|
||||
|
||||
/**
|
||||
* If `post[0]` in this slice is the actual root post (not an orphan thread),
|
||||
* then we may have a threadgate record to reference
|
||||
*/
|
||||
const threadgateRecord = AppBskyFeedThreadgate.isRecord(
|
||||
rootPost.threadgate?.record,
|
||||
)
|
||||
|
@ -422,41 +426,26 @@ let PostContent = ({
|
|||
const [limitLines, setLimitLines] = useState(
|
||||
() => countLines(richText.text) >= MAX_POST_LINES,
|
||||
)
|
||||
const {uris: hiddenReplyUris, recentlyUnhiddenUris} =
|
||||
useThreadgateHiddenReplyUris()
|
||||
const threadgateHiddenReplies = useMergedThreadgateHiddenReplies({
|
||||
threadgateRecord,
|
||||
})
|
||||
const additionalPostAlerts: AppModerationCause[] = React.useMemo(() => {
|
||||
const isPostHiddenByHiddenReplyCache = hiddenReplyUris.has(post.uri)
|
||||
const isPostHiddenByThreadgate =
|
||||
!recentlyUnhiddenUris.has(post.uri) &&
|
||||
!!threadgateRecord?.hiddenReplies?.includes(post.uri)
|
||||
const isHidden = isPostHiddenByHiddenReplyCache || isPostHiddenByThreadgate
|
||||
const isPostHiddenByThreadgate = threadgateHiddenReplies.has(post.uri)
|
||||
const rootPostUri = AppBskyFeedPost.isRecord(post.record)
|
||||
? post.record?.reply?.root?.uri || post.uri
|
||||
: undefined
|
||||
const isControlledByViewer =
|
||||
isPostHiddenByHiddenReplyCache ||
|
||||
(threadgateRecord &&
|
||||
new AtUri(threadgateRecord.post).host === currentAccount?.did)
|
||||
if (!isControlledByViewer) return []
|
||||
const alertSource =
|
||||
threadgateRecord && isPostHiddenByThreadgate
|
||||
? new AtUri(threadgateRecord.post).host
|
||||
: isPostHiddenByHiddenReplyCache
|
||||
? currentAccount?.did
|
||||
: undefined
|
||||
return isHidden && alertSource
|
||||
rootPostUri && new AtUri(rootPostUri).host === currentAccount?.did
|
||||
return isControlledByViewer && isPostHiddenByThreadgate
|
||||
? [
|
||||
{
|
||||
type: 'reply-hidden',
|
||||
source: {type: 'user', did: alertSource},
|
||||
source: {type: 'user', did: currentAccount?.did},
|
||||
priority: 6,
|
||||
},
|
||||
]
|
||||
: []
|
||||
}, [
|
||||
post,
|
||||
hiddenReplyUris,
|
||||
recentlyUnhiddenUris,
|
||||
threadgateRecord,
|
||||
currentAccount?.did,
|
||||
])
|
||||
}, [post, currentAccount?.did, threadgateHiddenReplies])
|
||||
|
||||
const onPressShowMore = React.useCallback(() => {
|
||||
setLimitLines(false)
|
||||
|
|
|
@ -37,7 +37,7 @@ import {useToggleQuoteDetachmentMutation} from '#/state/queries/postgate'
|
|||
import {getMaybeDetachedQuoteEmbed} from '#/state/queries/postgate/util'
|
||||
import {useToggleReplyVisibilityMutation} from '#/state/queries/threadgate'
|
||||
import {useSession} from '#/state/session'
|
||||
import {useThreadgateHiddenReplyUris} from '#/state/threadgate-hidden-replies'
|
||||
import {useMergedThreadgateHiddenReplies} from '#/state/threadgate-hidden-replies'
|
||||
import {getCurrentRoute} from 'lib/routes/helpers'
|
||||
import {shareUrl} from 'lib/sharing'
|
||||
import {toShareUrl} from 'lib/strings/url-helpers'
|
||||
|
@ -124,8 +124,6 @@ let PostDropdownBtn = ({
|
|||
const hideReplyConfirmControl = useDialogControl()
|
||||
const {mutateAsync: toggleReplyVisibility} =
|
||||
useToggleReplyVisibilityMutation()
|
||||
const {uris: hiddenReplies, recentlyUnhiddenUris} =
|
||||
useThreadgateHiddenReplyUris()
|
||||
|
||||
const postUri = post.uri
|
||||
const postCid = post.cid
|
||||
|
@ -147,10 +145,10 @@ let PostDropdownBtn = ({
|
|||
const isPostHidden = hiddenPosts && hiddenPosts.includes(postUri)
|
||||
const isAuthor = postAuthor.did === currentAccount?.did
|
||||
const isRootPostAuthor = new AtUri(rootUri).host === currentAccount?.did
|
||||
const isReplyHiddenByThreadgate =
|
||||
hiddenReplies.has(postUri) ||
|
||||
(!recentlyUnhiddenUris.has(postUri) &&
|
||||
threadgateRecord?.hiddenReplies?.includes(postUri))
|
||||
const threadgateHiddenReplies = useMergedThreadgateHiddenReplies({
|
||||
threadgateRecord,
|
||||
})
|
||||
const isReplyHiddenByThreadgate = threadgateHiddenReplies.has(postUri)
|
||||
|
||||
const {mutateAsync: toggleQuoteDetachment, isPending} =
|
||||
useToggleQuoteDetachmentMutation()
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue