diff --git a/app/src/main/java/com/infomaniak/swisstransfer/ui/components/BottomStickyButtonScaffold.kt b/app/src/main/java/com/infomaniak/swisstransfer/ui/components/BottomStickyButtonScaffold.kt
index 6c7294c7e..7237ac290 100644
--- a/app/src/main/java/com/infomaniak/swisstransfer/ui/components/BottomStickyButtonScaffold.kt
+++ b/app/src/main/java/com/infomaniak/swisstransfer/ui/components/BottomStickyButtonScaffold.kt
@@ -17,12 +17,22 @@
*/
package com.infomaniak.swisstransfer.ui.components
+import androidx.compose.foundation.background
import androidx.compose.foundation.layout.*
-import androidx.compose.material3.Scaffold
import androidx.compose.material3.SnackbarHost
import androidx.compose.material3.SnackbarHostState
+import androidx.compose.material3.Surface
+import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
+import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.text.style.TextAlign
+import com.infomaniak.swisstransfer.R
+import com.infomaniak.swisstransfer.ui.theme.Dimens
+import com.infomaniak.swisstransfer.ui.theme.SwissTransferTheme
+import com.infomaniak.swisstransfer.ui.utils.PreviewLargeWindow
+import com.infomaniak.swisstransfer.ui.utils.PreviewSmallWindow
@Composable
fun BottomStickyButtonScaffold(
@@ -33,7 +43,7 @@ fun BottomStickyButtonScaffold(
bottomButton: @Composable ((Modifier) -> Unit)? = null,
content: @Composable BoxScope.() -> Unit,
) {
- Scaffold(
+ SinglePaneScaffold(
snackbarHost = { snackbarHostState?.let { SnackbarHost(hostState = it) } },
topBar = topBar,
) { contentPaddings ->
@@ -41,9 +51,36 @@ fun BottomStickyButtonScaffold(
modifier = modifier
.fillMaxWidth()
.padding(contentPaddings),
+ horizontalAlignment = Alignment.CenterHorizontally,
) {
Box(modifier = Modifier.weight(1.0f), content = content)
- DoubleButtonCombo(topButton, bottomButton)
+ DoubleButtonCombo(
+ modifier = Modifier.padding(vertical = Dimens.ButtonComboVerticalPadding),
+ topButton = topButton,
+ bottomButton = bottomButton,
+ )
+ }
+ }
+}
+
+@PreviewSmallWindow
+@PreviewLargeWindow
+@Composable
+private fun Preview() {
+ SwissTransferTheme {
+ Surface {
+ BottomStickyButtonScaffold(
+ topBar = { BrandTopAppBar() },
+ topButton = { modifier -> LargeButton(R.string.appName, onClick = {}, modifier = modifier) },
+ ) {
+ Text(
+ modifier = Modifier
+ .fillMaxSize()
+ .background(Color.LightGray),
+ text = "content",
+ textAlign = TextAlign.Center,
+ )
+ }
}
}
}
diff --git a/app/src/main/java/com/infomaniak/swisstransfer/ui/components/DoubleButtonCombo.kt b/app/src/main/java/com/infomaniak/swisstransfer/ui/components/DoubleButtonCombo.kt
index ab7071426..e524f4ddd 100644
--- a/app/src/main/java/com/infomaniak/swisstransfer/ui/components/DoubleButtonCombo.kt
+++ b/app/src/main/java/com/infomaniak/swisstransfer/ui/components/DoubleButtonCombo.kt
@@ -32,11 +32,12 @@ private val WIDTH_THRESHOLD = 500.dp
@Composable
fun ColumnScope.DoubleButtonCombo(
+ modifier: Modifier = Modifier,
topButton: @Composable ((Modifier) -> Unit)? = null,
bottomButton: @Composable ((Modifier) -> Unit)? = null
) {
BoxWithConstraints(
- modifier = Modifier
+ modifier = modifier
.widthIn(max = Dimens.DoubleButtonMaxWidth)
.align(Alignment.CenterHorizontally),
) {
@@ -71,7 +72,7 @@ private fun VerticallyStackedButtons(
bottomButton(
Modifier
.fillMaxWidth()
- .padding(start = Margin.Medium, end = Margin.Medium, bottom = Margin.Large),
+ .padding(horizontal = Margin.Medium),
)
}
}
@@ -84,7 +85,7 @@ private fun HorizontallyStackedButtons(
Row(
modifier = Modifier
.fillMaxWidth()
- .padding(bottom = Margin.Large, start = Margin.Medium, end = Margin.Medium),
+ .padding(horizontal = Margin.Medium),
horizontalArrangement = Arrangement.spacedBy(Margin.Medium),
verticalAlignment = Alignment.CenterVertically,
) {
@@ -99,7 +100,7 @@ private fun SingleButton(button: @Composable (Modifier) -> Unit) {
button(
Modifier
.fillMaxWidth()
- .padding(bottom = Margin.Large, start = Margin.Medium, end = Margin.Medium),
+ .padding(horizontal = Margin.Medium),
)
}
}
@@ -125,6 +126,7 @@ private fun DoubleButtonComboPreview() {
)
},
)
+ Spacer(Modifier.height(Margin.Medium))
DoubleButtonCombo(
bottomButton = {
LargeButton(
diff --git a/app/src/main/java/com/infomaniak/swisstransfer/ui/components/SinglePaneScaffold.kt b/app/src/main/java/com/infomaniak/swisstransfer/ui/components/SinglePaneScaffold.kt
new file mode 100644
index 000000000..545dea914
--- /dev/null
+++ b/app/src/main/java/com/infomaniak/swisstransfer/ui/components/SinglePaneScaffold.kt
@@ -0,0 +1,71 @@
+/*
+ * Infomaniak SwissTransfer - Android
+ * Copyright (C) 2024 Infomaniak Network SA
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package com.infomaniak.swisstransfer.ui.components
+
+import androidx.compose.foundation.background
+import androidx.compose.foundation.layout.*
+import androidx.compose.material3.Scaffold
+import androidx.compose.material3.Surface
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.graphics.Color
+import com.infomaniak.swisstransfer.ui.theme.Dimens
+import com.infomaniak.swisstransfer.ui.theme.SwissTransferTheme
+import com.infomaniak.swisstransfer.ui.utils.PreviewLargeWindow
+import com.infomaniak.swisstransfer.ui.utils.PreviewLightAndDark
+
+@Composable
+fun SinglePaneScaffold(
+ topBar: @Composable () -> Unit = {},
+ bottomBar: @Composable () -> Unit = {},
+ snackbarHost: @Composable () -> Unit = {},
+ content: @Composable (PaddingValues) -> Unit,
+) {
+ Scaffold(
+ topBar = topBar,
+ bottomBar = bottomBar,
+ snackbarHost = snackbarHost,
+ ) { contentPadding ->
+ Box(
+ contentAlignment = Alignment.TopCenter,
+ modifier = Modifier.fillMaxWidth(),
+ ) {
+ Box(Modifier.widthIn(max = Dimens.MaxSinglePaneScreenWidth)) {
+ content(contentPadding)
+ }
+ }
+ }
+}
+
+@PreviewLightAndDark
+@PreviewLargeWindow
+@Composable
+private fun Preview() {
+ SwissTransferTheme {
+ Surface {
+ SinglePaneScaffold {
+ Box(
+ Modifier
+ .fillMaxSize()
+ .background(Color.Cyan)
+ )
+ }
+ }
+ }
+}
diff --git a/app/src/main/java/com/infomaniak/swisstransfer/ui/components/SwissTransferAlertDialog.kt b/app/src/main/java/com/infomaniak/swisstransfer/ui/components/SwissTransferAlertDialog.kt
index c1edffd88..a6faae7ce 100644
--- a/app/src/main/java/com/infomaniak/swisstransfer/ui/components/SwissTransferAlertDialog.kt
+++ b/app/src/main/java/com/infomaniak/swisstransfer/ui/components/SwissTransferAlertDialog.kt
@@ -39,7 +39,7 @@ fun SwissTransferAlertDialog(
@StringRes descriptionRes: Int,
onDismiss: () -> Unit,
onConfirmation: () -> Unit,
- shouldEnableConfirmButton: () -> Boolean = { true },
+ isConfirmButtonEnabled: () -> Boolean = { true },
content: @Composable (ColumnScope.() -> Unit)? = null,
) {
BasicAlertDialog(
@@ -56,7 +56,7 @@ fun SwissTransferAlertDialog(
additionalContent = content,
onDismiss = onDismiss,
onConfirmation = onConfirmation,
- shouldEnableConfirmButton = shouldEnableConfirmButton,
+ isConfirmButtonEnabled = isConfirmButtonEnabled,
)
}
}
@@ -70,16 +70,16 @@ private fun BasicAlertDialogContent(
additionalContent: @Composable (ColumnScope.() -> Unit)? = null,
onDismiss: () -> Unit,
onConfirmation: () -> Unit,
- shouldEnableConfirmButton: () -> Boolean = { true },
+ isConfirmButtonEnabled: () -> Boolean = { true },
) {
Column(modifier.padding(Margin.Large)) {
TitleAndDescription(titleRes, descriptionRes)
Spacer(Modifier.height(Margin.Large))
additionalContent?.let {
it()
- Spacer(Modifier.height(Margin.Large))
+ Spacer(Modifier.height(Margin.Mini))
}
- ActionButtons(onDismiss, onConfirmation, shouldEnableConfirmButton)
+ ActionButtons(onDismiss, onConfirmation, isConfirmButtonEnabled)
}
}
@@ -99,7 +99,7 @@ private fun TitleAndDescription(titleRes: Int, descriptionRes: Int) {
}
@Composable
-private fun ActionButtons(onDismissRequest: () -> Unit, onConfirmation: () -> Unit, shouldEnable: () -> Boolean) {
+private fun ActionButtons(onDismissRequest: () -> Unit, onConfirmation: () -> Unit, isEnabled: () -> Boolean) {
Row(
modifier = Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.End,
@@ -114,7 +114,7 @@ private fun ActionButtons(onDismissRequest: () -> Unit, onConfirmation: () -> Un
SmallButton(
titleRes = R.string.buttonConfirm,
onClick = onConfirmation,
- enabled = shouldEnable
+ enabled = isEnabled
)
}
}
diff --git a/app/src/main/java/com/infomaniak/swisstransfer/ui/components/SwissTransferBottomSheet.kt b/app/src/main/java/com/infomaniak/swisstransfer/ui/components/SwissTransferBottomSheet.kt
index 6c1e6caf3..1fbc249a5 100644
--- a/app/src/main/java/com/infomaniak/swisstransfer/ui/components/SwissTransferBottomSheet.kt
+++ b/app/src/main/java/com/infomaniak/swisstransfer/ui/components/SwissTransferBottomSheet.kt
@@ -40,6 +40,7 @@ import androidx.compose.ui.unit.dp
import com.infomaniak.swisstransfer.R
import com.infomaniak.swisstransfer.ui.images.AppImages.AppIllus
import com.infomaniak.swisstransfer.ui.images.illus.ArrowDownRightCurved
+import com.infomaniak.swisstransfer.ui.theme.Dimens
import com.infomaniak.swisstransfer.ui.theme.Margin
import com.infomaniak.swisstransfer.ui.theme.SwissTransferTheme
@@ -133,7 +134,11 @@ private fun BottomSheetContent(
Spacer(Modifier.height(Margin.Large))
}
- DoubleButtonCombo(topButton = topButton, bottomButton = bottomButton)
+ DoubleButtonCombo(
+ modifier = Modifier.padding(bottom = Dimens.ButtonComboVerticalPadding),
+ topButton = topButton,
+ bottomButton = bottomButton,
+ )
}
}
diff --git a/app/src/main/java/com/infomaniak/swisstransfer/ui/components/SwissTransferTextField.kt b/app/src/main/java/com/infomaniak/swisstransfer/ui/components/SwissTransferTextField.kt
index b79628195..694778247 100644
--- a/app/src/main/java/com/infomaniak/swisstransfer/ui/components/SwissTransferTextField.kt
+++ b/app/src/main/java/com/infomaniak/swisstransfer/ui/components/SwissTransferTextField.kt
@@ -46,8 +46,12 @@ import com.infomaniak.swisstransfer.ui.theme.SwissTransferTheme
/**
* Wrapper for Material's [OutlinedTextField] that enforce our design needs.
+ *
* By default, this TextField is single lined. You can specify [maxLineNumber] or [minLineNumber] to make it multi-lined
+ *
* If [isPassword] value is true, the [keyboardType] field will be ignored to force [KeyboardType.Password]
+ *
+ * To set an error message, you need to pass this message as [supportingText] and set [isError] to true
*/
@Composable
fun SwissTransferTextField(
@@ -62,8 +66,8 @@ fun SwissTransferTextField(
imeAction: ImeAction = ImeAction.Default,
keyboardActions: KeyboardActions = KeyboardActions.Default,
isReadOnly: Boolean = false,
- errorMessage: @Composable () -> String? = { null },
- supportingText: String? = null,
+ isError: Boolean = false,
+ supportingText: @Composable (() -> Unit)? = null,
onValueChange: ((String) -> Unit)? = null,
) {
@@ -80,17 +84,6 @@ fun SwissTransferTextField(
disabledTrailingIconColor = SwissTransferTheme.colors.iconColor,
)
- @Composable
- fun getSupportingText(): (@Composable () -> Unit)? {
- val displayText = if (text.isEmpty()) {
- supportingText
- } else {
- errorMessage() ?: supportingText
- }
-
- return displayText?.let { @Composable { Text(it) } }
- }
-
OutlinedTextField(
modifier = modifier,
readOnly = isReadOnly,
@@ -119,8 +112,8 @@ fun SwissTransferTextField(
imeAction = imeAction,
),
keyboardActions = keyboardActions,
- isError = errorMessage() != null && text.isNotEmpty(),
- supportingText = getSupportingText(),
+ isError = isError,
+ supportingText = supportingText,
)
}
@@ -139,18 +132,21 @@ private fun getShowPasswordButton(shouldShowPassword: Boolean, onClick: () -> Un
@Composable
@Preview
private fun Preview() {
+ val supportingText = "supporting Text"
+ val initialValue = "initialValue"
+
SwissTransferTheme {
Surface {
Column(Modifier.padding(Margin.Medium)) {
SwissTransferTextField(
label = stringResource(R.string.transferMessagePlaceholder),
initialValue = "test",
- errorMessage = { null },
)
SwissTransferTextField(
keyboardType = KeyboardType.Email,
initialValue = "a@a@.com",
- errorMessage = { "Invalid address" },
+ supportingText = { Text("Invalid address") },
+ isError = true,
label = stringResource(R.string.transferRecipientAddressPlaceholder),
)
SwissTransferTextField(
@@ -160,25 +156,25 @@ private fun Preview() {
)
SwissTransferTextField(
maxLineNumber = 10,
- initialValue = "initial value",
+ initialValue = initialValue,
isRequired = false,
label = stringResource(R.string.transferMessagePlaceholder),
- supportingText = "supporting Text",
+ supportingText = { Text(supportingText) },
)
SwissTransferTextField(
maxLineNumber = 10,
- initialValue = "initial value",
+ initialValue = initialValue,
isPassword = true,
label = stringResource(R.string.settingsOptionPassword),
- supportingText = "supporting Text",
+ supportingText = { Text(supportingText) },
)
SwissTransferTextField(
maxLineNumber = 10,
- initialValue = "initial value",
+ initialValue = initialValue,
isPassword = true,
label = stringResource(R.string.settingsOptionPassword),
- errorMessage = { "Wrong password" },
- supportingText = "supporting Text",
+ isError = true,
+ supportingText = { Text("Wrong password") },
)
}
}
diff --git a/app/src/main/java/com/infomaniak/swisstransfer/ui/images/icons/QrCode.kt b/app/src/main/java/com/infomaniak/swisstransfer/ui/images/icons/QrCode.kt
index f0f038ed8..be14ab524 100644
--- a/app/src/main/java/com/infomaniak/swisstransfer/ui/images/icons/QrCode.kt
+++ b/app/src/main/java/com/infomaniak/swisstransfer/ui/images/icons/QrCode.kt
@@ -27,7 +27,6 @@ import androidx.compose.ui.graphics.PathFillType.Companion.NonZero
import androidx.compose.ui.graphics.SolidColor
import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.graphics.vector.ImageVector.Builder
-import androidx.compose.ui.graphics.vector.group
import androidx.compose.ui.graphics.vector.path
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
@@ -48,63 +47,60 @@ val AppIcons.QrCode: ImageVector
viewportWidth = 24.0f,
viewportHeight = 25.0f,
).apply {
- group {
- path(
- fill = null,
- stroke = SolidColor(Color(0xFF9F9F9F)),
- strokeLineWidth = 1.5f,
- strokeLineCap = strokeCapRound,
- strokeLineJoin = strokeJoinRound,
- strokeLineMiter = 4.0f,
- pathFillType = NonZero,
- ) {
- moveTo(5.25f, 6.033f)
- horizontalLineToRelative(3.0f)
- verticalLineToRelative(3.0f)
- horizontalLineToRelative(-3.0f)
- close()
- moveToRelative(0.0f, 10.5f)
- horizontalLineToRelative(3.0f)
- verticalLineToRelative(3.0f)
- horizontalLineToRelative(-3.0f)
- close()
- moveToRelative(10.5f, -10.5f)
- horizontalLineToRelative(3.0f)
- verticalLineToRelative(3.0f)
- horizontalLineToRelative(-3.0f)
- close()
- moveToRelative(-10.5f, 7.5f)
- horizontalLineToRelative(6.0f)
- verticalLineToRelative(1.5f)
- moveToRelative(3.0f, 0.0f)
- verticalLineToRelative(4.5f)
- horizontalLineToRelative(4.5f)
- verticalLineToRelative(-4.5f)
- horizontalLineToRelative(-1.5f)
- moveToRelative(-6.0f, 3.0f)
- verticalLineToRelative(1.5f)
- moveToRelative(0.0f, -13.5f)
- verticalLineToRelative(4.5f)
- horizontalLineToRelative(1.5f)
- moveToRelative(3.0f, 1.5f)
- horizontalLineToRelative(3.0f)
- moveToRelative(-18.0f, -5.25f)
- verticalLineToRelative(-3.75f)
- arcToRelative(1.5f, 1.5f, 0.0f, false, true, 1.5f, -1.5f)
- horizontalLineTo(6.0f)
- moveToRelative(12.0f, 0.0f)
- horizontalLineToRelative(3.75f)
- arcToRelative(1.5f, 1.5f, 0.0f, false, true, 1.5f, 1.5f)
- verticalLineToRelative(3.75f)
- moveToRelative(0.0f, 12.0f)
- verticalLineToRelative(3.75f)
- arcToRelative(1.5f, 1.5f, 0.0f, false, true, -1.5f, 1.5f)
- horizontalLineTo(18.0f)
- moveToRelative(-12.0f, 0.0f)
- horizontalLineTo(2.25f)
- arcToRelative(1.5f, 1.5f, 0.0f, false, true, -1.5f, -1.5f)
- verticalLineToRelative(-3.75f)
- }
+ path(
+ stroke = SolidColor(Color(0xFF9F9F9F)),
+ strokeLineWidth = 1.5f,
+ strokeLineCap = strokeCapRound,
+ strokeLineJoin = strokeJoinRound,
+ strokeLineMiter = 4.0f,
+ pathFillType = NonZero,
+ ) {
+ moveTo(5.25f, 5.866f)
+ horizontalLineToRelative(3.0f)
+ verticalLineToRelative(3.0f)
+ horizontalLineToRelative(-3.0f)
+ close()
+ moveTo(5.25f, 16.366f)
+ horizontalLineToRelative(3.0f)
+ verticalLineToRelative(3.0f)
+ horizontalLineToRelative(-3.0f)
+ close()
+ moveTo(15.75f, 5.866f)
+ horizontalLineToRelative(3.0f)
+ verticalLineToRelative(3.0f)
+ horizontalLineToRelative(-3.0f)
+ close()
+ moveTo(5.25f, 13.366f)
+ horizontalLineToRelative(6.0f)
+ verticalLineToRelative(1.5f)
+ moveTo(14.25f, 14.866f)
+ verticalLineToRelative(4.5f)
+ horizontalLineToRelative(4.5f)
+ verticalLineToRelative(-4.5f)
+ horizontalLineToRelative(-1.5f)
+ moveTo(11.25f, 17.866f)
+ verticalLineToRelative(1.5f)
+ moveTo(11.25f, 5.866f)
+ verticalLineToRelative(4.5f)
+ horizontalLineToRelative(1.5f)
+ moveTo(15.75f, 11.866f)
+ horizontalLineToRelative(3.0f)
+ moveTo(0.75f, 6.616f)
+ verticalLineToRelative(-3.75f)
+ arcToRelative(1.5f, 1.5f, 0.0f, false, true, 1.5f, -1.5f)
+ horizontalLineTo(6.0f)
+ moveTo(18.0f, 1.366f)
+ horizontalLineToRelative(3.75f)
+ arcToRelative(1.5f, 1.5f, 0.0f, false, true, 1.5f, 1.5f)
+ verticalLineToRelative(3.75f)
+ moveTo(23.25f, 18.616f)
+ verticalLineToRelative(3.75f)
+ arcToRelative(1.5f, 1.5f, 0.0f, false, true, -1.5f, 1.5f)
+ horizontalLineTo(18.0f)
+ moveTo(6.0f, 23.866f)
+ horizontalLineTo(2.25f)
+ arcToRelative(1.5f, 1.5f, 0.0f, false, true, -1.5f, -1.5f)
+ verticalLineToRelative(-3.75f)
}
}.build()
diff --git a/app/src/main/java/com/infomaniak/swisstransfer/ui/screen/newtransfer/importfiles/ImportFilesScreen.kt b/app/src/main/java/com/infomaniak/swisstransfer/ui/screen/newtransfer/importfiles/ImportFilesScreen.kt
index a540d5e18..c8372578b 100644
--- a/app/src/main/java/com/infomaniak/swisstransfer/ui/screen/newtransfer/importfiles/ImportFilesScreen.kt
+++ b/app/src/main/java/com/infomaniak/swisstransfer/ui/screen/newtransfer/importfiles/ImportFilesScreen.kt
@@ -30,7 +30,6 @@ import androidx.compose.runtime.*
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.vector.ImageVector
-import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.tooling.preview.PreviewParameter
import androidx.hilt.navigation.compose.hiltViewModel
@@ -49,11 +48,8 @@ import com.infomaniak.swisstransfer.ui.screen.newtransfer.importfiles.components
import com.infomaniak.swisstransfer.ui.theme.Margin
import com.infomaniak.swisstransfer.ui.theme.SwissTransferTheme
import com.infomaniak.swisstransfer.ui.utils.GetSetCallbacks
-import com.infomaniak.swisstransfer.ui.utils.HumanReadableSizeUtils.getHumanReadableSize
import com.infomaniak.swisstransfer.ui.utils.PreviewAllWindows
-private const val TOTAL_FILE_SIZE: Long = 50_000_000_000L
-
@Composable
fun ImportFilesScreen(
importFilesViewModel: ImportFilesViewModel = hiltViewModel(),
@@ -147,34 +143,6 @@ private fun ImportFilesScreen(
shouldStartByPromptingUserForFiles: Boolean,
sendTransfer: () -> Unit,
) {
- val context = LocalContext.current
- var shouldShowInitialFilePick by rememberSaveable { mutableStateOf(shouldStartByPromptingUserForFiles) }
- var showTransferOption by rememberSaveable { mutableStateOf(null) }
-
- val importedFiles = files()
- val humanReadableSize = remember(importedFiles) {
- val usedSpace = importedFiles.sumOf { it.fileSize }
- val spaceLeft = (TOTAL_FILE_SIZE - usedSpace).coerceAtLeast(0)
- getHumanReadableSize(context, spaceLeft)
- }
-
- val filePickerLauncher = rememberLauncherForActivityResult(
- contract = ActivityResultContracts.OpenMultipleDocuments()
- ) { uris: List ->
- addFiles(uris)
- }
-
- fun pickFiles() {
- shouldShowInitialFilePick = false
- filePickerLauncher.launch(arrayOf("*/*"))
- }
-
- fun closeTransferOption() {
- showTransferOption = null
- }
-
- LaunchedEffect(Unit) { if (shouldShowInitialFilePick) pickFiles() }
-
BottomStickyButtonScaffold(
topBar = {
SwissTransferTopAppBar(
@@ -187,63 +155,84 @@ private fun ImportFilesScreen(
SendButton(filesToImportCount, currentSessionFilesCount, files, modifier, sendTransfer)
},
content = {
- Column(
- modifier = Modifier
- .padding(horizontal = Margin.Medium, vertical = Margin.Large)
- .verticalScroll(rememberScrollState()),
- ) {
- ImportFilesTitle(titleRes = R.string.myFilesTitle)
- ImportedFilesCard(
- modifier = Modifier.padding(vertical = Margin.Medium),
- files = files,
- humanReadableSize = { humanReadableSize },
- pickFiles = ::pickFiles,
- removeFileByUid = removeFileByUid,
- )
- ImportTextFields(transferMessage, selectedTransferType.get)
- ImportFilesTitle(Modifier.padding(vertical = Margin.Medium), titleRes = R.string.transferTypeTitle)
- TransferTypeButtons(selectedTransferType)
- ImportFilesTitle(Modifier.padding(vertical = Margin.Medium), titleRes = R.string.advancedSettingsTitle)
- TransferOptionsTypes(
- transferOptionsStates = transferOptionsCallbacks.transferOptionsStates,
- onClick = { selectedOptionType -> showTransferOption = selectedOptionType },
+ Column(modifier = Modifier.verticalScroll(rememberScrollState())) {
+ FilesToImport(files, removeFileByUid, addFiles, shouldStartByPromptingUserForFiles)
+ Spacer(Modifier.height(Margin.Medium))
+ ImportTextFields(
+ modifier = Modifier.padding(horizontal = Margin.Medium),
+ transferMessage = transferMessage,
+ selectedTransferType = selectedTransferType.get,
)
+ SendByOptions(selectedTransferType)
+ TransferOptions(transferOptionsCallbacks)
}
-
- TransferOptions({ showTransferOption }, transferOptionsCallbacks, ::closeTransferOption)
}
)
}
@Composable
-private fun ColumnScope.ImportTextFields(transferMessage: GetSetCallbacks, selectedTransferType: () -> TransferTypeUi) {
+private fun FilesToImport(
+ files: () -> List,
+ removeFileByUid: (uid: String) -> Unit,
+ addFiles: (List) -> Unit,
+ shouldStartByPromptingUserForFiles: Boolean,
+) {
+ var shouldShowInitialFilePick by rememberSaveable { mutableStateOf(shouldStartByPromptingUserForFiles) }
- EmailAddressesTextFields(selectedTransferType)
+ val filePickerLauncher = rememberLauncherForActivityResult(
+ contract = ActivityResultContracts.OpenMultipleDocuments(),
+ onResult = addFiles,
+ )
- SwissTransferTextField(
- modifier = Modifier.fillMaxWidth(),
- label = stringResource(R.string.transferMessagePlaceholder),
- isRequired = false,
- minLineNumber = 3,
- onValueChange = transferMessage.set,
+ fun pickFiles() {
+ shouldShowInitialFilePick = false
+ filePickerLauncher.launch(arrayOf("*/*"))
+ }
+
+ LaunchedEffect(Unit) { if (shouldShowInitialFilePick) pickFiles() }
+
+ ImportFilesTitle(modifier = Modifier.padding(horizontal = Margin.Medium), titleRes = R.string.myFilesTitle)
+ ImportedFilesCard(
+ modifier = Modifier.padding(horizontal = Margin.Medium),
+ files = files,
+ pickFiles = ::pickFiles,
+ removeFileByUid = removeFileByUid,
)
}
@Composable
-private fun ColumnScope.EmailAddressesTextFields(selectedTransferType: () -> TransferTypeUi) {
+private fun ImportTextFields(
+ modifier: Modifier,
+ transferMessage: GetSetCallbacks,
+ selectedTransferType: () -> TransferTypeUi,
+) {
+ Column(modifier) {
+ EmailAddressesTextFields(Modifier.fillMaxWidth(), selectedTransferType)
+ SwissTransferTextField(
+ modifier = Modifier.fillMaxWidth(),
+ label = stringResource(R.string.transferMessagePlaceholder),
+ isRequired = false,
+ minLineNumber = 3,
+ onValueChange = transferMessage.set,
+ )
+ }
+}
+
+@Composable
+private fun ColumnScope.EmailAddressesTextFields(modifier: Modifier, selectedTransferType: () -> TransferTypeUi) {
val shouldShowEmailAddressesFields by remember { derivedStateOf { selectedTransferType() == TransferTypeUi.MAIL } }
AnimatedVisibility(visible = shouldShowEmailAddressesFields) {
Column {
SwissTransferTextField(
- modifier = Modifier.fillMaxWidth(),
+ modifier = modifier,
label = stringResource(R.string.transferSenderAddressPlaceholder),
onValueChange = { /* TODO */ },
)
Spacer(Modifier.height(Margin.Medium))
SwissTransferTextField(
- modifier = Modifier.fillMaxWidth(),
+ modifier = modifier,
label = stringResource(R.string.transferRecipientAddressPlaceholder),
onValueChange = { /* TODO */ },
)
@@ -253,7 +242,31 @@ private fun ColumnScope.EmailAddressesTextFields(selectedTransferType: () -> Tra
}
@Composable
-private fun TransferOptions(
+private fun SendByOptions(selectedTransferType: GetSetCallbacks) {
+ ImportFilesTitle(Modifier.padding(horizontal = Margin.Medium), titleRes = R.string.transferTypeTitle)
+ TransferTypeButtons(selectedTransferType)
+}
+
+@Composable
+private fun TransferOptions(transferOptionsCallbacks: TransferOptionsCallbacks) {
+
+ var showTransferOption by rememberSaveable { mutableStateOf(null) }
+
+ fun closeTransferOption() {
+ showTransferOption = null
+ }
+
+ ImportFilesTitle(Modifier.padding(horizontal = Margin.Medium), titleRes = R.string.advancedSettingsTitle)
+ TransferOptionsTypes(
+ modifier = Modifier.padding(horizontal = Margin.Medium),
+ transferOptionsStates = transferOptionsCallbacks.transferOptionsStates,
+ onClick = { selectedOptionType -> showTransferOption = selectedOptionType },
+ )
+ TransferOptionsDialogs({ showTransferOption }, transferOptionsCallbacks, ::closeTransferOption)
+}
+
+@Composable
+private fun TransferOptionsDialogs(
selectedOptionType: () -> TransferOptionType?,
transferOptionsCallbacks: TransferOptionsCallbacks,
closeTransferOption: () -> Unit,
@@ -287,6 +300,15 @@ private fun TransferOptions(
}
}
+@Composable
+private fun ImportFilesTitle(modifier: Modifier = Modifier, @StringRes titleRes: Int) {
+ Text(
+ modifier = modifier.padding(vertical = Margin.Medium),
+ style = SwissTransferTheme.typography.bodySmallRegular,
+ text = stringResource(titleRes),
+ )
+}
+
@Composable
private fun SendButton(
filesToImportCount: () -> Int,
@@ -317,15 +339,6 @@ private fun SendButton(
)
}
-@Composable
-private fun ImportFilesTitle(modifier: Modifier = Modifier, @StringRes titleRes: Int) {
- Text(
- text = stringResource(titleRes),
- style = SwissTransferTheme.typography.bodySmallRegular,
- modifier = modifier,
- )
-}
-
data class TransferOptionsCallbacks(
val transferOptionsStates: () -> List,
val onTransferOptionValueSelected: (SettingOption) -> Unit,
@@ -382,7 +395,7 @@ private fun Preview(@PreviewParameter(FileUiListPreviewParameter::class) files:
filesToImportCount = { 0 },
currentSessionFilesCount = { 0 },
transferMessage = GetSetCallbacks(get = { "" }, set = {}),
- selectedTransferType = GetSetCallbacks(get = { TransferTypeUi.QR_CODE }, set = {}),
+ selectedTransferType = GetSetCallbacks(get = { TransferTypeUi.MAIL }, set = {}),
transferOptionsCallbacks = transferOptionsCallbacks,
removeFileByUid = {},
addFiles = {},
diff --git a/app/src/main/java/com/infomaniak/swisstransfer/ui/screen/newtransfer/importfiles/components/ImportedFilesCard.kt b/app/src/main/java/com/infomaniak/swisstransfer/ui/screen/newtransfer/importfiles/components/ImportedFilesCard.kt
index 390d72efe..3d88f8137 100644
--- a/app/src/main/java/com/infomaniak/swisstransfer/ui/screen/newtransfer/importfiles/components/ImportedFilesCard.kt
+++ b/app/src/main/java/com/infomaniak/swisstransfer/ui/screen/newtransfer/importfiles/components/ImportedFilesCard.kt
@@ -25,7 +25,11 @@ import androidx.compose.material3.Button
import androidx.compose.material3.ButtonDefaults
import androidx.compose.material3.Icon
import androidx.compose.runtime.Composable
+import androidx.compose.runtime.derivedStateOf
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
+import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.pluralStringResource
import androidx.compose.ui.tooling.preview.PreviewParameter
import androidx.compose.ui.unit.dp
@@ -40,17 +44,30 @@ import com.infomaniak.swisstransfer.ui.theme.CustomShapes
import com.infomaniak.swisstransfer.ui.theme.Margin
import com.infomaniak.swisstransfer.ui.theme.SwissTransferTheme
import com.infomaniak.swisstransfer.ui.utils.HumanReadableSizeUtils.formatSpaceLeft
+import com.infomaniak.swisstransfer.ui.utils.HumanReadableSizeUtils.getHumanReadableSize
import com.infomaniak.swisstransfer.ui.utils.PreviewLightAndDark
import kotlinx.parcelize.Parcelize
+private const val TOTAL_FILE_SIZE: Long = 50_000_000_000L
+
@Composable
fun ImportedFilesCard(
modifier: Modifier = Modifier,
files: () -> List,
- humanReadableSize: () -> String,
pickFiles: () -> Unit,
removeFileByUid: (uid: String) -> Unit,
) {
+
+ val context = LocalContext.current
+
+ val humanReadableSize by remember {
+ derivedStateOf {
+ val usedSpace = files().sumOf { it.fileSize }
+ val spaceLeft = (TOTAL_FILE_SIZE - usedSpace).coerceAtLeast(0)
+ getHumanReadableSize(context, spaceLeft)
+ }
+ }
+
SwissTransferCard(modifier) {
SharpRippleButton(onClick = { /* TODO */ }) {
TextDotText(
@@ -58,7 +75,7 @@ fun ImportedFilesCard(
val fileCount = files().count()
pluralStringResource(R.plurals.filesCount, fileCount, fileCount)
},
- secondText = { formatSpaceLeft(humanReadableSize) },
+ secondText = { formatSpaceLeft { humanReadableSize } },
modifier = Modifier.padding(start = Margin.Medium),
)
Spacer(Modifier.weight(1.0f))
@@ -130,7 +147,6 @@ private fun ImportedFilesCardPreview(@PreviewParameter(FileUiListPreviewParamete
ImportedFilesCard(
modifier = Modifier.padding(Margin.Medium),
files = { files },
- humanReadableSize = { "20 GB" },
pickFiles = {},
removeFileByUid = {},
)
diff --git a/app/src/main/java/com/infomaniak/swisstransfer/ui/screen/newtransfer/importfiles/components/PasswordOptionAlertDialog.kt b/app/src/main/java/com/infomaniak/swisstransfer/ui/screen/newtransfer/importfiles/components/PasswordOptionAlertDialog.kt
index 709b3527a..007742331 100644
--- a/app/src/main/java/com/infomaniak/swisstransfer/ui/screen/newtransfer/importfiles/components/PasswordOptionAlertDialog.kt
+++ b/app/src/main/java/com/infomaniak/swisstransfer/ui/screen/newtransfer/importfiles/components/PasswordOptionAlertDialog.kt
@@ -18,10 +18,7 @@
package com.infomaniak.swisstransfer.ui.screen.newtransfer.importfiles.components
import androidx.compose.animation.AnimatedVisibility
-import androidx.compose.foundation.layout.ColumnScope
-import androidx.compose.foundation.layout.Row
-import androidx.compose.foundation.layout.Spacer
-import androidx.compose.foundation.layout.height
+import androidx.compose.foundation.layout.*
import androidx.compose.material3.Surface
import androidx.compose.material3.Switch
import androidx.compose.material3.Text
@@ -29,10 +26,12 @@ import androidx.compose.runtime.*
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
+import androidx.compose.ui.draw.alpha
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.input.ImeAction
import androidx.compose.ui.tooling.preview.Preview
import com.infomaniak.swisstransfer.R
+import com.infomaniak.swisstransfer.ui.MatomoSwissTransfer.toFloat
import com.infomaniak.swisstransfer.ui.components.SwissTransferAlertDialog
import com.infomaniak.swisstransfer.ui.components.SwissTransferTextField
import com.infomaniak.swisstransfer.ui.screen.newtransfer.importfiles.PasswordTransferOption
@@ -75,9 +74,10 @@ fun PasswordOptionAlertDialog(
descriptionRes = R.string.settingsPasswordDescription,
onDismiss = ::onDismiss,
onConfirmation = ::onConfirmButtonClicked,
- shouldEnableConfirmButton = { if (isPasswordActivated) isPasswordValid() else true },
+ isConfirmButtonEnabled = { !isPasswordActivated || isPasswordValid() },
) {
ActivatePasswordSwitch(isChecked = isPasswordActivated, onCheckedChange = { isPasswordActivated = it })
+ Spacer(Modifier.height(Margin.Medium))
AnimatedPasswordInput(isPasswordActivated, password, isPasswordValid)
}
}
@@ -101,14 +101,22 @@ private fun ColumnScope.AnimatedPasswordInput(
password: GetSetCallbacks,
isPasswordValid: () -> Boolean
) {
+
+ val isError = !isPasswordValid() && password.get().isNotEmpty()
AnimatedVisibility(isChecked) {
- Spacer(Modifier.height(Margin.Mini))
SwissTransferTextField(
+ modifier = Modifier.fillMaxWidth(),
label = stringResource(R.string.settingsOptionPassword),
isPassword = true,
initialValue = password.get(),
imeAction = ImeAction.Done,
- errorMessage = { if (isPasswordValid()) null else stringResource(R.string.errorTransferPasswordLength) },
+ isError = isError,
+ supportingText = {
+ Text(
+ modifier = Modifier.alpha(isError.toFloat()),
+ text = stringResource(R.string.errorTransferPasswordLength),
+ )
+ },
onValueChange = { password.set(it) },
)
}
diff --git a/app/src/main/java/com/infomaniak/swisstransfer/ui/screen/newtransfer/importfiles/components/TransferTypeButtons.kt b/app/src/main/java/com/infomaniak/swisstransfer/ui/screen/newtransfer/importfiles/components/TransferTypeButtons.kt
index e32851f3a..fd2d5d665 100644
--- a/app/src/main/java/com/infomaniak/swisstransfer/ui/screen/newtransfer/importfiles/components/TransferTypeButtons.kt
+++ b/app/src/main/java/com/infomaniak/swisstransfer/ui/screen/newtransfer/importfiles/components/TransferTypeButtons.kt
@@ -20,13 +20,13 @@ package com.infomaniak.swisstransfer.ui.screen.newtransfer.importfiles.component
import androidx.annotation.PluralsRes
import androidx.annotation.StringRes
import androidx.compose.foundation.horizontalScroll
-import androidx.compose.foundation.layout.Arrangement
-import androidx.compose.foundation.layout.Row
+import androidx.compose.foundation.layout.*
import androidx.compose.foundation.rememberScrollState
import androidx.compose.material3.Surface
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.vector.ImageVector
+import androidx.compose.ui.unit.dp
import com.infomaniak.multiplatform_swisstransfer.common.models.TransferType
import com.infomaniak.swisstransfer.R
import com.infomaniak.swisstransfer.ui.images.AppImages.AppIcons
@@ -42,7 +42,9 @@ import com.infomaniak.swisstransfer.ui.utils.PreviewLightAndDark
@Composable
fun TransferTypeButtons(transferType: GetSetCallbacks) {
Row(
- modifier = Modifier.horizontalScroll(rememberScrollState()),
+ modifier = Modifier
+ .horizontalScroll(rememberScrollState())
+ .padding(horizontal = Margin.Medium),
horizontalArrangement = Arrangement.spacedBy(Margin.Mini),
) {
for (transferTypeEntry in TransferTypeUi.entries) {
diff --git a/app/src/main/java/com/infomaniak/swisstransfer/ui/theme/Dimens.kt b/app/src/main/java/com/infomaniak/swisstransfer/ui/theme/Dimens.kt
index fa589a989..547485b19 100644
--- a/app/src/main/java/com/infomaniak/swisstransfer/ui/theme/Dimens.kt
+++ b/app/src/main/java/com/infomaniak/swisstransfer/ui/theme/Dimens.kt
@@ -20,13 +20,15 @@ package com.infomaniak.swisstransfer.ui.theme
import androidx.compose.ui.unit.dp
object Dimens {
+ val MaxSinglePaneScreenWidth = 800.dp
val SettingHorizontalMargin = Margin.Medium
val SettingVerticalMargin = Margin.Small
val DescriptionWidth = 300.dp
val LargeButtonHeight = 56.dp
- val DoubleButtonMaxWidth = 800.dp
+ val DoubleButtonMaxWidth = MaxSinglePaneScreenWidth
val SingleButtonMaxWidth = DoubleButtonMaxWidth / 2
val SmallIconSize = 16.dp
val IconSize = 24.dp
val BorderWidth = 1.dp
+ val ButtonComboVerticalPadding = Margin.Small
}