Add a common audio device selector for radio and streams
This commit is contained in:
1 parent
bebc579180
commit
33ccba1f3f
3 files changed
+84
No files matched your search
+66
@@ -0,0 +1,66 @@
|
||||
package com.utun.chat.ui.components
|
||||
|
||||
import android.Manifest
|
||||
import android.content.pm.PackageManager
|
||||
import android.os.Build
|
||||
import androidx.activity.compose.rememberLauncherForActivityResult
|
||||
import androidx.activity.result.contract.ActivityResultContracts
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.automirrored.filled.VolumeUp
|
||||
import androidx.compose.material.icons.filled.HeadsetMic
|
||||
import androidx.compose.material3.*
|
||||
import androidx.compose.runtime.*
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.core.content.ContextCompat
|
||||
import com.utun.chat.R
|
||||
import com.utun.chat.data.MediaAudioController
|
||||
import com.utun.chat.data.MediaAudioProfile
|
||||
import com.utun.chat.data.LogManager
|
||||
|
||||
/** Один выбор для панели рации, публикации и всех экранов просмотра. */
|
||||
@Composable
|
||||
fun MediaAudioDeviceButton(tint: Color = LocalContentColor.current, onExpandedChange: (Boolean) -> Unit = {}) {
|
||||
val state by MediaAudioController.state.collectAsState()
|
||||
val context = LocalContext.current
|
||||
var expanded by remember { mutableStateOf(false) }
|
||||
val permission = rememberLauncherForActivityResult(ActivityResultContracts.RequestPermission()) { granted ->
|
||||
if (granted) MediaAudioController.select(MediaAudioProfile.BLUETOOTH)
|
||||
else LogManager.addLog("WARN", "media_audio", "Bluetooth selection cancelled: BLUETOOTH_CONNECT denied")
|
||||
}
|
||||
val bluetoothPermission = Build.VERSION.SDK_INT < 31 ||
|
||||
ContextCompat.checkSelfPermission(context, Manifest.permission.BLUETOOTH_CONNECT) == PackageManager.PERMISSION_GRANTED
|
||||
fun expand(value: Boolean) { expanded = value; onExpandedChange(value) }
|
||||
val labels = mapOf(MediaAudioProfile.AUTO to R.string.media_audio_auto, MediaAudioProfile.PHONE to R.string.media_audio_phone,
|
||||
MediaAudioProfile.WIRED to R.string.media_audio_wired, MediaAudioProfile.BLUETOOTH to R.string.media_audio_bluetooth)
|
||||
Box {
|
||||
IconButton(onClick = { expand(true) }) {
|
||||
Icon(if (state.active == MediaAudioProfile.PHONE) Icons.AutoMirrored.Filled.VolumeUp else Icons.Filled.HeadsetMic,
|
||||
stringResource(R.string.media_audio_devices, stringResource(labels.getValue(state.preferred))),
|
||||
tint = if (state.notice != null) MaterialTheme.colorScheme.error else tint)
|
||||
}
|
||||
DropdownMenu(expanded, onDismissRequest = { expand(false) }) {
|
||||
for ((profile, label) in labels) {
|
||||
val available = when (profile) {
|
||||
MediaAudioProfile.WIRED -> state.wiredAvailable
|
||||
MediaAudioProfile.BLUETOOTH -> state.bluetoothAvailable || !bluetoothPermission
|
||||
else -> true
|
||||
}
|
||||
DropdownMenuItem(text = { Text(stringResource(label)) }, enabled = available,
|
||||
trailingIcon = { if (state.preferred == profile) Text("✓") }, onClick = {
|
||||
expand(false)
|
||||
if (profile == MediaAudioProfile.BLUETOOTH && !bluetoothPermission)
|
||||
permission.launch(Manifest.permission.BLUETOOTH_CONNECT)
|
||||
else MediaAudioController.select(profile)
|
||||
})
|
||||
}
|
||||
HorizontalDivider()
|
||||
DropdownMenuItem(text = { Text(stringResource(R.string.media_audio_actual, state.inputName ?: "—", state.outputName ?: "—")) },
|
||||
onClick = {}, enabled = false)
|
||||
if (state.switching) DropdownMenuItem(text = { Text(stringResource(R.string.media_audio_switching)) }, onClick = {}, enabled = false)
|
||||
state.notice?.let { notice -> DropdownMenuItem(text = { Text(stringResource(notice), color = MaterialTheme.colorScheme.error) }, onClick = {}) }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -582,4 +582,13 @@
|
||||
<string name="block_incoming_calls_description">Отклонять входящие звонки vibechat без рингтона</string>
|
||||
<string name="block_incoming_radio">Отклонять все вызовы по рации</string>
|
||||
<string name="block_incoming_radio_description">Отклонять приглашения; включённая рация продолжит работать</string>
|
||||
<string name="media_audio_devices">Аудиоустройство: %1$s</string>
|
||||
<string name="media_audio_auto">Автоматически</string>
|
||||
<string name="media_audio_phone">Телефон</string>
|
||||
<string name="media_audio_wired">Проводное / USB</string>
|
||||
<string name="media_audio_bluetooth">Bluetooth</string>
|
||||
<string name="media_audio_actual">Микрофон: %1$s\nВыход: %2$s</string>
|
||||
<string name="media_audio_switching">Переключение аудиоустройства…</string>
|
||||
<string name="media_audio_fallback">Выбранное устройство отключено. Используется микрофон и динамик телефона.</string>
|
||||
<string name="media_audio_failed">Не удалось использовать выбранное аудиоустройство. Проверьте текущие микрофон и выход.</string>
|
||||
</resources>
|
||||
@@ -581,4 +581,13 @@
|
||||
<string name="block_incoming_calls_description">Reject incoming vibechat calls without ringing</string>
|
||||
<string name="block_incoming_radio">Reject all radio calls</string>
|
||||
<string name="block_incoming_radio_description">Reject radio invitations; the channel radio keeps working</string>
|
||||
<string name="media_audio_devices">Audio device: %1$s</string>
|
||||
<string name="media_audio_auto">Automatic</string>
|
||||
<string name="media_audio_phone">Phone</string>
|
||||
<string name="media_audio_wired">Wired / USB</string>
|
||||
<string name="media_audio_bluetooth">Bluetooth</string>
|
||||
<string name="media_audio_actual">Microphone: %1$s\nOutput: %2$s</string>
|
||||
<string name="media_audio_switching">Switching audio device…</string>
|
||||
<string name="media_audio_fallback">The selected device is disconnected. Phone audio is in use.</string>
|
||||
<string name="media_audio_failed">Could not use the selected audio device. Check the current microphone and output.</string>
|
||||
</resources>
|
||||
Reference in new issue
Block a user