diff options
Diffstat (limited to 'src/view/com/post-thread/PostThreadItem.tsx')
-rw-r--r-- | src/view/com/post-thread/PostThreadItem.tsx | 160 |
1 files changed, 59 insertions, 101 deletions
diff --git a/src/view/com/post-thread/PostThreadItem.tsx b/src/view/com/post-thread/PostThreadItem.tsx index 826d0d161..6555bdf73 100644 --- a/src/view/com/post-thread/PostThreadItem.tsx +++ b/src/view/com/post-thread/PostThreadItem.tsx @@ -5,13 +5,13 @@ import { AppBskyFeedDefs, AppBskyFeedPost, RichText as RichTextAPI, - PostModeration, + ModerationDecision, } from '@atproto/api' import {moderatePost_wrapped as moderatePost} from '#/lib/moderatePost_wrapped' import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome' import {PostThreadFollowBtn} from 'view/com/post-thread/PostThreadFollowBtn' import {Link, TextLink} from '../util/Link' -import {RichText} from '../util/text/RichText' +import {RichText} from '#/components/RichText' import {Text} from '../util/text/Text' import {PreviewableUserAvatar} from '../util/UserAvatar' import {s} from 'lib/styles' @@ -19,15 +19,14 @@ import {niceDate} from 'lib/strings/time' import {sanitizeDisplayName} from 'lib/strings/display-names' import {sanitizeHandle} from 'lib/strings/handles' import {countLines, pluralize} from 'lib/strings/helpers' -import {isEmbedByEmbedder} from 'lib/embeds' import {getTranslatorLink, isPostInLanguage} from '../../../locale/helpers' import {PostMeta} from '../util/PostMeta' import {PostEmbeds} from '../util/post-embeds' import {PostCtrls} from '../util/post-ctrls/PostCtrls' -import {PostHider} from '../util/moderation/PostHider' -import {ContentHider} from '../util/moderation/ContentHider' -import {PostAlerts} from '../util/moderation/PostAlerts' -import {PostSandboxWarning} from '../util/PostSandboxWarning' +import {PostHider} from '../../../components/moderation/PostHider' +import {ContentHider} from '../../../components/moderation/ContentHider' +import {PostAlerts} from '../../../components/moderation/PostAlerts' +import {LabelsOnMyPost} from '../../../components/moderation/LabelsOnMe' import {ErrorMessage} from '../util/error/ErrorMessage' import {usePalette} from 'lib/hooks/usePalette' import {formatCount} from '../util/numeric/format' @@ -44,6 +43,8 @@ import {Shadow, usePostShadow, POST_TOMBSTONE} from '#/state/cache/post-shadow' import {ThreadPost} from '#/state/queries/post-thread' import {useSession} from 'state/session' import {WhoCanReply} from '../threadgate/WhoCanReply' +import {LoadingPlaceholder} from '../util/LoadingPlaceholder' +import {atoms as a} from '#/alf' export function PostThreadItem({ post, @@ -93,6 +94,8 @@ export function PostThreadItem({ if (richText && moderation) { return ( <PostThreadItemLoaded + // Safeguard from clobbering per-post state below: + key={postShadowed.uri} post={postShadowed} prevPost={prevPost} nextPost={nextPost} @@ -144,7 +147,7 @@ let PostThreadItemLoaded = ({ post: Shadow<AppBskyFeedDefs.PostView> record: AppBskyFeedPost.Record richText: RichTextAPI - moderation: PostModeration + moderation: ModerationDecision treeView: boolean depth: number prevPost: ThreadPost | undefined @@ -164,8 +167,6 @@ let PostThreadItemLoaded = ({ () => countLines(richText?.text) >= MAX_POST_LINES, ) const {currentAccount} = useSession() - const hasEngagement = post.likeCount || post.repostCount - const rootUri = record.reply?.root?.uri || post.uri const postHref = React.useMemo(() => { const urip = new AtUri(post.uri) @@ -174,7 +175,6 @@ let PostThreadItemLoaded = ({ const itemTitle = _(msg`Post by ${post.author.handle}`) const authorHref = makeProfileLink(post.author) const authorTitle = post.author.handle - const isAuthorMuted = post.author.viewer?.muted const likesHref = React.useMemo(() => { const urip = new AtUri(post.uri) return makeProfileLink(post.author, 'post', urip.rkey, 'liked-by') @@ -205,11 +205,7 @@ let PostThreadItemLoaded = ({ uri: post.uri, cid: post.cid, text: record.text, - author: { - handle: post.author.handle, - displayName: post.author.displayName, - avatar: post.author.avatar, - }, + author: post.author, embed: post.embed, moderation, }, @@ -248,7 +244,6 @@ let PostThreadItemLoaded = ({ testID={`postThreadItem-by-${post.author.handle}`} style={[styles.outer, styles.outerHighlighted, pal.border, pal.view]} accessible={false}> - <PostSandboxWarning /> <View style={[styles.layout]}> <View style={[styles.layoutAvi, {paddingBottom: 8}]}> <PreviewableUserAvatar @@ -256,7 +251,8 @@ let PostThreadItemLoaded = ({ did={post.author.did} handle={post.author.handle} avatar={post.author.avatar} - moderation={moderation.avatar} + moderation={moderation.ui('avatar')} + type={post.author.associated?.labeler ? 'labeler' : 'user'} /> </View> <View style={styles.layoutContent}> @@ -271,35 +267,12 @@ let PostThreadItemLoaded = ({ {sanitizeDisplayName( post.author.displayName || sanitizeHandle(post.author.handle), + moderation.ui('displayName'), )} </Text> </Link> </View> <View style={styles.meta}> - {isAuthorMuted && ( - <View - style={[ - pal.viewLight, - { - flexDirection: 'row', - alignItems: 'center', - gap: 4, - borderRadius: 6, - paddingHorizontal: 6, - paddingVertical: 2, - marginRight: 4, - }, - ]}> - <FontAwesomeIcon - icon={['far', 'eye-slash']} - size={12} - color={pal.colors.textLight} - /> - <Text type="sm-medium" style={pal.textLight}> - Muted - </Text> - </View> - )} <Link style={s.flex1} href={authorHref} title={authorTitle}> <Text type="md" style={[pal.textLight]} numberOfLines={1}> {sanitizeHandle(post.author.handle, '@')} @@ -312,15 +285,16 @@ let PostThreadItemLoaded = ({ )} </View> <View style={[s.pl10, s.pr10, s.pb10]}> + <LabelsOnMyPost post={post} /> <ContentHider - moderation={moderation.content} + modui={moderation.ui('contentView')} ignoreMute style={styles.contentHider} childContainerStyle={styles.contentHiderChild}> <PostAlerts - moderation={moderation.content} + modui={moderation.ui('contentView')} includeMute - style={styles.alert} + style={[a.pt_2xs, a.pb_sm]} /> {richText?.text ? ( <View @@ -329,27 +303,18 @@ let PostThreadItemLoaded = ({ styles.postTextLargeContainer, ]}> <RichText - type="post-text-lg" - richText={richText} - lineHeight={1.3} - style={s.flex1} + enableTags selectable + value={richText} + style={[a.flex_1, a.text_xl]} + authorHandle={post.author.handle} /> </View> ) : undefined} {post.embed && ( - <ContentHider - moderation={moderation.embed} - moderationDecisions={moderation.decisions} - ignoreMute={isEmbedByEmbedder(post.embed, post.author.did)} - ignoreQuoteDecisions - style={s.mb10}> - <PostEmbeds - embed={post.embed} - moderation={moderation.embed} - moderationDecisions={moderation.decisions} - /> - </ContentHider> + <View style={[a.pb_sm]}> + <PostEmbeds embed={post.embed} moderation={moderation} /> + </View> )} </ContentHider> <ExpandedPostDetails @@ -357,9 +322,16 @@ let PostThreadItemLoaded = ({ translatorUrl={translatorUrl} needsTranslation={needsTranslation} /> - {hasEngagement ? ( + {post.repostCount !== 0 || post.likeCount !== 0 ? ( + // Show this section unless we're *sure* it has no engagement. <View style={[styles.expandedInfo, pal.border]}> - {post.repostCount ? ( + {post.repostCount == null && post.likeCount == null && ( + // If we're still loading and not sure, assume this post has engagement. + // This lets us avoid a layout shift for the common case (embedded post with likes/reposts). + // TODO: embeds should include metrics to avoid us having to guess. + <LoadingPlaceholder width={50} height={20} /> + )} + {post.repostCount != null && post.repostCount !== 0 ? ( <Link style={styles.expandedInfoItem} href={repostsHref} @@ -374,10 +346,8 @@ let PostThreadItemLoaded = ({ {pluralize(post.repostCount, 'repost')} </Text> </Link> - ) : ( - <></> - )} - {post.likeCount ? ( + ) : null} + {post.likeCount != null && post.likeCount !== 0 ? ( <Link style={styles.expandedInfoItem} href={likesHref} @@ -392,13 +362,9 @@ let PostThreadItemLoaded = ({ {pluralize(post.likeCount, 'like')} </Text> </Link> - ) : ( - <></> - )} + ) : null} </View> - ) : ( - <></> - )} + ) : null} <View style={[s.pl10, s.pr10, s.pb5]}> <PostCtrls big @@ -406,6 +372,7 @@ let PostThreadItemLoaded = ({ record={record} richText={richText} onPressReply={onPressReply} + logContext="PostThreadItem" /> </View> </View> @@ -431,15 +398,13 @@ let PostThreadItemLoaded = ({ testID={`postThreadItem-by-${post.author.handle}`} href={postHref} style={[pal.view]} - moderation={moderation.content} + modui={moderation.ui('contentList')} iconSize={isThreadedChild ? 26 : 38} iconStyles={ isThreadedChild ? {marginRight: 4} : {marginLeft: 2, marginRight: 2} }> - <PostSandboxWarning /> - <View style={{ flexDirection: 'row', @@ -454,7 +419,7 @@ let PostThreadItemLoaded = ({ styles.replyLine, { flexGrow: 1, - backgroundColor: pal.colors.border, + backgroundColor: pal.colors.replyLine, marginBottom: 4, }, ]} @@ -483,7 +448,8 @@ let PostThreadItemLoaded = ({ did={post.author.did} handle={post.author.handle} avatar={post.author.avatar} - moderation={moderation.avatar} + moderation={moderation.ui('avatar')} + type={post.author.associated?.labeler ? 'labeler' : 'user'} /> {showChildReplyLine && ( @@ -492,7 +458,7 @@ let PostThreadItemLoaded = ({ styles.replyLine, { flexGrow: 1, - backgroundColor: pal.colors.border, + backgroundColor: pal.colors.replyLine, marginTop: 4, }, ]} @@ -509,28 +475,30 @@ let PostThreadItemLoaded = ({ }> <PostMeta author={post.author} + moderation={moderation} authorHasWarning={!!post.author.labels?.length} timestamp={post.indexedAt} postHref={postHref} showAvatar={isThreadedChild} - avatarModeration={moderation.avatar} + avatarModeration={moderation.ui('avatar')} avatarSize={28} displayNameType="md-bold" displayNameStyle={isThreadedChild && s.ml2} style={isThreadedChild && s.mb2} /> + <LabelsOnMyPost post={post} /> <PostAlerts - moderation={moderation.content} - style={styles.alert} + modui={moderation.ui('contentList')} + style={[a.pt_xs, a.pb_sm]} /> {richText?.text ? ( <View style={styles.postTextContainer}> <RichText - type="post-text" - richText={richText} - style={[pal.text, s.flex1]} - lineHeight={1.3} + enableTags + value={richText} + style={[a.flex_1, a.text_md]} numberOfLines={limitLines ? MAX_POST_LINES : undefined} + authorHandle={post.author.handle} /> </View> ) : undefined} @@ -543,24 +511,16 @@ let PostThreadItemLoaded = ({ /> ) : undefined} {post.embed && ( - <ContentHider - style={styles.contentHider} - moderation={moderation.embed} - moderationDecisions={moderation.decisions} - ignoreMute={isEmbedByEmbedder(post.embed, post.author.did)} - ignoreQuoteDecisions> - <PostEmbeds - embed={post.embed} - moderation={moderation.embed} - moderationDecisions={moderation.decisions} - /> - </ContentHider> + <View style={[a.pb_xs]}> + <PostEmbeds embed={post.embed} moderation={moderation} /> + </View> )} <PostCtrls post={post} record={record} richText={richText} onPressReply={onPressReply} + logContext="PostThreadItem" /> </View> </View> @@ -578,7 +538,7 @@ let PostThreadItemLoaded = ({ title={itemTitle} noFeedback> <Text type="sm-medium" style={pal.textLight}> - More + <Trans>More</Trans> </Text> <FontAwesomeIcon icon="angle-right" @@ -621,7 +581,6 @@ function PostOuterWrapper({ return ( <View style={[ - pal.view, pal.border, styles.cursor, { @@ -649,7 +608,6 @@ function PostOuterWrapper({ <View style={[ styles.outer, - pal.view, pal.border, showParentReplyLine && hasPrecedingItem && styles.noTopBorder, styles.cursor, |