Channel scan select (#1141)

pull/1158/head
Robert-0410 2024-07-28 02:58:41 -07:00 zatwierdzone przez GitHub
rodzic 81297c46e9
commit ed17ae0734
Nie znaleziono w bazie danych klucza dla tego podpisu
ID klucza GPG: B5690EEEBB952194
2 zmienionych plików z 176 dodań i 2 usunięć

Wyświetl plik

@ -16,12 +16,14 @@ import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.itemsIndexed
import androidx.compose.foundation.lazy.rememberLazyListState
import androidx.compose.foundation.text.KeyboardActions
import androidx.compose.foundation.text.KeyboardOptions
import androidx.compose.material.ButtonDefaults
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.Card
import androidx.compose.material.Checkbox
import androidx.compose.material.Chip
@ -41,6 +43,9 @@ import androidx.compose.material.Text
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.twotone.Check
import androidx.compose.material.icons.twotone.Close
import androidx.compose.material.Button
import androidx.compose.material.Surface
import androidx.compose.material.ButtonDefaults
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.livedata.observeAsState
@ -72,6 +77,8 @@ import androidx.compose.ui.text.input.ImeAction
import androidx.compose.ui.text.input.KeyboardType
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import androidx.compose.ui.window.Dialog
import androidx.compose.ui.window.DialogProperties
import androidx.fragment.app.activityViewModels
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import androidx.lifecycle.viewmodel.compose.viewModel
@ -180,9 +187,12 @@ fun ChannelScreen(
val channelUrl = channelSet.getChannelUrl()
val modemPresetName = Channel(loraConfig = channelSet.loraConfig).name
val userScannedQrCode = remember { mutableStateOf(false) }
val scannedQR = remember { mutableStateOf("") }
val barcodeLauncher = rememberLauncherForActivityResult(ScanContract()) { result ->
if (result.contents != null) {
viewModel.setRequestChannelUrl(Uri.parse(result.contents))
scannedQR.value = result.contents
userScannedQrCode.value = true
}
}
@ -293,6 +303,15 @@ fun ChannelScreen(
.show()
}
if (userScannedQrCode.value)
/* Prompt the user to modify channels after scanning a QR code. */
ScannedQrCodeDialog(
channels = channels,
incoming = Uri.parse(scannedQR.value).toChannelSet(),
onDismiss = { userScannedQrCode.value = false },
onConfirm = { newChannelSet -> installSettings(newChannelSet) }
)
var showEditChannelDialog: Int? by remember { mutableStateOf(null) }
if (showEditChannelDialog != null) {
@ -547,6 +566,158 @@ private fun ChannelSelection(
}
}
/**
* Enables the user to select which channels to accept after scanning a QR code.
*/
@Suppress("LongMethod")
@Composable
fun ScannedQrCodeDialog(
channels: AppOnlyProtos.ChannelSet,
incoming: AppOnlyProtos.ChannelSet,
onDismiss: () -> Unit,
onConfirm: (AppOnlyProtos.ChannelSet) -> Unit
) {
var currentChannelSet by remember(channels) { mutableStateOf(channels) }
val modemPresetName = Channel(loraConfig = currentChannelSet.loraConfig).name
/* Holds selections made by the user */
val channelSelections = remember { mutableStateListOf(elements = Array(size = 8, init = { true })) }
/* The save button is enabled based on this count */
var totalCount = currentChannelSet.settingsList.size
for ((index, isSelected) in channelSelections.withIndex()) {
if (index >= incoming.settingsList.size)
break
if (isSelected)
totalCount++
}
Dialog(
onDismissRequest = { onDismiss() },
properties = DialogProperties(usePlatformDefaultWidth = false, dismissOnBackPress = true)
) {
Surface(
modifier = Modifier.fillMaxSize(),
shape = RoundedCornerShape(16.dp),
color = MaterialTheme.colors.background
) {
LazyColumn(
contentPadding = PaddingValues(horizontal = 24.dp, vertical = 16.dp),
horizontalAlignment = Alignment.CenterHorizontally
) {
/* Incoming ChannelSet */
item {
Text(
style = MaterialTheme.typography.body1,
text = stringResource(id = R.string.scanned_channels)
)
}
itemsIndexed(incoming.settingsList) { index, channel ->
ChannelSelection(
index = index,
title = channel.name.ifEmpty { modemPresetName },
enabled = true,
isSelected = channelSelections[index],
onSelected = { channelSelections[index] = it }
)
}
/* Current ChannelSet */
item {
Text(
style = MaterialTheme.typography.body1,
text = stringResource(id = R.string.current_channels)
)
}
itemsIndexed(currentChannelSet.settingsList) { index, channel ->
ChannelCard(
index = index,
title = channel.name.ifEmpty { modemPresetName },
enabled = true,
onEditClick = { /* Currently we don't enable editing from this dialog. */ },
onDeleteClick = {
val list = currentChannelSet.settingsList.toMutableList()
list.removeAt(index)
currentChannelSet = currentChannelSet.copy {
settings.clear()
settings.addAll(list)
}
}
)
}
/* User Actions via buttons */
item {
Row(
modifier = Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.SpaceEvenly
) {
/* Cancel */
Button(
onClick = onDismiss,
modifier = Modifier
.fillMaxWidth()
.height(48.dp)
.weight(1f)
.padding(3.dp)
) {
Text(
style = MaterialTheme.typography.body1,
text = stringResource(id = R.string.cancel)
)
}
/* Add - Appends incoming selected channels to the current set */
Button(
enabled = totalCount <= 8,
onClick = {
val appended = incoming.copy {
val result = settings.filterIndexed { i, _ ->
channelSelections.getOrNull(i) == true
}
settings.clear()
settings.addAll(currentChannelSet.settingsList)
settings.addAll(result)
}
onDismiss.invoke()
onConfirm.invoke(appended)
},
modifier = Modifier
.fillMaxWidth()
.height(48.dp)
.weight(1f)
.padding(3.dp)
) {
Text(
style = MaterialTheme.typography.body1,
text = stringResource(id = R.string.add)
)
}
/* Replace - Replaces the previous set with the scanned channel set */
Button(
onClick = {
onDismiss.invoke()
onConfirm.invoke(incoming)
},
modifier = Modifier
.fillMaxWidth()
.height(48.dp)
.weight(1f)
.padding(3.dp)
) {
Text(
style = MaterialTheme.typography.body1,
text = stringResource(id = R.string.replace)
)
}
}
}
}
}
}
}
@Preview(showBackground = true)
@Composable
private fun ChannelScreenPreview() {

Wyświetl plik

@ -206,4 +206,7 @@
<string name="mute_8_hours">8 hours</string>
<string name="mute_1_week">1 week</string>
<string name="mute_always">Always</string>
<string name="scanned_channels">Scanned Channels</string>
<string name="current_channels">Current Channels</string>
<string name="replace">Replace</string>
</resources>