From 5c74b7cd3e766a39dd5bb7634722b893d48fa77a Mon Sep 17 00:00:00 2001 From: evgeny Date: Sat, 3 Oct 2026 14:21:20 +0300 Subject: [PATCH] android radio: add plus and minus to volume PTT icon --- doc/tasks.md | 1 + .../com/utun/chat/ui/screens/ChatScreen.kt | 28 +++++++++++++++++-- 2 files changed, 27 insertions(+), 2 deletions(-) diff --git a/doc/tasks.md b/doc/tasks.md index dd8ca9c4..f283295c 100644 --- a/doc/tasks.md +++ b/doc/tasks.md @@ -233,6 +233,7 @@ [+] **PTT кнопками громкости на панели рации Android** — 03.10.2026: переключатель слева от VAD, включённое состояние подсвечено; панель и настройки используют общий DataStore Flow. + Значок: динамик по центру, плюс сверху, минус снизу; проверен на панели Samsung после чистых сборок ядра/Qt/APK. Сохранение обновляет быстрый кэш после записи; ошибки записи логируются без изменения состояния переключателя. Экранная кнопка, оверлей и кнопки громкости имеют независимые владельцы ручной передачи. Учёт отдельных volume-клавиш защищает от повторов и посторонних клавиш; потеря фокуса/выключение опции отменяет volume-PTT. diff --git a/tools/chatgui-android/app/src/main/java/com/utun/chat/ui/screens/ChatScreen.kt b/tools/chatgui-android/app/src/main/java/com/utun/chat/ui/screens/ChatScreen.kt index 5eb28993..0aa7f899 100644 --- a/tools/chatgui-android/app/src/main/java/com/utun/chat/ui/screens/ChatScreen.kt +++ b/tools/chatgui-android/app/src/main/java/com/utun/chat/ui/screens/ChatScreen.kt @@ -301,7 +301,8 @@ private fun RadioSourceBar(viewModel: ChatViewModel) { } } VerticalDivider(modifier = Modifier.height(32.dp), color = Color(0xFF344550)) - RadioControlButton(Icons.AutoMirrored.Filled.VolumeUp, stringResource(R.string.volume_ptt), volumePttEnabled) { + RadioControlButton(Icons.AutoMirrored.Filled.VolumeUp, stringResource(R.string.volume_ptt), + volumePttEnabled, volumeKeys = true) { viewModel.setRadioVolumePtt(!volumePttEnabled) } RadioControlButton(null, stringResource(if (vadEnabled) R.string.disable_vad else R.string.enable_vad), @@ -326,7 +327,8 @@ private fun RadioSourceBar(viewModel: ChatViewModel) { @Composable private fun RadioControlButton( icon: ImageVector?, label: String, active: Boolean, - centerIcon: ImageVector? = null, bluetooth: Boolean = false, floating: Boolean = false, text: String? = null, onClick: () -> Unit + centerIcon: ImageVector? = null, bluetooth: Boolean = false, floating: Boolean = false, + volumeKeys: Boolean = false, text: String? = null, onClick: () -> Unit ) { IconToggleButton( checked = active, @@ -344,6 +346,10 @@ private fun RadioControlButton( RadioFloatingIcon(label) return@IconToggleButton } + if (volumeKeys) { + RadioVolumeKeysIcon(label) + return@IconToggleButton + } val background = if (active) Color(0xFF1F6FEB) else Color(0xFF24323D) Box(modifier = Modifier.size(34.dp), contentAlignment = Alignment.Center) { Icon(requireNotNull(icon), contentDescription = label, modifier = Modifier.size(if (centerIcon != null) 32.dp else 28.dp)) @@ -362,6 +368,24 @@ private fun RadioControlButton( } } +/* Динамик по центру, плюс сверху и минус снизу — аппаратные кнопки громкости. */ +@Composable +private fun RadioVolumeKeysIcon(label: String) { + val color = LocalContentColor.current + Box(Modifier.size(34.dp).semantics { contentDescription = label }, contentAlignment = Alignment.Center) { + Icon(Icons.AutoMirrored.Filled.VolumeUp, contentDescription = null, modifier = Modifier.size(22.dp)) + Canvas(Modifier.matchParentSize()) { + val half = 2.5.dp.toPx() + val top = 3.5.dp.toPx() + val bottom = size.height - top + val stroke = 1.7.dp.toPx() + drawLine(color, Offset(center.x - half, top), Offset(center.x + half, top), stroke, cap = StrokeCap.Round) + drawLine(color, Offset(center.x, top - half), Offset(center.x, top + half), stroke, cap = StrokeCap.Round) + drawLine(color, Offset(center.x - half, bottom), Offset(center.x + half, bottom), stroke, cap = StrokeCap.Round) + } + } +} + /* Кружок и четыре стрелки наружу — плавающая/перемещаемая PTT-кнопка. */ @Composable private fun RadioFloatingIcon(label: String) {