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
|
|
@ -0,0 +1,173 @@
|
|||
/*
|
||||
* Copyright (c) 2026 Meshtastic LLC
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.meshtastic.core.repository
|
||||
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
|
||||
/** Reactive interface for analytics-related preferences. */
|
||||
interface AnalyticsPrefs {
|
||||
val analyticsAllowed: StateFlow<Boolean>
|
||||
|
||||
fun setAnalyticsAllowed(allowed: Boolean)
|
||||
|
||||
val installId: StateFlow<String>
|
||||
}
|
||||
|
||||
/** Reactive interface for homoglyph encoding preferences. */
|
||||
interface HomoglyphPrefs {
|
||||
val homoglyphEncodingEnabled: StateFlow<Boolean>
|
||||
|
||||
fun setHomoglyphEncodingEnabled(enabled: Boolean)
|
||||
}
|
||||
|
||||
/** Reactive interface for message filtering preferences. */
|
||||
interface FilterPrefs {
|
||||
val filterEnabled: StateFlow<Boolean>
|
||||
|
||||
fun setFilterEnabled(enabled: Boolean)
|
||||
|
||||
val filterWords: StateFlow<Set<String>>
|
||||
|
||||
fun setFilterWords(words: Set<String>)
|
||||
}
|
||||
|
||||
/** Reactive interface for mesh log preferences. */
|
||||
interface MeshLogPrefs {
|
||||
val retentionDays: StateFlow<Int>
|
||||
|
||||
fun setRetentionDays(days: Int)
|
||||
|
||||
val loggingEnabled: StateFlow<Boolean>
|
||||
|
||||
fun setLoggingEnabled(enabled: Boolean)
|
||||
|
||||
companion object {
|
||||
const val DEFAULT_RETENTION_DAYS = 30
|
||||
const val MIN_RETENTION_DAYS = -1
|
||||
const val MAX_RETENTION_DAYS = 365
|
||||
}
|
||||
}
|
||||
|
||||
/** Reactive interface for emoji preferences. */
|
||||
interface CustomEmojiPrefs {
|
||||
val customEmojiFrequency: StateFlow<String?>
|
||||
|
||||
fun setCustomEmojiFrequency(frequency: String?)
|
||||
}
|
||||
|
||||
/** Reactive interface for general UI preferences. */
|
||||
interface UiPrefs {
|
||||
val hasShownNotPairedWarning: StateFlow<Boolean>
|
||||
|
||||
fun setHasShownNotPairedWarning(shown: Boolean)
|
||||
|
||||
val showQuickChat: StateFlow<Boolean>
|
||||
|
||||
fun setShowQuickChat(show: Boolean)
|
||||
|
||||
fun shouldProvideNodeLocation(nodeNum: Int): StateFlow<Boolean>
|
||||
|
||||
fun setShouldProvideNodeLocation(nodeNum: Int, provide: Boolean)
|
||||
}
|
||||
|
||||
/** Reactive interface for general map preferences. */
|
||||
interface MapPrefs {
|
||||
val mapStyle: StateFlow<Int>
|
||||
|
||||
fun setMapStyle(style: Int)
|
||||
|
||||
val showOnlyFavorites: StateFlow<Boolean>
|
||||
|
||||
fun setShowOnlyFavorites(show: Boolean)
|
||||
|
||||
val showWaypointsOnMap: StateFlow<Boolean>
|
||||
|
||||
fun setShowWaypointsOnMap(show: Boolean)
|
||||
|
||||
val showPrecisionCircleOnMap: StateFlow<Boolean>
|
||||
|
||||
fun setShowPrecisionCircleOnMap(show: Boolean)
|
||||
|
||||
val lastHeardFilter: StateFlow<Long>
|
||||
|
||||
fun setLastHeardFilter(seconds: Long)
|
||||
|
||||
val lastHeardTrackFilter: StateFlow<Long>
|
||||
|
||||
fun setLastHeardTrackFilter(seconds: Long)
|
||||
}
|
||||
|
||||
/** Reactive interface for map consent. */
|
||||
interface MapConsentPrefs {
|
||||
fun shouldReportLocation(nodeNum: Int?): StateFlow<Boolean>
|
||||
|
||||
fun setShouldReportLocation(nodeNum: Int?, report: Boolean)
|
||||
}
|
||||
|
||||
/** Reactive interface for map tile provider settings. */
|
||||
interface MapTileProviderPrefs {
|
||||
val customTileProviders: StateFlow<String?>
|
||||
|
||||
fun setCustomTileProviders(providers: String?)
|
||||
}
|
||||
|
||||
/** Reactive interface for radio settings. */
|
||||
interface RadioPrefs {
|
||||
val devAddr: StateFlow<String?>
|
||||
|
||||
fun setDevAddr(address: String?)
|
||||
}
|
||||
|
||||
fun RadioPrefs.isBle() = devAddr.value?.startsWith("x") == true
|
||||
|
||||
fun RadioPrefs.isSerial() = devAddr.value?.startsWith("s") == true
|
||||
|
||||
fun RadioPrefs.isMock() = devAddr.value?.startsWith("m") == true
|
||||
|
||||
fun RadioPrefs.isTcp() = devAddr.value?.startsWith("t") == true
|
||||
|
||||
fun RadioPrefs.isNoop() = devAddr.value?.startsWith("n") == true
|
||||
|
||||
/** Reactive interface for mesh connection settings. */
|
||||
interface MeshPrefs {
|
||||
val deviceAddress: StateFlow<String?>
|
||||
|
||||
fun setDeviceAddress(address: String?)
|
||||
|
||||
fun shouldProvideNodeLocation(nodeNum: Int?): StateFlow<Boolean>
|
||||
|
||||
fun setShouldProvideNodeLocation(nodeNum: Int?, provide: Boolean)
|
||||
|
||||
fun getStoreForwardLastRequest(address: String?): StateFlow<Int>
|
||||
|
||||
fun setStoreForwardLastRequest(address: String?, timestamp: Int)
|
||||
}
|
||||
|
||||
/** Consolidated interface for all application preferences. */
|
||||
interface AppPreferences {
|
||||
val analytics: AnalyticsPrefs
|
||||
val homoglyph: HomoglyphPrefs
|
||||
val filter: FilterPrefs
|
||||
val meshLog: MeshLogPrefs
|
||||
val emoji: CustomEmojiPrefs
|
||||
val ui: UiPrefs
|
||||
val map: MapPrefs
|
||||
val mapConsent: MapConsentPrefs
|
||||
val mapTileProvider: MapTileProviderPrefs
|
||||
val radio: RadioPrefs
|
||||
val mesh: MeshPrefs
|
||||
}
|
||||
|
|
@ -1,34 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2025-2026 Meshtastic LLC
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.meshtastic.core.repository
|
||||
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
|
||||
/** Interface for managing database instances and cache limits. */
|
||||
interface DatabaseManager {
|
||||
/** Reactive stream of the current database cache limit. */
|
||||
val cacheLimit: StateFlow<Int>
|
||||
|
||||
/** Returns the current database cache limit from storage. */
|
||||
fun getCurrentCacheLimit(): Int
|
||||
|
||||
/** Sets the database cache limit. */
|
||||
fun setCacheLimit(limit: Int)
|
||||
|
||||
/** Switches the active database to the one associated with the given [address]. */
|
||||
suspend fun switchActiveDatabase(address: String?)
|
||||
}
|
||||
|
|
@ -1,21 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2025-2026 Meshtastic LLC
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.meshtastic.core.repository
|
||||
|
||||
interface HomoglyphPrefs {
|
||||
val homoglyphEncodingEnabled: Boolean
|
||||
}
|
||||
|
|
@ -0,0 +1,82 @@
|
|||
/*
|
||||
* Copyright (c) 2025-2026 Meshtastic LLC
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.meshtastic.core.repository
|
||||
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import org.meshtastic.core.database.entity.MeshLog
|
||||
import org.meshtastic.proto.MeshPacket
|
||||
import org.meshtastic.proto.MyNodeInfo
|
||||
import org.meshtastic.proto.PortNum
|
||||
import org.meshtastic.proto.Telemetry
|
||||
|
||||
/**
|
||||
* Repository interface for managing and retrieving logs from the database.
|
||||
*
|
||||
* This component provides access to the application's message log, telemetry history, and debug records. It supports
|
||||
* reactive queries for packets, telemetry data, and node-specific logs.
|
||||
*
|
||||
* This interface is shared across platforms via Kotlin Multiplatform (KMP).
|
||||
*/
|
||||
@Suppress("TooManyFunctions")
|
||||
interface MeshLogRepository {
|
||||
/** Retrieves all [MeshLog]s in the database, up to [maxItem]. */
|
||||
fun getAllLogs(maxItem: Int = DEFAULT_MAX_LOGS): Flow<List<MeshLog>>
|
||||
|
||||
/** Retrieves all [MeshLog]s in the database in the order they were received. */
|
||||
fun getAllLogsInReceiveOrder(maxItem: Int = DEFAULT_MAX_LOGS): Flow<List<MeshLog>>
|
||||
|
||||
/** Retrieves all [MeshLog]s in the database without any limit. */
|
||||
fun getAllLogsUnbounded(): Flow<List<MeshLog>>
|
||||
|
||||
/** Retrieves all [MeshLog]s associated with a specific [nodeNum] and [portNum]. */
|
||||
fun getLogsFrom(nodeNum: Int, portNum: Int): Flow<List<MeshLog>>
|
||||
|
||||
/** Retrieves all [MeshLog]s containing [MeshPacket]s for a specific [nodeNum]. */
|
||||
fun getMeshPacketsFrom(nodeNum: Int, portNum: Int = -1): Flow<List<MeshPacket>>
|
||||
|
||||
/** Retrieves telemetry history for a specific node, automatically handling local node redirection. */
|
||||
fun getTelemetryFrom(nodeNum: Int): Flow<List<Telemetry>>
|
||||
|
||||
/**
|
||||
* Retrieves all outgoing request logs for a specific [targetNodeNum] and [portNum].
|
||||
*
|
||||
* A request log is defined as an outgoing packet where `want_response` is true.
|
||||
*/
|
||||
fun getRequestLogs(targetNodeNum: Int, portNum: PortNum): Flow<List<MeshLog>>
|
||||
|
||||
/** Returns the cached [MyNodeInfo] from the system logs. */
|
||||
fun getMyNodeInfo(): Flow<MyNodeInfo?>
|
||||
|
||||
/** Persists a new log entry to the database. */
|
||||
suspend fun insert(log: MeshLog)
|
||||
|
||||
/** Clears all logs from the database. */
|
||||
suspend fun deleteAll()
|
||||
|
||||
/** Deletes a specific log entry by its [uuid]. */
|
||||
suspend fun deleteLog(uuid: String)
|
||||
|
||||
/** Deletes all logs associated with a specific [nodeNum] and [portNum]. */
|
||||
suspend fun deleteLogs(nodeNum: Int, portNum: Int)
|
||||
|
||||
/** Prunes the log database based on the configured [retentionDays]. */
|
||||
suspend fun deleteLogsOlderThan(retentionDays: Int)
|
||||
|
||||
companion object {
|
||||
const val DEFAULT_MAX_LOGS = 5000
|
||||
}
|
||||
}
|
||||
|
|
@ -89,7 +89,7 @@ class SendMessageUseCase(
|
|||
|
||||
// Apply homoglyph encoding
|
||||
val finalMessageText =
|
||||
if (homoglyphEncodingPrefs.homoglyphEncodingEnabled) {
|
||||
if (homoglyphEncodingPrefs.homoglyphEncodingEnabled.value) {
|
||||
HomoglyphCharacterStringTransformer.optimizeUtf8StringWithHomoglyphs(text)
|
||||
} else {
|
||||
text
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue