fix(mobile): open threads at the newest reply, with a shared jump-to-latest pill - #5364
fix(mobile): open threads at the newest reply, with a shared jump-to-latest pill#5364NuCl34R wants to merge 2 commits into
Conversation
Opening a thread on mobile landed on the thread head, forcing users to scroll through potentially hundreds of replies to reach the newest message. Desktop's thread panel already opens at the bottom. Once the authoritative thread query hydrates, jump to the last reply and align its trailing edge with the viewport bottom, then keep following the tail. Deep links to a specific reply keep their existing behavior and take precedence over the tail jump; short threads whose tail is already visible are left alone. Fixes block#4354 Signed-off-by: NuCl34R <nukecl34r@gmail.com>
Scrolling up in a long thread left no quick way back to the newest reply. Reuse the channel timeline's frosted Latest pill in the thread detail page: it appears when the newest reply scrolls out of view and animates back to the tail on tap. The pill widget is extracted from the channel message list into a shared public JumpToLatestButton used by both surfaces. _ThreadMessage and _Avatar move to a part file to keep thread_detail_page.dart under the 1000-line ceiling. Signed-off-by: NuCl34R <nukecl34r@gmail.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 8e84005e67
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| final targetAlignment = | ||
| 1.0 - (lastPosition.itemTrailingEdge - lastPosition.itemLeadingEdge); | ||
| itemScrollController.jumpTo(index: lastIndex, alignment: targetAlignment); |
There was a problem hiding this comment.
Account for the composer when aligning the tail
When a member opens a long thread after the composer dock has already been measured, this alignment places the newest reply's trailing edge at the physical bottom of the list viewport. Because the composer is overlaid on that same viewport and the list's bottom padding can be scrolled offscreen, a typical short newest reply can end up entirely behind the composer; the dock-height callback does not correct this when its height was already known. Align against the usable boundary above composerDockHeight (and the gutter), rather than 1.0.
Useful? React with 👍 / 👎.

Summary
Opening a thread on mobile lands on the thread head. In agent-heavy channels where threads routinely reach 300+ replies, reaching the newest message takes dozens of scroll gestures. Desktop's thread panel already opens at the bottom.
Two commits:
fix: open threads scrolled to the newest reply. Once the authoritative thread query hydrates, jump to the last reply, then align its trailing edge with the viewport bottom in a second pass (the tail must render before its extent is measurable). Guard rails:initialMessageIdkeeps its existing jump and takes precedence over the tail jump.feat: jump-to-latest pill in threads. The channel timeline's frosted "Latest" pill now also appears in threads when the newest reply scrolls out of view; tapping it animates back to the tail. The pill is extracted into a shared, documentedJumpToLatestButtonused by both surfaces (net deduplication)._ThreadMessage/_Avatarmove to apartfile to keepthread_detail_page.dartunder the 1000-line guard.Related issue
Fixes #4354.
Closest existing PRs (searched before opening):
No intent to race either one — happy to rebase on top if maintainers prefer to land one of those first, or to fold this PR's tests and pill onto it.
Testing
TDD: each behavior landed with a widget test written first and observed failing. New/updated tests in
channel_detail_page_test.dart:thread opens scrolled to the newest reply— 40-reply thread opens with the tail visible, head unbuiltinitial thread hydration lands on the newest reply— same, with delayed (Completer-driven) hydrationthread deep link still lands on the linked reply— deep-link precedence over the tail jumpthread shows a Latest pill when scrolled up that jumps back to the newest reply— pill appears on scroll-up, returns to the tail on tap, hides at the tailFull mobile suite: 1264/1264 green;
just mobile-checkclean (analyze, format, file-size guard). Both commits are DCO signed.On device: validated on a Galaxy S23 Ultra debug build against a production relay — long agent threads (300+ replies) open on the newest reply, the pill appears on scroll-up and returns to the tail, deep links and short threads behave as before. Screenshots to follow in a comment.
🤖 Generated with Claude Code