feat: Adding SaveFolderSelection

Signed-off-by: Myzel394 <50424412+Myzel394@users.noreply.github.com>
This commit is contained in:
Myzel394 2024-03-21 23:23:12 +01:00
parent e968e7e589
commit f06a79c1a8
No known key found for this signature in database
GPG Key ID: DEC4AAB876F73185
5 changed files with 167 additions and 10 deletions

View File

@ -0,0 +1,110 @@
package app.myzel394.alibi.ui.components.WelcomeScreen.atoms
import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
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.material.icons.Icons
import androidx.compose.material.icons.filled.Folder
import androidx.compose.material.icons.filled.Lock
import androidx.compose.material.icons.filled.PermMedia
import androidx.compose.material3.ButtonDefaults
import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.RadioButton
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.semantics.contentDescription
import androidx.compose.ui.semantics.semantics
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.components.atoms.MessageBox
import app.myzel394.alibi.ui.components.atoms.MessageType
const val CUSTOM_FOLDER = "custom"
@Composable
fun SaveFolderSelection(
modifier: Modifier = Modifier,
appSettings: AppSettings,
saveFolder: String?,
isLowOnStorage: Boolean,
onSaveFolderChange: (String?) -> Unit,
) {
val OPTIONS = mapOf<String?, Pair<String, ImageVector>>(
null to (stringResource(R.string.ui_welcome_saveFolder_values_internal) to Icons.Default.Lock),
RECORDER_MEDIA_SELECTED_VALUE to (stringResource(R.string.ui_welcome_saveFolder_values_media) to Icons.Default.PermMedia),
CUSTOM_FOLDER to (stringResource(R.string.ui_welcome_saveFolder_values_custom) to Icons.Default.Folder),
)
Column(
verticalArrangement = Arrangement.spacedBy(16.dp),
horizontalAlignment = Alignment.CenterHorizontally,
) {
Column(
modifier = Modifier
.fillMaxWidth()
.clip(MaterialTheme.shapes.medium)
.background(MaterialTheme.colorScheme.surfaceContainer)
.then(modifier),
verticalArrangement = Arrangement.Center,
) {
for ((folder, pair) in OPTIONS) {
val (label, icon) = pair
val a11yLabel = stringResource(
R.string.a11y_selectValue,
label
)
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)
) {
Row(
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.spacedBy(8.dp),
) {
RadioButton(
selected = saveFolder == folder,
onClick = { onSaveFolderChange(folder) },
)
Text(label)
}
Icon(
icon,
contentDescription = null,
modifier = Modifier
.size(ButtonDefaults.IconSize)
)
}
}
}
if (isLowOnStorage)
MessageBox(
type = MessageType.ERROR,
message = stringResource(R.string.ui_welcome_saveFolder_externalRequired)
)
}
}

View File

@ -69,7 +69,7 @@ fun TimeSelector(
) {
for ((duration, label) in OPTIONS) {
val a11yLabel = stringResource(
R.string.ui_welcome_timeSettings_selectTime,
R.string.a11y_selectValue,
label
)

View File

@ -1,6 +1,7 @@
package app.myzel394.alibi.ui.components.WelcomeScreen.pages
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
@ -10,6 +11,7 @@ import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.layout.widthIn
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.automirrored.filled.InsertDriveFile
import androidx.compose.material.icons.filled.ChevronLeft
@ -21,11 +23,19 @@ import androidx.compose.material3.IconButton
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import app.myzel394.alibi.R
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.components.WelcomeScreen.atoms.SaveFolderSelection
@ -33,7 +43,29 @@ import app.myzel394.alibi.ui.components.WelcomeScreen.atoms.SaveFolderSelection
fun SaveFolderPage(
onBack: () -> Unit,
onContinue: () -> Unit,
appSettings: AppSettings,
) {
var saveFolder by rememberSaveable { mutableStateOf<String?>(null) }
val context = LocalContext.current
val isLowOnStorage = if (saveFolder != null)
false
else {
val availableBytes = VideoBatchesFolder.viaInternalFolder(context).getAvailableBytes()
if (availableBytes == null) {
return
}
val bytesPerMinute = BatchesFolder.requiredBytesForOneMinuteOfRecording(appSettings)
val requiredBytes = appSettings.maxDuration / 1000 / 60 * bytesPerMinute
// Allow for a 10% margin of error
availableBytes < requiredBytes * 1.1
}
Column(
modifier = Modifier.fillMaxSize(),
verticalArrangement = Arrangement.SpaceBetween,
@ -63,7 +95,16 @@ fun SaveFolderPage(
)
}
Spacer(modifier = Modifier.weight(1f))
SaveFolderSelection()
Box(
modifier = Modifier.widthIn(max = 400.dp)
) {
SaveFolderSelection(
appSettings = appSettings,
saveFolder = saveFolder,
isLowOnStorage = isLowOnStorage,
onSaveFolderChange = { saveFolder = it },
)
}
Spacer(modifier = Modifier.weight(1f))
Row(
verticalAlignment = Alignment.CenterVertically,
@ -84,6 +125,7 @@ fun SaveFolderPage(
}
Button(
onClick = onContinue,
enabled = !isLowOnStorage,
modifier = Modifier
.fillMaxWidth()
.height(BIG_PRIMARY_BUTTON_SIZE),

View File

@ -8,7 +8,6 @@ import androidx.compose.foundation.pager.HorizontalPager
import androidx.compose.foundation.pager.rememberPagerState
import androidx.compose.material3.Scaffold
import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
@ -18,6 +17,7 @@ import app.myzel394.alibi.ui.components.WelcomeScreen.pages.ExplanationPage
import app.myzel394.alibi.ui.components.WelcomeScreen.pages.ResponsibilityPage
import app.myzel394.alibi.ui.components.WelcomeScreen.pages.SaveFolderPage
import app.myzel394.alibi.ui.components.WelcomeScreen.pages.TimeSettingsPage
import app.myzel394.alibi.ui.effects.rememberSettings
import kotlinx.coroutines.launch
@OptIn(ExperimentalFoundationApi::class)
@ -27,10 +27,7 @@ fun WelcomeScreen(
) {
val context = LocalContext.current
val dataStore = context.dataStore
val settings = dataStore
.data
.collectAsState(initial = null)
.value ?: return
val settings = rememberSettings()
val scope = rememberCoroutineScope()
val pagerState = rememberPagerState(
initialPage = 0,
@ -83,8 +80,11 @@ fun WelcomeScreen(
}
},
onContinue = {
finishTutorial()
}
scope.launch {
pagerState.animateScrollToPage(3)
}
},
appSettings = settings
)
}
}

View File

@ -11,6 +11,8 @@
<string name="form_error_value_mustBeGreaterThan">Please enter a number greater than <xliff:g name="min">%s</xliff:g></string>
<string name="form_value_selected">Selected: %s</string>
<string name="a11y_selectValue">Select %s</string>
<string name="notificationChannels_recorder_name">Recorder</string>
<string name="notificationChannels_recorder_description">Shows the current recording status</string>
@ -201,8 +203,11 @@
<string name="ui_welcome_timeSettings_values_15min">15 minutes</string>
<string name="ui_welcome_timeSettings_values_30min">30 minutes</string>
<string name="ui_welcome_timeSettings_values_1hour">1 hour</string>
<string name="ui_welcome_timeSettings_selectTime">Select %s</string>
<string name="ui_welcome_timeSettings_changeableHint">You can change this anytime</string>
<string name="ui_welcome_saveFolder_title">Where should Alibi store the batches?</string>
<string name="ui_welcome_saveFolder_message">By default, Alibi stores the batches into its own private, encrypted storage. You can change this and specify an external, unencrypted folder. If you want to let Alibi remember more than 15 minutes, you should choose an external folder, as the internal folder is very small.</string>
<string name="ui_welcome_saveFolder_values_internal">Internal Storage</string>
<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>
</resources>