mirror of
https://github.com/meshtastic/Meshtastic-Android.git
synced 2026-04-20 22:23:37 +00:00
feat: add nodelist sort options
This commit is contained in:
parent
f84a75569d
commit
4ceb4c5199
17 changed files with 368 additions and 89 deletions
|
|
@ -2,6 +2,7 @@ package com.geeksville.mesh.model
|
|||
|
||||
import androidx.lifecycle.Lifecycle
|
||||
import androidx.lifecycle.coroutineScope
|
||||
import com.geeksville.mesh.MeshProtos
|
||||
import com.geeksville.mesh.MyNodeInfo
|
||||
import com.geeksville.mesh.NodeInfo
|
||||
import com.geeksville.mesh.database.dao.NodeInfoDao
|
||||
|
|
@ -20,7 +21,6 @@ class NodeDB @Inject constructor(
|
|||
processLifecycle: Lifecycle,
|
||||
private val nodeInfoDao: NodeInfoDao,
|
||||
) {
|
||||
|
||||
// hardware info about our local device (can be null)
|
||||
private val _myNodeInfo = MutableStateFlow<MyNodeInfo?>(null)
|
||||
val myNodeInfo: StateFlow<MyNodeInfo?> get() = _myNodeInfo
|
||||
|
|
@ -58,8 +58,19 @@ class NodeDB @Inject constructor(
|
|||
.launchIn(processLifecycle.coroutineScope)
|
||||
}
|
||||
|
||||
fun getNodes(
|
||||
sort: NodeSortOption = NodeSortOption.LAST_HEARD,
|
||||
filter: String = "",
|
||||
includeUnknown: Boolean = true,
|
||||
) = nodeInfoDao.getNodes(
|
||||
sort = sort.sqlValue,
|
||||
filter = filter,
|
||||
includeUnknown = includeUnknown,
|
||||
unknownHwModel = MeshProtos.HardwareModel.UNSET
|
||||
)
|
||||
|
||||
fun myNodeInfoFlow(): Flow<MyNodeInfo?> = nodeInfoDao.getMyNodeInfo()
|
||||
fun nodeInfoFlow(): Flow<List<NodeInfo>> = nodeInfoDao.getNodes()
|
||||
|
||||
fun delNode(num: Int) {
|
||||
nodeInfoDao.delNode(num)
|
||||
}
|
||||
|
|
|
|||
12
app/src/main/java/com/geeksville/mesh/model/SortOption.kt
Normal file
12
app/src/main/java/com/geeksville/mesh/model/SortOption.kt
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
package com.geeksville.mesh.model
|
||||
|
||||
import androidx.annotation.StringRes
|
||||
import com.geeksville.mesh.R
|
||||
|
||||
enum class NodeSortOption(val sqlValue: String, @StringRes val stringRes: Int) {
|
||||
LAST_HEARD("last_heard", R.string.node_sort_last_heard),
|
||||
ALPHABETICAL("alpha", R.string.node_sort_alpha),
|
||||
DISTANCE("distance", R.string.node_sort_distance),
|
||||
CHANNEL("channel", R.string.node_sort_channel),
|
||||
VIA_MQTT("via_mqtt", R.string.node_sort_via_mqtt),
|
||||
}
|
||||
|
|
@ -32,6 +32,7 @@ import kotlinx.coroutines.Dispatchers
|
|||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||
import kotlinx.coroutines.flow.combine
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.SharingStarted.Companion.WhileSubscribed
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import kotlinx.coroutines.flow.filterNotNull
|
||||
import kotlinx.coroutines.flow.first
|
||||
|
|
@ -39,6 +40,7 @@ import kotlinx.coroutines.flow.flatMapLatest
|
|||
import kotlinx.coroutines.flow.launchIn
|
||||
import kotlinx.coroutines.flow.mapLatest
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
import kotlinx.coroutines.flow.stateIn
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
import java.io.BufferedWriter
|
||||
|
|
@ -97,6 +99,16 @@ internal fun getChannelList(
|
|||
}
|
||||
}
|
||||
|
||||
data class NodesUiState(
|
||||
val sort: NodeSortOption = NodeSortOption.LAST_HEARD,
|
||||
val filter: String = "",
|
||||
val includeUnknown: Boolean = false,
|
||||
) {
|
||||
companion object {
|
||||
val Empty = NodesUiState()
|
||||
}
|
||||
}
|
||||
|
||||
@HiltViewModel
|
||||
class UIViewModel @Inject constructor(
|
||||
private val app: Application,
|
||||
|
|
@ -138,18 +150,43 @@ class UIViewModel @Inject constructor(
|
|||
private val _focusedNode = MutableStateFlow<NodeInfo?>(null)
|
||||
val focusedNode: StateFlow<NodeInfo?> = _focusedNode
|
||||
|
||||
private val _nodeFilterText = MutableStateFlow("")
|
||||
val nodeFilterText: StateFlow<String> = _nodeFilterText
|
||||
private val nodeFilterText = MutableStateFlow("")
|
||||
private val nodeSortOption = MutableStateFlow(NodeSortOption.LAST_HEARD)
|
||||
private val includeUnknown = MutableStateFlow(false)
|
||||
|
||||
val filteredNodes = nodeDB.nodeDBbyNum.combine(_nodeFilterText) { nodes, filterText ->
|
||||
if (filterText.isBlank()) return@combine nodes
|
||||
|
||||
nodes.filter { entry ->
|
||||
entry.value.user?.longName?.contains(filterText, ignoreCase = true) == true ||
|
||||
entry.value.user?.shortName?.contains(filterText, ignoreCase = true) == true
|
||||
}
|
||||
fun setSortOption(sort: NodeSortOption) {
|
||||
nodeSortOption.value = sort
|
||||
}
|
||||
|
||||
fun toggleIncludeUnknown() {
|
||||
includeUnknown.value = !includeUnknown.value
|
||||
}
|
||||
|
||||
val nodeViewState: StateFlow<NodesUiState> = combine(
|
||||
nodeFilterText,
|
||||
nodeSortOption,
|
||||
includeUnknown,
|
||||
) { filter, sort, includeUnknown ->
|
||||
NodesUiState(
|
||||
sort = sort,
|
||||
filter = filter,
|
||||
includeUnknown = includeUnknown,
|
||||
)
|
||||
}.stateIn(
|
||||
scope = viewModelScope,
|
||||
started = WhileSubscribed(),
|
||||
initialValue = NodesUiState.Empty,
|
||||
)
|
||||
|
||||
@OptIn(ExperimentalCoroutinesApi::class)
|
||||
val filteredNodes: StateFlow<List<NodeInfo>> = nodeViewState.flatMapLatest { state ->
|
||||
nodeDB.getNodes(state.sort, state.filter, state.includeUnknown)
|
||||
}.stateIn(
|
||||
scope = viewModelScope,
|
||||
started = WhileSubscribed(5_000),
|
||||
initialValue = emptyList(),
|
||||
)
|
||||
|
||||
// hardware info about our local device (can be null)
|
||||
val myNodeInfo: StateFlow<MyNodeInfo?> get() = nodeDB.myNodeInfo
|
||||
val ourNodeInfo: StateFlow<NodeInfo?> get() = nodeDB.ourNodeInfo
|
||||
|
|
@ -596,7 +633,7 @@ class UIViewModel @Inject constructor(
|
|||
}
|
||||
|
||||
fun setNodeFilterText(text: String) {
|
||||
_nodeFilterText.value = text
|
||||
nodeFilterText.value = text
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue