|
|
|
|
@ -1,6 +1,7 @@
|
|
|
|
|
package com.utun.chat.ui.screens |
|
|
|
|
|
|
|
|
|
import com.utun.chat.R |
|
|
|
|
import kotlin.math.roundToInt |
|
|
|
|
import androidx.compose.ui.res.stringResource |
|
|
|
|
import androidx.compose.foundation.clickable |
|
|
|
|
import androidx.compose.foundation.Canvas |
|
|
|
|
@ -35,6 +36,7 @@ import com.utun.chat.data.RadioOverlayService
|
|
|
|
|
import com.utun.chat.data.RadioAudioEngine |
|
|
|
|
import com.utun.chat.data.RadioAutoSettings |
|
|
|
|
import com.utun.chat.data.ConfigProvider |
|
|
|
|
import com.utun.chat.data.CallVideoBitrateRange |
|
|
|
|
import com.utun.chat.data.MicrophonePermission |
|
|
|
|
import com.utun.chat.data.LogManager |
|
|
|
|
import com.utun.chat.data.ServerEntry |
|
|
|
|
@ -903,6 +905,11 @@ private fun AudioSettingsTab(vm: ChatViewModel) {
|
|
|
|
|
var presetExpanded by remember { mutableStateOf(false) } |
|
|
|
|
|
|
|
|
|
var jitterReserveMs by remember { mutableStateOf(provider.getInt("chat.call_jitter_max_reserve_ms")) } |
|
|
|
|
val savedVideoRange = remember { provider.getCallVideoBitrateRange() } |
|
|
|
|
var videoMinimum by rememberSaveable { mutableIntStateOf(savedVideoRange.minimum) } |
|
|
|
|
var videoMaximum by rememberSaveable { mutableIntStateOf(savedVideoRange.maximum) } |
|
|
|
|
var videoRangeSaving by remember { mutableStateOf(false) } |
|
|
|
|
var videoRangeSaveFailed by remember { mutableStateOf(false) } |
|
|
|
|
|
|
|
|
|
/* Все параметры восстанавливаются из одного снимка DataStore. */ |
|
|
|
|
var compressorOn by remember { mutableStateOf(savedVoiceSettings.compressorEnabled) } |
|
|
|
|
@ -1035,6 +1042,34 @@ private fun AudioSettingsTab(vm: ChatViewModel) {
|
|
|
|
|
} |
|
|
|
|
) |
|
|
|
|
|
|
|
|
|
Text(stringResource(R.string.call_video_bitrate_range), style = MaterialTheme.typography.titleMedium) |
|
|
|
|
Text(stringResource(R.string.call_video_bitrate_range_value, videoMinimum, videoMaximum)) |
|
|
|
|
Text(stringResource(R.string.call_video_bitrate_range_hint), style = MaterialTheme.typography.bodySmall) |
|
|
|
|
RangeSlider( |
|
|
|
|
value = videoMinimum.toFloat()..videoMaximum.toFloat(), |
|
|
|
|
onValueChange = { videoMinimum = it.start.roundToInt(); videoMaximum = it.endInclusive.roundToInt() }, |
|
|
|
|
valueRange = 300f..4000f, |
|
|
|
|
steps = 36, |
|
|
|
|
enabled = !videoRangeSaving, |
|
|
|
|
onValueChangeFinished = { |
|
|
|
|
val range = CallVideoBitrateRange(videoMinimum, videoMaximum) |
|
|
|
|
videoRangeSaving = true |
|
|
|
|
videoRangeSaveFailed = false |
|
|
|
|
vm.viewModelScope.launch { |
|
|
|
|
try { |
|
|
|
|
provider.saveCallVideoBitrateRange(range) |
|
|
|
|
NativeLib.setChatSetting("call_video_bitrate_range_kbps", range.encode()) |
|
|
|
|
} catch (e: IOException) { |
|
|
|
|
videoRangeSaveFailed = true |
|
|
|
|
LogManager.addLog("ERROR", "CallSettings", "Video bitrate range save failed: $range: $e") |
|
|
|
|
} finally { |
|
|
|
|
videoRangeSaving = false |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
) |
|
|
|
|
if (videoRangeSaveFailed) Text(stringResource(R.string.call_video_bitrate_range_save_failed), color = MaterialTheme.colorScheme.error) |
|
|
|
|
|
|
|
|
|
/* ── Voice Compressor ── */ |
|
|
|
|
Text(stringResource(R.string.voice_compressor), style = MaterialTheme.typography.titleMedium) |
|
|
|
|
Row(verticalAlignment = Alignment.CenterVertically) { |
|
|
|
|
|