The car audio choice moves to Settings, and says map apps' spoken directions stay on the phone with Through Gearslip

The phone's ID in the usage note can be selected and copied, for a request to see or
delete what was sent.
This commit is contained in:
Seb3thehacker committed 2026-11-11 11:29:22 -08:00
1 parent f10ffa4142
commit 0ca828de4a
4 files changed
+52 -38

No files matched your search

@@ -109,8 +109,6 @@ fun HomeScreen(
) {
Spacer(Modifier.height(16.dp))
StatusCard(status)
Spacer(Modifier.height(16.dp))
AudioSwitch()
if (live) BluetoothMissingCard()
if (live) BackgroundLocationCard()
BluetoothAddressCard()
@@ -315,34 +313,6 @@ private fun Arrow() = Icon(
tint = MaterialTheme.colorScheme.onSurfaceVariant,
)
/**
* Where the car's sound comes from, switchable in one tap from Home: Bluetooth, or through
* Gearslip over the car link. It takes effect at once when a car is connected.
*/
@Composable
private fun AudioSwitch() {
val pipe by app.seb3thehacker.gearslip.car.CarSettings.pipeAudio.collectAsState()
val thisCar by app.seb3thehacker.gearslip.car.CarSettings.thisCarPipes.collectAsState()
val through = pipe || thisCar
Column(verticalArrangement = Arrangement.spacedBy(8.dp)) {
Text(
stringResource(R.string.car_audio),
style = MaterialTheme.typography.labelLarge,
color = MaterialTheme.colorScheme.primary,
modifier = Modifier.padding(start = 4.dp),
)
androidx.compose.material3.SingleChoiceSegmentedButtonRow(Modifier.fillMaxWidth()) {
listOf(false to R.string.guide_audio_bluetooth, true to R.string.guide_audio_usb).forEachIndexed { i, (value, label) ->
SegmentedButton(
selected = through == value,
onClick = { app.seb3thehacker.gearslip.car.CarSettings.setPipeAudio(value) },
shape = androidx.compose.material3.SegmentedButtonDefaults.itemShape(i, 2),
) { Text(stringResource(label), maxLines = 1) }
}
}
}
}
@Composable
private fun StatusCard(status: SessionStatus.Snapshot) {
val scheme = MaterialTheme.colorScheme
@@ -1,5 +1,8 @@
package app.seb3thehacker.gearslip.ui
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.ui.semantics.semantics
import androidx.compose.ui.semantics.selected
import androidx.compose.material.icons.filled.Create
import androidx.compose.ui.res.stringResource
@@ -250,6 +253,7 @@ private fun ConnectionSection() {
icon = Icons.Filled.Home,
trailing = { Switch(checked = launcher, onCheckedChange = null) },
)
CarAudioSetting()
var address by remember { mutableStateOf(CarBluetooth.typedAddress(context)) }
var editing by remember { mutableStateOf(false) }
SettingsRow(
@@ -275,6 +279,42 @@ private fun ConnectionSection() {
}
}
/**
* Where the car's sound comes from: Bluetooth, or through Gearslip over the car link. Takes
* effect at once when a car is connected. The chosen pill is filled in the main colour, the
* other tonal, like the buttons on Home.
*/
@Composable
private fun CarAudioSetting() {
val pipe by app.seb3thehacker.gearslip.car.CarSettings.pipeAudio.collectAsState()
val thisCar by app.seb3thehacker.gearslip.car.CarSettings.thisCarPipes.collectAsState()
val through = pipe || thisCar
val scheme = MaterialTheme.colorScheme
// Android won't let Gearslip capture navigation voices, only media, so they stay on the phone.
SettingsRow(
stringResource(R.string.car_audio),
subtitle = if (through) stringResource(R.string.home_audio_usb_warning) else null,
icon = app.seb3thehacker.gearslip.car.MediaIcons.MusicNote,
)
androidx.compose.foundation.layout.Row(
Modifier.fillMaxWidth().padding(start = 56.dp, end = 16.dp, bottom = 12.dp),
horizontalArrangement = androidx.compose.foundation.layout.Arrangement.spacedBy(8.dp),
) {
listOf(false to R.string.guide_audio_bluetooth, true to R.string.guide_audio_usb).forEach { (value, label) ->
val chosen = through == value
androidx.compose.material3.Button(
onClick = { app.seb3thehacker.gearslip.car.CarSettings.setPipeAudio(value) },
colors = androidx.compose.material3.ButtonDefaults.buttonColors(
containerColor = if (chosen) scheme.primary else scheme.secondaryContainer,
contentColor = if (chosen) scheme.onPrimary else scheme.onSecondaryContainer,
),
contentPadding = androidx.compose.foundation.layout.PaddingValues(horizontal = 12.dp),
modifier = Modifier.weight(1f).height(48.dp).semantics { selected = chosen },
) { Text(stringResource(label), maxLines = 1) }
}
}
}
/** The phone's Bluetooth address, typed in by hand: Android doesn't let apps read it. */
@Composable
internal fun AddressDialog(initial: String, onDismiss: () -> Unit, onSave: (String) -> Boolean) {
@@ -129,12 +129,15 @@ internal fun ColumnScope.UsageStatsRows() {
shape = MaterialTheme.shapes.medium,
modifier = Modifier.fillMaxWidth().padding(start = 16.dp, end = 16.dp, bottom = 16.dp),
) {
Text(
note,
style = MaterialTheme.typography.bodySmall,
fontFamily = FontFamily.Monospace,
modifier = Modifier.padding(12.dp),
)
// Selectable, so the phone's "id" can be copied into a request to see or delete its notes.
androidx.compose.foundation.text.selection.SelectionContainer {
Text(
note,
style = MaterialTheme.typography.bodySmall,
fontFamily = FontFamily.Monospace,
modifier = Modifier.padding(12.dp),
)
}
}
}
}
+3 -2
View File
@@ -48,7 +48,8 @@
<string name="guide_recommended">Recommended</string>
<string name="guide_audio_bluetooth_body">No prompt each drive, and your map app\'s voice reaches the car.</string>
<string name="guide_audio_usb">Through Gearslip</string>
<string name="guide_audio_usb_body">Clearer sound with no delay. Each drive, Android asks you to share your screen, which lets Gearslip send the sound.</string>
<string name="guide_audio_usb_body">Clearer sound with no delay, but your map app\'s spoken directions play on the phone, not in the car. Each drive, Android asks you to share your screen, which lets Gearslip send the sound.</string>
<string name="home_audio_usb_warning">Spoken directions from map apps play on the phone, not in the car. Choose Bluetooth to hear them in the car.</string>
<string name="guide_optional">OPTIONAL</string>
<string name="guide_already_allowed">Already allowed.</string>
<string name="guide_scroll_more">Scroll for more ↓</string>
@@ -239,7 +240,7 @@
<string name="car_audio">Car audio</string>
<string name="car_audio_bt">Bluetooth (Recommended)</string>
<string name="car_audio_bt_sub">No prompt each drive, and your map app\'s voice reaches the car</string>
<string name="car_audio_usb_sub">Clearer sound with no delay. Each drive, Android asks you to share your screen, which lets Gearslip send the sound</string>
<string name="car_audio_usb_sub">Clearer sound with no delay, but map apps\' spoken directions play on the phone, not in the car. Each drive, Android asks you to share your screen, which lets Gearslip send the sound</string>
<string name="car_audio_usb_footer">Run the command in Help once, and Android stops asking.</string>
<string name="car_audio_bt_footer">Calls go over Bluetooth either way.</string>