From 25874f429e0eee7682ae3ed8b65a3458516c992f Mon Sep 17 00:00:00 2001 From: Gibran Chevalley Date: Mon, 25 Nov 2024 08:45:29 +0100 Subject: [PATCH 1/8] feat: Better abstract Button content logic by introducing GenericButton --- .../swisstransfer/ui/components/Buttons.kt | 46 ++++++++++++++----- 1 file changed, 34 insertions(+), 12 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 fc82cf8eb..4cb27d802 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 @@ -56,7 +56,7 @@ fun LargeButton( onClick: () -> Unit, imageVector: ImageVector? = null, ) { - CoreButton( + CoreTextButton( titleRes, modifier, ButtonSize.LARGE, @@ -83,7 +83,7 @@ fun SmallButton( onClick: () -> Unit, imageVector: ImageVector? = null, ) { - CoreButton( + CoreTextButton( titleRes, modifier, ButtonSize.SMALL, @@ -97,8 +97,8 @@ fun SmallButton( } @Composable -private fun CoreButton( - @StringRes titleRes: Int, +private fun CoreTextButton( + titleRes: Int, modifier: Modifier, buttonSize: ButtonSize, style: ButtonType, @@ -107,42 +107,64 @@ private fun CoreButton( progress: (() -> Float)?, onClick: () -> Unit, imageVector: ImageVector?, +) { + GenericButton( + modifier.height(buttonSize.height), + style, + enabled, + showIndeterminateProgress, + progress, + onClick, + ) { + ButtonTextContent(imageVector, titleRes) + } +} + +@Composable +fun GenericButton( + 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.height(buttonSize.height), + modifier = modifier, colors = buttonColors, shape = CustomShapes.MEDIUM, enabled = isEnabled, + contentPadding = contentPadding, onClick = onClick, ) { when { progress != null -> { val (progressColor, progressModifier) = getProgressSpecs(buttonColors) - KeepButtonSize(imageVector, titleRes) { + KeepButtonSize(content) { CircularProgressIndicator(modifier = progressModifier, color = progressColor, progress = progress) } } showIndeterminateProgress() -> { val (progressColor, progressModifier) = getProgressSpecs(buttonColors) - KeepButtonSize(imageVector, titleRes) { + KeepButtonSize(content) { CircularProgressIndicator(modifier = progressModifier, color = progressColor) } } - else -> { - ButtonTextContent(imageVector, titleRes) - } + else -> content() } } } @Composable -fun KeepButtonSize(imageVector: ImageVector?, titleRes: Int, content: @Composable () -> Unit) { +fun KeepButtonSize(targetSizeContent: @Composable () -> Unit, content: @Composable () -> Unit) { Box(contentAlignment = Alignment.Center) { Row(modifier = Modifier.alpha(0f)) { - ButtonTextContent(imageVector, titleRes) + targetSizeContent() } content() } From 2bcd41b58348b7726553a024a1138c44f1d674ed Mon Sep 17 00:00:00 2001 From: Gibran Chevalley Date: Mon, 25 Nov 2024 14:07:42 +0100 Subject: [PATCH 2/8] refactor: Move generic button to its own file --- .../swisstransfer/ui/components/Buttons.kt | 97 +----------- .../ui/components/GenericButton.kt | 149 ++++++++++++++++++ 2 files changed, 152 insertions(+), 94 deletions(-) create mode 100644 app/src/main/java/com/infomaniak/swisstransfer/ui/components/GenericButton.kt 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 4cb27d802..83a714b56 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 @@ -120,56 +115,6 @@ private fun CoreTextButton( } } -@Composable -fun GenericButton( - 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 -fun KeepButtonSize(targetSizeContent: @Composable () -> Unit, content: @Composable () -> Unit) { - Box(contentAlignment = Alignment.Center) { - Row(modifier = Modifier.alpha(0f)) { - targetSizeContent() - } - content() - } -} - @Composable private fun ButtonTextContent(imageVector: ImageVector?, titleRes: Int) { imageVector?.let { @@ -179,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/GenericButton.kt b/app/src/main/java/com/infomaniak/swisstransfer/ui/components/GenericButton.kt new file mode 100644 index 000000000..6237d28c5 --- /dev/null +++ b/app/src/main/java/com/infomaniak/swisstransfer/ui/components/GenericButton.kt @@ -0,0 +1,149 @@ +/* + * 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 + +@Composable +fun GenericButton( + 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 +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 { + GenericButton( + modifier = Modifier.height(40.dp), + style = buttonType, + onClick = {}, + content = { Text("Click me!") }, + ) + + Spacer(modifier = Modifier.width(12.dp)) + + GenericButton( + modifier = Modifier.height(40.dp), + style = buttonType, + onClick = {}, + progress = { 0.8f }, + content = { Text("Click me!") }, + ) + } + } + } + } + } +} From dd9cb6db94729e6ab942da8bff5469cdcddcaced Mon Sep 17 00:00:00 2001 From: Gibran Chevalley Date: Mon, 25 Nov 2024 15:24:29 +0100 Subject: [PATCH 3/8] docs: Add some clarifications on GenericButton --- .../swisstransfer/ui/components/GenericButton.kt | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/app/src/main/java/com/infomaniak/swisstransfer/ui/components/GenericButton.kt b/app/src/main/java/com/infomaniak/swisstransfer/ui/components/GenericButton.kt index 6237d28c5..83ff93e10 100644 --- a/app/src/main/java/com/infomaniak/swisstransfer/ui/components/GenericButton.kt +++ b/app/src/main/java/com/infomaniak/swisstransfer/ui/components/GenericButton.kt @@ -32,6 +32,15 @@ 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 GenericButton( modifier: Modifier = Modifier, From 3fed918354753e6a9a78ba8114b23ddd6cb95624 Mon Sep 17 00:00:00 2001 From: Gibran Chevalley Date: Mon, 25 Nov 2024 15:26:47 +0100 Subject: [PATCH 4/8] style: Rename CoreTextButton into CoreButton --- .../com/infomaniak/swisstransfer/ui/components/Buttons.kt | 6 +++--- 1 file changed, 3 insertions(+), 3 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 83a714b56..77a5e1a06 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 @@ -51,7 +51,7 @@ fun LargeButton( onClick: () -> Unit, imageVector: ImageVector? = null, ) { - CoreTextButton( + CoreButton( titleRes, modifier, ButtonSize.LARGE, @@ -78,7 +78,7 @@ fun SmallButton( onClick: () -> Unit, imageVector: ImageVector? = null, ) { - CoreTextButton( + CoreButton( titleRes, modifier, ButtonSize.SMALL, @@ -92,7 +92,7 @@ fun SmallButton( } @Composable -private fun CoreTextButton( +private fun CoreButton( titleRes: Int, modifier: Modifier, buttonSize: ButtonSize, From a5457fe862626a20a7394257fe91b6fb0a362ab4 Mon Sep 17 00:00:00 2001 From: Gibran Chevalley Date: Mon, 25 Nov 2024 15:33:11 +0100 Subject: [PATCH 5/8] style: Add missing new lines --- .../com/infomaniak/swisstransfer/ui/components/GenericButton.kt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/src/main/java/com/infomaniak/swisstransfer/ui/components/GenericButton.kt b/app/src/main/java/com/infomaniak/swisstransfer/ui/components/GenericButton.kt index 83ff93e10..95f25af31 100644 --- a/app/src/main/java/com/infomaniak/swisstransfer/ui/components/GenericButton.kt +++ b/app/src/main/java/com/infomaniak/swisstransfer/ui/components/GenericButton.kt @@ -80,6 +80,7 @@ fun GenericButton( } } } + @Composable fun KeepButtonSize(targetSizeContent: @Composable () -> Unit, content: @Composable () -> Unit) { Box(contentAlignment = Alignment.Center) { @@ -89,6 +90,7 @@ fun KeepButtonSize(targetSizeContent: @Composable () -> Unit, content: @Composab content() } } + @Composable private fun getProgressSpecs(buttonColors: ButtonColors): Pair { val progressColor = buttonColors.disabledContentColor From 85cabc98b12427dc9220b631c14927c689926a9d Mon Sep 17 00:00:00 2001 From: Gibran Chevalley Date: Mon, 25 Nov 2024 15:43:41 +0100 Subject: [PATCH 6/8] fix: Add missing private visibility modifier --- .../com/infomaniak/swisstransfer/ui/components/GenericButton.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/com/infomaniak/swisstransfer/ui/components/GenericButton.kt b/app/src/main/java/com/infomaniak/swisstransfer/ui/components/GenericButton.kt index 95f25af31..03ed98f31 100644 --- a/app/src/main/java/com/infomaniak/swisstransfer/ui/components/GenericButton.kt +++ b/app/src/main/java/com/infomaniak/swisstransfer/ui/components/GenericButton.kt @@ -82,7 +82,7 @@ fun GenericButton( } @Composable -fun KeepButtonSize(targetSizeContent: @Composable () -> Unit, content: @Composable () -> Unit) { +private fun KeepButtonSize(targetSizeContent: @Composable () -> Unit, content: @Composable () -> Unit) { Box(contentAlignment = Alignment.Center) { Row(modifier = Modifier.alpha(0f)) { targetSizeContent() From 3998a69e29be9219f7d33b817a3c1a351abd3874 Mon Sep 17 00:00:00 2001 From: Gibran Chevalley Date: Wed, 27 Nov 2024 10:17:29 +0100 Subject: [PATCH 7/8] refactor: Rename GenericButton into SwissTransferButton --- .../com/infomaniak/swisstransfer/ui/components/Buttons.kt | 2 +- .../components/{GenericButton.kt => SwissTransferButton.kt} | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) rename app/src/main/java/com/infomaniak/swisstransfer/ui/components/{GenericButton.kt => SwissTransferButton.kt} (97%) 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 77a5e1a06..87152627b 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 @@ -103,7 +103,7 @@ private fun CoreButton( onClick: () -> Unit, imageVector: ImageVector?, ) { - GenericButton( + SwissTransferButton( modifier.height(buttonSize.height), style, enabled, diff --git a/app/src/main/java/com/infomaniak/swisstransfer/ui/components/GenericButton.kt b/app/src/main/java/com/infomaniak/swisstransfer/ui/components/SwissTransferButton.kt similarity index 97% rename from app/src/main/java/com/infomaniak/swisstransfer/ui/components/GenericButton.kt rename to app/src/main/java/com/infomaniak/swisstransfer/ui/components/SwissTransferButton.kt index 03ed98f31..dd9b7b6c1 100644 --- a/app/src/main/java/com/infomaniak/swisstransfer/ui/components/GenericButton.kt +++ b/app/src/main/java/com/infomaniak/swisstransfer/ui/components/SwissTransferButton.kt @@ -42,7 +42,7 @@ import com.infomaniak.swisstransfer.ui.utils.PreviewLightAndDark * Specifying a progress has the priority over specifying showIndeterminateProgress. */ @Composable -fun GenericButton( +fun SwissTransferButton( modifier: Modifier = Modifier, style: ButtonType = ButtonType.PRIMARY, enabled: () -> Boolean = { true }, @@ -136,7 +136,7 @@ private fun Preview() { Column(verticalArrangement = Arrangement.spacedBy(8.dp)) { ButtonType.entries.forEach { buttonType -> Row { - GenericButton( + SwissTransferButton( modifier = Modifier.height(40.dp), style = buttonType, onClick = {}, @@ -145,7 +145,7 @@ private fun Preview() { Spacer(modifier = Modifier.width(12.dp)) - GenericButton( + SwissTransferButton( modifier = Modifier.height(40.dp), style = buttonType, onClick = {}, From 80d2b520f6aaa373b0043a6dfebe78cb512cf661 Mon Sep 17 00:00:00 2001 From: Gibran Chevalley Date: Wed, 27 Nov 2024 10:25:35 +0100 Subject: [PATCH 8/8] refactor: Put back missing @StringRes --- .../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 87152627b..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 @@ -93,7 +93,7 @@ fun SmallButton( @Composable private fun CoreButton( - titleRes: Int, + @StringRes titleRes: Int, modifier: Modifier, buttonSize: ButtonSize, style: ButtonType,