chat_settings: [chat] config section + live sync + fix test segfault
- New chat_setting.c/h: unified chat settings API (int/str getters) - Config parser supports [chat] section, calls chat_setting_set per key - chat_core exposes chat_core_set_setting / trampoline for GUI bridge - chatgui: AudioDevice + Storage pages persist to [chat] config + live apply - chatgui-android: ConfigProvider, NativeLib, headless handle chat settings - MessageList: 200 msg limit, fixed saveChannelState via trampoline - test_media_delivery_full: fix segfault at shutdown (mon() timer vs freed conns)
This commit is contained in:
1 parent
efbb495016
commit
b8920cf483
22 files changed
+420
-43
No files matched your search
@@ -36,9 +36,14 @@ class ConfigProvider(private val context: Context) {
|
||||
private val logUdpIp = stringPreferencesKey("log_udp_ip")
|
||||
private val logUdpPort = intPreferencesKey("log_udp_port")
|
||||
private val serversJson = stringPreferencesKey("servers")
|
||||
private val storageAutoload = intPreferencesKey("storage_autoload")
|
||||
private val storageAutoloadMaxsizeMb = intPreferencesKey("storage_autoload_maxsize_mb")
|
||||
private val storageMaxsizeGb = intPreferencesKey("storage_maxsize_gb")
|
||||
private val chatStorageAutoload = intPreferencesKey("chat_storage_autoload")
|
||||
private val chatStorageAutoloadMaxsizeMb = intPreferencesKey("chat_storage_autoload_maxsize_mb")
|
||||
private val chatStorageMaxsizeGb = intPreferencesKey("chat_storage_maxsize_gb")
|
||||
private val chatOpusCodecPreset = intPreferencesKey("chat_opus_codec_preset")
|
||||
private val chatCompressorEnabled = intPreferencesKey("chat_compressor_enabled")
|
||||
private val chatCompressorMaxGainDb = intPreferencesKey("chat_compressor_max_gain_db")
|
||||
private val chatCompressorRiseRate = intPreferencesKey("chat_compressor_rise_rate")
|
||||
private val chatMediaDownloadMaxPeers = intPreferencesKey("chat_media_download_max_peers")
|
||||
private val firstLaunchDone = booleanPreferencesKey("first_launch_done")
|
||||
|
||||
private val gson = Gson()
|
||||
@@ -133,9 +138,14 @@ class ConfigProvider(private val context: Context) {
|
||||
key == "node.listen_port" -> context.dataStore.data.first()[nodeListenPort] ?: 12345
|
||||
key == "control.port" -> context.dataStore.data.first()[controlPort] ?: 9999
|
||||
key == "log_udp.port" -> context.dataStore.data.first()[logUdpPort] ?: 9999
|
||||
key == "storage_autoload" -> context.dataStore.data.first()[storageAutoload] ?: 1
|
||||
key == "storage_autoload_maxsize_mb" -> context.dataStore.data.first()[storageAutoloadMaxsizeMb] ?: 10
|
||||
key == "storage_maxsize_gb" -> context.dataStore.data.first()[storageMaxsizeGb] ?: 1
|
||||
key == "chat.storage_autoload" -> context.dataStore.data.first()[chatStorageAutoload] ?: 1
|
||||
key == "chat.storage_autoload_maxsize_mb" -> context.dataStore.data.first()[chatStorageAutoloadMaxsizeMb] ?: 10
|
||||
key == "chat.storage_maxsize_gb" -> context.dataStore.data.first()[chatStorageMaxsizeGb] ?: 1
|
||||
key == "chat.opus_codec_preset" -> context.dataStore.data.first()[chatOpusCodecPreset] ?: 1
|
||||
key == "chat.compressor_enabled" -> context.dataStore.data.first()[chatCompressorEnabled] ?: 0
|
||||
key == "chat.compressor_max_gain_db" -> context.dataStore.data.first()[chatCompressorMaxGainDb] ?: 25
|
||||
key == "chat.compressor_rise_rate" -> context.dataStore.data.first()[chatCompressorRiseRate] ?: 10
|
||||
key == "chat.media_download_max_peers" -> context.dataStore.data.first()[chatMediaDownloadMaxPeers] ?: 3
|
||||
else -> 0
|
||||
}
|
||||
}
|
||||
@@ -155,9 +165,14 @@ class ConfigProvider(private val context: Context) {
|
||||
"debug.categories" -> prefs[debugCategories] = value
|
||||
"log_udp.ip" -> prefs[logUdpIp] = value
|
||||
"log_udp.port" -> prefs[logUdpPort] = value.toIntOrNull() ?: 0
|
||||
"storage_autoload" -> prefs[storageAutoload] = value.toIntOrNull() ?: 1
|
||||
"storage_autoload_maxsize_mb" -> prefs[storageAutoloadMaxsizeMb] = value.toIntOrNull() ?: 10
|
||||
"storage_maxsize_gb" -> prefs[storageMaxsizeGb] = value.toIntOrNull() ?: 1
|
||||
"chat.storage_autoload" -> prefs[chatStorageAutoload] = value.toIntOrNull() ?: 1
|
||||
"chat.storage_autoload_maxsize_mb" -> prefs[chatStorageAutoloadMaxsizeMb] = value.toIntOrNull() ?: 10
|
||||
"chat.storage_maxsize_gb" -> prefs[chatStorageMaxsizeGb] = value.toIntOrNull() ?: 1
|
||||
"chat.opus_codec_preset" -> prefs[chatOpusCodecPreset] = value.toIntOrNull() ?: 1
|
||||
"chat.compressor_enabled" -> prefs[chatCompressorEnabled] = value.toIntOrNull() ?: 0
|
||||
"chat.compressor_max_gain_db" -> prefs[chatCompressorMaxGainDb] = value.toIntOrNull() ?: 25
|
||||
"chat.compressor_rise_rate" -> prefs[chatCompressorRiseRate] = value.toIntOrNull() ?: 10
|
||||
"chat.media_download_max_peers" -> prefs[chatMediaDownloadMaxPeers] = value.toIntOrNull() ?: 3
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -281,6 +296,24 @@ class ConfigProvider(private val context: Context) {
|
||||
appendLine("[ntp]")
|
||||
appendLine("enabled=no")
|
||||
appendLine()
|
||||
appendLine("[chat]")
|
||||
val chatAutoload = getInt("chat.storage_autoload")
|
||||
val chatAutoloadMaxMb = getInt("chat.storage_autoload_maxsize_mb")
|
||||
val chatMaxGb = getInt("chat.storage_maxsize_gb")
|
||||
val chatOpusPreset = getInt("chat.opus_codec_preset")
|
||||
val chatCompEnabled = getInt("chat.compressor_enabled")
|
||||
val chatCompMaxGain = getInt("chat.compressor_max_gain_db")
|
||||
val chatCompRiseRate = getInt("chat.compressor_rise_rate")
|
||||
val chatDlMaxPeers = getInt("chat.media_download_max_peers")
|
||||
appendLine("storage_autoload=$chatAutoload")
|
||||
appendLine("storage_autoload_maxsize_mb=$chatAutoloadMaxMb")
|
||||
appendLine("storage_maxsize_gb=$chatMaxGb")
|
||||
appendLine("opus_codec_preset=$chatOpusPreset")
|
||||
appendLine("compressor_enabled=$chatCompEnabled")
|
||||
appendLine("compressor_max_gain_db=$chatCompMaxGain")
|
||||
appendLine("compressor_rise_rate=$chatCompRiseRate")
|
||||
appendLine("media_download_max_peers=$chatDlMaxPeers")
|
||||
appendLine()
|
||||
appendLine("[debug]")
|
||||
appendLine("console_level=info")
|
||||
val udpIp = getString("log_udp.ip") ?: ""
|
||||
|
||||
@@ -72,6 +72,10 @@ object NativeLib {
|
||||
fun clearDatabase(): Boolean = nativeClearDatabase()
|
||||
fun setDebugLevel(category: String, level: String) { nativeSetDebugLevel(category, level) }
|
||||
|
||||
/* ── Chat settings (live update via C side) ── */
|
||||
fun setChatSetting(name: String, value: String) { nativeSetChatSetting(name, value) }
|
||||
fun getChatSettingInt(name: String, def: Int = 0): Int = nativeGetChatSettingInt(name, def)
|
||||
|
||||
/** Enable/disable forwarding native C logs to LogManager (expensive, off by default) */
|
||||
fun subscribeNativeLogs(enabled: Boolean) { nativeSubscribeLogs(enabled) }
|
||||
fun setUdpLogTarget(ip: String, port: Int) { nativeSetUdpLogTarget(ip, port) }
|
||||
@@ -114,6 +118,8 @@ object NativeLib {
|
||||
private external fun nativeGetChannels(): String?
|
||||
private external fun nativeGetMessages(channelId: String, limit: Int): String?
|
||||
private external fun nativeSetDebugLevel(category: String, level: String)
|
||||
private external fun nativeSetChatSetting(name: String, value: String)
|
||||
private external fun nativeGetChatSettingInt(name: String, def: Int): Int
|
||||
private external fun nativeSubscribeLogs(enabled: Boolean)
|
||||
private external fun nativeSetUdpLogTarget(ip: String, port: Int)
|
||||
private external fun nativeRegenerateKeys()
|
||||
|
||||
@@ -324,6 +324,7 @@ private fun GeneralSettingsTab(vm: ChatViewModel, dirty: Boolean, onDirty: (Bool
|
||||
@Composable
|
||||
private fun AudioSettingsTab(vm: ChatViewModel) {
|
||||
val scope = rememberCoroutineScope()
|
||||
val provider = ChatApplication.instance.configProvider
|
||||
|
||||
/* Mic test state */
|
||||
var micTesting by remember { mutableStateOf(false) }
|
||||
@@ -352,6 +353,16 @@ private fun AudioSettingsTab(vm: ChatViewModel) {
|
||||
vm.setVoicePreset(preset)
|
||||
vm.setVoiceCompressor(compressorOn)
|
||||
vm.setCompressorConfig(maxGainDb, lookbackMs, lookaheadMs, riseRateTenths / 10f, targetLevelDb.toFloat())
|
||||
scope.launch {
|
||||
provider.setValue("chat.opus_codec_preset", preset.toString())
|
||||
provider.setValue("chat.compressor_enabled", if (compressorOn) "1" else "0")
|
||||
provider.setValue("chat.compressor_max_gain_db", maxGainDb.toString())
|
||||
provider.setValue("chat.compressor_rise_rate", riseRateTenths.toString())
|
||||
}
|
||||
NativeLib.setChatSetting("opus_codec_preset", preset.toString())
|
||||
NativeLib.setChatSetting("compressor_enabled", if (compressorOn) "1" else "0")
|
||||
NativeLib.setChatSetting("compressor_max_gain_db", maxGainDb.toString())
|
||||
NativeLib.setChatSetting("compressor_rise_rate", riseRateTenths.toString())
|
||||
}
|
||||
|
||||
Column(
|
||||
@@ -427,9 +438,9 @@ private fun StorageSettingsTab() {
|
||||
var maxStorageGb by remember { mutableStateOf("1") }
|
||||
|
||||
LaunchedEffect(Unit) {
|
||||
autoload = provider.getInt("storage_autoload") != 0
|
||||
autoloadMaxSizeMb = provider.getInt("storage_autoload_maxsize_mb").toString()
|
||||
maxStorageGb = provider.getInt("storage_maxsize_gb").toString()
|
||||
autoload = provider.getInt("chat.storage_autoload") != 0
|
||||
autoloadMaxSizeMb = provider.getInt("chat.storage_autoload_maxsize_mb").toString()
|
||||
maxStorageGb = provider.getInt("chat.storage_maxsize_gb").toString()
|
||||
}
|
||||
|
||||
Column(
|
||||
@@ -441,20 +452,22 @@ private fun StorageSettingsTab() {
|
||||
Text("Autoload media", modifier = Modifier.weight(1f))
|
||||
Switch(checked = autoload, onCheckedChange = {
|
||||
autoload = it
|
||||
scope.launch { provider.setValue("storage_autoload", if (it) "1" else "0") }
|
||||
val s = if (it) "1" else "0"
|
||||
scope.launch { provider.setValue("chat.storage_autoload", s) }
|
||||
NativeLib.setChatSetting("storage_autoload", s)
|
||||
})
|
||||
}
|
||||
|
||||
HorizontalDivider(Modifier.padding(vertical = 4.dp))
|
||||
|
||||
OutlinedTextField(autoloadMaxSizeMb,
|
||||
{ v -> autoloadMaxSizeMb = v; val nb = v.toIntOrNull(); if (nb != null && nb in 1..500) scope.launch { provider.setValue("storage_autoload_maxsize_mb", v) } },
|
||||
{ v -> autoloadMaxSizeMb = v; val nb = v.toIntOrNull(); if (nb != null && nb in 1..500) { scope.launch { provider.setValue("chat.storage_autoload_maxsize_mb", v) }; NativeLib.setChatSetting("storage_autoload_maxsize_mb", v) } },
|
||||
label = { Text("Autoload max size (MB)") },
|
||||
keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Number),
|
||||
singleLine = true, modifier = Modifier.padding(top = 4.dp))
|
||||
|
||||
OutlinedTextField(maxStorageGb,
|
||||
{ v -> maxStorageGb = v; val nb = v.toIntOrNull(); if (nb != null && nb in 1..100) scope.launch { provider.setValue("storage_maxsize_gb", v) } },
|
||||
{ v -> maxStorageGb = v; val nb = v.toIntOrNull(); if (nb != null && nb in 1..100) { scope.launch { provider.setValue("chat.storage_maxsize_gb", v) }; NativeLib.setChatSetting("storage_maxsize_gb", v) } },
|
||||
label = { Text("Max storage size (GB)") },
|
||||
keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Number),
|
||||
singleLine = true)
|
||||
|
||||
Reference in new issue
Block a user