Skip to content

Commit

Permalink
OudsButton now supports both determinate and indeterminate circular p…
Browse files Browse the repository at this point in the history
…rogress indicators
  • Loading branch information
florentmaitre committed Nov 29, 2024
1 parent bddd1cb commit 988953a
Show file tree
Hide file tree
Showing 29 changed files with 73 additions and 55 deletions.
2 changes: 0 additions & 2 deletions NOTICE.txt
Original file line number Diff line number Diff line change
Expand Up @@ -67,8 +67,6 @@ app/src/main/res/drawable-night-xxxhdpi/il_tokens_grid_min_width.png
app/src/prod/res/drawable/ic_launcher_background.xml
app/src/prod/res/drawable/ic_launcher_foreground.xml

core/src/main/res/drawable/loading_indicator_circular.xml

docs/images/favicon-16x16.png
docs/images/orange-logo.svg

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import androidx.compose.foundation.layout.padding
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.rememberBottomSheetScaffoldState
import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.painterResource
Expand Down Expand Up @@ -43,12 +44,19 @@ fun ButtonDemoScreen() = DemoScreen(rememberButtonDemoState()) {
selectedChipIndex = OudsButton.Hierarchy.entries.indexOf(hierarchy),
onSelectionChange = { id -> hierarchy = OudsButton.Hierarchy.entries[id] }
)
val styles = remember {
listOf(
OudsButton.Style.Default,
OudsButton.Style.Loading(progress = null),
OudsButton.Style.Skeleton
)
}
CustomizationChoiceChipsColumn(
modifier = Modifier.padding(top = OudsSpaceKeyToken.Fixed.Medium.value),
label = stringResource(R.string.app_components_button_style_label),
chipsLabels = OudsButton.Style.entries.map { it.name },
selectedChipIndex = OudsButton.Style.entries.indexOf(style),
onSelectionChange = { id -> style = OudsButton.Style.entries[id] }
chipsLabels = styles.map { it::class.simpleName.orEmpty() },
selectedChipIndex = styles.indexOf(style),
onSelectionChange = { id -> style = styles[id] }
)
CustomizationChoiceChipsColumn(
modifier = Modifier.padding(top = OudsSpaceKeyToken.Fixed.Medium.value),
Expand Down
1 change: 1 addition & 0 deletions core/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@

plugins {
id("library")
id(libs.plugins.kotlin.parcelize.get().pluginId) // https://github.com/gradle/gradle/issues/20084#issuecomment-1060822638
alias(libs.plugins.compose.compiler)
alias(libs.plugins.paparazzi)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,7 @@

package com.orange.ouds.core.component.button

import androidx.compose.animation.core.LinearEasing
import androidx.compose.animation.core.animateFloat
import androidx.compose.animation.core.infiniteRepeatable
import androidx.compose.animation.core.rememberInfiniteTransition
import androidx.compose.animation.core.tween
import android.os.Parcelable
import androidx.compose.foundation.border
import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.foundation.isSystemInDarkTheme
Expand All @@ -33,8 +29,8 @@ import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.Button
import androidx.compose.material3.ButtonColors
import androidx.compose.material3.ButtonDefaults
import androidx.compose.material3.CircularProgressIndicator
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.Icon
import androidx.compose.material3.LocalRippleConfiguration
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
Expand All @@ -47,14 +43,13 @@ import androidx.compose.ui.draw.alpha
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.ImageBitmap
import androidx.compose.ui.graphics.Shape
import androidx.compose.ui.graphics.graphicsLayer
import androidx.compose.ui.graphics.StrokeCap
import androidx.compose.ui.graphics.painter.Painter
import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.tooling.preview.PreviewParameter
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
import com.orange.ouds.core.R
import com.orange.ouds.core.component.content.OudsComponentContent
import com.orange.ouds.core.component.content.OudsComponentIcon
import com.orange.ouds.core.extensions.InteractionState
Expand All @@ -69,6 +64,7 @@ import com.orange.ouds.theme.outerBorder
import com.orange.ouds.theme.tokens.OudsBorderKeyToken
import com.orange.ouds.theme.tokens.OudsColorKeyToken
import com.orange.ouds.theme.tokens.OudsTypographyKeyToken
import kotlinx.parcelize.Parcelize

/**
* An OUDS button which displays only text.
Expand Down Expand Up @@ -193,7 +189,7 @@ private fun OudsButton(
modifier = modifier
.widthIn(min = buttonTokens.sizeMinWidth.dp)
.heightIn(min = buttonTokens.sizeMinHeight.dp, max = maxHeight)
.buttonBorder(hierarchy = hierarchy, state = state, shape = shape),
.border(hierarchy = hierarchy, state = state, shape = shape),
enabled = state != OudsButton.State.Disabled && state != OudsButton.State.Loading && state != OudsButton.State.Skeleton,
shape = shape,
colors = buttonColors(hierarchy = hierarchy, buttonState = state),
Expand All @@ -204,21 +200,9 @@ private fun OudsButton(
Box(contentAlignment = Alignment.Center) {
val isLoadingIndicatorVisible = state == OudsButton.State.Loading
if (isLoadingIndicatorVisible) {
val infiniteTransition = rememberInfiniteTransition("LoadingIndicatorInfiniteTransition")
val angle by infiniteTransition.animateFloat(
initialValue = 0f,
targetValue = 360f,
animationSpec = infiniteRepeatable(tween(1000, easing = LinearEasing)),
label = "LoadingIndicatorAngleAnimation"
)
Icon(
modifier = Modifier
.size(buttonTokens.sizeLoader.value)
.graphicsLayer { rotationZ = angle },
contentDescription = null,
painter = painterResource(id = R.drawable.loading_indicator_circular),
tint = contentColor(hierarchy = hierarchy, state = state)
)
val loadingStyle = style as? OudsButton.Style.Loading
val progress = if (previewState == OudsButton.State.Loading) 0.75f else loadingStyle?.progress
LoadingIndicator(hierarchy = hierarchy, progress)
}

Row(
Expand Down Expand Up @@ -261,13 +245,13 @@ private fun rememberOudsButtonState(
interactionState == InteractionState.Focused -> OudsButton.State.Focused
else -> OudsButton.State.Enabled
}
OudsButton.Style.Loading -> OudsButton.State.Loading
is OudsButton.Style.Loading -> OudsButton.State.Loading
OudsButton.Style.Skeleton -> OudsButton.State.Skeleton
}
}

@Composable
private fun Modifier.buttonBorder(hierarchy: OudsButton.Hierarchy, state: OudsButton.State, shape: Shape): Modifier {
private fun Modifier.border(hierarchy: OudsButton.Hierarchy, state: OudsButton.State, shape: Shape): Modifier {
val borderWidth = borderWidth(hierarchy = hierarchy, state = state)
val borderColor = borderColor(hierarchy = hierarchy, state = state)

Expand Down Expand Up @@ -464,6 +448,33 @@ private fun contentPadding(icon: OudsButton.Icon?, text: String?): PaddingValues
}
}

@Composable
private fun LoadingIndicator(hierarchy: OudsButton.Hierarchy, progress: Float?) {
val modifier = Modifier.size(OudsTheme.componentsTokens.button.sizeLoader.value)
val color = contentColor(hierarchy = hierarchy, state = OudsButton.State.Loading)
val strokeWidth = 3.dp
val trackColor = Color.Transparent
val strokeCap = StrokeCap.Square
if (progress != null) {
CircularProgressIndicator(
progress = { progress },
modifier = modifier,
color = color,
strokeWidth = strokeWidth,
trackColor = trackColor,
strokeCap = strokeCap
)
} else {
CircularProgressIndicator(
modifier = modifier,
color = color,
strokeWidth = strokeWidth,
trackColor = trackColor,
strokeCap = strokeCap
)
}
}

/**
* Contains the default values used by OUDS buttons.
*/
Expand Down Expand Up @@ -532,10 +543,31 @@ object OudsButton {
}

/**
* Represents the style of an OUDS button.
* Represents the different styles of an OUDS button.
*/
enum class Style {
Default, Loading, Skeleton
sealed class Style : Parcelable {

/**
* The button displays an icon and/or a text and supports user interactions if it is enabled.
*/
@Parcelize
data object Default : Style()

/**
* The button displays a circular loading indicator.
*
* @param progress The loading progress, where 0.0 represents no progress and 1.0 represents full progress.
* Values outside of this range are coerced into the range.
* Set this value to `null` to display a circular indeterminate progress indicator.
*/
@Parcelize
data class Loading(val progress: Float?) : Style()

/**
* This button displays a skeleton.
*/
@Parcelize
data object Skeleton : Style()
}

internal enum class State {
Expand Down
21 changes: 0 additions & 21 deletions core/src/main/res/drawable/loading_indicator_circular.xml

This file was deleted.

Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

0 comments on commit 988953a

Please sign in to comment.