feat(settings): promote Quick Controls to the top-level Settings landing
Persistent connection is a connection-level control flipped frequently, not chat-specific, so move the Quick Controls card out of Chat settings to the Settings root (beside the Active Agent / Profile lock cards) and add a Turn-complete alerts toggle. Both wire to the existing ConnectionViewModel flows (gatewayKeepAlive / notifyTurnComplete) - no new prefs. Removes the card from ChatSettingsScreen. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
9142fb8f79
commit
62961322b9
@@ -127,64 +127,10 @@ fun ChatSettingsScreen(
|
||||
.padding(horizontal = 16.dp, vertical = 16.dp),
|
||||
verticalArrangement = Arrangement.spacedBy(16.dp),
|
||||
) {
|
||||
// Quick Controls — the most-reached-for chat controls, pinned to the
|
||||
// very top of Settings. Intentionally extensible: more quick toggles
|
||||
// can join this card later; for now it hosts only Persistent
|
||||
// connection (relocated from the mid-list section below).
|
||||
Text(
|
||||
text = "Quick Controls",
|
||||
style = MaterialTheme.typography.titleMedium,
|
||||
color = MaterialTheme.colorScheme.primary,
|
||||
)
|
||||
Card(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.gradientBorder(
|
||||
shape = RoundedCornerShape(12.dp),
|
||||
isDarkTheme = isDarkTheme
|
||||
),
|
||||
colors = CardDefaults.cardColors(
|
||||
containerColor = MaterialTheme.colorScheme.surfaceVariant
|
||||
)
|
||||
) {
|
||||
Column(
|
||||
modifier = Modifier.padding(16.dp),
|
||||
verticalArrangement = Arrangement.spacedBy(12.dp)
|
||||
) {
|
||||
// Persistent connection — opt-in, both flavors. Holds the
|
||||
// app's connection to Hermes open in the background via a
|
||||
// persistent notification so messages and live features stay
|
||||
// responsive (relay-paired setups also keep device control +
|
||||
// notification mirroring reachable). Off by default; uses
|
||||
// more battery. Same pref/key as the former mid-list toggle.
|
||||
val gatewayKeepAlive by connectionViewModel.gatewayKeepAlive.collectAsState()
|
||||
Row(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
horizontalArrangement = Arrangement.SpaceBetween,
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
) {
|
||||
Column(modifier = Modifier.weight(1f)) {
|
||||
Text(
|
||||
text = "Persistent connection",
|
||||
style = MaterialTheme.typography.bodyMedium
|
||||
)
|
||||
Text(
|
||||
text = if (gatewayKeepAlive) {
|
||||
"Keeping your connection to Hermes open in the background"
|
||||
} else {
|
||||
"Connect on demand only · saves battery"
|
||||
},
|
||||
style = MaterialTheme.typography.bodySmall,
|
||||
color = MaterialTheme.colorScheme.onSurfaceVariant
|
||||
)
|
||||
}
|
||||
Switch(
|
||||
checked = gatewayKeepAlive,
|
||||
onCheckedChange = { connectionViewModel.setGatewayKeepAlive(it) }
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
// (Quick Controls — Persistent connection etc. — moved to the
|
||||
// top-level Settings landing, since they're connection-level controls
|
||||
// flipped frequently, not chat-specific. See SettingsScreen's
|
||||
// QuickControlsCard.)
|
||||
Card(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
|
||||
@@ -377,6 +377,17 @@ fun SettingsScreen(
|
||||
isDarkTheme = isDarkTheme,
|
||||
)
|
||||
|
||||
// ── Quick Controls ─────────────────────────────────────────
|
||||
// The switches flipped most often, pinned to the top-level Settings
|
||||
// landing instead of buried in a sub-screen. Persistent connection is
|
||||
// connection-level (not chat-specific), so it belongs here beside the
|
||||
// agent / profile cards. Extensible — add more frequently-toggled
|
||||
// switches in QuickControlsCard.
|
||||
QuickControlsCard(
|
||||
connectionViewModel = connectionViewModel,
|
||||
isDarkTheme = isDarkTheme,
|
||||
)
|
||||
|
||||
// (The "Active Connection quick-look card" that used to live
|
||||
// here — showing API / Relay / Session status rows with a
|
||||
// clickable shortcut into a separate singular-connection
|
||||
@@ -780,6 +791,98 @@ private fun ProfileLockCard(
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Quick Controls card on the top-level Settings landing — the switches the user
|
||||
* flips most often (Persistent connection, turn-complete alerts), kept out of
|
||||
* the per-feature sub-screens so they're one tap from the Settings root. Wired
|
||||
* straight to the same ConnectionViewModel flows the sub-screens use.
|
||||
*/
|
||||
@Composable
|
||||
private fun QuickControlsCard(
|
||||
connectionViewModel: ConnectionViewModel,
|
||||
isDarkTheme: Boolean,
|
||||
) {
|
||||
val gatewayKeepAlive by connectionViewModel.gatewayKeepAlive.collectAsState()
|
||||
val notifyTurnComplete by connectionViewModel.notifyTurnComplete.collectAsState()
|
||||
Card(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.gradientBorder(
|
||||
shape = RoundedCornerShape(12.dp),
|
||||
isDarkTheme = isDarkTheme,
|
||||
),
|
||||
colors = CardDefaults.cardColors(
|
||||
containerColor = MaterialTheme.colorScheme.surfaceVariant,
|
||||
),
|
||||
) {
|
||||
Column(
|
||||
modifier = Modifier.padding(16.dp),
|
||||
verticalArrangement = Arrangement.spacedBy(12.dp),
|
||||
) {
|
||||
Text(
|
||||
text = "Quick Controls",
|
||||
style = MaterialTheme.typography.labelLarge,
|
||||
color = MaterialTheme.colorScheme.primary,
|
||||
)
|
||||
// Persistent connection — connection-level keep-alive: holds the app
|
||||
// process up via a notification so the gateway chat socket (and, for
|
||||
// relay-paired setups, device control + notification mirroring) stays
|
||||
// reachable in the background. Off by default; uses more battery.
|
||||
QuickControlToggle(
|
||||
title = "Persistent connection",
|
||||
subtitle = if (gatewayKeepAlive) {
|
||||
"Keeping your connection to Hermes open in the background"
|
||||
} else {
|
||||
"Connect on demand only · saves battery"
|
||||
},
|
||||
checked = gatewayKeepAlive,
|
||||
onCheckedChange = { connectionViewModel.setGatewayKeepAlive(it) },
|
||||
)
|
||||
HorizontalDivider()
|
||||
QuickControlToggle(
|
||||
title = "Turn-complete alerts",
|
||||
subtitle = if (notifyTurnComplete) {
|
||||
"Notify when a reply finishes while the app is in the background"
|
||||
} else {
|
||||
"No alert when a backgrounded reply finishes"
|
||||
},
|
||||
checked = notifyTurnComplete,
|
||||
onCheckedChange = { connectionViewModel.setNotifyTurnComplete(it) },
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun QuickControlToggle(
|
||||
title: String,
|
||||
subtitle: String,
|
||||
checked: Boolean,
|
||||
onCheckedChange: (Boolean) -> Unit,
|
||||
) {
|
||||
Row(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
horizontalArrangement = Arrangement.SpaceBetween,
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
) {
|
||||
Column(modifier = Modifier.weight(1f)) {
|
||||
Text(
|
||||
text = title,
|
||||
style = MaterialTheme.typography.bodyLarge,
|
||||
maxLines = 1,
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
)
|
||||
Text(
|
||||
text = subtitle,
|
||||
style = MaterialTheme.typography.bodySmall,
|
||||
color = MaterialTheme.colorScheme.onSurfaceVariant,
|
||||
)
|
||||
}
|
||||
Spacer(modifier = Modifier.width(12.dp))
|
||||
Switch(checked = checked, onCheckedChange = onCheckedChange)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The one surface that ALWAYS lists every profile (it never gates on the lock
|
||||
* state — it's how the user picks the target or unlocks). A master "Lock to a
|
||||
|
||||
Reference in New Issue
Block a user