fix(android): reduce chat recomposition churn
This commit is contained in:
parent
3009e689bc
commit
56e23a887f
@ -6,12 +6,14 @@ import androidx.compose.foundation.layout.fillMaxSize
|
|||||||
import androidx.compose.foundation.layout.fillMaxWidth
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
import androidx.compose.foundation.layout.padding
|
import androidx.compose.foundation.layout.padding
|
||||||
import androidx.compose.foundation.lazy.LazyColumn
|
import androidx.compose.foundation.lazy.LazyColumn
|
||||||
|
import androidx.compose.foundation.lazy.items
|
||||||
import androidx.compose.foundation.lazy.rememberLazyListState
|
import androidx.compose.foundation.lazy.rememberLazyListState
|
||||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||||
import androidx.compose.material3.Surface
|
import androidx.compose.material3.Surface
|
||||||
import androidx.compose.material3.Text
|
import androidx.compose.material3.Text
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.LaunchedEffect
|
import androidx.compose.runtime.LaunchedEffect
|
||||||
|
import androidx.compose.runtime.remember
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
@ -34,11 +36,19 @@ fun ChatMessageListCard(
|
|||||||
modifier: Modifier = Modifier,
|
modifier: Modifier = Modifier,
|
||||||
) {
|
) {
|
||||||
val listState = rememberLazyListState()
|
val listState = rememberLazyListState()
|
||||||
|
val displayMessages = remember(messages) { messages.asReversed() }
|
||||||
|
val stream = streamingAssistantText?.trim()
|
||||||
|
|
||||||
// With reverseLayout the newest item is at index 0 (bottom of screen).
|
// New list items/tool rows should animate into view, but token streaming should not restart
|
||||||
LaunchedEffect(messages.size, pendingRunCount, pendingToolCalls.size, streamingAssistantText) {
|
// that animation on every delta.
|
||||||
|
LaunchedEffect(messages.size, pendingRunCount, pendingToolCalls.size) {
|
||||||
listState.animateScrollToItem(index = 0)
|
listState.animateScrollToItem(index = 0)
|
||||||
}
|
}
|
||||||
|
LaunchedEffect(stream) {
|
||||||
|
if (!stream.isNullOrEmpty()) {
|
||||||
|
listState.scrollToItem(index = 0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Box(modifier = modifier.fillMaxWidth()) {
|
Box(modifier = modifier.fillMaxWidth()) {
|
||||||
LazyColumn(
|
LazyColumn(
|
||||||
@ -50,8 +60,6 @@ fun ChatMessageListCard(
|
|||||||
) {
|
) {
|
||||||
// With reverseLayout = true, index 0 renders at the BOTTOM.
|
// With reverseLayout = true, index 0 renders at the BOTTOM.
|
||||||
// So we emit newest items first: streaming → tools → typing → messages (newest→oldest).
|
// So we emit newest items first: streaming → tools → typing → messages (newest→oldest).
|
||||||
|
|
||||||
val stream = streamingAssistantText?.trim()
|
|
||||||
if (!stream.isNullOrEmpty()) {
|
if (!stream.isNullOrEmpty()) {
|
||||||
item(key = "stream") {
|
item(key = "stream") {
|
||||||
ChatStreamingAssistantBubble(text = stream)
|
ChatStreamingAssistantBubble(text = stream)
|
||||||
@ -70,8 +78,8 @@ fun ChatMessageListCard(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
items(count = messages.size, key = { idx -> messages[messages.size - 1 - idx].id }) { idx ->
|
items(items = displayMessages, key = { it.id }) { message ->
|
||||||
ChatMessageBubble(message = messages[messages.size - 1 - idx])
|
ChatMessageBubble(message = message)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -160,7 +160,10 @@ private fun ChatThreadSelector(
|
|||||||
mainSessionKey: String,
|
mainSessionKey: String,
|
||||||
onSelectSession: (String) -> Unit,
|
onSelectSession: (String) -> Unit,
|
||||||
) {
|
) {
|
||||||
val sessionOptions = resolveSessionChoices(sessionKey, sessions, mainSessionKey = mainSessionKey)
|
val sessionOptions =
|
||||||
|
remember(sessionKey, sessions, mainSessionKey) {
|
||||||
|
resolveSessionChoices(sessionKey, sessions, mainSessionKey = mainSessionKey)
|
||||||
|
}
|
||||||
|
|
||||||
Row(
|
Row(
|
||||||
modifier = Modifier.fillMaxWidth().horizontalScroll(rememberScrollState()),
|
modifier = Modifier.fillMaxWidth().horizontalScroll(rememberScrollState()),
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user