mirror of
https://github.com/meshtastic/Meshtastic-Android.git
synced 2026-04-20 22:23:37 +00:00
fix: update channel URL to match channel selection
This commit is contained in:
parent
65d832ef99
commit
4e9055c9b1
3 changed files with 107 additions and 91 deletions
|
|
@ -48,7 +48,6 @@ import com.geeksville.mesh.databinding.ActivityMainBinding
|
|||
import com.geeksville.mesh.model.BluetoothViewModel
|
||||
import com.geeksville.mesh.model.DeviceVersion
|
||||
import com.geeksville.mesh.model.UIViewModel
|
||||
import com.geeksville.mesh.model.toChannelSet
|
||||
import com.geeksville.mesh.service.MeshService
|
||||
import com.geeksville.mesh.service.MeshServiceNotifications
|
||||
import com.geeksville.mesh.service.ServiceRepository
|
||||
|
|
@ -303,12 +302,7 @@ class MainActivity : AppCompatActivity(), Logging {
|
|||
when (appLinkAction) {
|
||||
Intent.ACTION_VIEW -> {
|
||||
debug("Asked to open a channel URL - ask user if they want to switch to that channel. If so send the config to the radio")
|
||||
try {
|
||||
appLinkData?.let { model.requestChannelSet(it.toChannelSet()) }
|
||||
} catch (ex: Throwable) {
|
||||
errormsg("Channel url error: ${ex.message}")
|
||||
showSnackbar("${getString(R.string.channel_invalid)}: ${ex.message}")
|
||||
}
|
||||
appLinkData?.let(model::requestChannelUrl)
|
||||
|
||||
// We now wait for the device to connect, once connected, we ask the user if they want to switch to the new channel
|
||||
}
|
||||
|
|
|
|||
|
|
@ -461,8 +461,11 @@ class UIViewModel @Inject constructor(
|
|||
private val _requestChannelSet = MutableStateFlow<AppOnlyProtos.ChannelSet?>(null)
|
||||
val requestChannelSet: StateFlow<AppOnlyProtos.ChannelSet?> get() = _requestChannelSet
|
||||
|
||||
fun requestChannelSet(channelSet: AppOnlyProtos.ChannelSet) {
|
||||
_requestChannelSet.value = channelSet
|
||||
fun requestChannelUrl(url: Uri) = runCatching {
|
||||
_requestChannelSet.value = url.toChannelSet()
|
||||
}.onFailure { ex ->
|
||||
errormsg("Channel url error: ${ex.message}")
|
||||
showSnackbar(R.string.channel_invalid)
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -125,7 +125,6 @@ fun ChannelScreen(
|
|||
) {
|
||||
val context = LocalContext.current
|
||||
val focusManager = LocalFocusManager.current
|
||||
val clipboardManager = LocalClipboardManager.current
|
||||
|
||||
val connectionState by viewModel.connectionState.collectAsStateWithLifecycle()
|
||||
val enabled = connectionState == MeshService.ConnectionState.CONNECTED && !viewModel.isManaged
|
||||
|
|
@ -138,22 +137,21 @@ fun ChannelScreen(
|
|||
/* Holds selections made by the user for QR generation. */
|
||||
val channelSelections = rememberSaveable(
|
||||
saver = listSaver(
|
||||
save = { stateList -> stateList.toList() },
|
||||
save = { it.toList() },
|
||||
restore = { it.toMutableStateList() }
|
||||
)
|
||||
) { mutableStateListOf(elements = Array(size = 8, init = { true })) }
|
||||
|
||||
val channelUrl = channelSet.getChannelUrl()
|
||||
val selectedChannelSet = channelSet.copy {
|
||||
val result = settings.filterIndexed { i, _ -> channelSelections.getOrNull(i) == true }
|
||||
settings.clear()
|
||||
settings.addAll(result)
|
||||
}
|
||||
val modemPresetName = Channel(loraConfig = channelSet.loraConfig).name
|
||||
|
||||
val barcodeLauncher = rememberLauncherForActivityResult(ScanContract()) { result ->
|
||||
if (result.contents != null) {
|
||||
try {
|
||||
viewModel.requestChannelSet(Uri.parse(result.contents).toChannelSet())
|
||||
} catch (ex: Throwable) {
|
||||
errormsg("Channel url error: ${ex.message}")
|
||||
viewModel.showSnackbar(R.string.channel_invalid)
|
||||
}
|
||||
viewModel.requestChannelUrl(Uri.parse(result.contents))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -340,64 +338,10 @@ fun ChannelScreen(
|
|||
}
|
||||
|
||||
item {
|
||||
var valueState by remember(channelUrl) { mutableStateOf(channelUrl) }
|
||||
val isError = valueState != channelUrl
|
||||
|
||||
OutlinedTextField(
|
||||
value = valueState.toString(),
|
||||
onValueChange = {
|
||||
try {
|
||||
valueState = Uri.parse(it)
|
||||
channelSet = valueState.toChannelSet()
|
||||
} catch (ex: Throwable) {
|
||||
// channelSet failed to update, isError true
|
||||
}
|
||||
},
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
EditChannelUrl(
|
||||
enabled = enabled,
|
||||
label = { Text("URL") },
|
||||
isError = isError,
|
||||
trailingIcon = {
|
||||
val isUrlEqual = channelUrl == channels.getChannelUrl()
|
||||
IconButton(onClick = {
|
||||
when {
|
||||
isError -> valueState = channelUrl
|
||||
!isUrlEqual -> viewModel.requestChannelSet(channels)
|
||||
else -> {
|
||||
// track how many times users share channels
|
||||
GeeksvilleApplication.analytics.track(
|
||||
"share",
|
||||
DataPair("content_type", "channel")
|
||||
)
|
||||
clipboardManager.setText(AnnotatedString(channelUrl.toString()))
|
||||
}
|
||||
}
|
||||
}) {
|
||||
Icon(
|
||||
imageVector = when {
|
||||
isError -> Icons.TwoTone.Close
|
||||
!isUrlEqual -> Icons.TwoTone.Check
|
||||
else -> Icons.TwoTone.ContentCopy
|
||||
},
|
||||
contentDescription = when {
|
||||
isError -> "Error"
|
||||
!isUrlEqual -> stringResource(R.string.send)
|
||||
else -> "Copy"
|
||||
},
|
||||
tint = if (isError) {
|
||||
MaterialTheme.colors.error
|
||||
} else {
|
||||
LocalContentColor.current.copy(alpha = LocalContentAlpha.current)
|
||||
}
|
||||
)
|
||||
}
|
||||
},
|
||||
maxLines = 1,
|
||||
singleLine = true,
|
||||
keyboardOptions = KeyboardOptions.Default.copy(
|
||||
keyboardType = KeyboardType.Uri, imeAction = ImeAction.Done
|
||||
),
|
||||
keyboardActions = KeyboardActions(onDone = { focusManager.clearFocus() }),
|
||||
channelUrl = selectedChannelSet.getChannelUrl(),
|
||||
onConfirm = viewModel::requestChannelUrl
|
||||
)
|
||||
}
|
||||
|
||||
|
|
@ -413,21 +357,20 @@ fun ChannelScreen(
|
|||
})
|
||||
}
|
||||
|
||||
if (isEditing) item {
|
||||
PreferenceFooter(
|
||||
enabled = enabled,
|
||||
onCancelClicked = {
|
||||
focusManager.clearFocus()
|
||||
showChannelEditor = false
|
||||
channelSet = channels
|
||||
},
|
||||
onSaveClicked = {
|
||||
focusManager.clearFocus()
|
||||
// viewModel.setRequestChannelUrl(channelUrl)
|
||||
sendButton()
|
||||
})
|
||||
} else {
|
||||
item {
|
||||
item {
|
||||
if (isEditing) {
|
||||
PreferenceFooter(
|
||||
enabled = enabled,
|
||||
onCancelClicked = {
|
||||
focusManager.clearFocus()
|
||||
showChannelEditor = false
|
||||
channelSet = channels
|
||||
},
|
||||
onSaveClicked = {
|
||||
focusManager.clearFocus()
|
||||
sendButton()
|
||||
})
|
||||
} else {
|
||||
PreferenceFooter(
|
||||
enabled = enabled,
|
||||
negativeText = R.string.reset,
|
||||
|
|
@ -438,7 +381,6 @@ fun ChannelScreen(
|
|||
positiveText = R.string.scan,
|
||||
onPositiveClicked = {
|
||||
focusManager.clearFocus()
|
||||
// viewModel.setRequestChannelUrl(channelUrl)
|
||||
if (context.hasCameraPermission()) zxingScan() else requestPermissionAndScan()
|
||||
})
|
||||
}
|
||||
|
|
@ -446,6 +388,83 @@ fun ChannelScreen(
|
|||
}
|
||||
}
|
||||
|
||||
@Suppress("LongMethod")
|
||||
@Composable
|
||||
private fun EditChannelUrl(
|
||||
enabled: Boolean,
|
||||
channelUrl: Uri,
|
||||
modifier: Modifier = Modifier,
|
||||
onConfirm: (Uri) -> Unit
|
||||
) {
|
||||
val focusManager = LocalFocusManager.current
|
||||
val clipboardManager = LocalClipboardManager.current
|
||||
|
||||
var valueState by remember(channelUrl) { mutableStateOf(channelUrl) }
|
||||
var isError by remember { mutableStateOf(false) }
|
||||
|
||||
OutlinedTextField(
|
||||
value = valueState.toString(),
|
||||
onValueChange = {
|
||||
isError = runCatching {
|
||||
valueState = Uri.parse(it)
|
||||
valueState.toChannelSet()
|
||||
}.isFailure
|
||||
},
|
||||
modifier = modifier.fillMaxWidth(),
|
||||
enabled = enabled,
|
||||
label = { Text("URL") },
|
||||
isError = isError,
|
||||
trailingIcon = {
|
||||
val isUrlEqual = valueState == channelUrl
|
||||
IconButton(onClick = {
|
||||
when {
|
||||
isError -> {
|
||||
isError = false
|
||||
valueState = channelUrl
|
||||
}
|
||||
|
||||
!isUrlEqual -> {
|
||||
onConfirm(valueState)
|
||||
valueState = channelUrl
|
||||
}
|
||||
|
||||
else -> {
|
||||
// track how many times users share channels
|
||||
GeeksvilleApplication.analytics.track(
|
||||
"share", DataPair("content_type", "channel")
|
||||
)
|
||||
clipboardManager.setText(AnnotatedString(valueState.toString()))
|
||||
}
|
||||
}
|
||||
}) {
|
||||
Icon(
|
||||
imageVector = when {
|
||||
isError -> Icons.TwoTone.Close
|
||||
!isUrlEqual -> Icons.TwoTone.Check
|
||||
else -> Icons.TwoTone.ContentCopy
|
||||
},
|
||||
contentDescription = when {
|
||||
isError -> stringResource(R.string.share)
|
||||
!isUrlEqual -> stringResource(R.string.send)
|
||||
else -> stringResource(R.string.share)
|
||||
},
|
||||
tint = if (isError) {
|
||||
MaterialTheme.colors.error
|
||||
} else {
|
||||
LocalContentColor.current.copy(alpha = LocalContentAlpha.current)
|
||||
}
|
||||
)
|
||||
}
|
||||
},
|
||||
maxLines = 1,
|
||||
singleLine = true,
|
||||
keyboardOptions = KeyboardOptions.Default.copy(
|
||||
keyboardType = KeyboardType.Uri, imeAction = ImeAction.Done
|
||||
),
|
||||
keyboardActions = KeyboardActions(onDone = { focusManager.clearFocus() }),
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun QrCodeImage(
|
||||
enabled: Boolean,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue