refactor: 优化前端UI组件
- 优化ConversationListItem对话列表项组件 - 优化ChapterCard章节卡片组件 - 优化ChapterReadingView章节阅读视图 - 优化FullTextReadingView全文阅读视图
This commit is contained in:
@@ -1,15 +1,18 @@
|
|||||||
package com.huaga.life_echo.ui.components.conversation
|
package com.huaga.life_echo.ui.components.conversation
|
||||||
|
|
||||||
import androidx.compose.foundation.background
|
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.layout.*
|
||||||
import androidx.compose.foundation.shape.CircleShape
|
import androidx.compose.foundation.shape.CircleShape
|
||||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||||
import androidx.compose.material3.Icon
|
import androidx.compose.material3.*
|
||||||
import androidx.compose.material3.IconButton
|
|
||||||
import androidx.compose.material3.MaterialTheme
|
|
||||||
import androidx.compose.material3.Text
|
|
||||||
import androidx.compose.runtime.Composable
|
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.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.draw.clip
|
import androidx.compose.ui.draw.clip
|
||||||
@@ -26,21 +29,52 @@ import com.huaga.life_echo.utils.TextUtils
|
|||||||
/**
|
/**
|
||||||
* 对话列表项组件
|
* 对话列表项组件
|
||||||
*/
|
*/
|
||||||
|
@OptIn(ExperimentalFoundationApi::class)
|
||||||
@Composable
|
@Composable
|
||||||
fun ConversationListItem(
|
fun ConversationListItem(
|
||||||
conversation: ConversationListItemDto,
|
conversation: ConversationListItemDto,
|
||||||
onClick: () -> Unit,
|
onClick: () -> Unit,
|
||||||
onDelete: (() -> Unit)? = null,
|
onDelete: (() -> Unit)? = null,
|
||||||
|
isSelected: Boolean = false,
|
||||||
|
isSelectionMode: Boolean = false,
|
||||||
|
onLongClick: (() -> Unit)? = null,
|
||||||
modifier: Modifier = Modifier
|
modifier: Modifier = Modifier
|
||||||
) {
|
) {
|
||||||
|
var showMenu by remember { mutableStateOf(false) }
|
||||||
|
|
||||||
Row(
|
Row(
|
||||||
modifier = modifier
|
modifier = modifier
|
||||||
.fillMaxWidth()
|
.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),
|
.padding(horizontal = 16.dp, vertical = 12.dp),
|
||||||
verticalAlignment = Alignment.CenterVertically
|
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(
|
Column(
|
||||||
modifier = Modifier.weight(1f)
|
modifier = Modifier.weight(1f)
|
||||||
) {
|
) {
|
||||||
@@ -52,11 +86,13 @@ fun ConversationListItem(
|
|||||||
fontSize = 16.sp,
|
fontSize = 16.sp,
|
||||||
fontWeight = FontWeight.Bold,
|
fontWeight = FontWeight.Bold,
|
||||||
color = MaterialTheme.colorScheme.onSurface,
|
color = MaterialTheme.colorScheme.onSurface,
|
||||||
modifier = Modifier.weight(1f)
|
modifier = Modifier.weight(1f),
|
||||||
|
maxLines = 1
|
||||||
)
|
)
|
||||||
|
|
||||||
// 未读消息数
|
// 未读消息数
|
||||||
if (conversation.unreadCount > 0) {
|
if (conversation.unreadCount > 0) {
|
||||||
|
Spacer(modifier = Modifier.width(4.dp))
|
||||||
Box(
|
Box(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.size(18.dp)
|
.size(18.dp)
|
||||||
@@ -77,10 +113,10 @@ fun ConversationListItem(
|
|||||||
Spacer(modifier = Modifier.height(4.dp))
|
Spacer(modifier = Modifier.height(4.dp))
|
||||||
|
|
||||||
Text(
|
Text(
|
||||||
text = TextUtils.ellipsizeSingleLine(conversation.latestMessagePreview, 50),
|
text = TextUtils.ellipsizeSingleLine(conversation.latestMessagePreview, 100),
|
||||||
fontSize = 14.sp,
|
fontSize = 14.sp,
|
||||||
color = MaterialTheme.colorScheme.onSurfaceVariant,
|
color = MaterialTheme.colorScheme.onSurfaceVariant,
|
||||||
maxLines = 1
|
maxLines = 2
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -92,19 +128,41 @@ fun ConversationListItem(
|
|||||||
modifier = Modifier.padding(start = 8.dp)
|
modifier = Modifier.padding(start = 8.dp)
|
||||||
)
|
)
|
||||||
|
|
||||||
// 删除按钮
|
// 三个点菜单按钮(仅在非多选模式时显示)
|
||||||
if (onDelete != null) {
|
if (onDelete != null && !isSelectionMode) {
|
||||||
Spacer(modifier = Modifier.width(8.dp))
|
Spacer(modifier = Modifier.width(4.dp))
|
||||||
IconButton(
|
Box {
|
||||||
onClick = { onDelete() },
|
IconButton(
|
||||||
modifier = Modifier.size(40.dp)
|
onClick = { showMenu = true },
|
||||||
) {
|
modifier = Modifier.size(40.dp)
|
||||||
Icon(
|
) {
|
||||||
imageVector = AppIcons.Delete,
|
Icon(
|
||||||
contentDescription = "删除",
|
imageVector = AppIcons.MoreVert,
|
||||||
tint = MaterialTheme.colorScheme.error,
|
contentDescription = "更多选项",
|
||||||
modifier = Modifier.size(20.dp)
|
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(
|
Box(
|
||||||
modifier = modifier
|
modifier = modifier
|
||||||
.clip(RoundedCornerShape(8.dp))
|
.clip(RoundedCornerShape(8.dp))
|
||||||
.background(LightPurple),
|
.background(if (isDefaultAssistant) LightPurple else MaterialTheme.colorScheme.primaryContainer),
|
||||||
contentAlignment = Alignment.Center
|
contentAlignment = Alignment.Center
|
||||||
) {
|
) {
|
||||||
if (avatarUrl != null) {
|
if (avatarUrl != null && !isDefaultAssistant) {
|
||||||
// TODO: 使用Coil或Glide加载网络图片
|
// TODO: 使用Coil或Glide加载网络图片
|
||||||
// 暂时显示图标
|
// 暂时显示图标
|
||||||
Icon(
|
Icon(
|
||||||
imageVector = AppIcons.Conversation,
|
imageVector = AppIcons.Conversation,
|
||||||
contentDescription = "头像",
|
contentDescription = "头像",
|
||||||
tint = Color.White,
|
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 {
|
} else {
|
||||||
Icon(
|
Icon(
|
||||||
imageVector = if (isDefaultAssistant) AppIcons.Book else AppIcons.Conversation,
|
imageVector = AppIcons.Conversation,
|
||||||
contentDescription = "头像",
|
contentDescription = "头像",
|
||||||
tint = Color.White,
|
tint = Color.White,
|
||||||
modifier = Modifier.size(24.dp)
|
modifier = Modifier.size(32.dp)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,7 +9,6 @@ import androidx.compose.foundation.shape.RoundedCornerShape
|
|||||||
import androidx.compose.material3.Card
|
import androidx.compose.material3.Card
|
||||||
import androidx.compose.material3.CardDefaults
|
import androidx.compose.material3.CardDefaults
|
||||||
import androidx.compose.material3.HorizontalDivider
|
import androidx.compose.material3.HorizontalDivider
|
||||||
import androidx.compose.material3.Icon
|
|
||||||
import androidx.compose.material3.MaterialTheme
|
import androidx.compose.material3.MaterialTheme
|
||||||
import androidx.compose.material3.Text
|
import androidx.compose.material3.Text
|
||||||
import androidx.compose.runtime.*
|
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.dp
|
||||||
import androidx.compose.ui.unit.sp
|
import androidx.compose.ui.unit.sp
|
||||||
import com.huaga.life_echo.network.models.ChapterDto
|
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.ui.theme.LightPurple
|
||||||
|
import com.huaga.life_echo.utils.TextUtils
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 章节卡片组件(可展开显示详细内容)
|
* 章节卡片组件(可展开显示详细内容)
|
||||||
@@ -72,8 +72,8 @@ fun ChapterCard(
|
|||||||
contentAlignment = Alignment.Center
|
contentAlignment = Alignment.Center
|
||||||
) {
|
) {
|
||||||
Text(
|
Text(
|
||||||
text = String.format("%02d", chapter.order_index),
|
text = "第${chapter.order_index}章",
|
||||||
fontSize = 18.sp,
|
fontSize = 14.sp,
|
||||||
fontWeight = FontWeight.Bold,
|
fontWeight = FontWeight.Bold,
|
||||||
color = Color.White
|
color = Color.White
|
||||||
)
|
)
|
||||||
@@ -98,14 +98,6 @@ fun ChapterCard(
|
|||||||
color = MaterialTheme.colorScheme.onSurfaceVariant
|
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()
|
.fillMaxWidth()
|
||||||
.padding(16.dp)
|
.padding(16.dp)
|
||||||
) {
|
) {
|
||||||
Text(
|
// 使用Markdown渲染,并移除{{IMAGE}}占位符(如果没有图片)
|
||||||
text = chapter.content,
|
val processedContent = TextUtils.removeImagePlaceholders(
|
||||||
fontSize = 14.sp,
|
chapter.content,
|
||||||
color = MaterialTheme.colorScheme.onSurface,
|
hasImages = chapter.images.isNotEmpty()
|
||||||
lineHeight = 22.sp
|
)
|
||||||
|
|
||||||
|
MarkdownText(
|
||||||
|
content = processedContent,
|
||||||
|
modifier = Modifier.fillMaxWidth(),
|
||||||
|
textColor = MaterialTheme.colorScheme.onSurface,
|
||||||
|
fontSize = 14,
|
||||||
|
lineHeight = 22
|
||||||
)
|
)
|
||||||
Spacer(modifier = Modifier.height(12.dp))
|
Spacer(modifier = Modifier.height(12.dp))
|
||||||
// 查看详情按钮
|
// 查看详情按钮
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ import androidx.compose.ui.unit.sp
|
|||||||
import com.huaga.life_echo.network.models.ChapterContentDto
|
import com.huaga.life_echo.network.models.ChapterContentDto
|
||||||
import com.huaga.life_echo.ui.components.common.MarkdownText
|
import com.huaga.life_echo.ui.components.common.MarkdownText
|
||||||
import com.huaga.life_echo.ui.theme.LightPurple
|
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)
|
modifier = Modifier.padding(bottom = 24.dp)
|
||||||
)
|
)
|
||||||
|
|
||||||
// 正文内容(支持 Markdown)
|
// 正文内容(支持 Markdown,移除{{IMAGE}}占位符如果没有图片)
|
||||||
|
val processedContent = TextUtils.removeImagePlaceholders(
|
||||||
|
chapter.content,
|
||||||
|
hasImages = chapter.images.isNotEmpty()
|
||||||
|
)
|
||||||
MarkdownText(
|
MarkdownText(
|
||||||
content = chapter.content,
|
content = processedContent,
|
||||||
modifier = Modifier.padding(bottom = 16.dp),
|
modifier = Modifier.padding(bottom = 16.dp),
|
||||||
textColor = MaterialTheme.colorScheme.onSurface,
|
textColor = MaterialTheme.colorScheme.onSurface,
|
||||||
fontSize = 16,
|
fontSize = 16,
|
||||||
|
|||||||
@@ -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.components.common.MarkdownText
|
||||||
import com.huaga.life_echo.ui.icons.AppIcons
|
import com.huaga.life_echo.ui.icons.AppIcons
|
||||||
import com.huaga.life_echo.ui.theme.LightPurple
|
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)
|
modifier = Modifier.padding(bottom = 16.dp)
|
||||||
)
|
)
|
||||||
|
|
||||||
// 章节内容(支持 Markdown)
|
// 章节内容(支持 Markdown,移除{{IMAGE}}占位符如果没有图片)
|
||||||
|
val processedContent = TextUtils.removeImagePlaceholders(
|
||||||
|
chapter.content,
|
||||||
|
hasImages = chapter.images.isNotEmpty()
|
||||||
|
)
|
||||||
MarkdownText(
|
MarkdownText(
|
||||||
content = chapter.content,
|
content = processedContent,
|
||||||
modifier = Modifier.padding(bottom = 16.dp),
|
modifier = Modifier.padding(bottom = 16.dp),
|
||||||
textColor = MaterialTheme.colorScheme.onSurface,
|
textColor = MaterialTheme.colorScheme.onSurface,
|
||||||
fontSize = 16,
|
fontSize = 16,
|
||||||
|
|||||||
Reference in New Issue
Block a user