Skip to content

feat(chat): jump-to-bottom button with unread badge - #1068

Merged
bmc08gt merged 19 commits into
mainfrom
feat/chat-jump-to-bottom
Oct 15, 2026
Merged

bmc08gt merged 19 commits into
mainfrom
feat/chat-jump-to-bottom

Conversation

@bmc08gt

@bmc08gt bmc08gt commented Oct 15, 2026

Copy link
Copy Markdown
Collaborator

Adds a jump-to-bottom button to the chat transcript, with an unread badge, matching Android (code-payments/code-android-app#1783).

The button shows once you scroll away from the newest message and scrolls back down on tap. The badge counts messages that arrived after the chat opened, frozen at the unread-divider count until your first drag, and clears on your own send. The viewer read pointer now advances to a confirmed own send, as Android does.

The button sits in a column above the $ button inside the composer bar's SwiftUI hierarchy, so it moves with $ on the same transaction when the keyboard opens or closes. An earlier version hosted it in a second UIHostingController; that one ran a frame ahead of $ and drew a second copy of the composer. BarClipView now masks a band above the bar's trailing edge for the button. The transcript inset and keyboard floor still come from the composer frame alone, which ChatScreenBarClipTests pins.

The button uses the composer's composerGlass, the same as $, with no shadow.

agent-team and others added 19 commits October 14, 2026 20:02
…ript

The badge counts inbound messages after the viewer's read pointer, read through
the same helper the unread divider and advanceReadPointer use. The button shows
once the opening scroll has landed and the reader is off the bottom; tapping it
scrolls through ChatViewController.scrollToBottom, jumping past 100 rows.
A status-bar tap, a deceleration's end or a settled scroll animation never passed the drag check in scrollViewDidScroll, so the jump button kept its old visibility.
…e the hold on own send

The arrival cutoff is now the larger of the read pointer at open and the newest inbound id once the opening load has landed, so loaded history no longer counts as arrivals. A confirmed own send, text or media, ends the frozen count.
…elease the badge only onto a moved pointer

A coordinator built after the opening load now starts with the load marked landed, so arrivals still count. An own send bumps the release counter only when advanceReadPointer reports the pointer at or past it.
…ul newest-page load

loadMessages now reports whether the page was fetched and persisted. The screen seats the cutoff only on success, and the controller records each landing so a retry, backfill or join after a failed opening load seats it instead. Until then nothing counts as an arrival.
The painted fade covered the newest message rows, and the button's glass already separates it.
The jump button now centres on the Send Cash button's column instead of sitting at a fixed 16pt inset, so the two stack. The bar reports the column's centre from its own layout constants, for the keyboard-up and keyboard-down insets.
The jump button's column now follows the bar's compact state (the composer's focus) instead of the keyboard's visibility, and moves on the same spring the bar widens on.
…ser bar

The button is a SwiftUI column hosted next to the bar and moves on the same spring as the bar's $ button, sharing one inset function. Its state lives in JumpToBottomModel instead of the UIKit controller.
The button is now drawn in SwiftUI with the composer's glass, in a namespace of its own so it never merges with the $ button. The UIKit frost, hairline and shadow are gone, along with the UIKit control and its representable.
…ierarchy

The button was a second hosting controller beside the bar, so it ran a frame ahead of the $ button on every keyboard transition and a second composer row showed above the real one. It is now an overlay in ConversationBottomBar, and the bar's clip leaves its travel area uncut without growing the transcript inset or keyboard floor.
@bmc08gt bmc08gt self-assigned this Oct 15, 2026
@bmc08gt
bmc08gt merged commit d620110 into main Oct 15, 2026
2 of 3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant