
























@@ -898,32 +898,38 @@ private fun SettingsShellScreen(
898898ProfilePanel(displayName = displayName.ifBlank { "OpenClaw" }, onClick = { onRouteChange(SettingsRoute.Profile) })
899899 }
900900901- item {
902-SettingsGroup(
903- rows =
904-listOf(
905-SettingsRow("Profile", displayName.ifBlank { "Local device" }, Icons.Default.Person, route = SettingsRoute.Profile),
906-SettingsRow("Voice", if (speakerEnabled) "Speaker on" else "Speaker muted", Icons.Default.Mic, route = SettingsRoute.Voice),
907-SettingsRow("Agents", if (agents.isEmpty()) "Load from gateway" else "${agents.size} available", Icons.Default.Person, status = agents.isNotEmpty(), route = SettingsRoute.Agents),
908-SettingsRow("Approvals", approvalsSummary(pendingToolCalls.size), Icons.Default.Lock, status = approvalsStatus(pendingToolCalls.size), route = SettingsRoute.Approvals),
909-SettingsRow("Cron Jobs", cronJobsSummary(cronStatus.jobs), Icons.Outlined.AccessTime, status = if (cronStatus.jobs > 0) cronStatus.enabled else null, route = SettingsRoute.CronJobs),
910-SettingsRow("Usage", usageSummaryText(usageSummary.providers.size), Icons.Default.Storage, status = if (usageSummary.providers.isNotEmpty()) true else null, route = SettingsRoute.Usage),
911-SettingsRow("Skills", skillsSummaryText(skillsSummary.skills), Icons.Default.Settings, status = skillsStatus(skillsSummary.skills), route = SettingsRoute.Skills),
912-SettingsRow("Nodes & Devices", nodesDevicesSummaryText(nodesDevicesSummary), Icons.Default.Cloud, status = nodesDevicesStatus(nodesDevicesSummary), route = SettingsRoute.NodesDevices),
913-SettingsRow("Channels", channelsSummaryText(channelsSummary), Icons.Default.Notifications, status = channelsStatus(channelsSummary), route = SettingsRoute.Channels),
914-SettingsRow("Dreaming", dreamingSummaryText(dreamingSummary), Icons.Default.Storage, status = dreamingStatus(dreamingSummary), route = SettingsRoute.Dreaming),
915-SettingsRow("Canvas", "Screen surface", Icons.AutoMirrored.Filled.ScreenShare, status = isConnected, route = SettingsRoute.Canvas),
916-SettingsRow("Notifications", if (notificationForwardingEnabled) "Smart delivery" else "Off", Icons.Default.Notifications, route = SettingsRoute.Notifications),
917-SettingsRow("Phone Capabilities", if (cameraEnabled) "Camera enabled" else "Locked", Icons.Default.Lock, status = !cameraEnabled, route = SettingsRoute.PhoneCapabilities),
918-SettingsRow("Gateway", gatewaySummary(statusText, isConnected), Icons.Default.Cloud, status = isConnected, route = SettingsRoute.Gateway),
919-SettingsRow("Appearance", appearanceThemeSummary(appearanceThemeMode), Icons.Default.Palette, route = SettingsRoute.Appearance),
920-SettingsRow("Health", "Diagnostics", Icons.Default.Settings, status = isConnected, route = SettingsRoute.Health),
921-SettingsRow("About", "Version and update", Icons.Default.Storage, route = SettingsRoute.About),
922- ),
923- onOpen = onRouteChange,
901+val settingsRows =
902+listOf(
903+SettingsRow("Gateway", gatewaySummary(statusText, isConnected), Icons.Default.Cloud, status = isConnected, route = SettingsRoute.Gateway),
904+SettingsRow("Nodes & Devices", nodesDevicesSummaryText(nodesDevicesSummary), Icons.Default.Cloud, status = nodesDevicesStatus(nodesDevicesSummary), route = SettingsRoute.NodesDevices),
905+SettingsRow("Channels", channelsSummaryText(channelsSummary), Icons.Default.Notifications, status = channelsStatus(channelsSummary), route = SettingsRoute.Channels),
906+SettingsRow("Agents", if (agents.isEmpty()) "Load from gateway" else "${agents.size} available", Icons.Default.Person, status = agents.isNotEmpty(), route = SettingsRoute.Agents),
907+SettingsRow("Approvals", approvalsSummary(pendingToolCalls.size), Icons.Default.Lock, status = approvalsStatus(pendingToolCalls.size), route = SettingsRoute.Approvals),
908+SettingsRow("Cron Jobs", cronJobsSummary(cronStatus.jobs), Icons.Outlined.AccessTime, status = if (cronStatus.jobs > 0) cronStatus.enabled else null, route = SettingsRoute.CronJobs),
909+SettingsRow("Usage", usageSummaryText(usageSummary.providers.size), Icons.Default.Storage, status = if (usageSummary.providers.isNotEmpty()) true else null, route = SettingsRoute.Usage),
910+SettingsRow("Skills", skillsSummaryText(skillsSummary.skills), Icons.Default.Settings, status = skillsStatus(skillsSummary.skills), route = SettingsRoute.Skills),
911+SettingsRow("Dreaming", dreamingSummaryText(dreamingSummary), Icons.Default.Storage, status = dreamingStatus(dreamingSummary), route = SettingsRoute.Dreaming),
912+SettingsRow("Voice", if (speakerEnabled) "Speaker on" else "Speaker muted", Icons.Default.Mic, route = SettingsRoute.Voice),
913+SettingsRow("Canvas", "Screen surface", Icons.AutoMirrored.Filled.ScreenShare, status = isConnected, route = SettingsRoute.Canvas),
914+SettingsRow("Notifications", if (notificationForwardingEnabled) "Smart delivery" else "Off", Icons.Default.Notifications, route = SettingsRoute.Notifications),
915+SettingsRow("Phone Capabilities", if (cameraEnabled) "Camera enabled" else "Locked", Icons.Default.Lock, status = !cameraEnabled, route = SettingsRoute.PhoneCapabilities),
916+SettingsRow("Appearance", appearanceThemeSummary(appearanceThemeMode), Icons.Default.Palette, route = SettingsRoute.Appearance),
917+SettingsRow("About", "Version and update", Icons.Default.Storage, route = SettingsRoute.About),
918+SettingsRow("Health", "Diagnostics", Icons.Default.Settings, status = isConnected, route = SettingsRoute.Health),
924919 )
920+921+ settingsSections(settingsRows).forEach { section ->
922+ item {
923+SettingsSectionTitle(section.title)
924+ }
925+ item {
926+SettingsGroup(rows = section.rows, onOpen = onRouteChange)
927+ }
925928 }
926929930+ item {
931+SettingsSectionTitle("Account")
932+ }
927933 item {
928934SettingsGroup(
929935 rows = listOf(SettingsRow("Sign Out", "Disconnect", Icons.AutoMirrored.Filled.ExitToApp)),
@@ -1057,14 +1063,73 @@ private fun dreamingStatus(summary: GatewayDreamingSummary): Boolean? =
10571063else -> null
10581064 }
105910651060-private data class SettingsRow(
1066+internal data class SettingsRow(
10611067val title: String,
10621068val value: String,
10631069val icon: ImageVector,
10641070val status: Boolean? = null,
10651071val route: SettingsRoute? = null,
10661072)
106710731074+internal data class SettingsSection(
1075+val title: String,
1076+val rows: List<SettingsRow>,
1077+)
1078+1079+internal fun settingsSections(rows: List<SettingsRow>): List<SettingsSection> =
1080+ settingsSectionOrder.mapNotNull { title ->
1081+val sectionRows = rows.filter { row -> row.route?.let(::settingsSectionTitleForRoute) == title }
1082+if (sectionRows.isEmpty()) null else SettingsSection(title = title, rows = sectionRows)
1083+ }
1084+1085+private val settingsSectionOrder =
1086+listOf(
1087+"Connection",
1088+"Agents & automation",
1089+"Phone context & privacy",
1090+"Profile & device",
1091+"Diagnostics",
1092+ )
1093+1094+internal fun settingsSectionTitleForRoute(route: SettingsRoute): String =
1095+when (route) {
1096+SettingsRoute.Gateway,
1097+SettingsRoute.NodesDevices,
1098+SettingsRoute.Channels,
1099+-> "Connection"
1100+1101+SettingsRoute.Agents,
1102+SettingsRoute.Approvals,
1103+SettingsRoute.CronJobs,
1104+SettingsRoute.Usage,
1105+SettingsRoute.Skills,
1106+SettingsRoute.Dreaming,
1107+-> "Agents & automation"
1108+1109+SettingsRoute.Voice,
1110+SettingsRoute.Canvas,
1111+SettingsRoute.Notifications,
1112+SettingsRoute.PhoneCapabilities,
1113+-> "Phone context & privacy"
1114+1115+SettingsRoute.Profile,
1116+SettingsRoute.Appearance,
1117+SettingsRoute.About,
1118+-> "Profile & device"
1119+1120+SettingsRoute.Health -> "Diagnostics"
1121+SettingsRoute.Home -> "Diagnostics"
1122+ }
1123+1124+@Composable
1125+private fun SettingsSectionTitle(title: String) {
1126+Text(
1127+ text = title.uppercase(),
1128+ style = ClawTheme.type.caption.copy(fontSize = 12.sp, lineHeight = 16.sp),
1129+ color = ClawTheme.colors.textMuted,
1130+ )
1131+}
1132+10681133@Composable
10691134private fun ProfilePanel(
10701135displayName: String,
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。