mirror of
https://github.com/meshtastic/Meshtastic-Android.git
synced 2026-04-20 22:23:37 +00:00
Feat/2412 ignored nodes (#2470)
Signed-off-by: DaneEvans <dane@goneepic.com> Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
This commit is contained in:
parent
ee99d79574
commit
5a6a1cb44a
4 changed files with 124 additions and 40 deletions
|
|
@ -160,6 +160,7 @@ data class NodesUiState(
|
|||
val distanceUnits: Int = 0,
|
||||
val tempInFahrenheit: Boolean = false,
|
||||
val showDetails: Boolean = false,
|
||||
val showIgnored: Boolean = false,
|
||||
) {
|
||||
companion object {
|
||||
val Empty = NodesUiState()
|
||||
|
|
@ -310,6 +311,12 @@ class UIViewModel @Inject constructor(
|
|||
private val showPrecisionCircleOnMap =
|
||||
MutableStateFlow(preferences.getBoolean("show-precision-circle-on-map", true))
|
||||
|
||||
private val showIgnored = MutableStateFlow(preferences.getBoolean("show-ignored", false))
|
||||
fun toggleShowIgnored() {
|
||||
showIgnored.value = !showIgnored.value
|
||||
preferences.edit { putBoolean("show-ignored", showIgnored.value) }
|
||||
}
|
||||
|
||||
fun setSortOption(sort: NodeSortOption) {
|
||||
nodeSortOption.value = sort
|
||||
preferences.edit { putInt("node-sort-option", sort.ordinal) }
|
||||
|
|
@ -355,6 +362,7 @@ class UIViewModel @Inject constructor(
|
|||
val includeUnknown: Boolean,
|
||||
val onlyOnline: Boolean,
|
||||
val onlyDirect: Boolean,
|
||||
val showIgnored: Boolean,
|
||||
)
|
||||
|
||||
val nodeFilterStateFlow: Flow<NodeFilterState> = combine(
|
||||
|
|
@ -362,8 +370,9 @@ class UIViewModel @Inject constructor(
|
|||
includeUnknown,
|
||||
onlyOnline,
|
||||
onlyDirect,
|
||||
) { filterText, includeUnknown, onlyOnline, onlyDirect ->
|
||||
NodeFilterState(filterText, includeUnknown, onlyOnline, onlyDirect)
|
||||
showIgnored,
|
||||
) { filterText, includeUnknown, onlyOnline, onlyDirect, showIgnored ->
|
||||
NodeFilterState(filterText, includeUnknown, onlyOnline, onlyDirect, showIgnored)
|
||||
}
|
||||
|
||||
val nodesUiState: StateFlow<NodesUiState> = combine(
|
||||
|
|
@ -382,6 +391,7 @@ class UIViewModel @Inject constructor(
|
|||
distanceUnits = profile.config.display.units.number,
|
||||
tempInFahrenheit = profile.moduleConfig.telemetry.environmentDisplayFahrenheit,
|
||||
showDetails = showDetails,
|
||||
showIgnored = filterFlow.showIgnored,
|
||||
)
|
||||
}.stateIn(
|
||||
scope = viewModelScope,
|
||||
|
|
@ -397,6 +407,9 @@ class UIViewModel @Inject constructor(
|
|||
|
||||
val nodeList: StateFlow<List<Node>> = nodesUiState.flatMapLatest { state ->
|
||||
nodeDB.getNodes(state.sort, state.filter, state.includeUnknown, state.onlyOnline, state.onlyDirect)
|
||||
.map { list ->
|
||||
list.filter { it.isIgnored == state.showIgnored }
|
||||
}
|
||||
}.stateIn(
|
||||
scope = viewModelScope,
|
||||
started = SharingStarted.WhileSubscribed(5_000),
|
||||
|
|
|
|||
|
|
@ -65,6 +65,8 @@ fun NodeScreen(
|
|||
|
||||
val nodes by model.nodeList.collectAsStateWithLifecycle()
|
||||
val ourNode by model.ourNodeInfo.collectAsStateWithLifecycle()
|
||||
val unfilteredNodes by model.unfilteredNodeList.collectAsStateWithLifecycle()
|
||||
val ignoredNodeCount = unfilteredNodes.count { it.isIgnored }
|
||||
|
||||
val listState = rememberLazyListState()
|
||||
|
||||
|
|
@ -114,6 +116,9 @@ fun NodeScreen(
|
|||
onToggleOnlyDirect = model::toggleOnlyDirect,
|
||||
showDetails = state.showDetails,
|
||||
onToggleShowDetails = model::toggleShowDetails,
|
||||
showIgnored = state.showIgnored,
|
||||
onToggleShowIgnored = model::toggleShowIgnored,
|
||||
ignoredNodeCount = ignoredNodeCount,
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -21,8 +21,10 @@ import androidx.compose.animation.AnimatedVisibility
|
|||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.defaultMinSize
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.heightIn
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.text.KeyboardActions
|
||||
|
|
@ -75,29 +77,54 @@ fun NodeFilterTextField(
|
|||
onToggleOnlyDirect: () -> Unit,
|
||||
showDetails: Boolean,
|
||||
onToggleShowDetails: () -> Unit,
|
||||
showIgnored: Boolean,
|
||||
onToggleShowIgnored: () -> Unit,
|
||||
ignoredNodeCount: Int,
|
||||
) {
|
||||
Row(
|
||||
modifier = modifier.background(MaterialTheme.colorScheme.background),
|
||||
) {
|
||||
NodeFilterTextField(
|
||||
filterText = filterText,
|
||||
onTextChange = onTextChange,
|
||||
modifier = Modifier.weight(1f)
|
||||
)
|
||||
Column(modifier = modifier.background(MaterialTheme.colorScheme.background)) {
|
||||
Row {
|
||||
NodeFilterTextField(
|
||||
filterText = filterText,
|
||||
onTextChange = onTextChange,
|
||||
modifier = Modifier.weight(1f)
|
||||
)
|
||||
|
||||
NodeSortButton(
|
||||
modifier = Modifier.align(Alignment.CenterVertically),
|
||||
currentSortOption = currentSortOption,
|
||||
onSortSelect = onSortSelect,
|
||||
includeUnknown = includeUnknown,
|
||||
onToggleIncludeUnknown = onToggleIncludeUnknown,
|
||||
onlyOnline = onlyOnline,
|
||||
onToggleOnlyOnline = onToggleOnlyOnline,
|
||||
onlyDirect = onlyDirect,
|
||||
onToggleOnlyDirect = onToggleOnlyDirect,
|
||||
showDetails = showDetails,
|
||||
onToggleShowDetails = onToggleShowDetails,
|
||||
)
|
||||
NodeSortButton(
|
||||
modifier = Modifier.align(Alignment.CenterVertically),
|
||||
currentSortOption = currentSortOption,
|
||||
onSortSelect = onSortSelect,
|
||||
toggles = NodeFilterToggles(
|
||||
includeUnknown = includeUnknown,
|
||||
onToggleIncludeUnknown = onToggleIncludeUnknown,
|
||||
onlyOnline = onlyOnline,
|
||||
onToggleOnlyOnline = onToggleOnlyOnline,
|
||||
onlyDirect = onlyDirect,
|
||||
onToggleOnlyDirect = onToggleOnlyDirect,
|
||||
showDetails = showDetails,
|
||||
onToggleShowDetails = onToggleShowDetails,
|
||||
showIgnored = showIgnored,
|
||||
onToggleShowIgnored = onToggleShowIgnored,
|
||||
ignoredNodeCount = ignoredNodeCount,
|
||||
),
|
||||
)
|
||||
}
|
||||
if (showIgnored) {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.background(MaterialTheme.colorScheme.surfaceDim)
|
||||
.clickable { onToggleShowIgnored() }
|
||||
.padding(vertical = 16.dp, horizontal = 24.dp)
|
||||
) {
|
||||
Text(
|
||||
text = stringResource(id = R.string.node_filter_ignored),
|
||||
style = MaterialTheme.typography.titleMedium,
|
||||
color = MaterialTheme.colorScheme.onSurface,
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
textAlign = androidx.compose.ui.text.style.TextAlign.Center,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -159,14 +186,7 @@ private fun NodeFilterTextField(
|
|||
private fun NodeSortButton(
|
||||
currentSortOption: NodeSortOption,
|
||||
onSortSelect: (NodeSortOption) -> Unit,
|
||||
includeUnknown: Boolean,
|
||||
onToggleIncludeUnknown: () -> Unit,
|
||||
onlyOnline: Boolean,
|
||||
onToggleOnlyOnline: () -> Unit,
|
||||
onlyDirect: Boolean,
|
||||
onToggleOnlyDirect: () -> Unit,
|
||||
showDetails: Boolean,
|
||||
onToggleShowDetails: () -> Unit,
|
||||
toggles: NodeFilterToggles,
|
||||
modifier: Modifier = Modifier,
|
||||
) = Box(modifier) {
|
||||
var expanded by remember { mutableStateOf(false) }
|
||||
|
|
@ -202,12 +222,12 @@ private fun NodeSortButton(
|
|||
HorizontalDivider()
|
||||
DropdownMenuItem(
|
||||
onClick = {
|
||||
onToggleIncludeUnknown()
|
||||
toggles.onToggleIncludeUnknown()
|
||||
expanded = false
|
||||
},
|
||||
text = {
|
||||
Row {
|
||||
AnimatedVisibility(visible = includeUnknown) {
|
||||
AnimatedVisibility(visible = toggles.includeUnknown) {
|
||||
Icon(
|
||||
imageVector = Icons.Default.Done,
|
||||
contentDescription = null,
|
||||
|
|
@ -222,12 +242,12 @@ private fun NodeSortButton(
|
|||
)
|
||||
DropdownMenuItem(
|
||||
onClick = {
|
||||
onToggleOnlyOnline()
|
||||
toggles.onToggleOnlyOnline()
|
||||
expanded = false
|
||||
},
|
||||
text = {
|
||||
Row {
|
||||
AnimatedVisibility(visible = onlyOnline) {
|
||||
AnimatedVisibility(visible = toggles.onlyOnline) {
|
||||
Icon(
|
||||
imageVector = Icons.Default.Done,
|
||||
contentDescription = null,
|
||||
|
|
@ -242,12 +262,12 @@ private fun NodeSortButton(
|
|||
)
|
||||
DropdownMenuItem(
|
||||
onClick = {
|
||||
onToggleOnlyDirect()
|
||||
toggles.onToggleOnlyDirect()
|
||||
expanded = false
|
||||
},
|
||||
text = {
|
||||
Row {
|
||||
AnimatedVisibility(visible = onlyDirect) {
|
||||
AnimatedVisibility(visible = toggles.onlyDirect) {
|
||||
Icon(
|
||||
imageVector = Icons.Default.Done,
|
||||
contentDescription = null,
|
||||
|
|
@ -263,12 +283,12 @@ private fun NodeSortButton(
|
|||
HorizontalDivider()
|
||||
DropdownMenuItem(
|
||||
onClick = {
|
||||
onToggleShowDetails()
|
||||
toggles.onToggleShowDetails()
|
||||
expanded = false
|
||||
},
|
||||
text = {
|
||||
Row {
|
||||
AnimatedVisibility(visible = showDetails) {
|
||||
AnimatedVisibility(visible = toggles.showDetails) {
|
||||
Icon(
|
||||
imageVector = Icons.Default.Done,
|
||||
contentDescription = null,
|
||||
|
|
@ -281,6 +301,34 @@ private fun NodeSortButton(
|
|||
}
|
||||
}
|
||||
)
|
||||
HorizontalDivider()
|
||||
DropdownMenuItem(
|
||||
onClick = {
|
||||
toggles.onToggleShowIgnored()
|
||||
expanded = false
|
||||
},
|
||||
text = {
|
||||
Row {
|
||||
AnimatedVisibility(visible = toggles.showIgnored) {
|
||||
Icon(
|
||||
imageVector = Icons.Default.Done,
|
||||
contentDescription = null,
|
||||
modifier = Modifier.padding(end = 4.dp),
|
||||
)
|
||||
}
|
||||
Text(
|
||||
text = stringResource(id = R.string.node_filter_show_ignored),
|
||||
)
|
||||
if (toggles.ignoredNodeCount > 0) {
|
||||
Text(
|
||||
text = " (${toggles.ignoredNodeCount})",
|
||||
color = MaterialTheme.colorScheme.primary,
|
||||
modifier = Modifier.padding(start = 4.dp),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -302,6 +350,23 @@ private fun NodeFilterTextFieldPreview() {
|
|||
onToggleOnlyDirect = {},
|
||||
showDetails = false,
|
||||
onToggleShowDetails = {},
|
||||
showIgnored = false,
|
||||
onToggleShowIgnored = {},
|
||||
ignoredNodeCount = 0,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
data class NodeFilterToggles(
|
||||
val includeUnknown: Boolean,
|
||||
val onToggleIncludeUnknown: () -> Unit,
|
||||
val onlyOnline: Boolean,
|
||||
val onToggleOnlyOnline: () -> Unit,
|
||||
val onlyDirect: Boolean,
|
||||
val onToggleOnlyDirect: () -> Unit,
|
||||
val showDetails: Boolean,
|
||||
val onToggleShowDetails: () -> Unit,
|
||||
val showIgnored: Boolean,
|
||||
val onToggleShowIgnored: () -> Unit,
|
||||
val ignoredNodeCount: Int,
|
||||
)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue