From ac2a71af8af6b1ea203d05621d3a5ec6251aa703 Mon Sep 17 00:00:00 2001 From: Gibran Chevalley Date: Thu, 3 Oct 2024 16:17:36 +0200 Subject: [PATCH 01/27] List amount of selected files and add button --- .../ui/components/SwissTransferCard.kt | 64 +++++++++ .../swisstransfer/ui/images/icons/AddThick.kt | 66 +++++++++ .../screen/newtransfer/NewTransferNavHost.kt | 1 - .../importfiles/ImportFilesScreen.kt | 125 ++++++++++++++---- 4 files changed, 227 insertions(+), 29 deletions(-) create mode 100644 app/src/main/java/com/infomaniak/swisstransfer/ui/components/SwissTransferCard.kt create mode 100644 app/src/main/java/com/infomaniak/swisstransfer/ui/images/icons/AddThick.kt diff --git a/app/src/main/java/com/infomaniak/swisstransfer/ui/components/SwissTransferCard.kt b/app/src/main/java/com/infomaniak/swisstransfer/ui/components/SwissTransferCard.kt new file mode 100644 index 000000000..d5e4f47ec --- /dev/null +++ b/app/src/main/java/com/infomaniak/swisstransfer/ui/components/SwissTransferCard.kt @@ -0,0 +1,64 @@ +/* + * 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 android.content.res.Configuration +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.ColumnScope +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size +import androidx.compose.material3.Card +import androidx.compose.material3.CardDefaults +import androidx.compose.material3.Surface +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import com.infomaniak.swisstransfer.ui.theme.Margin +import com.infomaniak.swisstransfer.ui.theme.Shapes +import com.infomaniak.swisstransfer.ui.theme.SwissTransferTheme + +@Composable +fun SwissTransferCard(modifier: Modifier = Modifier, content: @Composable ColumnScope.() -> Unit) { + Card( + modifier = modifier, + shape = Shapes.medium, + colors = CardDefaults.cardColors(contentColor = SwissTransferTheme.colors.secondaryTextColor), + content = content + ) +} + +@Preview(name = "Light") +@Preview(name = "Dark", uiMode = Configuration.UI_MODE_NIGHT_YES or Configuration.UI_MODE_TYPE_NORMAL) +@Composable +private fun SwissTransferCardPreview() { + SwissTransferTheme { + Surface { + SwissTransferCard( + modifier = Modifier + .size(300.dp, 200.dp) + .padding(Margin.Medium) + ) { + Column(Modifier.padding(Margin.Large)) { + Text("Hello World!") + } + } + } + } +} diff --git a/app/src/main/java/com/infomaniak/swisstransfer/ui/images/icons/AddThick.kt b/app/src/main/java/com/infomaniak/swisstransfer/ui/images/icons/AddThick.kt new file mode 100644 index 000000000..7ae942529 --- /dev/null +++ b/app/src/main/java/com/infomaniak/swisstransfer/ui/images/icons/AddThick.kt @@ -0,0 +1,66 @@ +package com.infomaniak.swisstransfer.ui.images.icons + +import androidx.compose.foundation.Image +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.size +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +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 +import com.infomaniak.swisstransfer.ui.images.AppImages +import com.infomaniak.swisstransfer.ui.images.AppImages.AppIcons +import androidx.compose.ui.graphics.StrokeCap.Companion.Round as strokeCapRound +import androidx.compose.ui.graphics.StrokeJoin.Companion.Round as strokeJoinRound + +val AppIcons.AddThick: ImageVector + get() { + if (_addThick != null) { + return _addThick!! + } + _addThick = Builder( + name = "AddThick", + defaultWidth = 24.0.dp, + defaultHeight = 24.0.dp, + viewportWidth = 16.0f, + viewportHeight = 16.0f + ).apply { + group { + path( + fill = null, + stroke = SolidColor(Color(0xFF9F9F9F)), + strokeLineWidth = 2.0f, + strokeLineCap = strokeCapRound, + strokeLineJoin = strokeJoinRound, + strokeLineMiter = 4.0f, + pathFillType = NonZero + ) { + moveTo(1.0f, 8.0f) + horizontalLineToRelative(14.0f) + moveTo(8.0f, 1.0f) + verticalLineToRelative(14.0f) + } + } + }.build() + return _addThick!! + } + +private var _addThick: ImageVector? = null + +@Preview +@Composable +private fun Preview() { + Box { + Image( + imageVector = AppIcons.AddThick, + contentDescription = null, + modifier = Modifier.size(AppImages.previewSize) + ) + } +} diff --git a/app/src/main/java/com/infomaniak/swisstransfer/ui/screen/newtransfer/NewTransferNavHost.kt b/app/src/main/java/com/infomaniak/swisstransfer/ui/screen/newtransfer/NewTransferNavHost.kt index 12a3530db..f9a0d1a66 100644 --- a/app/src/main/java/com/infomaniak/swisstransfer/ui/screen/newtransfer/NewTransferNavHost.kt +++ b/app/src/main/java/com/infomaniak/swisstransfer/ui/screen/newtransfer/NewTransferNavHost.kt @@ -36,7 +36,6 @@ fun NewTransferNavHost(navController: NavHostController, closeActivity: () -> Un NavHost(navController, NewTransferNavigation.startDestination) { composable { ImportFilesScreen( - navigateToTransferTypeScreen = { navController.navigate(TransferTypeDestination) }, closeActivity = closeActivity, ) } 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 ba400fa79..73289b96e 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 @@ -18,46 +18,61 @@ package com.infomaniak.swisstransfer.ui.screen.newtransfer.importfiles import android.net.Uri +import android.text.format.Formatter import androidx.activity.compose.rememberLauncherForActivityResult import androidx.activity.result.contract.ActivityResultContracts +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.foundation.lazy.LazyRow import androidx.compose.foundation.lazy.items +import androidx.compose.material3.Button +import androidx.compose.material3.ButtonDefaults +import androidx.compose.material3.Icon import androidx.compose.material3.Text import androidx.compose.runtime.* import androidx.compose.runtime.saveable.rememberSaveable +import androidx.compose.ui.Modifier +import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.unit.dp +import androidx.core.net.toUri import androidx.hilt.navigation.compose.hiltViewModel import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.infomaniak.swisstransfer.R import com.infomaniak.swisstransfer.ui.components.* -import com.infomaniak.swisstransfer.ui.images.AppImages.AppIcons -import com.infomaniak.swisstransfer.ui.images.AppImages.AppIllus -import com.infomaniak.swisstransfer.ui.images.icons.Add -import com.infomaniak.swisstransfer.ui.images.illus.MascotWithMagnifyingGlass +import com.infomaniak.swisstransfer.ui.images.AppImages +import com.infomaniak.swisstransfer.ui.images.icons.AddThick +import com.infomaniak.swisstransfer.ui.images.icons.ChevronRightSmall import com.infomaniak.swisstransfer.ui.screen.newtransfer.NewTransferViewModel import com.infomaniak.swisstransfer.ui.screen.newtransfer.TransferFile +import com.infomaniak.swisstransfer.ui.theme.Margin +import com.infomaniak.swisstransfer.ui.theme.Shapes import com.infomaniak.swisstransfer.ui.theme.SwissTransferTheme import com.infomaniak.swisstransfer.ui.utils.PreviewLargeWindow import com.infomaniak.swisstransfer.ui.utils.PreviewSmallWindow +private const val TOTAL_FILE_SIZE: Long = 50_000_000_000 + @Composable fun ImportFilesScreen( newTransferViewModel: NewTransferViewModel = hiltViewModel(), - navigateToTransferTypeScreen: () -> Unit, closeActivity: () -> Unit, ) { val transferFiles by newTransferViewModel.transferFiles.collectAsStateWithLifecycle() - ImportFilesScreen({ transferFiles }, newTransferViewModel::addFiles, navigateToTransferTypeScreen, closeActivity) + ImportFilesScreen({ transferFiles }, newTransferViewModel::addFiles, closeActivity) } @Composable private fun ImportFilesScreen( transferFiles: () -> List, addFiles: (List) -> Unit, - navigateToTransferTypeScreen: () -> Unit, closeActivity: () -> Unit, ) { var showUploadSourceChoiceBottomSheet by rememberSaveable { mutableStateOf(true) } - val isNextButtonEnabled by remember { derivedStateOf { transferFiles().isNotEmpty() } } + val fileCount by remember { derivedStateOf { transferFiles().count() } } + val totalFileSize by remember { derivedStateOf { transferFiles().sumOf { it.size } } } + val isSendButtonEnabled by remember { derivedStateOf { transferFiles().isNotEmpty() } } val filePickerLauncher = rememberLauncherForActivityResult( contract = ActivityResultContracts.OpenMultipleDocuments() @@ -76,28 +91,49 @@ private fun ImportFilesScreen( topButton = { modifier -> LargeButton( modifier = modifier, - titleRes = R.string.buttonAddFiles, - imageVector = AppIcons.Add, - style = ButtonType.TERTIARY, - onClick = { showUploadSourceChoiceBottomSheet = true }, - ) - }, - bottomButton = { modifier -> - LargeButton( - modifier = modifier, - titleRes = R.string.buttonNext, - enabled = isNextButtonEnabled, - onClick = { navigateToTransferTypeScreen() }, + titleRes = R.string.sentTitle, // TODO + style = ButtonType.PRIMARY, + enabled = isSendButtonEnabled, // TODO: Worth passing as lambda? + onClick = { /*TODO*/ }, ) }, content = { - if (transferFiles().isEmpty()) { - EmptyState( - icon = AppIllus.MascotWithMagnifyingGlass, - title = R.string.noFileTitle, - description = R.string.noFileDescription, - ) - } else { + SwissTransferCard(Modifier.padding(Margin.Medium)) { + SharpRippleButton(onClick = { /*TODO*/ }) { + Text( + "${fileCount} files", // TODO + modifier = Modifier.padding(start = Margin.Medium), + color = SwissTransferTheme.colors.secondaryTextColor, + ) + Text( + "•", + modifier = Modifier.padding(horizontal = Margin.Small), + color = SwissTransferTheme.colors.secondaryTextColor + ) + Text( + "${formatSpaceLeft(totalFileSize)} left", // TODO + color = SwissTransferTheme.colors.secondaryTextColor + ) + Spacer(modifier = Modifier.weight(1f)) + Icon( + imageVector = AppImages.AppIcons.ChevronRightSmall, + contentDescription = null, + modifier = Modifier.padding(Margin.Medium), + tint = SwissTransferTheme.colors.iconColor + ) + } + + LazyRow( + Modifier + .padding(horizontal = Margin.Medium) + .padding(bottom = Margin.Medium) + ) { + item { + AddNewFileButton { showUploadSourceChoiceBottomSheet = true } + } + } + + LazyColumn { items(items = transferFiles(), key = { it.fileName }) { file -> Text(text = "${file.fileName} - ${file.size}") @@ -114,11 +150,44 @@ private fun ImportFilesScreen( ) } +@Composable +private fun AddNewFileButton(onClick: () -> Unit) { + Button( + modifier = Modifier.size(80.dp), + shape = Shapes.medium, + colors = ButtonDefaults.buttonColors( + containerColor = SwissTransferTheme.materialColors.surface, + contentColor = SwissTransferTheme.materialColors.primary, + ), + onClick = onClick, + ) { + Icon( + modifier = Modifier.size(24.dp), + imageVector = AppImages.AppIcons.AddThick, + contentDescription = null, + ) + } +} + +@Composable +private fun formatSpaceLeft(usedSpace: Long): String { + val spaceLeft = TOTAL_FILE_SIZE - usedSpace + return Formatter.formatShortFileSize(LocalContext.current, spaceLeft) +} + @PreviewSmallWindow @PreviewLargeWindow @Composable private fun ImportFilesScreenPreview() { SwissTransferTheme { - ImportFilesScreen({ emptyList() }, {}, navigateToTransferTypeScreen = {}, closeActivity = {}) + ImportFilesScreen({ + listOf( + TransferFile( + "Time-Clock-Circle--Streamline-Ultimate.svg (1).svg", + 234567832, + "https://fastly.picsum.photos/id/1/200/300.jpg".toUri() + ) + ) + }, {}, closeActivity = {}) } } From 5436a1a687b011107a57e1b3630f306b6f3bf1aa Mon Sep 17 00:00:00 2001 From: Gibran Chevalley Date: Thu, 10 Oct 2024 13:07:58 +0200 Subject: [PATCH 02/27] Display the list of picked files using SmallFileTile --- .../ui/components/CrossCircleButton.kt | 78 ++++++++++++ .../swisstransfer/ui/components/FileIcon.kt | 47 +++++++ .../swisstransfer/ui/components/FileItem.kt | 48 +------ .../ui/components/SmallFileTile.kt | 119 ++++++++++++++++++ .../newtransfer/NewTransferViewModel.kt | 5 +- .../newtransfer/TransferFilesManager.kt | 15 ++- .../importfiles/ImportFilesScreen.kt | 39 +++--- 7 files changed, 278 insertions(+), 73 deletions(-) create mode 100644 app/src/main/java/com/infomaniak/swisstransfer/ui/components/CrossCircleButton.kt create mode 100644 app/src/main/java/com/infomaniak/swisstransfer/ui/components/FileIcon.kt create mode 100644 app/src/main/java/com/infomaniak/swisstransfer/ui/components/SmallFileTile.kt diff --git a/app/src/main/java/com/infomaniak/swisstransfer/ui/components/CrossCircleButton.kt b/app/src/main/java/com/infomaniak/swisstransfer/ui/components/CrossCircleButton.kt new file mode 100644 index 000000000..d5022f0d5 --- /dev/null +++ b/app/src/main/java/com/infomaniak/swisstransfer/ui/components/CrossCircleButton.kt @@ -0,0 +1,78 @@ +/* + * 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.layout.* +import androidx.compose.foundation.shape.CircleShape +import androidx.compose.material3.* +import androidx.compose.runtime.Composable +import androidx.compose.runtime.CompositionLocalProvider +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.unit.Dp +import androidx.compose.ui.unit.coerceAtLeast +import androidx.compose.ui.unit.dp +import com.infomaniak.swisstransfer.R +import com.infomaniak.swisstransfer.ui.images.AppImages +import com.infomaniak.swisstransfer.ui.images.icons.CrossThick +import com.infomaniak.swisstransfer.ui.theme.Margin +import com.infomaniak.swisstransfer.ui.theme.SwissTransferTheme +import com.infomaniak.swisstransfer.ui.utils.PreviewLargeWindow +import com.infomaniak.swisstransfer.ui.utils.PreviewSmallWindow + +@Composable +@OptIn(ExperimentalMaterial3Api::class) +fun BoxScope.CrossCircleButton(onClick: (() -> Unit)?, size: Dp = 48.dp) { + CompositionLocalProvider(LocalRippleConfiguration provides RippleConfiguration(color = Color.White)) { + val buttonPadding = ((size - 24.dp) / 2f).coerceAtLeast(0.dp) + + Button( + modifier = Modifier + .size(size) + .padding(buttonPadding) + .align(Alignment.TopEnd), + contentPadding = PaddingValues(0.dp), + shape = CircleShape, + colors = ButtonDefaults.buttonColors(containerColor = SwissTransferTheme.colors.fileItemRemoveButtonBackground), + onClick = onClick ?: {}, + ) { + Icon( + modifier = Modifier.size(Margin.Small), + imageVector = AppImages.AppIcons.CrossThick, + contentDescription = stringResource(R.string.contentDescriptionButtonRemove), + tint = Color.White + ) + } + } +} + + +@PreviewSmallWindow +@PreviewLargeWindow +@Composable +private fun CrossCircleButtonPreview() { + SwissTransferTheme { + Surface { + Box { + CrossCircleButton({}) + } + } + } +} diff --git a/app/src/main/java/com/infomaniak/swisstransfer/ui/components/FileIcon.kt b/app/src/main/java/com/infomaniak/swisstransfer/ui/components/FileIcon.kt new file mode 100644 index 000000000..316ff239d --- /dev/null +++ b/app/src/main/java/com/infomaniak/swisstransfer/ui/components/FileIcon.kt @@ -0,0 +1,47 @@ +/* + * 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.Canvas +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.size +import androidx.compose.material3.Icon +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.unit.Dp +import com.infomaniak.library.filetypes.FileType +import com.infomaniak.swisstransfer.ui.theme.LocalIsDarkMode + +@Composable +fun FileIcon(fileType: FileType, color: Color, circleSize: Dp) { + Box(contentAlignment = Alignment.Center, modifier = Modifier.fillMaxSize()) { + Canvas(modifier = Modifier.size(circleSize)) { + drawCircle(color = color) + } + + Icon( + modifier = Modifier.size(circleSize / 2), + imageVector = fileType.icon, + contentDescription = null, + tint = fileType.color(LocalIsDarkMode.current) + ) + } +} diff --git a/app/src/main/java/com/infomaniak/swisstransfer/ui/components/FileItem.kt b/app/src/main/java/com/infomaniak/swisstransfer/ui/components/FileItem.kt index f36ce4b38..246a6e7b0 100644 --- a/app/src/main/java/com/infomaniak/swisstransfer/ui/components/FileItem.kt +++ b/app/src/main/java/com/infomaniak/swisstransfer/ui/components/FileItem.kt @@ -20,29 +20,20 @@ package com.infomaniak.swisstransfer.ui.components import android.net.Uri import android.text.format.Formatter import androidx.compose.foundation.BorderStroke -import androidx.compose.foundation.Canvas import androidx.compose.foundation.background import androidx.compose.foundation.layout.* -import androidx.compose.foundation.shape.CircleShape import androidx.compose.material3.* import androidx.compose.runtime.* import androidx.compose.runtime.saveable.rememberSaveable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import androidx.compose.ui.graphics.Color import androidx.compose.ui.layout.ContentScale import androidx.compose.ui.platform.LocalContext -import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp import androidx.core.net.toUri import coil.compose.AsyncImage import coil.request.ImageRequest -import com.infomaniak.library.filetypes.FileType -import com.infomaniak.swisstransfer.R -import com.infomaniak.swisstransfer.ui.images.AppImages -import com.infomaniak.swisstransfer.ui.images.icons.CrossThick -import com.infomaniak.swisstransfer.ui.theme.LocalIsDarkMode import com.infomaniak.swisstransfer.ui.theme.Margin import com.infomaniak.swisstransfer.ui.theme.Shapes import com.infomaniak.swisstransfer.ui.theme.SwissTransferTheme @@ -76,7 +67,7 @@ fun FileItem( if (displayPreview) { FileThumbnail(file.uri.toUri(), onError = { displayPreview = false }) } else { - FileIcon(file.fileType) + FileIcon(file.fileType, color = SwissTransferTheme.materialColors.surface, circleSize = 64.dp) } }, onClick = onClick, @@ -125,25 +116,7 @@ private fun FileItemContent( ) } - if (isRemoveButtonVisible) { - Button( - modifier = Modifier - .size(Margin.XXLarge) - .padding(12.dp) - .align(Alignment.TopEnd), - contentPadding = PaddingValues(0.dp), - shape = CircleShape, - colors = ButtonDefaults.buttonColors(containerColor = SwissTransferTheme.colors.fileItemRemoveButtonBackground), - onClick = onRemove ?: {}, - ) { - Icon( - modifier = Modifier.size(Margin.Small), - imageVector = AppImages.AppIcons.CrossThick, - contentDescription = stringResource(R.string.contentDescriptionButtonRemove), - tint = Color.White - ) - } - } + if (isRemoveButtonVisible) CrossCircleButton(onClick = onRemove) } Column(Modifier.padding(Margin.Small)) { @@ -179,23 +152,6 @@ private fun FileThumbnail(uri: Uri, onError: () -> Unit) { ) } -@Composable -private fun FileIcon(fileType: FileType) { - Box(contentAlignment = Alignment.Center, modifier = Modifier.fillMaxSize()) { - val surfaceColor = SwissTransferTheme.materialColors.surface - Canvas(modifier = Modifier.size(64.dp)) { - drawCircle(color = surfaceColor) - } - - Icon( - modifier = Modifier.size(32.dp), - imageVector = fileType.icon, - contentDescription = null, - tint = fileType.color(LocalIsDarkMode.current) - ) - } -} - @PreviewSmallWindow @PreviewLargeWindow @Composable diff --git a/app/src/main/java/com/infomaniak/swisstransfer/ui/components/SmallFileTile.kt b/app/src/main/java/com/infomaniak/swisstransfer/ui/components/SmallFileTile.kt new file mode 100644 index 000000000..658302353 --- /dev/null +++ b/app/src/main/java/com/infomaniak/swisstransfer/ui/components/SmallFileTile.kt @@ -0,0 +1,119 @@ +/* + * 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.Surface +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.Modifier +import androidx.compose.ui.draw.clip +import androidx.compose.ui.graphics.Shape +import androidx.compose.ui.layout.ContentScale +import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.unit.Dp +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.times +import coil.compose.AsyncImage +import coil.request.ImageRequest +import com.infomaniak.swisstransfer.ui.theme.Shapes +import com.infomaniak.swisstransfer.ui.theme.SwissTransferTheme +import com.infomaniak.swisstransfer.ui.utils.PreviewLargeWindow +import com.infomaniak.swisstransfer.ui.utils.PreviewSmallWindow +import com.infomaniak.swisstransfer.ui.utils.fileType +import com.infomaniak.swisstransfer.ui.utils.hasPreview + +@Composable +fun SmallFileTile(file: FileUiItem, smallFileTileSize: SmallFileTileSize, onRemove: (() -> Unit)? = null) { + var displayPreview by rememberSaveable { mutableStateOf(file.hasPreview) } + + Box( + Modifier + .size(smallFileTileSize.size) + .clip(smallFileTileSize.shape) + .background(SwissTransferTheme.materialColors.surface), + ) { + if (displayPreview) { + AsyncImage( + model = ImageRequest.Builder(LocalContext.current) + .data(file.uri) + .crossfade(true) + .build(), + contentDescription = null, + contentScale = ContentScale.Crop, + onError = { displayPreview = false }, + modifier = Modifier.fillMaxSize(), + ) + } else { + FileIcon( + file.fileType, + color = SwissTransferTheme.materialColors.surfaceContainerHighest, + circleSize = smallFileTileSize.iconCircleSize(), + ) + } + + onRemove?.let { CrossCircleButton(onClick = it, size = 40.dp) } + } +} + +enum class SmallFileTileSize(val size: Dp, val shape: Shape) { + SMALL(48.dp, Shapes.small), + LARGE(80.dp, Shapes.medium); + + fun iconCircleSize(): Dp = 2f / 3 * size +} + +@PreviewSmallWindow +@PreviewLargeWindow +@Composable +private fun SmallFileTilePreview() { + SwissTransferTheme { + Surface(color = SwissTransferTheme.materialColors.surfaceContainerHighest) { + Column(Modifier.padding(16.dp)) { + SmallFileTile( + object : FileUiItem { + override val fileName: String = "How to not get fired.pdf" + override val uid: String = fileName + override val fileSizeInBytes: Long = 10302130 + override val mimeType: String? = null + override val uri: String = "" + }, + SmallFileTileSize.LARGE, + {} + ) + + Spacer(modifier = Modifier.height(16.dp)) + + SmallFileTile( + object : FileUiItem { + override val fileName: String = "How to not get fired.pdf" + override val uid: String = fileName + override val fileSizeInBytes: Long = 10302130 + override val mimeType: String? = null + override val uri: String = "" + }, + SmallFileTileSize.SMALL, + ) + } + } + } +} diff --git a/app/src/main/java/com/infomaniak/swisstransfer/ui/screen/newtransfer/NewTransferViewModel.kt b/app/src/main/java/com/infomaniak/swisstransfer/ui/screen/newtransfer/NewTransferViewModel.kt index bc9fecf33..f4e453101 100644 --- a/app/src/main/java/com/infomaniak/swisstransfer/ui/screen/newtransfer/NewTransferViewModel.kt +++ b/app/src/main/java/com/infomaniak/swisstransfer/ui/screen/newtransfer/NewTransferViewModel.kt @@ -20,6 +20,7 @@ package com.infomaniak.swisstransfer.ui.screen.newtransfer import android.net.Uri import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope +import com.infomaniak.swisstransfer.ui.components.FileUiItem import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.flow.MutableSharedFlow import kotlinx.coroutines.flow.MutableStateFlow @@ -31,8 +32,8 @@ import javax.inject.Inject @HiltViewModel class NewTransferViewModel @Inject constructor(private val transferFilesManager: TransferFilesManager) : ViewModel() { - private val _transferFiles = MutableStateFlow>(emptyList()) - val transferFiles: StateFlow> = _transferFiles + private val _transferFiles = MutableStateFlow>(emptyList()) + val transferFiles: StateFlow> = _transferFiles private val _failedTransferFileCount = MutableSharedFlow() val failedTransferFileCount: SharedFlow = _failedTransferFileCount diff --git a/app/src/main/java/com/infomaniak/swisstransfer/ui/screen/newtransfer/TransferFilesManager.kt b/app/src/main/java/com/infomaniak/swisstransfer/ui/screen/newtransfer/TransferFilesManager.kt index 71ee71b60..2cf2b3cff 100644 --- a/app/src/main/java/com/infomaniak/swisstransfer/ui/screen/newtransfer/TransferFilesManager.kt +++ b/app/src/main/java/com/infomaniak/swisstransfer/ui/screen/newtransfer/TransferFilesManager.kt @@ -22,6 +22,7 @@ import android.content.Context import android.database.Cursor import android.net.Uri import android.provider.OpenableColumns +import com.infomaniak.swisstransfer.ui.components.FileUiItem import com.infomaniak.swisstransfer.ui.utils.FileNameUtils import dagger.hilt.android.qualifiers.ApplicationContext import javax.inject.Inject @@ -29,9 +30,9 @@ import javax.inject.Singleton @Singleton class TransferFilesManager @Inject constructor(@ApplicationContext private val appContext: Context) { - fun getTransferFiles(uris: List, alreadyUsedFileNames: Set): MutableSet { + fun getTransferFiles(uris: List, alreadyUsedFileNames: Set): MutableSet { val currentUsedFileNames = alreadyUsedFileNames.toMutableSet() - val transferFiles = mutableSetOf() + val transferFiles = mutableSetOf() uris.forEach { uri -> getTransferFile(uri, currentUsedFileNames)?.let { transferFile -> @@ -43,13 +44,19 @@ class TransferFilesManager @Inject constructor(@ApplicationContext private val a return transferFiles } - private fun getTransferFile(uri: Uri, alreadyUsedFileNames: Set): TransferFile? { + private fun getTransferFile(uri: Uri, alreadyUsedFileNames: Set): FileUiItem? { val contentResolver: ContentResolver = appContext.contentResolver val cursor: Cursor? = contentResolver.query(uri, null, null, null, null) return cursor?.getFileNameAndSize()?.let { (name, size) -> val uniqueName = FileNameUtils.postfixExistingFileNames(name, alreadyUsedFileNames) - TransferFile(uniqueName, size, uri) + object: FileUiItem { + override val fileName: String = uniqueName + override val uid: String = fileName + override val fileSizeInBytes: Long = size + override val mimeType: String? = null + override val uri: String = uri.toString() + } } } 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 73289b96e..eeefb9a46 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 @@ -21,10 +21,7 @@ import android.net.Uri import android.text.format.Formatter import androidx.activity.compose.rememberLauncherForActivityResult import androidx.activity.result.contract.ActivityResultContracts -import androidx.compose.foundation.layout.Spacer -import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.layout.size -import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.foundation.layout.* import androidx.compose.foundation.lazy.LazyRow import androidx.compose.foundation.lazy.items import androidx.compose.material3.Button @@ -36,7 +33,6 @@ import androidx.compose.runtime.saveable.rememberSaveable import androidx.compose.ui.Modifier import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.unit.dp -import androidx.core.net.toUri import androidx.hilt.navigation.compose.hiltViewModel import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.infomaniak.swisstransfer.R @@ -45,7 +41,6 @@ import com.infomaniak.swisstransfer.ui.images.AppImages import com.infomaniak.swisstransfer.ui.images.icons.AddThick import com.infomaniak.swisstransfer.ui.images.icons.ChevronRightSmall import com.infomaniak.swisstransfer.ui.screen.newtransfer.NewTransferViewModel -import com.infomaniak.swisstransfer.ui.screen.newtransfer.TransferFile import com.infomaniak.swisstransfer.ui.theme.Margin import com.infomaniak.swisstransfer.ui.theme.Shapes import com.infomaniak.swisstransfer.ui.theme.SwissTransferTheme @@ -65,13 +60,13 @@ fun ImportFilesScreen( @Composable private fun ImportFilesScreen( - transferFiles: () -> List, + transferFiles: () -> List, addFiles: (List) -> Unit, closeActivity: () -> Unit, ) { var showUploadSourceChoiceBottomSheet by rememberSaveable { mutableStateOf(true) } val fileCount by remember { derivedStateOf { transferFiles().count() } } - val totalFileSize by remember { derivedStateOf { transferFiles().sumOf { it.size } } } + val totalFileSize by remember { derivedStateOf { transferFiles().sumOf { it.fileSizeInBytes } } } val isSendButtonEnabled by remember { derivedStateOf { transferFiles().isNotEmpty() } } val filePickerLauncher = rememberLauncherForActivityResult( @@ -124,19 +119,19 @@ private fun ImportFilesScreen( } LazyRow( - Modifier - .padding(horizontal = Margin.Medium) - .padding(bottom = Margin.Medium) + Modifier.padding(bottom = Margin.Medium), + contentPadding = PaddingValues(Margin.Medium), + horizontalArrangement = Arrangement.spacedBy(Margin.Medium) ) { item { AddNewFileButton { showUploadSourceChoiceBottomSheet = true } } - } - - LazyColumn { - items(items = transferFiles(), key = { it.fileName }) { file -> - Text(text = "${file.fileName} - ${file.size}") + items( + items = transferFiles(), + key = { it.uid }, + ) { file -> + SmallFileTile(file, SmallFileTileSize.LARGE) {/*TODO*/ } } } } @@ -182,11 +177,13 @@ private fun ImportFilesScreenPreview() { SwissTransferTheme { ImportFilesScreen({ listOf( - TransferFile( - "Time-Clock-Circle--Streamline-Ultimate.svg (1).svg", - 234567832, - "https://fastly.picsum.photos/id/1/200/300.jpg".toUri() - ) + object : FileUiItem { + override val uid = "" + override val fileName = "Time-Clock-Circle--Streamline-Ultimate.svg (1).svg" + override val fileSizeInBytes = 234567832L + override val mimeType = null + override val uri = "https://fastly.picsum.photos/id/1/200/300.jpg" + } ) }, {}, closeActivity = {}) } From 4f88a8279988e203be36d792dfca81a369c6d79b Mon Sep 17 00:00:00 2001 From: Gibran Chevalley Date: Thu, 10 Oct 2024 14:10:37 +0200 Subject: [PATCH 03/27] Factorize file preview logic between FileTile and SmallFileTile --- .../swisstransfer/ui/components/FileItem.kt | 34 +++------------ .../{FileIcon.kt => FilePreview.kt} | 41 ++++++++++++++++++- .../ui/components/SmallFileTile.kt | 35 +++------------- 3 files changed, 50 insertions(+), 60 deletions(-) rename app/src/main/java/com/infomaniak/swisstransfer/ui/components/{FileIcon.kt => FilePreview.kt} (57%) diff --git a/app/src/main/java/com/infomaniak/swisstransfer/ui/components/FileItem.kt b/app/src/main/java/com/infomaniak/swisstransfer/ui/components/FileItem.kt index 246a6e7b0..97f2e25a0 100644 --- a/app/src/main/java/com/infomaniak/swisstransfer/ui/components/FileItem.kt +++ b/app/src/main/java/com/infomaniak/swisstransfer/ui/components/FileItem.kt @@ -17,30 +17,22 @@ */ package com.infomaniak.swisstransfer.ui.components -import android.net.Uri import android.text.format.Formatter import androidx.compose.foundation.BorderStroke import androidx.compose.foundation.background import androidx.compose.foundation.layout.* import androidx.compose.material3.* import androidx.compose.runtime.* -import androidx.compose.runtime.saveable.rememberSaveable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import androidx.compose.ui.layout.ContentScale import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp -import androidx.core.net.toUri -import coil.compose.AsyncImage -import coil.request.ImageRequest import com.infomaniak.swisstransfer.ui.theme.Margin import com.infomaniak.swisstransfer.ui.theme.Shapes import com.infomaniak.swisstransfer.ui.theme.SwissTransferTheme import com.infomaniak.swisstransfer.ui.utils.PreviewLargeWindow import com.infomaniak.swisstransfer.ui.utils.PreviewSmallWindow -import com.infomaniak.swisstransfer.ui.utils.fileType -import com.infomaniak.swisstransfer.ui.utils.hasPreview // TODO: Get the interface from the shared kmp code interface FileUiItem { @@ -62,13 +54,11 @@ fun FileItem( ) { FileItemContent( content = { - var displayPreview by rememberSaveable { mutableStateOf(file.hasPreview) } - - if (displayPreview) { - FileThumbnail(file.uri.toUri(), onError = { displayPreview = false }) - } else { - FileIcon(file.fileType, color = SwissTransferTheme.materialColors.surface, circleSize = 64.dp) - } + FilePreview( + file = file, + circleColor = SwissTransferTheme.materialColors.surface, + circleSize = 64.dp, + ) }, onClick = onClick, isCheckboxVisible = isCheckboxVisible, @@ -138,20 +128,6 @@ private fun FileItemContent( } } -@Composable -private fun FileThumbnail(uri: Uri, onError: () -> Unit) { - AsyncImage( - model = ImageRequest.Builder(LocalContext.current) - .data(uri) - .crossfade(true) - .build(), - contentDescription = null, - contentScale = ContentScale.Crop, - onError = { onError() }, - modifier = Modifier.fillMaxSize(), - ) -} - @PreviewSmallWindow @PreviewLargeWindow @Composable diff --git a/app/src/main/java/com/infomaniak/swisstransfer/ui/components/FileIcon.kt b/app/src/main/java/com/infomaniak/swisstransfer/ui/components/FilePreview.kt similarity index 57% rename from app/src/main/java/com/infomaniak/swisstransfer/ui/components/FileIcon.kt rename to app/src/main/java/com/infomaniak/swisstransfer/ui/components/FilePreview.kt index 316ff239d..0bb008c30 100644 --- a/app/src/main/java/com/infomaniak/swisstransfer/ui/components/FileIcon.kt +++ b/app/src/main/java/com/infomaniak/swisstransfer/ui/components/FilePreview.kt @@ -23,15 +23,54 @@ import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.size import androidx.compose.material3.Icon 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.graphics.Color +import androidx.compose.ui.layout.ContentScale +import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.unit.Dp +import coil.compose.AsyncImage +import coil.request.ImageRequest import com.infomaniak.library.filetypes.FileType import com.infomaniak.swisstransfer.ui.theme.LocalIsDarkMode +import com.infomaniak.swisstransfer.ui.utils.fileType +import com.infomaniak.swisstransfer.ui.utils.hasPreview @Composable -fun FileIcon(fileType: FileType, color: Color, circleSize: Dp) { +fun FilePreview( + file: FileUiItem, + circleColor: Color, + circleSize: Dp +) { + var displayPreview by rememberSaveable { mutableStateOf(file.hasPreview) } + + if (displayPreview) { + FileThumbnail(file.uri, onError = { displayPreview = false }) + } else { + FileIcon(file.fileType, circleColor, circleSize) + } +} + +@Composable +private fun FileThumbnail(uri: String, onError: () -> Unit) { + AsyncImage( + model = ImageRequest.Builder(LocalContext.current) + .data(uri) + .crossfade(true) + .build(), + contentDescription = null, + contentScale = ContentScale.Crop, + onError = { onError() }, + modifier = Modifier.fillMaxSize(), + ) +} + +@Composable +private fun FileIcon(fileType: FileType, color: Color, circleSize: Dp) { Box(contentAlignment = Alignment.Center, modifier = Modifier.fillMaxSize()) { Canvas(modifier = Modifier.size(circleSize)) { drawCircle(color = color) diff --git a/app/src/main/java/com/infomaniak/swisstransfer/ui/components/SmallFileTile.kt b/app/src/main/java/com/infomaniak/swisstransfer/ui/components/SmallFileTile.kt index 658302353..6ec567ab1 100644 --- a/app/src/main/java/com/infomaniak/swisstransfer/ui/components/SmallFileTile.kt +++ b/app/src/main/java/com/infomaniak/swisstransfer/ui/components/SmallFileTile.kt @@ -21,55 +21,30 @@ import androidx.compose.foundation.background import androidx.compose.foundation.layout.* import androidx.compose.material3.Surface 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.Modifier import androidx.compose.ui.draw.clip import androidx.compose.ui.graphics.Shape -import androidx.compose.ui.layout.ContentScale -import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.times -import coil.compose.AsyncImage -import coil.request.ImageRequest import com.infomaniak.swisstransfer.ui.theme.Shapes import com.infomaniak.swisstransfer.ui.theme.SwissTransferTheme import com.infomaniak.swisstransfer.ui.utils.PreviewLargeWindow import com.infomaniak.swisstransfer.ui.utils.PreviewSmallWindow -import com.infomaniak.swisstransfer.ui.utils.fileType -import com.infomaniak.swisstransfer.ui.utils.hasPreview @Composable fun SmallFileTile(file: FileUiItem, smallFileTileSize: SmallFileTileSize, onRemove: (() -> Unit)? = null) { - var displayPreview by rememberSaveable { mutableStateOf(file.hasPreview) } - Box( Modifier .size(smallFileTileSize.size) .clip(smallFileTileSize.shape) .background(SwissTransferTheme.materialColors.surface), ) { - if (displayPreview) { - AsyncImage( - model = ImageRequest.Builder(LocalContext.current) - .data(file.uri) - .crossfade(true) - .build(), - contentDescription = null, - contentScale = ContentScale.Crop, - onError = { displayPreview = false }, - modifier = Modifier.fillMaxSize(), - ) - } else { - FileIcon( - file.fileType, - color = SwissTransferTheme.materialColors.surfaceContainerHighest, - circleSize = smallFileTileSize.iconCircleSize(), - ) - } + FilePreview( + file = file, + circleColor = SwissTransferTheme.materialColors.surfaceContainerHighest, + circleSize = smallFileTileSize.iconCircleSize(), + ) onRemove?.let { CrossCircleButton(onClick = it, size = 40.dp) } } From 7387299b12964f8a35c4f7f9a9d9ee2f25663ede Mon Sep 17 00:00:00 2001 From: Gibran Chevalley Date: Thu, 10 Oct 2024 14:31:03 +0200 Subject: [PATCH 04/27] Remove old TransferFile names from methods and variables --- .../newtransfer/NewTransferViewModel.kt | 16 +++++++------- .../ui/screen/newtransfer/TransferFile.kt | 22 ------------------- .../newtransfer/TransferFilesManager.kt | 14 ++++++------ .../importfiles/ImportFilesScreen.kt | 14 ++++++------ 4 files changed, 22 insertions(+), 44 deletions(-) delete mode 100644 app/src/main/java/com/infomaniak/swisstransfer/ui/screen/newtransfer/TransferFile.kt diff --git a/app/src/main/java/com/infomaniak/swisstransfer/ui/screen/newtransfer/NewTransferViewModel.kt b/app/src/main/java/com/infomaniak/swisstransfer/ui/screen/newtransfer/NewTransferViewModel.kt index f4e453101..f51ce0b3d 100644 --- a/app/src/main/java/com/infomaniak/swisstransfer/ui/screen/newtransfer/NewTransferViewModel.kt +++ b/app/src/main/java/com/infomaniak/swisstransfer/ui/screen/newtransfer/NewTransferViewModel.kt @@ -32,20 +32,20 @@ import javax.inject.Inject @HiltViewModel class NewTransferViewModel @Inject constructor(private val transferFilesManager: TransferFilesManager) : ViewModel() { - private val _transferFiles = MutableStateFlow>(emptyList()) - val transferFiles: StateFlow> = _transferFiles + private val _files = MutableStateFlow>(emptyList()) + val files: StateFlow> = _files - private val _failedTransferFileCount = MutableSharedFlow() - val failedTransferFileCount: SharedFlow = _failedTransferFileCount + private val _failedFileCount = MutableSharedFlow() + val failedFileCount: SharedFlow = _failedFileCount fun addFiles(uris: List) { viewModelScope.launch { - val alreadyUsedFileNames = buildSet { transferFiles.value.forEach { add(it.fileName) } } + val alreadyUsedFileNames = buildSet { files.value.forEach { add(it.fileName) } } - val newTransferFiles = transferFilesManager.getTransferFiles(uris, alreadyUsedFileNames) + val newFiles = transferFilesManager.getFiles(uris, alreadyUsedFileNames) - _transferFiles.value += newTransferFiles - _failedTransferFileCount.emit(uris.count() - newTransferFiles.count()) + _files.value += newFiles + _failedFileCount.emit(uris.count() - newFiles.count()) } } } diff --git a/app/src/main/java/com/infomaniak/swisstransfer/ui/screen/newtransfer/TransferFile.kt b/app/src/main/java/com/infomaniak/swisstransfer/ui/screen/newtransfer/TransferFile.kt deleted file mode 100644 index e1e98d815..000000000 --- a/app/src/main/java/com/infomaniak/swisstransfer/ui/screen/newtransfer/TransferFile.kt +++ /dev/null @@ -1,22 +0,0 @@ -/* - * 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.screen.newtransfer - -import android.net.Uri - -data class TransferFile(val fileName: String, val size: Long, val uri: Uri) diff --git a/app/src/main/java/com/infomaniak/swisstransfer/ui/screen/newtransfer/TransferFilesManager.kt b/app/src/main/java/com/infomaniak/swisstransfer/ui/screen/newtransfer/TransferFilesManager.kt index 2cf2b3cff..bb1c3fb2a 100644 --- a/app/src/main/java/com/infomaniak/swisstransfer/ui/screen/newtransfer/TransferFilesManager.kt +++ b/app/src/main/java/com/infomaniak/swisstransfer/ui/screen/newtransfer/TransferFilesManager.kt @@ -30,21 +30,21 @@ import javax.inject.Singleton @Singleton class TransferFilesManager @Inject constructor(@ApplicationContext private val appContext: Context) { - fun getTransferFiles(uris: List, alreadyUsedFileNames: Set): MutableSet { + fun getFiles(uris: List, alreadyUsedFileNames: Set): MutableSet { val currentUsedFileNames = alreadyUsedFileNames.toMutableSet() - val transferFiles = mutableSetOf() + val files = mutableSetOf() uris.forEach { uri -> - getTransferFile(uri, currentUsedFileNames)?.let { transferFile -> - currentUsedFileNames += transferFile.fileName - transferFiles += transferFile + getFile(uri, currentUsedFileNames)?.let { file -> + currentUsedFileNames += file.fileName + files += file } } - return transferFiles + return files } - private fun getTransferFile(uri: Uri, alreadyUsedFileNames: Set): FileUiItem? { + private fun getFile(uri: Uri, alreadyUsedFileNames: Set): FileUiItem? { val contentResolver: ContentResolver = appContext.contentResolver val cursor: Cursor? = contentResolver.query(uri, null, null, null, null) 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 eeefb9a46..3eca1ec5d 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 @@ -54,20 +54,20 @@ fun ImportFilesScreen( newTransferViewModel: NewTransferViewModel = hiltViewModel(), closeActivity: () -> Unit, ) { - val transferFiles by newTransferViewModel.transferFiles.collectAsStateWithLifecycle() - ImportFilesScreen({ transferFiles }, newTransferViewModel::addFiles, closeActivity) + val files by newTransferViewModel.files.collectAsStateWithLifecycle() + ImportFilesScreen({ files }, newTransferViewModel::addFiles, closeActivity) } @Composable private fun ImportFilesScreen( - transferFiles: () -> List, + files: () -> List, addFiles: (List) -> Unit, closeActivity: () -> Unit, ) { var showUploadSourceChoiceBottomSheet by rememberSaveable { mutableStateOf(true) } - val fileCount by remember { derivedStateOf { transferFiles().count() } } - val totalFileSize by remember { derivedStateOf { transferFiles().sumOf { it.fileSizeInBytes } } } - val isSendButtonEnabled by remember { derivedStateOf { transferFiles().isNotEmpty() } } + val fileCount by remember { derivedStateOf { files().count() } } + val totalFileSize by remember { derivedStateOf { files().sumOf { it.fileSizeInBytes } } } + val isSendButtonEnabled by remember { derivedStateOf { files().isNotEmpty() } } val filePickerLauncher = rememberLauncherForActivityResult( contract = ActivityResultContracts.OpenMultipleDocuments() @@ -128,7 +128,7 @@ private fun ImportFilesScreen( } items( - items = transferFiles(), + items = files(), key = { it.uid }, ) { file -> SmallFileTile(file, SmallFileTileSize.LARGE) {/*TODO*/ } From 255b4f088f46cd517b05cba251aee3c4af207eb5 Mon Sep 17 00:00:00 2001 From: Gibran Chevalley Date: Thu, 10 Oct 2024 15:23:15 +0200 Subject: [PATCH 05/27] Remove imported files when clicking the remove button and animate it all --- app/build.gradle.kts | 1 + .../ui/components/SmallFileTile.kt | 14 ++++---- .../newtransfer/NewTransferViewModel.kt | 4 +++ .../importfiles/ImportFilesScreen.kt | 36 ++++++++++++++----- 4 files changed, 39 insertions(+), 16 deletions(-) diff --git a/app/build.gradle.kts b/app/build.gradle.kts index bb697e9e7..125cc9580 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -4,6 +4,7 @@ plugins { alias(libs.plugins.compose.compiler) alias(libs.plugins.kapt) alias(libs.plugins.hilt) + id("kotlin-parcelize") kotlin("plugin.serialization") version libs.versions.kotlin } diff --git a/app/src/main/java/com/infomaniak/swisstransfer/ui/components/SmallFileTile.kt b/app/src/main/java/com/infomaniak/swisstransfer/ui/components/SmallFileTile.kt index 6ec567ab1..07ab5d340 100644 --- a/app/src/main/java/com/infomaniak/swisstransfer/ui/components/SmallFileTile.kt +++ b/app/src/main/java/com/infomaniak/swisstransfer/ui/components/SmallFileTile.kt @@ -33,9 +33,9 @@ import com.infomaniak.swisstransfer.ui.utils.PreviewLargeWindow import com.infomaniak.swisstransfer.ui.utils.PreviewSmallWindow @Composable -fun SmallFileTile(file: FileUiItem, smallFileTileSize: SmallFileTileSize, onRemove: (() -> Unit)? = null) { +fun SmallFileTile(modifier: Modifier = Modifier, file: FileUiItem, smallFileTileSize: SmallFileTileSize, onRemove: (() -> Unit)? = null) { Box( - Modifier + modifier .size(smallFileTileSize.size) .clip(smallFileTileSize.shape) .background(SwissTransferTheme.materialColors.surface), @@ -65,28 +65,28 @@ private fun SmallFileTilePreview() { Surface(color = SwissTransferTheme.materialColors.surfaceContainerHighest) { Column(Modifier.padding(16.dp)) { SmallFileTile( - object : FileUiItem { + file = object : FileUiItem { override val fileName: String = "How to not get fired.pdf" override val uid: String = fileName override val fileSizeInBytes: Long = 10302130 override val mimeType: String? = null override val uri: String = "" }, - SmallFileTileSize.LARGE, - {} + smallFileTileSize = SmallFileTileSize.LARGE, + onRemove = {} ) Spacer(modifier = Modifier.height(16.dp)) SmallFileTile( - object : FileUiItem { + file = object : FileUiItem { override val fileName: String = "How to not get fired.pdf" override val uid: String = fileName override val fileSizeInBytes: Long = 10302130 override val mimeType: String? = null override val uri: String = "" }, - SmallFileTileSize.SMALL, + smallFileTileSize = SmallFileTileSize.SMALL, ) } } diff --git a/app/src/main/java/com/infomaniak/swisstransfer/ui/screen/newtransfer/NewTransferViewModel.kt b/app/src/main/java/com/infomaniak/swisstransfer/ui/screen/newtransfer/NewTransferViewModel.kt index f51ce0b3d..01029191c 100644 --- a/app/src/main/java/com/infomaniak/swisstransfer/ui/screen/newtransfer/NewTransferViewModel.kt +++ b/app/src/main/java/com/infomaniak/swisstransfer/ui/screen/newtransfer/NewTransferViewModel.kt @@ -48,4 +48,8 @@ class NewTransferViewModel @Inject constructor(private val transferFilesManager: _failedFileCount.emit(uris.count() - newFiles.count()) } } + + fun removeFileByUid(uid: String) { + _files.value = _files.value.filterNot { it.uid == uid } + } } 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 3eca1ec5d..3b10753b5 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 @@ -18,6 +18,7 @@ package com.infomaniak.swisstransfer.ui.screen.newtransfer.importfiles import android.net.Uri +import android.os.Parcelable import android.text.format.Formatter import androidx.activity.compose.rememberLauncherForActivityResult import androidx.activity.result.contract.ActivityResultContracts @@ -46,6 +47,7 @@ import com.infomaniak.swisstransfer.ui.theme.Shapes import com.infomaniak.swisstransfer.ui.theme.SwissTransferTheme import com.infomaniak.swisstransfer.ui.utils.PreviewLargeWindow import com.infomaniak.swisstransfer.ui.utils.PreviewSmallWindow +import kotlinx.parcelize.Parcelize private const val TOTAL_FILE_SIZE: Long = 50_000_000_000 @@ -55,12 +57,13 @@ fun ImportFilesScreen( closeActivity: () -> Unit, ) { val files by newTransferViewModel.files.collectAsStateWithLifecycle() - ImportFilesScreen({ files }, newTransferViewModel::addFiles, closeActivity) + ImportFilesScreen({ files }, newTransferViewModel::removeFileByUid, newTransferViewModel::addFiles, closeActivity) } @Composable private fun ImportFilesScreen( files: () -> List, + removeFileByUid: (uid: String) -> Unit, addFiles: (List) -> Unit, closeActivity: () -> Unit, ) { @@ -119,19 +122,24 @@ private fun ImportFilesScreen( } LazyRow( - Modifier.padding(bottom = Margin.Medium), + Modifier.fillMaxWidth(), contentPadding = PaddingValues(Margin.Medium), horizontalArrangement = Arrangement.spacedBy(Margin.Medium) ) { - item { - AddNewFileButton { showUploadSourceChoiceBottomSheet = true } + item(key = TransferLazyRowKey(TransferLazyRowKey.Type.ADD_BUTTON)) { + AddNewFileButton(Modifier.animateItem()) { showUploadSourceChoiceBottomSheet = true } } items( items = files(), - key = { it.uid }, + key = { TransferLazyRowKey(TransferLazyRowKey.Type.FILE, it.uid) }, ) { file -> - SmallFileTile(file, SmallFileTileSize.LARGE) {/*TODO*/ } + SmallFileTile( + modifier = Modifier.animateItem(), + file = file, + smallFileTileSize = SmallFileTileSize.LARGE, + onRemove = { removeFileByUid(file.uid) } + ) } } } @@ -146,9 +154,9 @@ private fun ImportFilesScreen( } @Composable -private fun AddNewFileButton(onClick: () -> Unit) { +private fun AddNewFileButton(modifier: Modifier = Modifier, onClick: () -> Unit) { Button( - modifier = Modifier.size(80.dp), + modifier = modifier.size(80.dp), shape = Shapes.medium, colors = ButtonDefaults.buttonColors( containerColor = SwissTransferTheme.materialColors.surface, @@ -170,6 +178,16 @@ private fun formatSpaceLeft(usedSpace: Long): String { return Formatter.formatShortFileSize(LocalContext.current, spaceLeft) } +@Parcelize +private data class TransferLazyRowKey( + val type: Type, + val fileUid: String? = null +) : Parcelable { + enum class Type { + ADD_BUTTON, FILE + } +} + @PreviewSmallWindow @PreviewLargeWindow @Composable @@ -185,6 +203,6 @@ private fun ImportFilesScreenPreview() { override val uri = "https://fastly.picsum.photos/id/1/200/300.jpg" } ) - }, {}, closeActivity = {}) + }, {}, {}, closeActivity = {}) } } From ed9de9127ed0c9da6ff28c3cb9404aa9103821f5 Mon Sep 17 00:00:00 2001 From: Gibran Chevalley Date: Thu, 10 Oct 2024 16:16:58 +0200 Subject: [PATCH 06/27] Use correct strings for the files to transfers --- .../importfiles/ImportFilesScreen.kt | 20 ++++++++++++------- app/src/main/res/values-de/strings.xml | 9 +++++++++ app/src/main/res/values-es/strings.xml | 9 +++++++++ app/src/main/res/values-fr/strings.xml | 9 +++++++++ app/src/main/res/values-it/strings.xml | 9 +++++++++ app/src/main/res/values/strings.xml | 9 +++++++++ 6 files changed, 58 insertions(+), 7 deletions(-) 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 3b10753b5..ca2e2e0bc 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 @@ -33,6 +33,7 @@ import androidx.compose.runtime.* import androidx.compose.runtime.saveable.rememberSaveable import androidx.compose.ui.Modifier import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.res.pluralStringResource import androidx.compose.ui.unit.dp import androidx.hilt.navigation.compose.hiltViewModel import androidx.lifecycle.compose.collectAsStateWithLifecycle @@ -89,7 +90,7 @@ private fun ImportFilesScreen( topButton = { modifier -> LargeButton( modifier = modifier, - titleRes = R.string.sentTitle, // TODO + titleRes = R.string.transferSendButton, style = ButtonType.PRIMARY, enabled = isSendButtonEnabled, // TODO: Worth passing as lambda? onClick = { /*TODO*/ }, @@ -99,18 +100,21 @@ private fun ImportFilesScreen( SwissTransferCard(Modifier.padding(Margin.Medium)) { SharpRippleButton(onClick = { /*TODO*/ }) { Text( - "${fileCount} files", // TODO + pluralStringResource(R.plurals.filesCount, fileCount, fileCount), modifier = Modifier.padding(start = Margin.Medium), color = SwissTransferTheme.colors.secondaryTextColor, + style = SwissTransferTheme.typography.bodySmallRegular, ) Text( "•", modifier = Modifier.padding(horizontal = Margin.Small), - color = SwissTransferTheme.colors.secondaryTextColor + color = SwissTransferTheme.colors.secondaryTextColor, + style = SwissTransferTheme.typography.bodySmallRegular, ) Text( - "${formatSpaceLeft(totalFileSize)} left", // TODO - color = SwissTransferTheme.colors.secondaryTextColor + formatSpaceLeft(totalFileSize), + color = SwissTransferTheme.colors.secondaryTextColor, + style = SwissTransferTheme.typography.bodySmallRegular, ) Spacer(modifier = Modifier.weight(1f)) Icon( @@ -174,8 +178,10 @@ private fun AddNewFileButton(modifier: Modifier = Modifier, onClick: () -> Unit) @Composable private fun formatSpaceLeft(usedSpace: Long): String { - val spaceLeft = TOTAL_FILE_SIZE - usedSpace - return Formatter.formatShortFileSize(LocalContext.current, spaceLeft) + val spaceLeft = (TOTAL_FILE_SIZE - usedSpace).coerceAtLeast(0) + val formattedSpaceLeft = Formatter.formatShortFileSize(LocalContext.current, spaceLeft) + val quantity = 2 + return pluralStringResource(R.plurals.transferSpaceLeft, quantity, formattedSpaceLeft) } @Parcelize diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml index 2aa1eb992..91d0516d7 100644 --- a/app/src/main/res/values-de/strings.xml +++ b/app/src/main/res/values-de/strings.xml @@ -22,6 +22,10 @@ Schliessen Datei entfernen Neuer Transfer + + %d Datei + %d Dateien + Mache deine erste Überweisung! Zu übertragende Dateien Fügt bis zu 50 GB an Dateien hinzu @@ -60,6 +64,11 @@ %d Tag %d Tage + Senden + + %s übrig + %s übrig + E-Mail Link In der Nähe diff --git a/app/src/main/res/values-es/strings.xml b/app/src/main/res/values-es/strings.xml index 5cf57976d..1d189b1d0 100644 --- a/app/src/main/res/values-es/strings.xml +++ b/app/src/main/res/values-es/strings.xml @@ -22,6 +22,10 @@ Cerrar Eliminar archivo Nueva transferencia + + %d archivo + %d archivos + Realice su primera transferencia Archivos para transferir Añade hasta 50 GB de archivos @@ -60,6 +64,11 @@ día %d %d días + Enviar + + Queda %s + Quedan %s + Correo electrónico Enlace Proximidad diff --git a/app/src/main/res/values-fr/strings.xml b/app/src/main/res/values-fr/strings.xml index 6d2cc0d60..31f0a2eca 100644 --- a/app/src/main/res/values-fr/strings.xml +++ b/app/src/main/res/values-fr/strings.xml @@ -22,6 +22,10 @@ Fermer Supprimer le fichier Nouveau transfert + + %d fichier + %d fichiers + Fais ton premier transfert ! Fichiers à transférer Ajoute jusqu’à 50 Go de fichiers @@ -60,6 +64,11 @@ %d jour %d jours + Envoyer + + %s restant + %s restants + E-mail Lien A proximité diff --git a/app/src/main/res/values-it/strings.xml b/app/src/main/res/values-it/strings.xml index 9bc9fdc39..774d80f0c 100644 --- a/app/src/main/res/values-it/strings.xml +++ b/app/src/main/res/values-it/strings.xml @@ -22,6 +22,10 @@ Chiudi Rimuovi il file Nuovo trasferimento + + %d file + %d file + Effettua il tuo primo trasferimento! File da trasferire Aggiungere fino a 50 GB di file @@ -60,6 +64,11 @@ %d giorno %d giorni + Invia + + %s rimasto + %s rimasti + Email Link Vicino diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index c2be9758a..ed76e4458 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -25,6 +25,10 @@ Close Remove file New transfer + + %d file + %d files + Make your first transfer! Files to transfer Add up to 50 GB of files @@ -63,6 +67,11 @@ %d day %d days + Send + + %s left + %s left + Email Link Proximity From 3be3c119d7dd12435ec6833159b3c1461b928355 Mon Sep 17 00:00:00 2001 From: Gibran Chevalley Date: Fri, 11 Oct 2024 10:20:49 +0200 Subject: [PATCH 07/27] Find a way to detect the quantity of left file size for plural string --- .../newtransfer/importfiles/ImportFilesScreen.kt | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) 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 ca2e2e0bc..0d74ac39b 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 @@ -17,6 +17,7 @@ */ package com.infomaniak.swisstransfer.ui.screen.newtransfer.importfiles +import android.icu.text.NumberFormat import android.net.Uri import android.os.Parcelable import android.text.format.Formatter @@ -180,10 +181,23 @@ private fun AddNewFileButton(modifier: Modifier = Modifier, onClick: () -> Unit) private fun formatSpaceLeft(usedSpace: Long): String { val spaceLeft = (TOTAL_FILE_SIZE - usedSpace).coerceAtLeast(0) val formattedSpaceLeft = Formatter.formatShortFileSize(LocalContext.current, spaceLeft) - val quantity = 2 + val quantity = getQuantityFromFormattedSize(formattedSpaceLeft) return pluralStringResource(R.plurals.transferSpaceLeft, quantity, formattedSpaceLeft) } +@Composable +private fun getQuantityFromFormattedSize(formattedSize: String): Int { + val sizeParts = formattedSize.split(' ', Typography.nbsp) // Space for languages such as EN and NBSP for languages such as FR + + return if (sizeParts.size == 2) { + val local = LocalContext.current.resources.configuration.getLocales().get(0) + val parsedNumber = NumberFormat.getInstance(local).parse(sizeParts[0]) + parsedNumber?.toDouble()?.toInt() ?: 0 + } else { + 0 + } +} + @Parcelize private data class TransferLazyRowKey( val type: Type, From 0cec152e42b59dce9c93dfc30d63a135330d64ea Mon Sep 17 00:00:00 2001 From: Gibran Chevalley Date: Fri, 11 Oct 2024 15:22:06 +0200 Subject: [PATCH 08/27] Clean code --- .../ui/components/SmallFileTile.kt | 15 ++++-- .../swisstransfer/ui/images/icons/AddThick.kt | 29 +++++------- .../ui/images/icons/ArrowOpenOutside.kt | 47 +++++++++---------- .../ui/images/icons/CrossThick.kt | 29 +++++------- .../importfiles/ImportFilesScreen.kt | 2 +- 5 files changed, 59 insertions(+), 63 deletions(-) diff --git a/app/src/main/java/com/infomaniak/swisstransfer/ui/components/SmallFileTile.kt b/app/src/main/java/com/infomaniak/swisstransfer/ui/components/SmallFileTile.kt index 07ab5d340..49d123802 100644 --- a/app/src/main/java/com/infomaniak/swisstransfer/ui/components/SmallFileTile.kt +++ b/app/src/main/java/com/infomaniak/swisstransfer/ui/components/SmallFileTile.kt @@ -17,6 +17,7 @@ */ package com.infomaniak.swisstransfer.ui.components +import android.content.res.Configuration import androidx.compose.foundation.background import androidx.compose.foundation.layout.* import androidx.compose.material3.Surface @@ -24,16 +25,20 @@ import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip import androidx.compose.ui.graphics.Shape +import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.times import com.infomaniak.swisstransfer.ui.theme.Shapes import com.infomaniak.swisstransfer.ui.theme.SwissTransferTheme -import com.infomaniak.swisstransfer.ui.utils.PreviewLargeWindow -import com.infomaniak.swisstransfer.ui.utils.PreviewSmallWindow @Composable -fun SmallFileTile(modifier: Modifier = Modifier, file: FileUiItem, smallFileTileSize: SmallFileTileSize, onRemove: (() -> Unit)? = null) { +fun SmallFileTile( + modifier: Modifier = Modifier, + file: FileUiItem, + smallFileTileSize: SmallFileTileSize, + onRemove: (() -> Unit)? = null, +) { Box( modifier .size(smallFileTileSize.size) @@ -57,8 +62,8 @@ enum class SmallFileTileSize(val size: Dp, val shape: Shape) { fun iconCircleSize(): Dp = 2f / 3 * size } -@PreviewSmallWindow -@PreviewLargeWindow +@Preview(name = "Light") +@Preview(name = "Dark", uiMode = Configuration.UI_MODE_NIGHT_YES or Configuration.UI_MODE_TYPE_NORMAL) @Composable private fun SmallFileTilePreview() { SwissTransferTheme { diff --git a/app/src/main/java/com/infomaniak/swisstransfer/ui/images/icons/AddThick.kt b/app/src/main/java/com/infomaniak/swisstransfer/ui/images/icons/AddThick.kt index 7ae942529..498de20ea 100644 --- a/app/src/main/java/com/infomaniak/swisstransfer/ui/images/icons/AddThick.kt +++ b/app/src/main/java/com/infomaniak/swisstransfer/ui/images/icons/AddThick.kt @@ -10,7 +10,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 @@ -31,21 +30,19 @@ val AppIcons.AddThick: ImageVector viewportWidth = 16.0f, viewportHeight = 16.0f ).apply { - group { - path( - fill = null, - stroke = SolidColor(Color(0xFF9F9F9F)), - strokeLineWidth = 2.0f, - strokeLineCap = strokeCapRound, - strokeLineJoin = strokeJoinRound, - strokeLineMiter = 4.0f, - pathFillType = NonZero - ) { - moveTo(1.0f, 8.0f) - horizontalLineToRelative(14.0f) - moveTo(8.0f, 1.0f) - verticalLineToRelative(14.0f) - } + path( + fill = null, + stroke = SolidColor(Color(0xFF9F9F9F)), + strokeLineWidth = 2.0f, + strokeLineCap = strokeCapRound, + strokeLineJoin = strokeJoinRound, + strokeLineMiter = 4.0f, + pathFillType = NonZero + ) { + moveTo(1.0f, 8.0f) + horizontalLineToRelative(14.0f) + moveTo(8.0f, 1.0f) + verticalLineToRelative(14.0f) } }.build() return _addThick!! diff --git a/app/src/main/java/com/infomaniak/swisstransfer/ui/images/icons/ArrowOpenOutside.kt b/app/src/main/java/com/infomaniak/swisstransfer/ui/images/icons/ArrowOpenOutside.kt index ddf379303..0467cc453 100644 --- a/app/src/main/java/com/infomaniak/swisstransfer/ui/images/icons/ArrowOpenOutside.kt +++ b/app/src/main/java/com/infomaniak/swisstransfer/ui/images/icons/ArrowOpenOutside.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,30 +47,28 @@ val AppIcons.ArrowOpenOutside: ImageVector viewportWidth = 16.0f, viewportHeight = 16.0f, ).apply { - group { - path( - fill = null, - stroke = SolidColor(Color(0xFF9F9F9F)), - strokeLineWidth = 2.0f, - strokeLineCap = strokeCapRound, - strokeLineJoin = strokeJoinRound, - strokeLineMiter = 4.0f, - pathFillType = NonZero, - ) { - moveTo(15.0f, 5.2f) - verticalLineTo(1.0f) - horizontalLineToRelative(-4.2f) - moveTo(15.0f, 1.0f) - lineToRelative(-9.333f, 9.333f) - moveTo(7.533f, 3.8f) - horizontalLineToRelative(-5.6f) - arcTo(0.933f, 0.933f, 0.0f, false, false, 1.0f, 4.733f) - verticalLineToRelative(9.334f) - arcTo(0.933f, 0.933f, 0.0f, false, false, 1.933f, 15.0f) - horizontalLineToRelative(9.334f) - arcToRelative(0.933f, 0.933f, 0.0f, false, false, 0.933f, -0.933f) - verticalLineToRelative(-5.6f) - } + path( + fill = null, + stroke = SolidColor(Color(0xFF9F9F9F)), + strokeLineWidth = 2.0f, + strokeLineCap = strokeCapRound, + strokeLineJoin = strokeJoinRound, + strokeLineMiter = 4.0f, + pathFillType = NonZero, + ) { + moveTo(15.0f, 5.2f) + verticalLineTo(1.0f) + horizontalLineToRelative(-4.2f) + moveTo(15.0f, 1.0f) + lineToRelative(-9.333f, 9.333f) + moveTo(7.533f, 3.8f) + horizontalLineToRelative(-5.6f) + arcTo(0.933f, 0.933f, 0.0f, false, false, 1.0f, 4.733f) + verticalLineToRelative(9.334f) + arcTo(0.933f, 0.933f, 0.0f, false, false, 1.933f, 15.0f) + horizontalLineToRelative(9.334f) + arcToRelative(0.933f, 0.933f, 0.0f, false, false, 0.933f, -0.933f) + verticalLineToRelative(-5.6f) } }.build() diff --git a/app/src/main/java/com/infomaniak/swisstransfer/ui/images/icons/CrossThick.kt b/app/src/main/java/com/infomaniak/swisstransfer/ui/images/icons/CrossThick.kt index 845f8c729..cae1f6777 100644 --- a/app/src/main/java/com/infomaniak/swisstransfer/ui/images/icons/CrossThick.kt +++ b/app/src/main/java/com/infomaniak/swisstransfer/ui/images/icons/CrossThick.kt @@ -10,7 +10,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 @@ -30,21 +29,19 @@ val AppImages.AppIcons.CrossThick: ImageVector viewportWidth = 16.0f, viewportHeight = 16.0f ).apply { - group { - path( - fill = null, - stroke = SolidColor(Color(0xFF9F9F9F)), - strokeLineWidth = 2.0f, - strokeLineCap = strokeCapRound, - strokeLineJoin = strokeJoinRound, - strokeLineMiter = 4.0f, - pathFillType = NonZero - ) { - moveTo(1.0f, 15.0f) - lineTo(15.0f, 1.0f) - moveToRelative(0.0f, 14.0f) - lineTo(1.0f, 1.0f) - } + path( + fill = null, + stroke = SolidColor(Color(0xFF9F9F9F)), + strokeLineWidth = 2.0f, + strokeLineCap = strokeCapRound, + strokeLineJoin = strokeJoinRound, + strokeLineMiter = 4.0f, + pathFillType = NonZero + ) { + moveTo(1.0f, 15.0f) + lineTo(15.0f, 1.0f) + moveToRelative(0.0f, 14.0f) + lineTo(1.0f, 1.0f) } }.build() return _crossThick!! 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 0d74ac39b..d47b99416 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 @@ -220,7 +220,7 @@ private fun ImportFilesScreenPreview() { override val fileName = "Time-Clock-Circle--Streamline-Ultimate.svg (1).svg" override val fileSizeInBytes = 234567832L override val mimeType = null - override val uri = "https://fastly.picsum.photos/id/1/200/300.jpg" + override val uri = "" } ) }, {}, {}, closeActivity = {}) From 733ddaa6827ef5f60652e67971c2903846fa6a7f Mon Sep 17 00:00:00 2001 From: Gibran Chevalley Date: Fri, 11 Oct 2024 15:28:33 +0200 Subject: [PATCH 09/27] Optimize recomposition of space left plural string --- .../importfiles/ImportFilesScreen.kt | 26 +++++++++++++------ 1 file changed, 18 insertions(+), 8 deletions(-) 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 d47b99416..7b323cf4b 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 @@ -17,6 +17,7 @@ */ package com.infomaniak.swisstransfer.ui.screen.newtransfer.importfiles +import android.content.Context import android.icu.text.NumberFormat import android.net.Uri import android.os.Parcelable @@ -69,9 +70,15 @@ private fun ImportFilesScreen( addFiles: (List) -> Unit, closeActivity: () -> Unit, ) { + val context = LocalContext.current var showUploadSourceChoiceBottomSheet by rememberSaveable { mutableStateOf(true) } val fileCount by remember { derivedStateOf { files().count() } } - val totalFileSize by remember { derivedStateOf { files().sumOf { it.fileSizeInBytes } } } + val formattedSizeWithUnits by remember { + derivedStateOf { + val totalFileSize = files().sumOf { it.fileSizeInBytes } + getFormattedSizeWithUnits(totalFileSize, context) + } + } val isSendButtonEnabled by remember { derivedStateOf { files().isNotEmpty() } } val filePickerLauncher = rememberLauncherForActivityResult( @@ -113,7 +120,7 @@ private fun ImportFilesScreen( style = SwissTransferTheme.typography.bodySmallRegular, ) Text( - formatSpaceLeft(totalFileSize), + formatSpaceLeft(formattedSizeWithUnits), color = SwissTransferTheme.colors.secondaryTextColor, style = SwissTransferTheme.typography.bodySmallRegular, ) @@ -177,16 +184,19 @@ private fun AddNewFileButton(modifier: Modifier = Modifier, onClick: () -> Unit) } } -@Composable -private fun formatSpaceLeft(usedSpace: Long): String { +private fun getFormattedSizeWithUnits(usedSpace: Long, context: Context): String { val spaceLeft = (TOTAL_FILE_SIZE - usedSpace).coerceAtLeast(0) - val formattedSpaceLeft = Formatter.formatShortFileSize(LocalContext.current, spaceLeft) - val quantity = getQuantityFromFormattedSize(formattedSpaceLeft) - return pluralStringResource(R.plurals.transferSpaceLeft, quantity, formattedSpaceLeft) + return Formatter.formatShortFileSize(context, spaceLeft) +} + +@Composable +private fun formatSpaceLeft(formattedSizeWithUnits: String): String { + val quantity = getQuantityFromFormattedSizeWithUnits(formattedSizeWithUnits) + return pluralStringResource(R.plurals.transferSpaceLeft, quantity, formattedSizeWithUnits) } @Composable -private fun getQuantityFromFormattedSize(formattedSize: String): Int { +private fun getQuantityFromFormattedSizeWithUnits(formattedSize: String): Int { val sizeParts = formattedSize.split(' ', Typography.nbsp) // Space for languages such as EN and NBSP for languages such as FR return if (sizeParts.size == 2) { From f04a015cccbfce9946a68978524ae3712eac4a15 Mon Sep 17 00:00:00 2001 From: Gibran Chevalley Date: Fri, 11 Oct 2024 15:33:03 +0200 Subject: [PATCH 10/27] Use a lambda for `enabled` in swiss transfer buttons to avoid recompositions --- .../com/infomaniak/swisstransfer/ui/components/Buttons.kt | 8 ++++---- .../screen/newtransfer/importfiles/ImportFilesScreen.kt | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/app/src/main/java/com/infomaniak/swisstransfer/ui/components/Buttons.kt b/app/src/main/java/com/infomaniak/swisstransfer/ui/components/Buttons.kt index 0afd43465..34950d454 100644 --- a/app/src/main/java/com/infomaniak/swisstransfer/ui/components/Buttons.kt +++ b/app/src/main/java/com/infomaniak/swisstransfer/ui/components/Buttons.kt @@ -41,7 +41,7 @@ fun LargeButton( @StringRes titleRes: Int, modifier: Modifier = Modifier, style: ButtonType = ButtonType.PRIMARY, - enabled: Boolean = true, + enabled: () -> Boolean = { true }, onClick: () -> Unit, imageVector: ImageVector? = null, ) { @@ -53,7 +53,7 @@ fun SmallButton( @StringRes titleRes: Int, modifier: Modifier = Modifier, style: ButtonType = ButtonType.PRIMARY, - enabled: Boolean = true, + enabled: () -> Boolean = { true }, onClick: () -> Unit, imageVector: ImageVector? = null, ) { @@ -66,7 +66,7 @@ private fun CoreButton( modifier: Modifier, buttonSize: ButtonSize, style: ButtonType, - enabled: Boolean, + enabled: () -> Boolean, onClick: () -> Unit, imageVector: ImageVector?, ) { @@ -74,7 +74,7 @@ private fun CoreButton( modifier = modifier.height(buttonSize.height), colors = style.buttonColors(), shape = Shapes.medium, - enabled = enabled, + enabled = enabled(), onClick = onClick, ) { imageVector?.let { 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 7b323cf4b..55753d06a 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 @@ -100,7 +100,7 @@ private fun ImportFilesScreen( modifier = modifier, titleRes = R.string.transferSendButton, style = ButtonType.PRIMARY, - enabled = isSendButtonEnabled, // TODO: Worth passing as lambda? + enabled = { isSendButtonEnabled }, onClick = { /*TODO*/ }, ) }, From 0c826bc88aa9b6cdb4e0416c784c921b986eb69c Mon Sep 17 00:00:00 2001 From: Gibran Chevalley Date: Fri, 11 Oct 2024 15:59:40 +0200 Subject: [PATCH 11/27] Extract composables into a SelectedFilesCard for readability --- .../importfiles/ImportFilesScreen.kt | 130 ++++++++++-------- 1 file changed, 74 insertions(+), 56 deletions(-) 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 55753d06a..544544bf2 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 @@ -105,56 +105,13 @@ private fun ImportFilesScreen( ) }, content = { - SwissTransferCard(Modifier.padding(Margin.Medium)) { - SharpRippleButton(onClick = { /*TODO*/ }) { - Text( - pluralStringResource(R.plurals.filesCount, fileCount, fileCount), - modifier = Modifier.padding(start = Margin.Medium), - color = SwissTransferTheme.colors.secondaryTextColor, - style = SwissTransferTheme.typography.bodySmallRegular, - ) - Text( - "•", - modifier = Modifier.padding(horizontal = Margin.Small), - color = SwissTransferTheme.colors.secondaryTextColor, - style = SwissTransferTheme.typography.bodySmallRegular, - ) - Text( - formatSpaceLeft(formattedSizeWithUnits), - color = SwissTransferTheme.colors.secondaryTextColor, - style = SwissTransferTheme.typography.bodySmallRegular, - ) - Spacer(modifier = Modifier.weight(1f)) - Icon( - imageVector = AppImages.AppIcons.ChevronRightSmall, - contentDescription = null, - modifier = Modifier.padding(Margin.Medium), - tint = SwissTransferTheme.colors.iconColor - ) - } - - LazyRow( - Modifier.fillMaxWidth(), - contentPadding = PaddingValues(Margin.Medium), - horizontalArrangement = Arrangement.spacedBy(Margin.Medium) - ) { - item(key = TransferLazyRowKey(TransferLazyRowKey.Type.ADD_BUTTON)) { - AddNewFileButton(Modifier.animateItem()) { showUploadSourceChoiceBottomSheet = true } - } - - items( - items = files(), - key = { TransferLazyRowKey(TransferLazyRowKey.Type.FILE, it.uid) }, - ) { file -> - SmallFileTile( - modifier = Modifier.animateItem(), - file = file, - smallFileTileSize = SmallFileTileSize.LARGE, - onRemove = { removeFileByUid(file.uid) } - ) - } - } - } + SelectedFilesCard( + fileCount = { fileCount }, + formattedSizeWithUnits = { formattedSizeWithUnits }, + showUploadSourceChoiceBottomSheet = { showUploadSourceChoiceBottomSheet = true }, + files = files, + removeFileByUid = removeFileByUid, + ) UploadSourceChoiceBottomSheet( isBottomSheetVisible = { showUploadSourceChoiceBottomSheet }, @@ -165,6 +122,67 @@ private fun ImportFilesScreen( ) } +@Composable +private fun SelectedFilesCard( + fileCount: () -> Int, + formattedSizeWithUnits: () -> String, + showUploadSourceChoiceBottomSheet: () -> Unit, + files: () -> List, + removeFileByUid: (uid: String) -> Unit +) { + SwissTransferCard(Modifier.padding(Margin.Medium)) { + SharpRippleButton(onClick = { /*TODO*/ }) { + val count = fileCount() + Text( + pluralStringResource(R.plurals.filesCount, count, count), + modifier = Modifier.padding(start = Margin.Medium), + color = SwissTransferTheme.colors.secondaryTextColor, + style = SwissTransferTheme.typography.bodySmallRegular, + ) + Text( + "•", + modifier = Modifier.padding(horizontal = Margin.Small), + color = SwissTransferTheme.colors.secondaryTextColor, + style = SwissTransferTheme.typography.bodySmallRegular, + ) + Text( + formatSpaceLeft(formattedSizeWithUnits), + color = SwissTransferTheme.colors.secondaryTextColor, + style = SwissTransferTheme.typography.bodySmallRegular, + ) + Spacer(modifier = Modifier.weight(1f)) + Icon( + imageVector = AppImages.AppIcons.ChevronRightSmall, + contentDescription = null, + modifier = Modifier.padding(Margin.Medium), + tint = SwissTransferTheme.colors.iconColor + ) + } + + LazyRow( + Modifier.fillMaxWidth(), + contentPadding = PaddingValues(Margin.Medium), + horizontalArrangement = Arrangement.spacedBy(Margin.Medium) + ) { + item(key = TransferLazyRowKey(TransferLazyRowKey.Type.ADD_BUTTON)) { + AddNewFileButton(Modifier.animateItem()) { showUploadSourceChoiceBottomSheet() } + } + + items( + items = files(), + key = { TransferLazyRowKey(TransferLazyRowKey.Type.FILE, it.uid) }, + ) { file -> + SmallFileTile( + modifier = Modifier.animateItem(), + file = file, + smallFileTileSize = SmallFileTileSize.LARGE, + onRemove = { removeFileByUid(file.uid) } + ) + } + } + } +} + @Composable private fun AddNewFileButton(modifier: Modifier = Modifier, onClick: () -> Unit) { Button( @@ -190,17 +208,17 @@ private fun getFormattedSizeWithUnits(usedSpace: Long, context: Context): String } @Composable -private fun formatSpaceLeft(formattedSizeWithUnits: String): String { - val quantity = getQuantityFromFormattedSizeWithUnits(formattedSizeWithUnits) - return pluralStringResource(R.plurals.transferSpaceLeft, quantity, formattedSizeWithUnits) +private fun formatSpaceLeft(formattedSizeWithUnits: () -> String): String { + val formattedSize = formattedSizeWithUnits() + val quantity = LocalContext.current.getQuantityFromFormattedSizeWithUnits(formattedSize) + return pluralStringResource(R.plurals.transferSpaceLeft, quantity, formattedSize) } -@Composable -private fun getQuantityFromFormattedSizeWithUnits(formattedSize: String): Int { +private fun Context.getQuantityFromFormattedSizeWithUnits(formattedSize: String): Int { val sizeParts = formattedSize.split(' ', Typography.nbsp) // Space for languages such as EN and NBSP for languages such as FR return if (sizeParts.size == 2) { - val local = LocalContext.current.resources.configuration.getLocales().get(0) + val local = resources.configuration.getLocales().get(0) val parsedNumber = NumberFormat.getInstance(local).parse(sizeParts[0]) parsedNumber?.toDouble()?.toInt() ?: 0 } else { From 325ba35814b6af6ccb72339465e046a0a3a6ece4 Mon Sep 17 00:00:00 2001 From: Gibran Chevalley Date: Fri, 11 Oct 2024 16:59:56 +0200 Subject: [PATCH 12/27] Extract SelectedFilesCard to its own component --- .../importfiles/ImportFilesScreen.kt | 133 +------------ .../importfiles/SelectedFilesCard.kt | 184 ++++++++++++++++++ 2 files changed, 188 insertions(+), 129 deletions(-) create mode 100644 app/src/main/java/com/infomaniak/swisstransfer/ui/screen/newtransfer/importfiles/SelectedFilesCard.kt 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 544544bf2..ace5600c9 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 @@ -18,39 +18,24 @@ package com.infomaniak.swisstransfer.ui.screen.newtransfer.importfiles import android.content.Context -import android.icu.text.NumberFormat import android.net.Uri -import android.os.Parcelable import android.text.format.Formatter import androidx.activity.compose.rememberLauncherForActivityResult import androidx.activity.result.contract.ActivityResultContracts -import androidx.compose.foundation.layout.* -import androidx.compose.foundation.lazy.LazyRow -import androidx.compose.foundation.lazy.items -import androidx.compose.material3.Button -import androidx.compose.material3.ButtonDefaults -import androidx.compose.material3.Icon -import androidx.compose.material3.Text +import androidx.compose.foundation.layout.padding import androidx.compose.runtime.* import androidx.compose.runtime.saveable.rememberSaveable import androidx.compose.ui.Modifier import androidx.compose.ui.platform.LocalContext -import androidx.compose.ui.res.pluralStringResource -import androidx.compose.ui.unit.dp import androidx.hilt.navigation.compose.hiltViewModel import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.infomaniak.swisstransfer.R import com.infomaniak.swisstransfer.ui.components.* -import com.infomaniak.swisstransfer.ui.images.AppImages -import com.infomaniak.swisstransfer.ui.images.icons.AddThick -import com.infomaniak.swisstransfer.ui.images.icons.ChevronRightSmall import com.infomaniak.swisstransfer.ui.screen.newtransfer.NewTransferViewModel import com.infomaniak.swisstransfer.ui.theme.Margin -import com.infomaniak.swisstransfer.ui.theme.Shapes import com.infomaniak.swisstransfer.ui.theme.SwissTransferTheme import com.infomaniak.swisstransfer.ui.utils.PreviewLargeWindow import com.infomaniak.swisstransfer.ui.utils.PreviewSmallWindow -import kotlinx.parcelize.Parcelize private const val TOTAL_FILE_SIZE: Long = 50_000_000_000 @@ -72,7 +57,6 @@ private fun ImportFilesScreen( ) { val context = LocalContext.current var showUploadSourceChoiceBottomSheet by rememberSaveable { mutableStateOf(true) } - val fileCount by remember { derivedStateOf { files().count() } } val formattedSizeWithUnits by remember { derivedStateOf { val totalFileSize = files().sumOf { it.fileSizeInBytes } @@ -106,10 +90,10 @@ private fun ImportFilesScreen( }, content = { SelectedFilesCard( - fileCount = { fileCount }, + modifier = Modifier.padding(Margin.Medium), + files = files, formattedSizeWithUnits = { formattedSizeWithUnits }, showUploadSourceChoiceBottomSheet = { showUploadSourceChoiceBottomSheet = true }, - files = files, removeFileByUid = removeFileByUid, ) @@ -122,120 +106,11 @@ private fun ImportFilesScreen( ) } -@Composable -private fun SelectedFilesCard( - fileCount: () -> Int, - formattedSizeWithUnits: () -> String, - showUploadSourceChoiceBottomSheet: () -> Unit, - files: () -> List, - removeFileByUid: (uid: String) -> Unit -) { - SwissTransferCard(Modifier.padding(Margin.Medium)) { - SharpRippleButton(onClick = { /*TODO*/ }) { - val count = fileCount() - Text( - pluralStringResource(R.plurals.filesCount, count, count), - modifier = Modifier.padding(start = Margin.Medium), - color = SwissTransferTheme.colors.secondaryTextColor, - style = SwissTransferTheme.typography.bodySmallRegular, - ) - Text( - "•", - modifier = Modifier.padding(horizontal = Margin.Small), - color = SwissTransferTheme.colors.secondaryTextColor, - style = SwissTransferTheme.typography.bodySmallRegular, - ) - Text( - formatSpaceLeft(formattedSizeWithUnits), - color = SwissTransferTheme.colors.secondaryTextColor, - style = SwissTransferTheme.typography.bodySmallRegular, - ) - Spacer(modifier = Modifier.weight(1f)) - Icon( - imageVector = AppImages.AppIcons.ChevronRightSmall, - contentDescription = null, - modifier = Modifier.padding(Margin.Medium), - tint = SwissTransferTheme.colors.iconColor - ) - } - - LazyRow( - Modifier.fillMaxWidth(), - contentPadding = PaddingValues(Margin.Medium), - horizontalArrangement = Arrangement.spacedBy(Margin.Medium) - ) { - item(key = TransferLazyRowKey(TransferLazyRowKey.Type.ADD_BUTTON)) { - AddNewFileButton(Modifier.animateItem()) { showUploadSourceChoiceBottomSheet() } - } - - items( - items = files(), - key = { TransferLazyRowKey(TransferLazyRowKey.Type.FILE, it.uid) }, - ) { file -> - SmallFileTile( - modifier = Modifier.animateItem(), - file = file, - smallFileTileSize = SmallFileTileSize.LARGE, - onRemove = { removeFileByUid(file.uid) } - ) - } - } - } -} - -@Composable -private fun AddNewFileButton(modifier: Modifier = Modifier, onClick: () -> Unit) { - Button( - modifier = modifier.size(80.dp), - shape = Shapes.medium, - colors = ButtonDefaults.buttonColors( - containerColor = SwissTransferTheme.materialColors.surface, - contentColor = SwissTransferTheme.materialColors.primary, - ), - onClick = onClick, - ) { - Icon( - modifier = Modifier.size(24.dp), - imageVector = AppImages.AppIcons.AddThick, - contentDescription = null, - ) - } -} - private fun getFormattedSizeWithUnits(usedSpace: Long, context: Context): String { val spaceLeft = (TOTAL_FILE_SIZE - usedSpace).coerceAtLeast(0) return Formatter.formatShortFileSize(context, spaceLeft) } -@Composable -private fun formatSpaceLeft(formattedSizeWithUnits: () -> String): String { - val formattedSize = formattedSizeWithUnits() - val quantity = LocalContext.current.getQuantityFromFormattedSizeWithUnits(formattedSize) - return pluralStringResource(R.plurals.transferSpaceLeft, quantity, formattedSize) -} - -private fun Context.getQuantityFromFormattedSizeWithUnits(formattedSize: String): Int { - val sizeParts = formattedSize.split(' ', Typography.nbsp) // Space for languages such as EN and NBSP for languages such as FR - - return if (sizeParts.size == 2) { - val local = resources.configuration.getLocales().get(0) - val parsedNumber = NumberFormat.getInstance(local).parse(sizeParts[0]) - parsedNumber?.toDouble()?.toInt() ?: 0 - } else { - 0 - } -} - -@Parcelize -private data class TransferLazyRowKey( - val type: Type, - val fileUid: String? = null -) : Parcelable { - enum class Type { - ADD_BUTTON, FILE - } -} - @PreviewSmallWindow @PreviewLargeWindow @Composable @@ -246,7 +121,7 @@ private fun ImportFilesScreenPreview() { object : FileUiItem { override val uid = "" override val fileName = "Time-Clock-Circle--Streamline-Ultimate.svg (1).svg" - override val fileSizeInBytes = 234567832L + override val fileSizeInBytes = 2367832L override val mimeType = null override val uri = "" } diff --git a/app/src/main/java/com/infomaniak/swisstransfer/ui/screen/newtransfer/importfiles/SelectedFilesCard.kt b/app/src/main/java/com/infomaniak/swisstransfer/ui/screen/newtransfer/importfiles/SelectedFilesCard.kt new file mode 100644 index 000000000..72fb8e24b --- /dev/null +++ b/app/src/main/java/com/infomaniak/swisstransfer/ui/screen/newtransfer/importfiles/SelectedFilesCard.kt @@ -0,0 +1,184 @@ +/* + * 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.screen.newtransfer.importfiles + +import android.content.Context +import android.content.res.Configuration +import android.icu.text.NumberFormat +import android.os.Parcelable +import androidx.compose.foundation.layout.* +import androidx.compose.foundation.lazy.LazyRow +import androidx.compose.foundation.lazy.items +import androidx.compose.material3.Button +import androidx.compose.material3.ButtonDefaults +import androidx.compose.material3.Icon +import androidx.compose.material3.Text +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.Preview +import androidx.compose.ui.unit.dp +import com.infomaniak.swisstransfer.R +import com.infomaniak.swisstransfer.ui.components.* +import com.infomaniak.swisstransfer.ui.images.AppImages +import com.infomaniak.swisstransfer.ui.images.icons.AddThick +import com.infomaniak.swisstransfer.ui.images.icons.ChevronRightSmall +import com.infomaniak.swisstransfer.ui.theme.Margin +import com.infomaniak.swisstransfer.ui.theme.Shapes +import com.infomaniak.swisstransfer.ui.theme.SwissTransferTheme +import kotlinx.parcelize.Parcelize + +@Composable +fun SelectedFilesCard( + modifier: Modifier = Modifier, + files: () -> List, + formattedSizeWithUnits: () -> String, + showUploadSourceChoiceBottomSheet: () -> Unit, + removeFileByUid: (uid: String) -> Unit +) { + val fileCount by remember { derivedStateOf { files().count() } } + + SwissTransferCard(modifier) { + SharpRippleButton(onClick = { /*TODO*/ }) { + Text( + pluralStringResource(R.plurals.filesCount, fileCount, fileCount), + modifier = Modifier.padding(start = Margin.Medium), + color = SwissTransferTheme.colors.secondaryTextColor, + style = SwissTransferTheme.typography.bodySmallRegular, + ) + Text( + "•", + modifier = Modifier.padding(horizontal = Margin.Small), + color = SwissTransferTheme.colors.secondaryTextColor, + style = SwissTransferTheme.typography.bodySmallRegular, + ) + Text( + formatSpaceLeft(formattedSizeWithUnits), + color = SwissTransferTheme.colors.secondaryTextColor, + style = SwissTransferTheme.typography.bodySmallRegular, + ) + Spacer(modifier = Modifier.weight(1f)) + Icon( + imageVector = AppImages.AppIcons.ChevronRightSmall, + contentDescription = null, + modifier = Modifier.padding(Margin.Medium), + tint = SwissTransferTheme.colors.iconColor + ) + } + + LazyRow( + Modifier.fillMaxWidth(), + contentPadding = PaddingValues(Margin.Medium), + horizontalArrangement = Arrangement.spacedBy(Margin.Medium) + ) { + item(key = TransferLazyRowKey(TransferLazyRowKey.Type.ADD_BUTTON)) { + AddNewFileButton(Modifier.animateItem()) { showUploadSourceChoiceBottomSheet() } + } + + items( + items = files(), + key = { TransferLazyRowKey(TransferLazyRowKey.Type.FILE, it.uid) }, + ) { file -> + SmallFileTile( + modifier = Modifier.animateItem(), + file = file, + smallFileTileSize = SmallFileTileSize.LARGE, + onRemove = { removeFileByUid(file.uid) } + ) + } + } + } +} + +@Composable +private fun formatSpaceLeft(formattedSizeWithUnits: () -> String): String { + val formattedSize = formattedSizeWithUnits() + val quantity = LocalContext.current.getQuantityFromFormattedSizeWithUnits(formattedSize) + return pluralStringResource(R.plurals.transferSpaceLeft, quantity, formattedSize) +} + +private fun Context.getQuantityFromFormattedSizeWithUnits(formattedSize: String): Int { + val sizeParts = formattedSize.split(' ', Typography.nbsp) // Space for languages such as EN and NBSP for languages such as FR + + return if (sizeParts.size == 2) { + val local = resources.configuration.getLocales().get(0) + val parsedNumber = NumberFormat.getInstance(local).parse(sizeParts[0]) + parsedNumber?.toDouble()?.toInt() ?: 0 + } else { + 0 + } +} + +@Composable +private fun AddNewFileButton(modifier: Modifier = Modifier, onClick: () -> Unit) { + Button( + modifier = modifier.size(80.dp), + shape = Shapes.medium, + colors = ButtonDefaults.buttonColors( + containerColor = SwissTransferTheme.materialColors.surface, + contentColor = SwissTransferTheme.materialColors.primary, + ), + onClick = onClick, + ) { + Icon( + modifier = Modifier.size(24.dp), + imageVector = AppImages.AppIcons.AddThick, + contentDescription = null, + ) + } +} + +@Parcelize +private data class TransferLazyRowKey( + val type: Type, + val fileUid: String? = null +) : Parcelable { + enum class Type { + ADD_BUTTON, FILE + } +} + + +@Preview(name = "Light") +@Preview(name = "Dark", uiMode = Configuration.UI_MODE_NIGHT_YES or Configuration.UI_MODE_TYPE_NORMAL) +@Composable +private fun SelectedFilesCardPreview() { + SwissTransferTheme { + SelectedFilesCard( + modifier = Modifier.padding(Margin.Medium), + files = { + listOf( + object : FileUiItem { + override val uid = "" + override val fileName = "Time-Clock-Circle--Streamline-Ultimate.svg (1).svg" + override val fileSizeInBytes = 234567832L + override val mimeType = null + override val uri = "" + } + ) + }, + formattedSizeWithUnits = { "20 GB" }, + showUploadSourceChoiceBottomSheet = {}, + removeFileByUid = {} + ) + } +} From f0d95c15e038df9fbc93ba2568ebab5e41600b39 Mon Sep 17 00:00:00 2001 From: Gibran Chevalley Date: Tue, 15 Oct 2024 09:52:04 +0200 Subject: [PATCH 13/27] Put last imported as the first items in the SelectedFilesCard Thanks to this the newly added files are visible and you can see them being added, else they're hidden outside the screen and you don't see any movement --- .../ui/screen/newtransfer/importfiles/SelectedFilesCard.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/com/infomaniak/swisstransfer/ui/screen/newtransfer/importfiles/SelectedFilesCard.kt b/app/src/main/java/com/infomaniak/swisstransfer/ui/screen/newtransfer/importfiles/SelectedFilesCard.kt index 72fb8e24b..b89db3b3a 100644 --- a/app/src/main/java/com/infomaniak/swisstransfer/ui/screen/newtransfer/importfiles/SelectedFilesCard.kt +++ b/app/src/main/java/com/infomaniak/swisstransfer/ui/screen/newtransfer/importfiles/SelectedFilesCard.kt @@ -95,7 +95,7 @@ fun SelectedFilesCard( } items( - items = files(), + items = files().asReversed(), key = { TransferLazyRowKey(TransferLazyRowKey.Type.FILE, it.uid) }, ) { file -> SmallFileTile( From f2f6fae5e8468bf81d5870758ecfd17cf6d9091f Mon Sep 17 00:00:00 2001 From: Gibran Chevalley Date: Wed, 16 Oct 2024 08:23:37 +0200 Subject: [PATCH 14/27] Fix padding around SelectedFilesCard --- .../ui/screen/newtransfer/importfiles/SelectedFilesCard.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/com/infomaniak/swisstransfer/ui/screen/newtransfer/importfiles/SelectedFilesCard.kt b/app/src/main/java/com/infomaniak/swisstransfer/ui/screen/newtransfer/importfiles/SelectedFilesCard.kt index b89db3b3a..e52d9b55d 100644 --- a/app/src/main/java/com/infomaniak/swisstransfer/ui/screen/newtransfer/importfiles/SelectedFilesCard.kt +++ b/app/src/main/java/com/infomaniak/swisstransfer/ui/screen/newtransfer/importfiles/SelectedFilesCard.kt @@ -87,7 +87,7 @@ fun SelectedFilesCard( LazyRow( Modifier.fillMaxWidth(), - contentPadding = PaddingValues(Margin.Medium), + contentPadding = PaddingValues(start = Margin.Medium, end = Margin.Medium, bottom = Margin.Medium), horizontalArrangement = Arrangement.spacedBy(Margin.Medium) ) { item(key = TransferLazyRowKey(TransferLazyRowKey.Type.ADD_BUTTON)) { From 776a4c9ac0d3fa0943a32664249f76d18b60ed6f Mon Sep 17 00:00:00 2001 From: Vincent TE <149579879+tevincent@users.noreply.github.com> Date: Thu, 17 Oct 2024 10:13:37 +0200 Subject: [PATCH 15/27] Add missing comas Co-authored-by: Kevin Boulongne <1788629+KevinBoulongne@users.noreply.github.com> Update app/src/main/java/com/infomaniak/swisstransfer/ui/components/FilePreview.kt Co-authored-by: Kevin Boulongne <1788629+KevinBoulongne@users.noreply.github.com> Update app/src/main/java/com/infomaniak/swisstransfer/ui/components/FilePreview.kt Co-authored-by: Kevin Boulongne <1788629+KevinBoulongne@users.noreply.github.com> Update app/src/main/java/com/infomaniak/swisstransfer/ui/components/SwissTransferCard.kt Co-authored-by: Kevin Boulongne <1788629+KevinBoulongne@users.noreply.github.com> Update app/src/main/java/com/infomaniak/swisstransfer/ui/screen/newtransfer/importfiles/ImportFilesScreen.kt Co-authored-by: Kevin Boulongne <1788629+KevinBoulongne@users.noreply.github.com> Update app/src/main/java/com/infomaniak/swisstransfer/ui/screen/newtransfer/importfiles/SelectedFilesCard.kt Co-authored-by: Kevin Boulongne <1788629+KevinBoulongne@users.noreply.github.com> Update app/src/main/java/com/infomaniak/swisstransfer/ui/screen/newtransfer/importfiles/SelectedFilesCard.kt Co-authored-by: Kevin Boulongne <1788629+KevinBoulongne@users.noreply.github.com> Update app/src/main/java/com/infomaniak/swisstransfer/ui/screen/newtransfer/importfiles/SelectedFilesCard.kt Co-authored-by: Kevin Boulongne <1788629+KevinBoulongne@users.noreply.github.com> Update app/src/main/java/com/infomaniak/swisstransfer/ui/screen/newtransfer/importfiles/SelectedFilesCard.kt Co-authored-by: Kevin Boulongne <1788629+KevinBoulongne@users.noreply.github.com> Update app/src/main/java/com/infomaniak/swisstransfer/ui/screen/newtransfer/importfiles/SelectedFilesCard.kt Co-authored-by: Kevin Boulongne <1788629+KevinBoulongne@users.noreply.github.com> --- .../swisstransfer/ui/components/CrossCircleButton.kt | 2 +- .../swisstransfer/ui/components/FilePreview.kt | 4 ++-- .../swisstransfer/ui/components/SwissTransferCard.kt | 2 +- .../newtransfer/importfiles/ImportFilesScreen.kt | 2 +- .../newtransfer/importfiles/SelectedFilesCard.kt | 10 +++++----- 5 files changed, 10 insertions(+), 10 deletions(-) diff --git a/app/src/main/java/com/infomaniak/swisstransfer/ui/components/CrossCircleButton.kt b/app/src/main/java/com/infomaniak/swisstransfer/ui/components/CrossCircleButton.kt index d5022f0d5..1f910edef 100644 --- a/app/src/main/java/com/infomaniak/swisstransfer/ui/components/CrossCircleButton.kt +++ b/app/src/main/java/com/infomaniak/swisstransfer/ui/components/CrossCircleButton.kt @@ -57,7 +57,7 @@ fun BoxScope.CrossCircleButton(onClick: (() -> Unit)?, size: Dp = 48.dp) { modifier = Modifier.size(Margin.Small), imageVector = AppImages.AppIcons.CrossThick, contentDescription = stringResource(R.string.contentDescriptionButtonRemove), - tint = Color.White + tint = Color.White, ) } } diff --git a/app/src/main/java/com/infomaniak/swisstransfer/ui/components/FilePreview.kt b/app/src/main/java/com/infomaniak/swisstransfer/ui/components/FilePreview.kt index 0bb008c30..3040a4b0c 100644 --- a/app/src/main/java/com/infomaniak/swisstransfer/ui/components/FilePreview.kt +++ b/app/src/main/java/com/infomaniak/swisstransfer/ui/components/FilePreview.kt @@ -44,7 +44,7 @@ import com.infomaniak.swisstransfer.ui.utils.hasPreview fun FilePreview( file: FileUiItem, circleColor: Color, - circleSize: Dp + circleSize: Dp, ) { var displayPreview by rememberSaveable { mutableStateOf(file.hasPreview) } @@ -80,7 +80,7 @@ private fun FileIcon(fileType: FileType, color: Color, circleSize: Dp) { modifier = Modifier.size(circleSize / 2), imageVector = fileType.icon, contentDescription = null, - tint = fileType.color(LocalIsDarkMode.current) + tint = fileType.color(LocalIsDarkMode.current), ) } } diff --git a/app/src/main/java/com/infomaniak/swisstransfer/ui/components/SwissTransferCard.kt b/app/src/main/java/com/infomaniak/swisstransfer/ui/components/SwissTransferCard.kt index d5e4f47ec..ad4aee559 100644 --- a/app/src/main/java/com/infomaniak/swisstransfer/ui/components/SwissTransferCard.kt +++ b/app/src/main/java/com/infomaniak/swisstransfer/ui/components/SwissTransferCard.kt @@ -40,7 +40,7 @@ fun SwissTransferCard(modifier: Modifier = Modifier, content: @Composable Column modifier = modifier, shape = Shapes.medium, colors = CardDefaults.cardColors(contentColor = SwissTransferTheme.colors.secondaryTextColor), - content = content + content = content, ) } 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 ace5600c9..5226798c3 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 @@ -37,7 +37,7 @@ import com.infomaniak.swisstransfer.ui.theme.SwissTransferTheme import com.infomaniak.swisstransfer.ui.utils.PreviewLargeWindow import com.infomaniak.swisstransfer.ui.utils.PreviewSmallWindow -private const val TOTAL_FILE_SIZE: Long = 50_000_000_000 +private const val TOTAL_FILE_SIZE: Long = 50_000_000_000L @Composable fun ImportFilesScreen( diff --git a/app/src/main/java/com/infomaniak/swisstransfer/ui/screen/newtransfer/importfiles/SelectedFilesCard.kt b/app/src/main/java/com/infomaniak/swisstransfer/ui/screen/newtransfer/importfiles/SelectedFilesCard.kt index e52d9b55d..f40b31e9e 100644 --- a/app/src/main/java/com/infomaniak/swisstransfer/ui/screen/newtransfer/importfiles/SelectedFilesCard.kt +++ b/app/src/main/java/com/infomaniak/swisstransfer/ui/screen/newtransfer/importfiles/SelectedFilesCard.kt @@ -53,7 +53,7 @@ fun SelectedFilesCard( files: () -> List, formattedSizeWithUnits: () -> String, showUploadSourceChoiceBottomSheet: () -> Unit, - removeFileByUid: (uid: String) -> Unit + removeFileByUid: (uid: String) -> Unit, ) { val fileCount by remember { derivedStateOf { files().count() } } @@ -81,14 +81,14 @@ fun SelectedFilesCard( imageVector = AppImages.AppIcons.ChevronRightSmall, contentDescription = null, modifier = Modifier.padding(Margin.Medium), - tint = SwissTransferTheme.colors.iconColor + tint = SwissTransferTheme.colors.iconColor, ) } LazyRow( Modifier.fillMaxWidth(), contentPadding = PaddingValues(start = Margin.Medium, end = Margin.Medium, bottom = Margin.Medium), - horizontalArrangement = Arrangement.spacedBy(Margin.Medium) + horizontalArrangement = Arrangement.spacedBy(Margin.Medium), ) { item(key = TransferLazyRowKey(TransferLazyRowKey.Type.ADD_BUTTON)) { AddNewFileButton(Modifier.animateItem()) { showUploadSourceChoiceBottomSheet() } @@ -102,7 +102,7 @@ fun SelectedFilesCard( modifier = Modifier.animateItem(), file = file, smallFileTileSize = SmallFileTileSize.LARGE, - onRemove = { removeFileByUid(file.uid) } + onRemove = { removeFileByUid(file.uid) }, ) } } @@ -150,7 +150,7 @@ private fun AddNewFileButton(modifier: Modifier = Modifier, onClick: () -> Unit) @Parcelize private data class TransferLazyRowKey( val type: Type, - val fileUid: String? = null + val fileUid: String? = null, ) : Parcelable { enum class Type { ADD_BUTTON, FILE From 296171a87840aa1c1ac01e3f278b42d060ddced8 Mon Sep 17 00:00:00 2001 From: Gibran Chevalley Date: Fri, 18 Oct 2024 09:40:56 +0200 Subject: [PATCH 16/27] Fix merge conflict --- .../java/com/infomaniak/swisstransfer/ui/components/Buttons.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/com/infomaniak/swisstransfer/ui/components/Buttons.kt b/app/src/main/java/com/infomaniak/swisstransfer/ui/components/Buttons.kt index 23dc5853c..6a49c7b39 100644 --- a/app/src/main/java/com/infomaniak/swisstransfer/ui/components/Buttons.kt +++ b/app/src/main/java/com/infomaniak/swisstransfer/ui/components/Buttons.kt @@ -117,7 +117,7 @@ private fun CoreButton( modifier = modifier.height(buttonSize.height), colors = buttonColors, shape = CustomShapes.medium, - enabled = enabled(), + enabled = isEnabled, onClick = onClick, ) { when { From 9fedb8f80cb21a71d4bdbf864796ad57a20a257e Mon Sep 17 00:00:00 2001 From: Gibran Chevalley Date: Fri, 18 Oct 2024 09:07:17 +0200 Subject: [PATCH 17/27] Add "many" plural form to picked file translations --- app/src/main/res/values-fr/strings.xml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/src/main/res/values-fr/strings.xml b/app/src/main/res/values-fr/strings.xml index cdc2261c1..afed8fadf 100644 --- a/app/src/main/res/values-fr/strings.xml +++ b/app/src/main/res/values-fr/strings.xml @@ -28,6 +28,7 @@ %d fichier %d fichiers + % de fichiers Fais ton premier transfert ! Fichiers à transférer @@ -78,6 +79,7 @@ %s restant %s restants + %s restant E-mail Lien From f201d1fc1e0017a1139da45fe7583805ddbb6d31 Mon Sep 17 00:00:00 2001 From: Gibran Chevalley Date: Fri, 18 Oct 2024 09:10:25 +0200 Subject: [PATCH 18/27] Rewrite kotlin parcelize import using kotlin() helper --- app/build.gradle.kts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 1a9ac79ea..a8369170e 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -5,7 +5,7 @@ plugins { alias(libs.plugins.kapt) alias(libs.plugins.hilt) alias(libs.plugins.sentry) - id("kotlin-parcelize") + kotlin("plugin.parcelize") kotlin("plugin.serialization") version libs.versions.kotlin } @@ -70,7 +70,7 @@ sentry { // If you disable this, you'll need to manually upload the mapping files with sentry-cli when you do a release. // Default is enabled. autoUploadProguardMapping = true - + // Does or doesn't include the source code of native code for Sentry. // This executes sentry-cli with the --include-sources param. automatically so you don't need to do it manually. // Default is disabled. From 28b25b4bf6e6db5ee50e6aca5713833d090b6bab Mon Sep 17 00:00:00 2001 From: Gibran Chevalley Date: Fri, 18 Oct 2024 09:19:26 +0200 Subject: [PATCH 19/27] Move SelectedFilesCard to the component package --- .../ui/screen/newtransfer/importfiles/ImportFilesScreen.kt | 1 + .../importfiles/{ => components}/SelectedFilesCard.kt | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) rename app/src/main/java/com/infomaniak/swisstransfer/ui/screen/newtransfer/importfiles/{ => components}/SelectedFilesCard.kt (99%) 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 308a3c6fe..d6bf94639 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 @@ -32,6 +32,7 @@ import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.infomaniak.swisstransfer.R import com.infomaniak.swisstransfer.ui.components.* import com.infomaniak.swisstransfer.ui.screen.newtransfer.NewTransferViewModel +import com.infomaniak.swisstransfer.ui.screen.newtransfer.importfiles.components.SelectedFilesCard import com.infomaniak.swisstransfer.ui.theme.Margin import com.infomaniak.swisstransfer.ui.theme.SwissTransferTheme import com.infomaniak.swisstransfer.ui.utils.PreviewAllWindows diff --git a/app/src/main/java/com/infomaniak/swisstransfer/ui/screen/newtransfer/importfiles/SelectedFilesCard.kt b/app/src/main/java/com/infomaniak/swisstransfer/ui/screen/newtransfer/importfiles/components/SelectedFilesCard.kt similarity index 99% rename from app/src/main/java/com/infomaniak/swisstransfer/ui/screen/newtransfer/importfiles/SelectedFilesCard.kt rename to app/src/main/java/com/infomaniak/swisstransfer/ui/screen/newtransfer/importfiles/components/SelectedFilesCard.kt index ac6f21a93..bb362063f 100644 --- a/app/src/main/java/com/infomaniak/swisstransfer/ui/screen/newtransfer/importfiles/SelectedFilesCard.kt +++ b/app/src/main/java/com/infomaniak/swisstransfer/ui/screen/newtransfer/importfiles/components/SelectedFilesCard.kt @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ -package com.infomaniak.swisstransfer.ui.screen.newtransfer.importfiles +package com.infomaniak.swisstransfer.ui.screen.newtransfer.importfiles.components import android.content.Context import android.content.res.Configuration From 910f2c7a089adbbcc4f8b3148d7a3dd929d26bc2 Mon Sep 17 00:00:00 2001 From: Gibran Chevalley Date: Fri, 18 Oct 2024 09:22:13 +0200 Subject: [PATCH 20/27] Better name "human readable size" related variables --- .../importfiles/ImportFilesScreen.kt | 8 ++++---- .../importfiles/components/SelectedFilesCard.kt | 17 +++++++++-------- 2 files changed, 13 insertions(+), 12 deletions(-) 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 d6bf94639..ac49958fd 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 @@ -57,10 +57,10 @@ private fun ImportFilesScreen( ) { val context = LocalContext.current var showUploadSourceChoiceBottomSheet by rememberSaveable { mutableStateOf(true) } - val formattedSizeWithUnits by remember { + val humanReadableSize by remember { derivedStateOf { val totalFileSize = files().sumOf { it.fileSizeInBytes } - getFormattedSizeWithUnits(totalFileSize, context) + getHumanReadableSize(totalFileSize, context) } } val isSendButtonEnabled by remember { derivedStateOf { files().isNotEmpty() } } @@ -92,7 +92,7 @@ private fun ImportFilesScreen( SelectedFilesCard( modifier = Modifier.padding(Margin.Medium), files = files, - formattedSizeWithUnits = { formattedSizeWithUnits }, + humanReadableSize = { humanReadableSize }, showUploadSourceChoiceBottomSheet = { showUploadSourceChoiceBottomSheet = true }, removeFileByUid = removeFileByUid, ) @@ -106,7 +106,7 @@ private fun ImportFilesScreen( ) } -private fun getFormattedSizeWithUnits(usedSpace: Long, context: Context): String { +private fun getHumanReadableSize(usedSpace: Long, context: Context): String { val spaceLeft = (TOTAL_FILE_SIZE - usedSpace).coerceAtLeast(0) return Formatter.formatShortFileSize(context, spaceLeft) } diff --git a/app/src/main/java/com/infomaniak/swisstransfer/ui/screen/newtransfer/importfiles/components/SelectedFilesCard.kt b/app/src/main/java/com/infomaniak/swisstransfer/ui/screen/newtransfer/importfiles/components/SelectedFilesCard.kt index bb362063f..a04dc74f8 100644 --- a/app/src/main/java/com/infomaniak/swisstransfer/ui/screen/newtransfer/importfiles/components/SelectedFilesCard.kt +++ b/app/src/main/java/com/infomaniak/swisstransfer/ui/screen/newtransfer/importfiles/components/SelectedFilesCard.kt @@ -51,7 +51,7 @@ import kotlinx.parcelize.Parcelize fun SelectedFilesCard( modifier: Modifier = Modifier, files: () -> List, - formattedSizeWithUnits: () -> String, + humanReadableSize: () -> String, showUploadSourceChoiceBottomSheet: () -> Unit, removeFileByUid: (uid: String) -> Unit, ) { @@ -72,7 +72,7 @@ fun SelectedFilesCard( style = SwissTransferTheme.typography.bodySmallRegular, ) Text( - formatSpaceLeft(formattedSizeWithUnits), + formatSpaceLeft(humanReadableSize), color = SwissTransferTheme.colors.secondaryTextColor, style = SwissTransferTheme.typography.bodySmallRegular, ) @@ -110,14 +110,15 @@ fun SelectedFilesCard( } @Composable -private fun formatSpaceLeft(formattedSizeWithUnits: () -> String): String { - val formattedSize = formattedSizeWithUnits() - val quantity = LocalContext.current.getQuantityFromFormattedSizeWithUnits(formattedSize) +private fun formatSpaceLeft(humanReadableSize: () -> String): String { + val formattedSize = humanReadableSize() + val quantity = LocalContext.current.getQuantityFromHumanReadableSize(formattedSize) return pluralStringResource(R.plurals.transferSpaceLeft, quantity, formattedSize) } -private fun Context.getQuantityFromFormattedSizeWithUnits(formattedSize: String): Int { - val sizeParts = formattedSize.split(' ', Typography.nbsp) // Space for languages such as EN and NBSP for languages such as FR +private fun Context.getQuantityFromHumanReadableSize(humanReadableSize: String): Int { + // Space character for languages such as EN and NBSP character for languages such as FR + val sizeParts = humanReadableSize.split(' ', Typography.nbsp) return if (sizeParts.size == 2) { val local = resources.configuration.getLocales().get(0) @@ -176,7 +177,7 @@ private fun SelectedFilesCardPreview() { } ) }, - formattedSizeWithUnits = { "20 GB" }, + humanReadableSize = { "20 GB" }, showUploadSourceChoiceBottomSheet = {}, removeFileByUid = {} ) From b4139481240c5a87cccb7219c9cb148a74251bb4 Mon Sep 17 00:00:00 2001 From: Gibran Chevalley Date: Fri, 18 Oct 2024 09:28:47 +0200 Subject: [PATCH 21/27] Extract some human readable size operations to its own utils file --- .../importfiles/ImportFilesScreen.kt | 13 ++--- .../components/SelectedFilesCard.kt | 21 +------- .../ui/utils/HumanReadableSizeUtils.kt | 52 +++++++++++++++++++ 3 files changed, 57 insertions(+), 29 deletions(-) create mode 100644 app/src/main/java/com/infomaniak/swisstransfer/ui/utils/HumanReadableSizeUtils.kt 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 ac49958fd..7348a9b4d 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 @@ -17,9 +17,7 @@ */ package com.infomaniak.swisstransfer.ui.screen.newtransfer.importfiles -import android.content.Context import android.net.Uri -import android.text.format.Formatter import androidx.activity.compose.rememberLauncherForActivityResult import androidx.activity.result.contract.ActivityResultContracts import androidx.compose.foundation.layout.padding @@ -35,6 +33,7 @@ import com.infomaniak.swisstransfer.ui.screen.newtransfer.NewTransferViewModel import com.infomaniak.swisstransfer.ui.screen.newtransfer.importfiles.components.SelectedFilesCard import com.infomaniak.swisstransfer.ui.theme.Margin import com.infomaniak.swisstransfer.ui.theme.SwissTransferTheme +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 @@ -59,8 +58,9 @@ private fun ImportFilesScreen( var showUploadSourceChoiceBottomSheet by rememberSaveable { mutableStateOf(true) } val humanReadableSize by remember { derivedStateOf { - val totalFileSize = files().sumOf { it.fileSizeInBytes } - getHumanReadableSize(totalFileSize, context) + val usedSpace = files().sumOf { it.fileSizeInBytes } + val spaceLeft = (TOTAL_FILE_SIZE - usedSpace).coerceAtLeast(0) + getHumanReadableSize(context, spaceLeft) } } val isSendButtonEnabled by remember { derivedStateOf { files().isNotEmpty() } } @@ -106,11 +106,6 @@ private fun ImportFilesScreen( ) } -private fun getHumanReadableSize(usedSpace: Long, context: Context): String { - val spaceLeft = (TOTAL_FILE_SIZE - usedSpace).coerceAtLeast(0) - return Formatter.formatShortFileSize(context, spaceLeft) -} - @PreviewAllWindows @Composable private fun ImportFilesScreenPreview() { diff --git a/app/src/main/java/com/infomaniak/swisstransfer/ui/screen/newtransfer/importfiles/components/SelectedFilesCard.kt b/app/src/main/java/com/infomaniak/swisstransfer/ui/screen/newtransfer/importfiles/components/SelectedFilesCard.kt index a04dc74f8..a7e092fac 100644 --- a/app/src/main/java/com/infomaniak/swisstransfer/ui/screen/newtransfer/importfiles/components/SelectedFilesCard.kt +++ b/app/src/main/java/com/infomaniak/swisstransfer/ui/screen/newtransfer/importfiles/components/SelectedFilesCard.kt @@ -45,6 +45,7 @@ import com.infomaniak.swisstransfer.ui.images.icons.ChevronRightSmall 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 kotlinx.parcelize.Parcelize @Composable @@ -109,26 +110,6 @@ fun SelectedFilesCard( } } -@Composable -private fun formatSpaceLeft(humanReadableSize: () -> String): String { - val formattedSize = humanReadableSize() - val quantity = LocalContext.current.getQuantityFromHumanReadableSize(formattedSize) - return pluralStringResource(R.plurals.transferSpaceLeft, quantity, formattedSize) -} - -private fun Context.getQuantityFromHumanReadableSize(humanReadableSize: String): Int { - // Space character for languages such as EN and NBSP character for languages such as FR - val sizeParts = humanReadableSize.split(' ', Typography.nbsp) - - return if (sizeParts.size == 2) { - val local = resources.configuration.getLocales().get(0) - val parsedNumber = NumberFormat.getInstance(local).parse(sizeParts[0]) - parsedNumber?.toDouble()?.toInt() ?: 0 - } else { - 0 - } -} - @Composable private fun AddNewFileButton(modifier: Modifier = Modifier, onClick: () -> Unit) { Button( diff --git a/app/src/main/java/com/infomaniak/swisstransfer/ui/utils/HumanReadableSizeUtils.kt b/app/src/main/java/com/infomaniak/swisstransfer/ui/utils/HumanReadableSizeUtils.kt new file mode 100644 index 000000000..2ed8ef796 --- /dev/null +++ b/app/src/main/java/com/infomaniak/swisstransfer/ui/utils/HumanReadableSizeUtils.kt @@ -0,0 +1,52 @@ +/* + * 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.utils + +import android.content.Context +import android.icu.text.NumberFormat +import android.text.format.Formatter +import androidx.compose.runtime.Composable +import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.res.pluralStringResource +import com.infomaniak.swisstransfer.R + +object HumanReadableSizeUtils { + fun getHumanReadableSize(context: Context, sizeInBytes: Long): String { + return Formatter.formatShortFileSize(context, sizeInBytes) + } + + @Composable + fun formatSpaceLeft(humanReadableSize: () -> String): String { + val formattedSize = humanReadableSize() + val quantity = LocalContext.current.getQuantityFromHumanReadableSize(formattedSize) + return pluralStringResource(R.plurals.transferSpaceLeft, quantity, formattedSize) + } + + private fun Context.getQuantityFromHumanReadableSize(humanReadableSize: String): Int { + // Space character for languages such as EN and NBSP character for languages such as FR + val sizeParts = humanReadableSize.split(' ', Typography.nbsp) + + return if (sizeParts.size == 2) { + val local = resources.configuration.getLocales().get(0) + val parsedNumber = NumberFormat.getInstance(local).parse(sizeParts[0]) + parsedNumber?.toDouble()?.toInt() ?: 0 + } else { + 0 + } + } +} From dba4637c9dbedcad04cab500f473e1bc764bad86 Mon Sep 17 00:00:00 2001 From: Gibran Chevalley Date: Fri, 18 Oct 2024 09:32:49 +0200 Subject: [PATCH 22/27] Remove wrong usage of derivedStateOf --- .../newtransfer/importfiles/ImportFilesScreen.kt | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) 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 7348a9b4d..f52a29144 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 @@ -56,14 +56,15 @@ private fun ImportFilesScreen( ) { val context = LocalContext.current var showUploadSourceChoiceBottomSheet by rememberSaveable { mutableStateOf(true) } - val humanReadableSize by remember { - derivedStateOf { - val usedSpace = files().sumOf { it.fileSizeInBytes } - val spaceLeft = (TOTAL_FILE_SIZE - usedSpace).coerceAtLeast(0) - getHumanReadableSize(context, spaceLeft) - } + + val importedFiles = files() + val humanReadableSize = remember(importedFiles) { + val usedSpace = importedFiles.sumOf { it.fileSizeInBytes } + val spaceLeft = (TOTAL_FILE_SIZE - usedSpace).coerceAtLeast(0) + getHumanReadableSize(context, spaceLeft) } - val isSendButtonEnabled by remember { derivedStateOf { files().isNotEmpty() } } + + val isSendButtonEnabled by remember { derivedStateOf { importedFiles.isNotEmpty() } } val filePickerLauncher = rememberLauncherForActivityResult( contract = ActivityResultContracts.OpenMultipleDocuments() From d71856689d2472ce0ad876b770b91032f3d9fa25 Mon Sep 17 00:00:00 2001 From: Gibran Chevalley Date: Fri, 18 Oct 2024 09:33:49 +0200 Subject: [PATCH 23/27] Rename SelectedFilesCard into ImportedFilesCard --- .../screen/newtransfer/importfiles/ImportFilesScreen.kt | 4 ++-- .../{SelectedFilesCard.kt => ImportedFilesCard.kt} | 9 +++------ 2 files changed, 5 insertions(+), 8 deletions(-) rename app/src/main/java/com/infomaniak/swisstransfer/ui/screen/newtransfer/importfiles/components/{SelectedFilesCard.kt => ImportedFilesCard.kt} (96%) 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 f52a29144..7e2314780 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,7 @@ import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.infomaniak.swisstransfer.R import com.infomaniak.swisstransfer.ui.components.* import com.infomaniak.swisstransfer.ui.screen.newtransfer.NewTransferViewModel -import com.infomaniak.swisstransfer.ui.screen.newtransfer.importfiles.components.SelectedFilesCard +import com.infomaniak.swisstransfer.ui.screen.newtransfer.importfiles.components.ImportedFilesCard import com.infomaniak.swisstransfer.ui.theme.Margin import com.infomaniak.swisstransfer.ui.theme.SwissTransferTheme import com.infomaniak.swisstransfer.ui.utils.HumanReadableSizeUtils.getHumanReadableSize @@ -90,7 +90,7 @@ private fun ImportFilesScreen( ) }, content = { - SelectedFilesCard( + ImportedFilesCard( modifier = Modifier.padding(Margin.Medium), files = files, humanReadableSize = { humanReadableSize }, diff --git a/app/src/main/java/com/infomaniak/swisstransfer/ui/screen/newtransfer/importfiles/components/SelectedFilesCard.kt b/app/src/main/java/com/infomaniak/swisstransfer/ui/screen/newtransfer/importfiles/components/ImportedFilesCard.kt similarity index 96% rename from app/src/main/java/com/infomaniak/swisstransfer/ui/screen/newtransfer/importfiles/components/SelectedFilesCard.kt rename to app/src/main/java/com/infomaniak/swisstransfer/ui/screen/newtransfer/importfiles/components/ImportedFilesCard.kt index a7e092fac..3f5bd174a 100644 --- a/app/src/main/java/com/infomaniak/swisstransfer/ui/screen/newtransfer/importfiles/components/SelectedFilesCard.kt +++ b/app/src/main/java/com/infomaniak/swisstransfer/ui/screen/newtransfer/importfiles/components/ImportedFilesCard.kt @@ -17,9 +17,7 @@ */ package com.infomaniak.swisstransfer.ui.screen.newtransfer.importfiles.components -import android.content.Context import android.content.res.Configuration -import android.icu.text.NumberFormat import android.os.Parcelable import androidx.compose.foundation.layout.* import androidx.compose.foundation.lazy.LazyRow @@ -33,7 +31,6 @@ 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.Preview import androidx.compose.ui.unit.dp @@ -49,7 +46,7 @@ import com.infomaniak.swisstransfer.ui.utils.HumanReadableSizeUtils.formatSpaceL import kotlinx.parcelize.Parcelize @Composable -fun SelectedFilesCard( +fun ImportedFilesCard( modifier: Modifier = Modifier, files: () -> List, humanReadableSize: () -> String, @@ -143,9 +140,9 @@ private data class TransferLazyRowKey( @Preview(name = "Light") @Preview(name = "Dark", uiMode = Configuration.UI_MODE_NIGHT_YES or Configuration.UI_MODE_TYPE_NORMAL) @Composable -private fun SelectedFilesCardPreview() { +private fun ImportededFilesCardPreview() { SwissTransferTheme { - SelectedFilesCard( + ImportedFilesCard( modifier = Modifier.padding(Margin.Medium), files = { listOf( From 2fd4cca51feb6086dd33fcf9f033b8a0e0e79b31 Mon Sep 17 00:00:00 2001 From: Gibran Chevalley Date: Fri, 18 Oct 2024 09:35:09 +0200 Subject: [PATCH 24/27] Better write CrossCircleButton --- .../swisstransfer/ui/components/CrossCircleButton.kt | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/app/src/main/java/com/infomaniak/swisstransfer/ui/components/CrossCircleButton.kt b/app/src/main/java/com/infomaniak/swisstransfer/ui/components/CrossCircleButton.kt index 1f910edef..10a8c525a 100644 --- a/app/src/main/java/com/infomaniak/swisstransfer/ui/components/CrossCircleButton.kt +++ b/app/src/main/java/com/infomaniak/swisstransfer/ui/components/CrossCircleButton.kt @@ -17,6 +17,7 @@ */ package com.infomaniak.swisstransfer.ui.components +import android.content.res.Configuration import androidx.compose.foundation.layout.* import androidx.compose.foundation.shape.CircleShape import androidx.compose.material3.* @@ -26,6 +27,7 @@ import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.compose.ui.res.stringResource +import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.coerceAtLeast import androidx.compose.ui.unit.dp @@ -34,15 +36,13 @@ import com.infomaniak.swisstransfer.ui.images.AppImages import com.infomaniak.swisstransfer.ui.images.icons.CrossThick import com.infomaniak.swisstransfer.ui.theme.Margin import com.infomaniak.swisstransfer.ui.theme.SwissTransferTheme -import com.infomaniak.swisstransfer.ui.utils.PreviewLargeWindow -import com.infomaniak.swisstransfer.ui.utils.PreviewSmallWindow @Composable @OptIn(ExperimentalMaterial3Api::class) fun BoxScope.CrossCircleButton(onClick: (() -> Unit)?, size: Dp = 48.dp) { - CompositionLocalProvider(LocalRippleConfiguration provides RippleConfiguration(color = Color.White)) { - val buttonPadding = ((size - 24.dp) / 2f).coerceAtLeast(0.dp) + val buttonPadding = ((size - 24.dp) / 2f).coerceAtLeast(0.dp) + CompositionLocalProvider(LocalRippleConfiguration provides RippleConfiguration(color = Color.White)) { Button( modifier = Modifier .size(size) @@ -64,8 +64,8 @@ fun BoxScope.CrossCircleButton(onClick: (() -> Unit)?, size: Dp = 48.dp) { } -@PreviewSmallWindow -@PreviewLargeWindow +@Preview(name = "Light") +@Preview(name = "Dark", uiMode = Configuration.UI_MODE_NIGHT_YES or Configuration.UI_MODE_TYPE_NORMAL) @Composable private fun CrossCircleButtonPreview() { SwissTransferTheme { From 740d3b9e53e9d04b9787eb542f6a129521bbba55 Mon Sep 17 00:00:00 2001 From: Gibran Chevalley Date: Fri, 18 Oct 2024 09:36:20 +0200 Subject: [PATCH 25/27] Rename SmallFileTile into SmallFileItem --- .../ui/components/{SmallFileTile.kt => SmallFileItem.kt} | 8 ++++---- .../importfiles/components/ImportedFilesCard.kt | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) rename app/src/main/java/com/infomaniak/swisstransfer/ui/components/{SmallFileTile.kt => SmallFileItem.kt} (96%) diff --git a/app/src/main/java/com/infomaniak/swisstransfer/ui/components/SmallFileTile.kt b/app/src/main/java/com/infomaniak/swisstransfer/ui/components/SmallFileItem.kt similarity index 96% rename from app/src/main/java/com/infomaniak/swisstransfer/ui/components/SmallFileTile.kt rename to app/src/main/java/com/infomaniak/swisstransfer/ui/components/SmallFileItem.kt index 6ddadc336..1811567c7 100644 --- a/app/src/main/java/com/infomaniak/swisstransfer/ui/components/SmallFileTile.kt +++ b/app/src/main/java/com/infomaniak/swisstransfer/ui/components/SmallFileItem.kt @@ -33,7 +33,7 @@ import com.infomaniak.swisstransfer.ui.theme.CustomShapes import com.infomaniak.swisstransfer.ui.theme.SwissTransferTheme @Composable -fun SmallFileTile( +fun SmallFileItem( modifier: Modifier = Modifier, file: FileUiItem, smallFileTileSize: SmallFileTileSize, @@ -65,11 +65,11 @@ enum class SmallFileTileSize(val size: Dp, val shape: Shape) { @Preview(name = "Light") @Preview(name = "Dark", uiMode = Configuration.UI_MODE_NIGHT_YES or Configuration.UI_MODE_TYPE_NORMAL) @Composable -private fun SmallFileTilePreview() { +private fun SmallFileItemPreview() { SwissTransferTheme { Surface(color = SwissTransferTheme.materialColors.surfaceContainerHighest) { Column(Modifier.padding(16.dp)) { - SmallFileTile( + SmallFileItem( file = object : FileUiItem { override val fileName: String = "How to not get fired.pdf" override val uid: String = fileName @@ -83,7 +83,7 @@ private fun SmallFileTilePreview() { Spacer(modifier = Modifier.height(16.dp)) - SmallFileTile( + SmallFileItem( file = object : FileUiItem { override val fileName: String = "How to not get fired.pdf" override val uid: String = fileName 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 3f5bd174a..2663051e0 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 @@ -96,7 +96,7 @@ fun ImportedFilesCard( items = files().asReversed(), key = { TransferLazyRowKey(TransferLazyRowKey.Type.FILE, it.uid) }, ) { file -> - SmallFileTile( + SmallFileItem( modifier = Modifier.animateItem(), file = file, smallFileTileSize = SmallFileTileSize.LARGE, From 7e64047daff852225638571820df4923880c8843 Mon Sep 17 00:00:00 2001 From: Gibran Chevalley Date: Fri, 18 Oct 2024 09:37:42 +0200 Subject: [PATCH 26/27] Optimize ImportedFilesCard --- .../importfiles/components/ImportedFilesCard.kt | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) 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 2663051e0..c8fc22e65 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 @@ -27,9 +27,6 @@ import androidx.compose.material3.ButtonDefaults import androidx.compose.material3.Icon import androidx.compose.material3.Text 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.res.pluralStringResource import androidx.compose.ui.tooling.preview.Preview @@ -53,7 +50,8 @@ fun ImportedFilesCard( showUploadSourceChoiceBottomSheet: () -> Unit, removeFileByUid: (uid: String) -> Unit, ) { - val fileCount by remember { derivedStateOf { files().count() } } + val importedFiles = files() + val fileCount = importedFiles.count() SwissTransferCard(modifier) { SharpRippleButton(onClick = { /*TODO*/ }) { @@ -93,7 +91,7 @@ fun ImportedFilesCard( } items( - items = files().asReversed(), + items = importedFiles.asReversed(), key = { TransferLazyRowKey(TransferLazyRowKey.Type.FILE, it.uid) }, ) { file -> SmallFileItem( From da57824fdb878861e5e9ee4ef68d6d064d783409 Mon Sep 17 00:00:00 2001 From: Gibran Chevalley Date: Fri, 18 Oct 2024 09:39:20 +0200 Subject: [PATCH 27/27] Replace [0] accessor with .first() --- .../infomaniak/swisstransfer/ui/utils/HumanReadableSizeUtils.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/com/infomaniak/swisstransfer/ui/utils/HumanReadableSizeUtils.kt b/app/src/main/java/com/infomaniak/swisstransfer/ui/utils/HumanReadableSizeUtils.kt index 2ed8ef796..1ea0e0e32 100644 --- a/app/src/main/java/com/infomaniak/swisstransfer/ui/utils/HumanReadableSizeUtils.kt +++ b/app/src/main/java/com/infomaniak/swisstransfer/ui/utils/HumanReadableSizeUtils.kt @@ -43,7 +43,7 @@ object HumanReadableSizeUtils { return if (sizeParts.size == 2) { val local = resources.configuration.getLocales().get(0) - val parsedNumber = NumberFormat.getInstance(local).parse(sizeParts[0]) + val parsedNumber = NumberFormat.getInstance(local).parse(sizeParts.first()) parsedNumber?.toDouble()?.toInt() ?: 0 } else { 0