Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
473f7e4
Fix badge kdoc
paulinea Jul 17, 2025
0fd4851
Add tag component to the lib
paulinea Jul 17, 2025
0005a64
Add tag component paparazzi snapshots
paulinea Jul 17, 2025
a63ca96
Add tag component to demo app
paulinea Jul 18, 2025
0edc261
Fix after rebase
paulinea Aug 5, 2025
a8b4077
Introduce inset padding for assets
paulinea Aug 6, 2025
d4731da
Update tag snapshots
paulinea Aug 6, 2025
7cb1aa1
Update tag bullet icon
paulinea Aug 6, 2025
19a8e8c
Review: Remove empty line
paulinea Aug 6, 2025
95b3331
Review: Update Tag illustration in demo app
paulinea Aug 6, 2025
9248a9c
Review: Add empty line
paulinea Aug 6, 2025
f0a199f
Review: Add missing top padding
paulinea Aug 6, 2025
d1bf31d
Review: Add loading customization switch
paulinea Aug 6, 2025
d345ccb
Review: Add loading parameter in the code snippet
paulinea Aug 6, 2025
afa060f
Review: Fix kdoc
paulinea Aug 6, 2025
3a7bbab
Review: Fix kdoc wording
paulinea Aug 6, 2025
ad3a474
Review: A tag with a disabled status and a loader is not allowed
paulinea Aug 6, 2025
8882e71
Review: Fix the space between asset and label
paulinea Aug 6, 2025
3924308
Review: Use StrokeCap.Butt for loader
paulinea Aug 6, 2025
994551e
Review: Add kdoc for Loading progress parameter
paulinea Aug 6, 2025
4e09372
Review: Use full names for OudsTag statuses
paulinea Aug 6, 2025
6c95e1f
Review: Add missing header
paulinea Aug 6, 2025
053a586
Update snapshots
paulinea Aug 6, 2025
952e408
Review: Update kdoc with design guideline URL and version
paulinea Aug 6, 2025
1abdbab
Review: Add version to Tag demo screen
paulinea Aug 6, 2025
e8fa73f
Update CheckedContent method to enhance previews
florentmaitre Aug 6, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions NOTICE.txt
Original file line number Diff line number Diff line change
Expand Up @@ -70,16 +70,17 @@ docs/assets/logo-icon.svg
theme-contract/src/main/res/drawable/ic_checkbox_indeterminate.xml
theme-contract/src/main/res/drawable/ic_checkbox_selected.xml
theme-contract/src/main/res/drawable/ic_chevron_left.xml
theme-contract/src/main/res/drawable/ic_tick.xml
theme-contract/src/main/res/drawable/ic_radio_button_selected.xml
theme-contract/src/main/res/drawable/ic_switch_selected.xml
theme-contract/src/main/res/drawable/ic_tag_bullet.xml
theme-contract/src/main/res/drawable/ic_tick.xml

theme-sosh/src/main/res/drawable/sosh_checkbox_indeterminate.xml
theme-sosh/src/main/res/drawable/sosh_checkbox_selected.xml
theme-sosh/src/main/res/drawable/sosh_chevron_left.xml
theme-sosh/src/main/res/drawable/sosh_tick.xml
theme-sosh/src/main/res/drawable/sosh_radio_button_selected.xml
theme-sosh/src/main/res/drawable/sosh_switch_selected.xml
theme-sosh/src/main/res/drawable/sosh_tick.xml
theme-sosh/src/main/res/font/sosh_black.ttf
theme-sosh/src/main/res/font/sosh_bold.ttf
theme-sosh/src/main/res/font/sosh_medium.ttf
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import com.orange.ouds.app.ui.components.radiobutton.RadioButtonDemoScreen
import com.orange.ouds.app.ui.components.radiobutton.RadioButtonItemDemoScreen
import com.orange.ouds.app.ui.components.switch.SwitchDemoScreen
import com.orange.ouds.app.ui.components.switch.SwitchItemDemoScreen
import com.orange.ouds.app.ui.components.tag.TagDemoScreen
import com.orange.ouds.app.ui.utilities.previewCompatibleClass

val components = Component::class.sealedSubclasses.mapNotNull { it.objectInstance }
Expand Down Expand Up @@ -110,6 +111,13 @@ sealed class Component(
{ SwitchIllustration() },
listOf(Variant.Switch, Variant.SwitchItem)
)

data object Tag : Component(
R.string.app_components_tag_label,
R.string.app_components_tag_description_text,
{ TagIllustration() },
demoScreen = { TagDemoScreen() }
)
}

sealed class Variant(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ import com.orange.ouds.core.component.OudsHorizontalDivider
import com.orange.ouds.core.component.OudsLink
import com.orange.ouds.core.component.OudsRadioButton
import com.orange.ouds.core.component.OudsSwitch
import com.orange.ouds.core.component.OudsTag
import com.orange.ouds.core.theme.isOudsInDarkTheme

@Composable
Expand Down Expand Up @@ -147,6 +148,11 @@ fun SwitchIllustration() = ComponentIllustration {
}
}

@Composable
fun TagIllustration() = ComponentIllustration {
OudsTag(label = stringResource(id = R.string.app_components_common_label_label), status = OudsTag.Status.Positive)
}

@Composable
private fun ComponentIllustration(content: @Composable () -> Unit) {
CompositionLocalProvider(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ import com.orange.ouds.app.ui.components.contentDescriptionArgument
import com.orange.ouds.app.ui.components.painterArgument
import com.orange.ouds.app.ui.utilities.Code
import com.orange.ouds.app.ui.utilities.composable.CustomizationDropdownMenu
import com.orange.ouds.app.ui.utilities.composable.CustomizationDropdownMenuItem
import com.orange.ouds.app.ui.utilities.composable.CustomizationFilterChips
import com.orange.ouds.app.ui.utilities.composable.CustomizationTextField
import com.orange.ouds.app.ui.utilities.composable.DemoScreen
Expand Down Expand Up @@ -66,26 +67,28 @@ private fun BadgeDemoBottomSheetContent(state: BadgeDemoState) {
)
CustomizationFilterChips(
modifier = Modifier.padding(top = OudsTheme.spaces.fixed.medium),
label = stringResource(R.string.app_components_badge_size_label),
label = stringResource(R.string.app_components_common_size_label),
chipLabels = OudsBadge.Size.entries.map { it.formattedName },
selectedChipIndex = OudsBadge.Size.entries.indexOf(size),
onSelectionChange = { id -> size = OudsBadge.Size.entries[id] }
)
val statuses = OudsBadge.Status.entries
CustomizationDropdownMenu(
label = stringResource(id = R.string.app_components_badge_status_label),
itemLabels = statuses.map { it.formattedName },
label = stringResource(id = R.string.app_components_common_status_label),
items = statuses.map { status ->
CustomizationDropdownMenuItem(
label = status.formattedName,
leadingIcon = {
Box(
modifier = Modifier
.fillMaxSize()
.background(status.backgroundColor)
)
}
)
},
selectedItemIndex = statuses.indexOf(status),
onSelectionChange = { status = statuses[it] },
itemLeadingIcons = statuses.map { status ->
{
Box(
modifier = Modifier
.fillMaxSize()
.background(status.backgroundColor)
)
}
}
onSelectionChange = { status = statuses[it] }
)
CustomizationTextField(
label = stringResource(R.string.app_components_badge_count_label),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ private fun ButtonDemoBottomSheetContent(state: ButtonDemoState) {
)
CustomizationFilterChips(
modifier = Modifier.padding(top = OudsTheme.spaces.fixed.medium),
label = stringResource(R.string.app_components_button_hierarchy_label),
label = stringResource(R.string.app_components_common_hierarchy_label),
chipLabels = OudsButton.Hierarchy.entries.map { it.name },
selectedChipIndex = OudsButton.Hierarchy.entries.indexOf(hierarchy),
onSelectionChange = { id -> hierarchy = OudsButton.Hierarchy.entries[id] }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ import com.orange.ouds.app.ui.components.labelArgument
import com.orange.ouds.app.ui.components.onClickArgument
import com.orange.ouds.app.ui.utilities.Code
import com.orange.ouds.app.ui.utilities.composable.CustomizationDropdownMenu
import com.orange.ouds.app.ui.utilities.composable.CustomizationDropdownMenuItem
import com.orange.ouds.app.ui.utilities.composable.DemoScreen
import com.orange.ouds.app.ui.utilities.formattedName
import com.orange.ouds.core.component.OudsButton
Expand All @@ -58,18 +59,20 @@ private fun ColoredBackgroundDemoBottomSheetContent(state: ColoredBackgroundDemo
val colors = OudsColoredBox.Color.entries.filter { it.mode.isSupported }
CustomizationDropdownMenu(
label = stringResource(id = R.string.app_components_coloredBackground_color_label),
itemLabels = colors.map { it.formattedName },
items = colors.map { color ->
CustomizationDropdownMenuItem(
label = color.formattedName,
leadingIcon = {
Box(
modifier = Modifier
.fillMaxSize()
.background(color.value)
)
}
)
},
selectedItemIndex = colors.indexOf(color),
onSelectionChange = { color = colors[it] },
itemLeadingIcons = colors.map { color ->
{
Box(
modifier = Modifier
.fillMaxSize()
.background(color.value)
)
}
}
)
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import androidx.compose.ui.unit.dp
import com.orange.ouds.app.R
import com.orange.ouds.app.ui.utilities.Code
import com.orange.ouds.app.ui.utilities.composable.CustomizationDropdownMenu
import com.orange.ouds.app.ui.utilities.composable.CustomizationDropdownMenuItem
import com.orange.ouds.app.ui.utilities.composable.DemoScreen
import com.orange.ouds.app.ui.utilities.formattedName
import com.orange.ouds.core.component.OudsDivider
Expand All @@ -52,18 +53,20 @@ private fun DividerDemoBottomSheetContent(state: DividerDemoState) {
val colors = OudsDivider.Color.entries
CustomizationDropdownMenu(
label = stringResource(id = R.string.app_components_common_color_label),
itemLabels = colors.map { it.formattedName },
items = colors.map { color ->
CustomizationDropdownMenuItem(
label = color.formattedName,
leadingIcon = {
Box(
modifier = Modifier
.fillMaxSize()
.background(color.value)
)
}
)
},
selectedItemIndex = colors.indexOf(color),
onSelectionChange = { color = colors[it] },
itemLeadingIcons = colors.map { color ->
{
Box(
modifier = Modifier
.fillMaxSize()
.background(color.value)
)
}
}
onSelectionChange = { color = colors[it] }
)
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,172 @@
/*
* Software Name: OUDS Android
* SPDX-FileCopyrightText: Copyright (c) Orange SA
* SPDX-License-Identifier: MIT
*
* This software is distributed under the MIT license,
* the text of which is available at https://opensource.org/license/MIT/
* or see the "LICENSE" file for more details.
*
* Software description: Android library of reusable graphical components
*/

package com.orange.ouds.app.ui.components.tag

import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.tooling.preview.PreviewLightDark
import com.orange.ouds.app.R
import com.orange.ouds.app.ui.components.Component
import com.orange.ouds.app.ui.components.labelArgument
import com.orange.ouds.app.ui.components.painterArgument
import com.orange.ouds.app.ui.utilities.Code
import com.orange.ouds.app.ui.utilities.composable.CustomizationDropdownMenu
import com.orange.ouds.app.ui.utilities.composable.CustomizationDropdownMenuItem
import com.orange.ouds.app.ui.utilities.composable.CustomizationFilterChips
import com.orange.ouds.app.ui.utilities.composable.CustomizationSwitchItem
import com.orange.ouds.app.ui.utilities.composable.CustomizationTextField
import com.orange.ouds.app.ui.utilities.composable.DemoScreen
import com.orange.ouds.app.ui.utilities.formattedName
import com.orange.ouds.core.component.OudsTag
import com.orange.ouds.core.theme.OudsTheme
import com.orange.ouds.core.utilities.OudsPreview
import com.orange.ouds.theme.OudsVersion

@Composable
fun TagDemoScreen() {
val state = rememberTagDemoState()
DemoScreen(
description = stringResource(id = Component.Tag.descriptionRes),
bottomSheetContent = { TagDemoBottomSheetContent(state = state) },
codeSnippet = { tagDemoCodeSnippet(state = state) },
demoContent = { TagDemoContent(state = state) },
version = OudsVersion.Component.Tag
)
}

@Composable
private fun TagDemoBottomSheetContent(state: TagDemoState) {
with(state) {
CustomizationFilterChips(
label = stringResource(R.string.app_components_common_hierarchy_label),
chipLabels = OudsTag.Hierarchy.entries.map { it.name },
selectedChipIndex = OudsTag.Hierarchy.entries.indexOf(hierarchy),
onSelectionChange = { id -> hierarchy = OudsTag.Hierarchy.entries[id] }
)
val statuses = OudsTag.Status.entries
CustomizationDropdownMenu(
modifier = Modifier.padding(top = OudsTheme.spaces.fixed.medium),
label = stringResource(id = R.string.app_components_common_status_label),
items = statuses.map { status ->
CustomizationDropdownMenuItem(
label = status.formattedName,
leadingIcon = {
Box(
modifier = Modifier
.fillMaxSize()
.background(status.backgroundColor(hierarchy))
)
},
enabled = !(status == OudsTag.Status.Disabled && loading)
)
},
selectedItemIndex = statuses.indexOf(status),
onSelectionChange = { status = statuses[it] }
)
CustomizationFilterChips(
modifier = Modifier.padding(top = OudsTheme.spaces.fixed.medium),
label = stringResource(R.string.app_components_common_layout_label),
chipLabels = TagDemoState.Layout.entries.map { stringResource(it.labelRes) },
selectedChipIndex = TagDemoState.Layout.entries.indexOf(layout),
onSelectionChange = { id -> layout = TagDemoState.Layout.entries[id] }
)
CustomizationSwitchItem(
label = stringResource(R.string.app_components_tag_loading_label),
checked = loading,
onCheckedChange = { loading = it },
enabled = loadingSwitchEnabled
)
CustomizationFilterChips(
modifier = Modifier.padding(top = OudsTheme.spaces.fixed.medium),
label = stringResource(R.string.app_components_tag_shape_label),
chipLabels = OudsTag.Shape.entries.map { it.name },
selectedChipIndex = OudsTag.Shape.entries.indexOf(shape),
onSelectionChange = { id -> shape = OudsTag.Shape.entries[id] }
)
CustomizationFilterChips(
modifier = Modifier.padding(top = OudsTheme.spaces.fixed.medium),
label = stringResource(R.string.app_components_common_size_label),
chipLabels = OudsTag.Size.entries.map { it.name },
selectedChipIndex = OudsTag.Size.entries.indexOf(size),
onSelectionChange = { id -> size = OudsTag.Size.entries[id] }
)
CustomizationTextField(
modifier = Modifier.padding(top = OudsTheme.spaces.fixed.medium),
label = stringResource(R.string.app_components_common_label_label),
value = label,
onValueChange = { value -> label = value }
)
}
}

@Composable
private fun TagDemoContent(state: TagDemoState) {
with(state) {
val loading = if (loading) OudsTag.Loading(null) else null
if (layout == TagDemoState.Layout.TextAndIcon) {
OudsTag(
icon = OudsTag.Icon(painter = painterResource(R.drawable.ic_heart)),
label = label,
hierarchy = hierarchy,
status = status,
size = size,
shape = shape,
loading = loading,
)
} else {
OudsTag(
hasBullet = layout == TagDemoState.Layout.TextAndBullet,
label = label,
hierarchy = hierarchy,
status = status,
size = size,
shape = shape,
loading = loading,
)
}
}
}

private fun Code.Builder.tagDemoCodeSnippet(state: TagDemoState) {
with(state) {
functionCall(OudsTag::class.simpleName.orEmpty()) {
when (layout) {
TagDemoState.Layout.TextAndBullet -> typedArgument("hasBullet", true)
TagDemoState.Layout.TextAndIcon -> {
constructorCallArgument<OudsTag.Icon>("icon") {
painterArgument(R.drawable.ic_heart)
}
}
TagDemoState.Layout.TextOnly -> {}
}
labelArgument(label)
typedArgument("hierarchy", hierarchy)
typedArgument("shape", shape)
typedArgument("size", size)
typedArgument("status", status)
typedArgument("loading", loading)
}
}
}

@PreviewLightDark
@Composable
private fun PreviewTagDemoScreen() = OudsPreview {
TagDemoScreen()
}
Loading
Loading