mirror of
https://github.com/twinksoftware/Gearslip.git
synced 2026-11-11 00:12:24 +01:00
home: show only the car's status; help, preview, logs and the dev test message move to Settings
This commit is contained in:
1 parent
7d9eb20ff0
commit
3869258e0e
5 files changed
+85
-124
No files matched your search
@@ -60,10 +60,13 @@ fun GearslipApp(onDisconnect: () -> Unit, onRequestCallScreening: () -> Unit) {
|
|||||||
var screen by rememberSaveable { mutableStateOf(if (Intro.due(context)) Screen.INTRO else afterIntro) }
|
var screen by rememberSaveable { mutableStateOf(if (Intro.due(context)) Screen.INTRO else afterIntro) }
|
||||||
// A replay from About goes back to Settings; the launch one carries on into setup.
|
// A replay from About goes back to Settings; the launch one carries on into setup.
|
||||||
var introReturn by rememberSaveable { mutableStateOf(afterIntro) }
|
var introReturn by rememberSaveable { mutableStateOf(afterIntro) }
|
||||||
// Home's usage notes row opens Settings at that section rather than at the top.
|
// Home's "it worked" card opens Settings at usage notes rather than at the top.
|
||||||
var settingsAtUsageNotes by rememberSaveable { mutableStateOf(false) }
|
var settingsAtUsageNotes by rememberSaveable { mutableStateOf(false) }
|
||||||
BackHandler(enabled = screen != Screen.HOME && screen != Screen.INTRO) {
|
BackHandler(enabled = screen != Screen.HOME && screen != Screen.INTRO) {
|
||||||
screen = if (screen == Screen.RECOMMENDED_APPS) Screen.SETTINGS else Screen.HOME
|
screen = when (screen) {
|
||||||
|
Screen.RECOMMENDED_APPS, Screen.LOGS, Screen.CAR_PREVIEW, Screen.HELP -> Screen.SETTINGS
|
||||||
|
else -> Screen.HOME
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Home stays upright; every other screen turns with the phone.
|
// Home stays upright; every other screen turns with the phone.
|
||||||
@@ -101,27 +104,27 @@ fun GearslipApp(onDisconnect: () -> Unit, onRequestCallScreening: () -> Unit) {
|
|||||||
when (screen) {
|
when (screen) {
|
||||||
Screen.INTRO -> IntroScreen(onDone = { screen = introReturn })
|
Screen.INTRO -> IntroScreen(onDone = { screen = introReturn })
|
||||||
Screen.HOME -> HomeScreen(
|
Screen.HOME -> HomeScreen(
|
||||||
onOpenLogs = { screen = Screen.LOGS },
|
|
||||||
onOpenSettings = { settingsAtUsageNotes = false; screen = Screen.SETTINGS },
|
onOpenSettings = { settingsAtUsageNotes = false; screen = Screen.SETTINGS },
|
||||||
onOpenCarPreview = { screen = Screen.CAR_PREVIEW },
|
|
||||||
onOpenHelp = { screen = Screen.HELP },
|
|
||||||
onOpenUsageNotes = { settingsAtUsageNotes = true; screen = Screen.SETTINGS },
|
onOpenUsageNotes = { settingsAtUsageNotes = true; screen = Screen.SETTINGS },
|
||||||
onDisconnect = onDisconnect,
|
onDisconnect = onDisconnect,
|
||||||
)
|
)
|
||||||
Screen.WHATS_NEW -> WhatsNewScreen(onBack = { screen = Screen.SETTINGS })
|
Screen.WHATS_NEW -> WhatsNewScreen(onBack = { screen = Screen.SETTINGS })
|
||||||
Screen.LOGS -> LogsScreen(onBack = { screen = Screen.HOME })
|
Screen.LOGS -> LogsScreen(onBack = { screen = Screen.SETTINGS })
|
||||||
Screen.SETTINGS -> SettingsScreen(
|
Screen.SETTINGS -> SettingsScreen(
|
||||||
onBack = { screen = Screen.HOME },
|
onBack = { screen = Screen.HOME },
|
||||||
onOpenRecommendedApps = { settingsAtUsageNotes = false; screen = Screen.RECOMMENDED_APPS },
|
onOpenRecommendedApps = { settingsAtUsageNotes = false; screen = Screen.RECOMMENDED_APPS },
|
||||||
onOpenWhatsNew = { settingsAtUsageNotes = false; screen = Screen.WHATS_NEW },
|
onOpenWhatsNew = { settingsAtUsageNotes = false; screen = Screen.WHATS_NEW },
|
||||||
|
onOpenHelp = { settingsAtUsageNotes = false; screen = Screen.HELP },
|
||||||
|
onOpenCarPreview = { settingsAtUsageNotes = false; screen = Screen.CAR_PREVIEW },
|
||||||
|
onOpenLogs = { settingsAtUsageNotes = false; screen = Screen.LOGS },
|
||||||
onReplayTutorial = { screen = Screen.SETUP_GUIDE },
|
onReplayTutorial = { screen = Screen.SETUP_GUIDE },
|
||||||
onReplayIntro = { introReturn = Screen.SETTINGS; screen = Screen.INTRO },
|
onReplayIntro = { introReturn = Screen.SETTINGS; screen = Screen.INTRO },
|
||||||
atUsageNotes = settingsAtUsageNotes,
|
atUsageNotes = settingsAtUsageNotes,
|
||||||
)
|
)
|
||||||
Screen.RECOMMENDED_APPS -> RecommendedAppsScreen(onBack = { screen = Screen.SETTINGS })
|
Screen.RECOMMENDED_APPS -> RecommendedAppsScreen(onBack = { screen = Screen.SETTINGS })
|
||||||
Screen.CAR_PREVIEW -> CarPreviewScreen(onBack = { screen = Screen.HOME })
|
Screen.CAR_PREVIEW -> CarPreviewScreen(onBack = { screen = Screen.SETTINGS })
|
||||||
Screen.HELP -> HelpScreen(
|
Screen.HELP -> HelpScreen(
|
||||||
onBack = { screen = Screen.HOME },
|
onBack = { screen = Screen.SETTINGS },
|
||||||
onRequestCallScreening = onRequestCallScreening,
|
onRequestCallScreening = onRequestCallScreening,
|
||||||
)
|
)
|
||||||
Screen.CERT_SETUP -> CertSetupScreen(
|
Screen.CERT_SETUP -> CertSetupScreen(
|
||||||
|
|||||||
@@ -47,10 +47,7 @@ import app.seb3thehacker.gearslip.stats.WorkedPrompt
|
|||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun HomeScreen(
|
fun HomeScreen(
|
||||||
onOpenLogs: () -> Unit,
|
|
||||||
onOpenSettings: () -> Unit,
|
onOpenSettings: () -> Unit,
|
||||||
onOpenCarPreview: () -> Unit,
|
|
||||||
onOpenHelp: () -> Unit,
|
|
||||||
onOpenUsageNotes: () -> Unit,
|
onOpenUsageNotes: () -> Unit,
|
||||||
onDisconnect: () -> Unit,
|
onDisconnect: () -> Unit,
|
||||||
) {
|
) {
|
||||||
@@ -108,10 +105,6 @@ fun HomeScreen(
|
|||||||
}
|
}
|
||||||
Spacer(Modifier.height(16.dp))
|
Spacer(Modifier.height(16.dp))
|
||||||
UpdateCard()
|
UpdateCard()
|
||||||
if (status.phase != SessionStatus.Phase.PROJECTING) {
|
|
||||||
Spacer(Modifier.height(16.dp))
|
|
||||||
WirelessCard()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sits at the bottom, where a thumb reaches it.
|
// Sits at the bottom, where a thumb reaches it.
|
||||||
@@ -120,29 +113,8 @@ fun HomeScreen(
|
|||||||
Button(onClick = onDisconnect, modifier = Modifier.fillMaxWidth().height(56.dp)) {
|
Button(onClick = onDisconnect, modifier = Modifier.fillMaxWidth().height(56.dp)) {
|
||||||
Text("Disconnect")
|
Text("Disconnect")
|
||||||
}
|
}
|
||||||
Spacer(Modifier.height(16.dp))
|
} else {
|
||||||
}
|
WirelessButton()
|
||||||
|
|
||||||
// Not while the card above is asking the same thing.
|
|
||||||
if (workedCar == null || live) {
|
|
||||||
UsageNotesHomeCard(onOpen = onOpenUsageNotes)
|
|
||||||
Spacer(Modifier.height(16.dp))
|
|
||||||
}
|
|
||||||
|
|
||||||
Surface(color = MaterialTheme.colorScheme.surfaceContainerHigh, shape = MaterialTheme.shapes.extraLarge) {
|
|
||||||
Column {
|
|
||||||
if (!live) {
|
|
||||||
ActionRow(Icons.Filled.PlayArrow, "Car preview", onOpenCarPreview)
|
|
||||||
RowDivider()
|
|
||||||
}
|
|
||||||
ActionRow(Icons.Filled.List, "Live logs", onOpenLogs)
|
|
||||||
RowDivider()
|
|
||||||
ActionRow(Icons.Filled.Info, "Connection help", onOpenHelp)
|
|
||||||
if (BuildConfig.DEBUG) {
|
|
||||||
RowDivider()
|
|
||||||
ActionRow(Icons.Filled.Send, "Send a test message") { TestMessage.post(context) }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -152,34 +124,6 @@ fun HomeScreen(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
|
||||||
private fun ActionRow(icon: ImageVector, label: String, onClick: () -> Unit) {
|
|
||||||
Row(
|
|
||||||
Modifier
|
|
||||||
.fillMaxWidth()
|
|
||||||
.clickable(onClick = onClick)
|
|
||||||
.padding(horizontal = 20.dp, vertical = 18.dp),
|
|
||||||
verticalAlignment = Alignment.CenterVertically,
|
|
||||||
horizontalArrangement = Arrangement.spacedBy(16.dp),
|
|
||||||
) {
|
|
||||||
Icon(icon, contentDescription = null, tint = MaterialTheme.colorScheme.primary)
|
|
||||||
Text(label, style = MaterialTheme.typography.titleMedium, modifier = Modifier.weight(1f))
|
|
||||||
Icon(
|
|
||||||
Icons.AutoMirrored.Filled.KeyboardArrowRight,
|
|
||||||
contentDescription = null,
|
|
||||||
tint = MaterialTheme.colorScheme.onSurfaceVariant,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Composable
|
|
||||||
private fun RowDivider() {
|
|
||||||
HorizontalDivider(
|
|
||||||
modifier = Modifier.padding(horizontal = 20.dp),
|
|
||||||
color = MaterialTheme.colorScheme.outlineVariant,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
private fun StatusCard(status: SessionStatus.Snapshot) {
|
private fun StatusCard(status: SessionStatus.Snapshot) {
|
||||||
val scheme = MaterialTheme.colorScheme
|
val scheme = MaterialTheme.colorScheme
|
||||||
|
|||||||
@@ -19,7 +19,11 @@ import androidx.compose.foundation.verticalScroll
|
|||||||
import androidx.compose.material.icons.Icons
|
import androidx.compose.material.icons.Icons
|
||||||
import androidx.compose.material.icons.automirrored.filled.ArrowBack
|
import androidx.compose.material.icons.automirrored.filled.ArrowBack
|
||||||
import androidx.compose.material.icons.automirrored.filled.KeyboardArrowRight
|
import androidx.compose.material.icons.automirrored.filled.KeyboardArrowRight
|
||||||
|
import androidx.compose.material.icons.automirrored.filled.List
|
||||||
|
import androidx.compose.material.icons.automirrored.filled.Send
|
||||||
import androidx.compose.material.icons.filled.Add
|
import androidx.compose.material.icons.filled.Add
|
||||||
|
import androidx.compose.material.icons.filled.Info
|
||||||
|
import androidx.compose.material.icons.filled.PlayArrow
|
||||||
import androidx.compose.material.icons.filled.Delete
|
import androidx.compose.material.icons.filled.Delete
|
||||||
import androidx.compose.material.icons.filled.KeyboardArrowDown
|
import androidx.compose.material.icons.filled.KeyboardArrowDown
|
||||||
import androidx.compose.material.icons.filled.KeyboardArrowUp
|
import androidx.compose.material.icons.filled.KeyboardArrowUp
|
||||||
@@ -60,6 +64,8 @@ import androidx.compose.ui.unit.dp
|
|||||||
import app.seb3thehacker.gearslip.AppSettings
|
import app.seb3thehacker.gearslip.AppSettings
|
||||||
import app.seb3thehacker.gearslip.BuildConfig
|
import app.seb3thehacker.gearslip.BuildConfig
|
||||||
import app.seb3thehacker.gearslip.CertProvider
|
import app.seb3thehacker.gearslip.CertProvider
|
||||||
|
import app.seb3thehacker.gearslip.SessionStatus
|
||||||
|
import app.seb3thehacker.gearslip.notify.TestMessage
|
||||||
import app.seb3thehacker.gearslip.car.CarSettings
|
import app.seb3thehacker.gearslip.car.CarSettings
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
@@ -74,12 +80,15 @@ fun SettingsScreen(
|
|||||||
onBack: () -> Unit,
|
onBack: () -> Unit,
|
||||||
onOpenRecommendedApps: () -> Unit,
|
onOpenRecommendedApps: () -> Unit,
|
||||||
onOpenWhatsNew: () -> Unit,
|
onOpenWhatsNew: () -> Unit,
|
||||||
|
onOpenHelp: () -> Unit,
|
||||||
|
onOpenCarPreview: () -> Unit,
|
||||||
|
onOpenLogs: () -> Unit,
|
||||||
onReplayTutorial: () -> Unit,
|
onReplayTutorial: () -> Unit,
|
||||||
onReplayIntro: () -> Unit,
|
onReplayIntro: () -> Unit,
|
||||||
atUsageNotes: Boolean = false,
|
atUsageNotes: Boolean = false,
|
||||||
) {
|
) {
|
||||||
val scroll = rememberScrollState()
|
val scroll = rememberScrollState()
|
||||||
// Opened from Home's usage notes row: start at that section.
|
// Opened from Home's "it worked" card: start at usage notes.
|
||||||
var usageNotesY by remember { mutableIntStateOf(-1) }
|
var usageNotesY by remember { mutableIntStateOf(-1) }
|
||||||
if (atUsageNotes) {
|
if (atUsageNotes) {
|
||||||
LaunchedEffect(Unit) {
|
LaunchedEffect(Unit) {
|
||||||
@@ -111,6 +120,7 @@ fun SettingsScreen(
|
|||||||
) {
|
) {
|
||||||
Spacer(Modifier.height(0.dp))
|
Spacer(Modifier.height(0.dp))
|
||||||
ConnectionSection()
|
ConnectionSection()
|
||||||
|
HelpSection(onOpenHelp, onOpenCarPreview, onOpenLogs)
|
||||||
CarAudioSection()
|
CarAudioSection()
|
||||||
VoiceModelSection()
|
VoiceModelSection()
|
||||||
if (SHOW_RECOMMENDED_APPS) AppsSection(onOpenRecommendedApps)
|
if (SHOW_RECOMMENDED_APPS) AppsSection(onOpenRecommendedApps)
|
||||||
@@ -185,6 +195,51 @@ private fun ConnectionSection() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Connection help, and the tools for checking what Gearslip does. */
|
||||||
|
@Composable
|
||||||
|
private fun HelpSection(onOpenHelp: () -> Unit, onOpenCarPreview: () -> Unit, onOpenLogs: () -> Unit) {
|
||||||
|
val context = LocalContext.current
|
||||||
|
val status by SessionStatus.state.collectAsState()
|
||||||
|
val live = status.phase == SessionStatus.Phase.CONNECTING || status.phase == SessionStatus.Phase.PROJECTING
|
||||||
|
SettingsSection("Help and tools") {
|
||||||
|
SettingsRow(
|
||||||
|
"Connection help",
|
||||||
|
Modifier.clickable(onClick = onOpenHelp),
|
||||||
|
subtitle = "Which cars work, and what to set up first",
|
||||||
|
icon = Icons.Filled.Info,
|
||||||
|
trailing = { Arrow() },
|
||||||
|
)
|
||||||
|
// The preview draws the car screen on the phone, so it waits until no car is using it.
|
||||||
|
if (!live) {
|
||||||
|
SettingsDivider()
|
||||||
|
SettingsRow(
|
||||||
|
"Car preview",
|
||||||
|
Modifier.clickable(onClick = onOpenCarPreview),
|
||||||
|
subtitle = "See the car screen on your phone",
|
||||||
|
icon = Icons.Filled.PlayArrow,
|
||||||
|
trailing = { Arrow() },
|
||||||
|
)
|
||||||
|
}
|
||||||
|
SettingsDivider()
|
||||||
|
SettingsRow(
|
||||||
|
"Live logs",
|
||||||
|
Modifier.clickable(onClick = onOpenLogs),
|
||||||
|
subtitle = "What Gearslip and the car are saying to each other",
|
||||||
|
icon = Icons.AutoMirrored.Filled.List,
|
||||||
|
trailing = { Arrow() },
|
||||||
|
)
|
||||||
|
if (BuildConfig.DEBUG) {
|
||||||
|
SettingsDivider()
|
||||||
|
SettingsRow(
|
||||||
|
"Send a test message",
|
||||||
|
Modifier.clickable { TestMessage.post(context) },
|
||||||
|
subtitle = "Dev builds only. Posts a message notification to read on the car",
|
||||||
|
icon = Icons.AutoMirrored.Filled.Send,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/** How music reaches the car: by Bluetooth as usual, or through Gearslip over USB. Same choice as setup. */
|
/** How music reaches the car: by Bluetooth as usual, or through Gearslip over USB. Same choice as setup. */
|
||||||
@Composable
|
@Composable
|
||||||
private fun CarAudioSection() {
|
private fun CarAudioSection() {
|
||||||
|
|||||||
@@ -256,44 +256,3 @@ 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) },
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
+16
-16
@@ -8,15 +8,13 @@ import androidx.activity.compose.rememberLauncherForActivityResult
|
|||||||
import androidx.activity.result.contract.ActivityResultContracts
|
import androidx.activity.result.contract.ActivityResultContracts
|
||||||
import androidx.compose.foundation.clickable
|
import androidx.compose.foundation.clickable
|
||||||
import androidx.compose.foundation.layout.Column
|
import androidx.compose.foundation.layout.Column
|
||||||
import androidx.compose.foundation.layout.Spacer
|
|
||||||
import androidx.compose.foundation.layout.fillMaxWidth
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
import androidx.compose.foundation.layout.height
|
import androidx.compose.foundation.layout.height
|
||||||
import androidx.compose.foundation.layout.padding
|
import androidx.compose.foundation.layout.padding
|
||||||
import androidx.compose.foundation.rememberScrollState
|
import androidx.compose.foundation.rememberScrollState
|
||||||
import androidx.compose.foundation.verticalScroll
|
import androidx.compose.foundation.verticalScroll
|
||||||
import androidx.compose.material.icons.Icons
|
|
||||||
import androidx.compose.material.icons.filled.Info
|
|
||||||
import androidx.compose.material3.AlertDialog
|
import androidx.compose.material3.AlertDialog
|
||||||
|
import androidx.compose.material3.FilledTonalButton
|
||||||
import androidx.compose.material3.MaterialTheme
|
import androidx.compose.material3.MaterialTheme
|
||||||
import androidx.compose.material3.Text
|
import androidx.compose.material3.Text
|
||||||
import androidx.compose.material3.TextButton
|
import androidx.compose.material3.TextButton
|
||||||
@@ -41,11 +39,11 @@ private val WIRELESS_PERMISSIONS = buildList {
|
|||||||
}.toTypedArray()
|
}.toTypedArray()
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Test entry point for wireless Android Auto: pick the paired car, and Gearslip connects to it
|
* Test entry point for wireless Android Auto, at the bottom of Home: pick the paired car, and
|
||||||
* over Bluetooth and Wi-Fi. Automatic start comes later.
|
* Gearslip connects to it over Bluetooth and Wi-Fi. Automatic start comes later.
|
||||||
*/
|
*/
|
||||||
@Composable
|
@Composable
|
||||||
internal fun WirelessCard() {
|
internal fun WirelessButton() {
|
||||||
val context = LocalContext.current
|
val context = LocalContext.current
|
||||||
var devices by remember { mutableStateOf<List<BluetoothDevice>?>(null) }
|
var devices by remember { mutableStateOf<List<BluetoothDevice>?>(null) }
|
||||||
var denied by remember { mutableStateOf(false) }
|
var denied by remember { mutableStateOf(false) }
|
||||||
@@ -56,18 +54,21 @@ internal fun WirelessCard() {
|
|||||||
if (granted()) devices = WirelessLink.pairedDevices(context) else denied = true
|
if (granted()) devices = WirelessLink.pairedDevices(context) else denied = true
|
||||||
}
|
}
|
||||||
|
|
||||||
SettingsCard {
|
if (denied) {
|
||||||
SettingsRow(
|
Text(
|
||||||
"Connect wirelessly (test)",
|
"Gearslip needs Bluetooth and nearby Wi-Fi access for this.",
|
||||||
Modifier.clickable {
|
style = MaterialTheme.typography.bodyMedium,
|
||||||
|
color = MaterialTheme.colorScheme.onSurfaceVariant,
|
||||||
|
modifier = Modifier.padding(bottom = 8.dp),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
FilledTonalButton(
|
||||||
|
onClick = {
|
||||||
denied = false
|
denied = false
|
||||||
if (granted()) devices = WirelessLink.pairedDevices(context) else ask.launch(WIRELESS_PERMISSIONS)
|
if (granted()) devices = WirelessLink.pairedDevices(context) else ask.launch(WIRELESS_PERMISSIONS)
|
||||||
},
|
},
|
||||||
subtitle = if (denied) "Gearslip needs Bluetooth and nearby Wi-Fi access for this"
|
modifier = Modifier.fillMaxWidth().height(56.dp),
|
||||||
else "Pick your car from the phone's paired devices",
|
) { Text("Connect wirelessly (test)") }
|
||||||
icon = Icons.Filled.Info,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
devices?.let { list ->
|
devices?.let { list ->
|
||||||
AlertDialog(
|
AlertDialog(
|
||||||
@@ -96,5 +97,4 @@ internal fun WirelessCard() {
|
|||||||
confirmButton = { TextButton(onClick = { devices = null }) { Text("Cancel") } },
|
confirmButton = { TextButton(onClick = { devices = null }) { Text("Cancel") } },
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
Spacer(Modifier.height(16.dp))
|
|
||||||
}
|
}
|
||||||
Reference in new issue
Block a user