refactor: 优化前端UI组件

- 优化MessageBubble消息气泡组件
- 优化ErrorView错误视图组件
- 优化WebSocketDebugPanel调试面板
- 优化ChapterCard章节卡片组件
- 优化ChapterReadingView章节阅读视图
- 优化FullTextReadingView全文阅读视图
- 优化OrganizeConversationDialog组织对话对话框
- 更新AppIcons图标
This commit is contained in:
iammm0
2026-01-28 12:59:32 +08:00
parent 4d5433d2e8
commit d5d8619f22
8 changed files with 104 additions and 26 deletions

View File

@@ -20,6 +20,7 @@ import androidx.compose.ui.graphics.Color
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import com.huaga.life_echo.ui.components.common.MarkdownText
import com.huaga.life_echo.ui.theme.LightPurple
/**
@@ -59,6 +60,7 @@ fun UserMessageBubble(
/**
* AI消息气泡左侧/白色)
* 支持 Markdown 格式渲染
*/
@Composable
fun AIMessageBubble(
@@ -82,12 +84,12 @@ fun AIMessageBubble(
containerColor = MaterialTheme.colorScheme.surface
)
) {
Text(
text = text,
MarkdownText(
content = text,
modifier = Modifier.padding(12.dp),
fontSize = 14.sp,
color = MaterialTheme.colorScheme.onSurface,
lineHeight = 20.sp
textColor = MaterialTheme.colorScheme.onSurface,
fontSize = 14,
lineHeight = 20
)
}
}

View File

@@ -11,17 +11,44 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import com.huaga.life_echo.config.AppConfig
import com.huaga.life_echo.ui.theme.LightPurple
/**
* 错误视图组件
*
* 生产模式下自动转换技术性错误为友好提示
* 开发模式下显示原始错误信息便于调试
*
* @param message 错误信息(可以是原始错误或自定义信息)
* @param errorType 可选的错误类型,用于显示更精确的友好提示
* @param onRetry 重试回调
*/
@Composable
fun ErrorView(
message: String,
errorType: ErrorType? = null,
onRetry: (() -> Unit)? = null,
modifier: Modifier = Modifier
) {
// 如果指定了错误类型,使用友好错误视图
if (errorType != null) {
FriendlyErrorView(
errorType = errorType,
originalMessage = message,
onRetry = onRetry,
modifier = modifier
)
return
}
// 处理显示消息:生产模式下过滤技术性错误
val displayMessage = if (AppConfig.isDebugMode) {
message
} else {
sanitizeErrorMessage(message)
}
Column(
modifier = modifier
.fillMaxWidth()
@@ -35,7 +62,7 @@ fun ErrorView(
)
Spacer(modifier = Modifier.height(16.dp))
Text(
text = message,
text = displayMessage,
fontSize = 16.sp,
color = MaterialTheme.colorScheme.onSurfaceVariant,
textAlign = TextAlign.Center
@@ -53,3 +80,40 @@ fun ErrorView(
}
}
}
/**
* 清理错误消息,将技术性错误转换为用户友好的提示
*/
private fun sanitizeErrorMessage(message: String): String {
val lowerMessage = message.lowercase()
return when {
// 网络相关错误
lowerMessage.contains("timeout") || lowerMessage.contains("timed out") ->
"网络响应超时,请稍后重试"
lowerMessage.contains("connect") || lowerMessage.contains("network") ||
lowerMessage.contains("socket") || lowerMessage.contains("unreachable") ->
"网络连接失败,请检查网络后重试"
// 服务器相关错误
lowerMessage.contains("500") || lowerMessage.contains("502") ||
lowerMessage.contains("503") || lowerMessage.contains("server error") ->
"服务暂时不可用,请稍后重试"
// 认证相关错误
lowerMessage.contains("401") || lowerMessage.contains("unauthorized") ||
lowerMessage.contains("token") && lowerMessage.contains("expired") ->
"登录已过期,请重新登录"
// 资源不存在
lowerMessage.contains("404") || lowerMessage.contains("not found") ->
"内容不存在或已被删除"
// 异常和技术性错误(包含堆栈信息的)
lowerMessage.contains("exception") || lowerMessage.contains("stacktrace") ||
message.contains("\n") || message.length > 100 ->
"操作失败,请稍后重试"
// 保留业务相关的简短错误信息
else -> message
}
}

View File

@@ -114,7 +114,7 @@ fun WebSocketDebugPanel(
DebugInfoRow("是否已连接", if (isConnected) "" else "", if (isConnected) Color(0xFF4CAF50) else Color(0xFFF44336))
DebugInfoRow("对话ID", conversationId ?: "未设置", MaterialTheme.colorScheme.onSurfaceVariant)
Divider(modifier = Modifier.padding(vertical = 4.dp))
HorizontalDivider(modifier = Modifier.padding(vertical = 4.dp))
// 消息统计
DebugInfoRow("消息总数", "$messageCount", MaterialTheme.colorScheme.primary)
@@ -123,7 +123,7 @@ fun WebSocketDebugPanel(
// 最后一条消息信息
if (lastMessageType != null) {
Divider(modifier = Modifier.padding(vertical = 4.dp))
HorizontalDivider(modifier = Modifier.padding(vertical = 4.dp))
DebugInfoRow("最后消息类型", lastMessageType, MaterialTheme.colorScheme.primary)
if (lastMessageTime != null) {
DebugInfoRow("最后消息时间", lastMessageTime, MaterialTheme.colorScheme.onSurfaceVariant)
@@ -132,7 +132,7 @@ fun WebSocketDebugPanel(
// 错误信息
if (errorMessages.isNotEmpty()) {
Divider(modifier = Modifier.padding(vertical = 4.dp))
HorizontalDivider(modifier = Modifier.padding(vertical = 4.dp))
Text(
text = "错误日志",
fontSize = 12.sp,

View File

@@ -8,6 +8,7 @@ import androidx.compose.foundation.layout.*
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.Card
import androidx.compose.material3.CardDefaults
import androidx.compose.material3.HorizontalDivider
import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
@@ -109,7 +110,7 @@ fun ChapterCard(
// 展开时显示详细内容
if (isExpanded) {
androidx.compose.material3.Divider(
HorizontalDivider(
modifier = Modifier.padding(horizontal = 16.dp)
)
Column(

View File

@@ -13,10 +13,12 @@ import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import com.huaga.life_echo.network.models.ChapterContentDto
import com.huaga.life_echo.ui.components.common.MarkdownText
import com.huaga.life_echo.ui.theme.LightPurple
/**
* 章节阅读视图组件
* 支持 Markdown 格式渲染
*/
@Composable
fun ChapterReadingView(
@@ -45,13 +47,13 @@ fun ChapterReadingView(
modifier = Modifier.padding(bottom = 24.dp)
)
// 正文内容
Text(
text = chapter.content,
fontSize = 16.sp,
lineHeight = 28.sp,
color = MaterialTheme.colorScheme.onSurface,
modifier = Modifier.padding(bottom = 16.dp)
// 正文内容(支持 Markdown
MarkdownText(
content = chapter.content,
modifier = Modifier.padding(bottom = 16.dp),
textColor = MaterialTheme.colorScheme.onSurface,
fontSize = 16,
lineHeight = 28
)
// 引用块

View File

@@ -17,11 +17,13 @@ import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import com.huaga.life_echo.network.models.ChapterContentDto
import com.huaga.life_echo.ui.components.common.MarkdownText
import com.huaga.life_echo.ui.icons.AppIcons
import com.huaga.life_echo.ui.theme.LightPurple
/**
* 全文阅读视图组件
* 支持 Markdown 格式渲染
*/
@Composable
fun FullTextReadingView(
@@ -59,13 +61,13 @@ fun FullTextReadingView(
modifier = Modifier.padding(bottom = 16.dp)
)
// 章节内容
Text(
text = chapter.content,
fontSize = 16.sp,
lineHeight = 28.sp,
color = MaterialTheme.colorScheme.onSurface,
modifier = Modifier.padding(bottom = 16.dp)
// 章节内容(支持 Markdown
MarkdownText(
content = chapter.content,
modifier = Modifier.padding(bottom = 16.dp),
textColor = MaterialTheme.colorScheme.onSurface,
fontSize = 16,
lineHeight = 28
)
// 引用块

View File

@@ -62,7 +62,7 @@ fun OrganizeConversationDialog(
}
}
Divider()
HorizontalDivider()
// 对话列表
if (isLoading) {

View File

@@ -3,6 +3,7 @@ package com.huaga.life_echo.ui.icons
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.automirrored.filled.ArrowBack
import androidx.compose.material.icons.automirrored.filled.Chat
import androidx.compose.material.icons.automirrored.filled.ExitToApp
import androidx.compose.material.icons.automirrored.filled.Help
import androidx.compose.material.icons.automirrored.filled.MenuBook
import androidx.compose.material.icons.automirrored.filled.Send
@@ -85,6 +86,12 @@ object AppIcons {
val ManageAccounts = Icons.Default.ManageAccounts
val Lock = Icons.Default.Lock
val Phone = Icons.Default.Phone
val ExitToApp = Icons.Default.ExitToApp
val ExitToApp = Icons.AutoMirrored.Filled.ExitToApp
val DevicesOther = Icons.Default.DevicesOther
// 错误处理图标
val WifiOff = Icons.Default.WifiOff
val CloudOff = Icons.Default.CloudOff
val SearchOff = Icons.Default.SearchOff
val SignalWifiOff = Icons.Default.SignalWifiOff
}