feat: add nodelist sort options

This commit is contained in:
andrekir 2024-05-27 09:56:26 -03:00 committed by Andre K
parent f84a75569d
commit 4ceb4c5199
17 changed files with 368 additions and 89 deletions

View file

@ -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)
}

View 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),
}

View file

@ -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
}
}