fix(ui): flip booleans with a switch instead of on/off menus

This commit is contained in:
Kurt Himebauch committed 2026-09-27 14:18:29 -04:00
1 parent 37af590ca2
commit cb1d70bb14
3 files changed
+50 -11

No files matched your search

@@ -278,15 +278,13 @@ internal fun SetupPanel(
FrameGenMenu(s, a, host)
}
}
SettingsRow("Session logs", "${if (s.logsEnabled) "Enabled" else "Disabled"} · logs are saved after each session") {
Row(horizontalArrangement = Arrangement.spacedBy(6.dp)) {
SecondaryButton(if (s.logsEnabled) "Turn off" else "Turn on") { a.onLogs() }
SecondaryButton("Share latest") { a.onShareLogs() }
}
}
SettingsRow("Offline mode", s.offlineAccount?.let { if (s.offline) "Enabled for $it" else "Signed in as $it" } ?: "Sign in to Steam first") {
SecondaryButton(if (s.offline) "Turn off" else "Turn on", enabled = s.offlineAccount != null) { a.onOffline() }
}
ToggleRow(host, "logs", "Session logs", "Saved after each session", s.logsEnabled) { a.onLogs() }
ActionRow("Latest session logs", "Send them with a bug report", "Share logs", a.onShareLogs)
ToggleRow(
host, "offline", "Offline mode",
s.offlineAccount?.let { "Signed in as $it" } ?: "Sign in to Steam first",
s.offline, enabled = s.offlineAccount != null,
) { a.onOffline() }
}
}
3 -> {
@@ -420,7 +420,7 @@ fun SessionDrawer(open: Boolean, page: Int, controllerActive: Boolean, onPageCha
}
SettingsGroup("Support") {
SettingsRow("Session logs", "Send this session's logs with a bug report") {
DrawerOutlineButton("Send logs", modifier = focus.track(page, "share-logs")) {
DrawerOutlineButton("Share logs", modifier = focus.track(page, "share-logs")) {
host.open = null
a.onShareLogs()
}
@@ -19,6 +19,8 @@ import androidx.compose.foundation.layout.size
import androidx.compose.ui.focus.focusProperties
import androidx.compose.ui.semantics.Role
import androidx.compose.ui.semantics.contentDescription
import androidx.compose.ui.semantics.stateDescription
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.ui.semantics.semantics
import androidx.compose.foundation.background
import androidx.compose.foundation.border
@@ -385,7 +387,46 @@ fun <T> ChoiceRow(
@Composable
fun ToggleRow(host: MenuHost, key: String, label: String, hint: String?, checked: Boolean, enabled: Boolean = true, chipModifier: Modifier = Modifier, onChange: (Boolean) -> Unit) =
ChoiceRow(host, key, label, hint, listOf(true to "On", false to "Off"), checked, enabled, chipModifier = chipModifier, onPick = onChange)
SettingsRow(label, hint) {
ToggleSwitch(checked, enabled, label, chipModifier) { host.open = null; onChange(it) }
}
/** An on/off switch: one tap or one A press flips it, where a menu of On and Off took three. */
@Composable
fun ToggleSwitch(checked: Boolean, enabled: Boolean = true, label: String? = null, modifier: Modifier = Modifier, onChange: (Boolean) -> Unit) {
val colors = MaterialTheme.colorScheme
val pal = LocalPalette.current
val src = remember { MutableInteractionSource() }
val hot = src.collectIsFocusedAsState().value || src.collectIsHoveredAsState().value
val track by animateColorAsState(if (checked) pal.signal else colors.surfaceVariant, Motion.tw(180), label = "switchTrack")
val edge by animateColorAsState(if (hot) pal.signal else if (checked) pal.signal else pal.line2, Motion.tw(180), label = "switchEdge")
val knob by animateFloatAsState(if (checked) 1f else 0f, Motion.sp(0.7f), label = "switchKnob")
val flip = { onChange(!checked) }
val shape = RoundedCornerShape(99.dp)
// 48dp tall to touch; the visible track sits inside it.
Box(
contentAlignment = Alignment.Center,
modifier = modifier
.heightIn(min = 48.dp).widthIn(min = 64.dp)
.alpha(if (enabled) 1f else 0.5f)
.hoverable(src)
.clickable(interactionSource = src, indication = null, enabled = enabled, role = Role.Switch, onClick = flip)
.controllerConfirm(enabled = enabled, onClick = flip)
.semantics { stateDescription = if (checked) "On" else "Off"; if (label != null) contentDescription = label },
) {
Box(
Modifier.size(width = 52.dp, height = 30.dp).clip(shape).background(track)
.border(if (hot) 2.dp else 1.dp, if (hot && checked) colors.onBackground else edge, shape),
) {
Box(
Modifier.padding(4.dp).size(22.dp)
.graphicsLayer { translationX = knob * 22.dp.toPx() }
.clip(CircleShape)
.background(if (checked) pal.onSignal else colors.onSurfaceVariant),
)
}
}
}
@Composable
fun MultiRow(