fix(ui): Unify buttons

This commit is contained in:
Myzel394 2024-01-06 16:36:35 +01:00
parent e6d31a0ba9
commit cfc3572cfa
No known key found for this signature in database
GPG Key ID: 79CC92F37B3E1A2B
27 changed files with 80 additions and 70 deletions

View File

@ -9,6 +9,7 @@ import android.provider.MediaStore
import androidx.annotation.RequiresApi
import androidx.documentfile.provider.DocumentFile
import app.myzel394.alibi.helpers.MediaConverter.Companion.concatenateAudioFiles
import app.myzel394.alibi.ui.AUDIO_RECORDING_BATCHES_SUBFOLDER_NAME
import app.myzel394.alibi.ui.MEDIA_SUBFOLDER_NAME
import app.myzel394.alibi.ui.RECORDER_INTERNAL_SELECTED_VALUE
import app.myzel394.alibi.ui.RECORDER_MEDIA_SELECTED_VALUE
@ -21,7 +22,7 @@ class AudioBatchesFolder(
override val context: Context,
override val type: BatchType,
override val customFolder: DocumentFile? = null,
override val subfolderName: String = ".audio_recordings",
override val subfolderName: String = AUDIO_RECORDING_BATCHES_SUBFOLDER_NAME,
) : BatchesFolder(
context,
type,

View File

@ -113,7 +113,6 @@ abstract class BatchesFolder(
}
fun getBatchesForFFmpeg(): List<String> {
// TODO: There is probably a better way to do this iteratively, look at it if you have time
return when (type) {
BatchType.INTERNAL ->
((getInternalFolder()
@ -299,7 +298,6 @@ abstract class BatchesFolder(
extension = extension,
)
// TODO: Smoother transition from start to status
concatenationFunction(
filePaths,
outputFile,

View File

@ -90,7 +90,6 @@ class MediaConverter {
val filePathsConcatenated = inputFiles.joinToString("|")
val command =
"-protocol_whitelist saf,concat,content,file,subfile" +
" -safe 0" +
" -strict normal" +
" -i 'concat:$filePathsConcatenated'" +
extraCommand +

View File

@ -13,6 +13,7 @@ import app.myzel394.alibi.helpers.MediaConverter.Companion.concatenateVideoFiles
import app.myzel394.alibi.ui.MEDIA_SUBFOLDER_NAME
import app.myzel394.alibi.ui.RECORDER_INTERNAL_SELECTED_VALUE
import app.myzel394.alibi.ui.RECORDER_MEDIA_SELECTED_VALUE
import app.myzel394.alibi.ui.VIDEO_RECORDING_BATCHES_SUBFOLDER_NAME
import com.arthenica.ffmpegkit.FFmpegKitConfig
import java.io.File
import java.time.LocalDateTime
@ -21,7 +22,7 @@ class VideoBatchesFolder(
override val context: Context,
override val type: BatchType,
override val customFolder: DocumentFile? = null,
override val subfolderName: String = ".video_recordings",
override val subfolderName: String = VIDEO_RECORDING_BATCHES_SUBFOLDER_NAME,
) : BatchesFolder(
context,
type,

View File

@ -15,6 +15,7 @@ import androidx.compose.material.icons.filled.Fingerprint
import androidx.compose.material.icons.filled.Lock
import androidx.compose.material3.Button
import androidx.compose.material3.ButtonDefaults
import androidx.compose.material3.ElevatedButton
import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Scaffold
@ -126,12 +127,12 @@ fun AsLockedApp(
style = MaterialTheme.typography.bodyLarge,
)
}
Button(
ElevatedButton(
modifier = Modifier
.fillMaxWidth()
.height(BIG_PRIMARY_BUTTON_SIZE),
onClick = ::openAuthentication,
colors = ButtonDefaults.filledTonalButtonColors(),
contentPadding = ButtonDefaults.ButtonWithIconContentPadding,
) {
Icon(
Icons.Default.Lock,

View File

@ -17,6 +17,9 @@ val MEDIA_RECORDINGS_PREFIX = "alibi-recording-"
val RECORDER_MEDIA_SELECTED_VALUE = "_'media"
val RECORDER_INTERNAL_SELECTED_VALUE = "_'internal"
val VIDEO_RECORDING_BATCHES_SUBFOLDER_NAME = ".video_recordings"
val AUDIO_RECORDING_BATCHES_SUBFOLDER_NAME = ".audio_recordings"
// You are not allowed to change the constants below.
// If you do so, you will be blocked on GitHub.
const val REPO_URL = "https://github.com/Myzel394/Alibi"

View File

@ -33,8 +33,10 @@ import androidx.compose.material.icons.filled.CurrencyYuan
import androidx.compose.material3.Button
import androidx.compose.material3.ButtonDefaults
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.material3.TextButton
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
@ -130,11 +132,11 @@ fun DonationsTile() {
Column {
val uriHandler = LocalUriHandler.current
Button(
TextButton(
onClick = {
uriHandler.openUri(GITHUB_SPONSORS_URL)
},
colors = ButtonDefaults.textButtonColors(),
contentPadding = ButtonDefaults.TextButtonWithIconContentPadding,
modifier = Modifier.fillMaxWidth(),
) {
Image(

View File

@ -16,6 +16,7 @@ import androidx.compose.material3.ButtonDefaults
import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.material3.TextButton
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
@ -62,12 +63,11 @@ fun GPGKeyOverview() {
)
.padding(8.dp),
)
Button(
TextButton(
onClick = {
val clip = ClipData.newPlainText("text", PUBLIC_KEY)
clipboardManager.setPrimaryClip(clip)
},
colors = ButtonDefaults.textButtonColors(),
modifier = Modifier
.fillMaxWidth()
) {

View File

@ -19,9 +19,11 @@ import androidx.compose.material.icons.filled.Edit
import androidx.compose.material.icons.filled.Notifications
import androidx.compose.material3.Button
import androidx.compose.material3.ButtonDefaults
import androidx.compose.material3.FilledTonalButton
import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.material3.TextButton
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
@ -82,10 +84,7 @@ fun LandingElement(
stringResource(R.string.ui_settings_customNotifications_landing_description),
style = MaterialTheme.typography.bodySmall,
)
Button(
onClick = onOpenEditor,
colors = ButtonDefaults.filledTonalButtonColors(),
) {
FilledTonalButton(onClick = onOpenEditor) {
Icon(
Icons.Default.Edit,
contentDescription = null,
@ -100,9 +99,8 @@ fun LandingElement(
}
}
}
Button(
TextButton(
onClick = context::openNotificationsSettings,
colors = ButtonDefaults.textButtonColors(),
) {
Text(
stringResource(R.string.ui_settings_customNotifications_landing_help_hideNotifications),

View File

@ -178,6 +178,7 @@ fun NotificationEditor(
notificationModel.asNotificationSettings()
)
},
contentPadding = ButtonDefaults.ButtonWithIconContentPadding,
modifier = Modifier
.fillMaxWidth()
.padding(horizontal = HORIZONTAL_PADDING)

View File

@ -7,6 +7,7 @@ import androidx.compose.material3.Button
import androidx.compose.material3.ButtonDefaults
import androidx.compose.material3.Icon
import androidx.compose.material3.Text
import androidx.compose.material3.TextButton
import androidx.compose.runtime.Composable
import androidx.compose.ui.res.stringResource
import app.myzel394.alibi.R
@ -30,10 +31,7 @@ fun BatchesInaccessibleDialog(
Text(stringResource(R.string.ui_recorder_error_batchesInaccessible_description))
},
confirmButton = {
Button(
onClick = onClose,
colors = ButtonDefaults.textButtonColors(),
) {
TextButton(onClick = onClose) {
Text(stringResource(R.string.dialog_close_neutral_label))
}
}

View File

@ -11,6 +11,7 @@ import androidx.compose.material3.Button
import androidx.compose.material3.ButtonDefaults
import androidx.compose.material3.Icon
import androidx.compose.material3.Text
import androidx.compose.material3.TextButton
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
@ -46,6 +47,7 @@ fun ConfirmDeletionDialog(
.semantics {
contentDescription = label
},
contentPadding = ButtonDefaults.ButtonWithIconContentPadding,
onClick = {
onConfirm()
},
@ -61,15 +63,15 @@ fun ConfirmDeletionDialog(
},
dismissButton = {
val label = stringResource(R.string.dialog_close_cancel_label)
Button(
TextButton(
modifier = Modifier
.semantics {
contentDescription = label
},
contentPadding = ButtonDefaults.TextButtonWithIconContentPadding,
onClick = {
onDismiss()
},
colors = ButtonDefaults.textButtonColors(),
) {
Icon(
Icons.Default.Cancel,

View File

@ -4,6 +4,7 @@ import androidx.compose.material3.Button
import androidx.compose.material3.ButtonDefaults
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.material3.TextButton
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
@ -34,7 +35,7 @@ fun DeleteButton(
)
}
val label = stringResource(R.string.ui_recorder_action_delete_label)
Button(
TextButton(
modifier = Modifier
.semantics {
contentDescription = label
@ -43,7 +44,6 @@ fun DeleteButton(
onClick = {
showDeleteDialog = true
},
colors = ButtonDefaults.textButtonColors(),
) {
Text(
label,

View File

@ -50,6 +50,7 @@ fun MicrophoneSelectionButton(
.fillMaxWidth()
.height(64.dp),
colors = if (selected) ButtonDefaults.buttonColors() else ButtonDefaults.textButtonColors(),
contentPadding = if (selected) ButtonDefaults.ButtonWithIconContentPadding else ButtonDefaults.TextButtonContentPadding,
) {
Row(
verticalAlignment = Alignment.CenterVertically,

View File

@ -7,6 +7,7 @@ import androidx.compose.material3.Button
import androidx.compose.material3.ButtonDefaults
import androidx.compose.material3.Icon
import androidx.compose.material3.Text
import androidx.compose.material3.TextButton
import androidx.compose.runtime.Composable
import androidx.compose.ui.res.stringResource
import app.myzel394.alibi.R
@ -31,18 +32,12 @@ fun RecorderErrorDialog(
Text(stringResource(R.string.ui_recorder_error_recording_description))
},
dismissButton = {
Button(
onClick = onClose,
colors = ButtonDefaults.textButtonColors(),
) {
TextButton(onClick = onClose) {
Text(stringResource(R.string.dialog_close_cancel_label))
}
},
confirmButton = {
Button(
onClick = onSave,
colors = ButtonDefaults.textButtonColors(),
) {
TextButton(onClick = onSave) {
Text(stringResource(R.string.ui_recorder_action_save_label))
}
}

View File

@ -4,6 +4,7 @@ import androidx.compose.material3.Button
import androidx.compose.material3.ButtonDefaults
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.material3.TextButton
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
@ -18,14 +19,13 @@ fun SaveButton(
) {
val label = stringResource(R.string.ui_recorder_action_save_label)
Button(
TextButton(
modifier = Modifier
.semantics {
contentDescription = label
}
.then(modifier),
onClick = onSave,
colors = ButtonDefaults.textButtonColors(),
) {
Text(
label,

View File

@ -23,6 +23,7 @@ fun TorchStatus(
Button(
onClick = onChange,
colors = if (enabled) ButtonDefaults.filledTonalButtonColors() else ButtonDefaults.outlinedButtonColors(),
contentPadding = ButtonDefaults.ButtonWithIconContentPadding,
) {
Icon(
if (enabled) Icons.Default.FlashlightOff else Icons.Default.FlashlightOn,

View File

@ -19,6 +19,7 @@ import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.ModalBottomSheet
import androidx.compose.material3.Text
import androidx.compose.material3.TextButton
import androidx.compose.material3.rememberModalBottomSheetState
import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsState
@ -188,14 +189,14 @@ fun MicrophoneSelection(
}
if (shownMicrophones.isNotEmpty() || (settings.audioRecorderSettings.showAllMicrophones && hiddenMicrophones.isNotEmpty())) {
Button(
TextButton(
onClick = {
scope.launch {
showSelection = true
sheetState.show()
}
},
colors = ButtonDefaults.textButtonColors(),
contentPadding = ButtonDefaults.TextButtonWithIconContentPadding,
) {
MicrophoneTypeInfo(
type = audioRecorder.selectedMicrophone?.type

View File

@ -14,6 +14,7 @@ import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.ModalBottomSheet
import androidx.compose.material3.Text
import androidx.compose.material3.TextButton
import androidx.compose.material3.rememberModalBottomSheetState
import androidx.compose.runtime.Composable
import androidx.compose.runtime.rememberCoroutineScope
@ -66,7 +67,7 @@ fun QuickMaxDurationSelector(
Column {
for (duration in EXAMPLE_MAX_DURATIONS) {
Button(
TextButton(
onClick = {
scope.launch {
sheetState.hide()

View File

@ -20,6 +20,7 @@ import androidx.compose.material3.ButtonDefaults
import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.material3.TextButton
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
@ -129,7 +130,7 @@ fun StartRecording(
DateTimeFormatter.ofLocalizedDate(FormatStyle.FULL)
.format(appSettings.lastRecording.recordingStart),
)
Button(
TextButton(
modifier = Modifier
.padding(16.dp)
.fillMaxWidth()
@ -137,8 +138,8 @@ fun StartRecording(
.semantics {
contentDescription = label
},
colors = ButtonDefaults.textButtonColors(),
onClick = onSaveLastRecording,
contentPadding = ButtonDefaults.TextButtonWithIconContentPadding,
) {
Icon(
Icons.Default.Save,

View File

@ -12,10 +12,12 @@ import androidx.compose.material.icons.filled.Upload
import androidx.compose.material3.AlertDialog
import androidx.compose.material3.Button
import androidx.compose.material3.ButtonDefaults
import androidx.compose.material3.FilledTonalButton
import androidx.compose.material3.Icon
import androidx.compose.material3.SnackbarDuration
import androidx.compose.material3.SnackbarHostState
import androidx.compose.material3.Text
import androidx.compose.material3.TextButton
import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
@ -96,8 +98,8 @@ fun ImportExport(
duration = SnackbarDuration.Short,
)
}
},
contentPadding = ButtonDefaults.ButtonWithIconContentPadding,
) {
Icon(
Icons.Default.CheckCircle,
@ -109,11 +111,10 @@ fun ImportExport(
}
},
dismissButton = {
Button(
TextButton(
onClick = {
settingsToBeImported = null
},
colors = ButtonDefaults.textButtonColors(),
) {
Text(stringResource(R.string.dialog_close_cancel_label))
}
@ -126,11 +127,11 @@ fun ImportExport(
verticalAlignment = Alignment.CenterVertically,
modifier = Modifier.fillMaxWidth(),
) {
Button(
FilledTonalButton(
onClick = {
openFile("application/json")
},
colors = ButtonDefaults.filledTonalButtonColors(),
contentPadding = ButtonDefaults.ButtonWithIconContentPadding,
) {
Icon(
Icons.Default.Download,
@ -140,7 +141,7 @@ fun ImportExport(
Spacer(modifier = Modifier.size(ButtonDefaults.IconSpacing))
Text(stringResource(R.string.ui_settings_option_import_label))
}
Button(
FilledTonalButton(
onClick = {
val rawContent = settings.exportToString()
@ -149,7 +150,7 @@ fun ImportExport(
saveFile(tempFile, "alibi_settings.json")
},
colors = ButtonDefaults.filledTonalButtonColors(),
contentPadding = ButtonDefaults.ButtonWithIconContentPadding,
) {
Icon(
Icons.Default.Upload,

View File

@ -39,6 +39,7 @@ import androidx.compose.material3.SheetState
import androidx.compose.material3.SnackbarDuration
import androidx.compose.material3.SnackbarHostState
import androidx.compose.material3.Text
import androidx.compose.material3.TextButton
import androidx.compose.material3.rememberModalBottomSheetState
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
@ -63,11 +64,13 @@ import app.myzel394.alibi.dataStore
import app.myzel394.alibi.db.AppSettings
import app.myzel394.alibi.helpers.AudioBatchesFolder
import app.myzel394.alibi.helpers.VideoBatchesFolder
import app.myzel394.alibi.ui.AUDIO_RECORDING_BATCHES_SUBFOLDER_NAME
import app.myzel394.alibi.ui.MEDIA_SUBFOLDER_NAME
import app.myzel394.alibi.ui.RECORDER_MEDIA_SELECTED_VALUE
import app.myzel394.alibi.ui.SHEET_BOTTOM_OFFSET
import app.myzel394.alibi.ui.SUPPORTS_SAVING_VIDEOS_IN_CUSTOM_FOLDERS
import app.myzel394.alibi.ui.SUPPORTS_SCOPED_STORAGE
import app.myzel394.alibi.ui.VIDEO_RECORDING_BATCHES_SUBFOLDER_NAME
import app.myzel394.alibi.ui.components.SettingsScreen.atoms.FolderBreadcrumbs
import app.myzel394.alibi.ui.components.atoms.MessageBox
import app.myzel394.alibi.ui.components.atoms.MessageType
@ -235,7 +238,6 @@ fun SaveFolderTile(
)
},
shape = MaterialTheme.shapes.small,
// TODO: Adjust padding everywhere
contentPadding = ButtonDefaults.TextButtonContentPadding,
colors = ButtonDefaults.filledTonalButtonColors(
contentColor = MaterialTheme.colorScheme.onTertiaryContainer,
@ -272,9 +274,7 @@ fun MediaFoldersExplanationDialog(
Text(stringResource(R.string.ui_settings_option_saveFolder_explainMediaFolder_label))
},
confirmButton = {
Button(
onClick = onDismiss,
) {
Button(onClick = onDismiss) {
Text(stringResource(R.string.dialog_close_neutral_label))
}
},
@ -348,7 +348,11 @@ fun MediaFoldersExplanationDialog(
}
}
Text(
stringResource(R.string.ui_settings_option_saveFolder_explainMediaFolder_subfoldersExplanation),
stringResource(
R.string.ui_settings_option_saveFolder_explainMediaFolder_subfoldersExplanation,
AUDIO_RECORDING_BATCHES_SUBFOLDER_NAME,
VIDEO_RECORDING_BATCHES_SUBFOLDER_NAME
),
style = MaterialTheme.typography.bodySmall,
color = MaterialTheme.colorScheme.onSurface,
)
@ -533,18 +537,16 @@ fun CustomFolderWarningDialog(
Text(text = text)
},
confirmButton = {
Button(
onClick = onConfirm,
) {
Button(onClick = onConfirm) {
Text(
text = stringResource(R.string.ui_settings_option_saveFolder_warning_action_confirm),
)
}
},
dismissButton = {
Button(
TextButton(
onClick = onDismiss,
colors = ButtonDefaults.textButtonColors(),
contentPadding = ButtonDefaults.TextButtonWithIconContentPadding,
) {
Icon(
Icons.Default.Cancel,
@ -596,9 +598,9 @@ fun ExternalPermissionRequiredDialog(
}
},
dismissButton = {
Button(
TextButton(
onClick = onDismiss,
colors = ButtonDefaults.textButtonColors(),
contentPadding = ButtonDefaults.TextButtonWithIconContentPadding,
) {
Icon(
Icons.Default.Cancel,

View File

@ -64,6 +64,7 @@ fun ExplanationPage(
.padding(16.dp)
.fillMaxWidth()
.height(BIG_PRIMARY_BUTTON_SIZE),
contentPadding = ButtonDefaults.ButtonWithIconContentPadding,
) {
Icon(
Icons.Default.ChevronRight,

View File

@ -64,6 +64,7 @@ fun ResponsibilityPage(
.padding(16.dp)
.fillMaxWidth()
.height(BIG_PRIMARY_BUTTON_SIZE),
contentPadding = ButtonDefaults.ButtonWithIconContentPadding,
) {
Icon(
Icons.Default.Check,

View File

@ -6,6 +6,7 @@ import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.lazy.LazyRow
import androidx.compose.material3.Button
import androidx.compose.material3.ButtonDefaults
import androidx.compose.material3.TextButton
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
@ -27,13 +28,10 @@ fun<T> ExampleListRoulette(
items(items.size) {
val item = items[it]
Button(
TextButton(
onClick = {
onItemSelected(item)
},
colors = ButtonDefaults.textButtonColors(),
shape = ButtonDefaults.textShape,
contentPadding = ButtonDefaults.TextButtonContentPadding,
) {
renderValue(item)
}

View File

@ -18,6 +18,7 @@ import androidx.compose.material3.Button
import androidx.compose.material3.ButtonDefaults
import androidx.compose.material3.Icon
import androidx.compose.material3.Text
import androidx.compose.material3.TextButton
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.mutableStateOf
@ -109,7 +110,8 @@ fun PermissionRequester(
onClick = {
visibleDialog = null
callback()
}
},
contentPadding = ButtonDefaults.ButtonWithIconContentPadding,
) {
Icon(
Icons.Default.Check,
@ -121,11 +123,11 @@ fun PermissionRequester(
}
},
dismissButton = {
Button(
TextButton(
onClick = {
visibleDialog = null
},
colors = ButtonDefaults.textButtonColors(),
contentPadding = ButtonDefaults.TextButtonWithIconContentPadding,
) {
Icon(
Icons.Default.Cancel,
@ -167,7 +169,8 @@ fun PermissionRequester(
onClick = {
visibleDialog = null
context.openAppSystemSettings()
}
},
contentPadding = ButtonDefaults.ButtonWithIconContentPadding,
) {
Icon(
Icons.Default.OpenInNew,
@ -179,11 +182,11 @@ fun PermissionRequester(
}
},
dismissButton = {
Button(
TextButton(
onClick = {
visibleDialog = null
},
colors = ButtonDefaults.textButtonColors(),
contentPadding = ButtonDefaults.TextButtonWithIconContentPadding,
) {
Icon(
Icons.Default.Cancel,

View File

@ -185,6 +185,6 @@
<string name="ui_settings_option_saveFolder_openFolder_label">Open Folder in Files</string>
<string name="ui_settings_option_saveFolder_explainMediaFolder_label">Where are my batches stored?</string>
<string name="ui_settings_option_saveFolder_explainMediaFolder_generalExplanation">To view your batches, open the Files app, go to the internal storage and then you will find your batches in following folders:</string>
<string name="ui_settings_option_saveFolder_explainMediaFolder_subfoldersExplanation">The final merged recordings will be saved in those folders. Each recording creates a subfolder to store the short batches in ("%s" for audio recordings, "%s" for video recordings). To view the individual batches, you may need to enable hidden files in the Files app.</string>
<string name="ui_settings_option_saveFolder_explainMediaFolder_subfoldersExplanation">The final merged recordings will be saved in those folders. Each recording creates a subfolder to store the short batches in (\"%s\" for audio recordings, \"%s\" for video recordings). To view the individual batches, you may need to enable hidden files in the Files app.</string>
<string name="ui_settings_option_saveFolder_explainMediaFolder_openFolderExplanation">Tap on a folder to open it in the Files app</string>
</resources>