Persist channel mute consistently and own panel preference changes
This commit is contained in:
1 parent
fb696d0d56
commit
c1ad35e152
3 files changed
+50
-23
No files matched your search
@@ -549,7 +549,14 @@ class ConfigProvider(private val context: Context) {
|
||||
/* ── Connection mode ── */
|
||||
|
||||
fun getConnectionMode(): String = runBlocking {
|
||||
context.dataStore.data.first()[connectionModeKey] ?: "auto"
|
||||
connectionMode(context.dataStore.data.first())
|
||||
}
|
||||
|
||||
private fun connectionMode(prefs: Preferences): String {
|
||||
val mode = prefs[connectionModeKey] ?: return "auto"
|
||||
if (mode == "auto" || mode == "manual") return mode
|
||||
LogManager.addLog("WARN", "CFG", "Unknown stored connection mode '$mode'; using auto")
|
||||
return "auto"
|
||||
}
|
||||
|
||||
suspend fun setConnectionMode(mode: String) {
|
||||
@@ -985,7 +992,7 @@ class ConfigProvider(private val context: Context) {
|
||||
val cfgFile = File(snapshot.directory, "utun.cfg")
|
||||
val stored = loadServers(cfgFile)
|
||||
val saved = stored.active + stored.inactive
|
||||
val mode = snapshot.preferences[connectionModeKey] ?: "auto"
|
||||
val mode = connectionMode(snapshot.preferences)
|
||||
val active = if (mode == "auto") detectInterfaces(saved, protocols) else stored.active
|
||||
val activeKeys = active.map { it.socketKey }.toSet()
|
||||
val inactive = saved.filter { it.socketKey !in activeKeys }.distinctBy { it.socketKey }
|
||||
|
||||
+17
-9
@@ -13,7 +13,6 @@ import androidx.compose.ui.unit.dp
|
||||
import com.utun.chat.ChatApplication
|
||||
import com.utun.chat.R
|
||||
import com.utun.chat.data.*
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
/** Свойства CHAT-группы: отдельный аватар группы и локальный звук уведомлений.
|
||||
* При открытии обновляет снимок; canEdit показывает кнопки публикации, окончательный допуск проверяет core.
|
||||
@@ -28,10 +27,13 @@ fun GroupPropertiesDialog(channel: Channel, onDismiss: () -> Unit) {
|
||||
val state = groups[channel.id]
|
||||
val editState = edits["group:${channel.id}"] ?: AvatarEditState.IDLE
|
||||
val working = editState == AvatarEditState.WORKING
|
||||
var soundOn by rememberSaveable(channel.id) { mutableStateOf(!NotificationSound.isMuted(channel.id)) }
|
||||
val provider = ChatApplication.instance.configProvider
|
||||
val soundPreferences = remember(provider) { provider.changes.observe("group sound", provider.notificationSoundSettings) }
|
||||
val soundSettings by soundPreferences.collectAsState(initial = NotificationSound.enabled to NotificationSound.mutedChannels)
|
||||
val soundFailed by provider.changes.failed.collectAsState()
|
||||
var pickerFailed by remember { mutableStateOf(false) }
|
||||
var pickedAccount by rememberSaveable { mutableStateOf(0L) }
|
||||
var pickedGroup by rememberSaveable { mutableStateOf("") }
|
||||
val scope = rememberCoroutineScope()
|
||||
val picker = rememberLauncherForActivityResult(ActivityResultContracts.GetContent()) { uri ->
|
||||
if (uri != null) repository.editGroup(pickedGroup, uri, pickedAccount)
|
||||
}
|
||||
@@ -53,21 +55,27 @@ fun GroupPropertiesDialog(channel: Channel, onDismiss: () -> Unit) {
|
||||
Text(stringResource(R.string.group_avatar_limits), style = MaterialTheme.typography.bodySmall)
|
||||
Row {
|
||||
TextButton(enabled = !working, onClick = {
|
||||
pickedAccount = repository.accountId; pickedGroup = channel.id; picker.launch("image/*")
|
||||
pickedAccount = repository.accountId; pickedGroup = channel.id
|
||||
try { pickerFailed = false; picker.launch("image/*") }
|
||||
catch (e: Exception) { pickerFailed = true; LogManager.addLog("ERROR", "Avatar", "Group image picker failed: $e") }
|
||||
}) { Text(stringResource(R.string.avatar_upload)) }
|
||||
TextButton(enabled = !working && state.hasImage, onClick = {
|
||||
repository.editGroup(channel.id, null, repository.accountId)
|
||||
}) { Text(stringResource(R.string.avatar_remove)) }
|
||||
}
|
||||
} else Text(stringResource(R.string.group_avatar_key_required), style = MaterialTheme.typography.bodySmall)
|
||||
if (editState == AvatarEditState.ERROR)
|
||||
if (editState == AvatarEditState.ERROR || pickerFailed)
|
||||
Text(stringResource(R.string.avatar_edit_failed), color = MaterialTheme.colorScheme.error)
|
||||
if (soundFailed) Text(stringResource(R.string.settings_update_failed), color = MaterialTheme.colorScheme.error)
|
||||
Row(verticalAlignment = Alignment.CenterVertically) {
|
||||
Text(stringResource(R.string.sound), modifier = Modifier.weight(1f))
|
||||
Switch(checked = soundOn, onCheckedChange = {
|
||||
soundOn = it; NotificationSound.setMuted(channel.id, !it)
|
||||
NativeLib.setSoundOnMessage(channel.id, it)
|
||||
scope.launch { ChatApplication.instance.configProvider.setChannelMuted(channel.id, !it) }
|
||||
Switch(checked = channel.id !in soundSettings.second, onCheckedChange = { enabled ->
|
||||
provider.changes.submit("group notification sound") {
|
||||
provider.setChannelMuted(channel.id, !enabled)
|
||||
NotificationSound.setMuted(channel.id, !enabled)
|
||||
if (NativeLib.isReady()) NativeLib.setSoundOnMessage(channel.id, enabled)
|
||||
LogManager.addLog("INFO", "Sound", "Group sound saved channel=${channel.id} enabled=$enabled")
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -438,8 +438,17 @@ class ChatViewModel : ViewModel() {
|
||||
}
|
||||
}
|
||||
viewModelScope.launch(Dispatchers.IO) {
|
||||
val key = ChatApplication.instance.configProvider.getString("node.public_key")
|
||||
if (key != null && key.length == 64) _pubKey.value = key
|
||||
try {
|
||||
val key = ChatApplication.instance.configProvider.getString("node.public_key")
|
||||
if (key != null && key.length == 64) _pubKey.value = key
|
||||
} catch (e: kotlinx.coroutines.CancellationException) { throw e }
|
||||
catch (e: Exception) { LogManager.addLog("ERROR", "KEYS", "Public key preferences unavailable: $e") }
|
||||
}
|
||||
viewModelScope.launch {
|
||||
val provider = ChatApplication.instance.configProvider
|
||||
provider.changes.observe("channel sound", provider.notificationSoundSettings).collect { (_, muted) ->
|
||||
_currentChannel.value?.let { _soundOn.value = it.id !in muted }
|
||||
}
|
||||
}
|
||||
viewModelScope.launch {
|
||||
delay(500)
|
||||
@@ -1060,16 +1069,15 @@ class ChatViewModel : ViewModel() {
|
||||
|
||||
fun setRadioVolumePtt(enabled: Boolean) {
|
||||
if (!_radioActive.value) return
|
||||
viewModelScope.launch {
|
||||
ChatApplication.instance.configProvider.setRadioVolumePtt(enabled)
|
||||
}
|
||||
val provider = ChatApplication.instance.configProvider
|
||||
provider.changes.submit("panel volume PTT") { provider.setRadioVolumePtt(enabled) }
|
||||
}
|
||||
|
||||
/** Переключатель авто-PTT на панели рации: сохранить выбор и перенастроить захват. */
|
||||
fun setRadioAutomatic(enabled: Boolean) {
|
||||
if (!_radioActive.value) return
|
||||
viewModelScope.launch {
|
||||
val ctx = ChatApplication.instance
|
||||
val ctx = ChatApplication.instance
|
||||
ctx.configProvider.changes.submit("panel automatic PTT") {
|
||||
ctx.configProvider.setValue("radio.auto_enabled", if (enabled) "1" else "0")
|
||||
LogManager.addLog("INFO", "RadioAudio", "Panel automatic transmission enabled=$enabled channel=$radioChannelId")
|
||||
if (enabled) RadioOverlayService.requestPermissions() else RadioOverlayService.sync(ctx)
|
||||
@@ -1271,8 +1279,8 @@ class ChatViewModel : ViewModel() {
|
||||
watchStreams()
|
||||
_radioActive.value = (radioChannelId == channel.id)
|
||||
_radioTalking.value = if (_radioActive.value) _radioTalkState.value.speakers.firstOrNull() else null
|
||||
_soundOn.value = NativeLib.getSoundOnMessage(channel.id)
|
||||
NotificationSound.setMuted(channel.id, !_soundOn.value)
|
||||
_soundOn.value = !NotificationSound.isMuted(channel.id)
|
||||
NativeLib.setSoundOnMessage(channel.id, _soundOn.value)
|
||||
r.connectChannel(channel.id)
|
||||
refreshMessages(channel.id)
|
||||
refreshMembers(channel.id)
|
||||
@@ -1282,9 +1290,13 @@ class ChatViewModel : ViewModel() {
|
||||
fun toggleSound() {
|
||||
val ch = _currentChannel.value ?: return
|
||||
val on = !_soundOn.value
|
||||
_soundOn.value = on
|
||||
NotificationSound.setMuted(ch.id, !on)
|
||||
NativeLib.setSoundOnMessage(ch.id, on)
|
||||
val provider = ChatApplication.instance.configProvider
|
||||
provider.changes.submit("channel notification sound") {
|
||||
provider.setChannelMuted(ch.id, !on)
|
||||
NotificationSound.setMuted(ch.id, !on)
|
||||
if (NativeLib.isReady()) NativeLib.setSoundOnMessage(ch.id, on)
|
||||
LogManager.addLog("INFO", "Sound", "Channel sound saved channel=${ch.id} enabled=$on")
|
||||
}
|
||||
}
|
||||
|
||||
/* ── DM (личные сообщения) ── */
|
||||
|
||||
Reference in new issue
Block a user