feat: Add MaxDurationTile

This commit is contained in:
Myzel394 2023-08-05 00:09:19 +02:00
parent df137be466
commit f045e6f610
No known key found for this signature in database
GPG Key ID: 79CC92F37B3E1A2B
2 changed files with 154 additions and 13 deletions

View File

@ -27,6 +27,7 @@ data class AppSettings(
@Serializable
data class AudioRecorderSettings(
val maxDuration: Long = 30 * 60 * 1000L,
// 60 seconds
val intervalDuration: Long = 60 * 1000L,
// 320 Kbps
@ -59,24 +60,15 @@ data class AudioRecorderSettings(
else
MediaRecorder.AudioEncoder.AMR_NB
fun getFileExtensions(): String =
when(getOutputFormat()) {
MediaRecorder.OutputFormat.AAC_ADTS -> "aac"
MediaRecorder.OutputFormat.THREE_GPP -> "3gp"
MediaRecorder.OutputFormat.MPEG_4 -> "mp4"
MediaRecorder.OutputFormat.MPEG_2_TS -> "ts"
MediaRecorder.OutputFormat.WEBM -> "webm"
MediaRecorder.OutputFormat.AMR_NB -> "amr"
MediaRecorder.OutputFormat.AMR_WB -> "awb"
MediaRecorder.OutputFormat.OGG -> "ogg"
else -> "raw"
}
fun setIntervalDuration(duration: Long): AudioRecorderSettings {
if (duration < 30 * 1000L || duration > 60 * 60 * 1000L) {
throw Exception("Interval duration must be between 30 seconds and 1 hour")
}
if (duration > maxDuration) {
throw Exception("Interval duration must be less than max duration")
}
return copy(intervalDuration = duration)
}
@ -113,7 +105,27 @@ data class AudioRecorderSettings(
return copy(encoder = encoder)
}
fun setMaxDuration(duration: Long): AudioRecorderSettings {
if (duration < 60 * 1000L || duration > 60 * 60 * 1000L) {
throw Exception("Max duration must be between 1 minute and 1 hour")
}
if (duration < intervalDuration) {
throw Exception("Max duration must be greater than interval duration")
}
return copy(maxDuration = duration)
}
companion object {
fun getDefaultInstance(): AudioRecorderSettings = AudioRecorderSettings()
val EXAMPLE_MAX_DURATIONS = listOf(
15 * 60 * 1000L,
30 * 60 * 1000L,
60 * 60 * 1000L,
2 * 60 * 60 * 1000L,
3 * 60 * 60 * 1000L,
)
val EXAMPLE_DURATION_TIMES = listOf(
60 * 1000L,
60 * 5 * 1000L,

View File

@ -0,0 +1,129 @@
package app.myzel394.locationtest.ui.components.SettingsScreen.atoms
import androidx.compose.foundation.lazy.LazyRow
import androidx.compose.foundation.text.KeyboardActions
import androidx.compose.foundation.text.KeyboardOptions
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Mic
import androidx.compose.material.icons.filled.Timer
import androidx.compose.material.icons.filled.Tune
import androidx.compose.material3.Button
import androidx.compose.material3.ButtonDefaults
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.text.input.KeyboardType
import androidx.compose.ui.unit.dp
import app.myzel394.locationtest.dataStore
import app.myzel394.locationtest.db.AppSettings
import app.myzel394.locationtest.db.AudioRecorderSettings
import app.myzel394.locationtest.ui.components.atoms.ExampleListRoulette
import app.myzel394.locationtest.ui.components.atoms.SettingsTile
import app.myzel394.locationtest.ui.utils.formatDuration
import com.maxkeppeker.sheets.core.models.base.IconSource
import com.maxkeppeker.sheets.core.models.base.rememberUseCaseState
import com.maxkeppeler.sheets.input.InputDialog
import com.maxkeppeler.sheets.input.models.InputHeader
import com.maxkeppeler.sheets.input.models.InputSelection
import com.maxkeppeler.sheets.input.models.InputTextField
import com.maxkeppeler.sheets.input.models.InputTextFieldType
import com.maxkeppeler.sheets.input.models.ValidationResult
import kotlinx.coroutines.launch
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun MaxDurationTile() {
val scope = rememberCoroutineScope()
val showDialog = rememberUseCaseState()
val dataStore = LocalContext.current.dataStore
val settings = dataStore
.data
.collectAsState(initial = AppSettings.getDefaultInstance())
.value
fun updateValue(maxDuration: Long) {
scope.launch {
dataStore.updateData {
it.setAudioRecorderSettings(
it.audioRecorderSettings.setMaxDuration(maxDuration)
)
}
}
}
InputDialog(
state = showDialog,
selection = InputSelection(
input = listOf(
InputTextField(
header = InputHeader(
title = "Set the maximum duration",
icon = IconSource(Icons.Default.Timer),
),
keyboardOptions = KeyboardOptions(
keyboardType = KeyboardType.Number,
),
type = InputTextFieldType.OUTLINED,
text = settings.audioRecorderSettings.maxDuration.toString(),
validationListener = { text ->
val maxDuration = text?.toLongOrNull()
if (maxDuration == null) {
ValidationResult.Invalid("Please enter a valid number")
}
if (maxDuration !in (60 * 1000L)..(60 * 60 * 1000L)) {
ValidationResult.Invalid("Please enter a number between 1 minute and 1 hour")
}
ValidationResult.Valid
},
key = "maxDuration",
)
),
) { result ->
val maxDuration = result.getString("maxDuration")?.toLongOrNull() ?: throw IllegalStateException("Invalid maxDuration")
updateValue(maxDuration)
}
)
SettingsTile(
title = "Max duration",
description = "Set the maximum duration of the recording",
leading = {
Icon(
Icons.Default.Timer,
contentDescription = null,
)
},
trailing = {
Button(
onClick = showDialog::show,
colors = ButtonDefaults.filledTonalButtonColors(
containerColor = MaterialTheme.colorScheme.surfaceVariant,
),
shape = MaterialTheme.shapes.medium,
) {
Text(
text = formatDuration(settings.audioRecorderSettings.maxDuration),
)
}
},
extra = {
ExampleListRoulette(
items = AudioRecorderSettings.EXAMPLE_MAX_DURATIONS,
onItemSelected = ::updateValue,
) {maxDuration ->
Text(
text = formatDuration(maxDuration),
)
}
}
)
}