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.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.Brush
import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.Color
import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp 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 @Composable
fun ChatHeader( fun ChatHeader(
title: String, title: String,
isOnline: Boolean = true, isOnline: Boolean = true,
onBackClick: () -> Unit, 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( Surface(
color = LightPurple, color = backgroundColor,
modifier = modifier.fillMaxWidth() modifier = modifier
.fillMaxWidth()
.then(backgroundModifier)
) { ) {
Row( Row(
modifier = Modifier modifier = Modifier

View File

@@ -14,7 +14,7 @@ import androidx.compose.ui.unit.sp
import com.huaga.life_echo.ui.theme.LightPurple import com.huaga.life_echo.ui.theme.LightPurple
/** /**
* 聊天输入框组件(支持高度自适应) * 聊天输入框组件(支持高度自适应和键盘自适应贴合
*/ */
@Composable @Composable
fun ChatInputField( fun ChatInputField(
@@ -27,13 +27,14 @@ fun ChatInputField(
) { ) {
var textFieldHeight by remember { mutableStateOf(56.dp) } var textFieldHeight by remember { mutableStateOf(56.dp) }
// 使用 windowInsetsPadding 实现键盘自适应贴合,确保输入框紧贴键盘
Surface( Surface(
modifier = modifier modifier = modifier
.fillMaxWidth() .fillMaxWidth()
.shadow(4.dp) .shadow(4.dp)
.windowInsetsPadding(WindowInsets.ime), .windowInsetsPadding(WindowInsets.ime), // 自适应键盘高度,紧贴键盘
color = MaterialTheme.colorScheme.surface, color = MaterialTheme.colorScheme.surface,
shape = RoundedCornerShape(topStart = 16.dp, topEnd = 16.dp) shape = RoundedCornerShape(topStart = 24.dp, topEnd = 24.dp)
) { ) {
Row( Row(
modifier = Modifier modifier = Modifier
@@ -64,7 +65,7 @@ fun ChatInputField(
fontSize = 14.sp fontSize = 14.sp
) )
}, },
shape = RoundedCornerShape(28.dp), shape = RoundedCornerShape(36.dp),
colors = OutlinedTextFieldDefaults.colors( colors = OutlinedTextFieldDefaults.colors(
unfocusedBorderColor = Color.Transparent, unfocusedBorderColor = Color.Transparent,
focusedBorderColor = LightPurple, 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.LazyListState
import androidx.compose.foundation.lazy.rememberLazyListState import androidx.compose.foundation.lazy.rememberLazyListState
import androidx.compose.foundation.shape.RoundedCornerShape 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.MaterialTheme
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
@@ -134,7 +134,7 @@ fun TimeDivider(
verticalAlignment = Alignment.CenterVertically, verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.Center horizontalArrangement = Arrangement.Center
) { ) {
Divider( HorizontalDivider(
modifier = Modifier.weight(1f), modifier = Modifier.weight(1f),
color = MaterialTheme.colorScheme.onSurfaceVariant.copy(alpha = 0.2f) color = MaterialTheme.colorScheme.onSurfaceVariant.copy(alpha = 0.2f)
) )
@@ -146,7 +146,7 @@ fun TimeDivider(
fontWeight = FontWeight.Normal fontWeight = FontWeight.Normal
) )
Spacer(modifier = Modifier.width(8.dp)) Spacer(modifier = Modifier.width(8.dp))
Divider( HorizontalDivider(
modifier = Modifier.weight(1f), modifier = Modifier.weight(1f),
color = MaterialTheme.colorScheme.onSurfaceVariant.copy(alpha = 0.2f) color = MaterialTheme.colorScheme.onSurfaceVariant.copy(alpha = 0.2f)
) )

View File

@@ -39,18 +39,13 @@ fun BookInfoCard(
modifier: Modifier = Modifier modifier: Modifier = Modifier
) { ) {
var isEditingTitle by remember { mutableStateOf(false) } var isEditingTitle by remember { mutableStateOf(false) }
var isEditingSubtitle by remember { mutableStateOf(false) }
var editedTitle by remember { mutableStateOf(book.title) } var editedTitle by remember { mutableStateOf(book.title) }
var editedSubtitle by remember { mutableStateOf(book.subtitle ?: "") }
val keyboardController = LocalSoftwareKeyboardController.current val keyboardController = LocalSoftwareKeyboardController.current
// 当book变化时更新编辑状态 // 当book变化时更新编辑状态
LaunchedEffect(book.title) { LaunchedEffect(book.title) {
editedTitle = book.title editedTitle = book.title
} }
LaunchedEffect(book.subtitle) {
editedSubtitle = book.subtitle ?: ""
}
Card( Card(
modifier = modifier.fillMaxWidth(), 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)) Spacer(modifier = Modifier.height(4.dp))
// 最后更新时间 // 书籍统计信息
Text( Row(
text = TimeUtils.formatUpdateTime(book.lastUpdatedAt), modifier = Modifier.fillMaxWidth(),
fontSize = 12.sp, horizontalArrangement = Arrangement.Center
color = MaterialTheme.colorScheme.onSurfaceVariant ) {
) 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 modifier: Modifier = Modifier
) { ) {
val statusText = when (chapter.status) { val statusText = when (chapter.status) {
"completed" -> "已整理${if (chapter.pageCount != null) " · 约${chapter.pageCount}" else ""}" "completed" -> "已整理"
"partial" -> "部分整理${if (chapter.pageCount != null) " · 约${chapter.pageCount}" else ""}" "partial" -> "部分整理"
else -> "待补充" else -> "待补充"
} }
@@ -62,7 +62,7 @@ fun ChapterCard(
contentAlignment = Alignment.Center contentAlignment = Alignment.Center
) { ) {
Text( Text(
text = String.format("%02d", chapter.orderIndex), text = String.format("%02d", chapter.order_index),
fontSize = 18.sp, fontSize = 18.sp,
fontWeight = FontWeight.Bold, fontWeight = FontWeight.Bold,
color = Color.White color = Color.White