mirror of
https://github.com/Myzel394/Alibi.git
synced 2025-06-19 07:15:25 +02:00
feat: Only show compatible output formats based on encoder
This commit is contained in:
parent
b0c036d297
commit
6c16928896
@ -228,6 +228,12 @@ data class AudioRecorderSettings(
|
|||||||
return copy(forceExactMaxDuration = forceExactMaxDuration)
|
return copy(forceExactMaxDuration = forceExactMaxDuration)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun isOutputFormatCompatible(format: Int): Boolean {
|
||||||
|
val supportedFormats = ENCODER_SUPPORTED_OUTPUT_FORMATS_MAP[getEncoder()]!!
|
||||||
|
|
||||||
|
return supportedFormats.contains(format)
|
||||||
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
fun getDefaultInstance(): AudioRecorderSettings = AudioRecorderSettings()
|
fun getDefaultInstance(): AudioRecorderSettings = AudioRecorderSettings()
|
||||||
val EXAMPLE_MAX_DURATIONS = listOf(
|
val EXAMPLE_MAX_DURATIONS = listOf(
|
||||||
@ -284,5 +290,41 @@ data class AudioRecorderSettings(
|
|||||||
6 to "VORBIS",
|
6 to "VORBIS",
|
||||||
7 to "OPUS",
|
7 to "OPUS",
|
||||||
)
|
)
|
||||||
|
val ENCODER_SUPPORTED_OUTPUT_FORMATS_MAP: Map<Int, Array<Int>> = mutableMapOf(
|
||||||
|
MediaRecorder.AudioEncoder.AAC to arrayOf(
|
||||||
|
MediaRecorder.OutputFormat.THREE_GPP,
|
||||||
|
MediaRecorder.OutputFormat.MPEG_4,
|
||||||
|
MediaRecorder.OutputFormat.AAC_ADTS,
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) MediaRecorder.OutputFormat.MPEG_2_TS else null,
|
||||||
|
).filterNotNull().toTypedArray(),
|
||||||
|
MediaRecorder.AudioEncoder.AAC_ELD to arrayOf(
|
||||||
|
MediaRecorder.OutputFormat.THREE_GPP,
|
||||||
|
MediaRecorder.OutputFormat.MPEG_4,
|
||||||
|
MediaRecorder.OutputFormat.AAC_ADTS,
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) MediaRecorder.OutputFormat.MPEG_2_TS else null,
|
||||||
|
).filterNotNull().toTypedArray(),
|
||||||
|
MediaRecorder.AudioEncoder.AMR_NB to arrayOf(
|
||||||
|
MediaRecorder.OutputFormat.THREE_GPP,
|
||||||
|
MediaRecorder.OutputFormat.AMR_NB,
|
||||||
|
),
|
||||||
|
MediaRecorder.AudioEncoder.AMR_WB to arrayOf(
|
||||||
|
MediaRecorder.OutputFormat.THREE_GPP,
|
||||||
|
MediaRecorder.OutputFormat.AMR_WB,
|
||||||
|
),
|
||||||
|
MediaRecorder.AudioEncoder.HE_AAC to arrayOf(
|
||||||
|
MediaRecorder.OutputFormat.THREE_GPP,
|
||||||
|
MediaRecorder.OutputFormat.MPEG_4,
|
||||||
|
MediaRecorder.OutputFormat.AAC_ADTS,
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) MediaRecorder.OutputFormat.MPEG_2_TS else null,
|
||||||
|
).filterNotNull().toTypedArray(),
|
||||||
|
MediaRecorder.AudioEncoder.VORBIS to arrayOf(
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) MediaRecorder.OutputFormat.OGG else null,
|
||||||
|
MediaRecorder.OutputFormat.MPEG_4
|
||||||
|
).filterNotNull().toTypedArray(),
|
||||||
|
).apply {
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
|
||||||
|
put(MediaRecorder.AudioEncoder.OPUS, arrayOf(MediaRecorder.OutputFormat.OGG))
|
||||||
|
}
|
||||||
|
}.toMap()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
package app.myzel394.alibi.ui.components.SettingsScreen.atoms
|
package app.myzel394.alibi.ui.components.SettingsScreen.atoms
|
||||||
|
|
||||||
|
import android.media.MediaRecorder
|
||||||
import androidx.compose.material.icons.Icons
|
import androidx.compose.material.icons.Icons
|
||||||
import androidx.compose.material.icons.filled.AudioFile
|
import androidx.compose.material.icons.filled.AudioFile
|
||||||
import androidx.compose.material3.Button
|
import androidx.compose.material3.Button
|
||||||
@ -7,9 +8,13 @@ import androidx.compose.material3.ButtonDefaults
|
|||||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||||
import androidx.compose.material3.Icon
|
import androidx.compose.material3.Icon
|
||||||
import androidx.compose.material3.MaterialTheme
|
import androidx.compose.material3.MaterialTheme
|
||||||
|
import androidx.compose.material3.SnackbarDuration
|
||||||
|
import androidx.compose.material3.SnackbarHostState
|
||||||
|
import androidx.compose.material3.SnackbarVisuals
|
||||||
import androidx.compose.material3.Text
|
import androidx.compose.material3.Text
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.collectAsState
|
import androidx.compose.runtime.collectAsState
|
||||||
|
import androidx.compose.runtime.remember
|
||||||
import androidx.compose.runtime.rememberCoroutineScope
|
import androidx.compose.runtime.rememberCoroutineScope
|
||||||
import androidx.compose.ui.platform.LocalContext
|
import androidx.compose.ui.platform.LocalContext
|
||||||
import androidx.compose.ui.res.stringResource
|
import androidx.compose.ui.res.stringResource
|
||||||
@ -19,6 +24,9 @@ import app.myzel394.alibi.db.AppSettings
|
|||||||
import app.myzel394.alibi.db.AudioRecorderSettings
|
import app.myzel394.alibi.db.AudioRecorderSettings
|
||||||
import app.myzel394.alibi.ui.components.atoms.ExampleListRoulette
|
import app.myzel394.alibi.ui.components.atoms.ExampleListRoulette
|
||||||
import app.myzel394.alibi.ui.components.atoms.SettingsTile
|
import app.myzel394.alibi.ui.components.atoms.SettingsTile
|
||||||
|
import app.myzel394.alibi.ui.utils.IconResource
|
||||||
|
import com.maxkeppeker.sheets.core.models.base.Header
|
||||||
|
import com.maxkeppeker.sheets.core.models.base.IconSource
|
||||||
import com.maxkeppeker.sheets.core.models.base.rememberUseCaseState
|
import com.maxkeppeker.sheets.core.models.base.rememberUseCaseState
|
||||||
import com.maxkeppeler.sheets.list.ListDialog
|
import com.maxkeppeler.sheets.list.ListDialog
|
||||||
import com.maxkeppeler.sheets.list.models.ListOption
|
import com.maxkeppeler.sheets.list.models.ListOption
|
||||||
@ -35,6 +43,9 @@ fun OutputFormatTile() {
|
|||||||
.data
|
.data
|
||||||
.collectAsState(initial = AppSettings.getDefaultInstance())
|
.collectAsState(initial = AppSettings.getDefaultInstance())
|
||||||
.value
|
.value
|
||||||
|
val availableOptions = if (settings.audioRecorderSettings.encoder == null)
|
||||||
|
AudioRecorderSettings.OUTPUT_FORMAT_INDEX_TEXT_MAP.keys.toTypedArray()
|
||||||
|
else arrayOf(MediaRecorder.OutputFormat.DEFAULT, *AudioRecorderSettings.ENCODER_SUPPORTED_OUTPUT_FORMATS_MAP[settings.audioRecorderSettings.encoder]!!)
|
||||||
|
|
||||||
fun updateValue(outputFormat: Int?) {
|
fun updateValue(outputFormat: Int?) {
|
||||||
scope.launch {
|
scope.launch {
|
||||||
@ -48,16 +59,23 @@ fun OutputFormatTile() {
|
|||||||
|
|
||||||
ListDialog(
|
ListDialog(
|
||||||
state = showDialog,
|
state = showDialog,
|
||||||
|
header = Header.Default(
|
||||||
|
title = stringResource(R.string.ui_settings_option_outputFormat_title),
|
||||||
|
icon = IconSource(
|
||||||
|
painter = IconResource.fromImageVector(Icons.Default.AudioFile).asPainterResource(),
|
||||||
|
contentDescription = null,
|
||||||
|
)
|
||||||
|
),
|
||||||
selection = ListSelection.Single(
|
selection = ListSelection.Single(
|
||||||
showRadioButtons = true,
|
showRadioButtons = true,
|
||||||
options = IntRange(0, 11).map { index ->
|
options = availableOptions.map { option ->
|
||||||
ListOption(
|
ListOption(
|
||||||
titleText = AudioRecorderSettings.OUTPUT_FORMAT_INDEX_TEXT_MAP[index]!!,
|
titleText = AudioRecorderSettings.OUTPUT_FORMAT_INDEX_TEXT_MAP[option]!!,
|
||||||
selected = settings.audioRecorderSettings.outputFormat == index,
|
selected = settings.audioRecorderSettings.outputFormat == option,
|
||||||
)
|
)
|
||||||
}.toList()
|
}.toList()
|
||||||
) {index, option ->
|
) {index, option ->
|
||||||
updateValue(index)
|
updateValue(availableOptions[index])
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
SettingsTile(
|
SettingsTile(
|
||||||
|
@ -16,11 +16,14 @@ import androidx.compose.material3.Icon
|
|||||||
import androidx.compose.material3.IconButton
|
import androidx.compose.material3.IconButton
|
||||||
import androidx.compose.material3.LargeTopAppBar
|
import androidx.compose.material3.LargeTopAppBar
|
||||||
import androidx.compose.material3.Scaffold
|
import androidx.compose.material3.Scaffold
|
||||||
|
import androidx.compose.material3.SnackbarHost
|
||||||
|
import androidx.compose.material3.SnackbarHostState
|
||||||
import androidx.compose.material3.Text
|
import androidx.compose.material3.Text
|
||||||
import androidx.compose.material3.TopAppBarDefaults
|
import androidx.compose.material3.TopAppBarDefaults
|
||||||
import androidx.compose.material3.rememberTopAppBarState
|
import androidx.compose.material3.rememberTopAppBarState
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.collectAsState
|
import androidx.compose.runtime.collectAsState
|
||||||
|
import androidx.compose.runtime.remember
|
||||||
import androidx.compose.runtime.rememberCoroutineScope
|
import androidx.compose.runtime.rememberCoroutineScope
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
@ -51,11 +54,13 @@ fun SettingsScreen(
|
|||||||
navController: NavController,
|
navController: NavController,
|
||||||
audioRecorder: AudioRecorderModel,
|
audioRecorder: AudioRecorderModel,
|
||||||
) {
|
) {
|
||||||
|
val snackbarHostState = remember { SnackbarHostState() }
|
||||||
val scrollBehavior = TopAppBarDefaults.exitUntilCollapsedScrollBehavior(
|
val scrollBehavior = TopAppBarDefaults.exitUntilCollapsedScrollBehavior(
|
||||||
rememberTopAppBarState()
|
rememberTopAppBarState()
|
||||||
)
|
)
|
||||||
|
|
||||||
Scaffold(
|
Scaffold(
|
||||||
|
snackbarHost = { SnackbarHost(hostState = snackbarHostState) },
|
||||||
topBar = {
|
topBar = {
|
||||||
LargeTopAppBar(
|
LargeTopAppBar(
|
||||||
title = {
|
title = {
|
||||||
@ -124,8 +129,8 @@ fun SettingsScreen(
|
|||||||
)
|
)
|
||||||
BitrateTile()
|
BitrateTile()
|
||||||
SamplingRateTile()
|
SamplingRateTile()
|
||||||
OutputFormatTile()
|
|
||||||
EncoderTile()
|
EncoderTile()
|
||||||
|
OutputFormatTile()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,32 @@
|
|||||||
|
package app.myzel394.alibi.ui.utils
|
||||||
|
|
||||||
|
import androidx.annotation.DrawableRes
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.ui.graphics.painter.Painter
|
||||||
|
import androidx.compose.ui.graphics.vector.ImageVector
|
||||||
|
import androidx.compose.ui.graphics.vector.rememberVectorPainter
|
||||||
|
import androidx.compose.ui.res.painterResource
|
||||||
|
|
||||||
|
class IconResource private constructor(
|
||||||
|
@DrawableRes private val resID: Int?,
|
||||||
|
private val imageVector: ImageVector?
|
||||||
|
) {
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun asPainterResource(): Painter {
|
||||||
|
resID?.let {
|
||||||
|
return painterResource(id = resID)
|
||||||
|
}
|
||||||
|
return rememberVectorPainter(image = imageVector!!)
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
fun fromDrawableResource(@DrawableRes resID: Int): IconResource {
|
||||||
|
return IconResource(resID, null)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun fromImageVector(imageVector: ImageVector?): IconResource {
|
||||||
|
return IconResource(null, imageVector)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -52,11 +52,12 @@
|
|||||||
<string name="ui_settings_option_bitrate_description">A higher bitrate means better quality but also larger file size</string>
|
<string name="ui_settings_option_bitrate_description">A higher bitrate means better quality but also larger file size</string>
|
||||||
<string name="ui_settings_option_bitrate_explanation">Set the bitrate for the audio recording</string>
|
<string name="ui_settings_option_bitrate_explanation">Set the bitrate for the audio recording</string>
|
||||||
<string name="ui_settings_option_outputFormat_title">Output Format</string>
|
<string name="ui_settings_option_outputFormat_title">Output Format</string>
|
||||||
<string name="ui_settings_value_auto_label">Auto</string>
|
<string name="ui_settings_option_outputFormat_extra_encoderChanged">Encoder has been changed because the current one was incompatible with this output format</string>
|
||||||
<string name="ui_settings_option_samplingRate_title">Sampling rate</string>
|
<string name="ui_settings_option_samplingRate_title">Sampling rate</string>
|
||||||
<string name="ui_settings_option_samplingRate_description">Define how many samples per second are taken from the audio signal</string>
|
<string name="ui_settings_option_samplingRate_description">Define how many samples per second are taken from the audio signal</string>
|
||||||
<string name="ui_settings_option_samplingRate_explanation">Set the sampling rate</string>
|
<string name="ui_settings_option_samplingRate_explanation">Set the sampling rate</string>
|
||||||
<string name="ui_settings_option_encoder_title">Encoder</string>
|
<string name="ui_settings_option_encoder_title">Encoder</string>
|
||||||
|
<string name="ui_settings_value_auto_label">Auto</string>
|
||||||
<string name="ui_audioRecorder_state_paused_title">Recording paused</string>
|
<string name="ui_audioRecorder_state_paused_title">Recording paused</string>
|
||||||
<string name="ui_audioRecorder_state_paused_description">Audio Recording has been paused</string>
|
<string name="ui_audioRecorder_state_paused_description">Audio Recording has been paused</string>
|
||||||
</resources>
|
</resources>
|
Loading…
x
Reference in New Issue
Block a user