Skip to content

feat(chat): mark the message a reply-quote jump lands on - #1432

Merged
bmc08gt merged 2 commits into
code/cashfrom
feat/chat-jump-attention
Sep 8, 2026
Merged

bmc08gt merged 2 commits into
code/cashfrom
feat/chat-jump-attention

Conversation

@bmc08gt

@bmc08gt bmc08gt commented Sep 8, 2026 •

Copy link
Copy Markdown
Collaborator

Tapping a reply quote scrolled the transcript to the quoted message and left it looking like every other message, sitting at the bottom edge of the screen. Nothing said which one you had just been taken to.

Where it lands

The target now comes to rest in the middle of the transcript, which is where iOS puts it (ChatViewController.scrollToRow, .centeredVertically).

Centring needs the message's height, and nothing knows that until it has been laid out. measuredHeight gets it by scrolling the target on screen and straight back off — both with the non-animated scrollToItem, which forces a remeasure and returns without suspending, so the pair runs inside one dispatch and the intermediate position is never drawn. The jump itself is then a single animateScrollToItem with the scrollOffset that centres it.

One animation, and it has to be one: a second scroll to correct the first starts from a standstill, so it reads as the list moving, stopping, and moving again rather than as one move to the message. Frame-differencing a screen recording of the tap shows the difference — a two-phase version measures 16.4, 11.5, 13.5, 8.8, 7.3, 7.8, 4.4 per frame, two acceleration bumps, against 18.2, 12.9, 4.4, 1.1, 1.1 for the single scroll.

A message taller than the band cannot be centred, so it is aligned to the band's start instead — the edge the jump arrives from, since the reply that quoted it sits below it.

The flash

The message it lands on goes white at 14% over the bubble, holds for 250ms, then fades off over 750ms linearly. Drawn in Bubble, so every variant gets it from one place and the scrim is clipped by the shape the bubble already has. The strength arrives as a lambda read in the draw phase, so the fade repaints the one bubble and recomposes nothing.

A tween rather than a spring, unlike the rest of ChatAnimations: this one runs from full to nothing with no competing target to be interrupted by, so there is no settling for a spring to express — only a rate, and a linear one is what reads as a light going out.

Tests

JumpCenteringTest covers the one number the jump now consists of: the scrollOffset handed to animateScrollToItem, across a message that fits, one that fills half the band, one too tall to centre, and a height that could not be measured. ChatJumpAttentionScreenshotTest renders the bubble at full attention and settled.

Tapping a quote scrolled the transcript to the quoted message and left it
looking like every other message, at the bottom edge of the screen.

Two changes. The target now lands in the middle of the transcript, which is
where iOS puts it (ChatViewController.scrollToRow, .centeredVertically), in
two scrolls: one to park its leading edge mid-band and measure it, one to
correct by where it came to rest. Correcting from the measured position is
what makes the ends behave — a target the list cannot scroll to the middle
stops short on the first pass, and the correction follows it there.

Then it flashes: white at 14% over the bubble, held and faded off. Drawn in
Bubble, so every variant gets it from one place and the scrim is clipped by
the shape the bubble already has. The strength arrives as a lambda read in
the draw phase, so the fade repaints the one bubble and recomposes nothing.
The jump ran two animations: one to put the target's leading edge at the
middle of the viewport, then a corrective scroll for half the message's
height once it had been laid out. The second one starts from a standstill,
so the list moved, stopped, and moved again.

Measure the target instead. `measuredHeight` scrolls it on screen and
straight back off, both with the non-animated `scrollToItem`, which forces
a remeasure and returns without suspending — the pair runs inside one
dispatch, so nothing is drawn at the intermediate position. With the
height known up front, the whole jump is one `animateScrollToItem` and the
`scrollOffset` that centres it.

Frame-differencing a screen recording of the tap shows the change: the old
build's per-frame motion is 16.4, 11.5, 13.5, 8.8, 7.3, 7.8, 4.4 — two
acceleration bumps — against 18.2, 12.9, 4.4, 1.1, 1.1 now, a single decay.
@bmc08gt bmc08gt self-assigned this Sep 8, 2026
@github-actions github-actions Bot added the type: feature New functionality label Sep 8, 2026
@bmc08gt
bmc08gt force-pushed the feat/chat-jump-attention branch from 3b2a426 to fa4d110 Compare September 8, 2026 19:03
@bmc08gt
bmc08gt merged commit 474e1b3 into code/cash Sep 8, 2026
3 checks passed
@bmc08gt
bmc08gt deleted the feat/chat-jump-attention branch September 23, 2026 16:46
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

type: feature New functionality

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant