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 fc82cf8eb..1ea5aab9a 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 @@ -20,15 +20,11 @@ package com.infomaniak.swisstransfer.ui.components import android.content.res.Configuration import androidx.annotation.StringRes import androidx.compose.foundation.layout.* -import androidx.compose.material3.* +import androidx.compose.material3.Icon +import androidx.compose.material3.Surface +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.Alignment import androidx.compose.ui.Modifier -import androidx.compose.ui.draw.alpha -import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.vector.ImageVector import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.Preview @@ -37,7 +33,6 @@ import androidx.compose.ui.unit.dp import com.infomaniak.swisstransfer.R import com.infomaniak.swisstransfer.ui.images.AppImages.AppIcons import com.infomaniak.swisstransfer.ui.images.icons.Add -import com.infomaniak.swisstransfer.ui.theme.CustomShapes import com.infomaniak.swisstransfer.ui.theme.Dimens import com.infomaniak.swisstransfer.ui.theme.Margin import com.infomaniak.swisstransfer.ui.theme.SwissTransferTheme @@ -108,43 +103,15 @@ private fun CoreButton( onClick: () -> Unit, imageVector: ImageVector?, ) { - val isEnabled by remember(progress) { derivedStateOf { enabled() && !showIndeterminateProgress() && progress == null } } - val buttonColors = style.buttonColors() - - Button( - modifier = modifier.height(buttonSize.height), - colors = buttonColors, - shape = CustomShapes.MEDIUM, - enabled = isEnabled, - onClick = onClick, + SwissTransferButton( + modifier.height(buttonSize.height), + style, + enabled, + showIndeterminateProgress, + progress, + onClick, ) { - when { - progress != null -> { - val (progressColor, progressModifier) = getProgressSpecs(buttonColors) - KeepButtonSize(imageVector, titleRes) { - CircularProgressIndicator(modifier = progressModifier, color = progressColor, progress = progress) - } - } - showIndeterminateProgress() -> { - val (progressColor, progressModifier) = getProgressSpecs(buttonColors) - KeepButtonSize(imageVector, titleRes) { - CircularProgressIndicator(modifier = progressModifier, color = progressColor) - } - } - else -> { - ButtonTextContent(imageVector, titleRes) - } - } - } -} - -@Composable -fun KeepButtonSize(imageVector: ImageVector?, titleRes: Int, content: @Composable () -> Unit) { - Box(contentAlignment = Alignment.Center) { - Row(modifier = Modifier.alpha(0f)) { - ButtonTextContent(imageVector, titleRes) - } - content() + ButtonTextContent(imageVector, titleRes) } } @@ -157,42 +124,6 @@ private fun ButtonTextContent(imageVector: ImageVector?, titleRes: Int) { Text(text = stringResource(id = titleRes), style = SwissTransferTheme.typography.bodyMedium) } -@Composable -private fun getProgressSpecs(buttonColors: ButtonColors): Pair { - val progressColor = buttonColors.disabledContentColor - val progressModifier = Modifier - .fillMaxHeight(0.8f) - .aspectRatio(1f) - return Pair(progressColor, progressModifier) -} - -enum class ButtonType(val buttonColors: @Composable () -> ButtonColors) { - PRIMARY({ - ButtonDefaults.buttonColors( - containerColor = SwissTransferTheme.materialColors.primary, - contentColor = SwissTransferTheme.materialColors.onPrimary, - ) - }), - SECONDARY({ - ButtonDefaults.buttonColors( - containerColor = SwissTransferTheme.colors.tertiaryButtonBackground, - contentColor = SwissTransferTheme.materialColors.primary, - ) - }), - TERTIARY({ - ButtonDefaults.buttonColors( - containerColor = Color.Transparent, - contentColor = SwissTransferTheme.materialColors.primary, - ) - }), - ERROR({ - ButtonDefaults.buttonColors( - containerColor = SwissTransferTheme.materialColors.error, - contentColor = SwissTransferTheme.materialColors.onError, - ) - }), -} - private enum class ButtonSize(val height: Dp) { LARGE(Dimens.LargeButtonHeight), SMALL(40.dp), diff --git a/app/src/main/java/com/infomaniak/swisstransfer/ui/components/SwissTransferButton.kt b/app/src/main/java/com/infomaniak/swisstransfer/ui/components/SwissTransferButton.kt new file mode 100644 index 000000000..dd9b7b6c1 --- /dev/null +++ b/app/src/main/java/com/infomaniak/swisstransfer/ui/components/SwissTransferButton.kt @@ -0,0 +1,160 @@ +/* + * 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.material3.* +import androidx.compose.runtime.Composable +import androidx.compose.runtime.derivedStateOf +import androidx.compose.runtime.getValue +import androidx.compose.runtime.remember +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.alpha +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.unit.dp +import com.infomaniak.swisstransfer.ui.theme.CustomShapes +import com.infomaniak.swisstransfer.ui.theme.SwissTransferTheme +import com.infomaniak.swisstransfer.ui.utils.PreviewLightAndDark + + +/** + * Most basic and customizable button component. + * + * Only needed for exceptional edge cases where [LargeButton] or [SmallButton] are not enough and we need more control over the + * button component. + * + * Specifying a progress has the priority over specifying showIndeterminateProgress. + */ +@Composable +fun SwissTransferButton( + modifier: Modifier = Modifier, + style: ButtonType = ButtonType.PRIMARY, + enabled: () -> Boolean = { true }, + showIndeterminateProgress: () -> Boolean = { false }, + progress: (() -> Float)? = null, + onClick: () -> Unit, + contentPadding: PaddingValues = ButtonDefaults.ContentPadding, + content: @Composable () -> Unit, +) { + val isEnabled by remember(progress) { derivedStateOf { enabled() && !showIndeterminateProgress() && progress == null } } + val buttonColors = style.buttonColors() + + Button( + modifier = modifier, + colors = buttonColors, + shape = CustomShapes.MEDIUM, + enabled = isEnabled, + contentPadding = contentPadding, + onClick = onClick, + ) { + when { + progress != null -> { + val (progressColor, progressModifier) = getProgressSpecs(buttonColors) + KeepButtonSize(content) { + CircularProgressIndicator(modifier = progressModifier, color = progressColor, progress = progress) + } + } + showIndeterminateProgress() -> { + val (progressColor, progressModifier) = getProgressSpecs(buttonColors) + KeepButtonSize(content) { + CircularProgressIndicator(modifier = progressModifier, color = progressColor) + } + } + else -> content() + } + } +} + +@Composable +private fun KeepButtonSize(targetSizeContent: @Composable () -> Unit, content: @Composable () -> Unit) { + Box(contentAlignment = Alignment.Center) { + Row(modifier = Modifier.alpha(0f)) { + targetSizeContent() + } + content() + } +} + +@Composable +private fun getProgressSpecs(buttonColors: ButtonColors): Pair { + val progressColor = buttonColors.disabledContentColor + val progressModifier = Modifier + .fillMaxHeight(0.8f) + .aspectRatio(1f) + return Pair(progressColor, progressModifier) +} + +enum class ButtonType(val buttonColors: @Composable () -> ButtonColors) { + PRIMARY({ + ButtonDefaults.buttonColors( + containerColor = SwissTransferTheme.materialColors.primary, + contentColor = SwissTransferTheme.materialColors.onPrimary, + ) + }), + SECONDARY({ + ButtonDefaults.buttonColors( + containerColor = SwissTransferTheme.colors.tertiaryButtonBackground, + contentColor = SwissTransferTheme.materialColors.primary, + ) + }), + TERTIARY({ + ButtonDefaults.buttonColors( + containerColor = Color.Transparent, + contentColor = SwissTransferTheme.materialColors.primary, + ) + }), + ERROR({ + ButtonDefaults.buttonColors( + containerColor = SwissTransferTheme.materialColors.error, + contentColor = SwissTransferTheme.materialColors.onError, + ) + }), +} + + +@PreviewLightAndDark +@Composable +private fun Preview() { + SwissTransferTheme { + Surface { + Column(verticalArrangement = Arrangement.spacedBy(8.dp)) { + ButtonType.entries.forEach { buttonType -> + Row { + SwissTransferButton( + modifier = Modifier.height(40.dp), + style = buttonType, + onClick = {}, + content = { Text("Click me!") }, + ) + + Spacer(modifier = Modifier.width(12.dp)) + + SwissTransferButton( + modifier = Modifier.height(40.dp), + style = buttonType, + onClick = {}, + progress = { 0.8f }, + content = { Text("Click me!") }, + ) + } + } + } + } + } +}