feat: Improve SaveFolder; Request permission: Show warning if custom folder not supported

Signed-off-by: Myzel394 <50424412+Myzel394@users.noreply.github.com>
This commit is contained in:
Myzel394 2024-03-22 00:10:42 +01:00
parent f06a79c1a8
commit 97acb6d977
No known key found for this signature in database
GPG Key ID: DEC4AAB876F73185
3 changed files with 230 additions and 32 deletions

View File

@ -8,6 +8,8 @@ import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Folder
import androidx.compose.material.icons.filled.Lock
@ -29,6 +31,7 @@ import androidx.compose.ui.unit.dp
import app.myzel394.alibi.R
import app.myzel394.alibi.db.AppSettings
import app.myzel394.alibi.ui.RECORDER_MEDIA_SELECTED_VALUE
import app.myzel394.alibi.ui.SUPPORTS_SAVING_VIDEOS_IN_CUSTOM_FOLDERS
import app.myzel394.alibi.ui.components.atoms.MessageBox
import app.myzel394.alibi.ui.components.atoms.MessageType
@ -48,9 +51,21 @@ fun SaveFolderSelection(
CUSTOM_FOLDER to (stringResource(R.string.ui_welcome_saveFolder_values_custom) to Icons.Default.Folder),
)
@Composable
fun createModifier(a11yLabel: String, onClick: () -> Unit) =
Modifier
.fillMaxWidth()
.clip(MaterialTheme.shapes.medium)
.semantics {
contentDescription = a11yLabel
}
.clickable(onClick = onClick)
.padding(16.dp)
.padding(end = 8.dp)
Column(
verticalArrangement = Arrangement.spacedBy(16.dp),
horizontalAlignment = Alignment.CenterHorizontally,
modifier = Modifier.verticalScroll(rememberScrollState()),
) {
Column(
modifier = Modifier
@ -60,27 +75,20 @@ fun SaveFolderSelection(
.then(modifier),
verticalArrangement = Arrangement.Center,
) {
for ((folder, pair) in OPTIONS) {
val (label, icon) = pair
let {
val label = stringResource(R.string.ui_welcome_saveFolder_values_internal)
val a11yLabel = stringResource(
R.string.a11y_selectValue,
label
)
val folder = null
Row(
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.SpaceBetween,
modifier = Modifier
.fillMaxWidth()
.clip(MaterialTheme.shapes.medium)
.semantics {
contentDescription = a11yLabel
}
.clickable {
onSaveFolderChange(folder)
}
.padding(16.dp)
.padding(end = 8.dp)
modifier = createModifier(a11yLabel) {
onSaveFolderChange(folder)
},
) {
Row(
verticalAlignment = Alignment.CenterVertically,
@ -93,13 +101,100 @@ fun SaveFolderSelection(
Text(label)
}
Icon(
icon,
Icons.Default.Lock,
contentDescription = null,
modifier = Modifier
.size(ButtonDefaults.IconSize)
)
}
}
let {
val label = stringResource(R.string.ui_welcome_saveFolder_values_media)
val a11yLabel = stringResource(
R.string.a11y_selectValue,
label
)
val folder = RECORDER_MEDIA_SELECTED_VALUE
Row(
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.SpaceBetween,
modifier = createModifier(a11yLabel) {
onSaveFolderChange(folder)
},
) {
Row(
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.spacedBy(8.dp),
) {
RadioButton(
selected = saveFolder == folder,
onClick = { onSaveFolderChange(folder) },
)
Text(label)
}
Icon(
Icons.Default.Lock,
contentDescription = null,
modifier = Modifier
.size(ButtonDefaults.IconSize)
)
}
}
let {
val label = stringResource(R.string.ui_welcome_saveFolder_values_custom)
val a11yLabel = stringResource(
R.string.a11y_selectValue,
label
)
val folder = CUSTOM_FOLDER
Column(
horizontalAlignment = Alignment.Start,
) {
Row(
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.SpaceBetween,
modifier = createModifier(a11yLabel) {
onSaveFolderChange(folder)
},
) {
Row(
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.spacedBy(8.dp),
) {
RadioButton(
selected = saveFolder == folder,
onClick = { onSaveFolderChange(folder) },
)
Text(label)
}
Icon(
Icons.Default.Lock,
contentDescription = null,
modifier = Modifier
.size(ButtonDefaults.IconSize)
)
}
if (!SUPPORTS_SAVING_VIDEOS_IN_CUSTOM_FOLDERS) {
Column(
modifier = Modifier
.padding(horizontal = 32.dp, vertical = 12.dp),
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.spacedBy(8.dp),
) {
Text(
stringResource(R.string.ui_settings_option_saveFolder_videoUnsupported),
fontSize = MaterialTheme.typography.titleSmall.fontSize,
)
Text(
stringResource(R.string.ui_minApiRequired, 8, 26),
fontSize = MaterialTheme.typography.bodySmall.fontSize,
)
}
}
}
}
}
if (isLowOnStorage)
MessageBox(

View File

@ -1,5 +1,6 @@
package app.myzel394.alibi.ui.components.WelcomeScreen.pages
import android.Manifest
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
@ -16,12 +17,15 @@ import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.automirrored.filled.InsertDriveFile
import androidx.compose.material.icons.filled.ChevronLeft
import androidx.compose.material.icons.filled.ChevronRight
import androidx.compose.material.icons.filled.Folder
import androidx.compose.material3.AlertDialog
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
@ -37,7 +41,14 @@ import app.myzel394.alibi.db.AppSettings
import app.myzel394.alibi.helpers.BatchesFolder
import app.myzel394.alibi.helpers.VideoBatchesFolder
import app.myzel394.alibi.ui.BIG_PRIMARY_BUTTON_SIZE
import app.myzel394.alibi.ui.RECORDER_MEDIA_SELECTED_VALUE
import app.myzel394.alibi.ui.SUPPORTS_SCOPED_STORAGE
import app.myzel394.alibi.ui.components.WelcomeScreen.atoms.SaveFolderSelection
import app.myzel394.alibi.ui.components.atoms.MessageBox
import app.myzel394.alibi.ui.components.atoms.MessageType
import app.myzel394.alibi.ui.components.atoms.PermissionRequester
import app.myzel394.alibi.ui.components.atoms.VisualDensity
import app.myzel394.alibi.ui.utils.rememberFolderSelectorDialog
@Composable
fun SaveFolderPage(
@ -67,7 +78,8 @@ fun SaveFolderPage(
Column(
modifier = Modifier.fillMaxSize(),
modifier = Modifier
.fillMaxSize(),
verticalArrangement = Arrangement.SpaceBetween,
horizontalAlignment = Alignment.CenterHorizontally,
) {
@ -94,7 +106,7 @@ fun SaveFolderPage(
stringResource(R.string.ui_welcome_saveFolder_message),
)
}
Spacer(modifier = Modifier.weight(1f))
Spacer(modifier = Modifier.weight(2f))
Box(
modifier = Modifier.widthIn(max = 400.dp)
) {
@ -106,6 +118,16 @@ fun SaveFolderPage(
)
}
Spacer(modifier = Modifier.weight(1f))
Box(
modifier = Modifier.widthIn(max = 400.dp)
) {
MessageBox(
type = MessageType.INFO,
message = stringResource(R.string.ui_welcome_timeSettings_changeableHint),
density = VisualDensity.DENSE,
)
}
Spacer(modifier = Modifier.weight(2f))
Row(
verticalAlignment = Alignment.CenterVertically,
modifier = Modifier
@ -123,22 +145,101 @@ fun SaveFolderPage(
contentDescription = null,
)
}
Button(
onClick = onContinue,
enabled = !isLowOnStorage,
modifier = Modifier
.fillMaxWidth()
.height(BIG_PRIMARY_BUTTON_SIZE),
contentPadding = ButtonDefaults.ButtonWithIconContentPadding,
) {
Icon(
Icons.Default.ChevronRight,
contentDescription = null,
modifier = Modifier.size(ButtonDefaults.IconSize)
)
Spacer(modifier = Modifier.width(ButtonDefaults.IconSpacing))
Text(stringResource(R.string.continue_label))
PermissionRequester(
permission = Manifest.permission.WRITE_EXTERNAL_STORAGE,
icon = Icons.AutoMirrored.Filled.InsertDriveFile,
onPermissionAvailable = onContinue,
) { requestWritePermission ->
val selectFolder = rememberFolderSelectorDialog { folder ->
if (folder == null) {
return@rememberFolderSelectorDialog
}
onContinue()
}
var showCustomFolderHint by rememberSaveable { mutableStateOf(false) }
if (showCustomFolderHint) {
_CustomFolderDialog(
onAbort = { showCustomFolderHint = false },
onOk = {
showCustomFolderHint = false
selectFolder()
},
)
}
Button(
onClick = {
when (saveFolder) {
null -> onContinue()
RECORDER_MEDIA_SELECTED_VALUE -> {
if (SUPPORTS_SCOPED_STORAGE) {
onContinue()
} else {
requestWritePermission()
}
}
else -> {
showCustomFolderHint = true
}
}
},
enabled = !isLowOnStorage,
modifier = Modifier
.fillMaxWidth()
.height(BIG_PRIMARY_BUTTON_SIZE),
contentPadding = ButtonDefaults.ButtonWithIconContentPadding,
) {
Icon(
Icons.Default.ChevronRight,
contentDescription = null,
modifier = Modifier.size(ButtonDefaults.IconSize)
)
Spacer(modifier = Modifier.width(ButtonDefaults.IconSpacing))
Text(stringResource(R.string.continue_label))
}
}
}
}
}
@Composable
fun _CustomFolderDialog(
onAbort: () -> Unit,
onOk: () -> Unit,
) {
AlertDialog(
onDismissRequest = onAbort,
icon = {
Icon(
Icons.Default.Folder,
contentDescription = null,
)
},
title = {
Text(stringResource(R.string.ui_welcome_saveFolder_customFolder_title))
},
text = {
Text(stringResource(R.string.ui_welcome_saveFolder_customFolder_message))
},
dismissButton = {
TextButton(
onClick = onAbort,
contentPadding = ButtonDefaults.TextButtonContentPadding,
colors = ButtonDefaults.textButtonColors(),
) {
Text(stringResource(R.string.dialog_close_cancel_label))
}
},
confirmButton = {
Button(
onClick = onOk,
) {
Text(stringResource(R.string.dialog_close_neutral_label))
}
}
)
}

View File

@ -210,4 +210,6 @@
<string name="ui_welcome_saveFolder_values_custom">Custom Folder</string>
<string name="ui_welcome_saveFolder_values_media">Media Folder</string>
<string name="ui_welcome_saveFolder_externalRequired">Please select either the Media Folder or a Custom Folder. Alibi has not enough space to store the batches in the internal storage. Alternatively, go back one step and select a shorter duration.</string>
<string name="ui_welcome_saveFolder_customFolder_title">Select a Custom Folder</string>
<string name="ui_welcome_saveFolder_customFolder_message">You will now be asked to select a folder where Alibi should store the batches. Please select a folder where you have write access to.</string>
</resources>