From a18bb83c5ea6452b76f340771c3a491d81d6d599 Mon Sep 17 00:00:00 2001 From: iammm0 Date: Mon, 26 Jan 2026 11:54:11 +0800 Subject: [PATCH] =?UTF-8?q?refactor:=20=E4=BC=98=E5=8C=96=E5=89=8D?= =?UTF-8?q?=E7=AB=AF=E8=81=8A=E5=A4=A9UI=E7=BB=84=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 优化MessageBubble消息气泡组件 - 优化MessageList消息列表组件 --- .../ui/components/chat/MessageBubble.kt | 71 ++++++++++++++++++- .../ui/components/chat/MessageList.kt | 23 ++++-- 2 files changed, 85 insertions(+), 9 deletions(-) diff --git a/app-android/app/src/main/java/com/huaga/life_echo/ui/components/chat/MessageBubble.kt b/app-android/app/src/main/java/com/huaga/life_echo/ui/components/chat/MessageBubble.kt index f16bc19..f87b989 100644 --- a/app-android/app/src/main/java/com/huaga/life_echo/ui/components/chat/MessageBubble.kt +++ b/app-android/app/src/main/java/com/huaga/life_echo/ui/components/chat/MessageBubble.kt @@ -8,6 +8,11 @@ import androidx.compose.material3.CardDefaults import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Text import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.shadow @@ -38,14 +43,14 @@ fun UserMessageBubble( .shadow(2.dp, RoundedCornerShape(12.dp)), shape = RoundedCornerShape(12.dp), colors = CardDefaults.cardColors( - containerColor = LightPurple.copy(alpha = 0.2f) + containerColor = LightPurple // 使用完整的紫色,不再使用透明度 ) ) { Text( text = text, modifier = Modifier.padding(12.dp), fontSize = 14.sp, - color = MaterialTheme.colorScheme.onSurface, + color = Color.White, // 使用白色文字,确保在紫色背景上清晰可见 lineHeight = 20.sp ) } @@ -87,3 +92,65 @@ fun AIMessageBubble( } } } + +/** + * 流式AI消息气泡(带光标闪烁效果) + */ +@Composable +fun StreamingAIMessageBubble( + text: String, + modifier: Modifier = Modifier +) { + var showCursor by remember { mutableStateOf(true) } + + // 光标闪烁动画 + LaunchedEffect(Unit) { + while (true) { + showCursor = true + kotlinx.coroutines.delay(500) + showCursor = false + kotlinx.coroutines.delay(500) + } + } + + Row( + modifier = modifier + .fillMaxWidth() + .padding(horizontal = 16.dp, vertical = 8.dp), + horizontalArrangement = androidx.compose.foundation.layout.Arrangement.Start + ) { + Card( + modifier = Modifier + .weight(1f) + .shadow(2.dp, RoundedCornerShape(12.dp)), + shape = RoundedCornerShape(12.dp), + colors = CardDefaults.cardColors( + containerColor = MaterialTheme.colorScheme.surface + ) + ) { + Row( + modifier = Modifier.padding(12.dp), + verticalAlignment = androidx.compose.ui.Alignment.CenterVertically + ) { + Text( + text = text, + fontSize = 14.sp, + color = MaterialTheme.colorScheme.onSurface, + lineHeight = 20.sp + ) + // 光标闪烁效果 + if (showCursor) { + Text( + text = "▊", + fontSize = 14.sp, + color = MaterialTheme.colorScheme.primary, + fontWeight = FontWeight.Bold, + modifier = Modifier.padding(start = 2.dp) + ) + } else { + Spacer(modifier = Modifier.width(8.dp)) + } + } + } + } +} diff --git a/app-android/app/src/main/java/com/huaga/life_echo/ui/components/chat/MessageList.kt b/app-android/app/src/main/java/com/huaga/life_echo/ui/components/chat/MessageList.kt index ebac9f9..90df1b1 100644 --- a/app-android/app/src/main/java/com/huaga/life_echo/ui/components/chat/MessageList.kt +++ b/app-android/app/src/main/java/com/huaga/life_echo/ui/components/chat/MessageList.kt @@ -20,6 +20,7 @@ import androidx.compose.ui.unit.sp import com.huaga.life_echo.network.models.MessageDto import com.huaga.life_echo.ui.theme.LightPurple import com.huaga.life_echo.utils.TimeUtils +import kotlinx.coroutines.delay /** * 消息列表组件 @@ -35,10 +36,18 @@ fun MessageList( ) { val listState = rememberLazyListState() - // 自动滚动到底部 - LaunchedEffect(messages.size, isStreaming) { - if (messages.isNotEmpty() || isStreaming) { - listState.animateScrollToItem(messages.size) + // 自动滚动到底部 - 改进:流式输出时实时滚动 + LaunchedEffect(messages.size, isStreaming, streamingText) { + val targetIndex = messages.size + if (isStreaming) 1 else 0 + if (targetIndex > 0) { + // 流式输出时使用平滑滚动,其他情况使用动画滚动 + if (isStreaming && streamingText.isNotEmpty()) { + // 流式输出时,每次文本更新都滚动到底部 + kotlinx.coroutines.delay(50) // 短暂延迟确保内容已渲染 + listState.animateScrollToItem(targetIndex) + } else { + listState.animateScrollToItem(targetIndex) + } } } @@ -78,10 +87,10 @@ fun MessageList( lastDate = currentDate } - // 流式消息显示 + // 流式消息显示 - 使用专门的流式消息气泡组件 if (isStreaming) { - item { - AIMessageBubble( + item(key = "streaming_message") { + StreamingAIMessageBubble( text = streamingText ) }