mirror of
https://github.com/meshtastic/Meshtastic-Android.git
synced 2026-04-20 22:23:37 +00:00
refactor: migrate preferences to DataStore and decouple core:domain for KMP (#4731)
This commit is contained in:
parent
87fdaa26ff
commit
b9b68d2779
113 changed files with 1790 additions and 1320 deletions
|
|
@ -20,10 +20,10 @@ import android.net.Uri
|
|||
import kotlinx.coroutines.flow.Flow
|
||||
import org.meshtastic.core.database.entity.FirmwareRelease
|
||||
import org.meshtastic.core.model.DeviceHardware
|
||||
import org.meshtastic.core.prefs.radio.RadioPrefs
|
||||
import org.meshtastic.core.prefs.radio.isBle
|
||||
import org.meshtastic.core.prefs.radio.isSerial
|
||||
import org.meshtastic.core.prefs.radio.isTcp
|
||||
import org.meshtastic.core.repository.RadioPrefs
|
||||
import org.meshtastic.core.repository.isBle
|
||||
import org.meshtastic.core.repository.isSerial
|
||||
import org.meshtastic.core.repository.isTcp
|
||||
import org.meshtastic.feature.firmware.ota.Esp32OtaUpdateHandler
|
||||
import java.io.File
|
||||
import javax.inject.Inject
|
||||
|
|
@ -90,7 +90,7 @@ constructor(
|
|||
private fun getTarget(address: String): String = when {
|
||||
radioPrefs.isSerial() -> ""
|
||||
radioPrefs.isBle() -> address
|
||||
radioPrefs.isTcp() -> extractIpFromAddress(radioPrefs.devAddr) ?: ""
|
||||
radioPrefs.isTcp() -> extractIpFromAddress(radioPrefs.devAddr.value) ?: ""
|
||||
else -> ""
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -45,12 +45,12 @@ import org.meshtastic.core.model.ConnectionState
|
|||
import org.meshtastic.core.model.DeviceHardware
|
||||
import org.meshtastic.core.model.MyNodeInfo
|
||||
import org.meshtastic.core.model.RadioController
|
||||
import org.meshtastic.core.prefs.radio.RadioPrefs
|
||||
import org.meshtastic.core.prefs.radio.isBle
|
||||
import org.meshtastic.core.prefs.radio.isSerial
|
||||
import org.meshtastic.core.prefs.radio.isTcp
|
||||
import org.meshtastic.core.repository.DeviceHardwareRepository
|
||||
import org.meshtastic.core.repository.NodeRepository
|
||||
import org.meshtastic.core.repository.RadioPrefs
|
||||
import org.meshtastic.core.repository.isBle
|
||||
import org.meshtastic.core.repository.isSerial
|
||||
import org.meshtastic.core.repository.isTcp
|
||||
import org.meshtastic.core.resources.Res
|
||||
import org.meshtastic.core.resources.firmware_update_battery_low
|
||||
import org.meshtastic.core.resources.firmware_update_copying
|
||||
|
|
@ -157,7 +157,7 @@ constructor(
|
|||
_state.value = FirmwareUpdateState.Checking
|
||||
runCatching {
|
||||
val ourNode = nodeRepository.myNodeInfo.value
|
||||
val address = radioPrefs.devAddr?.drop(1)
|
||||
val address = radioPrefs.devAddr.value?.drop(1)
|
||||
if (address == null || ourNode == null) {
|
||||
_state.value = FirmwareUpdateState.Error(getString(Res.string.firmware_update_no_device))
|
||||
return@launch
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ import org.meshtastic.core.common.BuildConfigProvider
|
|||
import org.meshtastic.core.model.DataPacket
|
||||
import org.meshtastic.core.model.RadioController
|
||||
import org.meshtastic.core.navigation.MapRoutes
|
||||
import org.meshtastic.core.prefs.map.MapPrefs
|
||||
import org.meshtastic.core.repository.MapPrefs
|
||||
import org.meshtastic.core.repository.NodeRepository
|
||||
import org.meshtastic.core.repository.PacketRepository
|
||||
import org.meshtastic.core.repository.RadioConfigRepository
|
||||
|
|
@ -52,9 +52,9 @@ constructor(
|
|||
val selectedWaypointId: StateFlow<Int?> = _selectedWaypointId.asStateFlow()
|
||||
|
||||
var mapStyleId: Int
|
||||
get() = mapPrefs.mapStyle
|
||||
get() = mapPrefs.mapStyle.value
|
||||
set(value) {
|
||||
mapPrefs.mapStyle = value
|
||||
mapPrefs.setMapStyle(value)
|
||||
}
|
||||
|
||||
val localConfig = radioConfigRepository.localConfigFlow.stateInWhileSubscribed(initialValue = LocalConfig())
|
||||
|
|
|
|||
|
|
@ -49,7 +49,7 @@ import org.meshtastic.core.datastore.UiPreferencesDataSource
|
|||
import org.meshtastic.core.model.RadioController
|
||||
import org.meshtastic.core.navigation.MapRoutes
|
||||
import org.meshtastic.core.prefs.map.GoogleMapsPrefs
|
||||
import org.meshtastic.core.prefs.map.MapPrefs
|
||||
import org.meshtastic.core.repository.MapPrefs
|
||||
import org.meshtastic.core.repository.NodeRepository
|
||||
import org.meshtastic.core.repository.PacketRepository
|
||||
import org.meshtastic.core.repository.RadioConfigRepository
|
||||
|
|
@ -96,9 +96,9 @@ constructor(
|
|||
val selectedWaypointId: StateFlow<Int?> = _selectedWaypointId.asStateFlow()
|
||||
|
||||
private val targetLatLng =
|
||||
googleMapsPrefs.cameraTargetLat
|
||||
googleMapsPrefs.cameraTargetLat.value
|
||||
.takeIf { it != 0.0 }
|
||||
?.let { lat -> googleMapsPrefs.cameraTargetLng.takeIf { it != 0.0 }?.let { lng -> LatLng(lat, lng) } }
|
||||
?.let { lat -> googleMapsPrefs.cameraTargetLng.value.takeIf { it != 0.0 }?.let { lng -> LatLng(lat, lng) } }
|
||||
?: ourNodeInfo.value?.position?.toLatLng()
|
||||
?: LatLng(0.0, 0.0)
|
||||
|
||||
|
|
@ -107,9 +107,9 @@ constructor(
|
|||
position =
|
||||
CameraPosition(
|
||||
targetLatLng,
|
||||
googleMapsPrefs.cameraZoom,
|
||||
googleMapsPrefs.cameraTilt,
|
||||
googleMapsPrefs.cameraBearing,
|
||||
googleMapsPrefs.cameraZoom.value,
|
||||
googleMapsPrefs.cameraTilt.value,
|
||||
googleMapsPrefs.cameraBearing.value,
|
||||
),
|
||||
)
|
||||
|
||||
|
|
@ -222,7 +222,7 @@ constructor(
|
|||
) {
|
||||
_selectedCustomTileProviderUrl.value = null
|
||||
// Also clear from prefs
|
||||
googleMapsPrefs.selectedCustomTileUrl = null
|
||||
googleMapsPrefs.setSelectedCustomTileUrl(null)
|
||||
}
|
||||
|
||||
if (configToRemove.localUri != null) {
|
||||
|
|
@ -238,28 +238,28 @@ constructor(
|
|||
if (!config.isLocal && !isValidTileUrlTemplate(config.urlTemplate)) {
|
||||
Logger.withTag("MapViewModel").w("Attempted to select invalid URL template: ${config.urlTemplate}")
|
||||
_selectedCustomTileProviderUrl.value = null
|
||||
googleMapsPrefs.selectedCustomTileUrl = null
|
||||
googleMapsPrefs.setSelectedCustomTileUrl(null)
|
||||
return
|
||||
}
|
||||
// Use localUri if present, otherwise urlTemplate
|
||||
val selectedUrl = config.localUri ?: config.urlTemplate
|
||||
_selectedCustomTileProviderUrl.value = selectedUrl
|
||||
_selectedGoogleMapType.value = MapType.NONE
|
||||
googleMapsPrefs.selectedCustomTileUrl = selectedUrl
|
||||
googleMapsPrefs.selectedGoogleMapType = null
|
||||
googleMapsPrefs.setSelectedCustomTileUrl(selectedUrl)
|
||||
googleMapsPrefs.setSelectedGoogleMapType(null)
|
||||
} else {
|
||||
_selectedCustomTileProviderUrl.value = null
|
||||
_selectedGoogleMapType.value = MapType.NORMAL
|
||||
googleMapsPrefs.selectedCustomTileUrl = null
|
||||
googleMapsPrefs.selectedGoogleMapType = MapType.NORMAL.name
|
||||
googleMapsPrefs.setSelectedCustomTileUrl(null)
|
||||
googleMapsPrefs.setSelectedGoogleMapType(MapType.NORMAL.name)
|
||||
}
|
||||
}
|
||||
|
||||
fun setSelectedGoogleMapType(mapType: MapType) {
|
||||
_selectedGoogleMapType.value = mapType
|
||||
_selectedCustomTileProviderUrl.value = null // Clear custom selection
|
||||
googleMapsPrefs.selectedGoogleMapType = mapType.name
|
||||
googleMapsPrefs.selectedCustomTileUrl = null
|
||||
googleMapsPrefs.setSelectedGoogleMapType(mapType.name)
|
||||
googleMapsPrefs.setSelectedCustomTileUrl(null)
|
||||
}
|
||||
|
||||
private var currentTileProvider: TileProvider? = null
|
||||
|
|
@ -354,16 +354,16 @@ constructor(
|
|||
|
||||
fun saveCameraPosition(cameraPosition: CameraPosition) {
|
||||
viewModelScope.launch {
|
||||
googleMapsPrefs.cameraTargetLat = cameraPosition.target.latitude
|
||||
googleMapsPrefs.cameraTargetLng = cameraPosition.target.longitude
|
||||
googleMapsPrefs.cameraZoom = cameraPosition.zoom
|
||||
googleMapsPrefs.cameraTilt = cameraPosition.tilt
|
||||
googleMapsPrefs.cameraBearing = cameraPosition.bearing
|
||||
googleMapsPrefs.setCameraTargetLat(cameraPosition.target.latitude)
|
||||
googleMapsPrefs.setCameraTargetLng(cameraPosition.target.longitude)
|
||||
googleMapsPrefs.setCameraZoom(cameraPosition.zoom)
|
||||
googleMapsPrefs.setCameraTilt(cameraPosition.tilt)
|
||||
googleMapsPrefs.setCameraBearing(cameraPosition.bearing)
|
||||
}
|
||||
}
|
||||
|
||||
private fun loadPersistedMapType() {
|
||||
val savedCustomUrl = googleMapsPrefs.selectedCustomTileUrl
|
||||
val savedCustomUrl = googleMapsPrefs.selectedCustomTileUrl.value
|
||||
if (savedCustomUrl != null) {
|
||||
// Check if this custom provider still exists
|
||||
if (
|
||||
|
|
@ -375,18 +375,18 @@ constructor(
|
|||
MapType.NONE // MapType.NONE to hide google basemap when using custom provider
|
||||
} else {
|
||||
// The saved custom URL is no longer valid or doesn't exist, remove preference
|
||||
googleMapsPrefs.selectedCustomTileUrl = null
|
||||
googleMapsPrefs.setSelectedCustomTileUrl(null)
|
||||
// Fallback to default Google Map type
|
||||
_selectedGoogleMapType.value = MapType.NORMAL
|
||||
}
|
||||
} else {
|
||||
val savedGoogleMapTypeName = googleMapsPrefs.selectedGoogleMapType
|
||||
val savedGoogleMapTypeName = googleMapsPrefs.selectedGoogleMapType.value
|
||||
try {
|
||||
_selectedGoogleMapType.value = MapType.valueOf(savedGoogleMapTypeName ?: MapType.NORMAL.name)
|
||||
} catch (e: IllegalArgumentException) {
|
||||
Logger.e(e) { "Invalid saved Google Map type: $savedGoogleMapTypeName" }
|
||||
_selectedGoogleMapType.value = MapType.NORMAL // Fallback in case of invalid stored name
|
||||
googleMapsPrefs.selectedGoogleMapType = null
|
||||
googleMapsPrefs.setSelectedGoogleMapType(null)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -399,7 +399,7 @@ constructor(
|
|||
val persistedLayerFiles = layersDir.listFiles()
|
||||
|
||||
if (persistedLayerFiles != null) {
|
||||
val hiddenLayerUrls = googleMapsPrefs.hiddenLayerUrls
|
||||
val hiddenLayerUrls = googleMapsPrefs.hiddenLayerUrls.value
|
||||
val loadedItems =
|
||||
persistedLayerFiles.mapNotNull { file ->
|
||||
if (file.isFile) {
|
||||
|
|
@ -429,7 +429,7 @@ constructor(
|
|||
}
|
||||
|
||||
val networkItems =
|
||||
googleMapsPrefs.networkMapLayers.mapNotNull { networkString ->
|
||||
googleMapsPrefs.networkMapLayers.value.mapNotNull { networkString ->
|
||||
try {
|
||||
val parts = networkString.split("|:|")
|
||||
if (parts.size == 3) {
|
||||
|
|
@ -532,7 +532,7 @@ constructor(
|
|||
_mapLayers.value = _mapLayers.value + newItem
|
||||
|
||||
val networkLayerString = "${newItem.id}|:|${newItem.name}|:|${newItem.uri}"
|
||||
googleMapsPrefs.networkMapLayers = googleMapsPrefs.networkMapLayers + networkLayerString
|
||||
googleMapsPrefs.setNetworkMapLayers(googleMapsPrefs.networkMapLayers.value + networkLayerString)
|
||||
} catch (e: Exception) {
|
||||
_errorFlow.emit("Invalid URL.")
|
||||
}
|
||||
|
|
@ -572,9 +572,9 @@ constructor(
|
|||
|
||||
toggledLayer?.let {
|
||||
if (it.isVisible) {
|
||||
googleMapsPrefs.hiddenLayerUrls -= it.uri.toString()
|
||||
googleMapsPrefs.setHiddenLayerUrls(googleMapsPrefs.hiddenLayerUrls.value - it.uri.toString())
|
||||
} else {
|
||||
googleMapsPrefs.hiddenLayerUrls += it.uri.toString()
|
||||
googleMapsPrefs.setHiddenLayerUrls(googleMapsPrefs.hiddenLayerUrls.value + it.uri.toString())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -584,12 +584,13 @@ constructor(
|
|||
val layerToRemove = _mapLayers.value.find { it.id == layerId }
|
||||
layerToRemove?.uri?.let { uri ->
|
||||
if (layerToRemove.isNetwork) {
|
||||
googleMapsPrefs.networkMapLayers =
|
||||
googleMapsPrefs.networkMapLayers.filterNot { it.startsWith("$layerId|:|") }.toSet()
|
||||
googleMapsPrefs.setNetworkMapLayers(
|
||||
googleMapsPrefs.networkMapLayers.value.filterNot { it.startsWith("$layerId|:|") }.toSet(),
|
||||
)
|
||||
} else {
|
||||
deleteFileToInternalStorage(uri)
|
||||
}
|
||||
googleMapsPrefs.hiddenLayerUrls -= uri.toString()
|
||||
googleMapsPrefs.setHiddenLayerUrls(googleMapsPrefs.hiddenLayerUrls.value - uri.toString())
|
||||
}
|
||||
_mapLayers.value = _mapLayers.value.filterNot { it.id == layerId }
|
||||
}
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@ import org.meshtastic.core.common.util.nowSeconds
|
|||
import org.meshtastic.core.model.DataPacket
|
||||
import org.meshtastic.core.model.Node
|
||||
import org.meshtastic.core.model.RadioController
|
||||
import org.meshtastic.core.prefs.map.MapPrefs
|
||||
import org.meshtastic.core.repository.MapPrefs
|
||||
import org.meshtastic.core.repository.NodeRepository
|
||||
import org.meshtastic.core.repository.PacketRepository
|
||||
import org.meshtastic.core.resources.Res
|
||||
|
|
@ -90,47 +90,48 @@ abstract class BaseMapViewModel(
|
|||
}
|
||||
.stateInWhileSubscribed(initialValue = emptyMap())
|
||||
|
||||
private val showOnlyFavorites = MutableStateFlow(mapPrefs.showOnlyFavorites)
|
||||
private val showOnlyFavorites = MutableStateFlow(mapPrefs.showOnlyFavorites.value)
|
||||
val showOnlyFavoritesOnMap = showOnlyFavorites
|
||||
|
||||
fun toggleOnlyFavorites() {
|
||||
val newValue = !showOnlyFavorites.value
|
||||
showOnlyFavorites.value = newValue
|
||||
mapPrefs.showOnlyFavorites = newValue
|
||||
mapPrefs.setShowOnlyFavorites(newValue)
|
||||
}
|
||||
|
||||
private val showWaypoints = MutableStateFlow(mapPrefs.showWaypointsOnMap)
|
||||
private val showWaypoints = MutableStateFlow(mapPrefs.showWaypointsOnMap.value)
|
||||
val showWaypointsOnMap = showWaypoints
|
||||
|
||||
fun toggleShowWaypointsOnMap() {
|
||||
val newValue = !showWaypoints.value
|
||||
showWaypoints.value = newValue
|
||||
mapPrefs.showWaypointsOnMap = newValue
|
||||
mapPrefs.setShowWaypointsOnMap(newValue)
|
||||
}
|
||||
|
||||
private val showPrecisionCircle = MutableStateFlow(mapPrefs.showPrecisionCircleOnMap)
|
||||
private val showPrecisionCircle = MutableStateFlow(mapPrefs.showPrecisionCircleOnMap.value)
|
||||
val showPrecisionCircleOnMap = showPrecisionCircle
|
||||
|
||||
fun toggleShowPrecisionCircleOnMap() {
|
||||
val newValue = !showPrecisionCircle.value
|
||||
showPrecisionCircle.value = newValue
|
||||
mapPrefs.showPrecisionCircleOnMap = newValue
|
||||
mapPrefs.setShowPrecisionCircleOnMap(newValue)
|
||||
}
|
||||
|
||||
private val lastHeardFilterValue = MutableStateFlow(LastHeardFilter.fromSeconds(mapPrefs.lastHeardFilter))
|
||||
private val lastHeardFilterValue = MutableStateFlow(LastHeardFilter.fromSeconds(mapPrefs.lastHeardFilter.value))
|
||||
val lastHeardFilter = lastHeardFilterValue
|
||||
|
||||
fun setLastHeardFilter(filter: LastHeardFilter) {
|
||||
lastHeardFilterValue.value = filter
|
||||
mapPrefs.lastHeardFilter = filter.seconds
|
||||
mapPrefs.setLastHeardFilter(filter.seconds)
|
||||
}
|
||||
|
||||
private val lastHeardTrackFilterValue = MutableStateFlow(LastHeardFilter.fromSeconds(mapPrefs.lastHeardTrackFilter))
|
||||
private val lastHeardTrackFilterValue =
|
||||
MutableStateFlow(LastHeardFilter.fromSeconds(mapPrefs.lastHeardTrackFilter.value))
|
||||
val lastHeardTrackFilter = lastHeardTrackFilterValue
|
||||
|
||||
fun setLastHeardTrackFilter(filter: LastHeardFilter) {
|
||||
lastHeardTrackFilterValue.value = filter
|
||||
mapPrefs.lastHeardTrackFilter = filter.seconds
|
||||
mapPrefs.setLastHeardTrackFilter(filter.seconds)
|
||||
}
|
||||
|
||||
abstract fun getUser(userId: String?): org.meshtastic.proto.User
|
||||
|
|
|
|||
|
|
@ -28,10 +28,10 @@ import kotlinx.coroutines.flow.map
|
|||
import kotlinx.coroutines.flow.mapLatest
|
||||
import kotlinx.coroutines.flow.toList
|
||||
import org.meshtastic.core.common.BuildConfigProvider
|
||||
import org.meshtastic.core.data.repository.MeshLogRepository
|
||||
import org.meshtastic.core.database.entity.MeshLog
|
||||
import org.meshtastic.core.navigation.NodesRoutes
|
||||
import org.meshtastic.core.prefs.map.MapPrefs
|
||||
import org.meshtastic.core.repository.MapPrefs
|
||||
import org.meshtastic.core.repository.MeshLogRepository
|
||||
import org.meshtastic.core.repository.NodeRepository
|
||||
import org.meshtastic.core.ui.util.toPosition
|
||||
import org.meshtastic.core.ui.viewmodel.stateInWhileSubscribed
|
||||
|
|
@ -81,5 +81,5 @@ constructor(
|
|||
.stateInWhileSubscribed(initialValue = emptyList())
|
||||
|
||||
val tileSource
|
||||
get() = CustomTileSource.getTileSource(mapPrefs.mapStyle)
|
||||
get() = CustomTileSource.getTileSource(mapPrefs.mapStyle.value)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -44,7 +44,7 @@ import org.meshtastic.core.datastore.UiPreferencesDataSource
|
|||
import org.meshtastic.core.model.ConnectionState
|
||||
import org.meshtastic.core.model.RadioController
|
||||
import org.meshtastic.core.prefs.map.GoogleMapsPrefs
|
||||
import org.meshtastic.core.prefs.map.MapPrefs
|
||||
import org.meshtastic.core.repository.MapPrefs
|
||||
import org.meshtastic.core.repository.NodeRepository
|
||||
import org.meshtastic.core.repository.PacketRepository
|
||||
import org.meshtastic.core.repository.RadioConfigRepository
|
||||
|
|
@ -72,6 +72,22 @@ class MapViewModelTest {
|
|||
@Before
|
||||
fun setup() {
|
||||
Dispatchers.setMain(testDispatcher)
|
||||
every { mapPrefs.mapStyle } returns MutableStateFlow(0)
|
||||
every { mapPrefs.showOnlyFavorites } returns MutableStateFlow(false)
|
||||
every { mapPrefs.showWaypointsOnMap } returns MutableStateFlow(true)
|
||||
every { mapPrefs.showPrecisionCircleOnMap } returns MutableStateFlow(true)
|
||||
every { mapPrefs.lastHeardFilter } returns MutableStateFlow(0L)
|
||||
every { mapPrefs.lastHeardTrackFilter } returns MutableStateFlow(0L)
|
||||
|
||||
every { googleMapsPrefs.cameraTargetLat } returns MutableStateFlow(0.0)
|
||||
every { googleMapsPrefs.cameraTargetLng } returns MutableStateFlow(0.0)
|
||||
every { googleMapsPrefs.cameraZoom } returns MutableStateFlow(0f)
|
||||
every { googleMapsPrefs.cameraTilt } returns MutableStateFlow(0f)
|
||||
every { googleMapsPrefs.cameraBearing } returns MutableStateFlow(0f)
|
||||
every { googleMapsPrefs.selectedCustomTileUrl } returns MutableStateFlow(null)
|
||||
every { googleMapsPrefs.selectedGoogleMapType } returns MutableStateFlow(null)
|
||||
every { googleMapsPrefs.hiddenLayerUrls } returns MutableStateFlow(emptySet())
|
||||
|
||||
every { customTileProviderRepository.getCustomTileProviders() } returns flowOf(emptyList())
|
||||
every { radioConfigRepository.deviceProfileFlow } returns flowOf(mockk(relaxed = true))
|
||||
every { uiPreferencesDataSource.theme } returns MutableStateFlow(1)
|
||||
|
|
|
|||
|
|
@ -38,14 +38,14 @@ import org.meshtastic.core.model.DataPacket
|
|||
import org.meshtastic.core.model.Message
|
||||
import org.meshtastic.core.model.Node
|
||||
import org.meshtastic.core.model.service.ServiceAction
|
||||
import org.meshtastic.core.prefs.emoji.CustomEmojiPrefs
|
||||
import org.meshtastic.core.prefs.homoglyph.HomoglyphPrefs
|
||||
import org.meshtastic.core.prefs.ui.UiPrefs
|
||||
import org.meshtastic.core.repository.CustomEmojiPrefs
|
||||
import org.meshtastic.core.repository.HomoglyphPrefs
|
||||
import org.meshtastic.core.repository.MeshServiceNotifications
|
||||
import org.meshtastic.core.repository.NodeRepository
|
||||
import org.meshtastic.core.repository.PacketRepository
|
||||
import org.meshtastic.core.repository.RadioConfigRepository
|
||||
import org.meshtastic.core.repository.ServiceRepository
|
||||
import org.meshtastic.core.repository.UiPrefs
|
||||
import org.meshtastic.core.repository.usecase.SendMessageUseCase
|
||||
import org.meshtastic.core.ui.viewmodel.stateInWhileSubscribed
|
||||
import org.meshtastic.proto.ChannelSet
|
||||
|
|
@ -79,7 +79,7 @@ constructor(
|
|||
|
||||
val channels = radioConfigRepository.channelSetFlow.stateInWhileSubscribed(ChannelSet())
|
||||
|
||||
private val _showQuickChat = MutableStateFlow(uiPrefs.showQuickChat)
|
||||
private val _showQuickChat = MutableStateFlow(uiPrefs.showQuickChat.value)
|
||||
val showQuickChat: StateFlow<Boolean> = _showQuickChat
|
||||
|
||||
private val _showFiltered = MutableStateFlow(false)
|
||||
|
|
@ -109,7 +109,7 @@ constructor(
|
|||
|
||||
val frequentEmojis: List<String>
|
||||
get() =
|
||||
customEmojiPrefs.customEmojiFrequency
|
||||
customEmojiPrefs.customEmojiFrequency.value
|
||||
?.split(",")
|
||||
?.associate { entry ->
|
||||
entry.split("=", limit = 2).takeIf { it.size == 2 }?.let { it[0] to it[1].toInt() } ?: ("" to 0)
|
||||
|
|
@ -119,7 +119,7 @@ constructor(
|
|||
?.map { it.first }
|
||||
?.take(6) ?: listOf("👍", "👎", "😂", "🔥", "❤️", "😮")
|
||||
|
||||
val homoglyphEncodingEnabled = homoglyphEncodingPrefs.getHomoglyphEncodingEnabledChangesFlow()
|
||||
val homoglyphEncodingEnabled = homoglyphEncodingPrefs.homoglyphEncodingEnabled
|
||||
|
||||
val firstUnreadMessageUuid: StateFlow<Long?> =
|
||||
contactKeyForPagedMessages
|
||||
|
|
@ -163,7 +163,7 @@ constructor(
|
|||
return pagedMessagesForContactKey
|
||||
}
|
||||
|
||||
fun toggleShowQuickChat() = toggle(_showQuickChat) { uiPrefs.showQuickChat = it }
|
||||
fun toggleShowQuickChat() = toggle(_showQuickChat) { uiPrefs.setShowQuickChat(it) }
|
||||
|
||||
fun toggleShowFiltered() {
|
||||
_showFiltered.update { !it }
|
||||
|
|
|
|||
|
|
@ -24,7 +24,6 @@ import kotlinx.coroutines.flow.flatMapLatest
|
|||
import kotlinx.coroutines.flow.map
|
||||
import kotlinx.coroutines.flow.onStart
|
||||
import org.meshtastic.core.data.repository.FirmwareReleaseRepository
|
||||
import org.meshtastic.core.data.repository.MeshLogRepository
|
||||
import org.meshtastic.core.database.entity.FirmwareRelease
|
||||
import org.meshtastic.core.database.entity.MeshLog
|
||||
import org.meshtastic.core.model.MyNodeInfo
|
||||
|
|
@ -32,6 +31,7 @@ import org.meshtastic.core.model.Node
|
|||
import org.meshtastic.core.model.util.hasValidEnvironmentMetrics
|
||||
import org.meshtastic.core.model.util.isDirectSignal
|
||||
import org.meshtastic.core.repository.DeviceHardwareRepository
|
||||
import org.meshtastic.core.repository.MeshLogRepository
|
||||
import org.meshtastic.core.repository.NodeRepository
|
||||
import org.meshtastic.core.repository.RadioConfigRepository
|
||||
import org.meshtastic.core.resources.Res
|
||||
|
|
|
|||
|
|
@ -45,7 +45,6 @@ import org.jetbrains.compose.resources.StringResource
|
|||
import org.meshtastic.core.common.util.nowSeconds
|
||||
import org.meshtastic.core.common.util.toDate
|
||||
import org.meshtastic.core.common.util.toInstant
|
||||
import org.meshtastic.core.data.repository.MeshLogRepository
|
||||
import org.meshtastic.core.data.repository.TracerouteSnapshotRepository
|
||||
import org.meshtastic.core.database.entity.MeshLog
|
||||
import org.meshtastic.core.di.CoroutineDispatchers
|
||||
|
|
@ -54,6 +53,7 @@ import org.meshtastic.core.model.TelemetryType
|
|||
import org.meshtastic.core.model.evaluateTracerouteMapAvailability
|
||||
import org.meshtastic.core.model.util.UnitConversions
|
||||
import org.meshtastic.core.navigation.NodesRoutes
|
||||
import org.meshtastic.core.repository.MeshLogRepository
|
||||
import org.meshtastic.core.repository.NodeRepository
|
||||
import org.meshtastic.core.repository.ServiceRepository
|
||||
import org.meshtastic.core.resources.Res
|
||||
|
|
@ -134,7 +134,7 @@ constructor(
|
|||
val availableTimeFrames: StateFlow<List<TimeFrame>> =
|
||||
combine(state, environmentState) { currentState, envState ->
|
||||
val stateOldest = currentState.oldestTimestampSeconds()
|
||||
val envOldest = envState.environmentMetrics.minOfOrNull { (it.time ?: 0).toLong() }?.takeIf { it > 0 }
|
||||
val envOldest = envState.environmentMetrics.minOfOrNull { it.time.toLong() }?.takeIf { it > 0 }
|
||||
val oldest = listOfNotNull(stateOldest, envOldest).minOrNull() ?: nowSeconds
|
||||
TimeFrame.entries.filter { it.isAvailable(oldest) }
|
||||
}
|
||||
|
|
@ -148,7 +148,7 @@ constructor(
|
|||
val filteredEnvironmentMetrics: StateFlow<List<Telemetry>> =
|
||||
combine(environmentState, _timeFrame, state) { envState, timeFrame, currentState ->
|
||||
val threshold = timeFrame.timeThreshold()
|
||||
val data = envState.environmentMetrics.filter { (it.time ?: 0).toLong() >= threshold }
|
||||
val data = envState.environmentMetrics.filter { it.time.toLong() >= threshold }
|
||||
if (currentState.isFahrenheit) {
|
||||
data.map { telemetry ->
|
||||
val em = telemetry.environment_metrics ?: return@map telemetry
|
||||
|
|
@ -341,7 +341,7 @@ constructor(
|
|||
val dateFormat = SimpleDateFormat("\"yyyy-MM-dd\",\"HH:mm:ss\"", Locale.getDefault())
|
||||
|
||||
positions.forEach { position ->
|
||||
val rxDateTime = dateFormat.format(((position.time ?: 0).toLong() * 1000L).toInstant().toDate())
|
||||
val rxDateTime = dateFormat.format((position.time.toLong() * 1000L).toInstant().toDate())
|
||||
val latitude = (position.latitude_i ?: 0) * 1e-7
|
||||
val longitude = (position.longitude_i ?: 0) * 1e-7
|
||||
val altitude = position.altitude
|
||||
|
|
@ -377,7 +377,7 @@ constructor(
|
|||
if (packet != null && decoded != null && decoded.portnum == PortNum.PAXCOUNTER_APP) {
|
||||
if (decoded.want_response == true) return null
|
||||
val pax = ProtoPaxcount.ADAPTER.decode(decoded.payload)
|
||||
if ((pax.ble ?: 0) != 0 || (pax.wifi ?: 0) != 0 || (pax.uptime ?: 0) != 0) return pax
|
||||
if (pax.ble != 0 || pax.wifi != 0 || pax.uptime != 0) return pax
|
||||
}
|
||||
} catch (e: IOException) {
|
||||
Logger.e(e) { "Failed to parse Paxcount from binary data" }
|
||||
|
|
|
|||
|
|
@ -32,6 +32,7 @@ import kotlinx.coroutines.flow.update
|
|||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
import org.meshtastic.core.common.BuildConfigProvider
|
||||
import org.meshtastic.core.common.database.DatabaseManager
|
||||
import org.meshtastic.core.domain.usecase.settings.ExportDataUseCase
|
||||
import org.meshtastic.core.domain.usecase.settings.IsOtaCapableUseCase
|
||||
import org.meshtastic.core.domain.usecase.settings.MeshLocationUseCase
|
||||
|
|
@ -43,11 +44,10 @@ import org.meshtastic.core.domain.usecase.settings.SetThemeUseCase
|
|||
import org.meshtastic.core.model.MyNodeInfo
|
||||
import org.meshtastic.core.model.Node
|
||||
import org.meshtastic.core.model.RadioController
|
||||
import org.meshtastic.core.prefs.meshlog.MeshLogPrefs
|
||||
import org.meshtastic.core.prefs.ui.UiPrefs
|
||||
import org.meshtastic.core.repository.DatabaseManager
|
||||
import org.meshtastic.core.repository.MeshLogPrefs
|
||||
import org.meshtastic.core.repository.NodeRepository
|
||||
import org.meshtastic.core.repository.RadioConfigRepository
|
||||
import org.meshtastic.core.repository.UiPrefs
|
||||
import org.meshtastic.core.ui.viewmodel.stateInWhileSubscribed
|
||||
import org.meshtastic.proto.LocalConfig
|
||||
import java.io.BufferedWriter
|
||||
|
|
@ -126,10 +126,10 @@ constructor(
|
|||
}
|
||||
|
||||
// MeshLog retention period (bounded by MeshLogPrefsImpl constants)
|
||||
private val _meshLogRetentionDays = MutableStateFlow(meshLogPrefs.retentionDays)
|
||||
private val _meshLogRetentionDays = MutableStateFlow(meshLogPrefs.retentionDays.value)
|
||||
val meshLogRetentionDays: StateFlow<Int> = _meshLogRetentionDays.asStateFlow()
|
||||
|
||||
private val _meshLogLoggingEnabled = MutableStateFlow(meshLogPrefs.loggingEnabled)
|
||||
private val _meshLogLoggingEnabled = MutableStateFlow(meshLogPrefs.loggingEnabled.value)
|
||||
val meshLogLoggingEnabled: StateFlow<Boolean> = _meshLogLoggingEnabled.asStateFlow()
|
||||
|
||||
fun setMeshLogRetentionDays(days: Int) {
|
||||
|
|
|
|||
|
|
@ -36,13 +36,13 @@ import kotlinx.coroutines.withContext
|
|||
import org.meshtastic.core.common.util.nowInstant
|
||||
import org.meshtastic.core.common.util.toDate
|
||||
import org.meshtastic.core.common.util.toInstant
|
||||
import org.meshtastic.core.data.repository.MeshLogRepository
|
||||
import org.meshtastic.core.database.entity.MeshLog
|
||||
import org.meshtastic.core.database.entity.Packet
|
||||
import org.meshtastic.core.model.getTracerouteResponse
|
||||
import org.meshtastic.core.model.util.decodeOrNull
|
||||
import org.meshtastic.core.model.util.toReadableString
|
||||
import org.meshtastic.core.prefs.meshlog.MeshLogPrefs
|
||||
import org.meshtastic.core.repository.MeshLogPrefs
|
||||
import org.meshtastic.core.repository.MeshLogRepository
|
||||
import org.meshtastic.core.repository.NodeRepository
|
||||
import org.meshtastic.core.resources.Res
|
||||
import org.meshtastic.core.resources.debug_clear
|
||||
|
|
@ -230,10 +230,10 @@ constructor(
|
|||
.mapLatest { logs -> withContext(Dispatchers.Default) { toUiState(logs) } }
|
||||
.stateInWhileSubscribed(initialValue = persistentListOf())
|
||||
|
||||
private val _retentionDays = MutableStateFlow(meshLogPrefs.retentionDays)
|
||||
private val _retentionDays = MutableStateFlow(meshLogPrefs.retentionDays.value)
|
||||
val retentionDays: StateFlow<Int> = _retentionDays.asStateFlow()
|
||||
|
||||
private val _loggingEnabled = MutableStateFlow(meshLogPrefs.loggingEnabled)
|
||||
private val _loggingEnabled = MutableStateFlow(meshLogPrefs.loggingEnabled.value)
|
||||
val loggingEnabled: StateFlow<Boolean> = _loggingEnabled.asStateFlow()
|
||||
|
||||
// --- Managers ---
|
||||
|
|
@ -265,18 +265,18 @@ constructor(
|
|||
|
||||
fun setRetentionDays(days: Int) {
|
||||
val clamped = days.coerceIn(MeshLogPrefs.MIN_RETENTION_DAYS, MeshLogPrefs.MAX_RETENTION_DAYS)
|
||||
meshLogPrefs.retentionDays = clamped
|
||||
meshLogPrefs.setRetentionDays(clamped)
|
||||
_retentionDays.value = clamped
|
||||
viewModelScope.launch { meshLogRepository.deleteLogsOlderThan(clamped) }
|
||||
}
|
||||
|
||||
fun setLoggingEnabled(enabled: Boolean) {
|
||||
meshLogPrefs.loggingEnabled = enabled
|
||||
meshLogPrefs.setLoggingEnabled(enabled)
|
||||
_loggingEnabled.value = enabled
|
||||
if (!enabled) {
|
||||
viewModelScope.launch { meshLogRepository.deleteAll() }
|
||||
} else {
|
||||
viewModelScope.launch { meshLogRepository.deleteLogsOlderThan(meshLogPrefs.retentionDays) }
|
||||
viewModelScope.launch { meshLogRepository.deleteLogsOlderThan(meshLogPrefs.retentionDays.value) }
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ import dagger.hilt.android.lifecycle.HiltViewModel
|
|||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import kotlinx.coroutines.flow.asStateFlow
|
||||
import org.meshtastic.core.prefs.filter.FilterPrefs
|
||||
import org.meshtastic.core.repository.FilterPrefs
|
||||
import org.meshtastic.core.repository.MessageFilter
|
||||
import javax.inject.Inject
|
||||
|
||||
|
|
@ -33,32 +33,32 @@ constructor(
|
|||
private val messageFilter: MessageFilter,
|
||||
) : ViewModel() {
|
||||
|
||||
private val _filterEnabled = MutableStateFlow(filterPrefs.filterEnabled)
|
||||
private val _filterEnabled = MutableStateFlow(filterPrefs.filterEnabled.value)
|
||||
val filterEnabled: StateFlow<Boolean> = _filterEnabled.asStateFlow()
|
||||
|
||||
private val _filterWords = MutableStateFlow(filterPrefs.filterWords.toList().sorted())
|
||||
private val _filterWords = MutableStateFlow(filterPrefs.filterWords.value.toList().sorted())
|
||||
val filterWords: StateFlow<List<String>> = _filterWords.asStateFlow()
|
||||
|
||||
fun setFilterEnabled(enabled: Boolean) {
|
||||
filterPrefs.filterEnabled = enabled
|
||||
filterPrefs.setFilterEnabled(enabled)
|
||||
_filterEnabled.value = enabled
|
||||
}
|
||||
|
||||
fun addFilterWord(word: String) {
|
||||
if (word.isBlank()) return
|
||||
val trimmed = word.trim()
|
||||
val current = filterPrefs.filterWords.toMutableSet()
|
||||
val current = filterPrefs.filterWords.value.toMutableSet()
|
||||
if (current.add(trimmed)) {
|
||||
filterPrefs.filterWords = current
|
||||
filterPrefs.setFilterWords(current)
|
||||
_filterWords.value = current.toList().sorted()
|
||||
messageFilter.rebuildPatterns()
|
||||
}
|
||||
}
|
||||
|
||||
fun removeFilterWord(word: String) {
|
||||
val current = filterPrefs.filterWords.toMutableSet()
|
||||
val current = filterPrefs.filterWords.value.toMutableSet()
|
||||
if (current.remove(word)) {
|
||||
filterPrefs.filterWords = current
|
||||
filterPrefs.setFilterWords(current)
|
||||
_filterWords.value = current.toList().sorted()
|
||||
messageFilter.rebuildPatterns()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -58,9 +58,9 @@ import org.meshtastic.core.model.MyNodeInfo
|
|||
import org.meshtastic.core.model.Node
|
||||
import org.meshtastic.core.model.Position
|
||||
import org.meshtastic.core.navigation.SettingsRoutes
|
||||
import org.meshtastic.core.prefs.analytics.AnalyticsPrefs
|
||||
import org.meshtastic.core.prefs.homoglyph.HomoglyphPrefs
|
||||
import org.meshtastic.core.prefs.map.MapConsentPrefs
|
||||
import org.meshtastic.core.repository.AnalyticsPrefs
|
||||
import org.meshtastic.core.repository.HomoglyphPrefs
|
||||
import org.meshtastic.core.repository.MapConsentPrefs
|
||||
import org.meshtastic.core.repository.NodeRepository
|
||||
import org.meshtastic.core.repository.PacketRepository
|
||||
import org.meshtastic.core.repository.RadioConfigRepository
|
||||
|
|
@ -131,13 +131,13 @@ constructor(
|
|||
private val adminActionsUseCase: AdminActionsUseCase,
|
||||
private val processRadioResponseUseCase: ProcessRadioResponseUseCase,
|
||||
) : ViewModel() {
|
||||
var analyticsAllowedFlow = analyticsPrefs.getAnalyticsAllowedChangesFlow()
|
||||
var analyticsAllowedFlow = analyticsPrefs.analyticsAllowed
|
||||
|
||||
fun toggleAnalyticsAllowed() {
|
||||
toggleAnalyticsUseCase()
|
||||
}
|
||||
|
||||
val homoglyphEncodingEnabledFlow = homoglyphEncodingPrefs.getHomoglyphEncodingEnabledChangesFlow()
|
||||
val homoglyphEncodingEnabledFlow = homoglyphEncodingPrefs.homoglyphEncodingEnabled
|
||||
|
||||
fun toggleHomoglyphCharactersEncodingEnabled() {
|
||||
toggleHomoglyphEncodingUseCase()
|
||||
|
|
|
|||
|
|
@ -61,7 +61,8 @@ fun MQTTConfigScreen(viewModel: RadioConfigViewModel = hiltViewModel(), onBack:
|
|||
|
||||
val currentMapReportSettings = formState.value.map_report_settings ?: ModuleConfig.MapReportSettings()
|
||||
if (!(currentMapReportSettings.should_report_location ?: false)) {
|
||||
val settings = currentMapReportSettings.copy(should_report_location = viewModel.shouldReportLocation(destNum))
|
||||
val settings =
|
||||
currentMapReportSettings.copy(should_report_location = viewModel.shouldReportLocation(destNum).value)
|
||||
formState.value = formState.value.copy(map_report_settings = settings)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -30,6 +30,7 @@ import org.junit.After
|
|||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
import org.meshtastic.core.common.BuildConfigProvider
|
||||
import org.meshtastic.core.common.database.DatabaseManager
|
||||
import org.meshtastic.core.domain.usecase.settings.ExportDataUseCase
|
||||
import org.meshtastic.core.domain.usecase.settings.IsOtaCapableUseCase
|
||||
import org.meshtastic.core.domain.usecase.settings.MeshLocationUseCase
|
||||
|
|
@ -39,11 +40,10 @@ import org.meshtastic.core.domain.usecase.settings.SetMeshLogSettingsUseCase
|
|||
import org.meshtastic.core.domain.usecase.settings.SetProvideLocationUseCase
|
||||
import org.meshtastic.core.domain.usecase.settings.SetThemeUseCase
|
||||
import org.meshtastic.core.model.RadioController
|
||||
import org.meshtastic.core.prefs.meshlog.MeshLogPrefs
|
||||
import org.meshtastic.core.prefs.ui.UiPrefs
|
||||
import org.meshtastic.core.repository.DatabaseManager
|
||||
import org.meshtastic.core.repository.MeshLogPrefs
|
||||
import org.meshtastic.core.repository.NodeRepository
|
||||
import org.meshtastic.core.repository.RadioConfigRepository
|
||||
import org.meshtastic.core.repository.UiPrefs
|
||||
import org.robolectric.annotation.Config
|
||||
|
||||
@OptIn(ExperimentalCoroutinesApi::class)
|
||||
|
|
|
|||
|
|
@ -32,8 +32,8 @@ import org.junit.After
|
|||
import org.junit.Assert.assertEquals
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
import org.meshtastic.core.data.repository.MeshLogRepository
|
||||
import org.meshtastic.core.prefs.meshlog.MeshLogPrefs
|
||||
import org.meshtastic.core.repository.MeshLogPrefs
|
||||
import org.meshtastic.core.repository.MeshLogRepository
|
||||
import org.meshtastic.core.repository.NodeRepository
|
||||
import org.meshtastic.core.ui.util.AlertManager
|
||||
|
||||
|
|
@ -56,8 +56,8 @@ class DebugViewModelTest {
|
|||
every { meshLogRepository.getAllLogs() } returns flowOf(emptyList())
|
||||
every { nodeRepository.myNodeInfo } returns MutableStateFlow(null)
|
||||
every { nodeRepository.nodeDBbyNum } returns MutableStateFlow(emptyMap())
|
||||
every { meshLogPrefs.retentionDays } returns 7
|
||||
every { meshLogPrefs.loggingEnabled } returns true
|
||||
every { meshLogPrefs.retentionDays.value } returns 7
|
||||
every { meshLogPrefs.loggingEnabled.value } returns true
|
||||
|
||||
viewModel =
|
||||
DebugViewModel(
|
||||
|
|
@ -77,7 +77,7 @@ class DebugViewModelTest {
|
|||
fun `setRetentionDays updates prefs and deletes old logs`() = runTest {
|
||||
viewModel.setRetentionDays(14)
|
||||
|
||||
verify { meshLogPrefs.retentionDays = 14 }
|
||||
verify { meshLogPrefs.setRetentionDays(14) }
|
||||
coVerify { meshLogRepository.deleteLogsOlderThan(14) }
|
||||
assertEquals(14, viewModel.retentionDays.value)
|
||||
}
|
||||
|
|
@ -86,7 +86,7 @@ class DebugViewModelTest {
|
|||
fun `setLoggingEnabled false deletes all logs`() = runTest {
|
||||
viewModel.setLoggingEnabled(false)
|
||||
|
||||
verify { meshLogPrefs.loggingEnabled = false }
|
||||
verify { meshLogPrefs.setLoggingEnabled(false) }
|
||||
coVerify { meshLogRepository.deleteAll() }
|
||||
assertEquals(false, viewModel.loggingEnabled.value)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ import io.mockk.verify
|
|||
import org.junit.Assert.assertEquals
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
import org.meshtastic.core.prefs.filter.FilterPrefs
|
||||
import org.meshtastic.core.repository.FilterPrefs
|
||||
import org.meshtastic.core.repository.MessageFilter
|
||||
|
||||
class FilterSettingsViewModelTest {
|
||||
|
|
@ -34,8 +34,8 @@ class FilterSettingsViewModelTest {
|
|||
|
||||
@Before
|
||||
fun setUp() {
|
||||
every { filterPrefs.filterEnabled } returns true
|
||||
every { filterPrefs.filterWords } returns setOf("apple", "banana")
|
||||
every { filterPrefs.filterEnabled.value } returns true
|
||||
every { filterPrefs.filterWords.value } returns setOf("apple", "banana")
|
||||
|
||||
viewModel = FilterSettingsViewModel(filterPrefs = filterPrefs, messageFilter = messageFilter)
|
||||
}
|
||||
|
|
@ -43,7 +43,7 @@ class FilterSettingsViewModelTest {
|
|||
@Test
|
||||
fun `setFilterEnabled updates prefs and state`() {
|
||||
viewModel.setFilterEnabled(false)
|
||||
verify { filterPrefs.filterEnabled = false }
|
||||
verify { filterPrefs.setFilterEnabled(false) }
|
||||
assertEquals(false, viewModel.filterEnabled.value)
|
||||
}
|
||||
|
||||
|
|
@ -51,7 +51,7 @@ class FilterSettingsViewModelTest {
|
|||
fun `addFilterWord updates prefs and rebuilds patterns`() {
|
||||
viewModel.addFilterWord("cherry")
|
||||
|
||||
verify { filterPrefs.filterWords = any() }
|
||||
verify { filterPrefs.setFilterWords(any()) }
|
||||
verify { messageFilter.rebuildPatterns() }
|
||||
assertEquals(listOf("apple", "banana", "cherry"), viewModel.filterWords.value)
|
||||
}
|
||||
|
|
@ -60,7 +60,7 @@ class FilterSettingsViewModelTest {
|
|||
fun `removeFilterWord updates prefs and rebuilds patterns`() {
|
||||
viewModel.removeFilterWord("apple")
|
||||
|
||||
verify { filterPrefs.filterWords = any() }
|
||||
verify { filterPrefs.setFilterWords(any()) }
|
||||
verify { messageFilter.rebuildPatterns() }
|
||||
assertEquals(listOf("banana"), viewModel.filterWords.value)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -45,9 +45,9 @@ import org.meshtastic.core.domain.usecase.settings.RadioResponseResult
|
|||
import org.meshtastic.core.domain.usecase.settings.ToggleAnalyticsUseCase
|
||||
import org.meshtastic.core.domain.usecase.settings.ToggleHomoglyphEncodingUseCase
|
||||
import org.meshtastic.core.model.Node
|
||||
import org.meshtastic.core.prefs.analytics.AnalyticsPrefs
|
||||
import org.meshtastic.core.prefs.homoglyph.HomoglyphPrefs
|
||||
import org.meshtastic.core.prefs.map.MapConsentPrefs
|
||||
import org.meshtastic.core.repository.AnalyticsPrefs
|
||||
import org.meshtastic.core.repository.HomoglyphPrefs
|
||||
import org.meshtastic.core.repository.MapConsentPrefs
|
||||
import org.meshtastic.core.repository.NodeRepository
|
||||
import org.meshtastic.core.repository.PacketRepository
|
||||
import org.meshtastic.core.repository.RadioConfigRepository
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue