refactor: 优化前端UI组件

- 优化ConversationListItem对话列表项组件
- 优化ChapterCard章节卡片组件
- 优化ChapterReadingView章节阅读视图
- 优化FullTextReadingView全文阅读视图
This commit is contained in:
iammm0
2026-01-29 10:57:13 +08:00
parent 2b9f79070d
commit 5508d94e54
4 changed files with 124 additions and 49 deletions

View File

@@ -1,15 +1,18 @@
package com.huaga.life_echo.ui.components.conversation
import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
import androidx.compose.foundation.combinedClickable
import androidx.compose.foundation.ExperimentalFoundationApi
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.material3.*
import androidx.compose.runtime.Composable
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.clip
@@ -26,21 +29,52 @@ import com.huaga.life_echo.utils.TextUtils
/**
* 对话列表项组件
*/
@OptIn(ExperimentalFoundationApi::class)
@Composable
fun ConversationListItem(
conversation: ConversationListItemDto,
onClick: () -> Unit,
onDelete: (() -> Unit)? = null,
isSelected: Boolean = false,
isSelectionMode: Boolean = false,
onLongClick: (() -> Unit)? = null,
modifier: Modifier = Modifier
) {
var showMenu by remember { mutableStateOf(false) }
Row(
modifier = modifier
.fillMaxWidth()
.clickable { onClick() }
.combinedClickable(
onClick = onClick,
onLongClick = onLongClick ?: {}
)
.background(
if (isSelected) LightPurple.copy(alpha = 0.1f)
else Color.Transparent
)
.padding(horizontal = 16.dp, vertical = 12.dp),
verticalAlignment = Alignment.CenterVertically
) {
// 对话信息(暂时不显示头像
// 选择框(仅在多选模式时显示
if (isSelectionMode) {
Checkbox(
checked = isSelected,
onCheckedChange = { onClick() },
modifier = Modifier.padding(end = 12.dp)
)
}
// 头像
ConversationAvatar(
avatarUrl = conversation.avatarUrl,
isDefaultAssistant = conversation.isDefaultAssistant,
modifier = Modifier.size(48.dp)
)
Spacer(modifier = Modifier.width(12.dp))
// 对话信息
Column(
modifier = Modifier.weight(1f)
) {
@@ -52,11 +86,13 @@ fun ConversationListItem(
fontSize = 16.sp,
fontWeight = FontWeight.Bold,
color = MaterialTheme.colorScheme.onSurface,
modifier = Modifier.weight(1f)
modifier = Modifier.weight(1f),
maxLines = 1
)
// 未读消息数
if (conversation.unreadCount > 0) {
Spacer(modifier = Modifier.width(4.dp))
Box(
modifier = Modifier
.size(18.dp)
@@ -77,10 +113,10 @@ fun ConversationListItem(
Spacer(modifier = Modifier.height(4.dp))
Text(
text = TextUtils.ellipsizeSingleLine(conversation.latestMessagePreview, 50),
text = TextUtils.ellipsizeSingleLine(conversation.latestMessagePreview, 100),
fontSize = 14.sp,
color = MaterialTheme.colorScheme.onSurfaceVariant,
maxLines = 1
maxLines = 2
)
}
@@ -92,19 +128,41 @@ fun ConversationListItem(
modifier = Modifier.padding(start = 8.dp)
)
// 删除按钮
if (onDelete != null) {
Spacer(modifier = Modifier.width(8.dp))
IconButton(
onClick = { onDelete() },
modifier = Modifier.size(40.dp)
) {
Icon(
imageVector = AppIcons.Delete,
contentDescription = "删除",
tint = MaterialTheme.colorScheme.error,
modifier = Modifier.size(20.dp)
)
// 三个点菜单按钮(仅在非多选模式时显示)
if (onDelete != null && !isSelectionMode) {
Spacer(modifier = Modifier.width(4.dp))
Box {
IconButton(
onClick = { showMenu = true },
modifier = Modifier.size(40.dp)
) {
Icon(
imageVector = AppIcons.MoreVert,
contentDescription = "更多选项",
tint = MaterialTheme.colorScheme.onSurfaceVariant,
modifier = Modifier.size(20.dp)
)
}
DropdownMenu(
expanded = showMenu,
onDismissRequest = { showMenu = false }
) {
DropdownMenuItem(
text = { Text("删除", color = MaterialTheme.colorScheme.error) },
onClick = {
showMenu = false
onDelete()
},
leadingIcon = {
Icon(
imageVector = AppIcons.Delete,
contentDescription = null,
tint = MaterialTheme.colorScheme.error
)
}
)
}
}
}
}
@@ -122,24 +180,32 @@ fun ConversationAvatar(
Box(
modifier = modifier
.clip(RoundedCornerShape(8.dp))
.background(LightPurple),
.background(if (isDefaultAssistant) LightPurple else MaterialTheme.colorScheme.primaryContainer),
contentAlignment = Alignment.Center
) {
if (avatarUrl != null) {
if (avatarUrl != null && !isDefaultAssistant) {
// TODO: 使用Coil或Glide加载网络图片
// 暂时显示图标
Icon(
imageVector = AppIcons.Conversation,
contentDescription = "头像",
tint = Color.White,
modifier = Modifier.size(24.dp)
modifier = Modifier.size(32.dp)
)
} else if (isDefaultAssistant) {
// 回忆录助手使用应用图标使用Book图标作为占位符实际应该加载应用图标
Icon(
imageVector = AppIcons.Book,
contentDescription = "回忆录助手",
tint = Color.White,
modifier = Modifier.size(32.dp)
)
} else {
Icon(
imageVector = if (isDefaultAssistant) AppIcons.Book else AppIcons.Conversation,
imageVector = AppIcons.Conversation,
contentDescription = "头像",
tint = Color.White,
modifier = Modifier.size(24.dp)
modifier = Modifier.size(32.dp)
)
}
}

View File

@@ -9,7 +9,6 @@ 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
import androidx.compose.runtime.*
@@ -22,8 +21,9 @@ 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.ChapterDto
import com.huaga.life_echo.ui.icons.AppIcons
import com.huaga.life_echo.ui.components.common.MarkdownText
import com.huaga.life_echo.ui.theme.LightPurple
import com.huaga.life_echo.utils.TextUtils
/**
* 章节卡片组件(可展开显示详细内容)
@@ -72,8 +72,8 @@ fun ChapterCard(
contentAlignment = Alignment.Center
) {
Text(
text = String.format("%02d", chapter.order_index),
fontSize = 18.sp,
text = "${chapter.order_index}",
fontSize = 14.sp,
fontWeight = FontWeight.Bold,
color = Color.White
)
@@ -98,14 +98,6 @@ fun ChapterCard(
color = MaterialTheme.colorScheme.onSurfaceVariant
)
}
// 展开/收起图标
Icon(
imageVector = if (isExpanded) AppIcons.ExpandLess else AppIcons.ExpandMore,
contentDescription = if (isExpanded) "收起" else "展开",
tint = MaterialTheme.colorScheme.onSurfaceVariant,
modifier = Modifier.size(24.dp)
)
}
// 展开时显示详细内容
@@ -118,11 +110,18 @@ fun ChapterCard(
.fillMaxWidth()
.padding(16.dp)
) {
Text(
text = chapter.content,
fontSize = 14.sp,
color = MaterialTheme.colorScheme.onSurface,
lineHeight = 22.sp
// 使用Markdown渲染并移除{{IMAGE}}占位符(如果没有图片)
val processedContent = TextUtils.removeImagePlaceholders(
chapter.content,
hasImages = chapter.images.isNotEmpty()
)
MarkdownText(
content = processedContent,
modifier = Modifier.fillMaxWidth(),
textColor = MaterialTheme.colorScheme.onSurface,
fontSize = 14,
lineHeight = 22
)
Spacer(modifier = Modifier.height(12.dp))
// 查看详情按钮

View File

@@ -15,6 +15,7 @@ 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
import com.huaga.life_echo.utils.TextUtils
/**
* 章节阅读视图组件
@@ -47,9 +48,13 @@ fun ChapterReadingView(
modifier = Modifier.padding(bottom = 24.dp)
)
// 正文内容(支持 Markdown
// 正文内容(支持 Markdown,移除{{IMAGE}}占位符如果没有图片
val processedContent = TextUtils.removeImagePlaceholders(
chapter.content,
hasImages = chapter.images.isNotEmpty()
)
MarkdownText(
content = chapter.content,
content = processedContent,
modifier = Modifier.padding(bottom = 16.dp),
textColor = MaterialTheme.colorScheme.onSurface,
fontSize = 16,

View File

@@ -20,6 +20,7 @@ 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
import com.huaga.life_echo.utils.TextUtils
/**
* 全文阅读视图组件
@@ -61,9 +62,13 @@ fun FullTextReadingView(
modifier = Modifier.padding(bottom = 16.dp)
)
// 章节内容(支持 Markdown
// 章节内容(支持 Markdown,移除{{IMAGE}}占位符如果没有图片
val processedContent = TextUtils.removeImagePlaceholders(
chapter.content,
hasImages = chapter.images.isNotEmpty()
)
MarkdownText(
content = chapter.content,
content = processedContent,
modifier = Modifier.padding(bottom = 16.dp),
textColor = MaterialTheme.colorScheme.onSurface,
fontSize = 16,