style(ui): 列表项加卡片容器;登出移到设置页底部;按钮改矢量图标

新增 PreferenceCard(BasicComponent 本身无背景/圆角);抽屉去掉登出、新建与删除改图标按钮;设置页返回改 ChevronBackward、底部新增登出图标。
This commit is contained in:
AskaEth committed 2026-09-08 23:13:00 +08:00
1 parent df2a26701c
commit cf291b58ab
4 files changed
+116 -56

No files matched your search

@@ -36,7 +36,11 @@ fun ChatHomeScreen(
BackHandler(enabled = drawerOpen) { drawerOpen = false } BackHandler(enabled = drawerOpen) { drawerOpen = false }
if (showSettings) { if (showSettings) {
SettingsScreen(container = container, onBack = { showSettings = false }) SettingsScreen(
container = container,
onBack = { showSettings = false },
onLogout = onLogout,
)
} else { } else {
MiuixDrawer( MiuixDrawer(
open = drawerOpen, open = drawerOpen,
@@ -63,7 +67,6 @@ fun ChatHomeScreen(
drawerOpen = false drawerOpen = false
showSettings = true showSettings = true
}, },
onLogout = onLogout,
) )
}, },
) )
@@ -0,0 +1,33 @@
package top.yeij.cyrene.ui.common
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.unit.dp
import top.yukonga.miuix.kmp.theme.MiuixTheme
/**
* Miuix 的 `BasicComponent` / Preference 系列本身**没有背景与圆角**(只是可点击的 Column),
* 需要外面包一层卡片容器才能得到 MD3 的「小圆角卡片」外观。
*
* 页面底色用 `surface`、卡片用 `surfaceContainer`:浅色下 #F7F7F7 对 #FFFFFF,
* 深色下 #000000 对 #242424,卡片因此能凸显出来。
*/
@Composable
fun PreferenceCard(
modifier: Modifier = Modifier,
content: @Composable () -> Unit,
) {
Box(
modifier = modifier
.fillMaxWidth()
.clip(RoundedCornerShape(16.dp))
.background(MiuixTheme.colorScheme.surfaceContainer),
) {
content()
}
}
@@ -23,12 +23,18 @@ import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.compose.ui.window.Dialog import androidx.compose.ui.window.Dialog
import top.yeij.cyrene.ui.common.PreferenceCard
import top.yukonga.miuix.kmp.basic.BasicComponent import top.yukonga.miuix.kmp.basic.BasicComponent
import top.yukonga.miuix.kmp.basic.Icon
import top.yukonga.miuix.kmp.basic.IconButton
import top.yukonga.miuix.kmp.basic.Text import top.yukonga.miuix.kmp.basic.Text
import top.yukonga.miuix.kmp.basic.TextButton import top.yukonga.miuix.kmp.basic.TextButton
import top.yukonga.miuix.kmp.icon.MiuixIcons
import top.yukonga.miuix.kmp.icon.extended.Add
import top.yukonga.miuix.kmp.icon.extended.Delete
import top.yukonga.miuix.kmp.theme.MiuixTheme import top.yukonga.miuix.kmp.theme.MiuixTheme
/** 侧边栏内容:会话列表 + IoT/设置占位 + 登出。列表项统一用 Miuix 的 MD3 圆角卡片。 */ /** 侧边栏内容:会话列表 + IoT/设置入口。列表项为 MD3 小圆角卡片。 */
@Composable @Composable
fun ColumnScope.SessionDrawerContent( fun ColumnScope.SessionDrawerContent(
state: SessionsUiState, state: SessionsUiState,
@@ -37,7 +43,6 @@ fun ColumnScope.SessionDrawerContent(
onDelete: (SessionItem) -> Unit, onDelete: (SessionItem) -> Unit,
onOpenIot: () -> Unit, onOpenIot: () -> Unit,
onOpenSettings: () -> Unit, onOpenSettings: () -> Unit,
onLogout: () -> Unit,
) { ) {
var pendingDelete by remember { mutableStateOf<SessionItem?>(null) } var pendingDelete by remember { mutableStateOf<SessionItem?>(null) }
@@ -53,11 +58,13 @@ fun ColumnScope.SessionDrawerContent(
Row( Row(
modifier = Modifier modifier = Modifier
.fillMaxWidth() .fillMaxWidth()
.padding(start = 20.dp, end = 12.dp, bottom = 4.dp), .padding(start = 20.dp, end = 8.dp, bottom = 4.dp),
verticalAlignment = Alignment.CenterVertically, verticalAlignment = Alignment.CenterVertically,
) { ) {
Text("会话", style = MiuixTheme.textStyles.subtitle, modifier = Modifier.weight(1f)) Text("会话", style = MiuixTheme.textStyles.subtitle, modifier = Modifier.weight(1f))
TextButton("新建", onClick = onCreate) IconButton(onClick = onCreate) {
Icon(imageVector = MiuixIcons.Add, contentDescription = "新建会话")
}
} }
LazyColumn( LazyColumn(
@@ -91,11 +98,9 @@ fun ColumnScope.SessionDrawerContent(
} }
Spacer(Modifier.height(12.dp)) Spacer(Modifier.height(12.dp))
DrawerAction("IoT(规划中)", onOpenIot) PreferenceCard { BasicComponent(title = "IoT(规划中)", onClick = onOpenIot) }
Spacer(Modifier.height(8.dp)) Spacer(Modifier.height(8.dp))
DrawerAction("App 设置", onOpenSettings) PreferenceCard { BasicComponent(title = "App 设置", onClick = onOpenSettings) }
Spacer(Modifier.height(8.dp))
DrawerAction("登出", onLogout)
Spacer(Modifier.height(16.dp)) Spacer(Modifier.height(16.dp))
pendingDelete?.let { target -> pendingDelete?.let { target ->
@@ -119,6 +124,7 @@ private fun SessionRow(
onClick: () -> Unit, onClick: () -> Unit,
onDelete: () -> Unit, onDelete: () -> Unit,
) { ) {
PreferenceCard {
BasicComponent( BasicComponent(
title = session.title, title = session.title,
onClick = onClick, onClick = onClick,
@@ -128,26 +134,21 @@ private fun SessionRow(
text = "✓", text = "✓",
style = MiuixTheme.textStyles.main, style = MiuixTheme.textStyles.main,
color = MiuixTheme.colorScheme.primary, color = MiuixTheme.colorScheme.primary,
modifier = Modifier.padding(horizontal = 6.dp), modifier = Modifier.padding(horizontal = 4.dp),
) )
} }
if (!session.isMain) { if (!session.isMain) {
Text( IconButton(onClick = onDelete) {
text = "删除", Icon(
style = MiuixTheme.textStyles.footnote1, imageVector = MiuixIcons.Delete,
color = MiuixTheme.colorScheme.error, contentDescription = "删除会话",
modifier = Modifier tint = MiuixTheme.colorScheme.error,
.clickable(onClick = onDelete)
.padding(horizontal = 8.dp, vertical = 4.dp),
) )
} }
}
}, },
) )
} }
@Composable
private fun DrawerAction(label: String, onClick: () -> Unit) {
BasicComponent(title = label, onClick = onClick)
} }
@Composable @Composable
@@ -1,5 +1,6 @@
package top.yeij.cyrene.ui.settings package top.yeij.cyrene.ui.settings
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.Spacer
@@ -21,11 +22,16 @@ import top.yeij.cyrene.BuildConfig
import top.yeij.cyrene.app.AppContainer import top.yeij.cyrene.app.AppContainer
import top.yeij.cyrene.core.prefs.AppPrefs import top.yeij.cyrene.core.prefs.AppPrefs
import top.yeij.cyrene.core.prefs.ThemeMode import top.yeij.cyrene.core.prefs.ThemeMode
import top.yeij.cyrene.ui.common.PreferenceCard
import top.yukonga.miuix.kmp.basic.BasicComponent import top.yukonga.miuix.kmp.basic.BasicComponent
import top.yukonga.miuix.kmp.basic.Icon
import top.yukonga.miuix.kmp.basic.IconButton
import top.yukonga.miuix.kmp.basic.Scaffold import top.yukonga.miuix.kmp.basic.Scaffold
import top.yukonga.miuix.kmp.basic.SmallTopAppBar import top.yukonga.miuix.kmp.basic.SmallTopAppBar
import top.yukonga.miuix.kmp.basic.Text import top.yukonga.miuix.kmp.basic.Text
import top.yukonga.miuix.kmp.basic.TextButton import top.yukonga.miuix.kmp.icon.MiuixIcons
import top.yukonga.miuix.kmp.icon.extended.Back
import top.yukonga.miuix.kmp.icon.extended.ChevronBackward
import top.yukonga.miuix.kmp.preference.SwitchPreference import top.yukonga.miuix.kmp.preference.SwitchPreference
import top.yukonga.miuix.kmp.theme.MiuixTheme import top.yukonga.miuix.kmp.theme.MiuixTheme
@@ -33,6 +39,7 @@ import top.yukonga.miuix.kmp.theme.MiuixTheme
fun SettingsScreen( fun SettingsScreen(
container: AppContainer, container: AppContainer,
onBack: () -> Unit, onBack: () -> Unit,
onLogout: () -> Unit = {},
) { ) {
val prefs by container.appSettings.data.collectAsState(initial = AppPrefs()) val prefs by container.appSettings.data.collectAsState(initial = AppPrefs())
val scope = rememberCoroutineScope() val scope = rememberCoroutineScope()
@@ -42,7 +49,11 @@ fun SettingsScreen(
topBar = { topBar = {
SmallTopAppBar( SmallTopAppBar(
title = "App 设置", title = "App 设置",
navigationIcon = { TextButton("返回", onClick = onBack) }, navigationIcon = {
IconButton(onClick = onBack) {
Icon(imageVector = MiuixIcons.ChevronBackward, contentDescription = "返回")
}
},
) )
}, },
) { padding -> ) { padding ->
@@ -54,44 +65,77 @@ fun SettingsScreen(
) { ) {
SectionTitle("外观") SectionTitle("外观")
ThemeMode.entries.forEach { mode -> ThemeMode.entries.forEach { mode ->
ThemeOption( PreferenceCard {
label = mode.label(), BasicComponent(
selected = prefs.themeMode == mode, title = mode.label(),
onClick = { scope.launch { settings.setThemeMode(mode) } }, onClick = { scope.launch { settings.setThemeMode(mode) } },
endActions = {
if (prefs.themeMode == mode) {
Text(
text = "✓",
style = MiuixTheme.textStyles.main,
color = MiuixTheme.colorScheme.primary,
) )
}
},
)
}
Spacer(Modifier.height(8.dp)) Spacer(Modifier.height(8.dp))
} }
SectionTitle("聊天") SectionTitle("聊天")
PreferenceCard {
SwitchPreference( SwitchPreference(
title = "显示旁白", title = "显示旁白",
summary = "以灰斜体小字显示 <action> / <narration>", summary = "以灰斜体小字显示 <action> / <narration>",
checked = prefs.showNarration, checked = prefs.showNarration,
onCheckedChange = { scope.launch { settings.setShowNarration(it) } }, onCheckedChange = { scope.launch { settings.setShowNarration(it) } },
) )
}
Spacer(Modifier.height(8.dp)) Spacer(Modifier.height(8.dp))
PreferenceCard {
SwitchPreference( SwitchPreference(
title = "思维链默认展开", title = "思维链默认展开",
summary = "流式期间展开思维链,结束后自动折叠", summary = "流式期间展开思维链,结束后自动折叠",
checked = prefs.thinkingExpanded, checked = prefs.thinkingExpanded,
onCheckedChange = { scope.launch { settings.setThinkingExpanded(it) } }, onCheckedChange = { scope.launch { settings.setThinkingExpanded(it) } },
) )
}
SectionTitle("关于") SectionTitle("关于")
Row( PreferenceCard {
modifier = Modifier BasicComponent(
.fillMaxWidth() title = "版本",
.padding(horizontal = 20.dp, vertical = 14.dp), summary = null,
verticalAlignment = Alignment.CenterVertically, endActions = {
) {
Text("版本", style = MiuixTheme.textStyles.main, modifier = Modifier.weight(1f))
Text( Text(
text = "${BuildConfig.VERSION_NAME} (${BuildConfig.VERSION_CODE})", text = "${BuildConfig.VERSION_NAME} (${BuildConfig.VERSION_CODE})",
style = MiuixTheme.textStyles.footnote1, style = MiuixTheme.textStyles.footnote1,
color = MiuixTheme.colorScheme.onSurfaceVariantSummary, color = MiuixTheme.colorScheme.onSurfaceVariantSummary,
) )
},
)
} }
Spacer(Modifier.height(24.dp))
Spacer(Modifier.height(32.dp))
PreferenceCard {
Row(
modifier = Modifier
.fillMaxWidth()
.padding(vertical = 8.dp),
horizontalArrangement = Arrangement.Center,
verticalAlignment = Alignment.CenterVertically,
) {
IconButton(onClick = onLogout) {
Icon(
imageVector = MiuixIcons.Back,
contentDescription = "登出",
tint = MiuixTheme.colorScheme.error,
)
}
}
}
Spacer(Modifier.height(32.dp))
} }
} }
} }
@@ -106,27 +150,6 @@ private fun SectionTitle(text: String) {
) )
} }
@Composable
private fun ThemeOption(
label: String,
selected: Boolean,
onClick: () -> Unit,
) {
BasicComponent(
title = label,
onClick = onClick,
endActions = {
if (selected) {
Text(
text = "✓",
style = MiuixTheme.textStyles.main,
color = MiuixTheme.colorScheme.primary,
)
}
},
)
}
private fun ThemeMode.label(): String = when (this) { private fun ThemeMode.label(): String = when (this) {
ThemeMode.System -> "跟随系统" ThemeMode.System -> "跟随系统"
ThemeMode.Light -> "浅色" ThemeMode.Light -> "浅色"