Checkpoint new traversal

This commit is contained in:
Eric Bailey
2025-05-28 15:56:02 -05:00
parent 1cc02b8bbd
commit 2c80c1f288
6 changed files with 154 additions and 14 deletions
@@ -193,19 +193,14 @@ let PostThreadItemLoaded = ({
],
]}>
{Array.from(Array(indents)).map((_, n: number) => {
const isLastIteration = n === indents - 1
const isSkipped = item.ui.skippedIndents.has(n)
return (
<View
key={`${post.uri}-padding-${n}`}
style={[
t.atoms.border_contrast_low,
{
borderRightWidth:
isLastIteration &&
item.ui.isDeadEnd &&
!item.ui.precedesParentReadMore
? 0
: REPLY_LINE_WIDTH,
borderRightWidth: isSkipped ? 0 : REPLY_LINE_WIDTH,
width: TREE_INDENT + TREE_AVI_WIDTH / 2,
left: 1,
},
@@ -229,7 +224,7 @@ let PostThreadItemLoaded = ({
!item.ui.precedesParentReadMore &&
!item.ui.precedesChildReadMore && [a.pb_sm],
]}>
{item.ui.indent > 1 && item.ui.parentHasBranchingReplies && (
{item.ui.indent > 1 && (
<View
style={[
a.absolute,
+1 -1
View File
@@ -41,7 +41,7 @@ export function usePostThread({
const {data} = await agent.app.bsky.unspecced.getPostThreadV2({
anchor: params.anchor!,
branchingFactor: params.view === 'linear' ? 1 : 3, // 100 TODO
below: 3,
below: 6,
sort: params.sort,
prioritizeFollowedUsers: params.prioritizeFollowedUsers,
})
+67 -3
View File
@@ -6,6 +6,7 @@ import {
import {
HiddenReplyKind,
type NTraversalMetadata,
type PostThreadParams,
type Slice,
type TraversalMetadata,
@@ -13,6 +14,8 @@ import {
import {
getPostRecord,
getPostTraversalMetadata,
getThreadPostUI,
getTraversalMetadata,
} from '#/state/queries/usePostThread/utils'
import * as views from '#/state/queries/usePostThread/views'
@@ -147,7 +150,6 @@ export function flatten(
}
}
}
console.log(flattened)
/*
* Insert hidden items and buttons to show them
@@ -205,6 +207,11 @@ export function sort(
const muted: Slice[] = []
const postDataMap = new Map<string, TraversalMetadata | undefined>()
const metadatas = new Map<string, NTraversalMetadata>()
// @ts-ignore
window.__data = metadatas // for debugging
traversal: for (let i = 0; i < thread.length; i++) {
const item = thread[i]
@@ -297,8 +304,25 @@ export function sort(
i = branch.end
continue traversal
} else if (AppBskyUnspeccedGetPostThreadV2.isThreadItemPost(item.value)) {
const parentMetadata = metadatas.get(
getPostRecord(item.value.post).reply?.parent?.uri || '',
)
const oneUp = thread.at(i - 1)
const oneDown = thread.at(i + 1)
const metadata = getTraversalMetadata({
item,
parentMetadata,
prevItem: oneUp,
nextItem: oneDown,
})
if (parentMetadata) {
parentMetadata.seenReplies += 1
metadata.isLastSibling =
parentMetadata.replies === parentMetadata.seenReplies
}
metadatas.set(item.uri, metadata)
metadatas.set(metadata.text, metadata) // TODO debugging
const post = views.threadPost({
uri: item.uri,
depth: item.depth,
@@ -345,6 +369,26 @@ export function sort(
if (
AppBskyUnspeccedGetPostThreadV2.isThreadItemPost(child.value)
) {
const childParentMetadata = metadatas.get(
getPostRecord(child.value.post).reply?.parent?.uri || '',
)
const prevItem = thread[ci - 1]
const nextItem = thread[ci + 1]
const childMetadata = getTraversalMetadata({
item: child,
prevItem,
nextItem,
parentMetadata: childParentMetadata,
})
if (childParentMetadata) {
childParentMetadata.seenReplies += 1
childMetadata.isLastSibling =
childParentMetadata.replies ===
childParentMetadata.seenReplies
}
metadatas.set(item.uri, childMetadata)
metadatas.set(childMetadata.text, childMetadata) // TODO debugging
const childPost = views.threadPost({
uri: child.uri,
depth: child.depth,
@@ -352,8 +396,8 @@ export function sort(
traversalMetadata: postDataMap.get(
getPostRecord(child.value.post)?.reply?.parent?.uri || '',
),
oneUp: thread[ci - 1],
oneDown: thread[ci + 1],
oneUp: prevItem,
oneDown: nextItem,
moderationOpts,
})
postDataMap.set(child.uri, getPostTraversalMetadata(childPost))
@@ -394,6 +438,26 @@ export function sort(
}
}
for (const item of items) {
if (item.type === 'threadPost') {
const metadata = metadatas.get(item.uri)
if (metadata) {
if (metadata.parentMetadata) {
metadata.skippedIndents = new Set([
...metadata.parentMetadata.skippedIndents,
])
}
if (metadata.isLastSibling) {
metadata.skippedIndents.add(item.depth - 2)
}
item.ui = getThreadPostUI(metadata)
}
}
}
// console.log(metadatas)
return {
items,
hidden,
+17
View File
@@ -64,6 +64,8 @@ export type Slice =
* this item.
*/
precedesChildReadMore?: boolean
skippedIndents: Set<number>
[key: string]: any
}
}
| {
@@ -109,3 +111,18 @@ export type TraversalMetadata = {
indent: number
hasBranchingReplies: boolean
}
export type NTraversalMetadata = {
depth: number
indent: number
replies: number
unhydratedReplies: number
seenReplies: number
hasBranchingReplies: boolean
isLastSibling: boolean
parentMetadata?: NTraversalMetadata
prevItemDepth?: number
nextItemDepth?: number
skippedIndents: Set<number>
[key: string]: any
}
+65
View File
@@ -7,6 +7,7 @@ import {
} from '@atproto/api'
import {
type NTraversalMetadata,
type Slice,
type TraversalMetadata,
} from '#/state/queries/usePostThread/types'
@@ -57,3 +58,67 @@ export function getPostTraversalMetadata(
hasBranchingReplies: replyCount > 1 && replyCount - unhydratedReplies > 1,
}
}
export function getTraversalMetadata({
item,
prevItem,
nextItem,
parentMetadata,
}: {
item: AppBskyUnspeccedGetPostThreadV2.ThreadItem
prevItem?: AppBskyUnspeccedGetPostThreadV2.ThreadItem
nextItem?: AppBskyUnspeccedGetPostThreadV2.ThreadItem
parentMetadata?: NTraversalMetadata
}): NTraversalMetadata {
if (!AppBskyUnspeccedGetPostThreadV2.isThreadItemPost(item.value)) {
throw new Error(`Expected thread item to be a post`)
}
const replies = item.value.post.replyCount || 0
const unhydratedReplies = item.value.moreReplies || 0
const hasBranchingReplies = replies > 1 && replies - unhydratedReplies > 1
return {
depth: item.depth,
// TODO maybe not used
indent: parentMetadata?.hasBranchingReplies
? item.depth
: parentMetadata?.indent || item.depth,
replies,
unhydratedReplies,
seenReplies: 0,
hasBranchingReplies,
parentMetadata,
isLastSibling: false,
skippedIndents: new Set(),
prevItemDepth: prevItem?.depth,
nextItemDepth: nextItem?.depth,
// TODO non-spec
text: getPostRecord(item.value.post).text,
}
}
export function getThreadPostUI({
depth,
indent,
replies,
parentMetadata,
prevItemDepth,
nextItemDepth,
skippedIndents,
}: NTraversalMetadata) {
return {
isAnchor: depth === 0,
showParentReplyLine:
!!prevItemDepth && prevItemDepth !== 0 && prevItemDepth < depth,
showChildReplyLine: replies > 0,
indent: depth,
parentHasBranchingReplies: !!parentMetadata?.hasBranchingReplies,
/*
* If there are no slices below this one, or the next slice is less
* indented than the computed indent for this post.
*/
isDeadEnd: nextItemDepth === undefined || nextItemDepth < indent,
skippedIndents,
}
}
+1 -2
View File
@@ -117,6 +117,7 @@ export function threadPost({
* indented than the computed indent for this post.
*/
isDeadEnd: !oneDown || oneDown?.depth < indent,
skippedIndents: new Set(),
},
}
}
@@ -152,11 +153,9 @@ export function postViewToThreadPlaceholder(
value: {
$type: 'app.bsky.unspecced.getPostThreadV2#threadItemPost',
post,
hiddenByThreadgate: false,
opThread: false,
moreParents: false,
moreReplies: 0,
mutedByViewer: false,
},
}
}