Show just-posted replies above OP replies (#4901)

* Unify onPostReply handler

* Show just-posted replies above OP replies

* Only do this for the highlighted post or thread mode

It's confusing to have your post displace OP thread or other people's leaf posts.
zio/stable
dan 2024-08-08 19:19:58 +01:00 committed by GitHub
parent c1af767fa6
commit e782db33dc
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 53 additions and 10 deletions

View File

@ -137,6 +137,7 @@ export function sortThread(
opts: UsePreferencesQueryResponse['threadViewPrefs'], opts: UsePreferencesQueryResponse['threadViewPrefs'],
modCache: ThreadModerationCache, modCache: ThreadModerationCache,
currentDid: string | undefined, currentDid: string | undefined,
justPostedUris: Set<string>,
): ThreadNode { ): ThreadNode {
if (node.type !== 'post') { if (node.type !== 'post') {
return node return node
@ -150,6 +151,20 @@ export function sortThread(
return -1 return -1
} }
if (node.ctx.isHighlightedPost || opts.lab_treeViewEnabled) {
const aIsJustPosted =
a.post.author.did === currentDid && justPostedUris.has(a.post.uri)
const bIsJustPosted =
b.post.author.did === currentDid && justPostedUris.has(b.post.uri)
if (aIsJustPosted && bIsJustPosted) {
return a.post.indexedAt.localeCompare(b.post.indexedAt) // oldest
} else if (aIsJustPosted) {
return -1 // reply while onscreen
} else if (bIsJustPosted) {
return 1 // reply while onscreen
}
}
const aIsByOp = a.post.author.did === node.post?.author.did const aIsByOp = a.post.author.did === node.post?.author.did
const bIsByOp = b.post.author.did === node.post?.author.did const bIsByOp = b.post.author.did === node.post?.author.did
if (aIsByOp && bIsByOp) { if (aIsByOp && bIsByOp) {
@ -206,7 +221,9 @@ export function sortThread(
} }
return b.post.indexedAt.localeCompare(a.post.indexedAt) return b.post.indexedAt.localeCompare(a.post.indexedAt)
}) })
node.replies.forEach(reply => sortThread(reply, opts, modCache, currentDid)) node.replies.forEach(reply =>
sortThread(reply, opts, modCache, currentDid, justPostedUris),
)
} }
return node return node
} }

View File

@ -1,10 +1,11 @@
import React from 'react' import React from 'react'
import { import {
AppBskyActorDefs,
AppBskyEmbedRecord, AppBskyEmbedRecord,
AppBskyRichtextFacet, AppBskyRichtextFacet,
ModerationDecision, ModerationDecision,
AppBskyActorDefs,
} from '@atproto/api' } from '@atproto/api'
import {useNonReactiveCallback} from '#/lib/hooks/useNonReactiveCallback' import {useNonReactiveCallback} from '#/lib/hooks/useNonReactiveCallback'
export interface ComposerOptsPostRef { export interface ComposerOptsPostRef {
@ -31,7 +32,7 @@ export interface ComposerOptsQuote {
} }
export interface ComposerOpts { export interface ComposerOpts {
replyTo?: ComposerOptsPostRef replyTo?: ComposerOptsPostRef
onPost?: () => void onPost?: (postUri: string | undefined) => void
quote?: ComposerOptsQuote quote?: ComposerOptsQuote
mention?: string // handle of user to mention mention?: string // handle of user to mention
openPicker?: (pos: DOMRect | undefined) => void openPicker?: (pos: DOMRect | undefined) => void

View File

@ -392,7 +392,7 @@ export const ComposePost = observer(function ComposePost({
emitPostCreated() emitPostCreated()
} }
setLangPrefs.savePostLanguageToHistory() setLangPrefs.savePostLanguageToHistory()
onPost?.() onPost?.(postUri)
onClose() onClose()
Toast.show( Toast.show(
replyTo replyTo

View File

@ -160,12 +160,22 @@ export function PostThread({uri}: {uri: string | undefined}) {
return cache return cache
}, [thread, moderationOpts]) }, [thread, moderationOpts])
const [justPostedUris, setJustPostedUris] = React.useState(
() => new Set<string>(),
)
const skeleton = React.useMemo(() => { const skeleton = React.useMemo(() => {
const threadViewPrefs = preferences?.threadViewPrefs const threadViewPrefs = preferences?.threadViewPrefs
if (!threadViewPrefs || !thread) return null if (!threadViewPrefs || !thread) return null
return createThreadSkeleton( return createThreadSkeleton(
sortThread(thread, threadViewPrefs, threadModerationCache, currentDid), sortThread(
thread,
threadViewPrefs,
threadModerationCache,
currentDid,
justPostedUris,
),
!!currentDid, !!currentDid,
treeView, treeView,
threadModerationCache, threadModerationCache,
@ -178,6 +188,7 @@ export function PostThread({uri}: {uri: string | undefined}) {
treeView, treeView,
threadModerationCache, threadModerationCache,
hiddenRepliesState, hiddenRepliesState,
justPostedUris,
]) ])
const error = React.useMemo(() => { const error = React.useMemo(() => {
@ -302,6 +313,20 @@ export function PostThread({uri}: {uri: string | undefined}) {
setMaxReplies(prev => prev + 50) setMaxReplies(prev => prev + 50)
}, [isFetching, maxReplies, posts.length]) }, [isFetching, maxReplies, posts.length])
const onPostReply = React.useCallback(
(postUri: string | undefined) => {
refetch()
if (postUri) {
setJustPostedUris(set => {
const nextSet = new Set(set)
nextSet.add(postUri)
return nextSet
})
}
},
[refetch],
)
const {openComposer} = useComposerControls() const {openComposer} = useComposerControls()
const onPressReply = React.useCallback(() => { const onPressReply = React.useCallback(() => {
if (thread?.type !== 'post') { if (thread?.type !== 'post') {
@ -315,9 +340,9 @@ export function PostThread({uri}: {uri: string | undefined}) {
author: thread.post.author, author: thread.post.author,
embed: thread.post.embed, embed: thread.post.embed,
}, },
onPost: () => refetch(), onPost: onPostReply,
}) })
}, [openComposer, thread, refetch]) }, [openComposer, thread, onPostReply])
const canReply = !error && rootPost && !rootPost.viewer?.replyDisabled const canReply = !error && rootPost && !rootPost.viewer?.replyDisabled
const hasParents = const hasParents =
@ -415,7 +440,7 @@ export function PostThread({uri}: {uri: string | undefined}) {
HiddenRepliesState.ShowAndOverridePostHider && HiddenRepliesState.ShowAndOverridePostHider &&
item.ctx.depth > 0 item.ctx.depth > 0
} }
onPostReply={refetch} onPostReply={onPostReply}
hideTopBorder={index === 0 && !item.ctx.isParentLoading} hideTopBorder={index === 0 && !item.ctx.isParentLoading}
/> />
</View> </View>

View File

@ -75,7 +75,7 @@ export function PostThreadItem({
showParentReplyLine?: boolean showParentReplyLine?: boolean
hasPrecedingItem: boolean hasPrecedingItem: boolean
overrideBlur: boolean overrideBlur: boolean
onPostReply: () => void onPostReply: (postUri: string | undefined) => void
hideTopBorder?: boolean hideTopBorder?: boolean
}) { }) {
const postShadowed = usePostShadow(post) const postShadowed = usePostShadow(post)
@ -169,7 +169,7 @@ let PostThreadItemLoaded = ({
showParentReplyLine?: boolean showParentReplyLine?: boolean
hasPrecedingItem: boolean hasPrecedingItem: boolean
overrideBlur: boolean overrideBlur: boolean
onPostReply: () => void onPostReply: (postUri: string | undefined) => void
hideTopBorder?: boolean hideTopBorder?: boolean
}): React.ReactNode => { }): React.ReactNode => {
const pal = usePalette('default') const pal = usePalette('default')