diff --git a/app/src/main/kotlin/org/meshtastic/app/ui/Main.kt b/app/src/main/kotlin/org/meshtastic/app/ui/Main.kt index 46409b14e..767cff54d 100644 --- a/app/src/main/kotlin/org/meshtastic/app/ui/Main.kt +++ b/app/src/main/kotlin/org/meshtastic/app/ui/Main.kt @@ -44,6 +44,7 @@ import org.meshtastic.core.ui.component.MeshtasticNavigationSuite import org.meshtastic.core.ui.viewmodel.UIViewModel import org.meshtastic.feature.connections.navigation.connectionsGraph import org.meshtastic.feature.firmware.navigation.firmwareGraph +import org.meshtastic.feature.settings.radio.RadioConfigViewModel import org.meshtastic.feature.map.navigation.mapGraph import org.meshtastic.feature.messaging.navigation.contactsGraph import org.meshtastic.feature.node.navigation.nodesGraph @@ -86,7 +87,7 @@ fun MainScreen() { ) mapGraph(backStack) channelsGraph(backStack) - connectionsGraph(backStack) + connectionsGraph(backStack) { koinViewModel() } settingsGraph(backStack) firmwareGraph(backStack) wifiProvisionGraph(backStack) diff --git a/app/src/test/kotlin/org/meshtastic/app/ui/NavigationAssemblyTest.kt b/app/src/test/kotlin/org/meshtastic/app/ui/NavigationAssemblyTest.kt index 1fd4b39ce..8bae44f75 100644 --- a/app/src/test/kotlin/org/meshtastic/app/ui/NavigationAssemblyTest.kt +++ b/app/src/test/kotlin/org/meshtastic/app/ui/NavigationAssemblyTest.kt @@ -21,9 +21,12 @@ import androidx.compose.ui.test.v2.runComposeUiTest import androidx.navigation3.runtime.NavKey import androidx.navigation3.runtime.entryProvider import androidx.navigation3.runtime.rememberNavBackStack +import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.emptyFlow import org.junit.Test import org.junit.runner.RunWith +import org.meshtastic.core.model.RadioConfigStateProvider +import org.meshtastic.core.model.ResponseState import org.meshtastic.core.navigation.NodesRoute import org.meshtastic.feature.connections.navigation.connectionsGraph import org.meshtastic.feature.firmware.navigation.firmwareGraph @@ -49,7 +52,14 @@ class NavigationAssemblyTest { nodesGraph(backStack = backStack, scrollToTopEvents = emptyFlow()) mapGraph(backStack) channelsGraph(backStack) - connectionsGraph(backStack) + connectionsGraph(backStack) { + object : RadioConfigStateProvider { + override val packetResponseState = MutableStateFlow>(ResponseState.Empty) + override val pendingRouteName = MutableStateFlow("") + override fun requestConfigLoad(routeName: String) {} + override fun clearPacketResponse() {} + } + } settingsGraph(backStack) firmwareGraph(backStack) } diff --git a/core/model/src/commonMain/kotlin/org/meshtastic/core/model/RadioConfigStateProvider.kt b/core/model/src/commonMain/kotlin/org/meshtastic/core/model/RadioConfigStateProvider.kt new file mode 100644 index 000000000..aefa34dbb --- /dev/null +++ b/core/model/src/commonMain/kotlin/org/meshtastic/core/model/RadioConfigStateProvider.kt @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2026 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 org.meshtastic.core.model + +import kotlinx.coroutines.flow.StateFlow + +/** + * Minimal interface exposing radio-config packet response state. + * Used by feature/connections to observe config-loading progress without + * depending on the full RadioConfigViewModel in feature/settings. + */ +interface RadioConfigStateProvider { + /** Current packet response state (loading/success/error/empty). */ + val packetResponseState: StateFlow> + + /** Route name associated with the pending config request (e.g. "LORA"). */ + val pendingRouteName: StateFlow + + /** Initiate a config load for the given route name. */ + fun requestConfigLoad(routeName: String) + + /** Clear the packet response, resetting to [ResponseState.Empty]. */ + fun clearPacketResponse() +} diff --git a/feature/settings/src/commonMain/kotlin/org/meshtastic/feature/settings/radio/ResponseState.kt b/core/model/src/commonMain/kotlin/org/meshtastic/core/model/ResponseState.kt similarity index 96% rename from feature/settings/src/commonMain/kotlin/org/meshtastic/feature/settings/radio/ResponseState.kt rename to core/model/src/commonMain/kotlin/org/meshtastic/core/model/ResponseState.kt index d0af14039..912b8b101 100644 --- a/feature/settings/src/commonMain/kotlin/org/meshtastic/feature/settings/radio/ResponseState.kt +++ b/core/model/src/commonMain/kotlin/org/meshtastic/core/model/ResponseState.kt @@ -14,7 +14,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ -package org.meshtastic.feature.settings.radio +package org.meshtastic.core.model import org.meshtastic.core.resources.UiText diff --git a/feature/settings/src/commonMain/kotlin/org/meshtastic/feature/settings/radio/component/PacketResponseStateDialog.kt b/core/ui/src/commonMain/kotlin/org/meshtastic/core/ui/component/PacketResponseStateDialog.kt similarity index 97% rename from feature/settings/src/commonMain/kotlin/org/meshtastic/feature/settings/radio/component/PacketResponseStateDialog.kt rename to core/ui/src/commonMain/kotlin/org/meshtastic/core/ui/component/PacketResponseStateDialog.kt index c0e536e89..2e772f46f 100644 --- a/feature/settings/src/commonMain/kotlin/org/meshtastic/feature/settings/radio/component/PacketResponseStateDialog.kt +++ b/core/ui/src/commonMain/kotlin/org/meshtastic/core/ui/component/PacketResponseStateDialog.kt @@ -14,7 +14,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ -package org.meshtastic.feature.settings.radio.component +package org.meshtastic.core.ui.component import androidx.compose.animation.core.animateFloatAsState import androidx.compose.foundation.layout.Arrangement @@ -36,17 +36,16 @@ import androidx.compose.ui.unit.dp import kotlinx.coroutines.delay import org.jetbrains.compose.resources.stringResource import org.meshtastic.core.common.util.MetricFormatter +import org.meshtastic.core.model.ResponseState import org.meshtastic.core.resources.Res import org.meshtastic.core.resources.cancel import org.meshtastic.core.resources.close import org.meshtastic.core.resources.delivery_confirmed import org.meshtastic.core.resources.delivery_confirmed_reboot_warning import org.meshtastic.core.resources.error -import org.meshtastic.core.ui.component.MeshtasticDialog import org.meshtastic.core.ui.icon.Error import org.meshtastic.core.ui.icon.MeshtasticIcons import org.meshtastic.core.ui.icon.Success -import org.meshtastic.feature.settings.radio.ResponseState private const val AUTO_DISMISS_DELAY_MS = 1500L diff --git a/desktop/src/main/kotlin/org/meshtastic/desktop/navigation/DesktopNavigation.kt b/desktop/src/main/kotlin/org/meshtastic/desktop/navigation/DesktopNavigation.kt index d7581cc9c..ccdba56b6 100644 --- a/desktop/src/main/kotlin/org/meshtastic/desktop/navigation/DesktopNavigation.kt +++ b/desktop/src/main/kotlin/org/meshtastic/desktop/navigation/DesktopNavigation.kt @@ -19,6 +19,7 @@ package org.meshtastic.desktop.navigation import androidx.navigation3.runtime.EntryProviderScope import androidx.navigation3.runtime.NavBackStack import androidx.navigation3.runtime.NavKey +import org.koin.compose.viewmodel.koinViewModel import org.meshtastic.core.navigation.MultiBackstack import org.meshtastic.core.navigation.TopLevelDestination import org.meshtastic.core.ui.viewmodel.UIViewModel @@ -28,6 +29,7 @@ import org.meshtastic.feature.map.navigation.mapGraph import org.meshtastic.feature.messaging.navigation.contactsGraph import org.meshtastic.feature.node.navigation.nodesGraph import org.meshtastic.feature.settings.navigation.settingsGraph +import org.meshtastic.feature.settings.radio.RadioConfigViewModel import org.meshtastic.feature.settings.radio.channel.channelsGraph import org.meshtastic.feature.wifiprovision.navigation.wifiProvisionGraph @@ -53,6 +55,6 @@ fun EntryProviderScope.desktopNavGraph( firmwareGraph(backStack) settingsGraph(backStack) channelsGraph(backStack) - connectionsGraph(backStack) + connectionsGraph(backStack) { koinViewModel() } wifiProvisionGraph(backStack) } diff --git a/feature/connections/build.gradle.kts b/feature/connections/build.gradle.kts index e22f03a39..99779604c 100644 --- a/feature/connections/build.gradle.kts +++ b/feature/connections/build.gradle.kts @@ -40,7 +40,6 @@ kotlin { implementation(projects.core.ui) implementation(projects.core.ble) implementation(projects.core.network) - implementation(projects.feature.settings) implementation(libs.jetbrains.navigation3.ui) } diff --git a/feature/connections/src/commonMain/kotlin/org/meshtastic/feature/connections/navigation/ConnectionsNavigation.kt b/feature/connections/src/commonMain/kotlin/org/meshtastic/feature/connections/navigation/ConnectionsNavigation.kt index 7b91f0975..6b045afef 100644 --- a/feature/connections/src/commonMain/kotlin/org/meshtastic/feature/connections/navigation/ConnectionsNavigation.kt +++ b/feature/connections/src/commonMain/kotlin/org/meshtastic/feature/connections/navigation/ConnectionsNavigation.kt @@ -16,22 +16,26 @@ */ package org.meshtastic.feature.connections.navigation +import androidx.compose.runtime.Composable import androidx.navigation3.runtime.EntryProviderScope import androidx.navigation3.runtime.NavBackStack import androidx.navigation3.runtime.NavKey import org.koin.compose.viewmodel.koinViewModel +import org.meshtastic.core.model.RadioConfigStateProvider import org.meshtastic.core.navigation.ConnectionsRoute import org.meshtastic.core.navigation.NodesRoute import org.meshtastic.feature.connections.ScannerViewModel import org.meshtastic.feature.connections.ui.ConnectionsScreen -import org.meshtastic.feature.settings.radio.RadioConfigViewModel /** Navigation graph for for the top level ConnectionsScreen - [ConnectionsRoute.Connections]. */ -fun EntryProviderScope.connectionsGraph(backStack: NavBackStack) { +fun EntryProviderScope.connectionsGraph( + backStack: NavBackStack, + radioConfigStateProvider: @Composable () -> RadioConfigStateProvider, +) { entry { ConnectionsScreen( scanModel = koinViewModel(), - radioConfigViewModel = koinViewModel(), + radioConfigStateProvider = radioConfigStateProvider(), onClickNodeChip = { id -> backStack.add(NodesRoute.NodeDetail(id)) }, onNavigateToNodeDetails = { id -> backStack.add(NodesRoute.NodeDetail(id)) }, onConfigNavigate = { route -> backStack.add(route) }, @@ -41,7 +45,7 @@ fun EntryProviderScope.connectionsGraph(backStack: NavBackStack) entry { ConnectionsScreen( scanModel = koinViewModel(), - radioConfigViewModel = koinViewModel(), + radioConfigStateProvider = radioConfigStateProvider(), onClickNodeChip = { id -> backStack.add(NodesRoute.NodeDetail(id)) }, onNavigateToNodeDetails = { id -> backStack.add(NodesRoute.NodeDetail(id)) }, onConfigNavigate = { route -> backStack.add(route) }, diff --git a/feature/connections/src/commonMain/kotlin/org/meshtastic/feature/connections/ui/ConnectionsScreen.kt b/feature/connections/src/commonMain/kotlin/org/meshtastic/feature/connections/ui/ConnectionsScreen.kt index 0a180fd4b..fc862ac28 100644 --- a/feature/connections/src/commonMain/kotlin/org/meshtastic/feature/connections/ui/ConnectionsScreen.kt +++ b/feature/connections/src/commonMain/kotlin/org/meshtastic/feature/connections/ui/ConnectionsScreen.kt @@ -78,10 +78,8 @@ import org.meshtastic.feature.connections.ui.components.ConnectingDeviceInfo import org.meshtastic.feature.connections.ui.components.CurrentlyConnectedInfo import org.meshtastic.feature.connections.ui.components.DeviceList import org.meshtastic.feature.connections.ui.components.TransportFilterChips -import org.meshtastic.feature.settings.navigation.ConfigRoute -import org.meshtastic.feature.settings.navigation.getNavRouteFrom -import org.meshtastic.feature.settings.radio.RadioConfigViewModel -import org.meshtastic.feature.settings.radio.component.PacketResponseStateDialog +import org.meshtastic.core.model.RadioConfigStateProvider +import org.meshtastic.core.ui.component.PacketResponseStateDialog import kotlin.uuid.ExperimentalUuidApi /** @@ -98,12 +96,13 @@ private val CardMinHeight = 100.dp fun ConnectionsScreen( connectionsViewModel: ConnectionsViewModel = koinViewModel(), scanModel: ScannerViewModel = koinViewModel(), - radioConfigViewModel: RadioConfigViewModel = koinViewModel(), + radioConfigStateProvider: RadioConfigStateProvider, onClickNodeChip: (Int) -> Unit, onNavigateToNodeDetails: (Int) -> Unit, onConfigNavigate: (Route) -> Unit, ) { - val radioConfigState by radioConfigViewModel.radioConfigState.collectAsStateWithLifecycle() + val responseState by radioConfigStateProvider.packetResponseState.collectAsStateWithLifecycle() + val pendingRoute by radioConfigStateProvider.pendingRouteName.collectAsStateWithLifecycle() val connectionProgress by scanModel.connectionProgressText.collectAsStateWithLifecycle() val connectionStatus by connectionsViewModel.connectionStatus.collectAsStateWithLifecycle() val connectionState by connectionsViewModel.connectionState.collectAsStateWithLifecycle() @@ -153,18 +152,16 @@ fun ConnectionsScreen( var isWaiting by remember { mutableStateOf(false) } if (isWaiting) { PacketResponseStateDialog( - state = radioConfigState.responseState, + state = responseState, onDismiss = { isWaiting = false - radioConfigViewModel.clearPacketResponse() + radioConfigStateProvider.clearPacketResponse() }, onComplete = { - getNavRouteFrom(radioConfigState.route)?.let { route -> + if (pendingRoute == "LORA") { isWaiting = false - radioConfigViewModel.clearPacketResponse() - if (route == SettingsRoute.LoRa) { - onConfigNavigate(SettingsRoute.LoRa) - } + radioConfigStateProvider.clearPacketResponse() + onConfigNavigate(SettingsRoute.LoRa) } }, ) @@ -264,7 +261,7 @@ fun ConnectionsScreen( text = stringResource(Res.string.set_your_region), onClick = { isWaiting = true - radioConfigViewModel.setResponseStateLoading(ConfigRoute.LORA) + radioConfigStateProvider.requestConfigLoad("LORA") }, ) } diff --git a/feature/settings/src/commonMain/kotlin/org/meshtastic/feature/settings/AdministrationScreen.kt b/feature/settings/src/commonMain/kotlin/org/meshtastic/feature/settings/AdministrationScreen.kt index 12943e346..077b2b9a2 100644 --- a/feature/settings/src/commonMain/kotlin/org/meshtastic/feature/settings/AdministrationScreen.kt +++ b/feature/settings/src/commonMain/kotlin/org/meshtastic/feature/settings/AdministrationScreen.kt @@ -51,9 +51,9 @@ import org.meshtastic.feature.settings.component.ExpressiveSection import org.meshtastic.feature.settings.radio.AdminRoute import org.meshtastic.feature.settings.radio.RadioConfigState import org.meshtastic.feature.settings.radio.RadioConfigViewModel -import org.meshtastic.feature.settings.radio.ResponseState +import org.meshtastic.core.model.ResponseState import org.meshtastic.feature.settings.radio.component.LoadingOverlay -import org.meshtastic.feature.settings.radio.component.PacketResponseStateDialog +import org.meshtastic.core.ui.component.PacketResponseStateDialog import org.meshtastic.feature.settings.radio.component.ShutdownConfirmationDialog import org.meshtastic.feature.settings.radio.component.WarningDialog diff --git a/feature/settings/src/commonMain/kotlin/org/meshtastic/feature/settings/radio/RadioConfigViewModel.kt b/feature/settings/src/commonMain/kotlin/org/meshtastic/feature/settings/radio/RadioConfigViewModel.kt index 20089e9bd..d2a06d693 100644 --- a/feature/settings/src/commonMain/kotlin/org/meshtastic/feature/settings/radio/RadioConfigViewModel.kt +++ b/feature/settings/src/commonMain/kotlin/org/meshtastic/feature/settings/radio/RadioConfigViewModel.kt @@ -22,12 +22,15 @@ import androidx.lifecycle.viewModelScope import co.touchlab.kermit.Logger import kotlinx.coroutines.Job import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.flow.launchIn +import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.onEach +import kotlinx.coroutines.flow.stateIn import kotlinx.coroutines.flow.update import kotlinx.coroutines.launch import org.jetbrains.compose.resources.StringResource @@ -48,6 +51,7 @@ import org.meshtastic.core.model.MqttProbeStatus import org.meshtastic.core.model.MyNodeInfo import org.meshtastic.core.model.Node import org.meshtastic.core.model.Position +import org.meshtastic.core.model.RadioConfigStateProvider import org.meshtastic.core.repository.AnalyticsPrefs import org.meshtastic.core.repository.FileService import org.meshtastic.core.repository.HomoglyphPrefs @@ -80,6 +84,7 @@ import org.meshtastic.proto.LocalConfig import org.meshtastic.proto.LocalModuleConfig import org.meshtastic.proto.ModuleConfig import org.meshtastic.proto.User +import org.meshtastic.core.model.ResponseState /** Data class that represents the current RadioConfig state. */ @androidx.compose.runtime.Immutable @@ -124,7 +129,7 @@ open class RadioConfigViewModel( private val locationService: LocationService, private val fileService: FileService, private val mqttManager: MqttManager, -) : ViewModel() { +) : ViewModel(), RadioConfigStateProvider { val analyticsAllowedFlow = analyticsPrefs.analyticsAllowed fun toggleAnalyticsAllowed() { @@ -398,10 +403,29 @@ open class RadioConfigViewModel( safeLaunch(tag = "installProfile") { installProfileUseCase(destNum, protobuf, destNode.value?.user) } } - fun clearPacketResponse() { + // region RadioConfigStateProvider implementation + + override val packetResponseState: StateFlow> = + _radioConfigState.map { it.responseState } + .stateIn(viewModelScope, SharingStarted.WhileSubscribed(5_000), ResponseState.Empty) + + override val pendingRouteName: StateFlow = + _radioConfigState.map { it.route } + .stateIn(viewModelScope, SharingStarted.WhileSubscribed(5_000), "") + + override fun requestConfigLoad(routeName: String) { + val route = ConfigRoute.entries.find { it.name == routeName } + ?: ModuleRoute.entries.find { it.name == routeName } + ?: return + setResponseStateLoading(route) + } + + override fun clearPacketResponse() { _radioConfigState.update { it.copy(responseState = ResponseState.Empty) } } + // endregion + fun setResponseStateLoading(route: Enum<*>) { val destNum = destNumFlow.value ?: destNode.value?.num ?: return diff --git a/feature/settings/src/commonMain/kotlin/org/meshtastic/feature/settings/radio/channel/ChannelConfigScreen.kt b/feature/settings/src/commonMain/kotlin/org/meshtastic/feature/settings/radio/channel/ChannelConfigScreen.kt index efdc699b1..7b43fc87b 100644 --- a/feature/settings/src/commonMain/kotlin/org/meshtastic/feature/settings/radio/channel/ChannelConfigScreen.kt +++ b/feature/settings/src/commonMain/kotlin/org/meshtastic/feature/settings/radio/channel/ChannelConfigScreen.kt @@ -65,14 +65,14 @@ import org.meshtastic.core.ui.component.rememberDragDropState import org.meshtastic.core.ui.icon.Add import org.meshtastic.core.ui.icon.MeshtasticIcons import org.meshtastic.feature.settings.radio.RadioConfigViewModel -import org.meshtastic.feature.settings.radio.ResponseState +import org.meshtastic.core.model.ResponseState import org.meshtastic.feature.settings.radio.channel.component.ChannelCard import org.meshtastic.feature.settings.radio.channel.component.ChannelConfigHeader import org.meshtastic.feature.settings.radio.channel.component.ChannelLegend import org.meshtastic.feature.settings.radio.channel.component.ChannelLegendDialog import org.meshtastic.feature.settings.radio.channel.component.EditChannelDialog import org.meshtastic.feature.settings.radio.component.LoadingOverlay -import org.meshtastic.feature.settings.radio.component.PacketResponseStateDialog +import org.meshtastic.core.ui.component.PacketResponseStateDialog import org.meshtastic.proto.ChannelSettings import org.meshtastic.proto.Config diff --git a/feature/settings/src/commonMain/kotlin/org/meshtastic/feature/settings/radio/channel/ChannelScreen.kt b/feature/settings/src/commonMain/kotlin/org/meshtastic/feature/settings/radio/channel/ChannelScreen.kt index 97352c2b3..b99de7248 100644 --- a/feature/settings/src/commonMain/kotlin/org/meshtastic/feature/settings/radio/channel/ChannelScreen.kt +++ b/feature/settings/src/commonMain/kotlin/org/meshtastic/feature/settings/radio/channel/ChannelScreen.kt @@ -95,7 +95,7 @@ import org.meshtastic.feature.settings.channel.ChannelViewModel import org.meshtastic.feature.settings.navigation.ConfigRoute import org.meshtastic.feature.settings.navigation.getNavRouteFrom import org.meshtastic.feature.settings.radio.RadioConfigViewModel -import org.meshtastic.feature.settings.radio.component.PacketResponseStateDialog +import org.meshtastic.core.ui.component.PacketResponseStateDialog import org.meshtastic.proto.ChannelSet import org.meshtastic.proto.ChannelSettings import org.meshtastic.proto.Config diff --git a/feature/settings/src/commonMain/kotlin/org/meshtastic/feature/settings/radio/component/LoadingOverlay.kt b/feature/settings/src/commonMain/kotlin/org/meshtastic/feature/settings/radio/component/LoadingOverlay.kt index 2f2695331..cb79b1990 100644 --- a/feature/settings/src/commonMain/kotlin/org/meshtastic/feature/settings/radio/component/LoadingOverlay.kt +++ b/feature/settings/src/commonMain/kotlin/org/meshtastic/feature/settings/radio/component/LoadingOverlay.kt @@ -40,7 +40,7 @@ import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.unit.dp import org.meshtastic.core.common.util.MetricFormatter -import org.meshtastic.feature.settings.radio.ResponseState +import org.meshtastic.core.model.ResponseState private const val LOADING_OVERLAY_ALPHA = 0.8f private const val PERCENTAGE_FACTOR = 100 diff --git a/feature/settings/src/commonMain/kotlin/org/meshtastic/feature/settings/radio/component/RadioConfigScreenList.kt b/feature/settings/src/commonMain/kotlin/org/meshtastic/feature/settings/radio/component/RadioConfigScreenList.kt index d5a956cab..c93b6c2aa 100644 --- a/feature/settings/src/commonMain/kotlin/org/meshtastic/feature/settings/radio/component/RadioConfigScreenList.kt +++ b/feature/settings/src/commonMain/kotlin/org/meshtastic/feature/settings/radio/component/RadioConfigScreenList.kt @@ -40,8 +40,9 @@ import org.meshtastic.core.resources.Res import org.meshtastic.core.resources.discard_changes import org.meshtastic.core.resources.save_changes import org.meshtastic.core.ui.component.MainAppBar +import org.meshtastic.core.ui.component.PacketResponseStateDialog import org.meshtastic.core.ui.component.PreferenceFooter -import org.meshtastic.feature.settings.radio.ResponseState +import org.meshtastic.core.model.ResponseState @Suppress("LongMethod") @Composable