Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adds and use the component to display picked files during a new transfer #87

Merged
merged 30 commits into from
Oct 18, 2024
Merged
Show file tree
Hide file tree
Changes from 17 commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
ac2a71a
List amount of selected files and add button
LunarX Oct 3, 2024
5436a1a
Display the list of picked files using SmallFileTile
LunarX Oct 10, 2024
4f88a82
Factorize file preview logic between FileTile and SmallFileTile
LunarX Oct 10, 2024
7387299
Remove old TransferFile names from methods and variables
LunarX Oct 10, 2024
255b4f0
Remove imported files when clicking the remove button and animate it all
LunarX Oct 10, 2024
ed9de91
Use correct strings for the files to transfers
LunarX Oct 10, 2024
3be3c11
Find a way to detect the quantity of left file size for plural string
LunarX Oct 11, 2024
0cec152
Clean code
LunarX Oct 11, 2024
733ddaa
Optimize recomposition of space left plural string
LunarX Oct 11, 2024
f04a015
Use a lambda for `enabled` in swiss transfer buttons to avoid recompo…
LunarX Oct 11, 2024
0c826bc
Extract composables into a SelectedFilesCard for readability
LunarX Oct 11, 2024
325ba35
Extract SelectedFilesCard to its own component
LunarX Oct 11, 2024
f0d95c1
Put last imported as the first items in the SelectedFilesCard
LunarX Oct 15, 2024
f2f6fae
Fix padding around SelectedFilesCard
LunarX Oct 16, 2024
776a4c9
Add missing comas
tevincent Oct 17, 2024
6c5ba5c
Merge remote-tracking branch 'origin/main' into display-picked-files
LunarX Oct 17, 2024
874b204
Merge remote-tracking branch 'origin/main' into display-picked-files
LunarX Oct 17, 2024
8614712
Merge remote-tracking branch 'origin/main' into display-picked-files
LunarX Oct 18, 2024
296171a
Fix merge conflict
LunarX Oct 18, 2024
9fedb8f
Add "many" plural form to picked file translations
LunarX Oct 18, 2024
f201d1f
Rewrite kotlin parcelize import using kotlin() helper
LunarX Oct 18, 2024
28b25b4
Move SelectedFilesCard to the component package
LunarX Oct 18, 2024
910f2c7
Better name "human readable size" related variables
LunarX Oct 18, 2024
b413948
Extract some human readable size operations to its own utils file
LunarX Oct 18, 2024
dba4637
Remove wrong usage of derivedStateOf
LunarX Oct 18, 2024
d718566
Rename SelectedFilesCard into ImportedFilesCard
LunarX Oct 18, 2024
2fd4cca
Better write CrossCircleButton
LunarX Oct 18, 2024
740d3b9
Rename SmallFileTile into SmallFileItem
LunarX Oct 18, 2024
7e64047
Optimize ImportedFilesCard
LunarX Oct 18, 2024
da57824
Replace [0] accessor with .first()
LunarX Oct 18, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ plugins {
alias(libs.plugins.kapt)
alias(libs.plugins.hilt)
alias(libs.plugins.sentry)
id("kotlin-parcelize")
LunarX marked this conversation as resolved.
Show resolved Hide resolved
kotlin("plugin.serialization") version libs.versions.kotlin
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ fun LargeButton(
@StringRes titleRes: Int,
modifier: Modifier = Modifier,
style: ButtonType = ButtonType.PRIMARY,
enabled: Boolean = true,
enabled: () -> Boolean = { true },
onClick: () -> Unit,
imageVector: ImageVector? = null,
) {
Expand All @@ -54,7 +54,7 @@ fun SmallButton(
@StringRes titleRes: Int,
modifier: Modifier = Modifier,
style: ButtonType = ButtonType.PRIMARY,
enabled: Boolean = true,
enabled: () -> Boolean = { true },
onClick: () -> Unit,
imageVector: ImageVector? = null,
) {
Expand All @@ -67,15 +67,15 @@ private fun CoreButton(
modifier: Modifier,
buttonSize: ButtonSize,
style: ButtonType,
enabled: Boolean,
enabled: () -> Boolean,
onClick: () -> Unit,
imageVector: ImageVector?,
) {
Button(
modifier = modifier.height(buttonSize.height),
colors = style.buttonColors(),
shape = CustomShapes.medium,
enabled = enabled,
enabled = enabled(),
onClick = onClick,
) {
imageVector?.let {
Expand Down
Original file line number Diff line number Diff line change
@@ -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 <http://www.gnu.org/licenses/>.
*/
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)
LunarX marked this conversation as resolved.
Show resolved Hide resolved

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({})
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,22 +17,15 @@
*/
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
Expand All @@ -48,8 +41,6 @@ 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
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 {
Expand All @@ -71,13 +62,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)
}
FilePreview(
file = file,
circleColor = SwissTransferTheme.materialColors.surface,
circleSize = 64.dp,
)
},
onClick = onClick,
isCheckboxVisible = isCheckboxVisible,
Expand Down Expand Up @@ -125,25 +114,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)) {
Expand All @@ -165,37 +136,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(),
)
}

@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
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
/*
* 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 <http://www.gnu.org/licenses/>.
*/
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.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 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)
}

Icon(
modifier = Modifier.size(circleSize / 2),
imageVector = fileType.icon,
contentDescription = null,
tint = fileType.color(LocalIsDarkMode.current),
)
}
}
sirambd marked this conversation as resolved.
Show resolved Hide resolved
Loading
Loading