refactor: QrCodeScanDialog with single channel list and Add/Remove toggle (#1179)

This commit is contained in:
Andre K 2024-08-03 10:47:16 -03:00 committed by GitHub
parent b59db299c7
commit 13606ad1f9
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 128 additions and 97 deletions

View file

@ -525,9 +525,12 @@ private fun ChannelListView(
)
}
OutlinedButton(
modifier = Modifier.fillMaxWidth(),
onClick = onClick,
modifier = Modifier.fillMaxWidth(),
enabled = enabled,
colors = ButtonDefaults.outlinedButtonColors(
contentColor = MaterialTheme.colors.onSurface,
),
) { Text(text = stringResource(R.string.edit)) }
},
second = {

View file

@ -1,19 +1,23 @@
package com.geeksville.mesh.ui.components
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.ExperimentalLayoutApi
import androidx.compose.foundation.layout.FlowRow
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.widthIn
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.itemsIndexed
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.Button
import androidx.compose.material.ButtonDefaults
import androidx.compose.material.MaterialTheme
import androidx.compose.material.OutlinedButton
import androidx.compose.material.Surface
import androidx.compose.material.Text
import androidx.compose.material.TextButton
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateListOf
@ -23,6 +27,7 @@ import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.tooling.preview.PreviewScreenSizes
import androidx.compose.ui.unit.dp
import androidx.compose.ui.window.Dialog
@ -32,12 +37,12 @@ import com.geeksville.mesh.R
import com.geeksville.mesh.channelSet
import com.geeksville.mesh.copy
import com.geeksville.mesh.model.Channel
import com.geeksville.mesh.ui.components.config.ChannelCard
import com.geeksville.mesh.ui.components.config.ChannelSelection
/**
* Enables the user to select which channels to accept after scanning a QR code.
*/
@OptIn(ExperimentalLayoutApi::class)
@Suppress("LongMethod")
@Composable
fun ScannedQrCodeDialog(
@ -46,19 +51,31 @@ fun ScannedQrCodeDialog(
onDismiss: () -> Unit,
onConfirm: (ChannelSet) -> Unit
) {
var currentChannelSet by remember(channels) { mutableStateOf(channels) }
val modemPresetName = Channel(loraConfig = currentChannelSet.loraConfig).name
var shouldReplace by remember { mutableStateOf(true) }
val channelSet = remember(shouldReplace) {
if (shouldReplace) {
incoming
} else {
channels.copy {
val result = LinkedHashSet(settings + incoming.settingsList)
settings.clear()
settings.addAll(result)
}
}
}
val modemPresetName = Channel(loraConfig = channelSet.loraConfig).name
/* Holds selections made by the user */
val channelSelections = remember { mutableStateListOf(elements = Array(size = 8, init = { true })) }
val channelSelections = remember(channelSet) {
mutableStateListOf(elements = Array(size = channelSet.settingsCount, 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++
val selectedChannelSet = channelSet.copy {
val result = settings.filterIndexed { i, _ -> channelSelections.getOrNull(i) == true }
settings.clear()
settings.addAll(result)
}
Dialog(
@ -66,7 +83,7 @@ fun ScannedQrCodeDialog(
properties = DialogProperties(usePlatformDefaultWidth = false, dismissOnBackPress = true)
) {
Surface(
modifier = Modifier.fillMaxSize(),
modifier = Modifier.widthIn(max = 600.dp),
shape = RoundedCornerShape(16.dp),
color = MaterialTheme.colors.background
) {
@ -74,108 +91,89 @@ fun ScannedQrCodeDialog(
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)
text = stringResource(id = R.string.new_channel_rcvd),
modifier = Modifier.padding(20.dp),
style = MaterialTheme.typography.h6,
)
}
itemsIndexed(incoming.settingsList) { index, channel ->
itemsIndexed(channelSet.settingsList) { index, channel ->
ChannelSelection(
index = index,
title = channel.name.ifEmpty { modemPresetName },
enabled = true,
isSelected = channelSelections[index],
onSelected = { channelSelections[index] = it }
onSelected = {
if (it || selectedChannelSet.settingsCount > 1) {
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)
}
}
)
Row(
modifier = Modifier.padding(vertical = 20.dp),
) {
val selectedColors = ButtonDefaults.buttonColors()
val unselectedColors = ButtonDefaults.outlinedButtonColors(
contentColor = MaterialTheme.colors.onSurface,
)
OutlinedButton(
onClick = { shouldReplace = false },
modifier = Modifier
.height(48.dp)
.weight(1f),
colors = if (!shouldReplace) selectedColors else unselectedColors,
) { Text(text = stringResource(R.string.add)) }
OutlinedButton(
onClick = { shouldReplace = true },
modifier = Modifier
.height(48.dp)
.weight(1f),
colors = if (shouldReplace) selectedColors else unselectedColors,
) { Text(text = stringResource(R.string.replace)) }
}
}
/* User Actions via buttons */
item {
Row(
modifier = Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.SpaceEvenly
FlowRow(
horizontalArrangement = Arrangement.SpaceBetween,
modifier = Modifier
.fillMaxWidth()
.padding(horizontal = 24.dp)
) {
/* Cancel */
Button(
onClick = onDismiss,
modifier = Modifier
.fillMaxWidth()
.height(48.dp)
.weight(1f)
.padding(3.dp)
TextButton(
onClick = {
onDismiss()
},
) {
Text(
text = stringResource(id = R.string.cancel),
color = MaterialTheme.colors.onSurface,
overflow = TextOverflow.Ellipsis,
maxLines = 1,
style = MaterialTheme.typography.body1,
text = stringResource(id = R.string.cancel)
)
}
/* Add - Appends incoming selected channels to the current set */
Button(
enabled = totalCount <= 8,
TextButton(
onClick = {
val appended = currentChannelSet.copy {
val result = incoming.settingsList.filterIndexed { i, _ ->
channelSelections.getOrNull(i) == true
}
settings.addAll(result)
}
onDismiss.invoke()
onConfirm.invoke(appended)
onDismiss()
onConfirm(selectedChannelSet)
},
modifier = Modifier
.fillMaxWidth()
.height(48.dp)
.weight(1f)
.padding(3.dp)
enabled = selectedChannelSet.settingsCount in 1..8,
) {
Text(
text = stringResource(id = R.string.accept),
color = MaterialTheme.colors.onSurface,
overflow = TextOverflow.Ellipsis,
maxLines = 1,
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)
)
}
}

View file

@ -42,6 +42,7 @@ import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalFocusManager
import androidx.compose.ui.platform.LocalHapticFeedback
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
@ -79,11 +80,18 @@ private fun ChannelItem(
val textColor = if (enabled) Color.Unspecified
else MaterialTheme.colors.onSurface.copy(alpha = ContentAlpha.disabled)
Chip(onClick = onClick) { Text("$index") }
Chip(onClick = onClick) {
Text(
text = "$index",
color = textColor,
)
}
Text(
text = title,
modifier = Modifier.weight(1f),
color = textColor,
overflow = TextOverflow.Ellipsis,
maxLines = 1,
style = MaterialTheme.typography.body1,
)
content()