diff --git a/app/src/main/java/com/geeksville/mesh/model/UIState.kt b/app/src/main/java/com/geeksville/mesh/model/UIState.kt index bec391d9c..b7893b30a 100644 --- a/app/src/main/java/com/geeksville/mesh/model/UIState.kt +++ b/app/src/main/java/com/geeksville/mesh/model/UIState.kt @@ -370,7 +370,7 @@ class UIViewModel @Inject constructor( } // managed mode disables all access to configuration - val isManaged: Boolean get() = config.device.isManaged + val isManaged: Boolean get() = config.device.isManaged || config.security.isManaged val myNodeNum get() = myNodeInfo.value?.myNodeNum val maxChannels get() = myNodeInfo.value?.maxChannels ?: 8 diff --git a/app/src/main/java/com/geeksville/mesh/service/MeshService.kt b/app/src/main/java/com/geeksville/mesh/service/MeshService.kt index 361622979..e97ab60aa 100644 --- a/app/src/main/java/com/geeksville/mesh/service/MeshService.kt +++ b/app/src/main/java/com/geeksville/mesh/service/MeshService.kt @@ -1547,7 +1547,7 @@ class MeshService : Service(), Logging { if (deviceVersion < minDeviceVersion || appVersion < minAppVersion) { info("Device firmware or app is too old, faking config so firmware update can occur") clearLocalConfig() - setLocalConfig(config { device = device.copy { isManaged = true } }) + setLocalConfig(config { security = security.copy { isManaged = true } }) } onHasSettings() } diff --git a/app/src/main/java/com/geeksville/mesh/ui/DeviceSettingsFragment.kt b/app/src/main/java/com/geeksville/mesh/ui/DeviceSettingsFragment.kt index 658dc8a49..429b86480 100644 --- a/app/src/main/java/com/geeksville/mesh/ui/DeviceSettingsFragment.kt +++ b/app/src/main/java/com/geeksville/mesh/ui/DeviceSettingsFragment.kt @@ -85,6 +85,7 @@ import com.geeksville.mesh.ui.components.config.PositionConfigItemList import com.geeksville.mesh.ui.components.config.PowerConfigItemList import com.geeksville.mesh.ui.components.config.RangeTestConfigItemList import com.geeksville.mesh.ui.components.config.RemoteHardwareConfigItemList +import com.geeksville.mesh.ui.components.config.SecurityConfigItemList import com.geeksville.mesh.ui.components.config.SerialConfigItemList import com.geeksville.mesh.ui.components.config.StoreForwardConfigItemList import com.geeksville.mesh.ui.components.config.TelemetryConfigItemList @@ -172,6 +173,7 @@ enum class ConfigRoute(val title: String, val configType: Int = 0) { DISPLAY("Display", 4), LORA("LoRa", 5), BLUETOOTH("Bluetooth", 6), + SECURITY("Security", 7), ; } @@ -482,6 +484,16 @@ fun RadioConfigNavHost( } ) } + composable(ConfigRoute.SECURITY.name) { + SecurityConfigItemList( + securityConfig = radioConfigState.radioConfig.security, + enabled = connected, + onConfirm = { securityInput -> + val config = config { security = securityInput } + viewModel.setRemoteConfig(destNum, config) + } + ) + } composable(ModuleRoute.MQTT.name) { MQTTConfigItemList( mqttConfig = radioConfigState.moduleConfig.mqtt, diff --git a/app/src/main/java/com/geeksville/mesh/ui/components/config/BluetoothConfigItemList.kt b/app/src/main/java/com/geeksville/mesh/ui/components/config/BluetoothConfigItemList.kt index 066f57658..04eec1f8d 100644 --- a/app/src/main/java/com/geeksville/mesh/ui/components/config/BluetoothConfigItemList.kt +++ b/app/src/main/java/com/geeksville/mesh/ui/components/config/BluetoothConfigItemList.kt @@ -64,16 +64,6 @@ fun BluetoothConfigItemList( }) } - item { - SwitchPreference(title = "Device logging enabled", - checked = bluetoothInput.deviceLoggingEnabled, - enabled = enabled, - onCheckedChange = { - bluetoothInput = bluetoothInput.copy { deviceLoggingEnabled = it } - }) - } - item { Divider() } - item { PreferenceFooter( enabled = bluetoothInput != bluetoothConfig, diff --git a/app/src/main/java/com/geeksville/mesh/ui/components/config/DeviceConfigItemList.kt b/app/src/main/java/com/geeksville/mesh/ui/components/config/DeviceConfigItemList.kt index dc785717c..52b87cded 100644 --- a/app/src/main/java/com/geeksville/mesh/ui/components/config/DeviceConfigItemList.kt +++ b/app/src/main/java/com/geeksville/mesh/ui/components/config/DeviceConfigItemList.kt @@ -48,22 +48,6 @@ fun DeviceConfigItemList( } item { Divider() } - item { - SwitchPreference(title = "Serial output enabled", - checked = deviceInput.serialEnabled, - enabled = enabled, - onCheckedChange = { deviceInput = deviceInput.copy { serialEnabled = it } }) - } - item { Divider() } - - item { - SwitchPreference(title = "Debug log enabled", - checked = deviceInput.debugLogEnabled, - enabled = enabled, - onCheckedChange = { deviceInput = deviceInput.copy { debugLogEnabled = it } }) - } - item { Divider() } - item { EditTextPreference(title = "Redefine PIN_BUTTON", value = deviceInput.buttonGpio, @@ -115,16 +99,6 @@ fun DeviceConfigItemList( } item { Divider() } - item { - SwitchPreference(title = "Managed mode", - checked = deviceInput.isManaged, - enabled = enabled, - onCheckedChange = { - deviceInput = deviceInput.copy { isManaged = it } - }) - } - item { Divider() } - item { SwitchPreference(title = "Disable triple-click", checked = deviceInput.disableTripleClick, diff --git a/app/src/main/java/com/geeksville/mesh/ui/components/config/NetworkConfigItemList.kt b/app/src/main/java/com/geeksville/mesh/ui/components/config/NetworkConfigItemList.kt index 00a7ff711..78d0a6c1f 100644 --- a/app/src/main/java/com/geeksville/mesh/ui/components/config/NetworkConfigItemList.kt +++ b/app/src/main/java/com/geeksville/mesh/ui/components/config/NetworkConfigItemList.kt @@ -18,6 +18,7 @@ import androidx.compose.runtime.saveable.rememberSaveable import androidx.compose.runtime.setValue import androidx.compose.ui.Modifier import androidx.compose.ui.platform.LocalFocusManager +import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.input.ImeAction import androidx.compose.ui.text.input.KeyboardType import androidx.compose.ui.tooling.preview.Preview @@ -68,8 +69,7 @@ fun NetworkConfigItemList( if (result.contents != null) { val (ssid, psk) = extractWifiCredentials(result.contents) if (ssid != null && psk != null) { - networkInput = networkInput.copy { wifiSsid = ssid } - networkInput = networkInput.copy { wifiPsk = psk } + networkInput = networkInput.copy { wifiSsid = ssid; wifiPsk = psk } } else { showScanErrorDialog = true } @@ -130,8 +130,9 @@ fun NetworkConfigItemList( .fillMaxWidth() .padding(vertical = 8.dp) .height(48.dp), + enabled = enabled, ) { - Text(text = "Scan WiFi QR code") + Text(text = stringResource(R.string.wifi_qr_code_scan)) } } diff --git a/app/src/main/java/com/geeksville/mesh/ui/components/config/SecurityConfigItemList.kt b/app/src/main/java/com/geeksville/mesh/ui/components/config/SecurityConfigItemList.kt new file mode 100644 index 000000000..62515d377 --- /dev/null +++ b/app/src/main/java/com/geeksville/mesh/ui/components/config/SecurityConfigItemList.kt @@ -0,0 +1,134 @@ +package com.geeksville.mesh.ui.components.config + +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.foundation.text.KeyboardActions +import androidx.compose.material.Divider +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.saveable.rememberSaveable +import androidx.compose.runtime.setValue +import androidx.compose.ui.Modifier +import androidx.compose.ui.platform.LocalFocusManager +import androidx.compose.ui.tooling.preview.Preview +import com.geeksville.mesh.ConfigProtos.Config.SecurityConfig +import com.geeksville.mesh.copy +import com.geeksville.mesh.ui.components.EditBase64Preference +import com.geeksville.mesh.ui.components.PreferenceCategory +import com.geeksville.mesh.ui.components.PreferenceFooter +import com.geeksville.mesh.ui.components.SwitchPreference + +@Suppress("LongMethod") +@Composable +fun SecurityConfigItemList( + securityConfig: SecurityConfig, + enabled: Boolean, + onConfirm: (config: SecurityConfig) -> Unit, +) { + val focusManager = LocalFocusManager.current + var securityInput by rememberSaveable { mutableStateOf(securityConfig) } + + LazyColumn( + modifier = Modifier.fillMaxSize() + ) { + item { PreferenceCategory(text = "Security Config") } + + item { + EditBase64Preference( + title = "Public Key", + value = securityInput.publicKey, + enabled = enabled, + keyboardActions = KeyboardActions(onDone = { focusManager.clearFocus() }), + onValueChange = { + securityInput = securityInput.copy { publicKey = it } + }, + ) + } + + item { + EditBase64Preference( + title = "Private Key", + value = securityInput.privateKey, + enabled = enabled, + keyboardActions = KeyboardActions(onDone = { focusManager.clearFocus() }), + onValueChange = { + securityInput = securityInput.copy { privateKey = it } + }, + ) + } + + item { + EditBase64Preference( + title = "Admin Key", + value = securityInput.adminKey, + enabled = enabled, + keyboardActions = KeyboardActions(onDone = { focusManager.clearFocus() }), + onValueChange = { + securityInput = securityInput.copy { adminKey = it } + }, + ) + } + + item { + SwitchPreference(title = "Managed mode", + checked = securityInput.isManaged, + enabled = enabled, + onCheckedChange = { + securityInput = securityInput.copy { isManaged = it } + }) + } + item { Divider() } + + item { + SwitchPreference(title = "Serial enabled", + checked = securityInput.serialEnabled, + enabled = enabled, + onCheckedChange = { securityInput = securityInput.copy { serialEnabled = it } }) + } + item { Divider() } + + item { + SwitchPreference(title = "Debug log API enabled", + checked = securityInput.debugLogApiEnabled, + enabled = enabled, + onCheckedChange = { + securityInput = securityInput.copy { debugLogApiEnabled = it } + }) + } + item { Divider() } + + item { + SwitchPreference(title = "Legacy Admin Channel", + checked = securityInput.adminChannelEnabled, + enabled = enabled, + onCheckedChange = { + securityInput = securityInput.copy { adminChannelEnabled = it } + }) + } + item { Divider() } + + item { + PreferenceFooter( + enabled = securityInput != securityConfig, + onCancelClicked = { + focusManager.clearFocus() + }, + onSaveClicked = { + focusManager.clearFocus() + onConfirm(securityInput) + } + ) + } + } +} + +@Preview(showBackground = true) +@Composable +private fun SecurityConfigPreview() { + SecurityConfigItemList( + securityConfig = SecurityConfig.getDefaultInstance(), + enabled = true, + onConfirm = {}, + ) +}