Refactor post threads to use react query (#1851)
* Add post and post-thread queries * Update PostThread components to use new queries * Move from normalized cache to shadow cache model * Merge post shadow into the post automatically * Remove dead code * Remove old temporary session * Fix: set agent on session creation * Temporarily double-login * Handle post-thread uri resolution errors
This commit is contained in:
parent
625cbc435f
commit
fb4f5709c4
12 changed files with 1386 additions and 476 deletions
|
@ -1,18 +1,17 @@
|
|||
import React, {useMemo} from 'react'
|
||||
import {observer} from 'mobx-react-lite'
|
||||
import {Linking, StyleSheet, View} from 'react-native'
|
||||
import Clipboard from '@react-native-clipboard/clipboard'
|
||||
import {AtUri, AppBskyFeedDefs} from '@atproto/api'
|
||||
import {StyleSheet, View} from 'react-native'
|
||||
import {
|
||||
FontAwesomeIcon,
|
||||
FontAwesomeIconStyle,
|
||||
} from '@fortawesome/react-native-fontawesome'
|
||||
import {PostThreadItemModel} from 'state/models/content/post-thread-item'
|
||||
AtUri,
|
||||
AppBskyFeedDefs,
|
||||
AppBskyFeedPost,
|
||||
RichText as RichTextAPI,
|
||||
moderatePost,
|
||||
PostModeration,
|
||||
} from '@atproto/api'
|
||||
import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome'
|
||||
import {Link, TextLink} from '../util/Link'
|
||||
import {RichText} from '../util/text/RichText'
|
||||
import {Text} from '../util/text/Text'
|
||||
import {PostDropdownBtn} from '../util/forms/PostDropdownBtn'
|
||||
import * as Toast from '../util/Toast'
|
||||
import {PreviewableUserAvatar} from '../util/UserAvatar'
|
||||
import {s} from 'lib/styles'
|
||||
import {niceDate} from 'lib/strings/time'
|
||||
|
@ -24,7 +23,8 @@ import {getTranslatorLink, isPostInLanguage} from '../../../locale/helpers'
|
|||
import {useStores} from 'state/index'
|
||||
import {PostMeta} from '../util/PostMeta'
|
||||
import {PostEmbeds} from '../util/post-embeds'
|
||||
import {PostCtrls} from '../util/post-ctrls/PostCtrls'
|
||||
import {PostCtrls} from '../util/post-ctrls/PostCtrls2'
|
||||
import {PostDropdownBtn} from '../util/forms/PostDropdownBtn2'
|
||||
import {PostHider} from '../util/moderation/PostHider'
|
||||
import {ContentHider} from '../util/moderation/ContentHider'
|
||||
import {PostAlerts} from '../util/moderation/PostAlerts'
|
||||
|
@ -36,54 +36,145 @@ import {TimeElapsed} from 'view/com/util/TimeElapsed'
|
|||
import {makeProfileLink} from 'lib/routes/links'
|
||||
import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries'
|
||||
import {MAX_POST_LINES} from 'lib/constants'
|
||||
import {logger} from '#/logger'
|
||||
import {Trans} from '@lingui/macro'
|
||||
import {useMutedThreads, useToggleThreadMute} from '#/state/muted-threads'
|
||||
import {useLanguagePrefs} from '#/state/preferences'
|
||||
import {usePostShadow, POST_TOMBSTONE} from '#/state/cache/post-shadow'
|
||||
|
||||
export const PostThreadItem = observer(function PostThreadItem({
|
||||
item,
|
||||
onPostReply,
|
||||
hasPrecedingItem,
|
||||
export function PostThreadItem({
|
||||
post,
|
||||
record,
|
||||
dataUpdatedAt,
|
||||
treeView,
|
||||
depth,
|
||||
isHighlightedPost,
|
||||
hasMore,
|
||||
showChildReplyLine,
|
||||
showParentReplyLine,
|
||||
hasPrecedingItem,
|
||||
onPostReply,
|
||||
}: {
|
||||
item: PostThreadItemModel
|
||||
onPostReply: () => void
|
||||
hasPrecedingItem: boolean
|
||||
post: AppBskyFeedDefs.PostView
|
||||
record: AppBskyFeedPost.Record
|
||||
dataUpdatedAt: number
|
||||
treeView: boolean
|
||||
depth: number
|
||||
isHighlightedPost?: boolean
|
||||
hasMore?: boolean
|
||||
showChildReplyLine?: boolean
|
||||
showParentReplyLine?: boolean
|
||||
hasPrecedingItem: boolean
|
||||
onPostReply: () => void
|
||||
}) {
|
||||
const store = useStores()
|
||||
const postShadowed = usePostShadow(post, dataUpdatedAt)
|
||||
const richText = useMemo(
|
||||
() =>
|
||||
post &&
|
||||
AppBskyFeedPost.isRecord(post?.record) &&
|
||||
AppBskyFeedPost.validateRecord(post?.record).success
|
||||
? new RichTextAPI({
|
||||
text: post.record.text,
|
||||
facets: post.record.facets,
|
||||
})
|
||||
: undefined,
|
||||
[post],
|
||||
)
|
||||
const moderation = useMemo(
|
||||
() =>
|
||||
post ? moderatePost(post, store.preferences.moderationOpts) : undefined,
|
||||
[post, store],
|
||||
)
|
||||
if (postShadowed === POST_TOMBSTONE) {
|
||||
return <PostThreadItemDeleted />
|
||||
}
|
||||
if (richText && moderation) {
|
||||
return (
|
||||
<PostThreadItemLoaded
|
||||
post={postShadowed}
|
||||
record={record}
|
||||
richText={richText}
|
||||
moderation={moderation}
|
||||
treeView={treeView}
|
||||
depth={depth}
|
||||
isHighlightedPost={isHighlightedPost}
|
||||
hasMore={hasMore}
|
||||
showChildReplyLine={showChildReplyLine}
|
||||
showParentReplyLine={showParentReplyLine}
|
||||
hasPrecedingItem={hasPrecedingItem}
|
||||
onPostReply={onPostReply}
|
||||
/>
|
||||
)
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
function PostThreadItemDeleted() {
|
||||
const styles = useStyles()
|
||||
const pal = usePalette('default')
|
||||
return (
|
||||
<View style={[styles.outer, pal.border, pal.view, s.p20, s.flexRow]}>
|
||||
<FontAwesomeIcon icon={['far', 'trash-can']} color={pal.colors.icon} />
|
||||
<Text style={[pal.textLight, s.ml10]}>
|
||||
<Trans>This post has been deleted.</Trans>
|
||||
</Text>
|
||||
</View>
|
||||
)
|
||||
}
|
||||
|
||||
function PostThreadItemLoaded({
|
||||
post,
|
||||
record,
|
||||
richText,
|
||||
moderation,
|
||||
treeView,
|
||||
depth,
|
||||
isHighlightedPost,
|
||||
hasMore,
|
||||
showChildReplyLine,
|
||||
showParentReplyLine,
|
||||
hasPrecedingItem,
|
||||
onPostReply,
|
||||
}: {
|
||||
post: AppBskyFeedDefs.PostView
|
||||
record: AppBskyFeedPost.Record
|
||||
richText: RichTextAPI
|
||||
moderation: PostModeration
|
||||
treeView: boolean
|
||||
depth: number
|
||||
isHighlightedPost?: boolean
|
||||
hasMore?: boolean
|
||||
showChildReplyLine?: boolean
|
||||
showParentReplyLine?: boolean
|
||||
hasPrecedingItem: boolean
|
||||
onPostReply: () => void
|
||||
}) {
|
||||
const pal = usePalette('default')
|
||||
const store = useStores()
|
||||
const mutedThreads = useMutedThreads()
|
||||
const toggleThreadMute = useToggleThreadMute()
|
||||
const langPrefs = useLanguagePrefs()
|
||||
const [deleted, setDeleted] = React.useState(false)
|
||||
const [limitLines, setLimitLines] = React.useState(
|
||||
countLines(item.richText?.text) >= MAX_POST_LINES,
|
||||
countLines(richText?.text) >= MAX_POST_LINES,
|
||||
)
|
||||
const styles = useStyles()
|
||||
const record = item.postRecord
|
||||
const hasEngagement = item.post.likeCount || item.post.repostCount
|
||||
const hasEngagement = post.likeCount || post.repostCount
|
||||
|
||||
const itemUri = item.post.uri
|
||||
const itemCid = item.post.cid
|
||||
const itemHref = React.useMemo(() => {
|
||||
const urip = new AtUri(item.post.uri)
|
||||
return makeProfileLink(item.post.author, 'post', urip.rkey)
|
||||
}, [item.post.uri, item.post.author])
|
||||
const itemTitle = `Post by ${item.post.author.handle}`
|
||||
const authorHref = makeProfileLink(item.post.author)
|
||||
const authorTitle = item.post.author.handle
|
||||
const isAuthorMuted = item.post.author.viewer?.muted
|
||||
const rootUri = record.reply?.root?.uri || post.uri
|
||||
const postHref = React.useMemo(() => {
|
||||
const urip = new AtUri(post.uri)
|
||||
return makeProfileLink(post.author, 'post', urip.rkey)
|
||||
}, [post.uri, post.author])
|
||||
const itemTitle = `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(item.post.uri)
|
||||
return makeProfileLink(item.post.author, 'post', urip.rkey, 'liked-by')
|
||||
}, [item.post.uri, item.post.author])
|
||||
const urip = new AtUri(post.uri)
|
||||
return makeProfileLink(post.author, 'post', urip.rkey, 'liked-by')
|
||||
}, [post.uri, post.author])
|
||||
const likesTitle = 'Likes on this post'
|
||||
const repostsHref = React.useMemo(() => {
|
||||
const urip = new AtUri(item.post.uri)
|
||||
return makeProfileLink(item.post.author, 'post', urip.rkey, 'reposted-by')
|
||||
}, [item.post.uri, item.post.author])
|
||||
const urip = new AtUri(post.uri)
|
||||
return makeProfileLink(post.author, 'post', urip.rkey, 'reposted-by')
|
||||
}, [post.uri, post.author])
|
||||
const repostsTitle = 'Reposts of this post'
|
||||
|
||||
const translatorUrl = getTranslatorLink(
|
||||
|
@ -94,73 +185,26 @@ export const PostThreadItem = observer(function PostThreadItem({
|
|||
() =>
|
||||
Boolean(
|
||||
langPrefs.primaryLanguage &&
|
||||
!isPostInLanguage(item.post, [langPrefs.primaryLanguage]),
|
||||
!isPostInLanguage(post, [langPrefs.primaryLanguage]),
|
||||
),
|
||||
[item.post, langPrefs.primaryLanguage],
|
||||
[post, langPrefs.primaryLanguage],
|
||||
)
|
||||
|
||||
const onPressReply = React.useCallback(() => {
|
||||
store.shell.openComposer({
|
||||
replyTo: {
|
||||
uri: item.post.uri,
|
||||
cid: item.post.cid,
|
||||
text: record?.text as string,
|
||||
uri: post.uri,
|
||||
cid: post.cid,
|
||||
text: record.text,
|
||||
author: {
|
||||
handle: item.post.author.handle,
|
||||
displayName: item.post.author.displayName,
|
||||
avatar: item.post.author.avatar,
|
||||
handle: post.author.handle,
|
||||
displayName: post.author.displayName,
|
||||
avatar: post.author.avatar,
|
||||
},
|
||||
},
|
||||
onPost: onPostReply,
|
||||
})
|
||||
}, [store, item, record, onPostReply])
|
||||
|
||||
const onPressToggleRepost = React.useCallback(() => {
|
||||
return item
|
||||
.toggleRepost()
|
||||
.catch(e => logger.error('Failed to toggle repost', {error: e}))
|
||||
}, [item])
|
||||
|
||||
const onPressToggleLike = React.useCallback(() => {
|
||||
return item
|
||||
.toggleLike()
|
||||
.catch(e => logger.error('Failed to toggle like', {error: e}))
|
||||
}, [item])
|
||||
|
||||
const onCopyPostText = React.useCallback(() => {
|
||||
Clipboard.setString(record?.text || '')
|
||||
Toast.show('Copied to clipboard')
|
||||
}, [record])
|
||||
|
||||
const onOpenTranslate = React.useCallback(() => {
|
||||
Linking.openURL(translatorUrl)
|
||||
}, [translatorUrl])
|
||||
|
||||
const onToggleThreadMute = React.useCallback(() => {
|
||||
try {
|
||||
const muted = toggleThreadMute(item.data.rootUri)
|
||||
if (muted) {
|
||||
Toast.show('You will no longer receive notifications for this thread')
|
||||
} else {
|
||||
Toast.show('You will now receive notifications for this thread')
|
||||
}
|
||||
} catch (e) {
|
||||
logger.error('Failed to toggle thread mute', {error: e})
|
||||
}
|
||||
}, [item, toggleThreadMute])
|
||||
|
||||
const onDeletePost = React.useCallback(() => {
|
||||
item.delete().then(
|
||||
() => {
|
||||
setDeleted(true)
|
||||
Toast.show('Post deleted')
|
||||
},
|
||||
e => {
|
||||
logger.error('Failed to delete post', {error: e})
|
||||
Toast.show('Failed to delete post, please try again')
|
||||
},
|
||||
)
|
||||
}, [item])
|
||||
}, [store, post, record, onPostReply])
|
||||
|
||||
const onPressShowMore = React.useCallback(() => {
|
||||
setLimitLines(false)
|
||||
|
@ -170,24 +214,10 @@ export const PostThreadItem = observer(function PostThreadItem({
|
|||
return <ErrorMessage message="Invalid or unsupported post record" />
|
||||
}
|
||||
|
||||
if (deleted) {
|
||||
return (
|
||||
<View style={[styles.outer, pal.border, pal.view, s.p20, s.flexRow]}>
|
||||
<FontAwesomeIcon
|
||||
icon={['far', 'trash-can']}
|
||||
style={pal.icon as FontAwesomeIconStyle}
|
||||
/>
|
||||
<Text style={[pal.textLight, s.ml10]}>
|
||||
<Trans>This post has been deleted.</Trans>
|
||||
</Text>
|
||||
</View>
|
||||
)
|
||||
}
|
||||
|
||||
if (item._isHighlightedPost) {
|
||||
if (isHighlightedPost) {
|
||||
return (
|
||||
<>
|
||||
{item.rootUri !== item.uri && (
|
||||
{rootUri !== post.uri && (
|
||||
<View style={{paddingLeft: 16, flexDirection: 'row', height: 16}}>
|
||||
<View style={{width: 38}}>
|
||||
<View
|
||||
|
@ -204,7 +234,7 @@ export const PostThreadItem = observer(function PostThreadItem({
|
|||
)}
|
||||
|
||||
<Link
|
||||
testID={`postThreadItem-by-${item.post.author.handle}`}
|
||||
testID={`postThreadItem-by-${post.author.handle}`}
|
||||
style={[styles.outer, styles.outerHighlighted, pal.border, pal.view]}
|
||||
noFeedback
|
||||
accessible={false}>
|
||||
|
@ -213,10 +243,10 @@ export const PostThreadItem = observer(function PostThreadItem({
|
|||
<View style={[styles.layoutAvi, {paddingBottom: 8}]}>
|
||||
<PreviewableUserAvatar
|
||||
size={52}
|
||||
did={item.post.author.did}
|
||||
handle={item.post.author.handle}
|
||||
avatar={item.post.author.avatar}
|
||||
moderation={item.moderation.avatar}
|
||||
did={post.author.did}
|
||||
handle={post.author.handle}
|
||||
avatar={post.author.avatar}
|
||||
moderation={moderation.avatar}
|
||||
/>
|
||||
</View>
|
||||
<View style={styles.layoutContent}>
|
||||
|
@ -233,17 +263,17 @@ export const PostThreadItem = observer(function PostThreadItem({
|
|||
numberOfLines={1}
|
||||
lineHeight={1.2}>
|
||||
{sanitizeDisplayName(
|
||||
item.post.author.displayName ||
|
||||
sanitizeHandle(item.post.author.handle),
|
||||
post.author.displayName ||
|
||||
sanitizeHandle(post.author.handle),
|
||||
)}
|
||||
</Text>
|
||||
</Link>
|
||||
<TimeElapsed timestamp={item.post.indexedAt}>
|
||||
<TimeElapsed timestamp={post.indexedAt}>
|
||||
{({timeElapsed}) => (
|
||||
<Text
|
||||
type="md"
|
||||
style={[styles.metaItem, pal.textLight]}
|
||||
title={niceDate(item.post.indexedAt)}>
|
||||
title={niceDate(post.indexedAt)}>
|
||||
· {timeElapsed}
|
||||
</Text>
|
||||
)}
|
||||
|
@ -280,23 +310,15 @@ export const PostThreadItem = observer(function PostThreadItem({
|
|||
href={authorHref}
|
||||
title={authorTitle}>
|
||||
<Text type="md" style={[pal.textLight]} numberOfLines={1}>
|
||||
{sanitizeHandle(item.post.author.handle, '@')}
|
||||
{sanitizeHandle(post.author.handle, '@')}
|
||||
</Text>
|
||||
</Link>
|
||||
</View>
|
||||
</View>
|
||||
<PostDropdownBtn
|
||||
testID="postDropdownBtn"
|
||||
itemUri={itemUri}
|
||||
itemCid={itemCid}
|
||||
itemHref={itemHref}
|
||||
itemTitle={itemTitle}
|
||||
isAuthor={item.post.author.did === store.me.did}
|
||||
isThreadMuted={mutedThreads.includes(item.data.rootUri)}
|
||||
onCopyPostText={onCopyPostText}
|
||||
onOpenTranslate={onOpenTranslate}
|
||||
onToggleThreadMute={onToggleThreadMute}
|
||||
onDeletePost={onDeletePost}
|
||||
post={post}
|
||||
record={record}
|
||||
style={{
|
||||
paddingVertical: 6,
|
||||
paddingHorizontal: 10,
|
||||
|
@ -307,16 +329,16 @@ export const PostThreadItem = observer(function PostThreadItem({
|
|||
</View>
|
||||
<View style={[s.pl10, s.pr10, s.pb10]}>
|
||||
<ContentHider
|
||||
moderation={item.moderation.content}
|
||||
moderation={moderation.content}
|
||||
ignoreMute
|
||||
style={styles.contentHider}
|
||||
childContainerStyle={styles.contentHiderChild}>
|
||||
<PostAlerts
|
||||
moderation={item.moderation.content}
|
||||
moderation={moderation.content}
|
||||
includeMute
|
||||
style={styles.alert}
|
||||
/>
|
||||
{item.richText?.text ? (
|
||||
{richText?.text ? (
|
||||
<View
|
||||
style={[
|
||||
styles.postTextContainer,
|
||||
|
@ -324,59 +346,56 @@ export const PostThreadItem = observer(function PostThreadItem({
|
|||
]}>
|
||||
<RichText
|
||||
type="post-text-lg"
|
||||
richText={item.richText}
|
||||
richText={richText}
|
||||
lineHeight={1.3}
|
||||
style={s.flex1}
|
||||
/>
|
||||
</View>
|
||||
) : undefined}
|
||||
{item.post.embed && (
|
||||
{post.embed && (
|
||||
<ContentHider
|
||||
moderation={item.moderation.embed}
|
||||
ignoreMute={isEmbedByEmbedder(
|
||||
item.post.embed,
|
||||
item.post.author.did,
|
||||
)}
|
||||
moderation={moderation.embed}
|
||||
ignoreMute={isEmbedByEmbedder(post.embed, post.author.did)}
|
||||
style={s.mb10}>
|
||||
<PostEmbeds
|
||||
embed={item.post.embed}
|
||||
moderation={item.moderation.embed}
|
||||
embed={post.embed}
|
||||
moderation={moderation.embed}
|
||||
/>
|
||||
</ContentHider>
|
||||
)}
|
||||
</ContentHider>
|
||||
<ExpandedPostDetails
|
||||
post={item.post}
|
||||
post={post}
|
||||
translatorUrl={translatorUrl}
|
||||
needsTranslation={needsTranslation}
|
||||
/>
|
||||
{hasEngagement ? (
|
||||
<View style={[styles.expandedInfo, pal.border]}>
|
||||
{item.post.repostCount ? (
|
||||
{post.repostCount ? (
|
||||
<Link
|
||||
style={styles.expandedInfoItem}
|
||||
href={repostsHref}
|
||||
title={repostsTitle}>
|
||||
<Text testID="repostCount" type="lg" style={pal.textLight}>
|
||||
<Text type="xl-bold" style={pal.text}>
|
||||
{formatCount(item.post.repostCount)}
|
||||
{formatCount(post.repostCount)}
|
||||
</Text>{' '}
|
||||
{pluralize(item.post.repostCount, 'repost')}
|
||||
{pluralize(post.repostCount, 'repost')}
|
||||
</Text>
|
||||
</Link>
|
||||
) : (
|
||||
<></>
|
||||
)}
|
||||
{item.post.likeCount ? (
|
||||
{post.likeCount ? (
|
||||
<Link
|
||||
style={styles.expandedInfoItem}
|
||||
href={likesHref}
|
||||
title={likesTitle}>
|
||||
<Text testID="likeCount" type="lg" style={pal.textLight}>
|
||||
<Text type="xl-bold" style={pal.text}>
|
||||
{formatCount(item.post.likeCount)}
|
||||
{formatCount(post.likeCount)}
|
||||
</Text>{' '}
|
||||
{pluralize(item.post.likeCount, 'like')}
|
||||
{pluralize(post.likeCount, 'like')}
|
||||
</Text>
|
||||
</Link>
|
||||
) : (
|
||||
|
@ -389,24 +408,9 @@ export const PostThreadItem = observer(function PostThreadItem({
|
|||
<View style={[s.pl10, s.pb5]}>
|
||||
<PostCtrls
|
||||
big
|
||||
itemUri={itemUri}
|
||||
itemCid={itemCid}
|
||||
itemHref={itemHref}
|
||||
itemTitle={itemTitle}
|
||||
author={item.post.author}
|
||||
text={item.richText?.text || record.text}
|
||||
indexedAt={item.post.indexedAt}
|
||||
isAuthor={item.post.author.did === store.me.did}
|
||||
isReposted={!!item.post.viewer?.repost}
|
||||
isLiked={!!item.post.viewer?.like}
|
||||
isThreadMuted={mutedThreads.includes(item.data.rootUri)}
|
||||
post={post}
|
||||
record={record}
|
||||
onPressReply={onPressReply}
|
||||
onPressToggleRepost={onPressToggleRepost}
|
||||
onPressToggleLike={onPressToggleLike}
|
||||
onCopyPostText={onCopyPostText}
|
||||
onOpenTranslate={onOpenTranslate}
|
||||
onToggleThreadMute={onToggleThreadMute}
|
||||
onDeletePost={onDeletePost}
|
||||
/>
|
||||
</View>
|
||||
</View>
|
||||
|
@ -414,17 +418,19 @@ export const PostThreadItem = observer(function PostThreadItem({
|
|||
</>
|
||||
)
|
||||
} else {
|
||||
const isThreadedChild = treeView && item._depth > 1
|
||||
const isThreadedChild = treeView && depth > 1
|
||||
return (
|
||||
<PostOuterWrapper
|
||||
item={item}
|
||||
hasPrecedingItem={hasPrecedingItem}
|
||||
treeView={treeView}>
|
||||
post={post}
|
||||
depth={depth}
|
||||
showParentReplyLine={!!showParentReplyLine}
|
||||
treeView={treeView}
|
||||
hasPrecedingItem={hasPrecedingItem}>
|
||||
<PostHider
|
||||
testID={`postThreadItem-by-${item.post.author.handle}`}
|
||||
href={itemHref}
|
||||
testID={`postThreadItem-by-${post.author.handle}`}
|
||||
href={postHref}
|
||||
style={[pal.view]}
|
||||
moderation={item.moderation.content}>
|
||||
moderation={moderation.content}>
|
||||
<PostSandboxWarning />
|
||||
|
||||
<View
|
||||
|
@ -435,7 +441,7 @@ export const PostThreadItem = observer(function PostThreadItem({
|
|||
height: isThreadedChild ? 8 : 16,
|
||||
}}>
|
||||
<View style={{width: 38}}>
|
||||
{!isThreadedChild && item._showParentReplyLine && (
|
||||
{!isThreadedChild && showParentReplyLine && (
|
||||
<View
|
||||
style={[
|
||||
styles.replyLine,
|
||||
|
@ -454,21 +460,20 @@ export const PostThreadItem = observer(function PostThreadItem({
|
|||
style={[
|
||||
styles.layout,
|
||||
{
|
||||
paddingBottom:
|
||||
item._showChildReplyLine && !isThreadedChild ? 0 : 8,
|
||||
paddingBottom: showChildReplyLine && !isThreadedChild ? 0 : 8,
|
||||
},
|
||||
]}>
|
||||
{!isThreadedChild && (
|
||||
<View style={styles.layoutAvi}>
|
||||
<PreviewableUserAvatar
|
||||
size={38}
|
||||
did={item.post.author.did}
|
||||
handle={item.post.author.handle}
|
||||
avatar={item.post.author.avatar}
|
||||
moderation={item.moderation.avatar}
|
||||
did={post.author.did}
|
||||
handle={post.author.handle}
|
||||
avatar={post.author.avatar}
|
||||
moderation={moderation.avatar}
|
||||
/>
|
||||
|
||||
{item._showChildReplyLine && (
|
||||
{showChildReplyLine && (
|
||||
<View
|
||||
style={[
|
||||
styles.replyLine,
|
||||
|
@ -485,10 +490,10 @@ export const PostThreadItem = observer(function PostThreadItem({
|
|||
|
||||
<View style={styles.layoutContent}>
|
||||
<PostMeta
|
||||
author={item.post.author}
|
||||
authorHasWarning={!!item.post.author.labels?.length}
|
||||
timestamp={item.post.indexedAt}
|
||||
postHref={itemHref}
|
||||
author={post.author}
|
||||
authorHasWarning={!!post.author.labels?.length}
|
||||
timestamp={post.indexedAt}
|
||||
postHref={postHref}
|
||||
showAvatar={isThreadedChild}
|
||||
avatarSize={26}
|
||||
displayNameType="md-bold"
|
||||
|
@ -496,14 +501,14 @@ export const PostThreadItem = observer(function PostThreadItem({
|
|||
style={isThreadedChild && s.mb5}
|
||||
/>
|
||||
<PostAlerts
|
||||
moderation={item.moderation.content}
|
||||
moderation={moderation.content}
|
||||
style={styles.alert}
|
||||
/>
|
||||
{item.richText?.text ? (
|
||||
{richText?.text ? (
|
||||
<View style={styles.postTextContainer}>
|
||||
<RichText
|
||||
type="post-text"
|
||||
richText={item.richText}
|
||||
richText={richText}
|
||||
style={[pal.text, s.flex1]}
|
||||
lineHeight={1.3}
|
||||
numberOfLines={limitLines ? MAX_POST_LINES : undefined}
|
||||
|
@ -518,42 +523,24 @@ export const PostThreadItem = observer(function PostThreadItem({
|
|||
href="#"
|
||||
/>
|
||||
) : undefined}
|
||||
{item.post.embed && (
|
||||
{post.embed && (
|
||||
<ContentHider
|
||||
style={styles.contentHider}
|
||||
moderation={item.moderation.embed}>
|
||||
moderation={moderation.embed}>
|
||||
<PostEmbeds
|
||||
embed={item.post.embed}
|
||||
moderation={item.moderation.embed}
|
||||
embed={post.embed}
|
||||
moderation={moderation.embed}
|
||||
/>
|
||||
</ContentHider>
|
||||
)}
|
||||
<PostCtrls
|
||||
itemUri={itemUri}
|
||||
itemCid={itemCid}
|
||||
itemHref={itemHref}
|
||||
itemTitle={itemTitle}
|
||||
author={item.post.author}
|
||||
text={item.richText?.text || record.text}
|
||||
indexedAt={item.post.indexedAt}
|
||||
isAuthor={item.post.author.did === store.me.did}
|
||||
replyCount={item.post.replyCount}
|
||||
repostCount={item.post.repostCount}
|
||||
likeCount={item.post.likeCount}
|
||||
isReposted={!!item.post.viewer?.repost}
|
||||
isLiked={!!item.post.viewer?.like}
|
||||
isThreadMuted={mutedThreads.includes(item.data.rootUri)}
|
||||
post={post}
|
||||
record={record}
|
||||
onPressReply={onPressReply}
|
||||
onPressToggleRepost={onPressToggleRepost}
|
||||
onPressToggleLike={onPressToggleLike}
|
||||
onCopyPostText={onCopyPostText}
|
||||
onOpenTranslate={onOpenTranslate}
|
||||
onToggleThreadMute={onToggleThreadMute}
|
||||
onDeletePost={onDeletePost}
|
||||
/>
|
||||
</View>
|
||||
</View>
|
||||
{item._hasMore ? (
|
||||
{hasMore ? (
|
||||
<Link
|
||||
style={[
|
||||
styles.loadMore,
|
||||
|
@ -563,7 +550,7 @@ export const PostThreadItem = observer(function PostThreadItem({
|
|||
paddingBottom: treeView ? 4 : 12,
|
||||
},
|
||||
]}
|
||||
href={itemHref}
|
||||
href={postHref}
|
||||
title={itemTitle}
|
||||
noFeedback>
|
||||
<Text type="sm-medium" style={pal.textLight}>
|
||||
|
@ -580,22 +567,26 @@ export const PostThreadItem = observer(function PostThreadItem({
|
|||
</PostOuterWrapper>
|
||||
)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
function PostOuterWrapper({
|
||||
item,
|
||||
hasPrecedingItem,
|
||||
post,
|
||||
treeView,
|
||||
depth,
|
||||
showParentReplyLine,
|
||||
hasPrecedingItem,
|
||||
children,
|
||||
}: React.PropsWithChildren<{
|
||||
item: PostThreadItemModel
|
||||
hasPrecedingItem: boolean
|
||||
post: AppBskyFeedDefs.PostView
|
||||
treeView: boolean
|
||||
depth: number
|
||||
showParentReplyLine: boolean
|
||||
hasPrecedingItem: boolean
|
||||
}>) {
|
||||
const {isMobile} = useWebMediaQueries()
|
||||
const pal = usePalette('default')
|
||||
const styles = useStyles()
|
||||
if (treeView && item._depth > 1) {
|
||||
if (treeView && depth > 1) {
|
||||
return (
|
||||
<View
|
||||
style={[
|
||||
|
@ -605,13 +596,13 @@ function PostOuterWrapper({
|
|||
{
|
||||
flexDirection: 'row',
|
||||
paddingLeft: 20,
|
||||
borderTopWidth: item._depth === 1 ? 1 : 0,
|
||||
paddingTop: item._depth === 1 ? 8 : 0,
|
||||
borderTopWidth: depth === 1 ? 1 : 0,
|
||||
paddingTop: depth === 1 ? 8 : 0,
|
||||
},
|
||||
]}>
|
||||
{Array.from(Array(item._depth - 1)).map((_, n: number) => (
|
||||
{Array.from(Array(depth - 1)).map((_, n: number) => (
|
||||
<View
|
||||
key={`${item.uri}-padding-${n}`}
|
||||
key={`${post.uri}-padding-${n}`}
|
||||
style={{
|
||||
borderLeftWidth: 2,
|
||||
borderLeftColor: pal.colors.border,
|
||||
|
@ -630,7 +621,7 @@ function PostOuterWrapper({
|
|||
styles.outer,
|
||||
pal.view,
|
||||
pal.border,
|
||||
item._showParentReplyLine && hasPrecedingItem && styles.noTopBorder,
|
||||
showParentReplyLine && hasPrecedingItem && styles.noTopBorder,
|
||||
styles.cursor,
|
||||
]}>
|
||||
{children}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue