diff --git a/app/src/main/java/app/myzel394/alibi/ui/components/WelcomeScreen/atoms/SaveFolderSelection.kt b/app/src/main/java/app/myzel394/alibi/ui/components/WelcomeScreen/atoms/SaveFolderSelection.kt
index c84fe60..02b79e7 100644
--- a/app/src/main/java/app/myzel394/alibi/ui/components/WelcomeScreen/atoms/SaveFolderSelection.kt
+++ b/app/src/main/java/app/myzel394/alibi/ui/components/WelcomeScreen/atoms/SaveFolderSelection.kt
@@ -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(
diff --git a/app/src/main/java/app/myzel394/alibi/ui/components/WelcomeScreen/pages/SaveFolderPage.kt b/app/src/main/java/app/myzel394/alibi/ui/components/WelcomeScreen/pages/SaveFolderPage.kt
index d45ea15..19d499c 100644
--- a/app/src/main/java/app/myzel394/alibi/ui/components/WelcomeScreen/pages/SaveFolderPage.kt
+++ b/app/src/main/java/app/myzel394/alibi/ui/components/WelcomeScreen/pages/SaveFolderPage.kt
@@ -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))
+ }
+ }
+ )
+
}
\ No newline at end of file
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index cc23b40..15abe38 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -210,4 +210,6 @@
Custom Folder
Media Folder
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.
+ Select a Custom Folder
+ 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.
\ No newline at end of file