From 2497099d817b503471b8bbd3d5ca4e1d2a78d01f Mon Sep 17 00:00:00 2001 From: Eric Bailey Date: Sun, 25 May 2025 14:54:56 -0500 Subject: [PATCH] Handle read more cases in tree view --- src/state/queries/usePostThread/traversal.ts | 65 ++++++++++++-------- src/state/queries/usePostThread/views.ts | 18 ++++++ src/view/screens/PostThread.tsx | 2 +- 3 files changed, 59 insertions(+), 26 deletions(-) diff --git a/src/state/queries/usePostThread/traversal.ts b/src/state/queries/usePostThread/traversal.ts index 842cd511b2..f89bfc3c85 100644 --- a/src/state/queries/usePostThread/traversal.ts +++ b/src/state/queries/usePostThread/traversal.ts @@ -1,6 +1,5 @@ import { AppBskyUnspeccedGetPostThreadV2, - AtUri, type ModerationDecision, type ModerationOpts, } from '@atproto/api' @@ -21,8 +20,7 @@ export function flatten( }, ) { const flattened: Slice[] = sorted.items - - const unhydratedReplyIntervals = [] + const parentsWithUnhydratedReplies = [] for (let i = 0; i < flattened.length; i++) { const item = flattened[i] @@ -40,33 +38,50 @@ export function flatten( }) } - const prev = unhydratedReplyIntervals[unhydratedReplyIntervals.length - 1] + const maybeParent = + parentsWithUnhydratedReplies[parentsWithUnhydratedReplies.length - 1] - if (item.value.moreReplies > 0) { - unhydratedReplyIntervals.push({ - item, - replyCount: item.value.moreReplies, - }) + if (maybeParent) { + // next item is a sibling or an aunt/uncle + if (item.depth <= maybeParent.depth) { + flattened.splice( + i, + 0, + views.readMore({ + item, + parent: maybeParent, + }), + ) + parentsWithUnhydratedReplies.pop() + i++ // skip over the read more item + } else if (i === flattened.length - 1) { + // last iteration might have a parent + flattened.push( + views.readMore({ + item, + parent: maybeParent, + }), + ) + break + } } /* - * If direct child of previous item with `hasMoreReplies`, subtract + * Lastly, insert next read more if necessary */ - if (prev && item.depth === prev.item.depth + 1) { - // TODO test if we need this - // prev.replyCount = Math.max(0, prev.replyCount - 1) - } - - if (prev && item.depth <= prev.item.depth) { - flattened.splice(i, 0, { - type: 'readMore', - key: `readMore:${prev.item.uri}`, - indent: prev.item.depth + (item.depth < prev.item.depth ? -1 : 0), - replyCount: prev.replyCount, - nextAnchor: prev.item, - nextAnchorUri: new AtUri(prev.item.uri), - }) - unhydratedReplyIntervals.pop() + if (item.value.moreReplies > 0) { + // last iteration might have its own read more + if (i === flattened.length - 1) { + flattened.push( + views.readMore({ + item, + parent: item, + }), + ) + break + } else { + parentsWithUnhydratedReplies.push(item) + } } } } diff --git a/src/state/queries/usePostThread/views.ts b/src/state/queries/usePostThread/views.ts index 002ffa79db..fb7a030501 100644 --- a/src/state/queries/usePostThread/views.ts +++ b/src/state/queries/usePostThread/views.ts @@ -3,6 +3,7 @@ import { type AppBskyFeedDefs, type AppBskyFeedPost, type AppBskyUnspeccedGetPostThreadV2, + AtUri, moderatePost, type ModerationOpts, } from '@atproto/api' @@ -99,6 +100,23 @@ export function threadPost({ } } +export function readMore({ + item, + parent, +}: { + item: Extract + parent: Extract +}) { + return { + type: 'readMore' as const, + key: `readMore:${parent.uri}`, + indent: parent.depth + (item.depth < parent.depth ? -1 : 0), + replyCount: parent.value.moreReplies, + nextAnchor: parent, + nextAnchorUri: new AtUri(parent.uri), + } +} + export function postViewToThreadPlaceholder( post: AppBskyFeedDefs.PostView, ): $Typed< diff --git a/src/view/screens/PostThread.tsx b/src/view/screens/PostThread.tsx index 1e90169f2a..10b3ea872c 100644 --- a/src/view/screens/PostThread.tsx +++ b/src/view/screens/PostThread.tsx @@ -313,7 +313,7 @@ export function Inner({uri}: {uri: string | undefined}) { t.atoms.text_contrast_medium, (hovered || pressed) && a.underline, ]}> - Read {item.replyCount} more replies + Read {item.replyCount} more replies ({item.key}) )