Extract node list display settings to dedicated screen (#5580)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
James Rich
2026-05-22 17:01:50 -07:00
committed by GitHub
parent d870141b7c
commit a67927818b
12 changed files with 295 additions and 174 deletions

View File

@@ -166,6 +166,8 @@ sealed interface SettingsRoute : Route {
@Serializable data object FilterSettings : SettingsRoute
@Serializable data object NodeList : SettingsRoute
// endregion
// region help & documentation routes

View File

@@ -49,6 +49,7 @@ import org.meshtastic.core.resources.export_configuration
import org.meshtastic.core.resources.filter_settings
import org.meshtastic.core.resources.help_and_documentation
import org.meshtastic.core.resources.import_configuration
import org.meshtastic.core.resources.node_layout_section_title
import org.meshtastic.core.resources.preferences_language
import org.meshtastic.core.resources.remotely_administrating
import org.meshtastic.core.resources.wifi_devices
@@ -57,12 +58,12 @@ import org.meshtastic.core.ui.component.MainAppBar
import org.meshtastic.core.ui.component.MeshtasticDialog
import org.meshtastic.core.ui.icon.FilterList
import org.meshtastic.core.ui.icon.HelpOutline
import org.meshtastic.core.ui.icon.List
import org.meshtastic.core.ui.icon.MeshtasticIcons
import org.meshtastic.core.ui.icon.Wifi
import org.meshtastic.feature.settings.component.AppInfoSection
import org.meshtastic.feature.settings.component.AppearanceSection
import org.meshtastic.feature.settings.component.ExpressiveSection
import org.meshtastic.feature.settings.component.NodeLayoutSettings
import org.meshtastic.feature.settings.component.PersistenceSection
import org.meshtastic.feature.settings.component.PrivacySection
import org.meshtastic.feature.settings.component.ThemePickerDialog
@@ -241,39 +242,14 @@ fun SettingsScreen(
onShowThemePicker = { showThemePickerDialog = true },
)
val densityName by settingsViewModel.nodeListDensity.collectAsStateWithLifecycle()
val density = org.meshtastic.core.model.NodeListDensity.fromName(densityName)
val showPower by settingsViewModel.shouldShowPower.collectAsStateWithLifecycle()
val showLastHeard by settingsViewModel.shouldShowLastHeard.collectAsStateWithLifecycle()
val lastHeardRelative by settingsViewModel.lastHeardIsRelative.collectAsStateWithLifecycle()
val showLocation by settingsViewModel.shouldShowLocation.collectAsStateWithLifecycle()
val showHops by settingsViewModel.shouldShowHops.collectAsStateWithLifecycle()
val showSignal by settingsViewModel.shouldShowSignal.collectAsStateWithLifecycle()
val showChannel by settingsViewModel.shouldShowChannel.collectAsStateWithLifecycle()
val showRole by settingsViewModel.shouldShowRole.collectAsStateWithLifecycle()
val showTelemetry by settingsViewModel.shouldShowTelemetry.collectAsStateWithLifecycle()
NodeLayoutSettings(
density = density,
onDensityChange = { settingsViewModel.setNodeListDensity(it.name) },
showPower = showPower,
onShowPowerChange = { settingsViewModel.setShouldShowPower(it) },
showLastHeard = showLastHeard,
onShowLastHeardChange = { settingsViewModel.setShouldShowLastHeard(it) },
lastHeardIsRelative = lastHeardRelative,
onLastHeardIsRelativeChange = { settingsViewModel.setLastHeardIsRelative(it) },
showLocation = showLocation,
onShowLocationChange = { settingsViewModel.setShouldShowLocation(it) },
showHops = showHops,
onShowHopsChange = { settingsViewModel.setShouldShowHops(it) },
showSignal = showSignal,
onShowSignalChange = { settingsViewModel.setShouldShowSignal(it) },
showChannel = showChannel,
onShowChannelChange = { settingsViewModel.setShouldShowChannel(it) },
showRole = showRole,
onShowRoleChange = { settingsViewModel.setShouldShowRole(it) },
showTelemetry = showTelemetry,
onShowTelemetryChange = { settingsViewModel.setShouldShowTelemetry(it) },
)
ExpressiveSection(title = stringResource(Res.string.node_layout_section_title)) {
ListItem(
text = stringResource(Res.string.node_layout_section_title),
leadingIcon = MeshtasticIcons.List,
) {
onNavigate(SettingsRoute.NodeList)
}
}
ExpressiveSection(title = stringResource(Res.string.wifi_devices)) {
ListItem(text = stringResource(Res.string.wifi_devices), leadingIcon = MeshtasticIcons.Wifi) {

View File

@@ -0,0 +1,90 @@
/*
* 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 <https://www.gnu.org/licenses/>.
*/
@file:OptIn(ExperimentalMaterial3ExpressiveApi::class)
package org.meshtastic.feature.settings
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll
import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi
import androidx.compose.material3.Scaffold
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import org.jetbrains.compose.resources.stringResource
import org.meshtastic.core.resources.Res
import org.meshtastic.core.resources.node_layout_section_title
import org.meshtastic.core.ui.component.MainAppBar
import org.meshtastic.feature.settings.component.NodeLayoutSettings
/**
* Dedicated settings screen for node list display options (density and field visibility). Provides a focused interface
* for customizing how nodes are rendered in the list view.
*
* Material 3 expressive design highlights:
* - **Section organization**: NodeLayoutSettings component handles grouped layout with cards
* - **Visual hierarchy**: MainAppBar provides clear screen identity and navigation
* - **Spacing rhythm**: 16dp content padding with 16dp section gaps for consistent rhythm
* - **Scrollability**: Full vertical scroll support for all display variations
* - **Responsive preview**: Live preview updates as density and field options change
*
* @param settingsViewModel Provides access to node display preferences and update methods
* @param onNavigateUp Callback when user requests navigation back (back button in app bar)
*/
@Composable
fun NodeListScreen(settingsViewModel: SettingsViewModel, onNavigateUp: () -> Unit, modifier: Modifier = Modifier) {
val settings by settingsViewModel.nodeListSettings.collectAsStateWithLifecycle()
Scaffold(
modifier = modifier,
topBar = {
MainAppBar(
title = stringResource(Res.string.node_layout_section_title),
canNavigateUp = true,
onNavigateUp = onNavigateUp,
ourNode = null,
showNodeChip = false,
actions = {},
onClickChip = {},
)
},
) { paddingValues ->
Column(
modifier = Modifier.verticalScroll(rememberScrollState()).padding(paddingValues).padding(16.dp),
verticalArrangement = Arrangement.spacedBy(16.dp),
) {
NodeLayoutSettings(
state = settings,
onDensityChange = { settingsViewModel.setNodeListDensity(it.name) },
onShowPowerChange = { settingsViewModel.setShouldShowPower(it) },
onShowLastHeardChange = { settingsViewModel.setShouldShowLastHeard(it) },
onLastHeardIsRelativeChange = { settingsViewModel.setLastHeardIsRelative(it) },
onShowLocationChange = { settingsViewModel.setShouldShowLocation(it) },
onShowHopsChange = { settingsViewModel.setShouldShowHops(it) },
onShowSignalChange = { settingsViewModel.setShouldShowSignal(it) },
onShowChannelChange = { settingsViewModel.setShouldShowChannel(it) },
onShowRoleChange = { settingsViewModel.setShouldShowRole(it) },
onShowTelemetryChange = { settingsViewModel.setShouldShowTelemetry(it) },
)
}
}
}

View File

@@ -20,6 +20,7 @@ import androidx.lifecycle.ViewModel
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.flatMapLatest
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.flow.map
@@ -42,6 +43,7 @@ import org.meshtastic.core.domain.usecase.settings.SetThemeUseCase
import org.meshtastic.core.model.ConnectionState
import org.meshtastic.core.model.MyNodeInfo
import org.meshtastic.core.model.Node
import org.meshtastic.core.model.NodeListDensity
import org.meshtastic.core.model.RadioController
import org.meshtastic.core.repository.FileService
import org.meshtastic.core.repository.MeshLogPrefs
@@ -223,4 +225,62 @@ class SettingsViewModel(
fun setShouldShowRole(value: Boolean) = uiPrefs.setShouldShowRole(value)
fun setShouldShowTelemetry(value: Boolean) = uiPrefs.setShouldShowTelemetry(value)
// Aggregated node list settings — nested combines because typed overloads max at 5 args
val nodeListSettings =
combine(
combine(
nodeListDensity,
shouldShowPower,
shouldShowLastHeard,
lastHeardIsRelative,
shouldShowLocation,
) { density, power, lastHeard, heardRelative, location ->
NodeListSettingsState(
density = NodeListDensity.fromName(density),
showPower = power,
showLastHeard = lastHeard,
lastHeardIsRelative = heardRelative,
showLocation = location,
)
},
combine(shouldShowHops, shouldShowSignal, shouldShowChannel, shouldShowRole, shouldShowTelemetry) {
hops,
signal,
channel,
role,
telemetry,
->
NodeListSettingsState(
showHops = hops,
showSignal = signal,
showChannel = channel,
showRole = role,
showTelemetry = telemetry,
)
},
) { first, second ->
first.copy(
showHops = second.showHops,
showSignal = second.showSignal,
showChannel = second.showChannel,
showRole = second.showRole,
showTelemetry = second.showTelemetry,
)
}
.stateInWhileSubscribed(initialValue = NodeListSettingsState())
}
/** Aggregated state for node list display settings to reduce recomposition overhead. */
data class NodeListSettingsState(
val density: NodeListDensity = NodeListDensity.COMPLETE,
val showPower: Boolean = false,
val showLastHeard: Boolean = false,
val lastHeardIsRelative: Boolean = false,
val showLocation: Boolean = false,
val showHops: Boolean = false,
val showSignal: Boolean = false,
val showChannel: Boolean = false,
val showRole: Boolean = false,
val showTelemetry: Boolean = false,
)

View File

@@ -22,6 +22,8 @@ import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.Card
import androidx.compose.material3.CardDefaults
import androidx.compose.material3.HorizontalDivider
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.SegmentedButton
@@ -57,6 +59,7 @@ import org.meshtastic.core.resources.node_layout_signal_direct_only
import org.meshtastic.core.ui.component.NodeItem
import org.meshtastic.core.ui.component.NodeItemCompact
import org.meshtastic.core.ui.component.SwitchPreference
import org.meshtastic.feature.settings.NodeListSettingsState
import org.meshtastic.proto.Config
import org.meshtastic.proto.DeviceMetrics
import org.meshtastic.proto.EnvironmentMetrics
@@ -68,25 +71,16 @@ import org.meshtastic.proto.User
@Composable
@Suppress("LongParameterList", "LongMethod")
fun NodeLayoutSettings(
density: NodeListDensity,
state: NodeListSettingsState,
onDensityChange: (NodeListDensity) -> Unit,
showPower: Boolean,
onShowPowerChange: (Boolean) -> Unit,
showLastHeard: Boolean,
onShowLastHeardChange: (Boolean) -> Unit,
lastHeardIsRelative: Boolean,
onLastHeardIsRelativeChange: (Boolean) -> Unit,
showLocation: Boolean,
onShowLocationChange: (Boolean) -> Unit,
showHops: Boolean,
onShowHopsChange: (Boolean) -> Unit,
showSignal: Boolean,
onShowSignalChange: (Boolean) -> Unit,
showChannel: Boolean,
onShowChannelChange: (Boolean) -> Unit,
showRole: Boolean,
onShowRoleChange: (Boolean) -> Unit,
showTelemetry: Boolean,
onShowTelemetryChange: (Boolean) -> Unit,
modifier: Modifier = Modifier,
) {
@@ -104,7 +98,7 @@ fun NodeLayoutSettings(
SegmentedButton(
shape = SegmentedButtonDefaults.itemShape(index, NodeListDensity.entries.size),
onClick = { onDensityChange(option) },
selected = density == option,
selected = state.density == option,
label = { Text(label) },
)
}
@@ -122,7 +116,7 @@ fun NodeLayoutSettings(
val localNode = remember { previewLocalNode() }
Box(modifier = Modifier.animateContentSize().padding(bottom = 8.dp)) {
when (density) {
when (state.density) {
NodeListDensity.COMPLETE ->
NodeItem(
thisNode = localNode,
@@ -130,7 +124,7 @@ fun NodeLayoutSettings(
distanceUnits = 0,
tempInFahrenheit = false,
connectionState = ConnectionState.Connected,
showTelemetry = showTelemetry,
showTelemetry = state.showTelemetry,
)
NodeListDensity.COMPACT ->
@@ -138,15 +132,15 @@ fun NodeLayoutSettings(
thisNode = localNode,
thatNode = previewNode,
distanceUnits = 0,
showPower = showPower,
showLastHeard = showLastHeard,
lastHeardIsRelative = lastHeardIsRelative,
showLocation = showLocation,
showHops = showHops,
showSignal = showSignal,
showChannel = showChannel,
showRole = showRole,
showTelemetry = showTelemetry,
showPower = state.showPower,
showLastHeard = state.showLastHeard,
lastHeardIsRelative = state.lastHeardIsRelative,
showLocation = state.showLocation,
showHops = state.showHops,
showSignal = state.showSignal,
showChannel = state.showChannel,
showRole = state.showRole,
showTelemetry = state.showTelemetry,
)
}
}
@@ -157,12 +151,12 @@ fun NodeLayoutSettings(
// Shared toggle — applies to both layouts
SwitchPreference(
title = stringResource(Res.string.node_layout_log_icons),
checked = showTelemetry,
checked = state.showTelemetry,
enabled = true,
onCheckedChange = onShowTelemetryChange,
)
if (density == NodeListDensity.COMPLETE) {
if (state.density == NodeListDensity.COMPLETE) {
Text(
text = stringResource(Res.string.node_layout_complete_description),
style = MaterialTheme.typography.bodyMedium,
@@ -176,56 +170,62 @@ fun NodeLayoutSettings(
text = stringResource(Res.string.node_layout_compact_fields_header),
style = MaterialTheme.typography.labelMedium,
color = MaterialTheme.colorScheme.onSurfaceVariant,
modifier = Modifier.padding(start = 16.dp, top = 12.dp, bottom = 4.dp),
)
SwitchPreference(
title = stringResource(Res.string.node_layout_power),
checked = showPower,
enabled = true,
onCheckedChange = onShowPowerChange,
)
SwitchPreference(
title = stringResource(Res.string.node_layout_last_heard_time),
checked = showLastHeard,
enabled = true,
onCheckedChange = onShowLastHeardChange,
)
SwitchPreference(
title = stringResource(Res.string.node_layout_relative_last_heard),
checked = lastHeardIsRelative,
enabled = showLastHeard,
onCheckedChange = onLastHeardIsRelativeChange,
)
SwitchPreference(
title = stringResource(Res.string.node_layout_distance_and_bearing),
checked = showLocation,
enabled = true,
onCheckedChange = onShowLocationChange,
)
SwitchPreference(
title = stringResource(Res.string.node_layout_hops_away),
checked = showHops,
enabled = true,
onCheckedChange = onShowHopsChange,
)
SwitchPreference(
title = stringResource(Res.string.node_layout_signal_direct_only),
checked = showSignal,
enabled = true,
onCheckedChange = onShowSignalChange,
)
SwitchPreference(
title = stringResource(Res.string.node_layout_channel),
checked = showChannel,
enabled = true,
onCheckedChange = onShowChannelChange,
)
SwitchPreference(
title = stringResource(Res.string.node_layout_device_role),
checked = showRole,
enabled = true,
onCheckedChange = onShowRoleChange,
modifier = Modifier.padding(start = 16.dp, top = 12.dp, bottom = 8.dp),
)
Card(
modifier = Modifier.fillMaxWidth().padding(horizontal = 16.dp),
colors = CardDefaults.cardColors(containerColor = MaterialTheme.colorScheme.surfaceContainerLow),
) {
SwitchPreference(
title = stringResource(Res.string.node_layout_power),
checked = state.showPower,
enabled = true,
onCheckedChange = onShowPowerChange,
)
SwitchPreference(
title = stringResource(Res.string.node_layout_last_heard_time),
checked = state.showLastHeard,
enabled = true,
onCheckedChange = onShowLastHeardChange,
)
SwitchPreference(
title = stringResource(Res.string.node_layout_relative_last_heard),
checked = state.lastHeardIsRelative,
enabled = state.showLastHeard,
onCheckedChange = onLastHeardIsRelativeChange,
)
SwitchPreference(
title = stringResource(Res.string.node_layout_distance_and_bearing),
checked = state.showLocation,
enabled = true,
onCheckedChange = onShowLocationChange,
)
SwitchPreference(
title = stringResource(Res.string.node_layout_hops_away),
checked = state.showHops,
enabled = true,
onCheckedChange = onShowHopsChange,
)
SwitchPreference(
title = stringResource(Res.string.node_layout_signal_direct_only),
checked = state.showSignal,
enabled = true,
onCheckedChange = onShowSignalChange,
)
SwitchPreference(
title = stringResource(Res.string.node_layout_channel),
checked = state.showChannel,
enabled = true,
onCheckedChange = onShowChannelChange,
)
SwitchPreference(
title = stringResource(Res.string.node_layout_device_role),
checked = state.showRole,
enabled = true,
onCheckedChange = onShowRoleChange,
)
}
Spacer(modifier = Modifier.height(16.dp))
}
}
}

View File

@@ -33,6 +33,7 @@ import org.meshtastic.core.model.NodeListDensity
import org.meshtastic.core.ui.component.NodeItem
import org.meshtastic.core.ui.component.NodeItemCompact
import org.meshtastic.core.ui.theme.AppTheme
import org.meshtastic.feature.settings.NodeListSettingsState
@PreviewLightDark
@Composable
@@ -40,25 +41,28 @@ fun NodeLayoutSettingsCompactPreview() {
AppTheme {
Surface {
NodeLayoutSettings(
density = NodeListDensity.COMPACT,
state =
NodeListSettingsState(
density = NodeListDensity.COMPACT,
showPower = true,
showLastHeard = true,
lastHeardIsRelative = true,
showLocation = true,
showHops = true,
showSignal = true,
showChannel = false,
showRole = true,
showTelemetry = true,
),
onDensityChange = {},
showPower = true,
onShowPowerChange = {},
showLastHeard = true,
onShowLastHeardChange = {},
lastHeardIsRelative = true,
onLastHeardIsRelativeChange = {},
showLocation = true,
onShowLocationChange = {},
showHops = true,
onShowHopsChange = {},
showSignal = true,
onShowSignalChange = {},
showChannel = false,
onShowChannelChange = {},
showRole = true,
onShowRoleChange = {},
showTelemetry = true,
onShowTelemetryChange = {},
)
}
@@ -71,25 +75,28 @@ fun NodeLayoutSettingsCompletePreview() {
AppTheme {
Surface {
NodeLayoutSettings(
density = NodeListDensity.COMPLETE,
state =
NodeListSettingsState(
density = NodeListDensity.COMPLETE,
showPower = true,
showLastHeard = true,
lastHeardIsRelative = true,
showLocation = true,
showHops = true,
showSignal = true,
showChannel = true,
showRole = true,
showTelemetry = true,
),
onDensityChange = {},
showPower = true,
onShowPowerChange = {},
showLastHeard = true,
onShowLastHeardChange = {},
lastHeardIsRelative = true,
onLastHeardIsRelativeChange = {},
showLocation = true,
onShowLocationChange = {},
showHops = true,
onShowHopsChange = {},
showSignal = true,
onShowSignalChange = {},
showChannel = true,
onShowChannelChange = {},
showRole = true,
onShowRoleChange = {},
showTelemetry = true,
onShowTelemetryChange = {},
)
}
@@ -103,25 +110,28 @@ fun NodeLayoutSettingsCompactMinimalPreview() {
AppTheme {
Surface {
NodeLayoutSettings(
density = NodeListDensity.COMPACT,
state =
NodeListSettingsState(
density = NodeListDensity.COMPACT,
showPower = false,
showLastHeard = true,
lastHeardIsRelative = true,
showLocation = false,
showHops = false,
showSignal = true,
showChannel = false,
showRole = false,
showTelemetry = false,
),
onDensityChange = {},
showPower = false,
onShowPowerChange = {},
showLastHeard = true,
onShowLastHeardChange = {},
lastHeardIsRelative = true,
onLastHeardIsRelativeChange = {},
showLocation = false,
onShowLocationChange = {},
showHops = false,
onShowHopsChange = {},
showSignal = true,
onShowSignalChange = {},
showChannel = false,
onShowChannelChange = {},
showRole = false,
onShowRoleChange = {},
showTelemetry = false,
onShowTelemetryChange = {},
)
}

View File

@@ -34,6 +34,7 @@ import org.meshtastic.feature.settings.AboutScreen
import org.meshtastic.feature.settings.AdministrationScreen
import org.meshtastic.feature.settings.DeviceConfigurationScreen
import org.meshtastic.feature.settings.ModuleConfigurationScreen
import org.meshtastic.feature.settings.NodeListScreen
import org.meshtastic.feature.settings.SettingsViewModel
import org.meshtastic.feature.settings.debugging.DebugScreen
import org.meshtastic.feature.settings.debugging.DebugViewModel
@@ -78,9 +79,7 @@ fun getRadioConfigViewModel(backStack: NavBackStack<NavKey>, destNumOverride: In
?: remember(backStack.toList()) {
backStack.lastOrNull { it is SettingsRoute.Settings }?.let { (it as SettingsRoute.Settings).destNum }
}
return koinViewModel<RadioConfigViewModel>(key = destNum?.toString()) {
parametersOf(destNum)
}
return koinViewModel<RadioConfigViewModel>(key = destNum?.toString()) { parametersOf(destNum) }
}
@Suppress("LongMethod", "CyclomaticComplexMethod")
@@ -243,6 +242,14 @@ fun EntryProviderScope<NavKey>.settingsGraph(backStack: NavBackStack<NavKey>) {
val viewModel: FilterSettingsViewModel = koinViewModel()
FilterSettingsScreen(viewModel = viewModel, onBack = dropUnlessResumed { backStack.removeLastOrNull() })
}
entry<SettingsRoute.NodeList> {
val settingsViewModel: SettingsViewModel = koinViewModel()
NodeListScreen(
settingsViewModel = settingsViewModel,
onNavigateUp = dropUnlessResumed { backStack.removeLastOrNull() },
)
}
}
/** Expect declaration for the platform-specific settings main screen. */

View File

@@ -52,6 +52,7 @@ import org.meshtastic.core.resources.help_and_documentation
import org.meshtastic.core.resources.info
import org.meshtastic.core.resources.modules_already_unlocked
import org.meshtastic.core.resources.modules_unlocked
import org.meshtastic.core.resources.node_layout_section_title
import org.meshtastic.core.resources.preferences_language
import org.meshtastic.core.resources.remotely_administrating
import org.meshtastic.core.resources.theme
@@ -65,13 +66,13 @@ import org.meshtastic.core.ui.icon.FormatPaint
import org.meshtastic.core.ui.icon.HelpOutline
import org.meshtastic.core.ui.icon.Info
import org.meshtastic.core.ui.icon.Language
import org.meshtastic.core.ui.icon.List
import org.meshtastic.core.ui.icon.Memory
import org.meshtastic.core.ui.icon.MeshtasticIcons
import org.meshtastic.core.ui.icon.Wifi
import org.meshtastic.core.ui.util.rememberShowToastResource
import org.meshtastic.feature.settings.component.ExpressiveSection
import org.meshtastic.feature.settings.component.HomoglyphSetting
import org.meshtastic.feature.settings.component.NodeLayoutSettings
import org.meshtastic.feature.settings.component.NotificationSection
import org.meshtastic.feature.settings.component.ThemePickerDialog
import org.meshtastic.feature.settings.navigation.ConfigRoute
@@ -203,39 +204,14 @@ fun DesktopSettingsScreen(
)
}
val densityName by settingsViewModel.nodeListDensity.collectAsStateWithLifecycle()
val density = org.meshtastic.core.model.NodeListDensity.fromName(densityName)
val showPower by settingsViewModel.shouldShowPower.collectAsStateWithLifecycle()
val showLastHeard by settingsViewModel.shouldShowLastHeard.collectAsStateWithLifecycle()
val lastHeardRelative by settingsViewModel.lastHeardIsRelative.collectAsStateWithLifecycle()
val showLocation by settingsViewModel.shouldShowLocation.collectAsStateWithLifecycle()
val showHops by settingsViewModel.shouldShowHops.collectAsStateWithLifecycle()
val showSignal by settingsViewModel.shouldShowSignal.collectAsStateWithLifecycle()
val showChannel by settingsViewModel.shouldShowChannel.collectAsStateWithLifecycle()
val showRole by settingsViewModel.shouldShowRole.collectAsStateWithLifecycle()
val showTelemetry by settingsViewModel.shouldShowTelemetry.collectAsStateWithLifecycle()
NodeLayoutSettings(
density = density,
onDensityChange = { settingsViewModel.setNodeListDensity(it.name) },
showPower = showPower,
onShowPowerChange = { settingsViewModel.setShouldShowPower(it) },
showLastHeard = showLastHeard,
onShowLastHeardChange = { settingsViewModel.setShouldShowLastHeard(it) },
lastHeardIsRelative = lastHeardRelative,
onLastHeardIsRelativeChange = { settingsViewModel.setLastHeardIsRelative(it) },
showLocation = showLocation,
onShowLocationChange = { settingsViewModel.setShouldShowLocation(it) },
showHops = showHops,
onShowHopsChange = { settingsViewModel.setShouldShowHops(it) },
showSignal = showSignal,
onShowSignalChange = { settingsViewModel.setShouldShowSignal(it) },
showChannel = showChannel,
onShowChannelChange = { settingsViewModel.setShouldShowChannel(it) },
showRole = showRole,
onShowRoleChange = { settingsViewModel.setShouldShowRole(it) },
showTelemetry = showTelemetry,
onShowTelemetryChange = { settingsViewModel.setShouldShowTelemetry(it) },
)
ExpressiveSection(title = stringResource(Res.string.node_layout_section_title)) {
ListItem(
text = stringResource(Res.string.node_layout_section_title),
leadingIcon = MeshtasticIcons.List,
) {
onNavigate(SettingsRoute.NodeList)
}
}
ExpressiveSection(title = stringResource(Res.string.wifi_devices)) {
ListItem(text = stringResource(Res.string.wifi_devices), leadingIcon = MeshtasticIcons.Wifi) {

View File

Binary file not shown.

Before

Width:  |  Height:  |  Size: 115 KiB

After

Width:  |  Height:  |  Size: 121 KiB

View File

Binary file not shown.

Before

Width:  |  Height:  |  Size: 115 KiB

After

Width:  |  Height:  |  Size: 120 KiB

View File

Binary file not shown.

Before

Width:  |  Height:  |  Size: 135 KiB

After

Width:  |  Height:  |  Size: 139 KiB

View File

Binary file not shown.

Before

Width:  |  Height:  |  Size: 133 KiB

After

Width:  |  Height:  |  Size: 137 KiB