Own radio settings changes and preserve observed state after IO failures

This commit is contained in:
evgeny committed 2026-10-29 13:35:19 +01:00
1 parent 61bdf4a6df
commit eb837206c3
1 file changed
+41 -31
@@ -332,8 +332,8 @@ private fun DeveloperSettingsTab(vm: ChatViewModel, onDirty: (Boolean) -> Unit,
var autoConnect by remember { mutableStateOf(true) }
val localSocketStates by vm.localSockets.collectAsState()
val serviceEnabled by provider.serviceEnabledFlow.collectAsState(initial = true)
val startOnBoot by provider.startOnBootFlow.collectAsState(initial = true)
val serviceEnabled by remember { provider.changes.observe("service preference", provider.serviceEnabledFlow) }.collectAsState(initial = true)
val startOnBoot by remember { provider.changes.observe("boot preference", provider.startOnBootFlow) }.collectAsState(initial = true)
var savingStartOnBoot by remember { mutableStateOf(false) }
var startOnBootError by remember { mutableStateOf(false) }
@@ -387,7 +387,7 @@ private fun DeveloperSettingsTab(vm: ChatViewModel, onDirty: (Boolean) -> Unit,
autoConnect = provider.getInt("chat.group_autoconnect") != 0
}
val save = { s: List<ServerEntry> ->
val save: (List<ServerEntry>) -> Unit = { s ->
onDirty(true)
servers = s
val revision = ++serverSaveRevision
@@ -402,7 +402,7 @@ private fun DeveloperSettingsTab(vm: ChatViewModel, onDirty: (Boolean) -> Unit,
}
}
}
val switchMode = { mode: String ->
val switchMode: (String) -> Unit = { mode ->
onDirty(true)
provider.changes.submit("connection mode") {
try {
@@ -418,13 +418,13 @@ private fun DeveloperSettingsTab(vm: ChatViewModel, onDirty: (Boolean) -> Unit,
}
}
}
val setDebug = { level: String ->
val setDebug: (String) -> Unit = { level ->
provider.changes.submit("debug level") {
provider.setValue("debug.console_level", level)
NativeLib.setDebugLevel("", level); debugLevel = level
}
}
val setCatLevel = { cat: String, lvl: String ->
val setCatLevel: (String, String) -> Unit = { cat, lvl ->
val updated = catLevels.toMutableMap()
if (lvl == "") updated.remove(cat) else updated[cat] = lvl
val csv = updated.entries.joinToString(",") { "${it.key}=${it.value}" }
@@ -859,7 +859,8 @@ private fun DeveloperSettingsTab(vm: ChatViewModel, onDirty: (Boolean) -> Unit,
internal fun RadioAutomaticSettings(provider: ConfigProvider, compact: Boolean = false) {
val engine = remember { RadioAudioEngine.instance() }
val scope = rememberCoroutineScope()
val saved by provider.radioAutoSettings.collectAsState(initial = remember { provider.getRadioAutoSettings() })
val saved by remember { provider.changes.observe("radio automatic preferences", provider.radioAutoSettings) }
.collectAsState(initial = remember { provider.getRadioAutoSettings() })
var draft by remember(saved) { mutableStateOf(saved) }
var saving by remember { mutableStateOf(false) }
var saveError by remember { mutableStateOf(false) }
@@ -971,7 +972,7 @@ internal fun RadioAutomaticSettings(provider: ConfigProvider, compact: Boolean =
val next = draft
val restart = next.enabled && !saved.enabled
saving = true; saveError = false
scope.launch {
provider.changes.submit("radio automatic transmission") {
try {
provider.saveRadioAutoSettings(next)
engine.reconfigure(restartAuto = restart)
@@ -980,6 +981,7 @@ internal fun RadioAutomaticSettings(provider: ConfigProvider, compact: Boolean =
catch (e: Exception) {
saveError = true
LogManager.addLog("ERROR", "radio", "Cannot save automatic transmission settings: $e")
throw e
} finally { saving = false }
}
}) { Text(stringResource(R.string.radio_auto_apply)) }
@@ -1005,18 +1007,20 @@ private fun RadioSettingsTab() {
HorizontalDivider(Modifier.padding(vertical = 4.dp))
/* ── Volume-кнопки PTT ── */
val volumePtt by provider.radioVolumePttEnabled.collectAsState(initial = provider.getRadioVolumePtt())
val volumePtt by remember { provider.changes.observe("volume PTT preference", provider.radioVolumePttEnabled) }
.collectAsState(initial = provider.getRadioVolumePtt())
Row(verticalAlignment = Alignment.CenterVertically) {
Text(stringResource(R.string.volume_ptt), modifier = Modifier.weight(1f))
Switch(checked = volumePtt, onCheckedChange = {
scope.launch { provider.setRadioVolumePtt(it) }
provider.changes.submit("volume PTT") { provider.setRadioVolumePtt(it) }
})
}
HorizontalDivider(Modifier.padding(vertical = 4.dp))
/* ── Оверлей PTT поверх приложений ── */
val overlayEnabled by provider.radioOverlayEnabled.collectAsState(initial = provider.getRadioOverlay())
val overlayEnabled by remember { provider.changes.observe("overlay preference", provider.radioOverlayEnabled) }
.collectAsState(initial = provider.getRadioOverlay())
val overlayShown by RadioOverlayService.isShown.collectAsState()
val overlayStatus by RadioOverlayService.status.collectAsState()
Row(verticalAlignment = Alignment.CenterVertically) {
@@ -1030,7 +1034,7 @@ private fun RadioSettingsTab() {
)
}
Switch(checked = overlayEnabled, onCheckedChange = { enabled ->
scope.launch { RadioOverlayService.setEnabled(enabled) }
provider.changes.submit("radio overlay") { RadioOverlayService.setEnabled(enabled) }
})
}
@@ -1050,9 +1054,9 @@ private fun RadioSettingsTab() {
ExposedDropdownMenu(micExpanded, onDismissRequest = { micExpanded = false }) {
micSources.forEachIndexed { i, n ->
DropdownMenuItem(text = { Text(n) }, onClick = {
micSource = i
scope.launch {
provider.changes.submit("radio microphone source") {
provider.setRadioMicSource(i)
micSource = i
RadioAudioEngine.instance().reconfigure()
}
micExpanded = false
@@ -1072,9 +1076,9 @@ private fun RadioSettingsTab() {
style = MaterialTheme.typography.bodySmall)
}
Switch(checked = captureStereo, onCheckedChange = {
captureStereo = it
scope.launch {
provider.changes.submit("radio stereo capture") {
provider.setRadioCaptureStereo(it)
captureStereo = it
NativeLib.setChatSetting("radio_capture_stereo", if (it) "1" else "0")
RadioAudioEngine.instance().reconfigure()
}
@@ -1090,20 +1094,24 @@ private fun RadioSettingsTab() {
Row(verticalAlignment = Alignment.CenterVertically) {
Text(stringResource(R.string.enable_compressor), modifier = Modifier.weight(1f))
Switch(checked = radioCompOn, onCheckedChange = {
radioCompOn = it
scope.launch { provider.setValue("radio.compressor_enabled", if (it) "1" else "0") }
NativeLib.setChatSetting("radio_compressor_enabled", if (it) "1" else "0")
RadioAudioEngine.instance().reconfigure()
provider.changes.submit("radio compressor") {
provider.setValue("radio.compressor_enabled", if (it) "1" else "0"); radioCompOn = it
if (NativeLib.isReady()) NativeLib.setChatSetting("radio_compressor_enabled", if (it) "1" else "0")
RadioAudioEngine.instance().reconfigure()
}
})
}
LabeledSlider(stringResource(R.string.max_gain), radioCompMaxGain.toFloat(), 1f..45f, 44, "${radioCompMaxGain} dB",
{ v ->
radioCompMaxGain = v.toInt()
NativeLib.setChatSetting("radio_compressor_max_gain_db", radioCompMaxGain.toString())
},
onValueChangeFinished = {
scope.launch { provider.setValue("radio.compressor_max_gain_db", radioCompMaxGain.toString()) }
RadioAudioEngine.instance().reconfigure()
val gain = radioCompMaxGain
provider.changes.submit("radio compressor gain") {
provider.setValue("radio.compressor_max_gain_db", gain.toString())
if (NativeLib.isReady()) NativeLib.setChatSetting("radio_compressor_max_gain_db", gain.toString())
RadioAudioEngine.instance().reconfigure()
}
})
HorizontalDivider(Modifier.padding(vertical = 4.dp))
@@ -1123,10 +1131,11 @@ private fun RadioSettingsTab() {
ExposedDropdownMenu(opusModeExpanded, onDismissRequest = { opusModeExpanded = false }) {
opusModes.forEachIndexed { i, n ->
DropdownMenuItem(text = { Text(n) }, onClick = {
opusMode = i
scope.launch { provider.setValue("radio.opus_mode", i.toString()) }
NativeLib.setChatSetting("radio_opus_mode", i.toString())
RadioAudioEngine.instance().reconfigure()
provider.changes.submit("radio Opus mode") {
provider.setValue("radio.opus_mode", i.toString()); opusMode = i
if (NativeLib.isReady()) NativeLib.setChatSetting("radio_opus_mode", i.toString())
RadioAudioEngine.instance().reconfigure()
}
opusModeExpanded = false
})
}
@@ -1139,10 +1148,11 @@ private fun RadioSettingsTab() {
ExposedDropdownMenu(opusBitrateExpanded, onDismissRequest = { opusBitrateExpanded = false }) {
opusBitrates.forEach { b ->
DropdownMenuItem(text = { Text(stringResource(R.string.bitrate_kbps, b)) }, onClick = {
opusBitrate = b
scope.launch { provider.setValue("radio.opus_bitrate", b.toString()) }
NativeLib.setChatSetting("radio_opus_bitrate", b.toString())
RadioAudioEngine.instance().reconfigure()
provider.changes.submit("radio Opus bitrate") {
provider.setValue("radio.opus_bitrate", b.toString()); opusBitrate = b
if (NativeLib.isReady()) NativeLib.setChatSetting("radio_opus_bitrate", b.toString())
RadioAudioEngine.instance().reconfigure()
}
opusBitrateExpanded = false
})
}