From ffddc16f5a146fac388b5c47d8f454686870076c Mon Sep 17 00:00:00 2001 From: Eric Bailey Date: Wed, 11 Jun 2025 14:15:03 -0500 Subject: [PATCH] Integrate post-source (cherry picked from commit fe053e9b38395a4fcb30a4367bc800f64ea84fe9) --- .../components/ThreadItemAnchor.tsx | 92 ++++++++++++++++--- src/screens/PostThread/index.tsx | 32 ++++++- 2 files changed, 108 insertions(+), 16 deletions(-) diff --git a/src/screens/PostThread/components/ThreadItemAnchor.tsx b/src/screens/PostThread/components/ThreadItemAnchor.tsx index 55f6179792..0aacd4e771 100644 --- a/src/screens/PostThread/components/ThreadItemAnchor.tsx +++ b/src/screens/PostThread/components/ThreadItemAnchor.tsx @@ -1,7 +1,7 @@ import {memo, useCallback, useMemo} from 'react' import {type GestureResponderEvent, Text as RNText, View} from 'react-native' import { - type AppBskyFeedDefs, + AppBskyFeedDefs, AppBskyFeedPost, type AppBskyFeedThreadgate, AtUri, @@ -26,11 +26,13 @@ import { usePostShadow, } from '#/state/cache/post-shadow' import {useProfileShadow} from '#/state/cache/profile-shadow' +import {FeedFeedbackProvider, useFeedFeedback} from '#/state/feed-feedback' import {useLanguagePrefs} from '#/state/preferences' import {type ThreadItem} from '#/state/queries/usePostThread/types' import {useSession} from '#/state/session' import {type OnPostSuccessData} from '#/state/shell/composer' import {useMergedThreadgateHiddenReplies} from '#/state/threadgate-hidden-replies' +import {type PostSource} from '#/state/unstable-post-source' import {PostThreadFollowBtn} from '#/view/com/post-thread/PostThreadFollowBtn' import {Link} from '#/view/com/util/Link' import {formatCount} from '#/view/com/util/numeric/format' @@ -64,10 +66,12 @@ export function ThreadItemAnchor({ item, onPostSuccess, threadgateRecord, + postSource, }: { item: Extract onPostSuccess?: (data: OnPostSuccessData) => void threadgateRecord?: AppBskyFeedThreadgate.Record + postSource?: PostSource }) { const postShadow = usePostShadow(item.value.post) const threadRootUri = item.value.post.record.reply?.root?.uri || item.uri @@ -86,6 +90,7 @@ export function ThreadItemAnchor({ postShadow={postShadow} onPostSuccess={onPostSuccess} threadgateRecord={threadgateRecord} + postSource={postSource} /> ) } @@ -161,17 +166,20 @@ const ThreadItemAnchorInner = memo(function ThreadItemAnchorInner({ postShadow, onPostSuccess, threadgateRecord, + postSource, }: { item: Extract isRoot: boolean postShadow: Shadow onPostSuccess?: (data: OnPostSuccessData) => void threadgateRecord?: AppBskyFeedThreadgate.Record + postSource?: PostSource }) { const t = useTheme() const {_, i18n} = useLingui() const {openComposer} = useOpenComposer() - const {currentAccount} = useSession() + const {currentAccount, hasSession} = useSession() + const feedFeedback = useFeedFeedback(postSource?.feed, hasSession) const post = item.value.post const record = item.value.post.record @@ -228,6 +236,17 @@ const ThreadItemAnchorInner = memo(function ThreadItemAnchorInner({ const showFollowButton = currentAccount?.did !== post.author.did && !onlyFollowersCanReply + const viaRepost = useMemo(() => { + const reason = postSource?.post.reason + + if (AppBskyFeedDefs.isReasonRepost(reason) && reason.uri && reason.cid) { + return { + uri: reason.uri, + cid: reason.cid, + } + } + }, [postSource]) + const onPressReply = useCallback(() => { openComposer({ replyTo: { @@ -240,7 +259,46 @@ const ThreadItemAnchorInner = memo(function ThreadItemAnchorInner({ }, onPostSuccess: onPostSuccess, }) - }, [openComposer, post, record, onPostSuccess, moderation]) + + if (postSource) { + feedFeedback.sendInteraction({ + item: post.uri, + event: 'app.bsky.feed.defs#interactionReply', + feedContext: postSource.post.feedContext, + reqId: postSource.post.reqId, + }) + } + }, [ + openComposer, + post, + record, + onPostSuccess, + moderation, + postSource, + feedFeedback, + ]) + + const onOpenAuthor = () => { + if (postSource) { + feedFeedback.sendInteraction({ + item: post.uri, + event: 'app.bsky.feed.defs#clickthroughAuthor', + feedContext: postSource.post.feedContext, + reqId: postSource.post.reqId, + }) + } + } + + const onOpenEmbed = () => { + if (postSource) { + feedFeedback.sendInteraction({ + item: post.uri, + event: 'app.bsky.feed.defs#clickthroughEmbed', + feedContext: postSource.post.feedContext, + reqId: postSource.post.reqId, + }) + } + } return ( <> @@ -261,13 +319,15 @@ const ThreadItemAnchorInner = memo(function ThreadItemAnchorInner({ moderation={moderation.ui('avatar')} type={post.author.associated?.labeler ? 'labeler' : 'user'} live={live} + onBeforePress={onOpenAuthor} /> + title={authorTitle} + onBeforePress={onOpenAuthor}> )} @@ -411,15 +472,20 @@ const ThreadItemAnchorInner = memo(function ThreadItemAnchorInner({ marginLeft: -5, }, ]}> - + + + diff --git a/src/screens/PostThread/index.tsx b/src/screens/PostThread/index.tsx index 4c9d489ac9..a4f94851ad 100644 --- a/src/screens/PostThread/index.tsx +++ b/src/screens/PostThread/index.tsx @@ -5,11 +5,13 @@ import {Trans} from '@lingui/macro' import {useInitialNumToRender} from '#/lib/hooks/useInitialNumToRender' import {useOpenComposer} from '#/lib/hooks/useOpenComposer' +import {useFeedFeedback} from '#/state/feed-feedback' import {type ThreadViewOption} from '#/state/queries/preferences/useThreadPreferences' import {type ThreadItem, usePostThread} from '#/state/queries/usePostThread' import {useSession} from '#/state/session' import {type OnPostSuccessData} from '#/state/shell/composer' import {useShellLayout} from '#/state/shell/shell-layout' +import {useUnstablePostSource} from '#/state/unstable-post-source' import {PostThreadComposePrompt} from '#/view/com/post-thread/PostThreadComposePrompt' import {List, type ListMethods} from '#/view/com/util/List' import {HeaderDropdown} from '#/screens/PostThread/components/HeaderDropdown' @@ -40,11 +42,13 @@ import {ListFooter} from '#/components/Lists' const PARENT_CHUNK_SIZE = 5 const CHILDREN_CHUNK_SIZE = 50 -export function PostThread({uri}: {uri: string | undefined}) { +export function PostThread({uri}: {uri: string}) { const {gtMobile} = useBreakpoints() const {hasSession} = useSession() const initialNumToRender = useInitialNumToRender() // TODO const {height: windowHeight} = useWindowDimensions() + const anchorPostSource = useUnstablePostSource(uri) + const feedFeedback = useFeedFeedback(anchorPostSource?.feed, hasSession) /* * One query to rule them all @@ -87,7 +91,22 @@ export function PostThread({uri}: {uri: string | undefined}) { }, onPostSuccess: optimisticOnPostReply, }) - }, [anchor, openComposer, optimisticOnPostReply]) + + if (anchorPostSource) { + feedFeedback.sendInteraction({ + item: post.uri, + event: 'app.bsky.feed.defs#interactionReply', + feedContext: anchorPostSource.post.feedContext, + reqId: anchorPostSource.post.reqId, + }) + } + }, [ + anchor, + openComposer, + optimisticOnPostReply, + anchorPostSource, + feedFeedback, + ]) const isRoot = !!anchor && anchor.value.post.record.reply === undefined const canReply = !anchor?.value.post?.viewer?.replyDisabled @@ -380,6 +399,7 @@ export function PostThread({uri}: {uri: string | undefined}) { item={item} threadgateRecord={thread.data.threadgate?.record ?? undefined} onPostSuccess={optimisticOnPostReply} + postSource={anchorPostSource} /> ) @@ -452,7 +472,13 @@ export function PostThread({uri}: {uri: string | undefined}) { } return null }, - [thread, optimisticOnPostReply, onReplyToAnchor, gtMobile], + [ + thread, + optimisticOnPostReply, + onReplyToAnchor, + gtMobile, + anchorPostSource, + ], ) return (