fix: 进入对话之后默认展示最新消息
This commit is contained in:
@@ -12,6 +12,8 @@ import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.key
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.mutableIntStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.rememberCoroutineScope
|
||||
@@ -36,6 +38,7 @@ import kotlinx.coroutines.launch
|
||||
* 消息列表组件
|
||||
*
|
||||
* @param messages 消息列表
|
||||
* @param conversationId 当前对话 ID,用于切换对话时重置滚动状态,使每次打开都从底部开始
|
||||
* @param isStreaming 是否正在流式接收
|
||||
* @param streamingText 流式文本内容
|
||||
* @param isTyping 是否正在输入
|
||||
@@ -46,6 +49,7 @@ import kotlinx.coroutines.launch
|
||||
@Composable
|
||||
fun MessageList(
|
||||
messages: List<MessageDto>,
|
||||
conversationId: String? = null,
|
||||
isStreaming: Boolean = false,
|
||||
streamingText: String = "",
|
||||
isTyping: Boolean = false,
|
||||
@@ -57,46 +61,48 @@ fun MessageList(
|
||||
audioFilePaths: Map<String, String> = emptyMap(),
|
||||
audioDurations: Map<String, Int> = emptyMap() // messageId -> 时长(秒)
|
||||
) {
|
||||
val listState = rememberLazyListState()
|
||||
val scope = rememberCoroutineScope()
|
||||
var lastHeightPx by remember { mutableIntStateOf(0) }
|
||||
|
||||
// 计算实际的列表项数量(考虑分割消息和附加项)
|
||||
// 计算实际的列表项数量(考虑分割消息和附加项)- 需在 listState 之前计算,用于初始滚动位置
|
||||
val estimatedItemCount = remember(messages, isStreaming, streamingText, isTyping) {
|
||||
var count = 0
|
||||
var lastTimestamp: Long? = null
|
||||
|
||||
messages.forEachIndexed { index, message ->
|
||||
// 时间分隔线
|
||||
if (index > 0 && lastTimestamp != null && (message.timestamp - lastTimestamp!!) > 300000) {
|
||||
count++
|
||||
}
|
||||
|
||||
// 消息气泡(考虑分割)
|
||||
if (message.senderType == "assistant") {
|
||||
val parts = message.content.split("[SPLIT]").filter { it.trim().isNotEmpty() }
|
||||
count += if (parts.size > 1) parts.size else 1
|
||||
} else {
|
||||
count++
|
||||
}
|
||||
|
||||
lastTimestamp = message.timestamp
|
||||
}
|
||||
|
||||
// 流式消息
|
||||
if (isStreaming) {
|
||||
val streamingParts = streamingText.split("[SPLIT]").filter { it.trim().isNotEmpty() }
|
||||
count += if (streamingParts.size > 1) streamingParts.size else 1
|
||||
}
|
||||
|
||||
// 输入指示器
|
||||
if (isTyping || (isStreaming && streamingText.isEmpty())) {
|
||||
count++
|
||||
}
|
||||
|
||||
count
|
||||
}
|
||||
|
||||
// 当前对话是否已加载过消息(用于首次显示时直接定位到底部,避免从顶部再滑到底部)
|
||||
var hasReceivedMessages by remember(conversationId) { mutableStateOf(false) }
|
||||
LaunchedEffect(conversationId, messages) {
|
||||
if (messages.isNotEmpty()) hasReceivedMessages = true
|
||||
}
|
||||
|
||||
// 用 key 在「首次有消息」时重建列表状态,使 initialFirstVisibleItemIndex 生效,打开对话即显示底部
|
||||
val initialIndex = if (hasReceivedMessages && estimatedItemCount > 0) (estimatedItemCount - 1).coerceAtLeast(0) else 0
|
||||
val listState = key(conversationId, hasReceivedMessages) {
|
||||
rememberLazyListState(initialFirstVisibleItemIndex = initialIndex, initialFirstVisibleItemScrollOffset = 0)
|
||||
}
|
||||
|
||||
// 自动滚动到底部 - 当消息变化或流式内容更新时滚动
|
||||
LaunchedEffect(messages.size, messages.lastOrNull()?.id, isStreaming, streamingText, isTyping) {
|
||||
// 短暂延迟确保内容已渲染
|
||||
|
||||
@@ -189,6 +189,7 @@ fun CreateMemoryScreen(
|
||||
// 使用新的MessageList组件(包含所有消息、流式内容和输入指示器)
|
||||
MessageList(
|
||||
messages = messages,
|
||||
conversationId = conversationId,
|
||||
isStreaming = isStreaming,
|
||||
streamingText = streamingText,
|
||||
isTyping = isTyping,
|
||||
|
||||
Reference in New Issue
Block a user