From f1bb020203ee59c4416114a9e925c796086d736d Mon Sep 17 00:00:00 2001 From: Phil Oliver <3497406+poliver@users.noreply.github.com> Date: Mon, 25 Aug 2025 15:44:32 -0400 Subject: [PATCH] Relocate radio config to new top-level Settings screen (#2834) --- .../compose/EditDeviceProfileDialogTest.kt | 30 +- .../compose/MapReportingPreferenceTest.kt | 25 +- .../mesh/navigation/ChannelsRoutes.kt | 4 +- .../mesh/navigation/ConnectionsRoutes.kt | 6 +- .../geeksville/mesh/navigation/NavGraph.kt | 4 +- ...RadioConfigRoutes.kt => SettingsRoutes.kt} | 265 +++++++++--------- .../main/java/com/geeksville/mesh/ui/Main.kt | 11 +- .../mesh/ui/common/components/MainAppBar.kt | 20 +- .../common/components/ScannedQrCodeDialog.kt | 2 +- .../components/TitledCard.kt | 8 +- .../mesh/ui/common/icons/Settings.kt | 160 +++++++++++ .../mesh/ui/connections/Connections.kt | 14 +- .../ui/connections/components/BLEDevices.kt | 1 + .../components/CurrentlyConnectedCard.kt | 6 +- .../connections/components/NetworkDevices.kt | 1 + .../ui/connections/components/UsbDevices.kt | 1 + .../com/geeksville/mesh/ui/node/NodeDetail.kt | 6 +- .../ui/settings/components/SettingsItem.kt | 87 ++++++ .../radio}/CleanNodeDatabaseScreen.kt | 2 +- .../radio}/CleanNodeDatabaseViewModel.kt | 2 +- .../radio}/RadioConfig.kt | 123 +++++--- .../radio}/RadioConfigViewModel.kt | 6 +- .../radio}/ResponseState.kt | 9 +- .../AmbientLightingConfigItemList.kt | 37 +-- .../radio}/components/AudioConfigItemList.kt | 51 ++-- .../components/BluetoothConfigItemList.kt | 36 +-- .../components/CannedMessageConfigItemList.kt | 86 ++---- .../components/ChannelSettingsItemList.kt | 4 +- .../DetectionSensorConfigItemList.kt | 63 ++--- .../radio}/components/DeviceConfigItemList.kt | 170 ++++------- .../components/DisplayConfigItemList.kt | 4 +- .../radio}/components/EditChannelDialog.kt | 2 +- .../components/EditDeviceProfileDialog.kt | 59 ++-- .../ExternalNotificationConfigItemList.kt | 114 +++----- .../radio}/components/LoRaConfigItemList.kt | 78 +++--- .../radio}/components/MQTTConfigItemList.kt | 4 +- .../components/MapReportingPreference.kt | 41 +-- .../components/NeighborInfoConfigItemList.kt | 35 +-- .../components/NetworkConfigItemList.kt | 135 ++++----- .../components/PacketResponseStateDialog.kt | 52 ++-- .../components/PaxcounterConfigItemList.kt | 39 +-- .../components/PositionConfigItemList.kt | 4 +- .../radio}/components/PowerConfigItemList.kt | 4 +- .../components/RangeTestConfigItemList.kt | 33 +-- .../RemoteHardwareConfigItemList.kt | 42 ++- .../components/SecurityConfigItemList.kt | 137 ++++----- .../radio}/components/SerialConfigItemList.kt | 58 ++-- .../components/StoreForwardConfigItemList.kt | 41 +-- .../components/TelemetryConfigItemList.kt | 67 ++--- .../radio}/components/UserConfigItemList.kt | 68 ++--- .../com/geeksville/mesh/ui/sharing/Channel.kt | 6 +- app/src/main/res/values/strings.xml | 3 +- 52 files changed, 1077 insertions(+), 1189 deletions(-) rename app/src/main/java/com/geeksville/mesh/navigation/{RadioConfigRoutes.kt => SettingsRoutes.kt} (64%) rename app/src/main/java/com/geeksville/mesh/ui/{connections => common}/components/TitledCard.kt (86%) create mode 100644 app/src/main/java/com/geeksville/mesh/ui/common/icons/Settings.kt create mode 100644 app/src/main/java/com/geeksville/mesh/ui/settings/components/SettingsItem.kt rename app/src/main/java/com/geeksville/mesh/ui/{radioconfig => settings/radio}/CleanNodeDatabaseScreen.kt (99%) rename app/src/main/java/com/geeksville/mesh/ui/{radioconfig => settings/radio}/CleanNodeDatabaseViewModel.kt (99%) rename app/src/main/java/com/geeksville/mesh/ui/{radioconfig => settings/radio}/RadioConfig.kt (78%) rename app/src/main/java/com/geeksville/mesh/ui/{radioconfig => settings/radio}/RadioConfigViewModel.kt (99%) rename app/src/main/java/com/geeksville/mesh/ui/{radioconfig => settings/radio}/ResponseState.kt (90%) rename app/src/main/java/com/geeksville/mesh/ui/{radioconfig => settings/radio}/components/AmbientLightingConfigItemList.kt (85%) rename app/src/main/java/com/geeksville/mesh/ui/{radioconfig => settings/radio}/components/AudioConfigItemList.kt (86%) rename app/src/main/java/com/geeksville/mesh/ui/{radioconfig => settings/radio}/components/BluetoothConfigItemList.kt (86%) rename app/src/main/java/com/geeksville/mesh/ui/{radioconfig => settings/radio}/components/CannedMessageConfigItemList.kt (76%) rename app/src/main/java/com/geeksville/mesh/ui/{radioconfig => settings/radio}/components/ChannelSettingsItemList.kt (99%) rename app/src/main/java/com/geeksville/mesh/ui/{radioconfig => settings/radio}/components/DetectionSensorConfigItemList.kt (77%) rename app/src/main/java/com/geeksville/mesh/ui/{radioconfig => settings/radio}/components/DeviceConfigItemList.kt (66%) rename app/src/main/java/com/geeksville/mesh/ui/{radioconfig => settings/radio}/components/DisplayConfigItemList.kt (98%) rename app/src/main/java/com/geeksville/mesh/ui/{radioconfig => settings/radio}/components/EditChannelDialog.kt (99%) rename app/src/main/java/com/geeksville/mesh/ui/{radioconfig => settings/radio}/components/EditDeviceProfileDialog.kt (73%) rename app/src/main/java/com/geeksville/mesh/ui/{radioconfig => settings/radio}/components/ExternalNotificationConfigItemList.kt (76%) rename app/src/main/java/com/geeksville/mesh/ui/{radioconfig => settings/radio}/components/LoRaConfigItemList.kt (88%) rename app/src/main/java/com/geeksville/mesh/ui/{radioconfig => settings/radio}/components/MQTTConfigItemList.kt (98%) rename app/src/main/java/com/geeksville/mesh/ui/{radioconfig => settings/radio}/components/MapReportingPreference.kt (83%) rename app/src/main/java/com/geeksville/mesh/ui/{radioconfig => settings/radio}/components/NeighborInfoConfigItemList.kt (83%) rename app/src/main/java/com/geeksville/mesh/ui/{radioconfig => settings/radio}/components/NetworkConfigItemList.kt (77%) rename app/src/main/java/com/geeksville/mesh/ui/{radioconfig => settings/radio}/components/PacketResponseStateDialog.kt (68%) rename app/src/main/java/com/geeksville/mesh/ui/{radioconfig => settings/radio}/components/PaxcounterConfigItemList.kt (82%) rename app/src/main/java/com/geeksville/mesh/ui/{radioconfig => settings/radio}/components/PositionConfigItemList.kt (99%) rename app/src/main/java/com/geeksville/mesh/ui/{radioconfig => settings/radio}/components/PowerConfigItemList.kt (98%) rename app/src/main/java/com/geeksville/mesh/ui/{radioconfig => settings/radio}/components/RangeTestConfigItemList.kt (86%) rename app/src/main/java/com/geeksville/mesh/ui/{radioconfig => settings/radio}/components/RemoteHardwareConfigItemList.kt (81%) rename app/src/main/java/com/geeksville/mesh/ui/{radioconfig => settings/radio}/components/SecurityConfigItemList.kt (73%) rename app/src/main/java/com/geeksville/mesh/ui/{radioconfig => settings/radio}/components/SerialConfigItemList.kt (84%) rename app/src/main/java/com/geeksville/mesh/ui/{radioconfig => settings/radio}/components/StoreForwardConfigItemList.kt (84%) rename app/src/main/java/com/geeksville/mesh/ui/{radioconfig => settings/radio}/components/TelemetryConfigItemList.kt (75%) rename app/src/main/java/com/geeksville/mesh/ui/{radioconfig => settings/radio}/components/UserConfigItemList.kt (78%) diff --git a/app/src/androidTest/java/com/geeksville/mesh/compose/EditDeviceProfileDialogTest.kt b/app/src/androidTest/java/com/geeksville/mesh/compose/EditDeviceProfileDialogTest.kt index 33a55bc0b..498762456 100644 --- a/app/src/androidTest/java/com/geeksville/mesh/compose/EditDeviceProfileDialogTest.kt +++ b/app/src/androidTest/java/com/geeksville/mesh/compose/EditDeviceProfileDialogTest.kt @@ -27,7 +27,7 @@ import com.geeksville.mesh.ClientOnlyProtos.DeviceProfile import com.geeksville.mesh.R import com.geeksville.mesh.deviceProfile import com.geeksville.mesh.position -import com.geeksville.mesh.ui.radioconfig.components.EditDeviceProfileDialog +import com.geeksville.mesh.ui.settings.radio.components.EditDeviceProfileDialog import org.junit.Assert import org.junit.Rule import org.junit.Test @@ -36,11 +36,9 @@ import org.junit.runner.RunWith @RunWith(AndroidJUnit4::class) class EditDeviceProfileDialogTest { - @get:Rule - val composeTestRule = createComposeRule() + @get:Rule val composeTestRule = createComposeRule() - private fun getString(id: Int): String = - InstrumentationRegistry.getInstrumentation().targetContext.getString(id) + private fun getString(id: Int): String = InstrumentationRegistry.getInstrumentation().targetContext.getString(id) private val title = "Export configuration" private val deviceProfile = deviceProfile { @@ -54,17 +52,15 @@ class EditDeviceProfileDialogTest { } } - private fun testEditDeviceProfileDialog( - onDismiss: () -> Unit = {}, - onConfirm: (DeviceProfile) -> Unit = {}, - ) = composeTestRule.setContent { - EditDeviceProfileDialog( - title = title, - deviceProfile = deviceProfile, - onConfirm = onConfirm, - onDismiss = onDismiss, - ) - } + private fun testEditDeviceProfileDialog(onDismiss: () -> Unit = {}, onConfirm: (DeviceProfile) -> Unit = {}) = + composeTestRule.setContent { + EditDeviceProfileDialog( + title = title, + deviceProfile = deviceProfile, + onConfirm = onConfirm, + onDismiss = onDismiss, + ) + } @Test fun testEditDeviceProfileDialog_showsDialogTitle() { @@ -113,4 +109,4 @@ class EditDeviceProfileDialogTest { // Verify onConfirm is called with the correct DeviceProfile Assert.assertEquals(deviceProfile, actualDeviceProfile) } -} \ No newline at end of file +} diff --git a/app/src/androidTest/java/com/geeksville/mesh/compose/MapReportingPreferenceTest.kt b/app/src/androidTest/java/com/geeksville/mesh/compose/MapReportingPreferenceTest.kt index 343dcaebb..e02222581 100644 --- a/app/src/androidTest/java/com/geeksville/mesh/compose/MapReportingPreferenceTest.kt +++ b/app/src/androidTest/java/com/geeksville/mesh/compose/MapReportingPreferenceTest.kt @@ -27,7 +27,7 @@ import androidx.compose.ui.test.performClick import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.platform.app.InstrumentationRegistry import com.geeksville.mesh.R -import com.geeksville.mesh.ui.radioconfig.components.MapReportingPreference +import com.geeksville.mesh.ui.settings.radio.components.MapReportingPreference import org.junit.Assert import org.junit.Rule import org.junit.Test @@ -36,30 +36,19 @@ import org.junit.runner.RunWith @RunWith(AndroidJUnit4::class) class MapReportingPreferenceTest { - @get:Rule - val composeTestRule = createComposeRule() + @get:Rule val composeTestRule = createComposeRule() - private fun getString(id: Int): String = - InstrumentationRegistry.getInstrumentation().targetContext.getString(id) + private fun getString(id: Int): String = InstrumentationRegistry.getInstrumentation().targetContext.getString(id) var mapReportingEnabled = false var shouldReportLocation = false var positionPrecision = 5 var positionReportingInterval = 60 - var mapReportingEnabledChanged = { enabled: Boolean -> - mapReportingEnabled = enabled - } - var shouldReportLocationChanged = { enabled: Boolean -> - shouldReportLocation = enabled - } - var positionPrecisionChanged = { precision: Int -> - positionPrecision = precision - } - var positionReportingIntervalChanged = { interval: Int -> - positionReportingInterval = interval - } - + var mapReportingEnabledChanged = { enabled: Boolean -> mapReportingEnabled = enabled } + var shouldReportLocationChanged = { enabled: Boolean -> shouldReportLocation = enabled } + var positionPrecisionChanged = { precision: Int -> positionPrecision = precision } + var positionReportingIntervalChanged = { interval: Int -> positionReportingInterval = interval } private fun testMapReportingPreference() = composeTestRule.setContent { Column { diff --git a/app/src/main/java/com/geeksville/mesh/navigation/ChannelsRoutes.kt b/app/src/main/java/com/geeksville/mesh/navigation/ChannelsRoutes.kt index da929f2ad..36febea23 100644 --- a/app/src/main/java/com/geeksville/mesh/navigation/ChannelsRoutes.kt +++ b/app/src/main/java/com/geeksville/mesh/navigation/ChannelsRoutes.kt @@ -25,8 +25,8 @@ import androidx.navigation.compose.composable import androidx.navigation.navDeepLink import androidx.navigation.navigation import com.geeksville.mesh.model.UIViewModel -import com.geeksville.mesh.ui.radioconfig.components.ChannelConfigScreen -import com.geeksville.mesh.ui.radioconfig.components.LoRaConfigScreen +import com.geeksville.mesh.ui.settings.radio.components.ChannelConfigScreen +import com.geeksville.mesh.ui.settings.radio.components.LoRaConfigScreen import com.geeksville.mesh.ui.sharing.ChannelScreen import kotlinx.serialization.Serializable diff --git a/app/src/main/java/com/geeksville/mesh/navigation/ConnectionsRoutes.kt b/app/src/main/java/com/geeksville/mesh/navigation/ConnectionsRoutes.kt index d9f929bde..c3794eed6 100644 --- a/app/src/main/java/com/geeksville/mesh/navigation/ConnectionsRoutes.kt +++ b/app/src/main/java/com/geeksville/mesh/navigation/ConnectionsRoutes.kt @@ -27,7 +27,7 @@ import androidx.navigation.navigation import com.geeksville.mesh.model.BluetoothViewModel import com.geeksville.mesh.model.UIViewModel import com.geeksville.mesh.ui.connections.ConnectionsScreen -import com.geeksville.mesh.ui.radioconfig.components.LoRaConfigScreen +import com.geeksville.mesh.ui.settings.radio.components.LoRaConfigScreen import kotlinx.serialization.Serializable @Serializable @@ -56,7 +56,7 @@ fun NavGraphBuilder.connectionsGraph( uiViewModel = uiViewModel, bluetoothViewModel = bluetoothViewModel, radioConfigViewModel = hiltViewModel(parentEntry), - onNavigateToRadioConfig = { navController.navigate(RadioConfigRoutes.RadioConfig()) }, + onNavigateToSettings = { navController.navigate(SettingsRoutes.Settings()) }, onNavigateToNodeDetails = { navController.navigate(NodesRoutes.NodeDetailGraph(it)) }, onConfigNavigate = { route -> navController.navigate(route) }, ) @@ -66,7 +66,7 @@ fun NavGraphBuilder.connectionsGraph( } private fun NavGraphBuilder.configRoutes(navController: NavHostController) { - composable { backStackEntry -> + composable { backStackEntry -> val parentEntry = remember(backStackEntry) { navController.getBackStackEntry(ConnectionsRoutes.ConnectionsGraph) } LoRaConfigScreen(hiltViewModel(parentEntry)) diff --git a/app/src/main/java/com/geeksville/mesh/navigation/NavGraph.kt b/app/src/main/java/com/geeksville/mesh/navigation/NavGraph.kt index 74b83a74f..8e47d49d6 100644 --- a/app/src/main/java/com/geeksville/mesh/navigation/NavGraph.kt +++ b/app/src/main/java/com/geeksville/mesh/navigation/NavGraph.kt @@ -59,7 +59,7 @@ fun NavDestination.isNodeDetailRoute(): Boolean = NodeDetailRoute.entries.any { fun NavDestination.showLongNameTitle(): Boolean = !this.isTopLevel() && ( - this.hasRoute() || + this.hasRoute() || this.hasRoute() || this.isConfigRoute() || this.isNodeDetailRoute() @@ -85,6 +85,6 @@ fun NavGraph( ) { DebugScreen() } - radioConfigGraph(navController, uIViewModel) + settingsGraph(navController, uIViewModel) } } diff --git a/app/src/main/java/com/geeksville/mesh/navigation/RadioConfigRoutes.kt b/app/src/main/java/com/geeksville/mesh/navigation/SettingsRoutes.kt similarity index 64% rename from app/src/main/java/com/geeksville/mesh/navigation/RadioConfigRoutes.kt rename to app/src/main/java/com/geeksville/mesh/navigation/SettingsRoutes.kt index fc0746d6d..91d61c3b4 100644 --- a/app/src/main/java/com/geeksville/mesh/navigation/RadioConfigRoutes.kt +++ b/app/src/main/java/com/geeksville/mesh/navigation/SettingsRoutes.kt @@ -56,38 +56,40 @@ import com.geeksville.mesh.AdminProtos import com.geeksville.mesh.MeshProtos.DeviceMetadata import com.geeksville.mesh.R import com.geeksville.mesh.model.UIViewModel -import com.geeksville.mesh.ui.radioconfig.CleanNodeDatabaseScreen -import com.geeksville.mesh.ui.radioconfig.RadioConfigScreen -import com.geeksville.mesh.ui.radioconfig.RadioConfigViewModel -import com.geeksville.mesh.ui.radioconfig.components.AmbientLightingConfigScreen -import com.geeksville.mesh.ui.radioconfig.components.AudioConfigScreen -import com.geeksville.mesh.ui.radioconfig.components.BluetoothConfigScreen -import com.geeksville.mesh.ui.radioconfig.components.CannedMessageConfigScreen -import com.geeksville.mesh.ui.radioconfig.components.ChannelConfigScreen -import com.geeksville.mesh.ui.radioconfig.components.DetectionSensorConfigScreen -import com.geeksville.mesh.ui.radioconfig.components.DeviceConfigScreen -import com.geeksville.mesh.ui.radioconfig.components.DisplayConfigScreen -import com.geeksville.mesh.ui.radioconfig.components.ExternalNotificationConfigScreen -import com.geeksville.mesh.ui.radioconfig.components.LoRaConfigScreen -import com.geeksville.mesh.ui.radioconfig.components.MQTTConfigScreen -import com.geeksville.mesh.ui.radioconfig.components.NeighborInfoConfigScreen -import com.geeksville.mesh.ui.radioconfig.components.NetworkConfigScreen -import com.geeksville.mesh.ui.radioconfig.components.PaxcounterConfigScreen -import com.geeksville.mesh.ui.radioconfig.components.PositionConfigScreen -import com.geeksville.mesh.ui.radioconfig.components.PowerConfigScreen -import com.geeksville.mesh.ui.radioconfig.components.RangeTestConfigScreen -import com.geeksville.mesh.ui.radioconfig.components.RemoteHardwareConfigScreen -import com.geeksville.mesh.ui.radioconfig.components.SecurityConfigScreen -import com.geeksville.mesh.ui.radioconfig.components.SerialConfigScreen -import com.geeksville.mesh.ui.radioconfig.components.StoreForwardConfigScreen -import com.geeksville.mesh.ui.radioconfig.components.TelemetryConfigScreen -import com.geeksville.mesh.ui.radioconfig.components.UserConfigScreen +import com.geeksville.mesh.ui.settings.radio.CleanNodeDatabaseScreen +import com.geeksville.mesh.ui.settings.radio.RadioConfigScreen +import com.geeksville.mesh.ui.settings.radio.RadioConfigViewModel +import com.geeksville.mesh.ui.settings.radio.components.AmbientLightingConfigScreen +import com.geeksville.mesh.ui.settings.radio.components.AudioConfigScreen +import com.geeksville.mesh.ui.settings.radio.components.BluetoothConfigScreen +import com.geeksville.mesh.ui.settings.radio.components.CannedMessageConfigScreen +import com.geeksville.mesh.ui.settings.radio.components.ChannelConfigScreen +import com.geeksville.mesh.ui.settings.radio.components.DetectionSensorConfigScreen +import com.geeksville.mesh.ui.settings.radio.components.DeviceConfigScreen +import com.geeksville.mesh.ui.settings.radio.components.DisplayConfigScreen +import com.geeksville.mesh.ui.settings.radio.components.ExternalNotificationConfigScreen +import com.geeksville.mesh.ui.settings.radio.components.LoRaConfigScreen +import com.geeksville.mesh.ui.settings.radio.components.MQTTConfigScreen +import com.geeksville.mesh.ui.settings.radio.components.NeighborInfoConfigScreen +import com.geeksville.mesh.ui.settings.radio.components.NetworkConfigScreen +import com.geeksville.mesh.ui.settings.radio.components.PaxcounterConfigScreen +import com.geeksville.mesh.ui.settings.radio.components.PositionConfigScreen +import com.geeksville.mesh.ui.settings.radio.components.PowerConfigScreen +import com.geeksville.mesh.ui.settings.radio.components.RangeTestConfigScreen +import com.geeksville.mesh.ui.settings.radio.components.RemoteHardwareConfigScreen +import com.geeksville.mesh.ui.settings.radio.components.SecurityConfigScreen +import com.geeksville.mesh.ui.settings.radio.components.SerialConfigScreen +import com.geeksville.mesh.ui.settings.radio.components.StoreForwardConfigScreen +import com.geeksville.mesh.ui.settings.radio.components.TelemetryConfigScreen +import com.geeksville.mesh.ui.settings.radio.components.UserConfigScreen import kotlinx.serialization.Serializable -sealed class RadioConfigRoutes { - @Serializable data class RadioConfigGraph(val destNum: Int? = null) : Graph +sealed class SettingsRoutes { + @Serializable data class SettingsGraph(val destNum: Int? = null) : Graph - @Serializable data class RadioConfig(val destNum: Int? = null) : Route + @Serializable data class Settings(val destNum: Int? = null) : Route + + // region radio Config Routes @Serializable data object User : Route @@ -109,6 +111,10 @@ sealed class RadioConfigRoutes { @Serializable data object Security : Route + // endregion + + // region module config routes + @Serializable data object MQTT : Route @Serializable data object Serial : Route @@ -135,30 +141,35 @@ sealed class RadioConfigRoutes { @Serializable data object Paxcounter : Route + // endregion + + // region advanced config routes + @Serializable data object CleanNodeDb : Route + + // endregion } fun getNavRouteFrom(routeName: String): Route? = ConfigRoute.entries.find { it.name == routeName }?.route ?: ModuleRoute.entries.find { it.name == routeName }?.route @Suppress("LongMethod") -fun NavGraphBuilder.radioConfigGraph(navController: NavHostController, uiViewModel: UIViewModel) { - navigation(startDestination = RadioConfigRoutes.RadioConfig()) { - composable( - deepLinks = - listOf(navDeepLink(basePath = "$DEEP_LINK_BASE_URI/radio_config")), +fun NavGraphBuilder.settingsGraph(navController: NavHostController, uiViewModel: UIViewModel) { + navigation(startDestination = SettingsRoutes.Settings()) { + composable( + deepLinks = listOf(navDeepLink(basePath = "$DEEP_LINK_BASE_URI/settings")), ) { backStackEntry -> val parentEntry = - remember(backStackEntry) { navController.getBackStackEntry(RadioConfigRoutes.RadioConfigGraph::class) } + remember(backStackEntry) { navController.getBackStackEntry(SettingsRoutes.SettingsGraph::class) } RadioConfigScreen(uiViewModel = uiViewModel, viewModel = hiltViewModel(parentEntry)) { - navController.navigate(it) { popUpTo(RadioConfigRoutes.RadioConfig()) { inclusive = false } } + navController.navigate(it) { popUpTo(SettingsRoutes.Settings()) { inclusive = false } } } } - composable( + composable( deepLinks = listOf( - navDeepLink( - basePath = "$DEEP_LINK_BASE_URI/radio_config/clean_node_db", + navDeepLink( + basePath = "$DEEP_LINK_BASE_URI/settings/radio/clean_node_db", ), ), ) { @@ -174,7 +185,7 @@ fun NavGraphBuilder.radioConfigGraph(navController: NavHostController, uiViewMod * * This function simplifies adding screens by handling common tasks like: * - Setting up deep links based on the route's name. - * - Retrieving the parent [NavBackStackEntry] for the [RadioConfigRoutes.RadioConfigGraph]. + * - Retrieving the parent [NavBackStackEntry] for the [SettingsRoutes.SettingsGraph]. * - Providing the [RadioConfigViewModel] scoped to the parent graph, which the [screenContent] will use. * * @param R The type of the [Route] object, must be serializable. @@ -191,12 +202,14 @@ private inline fun NavGraphBuilder.addRadioConfigScreenCompo composable( deepLinks = listOf( - navDeepLink(basePath = "$DEEP_LINK_BASE_URI/radio_config/{destNum}/${routeNameString.lowercase()}"), - navDeepLink(basePath = "$DEEP_LINK_BASE_URI/radio_config/${routeNameString.lowercase()}"), + navDeepLink( + basePath = "$DEEP_LINK_BASE_URI/settings/radio/{destNum}/${routeNameString.lowercase()}", + ), + navDeepLink(basePath = "$DEEP_LINK_BASE_URI/settings/radio/${routeNameString.lowercase()}"), ), ) { backStackEntry -> val parentEntry = - remember(backStackEntry) { navController.getBackStackEntry(RadioConfigRoutes.RadioConfigGraph::class) } + remember(backStackEntry) { navController.getBackStackEntry(SettingsRoutes.SettingsGraph::class) } val viewModel = hiltViewModel(parentEntry) screenContent(viewModel) } @@ -206,62 +219,46 @@ private inline fun NavGraphBuilder.addRadioConfigScreenCompo private fun NavGraphBuilder.configRoutesScreens(navController: NavHostController) { ConfigRoute.entries.forEach { entry -> when (entry.route) { - is RadioConfigRoutes.User -> - addRadioConfigScreenComposable( + is SettingsRoutes.User -> + addRadioConfigScreenComposable(navController, entry.name, entry.screenComposable) + is SettingsRoutes.ChannelConfig -> + addRadioConfigScreenComposable( navController, entry.name, entry.screenComposable, ) - is RadioConfigRoutes.ChannelConfig -> - addRadioConfigScreenComposable( + is SettingsRoutes.Device -> + addRadioConfigScreenComposable(navController, entry.name, entry.screenComposable) + is SettingsRoutes.Position -> + addRadioConfigScreenComposable( navController, entry.name, entry.screenComposable, ) - is RadioConfigRoutes.Device -> - addRadioConfigScreenComposable( + is SettingsRoutes.Power -> + addRadioConfigScreenComposable(navController, entry.name, entry.screenComposable) + is SettingsRoutes.Network -> + addRadioConfigScreenComposable( navController, entry.name, entry.screenComposable, ) - is RadioConfigRoutes.Position -> - addRadioConfigScreenComposable( + is SettingsRoutes.Display -> + addRadioConfigScreenComposable( navController, entry.name, entry.screenComposable, ) - is RadioConfigRoutes.Power -> - addRadioConfigScreenComposable( + is SettingsRoutes.LoRa -> + addRadioConfigScreenComposable(navController, entry.name, entry.screenComposable) + is SettingsRoutes.Bluetooth -> + addRadioConfigScreenComposable( navController, entry.name, entry.screenComposable, ) - is RadioConfigRoutes.Network -> - addRadioConfigScreenComposable( - navController, - entry.name, - entry.screenComposable, - ) - is RadioConfigRoutes.Display -> - addRadioConfigScreenComposable( - navController, - entry.name, - entry.screenComposable, - ) - is RadioConfigRoutes.LoRa -> - addRadioConfigScreenComposable( - navController, - entry.name, - entry.screenComposable, - ) - is RadioConfigRoutes.Bluetooth -> - addRadioConfigScreenComposable( - navController, - entry.name, - entry.screenComposable, - ) - is RadioConfigRoutes.Security -> - addRadioConfigScreenComposable( + is SettingsRoutes.Security -> + addRadioConfigScreenComposable( navController, entry.name, entry.screenComposable, @@ -275,80 +272,68 @@ private fun NavGraphBuilder.configRoutesScreens(navController: NavHostController private fun NavGraphBuilder.moduleRoutesScreens(navController: NavHostController) { ModuleRoute.entries.forEach { entry -> when (entry.route) { - is RadioConfigRoutes.MQTT -> - addRadioConfigScreenComposable( + is SettingsRoutes.MQTT -> + addRadioConfigScreenComposable(navController, entry.name, entry.screenComposable) + is SettingsRoutes.Serial -> + addRadioConfigScreenComposable(navController, entry.name, entry.screenComposable) + is SettingsRoutes.ExtNotification -> + addRadioConfigScreenComposable( navController, entry.name, entry.screenComposable, ) - is RadioConfigRoutes.Serial -> - addRadioConfigScreenComposable( + is SettingsRoutes.StoreForward -> + addRadioConfigScreenComposable( navController, entry.name, entry.screenComposable, ) - is RadioConfigRoutes.ExtNotification -> - addRadioConfigScreenComposable( + is SettingsRoutes.RangeTest -> + addRadioConfigScreenComposable( navController, entry.name, entry.screenComposable, ) - is RadioConfigRoutes.StoreForward -> - addRadioConfigScreenComposable( + is SettingsRoutes.Telemetry -> + addRadioConfigScreenComposable( navController, entry.name, entry.screenComposable, ) - is RadioConfigRoutes.RangeTest -> - addRadioConfigScreenComposable( + is SettingsRoutes.CannedMessage -> + addRadioConfigScreenComposable( navController, entry.name, entry.screenComposable, ) - is RadioConfigRoutes.Telemetry -> - addRadioConfigScreenComposable( + is SettingsRoutes.Audio -> + addRadioConfigScreenComposable(navController, entry.name, entry.screenComposable) + is SettingsRoutes.RemoteHardware -> + addRadioConfigScreenComposable( navController, entry.name, entry.screenComposable, ) - is RadioConfigRoutes.CannedMessage -> - addRadioConfigScreenComposable( + is SettingsRoutes.NeighborInfo -> + addRadioConfigScreenComposable( navController, entry.name, entry.screenComposable, ) - is RadioConfigRoutes.Audio -> - addRadioConfigScreenComposable( + is SettingsRoutes.AmbientLighting -> + addRadioConfigScreenComposable( navController, entry.name, entry.screenComposable, ) - is RadioConfigRoutes.RemoteHardware -> - addRadioConfigScreenComposable( + is SettingsRoutes.DetectionSensor -> + addRadioConfigScreenComposable( navController, entry.name, entry.screenComposable, ) - is RadioConfigRoutes.NeighborInfo -> - addRadioConfigScreenComposable( - navController, - entry.name, - entry.screenComposable, - ) - is RadioConfigRoutes.AmbientLighting -> - addRadioConfigScreenComposable( - navController, - entry.name, - entry.screenComposable, - ) - is RadioConfigRoutes.DetectionSensor -> - addRadioConfigScreenComposable( - navController, - entry.name, - entry.screenComposable, - ) - is RadioConfigRoutes.Paxcounter -> - addRadioConfigScreenComposable( + is SettingsRoutes.Paxcounter -> + addRadioConfigScreenComposable( navController, entry.name, entry.screenComposable, @@ -366,66 +351,66 @@ enum class ConfigRoute( val type: Int = 0, val screenComposable: @Composable (viewModel: RadioConfigViewModel) -> Unit, ) { - USER(R.string.user, RadioConfigRoutes.User, Icons.Default.Person, 0, { vm -> UserConfigScreen(vm) }), + USER(R.string.user, SettingsRoutes.User, Icons.Default.Person, 0, { vm -> UserConfigScreen(vm) }), CHANNELS( R.string.channels, - RadioConfigRoutes.ChannelConfig, + SettingsRoutes.ChannelConfig, Icons.AutoMirrored.Default.List, 0, { vm -> ChannelConfigScreen(vm) }, ), DEVICE( R.string.device, - RadioConfigRoutes.Device, + SettingsRoutes.Device, Icons.Default.Router, AdminProtos.AdminMessage.ConfigType.DEVICE_CONFIG_VALUE, { vm -> DeviceConfigScreen(vm) }, ), POSITION( R.string.position, - RadioConfigRoutes.Position, + SettingsRoutes.Position, Icons.Default.LocationOn, AdminProtos.AdminMessage.ConfigType.POSITION_CONFIG_VALUE, { vm -> PositionConfigScreen(vm) }, ), POWER( R.string.power, - RadioConfigRoutes.Power, + SettingsRoutes.Power, Icons.Default.Power, AdminProtos.AdminMessage.ConfigType.POWER_CONFIG_VALUE, { vm -> PowerConfigScreen(vm) }, ), NETWORK( R.string.network, - RadioConfigRoutes.Network, + SettingsRoutes.Network, Icons.Default.Wifi, AdminProtos.AdminMessage.ConfigType.NETWORK_CONFIG_VALUE, { vm -> NetworkConfigScreen(vm) }, ), DISPLAY( R.string.display, - RadioConfigRoutes.Display, + SettingsRoutes.Display, Icons.Default.DisplaySettings, AdminProtos.AdminMessage.ConfigType.DISPLAY_CONFIG_VALUE, { vm -> DisplayConfigScreen(vm) }, ), LORA( R.string.lora, - RadioConfigRoutes.LoRa, + SettingsRoutes.LoRa, Icons.Default.CellTower, AdminProtos.AdminMessage.ConfigType.LORA_CONFIG_VALUE, { vm -> LoRaConfigScreen(vm) }, ), BLUETOOTH( R.string.bluetooth, - RadioConfigRoutes.Bluetooth, + SettingsRoutes.Bluetooth, Icons.Default.Bluetooth, AdminProtos.AdminMessage.ConfigType.BLUETOOTH_CONFIG_VALUE, { vm -> BluetoothConfigScreen(vm) }, ), SECURITY( R.string.security, - RadioConfigRoutes.Security, + SettingsRoutes.Security, Icons.Default.Security, AdminProtos.AdminMessage.ConfigType.SECURITY_CONFIG_VALUE, { vm -> SecurityConfigScreen(vm) }, @@ -454,91 +439,91 @@ enum class ModuleRoute( ) { MQTT( R.string.mqtt, - RadioConfigRoutes.MQTT, + SettingsRoutes.MQTT, Icons.Default.Cloud, AdminProtos.AdminMessage.ModuleConfigType.MQTT_CONFIG_VALUE, { vm -> MQTTConfigScreen(vm) }, ), SERIAL( R.string.serial, - RadioConfigRoutes.Serial, + SettingsRoutes.Serial, Icons.Default.Usb, AdminProtos.AdminMessage.ModuleConfigType.SERIAL_CONFIG_VALUE, { vm -> SerialConfigScreen(vm) }, ), EXT_NOTIFICATION( R.string.external_notification, - RadioConfigRoutes.ExtNotification, + SettingsRoutes.ExtNotification, Icons.Default.Notifications, AdminProtos.AdminMessage.ModuleConfigType.EXTNOTIF_CONFIG_VALUE, { vm -> ExternalNotificationConfigScreen(vm) }, ), STORE_FORWARD( R.string.store_forward, - RadioConfigRoutes.StoreForward, + SettingsRoutes.StoreForward, Icons.AutoMirrored.Default.Forward, AdminProtos.AdminMessage.ModuleConfigType.STOREFORWARD_CONFIG_VALUE, { vm -> StoreForwardConfigScreen(vm) }, ), RANGE_TEST( R.string.range_test, - RadioConfigRoutes.RangeTest, + SettingsRoutes.RangeTest, Icons.Default.Speed, AdminProtos.AdminMessage.ModuleConfigType.RANGETEST_CONFIG_VALUE, { vm -> RangeTestConfigScreen(vm) }, ), TELEMETRY( R.string.telemetry, - RadioConfigRoutes.Telemetry, + SettingsRoutes.Telemetry, Icons.Default.DataUsage, AdminProtos.AdminMessage.ModuleConfigType.TELEMETRY_CONFIG_VALUE, { vm -> TelemetryConfigScreen(vm) }, ), CANNED_MESSAGE( R.string.canned_message, - RadioConfigRoutes.CannedMessage, + SettingsRoutes.CannedMessage, Icons.AutoMirrored.Default.Message, AdminProtos.AdminMessage.ModuleConfigType.CANNEDMSG_CONFIG_VALUE, { vm -> CannedMessageConfigScreen(vm) }, ), AUDIO( R.string.audio, - RadioConfigRoutes.Audio, + SettingsRoutes.Audio, Icons.AutoMirrored.Default.VolumeUp, AdminProtos.AdminMessage.ModuleConfigType.AUDIO_CONFIG_VALUE, { vm -> AudioConfigScreen(vm) }, ), REMOTE_HARDWARE( R.string.remote_hardware, - RadioConfigRoutes.RemoteHardware, + SettingsRoutes.RemoteHardware, Icons.Default.SettingsRemote, AdminProtos.AdminMessage.ModuleConfigType.REMOTEHARDWARE_CONFIG_VALUE, { vm -> RemoteHardwareConfigScreen(vm) }, ), NEIGHBOR_INFO( R.string.neighbor_info, - RadioConfigRoutes.NeighborInfo, + SettingsRoutes.NeighborInfo, Icons.Default.People, AdminProtos.AdminMessage.ModuleConfigType.NEIGHBORINFO_CONFIG_VALUE, { vm -> NeighborInfoConfigScreen(vm) }, ), AMBIENT_LIGHTING( R.string.ambient_lighting, - RadioConfigRoutes.AmbientLighting, + SettingsRoutes.AmbientLighting, Icons.Default.LightMode, AdminProtos.AdminMessage.ModuleConfigType.AMBIENTLIGHTING_CONFIG_VALUE, { vm -> AmbientLightingConfigScreen(vm) }, ), DETECTION_SENSOR( R.string.detection_sensor, - RadioConfigRoutes.DetectionSensor, + SettingsRoutes.DetectionSensor, Icons.Default.Sensors, AdminProtos.AdminMessage.ModuleConfigType.DETECTIONSENSOR_CONFIG_VALUE, { vm -> DetectionSensorConfigScreen(vm) }, ), PAXCOUNTER( R.string.paxcounter, - RadioConfigRoutes.Paxcounter, + SettingsRoutes.Paxcounter, Icons.Default.PermScanWifi, AdminProtos.AdminMessage.ModuleConfigType.PAXCOUNTER_CONFIG_VALUE, { vm -> PaxcounterConfigScreen(vm) }, diff --git a/app/src/main/java/com/geeksville/mesh/ui/Main.kt b/app/src/main/java/com/geeksville/mesh/ui/Main.kt index ad4920dec..f46e00900 100644 --- a/app/src/main/java/com/geeksville/mesh/ui/Main.kt +++ b/app/src/main/java/com/geeksville/mesh/ui/Main.kt @@ -34,7 +34,6 @@ import androidx.compose.foundation.layout.safeDrawingPadding import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.verticalScroll import androidx.compose.material.icons.Icons -import androidx.compose.material.icons.rounded.QrCode2 import androidx.compose.material.icons.rounded.Wifi import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.MaterialTheme.colorScheme @@ -90,8 +89,8 @@ import com.geeksville.mesh.navigation.ContactsRoutes import com.geeksville.mesh.navigation.MapRoutes import com.geeksville.mesh.navigation.NavGraph import com.geeksville.mesh.navigation.NodesRoutes -import com.geeksville.mesh.navigation.RadioConfigRoutes import com.geeksville.mesh.navigation.Route +import com.geeksville.mesh.navigation.SettingsRoutes import com.geeksville.mesh.repository.radio.MeshActivity import com.geeksville.mesh.service.ConnectionState import com.geeksville.mesh.service.MeshService @@ -104,6 +103,7 @@ import com.geeksville.mesh.ui.common.icons.Conversations import com.geeksville.mesh.ui.common.icons.Map import com.geeksville.mesh.ui.common.icons.MeshtasticIcons import com.geeksville.mesh.ui.common.icons.Nodes +import com.geeksville.mesh.ui.common.icons.Settings import com.geeksville.mesh.ui.common.theme.StatusColors.StatusBlue import com.geeksville.mesh.ui.common.theme.StatusColors.StatusGreen import com.geeksville.mesh.ui.connections.DeviceType @@ -120,7 +120,7 @@ enum class TopLevelDestination(@StringRes val label: Int, val icon: ImageVector, Conversations(R.string.conversations, MeshtasticIcons.Conversations, ContactsRoutes.ContactsGraph), Nodes(R.string.nodes, MeshtasticIcons.Nodes, NodesRoutes.NodesGraph), Map(R.string.map, MeshtasticIcons.Map, MapRoutes.Map), - Share(R.string.bottom_nav_share, Icons.Rounded.QrCode2, ChannelsRoutes.ChannelsGraph), + Settings(R.string.bottom_nav_settings, MeshtasticIcons.Settings, SettingsRoutes.SettingsGraph()), Connections(R.string.connections, Icons.Rounded.Wifi, ConnectionsRoutes.ConnectionsGraph), ; @@ -150,7 +150,6 @@ fun MainScreen( ) { val navController = rememberNavController() val connectionState by uIViewModel.connectionState.collectAsStateWithLifecycle() - val localConfig by uIViewModel.localConfig.collectAsStateWithLifecycle() val requestChannelSet by uIViewModel.requestChannelSet.collectAsStateWithLifecycle() if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { @@ -205,7 +204,7 @@ fun MainScreen( text = { Text(text = message) }, onConfirm = { if (compromisedKeys) { - navController.navigate(RadioConfigRoutes.Security) + navController.navigate(SettingsRoutes.Security) } uIViewModel.clearClientNotification(notification) }, @@ -348,13 +347,11 @@ fun MainScreen( } MainAppBar( viewModel = uIViewModel, - isManaged = localConfig.security.isManaged, navController = navController, onAction = { action -> if (action is MainMenuAction) { when (action) { MainMenuAction.DEBUG -> navController.navigate(Route.DebugPanel) - MainMenuAction.RADIO_CONFIG -> navController.navigate(RadioConfigRoutes.RadioConfig()) MainMenuAction.QUICK_CHAT -> navController.navigate(ContactsRoutes.QuickChat) MainMenuAction.SHOW_INTRO -> uIViewModel.onMainMenuAction(action) else -> onAction(action) diff --git a/app/src/main/java/com/geeksville/mesh/ui/common/components/MainAppBar.kt b/app/src/main/java/com/geeksville/mesh/ui/common/components/MainAppBar.kt index 7574da82a..e41879e9a 100644 --- a/app/src/main/java/com/geeksville/mesh/ui/common/components/MainAppBar.kt +++ b/app/src/main/java/com/geeksville/mesh/ui/common/components/MainAppBar.kt @@ -55,14 +55,14 @@ import com.geeksville.mesh.model.Node import com.geeksville.mesh.model.UIViewModel import com.geeksville.mesh.navigation.ContactsRoutes import com.geeksville.mesh.navigation.NodesRoutes -import com.geeksville.mesh.navigation.RadioConfigRoutes import com.geeksville.mesh.navigation.Route +import com.geeksville.mesh.navigation.SettingsRoutes import com.geeksville.mesh.navigation.showLongNameTitle import com.geeksville.mesh.ui.TopLevelDestination.Companion.isTopLevel import com.geeksville.mesh.ui.common.theme.AppTheme import com.geeksville.mesh.ui.debug.DebugMenuActions import com.geeksville.mesh.ui.node.components.NodeChip -import com.geeksville.mesh.ui.radioconfig.RadioConfigMenuActions +import com.geeksville.mesh.ui.settings.radio.RadioConfigMenuActions @Suppress("CyclomaticComplexMethod") @Composable @@ -70,7 +70,6 @@ fun MainAppBar( modifier: Modifier = Modifier, viewModel: UIViewModel = hiltViewModel(), navController: NavHostController, - isManaged: Boolean, onAction: (Any?) -> Unit, ) { val backStackEntry by navController.currentBackStackEntryAsState() @@ -119,11 +118,11 @@ fun MainAppBar( actions = { currentDestination?.let { when { - it.isTopLevel() -> MainMenuActions(isManaged, onAction) + it.isTopLevel() -> MainMenuActions(onAction) currentDestination.hasRoute() -> DebugMenuActions() - currentDestination.hasRoute() -> + currentDestination.hasRoute() -> RadioConfigMenuActions(viewModel = viewModel) else -> {} @@ -208,7 +207,6 @@ private fun TopBarActions( enum class MainMenuAction(@StringRes val stringRes: Int) { DEBUG(R.string.debug_panel), - RADIO_CONFIG(R.string.radio_configuration), EXPORT_RANGETEST(R.string.save_rangetest), THEME(R.string.theme), LANGUAGE(R.string.preferences_language), @@ -217,7 +215,7 @@ enum class MainMenuAction(@StringRes val stringRes: Int) { } @Composable -private fun MainMenuActions(isManaged: Boolean, onAction: (MainMenuAction) -> Unit) { +private fun MainMenuActions(onAction: (MainMenuAction) -> Unit) { var showMenu by remember { mutableStateOf(false) } IconButton(onClick = { showMenu = true }) { Icon(imageVector = Icons.Default.MoreVert, contentDescription = stringResource(R.string.overflow_menu)) @@ -235,11 +233,7 @@ private fun MainMenuActions(isManaged: Boolean, onAction: (MainMenuAction) -> Un onAction(action) showMenu = false }, - enabled = - when (action) { - MainMenuAction.RADIO_CONFIG -> !isManaged - else -> true - }, + enabled = true, ) } } @@ -257,7 +251,7 @@ private fun MainAppBarPreview(@PreviewParameter(BooleanProvider::class) canNavig showNodeChip = true, canNavigateUp = canNavigateUp, onNavigateUp = {}, - actions = { MainMenuActions(isManaged = false, onAction = {}) }, + actions = { MainMenuActions(onAction = {}) }, ) {} } } diff --git a/app/src/main/java/com/geeksville/mesh/ui/common/components/ScannedQrCodeDialog.kt b/app/src/main/java/com/geeksville/mesh/ui/common/components/ScannedQrCodeDialog.kt index 769c4c228..679dcdc58 100644 --- a/app/src/main/java/com/geeksville/mesh/ui/common/components/ScannedQrCodeDialog.kt +++ b/app/src/main/java/com/geeksville/mesh/ui/common/components/ScannedQrCodeDialog.kt @@ -57,7 +57,7 @@ import com.geeksville.mesh.channelSet import com.geeksville.mesh.copy import com.geeksville.mesh.model.Channel import com.geeksville.mesh.model.UIViewModel -import com.geeksville.mesh.ui.radioconfig.components.ChannelSelection +import com.geeksville.mesh.ui.settings.radio.components.ChannelSelection @Composable fun ScannedQrCodeDialog(viewModel: UIViewModel, incoming: ChannelSet) { diff --git a/app/src/main/java/com/geeksville/mesh/ui/connections/components/TitledCard.kt b/app/src/main/java/com/geeksville/mesh/ui/common/components/TitledCard.kt similarity index 86% rename from app/src/main/java/com/geeksville/mesh/ui/connections/components/TitledCard.kt rename to app/src/main/java/com/geeksville/mesh/ui/common/components/TitledCard.kt index 3eabdb888..a84724df0 100644 --- a/app/src/main/java/com/geeksville/mesh/ui/connections/components/TitledCard.kt +++ b/app/src/main/java/com/geeksville/mesh/ui/common/components/TitledCard.kt @@ -15,7 +15,7 @@ * along with this program. If not, see . */ -package com.geeksville.mesh.ui.connections.components +package com.geeksville.mesh.ui.common.components import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box @@ -35,8 +35,8 @@ import androidx.compose.ui.unit.dp import com.geeksville.mesh.ui.common.theme.AppTheme @Composable -fun TitledCard(title: String, content: @Composable ColumnScope.() -> Unit) { - Column(verticalArrangement = Arrangement.spacedBy(8.dp)) { +fun TitledCard(title: String, modifier: Modifier = Modifier, content: @Composable ColumnScope.() -> Unit) { + Column(modifier = modifier, verticalArrangement = Arrangement.spacedBy(8.dp)) { Text( title, modifier = Modifier.padding(horizontal = 16.dp).fillMaxWidth(), @@ -49,6 +49,6 @@ fun TitledCard(title: String, content: @Composable ColumnScope.() -> Unit) { @PreviewLightDark @Composable -fun TitledCardPreview() { +private fun TitledCardPreview() { AppTheme { Surface { TitledCard(title = "Title") { Box(modifier = Modifier.fillMaxWidth().height(100.dp)) {} } } } } diff --git a/app/src/main/java/com/geeksville/mesh/ui/common/icons/Settings.kt b/app/src/main/java/com/geeksville/mesh/ui/common/icons/Settings.kt new file mode 100644 index 000000000..0defebd43 --- /dev/null +++ b/app/src/main/java/com/geeksville/mesh/ui/common/icons/Settings.kt @@ -0,0 +1,160 @@ +/* + * Copyright (c) 2025 Meshtastic LLC + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.geeksville.mesh.ui.common.icons + +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.graphics.SolidColor +import androidx.compose.ui.graphics.vector.ImageVector +import androidx.compose.ui.graphics.vector.path +import androidx.compose.ui.unit.dp + +/** + * This is from Material Symbols. + * + * @see + * [settings](https://fonts.google.com/icons?selected=Material+Symbols+Rounded:settings:FILL@0;wght@400;GRAD@0;opsz@24&icon.style=Rounded&icon.query=settings&icon.set=Material+Symbols&icon.size=24&icon.color=%23e3e3e3&icon.platform=android) + */ +val MeshtasticIcons.Settings: ImageVector + get() { + if (settings != null) { + return settings!! + } + settings = + ImageVector.Builder( + name = "Settings", + defaultWidth = 24.dp, + defaultHeight = 24.dp, + viewportWidth = 960f, + viewportHeight = 960f, + ) + .apply { + path(fill = SolidColor(Color(0xFFE3E3E3))) { + moveTo(433f, 880f) + quadToRelative(-27f, 0f, -46.5f, -18f) + reflectiveQuadTo(363f, 818f) + lineToRelative(-9f, -66f) + quadToRelative(-13f, -5f, -24.5f, -12f) + reflectiveQuadTo(307f, 725f) + lineToRelative(-62f, 26f) + quadToRelative(-25f, 11f, -50f, 2f) + reflectiveQuadToRelative(-39f, -32f) + lineToRelative(-47f, -82f) + quadToRelative(-14f, -23f, -8f, -49f) + reflectiveQuadToRelative(27f, -43f) + lineToRelative(53f, -40f) + quadToRelative(-1f, -7f, -1f, -13.5f) + verticalLineToRelative(-27f) + quadToRelative(0f, -6.5f, 1f, -13.5f) + lineToRelative(-53f, -40f) + quadToRelative(-21f, -17f, -27f, -43f) + reflectiveQuadToRelative(8f, -49f) + lineToRelative(47f, -82f) + quadToRelative(14f, -23f, 39f, -32f) + reflectiveQuadToRelative(50f, 2f) + lineToRelative(62f, 26f) + quadToRelative(11f, -8f, 23f, -15f) + reflectiveQuadToRelative(24f, -12f) + lineToRelative(9f, -66f) + quadToRelative(4f, -26f, 23.5f, -44f) + reflectiveQuadToRelative(46.5f, -18f) + horizontalLineToRelative(94f) + quadToRelative(27f, 0f, 46.5f, 18f) + reflectiveQuadToRelative(23.5f, 44f) + lineToRelative(9f, 66f) + quadToRelative(13f, 5f, 24.5f, 12f) + reflectiveQuadToRelative(22.5f, 15f) + lineToRelative(62f, -26f) + quadToRelative(25f, -11f, 50f, -2f) + reflectiveQuadToRelative(39f, 32f) + lineToRelative(47f, 82f) + quadToRelative(14f, 23f, 8f, 49f) + reflectiveQuadToRelative(-27f, 43f) + lineToRelative(-53f, 40f) + quadToRelative(1f, 7f, 1f, 13.5f) + verticalLineToRelative(27f) + quadToRelative(0f, 6.5f, -2f, 13.5f) + lineToRelative(53f, 40f) + quadToRelative(21f, 17f, 27f, 43f) + reflectiveQuadToRelative(-8f, 49f) + lineToRelative(-48f, 82f) + quadToRelative(-14f, 23f, -39f, 32f) + reflectiveQuadToRelative(-50f, -2f) + lineToRelative(-60f, -26f) + quadToRelative(-11f, 8f, -23f, 15f) + reflectiveQuadToRelative(-24f, 12f) + lineToRelative(-9f, 66f) + quadToRelative(-4f, 26f, -23.5f, 44f) + reflectiveQuadTo(527f, 880f) + horizontalLineToRelative(-94f) + close() + moveTo(440f, 800f) + horizontalLineToRelative(79f) + lineToRelative(14f, -106f) + quadToRelative(31f, -8f, 57.5f, -23.5f) + reflectiveQuadTo(639f, 633f) + lineToRelative(99f, 41f) + lineToRelative(39f, -68f) + lineToRelative(-86f, -65f) + quadToRelative(5f, -14f, 7f, -29.5f) + reflectiveQuadToRelative(2f, -31.5f) + quadToRelative(0f, -16f, -2f, -31.5f) + reflectiveQuadToRelative(-7f, -29.5f) + lineToRelative(86f, -65f) + lineToRelative(-39f, -68f) + lineToRelative(-99f, 42f) + quadToRelative(-22f, -23f, -48.5f, -38.5f) + reflectiveQuadTo(533f, 266f) + lineToRelative(-13f, -106f) + horizontalLineToRelative(-79f) + lineToRelative(-14f, 106f) + quadToRelative(-31f, 8f, -57.5f, 23.5f) + reflectiveQuadTo(321f, 327f) + lineToRelative(-99f, -41f) + lineToRelative(-39f, 68f) + lineToRelative(86f, 64f) + quadToRelative(-5f, 15f, -7f, 30f) + reflectiveQuadToRelative(-2f, 32f) + quadToRelative(0f, 16f, 2f, 31f) + reflectiveQuadToRelative(7f, 30f) + lineToRelative(-86f, 65f) + lineToRelative(39f, 68f) + lineToRelative(99f, -42f) + quadToRelative(22f, 23f, 48.5f, 38.5f) + reflectiveQuadTo(427f, 694f) + lineToRelative(13f, 106f) + close() + moveTo(482f, 620f) + quadToRelative(58f, 0f, 99f, -41f) + reflectiveQuadToRelative(41f, -99f) + quadToRelative(0f, -58f, -41f, -99f) + reflectiveQuadToRelative(-99f, -41f) + quadToRelative(-59f, 0f, -99.5f, 41f) + reflectiveQuadTo(342f, 480f) + quadToRelative(0f, 58f, 40.5f, 99f) + reflectiveQuadToRelative(99.5f, 41f) + close() + moveTo(480f, 480f) + close() + } + } + .build() + + return settings!! + } + +private var settings: ImageVector? = null diff --git a/app/src/main/java/com/geeksville/mesh/ui/connections/Connections.kt b/app/src/main/java/com/geeksville/mesh/ui/connections/Connections.kt index 5b8775457..aa69cfbd2 100644 --- a/app/src/main/java/com/geeksville/mesh/ui/connections/Connections.kt +++ b/app/src/main/java/com/geeksville/mesh/ui/connections/Connections.kt @@ -94,8 +94,8 @@ import com.geeksville.mesh.model.NO_DEVICE_SELECTED import com.geeksville.mesh.model.Node import com.geeksville.mesh.model.UIViewModel import com.geeksville.mesh.navigation.ConfigRoute -import com.geeksville.mesh.navigation.RadioConfigRoutes import com.geeksville.mesh.navigation.Route +import com.geeksville.mesh.navigation.SettingsRoutes import com.geeksville.mesh.navigation.getNavRouteFrom import com.geeksville.mesh.service.ConnectionState import com.geeksville.mesh.ui.common.components.SwitchPreference @@ -103,8 +103,8 @@ import com.geeksville.mesh.ui.connections.components.BLEDevices import com.geeksville.mesh.ui.connections.components.CurrentlyConnectedCard import com.geeksville.mesh.ui.connections.components.NetworkDevices import com.geeksville.mesh.ui.connections.components.UsbDevices -import com.geeksville.mesh.ui.radioconfig.RadioConfigViewModel -import com.geeksville.mesh.ui.radioconfig.components.PacketResponseStateDialog +import com.geeksville.mesh.ui.settings.radio.RadioConfigViewModel +import com.geeksville.mesh.ui.settings.radio.components.PacketResponseStateDialog import com.geeksville.mesh.ui.sharing.SharedContactDialog import com.google.accompanist.permissions.ExperimentalPermissionsApi import com.google.accompanist.permissions.rememberMultiplePermissionsState @@ -129,7 +129,7 @@ fun ConnectionsScreen( scanModel: BTScanModel = hiltViewModel(), bluetoothViewModel: BluetoothViewModel = hiltViewModel(), radioConfigViewModel: RadioConfigViewModel = hiltViewModel(), - onNavigateToRadioConfig: () -> Unit, + onNavigateToSettings: () -> Unit, onNavigateToNodeDetails: (Int) -> Unit, onConfigNavigate: (Route) -> Unit, ) { @@ -167,8 +167,8 @@ fun ConnectionsScreen( getNavRouteFrom(radioConfigState.route)?.let { route -> isWaiting = false radioConfigViewModel.clearPacketResponse() - if (route == RadioConfigRoutes.LoRa) { - onConfigNavigate(RadioConfigRoutes.LoRa) + if (route == SettingsRoutes.LoRa) { + onConfigNavigate(SettingsRoutes.LoRa) } } }, @@ -260,7 +260,7 @@ fun ConnectionsScreen( node = node, onNavigateToNodeDetails = onNavigateToNodeDetails, onSetShowSharedContact = { showSharedContact = it }, - onNavigateToRadioConfig = onNavigateToRadioConfig, + onNavigateToSettings = onNavigateToSettings, onClickDisconnect = { scanModel.disconnect() }, ) } diff --git a/app/src/main/java/com/geeksville/mesh/ui/connections/components/BLEDevices.kt b/app/src/main/java/com/geeksville/mesh/ui/connections/components/BLEDevices.kt index 79fdd5412..a478f788c 100644 --- a/app/src/main/java/com/geeksville/mesh/ui/connections/components/BLEDevices.kt +++ b/app/src/main/java/com/geeksville/mesh/ui/connections/components/BLEDevices.kt @@ -50,6 +50,7 @@ import com.geeksville.mesh.R import com.geeksville.mesh.model.BTScanModel import com.geeksville.mesh.model.DeviceListEntry import com.geeksville.mesh.service.ConnectionState +import com.geeksville.mesh.ui.common.components.TitledCard import com.google.accompanist.permissions.ExperimentalPermissionsApi import com.google.accompanist.permissions.MultiplePermissionsState import com.google.accompanist.permissions.rememberMultiplePermissionsState diff --git a/app/src/main/java/com/geeksville/mesh/ui/connections/components/CurrentlyConnectedCard.kt b/app/src/main/java/com/geeksville/mesh/ui/connections/components/CurrentlyConnectedCard.kt index a86f946b9..0bd09b447 100644 --- a/app/src/main/java/com/geeksville/mesh/ui/connections/components/CurrentlyConnectedCard.kt +++ b/app/src/main/java/com/geeksville/mesh/ui/connections/components/CurrentlyConnectedCard.kt @@ -58,7 +58,7 @@ fun CurrentlyConnectedCard( modifier: Modifier = Modifier, onNavigateToNodeDetails: (Int) -> Unit, onSetShowSharedContact: (Node) -> Unit, - onNavigateToRadioConfig: () -> Unit, + onNavigateToSettings: () -> Unit, onClickDisconnect: () -> Unit, ) { Card(modifier = modifier) { @@ -98,7 +98,7 @@ fun CurrentlyConnectedCard( } } - IconButton(enabled = true, onClick = onNavigateToRadioConfig) { + IconButton(enabled = true, onClick = onNavigateToSettings) { Icon( imageVector = Icons.Default.Settings, contentDescription = stringResource(id = R.string.radio_configuration), @@ -142,7 +142,7 @@ private fun CurrentlyConnectedCardPreview() { ), onNavigateToNodeDetails = {}, onSetShowSharedContact = {}, - onNavigateToRadioConfig = {}, + onNavigateToSettings = {}, onClickDisconnect = {}, ) } diff --git a/app/src/main/java/com/geeksville/mesh/ui/connections/components/NetworkDevices.kt b/app/src/main/java/com/geeksville/mesh/ui/connections/components/NetworkDevices.kt index 0e09b4222..3aa47802a 100644 --- a/app/src/main/java/com/geeksville/mesh/ui/connections/components/NetworkDevices.kt +++ b/app/src/main/java/com/geeksville/mesh/ui/connections/components/NetworkDevices.kt @@ -56,6 +56,7 @@ import com.geeksville.mesh.model.BTScanModel import com.geeksville.mesh.model.DeviceListEntry import com.geeksville.mesh.repository.network.NetworkRepository import com.geeksville.mesh.service.ConnectionState +import com.geeksville.mesh.ui.common.components.TitledCard import com.geeksville.mesh.ui.common.theme.AppTheme import com.geeksville.mesh.ui.connections.isIPAddress import kotlinx.coroutines.launch diff --git a/app/src/main/java/com/geeksville/mesh/ui/connections/components/UsbDevices.kt b/app/src/main/java/com/geeksville/mesh/ui/connections/components/UsbDevices.kt index 6265afb0b..2dfdddd53 100644 --- a/app/src/main/java/com/geeksville/mesh/ui/connections/components/UsbDevices.kt +++ b/app/src/main/java/com/geeksville/mesh/ui/connections/components/UsbDevices.kt @@ -27,6 +27,7 @@ import com.geeksville.mesh.R import com.geeksville.mesh.model.BTScanModel import com.geeksville.mesh.model.DeviceListEntry import com.geeksville.mesh.service.ConnectionState +import com.geeksville.mesh.ui.common.components.TitledCard import com.geeksville.mesh.ui.common.theme.AppTheme @Composable diff --git a/app/src/main/java/com/geeksville/mesh/ui/node/NodeDetail.kt b/app/src/main/java/com/geeksville/mesh/ui/node/NodeDetail.kt index f3c1e2697..8792ea742 100644 --- a/app/src/main/java/com/geeksville/mesh/ui/node/NodeDetail.kt +++ b/app/src/main/java/com/geeksville/mesh/ui/node/NodeDetail.kt @@ -141,8 +141,8 @@ import com.geeksville.mesh.model.Node import com.geeksville.mesh.model.UIViewModel import com.geeksville.mesh.model.isUnmessageableRole import com.geeksville.mesh.navigation.NodeDetailRoutes -import com.geeksville.mesh.navigation.RadioConfigRoutes import com.geeksville.mesh.navigation.Route +import com.geeksville.mesh.navigation.SettingsRoutes import com.geeksville.mesh.service.ServiceAction import com.geeksville.mesh.ui.common.components.PreferenceCategory import com.geeksville.mesh.ui.common.preview.NodePreviewParameterProvider @@ -153,7 +153,7 @@ import com.geeksville.mesh.ui.common.theme.StatusColors.StatusRed import com.geeksville.mesh.ui.common.theme.StatusColors.StatusYellow import com.geeksville.mesh.ui.node.components.NodeActionDialogs import com.geeksville.mesh.ui.node.components.NodeMenuAction -import com.geeksville.mesh.ui.radioconfig.NavCard +import com.geeksville.mesh.ui.settings.radio.NavCard import com.geeksville.mesh.ui.sharing.SharedContactDialog import com.geeksville.mesh.util.UnitConversions import com.geeksville.mesh.util.UnitConversions.toTempString @@ -440,7 +440,7 @@ private fun AdministrationSection( icon = Icons.Default.Settings, enabled = metricsState.isLocal || node.metadata != null, ) { - onAction(NodeDetailAction.Navigate(RadioConfigRoutes.RadioConfig(node.num))) + onAction(NodeDetailAction.Navigate(SettingsRoutes.Settings(node.num))) } } diff --git a/app/src/main/java/com/geeksville/mesh/ui/settings/components/SettingsItem.kt b/app/src/main/java/com/geeksville/mesh/ui/settings/components/SettingsItem.kt new file mode 100644 index 000000000..f13e1c47c --- /dev/null +++ b/app/src/main/java/com/geeksville/mesh/ui/settings/components/SettingsItem.kt @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2025 Meshtastic LLC + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.geeksville.mesh.ui.settings.components + +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.layout.width +import androidx.compose.foundation.layout.wrapContentSize +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.automirrored.rounded.KeyboardArrowRight +import androidx.compose.material.icons.rounded.Android +import androidx.compose.material3.Card +import androidx.compose.material3.CardDefaults +import androidx.compose.material3.Icon +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.graphics.vector.ImageVector +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import com.geeksville.mesh.ui.common.theme.AppTheme + +@Composable +fun SettingsItem( + text: String, + enabled: Boolean, + leadingIcon: ImageVector? = null, + trailingIcon: ImageVector? = Icons.AutoMirrored.Rounded.KeyboardArrowRight, + onClick: () -> Unit, +) { + Card( + onClick = onClick, + enabled = enabled, + colors = CardDefaults.cardColors( + containerColor = Color.Transparent, + disabledContainerColor = Color.Transparent, + ), + ) { + Row( + verticalAlignment = Alignment.CenterVertically, + modifier = Modifier.fillMaxWidth().padding(vertical = 12.dp, horizontal = 16.dp), + ) { + leadingIcon?.let { + Icon(imageVector = it, contentDescription = text, modifier = Modifier.size(24.dp)) + Spacer(modifier = Modifier.width(16.dp)) + } + Text(text = text, style = MaterialTheme.typography.bodyLarge, modifier = Modifier.weight(1f)) + + trailingIcon?.let { + Icon(imageVector = it, contentDescription = null, modifier = Modifier.wrapContentSize()) + } + } + } +} + +@Preview(showBackground = true) +@Composable +private fun SettingsItemPreview() { + AppTheme { SettingsItem(text = "Text", leadingIcon = Icons.Rounded.Android, enabled = true) {} } +} + +@Preview(showBackground = true) +@Composable +private fun SettingsItemDisabledPreview() { + AppTheme { SettingsItem(text = "Text", leadingIcon = Icons.Rounded.Android, enabled = false) {} } +} diff --git a/app/src/main/java/com/geeksville/mesh/ui/radioconfig/CleanNodeDatabaseScreen.kt b/app/src/main/java/com/geeksville/mesh/ui/settings/radio/CleanNodeDatabaseScreen.kt similarity index 99% rename from app/src/main/java/com/geeksville/mesh/ui/radioconfig/CleanNodeDatabaseScreen.kt rename to app/src/main/java/com/geeksville/mesh/ui/settings/radio/CleanNodeDatabaseScreen.kt index 3abb27f68..1e5e699cc 100644 --- a/app/src/main/java/com/geeksville/mesh/ui/radioconfig/CleanNodeDatabaseScreen.kt +++ b/app/src/main/java/com/geeksville/mesh/ui/settings/radio/CleanNodeDatabaseScreen.kt @@ -15,7 +15,7 @@ * along with this program. If not, see . */ -package com.geeksville.mesh.ui.radioconfig +package com.geeksville.mesh.ui.settings.radio import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column diff --git a/app/src/main/java/com/geeksville/mesh/ui/radioconfig/CleanNodeDatabaseViewModel.kt b/app/src/main/java/com/geeksville/mesh/ui/settings/radio/CleanNodeDatabaseViewModel.kt similarity index 99% rename from app/src/main/java/com/geeksville/mesh/ui/radioconfig/CleanNodeDatabaseViewModel.kt rename to app/src/main/java/com/geeksville/mesh/ui/settings/radio/CleanNodeDatabaseViewModel.kt index 14c1da6a6..f2aa1c2e0 100644 --- a/app/src/main/java/com/geeksville/mesh/ui/radioconfig/CleanNodeDatabaseViewModel.kt +++ b/app/src/main/java/com/geeksville/mesh/ui/settings/radio/CleanNodeDatabaseViewModel.kt @@ -15,7 +15,7 @@ * along with this program. If not, see . */ -package com.geeksville.mesh.ui.radioconfig +package com.geeksville.mesh.ui.settings.radio import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope diff --git a/app/src/main/java/com/geeksville/mesh/ui/radioconfig/RadioConfig.kt b/app/src/main/java/com/geeksville/mesh/ui/settings/radio/RadioConfig.kt similarity index 78% rename from app/src/main/java/com/geeksville/mesh/ui/radioconfig/RadioConfig.kt rename to app/src/main/java/com/geeksville/mesh/ui/settings/radio/RadioConfig.kt index a4e652cd1..2e95605b2 100644 --- a/app/src/main/java/com/geeksville/mesh/ui/radioconfig/RadioConfig.kt +++ b/app/src/main/java/com/geeksville/mesh/ui/settings/radio/RadioConfig.kt @@ -15,7 +15,7 @@ * along with this program. If not, see . */ -package com.geeksville.mesh.ui.radioconfig +package com.geeksville.mesh.ui.settings.radio import android.app.Activity import android.content.Intent @@ -72,13 +72,15 @@ import com.geeksville.mesh.model.UIViewModel import com.geeksville.mesh.navigation.AdminRoute import com.geeksville.mesh.navigation.ConfigRoute import com.geeksville.mesh.navigation.ModuleRoute -import com.geeksville.mesh.navigation.RadioConfigRoutes import com.geeksville.mesh.navigation.Route +import com.geeksville.mesh.navigation.SettingsRoutes import com.geeksville.mesh.navigation.getNavRouteFrom -import com.geeksville.mesh.ui.common.components.PreferenceCategory +import com.geeksville.mesh.ui.common.components.TitledCard import com.geeksville.mesh.ui.common.theme.AppTheme -import com.geeksville.mesh.ui.radioconfig.components.EditDeviceProfileDialog -import com.geeksville.mesh.ui.radioconfig.components.PacketResponseStateDialog +import com.geeksville.mesh.ui.common.theme.StatusColors.StatusRed +import com.geeksville.mesh.ui.settings.components.SettingsItem +import com.geeksville.mesh.ui.settings.radio.components.EditDeviceProfileDialog +import com.geeksville.mesh.ui.settings.radio.components.PacketResponseStateDialog import kotlinx.coroutines.delay import kotlin.time.Duration.Companion.seconds @@ -105,6 +107,7 @@ fun RadioConfigScreen( nodeName?.let { uiViewModel.setTitle(it) } val excludedModulesUnlocked by uiViewModel.excludedModulesUnlocked.collectAsStateWithLifecycle() + val localConfig by uiViewModel.localConfig.collectAsStateWithLifecycle() val state by viewModel.radioConfigState.collectAsStateWithLifecycle() var isWaiting by remember { mutableStateOf(false) } @@ -177,6 +180,7 @@ fun RadioConfigScreen( RadioConfigItemList( modifier = modifier, state = state, + isManaged = localConfig.security.isManaged, excludedModulesUnlocked = excludedModulesUnlocked, onRouteClick = { route -> isWaiting = true @@ -272,9 +276,11 @@ private fun NavButton(@StringRes title: Int, enabled: Boolean, onClick: () -> Un } } +@Suppress("LongMethod") @Composable private fun RadioConfigItemList( state: RadioConfigState, + isManaged: Boolean, excludedModulesUnlocked: Boolean = false, modifier: Modifier = Modifier, onRouteClick: (Enum<*>) -> Unit = {}, @@ -282,7 +288,7 @@ private fun RadioConfigItemList( onExport: () -> Unit = {}, onNavigate: (Route) -> Unit, ) { - val enabled = state.connected && !state.responseState.isWaiting() + val enabled = state.connected && !state.responseState.isWaiting() && !isManaged var modules by remember { mutableStateOf(ModuleRoute.filterExcludedFrom(state.metadata)) } LaunchedEffect(excludedModulesUnlocked) { if (excludedModulesUnlocked) { @@ -291,44 +297,72 @@ private fun RadioConfigItemList( modules = ModuleRoute.filterExcludedFrom(state.metadata) } } - LazyColumn(modifier = modifier, contentPadding = PaddingValues(horizontal = 16.dp)) { - item { PreferenceCategory(stringResource(R.string.radio_configuration)) } - items(ConfigRoute.filterExcludedFrom(state.metadata)) { - NavCard(title = stringResource(it.title), icon = it.icon, enabled = enabled) { onRouteClick(it) } + LazyColumn(modifier = modifier, contentPadding = PaddingValues(16.dp)) { + item { + TitledCard(title = stringResource(R.string.radio_configuration)) { + if (isManaged) { + ManagedMessage() + } + + ConfigRoute.filterExcludedFrom(state.metadata).forEach { + SettingsItem(text = stringResource(it.title), leadingIcon = it.icon, enabled = enabled) { + onRouteClick(it) + } + } + } } - item { PreferenceCategory(stringResource(R.string.module_settings)) } - items(modules) { - NavCard(title = stringResource(it.title), icon = it.icon, enabled = enabled) { onRouteClick(it) } + item { + TitledCard(title = stringResource(R.string.module_settings), modifier = Modifier.padding(top = 16.dp)) { + if (isManaged) { + ManagedMessage() + } + + modules.forEach { + SettingsItem(text = stringResource(it.title), leadingIcon = it.icon, enabled = enabled) { + onRouteClick(it) + } + } + } } if (state.isLocal) { item { - PreferenceCategory(stringResource(R.string.backup_restore)) - NavCard( - title = stringResource(R.string.import_configuration), - icon = Icons.Default.Download, - enabled = enabled, - onClick = onImport, - ) - NavCard( - title = stringResource(R.string.export_configuration), - icon = Icons.Default.Upload, - enabled = enabled, - onClick = onExport, - ) + TitledCard(title = stringResource(R.string.backup_restore), modifier = Modifier.padding(top = 16.dp)) { + if (isManaged) { + ManagedMessage() + } + + SettingsItem( + text = stringResource(R.string.import_configuration), + leadingIcon = Icons.Default.Download, + enabled = enabled, + onClick = onImport, + ) + SettingsItem( + text = stringResource(R.string.export_configuration), + leadingIcon = Icons.Default.Upload, + enabled = enabled, + onClick = onExport, + ) + } } } items(AdminRoute.entries) { NavButton(it.title, enabled) { onRouteClick(it) } } item { - PreferenceCategory("Advanced") - NavCard( - title = stringResource(R.string.clean_node_database_title), - enabled = enabled, - onClick = { onNavigate(RadioConfigRoutes.CleanNodeDb) }, - ) + TitledCard(title = "Advanced", modifier = Modifier.padding(top = 16.dp)) { + if (isManaged) { + ManagedMessage() + } + + SettingsItem( + text = stringResource(R.string.clean_node_database_title), + enabled = enabled, + onClick = { onNavigate(SettingsRoutes.CleanNodeDb) }, + ) + } } } } @@ -362,5 +396,28 @@ fun RadioConfigMenuActions(modifier: Modifier = Modifier, viewModel: UIViewModel @Preview(showBackground = true) @Composable private fun RadioSettingsScreenPreview() = AppTheme { - RadioConfigItemList(state = RadioConfigState(isLocal = true, connected = true), onNavigate = { _ -> }) + RadioConfigItemList( + state = RadioConfigState(isLocal = true, connected = true), + isManaged = false, + onNavigate = { _ -> }, + ) +} + +@Composable +private fun ManagedMessage() { + Text( + text = stringResource(R.string.message_device_managed), + modifier = Modifier.padding(horizontal = 16.dp, vertical = 8.dp), + color = MaterialTheme.colorScheme.StatusRed, + ) +} + +@Preview(showBackground = true) +@Composable +private fun RadioSettingsScreenManagedPreview() = AppTheme { + RadioConfigItemList( + state = RadioConfigState(isLocal = true, connected = true), + isManaged = true, + onNavigate = { _ -> }, + ) } diff --git a/app/src/main/java/com/geeksville/mesh/ui/radioconfig/RadioConfigViewModel.kt b/app/src/main/java/com/geeksville/mesh/ui/settings/radio/RadioConfigViewModel.kt similarity index 99% rename from app/src/main/java/com/geeksville/mesh/ui/radioconfig/RadioConfigViewModel.kt rename to app/src/main/java/com/geeksville/mesh/ui/settings/radio/RadioConfigViewModel.kt index 9625afdc5..158da8568 100644 --- a/app/src/main/java/com/geeksville/mesh/ui/radioconfig/RadioConfigViewModel.kt +++ b/app/src/main/java/com/geeksville/mesh/ui/settings/radio/RadioConfigViewModel.kt @@ -15,7 +15,7 @@ * along with this program. If not, see . */ -package com.geeksville.mesh.ui.radioconfig +package com.geeksville.mesh.ui.settings.radio import android.Manifest import android.app.Application @@ -56,7 +56,7 @@ import com.geeksville.mesh.moduleConfig import com.geeksville.mesh.navigation.AdminRoute import com.geeksville.mesh.navigation.ConfigRoute import com.geeksville.mesh.navigation.ModuleRoute -import com.geeksville.mesh.navigation.RadioConfigRoutes +import com.geeksville.mesh.navigation.SettingsRoutes import com.geeksville.mesh.repository.datastore.RadioConfigRepository import com.geeksville.mesh.repository.location.LocationRepository import com.geeksville.mesh.service.ConnectionState @@ -108,7 +108,7 @@ constructor( private val meshService: IMeshService? get() = radioConfigRepository.meshService - private val destNum = savedStateHandle.toRoute().destNum + private val destNum = savedStateHandle.toRoute().destNum private val _destNode = MutableStateFlow(null) val destNode: StateFlow get() = _destNode diff --git a/app/src/main/java/com/geeksville/mesh/ui/radioconfig/ResponseState.kt b/app/src/main/java/com/geeksville/mesh/ui/settings/radio/ResponseState.kt similarity index 90% rename from app/src/main/java/com/geeksville/mesh/ui/radioconfig/ResponseState.kt rename to app/src/main/java/com/geeksville/mesh/ui/settings/radio/ResponseState.kt index 0640f4807..d9e59dce1 100644 --- a/app/src/main/java/com/geeksville/mesh/ui/radioconfig/ResponseState.kt +++ b/app/src/main/java/com/geeksville/mesh/ui/settings/radio/ResponseState.kt @@ -15,17 +15,18 @@ * along with this program. If not, see . */ -package com.geeksville.mesh.ui.radioconfig +package com.geeksville.mesh.ui.settings.radio import com.geeksville.mesh.util.UiText -/** - * Generic sealed class defines each possible state of a response. - */ +/** Generic sealed class defines each possible state of a response. */ sealed class ResponseState { data object Empty : ResponseState() + data class Loading(var total: Int = 1, var completed: Int = 0) : ResponseState() + data class Success(val result: T) : ResponseState() + data class Error(val error: UiText) : ResponseState() fun isWaiting() = this !is Empty diff --git a/app/src/main/java/com/geeksville/mesh/ui/radioconfig/components/AmbientLightingConfigItemList.kt b/app/src/main/java/com/geeksville/mesh/ui/settings/radio/components/AmbientLightingConfigItemList.kt similarity index 85% rename from app/src/main/java/com/geeksville/mesh/ui/radioconfig/components/AmbientLightingConfigItemList.kt rename to app/src/main/java/com/geeksville/mesh/ui/settings/radio/components/AmbientLightingConfigItemList.kt index c6e91537c..2eda1d9c1 100644 --- a/app/src/main/java/com/geeksville/mesh/ui/radioconfig/components/AmbientLightingConfigItemList.kt +++ b/app/src/main/java/com/geeksville/mesh/ui/settings/radio/components/AmbientLightingConfigItemList.kt @@ -15,7 +15,7 @@ * along with this program. If not, see . */ -package com.geeksville.mesh.ui.radioconfig.components +package com.geeksville.mesh.ui.settings.radio.components import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.lazy.LazyColumn @@ -40,19 +40,14 @@ import com.geeksville.mesh.ui.common.components.EditTextPreference import com.geeksville.mesh.ui.common.components.PreferenceCategory import com.geeksville.mesh.ui.common.components.PreferenceFooter import com.geeksville.mesh.ui.common.components.SwitchPreference -import com.geeksville.mesh.ui.radioconfig.RadioConfigViewModel +import com.geeksville.mesh.ui.settings.radio.RadioConfigViewModel @Composable -fun AmbientLightingConfigScreen( - viewModel: RadioConfigViewModel = hiltViewModel(), -) { +fun AmbientLightingConfigScreen(viewModel: RadioConfigViewModel = hiltViewModel()) { val state by viewModel.radioConfigState.collectAsStateWithLifecycle() if (state.responseState.isWaiting()) { - PacketResponseStateDialog( - state = state.responseState, - onDismiss = viewModel::clearPacketResponse, - ) + PacketResponseStateDialog(state = state.responseState, onDismiss = viewModel::clearPacketResponse) } AmbientLightingConfigItemList( @@ -61,7 +56,7 @@ fun AmbientLightingConfigScreen( onSaveClicked = { ambientLightingInput -> val config = moduleConfig { ambientLighting = ambientLightingInput } viewModel.setModuleConfig(config) - } + }, ) } @@ -74,9 +69,7 @@ fun AmbientLightingConfigItemList( val focusManager = LocalFocusManager.current var ambientLightingInput by rememberSaveable { mutableStateOf(ambientLightingConfig) } - LazyColumn( - modifier = Modifier.fillMaxSize() - ) { + LazyColumn(modifier = Modifier.fillMaxSize()) { item { PreferenceCategory(text = stringResource(R.string.ambient_lighting_config)) } item { @@ -84,9 +77,7 @@ fun AmbientLightingConfigItemList( title = stringResource(R.string.led_state), checked = ambientLightingInput.ledState, enabled = enabled, - onCheckedChange = { - ambientLightingInput = ambientLightingInput.copy { ledState = it } - } + onCheckedChange = { ambientLightingInput = ambientLightingInput.copy { ledState = it } }, ) } item { HorizontalDivider() } @@ -97,9 +88,7 @@ fun AmbientLightingConfigItemList( value = ambientLightingInput.current, enabled = enabled, keyboardActions = KeyboardActions(onDone = { focusManager.clearFocus() }), - onValueChanged = { - ambientLightingInput = ambientLightingInput.copy { current = it } - } + onValueChanged = { ambientLightingInput = ambientLightingInput.copy { current = it } }, ) } @@ -109,7 +98,7 @@ fun AmbientLightingConfigItemList( value = ambientLightingInput.red, enabled = enabled, keyboardActions = KeyboardActions(onDone = { focusManager.clearFocus() }), - onValueChanged = { ambientLightingInput = ambientLightingInput.copy { red = it } } + onValueChanged = { ambientLightingInput = ambientLightingInput.copy { red = it } }, ) } @@ -119,7 +108,7 @@ fun AmbientLightingConfigItemList( value = ambientLightingInput.green, enabled = enabled, keyboardActions = KeyboardActions(onDone = { focusManager.clearFocus() }), - onValueChanged = { ambientLightingInput = ambientLightingInput.copy { green = it } } + onValueChanged = { ambientLightingInput = ambientLightingInput.copy { green = it } }, ) } @@ -129,7 +118,7 @@ fun AmbientLightingConfigItemList( value = ambientLightingInput.blue, enabled = enabled, keyboardActions = KeyboardActions(onDone = { focusManager.clearFocus() }), - onValueChanged = { ambientLightingInput = ambientLightingInput.copy { blue = it } } + onValueChanged = { ambientLightingInput = ambientLightingInput.copy { blue = it } }, ) } @@ -143,7 +132,7 @@ fun AmbientLightingConfigItemList( onSaveClicked = { focusManager.clearFocus() onSaveClicked(ambientLightingInput) - } + }, ) } } @@ -155,6 +144,6 @@ private fun AmbientLightingConfigPreview() { AmbientLightingConfigItemList( ambientLightingConfig = ModuleConfigProtos.ModuleConfig.AmbientLightingConfig.getDefaultInstance(), enabled = true, - onSaveClicked = { }, + onSaveClicked = {}, ) } diff --git a/app/src/main/java/com/geeksville/mesh/ui/radioconfig/components/AudioConfigItemList.kt b/app/src/main/java/com/geeksville/mesh/ui/settings/radio/components/AudioConfigItemList.kt similarity index 86% rename from app/src/main/java/com/geeksville/mesh/ui/radioconfig/components/AudioConfigItemList.kt rename to app/src/main/java/com/geeksville/mesh/ui/settings/radio/components/AudioConfigItemList.kt index 37313a441..ba51c3cec 100644 --- a/app/src/main/java/com/geeksville/mesh/ui/radioconfig/components/AudioConfigItemList.kt +++ b/app/src/main/java/com/geeksville/mesh/ui/settings/radio/components/AudioConfigItemList.kt @@ -15,7 +15,7 @@ * along with this program. If not, see . */ -package com.geeksville.mesh.ui.radioconfig.components +package com.geeksville.mesh.ui.settings.radio.components import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.lazy.LazyColumn @@ -42,19 +42,14 @@ import com.geeksville.mesh.ui.common.components.EditTextPreference import com.geeksville.mesh.ui.common.components.PreferenceCategory import com.geeksville.mesh.ui.common.components.PreferenceFooter import com.geeksville.mesh.ui.common.components.SwitchPreference -import com.geeksville.mesh.ui.radioconfig.RadioConfigViewModel +import com.geeksville.mesh.ui.settings.radio.RadioConfigViewModel @Composable -fun AudioConfigScreen( - viewModel: RadioConfigViewModel = hiltViewModel(), -) { +fun AudioConfigScreen(viewModel: RadioConfigViewModel = hiltViewModel()) { val state by viewModel.radioConfigState.collectAsStateWithLifecycle() if (state.responseState.isWaiting()) { - PacketResponseStateDialog( - state = state.responseState, - onDismiss = viewModel::clearPacketResponse, - ) + PacketResponseStateDialog(state = state.responseState, onDismiss = viewModel::clearPacketResponse) } AudioConfigItemList( @@ -63,22 +58,17 @@ fun AudioConfigScreen( onSaveClicked = { audioInput -> val config = moduleConfig { audio = audioInput } viewModel.setModuleConfig(config) - } + }, ) } +@Suppress("LongMethod") @Composable -fun AudioConfigItemList( - audioConfig: AudioConfig, - enabled: Boolean, - onSaveClicked: (AudioConfig) -> Unit, -) { +fun AudioConfigItemList(audioConfig: AudioConfig, enabled: Boolean, onSaveClicked: (AudioConfig) -> Unit) { val focusManager = LocalFocusManager.current var audioInput by rememberSaveable { mutableStateOf(audioConfig) } - LazyColumn( - modifier = Modifier.fillMaxSize() - ) { + LazyColumn(modifier = Modifier.fillMaxSize()) { item { PreferenceCategory(text = stringResource(R.string.audio_config)) } item { @@ -86,7 +76,7 @@ fun AudioConfigItemList( title = stringResource(R.string.codec_2_enabled), checked = audioInput.codec2Enabled, enabled = enabled, - onCheckedChange = { audioInput = audioInput.copy { codec2Enabled = it } } + onCheckedChange = { audioInput = audioInput.copy { codec2Enabled = it } }, ) } item { HorizontalDivider() } @@ -97,7 +87,7 @@ fun AudioConfigItemList( value = audioInput.pttPin, enabled = enabled, keyboardActions = KeyboardActions(onDone = { focusManager.clearFocus() }), - onValueChanged = { audioInput = audioInput.copy { pttPin = it } } + onValueChanged = { audioInput = audioInput.copy { pttPin = it } }, ) } @@ -105,11 +95,12 @@ fun AudioConfigItemList( DropDownPreference( title = stringResource(R.string.codec2_sample_rate), enabled = enabled, - items = AudioConfig.Audio_Baud.entries + items = + AudioConfig.Audio_Baud.entries .filter { it != AudioConfig.Audio_Baud.UNRECOGNIZED } .map { it to it.name }, selectedItem = audioInput.bitrate, - onItemSelected = { audioInput = audioInput.copy { bitrate = it } } + onItemSelected = { audioInput = audioInput.copy { bitrate = it } }, ) } item { Divider() } @@ -120,7 +111,7 @@ fun AudioConfigItemList( value = audioInput.i2SWs, enabled = enabled, keyboardActions = KeyboardActions(onDone = { focusManager.clearFocus() }), - onValueChanged = { audioInput = audioInput.copy { i2SWs = it } } + onValueChanged = { audioInput = audioInput.copy { i2SWs = it } }, ) } @@ -130,7 +121,7 @@ fun AudioConfigItemList( value = audioInput.i2SSd, enabled = enabled, keyboardActions = KeyboardActions(onDone = { focusManager.clearFocus() }), - onValueChanged = { audioInput = audioInput.copy { i2SSd = it } } + onValueChanged = { audioInput = audioInput.copy { i2SSd = it } }, ) } @@ -140,7 +131,7 @@ fun AudioConfigItemList( value = audioInput.i2SDin, enabled = enabled, keyboardActions = KeyboardActions(onDone = { focusManager.clearFocus() }), - onValueChanged = { audioInput = audioInput.copy { i2SDin = it } } + onValueChanged = { audioInput = audioInput.copy { i2SDin = it } }, ) } @@ -150,7 +141,7 @@ fun AudioConfigItemList( value = audioInput.i2SSck, enabled = enabled, keyboardActions = KeyboardActions(onDone = { focusManager.clearFocus() }), - onValueChanged = { audioInput = audioInput.copy { i2SSck = it } } + onValueChanged = { audioInput = audioInput.copy { i2SSck = it } }, ) } @@ -164,7 +155,7 @@ fun AudioConfigItemList( onSaveClicked = { focusManager.clearFocus() onSaveClicked(audioInput) - } + }, ) } } @@ -173,9 +164,5 @@ fun AudioConfigItemList( @Preview(showBackground = true) @Composable private fun AudioConfigPreview() { - AudioConfigItemList( - audioConfig = AudioConfig.getDefaultInstance(), - enabled = true, - onSaveClicked = { }, - ) + AudioConfigItemList(audioConfig = AudioConfig.getDefaultInstance(), enabled = true, onSaveClicked = {}) } diff --git a/app/src/main/java/com/geeksville/mesh/ui/radioconfig/components/BluetoothConfigItemList.kt b/app/src/main/java/com/geeksville/mesh/ui/settings/radio/components/BluetoothConfigItemList.kt similarity index 86% rename from app/src/main/java/com/geeksville/mesh/ui/radioconfig/components/BluetoothConfigItemList.kt rename to app/src/main/java/com/geeksville/mesh/ui/settings/radio/components/BluetoothConfigItemList.kt index c394ec702..0e70f1ab6 100644 --- a/app/src/main/java/com/geeksville/mesh/ui/radioconfig/components/BluetoothConfigItemList.kt +++ b/app/src/main/java/com/geeksville/mesh/ui/settings/radio/components/BluetoothConfigItemList.kt @@ -15,7 +15,7 @@ * along with this program. If not, see . */ -package com.geeksville.mesh.ui.radioconfig.components +package com.geeksville.mesh.ui.settings.radio.components import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.lazy.LazyColumn @@ -41,19 +41,14 @@ import com.geeksville.mesh.ui.common.components.EditTextPreference import com.geeksville.mesh.ui.common.components.PreferenceCategory import com.geeksville.mesh.ui.common.components.PreferenceFooter import com.geeksville.mesh.ui.common.components.SwitchPreference -import com.geeksville.mesh.ui.radioconfig.RadioConfigViewModel +import com.geeksville.mesh.ui.settings.radio.RadioConfigViewModel @Composable -fun BluetoothConfigScreen( - viewModel: RadioConfigViewModel = hiltViewModel(), -) { +fun BluetoothConfigScreen(viewModel: RadioConfigViewModel = hiltViewModel()) { val state by viewModel.radioConfigState.collectAsStateWithLifecycle() if (state.responseState.isWaiting()) { - PacketResponseStateDialog( - state = state.responseState, - onDismiss = viewModel::clearPacketResponse, - ) + PacketResponseStateDialog(state = state.responseState, onDismiss = viewModel::clearPacketResponse) } BluetoothConfigItemList( @@ -62,7 +57,7 @@ fun BluetoothConfigScreen( onSaveClicked = { bluetoothInput -> val config = config { bluetooth = bluetoothInput } viewModel.setConfig(config) - } + }, ) } @@ -75,9 +70,7 @@ fun BluetoothConfigItemList( val focusManager = LocalFocusManager.current var bluetoothInput by rememberSaveable { mutableStateOf(bluetoothConfig) } - LazyColumn( - modifier = Modifier.fillMaxSize() - ) { + LazyColumn(modifier = Modifier.fillMaxSize()) { item { PreferenceCategory(text = stringResource(R.string.bluetooth_config)) } item { @@ -85,7 +78,7 @@ fun BluetoothConfigItemList( title = stringResource(R.string.bluetooth_enabled), checked = bluetoothInput.enabled, enabled = enabled, - onCheckedChange = { bluetoothInput = bluetoothInput.copy { this.enabled = it } } + onCheckedChange = { bluetoothInput = bluetoothInput.copy { this.enabled = it } }, ) } item { HorizontalDivider() } @@ -94,11 +87,12 @@ fun BluetoothConfigItemList( DropDownPreference( title = stringResource(R.string.pairing_mode), enabled = enabled, - items = BluetoothConfig.PairingMode.entries + items = + BluetoothConfig.PairingMode.entries .filter { it != BluetoothConfig.PairingMode.UNRECOGNIZED } .map { it to it.name }, selectedItem = bluetoothInput.mode, - onItemSelected = { bluetoothInput = bluetoothInput.copy { mode = it } } + onItemSelected = { bluetoothInput = bluetoothInput.copy { mode = it } }, ) } item { HorizontalDivider() } @@ -113,7 +107,7 @@ fun BluetoothConfigItemList( if (it.toString().length == 6) { // ensure 6 digits bluetoothInput = bluetoothInput.copy { fixedPin = it } } - } + }, ) } @@ -127,7 +121,7 @@ fun BluetoothConfigItemList( onSaveClicked = { focusManager.clearFocus() onSaveClicked(bluetoothInput) - } + }, ) } } @@ -136,9 +130,5 @@ fun BluetoothConfigItemList( @Preview(showBackground = true) @Composable private fun BluetoothConfigPreview() { - BluetoothConfigItemList( - bluetoothConfig = BluetoothConfig.getDefaultInstance(), - enabled = true, - onSaveClicked = { }, - ) + BluetoothConfigItemList(bluetoothConfig = BluetoothConfig.getDefaultInstance(), enabled = true, onSaveClicked = {}) } diff --git a/app/src/main/java/com/geeksville/mesh/ui/radioconfig/components/CannedMessageConfigItemList.kt b/app/src/main/java/com/geeksville/mesh/ui/settings/radio/components/CannedMessageConfigItemList.kt similarity index 76% rename from app/src/main/java/com/geeksville/mesh/ui/radioconfig/components/CannedMessageConfigItemList.kt rename to app/src/main/java/com/geeksville/mesh/ui/settings/radio/components/CannedMessageConfigItemList.kt index 169abc934..4e73aa06f 100644 --- a/app/src/main/java/com/geeksville/mesh/ui/radioconfig/components/CannedMessageConfigItemList.kt +++ b/app/src/main/java/com/geeksville/mesh/ui/settings/radio/components/CannedMessageConfigItemList.kt @@ -15,7 +15,7 @@ * along with this program. If not, see . */ -package com.geeksville.mesh.ui.radioconfig.components +package com.geeksville.mesh.ui.settings.radio.components import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.lazy.LazyColumn @@ -44,19 +44,14 @@ import com.geeksville.mesh.ui.common.components.EditTextPreference import com.geeksville.mesh.ui.common.components.PreferenceCategory import com.geeksville.mesh.ui.common.components.PreferenceFooter import com.geeksville.mesh.ui.common.components.SwitchPreference -import com.geeksville.mesh.ui.radioconfig.RadioConfigViewModel +import com.geeksville.mesh.ui.settings.radio.RadioConfigViewModel @Composable -fun CannedMessageConfigScreen( - viewModel: RadioConfigViewModel = hiltViewModel(), -) { +fun CannedMessageConfigScreen(viewModel: RadioConfigViewModel = hiltViewModel()) { val state by viewModel.radioConfigState.collectAsStateWithLifecycle() if (state.responseState.isWaiting()) { - PacketResponseStateDialog( - state = state.responseState, - onDismiss = viewModel::clearPacketResponse, - ) + PacketResponseStateDialog(state = state.responseState, onDismiss = viewModel::clearPacketResponse) } CannedMessageConfigItemList( @@ -71,7 +66,7 @@ fun CannedMessageConfigScreen( val config = moduleConfig { cannedMessage = cannedMessageInput } viewModel.setModuleConfig(config) } - } + }, ) } @@ -86,9 +81,7 @@ fun CannedMessageConfigItemList( var messagesInput by rememberSaveable { mutableStateOf(messages) } var cannedMessageInput by rememberSaveable { mutableStateOf(cannedMessageConfig) } - LazyColumn( - modifier = Modifier.fillMaxSize() - ) { + LazyColumn(modifier = Modifier.fillMaxSize()) { item { PreferenceCategory(text = stringResource(R.string.canned_message_config)) } item { @@ -96,9 +89,7 @@ fun CannedMessageConfigItemList( title = stringResource(R.string.canned_message_enabled), checked = cannedMessageInput.enabled, enabled = enabled, - onCheckedChange = { - cannedMessageInput = cannedMessageInput.copy { this.enabled = it } - } + onCheckedChange = { cannedMessageInput = cannedMessageInput.copy { this.enabled = it } }, ) } item { HorizontalDivider() } @@ -108,9 +99,7 @@ fun CannedMessageConfigItemList( title = stringResource(R.string.rotary_encoder_1_enabled), checked = cannedMessageInput.rotary1Enabled, enabled = enabled, - onCheckedChange = { - cannedMessageInput = cannedMessageInput.copy { rotary1Enabled = it } - } + onCheckedChange = { cannedMessageInput = cannedMessageInput.copy { rotary1Enabled = it } }, ) } item { HorizontalDivider() } @@ -121,9 +110,7 @@ fun CannedMessageConfigItemList( value = cannedMessageInput.inputbrokerPinA, enabled = enabled, keyboardActions = KeyboardActions(onDone = { focusManager.clearFocus() }), - onValueChanged = { - cannedMessageInput = cannedMessageInput.copy { inputbrokerPinA = it } - } + onValueChanged = { cannedMessageInput = cannedMessageInput.copy { inputbrokerPinA = it } }, ) } @@ -133,9 +120,7 @@ fun CannedMessageConfigItemList( value = cannedMessageInput.inputbrokerPinB, enabled = enabled, keyboardActions = KeyboardActions(onDone = { focusManager.clearFocus() }), - onValueChanged = { - cannedMessageInput = cannedMessageInput.copy { inputbrokerPinB = it } - } + onValueChanged = { cannedMessageInput = cannedMessageInput.copy { inputbrokerPinB = it } }, ) } @@ -145,9 +130,7 @@ fun CannedMessageConfigItemList( value = cannedMessageInput.inputbrokerPinPress, enabled = enabled, keyboardActions = KeyboardActions(onDone = { focusManager.clearFocus() }), - onValueChanged = { - cannedMessageInput = cannedMessageInput.copy { inputbrokerPinPress = it } - } + onValueChanged = { cannedMessageInput = cannedMessageInput.copy { inputbrokerPinPress = it } }, ) } @@ -155,13 +138,12 @@ fun CannedMessageConfigItemList( DropDownPreference( title = stringResource(R.string.generate_input_event_on_press), enabled = enabled, - items = CannedMessageConfig.InputEventChar.entries + items = + CannedMessageConfig.InputEventChar.entries .filter { it != CannedMessageConfig.InputEventChar.UNRECOGNIZED } .map { it to it.name }, selectedItem = cannedMessageInput.inputbrokerEventPress, - onItemSelected = { - cannedMessageInput = cannedMessageInput.copy { inputbrokerEventPress = it } - } + onItemSelected = { cannedMessageInput = cannedMessageInput.copy { inputbrokerEventPress = it } }, ) } item { HorizontalDivider() } @@ -170,13 +152,12 @@ fun CannedMessageConfigItemList( DropDownPreference( title = stringResource(R.string.generate_input_event_on_cw), enabled = enabled, - items = CannedMessageConfig.InputEventChar.entries + items = + CannedMessageConfig.InputEventChar.entries .filter { it != CannedMessageConfig.InputEventChar.UNRECOGNIZED } .map { it to it.name }, selectedItem = cannedMessageInput.inputbrokerEventCw, - onItemSelected = { - cannedMessageInput = cannedMessageInput.copy { inputbrokerEventCw = it } - } + onItemSelected = { cannedMessageInput = cannedMessageInput.copy { inputbrokerEventCw = it } }, ) } item { HorizontalDivider() } @@ -185,13 +166,12 @@ fun CannedMessageConfigItemList( DropDownPreference( title = stringResource(R.string.generate_input_event_on_ccw), enabled = enabled, - items = CannedMessageConfig.InputEventChar.entries + items = + CannedMessageConfig.InputEventChar.entries .filter { it != CannedMessageConfig.InputEventChar.UNRECOGNIZED } .map { it to it.name }, selectedItem = cannedMessageInput.inputbrokerEventCcw, - onItemSelected = { - cannedMessageInput = cannedMessageInput.copy { inputbrokerEventCcw = it } - } + onItemSelected = { cannedMessageInput = cannedMessageInput.copy { inputbrokerEventCcw = it } }, ) } item { HorizontalDivider() } @@ -201,9 +181,7 @@ fun CannedMessageConfigItemList( title = stringResource(R.string.up_down_select_input_enabled), checked = cannedMessageInput.updown1Enabled, enabled = enabled, - onCheckedChange = { - cannedMessageInput = cannedMessageInput.copy { updown1Enabled = it } - } + onCheckedChange = { cannedMessageInput = cannedMessageInput.copy { updown1Enabled = it } }, ) } item { HorizontalDivider() } @@ -215,13 +193,10 @@ fun CannedMessageConfigItemList( maxSize = 63, // allow_input_source max_size:16 enabled = enabled, isError = false, - keyboardOptions = KeyboardOptions.Default.copy( - keyboardType = KeyboardType.Text, imeAction = ImeAction.Done - ), + keyboardOptions = + KeyboardOptions.Default.copy(keyboardType = KeyboardType.Text, imeAction = ImeAction.Done), keyboardActions = KeyboardActions(onDone = { focusManager.clearFocus() }), - onValueChanged = { - cannedMessageInput = cannedMessageInput.copy { allowInputSource = it } - } + onValueChanged = { cannedMessageInput = cannedMessageInput.copy { allowInputSource = it } }, ) } @@ -230,9 +205,7 @@ fun CannedMessageConfigItemList( title = stringResource(R.string.send_bell), checked = cannedMessageInput.sendBell, enabled = enabled, - onCheckedChange = { - cannedMessageInput = cannedMessageInput.copy { sendBell = it } - } + onCheckedChange = { cannedMessageInput = cannedMessageInput.copy { sendBell = it } }, ) } item { HorizontalDivider() } @@ -244,11 +217,10 @@ fun CannedMessageConfigItemList( maxSize = 200, // messages max_size:201 enabled = enabled, isError = false, - keyboardOptions = KeyboardOptions.Default.copy( - keyboardType = KeyboardType.Text, imeAction = ImeAction.Done - ), + keyboardOptions = + KeyboardOptions.Default.copy(keyboardType = KeyboardType.Text, imeAction = ImeAction.Done), keyboardActions = KeyboardActions(onDone = { focusManager.clearFocus() }), - onValueChanged = { messagesInput = it } + onValueChanged = { messagesInput = it }, ) } @@ -263,7 +235,7 @@ fun CannedMessageConfigItemList( onSaveClicked = { focusManager.clearFocus() onSaveClicked(messagesInput, cannedMessageInput) - } + }, ) } } diff --git a/app/src/main/java/com/geeksville/mesh/ui/radioconfig/components/ChannelSettingsItemList.kt b/app/src/main/java/com/geeksville/mesh/ui/settings/radio/components/ChannelSettingsItemList.kt similarity index 99% rename from app/src/main/java/com/geeksville/mesh/ui/radioconfig/components/ChannelSettingsItemList.kt rename to app/src/main/java/com/geeksville/mesh/ui/settings/radio/components/ChannelSettingsItemList.kt index 16d80ea85..2115bc6b6 100644 --- a/app/src/main/java/com/geeksville/mesh/ui/radioconfig/components/ChannelSettingsItemList.kt +++ b/app/src/main/java/com/geeksville/mesh/ui/settings/radio/components/ChannelSettingsItemList.kt @@ -15,7 +15,7 @@ * along with this program. If not, see . */ -package com.geeksville.mesh.ui.radioconfig.components +package com.geeksville.mesh.ui.settings.radio.components import androidx.compose.animation.AnimatedVisibility import androidx.compose.animation.core.FastOutSlowInEasing @@ -79,7 +79,7 @@ import com.geeksville.mesh.ui.common.components.SecurityIcon import com.geeksville.mesh.ui.common.components.dragContainer import com.geeksville.mesh.ui.common.components.dragDropItemsIndexed import com.geeksville.mesh.ui.common.components.rememberDragDropState -import com.geeksville.mesh.ui.radioconfig.RadioConfigViewModel +import com.geeksville.mesh.ui.settings.radio.RadioConfigViewModel @Composable private fun ChannelItem( diff --git a/app/src/main/java/com/geeksville/mesh/ui/radioconfig/components/DetectionSensorConfigItemList.kt b/app/src/main/java/com/geeksville/mesh/ui/settings/radio/components/DetectionSensorConfigItemList.kt similarity index 77% rename from app/src/main/java/com/geeksville/mesh/ui/radioconfig/components/DetectionSensorConfigItemList.kt rename to app/src/main/java/com/geeksville/mesh/ui/settings/radio/components/DetectionSensorConfigItemList.kt index dfb425fa6..00b627345 100644 --- a/app/src/main/java/com/geeksville/mesh/ui/radioconfig/components/DetectionSensorConfigItemList.kt +++ b/app/src/main/java/com/geeksville/mesh/ui/settings/radio/components/DetectionSensorConfigItemList.kt @@ -15,7 +15,7 @@ * along with this program. If not, see . */ -package com.geeksville.mesh.ui.radioconfig.components +package com.geeksville.mesh.ui.settings.radio.components import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.lazy.LazyColumn @@ -44,19 +44,14 @@ import com.geeksville.mesh.ui.common.components.EditTextPreference import com.geeksville.mesh.ui.common.components.PreferenceCategory import com.geeksville.mesh.ui.common.components.PreferenceFooter import com.geeksville.mesh.ui.common.components.SwitchPreference -import com.geeksville.mesh.ui.radioconfig.RadioConfigViewModel +import com.geeksville.mesh.ui.settings.radio.RadioConfigViewModel @Composable -fun DetectionSensorConfigScreen( - viewModel: RadioConfigViewModel = hiltViewModel(), -) { +fun DetectionSensorConfigScreen(viewModel: RadioConfigViewModel = hiltViewModel()) { val state by viewModel.radioConfigState.collectAsStateWithLifecycle() if (state.responseState.isWaiting()) { - PacketResponseStateDialog( - state = state.responseState, - onDismiss = viewModel::clearPacketResponse, - ) + PacketResponseStateDialog(state = state.responseState, onDismiss = viewModel::clearPacketResponse) } DetectionSensorConfigItemList( @@ -65,7 +60,7 @@ fun DetectionSensorConfigScreen( onSaveClicked = { detectionSensorInput -> val config = moduleConfig { detectionSensor = detectionSensorInput } viewModel.setModuleConfig(config) - } + }, ) } @@ -79,9 +74,7 @@ fun DetectionSensorConfigItemList( val focusManager = LocalFocusManager.current var detectionSensorInput by rememberSaveable { mutableStateOf(detectionSensorConfig) } - LazyColumn( - modifier = Modifier.fillMaxSize() - ) { + LazyColumn(modifier = Modifier.fillMaxSize()) { item { PreferenceCategory(text = stringResource(R.string.detection_sensor_config)) } item { @@ -89,9 +82,7 @@ fun DetectionSensorConfigItemList( title = stringResource(R.string.detection_sensor_enabled), checked = detectionSensorInput.enabled, enabled = enabled, - onCheckedChange = { - detectionSensorInput = detectionSensorInput.copy { this.enabled = it } - } + onCheckedChange = { detectionSensorInput = detectionSensorInput.copy { this.enabled = it } }, ) } item { HorizontalDivider() } @@ -102,9 +93,7 @@ fun DetectionSensorConfigItemList( value = detectionSensorInput.minimumBroadcastSecs, enabled = enabled, keyboardActions = KeyboardActions(onDone = { focusManager.clearFocus() }), - onValueChanged = { - detectionSensorInput = detectionSensorInput.copy { minimumBroadcastSecs = it } - } + onValueChanged = { detectionSensorInput = detectionSensorInput.copy { minimumBroadcastSecs = it } }, ) } @@ -114,9 +103,7 @@ fun DetectionSensorConfigItemList( value = detectionSensorInput.stateBroadcastSecs, enabled = enabled, keyboardActions = KeyboardActions(onDone = { focusManager.clearFocus() }), - onValueChanged = { - detectionSensorInput = detectionSensorInput.copy { stateBroadcastSecs = it } - } + onValueChanged = { detectionSensorInput = detectionSensorInput.copy { stateBroadcastSecs = it } }, ) } @@ -125,9 +112,7 @@ fun DetectionSensorConfigItemList( title = stringResource(R.string.send_bell_with_alert_message), checked = detectionSensorInput.sendBell, enabled = enabled, - onCheckedChange = { - detectionSensorInput = detectionSensorInput.copy { sendBell = it } - } + onCheckedChange = { detectionSensorInput = detectionSensorInput.copy { sendBell = it } }, ) } item { HorizontalDivider() } @@ -139,13 +124,10 @@ fun DetectionSensorConfigItemList( maxSize = 19, // name max_size:20 enabled = enabled, isError = false, - keyboardOptions = KeyboardOptions.Default.copy( - keyboardType = KeyboardType.Text, imeAction = ImeAction.Done - ), + keyboardOptions = + KeyboardOptions.Default.copy(keyboardType = KeyboardType.Text, imeAction = ImeAction.Done), keyboardActions = KeyboardActions(onDone = { focusManager.clearFocus() }), - onValueChanged = { - detectionSensorInput = detectionSensorInput.copy { name = it } - } + onValueChanged = { detectionSensorInput = detectionSensorInput.copy { name = it } }, ) } @@ -155,9 +137,7 @@ fun DetectionSensorConfigItemList( value = detectionSensorInput.monitorPin, enabled = enabled, keyboardActions = KeyboardActions(onDone = { focusManager.clearFocus() }), - onValueChanged = { - detectionSensorInput = detectionSensorInput.copy { monitorPin = it } - } + onValueChanged = { detectionSensorInput = detectionSensorInput.copy { monitorPin = it } }, ) } @@ -165,13 +145,12 @@ fun DetectionSensorConfigItemList( DropDownPreference( title = stringResource(R.string.detection_trigger_type), enabled = enabled, - items = ModuleConfig.DetectionSensorConfig.TriggerType.entries + items = + ModuleConfig.DetectionSensorConfig.TriggerType.entries .filter { it != ModuleConfig.DetectionSensorConfig.TriggerType.UNRECOGNIZED } .map { it to it.name }, selectedItem = detectionSensorInput.detectionTriggerType, - onItemSelected = { - detectionSensorInput = detectionSensorInput.copy { detectionTriggerType = it } - } + onItemSelected = { detectionSensorInput = detectionSensorInput.copy { detectionTriggerType = it } }, ) } item { HorizontalDivider() } @@ -181,9 +160,7 @@ fun DetectionSensorConfigItemList( title = stringResource(R.string.use_input_pullup_mode), checked = detectionSensorInput.usePullup, enabled = enabled, - onCheckedChange = { - detectionSensorInput = detectionSensorInput.copy { usePullup = it } - } + onCheckedChange = { detectionSensorInput = detectionSensorInput.copy { usePullup = it } }, ) } item { HorizontalDivider() } @@ -198,7 +175,7 @@ fun DetectionSensorConfigItemList( onSaveClicked = { focusManager.clearFocus() onSaveClicked(detectionSensorInput) - } + }, ) } } @@ -210,6 +187,6 @@ private fun DetectionSensorConfigPreview() { DetectionSensorConfigItemList( detectionSensorConfig = ModuleConfig.DetectionSensorConfig.getDefaultInstance(), enabled = true, - onSaveClicked = { }, + onSaveClicked = {}, ) } diff --git a/app/src/main/java/com/geeksville/mesh/ui/radioconfig/components/DeviceConfigItemList.kt b/app/src/main/java/com/geeksville/mesh/ui/settings/radio/components/DeviceConfigItemList.kt similarity index 66% rename from app/src/main/java/com/geeksville/mesh/ui/radioconfig/components/DeviceConfigItemList.kt rename to app/src/main/java/com/geeksville/mesh/ui/settings/radio/components/DeviceConfigItemList.kt index 2f04f18df..3776a2ba9 100644 --- a/app/src/main/java/com/geeksville/mesh/ui/radioconfig/components/DeviceConfigItemList.kt +++ b/app/src/main/java/com/geeksville/mesh/ui/settings/radio/components/DeviceConfigItemList.kt @@ -15,7 +15,7 @@ * along with this program. If not, see . */ -package com.geeksville.mesh.ui.radioconfig.components +package com.geeksville.mesh.ui.settings.radio.components import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Column @@ -58,47 +58,44 @@ import com.geeksville.mesh.ui.common.components.EditTextPreference import com.geeksville.mesh.ui.common.components.PreferenceCategory import com.geeksville.mesh.ui.common.components.PreferenceFooter import com.geeksville.mesh.ui.common.components.SwitchPreference -import com.geeksville.mesh.ui.radioconfig.RadioConfigViewModel +import com.geeksville.mesh.ui.settings.radio.RadioConfigViewModel private val DeviceConfig.Role.stringRes: Int - get() = when (this) { - DeviceConfig.Role.CLIENT -> R.string.role_client - DeviceConfig.Role.CLIENT_MUTE -> R.string.role_client_mute - DeviceConfig.Role.ROUTER -> R.string.role_router - DeviceConfig.Role.ROUTER_CLIENT -> R.string.role_router_client - DeviceConfig.Role.REPEATER -> R.string.role_repeater - DeviceConfig.Role.TRACKER -> R.string.role_tracker - DeviceConfig.Role.SENSOR -> R.string.role_sensor - DeviceConfig.Role.TAK -> R.string.role_tak - DeviceConfig.Role.CLIENT_HIDDEN -> R.string.role_client_hidden - DeviceConfig.Role.LOST_AND_FOUND -> R.string.role_lost_and_found - DeviceConfig.Role.TAK_TRACKER -> R.string.role_tak_tracker - DeviceConfig.Role.ROUTER_LATE -> R.string.role_router_late - else -> R.string.unrecognized - } + get() = + when (this) { + DeviceConfig.Role.CLIENT -> R.string.role_client + DeviceConfig.Role.CLIENT_MUTE -> R.string.role_client_mute + DeviceConfig.Role.ROUTER -> R.string.role_router + DeviceConfig.Role.ROUTER_CLIENT -> R.string.role_router_client + DeviceConfig.Role.REPEATER -> R.string.role_repeater + DeviceConfig.Role.TRACKER -> R.string.role_tracker + DeviceConfig.Role.SENSOR -> R.string.role_sensor + DeviceConfig.Role.TAK -> R.string.role_tak + DeviceConfig.Role.CLIENT_HIDDEN -> R.string.role_client_hidden + DeviceConfig.Role.LOST_AND_FOUND -> R.string.role_lost_and_found + DeviceConfig.Role.TAK_TRACKER -> R.string.role_tak_tracker + DeviceConfig.Role.ROUTER_LATE -> R.string.role_router_late + else -> R.string.unrecognized + } private val DeviceConfig.RebroadcastMode.stringRes: Int - get() = when (this) { - DeviceConfig.RebroadcastMode.ALL -> R.string.rebroadcast_mode_all - DeviceConfig.RebroadcastMode.ALL_SKIP_DECODING -> R.string.rebroadcast_mode_all_skip_decoding - DeviceConfig.RebroadcastMode.LOCAL_ONLY -> R.string.rebroadcast_mode_local_only - DeviceConfig.RebroadcastMode.KNOWN_ONLY -> R.string.rebroadcast_mode_known_only - DeviceConfig.RebroadcastMode.NONE -> R.string.rebroadcast_mode_none - DeviceConfig.RebroadcastMode.CORE_PORTNUMS_ONLY -> R.string.rebroadcast_mode_core_portnums_only - else -> R.string.unrecognized - } + get() = + when (this) { + DeviceConfig.RebroadcastMode.ALL -> R.string.rebroadcast_mode_all + DeviceConfig.RebroadcastMode.ALL_SKIP_DECODING -> R.string.rebroadcast_mode_all_skip_decoding + DeviceConfig.RebroadcastMode.LOCAL_ONLY -> R.string.rebroadcast_mode_local_only + DeviceConfig.RebroadcastMode.KNOWN_ONLY -> R.string.rebroadcast_mode_known_only + DeviceConfig.RebroadcastMode.NONE -> R.string.rebroadcast_mode_none + DeviceConfig.RebroadcastMode.CORE_PORTNUMS_ONLY -> R.string.rebroadcast_mode_core_portnums_only + else -> R.string.unrecognized + } @Composable -fun DeviceConfigScreen( - viewModel: RadioConfigViewModel = hiltViewModel(), -) { +fun DeviceConfigScreen(viewModel: RadioConfigViewModel = hiltViewModel()) { val state by viewModel.radioConfigState.collectAsStateWithLifecycle() if (state.responseState.isWaiting()) { - PacketResponseStateDialog( - state = state.responseState, - onDismiss = viewModel::clearPacketResponse, - ) + PacketResponseStateDialog(state = state.responseState, onDismiss = viewModel::clearPacketResponse) } DeviceConfigItemList( @@ -107,94 +104,62 @@ fun DeviceConfigScreen( onSaveClicked = { deviceInput -> val config = config { device = deviceInput } viewModel.setConfig(config) - } + }, ) } @Suppress("LongMethod") @Composable -fun RouterRoleConfirmationDialog( - onDismiss: () -> Unit, - onConfirm: () -> Unit, -) { +fun RouterRoleConfirmationDialog(onDismiss: () -> Unit, onConfirm: () -> Unit) { val dialogTitle = stringResource(R.string.are_you_sure) - val annotatedDialogText = AnnotatedString.fromHtml( - htmlString = stringResource(R.string.router_role_confirmation_text), - linkStyles = TextLinkStyles(style = SpanStyle(color = Color.Blue)) - ) + val annotatedDialogText = + AnnotatedString.fromHtml( + htmlString = stringResource(R.string.router_role_confirmation_text), + linkStyles = TextLinkStyles(style = SpanStyle(color = Color.Blue)), + ) var confirmed by rememberSaveable { mutableStateOf(false) } AlertDialog( - title = { - Text(text = dialogTitle) - }, + title = { Text(text = dialogTitle) }, text = { Column { Text(text = annotatedDialogText) Row( - modifier = Modifier - .fillMaxWidth() - .clickable(true) { - confirmed = !confirmed - }, - verticalAlignment = Alignment.CenterVertically + modifier = Modifier.fillMaxWidth().clickable(true) { confirmed = !confirmed }, + verticalAlignment = Alignment.CenterVertically, ) { - Checkbox( - checked = confirmed, - onCheckedChange = { confirmed = it } - ) + Checkbox(checked = confirmed, onCheckedChange = { confirmed = it }) Text(stringResource(R.string.i_know_what_i_m_doing)) } } }, onDismissRequest = onDismiss, confirmButton = { - TextButton( - onClick = onConfirm, - enabled = confirmed - ) { - Text(stringResource(R.string.accept)) - } + TextButton(onClick = onConfirm, enabled = confirmed) { Text(stringResource(R.string.accept)) } }, - dismissButton = { - TextButton( - onClick = onDismiss - ) { - Text(stringResource(R.string.cancel)) - } - } + dismissButton = { TextButton(onClick = onDismiss) { Text(stringResource(R.string.cancel)) } }, ) } +@Suppress("LongMethod") @Composable -fun DeviceConfigItemList( - deviceConfig: DeviceConfig, - enabled: Boolean, - onSaveClicked: (DeviceConfig) -> Unit, -) { +fun DeviceConfigItemList(deviceConfig: DeviceConfig, enabled: Boolean, onSaveClicked: (DeviceConfig) -> Unit) { val focusManager = LocalFocusManager.current var deviceInput by rememberSaveable { mutableStateOf(deviceConfig) } var selectedRole by rememberSaveable { mutableStateOf(deviceInput.role) } - val infrastructureRoles = listOf( - DeviceConfig.Role.ROUTER, - DeviceConfig.Role.REPEATER, - ) + val infrastructureRoles = listOf(DeviceConfig.Role.ROUTER, DeviceConfig.Role.REPEATER) if (selectedRole != deviceInput.role) { if (selectedRole in infrastructureRoles) { RouterRoleConfirmationDialog( onDismiss = { selectedRole = deviceInput.role }, - onConfirm = { - deviceInput = deviceInput.copy { role = selectedRole } - } + onConfirm = { deviceInput = deviceInput.copy { role = selectedRole } }, ) } else { deviceInput = deviceInput.copy { role = selectedRole } } } - LazyColumn( - modifier = Modifier.fillMaxSize() - ) { + LazyColumn(modifier = Modifier.fillMaxSize()) { item { PreferenceCategory(text = stringResource(R.string.device_config)) } item { @@ -202,9 +167,7 @@ fun DeviceConfigItemList( title = stringResource(R.string.role), enabled = enabled, selectedItem = deviceInput.role, - onItemSelected = { - selectedRole = it - }, + onItemSelected = { selectedRole = it }, summary = stringResource(id = deviceInput.role.stringRes), ) HorizontalDivider() @@ -216,9 +179,7 @@ fun DeviceConfigItemList( value = deviceInput.buttonGpio, enabled = enabled, keyboardActions = KeyboardActions(onDone = { focusManager.clearFocus() }), - onValueChanged = { - deviceInput = deviceInput.copy { buttonGpio = it } - } + onValueChanged = { deviceInput = deviceInput.copy { buttonGpio = it } }, ) } @@ -228,9 +189,7 @@ fun DeviceConfigItemList( value = deviceInput.buzzerGpio, enabled = enabled, keyboardActions = KeyboardActions(onDone = { focusManager.clearFocus() }), - onValueChanged = { - deviceInput = deviceInput.copy { buzzerGpio = it } - } + onValueChanged = { deviceInput = deviceInput.copy { buzzerGpio = it } }, ) } @@ -251,9 +210,7 @@ fun DeviceConfigItemList( value = deviceInput.nodeInfoBroadcastSecs, enabled = enabled, keyboardActions = KeyboardActions(onDone = { focusManager.clearFocus() }), - onValueChanged = { - deviceInput = deviceInput.copy { nodeInfoBroadcastSecs = it } - } + onValueChanged = { deviceInput = deviceInput.copy { nodeInfoBroadcastSecs = it } }, ) } @@ -263,7 +220,7 @@ fun DeviceConfigItemList( summary = stringResource(id = R.string.config_device_doubleTapAsButtonPress_summary), checked = deviceInput.doubleTapAsButtonPress, enabled = enabled, - onCheckedChange = { deviceInput = deviceInput.copy { doubleTapAsButtonPress = it } } + onCheckedChange = { deviceInput = deviceInput.copy { doubleTapAsButtonPress = it } }, ) HorizontalDivider() } @@ -274,7 +231,7 @@ fun DeviceConfigItemList( summary = stringResource(id = R.string.config_device_disableTripleClick_summary), checked = deviceInput.disableTripleClick, enabled = enabled, - onCheckedChange = { deviceInput = deviceInput.copy { disableTripleClick = it } } + onCheckedChange = { deviceInput = deviceInput.copy { disableTripleClick = it } }, ) HorizontalDivider() } @@ -286,13 +243,10 @@ fun DeviceConfigItemList( maxSize = 64, // tzdef max_size:65 enabled = enabled, isError = false, - keyboardOptions = KeyboardOptions.Default.copy( - keyboardType = KeyboardType.Text, imeAction = ImeAction.Done - ), + keyboardOptions = + KeyboardOptions.Default.copy(keyboardType = KeyboardType.Text, imeAction = ImeAction.Done), keyboardActions = KeyboardActions(onDone = { focusManager.clearFocus() }), - onValueChanged = { - deviceInput = deviceInput.copy { tzdef = it } - }, + onValueChanged = { deviceInput = deviceInput.copy { tzdef = it } }, ) } @@ -302,7 +256,7 @@ fun DeviceConfigItemList( summary = stringResource(id = R.string.config_device_ledHeartbeatDisabled_summary), checked = deviceInput.ledHeartbeatDisabled, enabled = enabled, - onCheckedChange = { deviceInput = deviceInput.copy { ledHeartbeatDisabled = it } } + onCheckedChange = { deviceInput = deviceInput.copy { ledHeartbeatDisabled = it } }, ) HorizontalDivider() } @@ -317,7 +271,7 @@ fun DeviceConfigItemList( onSaveClicked = { focusManager.clearFocus() onSaveClicked(deviceInput) - } + }, ) } } @@ -326,9 +280,5 @@ fun DeviceConfigItemList( @Preview(showBackground = true) @Composable private fun DeviceConfigPreview() { - DeviceConfigItemList( - deviceConfig = DeviceConfig.getDefaultInstance(), - enabled = true, - onSaveClicked = { }, - ) + DeviceConfigItemList(deviceConfig = DeviceConfig.getDefaultInstance(), enabled = true, onSaveClicked = {}) } diff --git a/app/src/main/java/com/geeksville/mesh/ui/radioconfig/components/DisplayConfigItemList.kt b/app/src/main/java/com/geeksville/mesh/ui/settings/radio/components/DisplayConfigItemList.kt similarity index 98% rename from app/src/main/java/com/geeksville/mesh/ui/radioconfig/components/DisplayConfigItemList.kt rename to app/src/main/java/com/geeksville/mesh/ui/settings/radio/components/DisplayConfigItemList.kt index d5b9c441a..1a550d257 100644 --- a/app/src/main/java/com/geeksville/mesh/ui/radioconfig/components/DisplayConfigItemList.kt +++ b/app/src/main/java/com/geeksville/mesh/ui/settings/radio/components/DisplayConfigItemList.kt @@ -15,7 +15,7 @@ * along with this program. If not, see . */ -package com.geeksville.mesh.ui.radioconfig.components +package com.geeksville.mesh.ui.settings.radio.components import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.lazy.LazyColumn @@ -41,7 +41,7 @@ import com.geeksville.mesh.ui.common.components.EditTextPreference import com.geeksville.mesh.ui.common.components.PreferenceCategory import com.geeksville.mesh.ui.common.components.PreferenceFooter import com.geeksville.mesh.ui.common.components.SwitchPreference -import com.geeksville.mesh.ui.radioconfig.RadioConfigViewModel +import com.geeksville.mesh.ui.settings.radio.RadioConfigViewModel @Composable fun DisplayConfigScreen(viewModel: RadioConfigViewModel = hiltViewModel()) { diff --git a/app/src/main/java/com/geeksville/mesh/ui/radioconfig/components/EditChannelDialog.kt b/app/src/main/java/com/geeksville/mesh/ui/settings/radio/components/EditChannelDialog.kt similarity index 99% rename from app/src/main/java/com/geeksville/mesh/ui/radioconfig/components/EditChannelDialog.kt rename to app/src/main/java/com/geeksville/mesh/ui/settings/radio/components/EditChannelDialog.kt index 0575a824c..85df04701 100644 --- a/app/src/main/java/com/geeksville/mesh/ui/radioconfig/components/EditChannelDialog.kt +++ b/app/src/main/java/com/geeksville/mesh/ui/settings/radio/components/EditChannelDialog.kt @@ -15,7 +15,7 @@ * along with this program. If not, see . */ -package com.geeksville.mesh.ui.radioconfig.components +package com.geeksville.mesh.ui.settings.radio.components import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column diff --git a/app/src/main/java/com/geeksville/mesh/ui/radioconfig/components/EditDeviceProfileDialog.kt b/app/src/main/java/com/geeksville/mesh/ui/settings/radio/components/EditDeviceProfileDialog.kt similarity index 73% rename from app/src/main/java/com/geeksville/mesh/ui/radioconfig/components/EditDeviceProfileDialog.kt rename to app/src/main/java/com/geeksville/mesh/ui/settings/radio/components/EditDeviceProfileDialog.kt index 903f2ec6e..a4ff3c928 100644 --- a/app/src/main/java/com/geeksville/mesh/ui/radioconfig/components/EditDeviceProfileDialog.kt +++ b/app/src/main/java/com/geeksville/mesh/ui/settings/radio/components/EditDeviceProfileDialog.kt @@ -15,7 +15,7 @@ * along with this program. If not, see . */ -package com.geeksville.mesh.ui.radioconfig.components +package com.geeksville.mesh.ui.settings.radio.components import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column @@ -45,7 +45,7 @@ import com.geeksville.mesh.R import com.geeksville.mesh.ui.common.components.SwitchPreference import com.google.protobuf.Descriptors -private const val SupportedFields = 7 +private const val SUPPORTED_FIELDS = 7 @Suppress("LongMethod") @OptIn(ExperimentalLayoutApi::class) @@ -58,10 +58,13 @@ fun EditDeviceProfileDialog( modifier: Modifier = Modifier, ) { val state = remember { - val fields = deviceProfile.descriptorForType.fields - .filter { it.number < SupportedFields } // TODO add ringtone & canned messages - mutableStateMapOf() - .apply { putAll(fields.associateWith(deviceProfile::hasField)) } + val fields = + deviceProfile.descriptorForType.fields.filter { + it.number < SUPPORTED_FIELDS + } // TODO add ringtone & canned messages + mutableStateMapOf().apply { + putAll(fields.associateWith(deviceProfile::hasField)) + } } AlertDialog( @@ -71,38 +74,36 @@ fun EditDeviceProfileDialog( Column(modifier.fillMaxWidth()) { Text( text = title, - style = MaterialTheme.typography.titleLarge.copy( + style = + MaterialTheme.typography.titleLarge.copy( fontWeight = FontWeight.Bold, textAlign = TextAlign.Center, ), - modifier = Modifier - .fillMaxWidth() - .padding(bottom = 16.dp), + modifier = Modifier.fillMaxWidth().padding(bottom = 16.dp), ) HorizontalDivider() - state.keys.sortedBy { it.number }.forEach { field -> - SwitchPreference( - title = field.name, - checked = state[field] == true, - enabled = deviceProfile.hasField(field), - onCheckedChange = { state[field] = it }, - padding = PaddingValues(0.dp) - ) - } + state.keys + .sortedBy { it.number } + .forEach { field -> + SwitchPreference( + title = field.name, + checked = state[field] == true, + enabled = deviceProfile.hasField(field), + onCheckedChange = { state[field] = it }, + padding = PaddingValues(0.dp), + ) + } HorizontalDivider() } }, confirmButton = { FlowRow( - modifier = modifier - .fillMaxWidth() - .padding(start = 24.dp, end = 24.dp, bottom = 16.dp), + modifier = modifier.fillMaxWidth().padding(start = 24.dp, end = 24.dp, bottom = 16.dp), horizontalArrangement = Arrangement.spacedBy(8.dp), ) { - TextButton( - modifier = modifier.weight(1f), - onClick = onDismiss - ) { Text(stringResource(R.string.cancel)) } + TextButton(modifier = modifier.weight(1f), onClick = onDismiss) { + Text(stringResource(R.string.cancel)) + } Button( modifier = modifier.weight(1f), onClick = { @@ -115,9 +116,11 @@ fun EditDeviceProfileDialog( onConfirm(builder.build()) }, enabled = state.values.any { it }, - ) { Text(stringResource(R.string.save)) } + ) { + Text(stringResource(R.string.save)) + } } - } + }, ) } diff --git a/app/src/main/java/com/geeksville/mesh/ui/radioconfig/components/ExternalNotificationConfigItemList.kt b/app/src/main/java/com/geeksville/mesh/ui/settings/radio/components/ExternalNotificationConfigItemList.kt similarity index 76% rename from app/src/main/java/com/geeksville/mesh/ui/radioconfig/components/ExternalNotificationConfigItemList.kt rename to app/src/main/java/com/geeksville/mesh/ui/settings/radio/components/ExternalNotificationConfigItemList.kt index f84909944..c544bf0de 100644 --- a/app/src/main/java/com/geeksville/mesh/ui/radioconfig/components/ExternalNotificationConfigItemList.kt +++ b/app/src/main/java/com/geeksville/mesh/ui/settings/radio/components/ExternalNotificationConfigItemList.kt @@ -15,7 +15,7 @@ * along with this program. If not, see . */ -package com.geeksville.mesh.ui.radioconfig.components +package com.geeksville.mesh.ui.settings.radio.components import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.lazy.LazyColumn @@ -44,19 +44,14 @@ import com.geeksville.mesh.ui.common.components.PreferenceCategory import com.geeksville.mesh.ui.common.components.PreferenceFooter import com.geeksville.mesh.ui.common.components.SwitchPreference import com.geeksville.mesh.ui.common.components.TextDividerPreference -import com.geeksville.mesh.ui.radioconfig.RadioConfigViewModel +import com.geeksville.mesh.ui.settings.radio.RadioConfigViewModel @Composable -fun ExternalNotificationConfigScreen( - viewModel: RadioConfigViewModel = hiltViewModel(), -) { +fun ExternalNotificationConfigScreen(viewModel: RadioConfigViewModel = hiltViewModel()) { val state by viewModel.radioConfigState.collectAsStateWithLifecycle() if (state.responseState.isWaiting()) { - PacketResponseStateDialog( - state = state.responseState, - onDismiss = viewModel::clearPacketResponse, - ) + PacketResponseStateDialog(state = state.responseState, onDismiss = viewModel::clearPacketResponse) } ExternalNotificationConfigItemList( @@ -71,7 +66,7 @@ fun ExternalNotificationConfigScreen( val config = moduleConfig { externalNotification = extNotificationInput } viewModel.setModuleConfig(config) } - } + }, ) } @@ -86,9 +81,7 @@ fun ExternalNotificationConfigItemList( var ringtoneInput by rememberSaveable { mutableStateOf(ringtone) } var externalNotificationInput by rememberSaveable { mutableStateOf(extNotificationConfig) } - LazyColumn( - modifier = Modifier.fillMaxSize() - ) { + LazyColumn(modifier = Modifier.fillMaxSize()) { item { PreferenceCategory(text = stringResource(R.string.external_notification_config)) } item { @@ -96,9 +89,7 @@ fun ExternalNotificationConfigItemList( title = stringResource(R.string.external_notification_enabled), checked = externalNotificationInput.enabled, enabled = enabled, - onCheckedChange = { - externalNotificationInput = externalNotificationInput.copy { this.enabled = it } - } + onCheckedChange = { externalNotificationInput = externalNotificationInput.copy { this.enabled = it } }, ) } @@ -109,9 +100,7 @@ fun ExternalNotificationConfigItemList( title = stringResource(R.string.alert_message_led), checked = externalNotificationInput.alertMessage, enabled = enabled, - onCheckedChange = { - externalNotificationInput = externalNotificationInput.copy { alertMessage = it } - } + onCheckedChange = { externalNotificationInput = externalNotificationInput.copy { alertMessage = it } }, ) } item { HorizontalDivider() } @@ -122,9 +111,8 @@ fun ExternalNotificationConfigItemList( checked = externalNotificationInput.alertMessageBuzzer, enabled = enabled, onCheckedChange = { - externalNotificationInput = - externalNotificationInput.copy { alertMessageBuzzer = it } - } + externalNotificationInput = externalNotificationInput.copy { alertMessageBuzzer = it } + }, ) } item { HorizontalDivider() } @@ -135,9 +123,8 @@ fun ExternalNotificationConfigItemList( checked = externalNotificationInput.alertMessageVibra, enabled = enabled, onCheckedChange = { - externalNotificationInput = - externalNotificationInput.copy { alertMessageVibra = it } - } + externalNotificationInput = externalNotificationInput.copy { alertMessageVibra = it } + }, ) } @@ -148,9 +135,7 @@ fun ExternalNotificationConfigItemList( title = stringResource(R.string.alert_bell_led), checked = externalNotificationInput.alertBell, enabled = enabled, - onCheckedChange = { - externalNotificationInput = externalNotificationInput.copy { alertBell = it } - } + onCheckedChange = { externalNotificationInput = externalNotificationInput.copy { alertBell = it } }, ) } item { HorizontalDivider() } @@ -161,9 +146,8 @@ fun ExternalNotificationConfigItemList( checked = externalNotificationInput.alertBellBuzzer, enabled = enabled, onCheckedChange = { - externalNotificationInput = - externalNotificationInput.copy { alertBellBuzzer = it } - } + externalNotificationInput = externalNotificationInput.copy { alertBellBuzzer = it } + }, ) } item { HorizontalDivider() } @@ -174,9 +158,8 @@ fun ExternalNotificationConfigItemList( checked = externalNotificationInput.alertBellVibra, enabled = enabled, onCheckedChange = { - externalNotificationInput = - externalNotificationInput.copy { alertBellVibra = it } - } + externalNotificationInput = externalNotificationInput.copy { alertBellVibra = it } + }, ) } item { HorizontalDivider() } @@ -187,23 +170,19 @@ fun ExternalNotificationConfigItemList( value = externalNotificationInput.output, enabled = enabled, keyboardActions = KeyboardActions(onDone = { focusManager.clearFocus() }), - onValueChanged = { - externalNotificationInput = externalNotificationInput.copy { output = it } - } + onValueChanged = { externalNotificationInput = externalNotificationInput.copy { output = it } }, ) } if (externalNotificationInput.output != 0) { item { - SwitchPreference( - title = stringResource(R.string.output_led_active_high), - checked = externalNotificationInput.active, - enabled = enabled, - onCheckedChange = { - externalNotificationInput = externalNotificationInput.copy { active = it } - } - ) - } + SwitchPreference( + title = stringResource(R.string.output_led_active_high), + checked = externalNotificationInput.active, + enabled = enabled, + onCheckedChange = { externalNotificationInput = externalNotificationInput.copy { active = it } }, + ) + } } item { HorizontalDivider() } @@ -213,23 +192,19 @@ fun ExternalNotificationConfigItemList( value = externalNotificationInput.outputBuzzer, enabled = enabled, keyboardActions = KeyboardActions(onDone = { focusManager.clearFocus() }), - onValueChanged = { - externalNotificationInput = externalNotificationInput.copy { outputBuzzer = it } - } + onValueChanged = { externalNotificationInput = externalNotificationInput.copy { outputBuzzer = it } }, ) } if (externalNotificationInput.outputBuzzer != 0) { item { - SwitchPreference( - title = stringResource(R.string.use_pwm_buzzer), - checked = externalNotificationInput.usePwm, - enabled = enabled, - onCheckedChange = { - externalNotificationInput = externalNotificationInput.copy { usePwm = it } - } - ) - } + SwitchPreference( + title = stringResource(R.string.use_pwm_buzzer), + checked = externalNotificationInput.usePwm, + enabled = enabled, + onCheckedChange = { externalNotificationInput = externalNotificationInput.copy { usePwm = it } }, + ) + } } item { HorizontalDivider() } @@ -239,9 +214,7 @@ fun ExternalNotificationConfigItemList( value = externalNotificationInput.outputVibra, enabled = enabled, keyboardActions = KeyboardActions(onDone = { focusManager.clearFocus() }), - onValueChanged = { - externalNotificationInput = externalNotificationInput.copy { outputVibra = it } - } + onValueChanged = { externalNotificationInput = externalNotificationInput.copy { outputVibra = it } }, ) } @@ -251,9 +224,7 @@ fun ExternalNotificationConfigItemList( value = externalNotificationInput.outputMs, enabled = enabled, keyboardActions = KeyboardActions(onDone = { focusManager.clearFocus() }), - onValueChanged = { - externalNotificationInput = externalNotificationInput.copy { outputMs = it } - } + onValueChanged = { externalNotificationInput = externalNotificationInput.copy { outputMs = it } }, ) } @@ -263,9 +234,7 @@ fun ExternalNotificationConfigItemList( value = externalNotificationInput.nagTimeout, enabled = enabled, keyboardActions = KeyboardActions(onDone = { focusManager.clearFocus() }), - onValueChanged = { - externalNotificationInput = externalNotificationInput.copy { nagTimeout = it } - } + onValueChanged = { externalNotificationInput = externalNotificationInput.copy { nagTimeout = it } }, ) } @@ -276,11 +245,10 @@ fun ExternalNotificationConfigItemList( maxSize = 230, // ringtone max_size:231 enabled = enabled, isError = false, - keyboardOptions = KeyboardOptions.Default.copy( - keyboardType = KeyboardType.Text, imeAction = ImeAction.Done - ), + keyboardOptions = + KeyboardOptions.Default.copy(keyboardType = KeyboardType.Text, imeAction = ImeAction.Done), keyboardActions = KeyboardActions(onDone = { focusManager.clearFocus() }), - onValueChanged = { ringtoneInput = it } + onValueChanged = { ringtoneInput = it }, ) } @@ -291,7 +259,7 @@ fun ExternalNotificationConfigItemList( enabled = enabled, onCheckedChange = { externalNotificationInput = externalNotificationInput.copy { useI2SAsBuzzer = it } - } + }, ) } item { HorizontalDivider() } @@ -307,7 +275,7 @@ fun ExternalNotificationConfigItemList( onSaveClicked = { focusManager.clearFocus() onSaveClicked(ringtoneInput, externalNotificationInput) - } + }, ) } } diff --git a/app/src/main/java/com/geeksville/mesh/ui/radioconfig/components/LoRaConfigItemList.kt b/app/src/main/java/com/geeksville/mesh/ui/settings/radio/components/LoRaConfigItemList.kt similarity index 88% rename from app/src/main/java/com/geeksville/mesh/ui/radioconfig/components/LoRaConfigItemList.kt rename to app/src/main/java/com/geeksville/mesh/ui/settings/radio/components/LoRaConfigItemList.kt index 76710f89d..cce70e743 100644 --- a/app/src/main/java/com/geeksville/mesh/ui/radioconfig/components/LoRaConfigItemList.kt +++ b/app/src/main/java/com/geeksville/mesh/ui/settings/radio/components/LoRaConfigItemList.kt @@ -15,7 +15,7 @@ * along with this program. If not, see . */ -package com.geeksville.mesh.ui.radioconfig.components +package com.geeksville.mesh.ui.settings.radio.components import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.lazy.LazyColumn @@ -48,19 +48,14 @@ import com.geeksville.mesh.ui.common.components.PreferenceCategory import com.geeksville.mesh.ui.common.components.PreferenceFooter import com.geeksville.mesh.ui.common.components.SignedIntegerEditTextPreference import com.geeksville.mesh.ui.common.components.SwitchPreference -import com.geeksville.mesh.ui.radioconfig.RadioConfigViewModel +import com.geeksville.mesh.ui.settings.radio.RadioConfigViewModel @Composable -fun LoRaConfigScreen( - viewModel: RadioConfigViewModel = hiltViewModel(), -) { +fun LoRaConfigScreen(viewModel: RadioConfigViewModel = hiltViewModel()) { val state by viewModel.radioConfigState.collectAsStateWithLifecycle() if (state.responseState.isWaiting()) { - PacketResponseStateDialog( - state = state.responseState, - onDismiss = viewModel::clearPacketResponse, - ) + PacketResponseStateDialog(state = state.responseState, onDismiss = viewModel::clearPacketResponse) } LoRaConfigItemList( @@ -86,13 +81,9 @@ fun LoRaConfigItemList( ) { val focusManager = LocalFocusManager.current var loraInput by rememberSaveable { mutableStateOf(loraConfig) } - val primaryChannel by remember(loraInput) { - mutableStateOf(Channel(primarySettings, loraInput)) - } + val primaryChannel by remember(loraInput) { mutableStateOf(Channel(primarySettings, loraInput)) } - LazyColumn( - modifier = Modifier.fillMaxSize() - ) { + LazyColumn(modifier = Modifier.fillMaxSize()) { item { PreferenceCategory(text = stringResource(R.string.lora_config)) } item { @@ -100,7 +91,7 @@ fun LoRaConfigItemList( title = stringResource(R.string.use_modem_preset), checked = loraInput.usePreset, enabled = enabled, - onCheckedChange = { loraInput = loraInput.copy { usePreset = it } } + onCheckedChange = { loraInput = loraInput.copy { usePreset = it } }, ) } item { HorizontalDivider() } @@ -110,11 +101,12 @@ fun LoRaConfigItemList( DropDownPreference( title = stringResource(R.string.modem_preset), enabled = enabled && loraInput.usePreset, - items = LoRaConfig.ModemPreset.entries + items = + LoRaConfig.ModemPreset.entries .filter { it != LoRaConfig.ModemPreset.UNRECOGNIZED } .map { it to it.name }, selectedItem = loraInput.modemPreset, - onItemSelected = { loraInput = loraInput.copy { modemPreset = it } } + onItemSelected = { loraInput = loraInput.copy { modemPreset = it } }, ) } item { HorizontalDivider() } @@ -125,7 +117,7 @@ fun LoRaConfigItemList( value = loraInput.bandwidth, enabled = enabled && !loraInput.usePreset, keyboardActions = KeyboardActions(onDone = { focusManager.clearFocus() }), - onValueChanged = { loraInput = loraInput.copy { bandwidth = it } } + onValueChanged = { loraInput = loraInput.copy { bandwidth = it } }, ) } @@ -135,7 +127,7 @@ fun LoRaConfigItemList( value = loraInput.spreadFactor, enabled = enabled && !loraInput.usePreset, keyboardActions = KeyboardActions(onDone = { focusManager.clearFocus() }), - onValueChanged = { loraInput = loraInput.copy { spreadFactor = it } } + onValueChanged = { loraInput = loraInput.copy { spreadFactor = it } }, ) } @@ -145,7 +137,7 @@ fun LoRaConfigItemList( value = loraInput.codingRate, enabled = enabled && !loraInput.usePreset, keyboardActions = KeyboardActions(onDone = { focusManager.clearFocus() }), - onValueChanged = { loraInput = loraInput.copy { codingRate = it } } + onValueChanged = { loraInput = loraInput.copy { codingRate = it } }, ) } } @@ -156,7 +148,7 @@ fun LoRaConfigItemList( value = loraInput.frequencyOffset, enabled = enabled, keyboardActions = KeyboardActions(onDone = { focusManager.clearFocus() }), - onValueChanged = { loraInput = loraInput.copy { frequencyOffset = it } } + onValueChanged = { loraInput = loraInput.copy { frequencyOffset = it } }, ) } @@ -166,7 +158,7 @@ fun LoRaConfigItemList( enabled = enabled, items = RegionInfo.entries.map { it.regionCode to it.description }, selectedItem = loraInput.region, - onItemSelected = { loraInput = loraInput.copy { region = it } } + onItemSelected = { loraInput = loraInput.copy { region = it } }, ) } item { HorizontalDivider() } @@ -177,7 +169,7 @@ fun LoRaConfigItemList( value = loraInput.hopLimit, enabled = enabled, keyboardActions = KeyboardActions(onDone = { focusManager.clearFocus() }), - onValueChanged = { loraInput = loraInput.copy { hopLimit = it } } + onValueChanged = { loraInput = loraInput.copy { hopLimit = it } }, ) } @@ -186,7 +178,7 @@ fun LoRaConfigItemList( title = stringResource(R.string.tx_enabled), checked = loraInput.txEnabled, enabled = enabled, - onCheckedChange = { loraInput = loraInput.copy { txEnabled = it } } + onCheckedChange = { loraInput = loraInput.copy { txEnabled = it } }, ) } item { HorizontalDivider() } @@ -213,7 +205,7 @@ fun LoRaConfigItemList( if (it <= loraInput.numChannels) { // total num of LoRa channels loraInput = loraInput.copy { channelNum = it } } - } + }, ) } @@ -222,7 +214,7 @@ fun LoRaConfigItemList( title = stringResource(R.string.override_duty_cycle), checked = loraInput.overrideDutyCycle, enabled = enabled, - onCheckedChange = { loraInput = loraInput.copy { overrideDutyCycle = it } } + onCheckedChange = { loraInput = loraInput.copy { overrideDutyCycle = it } }, ) } item { HorizontalDivider() } @@ -235,11 +227,12 @@ fun LoRaConfigItemList( enabled = enabled, keyboardActions = KeyboardActions(onDone = { focusManager.clearFocus() }), onValuesChanged = { list -> - loraInput = loraInput.copy { - ignoreIncoming.clear() - ignoreIncoming.addAll(list.filter { it != 0 }) - } - } + loraInput = + loraInput.copy { + ignoreIncoming.clear() + ignoreIncoming.addAll(list.filter { it != 0 }) + } + }, ) } @@ -248,7 +241,7 @@ fun LoRaConfigItemList( title = stringResource(R.string.sx126x_rx_boosted_gain), checked = loraInput.sx126XRxBoostedGain, enabled = enabled, - onCheckedChange = { loraInput = loraInput.copy { sx126XRxBoostedGain = it } } + onCheckedChange = { loraInput = loraInput.copy { sx126XRxBoostedGain = it } }, ) } item { HorizontalDivider() } @@ -257,11 +250,16 @@ fun LoRaConfigItemList( var isFocused by remember { mutableStateOf(false) } EditTextPreference( title = stringResource(R.string.override_frequency_mhz), - value = if (isFocused || loraInput.overrideFrequency != 0f) loraInput.overrideFrequency else primaryChannel.radioFreq, + value = + if (isFocused || loraInput.overrideFrequency != 0f) { + loraInput.overrideFrequency + } else { + primaryChannel.radioFreq + }, enabled = enabled, keyboardActions = KeyboardActions(onDone = { focusManager.clearFocus() }), onFocusChanged = { isFocused = it.isFocused }, - onValueChanged = { loraInput = loraInput.copy { overrideFrequency = it } } + onValueChanged = { loraInput = loraInput.copy { overrideFrequency = it } }, ) } @@ -271,7 +269,7 @@ fun LoRaConfigItemList( title = stringResource(R.string.pa_fan_disabled), checked = loraInput.paFanDisabled, enabled = enabled, - onCheckedChange = { loraInput = loraInput.copy { paFanDisabled = it } } + onCheckedChange = { loraInput = loraInput.copy { paFanDisabled = it } }, ) } item { HorizontalDivider() } @@ -282,7 +280,7 @@ fun LoRaConfigItemList( title = stringResource(R.string.ignore_mqtt), checked = loraInput.ignoreMqtt, enabled = enabled, - onCheckedChange = { loraInput = loraInput.copy { ignoreMqtt = it } } + onCheckedChange = { loraInput = loraInput.copy { ignoreMqtt = it } }, ) } item { HorizontalDivider() } @@ -292,7 +290,7 @@ fun LoRaConfigItemList( title = stringResource(R.string.ok_to_mqtt), checked = loraInput.configOkToMqtt, enabled = enabled, - onCheckedChange = { loraInput = loraInput.copy { configOkToMqtt = it } } + onCheckedChange = { loraInput = loraInput.copy { configOkToMqtt = it } }, ) } item { HorizontalDivider() } @@ -307,7 +305,7 @@ fun LoRaConfigItemList( onSaveClicked = { focusManager.clearFocus() onSaveClicked(loraInput) - } + }, ) } } @@ -320,6 +318,6 @@ private fun LoRaConfigPreview() { loraConfig = Channel.default.loraConfig, primarySettings = Channel.default.settings, enabled = true, - onSaveClicked = { }, + onSaveClicked = {}, ) } diff --git a/app/src/main/java/com/geeksville/mesh/ui/radioconfig/components/MQTTConfigItemList.kt b/app/src/main/java/com/geeksville/mesh/ui/settings/radio/components/MQTTConfigItemList.kt similarity index 98% rename from app/src/main/java/com/geeksville/mesh/ui/radioconfig/components/MQTTConfigItemList.kt rename to app/src/main/java/com/geeksville/mesh/ui/settings/radio/components/MQTTConfigItemList.kt index 9a29a9432..3e616d9cd 100644 --- a/app/src/main/java/com/geeksville/mesh/ui/radioconfig/components/MQTTConfigItemList.kt +++ b/app/src/main/java/com/geeksville/mesh/ui/settings/radio/components/MQTTConfigItemList.kt @@ -17,7 +17,7 @@ @file:Suppress("LongMethod") -package com.geeksville.mesh.ui.radioconfig.components +package com.geeksville.mesh.ui.settings.radio.components import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.lazy.LazyColumn @@ -46,7 +46,7 @@ import com.geeksville.mesh.ui.common.components.EditTextPreference import com.geeksville.mesh.ui.common.components.PreferenceCategory import com.geeksville.mesh.ui.common.components.PreferenceFooter import com.geeksville.mesh.ui.common.components.SwitchPreference -import com.geeksville.mesh.ui.radioconfig.RadioConfigViewModel +import com.geeksville.mesh.ui.settings.radio.RadioConfigViewModel @Composable fun MQTTConfigScreen(viewModel: RadioConfigViewModel = hiltViewModel()) { diff --git a/app/src/main/java/com/geeksville/mesh/ui/radioconfig/components/MapReportingPreference.kt b/app/src/main/java/com/geeksville/mesh/ui/settings/radio/components/MapReportingPreference.kt similarity index 83% rename from app/src/main/java/com/geeksville/mesh/ui/radioconfig/components/MapReportingPreference.kt rename to app/src/main/java/com/geeksville/mesh/ui/settings/radio/components/MapReportingPreference.kt index a0a0d2eec..7cc517953 100644 --- a/app/src/main/java/com/geeksville/mesh/ui/radioconfig/components/MapReportingPreference.kt +++ b/app/src/main/java/com/geeksville/mesh/ui/settings/radio/components/MapReportingPreference.kt @@ -15,7 +15,7 @@ * along with this program. If not, see . */ -package com.geeksville.mesh.ui.radioconfig.components +package com.geeksville.mesh.ui.settings.radio.components import androidx.compose.animation.AnimatedVisibility import androidx.compose.foundation.layout.Column @@ -48,8 +48,9 @@ import com.geeksville.mesh.util.DistanceUnit import com.geeksville.mesh.util.toDistanceString import kotlin.math.roundToInt -private const val PositionPrecisionMin = 12 -private const val PositionPrecisionMax = 15 +private const val POSITION_PRECISION_MIN = 12 +private const val POSITION_PRECISION_MAX = 15 + @Suppress("LongMethod") @Composable fun MapReportingPreference( @@ -62,13 +63,11 @@ fun MapReportingPreference( publishIntervalSecs: Int = 3600, onPublishIntervalSecsChanged: (Int) -> Unit = {}, enabled: Boolean, - focusManager: FocusManager + focusManager: FocusManager, ) { Column { var showMapReportingWarning by rememberSaveable { mutableStateOf(mapReportingEnabled) } - LaunchedEffect(mapReportingEnabled) { - showMapReportingWarning = mapReportingEnabled - } + LaunchedEffect(mapReportingEnabled) { showMapReportingWarning = mapReportingEnabled } SwitchPreference( title = stringResource(R.string.map_reporting), summary = stringResource(R.string.map_reporting_summary), @@ -81,21 +80,13 @@ fun MapReportingPreference( } else if (!checked) { onMapReportingEnabledChanged(false) } - } + }, ) AnimatedVisibility(showMapReportingWarning) { - Card( - modifier = Modifier.padding(16.dp), - ) { - Text( - text = stringResource(R.string.map_reporting_consent_header), - modifier = Modifier.padding(16.dp), - ) + Card(modifier = Modifier.padding(16.dp)) { + Text(text = stringResource(R.string.map_reporting_consent_header), modifier = Modifier.padding(16.dp)) HorizontalDivider() - Text( - stringResource(R.string.map_reporting_consent_text), - modifier = Modifier.padding(16.dp) - ) + Text(stringResource(R.string.map_reporting_consent_text), modifier = Modifier.padding(16.dp)) SwitchPreference( title = stringResource(R.string.i_agree), @@ -118,18 +109,14 @@ fun MapReportingPreference( value = positionPrecision.toFloat(), onValueChange = { onPositionPrecisionChanged(it.roundToInt()) }, enabled = enabled, - valueRange = PositionPrecisionMin.toFloat()..PositionPrecisionMax.toFloat(), - steps = PositionPrecisionMax - PositionPrecisionMin - 1, + valueRange = POSITION_PRECISION_MIN.toFloat()..POSITION_PRECISION_MAX.toFloat(), + steps = POSITION_PRECISION_MAX - POSITION_PRECISION_MIN - 1, ) val precisionMeters = precisionBitsToMeters(positionPrecision).toInt() val unit = DistanceUnit.Companion.getFromLocale() Text( text = precisionMeters.toDistanceString(unit), - modifier = Modifier.Companion.padding( - start = 16.dp, - end = 16.dp, - bottom = 16.dp - ), + modifier = Modifier.Companion.padding(start = 16.dp, end = 16.dp, bottom = 16.dp), fontSize = MaterialTheme.typography.bodyLarge.fontSize, overflow = TextOverflow.Companion.Ellipsis, maxLines = 1, @@ -161,6 +148,6 @@ fun MapReportingPreview() { positionPrecision = 5, onPositionPrecisionChanged = {}, enabled = true, - focusManager = focusManager + focusManager = focusManager, ) } diff --git a/app/src/main/java/com/geeksville/mesh/ui/radioconfig/components/NeighborInfoConfigItemList.kt b/app/src/main/java/com/geeksville/mesh/ui/settings/radio/components/NeighborInfoConfigItemList.kt similarity index 83% rename from app/src/main/java/com/geeksville/mesh/ui/radioconfig/components/NeighborInfoConfigItemList.kt rename to app/src/main/java/com/geeksville/mesh/ui/settings/radio/components/NeighborInfoConfigItemList.kt index 45b6c8f69..54de7fc60 100644 --- a/app/src/main/java/com/geeksville/mesh/ui/radioconfig/components/NeighborInfoConfigItemList.kt +++ b/app/src/main/java/com/geeksville/mesh/ui/settings/radio/components/NeighborInfoConfigItemList.kt @@ -15,7 +15,7 @@ * along with this program. If not, see . */ -package com.geeksville.mesh.ui.radioconfig.components +package com.geeksville.mesh.ui.settings.radio.components import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.lazy.LazyColumn @@ -40,19 +40,14 @@ import com.geeksville.mesh.ui.common.components.EditTextPreference import com.geeksville.mesh.ui.common.components.PreferenceCategory import com.geeksville.mesh.ui.common.components.PreferenceFooter import com.geeksville.mesh.ui.common.components.SwitchPreference -import com.geeksville.mesh.ui.radioconfig.RadioConfigViewModel +import com.geeksville.mesh.ui.settings.radio.RadioConfigViewModel @Composable -fun NeighborInfoConfigScreen( - viewModel: RadioConfigViewModel = hiltViewModel(), -) { +fun NeighborInfoConfigScreen(viewModel: RadioConfigViewModel = hiltViewModel()) { val state by viewModel.radioConfigState.collectAsStateWithLifecycle() if (state.responseState.isWaiting()) { - PacketResponseStateDialog( - state = state.responseState, - onDismiss = viewModel::clearPacketResponse, - ) + PacketResponseStateDialog(state = state.responseState, onDismiss = viewModel::clearPacketResponse) } NeighborInfoConfigItemList( @@ -61,7 +56,7 @@ fun NeighborInfoConfigScreen( onSaveClicked = { neighborInfoInput -> val config = moduleConfig { neighborInfo = neighborInfoInput } viewModel.setModuleConfig(config) - } + }, ) } @@ -74,9 +69,7 @@ fun NeighborInfoConfigItemList( val focusManager = LocalFocusManager.current var neighborInfoInput by rememberSaveable { mutableStateOf(neighborInfoConfig) } - LazyColumn( - modifier = Modifier.fillMaxSize() - ) { + LazyColumn(modifier = Modifier.fillMaxSize()) { item { PreferenceCategory(text = stringResource(R.string.neighbor_info_config)) } item { @@ -84,9 +77,7 @@ fun NeighborInfoConfigItemList( title = stringResource(R.string.neighbor_info_enabled), checked = neighborInfoInput.enabled, enabled = enabled, - onCheckedChange = { - neighborInfoInput = neighborInfoInput.copy { this.enabled = it } - } + onCheckedChange = { neighborInfoInput = neighborInfoInput.copy { this.enabled = it } }, ) } item { HorizontalDivider() } @@ -97,9 +88,7 @@ fun NeighborInfoConfigItemList( value = neighborInfoInput.updateInterval, enabled = enabled, keyboardActions = KeyboardActions(onDone = { focusManager.clearFocus() }), - onValueChanged = { - neighborInfoInput = neighborInfoInput.copy { updateInterval = it } - } + onValueChanged = { neighborInfoInput = neighborInfoInput.copy { updateInterval = it } }, ) } @@ -109,9 +98,7 @@ fun NeighborInfoConfigItemList( summary = stringResource(id = R.string.config_device_transmitOverLora_summary), checked = neighborInfoInput.transmitOverLora, enabled = enabled, - onCheckedChange = { - neighborInfoInput = neighborInfoInput.copy { transmitOverLora = it } - } + onCheckedChange = { neighborInfoInput = neighborInfoInput.copy { transmitOverLora = it } }, ) HorizontalDivider() } @@ -126,7 +113,7 @@ fun NeighborInfoConfigItemList( onSaveClicked = { focusManager.clearFocus() onSaveClicked(neighborInfoInput) - } + }, ) } } @@ -138,6 +125,6 @@ private fun NeighborInfoConfigPreview() { NeighborInfoConfigItemList( neighborInfoConfig = ModuleConfigProtos.ModuleConfig.NeighborInfoConfig.getDefaultInstance(), enabled = true, - onSaveClicked = { }, + onSaveClicked = {}, ) } diff --git a/app/src/main/java/com/geeksville/mesh/ui/radioconfig/components/NetworkConfigItemList.kt b/app/src/main/java/com/geeksville/mesh/ui/settings/radio/components/NetworkConfigItemList.kt similarity index 77% rename from app/src/main/java/com/geeksville/mesh/ui/radioconfig/components/NetworkConfigItemList.kt rename to app/src/main/java/com/geeksville/mesh/ui/settings/radio/components/NetworkConfigItemList.kt index 2827ebbf9..bad4fa122 100644 --- a/app/src/main/java/com/geeksville/mesh/ui/radioconfig/components/NetworkConfigItemList.kt +++ b/app/src/main/java/com/geeksville/mesh/ui/settings/radio/components/NetworkConfigItemList.kt @@ -15,7 +15,7 @@ * along with this program. If not, see . */ -package com.geeksville.mesh.ui.radioconfig.components +package com.geeksville.mesh.ui.settings.radio.components import androidx.activity.compose.rememberLauncherForActivityResult import androidx.compose.foundation.layout.fillMaxSize @@ -54,30 +54,20 @@ import com.geeksville.mesh.ui.common.components.PreferenceCategory import com.geeksville.mesh.ui.common.components.PreferenceFooter import com.geeksville.mesh.ui.common.components.SimpleAlertDialog import com.geeksville.mesh.ui.common.components.SwitchPreference -import com.geeksville.mesh.ui.radioconfig.RadioConfigViewModel +import com.geeksville.mesh.ui.settings.radio.RadioConfigViewModel import com.journeyapps.barcodescanner.ScanContract import com.journeyapps.barcodescanner.ScanOptions @Composable -private fun ScanErrorDialog( - onDismiss: () -> Unit = {} -) = SimpleAlertDialog( - title = R.string.error, - text = R.string.wifi_qr_code_error, - onDismiss = onDismiss, -) +private fun ScanErrorDialog(onDismiss: () -> Unit = {}) = + SimpleAlertDialog(title = R.string.error, text = R.string.wifi_qr_code_error, onDismiss = onDismiss) @Composable -fun NetworkConfigScreen( - viewModel: RadioConfigViewModel = hiltViewModel(), -) { +fun NetworkConfigScreen(viewModel: RadioConfigViewModel = hiltViewModel()) { val state by viewModel.radioConfigState.collectAsStateWithLifecycle() if (state.responseState.isWaiting()) { - PacketResponseStateDialog( - state = state.responseState, - onDismiss = viewModel::clearPacketResponse, - ) + PacketResponseStateDialog(state = state.responseState, onDismiss = viewModel::clearPacketResponse) } NetworkConfigItemList( @@ -88,13 +78,13 @@ fun NetworkConfigScreen( onSaveClicked = { networkInput -> val config = config { network = networkInput } viewModel.setConfig(config) - } + }, ) } -private fun extractWifiCredentials(qrCode: String) = Regex("""WIFI:S:(.*?);.*?P:(.*?);""") - .find(qrCode)?.destructured - ?.let { (ssid, password) -> ssid to password } ?: (null to null) +private fun extractWifiCredentials(qrCode: String) = + Regex("""WIFI:S:(.*?);.*?P:(.*?);""").find(qrCode)?.destructured?.let { (ssid, password) -> ssid to password } + ?: (null to null) @Suppress("LongMethod", "CyclomaticComplexMethod") @Composable @@ -113,33 +103,34 @@ fun NetworkConfigItemList( ScanErrorDialog { showScanErrorDialog = false } } - val barcodeLauncher = rememberLauncherForActivityResult(ScanContract()) { result -> - if (result.contents != null) { - val (ssid, psk) = extractWifiCredentials(result.contents) - if (ssid != null && psk != null) { - networkInput = networkInput.copy { - wifiSsid = ssid - wifiPsk = psk + val barcodeLauncher = + rememberLauncherForActivityResult(ScanContract()) { result -> + if (result.contents != null) { + val (ssid, psk) = extractWifiCredentials(result.contents) + if (ssid != null && psk != null) { + networkInput = + networkInput.copy { + wifiSsid = ssid + wifiPsk = psk + } + } else { + showScanErrorDialog = true } - } else { - showScanErrorDialog = true } } - } fun zxingScan() { - val zxingScan = ScanOptions().apply { - setCameraId(0) - setPrompt("") - setBeepEnabled(false) - setDesiredBarcodeFormats(ScanOptions.QR_CODE) - } + val zxingScan = + ScanOptions().apply { + setCameraId(0) + setPrompt("") + setBeepEnabled(false) + setDesiredBarcodeFormats(ScanOptions.QR_CODE) + } barcodeLauncher.launch(zxingScan) } - LazyColumn( - modifier = Modifier.fillMaxSize() - ) { + LazyColumn(modifier = Modifier.fillMaxSize()) { item { PreferenceCategory(text = stringResource(R.string.network_config)) } item { @@ -147,7 +138,7 @@ fun NetworkConfigItemList( title = stringResource(R.string.wifi_enabled), checked = networkInput.wifiEnabled, enabled = enabled && hasWifi, - onCheckedChange = { networkInput = networkInput.copy { wifiEnabled = it } } + onCheckedChange = { networkInput = networkInput.copy { wifiEnabled = it } }, ) HorizontalDivider() } @@ -159,13 +150,10 @@ fun NetworkConfigItemList( maxSize = 32, // wifi_ssid max_size:33 enabled = enabled && hasWifi, isError = false, - keyboardOptions = KeyboardOptions.Default.copy( - keyboardType = KeyboardType.Text, imeAction = ImeAction.Done - ), + keyboardOptions = + KeyboardOptions.Default.copy(keyboardType = KeyboardType.Text, imeAction = ImeAction.Done), keyboardActions = KeyboardActions(onDone = { focusManager.clearFocus() }), - onValueChanged = { - networkInput = networkInput.copy { wifiSsid = it } - } + onValueChanged = { networkInput = networkInput.copy { wifiSsid = it } }, ) } @@ -176,17 +164,14 @@ fun NetworkConfigItemList( maxSize = 64, // wifi_psk max_size:65 enabled = enabled && hasWifi, keyboardActions = KeyboardActions(onDone = { focusManager.clearFocus() }), - onValueChanged = { networkInput = networkInput.copy { wifiPsk = it } } + onValueChanged = { networkInput = networkInput.copy { wifiPsk = it } }, ) } item { Button( onClick = { zxingScan() }, - modifier = Modifier - .fillMaxWidth() - .padding(vertical = 8.dp) - .height(48.dp), + modifier = Modifier.fillMaxWidth().padding(vertical = 8.dp).height(48.dp), enabled = enabled && hasWifi, ) { Text(text = stringResource(R.string.wifi_qr_code_scan)) @@ -198,7 +183,7 @@ fun NetworkConfigItemList( title = stringResource(R.string.ethernet_enabled), checked = networkInput.ethEnabled, enabled = enabled && hasEthernet, - onCheckedChange = { networkInput = networkInput.copy { ethEnabled = it } } + onCheckedChange = { networkInput = networkInput.copy { ethEnabled = it } }, ) HorizontalDivider() } @@ -210,13 +195,10 @@ fun NetworkConfigItemList( maxSize = 32, // ntp_server max_size:33 enabled = enabled, isError = networkInput.ntpServer.isEmpty(), - keyboardOptions = KeyboardOptions.Default.copy( - keyboardType = KeyboardType.Uri, imeAction = ImeAction.Done - ), + keyboardOptions = + KeyboardOptions.Default.copy(keyboardType = KeyboardType.Uri, imeAction = ImeAction.Done), keyboardActions = KeyboardActions(onDone = { focusManager.clearFocus() }), - onValueChanged = { - networkInput = networkInput.copy { ntpServer = it } - } + onValueChanged = { networkInput = networkInput.copy { ntpServer = it } }, ) } @@ -227,13 +209,10 @@ fun NetworkConfigItemList( maxSize = 32, // rsyslog_server max_size:33 enabled = enabled, isError = false, - keyboardOptions = KeyboardOptions.Default.copy( - keyboardType = KeyboardType.Uri, imeAction = ImeAction.Done - ), + keyboardOptions = + KeyboardOptions.Default.copy(keyboardType = KeyboardType.Uri, imeAction = ImeAction.Done), keyboardActions = KeyboardActions(onDone = { focusManager.clearFocus() }), - onValueChanged = { - networkInput = networkInput.copy { rsyslogServer = it } - } + onValueChanged = { networkInput = networkInput.copy { rsyslogServer = it } }, ) } @@ -241,11 +220,12 @@ fun NetworkConfigItemList( DropDownPreference( title = stringResource(R.string.ipv4_mode), enabled = enabled, - items = NetworkConfig.AddressMode.entries + items = + NetworkConfig.AddressMode.entries .filter { it != NetworkConfig.AddressMode.UNRECOGNIZED } .map { it to it.name }, selectedItem = networkInput.addressMode, - onItemSelected = { networkInput = networkInput.copy { addressMode = it } } + onItemSelected = { networkInput = networkInput.copy { addressMode = it } }, ) HorizontalDivider() } @@ -259,7 +239,7 @@ fun NetworkConfigItemList( onValueChanged = { val ipv4 = networkInput.ipv4Config.copy { ip = it } networkInput = networkInput.copy { ipv4Config = ipv4 } - } + }, ) } @@ -272,7 +252,7 @@ fun NetworkConfigItemList( onValueChanged = { val ipv4 = networkInput.ipv4Config.copy { gateway = it } networkInput = networkInput.copy { ipv4Config = ipv4 } - } + }, ) } @@ -285,7 +265,7 @@ fun NetworkConfigItemList( onValueChanged = { val ipv4 = networkInput.ipv4Config.copy { subnet = it } networkInput = networkInput.copy { ipv4Config = ipv4 } - } + }, ) } @@ -298,14 +278,12 @@ fun NetworkConfigItemList( onValueChanged = { val ipv4 = networkInput.ipv4Config.copy { dns = it } networkInput = networkInput.copy { ipv4Config = ipv4 } - } + }, ) } item { HorizontalDivider() } if (hasEthernet || hasWifi) { - item { - PreferenceCategory(text = stringResource(R.string.udp_config)) - } + item { PreferenceCategory(text = stringResource(R.string.udp_config)) } item { SwitchPreference( @@ -313,11 +291,8 @@ fun NetworkConfigItemList( checked = networkInput.enabledProtocols == 1, enabled = enabled, onCheckedChange = { - networkInput = - networkInput.copy { - if (it) enabledProtocols = 1 else enabledProtocols = 0 - } - } + networkInput = networkInput.copy { if (it) enabledProtocols = 1 else enabledProtocols = 0 } + }, ) } @@ -333,7 +308,7 @@ fun NetworkConfigItemList( onSaveClicked = { focusManager.clearFocus() onSaveClicked(networkInput) - } + }, ) } } @@ -347,7 +322,7 @@ private fun NetworkConfigPreview() { hasEthernet = true, networkConfig = NetworkConfig.getDefaultInstance(), enabled = true, - onSaveClicked = { }, + onSaveClicked = {}, ) } diff --git a/app/src/main/java/com/geeksville/mesh/ui/radioconfig/components/PacketResponseStateDialog.kt b/app/src/main/java/com/geeksville/mesh/ui/settings/radio/components/PacketResponseStateDialog.kt similarity index 68% rename from app/src/main/java/com/geeksville/mesh/ui/radioconfig/components/PacketResponseStateDialog.kt rename to app/src/main/java/com/geeksville/mesh/ui/settings/radio/components/PacketResponseStateDialog.kt index b3428b24f..1776d6ba0 100644 --- a/app/src/main/java/com/geeksville/mesh/ui/radioconfig/components/PacketResponseStateDialog.kt +++ b/app/src/main/java/com/geeksville/mesh/ui/settings/radio/components/PacketResponseStateDialog.kt @@ -15,7 +15,7 @@ * along with this program. If not, see . */ -package com.geeksville.mesh.ui.radioconfig.components +package com.geeksville.mesh.ui.settings.radio.components import androidx.activity.compose.LocalOnBackPressedDispatcherOwner import androidx.compose.animation.core.animateFloatAsState @@ -37,35 +37,24 @@ import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import com.geeksville.mesh.R -import com.geeksville.mesh.ui.radioconfig.ResponseState +import com.geeksville.mesh.ui.settings.radio.ResponseState @Composable -fun PacketResponseStateDialog( - state: ResponseState, - onDismiss: () -> Unit = {}, - onComplete: () -> Unit = {}, -) { +fun PacketResponseStateDialog(state: ResponseState, onDismiss: () -> Unit = {}, onComplete: () -> Unit = {}) { val backDispatcher = LocalOnBackPressedDispatcherOwner.current?.onBackPressedDispatcher AlertDialog( onDismissRequest = {}, shape = RoundedCornerShape(16.dp), title = { - Column( - modifier = Modifier.fillMaxWidth(), - horizontalAlignment = Alignment.CenterHorizontally - ) { + Column(modifier = Modifier.fillMaxWidth(), horizontalAlignment = Alignment.CenterHorizontally) { if (state is ResponseState.Loading) { - val progress by animateFloatAsState( - targetValue = state.completed.toFloat() / state.total.toFloat(), - label = "progress", - ) + val progress by + animateFloatAsState( + targetValue = state.completed.toFloat() / state.total.toFloat(), + label = "progress", + ) Text("%.0f%%".format(progress * 100)) - LinearProgressIndicator( - progress = progress, - modifier = Modifier - .fillMaxWidth() - .padding(top = 8.dp), - ) + LinearProgressIndicator(progress = progress, modifier = Modifier.fillMaxWidth().padding(top = 8.dp)) if (state.total == state.completed) onComplete() } if (state is ResponseState.Success) { @@ -79,10 +68,8 @@ fun PacketResponseStateDialog( }, confirmButton = { Row( - modifier = Modifier - .fillMaxWidth() - .padding(start = 24.dp, end = 24.dp, bottom = 16.dp), - horizontalArrangement = Arrangement.Center + modifier = Modifier.fillMaxWidth().padding(start = 24.dp, end = 24.dp, bottom = 16.dp), + horizontalArrangement = Arrangement.Center, ) { Button( onClick = { @@ -91,20 +78,17 @@ fun PacketResponseStateDialog( backDispatcher?.onBackPressed() } }, - modifier = Modifier.padding(top = 16.dp) - ) { Text(stringResource(R.string.close)) } + modifier = Modifier.padding(top = 16.dp), + ) { + Text(stringResource(R.string.close)) + } } - } + }, ) } @Preview(showBackground = true) @Composable private fun PacketResponseStateDialogPreview() { - PacketResponseStateDialog( - state = ResponseState.Loading( - total = 17, - completed = 5, - ), - ) + PacketResponseStateDialog(state = ResponseState.Loading(total = 17, completed = 5)) } diff --git a/app/src/main/java/com/geeksville/mesh/ui/radioconfig/components/PaxcounterConfigItemList.kt b/app/src/main/java/com/geeksville/mesh/ui/settings/radio/components/PaxcounterConfigItemList.kt similarity index 82% rename from app/src/main/java/com/geeksville/mesh/ui/radioconfig/components/PaxcounterConfigItemList.kt rename to app/src/main/java/com/geeksville/mesh/ui/settings/radio/components/PaxcounterConfigItemList.kt index ede0da156..48ef0923c 100644 --- a/app/src/main/java/com/geeksville/mesh/ui/radioconfig/components/PaxcounterConfigItemList.kt +++ b/app/src/main/java/com/geeksville/mesh/ui/settings/radio/components/PaxcounterConfigItemList.kt @@ -15,7 +15,7 @@ * along with this program. If not, see . */ -package com.geeksville.mesh.ui.radioconfig.components +package com.geeksville.mesh.ui.settings.radio.components import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.lazy.LazyColumn @@ -40,19 +40,14 @@ import com.geeksville.mesh.ui.common.components.EditTextPreference import com.geeksville.mesh.ui.common.components.PreferenceCategory import com.geeksville.mesh.ui.common.components.PreferenceFooter import com.geeksville.mesh.ui.common.components.SwitchPreference -import com.geeksville.mesh.ui.radioconfig.RadioConfigViewModel +import com.geeksville.mesh.ui.settings.radio.RadioConfigViewModel @Composable -fun PaxcounterConfigScreen( - viewModel: RadioConfigViewModel = hiltViewModel(), -) { +fun PaxcounterConfigScreen(viewModel: RadioConfigViewModel = hiltViewModel()) { val state by viewModel.radioConfigState.collectAsStateWithLifecycle() if (state.responseState.isWaiting()) { - PacketResponseStateDialog( - state = state.responseState, - onDismiss = viewModel::clearPacketResponse, - ) + PacketResponseStateDialog(state = state.responseState, onDismiss = viewModel::clearPacketResponse) } PaxcounterConfigItemList( @@ -61,7 +56,7 @@ fun PaxcounterConfigScreen( onSaveClicked = { paxcounterConfigInput -> val config = moduleConfig { paxcounter = paxcounterConfigInput } viewModel.setModuleConfig(config) - } + }, ) } @@ -75,9 +70,7 @@ fun PaxcounterConfigItemList( val focusManager = LocalFocusManager.current var paxcounterInput by rememberSaveable { mutableStateOf(paxcounterConfig) } - LazyColumn( - modifier = Modifier.fillMaxSize() - ) { + LazyColumn(modifier = Modifier.fillMaxSize()) { item { PreferenceCategory(text = stringResource(R.string.paxcounter_config)) } item { @@ -85,9 +78,7 @@ fun PaxcounterConfigItemList( title = stringResource(R.string.paxcounter_enabled), checked = paxcounterInput.enabled, enabled = enabled, - onCheckedChange = { - paxcounterInput = paxcounterInput.copy { this.enabled = it } - } + onCheckedChange = { paxcounterInput = paxcounterInput.copy { this.enabled = it } }, ) } item { HorizontalDivider() } @@ -98,9 +89,7 @@ fun PaxcounterConfigItemList( value = paxcounterInput.paxcounterUpdateInterval, enabled = enabled, keyboardActions = KeyboardActions(onDone = { focusManager.clearFocus() }), - onValueChanged = { - paxcounterInput = paxcounterInput.copy { paxcounterUpdateInterval = it } - } + onValueChanged = { paxcounterInput = paxcounterInput.copy { paxcounterUpdateInterval = it } }, ) } @@ -110,9 +99,7 @@ fun PaxcounterConfigItemList( value = paxcounterInput.wifiThreshold, enabled = enabled, keyboardActions = KeyboardActions(onDone = { focusManager.clearFocus() }), - onValueChanged = { - paxcounterInput = paxcounterInput.copy { wifiThreshold = it } - } + onValueChanged = { paxcounterInput = paxcounterInput.copy { wifiThreshold = it } }, ) } @@ -122,9 +109,7 @@ fun PaxcounterConfigItemList( value = paxcounterInput.bleThreshold, enabled = enabled, keyboardActions = KeyboardActions(onDone = { focusManager.clearFocus() }), - onValueChanged = { - paxcounterInput = paxcounterInput.copy { bleThreshold = it } - } + onValueChanged = { paxcounterInput = paxcounterInput.copy { bleThreshold = it } }, ) } @@ -138,7 +123,7 @@ fun PaxcounterConfigItemList( onSaveClicked = { focusManager.clearFocus() onSaveClicked(paxcounterInput) - } + }, ) } } @@ -150,6 +135,6 @@ private fun PaxcounterConfigPreview() { PaxcounterConfigItemList( paxcounterConfig = ModuleConfigProtos.ModuleConfig.PaxcounterConfig.getDefaultInstance(), enabled = true, - onSaveClicked = { }, + onSaveClicked = {}, ) } diff --git a/app/src/main/java/com/geeksville/mesh/ui/radioconfig/components/PositionConfigItemList.kt b/app/src/main/java/com/geeksville/mesh/ui/settings/radio/components/PositionConfigItemList.kt similarity index 99% rename from app/src/main/java/com/geeksville/mesh/ui/radioconfig/components/PositionConfigItemList.kt rename to app/src/main/java/com/geeksville/mesh/ui/settings/radio/components/PositionConfigItemList.kt index b1fc16787..121647b26 100644 --- a/app/src/main/java/com/geeksville/mesh/ui/radioconfig/components/PositionConfigItemList.kt +++ b/app/src/main/java/com/geeksville/mesh/ui/settings/radio/components/PositionConfigItemList.kt @@ -15,7 +15,7 @@ * along with this program. If not, see . */ -package com.geeksville.mesh.ui.radioconfig.components +package com.geeksville.mesh.ui.settings.radio.components import android.Manifest import android.annotation.SuppressLint @@ -54,7 +54,7 @@ import com.geeksville.mesh.ui.common.components.EditTextPreference import com.geeksville.mesh.ui.common.components.PreferenceCategory import com.geeksville.mesh.ui.common.components.PreferenceFooter import com.geeksville.mesh.ui.common.components.SwitchPreference -import com.geeksville.mesh.ui.radioconfig.RadioConfigViewModel +import com.geeksville.mesh.ui.settings.radio.RadioConfigViewModel import com.google.accompanist.permissions.ExperimentalPermissionsApi import com.google.accompanist.permissions.rememberPermissionState import kotlinx.coroutines.launch diff --git a/app/src/main/java/com/geeksville/mesh/ui/radioconfig/components/PowerConfigItemList.kt b/app/src/main/java/com/geeksville/mesh/ui/settings/radio/components/PowerConfigItemList.kt similarity index 98% rename from app/src/main/java/com/geeksville/mesh/ui/radioconfig/components/PowerConfigItemList.kt rename to app/src/main/java/com/geeksville/mesh/ui/settings/radio/components/PowerConfigItemList.kt index 1406a80e9..c5d304c5a 100644 --- a/app/src/main/java/com/geeksville/mesh/ui/radioconfig/components/PowerConfigItemList.kt +++ b/app/src/main/java/com/geeksville/mesh/ui/settings/radio/components/PowerConfigItemList.kt @@ -15,7 +15,7 @@ * along with this program. If not, see . */ -package com.geeksville.mesh.ui.radioconfig.components +package com.geeksville.mesh.ui.settings.radio.components import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.lazy.LazyColumn @@ -40,7 +40,7 @@ import com.geeksville.mesh.ui.common.components.EditTextPreference import com.geeksville.mesh.ui.common.components.PreferenceCategory import com.geeksville.mesh.ui.common.components.PreferenceFooter import com.geeksville.mesh.ui.common.components.SwitchPreference -import com.geeksville.mesh.ui.radioconfig.RadioConfigViewModel +import com.geeksville.mesh.ui.settings.radio.RadioConfigViewModel @Composable fun PowerConfigScreen(viewModel: RadioConfigViewModel = hiltViewModel()) { diff --git a/app/src/main/java/com/geeksville/mesh/ui/radioconfig/components/RangeTestConfigItemList.kt b/app/src/main/java/com/geeksville/mesh/ui/settings/radio/components/RangeTestConfigItemList.kt similarity index 86% rename from app/src/main/java/com/geeksville/mesh/ui/radioconfig/components/RangeTestConfigItemList.kt rename to app/src/main/java/com/geeksville/mesh/ui/settings/radio/components/RangeTestConfigItemList.kt index e5c7a62f7..d04f7331b 100644 --- a/app/src/main/java/com/geeksville/mesh/ui/radioconfig/components/RangeTestConfigItemList.kt +++ b/app/src/main/java/com/geeksville/mesh/ui/settings/radio/components/RangeTestConfigItemList.kt @@ -15,7 +15,7 @@ * along with this program. If not, see . */ -package com.geeksville.mesh.ui.radioconfig.components +package com.geeksville.mesh.ui.settings.radio.components import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.lazy.LazyColumn @@ -40,19 +40,14 @@ import com.geeksville.mesh.ui.common.components.EditTextPreference import com.geeksville.mesh.ui.common.components.PreferenceCategory import com.geeksville.mesh.ui.common.components.PreferenceFooter import com.geeksville.mesh.ui.common.components.SwitchPreference -import com.geeksville.mesh.ui.radioconfig.RadioConfigViewModel +import com.geeksville.mesh.ui.settings.radio.RadioConfigViewModel @Composable -fun RangeTestConfigScreen( - viewModel: RadioConfigViewModel = hiltViewModel(), -) { +fun RangeTestConfigScreen(viewModel: RadioConfigViewModel = hiltViewModel()) { val state by viewModel.radioConfigState.collectAsStateWithLifecycle() if (state.responseState.isWaiting()) { - PacketResponseStateDialog( - state = state.responseState, - onDismiss = viewModel::clearPacketResponse, - ) + PacketResponseStateDialog(state = state.responseState, onDismiss = viewModel::clearPacketResponse) } RangeTestConfigItemList( @@ -61,7 +56,7 @@ fun RangeTestConfigScreen( onSaveClicked = { rangeTestInput -> val config = moduleConfig { rangeTest = rangeTestInput } viewModel.setModuleConfig(config) - } + }, ) } @@ -74,9 +69,7 @@ fun RangeTestConfigItemList( val focusManager = LocalFocusManager.current var rangeTestInput by rememberSaveable { mutableStateOf(rangeTestConfig) } - LazyColumn( - modifier = Modifier.fillMaxSize() - ) { + LazyColumn(modifier = Modifier.fillMaxSize()) { item { PreferenceCategory(text = stringResource(R.string.range_test_config)) } item { @@ -84,7 +77,7 @@ fun RangeTestConfigItemList( title = stringResource(R.string.range_test_enabled), checked = rangeTestInput.enabled, enabled = enabled, - onCheckedChange = { rangeTestInput = rangeTestInput.copy { this.enabled = it } } + onCheckedChange = { rangeTestInput = rangeTestInput.copy { this.enabled = it } }, ) } item { HorizontalDivider() } @@ -95,7 +88,7 @@ fun RangeTestConfigItemList( value = rangeTestInput.sender, enabled = enabled, keyboardActions = KeyboardActions(onDone = { focusManager.clearFocus() }), - onValueChanged = { rangeTestInput = rangeTestInput.copy { sender = it } } + onValueChanged = { rangeTestInput = rangeTestInput.copy { sender = it } }, ) } @@ -104,7 +97,7 @@ fun RangeTestConfigItemList( title = stringResource(R.string.save_csv_in_storage_esp32_only), checked = rangeTestInput.save, enabled = enabled, - onCheckedChange = { rangeTestInput = rangeTestInput.copy { save = it } } + onCheckedChange = { rangeTestInput = rangeTestInput.copy { save = it } }, ) } item { HorizontalDivider() } @@ -119,7 +112,7 @@ fun RangeTestConfigItemList( onSaveClicked = { focusManager.clearFocus() onSaveClicked(rangeTestInput) - } + }, ) } } @@ -128,9 +121,5 @@ fun RangeTestConfigItemList( @Preview(showBackground = true) @Composable private fun RangeTestConfig() { - RangeTestConfigItemList( - rangeTestConfig = RangeTestConfig.getDefaultInstance(), - enabled = true, - onSaveClicked = { }, - ) + RangeTestConfigItemList(rangeTestConfig = RangeTestConfig.getDefaultInstance(), enabled = true, onSaveClicked = {}) } diff --git a/app/src/main/java/com/geeksville/mesh/ui/radioconfig/components/RemoteHardwareConfigItemList.kt b/app/src/main/java/com/geeksville/mesh/ui/settings/radio/components/RemoteHardwareConfigItemList.kt similarity index 81% rename from app/src/main/java/com/geeksville/mesh/ui/radioconfig/components/RemoteHardwareConfigItemList.kt rename to app/src/main/java/com/geeksville/mesh/ui/settings/radio/components/RemoteHardwareConfigItemList.kt index bd72cb460..d9d727c34 100644 --- a/app/src/main/java/com/geeksville/mesh/ui/radioconfig/components/RemoteHardwareConfigItemList.kt +++ b/app/src/main/java/com/geeksville/mesh/ui/settings/radio/components/RemoteHardwareConfigItemList.kt @@ -15,7 +15,7 @@ * along with this program. If not, see . */ -package com.geeksville.mesh.ui.radioconfig.components +package com.geeksville.mesh.ui.settings.radio.components import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.lazy.LazyColumn @@ -40,19 +40,14 @@ import com.geeksville.mesh.ui.common.components.EditListPreference import com.geeksville.mesh.ui.common.components.PreferenceCategory import com.geeksville.mesh.ui.common.components.PreferenceFooter import com.geeksville.mesh.ui.common.components.SwitchPreference -import com.geeksville.mesh.ui.radioconfig.RadioConfigViewModel +import com.geeksville.mesh.ui.settings.radio.RadioConfigViewModel @Composable -fun RemoteHardwareConfigScreen( - viewModel: RadioConfigViewModel = hiltViewModel(), -) { +fun RemoteHardwareConfigScreen(viewModel: RadioConfigViewModel = hiltViewModel()) { val state by viewModel.radioConfigState.collectAsStateWithLifecycle() if (state.responseState.isWaiting()) { - PacketResponseStateDialog( - state = state.responseState, - onDismiss = viewModel::clearPacketResponse, - ) + PacketResponseStateDialog(state = state.responseState, onDismiss = viewModel::clearPacketResponse) } RemoteHardwareConfigItemList( @@ -61,7 +56,7 @@ fun RemoteHardwareConfigScreen( onSaveClicked = { remoteHardwareInput -> val config = moduleConfig { remoteHardware = remoteHardwareInput } viewModel.setModuleConfig(config) - } + }, ) } @@ -74,9 +69,7 @@ fun RemoteHardwareConfigItemList( val focusManager = LocalFocusManager.current var remoteHardwareInput by rememberSaveable { mutableStateOf(remoteHardwareConfig) } - LazyColumn( - modifier = Modifier.fillMaxSize() - ) { + LazyColumn(modifier = Modifier.fillMaxSize()) { item { PreferenceCategory(text = stringResource(R.string.remote_hardware_config)) } item { @@ -84,9 +77,7 @@ fun RemoteHardwareConfigItemList( title = stringResource(R.string.remote_hardware_enabled), checked = remoteHardwareInput.enabled, enabled = enabled, - onCheckedChange = { - remoteHardwareInput = remoteHardwareInput.copy { this.enabled = it } - } + onCheckedChange = { remoteHardwareInput = remoteHardwareInput.copy { this.enabled = it } }, ) } item { HorizontalDivider() } @@ -96,9 +87,7 @@ fun RemoteHardwareConfigItemList( title = stringResource(R.string.allow_undefined_pin_access), checked = remoteHardwareInput.allowUndefinedPinAccess, enabled = enabled, - onCheckedChange = { - remoteHardwareInput = remoteHardwareInput.copy { allowUndefinedPinAccess = it } - } + onCheckedChange = { remoteHardwareInput = remoteHardwareInput.copy { allowUndefinedPinAccess = it } }, ) } item { HorizontalDivider() } @@ -111,11 +100,12 @@ fun RemoteHardwareConfigItemList( enabled = enabled, keyboardActions = KeyboardActions(onDone = { focusManager.clearFocus() }), onValuesChanged = { list -> - remoteHardwareInput = remoteHardwareInput.copy { - availablePins.clear() - availablePins.addAll(list) - } - } + remoteHardwareInput = + remoteHardwareInput.copy { + availablePins.clear() + availablePins.addAll(list) + } + }, ) } @@ -129,7 +119,7 @@ fun RemoteHardwareConfigItemList( onSaveClicked = { focusManager.clearFocus() onSaveClicked(remoteHardwareInput) - } + }, ) } } @@ -141,6 +131,6 @@ private fun RemoteHardwareConfigPreview() { RemoteHardwareConfigItemList( remoteHardwareConfig = RemoteHardwareConfig.getDefaultInstance(), enabled = true, - onSaveClicked = { }, + onSaveClicked = {}, ) } diff --git a/app/src/main/java/com/geeksville/mesh/ui/radioconfig/components/SecurityConfigItemList.kt b/app/src/main/java/com/geeksville/mesh/ui/settings/radio/components/SecurityConfigItemList.kt similarity index 73% rename from app/src/main/java/com/geeksville/mesh/ui/radioconfig/components/SecurityConfigItemList.kt rename to app/src/main/java/com/geeksville/mesh/ui/settings/radio/components/SecurityConfigItemList.kt index 8dd41ffd4..5cae39f6e 100644 --- a/app/src/main/java/com/geeksville/mesh/ui/radioconfig/components/SecurityConfigItemList.kt +++ b/app/src/main/java/com/geeksville/mesh/ui/settings/radio/components/SecurityConfigItemList.kt @@ -15,7 +15,7 @@ * along with this program. If not, see . */ -package com.geeksville.mesh.ui.radioconfig.components +package com.geeksville.mesh.ui.settings.radio.components import android.app.Activity import android.content.Intent @@ -58,24 +58,19 @@ import com.geeksville.mesh.ui.common.components.PreferenceCategory import com.geeksville.mesh.ui.common.components.PreferenceFooter import com.geeksville.mesh.ui.common.components.SwitchPreference import com.geeksville.mesh.ui.node.NodeActionButton -import com.geeksville.mesh.ui.radioconfig.RadioConfigViewModel +import com.geeksville.mesh.ui.settings.radio.RadioConfigViewModel import com.geeksville.mesh.util.encodeToString import com.geeksville.mesh.util.toByteString import com.google.protobuf.ByteString import java.security.SecureRandom @Composable -fun SecurityConfigScreen( - viewModel: RadioConfigViewModel = hiltViewModel(), -) { +fun SecurityConfigScreen(viewModel: RadioConfigViewModel = hiltViewModel()) { val state by viewModel.radioConfigState.collectAsStateWithLifecycle() val node by viewModel.destNode.collectAsStateWithLifecycle() if (state.responseState.isWaiting()) { - PacketResponseStateDialog( - state = state.responseState, - onDismiss = viewModel::clearPacketResponse, - ) + PacketResponseStateDialog(state = state.responseState, onDismiss = viewModel::clearPacketResponse) } SecurityConfigItemList( @@ -86,9 +81,7 @@ fun SecurityConfigScreen( val config = config { security = securityInput } viewModel.setConfig(config) }, - onExport = { uri, securityConfig -> - viewModel.exportSecurityConfig(uri, securityConfig) - }, + onExport = { uri, securityConfig -> viewModel.exportSecurityConfig(uri, securityConfig) }, ) } @@ -114,13 +107,12 @@ fun SecurityConfigItemList( } } - val exportConfigLauncher = rememberLauncherForActivityResult( - ActivityResultContracts.StartActivityForResult() - ) { - if (it.resultCode == Activity.RESULT_OK) { - it.data?.data?.let { uri -> onExport(uri, securityConfig) } + val exportConfigLauncher = + rememberLauncherForActivityResult(ActivityResultContracts.StartActivityForResult()) { + if (it.resultCode == Activity.RESULT_OK) { + it.data?.data?.let { uri -> onExport(uri, securityConfig) } + } } - } var showKeyGenerationDialog by rememberSaveable { mutableStateOf(false) } PrivateKeyRegenerateDialog( @@ -131,7 +123,7 @@ fun SecurityConfigItemList( showKeyGenerationDialog = false onConfirm(securityInput) }, - onDismiss = { showKeyGenerationDialog = false } + onDismiss = { showKeyGenerationDialog = false }, ) var showEditSecurityConfigDialog by rememberSaveable { mutableStateOf(false) } if (showEditSecurityConfigDialog) { @@ -143,14 +135,15 @@ fun SecurityConfigItemList( TextButton( onClick = { showEditSecurityConfigDialog = false - val intent = Intent(Intent.ACTION_CREATE_DOCUMENT).apply { - addCategory(Intent.CATEGORY_OPENABLE) - type = "application/*" - putExtra( - Intent.EXTRA_TITLE, - "${user?.shortName}_keys_${System.currentTimeMillis()}.json" - ) - } + val intent = + Intent(Intent.ACTION_CREATE_DOCUMENT).apply { + addCategory(Intent.CATEGORY_OPENABLE) + type = "application/*" + putExtra( + Intent.EXTRA_TITLE, + "${user?.shortName}_keys_${System.currentTimeMillis()}.json", + ) + } exportConfigLauncher.launch(intent) }, ) { @@ -160,9 +153,7 @@ fun SecurityConfigItemList( ) } - LazyColumn( - modifier = Modifier.fillMaxSize() - ) { + LazyColumn(modifier = Modifier.fillMaxSize()) { item { PreferenceCategory(text = stringResource(R.string.security_config)) } item { @@ -177,11 +168,7 @@ fun SecurityConfigItemList( securityInput = securityInput.copy { publicKey = it } } }, - trailingIcon = { - CopyIconButton( - valueToCopy = securityInput.publicKey.encodeToString(), - ) - } + trailingIcon = { CopyIconButton(valueToCopy = securityInput.publicKey.encodeToString()) }, ) } @@ -196,11 +183,7 @@ fun SecurityConfigItemList( securityInput = securityInput.copy { privateKey = it } } }, - trailingIcon = { - CopyIconButton( - valueToCopy = securityInput.privateKey.encodeToString(), - ) - } + trailingIcon = { CopyIconButton(valueToCopy = securityInput.privateKey.encodeToString()) }, ) } @@ -210,9 +193,7 @@ fun SecurityConfigItemList( title = stringResource(R.string.regenerate_private_key), enabled = enabled, icon = Icons.TwoTone.Warning, - onClick = { - showKeyGenerationDialog = true - } + onClick = { showKeyGenerationDialog = true }, ) } @@ -222,9 +203,7 @@ fun SecurityConfigItemList( title = stringResource(R.string.export_keys), enabled = enabled, icon = Icons.TwoTone.Warning, - onClick = { - showEditSecurityConfigDialog = true - } + onClick = { showEditSecurityConfigDialog = true }, ) } @@ -236,10 +215,11 @@ fun SecurityConfigItemList( enabled = enabled, keyboardActions = KeyboardActions(onDone = { focusManager.clearFocus() }), onValuesChanged = { - securityInput = securityInput.copy { - adminKey.clear() - adminKey.addAll(it) - } + securityInput = + securityInput.copy { + adminKey.clear() + adminKey.addAll(it) + } }, ) } @@ -249,9 +229,7 @@ fun SecurityConfigItemList( title = stringResource(R.string.managed_mode), checked = securityInput.isManaged, enabled = enabled && securityInput.adminKeyCount > 0, - onCheckedChange = { - securityInput = securityInput.copy { isManaged = it } - } + onCheckedChange = { securityInput = securityInput.copy { isManaged = it } }, ) } item { HorizontalDivider() } @@ -261,7 +239,7 @@ fun SecurityConfigItemList( title = stringResource(R.string.serial_console), checked = securityInput.serialEnabled, enabled = enabled, - onCheckedChange = { securityInput = securityInput.copy { serialEnabled = it } } + onCheckedChange = { securityInput = securityInput.copy { serialEnabled = it } }, ) } item { HorizontalDivider() } @@ -271,9 +249,7 @@ fun SecurityConfigItemList( title = stringResource(R.string.debug_log_api_enabled), checked = securityInput.debugLogApiEnabled, enabled = enabled, - onCheckedChange = { - securityInput = securityInput.copy { debugLogApiEnabled = it } - } + onCheckedChange = { securityInput = securityInput.copy { debugLogApiEnabled = it } }, ) } item { HorizontalDivider() } @@ -283,9 +259,7 @@ fun SecurityConfigItemList( title = stringResource(R.string.legacy_admin_channel), checked = securityInput.adminChannelEnabled, enabled = enabled, - onCheckedChange = { - securityInput = securityInput.copy { adminChannelEnabled = it } - } + onCheckedChange = { securityInput = securityInput.copy { adminChannelEnabled = it } }, ) } item { HorizontalDivider() } @@ -300,7 +274,7 @@ fun SecurityConfigItemList( onSaveClicked = { focusManager.clearFocus() onConfirm(securityInput) - } + }, ) } } @@ -323,34 +297,27 @@ fun PrivateKeyRegenerateDialog( confirmButton = { TextButton( onClick = { - securityInput = securityInput.copy { - clearPrivateKey() - clearPublicKey() - // Generate a random "f" value - val f = ByteArray(32).apply { - SecureRandom().nextBytes(this) + securityInput = + securityInput.copy { + clearPrivateKey() + clearPublicKey() + // Generate a random "f" value + val f = ByteArray(32).apply { SecureRandom().nextBytes(this) } + // Adjust the value to make it valid as an "s" value for eval(). + // According to the specification we need to mask off the 3 + // right-most bits of f[0], mask off the left-most bit of f[31], + // and set the second to left-most bit of f[31]. + f[0] = (f[0].toInt() and 0xF8).toByte() + f[31] = ((f[31].toInt() and 0x7F) or 0x40).toByte() + privateKey = ByteString.copyFrom(f) } - // Adjust the value to make it valid as an "s" value for eval(). - // According to the specification we need to mask off the 3 - // right-most bits of f[0], mask off the left-most bit of f[31], - // and set the second to left-most bit of f[31]. - f[0] = (f[0].toInt() and 0xF8).toByte() - f[31] = ((f[31].toInt() and 0x7F) or 0x40).toByte() - privateKey = ByteString.copyFrom(f) - } onConfirm(securityInput) }, ) { Text(stringResource(R.string.okay)) } }, - dismissButton = { - TextButton( - onClick = onDismiss, - ) { - Text(stringResource(R.string.cancel)) - } - } + dismissButton = { TextButton(onClick = onDismiss) { Text(stringResource(R.string.cancel)) } }, ) } } @@ -358,9 +325,5 @@ fun PrivateKeyRegenerateDialog( @Preview(showBackground = true) @Composable private fun SecurityConfigPreview() { - SecurityConfigItemList( - securityConfig = SecurityConfig.getDefaultInstance(), - enabled = true, - onConfirm = {}, - ) + SecurityConfigItemList(securityConfig = SecurityConfig.getDefaultInstance(), enabled = true, onConfirm = {}) } diff --git a/app/src/main/java/com/geeksville/mesh/ui/radioconfig/components/SerialConfigItemList.kt b/app/src/main/java/com/geeksville/mesh/ui/settings/radio/components/SerialConfigItemList.kt similarity index 84% rename from app/src/main/java/com/geeksville/mesh/ui/radioconfig/components/SerialConfigItemList.kt rename to app/src/main/java/com/geeksville/mesh/ui/settings/radio/components/SerialConfigItemList.kt index b846f7580..ba4ff367f 100644 --- a/app/src/main/java/com/geeksville/mesh/ui/radioconfig/components/SerialConfigItemList.kt +++ b/app/src/main/java/com/geeksville/mesh/ui/settings/radio/components/SerialConfigItemList.kt @@ -15,7 +15,7 @@ * along with this program. If not, see . */ -package com.geeksville.mesh.ui.radioconfig.components +package com.geeksville.mesh.ui.settings.radio.components import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.lazy.LazyColumn @@ -41,19 +41,14 @@ import com.geeksville.mesh.ui.common.components.EditTextPreference import com.geeksville.mesh.ui.common.components.PreferenceCategory import com.geeksville.mesh.ui.common.components.PreferenceFooter import com.geeksville.mesh.ui.common.components.SwitchPreference -import com.geeksville.mesh.ui.radioconfig.RadioConfigViewModel +import com.geeksville.mesh.ui.settings.radio.RadioConfigViewModel @Composable -fun SerialConfigScreen( - viewModel: RadioConfigViewModel = hiltViewModel(), -) { +fun SerialConfigScreen(viewModel: RadioConfigViewModel = hiltViewModel()) { val state by viewModel.radioConfigState.collectAsStateWithLifecycle() if (state.responseState.isWaiting()) { - PacketResponseStateDialog( - state = state.responseState, - onDismiss = viewModel::clearPacketResponse, - ) + PacketResponseStateDialog(state = state.responseState, onDismiss = viewModel::clearPacketResponse) } SerialConfigItemList( @@ -62,22 +57,17 @@ fun SerialConfigScreen( onSaveClicked = { serialInput -> val config = moduleConfig { serial = serialInput } viewModel.setModuleConfig(config) - } + }, ) } +@Suppress("LongMethod") @Composable -fun SerialConfigItemList( - serialConfig: SerialConfig, - enabled: Boolean, - onSaveClicked: (SerialConfig) -> Unit, -) { +fun SerialConfigItemList(serialConfig: SerialConfig, enabled: Boolean, onSaveClicked: (SerialConfig) -> Unit) { val focusManager = LocalFocusManager.current var serialInput by rememberSaveable { mutableStateOf(serialConfig) } - LazyColumn( - modifier = Modifier.fillMaxSize() - ) { + LazyColumn(modifier = Modifier.fillMaxSize()) { item { PreferenceCategory(text = stringResource(R.string.serial_config)) } item { @@ -85,7 +75,7 @@ fun SerialConfigItemList( title = stringResource(R.string.serial_enabled), checked = serialInput.enabled, enabled = enabled, - onCheckedChange = { serialInput = serialInput.copy { this.enabled = it } } + onCheckedChange = { serialInput = serialInput.copy { this.enabled = it } }, ) } item { HorizontalDivider() } @@ -95,7 +85,7 @@ fun SerialConfigItemList( title = stringResource(R.string.echo_enabled), checked = serialInput.echo, enabled = enabled, - onCheckedChange = { serialInput = serialInput.copy { echo = it } } + onCheckedChange = { serialInput = serialInput.copy { echo = it } }, ) } item { HorizontalDivider() } @@ -106,7 +96,7 @@ fun SerialConfigItemList( value = serialInput.rxd, enabled = enabled, keyboardActions = KeyboardActions(onDone = { focusManager.clearFocus() }), - onValueChanged = { serialInput = serialInput.copy { rxd = it } } + onValueChanged = { serialInput = serialInput.copy { rxd = it } }, ) } @@ -116,7 +106,7 @@ fun SerialConfigItemList( value = serialInput.txd, enabled = enabled, keyboardActions = KeyboardActions(onDone = { focusManager.clearFocus() }), - onValueChanged = { serialInput = serialInput.copy { txd = it } } + onValueChanged = { serialInput = serialInput.copy { txd = it } }, ) } @@ -124,11 +114,12 @@ fun SerialConfigItemList( DropDownPreference( title = stringResource(R.string.serial_baud_rate), enabled = enabled, - items = SerialConfig.Serial_Baud.entries + items = + SerialConfig.Serial_Baud.entries .filter { it != SerialConfig.Serial_Baud.UNRECOGNIZED } .map { it to it.name }, selectedItem = serialInput.baud, - onItemSelected = { serialInput = serialInput.copy { baud = it } } + onItemSelected = { serialInput = serialInput.copy { baud = it } }, ) } item { HorizontalDivider() } @@ -139,7 +130,7 @@ fun SerialConfigItemList( value = serialInput.timeout, enabled = enabled, keyboardActions = KeyboardActions(onDone = { focusManager.clearFocus() }), - onValueChanged = { serialInput = serialInput.copy { timeout = it } } + onValueChanged = { serialInput = serialInput.copy { timeout = it } }, ) } @@ -147,11 +138,12 @@ fun SerialConfigItemList( DropDownPreference( title = stringResource(R.string.serial_mode), enabled = enabled, - items = SerialConfig.Serial_Mode.entries + items = + SerialConfig.Serial_Mode.entries .filter { it != SerialConfig.Serial_Mode.UNRECOGNIZED } .map { it to it.name }, selectedItem = serialInput.mode, - onItemSelected = { serialInput = serialInput.copy { mode = it } } + onItemSelected = { serialInput = serialInput.copy { mode = it } }, ) } item { HorizontalDivider() } @@ -161,9 +153,7 @@ fun SerialConfigItemList( title = stringResource(R.string.override_console_serial_port), checked = serialInput.overrideConsoleSerialPort, enabled = enabled, - onCheckedChange = { - serialInput = serialInput.copy { overrideConsoleSerialPort = it } - } + onCheckedChange = { serialInput = serialInput.copy { overrideConsoleSerialPort = it } }, ) } item { HorizontalDivider() } @@ -178,7 +168,7 @@ fun SerialConfigItemList( onSaveClicked = { focusManager.clearFocus() onSaveClicked(serialInput) - } + }, ) } } @@ -187,9 +177,5 @@ fun SerialConfigItemList( @Preview(showBackground = true) @Composable private fun SerialConfigPreview() { - SerialConfigItemList( - serialConfig = SerialConfig.getDefaultInstance(), - enabled = true, - onSaveClicked = { }, - ) + SerialConfigItemList(serialConfig = SerialConfig.getDefaultInstance(), enabled = true, onSaveClicked = {}) } diff --git a/app/src/main/java/com/geeksville/mesh/ui/radioconfig/components/StoreForwardConfigItemList.kt b/app/src/main/java/com/geeksville/mesh/ui/settings/radio/components/StoreForwardConfigItemList.kt similarity index 84% rename from app/src/main/java/com/geeksville/mesh/ui/radioconfig/components/StoreForwardConfigItemList.kt rename to app/src/main/java/com/geeksville/mesh/ui/settings/radio/components/StoreForwardConfigItemList.kt index e0f9e3f3d..23f9e4409 100644 --- a/app/src/main/java/com/geeksville/mesh/ui/radioconfig/components/StoreForwardConfigItemList.kt +++ b/app/src/main/java/com/geeksville/mesh/ui/settings/radio/components/StoreForwardConfigItemList.kt @@ -15,7 +15,7 @@ * along with this program. If not, see . */ -package com.geeksville.mesh.ui.radioconfig.components +package com.geeksville.mesh.ui.settings.radio.components import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.lazy.LazyColumn @@ -40,19 +40,14 @@ import com.geeksville.mesh.ui.common.components.EditTextPreference import com.geeksville.mesh.ui.common.components.PreferenceCategory import com.geeksville.mesh.ui.common.components.PreferenceFooter import com.geeksville.mesh.ui.common.components.SwitchPreference -import com.geeksville.mesh.ui.radioconfig.RadioConfigViewModel +import com.geeksville.mesh.ui.settings.radio.RadioConfigViewModel @Composable -fun StoreForwardConfigScreen( - viewModel: RadioConfigViewModel = hiltViewModel(), -) { +fun StoreForwardConfigScreen(viewModel: RadioConfigViewModel = hiltViewModel()) { val state by viewModel.radioConfigState.collectAsStateWithLifecycle() if (state.responseState.isWaiting()) { - PacketResponseStateDialog( - state = state.responseState, - onDismiss = viewModel::clearPacketResponse, - ) + PacketResponseStateDialog(state = state.responseState, onDismiss = viewModel::clearPacketResponse) } StoreForwardConfigItemList( @@ -61,7 +56,7 @@ fun StoreForwardConfigScreen( onSaveClicked = { storeForwardInput -> val config = moduleConfig { storeForward = storeForwardInput } viewModel.setModuleConfig(config) - } + }, ) } @@ -74,9 +69,7 @@ fun StoreForwardConfigItemList( val focusManager = LocalFocusManager.current var storeForwardInput by rememberSaveable { mutableStateOf(storeForwardConfig) } - LazyColumn( - modifier = Modifier.fillMaxSize() - ) { + LazyColumn(modifier = Modifier.fillMaxSize()) { item { PreferenceCategory(text = stringResource(R.string.store_forward_config)) } item { @@ -84,9 +77,7 @@ fun StoreForwardConfigItemList( title = stringResource(R.string.store_forward_enabled), checked = storeForwardInput.enabled, enabled = enabled, - onCheckedChange = { - storeForwardInput = storeForwardInput.copy { this.enabled = it } - } + onCheckedChange = { storeForwardInput = storeForwardInput.copy { this.enabled = it } }, ) } item { HorizontalDivider() } @@ -96,7 +87,7 @@ fun StoreForwardConfigItemList( title = stringResource(R.string.heartbeat), checked = storeForwardInput.heartbeat, enabled = enabled, - onCheckedChange = { storeForwardInput = storeForwardInput.copy { heartbeat = it } } + onCheckedChange = { storeForwardInput = storeForwardInput.copy { heartbeat = it } }, ) } item { HorizontalDivider() } @@ -107,7 +98,7 @@ fun StoreForwardConfigItemList( value = storeForwardInput.records, enabled = enabled, keyboardActions = KeyboardActions(onDone = { focusManager.clearFocus() }), - onValueChanged = { storeForwardInput = storeForwardInput.copy { records = it } } + onValueChanged = { storeForwardInput = storeForwardInput.copy { records = it } }, ) } @@ -117,9 +108,7 @@ fun StoreForwardConfigItemList( value = storeForwardInput.historyReturnMax, enabled = enabled, keyboardActions = KeyboardActions(onDone = { focusManager.clearFocus() }), - onValueChanged = { - storeForwardInput = storeForwardInput.copy { historyReturnMax = it } - } + onValueChanged = { storeForwardInput = storeForwardInput.copy { historyReturnMax = it } }, ) } @@ -129,9 +118,7 @@ fun StoreForwardConfigItemList( value = storeForwardInput.historyReturnWindow, enabled = enabled, keyboardActions = KeyboardActions(onDone = { focusManager.clearFocus() }), - onValueChanged = { - storeForwardInput = storeForwardInput.copy { historyReturnWindow = it } - } + onValueChanged = { storeForwardInput = storeForwardInput.copy { historyReturnWindow = it } }, ) } @@ -140,7 +127,7 @@ fun StoreForwardConfigItemList( title = stringResource(R.string.server), checked = storeForwardInput.isServer, enabled = enabled, - onCheckedChange = { storeForwardInput = storeForwardInput.copy { isServer = it } } + onCheckedChange = { storeForwardInput = storeForwardInput.copy { isServer = it } }, ) } item { HorizontalDivider() } @@ -155,7 +142,7 @@ fun StoreForwardConfigItemList( onSaveClicked = { focusManager.clearFocus() onSaveClicked(storeForwardInput) - } + }, ) } } @@ -167,6 +154,6 @@ private fun StoreForwardConfigPreview() { StoreForwardConfigItemList( storeForwardConfig = StoreForwardConfig.getDefaultInstance(), enabled = true, - onSaveClicked = { }, + onSaveClicked = {}, ) } diff --git a/app/src/main/java/com/geeksville/mesh/ui/radioconfig/components/TelemetryConfigItemList.kt b/app/src/main/java/com/geeksville/mesh/ui/settings/radio/components/TelemetryConfigItemList.kt similarity index 75% rename from app/src/main/java/com/geeksville/mesh/ui/radioconfig/components/TelemetryConfigItemList.kt rename to app/src/main/java/com/geeksville/mesh/ui/settings/radio/components/TelemetryConfigItemList.kt index deed92f0f..e132b0d1e 100644 --- a/app/src/main/java/com/geeksville/mesh/ui/radioconfig/components/TelemetryConfigItemList.kt +++ b/app/src/main/java/com/geeksville/mesh/ui/settings/radio/components/TelemetryConfigItemList.kt @@ -15,7 +15,7 @@ * along with this program. If not, see . */ -package com.geeksville.mesh.ui.radioconfig.components +package com.geeksville.mesh.ui.settings.radio.components import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.lazy.LazyColumn @@ -40,19 +40,14 @@ import com.geeksville.mesh.ui.common.components.EditTextPreference import com.geeksville.mesh.ui.common.components.PreferenceCategory import com.geeksville.mesh.ui.common.components.PreferenceFooter import com.geeksville.mesh.ui.common.components.SwitchPreference -import com.geeksville.mesh.ui.radioconfig.RadioConfigViewModel +import com.geeksville.mesh.ui.settings.radio.RadioConfigViewModel @Composable -fun TelemetryConfigScreen( - viewModel: RadioConfigViewModel = hiltViewModel(), -) { +fun TelemetryConfigScreen(viewModel: RadioConfigViewModel = hiltViewModel()) { val state by viewModel.radioConfigState.collectAsStateWithLifecycle() if (state.responseState.isWaiting()) { - PacketResponseStateDialog( - state = state.responseState, - onDismiss = viewModel::clearPacketResponse, - ) + PacketResponseStateDialog(state = state.responseState, onDismiss = viewModel::clearPacketResponse) } TelemetryConfigItemList( @@ -61,7 +56,7 @@ fun TelemetryConfigScreen( onSaveClicked = { telemetryInput -> val config = moduleConfig { telemetry = telemetryInput } viewModel.setModuleConfig(config) - } + }, ) } @@ -74,9 +69,7 @@ fun TelemetryConfigItemList( val focusManager = LocalFocusManager.current var telemetryInput by rememberSaveable { mutableStateOf(telemetryConfig) } - LazyColumn( - modifier = Modifier.fillMaxSize() - ) { + LazyColumn(modifier = Modifier.fillMaxSize()) { item { PreferenceCategory(text = stringResource(R.string.telemetry_config)) } item { @@ -85,9 +78,7 @@ fun TelemetryConfigItemList( value = telemetryInput.deviceUpdateInterval, enabled = enabled, keyboardActions = KeyboardActions(onDone = { focusManager.clearFocus() }), - onValueChanged = { - telemetryInput = telemetryInput.copy { deviceUpdateInterval = it } - } + onValueChanged = { telemetryInput = telemetryInput.copy { deviceUpdateInterval = it } }, ) } @@ -97,9 +88,7 @@ fun TelemetryConfigItemList( value = telemetryInput.environmentUpdateInterval, enabled = enabled, keyboardActions = KeyboardActions(onDone = { focusManager.clearFocus() }), - onValueChanged = { - telemetryInput = telemetryInput.copy { environmentUpdateInterval = it } - } + onValueChanged = { telemetryInput = telemetryInput.copy { environmentUpdateInterval = it } }, ) } @@ -108,9 +97,7 @@ fun TelemetryConfigItemList( title = stringResource(R.string.environment_metrics_module_enabled), checked = telemetryInput.environmentMeasurementEnabled, enabled = enabled, - onCheckedChange = { - telemetryInput = telemetryInput.copy { environmentMeasurementEnabled = it } - } + onCheckedChange = { telemetryInput = telemetryInput.copy { environmentMeasurementEnabled = it } }, ) } item { HorizontalDivider() } @@ -120,9 +107,7 @@ fun TelemetryConfigItemList( title = stringResource(R.string.environment_metrics_on_screen_enabled), checked = telemetryInput.environmentScreenEnabled, enabled = enabled, - onCheckedChange = { - telemetryInput = telemetryInput.copy { environmentScreenEnabled = it } - } + onCheckedChange = { telemetryInput = telemetryInput.copy { environmentScreenEnabled = it } }, ) } item { HorizontalDivider() } @@ -132,9 +117,7 @@ fun TelemetryConfigItemList( title = stringResource(R.string.environment_metrics_use_fahrenheit), checked = telemetryInput.environmentDisplayFahrenheit, enabled = enabled, - onCheckedChange = { - telemetryInput = telemetryInput.copy { environmentDisplayFahrenheit = it } - } + onCheckedChange = { telemetryInput = telemetryInput.copy { environmentDisplayFahrenheit = it } }, ) } item { HorizontalDivider() } @@ -144,9 +127,7 @@ fun TelemetryConfigItemList( title = stringResource(R.string.air_quality_metrics_module_enabled), checked = telemetryInput.airQualityEnabled, enabled = enabled, - onCheckedChange = { - telemetryInput = telemetryInput.copy { airQualityEnabled = it } - } + onCheckedChange = { telemetryInput = telemetryInput.copy { airQualityEnabled = it } }, ) } item { HorizontalDivider() } @@ -157,9 +138,7 @@ fun TelemetryConfigItemList( value = telemetryInput.airQualityInterval, enabled = enabled, keyboardActions = KeyboardActions(onDone = { focusManager.clearFocus() }), - onValueChanged = { - telemetryInput = telemetryInput.copy { airQualityInterval = it } - } + onValueChanged = { telemetryInput = telemetryInput.copy { airQualityInterval = it } }, ) } @@ -168,9 +147,7 @@ fun TelemetryConfigItemList( title = stringResource(R.string.power_metrics_module_enabled), checked = telemetryInput.powerMeasurementEnabled, enabled = enabled, - onCheckedChange = { - telemetryInput = telemetryInput.copy { powerMeasurementEnabled = it } - } + onCheckedChange = { telemetryInput = telemetryInput.copy { powerMeasurementEnabled = it } }, ) } item { HorizontalDivider() } @@ -181,9 +158,7 @@ fun TelemetryConfigItemList( value = telemetryInput.powerUpdateInterval, enabled = enabled, keyboardActions = KeyboardActions(onDone = { focusManager.clearFocus() }), - onValueChanged = { - telemetryInput = telemetryInput.copy { powerUpdateInterval = it } - } + onValueChanged = { telemetryInput = telemetryInput.copy { powerUpdateInterval = it } }, ) } @@ -192,9 +167,7 @@ fun TelemetryConfigItemList( title = stringResource(R.string.power_metrics_on_screen_enabled), checked = telemetryInput.powerScreenEnabled, enabled = enabled, - onCheckedChange = { - telemetryInput = telemetryInput.copy { powerScreenEnabled = it } - } + onCheckedChange = { telemetryInput = telemetryInput.copy { powerScreenEnabled = it } }, ) } item { HorizontalDivider() } @@ -209,7 +182,7 @@ fun TelemetryConfigItemList( onSaveClicked = { focusManager.clearFocus() onSaveClicked(telemetryInput) - } + }, ) } } @@ -218,9 +191,5 @@ fun TelemetryConfigItemList( @Preview(showBackground = true) @Composable private fun TelemetryConfigPreview() { - TelemetryConfigItemList( - telemetryConfig = TelemetryConfig.getDefaultInstance(), - enabled = true, - onSaveClicked = { }, - ) + TelemetryConfigItemList(telemetryConfig = TelemetryConfig.getDefaultInstance(), enabled = true, onSaveClicked = {}) } diff --git a/app/src/main/java/com/geeksville/mesh/ui/radioconfig/components/UserConfigItemList.kt b/app/src/main/java/com/geeksville/mesh/ui/settings/radio/components/UserConfigItemList.kt similarity index 78% rename from app/src/main/java/com/geeksville/mesh/ui/radioconfig/components/UserConfigItemList.kt rename to app/src/main/java/com/geeksville/mesh/ui/settings/radio/components/UserConfigItemList.kt index a7161367d..9ec407751 100644 --- a/app/src/main/java/com/geeksville/mesh/ui/radioconfig/components/UserConfigItemList.kt +++ b/app/src/main/java/com/geeksville/mesh/ui/settings/radio/components/UserConfigItemList.kt @@ -15,7 +15,7 @@ * along with this program. If not, see . */ -package com.geeksville.mesh.ui.radioconfig.components +package com.geeksville.mesh.ui.settings.radio.components import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.lazy.LazyColumn @@ -46,20 +46,15 @@ import com.geeksville.mesh.ui.common.components.PreferenceCategory import com.geeksville.mesh.ui.common.components.PreferenceFooter import com.geeksville.mesh.ui.common.components.RegularPreference import com.geeksville.mesh.ui.common.components.SwitchPreference -import com.geeksville.mesh.ui.radioconfig.RadioConfigViewModel +import com.geeksville.mesh.ui.settings.radio.RadioConfigViewModel import com.geeksville.mesh.user @Composable -fun UserConfigScreen( - viewModel: RadioConfigViewModel = hiltViewModel(), -) { +fun UserConfigScreen(viewModel: RadioConfigViewModel = hiltViewModel()) { val state by viewModel.radioConfigState.collectAsStateWithLifecycle() if (state.responseState.isWaiting()) { - PacketResponseStateDialog( - state = state.responseState, - onDismiss = viewModel::clearPacketResponse, - ) + PacketResponseStateDialog(state = state.responseState, onDismiss = viewModel::clearPacketResponse) } UserConfigItemList( @@ -85,18 +80,10 @@ fun UserConfigItemList( val validLongName = userInput.longName.isNotBlank() val validShortName = userInput.shortName.isNotBlank() val validNames = validLongName && validShortName - LazyColumn( - modifier = Modifier.fillMaxSize() - ) { + LazyColumn(modifier = Modifier.fillMaxSize()) { item { PreferenceCategory(text = stringResource(R.string.user_config)) } - item { - RegularPreference( - title = stringResource(R.string.node_id), - subtitle = userInput.id, - onClick = {} - ) - } + item { RegularPreference(title = stringResource(R.string.node_id), subtitle = userInput.id, onClick = {}) } item { HorizontalDivider() } item { @@ -106,13 +93,10 @@ fun UserConfigItemList( maxSize = 39, // long_name max_size:40 enabled = enabled, isError = !validLongName, - keyboardOptions = KeyboardOptions.Default.copy( - keyboardType = KeyboardType.Text, imeAction = ImeAction.Done - ), + keyboardOptions = + KeyboardOptions.Default.copy(keyboardType = KeyboardType.Text, imeAction = ImeAction.Done), keyboardActions = KeyboardActions(onDone = { focusManager.clearFocus() }), - onValueChanged = { - userInput = userInput.copy { longName = it } - } + onValueChanged = { userInput = userInput.copy { longName = it } }, ) } @@ -123,11 +107,10 @@ fun UserConfigItemList( maxSize = 4, // short_name max_size:5 enabled = enabled, isError = !validShortName, - keyboardOptions = KeyboardOptions.Default.copy( - keyboardType = KeyboardType.Text, imeAction = ImeAction.Done - ), + keyboardOptions = + KeyboardOptions.Default.copy(keyboardType = KeyboardType.Text, imeAction = ImeAction.Done), keyboardActions = KeyboardActions(onDone = { focusManager.clearFocus() }), - onValueChanged = { userInput = userInput.copy { shortName = it } } + onValueChanged = { userInput = userInput.copy { shortName = it } }, ) } @@ -135,7 +118,7 @@ fun UserConfigItemList( RegularPreference( title = stringResource(R.string.hardware_model), subtitle = userInput.hwModel.name, - onClick = {} + onClick = {}, ) } item { HorizontalDivider() } @@ -144,12 +127,11 @@ fun UserConfigItemList( SwitchPreference( title = stringResource(R.string.unmessageable), summary = stringResource(R.string.unmonitored_or_infrastructure), - checked = userInput.isUnmessagable || ( - firmwareVersion < DeviceVersion("2.6.9") && - userInput.role.isUnmessageableRole() - ), + checked = + userInput.isUnmessagable || + (firmwareVersion < DeviceVersion("2.6.9") && userInput.role.isUnmessageableRole()), enabled = userInput.hasIsUnmessagable() || firmwareVersion >= DeviceVersion("2.6.9"), - onCheckedChange = { userInput = userInput.copy { isUnmessagable = it } } + onCheckedChange = { userInput = userInput.copy { isUnmessagable = it } }, ) } @@ -161,7 +143,7 @@ fun UserConfigItemList( summary = stringResource(R.string.licensed_amateur_radio_text), checked = userInput.isLicensed, enabled = enabled, - onCheckedChange = { userInput = userInput.copy { isLicensed = it } } + onCheckedChange = { userInput = userInput.copy { isLicensed = it } }, ) } item { HorizontalDivider() } @@ -172,10 +154,11 @@ fun UserConfigItemList( onCancelClicked = { focusManager.clearFocus() userInput = userConfig - }, onSaveClicked = { + }, + onSaveClicked = { focusManager.clearFocus() onSaveClicked(userInput) - } + }, ) } } @@ -185,7 +168,8 @@ fun UserConfigItemList( @Composable private fun UserConfigPreview() { UserConfigItemList( - userConfig = user { + userConfig = + user { id = "!a280d9c8" longName = "Meshtastic d9c8" shortName = "d9c8" @@ -193,9 +177,7 @@ private fun UserConfigPreview() { isLicensed = false }, enabled = true, - onSaveClicked = { }, - metadata = deviceMetadata { - firmwareVersion = "2.8.0" - } + onSaveClicked = {}, + metadata = deviceMetadata { firmwareVersion = "2.8.0" }, ) } diff --git a/app/src/main/java/com/geeksville/mesh/ui/sharing/Channel.kt b/app/src/main/java/com/geeksville/mesh/ui/sharing/Channel.kt index 90cad2bb5..079014cef 100644 --- a/app/src/main/java/com/geeksville/mesh/ui/sharing/Channel.kt +++ b/app/src/main/java/com/geeksville/mesh/ui/sharing/Channel.kt @@ -104,9 +104,9 @@ import com.geeksville.mesh.navigation.getNavRouteFrom import com.geeksville.mesh.service.ConnectionState import com.geeksville.mesh.ui.common.components.AdaptiveTwoPane import com.geeksville.mesh.ui.common.components.PreferenceFooter -import com.geeksville.mesh.ui.radioconfig.RadioConfigViewModel -import com.geeksville.mesh.ui.radioconfig.components.ChannelSelection -import com.geeksville.mesh.ui.radioconfig.components.PacketResponseStateDialog +import com.geeksville.mesh.ui.settings.radio.RadioConfigViewModel +import com.geeksville.mesh.ui.settings.radio.components.ChannelSelection +import com.geeksville.mesh.ui.settings.radio.components.PacketResponseStateDialog import com.google.accompanist.permissions.ExperimentalPermissionsApi import com.google.accompanist.permissions.isGranted import com.google.accompanist.permissions.rememberPermissionState diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 0be2519a8..5381e7cff 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -628,7 +628,7 @@ Mesh Map Conversations Nodes - Share + Settings Set your region Reply Your node will periodically send an unencrypted map report packet to the configured MQTT server, this includes id, long and short name, approximate location, hardware model, role, firmware version, LoRa region, modem preset and primary channel name. @@ -672,6 +672,7 @@ UV Lux Unknown + This radio is managed and can only be changed by a remote admin. Clean Node Database Clean up nodes last seen older than %1$d days Clean up only unknown nodes