Hold the reader's place when a message arrives
Scrolled back through a conversation, every new message dragged the view with it -- which reads as the screen scrolling down on its own, at the exact moment somebody is trying to read something else. The list had no keys, so its rows were identified by position. The transcript is drawn newest-first, so a new message is an insertion at index 0: every existing row shifts up one index, the viewport stays on the index it was on, and the content slides through it. The working indicator appearing and disappearing did the same thing at the same end. So rows now carry the identity they always had in the data. Every transcript event has a seq, which is what the transcript is ordered by and never changes, and every row keeps the seq of the first event behind it -- a streaming message keeps the seq of its first delta, so it holds still for the whole answer rather than becoming a new row on every frame, and a tool call keeps its start's. Paging older history is the same insertion from the other end, and it is the thing this could plausibly have broken. Checked on the emulator: scrolled back mid-turn, the view sat still through twenty seconds of streamed deltas, and scrolling to the far end still fetched earlier pages and stayed where it was while they arrived.
This commit is contained in:
1 parent
5396da76c7
commit
279c76e8a1
2 files changed
+95
-26
No files matched your search
@@ -32,13 +32,27 @@ import androidx.compose.ui.unit.dp
|
||||
* of "these belong together" must not reach back into it.
|
||||
*/
|
||||
sealed class TranscriptRow {
|
||||
data class Single(val item: TranscriptItem) : TranscriptRow()
|
||||
/**
|
||||
* This row's identity in the list, taken from the first transcript event behind it.
|
||||
*
|
||||
* See [TranscriptItem.seq]: the list is keyed by this so that inserting a new message at one
|
||||
* end, or a page of history at the other, moves the rows and not the reader.
|
||||
*/
|
||||
abstract val seq: Long
|
||||
|
||||
data class Single(val item: TranscriptItem) : TranscriptRow() {
|
||||
override val seq: Long
|
||||
get() = item.seq
|
||||
}
|
||||
|
||||
/** Two or more calls with nothing between them; drawn as one collapsed card. */
|
||||
data class Tools(val calls: List<TranscriptItem.ToolRun>) : TranscriptRow() {
|
||||
/** Stable across reloads because it is the first call's own id. */
|
||||
val id: String
|
||||
get() = calls.first().id
|
||||
|
||||
override val seq: Long
|
||||
get() = calls.first().seq
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user