Skip to content

Commit d3f5b99

Browse files
committed
Add OudsFilterChip
1 parent 2152546 commit d3f5b99

30 files changed

Lines changed: 845 additions & 156 deletions

File tree

NOTICE.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,7 @@ app/src/prod/res/drawable/ic_launcher_foreground.xml
117117
core/src/main/res/drawable/checkbox_indeterminate.xml
118118
core/src/main/res/drawable/checkbox_selected.xml
119119
core/src/main/res/drawable/chevron_left.xml
120+
core/src/main/res/drawable/chip_tick.xml
120121
core/src/main/res/drawable/radiobutton_selected.xml
121122
core/src/main/res/drawable/switch_selected.xml
122123

app/src/main/java/com/orange/ouds/app/ui/components/button/ButtonDemoScreen.kt

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,7 @@ private fun ButtonDemoContent(state: ButtonDemoState) {
115115
hierarchy = hierarchy
116116
)
117117
}
118-
ButtonDemoState.Layout.IconAndText -> {
118+
ButtonDemoState.Layout.TextAndIcon -> {
119119
OudsButton(
120120
icon = icon,
121121
label = label,
@@ -142,13 +142,13 @@ private fun Code.Builder.buttonDemoCodeSnippet(state: ButtonDemoState) {
142142
with(state) {
143143
coloredBoxCall(onColoredBox) {
144144
functionCall(OudsButton::class.simpleName.orEmpty()) {
145-
if (layout in listOf(ButtonDemoState.Layout.IconOnly, ButtonDemoState.Layout.IconAndText)) {
145+
if (layout in listOf(ButtonDemoState.Layout.IconOnly, ButtonDemoState.Layout.TextAndIcon)) {
146146
constructorCallArgument<OudsButton.Icon>("icon") {
147147
painterArgument(R.drawable.ic_heart)
148148
contentDescriptionArgument(R.string.app_components_button_icon_a11y)
149149
}
150150
}
151-
if (layout in listOf(ButtonDemoState.Layout.TextOnly, ButtonDemoState.Layout.IconAndText)) {
151+
if (layout in listOf(ButtonDemoState.Layout.TextOnly, ButtonDemoState.Layout.TextAndIcon)) {
152152
labelArgument(label)
153153
}
154154
onClickArgument()

app/src/main/java/com/orange/ouds/app/ui/components/button/ButtonDemoState.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,7 @@ class ButtonDemoState(
107107

108108
enum class Layout(@StringRes val labelRes: Int) {
109109
TextOnly(R.string.app_components_common_textOnlyLayout_label),
110-
IconAndText(R.string.app_components_common_iconAndTextLayout_label),
110+
TextAndIcon(R.string.app_components_common_textAndIconLayout_label),
111111
IconOnly(R.string.app_components_button_iconOnlyLayout_label)
112112
}
113113
}

app/src/main/java/com/orange/ouds/app/ui/components/link/LinkDemoScreen.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@ private fun LinkDemoContent(state: LinkDemoState) {
9696
size = size
9797
)
9898
}
99-
LinkDemoState.Layout.IconAndText -> {
99+
LinkDemoState.Layout.TextAndIcon -> {
100100
OudsLink(
101101
label = label,
102102
icon = OudsLink.Icon(painterResource(id = R.drawable.ic_heart)),
@@ -134,7 +134,7 @@ private fun Code.Builder.linkDemoCodeSnippet(state: LinkDemoState) {
134134
labelArgument(label)
135135
when (layout) {
136136
LinkDemoState.Layout.TextOnly -> {}
137-
LinkDemoState.Layout.IconAndText -> {
137+
LinkDemoState.Layout.TextAndIcon -> {
138138
constructorCallArgument<OudsLink.Icon>("icon") {
139139
painterArgument(R.drawable.ic_heart)
140140
}

app/src/main/java/com/orange/ouds/app/ui/components/link/LinkDemoState.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@ class LinkDemoState(
8585

8686
enum class Layout(@StringRes val labelRes: Int) {
8787
TextOnly(R.string.app_components_common_textOnlyLayout_label),
88-
IconAndText(R.string.app_components_common_iconAndTextLayout_label),
88+
TextAndIcon(R.string.app_components_common_textAndIconLayout_label),
8989
ArrowBack(R.string.app_components_link_backLayout_label),
9090
ArrowNext(R.string.app_components_link_nextLayout_label)
9191
}

app/src/main/res/values-ar/strings.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,7 @@
100100
<string name="app_components_common_error_label">خطأ</string>
101101
<string name="app_components_common_layout_label">التخطيط</string>
102102
<string name="app_components_common_textOnlyLayout_label">نص فقط</string>
103-
<string name="app_components_common_iconAndTextLayout_label">رمز + نص</string>
103+
<string name="app_components_common_textAndIconLayout_label">رمز + نص</string>
104104
<string name="app_components_common_style_label">الأسلوب</string>
105105
<string name="app_components_common_label_label">التسمية</string>
106106
<string name="app_components_common_onColoredBackground_label">على خلفية ملونة</string>

app/src/main/res/values/strings.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,7 @@
111111
<string name="app_components_common_error_label">Error</string>
112112
<string name="app_components_common_layout_label">Layout</string>
113113
<string name="app_components_common_textOnlyLayout_label">Text only</string>
114-
<string name="app_components_common_iconAndTextLayout_label">Icon + text</string>
114+
<string name="app_components_common_textAndIconLayout_label">Text + icon</string>
115115
<string name="app_components_common_style_label">Style</string>
116116
<string name="app_components_common_label_label">Label</string>
117117
<string name="app_components_common_onColoredBackground_label">On colored background</string>
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
/*
2+
* Software Name: OUDS Android
3+
* SPDX-FileCopyrightText: Copyright (c) Orange SA
4+
* SPDX-License-Identifier: MIT
5+
*
6+
* This software is distributed under the MIT license,
7+
* the text of which is available at https://opensource.org/license/MIT/
8+
* or see the "LICENSE" file for more details.
9+
*
10+
* Software description: Android library of reusable graphical components
11+
*/
12+
13+
package com.orange.ouds.core.component
14+
15+
import androidx.compose.ui.Modifier
16+
import androidx.compose.ui.platform.testTag
17+
import androidx.compose.ui.test.assertIsNotSelected
18+
import androidx.compose.ui.test.junit4.createComposeRule
19+
import androidx.compose.ui.test.onNodeWithTag
20+
import androidx.compose.ui.test.performClick
21+
import com.orange.ouds.core.extension.setOudsContent
22+
import org.junit.Rule
23+
import org.junit.Test
24+
import org.mockito.kotlin.mock
25+
import org.mockito.kotlin.verify
26+
27+
internal class OudsFilterChipTest {
28+
29+
@get:Rule
30+
val composeTestRule = createComposeRule()
31+
32+
@Test
33+
fun oudsFilterChip_click_succeeds() {
34+
with(composeTestRule) {
35+
val testTag = "OudsFilterChip"
36+
val selected = false
37+
val onClick = mock<() -> Unit>()
38+
39+
setOudsContent {
40+
OudsFilterChip(
41+
selected = selected,
42+
onClick = onClick,
43+
label = "Label",
44+
modifier = Modifier.testTag(testTag)
45+
)
46+
}
47+
48+
onNodeWithTag(testTag).assertIsNotSelected()
49+
onNodeWithTag(testTag).performClick()
50+
verify(onClick).invoke()
51+
}
52+
}
53+
}

core/src/main/java/com/orange/ouds/core/component/OudsButton.kt

Lines changed: 78 additions & 83 deletions
Original file line numberDiff line numberDiff line change
@@ -30,10 +30,8 @@ import androidx.compose.foundation.layout.widthIn
3030
import androidx.compose.foundation.shape.RoundedCornerShape
3131
import androidx.compose.material3.CircularProgressIndicator
3232
import androidx.compose.material3.ExperimentalMaterial3Api
33-
import androidx.compose.material3.LocalRippleConfiguration
3433
import androidx.compose.material3.Text
3534
import androidx.compose.runtime.Composable
36-
import androidx.compose.runtime.CompositionLocalProvider
3735
import androidx.compose.runtime.getValue
3836
import androidx.compose.runtime.remember
3937
import androidx.compose.ui.Alignment
@@ -202,9 +200,9 @@ fun OudsButton(
202200
* @param interactionSource An optional hoisted [MutableInteractionSource] for observing and emitting [Interaction]s for this button. Note that if `null`
203201
* is provided, interactions will still happen internally.
204202
*
205-
* @sample com.orange.ouds.core.component.samples.OudsButtonIconAndTextSample
203+
* @sample com.orange.ouds.core.component.samples.OudsButtonTextAndIconSample
206204
*
207-
* @sample com.orange.ouds.core.component.samples.OudsButtonIconAndTextOnColoredBackgroundSample
205+
* @sample com.orange.ouds.core.component.samples.OudsButtonTextAndIconOnColoredBackgroundSample
208206
*/
209207
@Composable
210208
fun OudsButton(
@@ -258,87 +256,85 @@ private fun OudsButton(
258256
val maxHeight = if (icon != null && label == null) buttonTokens.sizeMaxHeightIconOnly.dp * iconScale else Dp.Unspecified
259257
val shape = RoundedCornerShape(buttonTokens.borderRadius.value)
260258

261-
CompositionLocalProvider(LocalRippleConfiguration provides null) {
262-
val stateDescription = if (state == OudsButton.State.Loading) stringResource(id = R.string.core_button_loading_a11y) else ""
263-
val contentColor = rememberInteractionColor(interactionState = interactionState) { buttonInteractionState ->
264-
val buttonState = getButtonState(enabled = enabled, style = style, interactionState = buttonInteractionState)
265-
contentColor(hierarchy = hierarchy, state = buttonState)
266-
}
267-
val backgroundColor = rememberInteractionColor(interactionState = interactionState) { buttonInteractionState ->
268-
val buttonState = getButtonState(enabled = enabled, style = style, interactionState = buttonInteractionState)
269-
backgroundColor(hierarchy = hierarchy, state = buttonState)
270-
}
271-
val borderWidth = rememberInteractionValue(
272-
interactionState = interactionState,
273-
toAnimatableFloat = { it?.value.orElse { 0f } },
274-
fromAnimatableFloat = { it.dp }
275-
) { buttonInteractionState ->
276-
val buttonState = getButtonState(enabled = enabled, style = style, interactionState = buttonInteractionState)
277-
borderWidth(hierarchy = hierarchy, state = buttonState)
278-
}
279-
val borderColor = rememberNullableInteractionColor(interactionState = interactionState) { buttonInteractionState ->
280-
val buttonState = getButtonState(enabled = enabled, style = style, interactionState = buttonInteractionState)
281-
borderColor(hierarchy = hierarchy, state = buttonState)
282-
}
259+
val stateDescription = if (state == OudsButton.State.Loading) stringResource(id = R.string.core_button_loading_a11y) else ""
260+
val contentColor = rememberInteractionColor(interactionState = interactionState) { buttonInteractionState ->
261+
val buttonState = getButtonState(enabled = enabled, style = style, interactionState = buttonInteractionState)
262+
contentColor(hierarchy = hierarchy, state = buttonState)
263+
}
264+
val backgroundColor = rememberInteractionColor(interactionState = interactionState) { buttonInteractionState ->
265+
val buttonState = getButtonState(enabled = enabled, style = style, interactionState = buttonInteractionState)
266+
backgroundColor(hierarchy = hierarchy, state = buttonState)
267+
}
268+
val borderWidth = rememberInteractionValue(
269+
interactionState = interactionState,
270+
toAnimatableFloat = { it?.value.orElse { 0f } },
271+
fromAnimatableFloat = { it.dp }
272+
) { buttonInteractionState ->
273+
val buttonState = getButtonState(enabled = enabled, style = style, interactionState = buttonInteractionState)
274+
borderWidth(hierarchy = hierarchy, state = buttonState)
275+
}
276+
val borderColor = rememberNullableInteractionColor(interactionState = interactionState) { buttonInteractionState ->
277+
val buttonState = getButtonState(enabled = enabled, style = style, interactionState = buttonInteractionState)
278+
borderColor(hierarchy = hierarchy, state = buttonState)
279+
}
283280

284-
Box(
285-
modifier = modifier
286-
.widthIn(min = buttonTokens.sizeMinWidth.dp)
287-
.heightIn(min = buttonTokens.sizeMinHeight.dp, max = maxHeight)
288-
.background(color = backgroundColor.value, shape = shape)
289-
.run {
290-
ifNotNull(borderWidth.value, borderColor.value) { borderWidth, borderColor ->
291-
border(width = borderWidth, color = borderColor, shape = shape)
292-
}.orElse {
293-
this
294-
}
281+
Box(
282+
modifier = modifier
283+
.widthIn(min = buttonTokens.sizeMinWidth.dp)
284+
.heightIn(min = buttonTokens.sizeMinHeight.dp, max = maxHeight)
285+
.background(color = backgroundColor.value, shape = shape)
286+
.run {
287+
ifNotNull(borderWidth.value, borderColor.value) { borderWidth, borderColor ->
288+
border(width = borderWidth, color = borderColor, shape = shape)
289+
}.orElse {
290+
this
295291
}
296-
.outerBorder(state = state, shape = shape)
297-
.semantics {
298-
this.stateDescription = stateDescription
299-
}
300-
.clickable(
301-
enabled = state !in remember { listOf(OudsButton.State.Disabled, OudsButton.State.Loading) },
302-
interactionSource = interactionSource,
303-
indication = InteractionValuesIndication(contentColor, backgroundColor, borderColor, borderWidth),
304-
onClick = onClick
305-
),
306-
contentAlignment = Alignment.Center
307-
) {
308-
if (state == OudsButton.State.Loading) {
309-
val loadingStyle = style as? OudsButton.Style.Loading
310-
val progress = if (getPreviewState<OudsButton.State>() == OudsButton.State.Loading) 0.75f else loadingStyle?.progress
311-
LoadingIndicator(hierarchy = hierarchy, progress = progress, scale = iconScale)
312292
}
293+
.outerBorder(state = state, shape = shape)
294+
.semantics {
295+
this.stateDescription = stateDescription
296+
}
297+
.clickable(
298+
enabled = state !in remember { listOf(OudsButton.State.Disabled, OudsButton.State.Loading) },
299+
interactionSource = interactionSource,
300+
indication = InteractionValuesIndication(contentColor, backgroundColor, borderColor, borderWidth),
301+
onClick = onClick
302+
),
303+
contentAlignment = Alignment.Center
304+
) {
305+
if (state == OudsButton.State.Loading) {
306+
val loadingStyle = style as? OudsButton.Style.Loading
307+
val progress = if (getPreviewState<OudsButton.State>() == OudsButton.State.Loading) 0.75f else loadingStyle?.progress
308+
LoadingIndicator(hierarchy = hierarchy, progress = progress, scale = iconScale)
309+
}
313310

314-
val alpha = if (state == OudsButton.State.Loading) 0f else 1f
315-
Row(
316-
modifier = Modifier
317-
.alpha(alpha = alpha)
318-
.padding(contentPadding(icon = icon, label = label)),
319-
horizontalArrangement = Arrangement.spacedBy(buttonTokens.spaceColumnGapIcon.value),
320-
verticalAlignment = Alignment.CenterVertically
321-
) {
322-
if (icon != null) {
323-
val size = if (label == null) buttonTokens.sizeIconOnly else buttonTokens.sizeIcon
324-
icon.Content(
325-
modifier = Modifier
326-
.size(size.value * iconScale)
327-
.semantics {
328-
contentDescription = if (label == null) icon.contentDescription else ""
329-
},
330-
extraParameters = OudsButton.Icon.ExtraParameters(tint = contentColor.value)
331-
)
332-
}
333-
if (label != null) {
334-
Text(
335-
modifier = modifier,
336-
text = label,
337-
color = contentColor.value,
338-
style = OudsTheme.typography.label.strong.large,
339-
textAlign = TextAlign.Center
340-
)
341-
}
311+
val alpha = if (state == OudsButton.State.Loading) 0f else 1f
312+
Row(
313+
modifier = Modifier
314+
.alpha(alpha = alpha)
315+
.padding(contentPadding(icon = icon, label = label)),
316+
horizontalArrangement = Arrangement.spacedBy(buttonTokens.spaceColumnGapIcon.value),
317+
verticalAlignment = Alignment.CenterVertically
318+
) {
319+
if (icon != null) {
320+
val size = if (label == null) buttonTokens.sizeIconOnly else buttonTokens.sizeIcon
321+
icon.Content(
322+
modifier = Modifier
323+
.size(size.value * iconScale)
324+
.semantics {
325+
contentDescription = if (label == null) icon.contentDescription else ""
326+
},
327+
extraParameters = OudsButton.Icon.ExtraParameters(tint = contentColor.value)
328+
)
329+
}
330+
if (label != null) {
331+
Text(
332+
modifier = modifier,
333+
text = label,
334+
color = contentColor.value,
335+
style = OudsTheme.typography.label.strong.large,
336+
textAlign = TextAlign.Center
337+
)
342338
}
343339
}
344340
}
@@ -577,8 +573,7 @@ object OudsButtonDefaults {
577573
object OudsButton {
578574

579575
/**
580-
* A button icon in an [OudsButton].
581-
* It is non-clickable and no content description is needed because a button label is always present.
576+
* An icon in an [OudsButton].
582577
*/
583578
class Icon private constructor(
584579
graphicsObject: Any,

0 commit comments

Comments
 (0)