Move Android VAD activation to the radio toolbar

This commit is contained in:
evgeny committed 2026-10-03 11:18:04 +03:00
1 parent 099c9b7eac
commit 9ff1f5645f
6 files changed
+29 -15

No files matched your search

@@ -349,6 +349,7 @@ class ConfigProvider(private val context: Context) {
}
val radioOverlayEnabled: Flow<Boolean> = context.dataStore.data.map { it[radioOverlayKey] ?: false }
val radioVadEnabled: Flow<Boolean> = context.dataStore.data.map { (it[radioVadEnabledKey] ?: 0) != 0 }
@Volatile private var radioOverlayCached = false
@Volatile private var radioOverlayLoaded = false
@@ -249,7 +249,7 @@ private fun RadioPttButton(
}
}
/* Единый выбор входа/выхода и переключатель плавающей PTT-кнопки. */
/* Единый выбор входа/выхода, VAD и плавающая PTT-кнопка. */
@Composable
private fun RadioSourceBar(viewModel: ChatViewModel) {
val radioAuto by viewModel.radioAuto.collectAsState()
@@ -260,6 +260,7 @@ private fun RadioSourceBar(viewModel: ChatViewModel) {
val provider = ChatApplication.instance.configProvider
val scope = rememberCoroutineScope()
val overlayEnabled by provider.radioOverlayEnabled.collectAsState(initial = provider.getRadioOverlay())
val vadEnabled by provider.radioVadEnabled.collectAsState(initial = provider.getInt("radio.vad_enabled") != 0)
val overlayShown by RadioOverlayService.isShown.collectAsState()
val overlayStatus by RadioOverlayService.status.collectAsState()
@@ -299,6 +300,10 @@ private fun RadioSourceBar(viewModel: ChatViewModel) {
}
}
VerticalDivider(modifier = Modifier.height(32.dp), color = Color(0xFF344550))
RadioControlButton(null, stringResource(if (vadEnabled) R.string.disable_vad else R.string.enable_vad),
vadEnabled, text = stringResource(R.string.vad_button)) {
viewModel.setRadioVad(!vadEnabled)
}
RadioControlButton(null, stringResource(R.string.floating_ptt), overlayShown, floating = true) {
scope.launch {
if (overlayEnabled && !overlayShown) RadioOverlayService.requestPermissions()
@@ -317,7 +322,7 @@ private fun RadioSourceBar(viewModel: ChatViewModel) {
@Composable
private fun RadioControlButton(
icon: ImageVector?, label: String, active: Boolean,
centerIcon: ImageVector? = null, bluetooth: Boolean = false, floating: Boolean = false, onClick: () -> Unit
centerIcon: ImageVector? = null, bluetooth: Boolean = false, floating: Boolean = false, text: String? = null, onClick: () -> Unit
) {
IconToggleButton(
checked = active,
@@ -327,6 +332,10 @@ private fun RadioControlButton(
containerColor = Color(0xFF24323D), contentColor = Color(0xFFAEBCC8),
checkedContainerColor = Color(0xFF1F6FEB), checkedContentColor = Color.White)
) {
if (text != null) {
Text(text, fontSize = 12.sp, modifier = Modifier.semantics { contentDescription = label })
return@IconToggleButton
}
if (floating) {
RadioFloatingIcon(label)
return@IconToggleButton
@@ -567,24 +567,11 @@ private fun RadioSettingsTab() {
modifier = Modifier.padding(16.dp).verticalScroll(rememberScrollState()),
verticalArrangement = Arrangement.spacedBy(12.dp)
) {
var vadEnabled by remember { mutableStateOf(provider.getInt("radio.vad_enabled") != 0) }
var vadThreshold by remember { mutableStateOf(provider.getInt("radio.vad_threshold")) }
var vadHangover by remember { mutableStateOf(provider.getInt("radio.vad_hangover_ms")) }
var vadCompMaxGain by remember { mutableStateOf(provider.getInt("radio.vad_compressor_max_gain_db")) }
val vadActive by RadioAudioEngine.instance().vadActiveFlow.collectAsState()
Text(stringResource(R.string.radio_vad), style = MaterialTheme.typography.titleMedium)
Row(verticalAlignment = Alignment.CenterVertically) {
Text(stringResource(R.string.enable_vad), modifier = Modifier.weight(1f))
Switch(checked = vadEnabled, onCheckedChange = { enabled ->
vadEnabled = enabled
scope.launch {
provider.setValue("radio.vad_enabled", if (enabled) "1" else "0")
NativeLib.setChatSetting("radio_vad_enabled", if (enabled) "1" else "0")
if (enabled) RadioOverlayService.requestPermissions() else RadioOverlayService.sync(ChatApplication.instance)
RadioAudioEngine.instance().reconfigure()
}
})
}
Text(stringResource(if (vadActive) R.string.vad_active else R.string.vad_inactive),
style = MaterialTheme.typography.bodySmall)
Text(stringResource(R.string.vad_screen_hint),
@@ -661,6 +661,19 @@ class ChatViewModel : ViewModel() {
radioAudio.talkEnd()
}
/** Переключатель авто-PTT на панели рации: сохранить выбор и перенастроить захват. */
fun setRadioVad(enabled: Boolean) {
if (!_radioActive.value) return
viewModelScope.launch {
val ctx = ChatApplication.instance
ctx.configProvider.setValue("radio.vad_enabled", if (enabled) "1" else "0")
NativeLib.setChatSetting("radio_vad_enabled", if (enabled) "1" else "0")
LogManager.addLog("INFO", "RadioAudio", "Panel VAD enabled=$enabled channel=$radioChannelId")
if (enabled) RadioOverlayService.requestPermissions() else RadioOverlayService.sync(ctx)
radioAudio.reconfigure()
}
}
/** Ручной выбор выхода рации (динамик/гарнитура) — синхронизирует вход. */
fun setRadioRoute(r: AudioRoute) {
if (!_radioActive.value) return