Own ordered settings changes independently of the Compose screen

This commit is contained in:
evgeny committed 2026-10-29 13:35:19 +01:00
1 parent 299518e866
commit a95245e272
3 files changed
+42

No files matched your search

@@ -42,6 +42,7 @@ data class RadioCompressorSettings(val enabled: Boolean = true, val maxGainDb: I
* При формировании конфига настройки и keys.conf читаются один раз; чтение/запись utun.cfg сериализованы.
*/
class ConfigProvider(private val context: Context) {
val changes = SettingsOperations()
private val configFiles = ConfigFileStore { level, message -> LogManager.addLog(level, "CFG", message) }
private val bleFlags = intPreferencesKey("bluetooth_flags")
fun getBleFlags(): Int = runBlocking { context.dataStore.data.first()[bleFlags] ?: 0 }
@@ -0,0 +1,40 @@
package com.utun.chat.data
import kotlinx.coroutines.CancellationException
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.CoroutineStart
import kotlinx.coroutines.Deferred
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.SupervisorJob
import kotlinx.coroutines.async
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.sync.Mutex
import kotlinx.coroutines.sync.withLock
/** Очередь Application на main: сохранить выбор, затем применить runtime без зависимости от UI scope.
* submit принимает неизменный снимок аргументов caller; отмена await не отменяет запись.
* awaitIdle ставит барьер после принятых изменений перед формированием restart-конфига. */
class SettingsOperations(private val scope: CoroutineScope = CoroutineScope(SupervisorJob() + Dispatchers.Main.immediate),
private val log: (String, String) -> Unit = { level, message -> LogManager.addLog(level, "Settings", message) }) {
private val mutex = Mutex()
private val _failed = MutableStateFlow(false)
val failed = _failed.asStateFlow()
fun submit(name: String, operation: suspend () -> Unit): Deferred<Unit> = scope.async(start = CoroutineStart.UNDISPATCHED) {
mutex.withLock {
try {
operation()
log("INFO", "Setting applied name=$name")
} catch (e: CancellationException) { throw e }
catch (e: Exception) { reportFailure(name, e); throw e }
}
}
fun reportFailure(name: String, error: Exception) {
_failed.value = true
log("ERROR", "Setting failed name=$name: ${error.javaClass.simpleName}: ${error.message}")
}
fun dismissFailure() { _failed.value = false }
suspend fun awaitIdle() { mutex.withLock { } }
}
@@ -28,6 +28,7 @@ kotlin {
"com/utun/chat/data/CallPlaybackBuffer.kt", "com/utun/chat/data/CallOutputRecovery.kt",
"com/utun/chat/data/CallState.kt", "com/utun/chat/data/CallAudioHost.kt")
kotlin.include("com/utun/chat/data/ConversationSubmissions.kt", "com/utun/chat/data/ConversationTarget.kt")
kotlin.include("com/utun/chat/data/SettingsOperations.kt")
}
}