Files
ai-app/app
irisandClaude Opus 5 5eba6ec529 Hold a row's top edge during layout, so nothing is drawn out of place
The correction ran in a coroutine, so it landed a frame or more after the
layout it was correcting: the wrong position was drawn once and then fixed,
which reads as a flick and gets worse the faster the screen refreshes. That
is a race with the display rather than a bug that can be tuned out, so the
fix is not a shorter delay but a different phase.

It now happens in the layout phase. `Modifier.holdTopEdge` learns the row's
new height from the measurement that produced it and asks the list to shift
by exactly that much, before anything is drawn. `requestScrollToItem` is
the form that may be asked for during layout; `dispatchRawDelta` is not --
it calls forceRemeasure and dies with "performMeasureAndLayout called
during measure layout", which cost one crash to establish.

The arming flag and the per-row height are deliberately not snapshot state.
Both are written from layout, where a snapshot write that composition reads
would schedule another recomposition -- another frame, which is the thing
being removed.

This also drops the machinery the previous attempt needed: no waiting on a
size change, no timeout, no marking the rows above to find one that could
still report the move. A row measures itself, so a row that shrinks out of
the viewport is no longer a special case.

Verified with ui-trace sampling at ~1kHz, where a single bad frame would
show as ten to twenty samples: expanding and collapsing from a heading are
each one step from old position to held position with nothing in between,
collapsing from the foot bar holds the four rows below it, a drag 120ms
after a tap is left alone, and scrolling back stays put for six seconds.
ktfmt, lint and 85 tests clean.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-30 12:15:44 -04:00
..