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
|
||||||
|
}
|
||||||
Reference in new issue
Block a user