mirror of
https://github.com/Myzel394/Alibi.git
synced 2025-06-18 23:05:26 +02:00
feat: Allow user to show all hidden microphones
This commit is contained in:
parent
3f72efc8e6
commit
c15c4b59fa
@ -142,6 +142,7 @@ data class AudioRecorderSettings(
|
|||||||
val samplingRate: Int? = null,
|
val samplingRate: Int? = null,
|
||||||
val outputFormat: Int? = null,
|
val outputFormat: Int? = null,
|
||||||
val encoder: Int? = null,
|
val encoder: Int? = null,
|
||||||
|
val showAllMicrophones: Boolean = false,
|
||||||
) {
|
) {
|
||||||
fun getOutputFormat(): Int {
|
fun getOutputFormat(): Int {
|
||||||
if (outputFormat != null) {
|
if (outputFormat != null) {
|
||||||
@ -269,6 +270,10 @@ data class AudioRecorderSettings(
|
|||||||
return copy(forceExactMaxDuration = forceExactMaxDuration)
|
return copy(forceExactMaxDuration = forceExactMaxDuration)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun setShowAllMicrophones(showAllMicrophones: Boolean): AudioRecorderSettings {
|
||||||
|
return copy(showAllMicrophones = showAllMicrophones)
|
||||||
|
}
|
||||||
|
|
||||||
fun isEncoderCompatible(encoder: Int): Boolean {
|
fun isEncoderCompatible(encoder: Int): Boolean {
|
||||||
if (outputFormat == null || outputFormat == MediaRecorder.OutputFormat.DEFAULT) {
|
if (outputFormat == null || outputFormat == MediaRecorder.OutputFormat.DEFAULT) {
|
||||||
return true
|
return true
|
||||||
|
@ -15,6 +15,7 @@ import androidx.compose.foundation.layout.width
|
|||||||
import androidx.compose.material3.LinearProgressIndicator
|
import androidx.compose.material3.LinearProgressIndicator
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.LaunchedEffect
|
import androidx.compose.runtime.LaunchedEffect
|
||||||
|
import androidx.compose.runtime.collectAsState
|
||||||
import androidx.compose.runtime.getValue
|
import androidx.compose.runtime.getValue
|
||||||
import androidx.compose.runtime.mutableStateOf
|
import androidx.compose.runtime.mutableStateOf
|
||||||
import androidx.compose.runtime.remember
|
import androidx.compose.runtime.remember
|
||||||
@ -23,6 +24,8 @@ import androidx.compose.ui.Alignment
|
|||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.platform.LocalContext
|
import androidx.compose.ui.platform.LocalContext
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
|
import app.myzel394.alibi.dataStore
|
||||||
|
import app.myzel394.alibi.db.AppSettings
|
||||||
import app.myzel394.alibi.ui.components.AudioRecorder.atoms.DeleteButton
|
import app.myzel394.alibi.ui.components.AudioRecorder.atoms.DeleteButton
|
||||||
import app.myzel394.alibi.ui.components.AudioRecorder.atoms.MicrophoneDisconnectedDialog
|
import app.myzel394.alibi.ui.components.AudioRecorder.atoms.MicrophoneDisconnectedDialog
|
||||||
import app.myzel394.alibi.ui.components.AudioRecorder.atoms.MicrophoneReconnectedDialog
|
import app.myzel394.alibi.ui.components.AudioRecorder.atoms.MicrophoneReconnectedDialog
|
||||||
@ -138,8 +141,18 @@ fun RecordingStatus(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val dataStore = LocalContext.current.dataStore
|
||||||
val microphones = MicrophoneInfo.fetchDeviceMicrophones(context)
|
val settings = dataStore
|
||||||
|
.data
|
||||||
|
.collectAsState(initial = AppSettings.getDefaultInstance())
|
||||||
|
.value
|
||||||
|
val microphones = MicrophoneInfo.fetchDeviceMicrophones(context).let {
|
||||||
|
if (settings.audioRecorderSettings.showAllMicrophones) {
|
||||||
|
it
|
||||||
|
} else {
|
||||||
|
MicrophoneInfo.filterMicrophones(it)
|
||||||
|
}
|
||||||
|
}
|
||||||
val microphoneStatus = audioRecorder.microphoneStatus
|
val microphoneStatus = audioRecorder.microphoneStatus
|
||||||
val previousStatus = rememberPrevious(microphoneStatus)
|
val previousStatus = rememberPrevious(microphoneStatus)
|
||||||
|
|
||||||
|
@ -0,0 +1,57 @@
|
|||||||
|
package app.myzel394.alibi.ui.components.SettingsScreen.atoms
|
||||||
|
|
||||||
|
import androidx.compose.material.icons.Icons
|
||||||
|
import androidx.compose.material.icons.filled.GraphicEq
|
||||||
|
import androidx.compose.material.icons.filled.MicExternalOn
|
||||||
|
import androidx.compose.material3.Icon
|
||||||
|
import androidx.compose.material3.Switch
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.collectAsState
|
||||||
|
import androidx.compose.runtime.rememberCoroutineScope
|
||||||
|
import androidx.compose.ui.platform.LocalContext
|
||||||
|
import androidx.compose.ui.res.stringResource
|
||||||
|
import app.myzel394.alibi.R
|
||||||
|
import app.myzel394.alibi.dataStore
|
||||||
|
import app.myzel394.alibi.db.AppSettings
|
||||||
|
import app.myzel394.alibi.ui.components.atoms.SettingsTile
|
||||||
|
import com.maxkeppeker.sheets.core.models.base.rememberUseCaseState
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun ShowAllMicrophonesTile() {
|
||||||
|
val scope = rememberCoroutineScope()
|
||||||
|
val dataStore = LocalContext.current.dataStore
|
||||||
|
val settings = dataStore
|
||||||
|
.data
|
||||||
|
.collectAsState(initial = AppSettings.getDefaultInstance())
|
||||||
|
.value
|
||||||
|
|
||||||
|
fun updateValue(showAllMicrophones: Boolean) {
|
||||||
|
scope.launch {
|
||||||
|
dataStore.updateData {
|
||||||
|
it.setAudioRecorderSettings(
|
||||||
|
it.audioRecorderSettings.setShowAllMicrophones(showAllMicrophones)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
SettingsTile(
|
||||||
|
title = stringResource(R.string.ui_settings_option_showAllMicrophones_title),
|
||||||
|
description = stringResource(R.string.ui_settings_option_showAllMicrophones_description),
|
||||||
|
leading = {
|
||||||
|
Icon(
|
||||||
|
Icons.Default.MicExternalOn,
|
||||||
|
contentDescription = null,
|
||||||
|
)
|
||||||
|
},
|
||||||
|
trailing = {
|
||||||
|
Switch(
|
||||||
|
checked = settings.audioRecorderSettings.showAllMicrophones,
|
||||||
|
onCheckedChange = ::updateValue,
|
||||||
|
)
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
@ -43,6 +43,7 @@ import app.myzel394.alibi.ui.components.SettingsScreen.atoms.IntervalDurationTil
|
|||||||
import app.myzel394.alibi.ui.components.SettingsScreen.atoms.MaxDurationTile
|
import app.myzel394.alibi.ui.components.SettingsScreen.atoms.MaxDurationTile
|
||||||
import app.myzel394.alibi.ui.components.SettingsScreen.atoms.OutputFormatTile
|
import app.myzel394.alibi.ui.components.SettingsScreen.atoms.OutputFormatTile
|
||||||
import app.myzel394.alibi.ui.components.SettingsScreen.atoms.SamplingRateTile
|
import app.myzel394.alibi.ui.components.SettingsScreen.atoms.SamplingRateTile
|
||||||
|
import app.myzel394.alibi.ui.components.SettingsScreen.atoms.ShowAllMicrophonesTile
|
||||||
import app.myzel394.alibi.ui.components.atoms.GlobalSwitch
|
import app.myzel394.alibi.ui.components.atoms.GlobalSwitch
|
||||||
import app.myzel394.alibi.ui.components.atoms.MessageBox
|
import app.myzel394.alibi.ui.components.atoms.MessageBox
|
||||||
import app.myzel394.alibi.ui.components.atoms.MessageType
|
import app.myzel394.alibi.ui.components.atoms.MessageType
|
||||||
@ -80,7 +81,7 @@ fun SettingsScreen(
|
|||||||
},
|
},
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.nestedScroll(scrollBehavior.nestedScrollConnection)
|
.nestedScroll(scrollBehavior.nestedScrollConnection)
|
||||||
) {padding ->
|
) { padding ->
|
||||||
Column(
|
Column(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.fillMaxSize()
|
.fillMaxSize()
|
||||||
@ -129,6 +130,7 @@ fun SettingsScreen(
|
|||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
.padding(horizontal = 16.dp, vertical = 32.dp)
|
.padding(horizontal = 16.dp, vertical = 32.dp)
|
||||||
)
|
)
|
||||||
|
ShowAllMicrophonesTile()
|
||||||
BitrateTile()
|
BitrateTile()
|
||||||
SamplingRateTile()
|
SamplingRateTile()
|
||||||
EncoderTile(snackbarHostState = snackbarHostState)
|
EncoderTile(snackbarHostState = snackbarHostState)
|
||||||
|
@ -55,21 +55,24 @@ data class MicrophoneInfo(
|
|||||||
fun fetchDeviceMicrophones(context: Context): List<MicrophoneInfo> {
|
fun fetchDeviceMicrophones(context: Context): List<MicrophoneInfo> {
|
||||||
return try {
|
return try {
|
||||||
val audioManager = context.getSystemService(Context.AUDIO_SERVICE)!! as AudioManager
|
val audioManager = context.getSystemService(Context.AUDIO_SERVICE)!! as AudioManager
|
||||||
val availableDevices = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
|
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
|
||||||
audioManager.availableCommunicationDevices.map(::fromDeviceInfo)
|
audioManager.availableCommunicationDevices.map(::fromDeviceInfo)
|
||||||
} else {
|
} else {
|
||||||
audioManager.getDevices(AudioManager.GET_DEVICES_INPUTS).map(::fromDeviceInfo)
|
audioManager.getDevices(AudioManager.GET_DEVICES_INPUTS).map(::fromDeviceInfo)
|
||||||
}
|
}
|
||||||
|
|
||||||
availableDevices.filter {
|
|
||||||
ALLOWED_MICROPHONE_TYPES.contains(it.deviceInfo.type) && it.deviceInfo.isSink
|
|
||||||
}
|
|
||||||
} catch (error: Exception) {
|
} catch (error: Exception) {
|
||||||
Log.getStackTraceString(error)
|
Log.getStackTraceString(error)
|
||||||
|
|
||||||
emptyList()
|
emptyList()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Filter microphones to only show normal ones
|
||||||
|
fun filterMicrophones(microphones: List<MicrophoneInfo>): List<MicrophoneInfo> {
|
||||||
|
return microphones.filter {
|
||||||
|
ALLOWED_MICROPHONE_TYPES.contains(it.deviceInfo.type) && it.deviceInfo.isSink
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -69,4 +69,6 @@
|
|||||||
<string name="ui_audioRecorder_error_microphoneDisconnected_message"><xliff:g name="name">%s</xliff:g> disconnected. Alibi will use the default microphone instead. We will automatically switch back to <xliff:g name="nam">%s</xliff:g> once it reconnects.</string>
|
<string name="ui_audioRecorder_error_microphoneDisconnected_message"><xliff:g name="name">%s</xliff:g> disconnected. Alibi will use the default microphone instead. We will automatically switch back to <xliff:g name="nam">%s</xliff:g> once it reconnects.</string>
|
||||||
<string name="ui_audioRecorder_error_microphoneReconnected_title">Microphone reconnected</string>
|
<string name="ui_audioRecorder_error_microphoneReconnected_title">Microphone reconnected</string>
|
||||||
<string name="ui_audioRecorder_error_microphoneReconnected_message"><xliff:g name="name">%s</xliff:g> reconnected! Alibi automatically changed the microphone input to it.</string>
|
<string name="ui_audioRecorder_error_microphoneReconnected_message"><xliff:g name="name">%s</xliff:g> reconnected! Alibi automatically changed the microphone input to it.</string>
|
||||||
|
<string name="ui_settings_option_showAllMicrophones_title">Show hidden microphones</string>
|
||||||
|
<string name="ui_settings_option_showAllMicrophones_description">Show all microphones, including internal ones</string>
|
||||||
</resources>
|
</resources>
|
Loading…
x
Reference in New Issue
Block a user