mirror of
https://github.com/twinksoftware/Gearslip.git
synced 2026-11-10 16:02:25 +01:00
car settings: build rows as they scroll into view
Opening Settings built every row of buttons at once, which took a noticeable moment. Only the ones on screen are built now.
This commit is contained in:
1 parent
e42cb767c9
commit
99ad0d03d7
1 file changed
+174
-123
@@ -5,6 +5,8 @@ import app.seb3thehacker.gearslip.car.theme.*
|
|||||||
import android.os.Build
|
import android.os.Build
|
||||||
import androidx.compose.foundation.layout.Arrangement
|
import androidx.compose.foundation.layout.Arrangement
|
||||||
import androidx.compose.foundation.layout.Column
|
import androidx.compose.foundation.layout.Column
|
||||||
|
import androidx.compose.foundation.layout.PaddingValues
|
||||||
|
import androidx.compose.foundation.lazy.LazyColumn
|
||||||
import androidx.compose.foundation.layout.Row
|
import androidx.compose.foundation.layout.Row
|
||||||
import androidx.compose.foundation.layout.Spacer
|
import androidx.compose.foundation.layout.Spacer
|
||||||
import androidx.compose.foundation.layout.fillMaxSize
|
import androidx.compose.foundation.layout.fillMaxSize
|
||||||
@@ -73,60 +75,76 @@ fun CarSettingsScreen() {
|
|||||||
value = withContext(Dispatchers.Default) { CertSummary.read(context) }
|
value = withContext(Dispatchers.Default) { CertSummary.read(context) }
|
||||||
}
|
}
|
||||||
|
|
||||||
Column(
|
LazyColumn(
|
||||||
Modifier
|
Modifier.fillMaxSize(),
|
||||||
.fillMaxSize()
|
// Built as it scrolls into view rather than all at once: every row here is a set of
|
||||||
.verticalScroll(rememberScrollState())
|
// buttons, and building the whole screen made opening Settings visibly slow.
|
||||||
.padding(horizontal = 24.dp, vertical = 16.dp),
|
contentPadding = PaddingValues(horizontal = 24.dp, vertical = 16.dp),
|
||||||
verticalArrangement = Arrangement.spacedBy(20.dp),
|
verticalArrangement = Arrangement.spacedBy(20.dp),
|
||||||
) {
|
) {
|
||||||
ScreenHeader("Settings")
|
item {
|
||||||
|
ScreenHeader("Settings")
|
||||||
|
}
|
||||||
|
|
||||||
ChoiceRow(
|
item {
|
||||||
"Open on connect",
|
ChoiceRow(
|
||||||
listOf(CarSettings.HOME to "Home") + CarApps.all.filter { it.id != "settings" }.map { it.id to it.label },
|
"Open on connect",
|
||||||
open,
|
listOf(CarSettings.HOME to "Home") + CarApps.all.filter { it.id != "settings" }.map { it.id to it.label },
|
||||||
) { CarSettings.setOpenOnConnect(it) }
|
open,
|
||||||
|
) { CarSettings.setOpenOnConnect(it) }
|
||||||
|
}
|
||||||
|
|
||||||
ChoiceRow(
|
item {
|
||||||
"Size",
|
ChoiceRow(
|
||||||
listOf(1f to "Normal", 1.25f to "Large", 1.5f to "Extra large"),
|
"Size",
|
||||||
scale,
|
listOf(1f to "Normal", 1.25f to "Large", 1.5f to "Extra large"),
|
||||||
) { CarSettings.setScale(it) }
|
scale,
|
||||||
|
) { CarSettings.setScale(it) }
|
||||||
|
}
|
||||||
|
|
||||||
ChoiceRow(
|
item {
|
||||||
"App theme",
|
ChoiceRow(
|
||||||
listOf(AppTheme.PHONE to "Follow phone", AppTheme.LIGHT to "Light", AppTheme.DARK to "Dark"),
|
"App theme",
|
||||||
theme,
|
listOf(AppTheme.PHONE to "Follow phone", AppTheme.LIGHT to "Light", AppTheme.DARK to "Dark"),
|
||||||
) { CarSettings.setAppTheme(it) }
|
theme,
|
||||||
|
) { CarSettings.setAppTheme(it) }
|
||||||
|
}
|
||||||
|
|
||||||
ChoiceRow(
|
item {
|
||||||
"Theme",
|
ChoiceRow(
|
||||||
GsThemes.builtIn.map { it.id to it.name },
|
"Theme",
|
||||||
uiTheme,
|
GsThemes.builtIn.map { it.id to it.name },
|
||||||
) { CarSettings.setUiTheme(it) }
|
uiTheme,
|
||||||
|
) { CarSettings.setUiTheme(it) }
|
||||||
|
}
|
||||||
|
|
||||||
ChoiceRow(
|
item {
|
||||||
"Map day/night",
|
ChoiceRow(
|
||||||
listOf(NightMode.AUTO to "Auto", NightMode.DAY to "Day", NightMode.NIGHT to "Night"),
|
"Map day/night",
|
||||||
night,
|
listOf(NightMode.AUTO to "Auto", NightMode.DAY to "Day", NightMode.NIGHT to "Night"),
|
||||||
) { CarSettings.setNightMode(it) }
|
night,
|
||||||
|
) { CarSettings.setNightMode(it) }
|
||||||
|
}
|
||||||
|
|
||||||
ChoiceRow(
|
item {
|
||||||
"Units",
|
ChoiceRow(
|
||||||
listOf(Units.AUTO to "Auto", Units.IMPERIAL to "Imperial (mi, ft, °F)", Units.METRIC to "Metric (km, m, °C)"),
|
"Units",
|
||||||
units,
|
listOf(Units.AUTO to "Auto", Units.IMPERIAL to "Imperial (mi, ft, °F)", Units.METRIC to "Metric (km, m, °C)"),
|
||||||
) { CarSettings.setUnits(it) }
|
units,
|
||||||
|
) { CarSettings.setUnits(it) }
|
||||||
|
}
|
||||||
|
|
||||||
// For a head unit that reports the wrong size and stretches the picture (issue #12).
|
// For a head unit that reports the wrong size and stretches the picture (issue #12).
|
||||||
ChoiceRow(
|
item {
|
||||||
"Screen size (next connection)",
|
ChoiceRow(
|
||||||
listOf<ScreenSize?>(null).plus(SCREEN_PRESETS).plus(screenSize).distinct()
|
"Screen size (next connection)",
|
||||||
.map { it to (it?.toString() ?: "From the car") },
|
listOf<ScreenSize?>(null).plus(SCREEN_PRESETS).plus(screenSize).distinct()
|
||||||
screenSize,
|
.map { it to (it?.toString() ?: "From the car") },
|
||||||
) { CarSettings.setScreenSize(it) }
|
screenSize,
|
||||||
|
) { CarSettings.setScreenSize(it) }
|
||||||
|
}
|
||||||
|
|
||||||
if (screenSize != null) {
|
if (screenSize != null) item {
|
||||||
ChoiceRow(
|
ChoiceRow(
|
||||||
"Fit to the screen",
|
"Fit to the screen",
|
||||||
listOf(ScreenFit.CROP to "Crop the edges", ScreenFit.SQUASH to "Squash to fit"),
|
listOf(ScreenFit.CROP to "Crop the edges", ScreenFit.SQUASH to "Squash to fit"),
|
||||||
@@ -134,105 +152,138 @@ fun CarSettingsScreen() {
|
|||||||
) { CarSettings.setScreenFit(it) }
|
) { CarSettings.setScreenFit(it) }
|
||||||
}
|
}
|
||||||
|
|
||||||
ChoiceRow(
|
item {
|
||||||
"Nav bar",
|
ChoiceRow(
|
||||||
listOf(
|
"Nav bar",
|
||||||
NavBarMode.SHOW to "Always show",
|
listOf(
|
||||||
NavBarMode.HIDE_NAVIGATING to "Hide while navigating",
|
NavBarMode.SHOW to "Always show",
|
||||||
NavBarMode.HIDE to "Hide until tapped",
|
NavBarMode.HIDE_NAVIGATING to "Hide while navigating",
|
||||||
),
|
NavBarMode.HIDE to "Hide until tapped",
|
||||||
navBar,
|
),
|
||||||
) { CarSettings.setNavBarMode(it) }
|
navBar,
|
||||||
|
) { CarSettings.setNavBarMode(it) }
|
||||||
|
}
|
||||||
|
|
||||||
ChoiceRow(
|
item {
|
||||||
"Player in the nav bar",
|
ChoiceRow(
|
||||||
listOf(false to "Skip buttons", true to "Song title"),
|
"Player in the nav bar",
|
||||||
playerTitle,
|
listOf(false to "Skip buttons", true to "Song title"),
|
||||||
) { CarSettings.setPlayerTitle(it) }
|
playerTitle,
|
||||||
|
) { CarSettings.setPlayerTitle(it) }
|
||||||
|
}
|
||||||
|
|
||||||
ChoiceRow(
|
item {
|
||||||
"Autoplay on connect",
|
ChoiceRow(
|
||||||
listOf(false to "Off", true to "On"),
|
"Autoplay on connect",
|
||||||
autoplay,
|
listOf(false to "Off", true to "On"),
|
||||||
) { CarSettings.setAutoplay(it) }
|
autoplay,
|
||||||
|
) { CarSettings.setAutoplay(it) }
|
||||||
|
}
|
||||||
|
|
||||||
ChoiceRow(
|
item {
|
||||||
"Car audio",
|
ChoiceRow(
|
||||||
listOf(false to "Bluetooth", true to "USB"),
|
"Car audio",
|
||||||
pipeAudio,
|
listOf(false to "Bluetooth", true to "USB"),
|
||||||
) { CarSettings.setPipeAudio(it) }
|
pipeAudio,
|
||||||
Text(
|
) { CarSettings.setPipeAudio(it) }
|
||||||
"USB sends the phone's sound through Gearslip. Android asks to share your screen each " +
|
}
|
||||||
"drive, and a few apps block it. Bluetooth plays as the phone normally would, and " +
|
|
||||||
"Android never asks.",
|
item {
|
||||||
style = MaterialTheme.typography.bodySmall,
|
Text(
|
||||||
color = MaterialTheme.colorScheme.onSurfaceVariant,
|
"USB sends the phone's sound through Gearslip. Android asks to share your screen each " +
|
||||||
)
|
"drive, and a few apps block it. Bluetooth plays as the phone normally would, and " +
|
||||||
if (!pipeAudio) {
|
"Android never asks.",
|
||||||
|
style = MaterialTheme.typography.bodySmall,
|
||||||
|
color = MaterialTheme.colorScheme.onSurfaceVariant,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!pipeAudio) item {
|
||||||
ChoiceRow(
|
ChoiceRow(
|
||||||
"Warn when Bluetooth isn't connected",
|
"Warn when Bluetooth isn't connected",
|
||||||
listOf(false to "Off", true to "On"),
|
listOf(false to "Off", true to "On"),
|
||||||
bluetoothWarning,
|
bluetoothWarning,
|
||||||
) { CarSettings.setBluetoothWarning(it) }
|
) { CarSettings.setBluetoothWarning(it) }
|
||||||
}
|
}
|
||||||
ChoiceRow(
|
|
||||||
"Warn when location is off",
|
|
||||||
listOf(false to "Off", true to "On"),
|
|
||||||
locationWarning,
|
|
||||||
) { CarSettings.setLocationWarning(it) }
|
|
||||||
|
|
||||||
ChoiceRow(
|
item {
|
||||||
"Spoken directions",
|
ChoiceRow(
|
||||||
listOf(false to "Off", true to "On"),
|
"Warn when location is off",
|
||||||
speakDirections,
|
listOf(false to "Off", true to "On"),
|
||||||
) { CarSettings.setSpeakDirections(it) }
|
locationWarning,
|
||||||
Text(
|
) { CarSettings.setLocationWarning(it) }
|
||||||
"Gearslip reads each turn aloud through the car's speakers, and the music dips while it " +
|
}
|
||||||
"speaks. Turn it off if your map app's own voice already plays in the car.",
|
|
||||||
style = MaterialTheme.typography.bodySmall,
|
|
||||||
color = MaterialTheme.colorScheme.onSurfaceVariant,
|
|
||||||
)
|
|
||||||
|
|
||||||
ExperimentalFeatureRow(
|
item {
|
||||||
title = "Use the phone's speech recognition",
|
ChoiceRow(
|
||||||
description = "Listens through the phone's own speech service instead of Gearslip's. On " +
|
"Spoken directions",
|
||||||
"most phones that's Google's, which may send your voice to Google. GrapheneOS has " +
|
listOf(false to "Off", true to "On"),
|
||||||
"none, so Gearslip keeps using its own.",
|
speakDirections,
|
||||||
checked = systemSpeech,
|
) { CarSettings.setSpeakDirections(it) }
|
||||||
) { CarSettings.setSystemSpeech(it) }
|
}
|
||||||
|
|
||||||
WebPageSetting()
|
item {
|
||||||
|
Text(
|
||||||
|
"Gearslip reads each turn aloud through the car's speakers, and the music dips while it " +
|
||||||
|
"speaks. Turn it off if your map app's own voice already plays in the car.",
|
||||||
|
style = MaterialTheme.typography.bodySmall,
|
||||||
|
color = MaterialTheme.colorScheme.onSurfaceVariant,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
ScreenFit(vehicle)
|
item {
|
||||||
|
ExperimentalFeatureRow(
|
||||||
|
title = "Use the phone's speech recognition",
|
||||||
|
description = "Listens through the phone's own speech service instead of Gearslip's. On " +
|
||||||
|
"most phones that's Google's, which may send your voice to Google. GrapheneOS has " +
|
||||||
|
"none, so Gearslip keeps using its own.",
|
||||||
|
checked = systemSpeech,
|
||||||
|
) { CarSettings.setSystemSpeech(it) }
|
||||||
|
}
|
||||||
|
|
||||||
ChoiceRow(
|
item {
|
||||||
"Experimental features",
|
WebPageSetting()
|
||||||
listOf(false to "Hide", true to "Show"),
|
}
|
||||||
experimentalFeatures,
|
|
||||||
) { CarSettings.setExperimentalFeaturesEnabled(it) }
|
item {
|
||||||
if (experimentalFeatures) {
|
ScreenFit(vehicle)
|
||||||
|
}
|
||||||
|
|
||||||
|
item {
|
||||||
|
ChoiceRow(
|
||||||
|
"Experimental features",
|
||||||
|
listOf(false to "Hide", true to "Show"),
|
||||||
|
experimentalFeatures,
|
||||||
|
) { CarSettings.setExperimentalFeaturesEnabled(it) }
|
||||||
|
}
|
||||||
|
|
||||||
|
if (experimentalFeatures) item {
|
||||||
ExperimentalFeaturesList(carSensors)
|
ExperimentalFeaturesList(carSensors)
|
||||||
}
|
}
|
||||||
|
|
||||||
Column(verticalArrangement = Arrangement.spacedBy(8.dp)) {
|
item {
|
||||||
Text("Connection", style = MaterialTheme.typography.titleMedium, color = MaterialTheme.colorScheme.primary)
|
Column(verticalArrangement = Arrangement.spacedBy(8.dp)) {
|
||||||
Info("Phone", "${Build.MANUFACTURER} ${Build.MODEL}")
|
Text("Connection", style = MaterialTheme.typography.titleMedium, color = MaterialTheme.colorScheme.primary)
|
||||||
Info("Vehicle", vehicle.ifEmpty { "-" })
|
Info("Phone", "${Build.MANUFACTURER} ${Build.MODEL}")
|
||||||
Info("Video", display.ifEmpty { "-" })
|
Info("Vehicle", vehicle.ifEmpty { "-" })
|
||||||
Info("Certificate", cert?.headline ?: "Checking…")
|
Info("Video", display.ifEmpty { "-" })
|
||||||
|
Info("Certificate", cert?.headline ?: "Checking…")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Column(verticalArrangement = Arrangement.spacedBy(8.dp)) {
|
item {
|
||||||
Text("About", style = MaterialTheme.typography.titleMedium, color = MaterialTheme.colorScheme.primary)
|
Column(verticalArrangement = Arrangement.spacedBy(8.dp)) {
|
||||||
Info("Version", app.seb3thehacker.gearslip.BuildConfig.VERSION_NAME)
|
Text("About", style = MaterialTheme.typography.titleMedium, color = MaterialTheme.colorScheme.primary)
|
||||||
Info("Build", app.seb3thehacker.gearslip.BuildConfig.VERSION_CODE.toString())
|
Info("Version", app.seb3thehacker.gearslip.BuildConfig.VERSION_NAME)
|
||||||
ExperimentalFeatureRow(
|
Info("Build", app.seb3thehacker.gearslip.BuildConfig.VERSION_CODE.toString())
|
||||||
"What's new after updates",
|
ExperimentalFeatureRow(
|
||||||
"Show the list of changes once, the first time the car connects after an update.",
|
"What's new after updates",
|
||||||
whatsNew,
|
"Show the list of changes once, the first time the car connects after an update.",
|
||||||
) { CarSettings.setWhatsNewAfterUpdates(it) }
|
whatsNew,
|
||||||
GsButton(onClick = CarSettings::openWhatsNew, tone = GsTone.Tonal, modifier = Modifier.height(56.dp)) {
|
) { CarSettings.setWhatsNewAfterUpdates(it) }
|
||||||
Text("What's new", style = MaterialTheme.typography.titleMedium)
|
GsButton(onClick = CarSettings::openWhatsNew, tone = GsTone.Tonal, modifier = Modifier.height(56.dp)) {
|
||||||
|
Text("What's new", style = MaterialTheme.typography.titleMedium)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in new issue
Block a user