diff --git a/src/components/Post/Embed/index.tsx b/src/components/Post/Embed/index.tsx index 306f7112d..d9bd26111 100644 --- a/src/components/Post/Embed/index.tsx +++ b/src/components/Post/Embed/index.tsx @@ -184,6 +184,16 @@ function RecordEmbed({ enabled: shouldDirectFetch, }) + if ( + (embed.type === 'post' || + embed.type === 'post_blocked' || + embed.type === 'post_detached' || + embed.type === 'post_not_found') && + embed.view.uri === rest.hideRecordEmbedUri + ) { + return null + } + switch (embed.type) { case 'feed': { return ( diff --git a/src/components/Post/Embed/types.ts b/src/components/Post/Embed/types.ts index eb0136b17..887499e40 100644 --- a/src/components/Post/Embed/types.ts +++ b/src/components/Post/Embed/types.ts @@ -17,6 +17,8 @@ export type CommonProps = { isWithinQuote?: boolean allowNestedQuotes?: boolean showPronouns?: boolean + /** Hides a quoted-post record while leaving any accompanying media visible. */ + hideRecordEmbedUri?: string /** * The post that contains this embed. Used for analytics on photo embed * events (post:photoEmbed:*). When the embed has no owning post (e.g. diff --git a/src/components/icons/Chevron.tsx b/src/components/icons/Chevron.tsx index b033e3c66..0fcb51514 100644 --- a/src/components/icons/Chevron.tsx +++ b/src/components/icons/Chevron.tsx @@ -20,6 +20,10 @@ export const ChevronTopBottom_Stroke2_Corner0_Rounded = createSinglePathSVG({ path: 'M11.293 4.293a1 1 0 0 1 1.414 0l4 4a1 1 0 0 1-1.414 1.414L12 6.414 8.707 9.707a1 1 0 0 1-1.414-1.414l4-4Zm-4 10a1 1 0 0 1 1.414 0L12 17.586l3.293-3.293a1 1 0 0 1 1.414 1.414l-4 4a1 1 0 0 1-1.414 0l-4-4a1 1 0 0 1 0-1.414Z', }) +export const ChevronBottomTop_Stroke2_Corner0_Rounded = createSinglePathSVG({ + path: 'M7.293 4.293a1 1 0 0 1 1.414 0L12 7.586l3.293-3.293a1 1 0 0 1 1.414 1.414l-4 4a1 1 0 0 1-1.414 0l-4-4a1 1 0 0 1 0-1.414Zm4 10a1 1 0 0 1 1.414 0l4 4a1 1 0 0 1-1.414 1.414L12 16.414l-3.293 3.293a1 1 0 0 1-1.414-1.414l4-4Z', +}) + /** * NOTE: Use with size `2xs` */ diff --git a/src/screens/Post/PostQuotes.tsx b/src/screens/Post/PostQuotes.tsx index 6c747ce6a..6a6c37238 100644 --- a/src/screens/Post/PostQuotes.tsx +++ b/src/screens/Post/PostQuotes.tsx @@ -1,7 +1,9 @@ +import {useCallback, useState} from 'react' import {msg} from '@lingui/core/macro' import {useLingui} from '@lingui/react' import {Plural, Trans} from '@lingui/react/macro' +import {HITSLOP_10} from '#/lib/constants' import {useSetTitle} from '#/lib/hooks/useSetTitle' import { type CommonNavigatorParams, @@ -12,6 +14,11 @@ import {usePostQuery} from '#/state/queries/post' import {useProfileQuery} from '#/state/queries/profile' import {useResolveDidQuery} from '#/state/queries/resolve-uri' import {PostQuotes as PostQuotesComponent} from '#/view/com/post-thread/PostQuotes' +import {Button, ButtonIcon} from '#/components/Button' +import { + ChevronBottomTop_Stroke2_Corner0_Rounded as ChevronIn, + ChevronTopBottom_Stroke2_Corner0_Rounded as ChevronOut, +} from '#/components/icons/Chevron' import * as Layout from '#/components/Layout' type Props = NativeStackScreenProps @@ -23,6 +30,11 @@ export const PostQuotesScreen = ({route}: Props) => { const {data: resolvedDid} = useResolveDidQuery(name) const {data: profile} = useProfileQuery({did: resolvedDid}) + const [isQuotedPostExtracted, setIsQuotedPostExtracted] = useState(false) + + const onToggleQuotedPost = useCallback(() => { + setIsQuotedPostExtracted(value => !value) + }, []) useSetTitle(profile ? _(msg`Post by @${profile.handle}`) : undefined) @@ -51,9 +63,33 @@ export const PostQuotesScreen = ({route}: Props) => { )} - + + {post && ( + + )} + - + ) } diff --git a/src/view/com/post-thread/PostQuotes.tsx b/src/view/com/post-thread/PostQuotes.tsx index b16281f9e..feb7a4d82 100644 --- a/src/view/com/post-thread/PostQuotes.tsx +++ b/src/view/com/post-thread/PostQuotes.tsx @@ -1,4 +1,5 @@ import {useCallback, useState} from 'react' +import {View} from 'react-native' import { type AppBskyFeedDefs, AppBskyFeedPost, @@ -7,6 +8,7 @@ import { } from '@atproto/api' import {msg} from '@lingui/core/macro' import {useLingui} from '@lingui/react' +import {Trans} from '@lingui/react/macro' import {useInitialNumToRender} from '#/lib/hooks/useInitialNumToRender' import {usePostViewTracking} from '#/lib/hooks/usePostViewTracking' @@ -16,24 +18,12 @@ import {useModerationOpts} from '#/state/preferences/moderation-opts' import {usePostQuotesQuery} from '#/state/queries/post-quotes' import {useResolveUriQuery} from '#/state/queries/resolve-uri' import {Post} from '#/view/com/post/Post' +import {atoms as a, useTheme} from '#/alf' import {ListFooter, ListMaybePlaceholder} from '#/components/Lists' +import {Text} from '#/components/Typography' import * as bsky from '#/types/bsky' import {List} from '../util/List' -function renderItem({ - item, - index, -}: { - item: { - post: AppBskyFeedDefs.PostView - moderation: ModerationDecision - record: AppBskyFeedPost.Record - } - index: number -}) { - return -} - function keyExtractor(item: { post: AppBskyFeedDefs.PostView moderation: ModerationDecision @@ -42,7 +32,41 @@ function keyExtractor(item: { return item.post.uri } -export function PostQuotes({uri}: {uri: string}) { +function ExtractedQuotedPost({post}: {post: AppBskyFeedDefs.PostView}) { + const t = useTheme() + + return ( + + + + + The quoted post has been extracted from the following + + + + ) +} + +export function PostQuotes({ + uri, + quotedPost, + isQuotedPostExtracted, +}: { + uri: string + quotedPost?: AppBskyFeedDefs.PostView + isQuotedPostExtracted: boolean +}) { const {_} = useLingui() const initialNumToRender = useInitialNumToRender() const [isPTRing, setIsPTRing] = useState(false) @@ -105,6 +129,27 @@ export function PostQuotes({uri}: {uri: string}) { } }, [isFetchingNextPage, hasNextPage, isError, fetchNextPage]) + const renderItem = useCallback( + ({ + item, + index, + }: { + item: { + post: AppBskyFeedDefs.PostView + moderation: ModerationDecision + record: AppBskyFeedPost.Record + } + index: number + }) => ( + + ), + [isQuotedPostExtracted, quotedPost?.uri], + ) + if (quotes.length < 1) { return ( trackPostView(item.post)} + ListHeaderComponent={ + isQuotedPostExtracted && quotedPost ? ( + + ) : undefined + } ListFooterComponent={ onBeforePress?: () => void }) { @@ -92,6 +94,7 @@ export function Post({ moderation={moderation} showReplyLine={showReplyLine} hideTopBorder={hideTopBorder} + hideQuoteEmbedUri={hideQuoteEmbedUri} style={style} onBeforePress={onBeforePress} /> @@ -108,6 +111,7 @@ function PostInner({ moderation, showReplyLine, hideTopBorder, + hideQuoteEmbedUri, style, onBeforePress: outerOnBeforePress, }: { @@ -117,6 +121,7 @@ function PostInner({ moderation: ModerationDecision showReplyLine?: boolean hideTopBorder?: boolean + hideQuoteEmbedUri?: string style?: StyleProp onBeforePress?: () => void }) { @@ -264,6 +269,7 @@ function PostInner({ moderation={moderation} viewContext={PostEmbedViewContext.Feed} post={post} + hideRecordEmbedUri={hideQuoteEmbedUri} /> ) : null}