Fix up traversal metadata

This commit is contained in:
Eric Bailey
2025-05-27 20:50:04 -05:00
parent e5cc0c0ed2
commit 1f73c05195
5 changed files with 58 additions and 27 deletions
@@ -4,7 +4,7 @@ import {useLingui} from '@lingui/react'
import {makeProfileLink} from '#/lib/routes/links' import {makeProfileLink} from '#/lib/routes/links'
import {type PostThreadParams, type Slice} from '#/state/queries/usePostThread' import {type PostThreadParams, type Slice} from '#/state/queries/usePostThread'
import {TREE_AVI_WIDTH,TREE_INDENT} from '#/screens/PostThread/const' import {TREE_AVI_WIDTH, TREE_INDENT} from '#/screens/PostThread/const'
import {atoms as a, useTheme} from '#/alf' import {atoms as a, useTheme} from '#/alf'
import {CirclePlus_Stroke2_Corner0_Rounded as CirclePlus} from '#/components/icons/CirclePlus' import {CirclePlus_Stroke2_Corner0_Rounded as CirclePlus} from '#/components/icons/CirclePlus'
import {Link} from '#/components/Link' import {Link} from '#/components/Link'
@@ -20,7 +20,7 @@ export function ReadMore({
const t = useTheme() const t = useTheme()
const {_} = useLingui() const {_} = useLingui()
const isTreeView = view === 'tree' const isTreeView = view === 'tree'
const indentCount = item.indent - 1 const indentCount = Math.max(0, item.indent - 1)
const treeIndents = isTreeView ? ( const treeIndents = isTreeView ? (
Array.from(Array(indentCount)).map((_, n: number) => ( Array.from(Array(indentCount)).map((_, n: number) => (
+16 -4
View File
@@ -8,7 +8,12 @@ import {
HiddenReplyKind, HiddenReplyKind,
type PostThreadParams, type PostThreadParams,
type Slice, type Slice,
type TraversalMetadata,
} from '#/state/queries/usePostThread/types' } from '#/state/queries/usePostThread/types'
import {
getPostRecord,
getPostTraversalMetadata,
} from '#/state/queries/usePostThread/utils'
import * as views from '#/state/queries/usePostThread/views' import * as views from '#/state/queries/usePostThread/views'
export function flatten( export function flatten(
@@ -168,6 +173,7 @@ export function sort(
const items: Slice[] = [] const items: Slice[] = []
const hidden: Slice[] = [] const hidden: Slice[] = []
const muted: Slice[] = [] const muted: Slice[] = []
const postDataMap = new Map<string, TraversalMetadata | undefined>()
traversal: for (let i = 0; i < thread.length; i++) { traversal: for (let i = 0; i < thread.length; i++) {
const item = thread[i] const item = thread[i]
@@ -193,6 +199,8 @@ export function sort(
) { ) {
items.push(views.threadPostBlocked(item)) items.push(views.threadPostBlocked(item))
} else if (AppBskyUnspeccedGetPostThreadV2.isThreadItemPost(item.value)) { } else if (AppBskyUnspeccedGetPostThreadV2.isThreadItemPost(item.value)) {
postDataMap.set(item.uri, getPostTraversalMetadata(item))
items.push( items.push(
views.threadPost({ views.threadPost({
uri: item.uri, uri: item.uri,
@@ -261,14 +269,16 @@ export function sort(
i = branch.end i = branch.end
continue traversal continue traversal
} else if (AppBskyUnspeccedGetPostThreadV2.isThreadItemPost(item.value)) { } else if (AppBskyUnspeccedGetPostThreadV2.isThreadItemPost(item.value)) {
postDataMap.set(item.uri, getPostTraversalMetadata(item))
const oneUp = thread.at(i - 1) const oneUp = thread.at(i - 1)
const oneDown = thread.at(i + 1) const oneDown = thread.at(i + 1)
const post = views.threadPost({ const post = views.threadPost({
uri: item.uri, uri: item.uri,
depth: item.depth, depth: item.depth,
value: item.value, value: item.value,
parent: thread.find( traversalMetadata: postDataMap.get(
p => p.uri === item.value.post.record.reply.parent.uri, getPostRecord(item.value.post)?.reply?.parent?.uri || '',
), ),
oneUp, oneUp,
oneDown, oneDown,
@@ -308,12 +318,14 @@ export function sort(
if ( if (
AppBskyUnspeccedGetPostThreadV2.isThreadItemPost(child.value) AppBskyUnspeccedGetPostThreadV2.isThreadItemPost(child.value)
) { ) {
postDataMap.set(child.uri, getPostTraversalMetadata(child))
const childPost = views.threadPost({ const childPost = views.threadPost({
uri: child.uri, uri: child.uri,
depth: child.depth, depth: child.depth,
value: child.value, value: child.value,
parent: thread.find( traversalMetadata: postDataMap.get(
p => p.uri === child.value.post.record.reply.parent.uri, getPostRecord(child.value.post)?.reply?.parent?.uri || '',
), ),
oneUp: thread[ci - 1], oneUp: thread[ci - 1],
oneDown: thread[ci + 1], oneDown: thread[ci + 1],
+5
View File
@@ -91,3 +91,8 @@ export type Slice =
nextAnchor: Extract<Slice, {type: 'threadPost'}> nextAnchor: Extract<Slice, {type: 'threadPost'}>
nextAnchorUri: AtUri nextAnchorUri: AtUri
} }
export type TraversalMetadata = {
depth: number
hasBranchingReplies: boolean
}
+24 -1
View File
@@ -2,10 +2,11 @@ import {
type AppBskyFeedDefs, type AppBskyFeedDefs,
AppBskyFeedPost, AppBskyFeedPost,
AppBskyFeedThreadgate, AppBskyFeedThreadgate,
type AppBskyUnspeccedGetPostThreadV2, AppBskyUnspeccedGetPostThreadV2,
AtUri, AtUri,
} from '@atproto/api' } from '@atproto/api'
import {type TraversalMetadata} from '#/state/queries/usePostThread/types'
import * as bsky from '#/types/bsky' import * as bsky from '#/types/bsky'
export function getThreadgateRecord( export function getThreadgateRecord(
@@ -31,3 +32,25 @@ export function getRootPostAtUri(post: AppBskyFeedDefs.PostView) {
} }
} }
} }
export function getPostRecord(post: AppBskyFeedDefs.PostView) {
return post.record as AppBskyFeedPost.Record
}
export function getPostTraversalMetadata(
item: AppBskyUnspeccedGetPostThreadV2.ThreadItem,
): TraversalMetadata | undefined {
if (!AppBskyUnspeccedGetPostThreadV2.isThreadItemPost(item.value)) return
const replyCount = item.value.post.replyCount || 0
const unhydratedReplies = item.value.moreReplies || 0
return {
depth: item.depth,
/**
* If the post has more than a single reply, and the total reply count
* minus the number of replies not present in the response is greater than
* 1, then we must have more than a single branch of replies present in the
* response, which can affect how we render tree view.
*/
hasBranchingReplies: replyCount > 1 && replyCount - unhydratedReplies > 1,
}
}
+11 -20
View File
@@ -8,7 +8,10 @@ import {
type ModerationOpts, type ModerationOpts,
} from '@atproto/api' } from '@atproto/api'
import {type Slice} from '#/state/queries/usePostThread/types' import {
type Slice,
type TraversalMetadata,
} from '#/state/queries/usePostThread/types'
export function threadPostNoUnauthenticated({ export function threadPostNoUnauthenticated({
uri, uri,
@@ -65,32 +68,18 @@ export function threadPost({
uri, uri,
depth, depth,
value, value,
parent: up,
oneUp, oneUp,
moderationOpts, moderationOpts,
traversalMetadata,
}: { }: {
uri: string uri: string
depth: number depth: number
value: $Typed<AppBskyUnspeccedGetPostThreadV2.ThreadItemPost> value: $Typed<AppBskyUnspeccedGetPostThreadV2.ThreadItemPost>
parent?: AppBskyUnspeccedGetPostThreadV2.OutputSchema['thread'][number]
oneUp?: AppBskyUnspeccedGetPostThreadV2.OutputSchema['thread'][number] oneUp?: AppBskyUnspeccedGetPostThreadV2.OutputSchema['thread'][number]
oneDown?: AppBskyUnspeccedGetPostThreadV2.OutputSchema['thread'][number] oneDown?: AppBskyUnspeccedGetPostThreadV2.OutputSchema['thread'][number]
moderationOpts: ModerationOpts moderationOpts: ModerationOpts
traversalMetadata?: TraversalMetadata
}): Extract<Slice, {type: 'threadPost'}> { }): Extract<Slice, {type: 'threadPost'}> {
const parent = (up && 'post' in up?.value
? up.value
: undefined) as unknown as AppBskyUnspeccedGetPostThreadV2.ThreadItemPost
const parentReplyCount = parent?.post?.replyCount || 0
const parentAdditionalReplies = parent?.moreReplies || 0
const parentHasBranchingReplies =
parentReplyCount > 1 && parentReplyCount - parentAdditionalReplies > 1
// if (!parentHasBranchingReplies) {
// console.log(value.post.record.text, {
// parentReplyCount,
// parentAdditionalReplies,
// })
// }
return { return {
type: 'threadPost', type: 'threadPost',
key: uri, key: uri,
@@ -111,8 +100,10 @@ export function threadPost({
isAnchor: depth === 0, isAnchor: depth === 0,
showParentReplyLine: !!oneUp && oneUp.depth !== 0 && oneUp.depth < depth, showParentReplyLine: !!oneUp && oneUp.depth !== 0 && oneUp.depth < depth,
showChildReplyLine: (value.post.replyCount || 0) > 0, showChildReplyLine: (value.post.replyCount || 0) > 0,
indent: parentHasBranchingReplies ? depth : up?.depth || depth, indent: traversalMetadata?.hasBranchingReplies
parentHasBranchingReplies, ? depth
: traversalMetadata?.depth || depth,
parentHasBranchingReplies: !!traversalMetadata?.hasBranchingReplies,
}, },
} }
} }
@@ -127,7 +118,7 @@ export function readMore({
key: `readMore:${parent.uri}`, key: `readMore:${parent.uri}`,
indent: parent.ui.parentHasBranchingReplies indent: parent.ui.parentHasBranchingReplies
? parent.depth ? parent.depth
: parent.depth - 1, : Math.max(0, parent.depth - 1),
replyCount: parent.value.moreReplies, replyCount: parent.value.moreReplies,
nextAnchor: parent, nextAnchor: parent,
nextAnchorUri: new AtUri(parent.uri), nextAnchorUri: new AtUri(parent.uri),