feat: Only show compatible output formats based on encoder

This commit is contained in:
Myzel394 2023-08-09 21:44:12 +02:00
parent b0c036d297
commit 6c16928896
No known key found for this signature in database
GPG Key ID: 79CC92F37B3E1A2B
5 changed files with 104 additions and 6 deletions

View File

@ -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()
} }
} }

View File

@ -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(

View File

@ -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()
} }
} }
} }

View File

@ -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)
}
}
}

View File

@ -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>