Skip to content

Commit

Permalink
feat(quantity-pickers): Add error message label and snapshot testing (#…
Browse files Browse the repository at this point in the history
…109)

Closes #80 #90
  • Loading branch information
corentin-stamper authored Apr 17, 2023
1 parent 173dba8 commit 3515450
Show file tree
Hide file tree
Showing 16 changed files with 462 additions and 76 deletions.
8 changes: 4 additions & 4 deletions quantity-pickers/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,11 @@ object VitaminQuantityPickers {
subtractEnabled: Boolean = true,
editTextEnabled: Boolean = true,
isExpanded: Boolean = false,
helperText: String? = null,
keyboardOptions: KeyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Number),
keyboardActions: KeyboardActions = KeyboardActions.Default,
colors: QuantityColors = VitaminQuantitiesColors.normal(),
shape: CornerBasedShape = VitaminTheme.shapes.radius100,
textStyle: TextStyle = VitaminTheme.typography.text2,
sizes: QuantitySizes = VitaminQuantitiesSizes.primary(),
ripple: RippleTheme = VitaminTheme.ripples.brand,
onAddClicked: () -> Unit,
onSubtractClicked: () -> Unit,
Expand Down Expand Up @@ -59,11 +59,11 @@ Parameters | Descriptions
`subtractEnabled: (Boolean)` | Whether substract button is enable or not
`editTextEnabled: (Boolean)` | Whether textField is enable or not
`isExpanded: Boolean = false` | If true, component will fill max width, otherwise get default width
`helperText: String? = null` | Helper text displayed at the QuantityPicker's bottom
`keyboardOptions: KeyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Number)` | Software keyboard options that contains such as KeyboardType and ImeAction
`keyboardActions: KeyboardActions = KeyboardActions.Default` | When the text input emit an IME action, the corresponding callback is called
`colors: QuantityColors = VitaminQuantitiesColors.normal()` | The color to notify your user if they are in normal or error state
`shape: CornerBasedShape = VitaminTheme.shapes.radius100` | The shape for icon buttons
`textStyle: TextStyle = VitaminTheme.typography.text2` | The typography of the text inside the text input
`sizes: QuantitySizes = VitaminQuantitiesSizes.primary()` | Sizes to be applied to the QuantityPicker
`ripple: RippleTheme = VitaminTheme.ripples.brand` | The ripple effect applied on buttons
`onAddClicked: (Boolean) -> Unit` | The callback to be called when add button is clicked
`onSubtractClicked: (Boolean) -> Unit` | The callback to be called when substract button is clicked
Expand Down
2 changes: 2 additions & 0 deletions quantity-pickers/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,12 @@ plugins {
id("kotlin-android")
id("VitaminComposeLibraryPlugin")
id("com.vanniktech.maven.publish")
id("app.cash.paparazzi")
}

dependencies {
api(project(":foundation:foundation"))
implementation(project(":foundation:foundation-icons"))
implementation(AndroidX.compose.ui.tooling)
testImplementation("com.google.testparameterinjector:test-parameter-injector:1.8")
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ data class QuantityColors(
val editTextBorderColor: Color,
val focusBorderColor: Color,
val backgroundColor: Color,
val helperColor: Color,
val state: State
)

Expand All @@ -30,7 +31,8 @@ object VitaminQuantitiesColors {
buttonsBorderColor: Color = VitaminTheme.colors.vtmnBorderInactive,
editTextBorderColor: Color = VitaminTheme.colors.vtmnBorderInactive,
focusBorderColor: Color = VitaminTheme.colors.vtmnBorderActive,
backgroundColor: Color = VitaminTheme.colors.vtmnBackgroundPrimary
backgroundColor: Color = VitaminTheme.colors.vtmnBackgroundPrimary,
helperColor: Color = VitaminTheme.colors.vtmnContentNegative
): QuantityColors =
remember(
textColor,
Expand All @@ -39,7 +41,8 @@ object VitaminQuantitiesColors {
buttonsBorderColor,
editTextBorderColor,
focusBorderColor,
backgroundColor
backgroundColor,
helperColor
) {
QuantityColors(
textColor = textColor,
Expand All @@ -49,6 +52,7 @@ object VitaminQuantitiesColors {
editTextBorderColor = editTextBorderColor,
focusBorderColor = focusBorderColor,
backgroundColor = backgroundColor,
helperColor = helperColor,
state = State.NORMAL
)
}
Expand All @@ -61,7 +65,8 @@ object VitaminQuantitiesColors {
buttonsBorderColor: Color = VitaminTheme.colors.vtmnBorderInactive,
editTextBorderColor: Color = VitaminTheme.colors.vtmnBorderNegative,
focusBorderColor: Color = VitaminTheme.colors.vtmnBorderNegative,
backgroundColor: Color = VitaminTheme.colors.vtmnBackgroundPrimary
backgroundColor: Color = VitaminTheme.colors.vtmnBackgroundPrimary,
helperColor: Color = VitaminTheme.colors.vtmnContentNegative
): QuantityColors =
remember(
textColor,
Expand All @@ -70,7 +75,8 @@ object VitaminQuantitiesColors {
buttonsBorderColor,
editTextBorderColor,
focusBorderColor,
backgroundColor
backgroundColor,
helperColor
) {
QuantityColors(
textColor = textColor,
Expand All @@ -80,6 +86,7 @@ object VitaminQuantitiesColors {
editTextBorderColor = editTextBorderColor,
focusBorderColor = focusBorderColor,
backgroundColor = backgroundColor,
helperColor = helperColor,
state = State.ERROR
)
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
package com.decathlon.vitamin.compose.quantity.pickers

import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.runtime.Composable
import androidx.compose.runtime.Immutable
import androidx.compose.runtime.remember
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
import com.decathlon.vitamin.compose.foundation.VitaminTheme

@Immutable
data class QuantitySizes(
val height: Dp,
val width: Dp,
val textStyle: TextStyle,
val shape: RoundedCornerShape,
val helperTextStyle: TextStyle,
val helperIconSize: Dp
)

object VitaminQuantitiesSizes {

@Composable
fun primary(
height: Dp = 48.dp,
width: Dp = 156.dp,
textStyle: TextStyle = VitaminTheme.typography.text2,
shape: RoundedCornerShape = VitaminTheme.shapes.radius100,
helperTextStyle: TextStyle = VitaminTheme.typography.text3,
helperIconSize: Dp = 16.dp
): QuantitySizes =
remember(
height,
width,
textStyle,
shape,
helperTextStyle,
helperIconSize
) {
QuantitySizes(
height = height,
width = width,
textStyle = textStyle,
shape = shape,
helperTextStyle = helperTextStyle,
helperIconSize = helperIconSize
)
}
}
Original file line number Diff line number Diff line change
@@ -1,37 +1,29 @@
package com.decathlon.vitamin.compose.quantity.pickers

import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxHeight
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.shape.CornerBasedShape
import androidx.compose.foundation.shape.CornerSize
import androidx.compose.foundation.text.KeyboardActions
import androidx.compose.foundation.text.KeyboardOptions
import androidx.compose.material.ripple.LocalRippleTheme
import androidx.compose.material.ripple.RippleTheme
import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.vector.rememberVectorPainter
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.semantics.contentDescription
import androidx.compose.ui.semantics.error
import androidx.compose.ui.semantics.semantics
import androidx.compose.ui.text.input.KeyboardType
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import com.decathlon.vitamin.compose.VitaminIcons
import com.decathlon.vitamin.compose.foundation.VitaminTheme
import com.decathlon.vitamin.compose.foundation.VtmnStatesDisabled
import com.decathlon.vitamin.compose.quantity.pickers.internals.IconButton
import com.decathlon.vitamin.compose.quantity.pickers.internals.MiddleTextField
import com.decathlon.vitamin.compose.vitaminicons.Fill
import com.decathlon.vitamin.compose.vitaminicons.fill.Add
import com.decathlon.vitamin.compose.vitaminicons.fill.Subtract
import com.decathlon.vitamin.compose.quantity.pickers.internals.HelperText
import com.decathlon.vitamin.compose.quantity.pickers.internals.Picker
import com.decathlon.vitamin.compose.vitaminicons.Line
import com.decathlon.vitamin.compose.vitaminicons.line.Information

internal const val VtmnStatesEnabled = 1.0f

Expand All @@ -44,11 +36,11 @@ object VitaminQuantityPickers {
* @param subtractEnabled Whether substract button is enable or not
* @param editTextEnabled Whether textField is enable or not
* @param isExpanded if true, component will fill max width, otherwise get default width
* @param helperText Helper text displayed at the QuantityPicker's bottom
* @param keyboardOptions Software keyboard options that contains such as KeyboardType and ImeAction
* @param keyboardActions When the text input emit an IME action, the corresponding callback is called
* @param colors The color to notify your user if they are in normal or error state
* @param shape The shape for icon buttons
* @param textStyle The typography of the text inside the text input
* @param sizes Sizes to be applied to the QuantityPicker. (VitaminQuantitiesSizes.primary())
* @param ripple The ripple effect applied on buttons
* @param onAddClicked The callback to be called when add button is clicked
* @param onSubtractClicked The callback to be called when substract button is clicked
Expand All @@ -62,71 +54,55 @@ object VitaminQuantityPickers {
subtractEnabled: Boolean = true,
editTextEnabled: Boolean = true,
isExpanded: Boolean = false,
helperText: String? = null,
keyboardOptions: KeyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Number),
keyboardActions: KeyboardActions = KeyboardActions.Default,
colors: QuantityColors = VitaminQuantitiesColors.normal(),
shape: CornerBasedShape = VitaminTheme.shapes.radius100,
textStyle: TextStyle = VitaminTheme.typography.text2,
sizes: QuantitySizes = VitaminQuantitiesSizes.primary(),
ripple: RippleTheme = VitaminTheme.ripples.brand,
onAddClicked: () -> Unit,
onSubtractClicked: () -> Unit,
onValueChange: (String) -> Unit
) {
CompositionLocalProvider(LocalRippleTheme provides ripple) {
Row(
val contentDescription = stringResource(id = R.string.vtmn_quantity_picker_accessibility_message, value)

Column(
modifier = modifier
.height(48.dp)
.then(
if (isExpanded) {
modifier.fillMaxWidth()
} else {
modifier.width(156.dp)
.semantics(
mergeDescendants = false
) {
this.contentDescription = contentDescription
helperText?.let {
this.error(it)
}
)
}
) {
IconButton(
painter = rememberVectorPainter(VitaminIcons.Fill.Subtract),
contentDescription = stringResource(id = R.string.vtmn_subtract_button_description),
enabled = subtractEnabled,
colors = colors,
shape = shape.copy(
topEnd = CornerSize(0.dp),
bottomEnd = CornerSize(0.dp)
),
onClick = onSubtractClicked
)

MiddleTextField(
modifier = Modifier
.background(
color = colors.backgroundColor.copy(
alpha = if (!addEnabled && !subtractEnabled) VtmnStatesDisabled else VtmnStatesEnabled
)
)
.fillMaxHeight()
.weight(1.0f),
Picker(
value = value,
modifier = modifier,
addEnabled = addEnabled,
subtractEnabled = subtractEnabled,
colors = colors,
textStyle = textStyle,
value = value,
onValueChange = onValueChange,
editTextEnabled = editTextEnabled,
isExpanded = isExpanded,
keyboardOptions = keyboardOptions,
keyboardActions = keyboardActions
)

IconButton(
painter = rememberVectorPainter(VitaminIcons.Fill.Add),
contentDescription = stringResource(id = R.string.vtmn_add_button_description),
enabled = addEnabled,
keyboardActions = keyboardActions,
colors = colors,
shape = shape.copy(
topStart = CornerSize(0.dp),
bottomStart = CornerSize(0.dp)
),
onClick = onAddClicked
sizes = sizes,
onAddClicked = onAddClicked,
onSubtractClicked = onSubtractClicked,
onValueChange = onValueChange
)

helperText?.let {
HelperText(
text = it,
textStyle = sizes.helperTextStyle,
icon = VitaminIcons.Line.Information,
iconSize = sizes.helperIconSize,
color = colors.helperColor
)
}
}
}
}
Expand Down Expand Up @@ -171,6 +147,20 @@ private fun PreviewQuantities() {
onSubtractClicked = {}
) {}
}

Spacer(modifier = Modifier.height(10.dp))

Column(Modifier) {
VitaminQuantityPickers.Primary(
value = "0",
addEnabled = true,
subtractEnabled = true,
onAddClicked = {},
onSubtractClicked = {},
helperText = "Error message goes here",
colors = VitaminQuantitiesColors.error()
) {}
}
}
}
}
Expand Down Expand Up @@ -199,6 +189,20 @@ private fun PreviewDarkQuantities() {
onSubtractClicked = {}
) {}
}

Spacer(modifier = Modifier.height(10.dp))

Column(Modifier) {
VitaminQuantityPickers.Primary(
value = "0",
addEnabled = true,
subtractEnabled = true,
onAddClicked = {},
onSubtractClicked = {},
helperText = "Error message goes here",
colors = VitaminQuantitiesColors.error()
) {}
}
}
}
}
Loading

0 comments on commit 3515450

Please sign in to comment.