mirror of
https://github.com/Myzel394/Alibi.git
synced 2025-06-19 07:15:25 +02:00
feat: Add VideoRecorderBitrateTile
This commit is contained in:
parent
4f265b23f8
commit
9598cd45fa
@ -40,6 +40,10 @@ data class AppSettings(
|
|||||||
return copy(audioRecorderSettings = audioRecorderSettings)
|
return copy(audioRecorderSettings = audioRecorderSettings)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun setVideoRecorderSettings(videoRecorderSettings: VideoRecorderSettings): AppSettings {
|
||||||
|
return copy(videoRecorderSettings = videoRecorderSettings)
|
||||||
|
}
|
||||||
|
|
||||||
fun setNotificationSettings(notificationSettings: NotificationSettings?): AppSettings {
|
fun setNotificationSettings(notificationSettings: NotificationSettings?): AppSettings {
|
||||||
return copy(notificationSettings = notificationSettings)
|
return copy(notificationSettings = notificationSettings)
|
||||||
}
|
}
|
||||||
@ -401,6 +405,20 @@ data class VideoRecorderSettings(
|
|||||||
"FHD" to Quality.FHD,
|
"FHD" to Quality.FHD,
|
||||||
"UHD" to Quality.UHD,
|
"UHD" to Quality.UHD,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
val EXAMPLE_BITRATE_VALUES = listOf(
|
||||||
|
null,
|
||||||
|
500 * 1000,
|
||||||
|
// 1 Mbps
|
||||||
|
1 * 1000 * 1000,
|
||||||
|
2 * 1000 * 1000,
|
||||||
|
4 * 1000 * 1000,
|
||||||
|
8 * 1000 * 1000,
|
||||||
|
16 * 1000 * 1000,
|
||||||
|
32 * 1000 * 1000,
|
||||||
|
50 * 1000 * 1000,
|
||||||
|
100 * 1000 * 1000,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -0,0 +1,145 @@
|
|||||||
|
package app.myzel394.alibi.ui.components.SettingsScreen.Tiles
|
||||||
|
|
||||||
|
import androidx.compose.foundation.text.KeyboardOptions
|
||||||
|
import androidx.compose.material.icons.Icons
|
||||||
|
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.rememberCoroutineScope
|
||||||
|
import androidx.compose.ui.platform.LocalContext
|
||||||
|
import androidx.compose.ui.res.stringResource
|
||||||
|
import androidx.compose.ui.text.input.KeyboardType
|
||||||
|
import app.myzel394.alibi.R
|
||||||
|
import app.myzel394.alibi.dataStore
|
||||||
|
import app.myzel394.alibi.db.AppSettings
|
||||||
|
import app.myzel394.alibi.db.AudioRecorderSettings
|
||||||
|
import app.myzel394.alibi.db.VideoRecorderSettings
|
||||||
|
import app.myzel394.alibi.ui.components.atoms.ExampleListRoulette
|
||||||
|
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.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 VideoRecorderBitrateTile(
|
||||||
|
settings: AppSettings,
|
||||||
|
) {
|
||||||
|
val scope = rememberCoroutineScope()
|
||||||
|
val showDialog = rememberUseCaseState()
|
||||||
|
val dataStore = LocalContext.current.dataStore
|
||||||
|
|
||||||
|
fun updateValue(bitRate: Int?) {
|
||||||
|
scope.launch {
|
||||||
|
dataStore.updateData {
|
||||||
|
it.setVideoRecorderSettings(
|
||||||
|
it.videoRecorderSettings.setTargetedVideoBitRate(bitRate)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val notNumberLabel = stringResource(R.string.form_error_type_notNumber)
|
||||||
|
InputDialog(
|
||||||
|
state = showDialog,
|
||||||
|
header = Header.Default(
|
||||||
|
title = stringResource(R.string.ui_settings_option_videoTargetedBitrate_title),
|
||||||
|
icon = IconSource(
|
||||||
|
painter = IconResource.fromImageVector(Icons.Default.Tune).asPainterResource(),
|
||||||
|
contentDescription = null,
|
||||||
|
)
|
||||||
|
),
|
||||||
|
selection = InputSelection(
|
||||||
|
input = listOf(
|
||||||
|
InputTextField(
|
||||||
|
header = InputHeader(
|
||||||
|
title = stringResource(id = R.string.ui_settings_option_videoTargetedBitrate_explanation),
|
||||||
|
),
|
||||||
|
keyboardOptions = KeyboardOptions(
|
||||||
|
keyboardType = KeyboardType.Number,
|
||||||
|
),
|
||||||
|
type = InputTextFieldType.OUTLINED,
|
||||||
|
text = if (settings.videoRecorderSettings.targetedVideoBitRate == null) "" else (settings.videoRecorderSettings.targetedVideoBitRate / 1000).toString(),
|
||||||
|
validationListener = { text ->
|
||||||
|
val bitRate = text?.toIntOrNull()
|
||||||
|
|
||||||
|
if (bitRate == null) {
|
||||||
|
return@InputTextField ValidationResult.Invalid(notNumberLabel)
|
||||||
|
}
|
||||||
|
|
||||||
|
ValidationResult.Valid
|
||||||
|
},
|
||||||
|
key = "bitrate",
|
||||||
|
)
|
||||||
|
),
|
||||||
|
) { result ->
|
||||||
|
val bitRate = result.getString("bitrate")?.toIntOrNull() ?: return@InputSelection
|
||||||
|
|
||||||
|
updateValue(bitRate * 1000)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
SettingsTile(
|
||||||
|
title = stringResource(R.string.ui_settings_option_videoTargetedBitrate_title),
|
||||||
|
description = stringResource(R.string.ui_settings_option_bitrate_description),
|
||||||
|
leading = {
|
||||||
|
Icon(
|
||||||
|
Icons.Default.Tune,
|
||||||
|
contentDescription = null,
|
||||||
|
)
|
||||||
|
},
|
||||||
|
trailing = {
|
||||||
|
Button(
|
||||||
|
onClick = showDialog::show,
|
||||||
|
colors = ButtonDefaults.filledTonalButtonColors(
|
||||||
|
containerColor = MaterialTheme.colorScheme.surfaceVariant,
|
||||||
|
),
|
||||||
|
shape = MaterialTheme.shapes.medium,
|
||||||
|
) {
|
||||||
|
Text(formatBitrate(settings.videoRecorderSettings.targetedVideoBitRate))
|
||||||
|
}
|
||||||
|
},
|
||||||
|
extra = {
|
||||||
|
ExampleListRoulette(
|
||||||
|
items = VideoRecorderSettings.EXAMPLE_BITRATE_VALUES,
|
||||||
|
onItemSelected = ::updateValue,
|
||||||
|
) { bitRate ->
|
||||||
|
Text(formatBitrate(bitRate))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun formatBitrate(bitrate: Int?): String {
|
||||||
|
return if (bitrate == null)
|
||||||
|
stringResource(R.string.ui_settings_value_auto_label)
|
||||||
|
else if (bitrate >= 1000 * 1000 && bitrate % (1000 * 1000) == 0)
|
||||||
|
stringResource(
|
||||||
|
R.string.format_mbps,
|
||||||
|
bitrate / 1000 / 1000,
|
||||||
|
)
|
||||||
|
else if (bitrate >= 1000 && bitrate % 1000 == 0)
|
||||||
|
stringResource(
|
||||||
|
R.string.format_kbps,
|
||||||
|
bitrate / 1000,
|
||||||
|
)
|
||||||
|
else
|
||||||
|
stringResource(
|
||||||
|
R.string.format_bps,
|
||||||
|
bitrate,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
@ -1,13 +1,11 @@
|
|||||||
package app.myzel394.alibi.ui.screens
|
package app.myzel394.alibi.ui.screens
|
||||||
|
|
||||||
import androidx.compose.animation.AnimatedVisibility
|
import androidx.compose.animation.AnimatedVisibility
|
||||||
import androidx.compose.foundation.background
|
|
||||||
import androidx.compose.foundation.layout.Arrangement
|
import androidx.compose.foundation.layout.Arrangement
|
||||||
import androidx.compose.foundation.layout.Box
|
import androidx.compose.foundation.layout.Box
|
||||||
import androidx.compose.foundation.layout.Column
|
import androidx.compose.foundation.layout.Column
|
||||||
import androidx.compose.foundation.layout.fillMaxSize
|
import androidx.compose.foundation.layout.fillMaxSize
|
||||||
import androidx.compose.foundation.layout.fillMaxWidth
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
import androidx.compose.foundation.layout.height
|
|
||||||
import androidx.compose.foundation.layout.padding
|
import androidx.compose.foundation.layout.padding
|
||||||
import androidx.compose.foundation.rememberScrollState
|
import androidx.compose.foundation.rememberScrollState
|
||||||
import androidx.compose.foundation.verticalScroll
|
import androidx.compose.foundation.verticalScroll
|
||||||
@ -40,7 +38,7 @@ import app.myzel394.alibi.R
|
|||||||
import app.myzel394.alibi.dataStore
|
import app.myzel394.alibi.dataStore
|
||||||
import app.myzel394.alibi.ui.SUPPORTS_DARK_MODE_NATIVELY
|
import app.myzel394.alibi.ui.SUPPORTS_DARK_MODE_NATIVELY
|
||||||
import app.myzel394.alibi.ui.components.SettingsScreen.Tiles.AboutTile
|
import app.myzel394.alibi.ui.components.SettingsScreen.Tiles.AboutTile
|
||||||
import app.myzel394.alibi.ui.components.SettingsScreen.Tiles.AudioRecorderBitrateTile
|
import app.myzel394.alibi.ui.components.SettingsScreen.Tiles.VideoRecorderBitrateTile
|
||||||
import app.myzel394.alibi.ui.components.SettingsScreen.Tiles.CustomNotificationTile
|
import app.myzel394.alibi.ui.components.SettingsScreen.Tiles.CustomNotificationTile
|
||||||
import app.myzel394.alibi.ui.components.SettingsScreen.Tiles.DeleteRecordingsImmediatelyTile
|
import app.myzel394.alibi.ui.components.SettingsScreen.Tiles.DeleteRecordingsImmediatelyTile
|
||||||
import app.myzel394.alibi.ui.components.SettingsScreen.Tiles.DividerTitle
|
import app.myzel394.alibi.ui.components.SettingsScreen.Tiles.DividerTitle
|
||||||
@ -164,15 +162,20 @@ fun SettingsScreen(
|
|||||||
title = stringResource(R.string.ui_settings_sections_audio_title),
|
title = stringResource(R.string.ui_settings_sections_audio_title),
|
||||||
description = stringResource(R.string.ui_settings_sections_audio_description),
|
description = stringResource(R.string.ui_settings_sections_audio_description),
|
||||||
)
|
)
|
||||||
|
|
||||||
AudioRecorderShowAllMicrophonesTile(settings = settings)
|
AudioRecorderShowAllMicrophonesTile(settings = settings)
|
||||||
AudioRecorderBitrateTile(settings = settings)
|
VideoRecorderBitrateTile(settings = settings)
|
||||||
AudioRecorderSamplingRateTile(settings = settings)
|
AudioRecorderSamplingRateTile(settings = settings)
|
||||||
AudioRecorderEncoderTile(
|
AudioRecorderEncoderTile(
|
||||||
snackbarHostState = snackbarHostState,
|
snackbarHostState = snackbarHostState,
|
||||||
settings = settings
|
settings = settings
|
||||||
)
|
)
|
||||||
AudioRecorderOutputFormatTile(settings = settings)
|
AudioRecorderOutputFormatTile(settings = settings)
|
||||||
|
|
||||||
|
DividerTitle(
|
||||||
|
title = stringResource(R.string.ui_settings_sections_video_title),
|
||||||
|
description = stringResource(R.string.ui_settings_sections_video_description),
|
||||||
|
)
|
||||||
|
VideoRecorderBitrateTile(settings = settings)
|
||||||
}
|
}
|
||||||
Divider(
|
Divider(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
|
@ -122,4 +122,10 @@
|
|||||||
<string name="ui_audioRecorder_action_save_openFolder">Open</string>
|
<string name="ui_audioRecorder_action_save_openFolder">Open</string>
|
||||||
<string name="ui_settings_sections_audio_title">Audio Recording</string>
|
<string name="ui_settings_sections_audio_title">Audio Recording</string>
|
||||||
<string name="ui_settings_sections_audio_description">Only applies to audio recordings</string>
|
<string name="ui_settings_sections_audio_description">Only applies to audio recordings</string>
|
||||||
|
<string name="ui_settings_sections_video_title">Video Recording</string>
|
||||||
|
<string name="ui_settings_sections_video_description">Only applies to video recordings</string>
|
||||||
|
<string name="ui_settings_option_videoTargetedBitrate_title">Targeted Bitrate</string>
|
||||||
|
<string name="ui_settings_option_videoTargetedBitrate_explanation">Bitrate for the video recording. Only applies to the video itself, not the audio. The actual bitrate may be different depending on what you will be recording.</string>
|
||||||
|
<string name="format_mbps">%s MB/s</string>
|
||||||
|
<string name="format_bps">%s B/s</string>
|
||||||
</resources>
|
</resources>
|
Loading…
x
Reference in New Issue
Block a user