refactor: 优化聊天和回忆录相关UI组件

- 优化ChatHeader聊天头部组件
- 优化ChatInputField聊天输入组件
- 优化MessageList消息列表组件
- 重构BookInfoCard书籍信息卡片
- 优化ChapterCard章节卡片
This commit is contained in:
iammm0
2026-01-22 17:58:37 +08:00
parent 7f4c3ffb9f
commit 7333bc4de5
5 changed files with 74 additions and 81 deletions

View File

@@ -11,6 +11,7 @@ import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.Brush
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp
@@ -20,17 +21,49 @@ import com.huaga.life_echo.ui.theme.LightPurple
/**
* 聊天头部组件
*
* @param title 标题
* @param isOnline 在线状态
* @param onBackClick 返回按钮点击回调
* @param modifier 修饰符
* @param isTransparent 是否透明化默认false
* @param transparencyType 透明化类型0=完全透明, 1=半透明, 2=渐变透明
* @param alpha 透明度0.0-1.0),用于半透明模式
*/
@Composable
fun ChatHeader(
title: String,
isOnline: Boolean = true,
onBackClick: () -> Unit,
modifier: Modifier = Modifier
modifier: Modifier = Modifier,
isTransparent: Boolean = false,
transparencyType: Int = 0, // 0=完全透明, 1=半透明, 2=渐变透明
alpha: Float = 0.5f
) {
val backgroundColor = when {
isTransparent && transparencyType == 0 -> Color.Transparent // 完全透明
isTransparent && transparencyType == 1 -> LightPurple.copy(alpha = alpha) // 半透明
isTransparent && transparencyType == 2 -> Color.Transparent // 渐变透明使用Brush
else -> LightPurple // 不透明
}
val backgroundModifier = when {
isTransparent && transparencyType == 2 -> Modifier.background(
Brush.verticalGradient(
colors = listOf(
LightPurple.copy(alpha = 0.95f),
LightPurple.copy(alpha = 0.0f)
)
)
)
else -> Modifier
}
Surface(
color = LightPurple,
modifier = modifier.fillMaxWidth()
color = backgroundColor,
modifier = modifier
.fillMaxWidth()
.then(backgroundModifier)
) {
Row(
modifier = Modifier

View File

@@ -14,7 +14,7 @@ import androidx.compose.ui.unit.sp
import com.huaga.life_echo.ui.theme.LightPurple
/**
* 聊天输入框组件(支持高度自适应)
* 聊天输入框组件(支持高度自适应和键盘自适应贴合
*/
@Composable
fun ChatInputField(
@@ -27,13 +27,14 @@ fun ChatInputField(
) {
var textFieldHeight by remember { mutableStateOf(56.dp) }
// 使用 windowInsetsPadding 实现键盘自适应贴合,确保输入框紧贴键盘
Surface(
modifier = modifier
.fillMaxWidth()
.shadow(4.dp)
.windowInsetsPadding(WindowInsets.ime),
.windowInsetsPadding(WindowInsets.ime), // 自适应键盘高度,紧贴键盘
color = MaterialTheme.colorScheme.surface,
shape = RoundedCornerShape(topStart = 16.dp, topEnd = 16.dp)
shape = RoundedCornerShape(topStart = 24.dp, topEnd = 24.dp)
) {
Row(
modifier = Modifier
@@ -64,7 +65,7 @@ fun ChatInputField(
fontSize = 14.sp
)
},
shape = RoundedCornerShape(28.dp),
shape = RoundedCornerShape(36.dp),
colors = OutlinedTextFieldDefaults.colors(
unfocusedBorderColor = Color.Transparent,
focusedBorderColor = LightPurple,

View File

@@ -6,7 +6,7 @@ import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.LazyListState
import androidx.compose.foundation.lazy.rememberLazyListState
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.Divider
import androidx.compose.material3.HorizontalDivider
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
@@ -134,7 +134,7 @@ fun TimeDivider(
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.Center
) {
Divider(
HorizontalDivider(
modifier = Modifier.weight(1f),
color = MaterialTheme.colorScheme.onSurfaceVariant.copy(alpha = 0.2f)
)
@@ -146,7 +146,7 @@ fun TimeDivider(
fontWeight = FontWeight.Normal
)
Spacer(modifier = Modifier.width(8.dp))
Divider(
HorizontalDivider(
modifier = Modifier.weight(1f),
color = MaterialTheme.colorScheme.onSurfaceVariant.copy(alpha = 0.2f)
)

View File

@@ -39,18 +39,13 @@ fun BookInfoCard(
modifier: Modifier = Modifier
) {
var isEditingTitle by remember { mutableStateOf(false) }
var isEditingSubtitle by remember { mutableStateOf(false) }
var editedTitle by remember { mutableStateOf(book.title) }
var editedSubtitle by remember { mutableStateOf(book.subtitle ?: "") }
val keyboardController = LocalSoftwareKeyboardController.current
// 当book变化时更新编辑状态
LaunchedEffect(book.title) {
editedTitle = book.title
}
LaunchedEffect(book.subtitle) {
editedSubtitle = book.subtitle ?: ""
}
Card(
modifier = modifier.fillMaxWidth(),
@@ -114,71 +109,35 @@ fun BookInfoCard(
}
}
Spacer(modifier = Modifier.height(8.dp))
// 副标题(可选,可编辑)
if (book.subtitle != null || isEditingSubtitle) {
if (isEditingSubtitle) {
TextField(
value = editedSubtitle,
onValueChange = { editedSubtitle = it },
singleLine = true,
keyboardOptions = KeyboardOptions(imeAction = ImeAction.Done),
keyboardActions = KeyboardActions(
onDone = {
isEditingSubtitle = false
keyboardController?.hide()
onSubtitleChange?.invoke(if (editedSubtitle.isNotBlank()) editedSubtitle else null)
}
),
placeholder = {
Text("副标题(可选)")
},
colors = TextFieldDefaults.colors(
focusedTextColor = MaterialTheme.colorScheme.onSurfaceVariant,
unfocusedTextColor = MaterialTheme.colorScheme.onSurfaceVariant
),
textStyle = MaterialTheme.typography.titleMedium
)
} else {
Row(
modifier = Modifier
.clickable { isEditingSubtitle = true }
.padding(vertical = 4.dp),
verticalAlignment = Alignment.CenterVertically
) {
Text(
text = book.subtitle ?: "",
fontSize = 18.sp,
color = MaterialTheme.colorScheme.primary
)
Spacer(modifier = Modifier.width(8.dp))
Icon(
imageVector = AppIcons.Edit,
contentDescription = "编辑",
tint = MaterialTheme.colorScheme.onSurfaceVariant,
modifier = Modifier.size(16.dp)
)
}
}
} else {
// 添加副标题按钮
Text(
text = "+ 添加副标题",
fontSize = 14.sp,
color = MaterialTheme.colorScheme.primary.copy(alpha = 0.6f),
modifier = Modifier.clickable { isEditingSubtitle = true }
)
}
Spacer(modifier = Modifier.height(4.dp))
// 最后更新时间
Text(
text = TimeUtils.formatUpdateTime(book.lastUpdatedAt),
fontSize = 12.sp,
color = MaterialTheme.colorScheme.onSurfaceVariant
)
// 书籍统计信息
Row(
modifier = Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.Center
) {
if (book.total_words != null && book.total_words > 0) {
Text(
text = "${book.total_words}",
fontSize = 12.sp,
color = MaterialTheme.colorScheme.onSurfaceVariant
)
}
if (book.total_pages != null && book.total_pages > 0) {
if (book.total_words != null && book.total_words > 0) {
Text(
text = " · ",
fontSize = 12.sp,
color = MaterialTheme.colorScheme.onSurfaceVariant
)
}
Text(
text = "${book.total_pages}",
fontSize = 12.sp,
color = MaterialTheme.colorScheme.onSurfaceVariant
)
}
}
}
}
}

View File

@@ -32,8 +32,8 @@ fun ChapterCard(
modifier: Modifier = Modifier
) {
val statusText = when (chapter.status) {
"completed" -> "已整理${if (chapter.pageCount != null) " · 约${chapter.pageCount}" else ""}"
"partial" -> "部分整理${if (chapter.pageCount != null) " · 约${chapter.pageCount}" else ""}"
"completed" -> "已整理"
"partial" -> "部分整理"
else -> "待补充"
}
@@ -62,7 +62,7 @@ fun ChapterCard(
contentAlignment = Alignment.Center
) {
Text(
text = String.format("%02d", chapter.orderIndex),
text = String.format("%02d", chapter.order_index),
fontSize = 18.sp,
fontWeight = FontWeight.Bold,
color = Color.White