refactor: 优化聊天和回忆录相关UI组件
- 优化ChatHeader聊天头部组件 - 优化ChatInputField聊天输入组件 - 优化MessageList消息列表组件 - 重构BookInfoCard书籍信息卡片 - 优化ChapterCard章节卡片
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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)
|
||||
)
|
||||
|
||||
@@ -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
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user