home: put Connect wirelessly in the status card, with the usage notes switch always under it

This commit is contained in:
Seb3thehacker committed 2026-10-13 15:48:54 -07:00
1 parent dd1fd0242f
commit 724dcf25c7
3 files changed
+53 -2

No files matched your search

@@ -97,6 +97,8 @@ fun HomeScreen(
) )
Spacer(Modifier.height(16.dp)) Spacer(Modifier.height(16.dp))
StatusCard(status) StatusCard(status)
Spacer(Modifier.height(16.dp))
UsageNotesHomeCard(onOpen = onOpenUsageNotes)
// The first drive that worked asks once to share it, right under the result. // The first drive that worked asks once to share it, right under the result.
val car = workedCar val car = workedCar
if (car != null && !live) { if (car != null && !live) {
@@ -256,3 +256,44 @@ internal fun WorkedCard(car: String, onSeeWhatsSent: () -> Unit, modifier: Modif
} }
} }
} }
/**
* Usage notes on Home, one row with one action either way. While they're off, the row is the
* switch, so opting in is a single tap. Once they're on, it shrinks to a quiet line that opens
* Settings at its usage notes section, so a driver already sharing isn't pitched again.
*/
@Composable
internal fun UsageNotesHomeCard(onOpen: () -> Unit, modifier: Modifier = Modifier) {
val context = LocalContext.current
var on by remember { mutableStateOf(UsageStats.enabled(context)) }
SettingsCard(modifier) {
if (on) {
SettingsRow(
"Sharing usage notes",
Modifier.clickable(onClick = onOpen),
subtitle = buildNote(),
icon = Icons.Filled.Check,
trailing = {
Icon(
Icons.AutoMirrored.Filled.KeyboardArrowRight,
contentDescription = null,
tint = MaterialTheme.colorScheme.onSurfaceVariant,
)
},
)
} else {
SettingsRow(
USAGE_STATS_TITLE,
Modifier.toggleable(false, role = Role.Switch) {
UsageStats.set(context, true, UsageStats.choices(context))
on = true
},
subtitle = buildNote() ?: ("A short note after each drive tells the next driver " +
"whether their car works. No name, account, or location"),
icon = Icons.Filled.Send,
trailing = { Switch(checked = false, onCheckedChange = null) },
)
}
}
}
@@ -84,6 +84,8 @@ object WirelessLink {
@Volatile private var worker: Thread? = null @Volatile private var worker: Thread? = null
/** Set when Android drops the car's network mid-try, so the rest don't bind to a dead one. */ /** Set when Android drops the car's network mid-try, so the rest don't bind to a dead one. */
@Volatile private var lostNetwork: Network? = null @Volatile private var lostNetwork: Network? = null
/** Bumped on each Wi-Fi join and on stop, so an older run of TCP tries ends instead of racing the new one. */
@Volatile private var tcpRun = 0
private val writeLock = Any() private val writeLock = Any()
/** Paired Bluetooth devices, cars or not: the driver picks theirs. Needs BLUETOOTH_CONNECT. */ /** Paired Bluetooth devices, cars or not: the driver picks theirs. Needs BLUETOOTH_CONNECT. */
@@ -112,6 +114,7 @@ object WirelessLink {
/** Closes the Bluetooth channel, the socket and the Wi-Fi request. Safe to call any time. */ /** Closes the Bluetooth channel, the socket and the Wi-Fi request. Safe to call any time. */
fun stop(context: Context) { fun stop(context: Context) {
tcpRun++
worker?.interrupt() worker?.interrupt()
worker = null worker = null
runCatching { listener?.close() } runCatching { listener?.close() }
@@ -303,7 +306,8 @@ object WirelessLink {
send(output, MSG_CONNECTION_STATUS, Protobuf.varintField(1, STATUS_SUCCESS)) send(output, MSG_CONNECTION_STATUS, Protobuf.varintField(1, STATUS_SUCCESS))
log.i("-> StartResponse (phone at $phoneIp), ConnectionStatus: success") log.i("-> StartResponse (phone at $phoneIp), ConnectionStatus: success")
}.onFailure { log.w("Bluetooth: couldn't report the Wi-Fi join (${it.message})") } }.onFailure { log.w("Bluetooth: couldn't report the Wi-Fi join (${it.message})") }
Thread({ connectTcp(context, output, name, net, ip, port) }, "gearslip-wireless-tcp").start() val run = ++tcpRun
Thread({ connectTcp(context, output, name, net, ip, port, run) }, "gearslip-wireless-tcp").start()
} }
override fun onUnavailable() { override fun onUnavailable() {
@@ -394,11 +398,15 @@ object WirelessLink {
} }
} }
private fun connectTcp(context: Context, output: OutputStream, name: String, net: Network, ip: String, port: Int) { private fun connectTcp(context: Context, output: OutputStream, name: String, net: Network, ip: String, port: Int, run: Int) {
SessionStatus.connecting("Wi-Fi: reaching $name") SessionStatus.connecting("Wi-Fi: reaching $name")
lostNetwork = null lostNetwork = null
var last: Exception? = null var last: Exception? = null
repeat(TCP_TRIES) { attempt -> repeat(TCP_TRIES) { attempt ->
if (run != tcpRun) {
log.i("TCP: stopping the tries on the old network - the car started over")
return
}
try { try {
// A network Android has dropped refuses every bind (EPERM). If the driver joined the // A network Android has dropped refuses every bind (EPERM). If the driver joined the
// car's Wi-Fi by hand, the phone's ordinary route reaches it, so use that instead. // car's Wi-Fi by hand, the phone's ordinary route reaches it, so use that instead.