Browse Source

android radio: add plus and minus to volume PTT icon

master
evgeny 1 week ago
parent
commit
5c74b7cd3e
  1. 1
      doc/tasks.md
  2. 28
      tools/chatgui-android/app/src/main/java/com/utun/chat/ui/screens/ChatScreen.kt

1
doc/tasks.md

@ -233,6 +233,7 @@
[+] **PTT кнопками громкости на панели рации Android** — 03.10.2026: [+] **PTT кнопками громкости на панели рации Android** — 03.10.2026:
переключатель слева от VAD, включённое состояние подсвечено; панель и настройки используют общий DataStore Flow. переключатель слева от VAD, включённое состояние подсвечено; панель и настройки используют общий DataStore Flow.
Значок: динамик по центру, плюс сверху, минус снизу; проверен на панели Samsung после чистых сборок ядра/Qt/APK.
Сохранение обновляет быстрый кэш после записи; ошибки записи логируются без изменения состояния переключателя. Сохранение обновляет быстрый кэш после записи; ошибки записи логируются без изменения состояния переключателя.
Экранная кнопка, оверлей и кнопки громкости имеют независимые владельцы ручной передачи. Экранная кнопка, оверлей и кнопки громкости имеют независимые владельцы ручной передачи.
Учёт отдельных volume-клавиш защищает от повторов и посторонних клавиш; потеря фокуса/выключение опции отменяет volume-PTT. Учёт отдельных volume-клавиш защищает от повторов и посторонних клавиш; потеря фокуса/выключение опции отменяет volume-PTT.

28
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)) 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) viewModel.setRadioVolumePtt(!volumePttEnabled)
} }
RadioControlButton(null, stringResource(if (vadEnabled) R.string.disable_vad else R.string.enable_vad), RadioControlButton(null, stringResource(if (vadEnabled) R.string.disable_vad else R.string.enable_vad),
@ -326,7 +327,8 @@ private fun RadioSourceBar(viewModel: ChatViewModel) {
@Composable @Composable
private fun RadioControlButton( private fun RadioControlButton(
icon: ImageVector?, label: String, active: Boolean, 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( IconToggleButton(
checked = active, checked = active,
@ -344,6 +346,10 @@ private fun RadioControlButton(
RadioFloatingIcon(label) RadioFloatingIcon(label)
return@IconToggleButton return@IconToggleButton
} }
if (volumeKeys) {
RadioVolumeKeysIcon(label)
return@IconToggleButton
}
val background = if (active) Color(0xFF1F6FEB) else Color(0xFF24323D) val background = if (active) Color(0xFF1F6FEB) else Color(0xFF24323D)
Box(modifier = Modifier.size(34.dp), contentAlignment = Alignment.Center) { 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)) 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-кнопка. */ /* Кружок и четыре стрелки наружу — плавающая/перемещаемая PTT-кнопка. */
@Composable @Composable
private fun RadioFloatingIcon(label: String) { private fun RadioFloatingIcon(label: String) {

Loading…
Cancel
Save