Fix computation of isLastSibling, isLastChild, and replyIndex (#9202)

* Fix computation of isLastSibling and isLastChild to account for muted or
otherwise hidden replies

* Update comments

* isLastSiblingByCounts isn't needed, should rely only on the count of replies seen

* The counters serve the same purpose, we only need to know the count of the actual replies rendered to the view in order to calculate the replyIndex

* Remove redundant check
This commit is contained in:
Eric Bailey
2025-10-15 11:13:08 -05:00
committed by GitHub
parent fe5a623b44
commit 27926f093c
3 changed files with 28 additions and 28 deletions
+14 -14
View File
@@ -135,11 +135,11 @@ export function sortAndAnnotateThreadItems(
} else if (AppBskyUnspeccedDefs.isThreadItemPost(item.value)) { } else if (AppBskyUnspeccedDefs.isThreadItemPost(item.value)) {
if (parentMetadata) { if (parentMetadata) {
/* /*
* Set this value before incrementing the parent's repliesSeenCounter * Set this value before incrementing the `repliesSeenCounter` later
* on, since `repliesSeenCounter` is 1-indexed and `replyIndex` is
* 0-indexed.
*/ */
metadata!.replyIndex = parentMetadata.repliesIndexCounter metadata!.replyIndex = parentMetadata.repliesSeenCounter
// Increment the parent's repliesIndexCounter
parentMetadata.repliesIndexCounter += 1
} }
const post = views.threadPost({ const post = views.threadPost({
@@ -193,11 +193,12 @@ export function sortAndAnnotateThreadItems(
storeTraversalMetadata(metadatas, childMetadata) storeTraversalMetadata(metadatas, childMetadata)
if (childParentMetadata) { if (childParentMetadata) {
/* /*
* Set this value before incrementing the parent's repliesIndexCounter * Set this value before incrementing the
* `repliesSeenCounter` later on, since `repliesSeenCounter`
* is 1-indexed and `replyIndex` is 0-indexed.
*/ */
childMetadata!.replyIndex = childMetadata!.replyIndex =
childParentMetadata.repliesIndexCounter childParentMetadata.repliesSeenCounter
childParentMetadata.repliesIndexCounter += 1
} }
const childPost = views.threadPost({ const childPost = views.threadPost({
@@ -264,14 +265,13 @@ export function sortAndAnnotateThreadItems(
if (nextItem?.type === 'threadPost') if (nextItem?.type === 'threadPost')
metadata.nextItemDepth = nextItem?.depth metadata.nextItemDepth = nextItem?.depth
/* /**
* Item is the last "sibling" if we know for sure we're out of * Item is also the last "sibling" if its index matches the total
* replies on the parent (even though this item itself may have its * number of replies we're actually able to render to the page.
* own reply branches).
*/ */
const isLastSiblingByCounts = const isLastSiblingDueToMissingReplies =
metadata.replyIndex === metadata.replyIndex ===
metadata.parentMetadata.repliesIndexCounter - 1 metadata.parentMetadata.repliesSeenCounter - 1
/* /*
* Item can also be the last "sibling" if we know we don't have a * Item can also be the last "sibling" if we know we don't have a
@@ -287,7 +287,7 @@ export function sortAndAnnotateThreadItems(
* Ok now we can set the last sibling state. * Ok now we can set the last sibling state.
*/ */
metadata.isLastSibling = metadata.isLastSibling =
isLastSiblingByCounts || isImplicitlyLastSibling isImplicitlyLastSibling || isLastSiblingDueToMissingReplies
/* /*
* Item is the last "child" in a branch if there is no next item, * Item is the last "child" in a branch if there is no next item,
+14 -13
View File
@@ -193,23 +193,24 @@ export type TraversalMetadata = {
*/ */
repliesUnhydrated: number repliesUnhydrated: number
/** /**
* The number of replies that have been seen so far in the traversal. * The number of replies that have been "seen" (actually able to be rendered)
* Excludes replies that are moderated in some way, since those are not * so far in the traversal. Excludes replies that are moderated in some way,
* "seen" on first load. Use `repliesIndexCounter` for the total number of * since those are not "seen" on first load.
* replies that were hydrated in the response.
* *
* After traversal, we can use this to calculate if we actually got all the * We use this to compute the `replyIndex` values of the children of this
* replies we expected, or if some were blocked, etc. * parent. E.g. if a reply is not hydrated on the response, or is moderated
* in some way (including by the user), this value is not incremented. So
* this represents the _actual_ index of the reply in the rendered view.
*
* Note: this is a "counter", not an "index". Because this value is
* incremented starting from 0, it is 1-indexed. So to when comparing to the
* `replyIndex`, you'll need to subtract 1 from this value.
*/ */
repliesSeenCounter: number repliesSeenCounter: number
/** /**
* The total number of replies to this post hydrated in this response. Used * The index-0-based index of this reply in the parent post's replies. This
* for populating the `replyIndex` of the post by referencing this value on * is computed from the `repliesSeenCounter` of the parent post, prior to it
* the parent. * being incremented for this reply.
*/
repliesIndexCounter: number
/**
* The index-0-based index of this reply in the parent post's replies.
*/ */
replyIndex: number replyIndex: number
/** /**
-1
View File
@@ -99,7 +99,6 @@ export function getTraversalMetadata({
repliesCount, repliesCount,
repliesUnhydrated, repliesUnhydrated,
repliesSeenCounter: 0, repliesSeenCounter: 0,
repliesIndexCounter: 0,
replyIndex: 0, replyIndex: 0,
skippedIndentIndices: new Set<number>(), skippedIndentIndices: new Set<number>(),
} }