refactor: 优化前端UI组件
- 优化MessageBubble消息气泡组件 - 优化ErrorView错误视图组件 - 优化WebSocketDebugPanel调试面板 - 优化ChapterCard章节卡片组件 - 优化ChapterReadingView章节阅读视图 - 优化FullTextReadingView全文阅读视图 - 优化OrganizeConversationDialog组织对话对话框 - 更新AppIcons图标
This commit is contained in:
@@ -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
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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
|
||||
)
|
||||
|
||||
// 引用块
|
||||
|
||||
@@ -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
|
||||
)
|
||||
|
||||
// 引用块
|
||||
|
||||
@@ -62,7 +62,7 @@ fun OrganizeConversationDialog(
|
||||
}
|
||||
}
|
||||
|
||||
Divider()
|
||||
HorizontalDivider()
|
||||
|
||||
// 对话列表
|
||||
if (isLoading) {
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user