Stop re-measuring the transcript at the keyboard, and seed the window
Three things, all of them the same shape: work done because something was asked a question at the wrong moment. The keyboard. The layout modifier passed `minHeight = viewportSize` down to its child, so every frame of the IME animation changed the child's constraints -- and changed constraints are exactly what defeats the early-return in `MeasurePassDelegate.remeasure`. The whole transcript was re-measured on the way up, measured on a Pixel 9 Pro XL as 250 measurements averaging 2.8ms with a 54.5ms worst. The minimum is applied to what this node reports now, not to what it asks its child for, so the child early-returns; the content is placed against the bottom to keep the anchoring the minimum existed for. It only ever bites on a conversation shorter than the screen, which was never the case paying for it. The flicker. `retained` starts empty, so on the composition that introduces the rows every one of them is outside the window, the whole transcript collapses to a single spacer, and it draws blank for a frame. Seeded now -- at the newest end on open, and around the anchor on a restore. The restore case is the one that bites: `placed()` jumps the view during placement, and a window recomputed there only schedules a recomposition, so the destination would draw as spacer for a frame or two after drawing ungates. Seeded by pixels rather than by a row count, because a run of tool calls is eight rows and less than half a screen. The block layers. Every paragraph of every reply had a layer, which was right when whole rows were re-recording constantly and one row's display list was 36,982px tall. Re-recording is rare now -- 65 whole rows in fifty seconds of reading -- and a layer costs a layout node and a display list held for the life of the row, against the node count the per-frame cost scales with. They go to the message still arriving, which is the only one whose drawing is invalidated often enough to want the granularity. Verified on the emulator against the case none of this was written for: a two-message conversation far shorter than the viewport still hangs from the composer, with the keyboard both up (messages at y1756-1940, composer 2109) and down (936-1120 against 1289). Mechanism for the block layers and the hole in the restore seeding both from the ai-app-2-6d session; the layers are not re-positioned per frame as I had it, they are baked into the row's display list. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
1 parent
f497d1f3ad
commit
41df8bb76a
4 files changed
+109
-30
No files matched your search
@@ -1493,7 +1493,14 @@ fun SessionScreen(settings: ServerSettings, summary: SessionSummary, onBack: ()
|
||||
images = item.images,
|
||||
)
|
||||
is TranscriptItem.AssistantMsg ->
|
||||
AssistantMessage(item.text, replies)
|
||||
// Only the last row can still be arriving, and only a row
|
||||
// that is still arriving earns a layer per block; see
|
||||
// [BlockedMarkdown].
|
||||
AssistantMessage(
|
||||
item.text,
|
||||
replies,
|
||||
live = row === rows.lastOrNull(),
|
||||
)
|
||||
is TranscriptItem.ToolRun ->
|
||||
ToolCard(
|
||||
tool = item,
|
||||
|
||||
Reference in new issue
Block a user