fix #1484: Filter out ignored nodes from map (#1676)

* fix #1484: Filter out ignored nodes from map

- Created a new `filteredNodeList` `StateFlow` in `UIState.kt` that filters out nodes marked as ignored.
- Updated `MapFragment.kt` to use `filteredNodeList` instead of `nodeList`, ensuring that ignored nodes are not displayed on the map.

* Refactor: Remove ExperimentalCoroutinesApi opt-in and add it to compiler args

- Removes the `@OptIn(ExperimentalCoroutinesApi::class)` annotation from multiple files.
- Adds `-opt-in=kotlinx.coroutines.ExperimentalCoroutinesApi` to the `freeCompilerArgs` in the `build.gradle` file, enabling the use of Experimental Coroutines API project-wide without the need for per-file opt-ins.
- The coroutine api is now applied globally.

Signed-off-by: James Rich <james.a.rich@gmail.com>

* detekt

Signed-off-by: James Rich <2199651+jamesarich@users.noreply.github.com>

---------

Signed-off-by: James Rich <james.a.rich@gmail.com>
Signed-off-by: James Rich <2199651+jamesarich@users.noreply.github.com>
pull/1687/head
James Rich 2025-03-17 11:40:08 -05:00 zatwierdzone przez GitHub
rodzic 559b47355d
commit 8e5accd518
Nie znaleziono w bazie danych klucza dla tego podpisu
ID klucza GPG: B5690EEEBB952194
7 zmienionych plików z 16 dodań i 17 usunięć

Wyświetl plik

@ -96,7 +96,10 @@ android {
}
kotlinOptions {
jvmTarget = JavaVersion.VERSION_17.toString()
freeCompilerArgs += ['-opt-in=kotlin.RequiresOptIn']
freeCompilerArgs += [
'-opt-in=kotlin.RequiresOptIn',
'-opt-in=kotlinx.coroutines.ExperimentalCoroutinesApi'
]
}
lint {
abortOnError false

Wyświetl plik

@ -18,12 +18,11 @@
package com.geeksville.mesh.database
import com.geeksville.mesh.CoroutineDispatchers
import com.geeksville.mesh.Portnums
import com.geeksville.mesh.MeshProtos.MeshPacket
import com.geeksville.mesh.Portnums
import com.geeksville.mesh.TelemetryProtos.Telemetry
import com.geeksville.mesh.database.dao.MeshLogDao
import com.geeksville.mesh.database.entity.MeshLog
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.conflate
import kotlinx.coroutines.flow.distinctUntilChanged
@ -54,7 +53,6 @@ class MeshLogRepository @Inject constructor(
.toBuilder().setTime((log.received_date / MILLIS_TO_SECONDS).toInt()).build()
}.getOrNull()
@OptIn(ExperimentalCoroutinesApi::class)
fun getTelemetryFrom(nodeNum: Int): Flow<List<Telemetry>> =
meshLogDao.getLogsFrom(nodeNum, Portnums.PortNum.TELEMETRY_APP_VALUE, MAX_MESH_PACKETS)
.distinctUntilChanged()
@ -73,7 +71,6 @@ class MeshLogRepository @Inject constructor(
* Retrieves MeshPackets matching 'nodeNum' and 'portNum'.
* If 'portNum' is not specified, returns all MeshPackets. Otherwise, filters by 'portNum'.
*/
@OptIn(ExperimentalCoroutinesApi::class)
fun getMeshPacketsFrom(
nodeNum: Int,
portNum: Int = Portnums.PortNum.UNKNOWN_APP_VALUE,

Wyświetl plik

@ -28,7 +28,6 @@ import com.geeksville.mesh.database.entity.MyNodeEntity
import com.geeksville.mesh.database.entity.NodeEntity
import com.geeksville.mesh.model.Node
import com.geeksville.mesh.model.NodeSortOption
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
@ -65,7 +64,6 @@ class NodeRepository @Inject constructor(
.map { map -> map.mapValues { (_, it) -> it.toEntity() } }
// A map from nodeNum to Node
@OptIn(ExperimentalCoroutinesApi::class)
val nodeDBbyNum: StateFlow<Map<Int, Node>> = nodeInfoDao.nodeDBbyNum()
.mapLatest { map -> map.mapValues { (_, it) -> it.toModel() } }
.onEach {
@ -94,7 +92,6 @@ class NodeRepository @Inject constructor(
.setHwModel(MeshProtos.HardwareModel.UNSET)
.build()
@OptIn(ExperimentalCoroutinesApi::class)
fun getNodes(
sort: NodeSortOption = NodeSortOption.LAST_HEARD,
filter: String = "",

Wyświetl plik

@ -43,7 +43,6 @@ import com.geeksville.mesh.navigation.Route
import com.geeksville.mesh.repository.datastore.RadioConfigRepository
import com.geeksville.mesh.ui.map.MAP_STYLE_ID
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asFlow
@ -224,7 +223,6 @@ class MetricsViewModel @Inject constructor(
private var deviceHardwareList: List<DeviceHardware> = listOf()
init {
@OptIn(ExperimentalCoroutinesApi::class)
radioConfigRepository.nodeDBbyNum
.mapLatest { nodes -> nodes[destNum] }
.distinctUntilChanged()

Wyświetl plik

@ -63,7 +63,6 @@ import com.geeksville.mesh.util.getShortDate
import com.geeksville.mesh.util.positionToMeter
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
@ -235,7 +234,6 @@ class UIViewModel @Inject constructor(
initialValue = NodesUiState.Empty,
)
@OptIn(ExperimentalCoroutinesApi::class)
val nodeList: StateFlow<List<Node>> = nodesUiState.flatMapLatest { state ->
nodeDB.getNodes(state.sort, state.filter, state.includeUnknown)
}.stateIn(
@ -244,6 +242,16 @@ class UIViewModel @Inject constructor(
initialValue = emptyList(),
)
val filteredNodeList: StateFlow<List<Node>> = nodeList.mapLatest { list ->
list.filter { node ->
!node.isIgnored
}
}.stateIn(
scope = viewModelScope,
started = SharingStarted.WhileSubscribed(5_000),
initialValue = emptyList(),
)
// hardware info about our local device (can be null)
val myNodeInfo: StateFlow<MyNodeEntity?> get() = nodeDB.myNodeInfo
val ourNodeInfo: StateFlow<Node?> get() = nodeDB.ourNodeInfo
@ -328,11 +336,9 @@ class UIViewModel @Inject constructor(
initialValue = emptyList(),
)
@OptIn(ExperimentalCoroutinesApi::class)
fun getMessagesFrom(contactKey: String) = packetRepository.getMessagesFrom(contactKey)
.mapLatest { list -> list.map { it.toMessage(::getNode) } }
@OptIn(ExperimentalCoroutinesApi::class)
val waypoints = packetRepository.getWaypoints().mapLatest { list ->
list.associateBy { packet -> packet.data.waypoint!!.id }
.filterValues { it.data.waypoint!!.expire > System.currentTimeMillis() / 1000 }

Wyświetl plik

@ -304,7 +304,7 @@ fun MapView(
if (permissions.entries.all { it.value }) map.toggleMyLocation()
}
val nodes by model.nodeList.collectAsStateWithLifecycle()
val nodes by model.filteredNodeList.collectAsStateWithLifecycle()
val waypoints by model.waypoints.collectAsStateWithLifecycle(emptyMap())
val markerIcon = remember {

Wyświetl plik

@ -51,7 +51,6 @@ import com.geeksville.mesh.util.UiText
import com.google.protobuf.MessageLite
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.combine
@ -103,7 +102,6 @@ class RadioConfigViewModel @Inject constructor(
val currentDeviceProfile get() = _currentDeviceProfile.value
init {
@OptIn(ExperimentalCoroutinesApi::class)
radioConfigRepository.nodeDBbyNum
.mapLatest { nodes -> nodes[destNum] ?: nodes.values.firstOrNull() }
.distinctUntilChanged()