fix(chat): conditional auto-scroll on new messages (#131) (#193)

This commit is contained in:
M57 authored and GitHub committed 2026-06-21 00:29:26 +03:00
1 parent 00c6e75f50
commit 5e90a4d1a7
1 file changed
+26 -1
@@ -37,6 +37,7 @@ import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.width import androidx.compose.foundation.layout.width
import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.LazyListState
import androidx.compose.foundation.lazy.items import androidx.compose.foundation.lazy.items
import androidx.compose.foundation.lazy.itemsIndexed import androidx.compose.foundation.lazy.itemsIndexed
import androidx.compose.foundation.lazy.rememberLazyListState import androidx.compose.foundation.lazy.rememberLazyListState
@@ -117,6 +118,7 @@ fun ChatScreen(
) { ) {
val state by viewModel.uiState.collectAsStateWithLifecycle() val state by viewModel.uiState.collectAsStateWithLifecycle()
val listState = rememberLazyListState() val listState = rememberLazyListState()
var lastSessionId by remember { mutableStateOf<String?>(null) }
val showScrollToBottom by remember { val showScrollToBottom by remember {
derivedStateOf { derivedStateOf {
state.messages.isNotEmpty() && listState.canScrollForward state.messages.isNotEmpty() && listState.canScrollForward
@@ -196,7 +198,13 @@ fun ChatScreen(
(if (state.streamingMessage != null) 1 else 0) + (if (state.streamingMessage != null) 1 else 0) +
(if (state.isThinking) 1 else 0) (if (state.isThinking) 1 else 0)
if (totalItems > 0) { if (totalItems > 0) {
listState.animateScrollToItem(totalItems - 1) val isSessionSwitch = state.currentSessionId != lastSessionId
if (isSessionSwitch) {
lastSessionId = state.currentSessionId
listState.scrollToItem(totalItems - 1)
} else if (listState.isAtBottom()) {
listState.animateScrollToItem(totalItems - 1)
}
} }
} }
@@ -516,6 +524,15 @@ fun ChatScreen(
onSend = { onSend = {
viewModel.sendMessage(inputText) viewModel.sendMessage(inputText)
inputText = "" inputText = ""
scrollScope.launch {
val totalItems =
state.messages.size +
(if (state.streamingMessage != null) 1 else 0) +
(if (state.isThinking) 1 else 0)
if (totalItems > 0) {
listState.animateScrollToItem(totalItems - 1)
}
}
}, },
onInterrupt = viewModel::interruptSession, onInterrupt = viewModel::interruptSession,
isAgentTyping = state.isAgentTyping, isAgentTyping = state.isAgentTyping,
@@ -1027,3 +1044,11 @@ private fun StreamingBubbleWithTypingEffect(
isCurrentMatch = false, isCurrentMatch = false,
) )
} }
private fun LazyListState.isAtBottom(threshold: Int = 3): Boolean {
val layoutInfo = this.layoutInfo
val visibleItems = layoutInfo.visibleItemsInfo
if (visibleItems.isEmpty()) return true
val lastVisibleItem = visibleItems.last()
return lastVisibleItem.index >= layoutInfo.totalItemsCount - threshold
}