diff --git a/app/src/main/java/com/orange/ouds/app/ui/BottomBar.kt b/app/src/main/java/com/orange/ouds/app/ui/BottomBar.kt index 0a7efd03f7..ccd2b215f8 100644 --- a/app/src/main/java/com/orange/ouds/app/ui/BottomBar.kt +++ b/app/src/main/java/com/orange/ouds/app/ui/BottomBar.kt @@ -42,9 +42,9 @@ import com.orange.ouds.app.R import com.orange.ouds.app.ui.utilities.LocalThemeDrawableResources import com.orange.ouds.app.ui.utilities.ThemeDrawableResourceProvider import com.orange.ouds.app.ui.utilities.composable.AppPreview +import com.orange.ouds.core.component.OudsIcon import com.orange.ouds.core.component.OudsNavigationBar import com.orange.ouds.core.component.OudsNavigationBarItem -import com.orange.ouds.core.component.OudsNavigationBarItemIcon import com.orange.ouds.core.theme.OudsTheme @Composable @@ -60,7 +60,7 @@ fun BottomBar(currentRoute: String, navigateToRoute: (String) -> Unit, modifier: items = BottomBarItem.entries.map { item -> OudsNavigationBarItem( selected = currentRoute == item.route, - icon = OudsNavigationBarItemIcon(painter = painterResource(item.iconResourceProvider.getResource(LocalThemeDrawableResources.current))), + icon = OudsIcon(painter = painterResource(item.iconResourceProvider.getResource(LocalThemeDrawableResources.current))), label = stringResource(item.titleRes), onClick = { navigateToRoute(item.route) } ) diff --git a/app/src/main/java/com/orange/ouds/app/ui/components/ComponentCode.kt b/app/src/main/java/com/orange/ouds/app/ui/components/ComponentCode.kt index 47fa0d193e..c377e70723 100644 --- a/app/src/main/java/com/orange/ouds/app/ui/components/ComponentCode.kt +++ b/app/src/main/java/com/orange/ouds/app/ui/components/ComponentCode.kt @@ -57,6 +57,7 @@ inline fun FunctionCall.Builder.iconArgument( constructorCallArgument(name) { painterArgument(if (tinted) resId else R.drawable.ic_untinted_square) contentDescriptionResId?.let { contentDescriptionArgument(it) } + // TODO: Remove generic type if (!tinted) tintedArgument(tinted) } } diff --git a/app/src/main/java/com/orange/ouds/app/ui/components/ComponentIllustrations.kt b/app/src/main/java/com/orange/ouds/app/ui/components/ComponentIllustrations.kt index e3f60b2244..cd0cd6fda0 100644 --- a/app/src/main/java/com/orange/ouds/app/ui/components/ComponentIllustrations.kt +++ b/app/src/main/java/com/orange/ouds/app/ui/components/ComponentIllustrations.kt @@ -54,15 +54,14 @@ import com.orange.ouds.core.component.OudsCircularProgressIndicator import com.orange.ouds.core.component.OudsColoredBox import com.orange.ouds.core.component.OudsFilterChip import com.orange.ouds.core.component.OudsFloatingActionButton -import com.orange.ouds.core.component.OudsFloatingActionButtonIcon import com.orange.ouds.core.component.OudsHorizontalDivider +import com.orange.ouds.core.component.OudsIcon import com.orange.ouds.core.component.OudsLink import com.orange.ouds.core.component.OudsLinkIndicator import com.orange.ouds.core.component.OudsListItem import com.orange.ouds.core.component.OudsListItemLeading import com.orange.ouds.core.component.OudsNavigationBar import com.orange.ouds.core.component.OudsNavigationBarItem -import com.orange.ouds.core.component.OudsNavigationBarItemIcon import com.orange.ouds.core.component.OudsPasswordInput import com.orange.ouds.core.component.OudsPinCodeInput import com.orange.ouds.core.component.OudsPinCodeInputLength @@ -186,10 +185,7 @@ fun DividerIllustration() = ComponentIllustration { @Composable fun FloatingActionButtonIllustration() = ComponentIllustration { OudsFloatingActionButton( - icon = OudsFloatingActionButtonIcon( - painter = painterResource(LocalThemeDrawableResources.current.tipsAndTricks), - contentDescription = "" - ), + icon = OudsIcon(painter = painterResource(LocalThemeDrawableResources.current.tipsAndTricks)), onClick = {} ) } @@ -221,7 +217,7 @@ fun NavigationBarIllustration() = ComponentIllustration { OudsNavigationBarItem( selected = index == 0, onClick = {}, - icon = OudsNavigationBarItemIcon(painter = painterResource(LocalThemeDrawableResources.current.tipsAndTricks)), + icon = OudsIcon(painter = painterResource(LocalThemeDrawableResources.current.tipsAndTricks)), label = stringResource(R.string.app_components_common_label_label) ) } diff --git a/app/src/main/java/com/orange/ouds/app/ui/components/alert/AlertMessageDemoScreen.kt b/app/src/main/java/com/orange/ouds/app/ui/components/alert/AlertMessageDemoScreen.kt index ea2c08139a..7ef0eabeef 100644 --- a/app/src/main/java/com/orange/ouds/app/ui/components/alert/AlertMessageDemoScreen.kt +++ b/app/src/main/java/com/orange/ouds/app/ui/components/alert/AlertMessageDemoScreen.kt @@ -40,11 +40,11 @@ import com.orange.ouds.app.ui.utilities.composable.CustomizationTextInput import com.orange.ouds.app.ui.utilities.composable.DemoScreen import com.orange.ouds.app.ui.utilities.nestedName import com.orange.ouds.app.ui.utilities.rememberUntintedIconPainter -import com.orange.ouds.core.component.OudsAlertIcon import com.orange.ouds.core.component.OudsAlertMessage import com.orange.ouds.core.component.OudsAlertMessageActionLink import com.orange.ouds.core.component.OudsAlertMessageActionLinkPosition import com.orange.ouds.core.component.OudsAlertMessageStatus +import com.orange.ouds.core.component.OudsIcon import com.orange.ouds.core.component.common.text.OudsAnnotatedAlertMessageBulletListLabel import com.orange.ouds.core.component.common.text.OudsAnnotatedAlertMessageDescription import com.orange.ouds.core.component.common.text.buildOudsAnnotatedAlertMessageBulletListLabel @@ -175,8 +175,8 @@ private fun AlertMessageDemoContent(state: AlertMessageDemoState) { with(state) { val alertIcon = when (icon) { AlertMessageDemoState.Icon.None -> null - AlertMessageDemoState.Icon.Tinted -> OudsAlertIcon(painter = painterResource(LocalThemeDrawableResources.current.tipsAndTricks), tinted = true) - AlertMessageDemoState.Icon.Untinted -> OudsAlertIcon(painter = rememberUntintedIconPainter(), tinted = false) + AlertMessageDemoState.Icon.Tinted -> OudsIcon(painter = painterResource(LocalThemeDrawableResources.current.tipsAndTricks), tinted = true) + AlertMessageDemoState.Icon.Untinted -> OudsIcon(painter = rememberUntintedIconPainter(), tinted = false) } val alertMessageStatus = when (status) { is OudsAlertMessageStatus.Accent -> OudsAlertMessageStatus.Accent(alertIcon) @@ -243,7 +243,7 @@ private fun Code.Builder.alertMessageDemoCodeSnippet(state: AlertMessageDemoStat is OudsAlertMessageStatus.Neutral -> { functionCallArgument(statusParameterName, status::class.java.nestedName) { if (icon != AlertMessageDemoState.Icon.None) { - iconArgument("icon", themeDrawableResources.tipsAndTricks, tinted = icon == AlertMessageDemoState.Icon.Tinted) + iconArgument("icon", themeDrawableResources.tipsAndTricks, tinted = icon == AlertMessageDemoState.Icon.Tinted) } } } diff --git a/app/src/main/java/com/orange/ouds/app/ui/components/alert/InlineAlertDemoScreen.kt b/app/src/main/java/com/orange/ouds/app/ui/components/alert/InlineAlertDemoScreen.kt index 4ede8b256b..3d9e29850f 100644 --- a/app/src/main/java/com/orange/ouds/app/ui/components/alert/InlineAlertDemoScreen.kt +++ b/app/src/main/java/com/orange/ouds/app/ui/components/alert/InlineAlertDemoScreen.kt @@ -37,7 +37,7 @@ import com.orange.ouds.app.ui.utilities.composable.CustomizationTextInput import com.orange.ouds.app.ui.utilities.composable.DemoScreen import com.orange.ouds.app.ui.utilities.nestedName import com.orange.ouds.app.ui.utilities.rememberUntintedIconPainter -import com.orange.ouds.core.component.OudsAlertIcon +import com.orange.ouds.core.component.OudsIcon import com.orange.ouds.core.component.OudsInlineAlert import com.orange.ouds.core.component.OudsInlineAlertStatus import com.orange.ouds.foundation.extensions.orElse @@ -65,8 +65,8 @@ private fun InlineAlertDemoBottomSheetContent(state: InlineAlertDemoState) { // Fixes a bug where calling sealedSubclasses returns an empty list in Compose previews // See https://issuetracker.google.com/issues/240601093 listOf( - OudsInlineAlertStatus.Accent(OudsAlertIcon.Default), - OudsInlineAlertStatus.Neutral(OudsAlertIcon.Default), + OudsInlineAlertStatus.Accent(OudsIcon.Default), + OudsInlineAlertStatus.Neutral(OudsIcon.Default), OudsInlineAlertStatus.Positive, OudsInlineAlertStatus.Info, OudsInlineAlertStatus.Warning, @@ -76,8 +76,8 @@ private fun InlineAlertDemoBottomSheetContent(state: InlineAlertDemoState) { OudsInlineAlertStatus::class.sealedSubclasses.mapNotNull { kClass -> tryOrNull { when (kClass) { - OudsInlineAlertStatus.Neutral::class -> OudsInlineAlertStatus.Neutral(OudsAlertIcon.Default) - OudsInlineAlertStatus.Accent::class -> OudsInlineAlertStatus.Accent(OudsAlertIcon.Default) + OudsInlineAlertStatus.Neutral::class -> OudsInlineAlertStatus.Neutral(OudsIcon.Default) + OudsInlineAlertStatus.Accent::class -> OudsInlineAlertStatus.Accent(OudsIcon.Default) else -> kClass.objectInstance } } @@ -121,8 +121,8 @@ private fun InlineAlertDemoBottomSheetContent(state: InlineAlertDemoState) { private fun InlineAlertDemoContent(state: InlineAlertDemoState) { with(state) { val alertIcon = when (icon) { - InlineAlertDemoState.Icon.Tinted -> OudsAlertIcon(painter = painterResource(LocalThemeDrawableResources.current.tipsAndTricks), tinted = true) - InlineAlertDemoState.Icon.Untinted -> OudsAlertIcon(painter = rememberUntintedIconPainter(), tinted = false) + InlineAlertDemoState.Icon.Tinted -> OudsIcon(painter = painterResource(LocalThemeDrawableResources.current.tipsAndTricks), tinted = true) + InlineAlertDemoState.Icon.Untinted -> OudsIcon(painter = rememberUntintedIconPainter(), tinted = false) } OudsInlineAlert( label = label, @@ -146,7 +146,7 @@ private fun Code.Builder.inlineAlertDemoCodeSnippet(state: InlineAlertDemoState, is OudsInlineAlertStatus.Accent, is OudsInlineAlertStatus.Neutral -> { functionCallArgument(statusParameterName, status::class.java.nestedName) { - iconArgument("icon", themeDrawableResources.tipsAndTricks, tinted = icon == InlineAlertDemoState.Icon.Tinted) + iconArgument("icon", themeDrawableResources.tipsAndTricks, tinted = icon == InlineAlertDemoState.Icon.Tinted) } } OudsInlineAlertStatus.Info, diff --git a/app/src/main/java/com/orange/ouds/app/ui/components/alert/InlineAlertDemoState.kt b/app/src/main/java/com/orange/ouds/app/ui/components/alert/InlineAlertDemoState.kt index 0e3ef298ce..910b1c0550 100644 --- a/app/src/main/java/com/orange/ouds/app/ui/components/alert/InlineAlertDemoState.kt +++ b/app/src/main/java/com/orange/ouds/app/ui/components/alert/InlineAlertDemoState.kt @@ -21,7 +21,7 @@ import androidx.compose.runtime.saveable.rememberSaveable import androidx.compose.runtime.setValue import androidx.compose.ui.res.stringResource import com.orange.ouds.app.R -import com.orange.ouds.core.component.OudsAlertIcon +import com.orange.ouds.core.component.OudsIcon import com.orange.ouds.core.component.OudsInlineAlertDefaults import com.orange.ouds.core.component.OudsInlineAlertStatus @@ -67,8 +67,8 @@ class InlineAlertDemoState( restore = { list: List -> val statusClassName = list[1] as String val status = when (val kClass = Class.forName(statusClassName).kotlin) { - OudsInlineAlertStatus.Neutral::class -> OudsInlineAlertStatus.Neutral(OudsAlertIcon.Default) - OudsInlineAlertStatus.Accent::class -> OudsInlineAlertStatus.Accent(OudsAlertIcon.Default) + OudsInlineAlertStatus.Neutral::class -> OudsInlineAlertStatus.Neutral(OudsIcon.Default) + OudsInlineAlertStatus.Accent::class -> OudsInlineAlertStatus.Accent(OudsIcon.Default) else -> kClass.objectInstance as OudsInlineAlertStatus } diff --git a/app/src/main/java/com/orange/ouds/app/ui/components/badge/BadgeDemoScreen.kt b/app/src/main/java/com/orange/ouds/app/ui/components/badge/BadgeDemoScreen.kt index caa0e47132..4543ea3f52 100644 --- a/app/src/main/java/com/orange/ouds/app/ui/components/badge/BadgeDemoScreen.kt +++ b/app/src/main/java/com/orange/ouds/app/ui/components/badge/BadgeDemoScreen.kt @@ -46,9 +46,9 @@ import com.orange.ouds.app.ui.utilities.composable.DemoScreen import com.orange.ouds.app.ui.utilities.nestedName import com.orange.ouds.app.ui.utilities.rememberUntintedIconPainter import com.orange.ouds.core.component.OudsBadge -import com.orange.ouds.core.component.OudsBadgeIcon import com.orange.ouds.core.component.OudsBadgeSize import com.orange.ouds.core.component.OudsBadgeStatus +import com.orange.ouds.core.component.OudsIcon import com.orange.ouds.core.component.OudsIconBadgeStatus import com.orange.ouds.foundation.extensions.orElse import com.orange.ouds.foundation.extensions.toSentenceCase @@ -192,7 +192,7 @@ private fun Code.Builder.badgeDemoCodeSnippet(state: BadgeDemoState, badgeWithIc is OudsIconBadgeStatus.Neutral, is OudsIconBadgeStatus.Accent -> { functionCallArgument(statusParameterName, badgeWithIconStatus::class.java.nestedName) { - iconArgument("icon", themeDrawableResources.tipsAndTricks, tinted = icon == BadgeDemoState.Icon.Tinted) + iconArgument("icon", themeDrawableResources.tipsAndTricks, tinted = icon == BadgeDemoState.Icon.Tinted) } } OudsIconBadgeStatus.Positive, @@ -216,8 +216,8 @@ private fun Code.Builder.badgeDemoCodeSnippet(state: BadgeDemoState, badgeWithIc private fun getBadgeWithIconStatus(state: BadgeDemoState): OudsIconBadgeStatus { with(state) { val badgeIcon = when (icon) { - BadgeDemoState.Icon.Tinted -> OudsBadgeIcon(painter = painterResource(id = LocalThemeDrawableResources.current.tipsAndTricks), tinted = true) - BadgeDemoState.Icon.Untinted -> OudsBadgeIcon(painter = rememberUntintedIconPainter(), tinted = false) + BadgeDemoState.Icon.Tinted -> OudsIcon(painter = painterResource(id = LocalThemeDrawableResources.current.tipsAndTricks), tinted = true) + BadgeDemoState.Icon.Untinted -> OudsIcon(painter = rememberUntintedIconPainter(), tinted = false) } return when (status) { OudsBadgeStatus.Neutral -> OudsIconBadgeStatus.Neutral(badgeIcon) diff --git a/app/src/main/java/com/orange/ouds/app/ui/components/button/ButtonDemoScreen.kt b/app/src/main/java/com/orange/ouds/app/ui/components/button/ButtonDemoScreen.kt index 6925799c76..8f2e874f9b 100644 --- a/app/src/main/java/com/orange/ouds/app/ui/components/button/ButtonDemoScreen.kt +++ b/app/src/main/java/com/orange/ouds/app/ui/components/button/ButtonDemoScreen.kt @@ -35,8 +35,8 @@ import com.orange.ouds.app.ui.utilities.composable.DemoScreen import com.orange.ouds.app.ui.utilities.rememberUntintedIconPainter import com.orange.ouds.core.component.OudsButton import com.orange.ouds.core.component.OudsButtonAppearance -import com.orange.ouds.core.component.OudsButtonIcon -import com.orange.ouds.core.component.OudsButtonLoader +import com.orange.ouds.core.component.OudsIcon +import com.orange.ouds.core.component.OudsLoader import com.orange.ouds.core.component.OudsSmallButton import com.orange.ouds.foundation.ExperimentalOudsApi import com.orange.ouds.theme.OudsVersion @@ -122,12 +122,12 @@ private fun ButtonDemoContent(state: ButtonDemoState) { ButtonDemoState.Icon.Tinted -> painterResource(id = LocalThemeDrawableResources.current.tipsAndTricks) ButtonDemoState.Icon.Untinted -> rememberUntintedIconPainter() } - val buttonIcon = OudsButtonIcon( + val buttonIcon = OudsIcon( painter = painter, contentDescription = stringResource(id = R.string.app_components_common_icon_a11y), tinted = icon == ButtonDemoState.Icon.Tinted ) - val loader = if (hasLoader) OudsButtonLoader(null) else null + val loader = if (hasLoader) OudsLoader(null) else null when (size) { ButtonDemoState.Size.Default -> when (layout) { @@ -191,7 +191,7 @@ private fun Code.Builder.buttonDemoCodeSnippet(state: ButtonDemoState, themeDraw } functionCall(functionName) { if (layout in listOf(ButtonDemoState.Layout.IconOnly, ButtonDemoState.Layout.TextAndIcon)) { - iconArgument( + iconArgument( "icon", themeDrawableResources.tipsAndTricks, R.string.app_components_common_icon_a11y, @@ -204,7 +204,7 @@ private fun Code.Builder.buttonDemoCodeSnippet(state: ButtonDemoState, themeDraw onClickArgument() enabledArgument(enabled) if (hasLoader) { - constructorCallArgument("loader") { + constructorCallArgument("loader") { typedArgument("progress", null) } } diff --git a/app/src/main/java/com/orange/ouds/app/ui/components/button/NavigationButtonDemoScreen.kt b/app/src/main/java/com/orange/ouds/app/ui/components/button/NavigationButtonDemoScreen.kt index f2fc565975..d919d7956d 100644 --- a/app/src/main/java/com/orange/ouds/app/ui/components/button/NavigationButtonDemoScreen.kt +++ b/app/src/main/java/com/orange/ouds/app/ui/components/button/NavigationButtonDemoScreen.kt @@ -27,11 +27,11 @@ 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.CustomizationTextInput import com.orange.ouds.app.ui.utilities.composable.DemoScreen -import com.orange.ouds.core.component.OudsButtonLoader +import com.orange.ouds.core.component.OudsLoader import com.orange.ouds.core.component.OudsNavigationButton import com.orange.ouds.core.component.OudsNavigationButtonAppearance -import com.orange.ouds.core.component.OudsNavigationButtonChevron import com.orange.ouds.core.component.OudsNavigationButtonDefaults +import com.orange.ouds.core.component.OudsNavigationButtonIndicator import com.orange.ouds.theme.OudsVersion @Composable @@ -64,10 +64,10 @@ private fun NavigationButtonDemoBottomSheetContent(state: NavigationButtonDemoSt ) CustomizationFilterChips( applyTopPadding = true, - label = stringResource(R.string.app_components_button_navigationButton_chevron_tech), - chipLabels = OudsNavigationButtonChevron.entries.map { it.name }, - selectedChipIndex = OudsNavigationButtonChevron.entries.indexOf(chevron), - onSelectionChange = { index -> chevron = OudsNavigationButtonChevron.entries[index] } + label = stringResource(R.string.app_components_button_navigationButton_indicator_tech), + chipLabels = OudsNavigationButtonIndicator.entries.map { it.name }, + selectedChipIndex = OudsNavigationButtonIndicator.entries.indexOf(indicator), + onSelectionChange = { index -> indicator = OudsNavigationButtonIndicator.entries[index] } ) CustomizationFilterChips( applyTopPadding = true, @@ -94,10 +94,10 @@ private fun NavigationButtonDemoBottomSheetContent(state: NavigationButtonDemoSt @Composable private fun NavigationButtonDemoContent(state: NavigationButtonDemoState) { with(state) { - val loader = if (hasLoader) OudsButtonLoader(null) else null + val loader = if (hasLoader) OudsLoader(null) else null OudsNavigationButton( label = label, - chevron = chevron, + indicator = indicator, onClick = {}, enabled = enabled, loader = loader, @@ -111,11 +111,11 @@ private fun Code.Builder.navigationButtonDemoCodeSnippet(state: NavigationButton coloredBoxCall(onColoredBox) { functionCall("OudsNavigationButton") { label?.let { labelArgument(label) } - typedArgument("chevron", chevron) + typedArgument("indicator", indicator) onClickArgument() if (!enabled) enabledArgument(enabled) if (hasLoader) { - constructorCallArgument("loader") { + constructorCallArgument("loader") { typedArgument("progress", null) } } diff --git a/app/src/main/java/com/orange/ouds/app/ui/components/button/NavigationButtonDemoState.kt b/app/src/main/java/com/orange/ouds/app/ui/components/button/NavigationButtonDemoState.kt index 82511dc831..7fa04ac183 100644 --- a/app/src/main/java/com/orange/ouds/app/ui/components/button/NavigationButtonDemoState.kt +++ b/app/src/main/java/com/orange/ouds/app/ui/components/button/NavigationButtonDemoState.kt @@ -19,8 +19,8 @@ import androidx.compose.runtime.saveable.listSaver import androidx.compose.runtime.saveable.rememberSaveable import androidx.compose.runtime.setValue import com.orange.ouds.core.component.OudsNavigationButtonAppearance -import com.orange.ouds.core.component.OudsNavigationButtonChevron import com.orange.ouds.core.component.OudsNavigationButtonDefaults +import com.orange.ouds.core.component.OudsNavigationButtonIndicator @Composable fun rememberNavigationButtonDemoState( @@ -28,10 +28,10 @@ fun rememberNavigationButtonDemoState( onColoredBox: Boolean = false, hasLoader: Boolean = false, appearance: OudsNavigationButtonAppearance = OudsNavigationButtonDefaults.Appearance, - chevron: OudsNavigationButtonChevron = OudsNavigationButtonDefaults.Chevron, + indicator: OudsNavigationButtonIndicator = OudsNavigationButtonDefaults.Indicator, label: String? = null -) = rememberSaveable(label, enabled, onColoredBox, hasLoader, appearance, chevron, saver = NavigationButtonDemoState.Saver) { - NavigationButtonDemoState(enabled, onColoredBox, hasLoader, appearance, chevron, label) +) = rememberSaveable(label, enabled, onColoredBox, hasLoader, appearance, indicator, saver = NavigationButtonDemoState.Saver) { + NavigationButtonDemoState(enabled, onColoredBox, hasLoader, appearance, indicator, label) } class NavigationButtonDemoState( @@ -39,7 +39,7 @@ class NavigationButtonDemoState( onColoredBox: Boolean, hasLoader: Boolean, appearance: OudsNavigationButtonAppearance, - chevron: OudsNavigationButtonChevron, + indicator: OudsNavigationButtonIndicator, label: String? ) : BaseButtonDemoState(enabled, onColoredBox, hasLoader) { @@ -53,7 +53,7 @@ class NavigationButtonDemoState( with(state) { listOf( appearance, - chevron, + indicator, label, with(BaseButtonDemoState.Saver) { save(state) } ) @@ -67,7 +67,7 @@ class NavigationButtonDemoState( onColoredBox, hasLoader, list[0] as OudsNavigationButtonAppearance, - list[1] as OudsNavigationButtonChevron, + list[1] as OudsNavigationButtonIndicator, list[2] as String? ) } @@ -85,7 +85,7 @@ class NavigationButtonDemoState( } } - var chevron: OudsNavigationButtonChevron by mutableStateOf(chevron) + var indicator: OudsNavigationButtonIndicator by mutableStateOf(indicator) var label: String? by mutableStateOf(label) diff --git a/app/src/main/java/com/orange/ouds/app/ui/components/chip/ChipDemoScreen.kt b/app/src/main/java/com/orange/ouds/app/ui/components/chip/ChipDemoScreen.kt index 4ebbd06b21..33e9998dc7 100644 --- a/app/src/main/java/com/orange/ouds/app/ui/components/chip/ChipDemoScreen.kt +++ b/app/src/main/java/com/orange/ouds/app/ui/components/chip/ChipDemoScreen.kt @@ -32,7 +32,7 @@ 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.CustomizationTextInput import com.orange.ouds.app.ui.utilities.rememberUntintedIconPainter -import com.orange.ouds.core.component.OudsChipIcon +import com.orange.ouds.core.component.OudsIcon import com.orange.ouds.core.theme.OudsTheme @Composable @@ -68,7 +68,7 @@ fun ChipDemoBottomSheetContent(state: ChipDemoState) { } @Composable -fun ChipDemoContent(state: ChipDemoState, content: @Composable (index: Int, icon: OudsChipIcon) -> Unit) { +fun ChipDemoContent(state: ChipDemoState, content: @Composable (index: Int, icon: OudsIcon) -> Unit) { with(state) { val themeDrawableResources = LocalThemeDrawableResources.current val icons = listOf( @@ -84,7 +84,7 @@ fun ChipDemoContent(state: ChipDemoState, content: @Composable (index: Int, icon ChipDemoState.Icon.Tinted -> painterResource(id = icons[index % icons.count()]) ChipDemoState.Icon.Untinted -> rememberUntintedIconPainter() } - val chipIcon = OudsChipIcon( + val chipIcon = OudsIcon( painter = painter, contentDescription = stringResource(id = R.string.app_components_common_icon_a11y), tinted = icon == ChipDemoState.Icon.Tinted @@ -98,7 +98,7 @@ fun ChipDemoContent(state: ChipDemoState, content: @Composable (index: Int, icon fun FunctionCall.Builder.chipArguments(state: ChipDemoState, themeDrawableResources: ThemeDrawableResources) = with(state) { onClickArgument() if (layout in listOf(ChipDemoState.Layout.IconOnly, ChipDemoState.Layout.TextAndIcon)) { - iconArgument("icon", themeDrawableResources.call, R.string.app_components_common_icon_a11y, icon == ChipDemoState.Icon.Tinted) + iconArgument("icon", themeDrawableResources.call, R.string.app_components_common_icon_a11y, icon == ChipDemoState.Icon.Tinted) } if (layout in listOf(ChipDemoState.Layout.TextOnly, ChipDemoState.Layout.TextAndIcon)) { val separator = if (label.isBlank()) "" else " " diff --git a/app/src/main/java/com/orange/ouds/app/ui/components/controlitem/ControlItemDemoScreen.kt b/app/src/main/java/com/orange/ouds/app/ui/components/controlitem/ControlItemDemoScreen.kt index 8ee6567715..a66311287b 100644 --- a/app/src/main/java/com/orange/ouds/app/ui/components/controlitem/ControlItemDemoScreen.kt +++ b/app/src/main/java/com/orange/ouds/app/ui/components/controlitem/ControlItemDemoScreen.kt @@ -31,7 +31,7 @@ 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.CustomizationTextInput import com.orange.ouds.app.ui.utilities.rememberUntintedIconPainter -import com.orange.ouds.core.component.OudsControlItemIcon +import com.orange.ouds.core.component.OudsIcon import com.orange.ouds.core.component.common.OudsError import com.orange.ouds.core.component.common.text.buildOudsAnnotatedErrorMessage @@ -206,11 +206,11 @@ private fun ControlItemConstrainedMaxWidthCustomization(state: ControlItemDemoSt } @Composable -fun controlItemIcon(state: ControlItemDemoState): OudsControlItemIcon? { +fun controlItemIcon(state: ControlItemDemoState): OudsIcon? { return when (state.icon) { ControlItemDemoState.Icon.None -> null - ControlItemDemoState.Icon.Tinted -> OudsControlItemIcon(painter = painterResource(id = LocalThemeDrawableResources.current.tipsAndTricks)) - ControlItemDemoState.Icon.Untinted -> OudsControlItemIcon(painter = rememberUntintedIconPainter(), tinted = false) + ControlItemDemoState.Icon.Tinted -> OudsIcon(painter = painterResource(id = LocalThemeDrawableResources.current.tipsAndTricks)) + ControlItemDemoState.Icon.Untinted -> OudsIcon(painter = rememberUntintedIconPainter(), tinted = false) } } @@ -236,7 +236,7 @@ fun FunctionCall.Builder.controlItemArguments(state: ControlItemDemoState, theme labelArgument(label) if (!description.isNullOrBlank()) typedArgument("description", description) if (icon != ControlItemDemoState.Icon.None) { - iconArgument("icon", themeDrawableResources.tipsAndTricks, tinted = icon == ControlItemDemoState.Icon.Tinted) + iconArgument("icon", themeDrawableResources.tipsAndTricks, tinted = icon == ControlItemDemoState.Icon.Tinted) } if (!edgeToEdge) typedArgument("edgeToEdge", edgeToEdge) if (divider) typedArgument("divider", divider) diff --git a/app/src/main/java/com/orange/ouds/app/ui/components/floatingactionbutton/FloatingActionButtonDemoScreen.kt b/app/src/main/java/com/orange/ouds/app/ui/components/floatingactionbutton/FloatingActionButtonDemoScreen.kt index deb1bd2eb5..0e7aa454cb 100644 --- a/app/src/main/java/com/orange/ouds/app/ui/components/floatingactionbutton/FloatingActionButtonDemoScreen.kt +++ b/app/src/main/java/com/orange/ouds/app/ui/components/floatingactionbutton/FloatingActionButtonDemoScreen.kt @@ -34,7 +34,7 @@ import com.orange.ouds.app.ui.utilities.rememberUntintedIconPainter import com.orange.ouds.core.component.OudsExtendedFloatingActionButton import com.orange.ouds.core.component.OudsFloatingActionButton import com.orange.ouds.core.component.OudsFloatingActionButtonAppearance -import com.orange.ouds.core.component.OudsFloatingActionButtonIcon +import com.orange.ouds.core.component.OudsIcon import com.orange.ouds.core.component.OudsLargeFloatingActionButton import com.orange.ouds.core.component.OudsSmallFloatingActionButton @@ -104,7 +104,7 @@ private fun FloatingActionButtonDemoContent(state: FloatingActionButtonDemoState FloatingActionButtonDemoState.Icon.Tinted -> painterResource(id = LocalThemeDrawableResources.current.tipsAndTricks) FloatingActionButtonDemoState.Icon.Untinted -> rememberUntintedIconPainter() } - val floatingActionButtonIcon = OudsFloatingActionButtonIcon( + val floatingActionButtonIcon = OudsIcon( painter = painter, contentDescription = stringResource(id = R.string.app_components_common_icon_a11y), tinted = icon == FloatingActionButtonDemoState.Icon.Tinted @@ -155,7 +155,7 @@ private fun Code.Builder.floatingActionButtonDemoCodeSnippet(state: FloatingActi labelArgument(label) } if (layout != FloatingActionButtonDemoState.Layout.TextOnly) { - iconArgument( + iconArgument( "icon", themeDrawableResources.tipsAndTricks, R.string.app_components_common_icon_a11y, diff --git a/app/src/main/java/com/orange/ouds/app/ui/components/link/LinkDemoScreen.kt b/app/src/main/java/com/orange/ouds/app/ui/components/link/LinkDemoScreen.kt index 8f05b6e4d5..19c3b7bc4b 100644 --- a/app/src/main/java/com/orange/ouds/app/ui/components/link/LinkDemoScreen.kt +++ b/app/src/main/java/com/orange/ouds/app/ui/components/link/LinkDemoScreen.kt @@ -33,9 +33,9 @@ import com.orange.ouds.app.ui.utilities.composable.CustomizationSwitchItem import com.orange.ouds.app.ui.utilities.composable.CustomizationTextInput import com.orange.ouds.app.ui.utilities.composable.DemoScreen import com.orange.ouds.app.ui.utilities.rememberUntintedIconPainter +import com.orange.ouds.core.component.OudsIcon import com.orange.ouds.core.component.OudsLink import com.orange.ouds.core.component.OudsLinkDensity -import com.orange.ouds.core.component.OudsLinkIcon import com.orange.ouds.core.component.OudsLinkIndicator import com.orange.ouds.core.component.OudsLinkSize import com.orange.ouds.theme.OudsVersion @@ -125,7 +125,7 @@ private fun LinkDemoContent(state: LinkDemoState) { } OudsLink( label = label, - icon = OudsLinkIcon(painter, tinted = icon == LinkDemoState.Icon.Tinted), + icon = OudsIcon(painter, tinted = icon == LinkDemoState.Icon.Tinted), onClick = {}, enabled = enabled, size = size, @@ -160,7 +160,7 @@ private fun Code.Builder.linkDemoCodeSnippet(state: LinkDemoState, themeDrawable labelArgument(label) when (layout) { LinkDemoState.Layout.TextOnly -> {} - LinkDemoState.Layout.TextAndIcon -> iconArgument( + LinkDemoState.Layout.TextAndIcon -> iconArgument( "icon", themeDrawableResources.tipsAndTricks, tinted = icon == LinkDemoState.Icon.Tinted diff --git a/app/src/main/java/com/orange/ouds/app/ui/components/navigationbar/NavigationBarDemoScreen.kt b/app/src/main/java/com/orange/ouds/app/ui/components/navigationbar/NavigationBarDemoScreen.kt index b2da1572d7..1d168f3e7b 100644 --- a/app/src/main/java/com/orange/ouds/app/ui/components/navigationbar/NavigationBarDemoScreen.kt +++ b/app/src/main/java/com/orange/ouds/app/ui/components/navigationbar/NavigationBarDemoScreen.kt @@ -36,10 +36,10 @@ import com.orange.ouds.app.ui.utilities.ThemeDrawableResources import com.orange.ouds.app.ui.utilities.composable.AppPreview import com.orange.ouds.app.ui.utilities.composable.CustomizationFilterChips import com.orange.ouds.app.ui.utilities.composable.DemoScreen +import com.orange.ouds.core.component.OudsIcon import com.orange.ouds.core.component.OudsNavigationBar import com.orange.ouds.core.component.OudsNavigationBarItem import com.orange.ouds.core.component.OudsNavigationBarItemBadge -import com.orange.ouds.core.component.OudsNavigationBarItemIcon import com.orange.ouds.core.theme.OudsTheme import com.orange.ouds.theme.OudsVersion @@ -96,7 +96,7 @@ private fun NavigationBarDemoContent(state: NavigationBarDemoState) { selected = selectedItemId == index, onClick = { selectedItemId = index }, label = label, - icon = OudsNavigationBarItemIcon(painter = painterResource(id = item.iconResourceProvider.getResource(LocalThemeDrawableResources.current))), + icon = OudsIcon(painter = painterResource(id = item.iconResourceProvider.getResource(LocalThemeDrawableResources.current))), badge = if (isLastItem) { when (lastItemBadge) { NavigationBarDemoState.ItemBadge.None -> null @@ -134,7 +134,7 @@ private fun Code.Builder.navigationBarDemoCodeSnippet( typedArgument("selected", index == state.selectedItemId) onClickArgument() labelArgument(label) - iconArgument("icon", item.iconResourceProvider.getResource(themeDrawableResources)) + iconArgument("icon", item.iconResourceProvider.getResource(themeDrawableResources)) if (isLastItem && lastItemBadge != NavigationBarDemoState.ItemBadge.None) { constructorCallArgument("badge") { when (lastItemBadge) { diff --git a/app/src/main/java/com/orange/ouds/app/ui/components/passwordinput/PasswordInputDemoScreen.kt b/app/src/main/java/com/orange/ouds/app/ui/components/passwordinput/PasswordInputDemoScreen.kt index 1abb1f8323..f139c6b56d 100644 --- a/app/src/main/java/com/orange/ouds/app/ui/components/passwordinput/PasswordInputDemoScreen.kt +++ b/app/src/main/java/com/orange/ouds/app/ui/components/passwordinput/PasswordInputDemoScreen.kt @@ -33,8 +33,8 @@ 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.CustomizationTextInput import com.orange.ouds.app.ui.utilities.composable.DemoScreen +import com.orange.ouds.core.component.OudsLoader import com.orange.ouds.core.component.OudsPasswordInput -import com.orange.ouds.core.component.OudsTextInputLoader import com.orange.ouds.core.component.common.OudsError import com.orange.ouds.core.component.common.text.buildOudsAnnotatedErrorMessage import com.orange.ouds.core.component.common.text.buildOudsAnnotatedHelperText @@ -152,7 +152,7 @@ private fun PasswordInputDemoBottomSheetContent(state: PasswordInputDemoState) { private fun PasswordInputDemoContent(state: PasswordInputDemoState) { with(state) { val focusManager = LocalFocusManager.current - val loader = if (hasLoader) OudsTextInputLoader(null) else null + val loader = if (hasLoader) OudsLoader(null) else null val passwordInputError = when { error && annotatedText -> { val errorMessageHtml = stringResource(R.string.app_components_passwordInput_annotatedErrorMessage_text) @@ -213,7 +213,7 @@ private fun Code.Builder.passwordInputDemoCodeSnippet(state: PasswordInputDemoSt typedArgument("outlined", outlined) if (lockIcon) typedArgument("lockIcon", lockIcon) if (hasLoader) { - constructorCallArgument("loader") { + constructorCallArgument("loader") { typedArgument("progress", null) } } diff --git a/app/src/main/java/com/orange/ouds/app/ui/components/tag/TagDemoScreen.kt b/app/src/main/java/com/orange/ouds/app/ui/components/tag/TagDemoScreen.kt index 6fd8a8cf48..2c2ab5f72e 100644 --- a/app/src/main/java/com/orange/ouds/app/ui/components/tag/TagDemoScreen.kt +++ b/app/src/main/java/com/orange/ouds/app/ui/components/tag/TagDemoScreen.kt @@ -39,10 +39,11 @@ import com.orange.ouds.app.ui.utilities.composable.CustomizationTextInput import com.orange.ouds.app.ui.utilities.composable.DemoScreen import com.orange.ouds.app.ui.utilities.nestedName import com.orange.ouds.app.ui.utilities.rememberUntintedIconPainter +import com.orange.ouds.core.component.OudsIcon +import com.orange.ouds.core.component.OudsLoader import com.orange.ouds.core.component.OudsTag import com.orange.ouds.core.component.OudsTagAppearance import com.orange.ouds.core.component.OudsTagAsset -import com.orange.ouds.core.component.OudsTagLoader import com.orange.ouds.core.component.OudsTagSize import com.orange.ouds.core.component.OudsTagStatus import com.orange.ouds.foundation.extensions.toSentenceCase @@ -164,12 +165,12 @@ private fun TagDemoBottomSheetContent(state: TagDemoState) { private fun TagDemoContent(state: TagDemoState) { with(state) { val content: @Composable (OudsTagSize, Boolean) -> Unit = { size, visible -> - val loader = if (hasLoader) OudsTagLoader(null) else null + val loader = if (hasLoader) OudsLoader(null) else null val painter = when (icon) { TagDemoState.Icon.Tinted -> painterResource(id = LocalThemeDrawableResources.current.tipsAndTricks) TagDemoState.Icon.Untinted -> rememberUntintedIconPainter() } - val tagIcon = OudsTagAsset.Icon(painter = painter, tinted = icon == TagDemoState.Icon.Tinted) + val tagIcon = OudsIcon(painter = painter, tinted = icon == TagDemoState.Icon.Tinted) val alpha = if (visible) 1f else 0f OudsTag( modifier = Modifier.alpha(alpha), @@ -189,22 +190,22 @@ private fun TagDemoContent(state: TagDemoState) { is OudsTagStatus.Positive -> when (layout) { TagDemoState.Layout.TextOnly -> OudsTagStatus.Positive() TagDemoState.Layout.TextAndBullet -> OudsTagStatus.Positive(asset = OudsTagAsset.Bullet) - TagDemoState.Layout.TextAndIcon -> OudsTagStatus.Positive(asset = OudsTagAsset.Icon.Default) + TagDemoState.Layout.TextAndIcon -> OudsTagStatus.Positive(asset = OudsIcon.Default) } is OudsTagStatus.Warning -> when (layout) { TagDemoState.Layout.TextOnly -> OudsTagStatus.Warning() TagDemoState.Layout.TextAndBullet -> OudsTagStatus.Warning(asset = OudsTagAsset.Bullet) - TagDemoState.Layout.TextAndIcon -> OudsTagStatus.Warning(asset = OudsTagAsset.Icon.Default) + TagDemoState.Layout.TextAndIcon -> OudsTagStatus.Warning(asset = OudsIcon.Default) } is OudsTagStatus.Negative -> when (layout) { TagDemoState.Layout.TextOnly -> OudsTagStatus.Negative() TagDemoState.Layout.TextAndBullet -> OudsTagStatus.Negative(asset = OudsTagAsset.Bullet) - TagDemoState.Layout.TextAndIcon -> OudsTagStatus.Negative(asset = OudsTagAsset.Icon.Default) + TagDemoState.Layout.TextAndIcon -> OudsTagStatus.Negative(asset = OudsIcon.Default) } is OudsTagStatus.Info -> when (layout) { TagDemoState.Layout.TextOnly -> OudsTagStatus.Info() TagDemoState.Layout.TextAndBullet -> OudsTagStatus.Info(asset = OudsTagAsset.Bullet) - TagDemoState.Layout.TextAndIcon -> OudsTagStatus.Info(asset = OudsTagAsset.Icon.Default) + TagDemoState.Layout.TextAndIcon -> OudsTagStatus.Info(asset = OudsIcon.Default) } }, size = size, @@ -237,7 +238,7 @@ private fun Code.Builder.tagDemoCodeSnippet(state: TagDemoState, themeDrawableRe TagDemoState.Layout.TextAndIcon -> { when (status) { is OudsTagStatus.Neutral, - is OudsTagStatus.Accent -> iconArgument( + is OudsTagStatus.Accent -> iconArgument( assetParameterName, themeDrawableResources.tipsAndTricks, tinted = icon == TagDemoState.Icon.Tinted @@ -245,13 +246,13 @@ private fun Code.Builder.tagDemoCodeSnippet(state: TagDemoState, themeDrawableRe is OudsTagStatus.Positive, is OudsTagStatus.Warning, is OudsTagStatus.Info, - is OudsTagStatus.Negative -> rawArgument(assetParameterName, OudsTagAsset.Icon.Default::class.java.nestedName) + is OudsTagStatus.Negative -> rawArgument(assetParameterName, OudsIcon.Default::class.java.nestedName) } } } } if (hasLoader) { - constructorCallArgument("loader") { + constructorCallArgument("loader") { typedArgument("progress", null) } } diff --git a/app/src/main/java/com/orange/ouds/app/ui/components/textarea/TextAreaDemoScreen.kt b/app/src/main/java/com/orange/ouds/app/ui/components/textarea/TextAreaDemoScreen.kt index 29bded52a4..63cad4abba 100644 --- a/app/src/main/java/com/orange/ouds/app/ui/components/textarea/TextAreaDemoScreen.kt +++ b/app/src/main/java/com/orange/ouds/app/ui/components/textarea/TextAreaDemoScreen.kt @@ -18,7 +18,6 @@ import androidx.compose.ui.platform.LocalFocusManager 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.utilities.appendHtml import com.orange.ouds.app.ui.components.Component import com.orange.ouds.app.ui.components.constrainedMaxWidthArgument import com.orange.ouds.app.ui.components.enabledArgument @@ -28,17 +27,17 @@ import com.orange.ouds.app.ui.components.labelArgument import com.orange.ouds.app.ui.components.onClickArgument import com.orange.ouds.app.ui.components.readOnlyArgument import com.orange.ouds.app.ui.utilities.Code +import com.orange.ouds.app.ui.utilities.appendHtml import com.orange.ouds.app.ui.utilities.composable.AppPreview import com.orange.ouds.app.ui.utilities.composable.CustomizationSwitchItem import com.orange.ouds.app.ui.utilities.composable.CustomizationTextInput import com.orange.ouds.app.ui.utilities.composable.DemoScreen +import com.orange.ouds.core.component.OudsLoader import com.orange.ouds.core.component.OudsTextArea import com.orange.ouds.core.component.OudsTextInputHelperLink -import com.orange.ouds.core.component.OudsTextInputLoader import com.orange.ouds.core.component.common.OudsError import com.orange.ouds.core.component.common.text.buildOudsAnnotatedErrorMessage import com.orange.ouds.core.component.common.text.buildOudsAnnotatedHelperText -import com.orange.ouds.core.component.common.text.withStrong import com.orange.ouds.theme.OudsVersion @Composable @@ -141,7 +140,7 @@ private fun TextAreaDemoBottomSheetContent(state: TextAreaDemoState) { private fun TextAreaDemoContent(state: TextAreaDemoState) { with(state) { val focusManager = LocalFocusManager.current - val loader = if (hasLoader) OudsTextInputLoader(null) else null + val loader = if (hasLoader) OudsLoader(null) else null val textAreaError = when { error && annotatedText -> { val errorHtml = stringResource(R.string.app_components_textArea_annotatedErrorMessage_text) @@ -202,7 +201,7 @@ private fun Code.Builder.textAreaDemoCodeSnippet(state: TextAreaDemoState) { if (placeholder.isNotEmpty()) typedArgument("placeholder", placeholder) typedArgument("outlined", outlined) if (hasLoader) { - constructorCallArgument("loader") { + constructorCallArgument("loader") { typedArgument("progress", null) } } diff --git a/app/src/main/java/com/orange/ouds/app/ui/components/textinput/TextInputDemoScreen.kt b/app/src/main/java/com/orange/ouds/app/ui/components/textinput/TextInputDemoScreen.kt index bda783508d..adebed090a 100644 --- a/app/src/main/java/com/orange/ouds/app/ui/components/textinput/TextInputDemoScreen.kt +++ b/app/src/main/java/com/orange/ouds/app/ui/components/textinput/TextInputDemoScreen.kt @@ -40,11 +40,11 @@ import com.orange.ouds.app.ui.utilities.composable.CustomizationSwitchItem import com.orange.ouds.app.ui.utilities.composable.CustomizationTextInput import com.orange.ouds.app.ui.utilities.composable.DemoScreen import com.orange.ouds.app.ui.utilities.rememberUntintedIconPainter +import com.orange.ouds.core.component.OudsIcon +import com.orange.ouds.core.component.OudsIconButton +import com.orange.ouds.core.component.OudsLoader import com.orange.ouds.core.component.OudsTextInput import com.orange.ouds.core.component.OudsTextInputHelperLink -import com.orange.ouds.core.component.OudsTextInputLeadingIcon -import com.orange.ouds.core.component.OudsTextInputLoader -import com.orange.ouds.core.component.OudsTextInputTrailingIconButton import com.orange.ouds.core.component.common.OudsError import com.orange.ouds.core.component.common.text.buildOudsAnnotatedErrorMessage import com.orange.ouds.core.component.common.text.buildOudsAnnotatedHelperText @@ -175,25 +175,21 @@ private fun TextInputDemoContent(state: TextInputDemoState) { with(state) { val textInputLeadingIcon = when (leadingIcon) { TextInputDemoState.LeadingIcon.None -> null - TextInputDemoState.LeadingIcon.Tinted -> OudsTextInputLeadingIcon( - painter = painterResource(id = LocalThemeDrawableResources.current.tipsAndTricks), - contentDescription = "" - ) - TextInputDemoState.LeadingIcon.Untinted -> OudsTextInputLeadingIcon( + TextInputDemoState.LeadingIcon.Tinted -> OudsIcon(painter = painterResource(id = LocalThemeDrawableResources.current.tipsAndTricks)) + TextInputDemoState.LeadingIcon.Untinted -> OudsIcon( painter = rememberUntintedIconPainter(), - contentDescription = "", tinted = false ) } val textInputTrailingIcon = when (trailingIcon) { TextInputDemoState.TrailingIcon.None -> null - TextInputDemoState.TrailingIcon.Tinted -> OudsTextInputTrailingIconButton( + TextInputDemoState.TrailingIcon.Tinted -> OudsIconButton( painter = painterResource(id = LocalThemeDrawableResources.current.tipsAndTricks), contentDescription = stringResource(id = R.string.app_components_textInput_trailingAction_a11y), onClick = {} ) } - val loader = if (hasLoader) OudsTextInputLoader(null) else null + val loader = if (hasLoader) OudsLoader(null) else null val textInputError = when { error && annotatedText -> { val errorHtml = stringResource(R.string.app_components_textInput_annotatedErrorMessage_text) @@ -260,14 +256,14 @@ private fun Code.Builder.textInputDemoCodeSnippet(state: TextInputDemoState, the if (placeholder.isNotEmpty()) typedArgument("placeholder", placeholder) typedArgument("outlined", outlined) if (leadingIcon != TextInputDemoState.LeadingIcon.None) { - iconArgument( + iconArgument( "leadingIcon", themeDrawableResources.tipsAndTricks, tinted = leadingIcon == TextInputDemoState.LeadingIcon.Tinted ) } if (trailingIcon != TextInputDemoState.TrailingIcon.None) { - constructorCallArgument("trailingIconButton") { + constructorCallArgument("trailingIconButton") { painterArgument(themeDrawableResources.tipsAndTricks) contentDescriptionArgument(R.string.app_components_textInput_trailingAction_a11y) onClickArgument { @@ -276,7 +272,7 @@ private fun Code.Builder.textInputDemoCodeSnippet(state: TextInputDemoState, the } } if (hasLoader) { - constructorCallArgument("loader") { + constructorCallArgument("loader") { typedArgument("progress", null) } } diff --git a/app/src/main/java/com/orange/ouds/app/ui/utilities/Code.kt b/app/src/main/java/com/orange/ouds/app/ui/utilities/Code.kt index e933a68be6..592641127c 100644 --- a/app/src/main/java/com/orange/ouds/app/ui/utilities/Code.kt +++ b/app/src/main/java/com/orange/ouds/app/ui/utilities/Code.kt @@ -25,7 +25,7 @@ import androidx.compose.ui.unit.Dp import com.orange.ouds.app.R import com.orange.ouds.app.ui.BottomBarItem import com.orange.ouds.app.ui.utilities.composable.AppPreview -import com.orange.ouds.core.component.OudsButtonIcon +import com.orange.ouds.core.component.OudsIcon import com.orange.ouds.core.theme.OudsTheme import com.orange.ouds.foundation.extensions.asOrNull import com.orange.ouds.foundation.extensions.tryOrNull @@ -324,7 +324,7 @@ internal fun PreviewCode() = AppPreview { newline() functionCall("OudsComponent") { trailingLambda = true - constructorCallArgument("icon") { + constructorCallArgument("icon") { functionCallArgument("painter", "painterResource") { typedArgument("id", themeDrawableResources.tipsAndTricks) } diff --git a/app/src/main/java/com/orange/ouds/app/ui/utilities/composable/CustomizationElements.kt b/app/src/main/java/com/orange/ouds/app/ui/utilities/composable/CustomizationElements.kt index d55924f70a..e3c19758d2 100644 --- a/app/src/main/java/com/orange/ouds/app/ui/utilities/composable/CustomizationElements.kt +++ b/app/src/main/java/com/orange/ouds/app/ui/utilities/composable/CustomizationElements.kt @@ -50,9 +50,9 @@ import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.dp import com.orange.ouds.app.R import com.orange.ouds.core.component.OudsFilterChip +import com.orange.ouds.core.component.OudsIconButton import com.orange.ouds.core.component.OudsSwitchItem import com.orange.ouds.core.component.OudsTextInput -import com.orange.ouds.core.component.OudsTextInputTrailingIconButton import com.orange.ouds.core.theme.OudsTheme private val labelTextStyle: TextStyle @@ -212,7 +212,7 @@ fun CustomizationTextInput( enabled = enabled, keyboardOptions = keyboardOptions, trailingIconButton = if (value.text.isNotEmpty()) { - OudsTextInputTrailingIconButton( + OudsIconButton( painter = painterResource(com.orange.ouds.theme.orange.R.drawable.ic_orange_component_tag_close), contentDescription = stringResource(R.string.app_components_common_textInputClearIcon_a11y), onClick = { diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index a0b764c122..643f1377f5 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -234,7 +234,7 @@ Button Default Navigation button - Chevron + Indicator Checkbox diff --git a/core/src/main/java/com/orange/ouds/core/component/OudsAlert.kt b/core/src/main/java/com/orange/ouds/core/component/OudsAlert.kt index fe5d13339f..4b0666bc3a 100644 --- a/core/src/main/java/com/orange/ouds/core/component/OudsAlert.kt +++ b/core/src/main/java/com/orange/ouds/core/component/OudsAlert.kt @@ -94,6 +94,13 @@ internal sealed class OudsAlertStatus( @Composable get() = defaultIconContentDescriptionProvider(this) + val defaultIcon: OudsIcon + get() = OudsIcon( + { defaultIconPainter.orElse { error("No default icon for status ${this::class.simpleName}") } }, + { defaultIconContentDescription }, + true + ) + /** * The asset color associated with this status. */ @@ -117,12 +124,13 @@ internal sealed class OudsAlertStatus( * This class handles the creation of the icon from different sources like [Painter], [ImageVector], or [ImageBitmap]. * An accessibility description is not required, as the alert's main `label` should provide the necessary context. */ +@Deprecated("") +@Suppress("DEPRECATION") open class OudsAlertIcon private constructor( graphicsObjectProvider: @Composable (OudsAlertIcon) -> Any, contentDescriptionProvider: @Composable (OudsAlertIcon) -> String, override val tinted: Boolean ) : OudsComponentIcon( - ExtraParameters::class.java, graphicsObjectProvider, contentDescriptionProvider ) { @@ -181,6 +189,7 @@ open class OudsAlertIcon private constructor( @Composable get() = extraParameters.tint + @Deprecated("") @ConsistentCopyVisibility data class ExtraParameters internal constructor( internal val tint: Color, diff --git a/core/src/main/java/com/orange/ouds/core/component/OudsAlertMessage.kt b/core/src/main/java/com/orange/ouds/core/component/OudsAlertMessage.kt index da18f22aef..0777c7e3f1 100644 --- a/core/src/main/java/com/orange/ouds/core/component/OudsAlertMessage.kt +++ b/core/src/main/java/com/orange/ouds/core/component/OudsAlertMessage.kt @@ -238,10 +238,7 @@ private fun OudsAlertMessage( modifier = Modifier .padding(top = spacePaddingBlock.value) .iconSize(sizeIcon.value * scale, status.icon.tinted), - extraParameters = OudsAlertIcon.ExtraParameters( - tint = status.assetColor, - status = status.value - ) + extraParameters = OudsIcon.ExtraParameters(tint = status.assetColor) ) Column( modifier = Modifier @@ -287,7 +284,7 @@ private fun OudsAlertMessage( } onClose?.let { OudsButton( - icon = OudsButtonIcon( + icon = OudsIcon( painter = painterResource(LocalDrawableResources.current.component.button.expurge), contentDescription = stringResource(R.string.core_alertMessage_close_a11y) ), @@ -327,7 +324,7 @@ data class OudsAlertMessageActionLink( val label: String, val onClick: () -> Unit, val position: OudsAlertMessageActionLinkPosition = OudsAlertMessageDefaults.ActionLinkPosition -) : OudsComponentContent(Nothing::class.java) { +) : OudsComponentContent() { @Composable override fun Content(modifier: Modifier) { @@ -366,7 +363,9 @@ enum class OudsAlertMessageActionLinkPosition { * @property value The [OudsAlertStatus] associated with this status. * @property icon The [OudsAlertIcon] to be displayed in the alert message, or `null` if there is no icon. */ -sealed class OudsAlertMessageStatus(internal val value: OudsAlertStatus, val icon: OudsAlertIcon? = null) { +sealed class OudsAlertMessageStatus(internal val value: OudsAlertStatus, val icon: OudsIcon?) { + + private constructor(value: OudsAlertStatus, icon: OudsIcon.Default) : this(value, value.defaultIcon) /** * Neutral status can be used as a generic informative alert without semantic meaning or colour association. @@ -375,7 +374,14 @@ sealed class OudsAlertMessageStatus(internal val value: OudsAlertStatus, val ico * * @property icon The optional [OudsAlertIcon] to be displayed at the start of the alert message. */ - class Neutral(icon: OudsAlertIcon? = null) : OudsAlertMessageStatus(OudsAlertStatus.Neutral(), icon) + class Neutral(icon: OudsIcon? = null) : OudsAlertMessageStatus(OudsAlertStatus.Neutral(), icon) { + + @Suppress("DEPRECATION") + @Deprecated("") + constructor(icon: OudsAlertIcon) : this(icon = icon.toIcon()) + + constructor(icon: OudsIcon.Default) : this(icon = OudsAlertStatus.Neutral().defaultIcon) + } /** * Accent status uses brand colours to draw attention to promotional or highlighted information while remaining non-critical. @@ -384,35 +390,42 @@ sealed class OudsAlertMessageStatus(internal val value: OudsAlertStatus, val ico * * @property icon The optional [OudsAlertIcon] to be displayed at the start of the alert message. */ - class Accent(icon: OudsAlertIcon? = null) : OudsAlertMessageStatus(OudsAlertStatus.Accent(), icon) + class Accent(icon: OudsIcon? = null) : OudsAlertMessageStatus(OudsAlertStatus.Accent(), icon) { + + @Suppress("DEPRECATION") + @Deprecated("") + constructor(icon: OudsAlertIcon) : this(icon = icon.toIcon()) + + constructor(icon: OudsIcon.Default) : this(icon = OudsAlertStatus.Accent().defaultIcon) + } /** * Negative status communicates a critical issue or error that prevents the user from proceeding until it is resolved. * These alerts remain visible until the problem is fixed or dismissed by the user. * This status displays a dedicated default icon. */ - data object Negative : OudsAlertMessageStatus(OudsAlertStatus.Negative(), OudsAlertIcon.Default) + data object Negative : OudsAlertMessageStatus(OudsAlertStatus.Negative(), OudsIcon.Default) /** * Positive status indicates that a task or process has been completed successfully. * These alerts reassure users and confirm that no further action is needed. * This status displays a dedicated default icon. */ - data object Positive : OudsAlertMessageStatus(OudsAlertStatus.Positive(), OudsAlertIcon.Default) + data object Positive : OudsAlertMessageStatus(OudsAlertStatus.Positive(), OudsIcon.Default) /** * Info status is used to share neutral system information or service updates that do not require immediate action. * Ideal for background processes or status messages where users simply need to stay informed. * This status displays a dedicated default icon. */ - data object Info : OudsAlertMessageStatus(OudsAlertStatus.Info(), OudsAlertIcon.Default) + data object Info : OudsAlertMessageStatus(OudsAlertStatus.Info(), OudsIcon.Default) /** * Used to draw attention to potential issues or upcoming changes that might affect the user’s service or experience. * Warnings encourage awareness but typically do not block actions. * This status displays a dedicated default icon. */ - data object Warning : OudsAlertMessageStatus(OudsAlertStatus.Warning(), OudsAlertIcon.Default) + data object Warning : OudsAlertMessageStatus(OudsAlertStatus.Warning(), OudsIcon.Default) internal val assetColor @Composable @@ -531,7 +544,7 @@ internal fun PreviewOudsAlertMessage( ).map { it.simpleName.orEmpty() }, maxItemsInEachRow = 1 ) { item -> - val icon = if (hasIcon) OudsAlertIcon(Icons.Outlined.FavoriteBorder) else null + val icon = if (hasIcon) OudsIcon(Icons.Outlined.FavoriteBorder) else null val status = when (item) { OudsAlertMessageStatus.Neutral::class.simpleName -> OudsAlertMessageStatus.Neutral(icon) OudsAlertMessageStatus.Accent::class.simpleName -> OudsAlertMessageStatus.Accent(icon) @@ -604,7 +617,7 @@ internal fun PreviewOudsAlertMessageWithUntintedIcon(theme: OudsThemeContract) = ).map { it.simpleName.orEmpty() }, maxItemsInEachRow = 1 ) { item -> - val icon = OudsAlertIcon(rememberRainbowHeartPainter(), tinted = false) + val icon = OudsIcon(rememberRainbowHeartPainter(), "", tinted = false) val status = when (item) { OudsAlertMessageStatus.Neutral::class.simpleName -> OudsAlertMessageStatus.Neutral(icon) OudsAlertMessageStatus.Accent::class.simpleName -> OudsAlertMessageStatus.Accent(icon) diff --git a/core/src/main/java/com/orange/ouds/core/component/OudsAvatar.kt b/core/src/main/java/com/orange/ouds/core/component/OudsAvatar.kt index 54965a18d5..44ed07a7bb 100644 --- a/core/src/main/java/com/orange/ouds/core/component/OudsAvatar.kt +++ b/core/src/main/java/com/orange/ouds/core/component/OudsAvatar.kt @@ -150,7 +150,7 @@ internal fun OudsAvatar( ) { OudsButton( modifier = Modifier.alpha(if (onClick != null) 1f else 0f), // If onClick is null, draw the button with alpha 0 anyway to get a consistent size for the avatar - icon = OudsButtonIcon(ColorPainter(Color.Transparent), ""), // Use transparent painter to scale the button with the font + icon = OudsIcon(ColorPainter(Color.Transparent), ""), // Use transparent painter to scale the button with the font onClick = { onClick?.invoke() }, appearance = OudsButtonAppearance.Minimal, interactionSource = interactionSource diff --git a/core/src/main/java/com/orange/ouds/core/component/OudsBadge.kt b/core/src/main/java/com/orange/ouds/core/component/OudsBadge.kt index 28dfe2c570..ad87b3df6a 100644 --- a/core/src/main/java/com/orange/ouds/core/component/OudsBadge.kt +++ b/core/src/main/java/com/orange/ouds/core/component/OudsBadge.kt @@ -273,9 +273,9 @@ private fun OudsBadge( } withIconStatus?.icon?.Content( modifier = Modifier.fillMaxSize(), - extraParameters = OudsBadgeIcon.ExtraParameters( + extraParameters = OudsIcon.ExtraParameters( enabled = enabled, - status = withIconStatus + tint = iconColor(status = withIconStatus.toBadgeStatus(), enabled = enabled) ) ) } @@ -396,11 +396,14 @@ const val OudsBadgeMaxCount = 99 * An icon in an [OudsBadge]. * This icon is not clickable. */ +@Suppress("DEPRECATION") +@Deprecated("") open class OudsBadgeIcon internal constructor( graphicsObjectProvider: @Composable (OudsBadgeIcon) -> Any, override val tinted: Boolean -) : OudsComponentIcon(ExtraParameters::class.java, graphicsObjectProvider, { "" }) { +) : OudsComponentIcon(graphicsObjectProvider, { "" }) { + @Deprecated("") @ConsistentCopyVisibility data class ExtraParameters internal constructor( internal val enabled: Boolean, @@ -449,7 +452,7 @@ open class OudsBadgeIcon internal constructor( override val tint: Color? @Composable - get() = if (tinted) iconColor(status = extraParameters.status.toBadgeStatus(), enabled = extraParameters.enabled) else null + get() = iconColor(status = extraParameters.status.toBadgeStatus(), enabled = extraParameters.enabled) } @@ -516,7 +519,7 @@ enum class OudsBadgeStatus { * For a badge without icon, please use [OudsBadgeStatus]. * A content description should be specified at [OudsBadge] level through semantics Modifier. */ -sealed class OudsIconBadgeStatus(val icon: OudsBadgeIcon) { +sealed class OudsIconBadgeStatus(val icon: OudsIcon) { /** * Used for general labels without specific emphasis. @@ -524,7 +527,12 @@ sealed class OudsIconBadgeStatus(val icon: OudsBadgeIcon) { * * @constructor Creates an instance of [OudsIconBadgeStatus.Neutral] with a custom icon. */ - class Neutral(icon: OudsBadgeIcon) : OudsIconBadgeStatus(icon) + class Neutral(icon: OudsIcon) : OudsIconBadgeStatus(icon) { + + @Deprecated("") + @Suppress("DEPRECATION") + constructor(icon: OudsBadgeIcon) : this(icon.toIcon()) + } /** * Employed to highlight discovery or exploration-related content. @@ -532,7 +540,12 @@ sealed class OudsIconBadgeStatus(val icon: OudsBadgeIcon) { * * @constructor Creates an instance of [OudsIconBadgeStatus.Accent] with a custom icon. */ - class Accent(icon: OudsBadgeIcon) : OudsIconBadgeStatus(icon) + class Accent(icon: OudsIcon) : OudsIconBadgeStatus(icon) { + + @Deprecated("") + @Suppress("DEPRECATION") + constructor(icon: OudsBadgeIcon) : this(icon.toIcon()) + } /** * Indicates success, completion, or approval. @@ -540,7 +553,13 @@ sealed class OudsIconBadgeStatus(val icon: OudsBadgeIcon) { * * @constructor Creates an instance of [OudsIconBadgeStatus.Positive] with its default dedicated icon. */ - data object Positive : OudsIconBadgeStatus(OudsBadgeIcon({ painterResource(OudsTheme.drawableResources.component.badgeIcon.tickConfirmationFill) }, true)) + data object Positive : OudsIconBadgeStatus( + OudsIcon( + { painterResource(OudsTheme.drawableResources.component.badgeIcon.tickConfirmationFill) }, + { "" }, + true + ) + ) /** * Provides informational context without urgency. @@ -548,7 +567,13 @@ sealed class OudsIconBadgeStatus(val icon: OudsBadgeIcon) { * * @constructor Creates an instance of [OudsIconBadgeStatus.Info] with its default dedicated icon. */ - data object Info : OudsIconBadgeStatus(OudsBadgeIcon({ painterResource(OudsTheme.drawableResources.component.badgeIcon.infoFill) }, true)) + data object Info : OudsIconBadgeStatus( + OudsIcon( + { painterResource(OudsTheme.drawableResources.component.badgeIcon.infoFill) }, + { "" }, + true + ) + ) /** * Negatives the user to potential risks or cautionary messages. @@ -557,9 +582,9 @@ sealed class OudsIconBadgeStatus(val icon: OudsBadgeIcon) { * @constructor Creates an instance of [OudsIconBadgeStatus.Warning] with its default dedicated icon. */ data object Warning : OudsIconBadgeStatus( - OudsBadgeIcon( + OudsIcon( { icon -> - if (icon.enabled == true) { + if (icon.extraParameters.enabled) { val iconTokens = OudsTheme.componentsTokens.icon LayeredTintedPainter( backPainter = painterResource(id = OudsTheme.drawableResources.component.badgeIcon.warningExternalShape), @@ -571,6 +596,7 @@ sealed class OudsIconBadgeStatus(val icon: OudsBadgeIcon) { painterResource(OudsTheme.drawableResources.component.badgeIcon.warningExternalShape) } }, + { "" }, true ) ) @@ -582,7 +608,13 @@ sealed class OudsIconBadgeStatus(val icon: OudsBadgeIcon) { * * @constructor Creates an instance of [OudsIconBadgeStatus.Negative] with its default dedicated icon. */ - data object Negative : OudsIconBadgeStatus(OudsBadgeIcon({ painterResource(OudsTheme.drawableResources.component.badgeIcon.errorFill) }, true)) + data object Negative : OudsIconBadgeStatus( + OudsIcon( + { painterResource(OudsTheme.drawableResources.component.badgeIcon.errorFill) }, + { "" }, + true + ) + ) /** * The color associated with this status. @@ -685,8 +717,8 @@ internal fun PreviewOudsBadgeWithIcon(theme: OudsThemeContract, darkThemeEnabled ).map { it.simpleName.orEmpty() }, ) { column, row -> val status = when (row) { - OudsIconBadgeStatus.Neutral::class.simpleName -> OudsIconBadgeStatus.Neutral(OudsBadgeIcon(Icons.Filled.FavoriteBorder)) - OudsIconBadgeStatus.Accent::class.simpleName -> OudsIconBadgeStatus.Accent(OudsBadgeIcon(Icons.Filled.FavoriteBorder)) + OudsIconBadgeStatus.Neutral::class.simpleName -> OudsIconBadgeStatus.Neutral(OudsIcon(Icons.Filled.FavoriteBorder)) + OudsIconBadgeStatus.Accent::class.simpleName -> OudsIconBadgeStatus.Accent(OudsIcon(Icons.Filled.FavoriteBorder)) OudsIconBadgeStatus.Positive::class.simpleName -> OudsIconBadgeStatus.Positive OudsIconBadgeStatus.Warning::class.simpleName -> OudsIconBadgeStatus.Warning OudsIconBadgeStatus.Negative::class.simpleName -> OudsIconBadgeStatus.Negative @@ -732,8 +764,8 @@ internal fun PreviewOudsBadgeWithUntintedIcon(theme: OudsThemeContract) = OudsPr ).map { it.simpleName.orEmpty() }, ) { column, row -> val status = when (row) { - OudsIconBadgeStatus.Neutral::class.simpleName -> OudsIconBadgeStatus.Neutral(OudsBadgeIcon(rememberRainbowHeartPainter(), tinted = false)) - OudsIconBadgeStatus.Accent::class.simpleName -> OudsIconBadgeStatus.Accent(OudsBadgeIcon(rememberRainbowHeartPainter(), tinted = false)) + OudsIconBadgeStatus.Neutral::class.simpleName -> OudsIconBadgeStatus.Neutral(OudsIcon(rememberRainbowHeartPainter(), "", tinted = false)) + OudsIconBadgeStatus.Accent::class.simpleName -> OudsIconBadgeStatus.Accent(OudsIcon(rememberRainbowHeartPainter(), "", tinted = false)) else -> error("Unknown row $row.") } val size = enumValueOf(column) diff --git a/core/src/main/java/com/orange/ouds/core/component/OudsBadgedIcon.kt b/core/src/main/java/com/orange/ouds/core/component/OudsBadgedIcon.kt index 409c72b69a..e40e0554a5 100644 --- a/core/src/main/java/com/orange/ouds/core/component/OudsBadgedIcon.kt +++ b/core/src/main/java/com/orange/ouds/core/component/OudsBadgedIcon.kt @@ -154,7 +154,7 @@ internal fun PreviewOudsBadgedIcon( Icon( modifier = Modifier.size(size), imageVector = Icons.Filled.FavoriteBorder, - contentDescription = "", + contentDescription = null, tint = OudsTheme.colorScheme.content.default ) } diff --git a/core/src/main/java/com/orange/ouds/core/component/OudsBasicChip.kt b/core/src/main/java/com/orange/ouds/core/component/OudsBasicChip.kt index 133cfc2b53..103cce0fd7 100644 --- a/core/src/main/java/com/orange/ouds/core/component/OudsBasicChip.kt +++ b/core/src/main/java/com/orange/ouds/core/component/OudsBasicChip.kt @@ -55,7 +55,7 @@ internal fun OudsBasicChip( selected: Boolean, onClick: () -> Unit, label: String?, - icon: OudsChipIcon?, + icon: OudsIcon?, iconPosition: OudsChipIconPosition, modifier: Modifier = Modifier, enabled: Boolean = true, @@ -160,14 +160,17 @@ internal fun OudsBasicChip( } } val iconContent: @Composable (Modifier) -> Unit = { modifier -> - icon?.Content( - modifier = modifier - .iconSize(chipTokens.sizeIcon.value * iconScale, tinted = icon.tinted) - .semantics { - contentDescription = if (label == null) icon.contentDescription else "" - }, - extraParameters = OudsChipIcon.ExtraParameters(tint = contentColor.value) - ) + if (icon != null) { + val iconContentDescription = icon.contentDescription.orEmpty() + icon.Content( + modifier = modifier + .iconSize(chipTokens.sizeIcon.value * iconScale, tinted = icon.tinted) + .semantics { + contentDescription = if (label == null) iconContentDescription else "" + }, + extraParameters = OudsIcon.ExtraParameters(tint = contentColor.value) + ) + } } val scope = remember { OudsChipScope() } @@ -270,7 +273,7 @@ private fun tickColor(state: OudsChipState, selected: Boolean): Color? { } @Composable -private fun contentPadding(label: String?, icon: OudsChipIcon?, iconPosition: OudsChipIconPosition, selected: Boolean): PaddingValues { +private fun contentPadding(label: String?, icon: OudsIcon?, iconPosition: OudsChipIconPosition, selected: Boolean): PaddingValues { return with(OudsTheme.componentsTokens.chip) { // If chip layout starts with an icon or the tick then we use spacePaddingInlineIcon as the start padding, otherwise spacePaddingInlineIconNone val start = if (selected diff --git a/core/src/main/java/com/orange/ouds/core/component/OudsBulletList.kt b/core/src/main/java/com/orange/ouds/core/component/OudsBulletList.kt index 533e51f43f..6947c0543e 100644 --- a/core/src/main/java/com/orange/ouds/core/component/OudsBulletList.kt +++ b/core/src/main/java/com/orange/ouds/core/component/OudsBulletList.kt @@ -450,7 +450,7 @@ sealed interface OudsBulletListUnorderedAsset : OudsPolymorphicComponentContent * This allows for complete visual customization of the bullet, for instance by using a Solaris icon. */ class Icon private constructor(graphicsObject: Any) : OudsBulletListUnorderedAsset, - OudsComponentIcon(OudsBulletListUnorderedAsset.ExtraParameters::class.java, graphicsObject, "") { + OudsComponentIcon(graphicsObject, "") { /** * Creates an instance of [OudsBulletListUnorderedAsset.Icon]. @@ -488,7 +488,6 @@ sealed interface OudsBulletListUnorderedAsset : OudsPolymorphicComponentContent */ data object Bullet : OudsBulletListUnorderedAsset, OudsComponentIcon( - OudsBulletListUnorderedAsset.ExtraParameters::class.java, { with(extraParameters) { val parentOrderedTypeCount = parentTypes.count { it is OudsBulletListType.Ordered } @@ -513,7 +512,6 @@ sealed interface OudsBulletListUnorderedAsset : OudsPolymorphicComponentContent * A bullet represented by a tick (check) icon. */ data object Tick : OudsBulletListUnorderedAsset, OudsComponentIcon( - OudsBulletListUnorderedAsset.ExtraParameters::class.java, { painterResource(OudsTheme.drawableResources.component.bulletList.tick) }, { "" } ) { diff --git a/core/src/main/java/com/orange/ouds/core/component/OudsButton.kt b/core/src/main/java/com/orange/ouds/core/component/OudsButton.kt index 2144b99a57..0f1465c049 100644 --- a/core/src/main/java/com/orange/ouds/core/component/OudsButton.kt +++ b/core/src/main/java/com/orange/ouds/core/component/OudsButton.kt @@ -129,7 +129,7 @@ fun OudsButton( onClick: () -> Unit, modifier: Modifier = Modifier, enabled: Boolean = true, - loader: OudsButtonLoader? = null, + loader: OudsLoader? = null, appearance: OudsButtonAppearance = OudsButtonDefaults.Appearance, interactionSource: MutableInteractionSource? = null ) { @@ -145,6 +145,66 @@ fun OudsButton( ) } +/** + * Button is a UI element that triggers an action or event, and is used to initiate tasks or confirming an action. + * Button appears in different layouts, styles and states to indicate hierarchy or emphasis. + * + * This version of the button uses the *text only* layout, which is the most common layout. + * Other layouts are available for this component: *text + icon* and *icon only*. + * + * This is the default size of the component. This size is used for the vast majority of applications. + * A small size is also available via [OudsSmallButton]. + * + * Note that if it is placed in an [OudsColoredBox], its monochrome variant is automatically displayed. + * The tokens associated with these specific colors can be customized by overriding [OudsButtonMonoTokens]. + * + * Rounded corners can be enabled or disabled using the [OudsThemeSettings.roundedCornerButtons] property in the settings of the theme provided + * when calling the [com.orange.ouds.core.theme.OudsTheme] method. + * + * > Design guidelines: [unified-design-system.orange.com](https://r.orange.fr/r/S-ouds-doc-button) + * + * > Design name: Button + * + * > Design version: 3.3.0 + * + * @param label Label displayed in the button describing the button action. Use action verbs or phrases to tell the user what will happen next. + * @param onClick Callback invoked when the button is clicked. + * @param modifier [Modifier] applied to the button. + * @param enabled Controls the enabled state of the button when there is no [loader]. + * When `false`, this button will not be clickable. + * Has no effect if [loader] is provided. + * @param loader An optional loading progress indicator displayed in the button to indicate an ongoing operation. + * @param appearance Appearance of the button among [OudsButtonAppearance] values. + * A button with [OudsButtonAppearance.Negative] is not allowed as a direct or indirect child of an [OudsColoredBox] and will throw an [IllegalStateException]. + * @param interactionSource An optional hoisted [MutableInteractionSource] for observing and emitting [Interaction]s for this button. Note that if `null` + * is provided, interactions will still happen internally. + * + * @sample com.orange.ouds.core.component.samples.OudsButtonTextOnlySample + * + * @sample com.orange.ouds.core.component.samples.OudsButtonTextOnlyOnColoredBackgroundSample + */ +@Deprecated("") +@Composable +fun OudsButton( + label: String, + onClick: () -> Unit, + modifier: Modifier = Modifier, + enabled: Boolean = true, + @Suppress("DEPRECATION") loader: OudsButtonLoader?, + appearance: OudsButtonAppearance = OudsButtonDefaults.Appearance, + interactionSource: MutableInteractionSource? = null +) { + OudsButton( + label = label, + onClick = onClick, + modifier = modifier, + enabled = enabled, + loader = loader?.toLoader(), + appearance = appearance, + interactionSource = interactionSource + ) +} + /** * Button is a UI element that triggers an action or event, and is used to initiate tasks or confirming an action. * Button appears in different layouts, styles and states to indicate hierarchy or emphasis. @@ -187,11 +247,11 @@ fun OudsButton( */ @Composable fun OudsButton( - icon: OudsButtonIcon, + icon: OudsIcon, onClick: () -> Unit, modifier: Modifier = Modifier, enabled: Boolean = true, - loader: OudsButtonLoader? = null, + loader: OudsLoader? = null, appearance: OudsButtonAppearance = OudsButtonDefaults.Appearance, interactionSource: MutableInteractionSource? = null ) { @@ -207,6 +267,68 @@ fun OudsButton( ) } +/** + * Button is a UI element that triggers an action or event, and is used to initiate tasks or confirming an action. + * Button appears in different layouts, styles and states to indicate hierarchy or emphasis. + * + * This version of the button uses the *icon only* layout, which is typically used in business or back-office interfaces. It is rarely used alone (usually part of a group of elements). + * Other layouts are available for this component: *text only* and *text + icon*. + * + * This is the default size of the component. This size is used for the vast majority of applications. + * A small size is also available via [OudsSmallButton]. + * + * Note that if it is placed in an [OudsColoredBox], its monochrome variant is automatically displayed. + * The tokens associated with these specific colors can be customized by overriding [OudsButtonMonoTokens]. + * + * Rounded corners can be enabled or disabled using the [OudsThemeSettings.roundedCornerButtons] property in the settings of the theme provided + * when calling the [com.orange.ouds.core.theme.OudsTheme] method. + * + * > Design guidelines: [unified-design-system.orange.com](https://r.orange.fr/r/S-ouds-doc-button) + * + * > Design name: Button + * + * > Design version: 3.3.0 + * + * @param icon Icon displayed in the button. Use an icon to add additional affordance where the icon has a clear and well-established meaning. + * @param onClick Callback invoked when the button is clicked. + * @param modifier [Modifier] applied to the button. + * @param enabled Controls the enabled state of the button when there is no [loader]. + * When `false`, this button will not be clickable. + * Has no effect if [loader] is provided. + * @param loader An optional loading progress indicator displayed in the button to indicate an ongoing operation. + * @param appearance Appearance of the button among [OudsButtonAppearance] values. + * A button with [OudsButtonAppearance.Negative] is not allowed as a direct or indirect child of an [OudsColoredBox] and will throw an [IllegalStateException]. + * @param interactionSource An optional hoisted [MutableInteractionSource] for observing and emitting [Interaction]s for this button. Note that if `null` + * is provided, interactions will still happen internally. + * + * @sample com.orange.ouds.core.component.samples.OudsButtonIconOnlySample + * + * @sample com.orange.ouds.core.component.samples.OudsButtonIconOnlyOnColoredBackgroundSample + * + * @sample com.orange.ouds.core.component.samples.OudsButtonIconOnlyWithUntintedIconSample + */ +@Deprecated("") +@Composable +fun OudsButton( + @Suppress("DEPRECATION") icon: OudsButtonIcon, + onClick: () -> Unit, + modifier: Modifier = Modifier, + enabled: Boolean = true, + @Suppress("DEPRECATION") loader: OudsButtonLoader? = null, + appearance: OudsButtonAppearance = OudsButtonDefaults.Appearance, + interactionSource: MutableInteractionSource? = null +) { + OudsButton( + icon = icon.toIcon(), + onClick = onClick, + modifier = modifier, + enabled = enabled, + loader = loader?.toLoader(), + appearance = appearance, + interactionSource = interactionSource + ) +} + /** * Button is a UI element that triggers an action or event, and is used to initiate tasks or confirming an action. * Button appears in different layouts, styles and states to indicate hierarchy or emphasis. @@ -251,12 +373,12 @@ fun OudsButton( */ @Composable fun OudsButton( - icon: OudsButtonIcon, + icon: OudsIcon, label: String, onClick: () -> Unit, modifier: Modifier = Modifier, enabled: Boolean = true, - loader: OudsButtonLoader? = null, + loader: OudsLoader? = null, appearance: OudsButtonAppearance = OudsButtonDefaults.Appearance, interactionSource: MutableInteractionSource? = null ) { @@ -272,16 +394,82 @@ fun OudsButton( ) } +/** + * Button is a UI element that triggers an action or event, and is used to initiate tasks or confirming an action. + * Button appears in different layouts, styles and states to indicate hierarchy or emphasis. + * + * This version of the button uses the *text + icon* layout, which should remain specific to clearly identified contexts (e.g., the use of an icon with a + * "Play" button is standard in the context of TV or video streaming). + * Other layouts are available for this component: *text only* and *icon only*. + * + * This is the default size of the component. This size is used for the vast majority of applications. + * A small size is also available via [OudsSmallButton]. + * + * Note that if it is placed in an [OudsColoredBox], its monochrome variant is automatically displayed. + * The tokens associated with these specific colors can be customized by overriding [OudsButtonMonoTokens]. + * + * Rounded corners can be enabled or disabled using the [OudsThemeSettings.roundedCornerButtons] property in the settings of the theme provided + * when calling the [com.orange.ouds.core.theme.OudsTheme] method. + * + * > Design guidelines: [unified-design-system.orange.com](https://r.orange.fr/r/S-ouds-doc-button) + * + * > Design name: Button + * + * > Design version: 3.3.0 + * + * @param icon Icon displayed in the button. Use an icon to add additional affordance where the icon has a clear and well-established meaning. + * @param label Label displayed in the button describing the button action. Use action verbs or phrases to tell the user what will happen next. + * @param onClick Callback invoked when the button is clicked. + * @param modifier [Modifier] applied to the button. + * @param enabled Controls the enabled state of the button when there is no [loader]. + * When `false`, this button will not be clickable. + * Has no effect if [loader] is provided. + * @param loader An optional loading progress indicator displayed in the button to indicate an ongoing operation. + * @param appearance Appearance of the button among [OudsButtonAppearance] values. + * A button with [OudsButtonAppearance.Negative] is not allowed as a direct or indirect child of an [OudsColoredBox] and will throw an [IllegalStateException]. + * @param interactionSource An optional hoisted [MutableInteractionSource] for observing and emitting [Interaction]s for this button. Note that if `null` + * is provided, interactions will still happen internally. + * + * @sample com.orange.ouds.core.component.samples.OudsButtonTextAndIconSample + * + * @sample com.orange.ouds.core.component.samples.OudsButtonTextAndIconOnColoredBackgroundSample + * + * @sample com.orange.ouds.core.component.samples.OudsButtonTextAndIconWithUntintedIconSample + */ +@Deprecated("") +@Composable +fun OudsButton( + @Suppress("DEPRECATION") icon: OudsButtonIcon, + label: String, + onClick: () -> Unit, + modifier: Modifier = Modifier, + enabled: Boolean = true, + @Suppress("DEPRECATION") loader: OudsButtonLoader? = null, + appearance: OudsButtonAppearance = OudsButtonDefaults.Appearance, + interactionSource: MutableInteractionSource? = null +) { + OudsButton( + icon = icon.toIcon(), + label = label, + onClick = onClick, + modifier = modifier, + enabled = enabled, + loader = loader?.toLoader(), + appearance = appearance, + interactionSource = interactionSource + ) +} + @Composable @JvmName("OudsButtonNullableIconAndLabel") internal fun OudsButton( - nullableIcon: OudsButtonIcon?, + nullableIcon: OudsIcon?, nullableLabel: String?, onClick: () -> Unit, modifier: Modifier = Modifier, component: OudsButtonComponent = OudsButtonComponent.Button, enabled: Boolean = true, - loader: OudsButtonLoader? = null, + loader: OudsLoader? = null, appearance: OudsButtonAppearance = OudsButtonDefaults.Appearance, iconOnlyBadge: OudsButtonIconBadge? = null, size: OudsButtonSize = OudsButtonSize.Default, @@ -387,7 +575,7 @@ internal fun OudsButton( verticalAlignment = Alignment.CenterVertically ) { val leadingText = when (component) { - is OudsButtonComponent.NavigationButton if component.chevron == OudsNavigationButtonChevron.Next -> true + is OudsButtonComponent.NavigationButton if component.indicator == OudsNavigationButtonIndicator.Next -> true OudsButtonComponent.Button, is OudsButtonComponent.NavigationButton -> false } @@ -404,6 +592,8 @@ internal fun OudsButton( default = if (label == null) buttonTokens.sizeIconOnlyDefault else buttonTokens.sizeIconDefault, small = if (label == null) buttonTokens.sizeIconOnlySmall else buttonTokens.sizeIconSmall ) + + val iconContentDescription = icon.contentDescription.orEmpty() val iconContent: @Composable () -> Unit = { icon.Content( modifier = Modifier @@ -411,12 +601,12 @@ internal fun OudsButton( .semantics { contentDescription = when (label) { // Ugly workaround to make TalkBack read badge and icon content descriptions correctly - null if iconOnlyBadge != null -> "${iconOnlyBadge.contentDescription}, ${icon.contentDescription}" - null -> icon.contentDescription + null if iconOnlyBadge != null -> "${iconOnlyBadge.contentDescription}, $iconContentDescription" + null -> iconContentDescription else -> "" } }, - extraParameters = OudsButtonIcon.ExtraParameters(tint = contentColor.value) + extraParameters = OudsIcon.ExtraParameters(tint = contentColor.value) ) } if (iconOnlyBadge != null && label == null) { @@ -470,7 +660,7 @@ private fun ButtonText(label: String, color: Color, size: OudsButtonSize) { } @Composable -private fun getButtonState(enabled: Boolean, loader: OudsButtonLoader?, interactionState: InteractionState): OudsButtonState { +private fun getButtonState(enabled: Boolean, loader: OudsLoader?, interactionState: InteractionState): OudsButtonState { return getPreviewEnumEntry().orElse { if (loader != null) { OudsButtonState.Loading @@ -708,7 +898,7 @@ private fun contentColor(appearance: OudsButtonAppearance, state: OudsButtonStat } @Composable -private fun contentPadding(component: OudsButtonComponent, icon: OudsButtonIcon?, label: String?, size: OudsButtonSize): PaddingValues { +private fun contentPadding(component: OudsButtonComponent, icon: OudsIcon?, label: String?, size: OudsButtonSize): PaddingValues { return with(OudsTheme.componentsTokens.button) { when (component) { is OudsButtonComponent.Button -> when { @@ -733,12 +923,12 @@ private fun contentPadding(component: OudsButtonComponent, icon: OudsButtonIcon? label != null -> { val startPadding: Dp val endPadding: Dp - when (component.chevron) { - OudsNavigationButtonChevron.Next -> { + when (component.indicator) { + OudsNavigationButtonIndicator.Next -> { startPadding = size.getTokenValue(default = spacePaddingInlineStartIconEndDefault, small = spacePaddingInlineStartIconEndSmall) endPadding = size.getTokenValue(default = spacePaddingInlineChevronEndDefault, small = spacePaddingInlineChevronEndSmall) } - OudsNavigationButtonChevron.Previous -> { + OudsNavigationButtonIndicator.Previous -> { startPadding = size.getTokenValue(default = spacePaddingInlineChevronStartDefault, small = spacePaddingInlineChevronStartSmall) endPadding = size.getTokenValue(default = spacePaddingInlineEndIconStartDefault, small = spacePaddingInlineEndIconStartSmall) } @@ -772,12 +962,15 @@ object OudsButtonDefaults { * An icon in an [OudsButton]. * This icon is non-clickable. */ +@Deprecated("") +@Suppress("DEPRECATION") class OudsButtonIcon private constructor( graphicsObject: Any, - val contentDescription: String, + contentDescription: String, override val tinted: Boolean ) : OudsComponentIcon(ExtraParameters::class.java, graphicsObject, contentDescription) { + @Deprecated("") @ConsistentCopyVisibility data class ExtraParameters internal constructor( internal val tint: Color @@ -865,7 +1058,11 @@ enum class OudsButtonAppearance { * Values outside of this range are coerced into the range. * Set this value to `null` to display a circular indeterminate progress indicator. */ -data class OudsButtonLoader(val progress: Float?) +@Deprecated("") +data class OudsButtonLoader(val progress: Float?) { + + internal fun toLoader() = OudsLoader(progress) +} internal data class OudsButtonIconBadge(val contentDescription: String, val borderColor: Color, val count: Int? = null) @@ -900,11 +1097,11 @@ internal sealed interface OudsButtonComponent { } /** - * Configuration for an [OudsNavigationButton] (including a chevron). + * Configuration for an [OudsNavigationButton] (including an indicator). * - * @property chevron The chevron to display in the button. + * @property indicator The indicator to display in the button. */ - class NavigationButton(val chevron: OudsNavigationButtonChevron) : OudsButtonComponent { + class NavigationButton(val indicator: OudsNavigationButtonIndicator) : OudsButtonComponent { @Composable override fun getColumnGap(size: OudsButtonSize): Dp { @@ -945,7 +1142,7 @@ internal fun PreviewOudsButton( ) = OudsPreview(theme = theme, darkThemeEnabled = darkThemeEnabled) { with(parameter) { val label = if (hasLabel) appearance.name else null - val icon = if (hasIcon) OudsButtonIcon(Icons.Filled.FavoriteBorder, "") else null + val icon = if (hasIcon) OudsIcon(Icons.Filled.FavoriteBorder) else null val content: @Composable () -> Unit = { PreviewEnumEntries(maxEnumEntriesInEachRow = 2) { when { @@ -989,7 +1186,7 @@ internal fun PreviewOudsButtonWithRoundedCorners(theme: OudsThemeContract) = Oud val appearance = OudsButtonAppearance.Default PreviewEnumEntries(maxEnumEntriesInEachRow = 2) { OudsButton( - icon = OudsButtonIcon(Icons.Filled.FavoriteBorder, ""), + icon = OudsIcon(Icons.Filled.FavoriteBorder), label = appearance.name, onClick = {}, appearance = appearance @@ -1007,7 +1204,7 @@ private fun PreviewOudsButtonWithIconBadge(@PreviewParameter(OudsButtonWithIconB internal fun PreviewOudsButtonWithIconBadge(theme: OudsThemeContract, count: Int) = OudsPreview(theme = theme) { PreviewEnumEntries(maxEnumEntriesInEachRow = 2) { OudsButton( - nullableIcon = OudsButtonIcon(Icons.Filled.FavoriteBorder, ""), + nullableIcon = OudsIcon(Icons.Filled.FavoriteBorder), nullableLabel = null, onClick = {}, appearance = OudsButtonAppearance.Minimal, @@ -1024,7 +1221,7 @@ private fun PreviewOudsButtonOnTwoLines() = PreviewOudsButtonOnTwoLines(getPrevi @Composable internal fun PreviewOudsButtonOnTwoLines(theme: OudsThemeContract) = OudsPreview(theme = theme) { OudsButton( - nullableIcon = OudsButtonIcon(Icons.Filled.FavoriteBorder, ""), + nullableIcon = OudsIcon(Icons.Filled.FavoriteBorder), nullableLabel = "Button\non two lines", onClick = {}, ) @@ -1039,9 +1236,8 @@ private fun PreviewOudsButtonWithUntintedIcon() = PreviewOudsButtonWithUntintedI internal fun PreviewOudsButtonWithUntintedIcon(theme: OudsThemeContract) = OudsPreview(theme = theme) { PreviewEnumEntries(maxEnumEntriesInEachRow = 2) { OudsButton( - nullableIcon = OudsButtonIcon( + nullableIcon = OudsIcon( painter = rememberRainbowHeartPainter(), - contentDescription = "", tinted = false ), nullableLabel = "Label", diff --git a/core/src/main/java/com/orange/ouds/core/component/OudsCheckboxItem.kt b/core/src/main/java/com/orange/ouds/core/component/OudsCheckboxItem.kt index 3291614274..eea0b00860 100644 --- a/core/src/main/java/com/orange/ouds/core/component/OudsCheckboxItem.kt +++ b/core/src/main/java/com/orange/ouds/core/component/OudsCheckboxItem.kt @@ -95,7 +95,7 @@ fun OudsCheckboxItem( onCheckedChange: ((Boolean) -> Unit)?, modifier: Modifier = Modifier, description: String? = null, - icon: OudsControlItemIcon? = null, + icon: OudsIcon? = null, edgeToEdge: Boolean = true, divider: Boolean = false, reversed: Boolean = false, @@ -125,6 +125,86 @@ fun OudsCheckboxItem( ) } +/** + * Checkbox item is a UI element that allows to select multiple options from a set of mutually non exclusive choices. Checkbox item covers a wider range of + * contexts by allowing to toggle the visibility of additional text labels and icon assets. + * + * The **checkbox item variant** can function as a simple input with a label, or it can be combined with optional elements such as description, a divider, or an icon, + * allowing it to suit various use cases. + * + * The OUDS checkbox item layout contains an [OudsCheckbox]. By clicking on a checkbox item, the user changes the checked state of its checkbox. + * + * > Design guidelines: [unified-design-system.orange.com](https://r.orange.fr/r/S-ouds-doc-checkbox) + * + * > Design name: Checkbox + * + * > Design version: 2.4.0 + * + * @see [OudsTriStateCheckboxItem] If you need an indeterminate state for the item's checkbox. + * @see [OudsCheckbox] If you want to use a standalone checkbox without any other element. + * + * @param checked Controls the checked state of the item's checkbox. + * @param label The main label of the checkbox item. + * @param onCheckedChange Callback invoked on checkbox item click. If `null`, then this is passive and relies entirely on a higher-level component to control + * the checked state. + * @param modifier [Modifier] applied to the layout of the checkbox item. + * @param description Optional text displayed below the label. + * @param icon Optional icon displayed in the item. By default, it has a trailing position. If [reversed] is set to `true`, it is displayed as a leading element. + * @param edgeToEdge Controls the horizontal layout of the item. When `true`, the item is designed to span the full width of the screen or container. When `false`, + * it is adapted for use within constrained layouts or containers with their own padding. Defaults to `true`. + * @param divider Controls the display of a divider at the bottom of the checkbox item. + * @param reversed When `false`, the checkbox has a leading position and the optional [icon] has a trailing position. Otherwise, it is reversed. + * @param enabled Controls the enabled state of the checkbox item. When `false`, the checkbox, the texts and the optional icon are disabled, and the item + * will not be clickable. + * @param readOnly Controls the read-only state of the checkbox item. When `true` the item's checkbox is disabled but the texts and the icon remain in + * enabled color. Note that if it is set to `true` and [enabled] is set to `false`, the checkbox item will be displayed in disabled state. + * @param error Optional [OudsError] to indicate that the checkbox item should appear in error state, `null` otherwise. + * @param constrainedMaxWidth When `true`, the item width is constrained to a maximum value defined by the design system. + * When `false`, no specific width constraint is applied, allowing the component to size itself or follow external modifiers. + * Defaults to `false`. + * @param interactionSource Optional hoisted [MutableInteractionSource] for observing and emitting [Interaction]s for the item's checkbox. Note that if `null` + * is provided, interactions will still happen internally. + * + * @sample com.orange.ouds.core.component.samples.OudsCheckboxItemSample + * @sample com.orange.ouds.core.component.samples.OudsCheckboxItemWithAnnotatedErrorMessageSample + * @sample com.orange.ouds.core.component.samples.OudsCheckboxItemWithUntintedIconSample + */ +@Deprecated("") +@Composable +fun OudsCheckboxItem( + checked: Boolean, + label: String, + onCheckedChange: ((Boolean) -> Unit)?, + modifier: Modifier = Modifier, + description: String? = null, + @Suppress("DEPRECATION") icon: OudsControlItemIcon?, + edgeToEdge: Boolean = true, + divider: Boolean = false, + reversed: Boolean = false, + enabled: Boolean = true, + readOnly: Boolean = false, + error: OudsError? = null, + constrainedMaxWidth: Boolean = false, + interactionSource: MutableInteractionSource? = null +) { + OudsCheckboxItem( + checked = checked, + label = label, + onCheckedChange = onCheckedChange, + modifier = modifier, + description = description, + icon = icon?.toIcon(), + edgeToEdge = edgeToEdge, + divider = divider, + reversed = reversed, + enabled = enabled, + readOnly = readOnly, + error = error, + constrainedMaxWidth = constrainedMaxWidth, + interactionSource = interactionSource + ) +} + /** * Checkbox item is a UI element that allows to select multiple options from a set of mutually non exclusive choices. Checkbox item covers a wider range of * contexts by allowing to toggle the visibility of additional text labels and icon assets. @@ -181,7 +261,7 @@ fun OudsTriStateCheckboxItem( onClick: (() -> Unit)?, modifier: Modifier = Modifier, description: String? = null, - icon: OudsControlItemIcon? = null, + icon: OudsIcon? = null, edgeToEdge: Boolean = true, divider: Boolean = false, reversed: Boolean = false, @@ -242,6 +322,91 @@ fun OudsTriStateCheckboxItem( ) } +/** + * Checkbox item is a UI element that allows to select multiple options from a set of mutually non exclusive choices. Checkbox item covers a wider range of + * contexts by allowing to toggle the visibility of additional text labels and icon assets. + * + * This checkbox item supports the indeterminate state: Checkboxes can have a parent-child relationship with other checkboxes. When the parent checkbox is + * checked, all child checkboxes are checked. If a parent checkbox is unchecked, all child checkboxes are unchecked. If some, but not all, child checkboxes are + * checked, the parent checkbox becomes an indeterminate checkbox. + * + * The **indeterminate checkbox item variant** can function as a simple input with a label, or it can be combined with optional elements such as description, + * a divider, or an icon, allowing it to suit various use cases. + * + * The OUDS indeterminate checkbox item layout contains an [OudsTriStateCheckbox]. By clicking on an indeterminate checkbox item, the user changes the checked + * state of its checkbox. + * + * > Design guidelines: [unified-design-system.orange.com](https://r.orange.fr/r/S-ouds-doc-checkbox) + * + * > Design name: Checkbox + * + * > Design version: 2.4.0 + * + * @see [OudsCheckboxItem] If you need a simple item's checkbox that represents [Boolean] state. + * @see [OudsTriStateCheckbox] If you only need an indeterminate standalone parent checkbox without any other element. + * + * @param state Controls whether item's TriStateCheckbox is checked, unchecked or in indeterminate state. + * @param label The main label of the checkbox item. + * @param onClick Callback invoked when checkbox item is being clicked, therefore the change of checkbox [ToggleableState] state is requested. If `null`, then + * this is passive and relies entirely on a higher-level component to control the state. + * @param modifier [Modifier] applied to the layout of the checkbox item. + * @param description Optional text displayed below the label. + * @param icon Optional icon displayed in the item. By default, it has a trailing position. If [reversed] is set to `true`, it is displayed as a leading element. + * @param edgeToEdge Controls the horizontal layout of the item. When `true`, the item is designed to span the full width of the screen or container. When `false`, + * it is adapted for use within constrained layouts or containers with their own padding. Defaults to `true`. + * @param divider Controls the display of a divider at the bottom of the checkbox item. + * @param reversed When `false`, the checkbox has a leading position and the optional [icon] has a trailing position. Otherwise, it is reversed. + * @param enabled Controls the enabled state of the checkbox item. When `false`, the checkbox, the texts and the optional icon are disabled, and the item + * will not be clickable. + * @param readOnly Controls the read-only state of the checkbox item. When `true` the item's checkbox is disabled but the texts and the icon remain in + * enabled color. Note that if it is set to `true` and [enabled] is set to `false`, the checkbox item will be displayed in disabled state. + * @param error Optional [OudsError] to indicate that the checkbox item should appear in error state, `null` otherwise. + * @param constrainedMaxWidth When `true`, the item width is constrained to a maximum value defined by the design system. + * When `false`, no specific width constraint is applied, allowing the component to size itself or follow external modifiers. + * Defaults to `false`. + * @param interactionSource Optional hoisted [MutableInteractionSource] for observing and emitting [Interaction]s for the item's checkbox. Note that + * if `null` is provided, interactions will still happen internally. + * + * @sample com.orange.ouds.core.component.samples.OudsTriStateCheckboxItemSample + * @sample com.orange.ouds.core.component.samples.OudsTriStateCheckboxItemWithAnnotatedErrorMessageSample + * @sample com.orange.ouds.core.component.samples.OudsTriStateCheckboxItemWithUntintedIconSample + */ +@Deprecated("") +@Composable +fun OudsTriStateCheckboxItem( + state: ToggleableState, + label: String, + onClick: (() -> Unit)?, + modifier: Modifier = Modifier, + description: String? = null, + @Suppress("DEPRECATION") icon: OudsControlItemIcon?, + edgeToEdge: Boolean = true, + divider: Boolean = false, + reversed: Boolean = false, + enabled: Boolean = true, + readOnly: Boolean = false, + error: OudsError? = null, + constrainedMaxWidth: Boolean = false, + interactionSource: MutableInteractionSource? = null +) { + OudsTriStateCheckboxItem( + state = state, + label = label, + onClick = onClick, + modifier = modifier, + description = description, + icon = icon?.toIcon(), + edgeToEdge = edgeToEdge, + divider = divider, + reversed = reversed, + enabled = enabled, + readOnly = readOnly, + error = error, + constrainedMaxWidth = constrainedMaxWidth, + interactionSource = interactionSource + ) +} + @Preview(name = "Light", heightDp = OudsPreviewableComponent.CheckboxItem.Default.PreviewHeightDp, device = OudsPreviewDevice) @Preview( name = "Dark", @@ -271,7 +436,7 @@ internal fun PreviewOudsCheckboxItem( divider = divider, error = error, reversed = reversed, - icon = if (hasIcon) OudsControlItemIcon(imageVector = Icons.Filled.Call) else null, + icon = if (hasIcon) OudsIcon(imageVector = Icons.Filled.Call) else null, interactionSource = remember { MutableInteractionSource() } ) } @@ -325,7 +490,7 @@ internal fun PreviewOudsCheckboxItemWithLongDescription(theme: OudsThemeContract label = "Label", onCheckedChange = {}, description = LoremIpsumText, - icon = OudsControlItemIcon(imageVector = Icons.Filled.Call) + icon = OudsIcon(imageVector = Icons.Filled.Call) ) } @@ -341,7 +506,7 @@ internal fun PreviewOudsCheckboxItemWithEdgeToEdgeDisabled(theme: OudsThemeContr checked = true, label = "Label", onCheckedChange = {}, - icon = OudsControlItemIcon(imageVector = Icons.Filled.Call), + icon = OudsIcon(imageVector = Icons.Filled.Call), edgeToEdge = false, divider = true, error = OudsError(ControlItemErrorMessage), @@ -365,7 +530,7 @@ internal fun PreviewOudsCheckboxItemConstrainedMaxWidth( checked = true, label = "Label", onCheckedChange = {}, - icon = OudsControlItemIcon(imageVector = Icons.Filled.Call), + icon = OudsIcon(imageVector = Icons.Filled.Call), constrainedMaxWidth = constrainedMaxWidth, edgeToEdge = false, divider = true @@ -407,7 +572,7 @@ internal fun PreviewOudsCheckboxItemWithUntintedIcon(theme: OudsThemeContract) = checked = false, label = "Label", onCheckedChange = {}, - icon = OudsControlItemIcon(painter = rememberRainbowHeartPainter(), tinted = false), + icon = OudsIcon(painter = rememberRainbowHeartPainter(), tinted = false), divider = true ) } diff --git a/core/src/main/java/com/orange/ouds/core/component/OudsChip.kt b/core/src/main/java/com/orange/ouds/core/component/OudsChip.kt index 90128e7362..9e25659110 100644 --- a/core/src/main/java/com/orange/ouds/core/component/OudsChip.kt +++ b/core/src/main/java/com/orange/ouds/core/component/OudsChip.kt @@ -35,12 +35,15 @@ import com.orange.ouds.foundation.RestrictedOudsApi * An icon in an [OudsFilterChip] or an [OudsSuggestionChip]. * This icon is not clickable. */ +@Suppress("DEPRECATION") +@Deprecated("") class OudsChipIcon private constructor( graphicsObject: Any, - val contentDescription: String, + contentDescription: String, override val tinted: Boolean ) : OudsComponentIcon(ExtraParameters::class.java, graphicsObject, contentDescription) { + @Deprecated("") @ConsistentCopyVisibility data class ExtraParameters internal constructor( internal val tint: Color diff --git a/core/src/main/java/com/orange/ouds/core/component/OudsControlItem.kt b/core/src/main/java/com/orange/ouds/core/component/OudsControlItem.kt index bdf0a4e058..5232452be6 100644 --- a/core/src/main/java/com/orange/ouds/core/component/OudsControlItem.kt +++ b/core/src/main/java/com/orange/ouds/core/component/OudsControlItem.kt @@ -58,13 +58,12 @@ import com.orange.ouds.foundation.utilities.BasicPreviewParameterProvider * The control item composable helps factorize common layout elements shared by [OudsCheckboxItem], [OudsTriStateCheckboxItem], [OudsRadioButtonItem], * and [OudsSwitchItem]. */ -@Suppress("DEPRECATION") @Composable internal fun OudsControlItem( state: OudsControlState, label: String, description: String?, - icon: OudsControlItemIcon?, + icon: OudsIcon?, edgeToEdge: Boolean, divider: Boolean, enabled: Boolean, @@ -112,7 +111,8 @@ internal fun OudsControlItem( icon?.let { { icon.Content( - extraParameters = OudsControlItemIcon.ExtraParameters( + modifier = Modifier.iconSize(OudsTheme.componentsTokens.listItem.sizeAssetSmall.value, icon.tinted), + extraParameters = OudsIcon.ExtraParameters( tint = if (state == OudsControlState.Disabled) OudsTheme.colorScheme.content.disabled else OudsTheme.colorScheme.content.default ) ) @@ -189,12 +189,15 @@ internal enum class OudsControlItemIndicatorPosition { * An icon in a control item like [OudsCheckboxItem] or [OudsRadioButtonItem]. * It is not clickable and requires no content description because a control item label is always present. */ +@Suppress("DEPRECATION") +@Deprecated("") class OudsControlItemIcon private constructor( graphicsObject: Any, override val tinted: Boolean ) : OudsComponentIcon(ExtraParameters::class.java, graphicsObject, "") { @ConsistentCopyVisibility + @Deprecated("") data class ExtraParameters internal constructor( internal val tint: Color ) : OudsComponentContent.ExtraParameters() @@ -412,4 +415,4 @@ internal class OudsControlItemConstrainedMaxWidthPreviewParameterProvider : Basi /** * Error message used in control items previews. */ -internal val ControlItemErrorMessage = "This field can't be activated" \ No newline at end of file +internal const val ControlItemErrorMessage = "This field can't be activated" \ No newline at end of file diff --git a/core/src/main/java/com/orange/ouds/core/component/OudsFilterChip.kt b/core/src/main/java/com/orange/ouds/core/component/OudsFilterChip.kt index eb7f9061c4..fff05680ea 100644 --- a/core/src/main/java/com/orange/ouds/core/component/OudsFilterChip.kt +++ b/core/src/main/java/com/orange/ouds/core/component/OudsFilterChip.kt @@ -112,7 +112,7 @@ fun OudsFilterChip( fun OudsFilterChip( selected: Boolean, onClick: () -> Unit, - icon: OudsChipIcon, + icon: OudsIcon, modifier: Modifier = Modifier, enabled: Boolean = true, interactionSource: MutableInteractionSource? = null @@ -128,6 +128,57 @@ fun OudsFilterChip( ) } +/** + * Filter chip is a UI element that allows to select or deselect an option within a series, and is commonly used to capture filtering decisions. + * Filter chip allows to filter content by being selected or deselected. It can be toggled "On" or "Off" to refine displayed results, + * and selected Filter Chips remain visually distinct to indicate active filters. + * + * This version of the chip uses the *icon only* layout which uses only an icon, making it a compact option for limited space. + * Works well with universally recognized symbols, such as a heart for favorites or a checkmark for selection. + * Other layouts are available for this component: *text only* and *text + icon*. + * + * > Design guidelines: [unified-design-system.orange.com](https://r.orange.fr/r/S-ouds-doc-filter-chip) + * + * > Design name: Filter Chip + * + * > Design version: 1.5.0 + * + * @param selected Whether this chip is selected or not. + * @param onClick Called when this chip is clicked. + * @param icon Icon displayed in the chip. Use an icon to add additional affordance where the icon has a clear and well-established meaning. + * @param modifier The [Modifier] to be applied to this chip. + * @param enabled Controls the enabled state of this chip. When `false`, this component will not + * respond to user input, and it will appear visually disabled and disabled to accessibility + * services. + * @param interactionSource An optional hoisted [MutableInteractionSource] for observing and + * emitting [Interaction]s for this chip. You can use this to change the chip's appearance or + * preview the chip in different states. Note that if `null` is provided, interactions will still + * happen internally. + * + * @sample com.orange.ouds.core.component.samples.OudsFilterChipIconOnlySample + * + * @sample com.orange.ouds.core.component.samples.OudsFilterChipIconOnlyWithUntintedIconSample + */ +@Deprecated("") +@Composable +fun OudsFilterChip( + selected: Boolean, + onClick: () -> Unit, + @Suppress("DEPRECATION") icon: OudsChipIcon, + modifier: Modifier = Modifier, + enabled: Boolean = true, + interactionSource: MutableInteractionSource? = null +) { + OudsFilterChip( + selected = selected, + onClick = onClick, + icon = icon.toIcon(), + modifier = modifier, + enabled = enabled, + interactionSource = interactionSource + ) +} + /** * Filter chip is a UI element that allows to select or deselect an option within a series, and is commonly used to capture filtering decisions. * Filter chip allows to filter content by being selected or deselected. It can be toggled "On" or "Off" to refine displayed results, @@ -165,7 +216,7 @@ fun OudsFilterChip( selected: Boolean, onClick: () -> Unit, label: String, - icon: OudsChipIcon, + icon: OudsIcon, modifier: Modifier = Modifier, enabled: Boolean = true, interactionSource: MutableInteractionSource? = null @@ -181,13 +232,67 @@ fun OudsFilterChip( ) } +/** + * Filter chip is a UI element that allows to select or deselect an option within a series, and is commonly used to capture filtering decisions. + * Filter chip allows to filter content by being selected or deselected. It can be toggled "On" or "Off" to refine displayed results, + * and selected Filter Chips remain visually distinct to indicate active filters. + * + * This version of the chip uses the *text + icon* layout which combines text with an icon to enhance clarity and recognition. + * Ideal when a visual cue helps reinforce the filter’s meaning. + * Other layouts are available for this component: *text only* and *icon only*. + * + * > Design guidelines: [unified-design-system.orange.com](https://r.orange.fr/r/S-ouds-doc-filter-chip) + * + * > Design name: Filter Chip + * + * > Design version: 1.5.0 + * + * @param selected Whether this chip is selected or not. + * @param onClick Called when this chip is clicked. + * @param label Text label displayed in the chip. + * @param icon Icon displayed in the chip. Use an icon to add additional affordance where the icon has a clear and well-established meaning. + * @param modifier The [Modifier] to be applied to this chip. + * @param enabled Controls the enabled state of this chip. When `false`, this component will not + * respond to user input, and it will appear visually disabled and disabled to accessibility + * services. + * @param interactionSource An optional hoisted [MutableInteractionSource] for observing and + * emitting [Interaction]s for this chip. You can use this to change the chip's appearance or + * preview the chip in different states. Note that if `null` is provided, interactions will still + * happen internally. + * + * @sample com.orange.ouds.core.component.samples.OudsFilterChipTextAndIconSample + * + * @sample com.orange.ouds.core.component.samples.OudsFilterChipTextAndIconWithUntintedIconSample + */ +@Deprecated("") +@Composable +fun OudsFilterChip( + selected: Boolean, + onClick: () -> Unit, + label: String, + @Suppress("DEPRECATION") icon: OudsChipIcon, + modifier: Modifier = Modifier, + enabled: Boolean = true, + interactionSource: MutableInteractionSource? = null +) { + OudsFilterChip( + selected = selected, + onClick = onClick, + label = label, + icon = icon.toIcon(), + modifier = modifier, + enabled = enabled, + interactionSource = interactionSource + ) +} + @Composable @JvmName("OudsFilterChipNullableLabelAndIcon") private fun OudsFilterChip( selected: Boolean, onClick: () -> Unit, nullableLabel: String?, - nullableIcon: OudsChipIcon?, + nullableIcon: OudsIcon?, modifier: Modifier = Modifier, enabled: Boolean = true, interactionSource: MutableInteractionSource? = null @@ -217,7 +322,7 @@ internal fun PreviewOudsFilterChip(theme: OudsThemeContract, darkThemeEnabled: B OudsPreview(theme = theme, darkThemeEnabled = darkThemeEnabled) { with(parameter) { val label = if (hasLabel) "Label" else null - val icon = if (hasIcon) OudsChipIcon(Icons.Filled.FavoriteBorder, "") else null + val icon = if (hasIcon) OudsIcon(Icons.Filled.FavoriteBorder) else null PreviewEnumEntries(maxEnumEntriesInEachRow = 3) { OudsFilterChip( selected = selected, @@ -241,7 +346,7 @@ internal fun PreviewOudsFilterChipWithUntintedIcon(theme: OudsThemeContract) = O PreviewEnumEntries(maxEnumEntriesInEachRow = 3) { OudsFilterChip( selected = false, - nullableIcon = OudsChipIcon(painter = rememberRainbowHeartPainter(), contentDescription = "", tinted = false), + nullableIcon = OudsIcon(painter = rememberRainbowHeartPainter(), tinted = false), nullableLabel = "Label", onClick = {} ) @@ -259,7 +364,7 @@ private fun PreviewOudsFilterChipOnTwoLines() { internal fun PreviewOudsFilterChipOnTwoLines(theme: OudsThemeContract) = OudsPreview(theme = theme) { OudsFilterChip( selected = false, - icon = OudsChipIcon(Icons.Filled.FavoriteBorder, ""), + icon = OudsIcon(Icons.Filled.FavoriteBorder), label = "Filter chip\non two lines", onClick = {} ) diff --git a/core/src/main/java/com/orange/ouds/core/component/OudsFloatingActionButton.kt b/core/src/main/java/com/orange/ouds/core/component/OudsFloatingActionButton.kt index a30be66ecf..d316a77651 100644 --- a/core/src/main/java/com/orange/ouds/core/component/OudsFloatingActionButton.kt +++ b/core/src/main/java/com/orange/ouds/core/component/OudsFloatingActionButton.kt @@ -92,7 +92,7 @@ import com.orange.ouds.theme.OudsThemeContract */ @Composable fun OudsFloatingActionButton( - icon: OudsFloatingActionButtonIcon, + icon: OudsIcon, onClick: () -> Unit, modifier: Modifier = Modifier, shape: Shape = OudsFloatingActionButtonDefaults.shape, @@ -121,6 +121,50 @@ fun OudsFloatingActionButton( } } +/** + * The FAB represents the most important action on a screen. It puts key actions within reach. + * + * FAB typically contains an icon, for a FAB with text and an icon, see + * [OudsExtendedFloatingActionButton]. + * + * > Design name: FAB + * + * > Design version: Draft + * + * @param icon Icon for this FAB. + * @param onClick Called when this FAB is clicked. + * @param modifier The [Modifier] to be applied to this FAB. + * @param shape Defines the shape of this FAB's container and shadow. + * @param appearance Appearance of the FAB among [OudsFloatingActionButtonAppearance] values. + * @param interactionSource An optional hoisted [MutableInteractionSource] for observing and + * emitting [Interaction]s for this FAB. You can use this to change the FAB's appearance or + * preview the FAB in different states. Note that if `null` is provided, interactions will still + * happen internally. + * + * @sample com.orange.ouds.core.component.samples.OudsFloatingActionButtonSample + * + * @sample com.orange.ouds.core.component.samples.OudsFloatingActionButtonWithUntintedIconSample + */ +@Deprecated("") +@Composable +fun OudsFloatingActionButton( + @Suppress("DEPRECATION") icon: OudsFloatingActionButtonIcon, + onClick: () -> Unit, + modifier: Modifier = Modifier, + shape: Shape = OudsFloatingActionButtonDefaults.shape, + appearance: OudsFloatingActionButtonAppearance = OudsFloatingActionButtonDefaults.Appearance, + interactionSource: MutableInteractionSource? = null +) { + OudsFloatingActionButton( + icon = icon.toIcon(), + onClick = onClick, + modifier = modifier, + shape = shape, + appearance = appearance, + interactionSource = interactionSource + ) +} + /** * The FAB represents the most important action on a screen. It puts key actions within reach. * @@ -147,7 +191,7 @@ fun OudsFloatingActionButton( */ @Composable fun OudsSmallFloatingActionButton( - icon: OudsFloatingActionButtonIcon, + icon: OudsIcon, onClick: () -> Unit, modifier: Modifier = Modifier, shape: Shape = OudsFloatingActionButtonDefaults.shape, @@ -176,6 +220,50 @@ fun OudsSmallFloatingActionButton( } } +/** + * The FAB represents the most important action on a screen. It puts key actions within reach. + * + * FAB typically contains an icon, for a FAB with text and an icon, see + * [OudsExtendedFloatingActionButton]. + * + * > Design name: FAB + * + * > Design version: Draft + * + * @param icon Icon for this FAB. + * @param onClick Called when this FAB is clicked. + * @param modifier The [Modifier] to be applied to this FAB. + * @param shape Defines the shape of this FAB's container and shadow. + * @param appearance Appearance of the FAB among [OudsFloatingActionButtonAppearance] values. + * @param interactionSource An optional hoisted [MutableInteractionSource] for observing and + * emitting [Interaction]s for this FAB. You can use this to change the FAB's appearance or + * preview the FAB in different states. Note that if `null` is provided, interactions will still + * happen internally. + * + * @sample com.orange.ouds.core.component.samples.OudsSmallFloatingActionButtonSample + * + * @sample com.orange.ouds.core.component.samples.OudsSmallFloatingActionButtonWithUntintedIconSample + */ +@Deprecated("") +@Composable +fun OudsSmallFloatingActionButton( + @Suppress("DEPRECATION") icon: OudsFloatingActionButtonIcon, + onClick: () -> Unit, + modifier: Modifier = Modifier, + shape: Shape = OudsFloatingActionButtonDefaults.shape, + appearance: OudsFloatingActionButtonAppearance = OudsFloatingActionButtonDefaults.Appearance, + interactionSource: MutableInteractionSource? = null +) { + OudsSmallFloatingActionButton( + icon = icon.toIcon(), + onClick = onClick, + modifier = modifier, + shape = shape, + appearance = appearance, + interactionSource = interactionSource + ) +} + /** * The FAB represents the most important action on a screen. It puts key actions within reach. * @@ -202,7 +290,7 @@ fun OudsSmallFloatingActionButton( */ @Composable fun OudsLargeFloatingActionButton( - icon: OudsFloatingActionButtonIcon, + icon: OudsIcon, onClick: () -> Unit, modifier: Modifier = Modifier, shape: Shape = OudsFloatingActionButtonDefaults.shape, @@ -231,6 +319,50 @@ fun OudsLargeFloatingActionButton( } } +/** + * The FAB represents the most important action on a screen. It puts key actions within reach. + * + * FAB typically contains an icon, for a FAB with text and an icon, see + * [OudsExtendedFloatingActionButton]. + * + * > Design name: FAB + * + * > Design version: Draft + * + * @param icon Icon for this FAB. + * @param onClick Called when this FAB is clicked. + * @param modifier The [Modifier] to be applied to this FAB. + * @param shape Defines the shape of this FAB's container and shadow. + * @param appearance Appearance of the FAB among [OudsFloatingActionButtonAppearance] values. + * @param interactionSource An optional hoisted [MutableInteractionSource] for observing and + * emitting [Interaction]s for this FAB. You can use this to change the FAB's appearance or + * preview the FAB in different states. Note that if `null` is provided, interactions will still + * happen internally. + * + * @sample com.orange.ouds.core.component.samples.OudsLargeFloatingActionButtonSample + * + * @sample com.orange.ouds.core.component.samples.OudsLargeFloatingActionButtonWithUntintedIconSample + */ +@Deprecated("") +@Composable +fun OudsLargeFloatingActionButton( + @Suppress("DEPRECATION") icon: OudsFloatingActionButtonIcon, + onClick: () -> Unit, + modifier: Modifier = Modifier, + shape: Shape = OudsFloatingActionButtonDefaults.shape, + appearance: OudsFloatingActionButtonAppearance = OudsFloatingActionButtonDefaults.Appearance, + interactionSource: MutableInteractionSource? = null +) { + OudsLargeFloatingActionButton( + icon = icon.toIcon(), + onClick = onClick, + modifier = modifier, + shape = shape, + appearance = appearance, + interactionSource = interactionSource + ) +} + /** * Extended FABs help people take primary actions. They're wider than FABs to accommodate a text * label and larger target area. @@ -316,7 +448,7 @@ fun OudsExtendedFloatingActionButton( @Composable fun OudsExtendedFloatingActionButton( label: String, - icon: OudsFloatingActionButtonIcon, + icon: OudsIcon, onClick: () -> Unit, modifier: Modifier = Modifier, expanded: Boolean = true, @@ -347,6 +479,59 @@ fun OudsExtendedFloatingActionButton( } } +/** + * Extended FABs help people take primary actions. They're wider than FABs to accommodate a text + * label and larger target area. + * + * The other extended floating action button overload is for FABs without an icon. + * + * Default content description for accessibility is extended from the extended fabs icon. For custom + * behavior, you can provide your own via [Modifier.semantics]. + * + * > Design name: FAB + * + * > Design version: Draft + * + * @param label Label displayed inside this FAB. + * @param icon Icon for this FAB. + * @param onClick Called when this FAB is clicked. + * @param modifier The [Modifier] to be applied to this FAB. + * @param shape Defines the shape of this FAB's container and shadow. + * @param expanded Controls the expansion state of this FAB. In an expanded state, the FAB will show + * both the [icon] and [label]. In a collapsed state, the FAB will show only the [icon]. + * @param interactionSource An optional hoisted [MutableInteractionSource] for observing and + * emitting [Interaction]s for this FAB. You can use this to change the FAB's appearance or + * preview the FAB in different states. Note that if `null` is provided, interactions will still + * happen internally. + * + * @sample com.orange.ouds.core.component.samples.OudsExtendedFloatingActionButtonSampleWithLabelAndIcon + * + * @sample com.orange.ouds.core.component.samples.OudsExtendedFloatingActionButtonWithUntintedIconSample + */ +@Deprecated("") +@Composable +fun OudsExtendedFloatingActionButton( + label: String, + @Suppress("DEPRECATION") icon: OudsFloatingActionButtonIcon, + onClick: () -> Unit, + modifier: Modifier = Modifier, + expanded: Boolean = true, + shape: Shape = OudsFloatingActionButtonDefaults.shape, + appearance: OudsFloatingActionButtonAppearance = OudsFloatingActionButtonDefaults.Appearance, + interactionSource: MutableInteractionSource? = null +) { + OudsExtendedFloatingActionButton( + label = label, + icon = icon.toIcon(), + onClick = onClick, + modifier = modifier, + expanded = expanded, + shape = shape, + appearance = appearance, + interactionSource = interactionSource + ) +} + @Composable private fun OudsFloatingActionButton( appearance: OudsFloatingActionButtonAppearance, @@ -384,14 +569,15 @@ private fun OudsFloatingActionButton( } @Composable -private fun Icon(icon: OudsFloatingActionButtonIcon, label: String? = null, large: Boolean = false) { +private fun Icon(icon: OudsIcon, label: String? = null, large: Boolean = false) { val iconSize = if (large) OudsTheme.sizes.icon.withLabel.large.sizeLarge else OudsTheme.componentsTokens.button.sizeIconOnlyDefault.value val iconScale = LocalConfiguration.current.fontScale + val iconContentDescription = icon.contentDescription.orEmpty() icon.Content( modifier = Modifier .size(iconSize * iconScale) .semantics { - contentDescription = if (label.isNullOrBlank().not()) label else icon.contentDescription + contentDescription = if (label.isNullOrBlank().not()) label else iconContentDescription } ) } @@ -480,9 +666,11 @@ object OudsFloatingActionButtonDefaults { /** * An icon in an [OudsFloatingActionButton]. */ +@Suppress("DEPRECATION") +@Deprecated("") class OudsFloatingActionButtonIcon private constructor( graphicsObject: Any, - val contentDescription: String, + contentDescription: String, override val tinted: Boolean ) : OudsComponentIcon( Nothing::class.java, @@ -562,7 +750,7 @@ internal fun PreviewOudsFloatingActionButton( ) = OudsPreview(theme = theme, darkThemeEnabled = darkThemeEnabled) { PreviewEnumEntries { OudsFloatingActionButton( - icon = OudsFloatingActionButtonIcon(Icons.Filled.FavoriteBorder, ""), + icon = OudsIcon(Icons.Filled.FavoriteBorder), onClick = {}, appearance = appearance ) @@ -584,7 +772,7 @@ internal fun PreviewOudsSmallFloatingActionButton( ) = OudsPreview(theme = theme, darkThemeEnabled = darkThemeEnabled) { PreviewEnumEntries { OudsSmallFloatingActionButton( - icon = OudsFloatingActionButtonIcon(Icons.Filled.FavoriteBorder, ""), + icon = OudsIcon(Icons.Filled.FavoriteBorder), onClick = {}, appearance = appearance ) @@ -612,7 +800,7 @@ internal fun PreviewOudsLargeFloatingActionButton( ) = OudsPreview(theme = theme, darkThemeEnabled = darkThemeEnabled) { PreviewEnumEntries { OudsLargeFloatingActionButton( - icon = OudsFloatingActionButtonIcon(Icons.Filled.FavoriteBorder, ""), + icon = OudsIcon(Icons.Filled.FavoriteBorder), onClick = {}, appearance = appearance ) @@ -657,7 +845,7 @@ internal fun PreviewOudsExtendedFloatingActionButton( OudsExtendedFloatingActionButtonPreviewGridRow.LabelAndIconCollapsed -> { OudsExtendedFloatingActionButton( label = "Label", - icon = OudsFloatingActionButtonIcon(Icons.Filled.FavoriteBorder, ""), + icon = OudsIcon(Icons.Filled.FavoriteBorder), onClick = {}, expanded = row == OudsExtendedFloatingActionButtonPreviewGridRow.LabelAndIconExpanded, appearance = appearance @@ -685,7 +873,7 @@ private fun PreviewOudsFloatingActionButtonWithUntintedIcon() { internal fun PreviewOudsFloatingActionButtonWithUntintedIcon(theme: OudsThemeContract) = OudsPreview(theme = theme) { PreviewEnumEntries { OudsFloatingActionButton( - icon = OudsFloatingActionButtonIcon(rememberRainbowHeartPainter(), "", tinted = false), + icon = OudsIcon(rememberRainbowHeartPainter(), "", tinted = false), onClick = {} ) } diff --git a/core/src/main/java/com/orange/ouds/core/component/OudsIcon.kt b/core/src/main/java/com/orange/ouds/core/component/OudsIcon.kt new file mode 100644 index 0000000000..477968de7e --- /dev/null +++ b/core/src/main/java/com/orange/ouds/core/component/OudsIcon.kt @@ -0,0 +1,66 @@ +/* + * 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.core.component + +import androidx.compose.runtime.Composable +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.graphics.ImageBitmap +import androidx.compose.ui.graphics.painter.Painter +import androidx.compose.ui.graphics.vector.ImageVector +import com.orange.ouds.core.component.content.OudsComponentContent +import com.orange.ouds.core.component.content.OudsComponentIcon + +class OudsIcon internal constructor( + graphicsObjectProvider: @Composable (OudsIcon) -> Any, + contentDescriptionProvider: @Composable (OudsIcon) -> String?, + override val tinted: Boolean +) : OudsComponentIcon(graphicsObjectProvider, contentDescriptionProvider, null), OudsTagAsset { + + open class ExtraParameters internal constructor( + val tint: Color? = null, + val enabled: Boolean = true + ) : OudsComponentContent.ExtraParameters() + + object Default : OudsTagAsset + + init { + // Set default extra parameters to avoid UninitializedPropertyAccessException + extraParameters = ExtraParameters() + } + + constructor( + painter: Painter, + contentDescription: String? = null, + tinted: Boolean = true + ) : this({ painter }, { contentDescription }, tinted) + + constructor( + imageVector: ImageVector, + contentDescription: String? = null, + tinted: Boolean = true + ) : this({ imageVector }, { contentDescription }, tinted) + + constructor( + bitmap: ImageBitmap, + contentDescription: String? = null, + tinted: Boolean = true + ) : this({ bitmap }, { contentDescription }, tinted) + + override val enabled: Boolean? + @Composable + get() = extraParameters.enabled + + override val tint: Color? + @Composable + get() = extraParameters.tint +} diff --git a/core/src/main/java/com/orange/ouds/core/component/OudsIconButton.kt b/core/src/main/java/com/orange/ouds/core/component/OudsIconButton.kt new file mode 100644 index 0000000000..14b37542b9 --- /dev/null +++ b/core/src/main/java/com/orange/ouds/core/component/OudsIconButton.kt @@ -0,0 +1,68 @@ +/* + * 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.core.component + +import androidx.compose.runtime.Composable +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.graphics.ImageBitmap +import androidx.compose.ui.graphics.painter.Painter +import androidx.compose.ui.graphics.vector.ImageVector +import com.orange.ouds.core.component.content.OudsComponentContent +import com.orange.ouds.core.component.content.OudsComponentIcon + +class OudsIconButton internal constructor( + graphicsObjectProvider: @Composable (OudsIconButton) -> Any, + contentDescriptionProvider: @Composable (OudsIconButton) -> String?, + override val tinted: Boolean, + onClick: () -> Unit +) : OudsComponentIcon(graphicsObjectProvider, contentDescriptionProvider, onClick) { + + open class ExtraParameters internal constructor( + val tint: Color? = null, + val enabled: Boolean = true + ) : OudsComponentContent.ExtraParameters() + + init { + // Set default extra parameters to avoid UninitializedPropertyAccessException + extraParameters = ExtraParameters() + } + + constructor( + painter: Painter, + onClick: () -> Unit, + contentDescription: String? = null, + tinted: Boolean = true + ) : this({ painter }, { contentDescription }, tinted, onClick) + + constructor( + imageVector: ImageVector, + onClick: () -> Unit, + contentDescription: String? = null, + tinted: Boolean = true + ) : this({ imageVector }, { contentDescription }, tinted, onClick) + + constructor( + bitmap: ImageBitmap, + onClick: () -> Unit, + contentDescription: String? = null, + tinted: Boolean = true + ) : this({ bitmap }, { contentDescription }, tinted, onClick) + + override val enabled: Boolean? + @Composable + get() = extraParameters.enabled + + override val tint: Color? + @Composable + get() = extraParameters.tint +} diff --git a/core/src/main/java/com/orange/ouds/core/component/OudsInlineAlert.kt b/core/src/main/java/com/orange/ouds/core/component/OudsInlineAlert.kt index 82627a0764..441cbf9190 100644 --- a/core/src/main/java/com/orange/ouds/core/component/OudsInlineAlert.kt +++ b/core/src/main/java/com/orange/ouds/core/component/OudsInlineAlert.kt @@ -79,10 +79,7 @@ fun OudsInlineAlert( ) { status.icon.Content( modifier = Modifier.iconSize(sizeIcon.value * scale, status.icon.tinted), - extraParameters = OudsAlertIcon.ExtraParameters( - tint = status.assetColor, - status = status.value - ) + extraParameters = OudsIcon.ExtraParameters(tint = status.assetColor) ) Text( modifier = Modifier.widthIn(max = OudsTheme.sizes.maxWidth.label.large), @@ -103,7 +100,7 @@ object OudsInlineAlertDefaults { /** * Default status of an [OudsInlineAlert]. */ - val Status: OudsInlineAlertStatus = OudsInlineAlertStatus.Neutral(OudsAlertIcon.Default) + val Status: OudsInlineAlertStatus = OudsInlineAlertStatus.Neutral(OudsIcon.Default) } /** @@ -114,7 +111,9 @@ object OudsInlineAlertDefaults { * @property value The [OudsAlertStatus] associated with this status. * @property icon The [OudsAlertIcon] to be displayed in the inline alert. */ -sealed class OudsInlineAlertStatus(internal val value: OudsAlertStatus, val icon: OudsAlertIcon) { +sealed class OudsInlineAlertStatus(internal val value: OudsAlertStatus, icon: OudsIcon? = null) { + + val icon: OudsIcon = icon ?: value.defaultIcon /** * Neutral status can be used for generic informational messages that provide context but carry no semantic meaning. @@ -122,10 +121,17 @@ sealed class OudsInlineAlertStatus(internal val value: OudsAlertStatus, val icon * * @property icon The [OudsAlertIcon] to be displayed in the inline alert. */ - class Neutral(icon: OudsAlertIcon) : OudsInlineAlertStatus( + class Neutral(icon: OudsIcon?) : OudsInlineAlertStatus( OudsAlertStatus.Neutral({ painterResource(OudsTheme.drawableResources.functional.socialAndEngagement.heartRecommend) }), icon - ) + ) { + + @Suppress("DEPRECATION") + @Deprecated("") + constructor(icon: OudsAlertIcon) : this(icon = icon.toIcon()) + + constructor(icon: OudsIcon.Default) : this(icon = null) + } /** * Accent status uses brand colours and can include decorative icons to draw attention to key marketing or communication content. @@ -133,34 +139,41 @@ sealed class OudsInlineAlertStatus(internal val value: OudsAlertStatus, val icon * * @property icon The [OudsAlertIcon] to be displayed in the inline alert. */ - class Accent(icon: OudsAlertIcon) : OudsInlineAlertStatus( + class Accent(icon: OudsIcon?) : OudsInlineAlertStatus( OudsAlertStatus.Accent({ painterResource(OudsTheme.drawableResources.functional.socialAndEngagement.heartRecommend) }), icon - ) + ) { + + @Suppress("DEPRECATION") + @Deprecated("") + constructor(icon: OudsAlertIcon) : this(icon = icon.toIcon()) + + constructor(icon: OudsIcon.Default) : this(icon = null) + } /** * Negative status indicates a failure, error, or blocking issue that needs user attention. * It uses the red “error” color and includes the standardized error icon. */ - object Negative : OudsInlineAlertStatus(OudsAlertStatus.Negative(), OudsAlertIcon.Default) + object Negative : OudsInlineAlertStatus(OudsAlertStatus.Negative()) /** * Positive status confirms that an action was completed successfully. * It uses a green color and the standard success icon. */ - object Positive : OudsInlineAlertStatus(OudsAlertStatus.Positive(), OudsAlertIcon.Default) + object Positive : OudsInlineAlertStatus(OudsAlertStatus.Positive()) /** * Info status provides neutral information or updates about the system or account status. * It uses blue for neutrality and clarity, and a dedicated default icon. */ - object Info : OudsInlineAlertStatus(OudsAlertStatus.Info(), OudsAlertIcon.Default) + object Info : OudsInlineAlertStatus(OudsAlertStatus.Info()) /** * Warning status draws attention to potential issues or upcoming changes. * It uses yellow to signal caution while remaining non-blocking and a dedicated default icon. */ - object Warning : OudsInlineAlertStatus(OudsAlertStatus.Warning(), OudsAlertIcon.Default) + object Warning : OudsInlineAlertStatus(OudsAlertStatus.Warning()) val assetColor @Composable @@ -206,7 +219,7 @@ internal fun PreviewOudsInlineAlert( ).map { it.simpleName.orEmpty() }, maxItemsInEachRow = 1 ) { item -> - val icon = OudsAlertIcon(Icons.Outlined.FavoriteBorder) + val icon = OudsIcon(Icons.Outlined.FavoriteBorder) val status = when (item) { OudsInlineAlertStatus.Neutral::class.simpleName -> OudsInlineAlertStatus.Neutral(icon) OudsInlineAlertStatus.Accent::class.simpleName -> OudsInlineAlertStatus.Accent(icon) @@ -239,7 +252,7 @@ internal fun PreviewOudsInlineAlertWithUntintedIcon(theme: OudsThemeContract) = ).map { it.simpleName.orEmpty() }, maxItemsInEachRow = 1 ) { item -> - val icon = OudsAlertIcon(rememberRainbowHeartPainter(), tinted = false) + val icon = OudsIcon(painter = rememberRainbowHeartPainter(), tinted = false) val status = when (item) { OudsInlineAlertStatus.Neutral::class.simpleName -> OudsInlineAlertStatus.Neutral(icon) OudsInlineAlertStatus.Accent::class.simpleName -> OudsInlineAlertStatus.Accent(icon) diff --git a/core/src/main/java/com/orange/ouds/core/component/OudsLink.kt b/core/src/main/java/com/orange/ouds/core/component/OudsLink.kt index 80f1436aef..d991321724 100644 --- a/core/src/main/java/com/orange/ouds/core/component/OudsLink.kt +++ b/core/src/main/java/com/orange/ouds/core/component/OudsLink.kt @@ -174,7 +174,7 @@ fun OudsLink( @Composable fun OudsLink( label: String, - icon: OudsLinkIcon, + icon: OudsIcon, onClick: () -> Unit, modifier: Modifier = Modifier, size: OudsLinkSize = OudsLinkDefaults.Size, @@ -193,6 +193,54 @@ fun OudsLink( ) } +/** + * Link is a UI element that allows to navigate from one location to another, either within the same page + * or across different pages in the same resource, or to an external resource. Link's primary function is navigation + * and it communicates its interactive nature visually and semantically. + * + * Note that if it is placed in an [OudsColoredBox], its monochrome variant is automatically displayed. + * The tokens associated with this variant can be customized by overriding [OudsLinkMonoTokens]. + * + * > Design guidelines: [unified-design-system.orange.com](https://r.orange.fr/r/S-ouds-doc-link) + * + * > Design name: Link + * + * > Design version: 2.4.0 + * + * @param label Label describing what is being linked to. + * @param icon Icon displayed in the link that can be used to indicate the destination or type of content being referenced. + * @param onClick Callback invoked when the link is clicked. + * @param modifier [Modifier] applied to the link. + * @param size Size of the link. See [OudsLinkSize] for available sizes. + * @param enabled Controls the enabled state of the link. When `false`, the link will not be clickable. + * @param density Density of the link. See [OudsLinkDensity] for available densities. + * + * @sample com.orange.ouds.core.component.samples.OudsLinkWithIconSample + * + * @sample com.orange.ouds.core.component.samples.OudsLinkWithUntintedIconSample + */ +@Deprecated("") +@Composable +fun OudsLink( + label: String, + @Suppress("DEPRECATION") icon: OudsLinkIcon, + onClick: () -> Unit, + modifier: Modifier = Modifier, + size: OudsLinkSize = OudsLinkDefaults.Size, + enabled: Boolean = true, + density: OudsLinkDensity = OudsLinkDefaults.Density +) { + OudsLink( + label = label, + icon = icon.toIcon(), + onClick = onClick, + modifier = modifier, + size = size, + enabled = enabled, + density = density + ) +} + /** * Link is a UI element that allows to navigate from one location to another, either within the same page * or across different pages in the same resource, or to an external resource. Link's primary function is navigation @@ -225,7 +273,7 @@ fun OudsLink( @Composable fun OudsLink( label: String, - icon: OudsLinkIcon, + @Suppress("DEPRECATION") icon: OudsLinkIcon, onClick: () -> Unit, modifier: Modifier = Modifier, size: OudsLinkSize = OudsLinkDefaults.Size, @@ -233,8 +281,7 @@ fun OudsLink( ) { OudsLink( label = label, - icon = icon, - indicator = null, + icon = icon.toIcon(), onClick = onClick, modifier = modifier, size = size, @@ -316,8 +363,7 @@ fun OudsLink( * @sample com.orange.ouds.core.component.samples.OudsLinkWithIndicatorSample */ @Deprecated( - message = "Use overload with indicator parameter instead. Replace OudsLinkChevron.Back with OudsLinkIndicator.Previous, or OudsLinkChevron.Next with OudsLinkIndicator.Next.", - level = DeprecationLevel.WARNING + message = "Use overload with indicator parameter instead. Replace OudsLinkChevron.Back with OudsLinkIndicator.Previous, or OudsLinkChevron.Next with OudsLinkIndicator.Next." ) @Composable fun OudsLink( @@ -342,7 +388,7 @@ fun OudsLink( @Composable private fun OudsLink( label: String, - icon: OudsLinkIcon?, + icon: OudsIcon?, indicator: OudsLinkIndicator?, onClick: () -> Unit, modifier: Modifier = Modifier, @@ -447,7 +493,7 @@ private fun OudsLink( } @Composable -private fun LinkIcon(icon: OudsLinkIcon?, indicator: OudsLinkIndicator?, size: OudsLinkSize, tint: Color) { +private fun LinkIcon(icon: OudsIcon?, indicator: OudsLinkIndicator?, size: OudsLinkSize, tint: Color) { with(OudsTheme.components.link) { val iconSize = size.getTokenValue(default = this.size.iconDefault, small = this.size.iconSmall) val linkIcon = when { @@ -460,13 +506,13 @@ private fun LinkIcon(icon: OudsLinkIcon?, indicator: OudsLinkIndicator?, size: O OudsLinkIndicator.External -> externalLink } } - OudsLinkIcon(painterResource(indicatorPainterResId)) + OudsIcon(painterResource(indicatorPainterResId)) } else -> null } linkIcon?.Content( modifier = Modifier.iconSize(iconSize, icon?.tinted.orElse { true }), - extraParameters = OudsLinkIcon.ExtraParameters(tint = tint) + extraParameters = OudsIcon.ExtraParameters(tint = tint) ) } } @@ -571,8 +617,7 @@ enum class OudsLinkSize { */ @Deprecated( message = "OudsLinkChevron has been replaced with OudsLinkIndicator.", - replaceWith = ReplaceWith("OudsLinkIndicator"), - level = DeprecationLevel.WARNING + replaceWith = ReplaceWith("OudsLinkIndicator") ) enum class OudsLinkChevron { @@ -640,11 +685,14 @@ enum class OudsLinkDensity { * An icon in an [OudsLink]. * This icon is non-clickable and no content description is needed because a link label is always present. */ +@Suppress("DEPRECATION") +@Deprecated("") open class OudsLinkIcon private constructor( graphicsObject: Any, override val tinted: Boolean ) : OudsComponentIcon(ExtraParameters::class.java, graphicsObject, "") { + @Deprecated("") @ConsistentCopyVisibility data class ExtraParameters internal constructor( internal val tint: Color @@ -706,7 +754,7 @@ internal fun PreviewOudsLink( parameter: OudsLinkPreviewParameter ) = OudsPreview(theme = theme, darkThemeEnabled = darkThemeEnabled) { with(parameter) { - val icon = if (hasIcon) OudsLinkIcon(Icons.Filled.FavoriteBorder) else null + val icon = if (hasIcon) OudsIcon(Icons.Filled.FavoriteBorder) else null val linkPreview: @Composable () -> Unit = { PreviewEnumEntries(maxEnumEntriesInEachRow = 3) { OudsLink( @@ -781,7 +829,7 @@ internal fun PreviewOudsLinkWithUntintedIcon(theme: OudsThemeContract) = OudsPre PreviewEnumEntries(maxEnumEntriesInEachRow = 3) { OudsLink( label = "Label", - icon = OudsLinkIcon(painter = rememberRainbowHeartPainter(), tinted = false), + icon = OudsIcon(painter = rememberRainbowHeartPainter(), tinted = false), onClick = {} ) } diff --git a/core/src/main/java/com/orange/ouds/core/component/OudsListItem.kt b/core/src/main/java/com/orange/ouds/core/component/OudsListItem.kt index 788b899db5..716c57087f 100644 --- a/core/src/main/java/com/orange/ouds/core/component/OudsListItem.kt +++ b/core/src/main/java/com/orange/ouds/core/component/OudsListItem.kt @@ -838,7 +838,6 @@ open class OudsListItemIcon internal constructor( internal val size: OudsListItemAssetSize, internal val status: OudsListItemIconStatus? ) : OudsComponentIcon( - OudsListItemLeadingTrailing.Icon.ExtraParameters::class.java, graphicsObjectProvider, contentDescriptionProvider ), OudsListItemLeadingTrailing.Icon { @@ -863,7 +862,7 @@ open class OudsListItemImage internal constructor( override val ratio: OudsListItemImageRatio, contentScale: ContentScale, internal val roundedCorner: Boolean -) : OudsComponentImage(Nothing::class.java, graphicsObject, contentDescription, contentScale = contentScale), OudsListItemLeadingTrailing.Image { +) : OudsComponentImage(graphicsObject, contentDescription, contentScale = contentScale), OudsListItemLeadingTrailing.Image { @Composable override fun Content(modifier: Modifier) { @@ -881,8 +880,7 @@ open class OudsListItemText internal constructor( private val label: String, private val style: OudsListItemTextStyle, private val extraLabel: String? -) : OudsComponentContent(OudsListItemLeadingTrailing.Text.ExtraParameters::class.java), - OudsListItemLeadingTrailing.Text { +) : OudsComponentContent(), OudsListItemLeadingTrailing.Text { @Composable override fun Content(modifier: Modifier) { diff --git a/core/src/main/java/com/orange/ouds/core/component/OudsLoader.kt b/core/src/main/java/com/orange/ouds/core/component/OudsLoader.kt new file mode 100644 index 0000000000..2741db8ca7 --- /dev/null +++ b/core/src/main/java/com/orange/ouds/core/component/OudsLoader.kt @@ -0,0 +1,22 @@ +/* + * 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.core.component + +/** + * A circular progress indicator displayed in an OUDS component. + * + * @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. + */ +class OudsLoader(val progress: Float?) diff --git a/core/src/main/java/com/orange/ouds/core/component/OudsNavigationBar.kt b/core/src/main/java/com/orange/ouds/core/component/OudsNavigationBar.kt index 156df212f3..7d31fcc526 100644 --- a/core/src/main/java/com/orange/ouds/core/component/OudsNavigationBar.kt +++ b/core/src/main/java/com/orange/ouds/core/component/OudsNavigationBar.kt @@ -205,11 +205,21 @@ fun OudsNavigationBar( data class OudsNavigationBarItem( val selected: Boolean, val onClick: () -> Unit, - val icon: OudsNavigationBarItemIcon, + val icon: OudsIcon, val label: String? = null, val badge: OudsNavigationBarItemBadge? = null, val interactionSource: MutableInteractionSource? = null -) : OudsComponentContent(ExtraParameters::class.java) { +) : OudsComponentContent() { + + @Deprecated("") + constructor( + selected: Boolean, + onClick: () -> Unit, + @Suppress("DEPRECATION") icon: OudsNavigationBarItemIcon, + label: String? = null, + badge: OudsNavigationBarItemBadge? = null, + interactionSource: MutableInteractionSource? = null + ) : this(selected, onClick, icon.toIcon(), label, badge, interactionSource) @ConsistentCopyVisibility data class ExtraParameters internal constructor( @@ -228,55 +238,56 @@ data class OudsNavigationBarItem( } val iconPosition = if (windowWidthSizeClass != WindowWidthSizeClass.MEDIUM) NavigationItemIconPosition.Top else NavigationItemIconPosition.Start - with(OudsTheme.componentsTokens.bar) { - val selectedContentColor = contentColor(state = state, selected = true) - val unselectedContentColor = contentColor(state = state, selected = false) - - CompositionLocalProvider(LocalRippleConfiguration provides null) { - ShortNavigationBarItem( - modifier = modifier - .fillMaxHeight() - .indicator(state = state, selected = selected, iconPosition = iconPosition) - .semantics { - contentDescription = badge?.contentDescription.orEmpty() - } - .componentContentTestTag(), - selected = selected, - onClick = onClick, - icon = { - if (badge != null) { - OudsBadgedIcon( - modifier = Modifier.size(OudsNavigationBarItemIcon.Size), - badgeCount = badge.count, - badgeBorderColor = OudsTheme.componentsTokens.bar.colorBorderBadge.value - ) { - icon.Content() - } - } else { - icon.Content() - } - }, - iconPosition = iconPosition, - label = label?.let { - { - Text( - text = it, - maxLines = 1, - overflow = TextOverflow.Ellipsis, - style = OudsTheme.typography.label.small.moderate - ) + val selectedContentColor = contentColor(state = state, selected = true) + val unselectedContentColor = contentColor(state = state, selected = false) + + CompositionLocalProvider(LocalRippleConfiguration provides null) { + ShortNavigationBarItem( + modifier = modifier + .fillMaxHeight() + .indicator(state = state, selected = selected, iconPosition = iconPosition) + .semantics { + contentDescription = badge?.contentDescription.orEmpty() + } + .componentContentTestTag(), + selected = selected, + onClick = onClick, + icon = { + val iconContent: @Composable () -> Unit = { + icon.Content(modifier = Modifier.size(OudsNavigationBarItemIconSize)) + } + if (badge != null) { + OudsBadgedIcon( + modifier = Modifier.size(OudsNavigationBarItemIconSize), + badgeCount = badge.count, + badgeBorderColor = OudsTheme.componentsTokens.bar.colorBorderBadge.value + ) { + iconContent() } - }, - colors = ShortNavigationBarItemDefaults.colors( - selectedIconColor = selectedContentColor, - selectedTextColor = selectedContentColor, - selectedIndicatorColor = materialIndicatorColor(state = state, selected = selected), - unselectedIconColor = unselectedContentColor, - unselectedTextColor = unselectedContentColor, - ), - interactionSource = interactionSource - ) - } + } else { + iconContent() + } + }, + iconPosition = iconPosition, + label = label?.let { + { + Text( + text = it, + maxLines = 1, + overflow = TextOverflow.Ellipsis, + style = OudsTheme.typography.label.small.moderate + ) + } + }, + colors = ShortNavigationBarItemDefaults.colors( + selectedIconColor = selectedContentColor, + selectedTextColor = selectedContentColor, + selectedIndicatorColor = materialIndicatorColor(state = state, selected = selected), + unselectedIconColor = unselectedContentColor, + unselectedTextColor = unselectedContentColor, + ), + interactionSource = interactionSource + ) } } } @@ -392,9 +403,13 @@ private fun topIndicatorColor(state: OudsNavigationBarItemState): Color { } } +internal val OudsNavigationBarItemIconSize = 24.dp + /** * An icon in an [OudsNavigationBarItem]. */ +@Suppress("DEPRECATION") +@Deprecated("") class OudsNavigationBarItemIcon private constructor( graphicsObject: Any, ) : OudsComponentIcon(Nothing::class.java, graphicsObject, "") { @@ -552,7 +567,7 @@ internal fun PreviewOudsNavigationBar( OudsNavigationBarItem( selected = index == 0, onClick = {}, - icon = OudsNavigationBarItemIcon(imageVector = item.imageVector), + icon = OudsIcon(imageVector = item.imageVector), label = item.label, badge = item.badge ) @@ -573,7 +588,7 @@ internal fun PreviewOudsNavigationBarItem( val item = OudsNavigationBarItem( selected = selected, onClick = {}, - icon = OudsNavigationBarItemIcon(imageVector = Icons.Default.Star), + icon = OudsIcon(imageVector = Icons.Default.Star), label = "Label" ) PreviewEnumEntries { diff --git a/core/src/main/java/com/orange/ouds/core/component/OudsNavigationButton.kt b/core/src/main/java/com/orange/ouds/core/component/OudsNavigationButton.kt index cef3d49c4e..f0752bec42 100644 --- a/core/src/main/java/com/orange/ouds/core/component/OudsNavigationButton.kt +++ b/core/src/main/java/com/orange/ouds/core/component/OudsNavigationButton.kt @@ -44,7 +44,7 @@ import com.orange.ouds.theme.OudsThemeContract * * @param onClick Callback invoked when the button is clicked. * @param modifier [Modifier] applied to the button. - * @param chevron Chevron of the navigation button. See [OudsNavigationButtonChevron] for allowed values. + * @param indicator Indicator of the navigation button. See [OudsNavigationButtonIndicator] for allowed values. * @param label Label displayed in the button describing the navigation action. This makes the action more explicit and accessible especially for new users * or in contexts where clarity is critical. * @param enabled Controls the enabled state of the button when there is no [loader]. @@ -63,28 +63,25 @@ import com.orange.ouds.theme.OudsThemeContract fun OudsNavigationButton( onClick: () -> Unit, modifier: Modifier = Modifier, - chevron: OudsNavigationButtonChevron = OudsNavigationButtonDefaults.Chevron, + indicator: OudsNavigationButtonIndicator = OudsNavigationButtonDefaults.Indicator, label: String? = null, enabled: Boolean = true, - loader: OudsButtonLoader? = null, + loader: OudsLoader? = null, appearance: OudsNavigationButtonAppearance = OudsNavigationButtonDefaults.Appearance, interactionSource: MutableInteractionSource? = null ) { val drawableResources = LocalDrawableResources.current - val iconResource = when (chevron) { - OudsNavigationButtonChevron.Next -> drawableResources.component.button.next - OudsNavigationButtonChevron.Previous -> drawableResources.component.button.previous + val iconResource = when (indicator) { + OudsNavigationButtonIndicator.Next -> drawableResources.component.button.next + OudsNavigationButtonIndicator.Previous -> drawableResources.component.button.previous } OudsButton( - nullableIcon = OudsButtonIcon( - painter = painterResource(iconResource), - contentDescription = "" // Not necessary because a label is present - ), + nullableIcon = OudsIcon(painter = painterResource(iconResource)), nullableLabel = label, onClick = onClick, modifier = modifier, - component = OudsButtonComponent.NavigationButton(chevron), + component = OudsButtonComponent.NavigationButton(indicator), enabled = enabled, loader = loader, appearance = appearance.toButtonAppearance(), @@ -92,6 +89,62 @@ fun OudsNavigationButton( ) } +/** + * Navigation button is a UI element that allows to move between different pages within a multipage interface. + * Navigation button is typically arrange in sequence to indicate the user's current position and provide controls to access previous, next, or specific pages. + * + * Note that if it is placed in an [OudsColoredBox], its monochrome variant is automatically displayed. + * + * Rounded corners can be enabled or disabled using the [com.orange.ouds.theme.OudsThemeSettings.roundedCornerButtons] property in the settings of the theme provided + * when calling the [com.orange.ouds.core.theme.OudsTheme] method. + * + * > Design guidelines: [unified-design-system.orange.com](https://r.orange.fr/r/S-ouds-doc-navigation-button) + * + * > Design name: Navigation Button + * + * > Design version: 3.3.0 + * + * @param onClick Callback invoked when the button is clicked. + * @param modifier [Modifier] applied to the button. + * @param chevron Chevron of the navigation button. See [OudsNavigationButtonChevron] for allowed values. + * @param label Label displayed in the button describing the navigation action. This makes the action more explicit and accessible especially for new users + * or in contexts where clarity is critical. + * @param enabled Controls the enabled state of the button when there is no [loader]. + * When `false`, this button will not be clickable. + * Has no effect if [loader] is provided. + * @param loader An optional loading progress indicator displayed in the button to indicate an ongoing operation. + * @param appearance Appearance of the button among [OudsNavigationButtonAppearance] values. + * A button with [OudsNavigationButtonAppearance.Brand] is not allowed as a direct or indirect child of an [OudsColoredBox] and will throw an [IllegalStateException]. + * @param interactionSource An optional hoisted [MutableInteractionSource] for observing and emitting interactions for this button. Note that if `null` + * is provided, interactions will still happen internally. + * + * @sample com.orange.ouds.core.component.samples.OudsNavigationButtonTextAndIconSample + * @sample com.orange.ouds.core.component.samples.OudsNavigationButtonIconOnlySample + */ +@Deprecated("") +@Composable +fun OudsNavigationButton( + onClick: () -> Unit, + modifier: Modifier = Modifier, + @Suppress("DEPRECATION") chevron: OudsNavigationButtonChevron = OudsNavigationButtonDefaults.Chevron, + label: String? = null, + enabled: Boolean = true, + @Suppress("DEPRECATION") loader: OudsButtonLoader?, + appearance: OudsNavigationButtonAppearance = OudsNavigationButtonDefaults.Appearance, + interactionSource: MutableInteractionSource? = null +) { + OudsNavigationButton( + onClick = onClick, + modifier = modifier, + indicator = chevron.toIndicator(), + label = label, + enabled = enabled, + loader = loader?.toLoader(), + appearance = appearance, + interactionSource = interactionSource + ) +} + /** * Default values for [OudsNavigationButton]. */ @@ -105,21 +158,56 @@ object OudsNavigationButtonDefaults { /** * Default chevron of an [OudsNavigationButton]. */ + @Suppress("DEPRECATION") + @Deprecated("Use OudsNavigationButtonDefaults.Indicator instead.") val Chevron = OudsNavigationButtonChevron.Next + + /** + * Default indicator of an [OudsNavigationButton]. + */ + val Indicator = OudsNavigationButtonIndicator.Next } /** * Represents the chevron of an [OudsNavigationButton]. Its position in the button changes depending on its value. */ +@Deprecated( + message = "OudsNavigationButtonChevron has been replaced with OudsNavigationButtonIndicator.", + replaceWith = ReplaceWith("OudsNavigationButtonIndicator") +) enum class OudsNavigationButtonChevron { /** * The Next chevron button is used to move the user forward in a sequence of content, steps or pages. */ + @Deprecated(message = "Use OudsNavigationButtonIndicator.Next instead.") Next, /** * The Previous chevron button allows the user to return to the prior step, page, or section. */ + @Deprecated(message = "Use OudsNavigationButtonIndicator.Previous instead.") + Previous; + + @Suppress("DEPRECATION") + internal fun toIndicator(): OudsNavigationButtonIndicator = when (this) { + Previous -> OudsNavigationButtonIndicator.Previous + Next -> OudsNavigationButtonIndicator.Next + } +} + +/** + * Represents the type of navigation indicator displayed in an [OudsNavigationButton]. + */ +enum class OudsNavigationButtonIndicator { + + /** + * The Previous indicator button allows the user to return to the prior step, page, or section. + */ + Next, + + /** + * The Next indicator button is used to move the user forward in a sequence of content, steps or pages. + */ Previous } @@ -186,14 +274,14 @@ internal fun PreviewOudsNavigationButton( PreviewEnumEntries(maxEnumEntriesInEachRow = 2) { if (hasLabel) { OudsNavigationButton( - label = chevron.name, - chevron = chevron, + label = indicator.name, + indicator = indicator, onClick = {}, appearance = appearance ) } else { OudsNavigationButton( - chevron = chevron, + indicator = indicator, onClick = {}, appearance = appearance ) @@ -238,14 +326,14 @@ private fun PreviewOudsNavigationButtonOnTwoLines() = PreviewOudsNavigationButto internal fun PreviewOudsNavigationButtonOnTwoLines(theme: OudsThemeContract) = OudsPreview(theme = theme) { OudsNavigationButton( label = "Navigation button\non two lines", - chevron = OudsNavigationButtonChevron.Next, + indicator = OudsNavigationButtonIndicator.Next, onClick = {}, ) } internal data class OudsNavigationButtonPreviewParameter( val appearance: OudsNavigationButtonAppearance, - val chevron: OudsNavigationButtonChevron, + val indicator: OudsNavigationButtonIndicator, val hasLabel: Boolean, val onColoredBox: Boolean = false ) @@ -256,10 +344,10 @@ internal class OudsNavigationButtonPreviewParameterProvider : private val previewParameterValues: List get() = buildList { OudsNavigationButtonAppearance.entries.forEach { appearance -> - OudsNavigationButtonChevron.entries.forEach { chevron -> + OudsNavigationButtonIndicator.entries.forEach { indicator -> val parameters = listOf( - OudsNavigationButtonPreviewParameter(appearance, chevron, hasLabel = true), - OudsNavigationButtonPreviewParameter(appearance, chevron, hasLabel = false), + OudsNavigationButtonPreviewParameter(appearance, indicator, hasLabel = true), + OudsNavigationButtonPreviewParameter(appearance, indicator, hasLabel = false), ) addAll(parameters) addAll(parameters.map { it.copy(onColoredBox = true) }) diff --git a/core/src/main/java/com/orange/ouds/core/component/OudsPasswordInput.kt b/core/src/main/java/com/orange/ouds/core/component/OudsPasswordInput.kt index 3fe02dcbc3..aa41a9d3cb 100644 --- a/core/src/main/java/com/orange/ouds/core/component/OudsPasswordInput.kt +++ b/core/src/main/java/com/orange/ouds/core/component/OudsPasswordInput.kt @@ -114,7 +114,7 @@ fun OudsPasswordInput( prefix: String? = null, enabled: Boolean = true, readOnly: Boolean = false, - loader: OudsTextInputLoader? = null, + loader: OudsLoader? = null, outlined: Boolean = false, error: OudsError? = null, helperText: String? = null, @@ -148,6 +148,103 @@ fun OudsPasswordInput( ) } +/** + * Password input is a UI element that allows to securely and confidentially capture a user's password. + * Password Input enhances privacy by replacing characters with dots, while they are being typed; and also embeds usability features such as the ability + * to show and hide password, and helper text to guide password creation. + * + * Rounded corners can be enabled or disabled using [OudsThemeSettings.roundedCornerTextInputs] property in the settings of the theme provided when calling + * the [com.orange.ouds.core.theme.OudsTheme] method. + * + * An overload accepting annotated types is available for rich text formatting. + * + * > Design guidelines: [unified-design-system.orange.com](https://r.orange.fr/r/S-ouds-doc-password-input) + * + * > Design name: Password Input + * + * > Design version: 1.3.1 + * + * @param state The editable text state of the password input, including the text itself, position of the cursor or selection and the text obfuscation mode. + * @param modifier [Modifier] applied to the password input. + * @param label Label displayed above the password input. It describes the purpose of the input. + * @param placeholder Text displayed when the password input is empty. It provides a hint or guidance inside the field to suggest expected input. + * @param lockIcon When `true`, a lock icon is displayed at the start of the password input to visually reinforce the security context. Defaults to `false`. + * @param prefix Text placed before the user's input. A prefix is not common and is discouraged in a Password Input component. In very specific cases, + * it can provide context or format requirements (e.g., “DEV-” for test accounts, "admin-" as a pattern to define an admin password) + * @param enabled Controls the enabled state of the password input. When `false`, this password input will not be focusable and will not react to input events. + * True by default. + * @param readOnly Controls the read-only state of the password input. When `true`, the text is visible but not editable. + * False by default. + * @param loader An optional loading progress indicator displayed in the password input to indicate an ongoing operation. + * @param outlined Controls the style of the password input. When `true`, it displays a minimalist password input with a transparent background and a visible + * stroke outlining the field. + * @param error Optional [OudsError] to indicate that the user input does not meet validation rules or expected formatting. Pass `null` if there is no error. + * @param helperText An optional helper text displayed below the password input. It conveys additional information about the input field, such as how it will be + * used. It should ideally only take up a single line, though it may wrap to multiple lines if required. + * @param constrainedMaxWidth When `true`, the password input width is constrained to a maximum value defined by the design system. + * When `false`, no specific width constraint is applied, allowing the component to size itself or follow external modifiers. + * Defaults to `false`. + * @param inputTransformation An optional [InputTransformation] that will be used to transform changes to the [OudsPasswordInputState] made by the user. The transformation + * will be applied to changes made by hardware and software keyboard events, pasting or dropping text, accessibility services, and tests. The transformation + * will _not_ be applied when changing the [state] programmatically, or when the transformation is changed. If the transformation is changed on an + * existing text field, it will be applied to the next user edit. The transformation will not immediately affect the current [state]. + * @param keyboardOptions Software keyboard options that contain configurations such as [KeyboardType] and [ImeAction]. + * @param onKeyboardAction Called when the user presses the action button in the input method editor (IME), or by pressing the enter key on a hardware keyboard. + * By default this parameter is null, and would execute the default behavior for a received IME Action e.g., [ImeAction.Done] would close the keyboard, + * [ImeAction.Next] would switch the focus to the next focusable item on the screen. + * @param onTextLayout Callback that is executed when a new text layout is calculated. A [TextLayoutResult] object that callback provides contains paragraph + * information, size of the text, baselines and other details. The callback can be used to add additional decoration or functionality to the text. + * For example, to draw a cursor or selection around the text. + * @param interactionSource An optional hoisted [MutableInteractionSource] for observing and emitting [Interaction]s for this password input. Note that if `null` + * is provided, interactions will still happen internally. + * + * @sample com.orange.ouds.core.component.samples.OudsPasswordInputSample + * @sample com.orange.ouds.core.component.samples.OudsPasswordInputErrorSample + */ +@Deprecated("") +@Composable +fun OudsPasswordInput( + state: OudsPasswordInputState, + modifier: Modifier = Modifier, + label: String? = null, + placeholder: String? = null, + lockIcon: Boolean = false, + prefix: String? = null, + enabled: Boolean = true, + readOnly: Boolean = false, + @Suppress("DEPRECATION") loader: OudsTextInputLoader?, + outlined: Boolean = false, + error: OudsError? = null, + helperText: String? = null, + constrainedMaxWidth: Boolean = false, + inputTransformation: InputTransformation? = null, + keyboardOptions: KeyboardOptions = OudsPasswordInputDefaults.KeyboardOptions, + onKeyboardAction: KeyboardActionHandler? = null, + onTextLayout: (Density.(getResult: () -> TextLayoutResult?) -> Unit)? = null, + interactionSource: MutableInteractionSource? = null +) { + OudsPasswordInput( + state = state, + modifier = modifier, + label = label, + placeholder = placeholder, + lockIcon = lockIcon, + prefix = prefix, + enabled = enabled, + readOnly = readOnly, + loader = loader?.toLoader(), + outlined = outlined, + error = error, + helperText = helperText, + constrainedMaxWidth = constrainedMaxWidth, + inputTransformation = inputTransformation, + keyboardOptions = keyboardOptions, + onKeyboardAction = onKeyboardAction, + onTextLayout = onTextLayout, + interactionSource = interactionSource + ) +} + /** * Password input is a UI element that allows to securely and confidentially capture a user's password. * Password Input enhances privacy by replacing characters with dots, while they are being typed; and also embeds usability features such as the ability @@ -212,7 +309,7 @@ fun OudsPasswordInput( prefix: String? = null, enabled: Boolean = true, readOnly: Boolean = false, - loader: OudsTextInputLoader? = null, + loader: OudsLoader? = null, outlined: Boolean = false, error: OudsError? = null, helperText: OudsAnnotatedHelperText, @@ -246,6 +343,104 @@ fun OudsPasswordInput( ) } +/** + * Password input is a UI element that allows to securely and confidentially capture a user's password. + * Password Input enhances privacy by replacing characters with dots, while they are being typed; and also embeds usability features such as the ability + * to show and hide password, and helper text to guide password creation. + * + * Rounded corners can be enabled or disabled using [OudsThemeSettings.roundedCornerTextInputs] property in the settings of the theme provided when calling + * the [com.orange.ouds.core.theme.OudsTheme] method. + * + * An overload accepting plain types is available for simple text without formatting. + * + * > Design guidelines: [unified-design-system.orange.com](https://r.orange.fr/r/S-ouds-doc-password-input) + * + * > Design name: Password Input + * + * > Design version: 1.3.1 + * + * @param state The editable text state of the password input, including the text itself, position of the cursor or selection and the text obfuscation mode. + * @param modifier [Modifier] applied to the password input. + * @param label Label displayed above the password input. It describes the purpose of the input. + * @param placeholder Text displayed when the password input is empty. It provides a hint or guidance inside the field to suggest expected input. + * @param lockIcon When `true`, a lock icon is displayed at the start of the password input to visually reinforce the security context. Defaults to `false`. + * @param prefix Text placed before the user's input. A prefix is not common and is discouraged in a Password Input component. In very specific cases, + * it can provide context or format requirements (e.g., “DEV-” for test accounts, "admin-" as a pattern to define an admin password) + * @param enabled Controls the enabled state of the password input. When `false`, this password input will not be focusable and will not react to input events. + * True by default. + * @param readOnly Controls the read-only state of the password input. When `true`, the text is visible but not editable. + * False by default. + * @param loader An optional loading progress indicator displayed in the password input to indicate an ongoing operation. + * @param outlined Controls the style of the password input. When `true`, it displays a minimalist password input with a transparent background and a visible + * stroke outlining the field. + * @param error Optional [OudsError] to indicate that the user input does not meet validation rules or expected formatting. Pass `null` if there is no error. + * @param helperText An annotated helper text displayed below the password input. It conveys additional information about the input field, such as how it will be + * used. It should ideally only take up a single line, though it may wrap to multiple lines if required. + * @param constrainedMaxWidth When `true`, the password input width is constrained to a maximum value defined by the design system. + * When `false`, no specific width constraint is applied, allowing the component to size itself or follow external modifiers. + * Defaults to `false`. + * @param inputTransformation An optional [InputTransformation] that will be used to transform changes to the [OudsPasswordInputState] made by the user. The transformation + * will be applied to changes made by hardware and software keyboard events, pasting or dropping text, accessibility services, and tests. The transformation + * will _not_ be applied when changing the [state] programmatically, or when the transformation is changed. If the transformation is changed on an + * existing text field, it will be applied to the next user edit. The transformation will not immediately affect the current [state]. + * @param keyboardOptions Software keyboard options that contain configurations such as [KeyboardType] and [ImeAction]. + * @param onKeyboardAction Called when the user presses the action button in the input method editor (IME), or by pressing the enter key on a hardware keyboard. + * By default this parameter is null, and would execute the default behavior for a received IME Action e.g., [ImeAction.Done] would close the keyboard, + * [ImeAction.Next] would switch the focus to the next focusable item on the screen. + * @param onTextLayout Callback that is executed when a new text layout is calculated. A [TextLayoutResult] object that callback provides contains paragraph + * information, size of the text, baselines and other details. The callback can be used to add additional decoration or functionality to the text. + * For example, to draw a cursor or selection around the text. + * @param interactionSource An optional hoisted [MutableInteractionSource] for observing and emitting [Interaction]s for this password input. Note that if `null` + * is provided, interactions will still happen internally. + * + * @sample com.orange.ouds.core.component.samples.OudsPasswordInputSample + * @sample com.orange.ouds.core.component.samples.OudsPasswordInputWithAnnotatedErrorMessageSample + * @sample com.orange.ouds.core.component.samples.OudsPasswordInputWithAnnotatedHelperTextSample + */ +@Deprecated("") +@Composable +fun OudsPasswordInput( + state: OudsPasswordInputState, + modifier: Modifier = Modifier, + label: String? = null, + placeholder: String? = null, + lockIcon: Boolean = false, + prefix: String? = null, + enabled: Boolean = true, + readOnly: Boolean = false, + @Suppress("DEPRECATION") loader: OudsTextInputLoader?, + outlined: Boolean = false, + error: OudsError? = null, + helperText: OudsAnnotatedHelperText, + constrainedMaxWidth: Boolean = false, + inputTransformation: InputTransformation? = null, + keyboardOptions: KeyboardOptions = OudsPasswordInputDefaults.KeyboardOptions, + onKeyboardAction: KeyboardActionHandler? = null, + onTextLayout: (Density.(getResult: () -> TextLayoutResult?) -> Unit)? = null, + interactionSource: MutableInteractionSource? = null +) { + OudsPasswordInput( + state = state, + modifier = modifier, + label = label, + placeholder = placeholder, + lockIcon = lockIcon, + prefix = prefix, + enabled = enabled, + readOnly = readOnly, + loader = loader?.toLoader(), + outlined = outlined, + error = error, + helperText = helperText, + constrainedMaxWidth = constrainedMaxWidth, + inputTransformation = inputTransformation, + keyboardOptions = keyboardOptions, + onKeyboardAction = onKeyboardAction, + onTextLayout = onTextLayout, + interactionSource = interactionSource + ) +} + @Composable private fun OudsPasswordInput( state: OudsPasswordInputState, @@ -256,7 +451,7 @@ private fun OudsPasswordInput( prefix: String? = null, enabled: Boolean = true, readOnly: Boolean = false, - loader: OudsTextInputLoader? = null, + loader: OudsLoader? = null, outlined: Boolean = false, error: OudsError? = null, helperText: String? = null, @@ -347,13 +542,10 @@ object OudsPasswordInputDefaults { } @Composable -private fun textInputLockIcon() = OudsTextInputLeadingIcon( - painter = painterResource(OudsTheme.drawableResources.communication.securityAndSafety.lockClosed), - contentDescription = "" -) +private fun textInputLockIcon() = OudsIcon(painter = painterResource(OudsTheme.drawableResources.communication.securityAndSafety.lockClosed)) @Composable -private fun trailingIconButton(isPasswordHidden: Boolean, onClick: () -> Unit): OudsTextInputTrailingIconButton { +private fun trailingIconButton(isPasswordHidden: Boolean, onClick: () -> Unit): OudsIconButton { val painterResId: Int val contentDescriptionResId: Int if (isPasswordHidden) { @@ -363,7 +555,7 @@ private fun trailingIconButton(isPasswordHidden: Boolean, onClick: () -> Unit): painterResId = OudsTheme.drawableResources.functional.settingsAndTools.accessibilityHide contentDescriptionResId = R.string.core_passwordInput_hidePassword_a11y } - return OudsTextInputTrailingIconButton( + return OudsIconButton( painter = painterResource(painterResId), contentDescription = stringResource(contentDescriptionResId), onClick = onClick @@ -475,6 +667,7 @@ private val previewParameterValues: List /** * @see OudsPasswordInput */ +@Suppress("DEPRECATION") @Composable @Deprecated( "Please use OudsPasswordInput composable instead, which is the equivalent of Material SecureTextField in OUDS Android.", diff --git a/core/src/main/java/com/orange/ouds/core/component/OudsRadioButtonItem.kt b/core/src/main/java/com/orange/ouds/core/component/OudsRadioButtonItem.kt index f7c64cb359..73cbafe041 100644 --- a/core/src/main/java/com/orange/ouds/core/component/OudsRadioButtonItem.kt +++ b/core/src/main/java/com/orange/ouds/core/component/OudsRadioButtonItem.kt @@ -100,7 +100,7 @@ fun OudsRadioButtonItem( modifier: Modifier = Modifier, extraLabel: String? = null, description: String? = null, - icon: OudsControlItemIcon? = null, + icon: OudsIcon? = null, edgeToEdge: Boolean = true, divider: Boolean = false, outlined: Boolean = false, @@ -162,6 +162,91 @@ fun OudsRadioButtonItem( ) } +/** + * Radio button item is a UI element that allows to select a single option from a set of mutually exclusive choices. + * Radio button item covers a wider range of contexts by allowing to toggle the visibility of additional text labels and icon assets. + * + * The **radio button item variant** can function as a simple input with a label in a selection group, or it can be combined with optional elements such as + * extra label, description, a divider, or an icon, allowing it to suit various use cases. + * + * The OUDS radio button item layout contains an [OudsRadioButton]. By clicking on the radio button item, the user changes the selected state of its radio button. + * + * > Design guidelines: [unified-design-system.orange.com](https://r.orange.fr/r/S-ouds-doc-radio-button) + * + * > Design name: Radio Button + * + * > Design version: 1.4.0 + * + * @see [OudsRadioButton] If you want to use a standalone radio button. + * + * @param selected Controls the selected state of the radio button. + * @param label The main label of the radio button item. + * @param onClick Callback invoked on radio button click. If `null`, then this radio button will not be interactable, unless something else handles its + * input events and updates its state. + * @param modifier [Modifier] applied to the layout of the radio button item. + * @param extraLabel Optional strong accompanying label for the main label. It is displayed between the [label] and the [description]. + * @param description Optional text displayed below the [label] and the [extraLabel]. + * @param icon Optional icon displayed in the item. By default, it has a trailing position. If [reversed] is set to `true`, it is displayed as a leading element. + * @param edgeToEdge Controls the horizontal layout of the item. When `true`, the item is designed to span the full width of the screen or container. When `false`, + * it is adapted for use within constrained layouts or containers with their own padding. Defaults to `true`. + * @param divider Controls the display of a divider at the bottom of the radio button item. + * @param outlined When set to `true`, the radio button item, if selected, is outlined to stand out and draw the user's attention. + * @param reversed When `false`, the radio button has a leading position and the optional [icon] has a trailing position. Otherwise, it is reversed. + * @param enabled Controls the enabled state of the radio button item. When `false`, the radio button, the texts and the optional icon are disabled, and the item + * will not be clickable. + * @param readOnly Controls the read-only state of the radio button item. When `true` the item's radio button is disabled but the texts and the icon remain in + * enabled color. Note that if it is set to `true` and [enabled] is set to `false`, the radio button item will be displayed in disabled state. + * @param error Optional [OudsError] to indicate that the radio button item should appear in error state, `null` otherwise. + * @param constrainedMaxWidth When `true`, the item width is constrained to a maximum value defined by the design system. + * When `false`, no specific width constraint is applied, allowing the component to size itself or follow external modifiers. + * Defaults to `false`. + * @param interactionSource Optional hoisted [MutableInteractionSource] for observing and emitting [Interaction]s for the item's radio button. Note that if `null` + * is provided, interactions will still happen internally. + * + * @sample com.orange.ouds.core.component.samples.OudsRadioButtonItemSample + * @sample com.orange.ouds.core.component.samples.OudsRadioButtonItemWithAnnotatedErrorMessageSample + * @sample com.orange.ouds.core.component.samples.OudsRadioButtonItemWithUntintedIconSample + */ +@Deprecated("") +@Composable +fun OudsRadioButtonItem( + selected: Boolean, + label: String, + onClick: (() -> Unit)?, + modifier: Modifier = Modifier, + extraLabel: String? = null, + description: String? = null, + @Suppress("DEPRECATION") icon: OudsControlItemIcon?, + edgeToEdge: Boolean = true, + divider: Boolean = false, + outlined: Boolean = false, + reversed: Boolean = false, + enabled: Boolean = true, + readOnly: Boolean = false, + error: OudsError? = null, + constrainedMaxWidth: Boolean = false, + interactionSource: MutableInteractionSource? = null +) { + OudsRadioButtonItem( + selected = selected, + label = label, + onClick = onClick, + modifier = modifier, + extraLabel = extraLabel, + description = description, + icon = icon?.toIcon(), + edgeToEdge = edgeToEdge, + divider = divider, + outlined = outlined, + reversed = reversed, + enabled = enabled, + readOnly = readOnly, + error = error, + constrainedMaxWidth = constrainedMaxWidth, + interactionSource = interactionSource + ) +} + @Composable private fun Modifier.border(outlined: Boolean, selected: Boolean, error: OudsError?, state: OudsControlState): Modifier { val borderColor = outlineBorderColor(state, selected, error) @@ -230,7 +315,7 @@ internal fun PreviewOudsRadioButtonItem( error = error, outlined = checkNotNull(extraParameter), reversed = reversed, - icon = if (hasIcon) OudsControlItemIcon(imageVector = Icons.Filled.Call) else null + icon = if (hasIcon) OudsIcon(imageVector = Icons.Filled.Call) else null ) } } @@ -284,7 +369,7 @@ internal fun PreviewOudsRadioButtonItemWithDescriptionText(theme: OudsThemeContr onClick = {}, extraLabel = "Extra label", description = LoremIpsumText, - icon = OudsControlItemIcon(imageVector = Icons.Filled.Call) + icon = OudsIcon(imageVector = Icons.Filled.Call) ) } @@ -302,7 +387,7 @@ internal fun PreviewOudsRadioButtonItemWithEdgeToEdgeDisabled(theme: OudsThemeCo label = "Label", onClick = {}, extraLabel = "Extra label", - icon = OudsControlItemIcon(imageVector = Icons.Filled.Call), + icon = OudsIcon(imageVector = Icons.Filled.Call), edgeToEdge = false, divider = true, error = OudsError(ControlItemErrorMessage) @@ -327,7 +412,7 @@ internal fun PreviewOudsRadioButtonItemConstrainedMaxWidth( label = "Label", onClick = {}, extraLabel = "Extra label", - icon = OudsControlItemIcon(imageVector = Icons.Filled.Call), + icon = OudsIcon(imageVector = Icons.Filled.Call), edgeToEdge = false, divider = true, constrainedMaxWidth = constrainedMaxWidth @@ -369,7 +454,7 @@ internal fun PreviewOudsRadioButtonItemWithUntintedIcon(theme: OudsThemeContract selected = false, label = "Label", onClick = {}, - icon = OudsControlItemIcon(painter = rememberRainbowHeartPainter(), tinted = false), + icon = OudsIcon(painter = rememberRainbowHeartPainter(), tinted = false), divider = true ) } diff --git a/core/src/main/java/com/orange/ouds/core/component/OudsSmallButton.kt b/core/src/main/java/com/orange/ouds/core/component/OudsSmallButton.kt index 5d0169982d..5e7f111808 100644 --- a/core/src/main/java/com/orange/ouds/core/component/OudsSmallButton.kt +++ b/core/src/main/java/com/orange/ouds/core/component/OudsSmallButton.kt @@ -73,13 +73,12 @@ import com.orange.ouds.theme.tokens.components.OudsButtonMonoTokens * @sample com.orange.ouds.core.component.samples.OudsSmallButtonTextOnlyOnColoredBackgroundSample */ @Composable -@ExperimentalOudsApi fun OudsSmallButton( label: String, onClick: () -> Unit, modifier: Modifier = Modifier, enabled: Boolean = true, - loader: OudsButtonLoader? = null, + loader: OudsLoader? = null, appearance: OudsButtonAppearance = OudsButtonDefaults.Appearance, interactionSource: MutableInteractionSource? = null ) { @@ -96,6 +95,69 @@ fun OudsSmallButton( ) } +/** + * Button is a UI element that triggers an action or event, and is used to initiate tasks or confirming an action. + * Button appears in different layouts, styles and states to indicate hierarchy or emphasis. + * + * This version of the button uses the *text only* layout, which is the most common layout. + * Other layouts are available for this component: *text + icon* and *icon only*. + * + * This size can be particularly useful in an information-dense interface or in the construction of a template or component requiring the use of small elements (in a "List item" component, for example). + * The default size is available via [OudsButton]. + * + * Note that if it is placed in an [OudsColoredBox], its monochrome variant is automatically displayed. + * The tokens associated with these specific colors can be customized by overriding [OudsButtonMonoTokens]. + * + * Rounded corners can be enabled or disabled using the [OudsThemeSettings.roundedCornerButtons] property in the settings of the theme provided + * when calling the [com.orange.ouds.core.theme.OudsTheme] method. + * + * > Design guidelines: [unified-design-system.orange.com](https://r.orange.fr/r/S-ouds-doc-button) + * + * > Design name: Button + * + * > Design version: 3.3.0 + * + * **Note**: This API is currently marked as experimental because it has been released ahead of + * the tokens 2.6.0 update. It will be stabilized once tokens 2.6.0 is integrated. + * + * @param label Label displayed in the button describing the button action. Use action verbs or phrases to tell the user what will happen next. + * @param onClick Callback invoked when the button is clicked. + * @param modifier [Modifier] applied to the button. + * @param enabled Controls the enabled state of the button when there is no [loader]. + * When `false`, this button will not be clickable. + * Has no effect if [loader] is provided. + * @param loader An optional loading progress indicator displayed in the button to indicate an ongoing operation. + * @param appearance Appearance of the button among [OudsButtonAppearance] values. + * A button with [OudsButtonAppearance.Negative] is not allowed as a direct or indirect child of an [OudsColoredBox] and will throw an [IllegalStateException]. + * @param interactionSource An optional hoisted [MutableInteractionSource] for observing and emitting [Interaction]s for this button. Note that if `null` + * is provided, interactions will still happen internally. + * + * @sample com.orange.ouds.core.component.samples.OudsSmallButtonTextOnlySample + * + * @sample com.orange.ouds.core.component.samples.OudsSmallButtonTextOnlyOnColoredBackgroundSample + */ +@Deprecated("") +@Composable +fun OudsSmallButton( + label: String, + onClick: () -> Unit, + modifier: Modifier = Modifier, + enabled: Boolean = true, + @Suppress("DEPRECATION") loader: OudsButtonLoader?, + appearance: OudsButtonAppearance = OudsButtonDefaults.Appearance, + interactionSource: MutableInteractionSource? = null +) { + OudsSmallButton( + label = label, + onClick = onClick, + modifier = modifier, + enabled = enabled, + loader = loader?.toLoader(), + appearance = appearance, + interactionSource = interactionSource + ) +} + /** * Button is a UI element that triggers an action or event, and is used to initiate tasks or confirming an action. * Button appears in different layouts, styles and states to indicate hierarchy or emphasis. @@ -140,13 +202,12 @@ fun OudsSmallButton( * @sample com.orange.ouds.core.component.samples.OudsSmallButtonIconOnlyWithUntintedIconSample */ @Composable -@ExperimentalOudsApi fun OudsSmallButton( - icon: OudsButtonIcon, + icon: OudsIcon, onClick: () -> Unit, modifier: Modifier = Modifier, enabled: Boolean = true, - loader: OudsButtonLoader? = null, + loader: OudsLoader? = null, appearance: OudsButtonAppearance = OudsButtonDefaults.Appearance, interactionSource: MutableInteractionSource? = null ) { @@ -163,6 +224,71 @@ fun OudsSmallButton( ) } +/** + * Button is a UI element that triggers an action or event, and is used to initiate tasks or confirming an action. + * Button appears in different layouts, styles and states to indicate hierarchy or emphasis. + * + * This version of the button uses the *icon only* layout, which is typically used in business or back-office interfaces. It is rarely used alone (usually part of a group of elements). + * Other layouts are available for this component: *text only* and *text + icon*. + * + * This size can be particularly useful in an information-dense interface or in the construction of a template or component requiring the use of small elements (in a "List item" component, for example). + * The default size is available via [OudsButton]. + * + * Note that if it is placed in an [OudsColoredBox], its monochrome variant is automatically displayed. + * The tokens associated with these specific colors can be customized by overriding [OudsButtonMonoTokens]. + * + * Rounded corners can be enabled or disabled using the [OudsThemeSettings.roundedCornerButtons] property in the settings of the theme provided + * when calling the [com.orange.ouds.core.theme.OudsTheme] method. + * + * > Design guidelines: [unified-design-system.orange.com](https://r.orange.fr/r/S-ouds-doc-button) + * + * > Design name: Button + * + * > Design version: 3.3.0 + * + * **Note**: This API is currently marked as experimental because it has been released ahead of + * the tokens 2.6.0 update. It will be stabilized once tokens 2.6.0 is integrated. + * + * @param icon Icon displayed in the button. Use an icon to add additional affordance where the icon has a clear and well-established meaning. + * @param onClick Callback invoked when the button is clicked. + * @param modifier [Modifier] applied to the button. + * @param enabled Controls the enabled state of the button when there is no [loader]. + * When `false`, this button will not be clickable. + * Has no effect if [loader] is provided. + * @param loader An optional loading progress indicator displayed in the button to indicate an ongoing operation. + * @param appearance Appearance of the button among [OudsButtonAppearance] values. + * A button with [OudsButtonAppearance.Negative] is not allowed as a direct or indirect child of an [OudsColoredBox] and will throw an [IllegalStateException]. + * @param interactionSource An optional hoisted [MutableInteractionSource] for observing and emitting [Interaction]s for this button. Note that if `null` + * is provided, interactions will still happen internally. + * + * @sample com.orange.ouds.core.component.samples.OudsSmallButtonIconOnlySample + * + * @sample com.orange.ouds.core.component.samples.OudsSmallButtonIconOnlyOnColoredBackgroundSample + * + * @sample com.orange.ouds.core.component.samples.OudsSmallButtonIconOnlyWithUntintedIconSample + */ +@Composable +@ExperimentalOudsApi +fun OudsSmallButton( + @Suppress("DEPRECATION") icon: OudsButtonIcon, + onClick: () -> Unit, + modifier: Modifier = Modifier, + enabled: Boolean = true, + @Suppress("DEPRECATION") loader: OudsButtonLoader? = null, + appearance: OudsButtonAppearance = OudsButtonDefaults.Appearance, + interactionSource: MutableInteractionSource? = null +) { + OudsSmallButton( + icon = icon.toIcon(), + onClick = onClick, + modifier = modifier, + enabled = enabled, + loader = loader?.toLoader(), + appearance = appearance, + interactionSource = interactionSource + ) +} + /** * Button is a UI element that triggers an action or event, and is used to initiate tasks or confirming an action. * Button appears in different layouts, styles and states to indicate hierarchy or emphasis. @@ -211,12 +337,12 @@ fun OudsSmallButton( @Composable @ExperimentalOudsApi fun OudsSmallButton( - icon: OudsButtonIcon, + icon: OudsIcon, label: String, onClick: () -> Unit, modifier: Modifier = Modifier, enabled: Boolean = true, - loader: OudsButtonLoader? = null, + loader: OudsLoader? = null, appearance: OudsButtonAppearance = OudsButtonDefaults.Appearance, interactionSource: MutableInteractionSource? = null ) { @@ -233,6 +359,75 @@ fun OudsSmallButton( ) } +/** + * Button is a UI element that triggers an action or event, and is used to initiate tasks or confirming an action. + * Button appears in different layouts, styles and states to indicate hierarchy or emphasis. + * + * This version of the button uses the *text + icon* layout, which should remain specific to clearly identified contexts (e.g., the use of an icon with a + * "Play" button is standard in the context of TV or video streaming). + * Other layouts are available for this component: *text only* and *icon only*. + * + * This size can be particularly useful in an information-dense interface or in the construction of a template or component requiring the use of small elements (in a "List item" component, for example). + * The default size is available via [OudsButton]. + * + * Note that if it is placed in an [OudsColoredBox], its monochrome variant is automatically displayed. + * The tokens associated with these specific colors can be customized by overriding [OudsButtonMonoTokens]. + * + * Rounded corners can be enabled or disabled using the [OudsThemeSettings.roundedCornerButtons] property in the settings of the theme provided + * when calling the [com.orange.ouds.core.theme.OudsTheme] method. + * + * > Design guidelines: [unified-design-system.orange.com](https://r.orange.fr/r/S-ouds-doc-button) + * + * > Design name: Button + * + * > Design version: 3.3.0 + * + * **Note**: This API is currently marked as experimental because it has been released ahead of + * the tokens 2.6.0 update. It will be stabilized once tokens 2.6.0 is integrated. + * + * @param icon Icon displayed in the button. Use an icon to add additional affordance where the icon has a clear and well-established meaning. + * @param label Label displayed in the button describing the button action. Use action verbs or phrases to tell the user what will happen next. + * @param onClick Callback invoked when the button is clicked. + * @param modifier [Modifier] applied to the button. + * @param enabled Controls the enabled state of the button when there is no [loader]. + * When `false`, this button will not be clickable. + * Has no effect if [loader] is provided. + * @param loader An optional loading progress indicator displayed in the button to indicate an ongoing operation. + * @param appearance Appearance of the button among [OudsButtonAppearance] values. + * A button with [OudsButtonAppearance.Negative] is not allowed as a direct or indirect child of an [OudsColoredBox] and will throw an [IllegalStateException]. + * @param interactionSource An optional hoisted [MutableInteractionSource] for observing and emitting [Interaction]s for this button. Note that if `null` + * is provided, interactions will still happen internally. + * + * @sample com.orange.ouds.core.component.samples.OudsSmallButtonTextAndIconSample + * + * @sample com.orange.ouds.core.component.samples.OudsSmallButtonTextAndIconOnColoredBackgroundSample + * + * @sample com.orange.ouds.core.component.samples.OudsSmallButtonTextAndIconWithUntintedIconSample + */ +@Deprecated("") +@Composable +fun OudsSmallButton( + @Suppress("DEPRECATION") icon: OudsButtonIcon, + label: String, + onClick: () -> Unit, + modifier: Modifier = Modifier, + enabled: Boolean = true, + @Suppress("DEPRECATION") loader: OudsButtonLoader? = null, + appearance: OudsButtonAppearance = OudsButtonDefaults.Appearance, + interactionSource: MutableInteractionSource? = null +) { + OudsSmallButton( + icon = icon.toIcon(), + label = label, + onClick = onClick, + modifier = modifier, + enabled = enabled, + loader = loader?.toLoader(), + appearance = appearance, + interactionSource = interactionSource + ) +} + @OudsPreviewLightDark @Composable @Suppress("PreviewShouldNotBeCalledRecursively") @@ -248,7 +443,7 @@ internal fun PreviewOudsSmallButton( ) = OudsPreview(theme = theme, darkThemeEnabled = darkThemeEnabled) { with(parameter) { val label = if (hasLabel) appearance.name else null - val icon = if (hasIcon) OudsButtonIcon(Icons.Filled.FavoriteBorder, "") else null + val icon = if (hasIcon) OudsIcon(Icons.Filled.FavoriteBorder) else null val content: @Composable () -> Unit = { PreviewEnumEntries(maxEnumEntriesInEachRow = 2) { when { @@ -294,7 +489,7 @@ internal fun PreviewOudsSmallButtonWithRoundedCorners( val appearance = OudsButtonAppearance.Default PreviewEnumEntries(maxEnumEntriesInEachRow = 2) { OudsSmallButton( - icon = OudsButtonIcon(Icons.Filled.FavoriteBorder, ""), + icon = OudsIcon(Icons.Filled.FavoriteBorder), label = appearance.name, onClick = {}, appearance = appearance @@ -310,7 +505,7 @@ private fun PreviewOudsSmallButtonOnTwoLines() = PreviewOudsSmallButtonOnTwoLine @Composable internal fun PreviewOudsSmallButtonOnTwoLines(theme: OudsThemeContract) = OudsPreview(theme = theme) { OudsSmallButton( - icon = OudsButtonIcon(Icons.Filled.FavoriteBorder, ""), + icon = OudsIcon(Icons.Filled.FavoriteBorder), label = "Button\non two lines", onClick = {}, ) @@ -325,9 +520,8 @@ private fun PreviewOudsSmallButtonWithUntintedIcon() = PreviewOudsSmallButtonWit internal fun PreviewOudsSmallButtonWithUntintedIcon(theme: OudsThemeContract) = OudsPreview(theme = theme) { PreviewEnumEntries(maxEnumEntriesInEachRow = 2) { OudsSmallButton( - icon = OudsButtonIcon( + icon = OudsIcon( painter = rememberRainbowHeartPainter(), - contentDescription = "", tinted = false ), label = "Label", diff --git a/core/src/main/java/com/orange/ouds/core/component/OudsSuggestionChip.kt b/core/src/main/java/com/orange/ouds/core/component/OudsSuggestionChip.kt index 511c00c3d2..7ebce62a11 100644 --- a/core/src/main/java/com/orange/ouds/core/component/OudsSuggestionChip.kt +++ b/core/src/main/java/com/orange/ouds/core/component/OudsSuggestionChip.kt @@ -109,7 +109,7 @@ fun OudsSuggestionChip( @Composable fun OudsSuggestionChip( onClick: () -> Unit, - icon: OudsChipIcon, + icon: OudsIcon, modifier: Modifier = Modifier, enabled: Boolean = true, interactionSource: MutableInteractionSource? = null @@ -124,6 +124,54 @@ fun OudsSuggestionChip( ) } +/** + * Suggestion chip is a UI element that allows to present recommended or predictive options based on user's input or context, + * and is commonly used to capture filtering decisions. Suggestion chip is typically non-selected by default and can be tapped + * or clicked to apply the suggestion, streamlining input and enhancing usability. + * + * This version of the chip uses the *icon only* layout which uses only an icon, making it a compact option for limited space. + * Works well with universally recognized symbols, such as a heart for favorites or a checkmark for selection. + * Other layouts are available for this component: *text only* and *text + icon*. + * + * > Design guidelines: [unified-design-system.orange.com](https://r.orange.fr/r/S-ouds-doc-suggestion-chip) + * + * > Design name: Suggestion Chip + * + * > Design version: 1.5.0 + * + * @param onClick Called when this chip is clicked. + * @param icon Icon displayed in the chip. Use an icon to add additional affordance where the icon has a clear and well-established meaning. + * @param modifier The [Modifier] to be applied to this chip. + * @param enabled Controls the enabled state of this chip. When `false`, this component will not + * respond to user input, and it will appear visually disabled and disabled to accessibility + * services. + * @param interactionSource An optional hoisted [MutableInteractionSource] for observing and + * emitting [Interaction]s for this chip. You can use this to change the chip's appearance or + * preview the chip in different states. Note that if `null` is provided, interactions will still + * happen internally. + * + * @sample com.orange.ouds.core.component.samples.OudsSuggestionChipIconOnlySample + * + * @sample com.orange.ouds.core.component.samples.OudsSuggestionChipIconOnlyWithUntintedIconSample + */ +@Deprecated("") +@Composable +fun OudsSuggestionChip( + onClick: () -> Unit, + @Suppress("DEPRECATION") icon: OudsChipIcon, + modifier: Modifier = Modifier, + enabled: Boolean = true, + interactionSource: MutableInteractionSource? = null +) { + OudsSuggestionChip( + onClick = onClick, + icon = icon.toIcon(), + modifier = modifier, + enabled = enabled, + interactionSource = interactionSource + ) +} + /** * Suggestion chip is a UI element that allows to present recommended or predictive options based on user's input or context, * and is commonly used to capture filtering decisions. Suggestion chip is typically non-selected by default and can be tapped @@ -159,7 +207,7 @@ fun OudsSuggestionChip( fun OudsSuggestionChip( onClick: () -> Unit, label: String, - icon: OudsChipIcon, + icon: OudsIcon, modifier: Modifier = Modifier, enabled: Boolean = true, interactionSource: MutableInteractionSource? = null @@ -174,6 +222,57 @@ fun OudsSuggestionChip( ) } +/** + * Suggestion chip is a UI element that allows to present recommended or predictive options based on user's input or context, + * and is commonly used to capture filtering decisions. Suggestion chip is typically non-selected by default and can be tapped + * or clicked to apply the suggestion, streamlining input and enhancing usability. + * + * This version of the chip uses the *text + icon* layout which combines text with an icon to enhance clarity and recognition. + * Ideal when a visual cue helps reinforce the filter's meaning. + * Other layouts are available for this component: *text only* and *icon only*. + * + * > Design guidelines: [unified-design-system.orange.com](https://r.orange.fr/r/S-ouds-doc-suggestion-chip) + * + * > Design name: Suggestion Chip + * + * > Design version: 1.5.0 + * + * @param onClick Called when this chip is clicked. + * @param label Text label displayed in the chip. + * @param icon Icon displayed in the chip. Use an icon to add additional affordance where the icon has a clear and well-established meaning. + * @param modifier The [Modifier] to be applied to this chip. + * @param enabled Controls the enabled state of this chip. When `false`, this component will not + * respond to user input, and it will appear visually disabled and disabled to accessibility + * services. + * @param interactionSource An optional hoisted [MutableInteractionSource] for observing and + * emitting [Interaction]s for this chip. You can use this to change the chip's appearance or + * preview the chip in different states. Note that if `null` is provided, interactions will still + * happen internally. + * + * @sample com.orange.ouds.core.component.samples.OudsSuggestionChipTextAndIconSample + * + * @sample com.orange.ouds.core.component.samples.OudsSuggestionChipTextAndIconWithUntintedIconSample + */ +@Deprecated("") +@Composable +fun OudsSuggestionChip( + onClick: () -> Unit, + label: String, + @Suppress("DEPRECATION") icon: OudsChipIcon, + modifier: Modifier = Modifier, + enabled: Boolean = true, + interactionSource: MutableInteractionSource? = null +) { + OudsSuggestionChip( + onClick = onClick, + label = label, + icon = icon.toIcon(), + modifier = modifier, + enabled = enabled, + interactionSource = interactionSource + ) +} + /** * Basic suggestion chip composable that allows to implement components that look close to a standard OUDS suggestion chip. * @@ -251,7 +350,7 @@ fun OudsBasicSuggestionChip( @ExperimentalOudsApi fun OudsBasicSuggestionChip( onClick: () -> Unit, - icon: OudsChipIcon, + icon: OudsIcon, modifier: Modifier = Modifier, enabled: Boolean = true, interactionSource: MutableInteractionSource? = null, @@ -300,7 +399,7 @@ fun OudsBasicSuggestionChip( fun OudsBasicSuggestionChip( onClick: () -> Unit, label: String, - icon: OudsChipIcon, + icon: OudsIcon, modifier: Modifier = Modifier, enabled: Boolean = true, interactionSource: MutableInteractionSource? = null, @@ -325,7 +424,7 @@ private fun OudsChipScope.DefaultSuggestionChipContent() = DefaultChipContent(Ou private fun OudsBasicSuggestionChip( onClick: () -> Unit, nullableLabel: String?, - nullableIcon: OudsChipIcon?, + nullableIcon: OudsIcon?, modifier: Modifier = Modifier, enabled: Boolean = true, interactionSource: MutableInteractionSource? = null, @@ -360,7 +459,7 @@ internal fun PreviewOudsSuggestionChip( ) = OudsPreview(theme = theme, darkThemeEnabled = darkThemeEnabled) { with(parameter) { val label = if (hasLabel) "Label" else null - val icon = if (hasIcon) OudsChipIcon(Icons.Filled.FavoriteBorder, "") else null + val icon = if (hasIcon) OudsIcon(Icons.Filled.FavoriteBorder) else null PreviewEnumEntries(maxEnumEntriesInEachRow = 3) { when { label != null && icon != null -> OudsSuggestionChip(onClick = {}, label = label, icon = icon) @@ -383,7 +482,7 @@ private fun PreviewOudsSuggestionChipWithUntintedIcon() { internal fun PreviewOudsSuggestionChipWithUntintedIcon(theme: OudsThemeContract) = OudsPreview(theme = theme) { PreviewEnumEntries(maxEnumEntriesInEachRow = 3) { OudsSuggestionChip( - icon = OudsChipIcon(painter = rememberRainbowHeartPainter(), contentDescription = "", tinted = false), + icon = OudsIcon(painter = rememberRainbowHeartPainter(), tinted = false), label = "Label", onClick = {} ) @@ -400,7 +499,7 @@ private fun PreviewOudsSuggestionChipOnTwoLines() { @Composable internal fun PreviewOudsSuggestionChipOnTwoLines(theme: OudsThemeContract) = OudsPreview(theme = theme) { OudsSuggestionChip( - icon = OudsChipIcon(Icons.Filled.FavoriteBorder, ""), + icon = OudsIcon(Icons.Filled.FavoriteBorder, ""), label = "Suggestion chip\non two lines", onClick = {} ) diff --git a/core/src/main/java/com/orange/ouds/core/component/OudsSwitchItem.kt b/core/src/main/java/com/orange/ouds/core/component/OudsSwitchItem.kt index 0c058263be..c029772dbd 100644 --- a/core/src/main/java/com/orange/ouds/core/component/OudsSwitchItem.kt +++ b/core/src/main/java/com/orange/ouds/core/component/OudsSwitchItem.kt @@ -94,7 +94,7 @@ fun OudsSwitchItem( onCheckedChange: ((Boolean) -> Unit)?, modifier: Modifier = Modifier, description: String? = null, - icon: OudsControlItemIcon? = null, + icon: OudsIcon? = null, edgeToEdge: Boolean = true, divider: Boolean = false, reversed: Boolean = false, @@ -149,6 +149,86 @@ fun OudsSwitchItem( ) } +/** + * Switch item is a UI element that allows to toggle between two states, typically "On" and "Off", and used to enable or disable features, options or settings. + * Switch item covers a wider range of contexts by allowing to toggle the visibility of additional text labels and icon assets. + * + * The **switch item variant** can function as a simple input with a label, or it can be combined with optional elements such as description, a divider, + * or an icon, allowing it to suit various use cases. + * It can be used in a list as a list item or as a single element to validate general conditions, for example. + * + * The OUDS switch item layout contains an [OudsSwitch]. By clicking the switch item, the user changes the checked state of its switch. + * + * > Design guidelines: [unified-design-system.orange.com](https://r.orange.fr/r/S-ouds-doc-switch) + * + * > Design name: Switch + * + * > Design version: 1.5.0 + * + * @see [OudsSwitch] If you want to use a standalone switch. + * + * @param checked Controls the checked state of the item's switch. + * @param label The main label of the switch item. + * @param onCheckedChange Callback invoked on switch item click. If `null`, then this is passive and relies entirely on a higher-level component to control + * the checked state. + * @param modifier [Modifier] applied to the layout of the switch item. + * @param description Optional text displayed below the label. + * @param icon Optional icon displayed in the item. By default, it has a leading position. If [reversed] is set to `true`, it is displayed as a trailing element. + * @param edgeToEdge Controls the horizontal layout of the item. When `true`, the item is designed to span the full width of the screen or container. When `false`, + * it is adapted for use within constrained layouts or containers with their own padding. Defaults to `true`. + * @param divider Controls the display of a divider at the bottom of the switch item. + * @param reversed When `false`, the switch has a trailing position and the optional [icon] has a leading position. Otherwise, it is reversed. + * @param enabled Controls the enabled state of the switch item. When `false`, the switch, the texts and the optional icon are disabled, and the item + * will not be clickable. + * @param readOnly Controls the read-only state of the switch item. When `true`, the item's switch is disabled but the texts and the icon remain in the + * enabled color. Note that if it is set to `true` and [enabled] is set to `false`, the switch item will be displayed in the disabled state. + * @param error Optional [OudsError] to provide if the switch item should appear in an error state, `null` otherwise. + * @param constrainedMaxWidth When `true`, the item width is constrained to a maximum value defined by the design system. + * When `false`, no specific width constraint is applied, allowing the component to size itself or follow external modifiers. + * Defaults to `false`. + * @param interactionSource Optional hoisted [MutableInteractionSource] for observing and emitting [Interaction]s for the item's switch. Note that if `null` + * is provided, interactions will still happen internally. + * + * @sample com.orange.ouds.core.component.samples.OudsSwitchItemSample + * @sample com.orange.ouds.core.component.samples.OudsSwitchItemWithAnnotatedErrorMessageSample + * @sample com.orange.ouds.core.component.samples.OudsSwitchItemWithUntintedIconSample + */ +@Deprecated("") +@Composable +fun OudsSwitchItem( + checked: Boolean, + label: String, + onCheckedChange: ((Boolean) -> Unit)?, + modifier: Modifier = Modifier, + description: String? = null, + @Suppress("DEPRECATION") icon: OudsControlItemIcon?, + edgeToEdge: Boolean = true, + divider: Boolean = false, + reversed: Boolean = false, + enabled: Boolean = true, + readOnly: Boolean = false, + error: OudsError? = null, + constrainedMaxWidth: Boolean = false, + interactionSource: MutableInteractionSource? = null +) { + OudsSwitchItem( + checked = checked, + label = label, + onCheckedChange = onCheckedChange, + modifier = modifier, + description = description, + icon = icon?.toIcon(), + edgeToEdge = edgeToEdge, + divider = divider, + reversed = reversed, + enabled = enabled, + readOnly = readOnly, + error = error, + constrainedMaxWidth = constrainedMaxWidth, + interactionSource = interactionSource + ) +} + @Preview(name = "Light", heightDp = OudsPreviewableComponent.SwitchItem.Default.PreviewHeightDp, device = OudsPreviewDevice) @Preview( name = "Dark", @@ -175,7 +255,7 @@ internal fun PreviewOudsSwitchItem( label = "Label", onCheckedChange = {}, description = description, - icon = if (hasIcon) OudsControlItemIcon(imageVector = Icons.Filled.Call) else null, + icon = if (hasIcon) OudsIcon(imageVector = Icons.Filled.Call) else null, divider = divider, reversed = reversed, error = error, @@ -197,7 +277,7 @@ internal fun PreviewOudsSwitchItemWithLongDescription(theme: OudsThemeContract) label = "Label", onCheckedChange = {}, description = LoremIpsumText, - icon = OudsControlItemIcon(imageVector = Icons.Filled.Call) + icon = OudsIcon(imageVector = Icons.Filled.Call) ) } @@ -213,7 +293,7 @@ internal fun PreviewOudsSwitchItemWithEdgeToEdgeDisabled(theme: OudsThemeContrac checked = true, label = "Label", onCheckedChange = {}, - icon = OudsControlItemIcon(imageVector = Icons.Filled.Call), + icon = OudsIcon(imageVector = Icons.Filled.Call), edgeToEdge = false, divider = true, error = OudsError(ControlItemErrorMessage), @@ -237,7 +317,7 @@ internal fun PreviewOudsSwitchItemConstrainedMaxWidth( checked = true, label = "Label", onCheckedChange = {}, - icon = OudsControlItemIcon(imageVector = Icons.Filled.Call), + icon = OudsIcon(imageVector = Icons.Filled.Call), constrainedMaxWidth = constrainedMaxWidth, edgeToEdge = false, divider = true @@ -279,7 +359,7 @@ internal fun PreviewOudsSwitchItemWithUntintedIcon(theme: OudsThemeContract) = O checked = false, label = "Label", onCheckedChange = {}, - icon = OudsControlItemIcon(painter = rememberRainbowHeartPainter(), tinted = false), + icon = OudsIcon(painter = rememberRainbowHeartPainter(), tinted = false), divider = true ) } diff --git a/core/src/main/java/com/orange/ouds/core/component/OudsTag.kt b/core/src/main/java/com/orange/ouds/core/component/OudsTag.kt index e2da3157e8..3f72d126df 100644 --- a/core/src/main/java/com/orange/ouds/core/component/OudsTag.kt +++ b/core/src/main/java/com/orange/ouds/core/component/OudsTag.kt @@ -130,7 +130,7 @@ fun OudsTag( status: OudsTagStatus = OudsTagDefaults.Status, roundedCorners: Boolean = true, size: OudsTagSize = OudsTagDefaults.Size, - loader: OudsTagLoader? = null + loader: OudsLoader? = null ) { val hasLoader = loader != null val hasAsset = status.asset != null || hasLoader @@ -192,6 +192,87 @@ fun OudsTag( } } +/** + * Tag is a UI element that allows to display short info like a label, keyword, or category. Tag helps users quickly find, group, or understand content. + * + * Tags have six statuses depending on the context of the information they represent. Each status is designed + * to convey a specific meaning and ensure clarity in communication. + * + * Four different layouts are supported: + * - Text only: when [status] asset is `null`, the tag displays only text. + * Used for simple labels, categories, or keywords without additional visual elements. + * - Text and bullet: when [status] asset is equal to [OudsTagAsset.Bullet], the tag displays a small indicator (bullet) alongside the text. + * Used to show status, presence, or activity next to the label. + * - Text and icon: when [status] asset is an [OudsTagAsset.Icon] or an [OudsTagAsset.Icon.Default], the tag includes an icon before the text. + * Used to visually reinforce the meaning of the tag, such as status, type, or action. + * - Text and loader: when [loader] is not `null`, the tag combines a loading spinner (or progress indicator) with text. + * Used to indicate that a process or action related to the tag is in progress. + * + * > Design guidelines: [unified-design-system.orange.com](https://r.orange.fr/r/S-ouds-doc-tag) + * + * > Design name: Tag + * + * > Design version: 1.5.0 + * + * @param label The label displayed in the tag. + * @param modifier [Modifier] applied to the tag. + * @param enabled Controls the enabled appearance of the tag. + * A tag with a loading spinner cannot be disabled. This will throw an [IllegalStateException]. + * @param appearance Appearance of the tag among [OudsTagAppearance] values. Combined with the [status] of the tag, the appearance determines the tag's background + * and content colors. + * @param status The status of the tag. Its background color and its content color are based on this status combined with the [appearance] of the tag. + * There are two types of statuses: + * - Non-functional statuses ([OudsTagStatus.Neutral] or [OudsTagStatus.Accent]) used to display categories, default states, or to draw attention without + * carrying a specific functional meaning (unlike functional tags such as success, info, etc.). + * Using a non-functional status, you can provide an icon related to the tag’s context to enhance recognition by providing an [OudsTagAsset.Icon] + * as the asset of the status. + * - Functional statuses communicate specific information or system feedback: [OudsTagStatus.Positive], [OudsTagStatus.Warning], [OudsTagStatus.Negative], + * [OudsTagStatus.Info]. + * Each functional status has its dedicated functional icon that matches the meaning of the tag. This icon will appear by providing [OudsTagAsset.Icon.Default] + * as the asset of the status. + * @param roundedCorners Controls the shape of the tag. + * When `true`, the tag has rounded corners, providing a softer and more approachable look, suitable for most modern interfaces. + * When `false`, the tag has sharp, square corners, providing a more formal, structured, or technical feel. Often used in a business context to label + * promotions, offers or important notices. + * @param size The size of the tag. + * @param loader An optional loading spinner (or progress indicator) displayed before the [label]. Used to indicate that a process or action related to the + * tag is in progress. + * A disabled tag cannot have a loader. This will throw an [IllegalStateException]. + * + * @sample com.orange.ouds.core.component.samples.OudsTagSample + * + * @sample com.orange.ouds.core.component.samples.OudsTagWithBulletSample + * + * @sample com.orange.ouds.core.component.samples.OudsTagWithDefaultIconSample + * + * @sample com.orange.ouds.core.component.samples.OudsTagWithIconSample + * + * @sample com.orange.ouds.core.component.samples.OudsTagWithUntintedIconSample + */ +@Deprecated("") +@Composable +fun OudsTag( + label: String, + modifier: Modifier = Modifier, + enabled: Boolean = true, + appearance: OudsTagAppearance = OudsTagDefaults.Appearance, + status: OudsTagStatus = OudsTagDefaults.Status, + roundedCorners: Boolean = true, + size: OudsTagSize = OudsTagDefaults.Size, + @Suppress("DEPRECATION") loader: OudsTagLoader? +) { + OudsTag( + label = label, + modifier = modifier, + enabled = enabled, + appearance = appearance, + status = status, + roundedCorners = roundedCorners, + size = size, + loader = loader?.toLoader() + ) +} + @Composable private fun shape(roundedCorners: Boolean): RoundedCornerShape { return with(OudsTheme.componentsTokens.tag) { @@ -439,18 +520,37 @@ enum class OudsTagAppearance { */ sealed interface OudsTagAsset : OudsPolymorphicComponentContent { + override fun toComponentContent(): OudsComponentContent { + @Suppress("UNCHECKED_CAST", "DEPRECATION") + return if (this == OudsIcon.Default) { + OudsIcon( + graphicsObjectProvider = { icon -> + with(icon.extraParameters as ExtraParameters) { + status.getDefaultIconPainter(appearance, enabled).orElse { + error("No default icon for status ${status::class.simpleName}") + } + } + }, + contentDescriptionProvider = { "" }, + tinted = true + ) + } else { + this + } as OudsComponentContent + } + /** * A bullet in an [OudsTag]. * This bullet is non-clickable. No content description is needed because a tag always contains a label. */ - data object Bullet : OudsTagAsset, OudsComponentContent(OudsTagAsset.ExtraParameters::class.java) { + data object Bullet : OudsTagAsset, OudsComponentContent() { @Composable override fun Content(modifier: Modifier) { Box( modifier = modifier .size(10.dp) - .background(extraParameters.tint, shape = RoundedCornerShape(percent = 50)) + .background(extraParameters.tint.orElse { Color.Unspecified }, shape = RoundedCornerShape(percent = 50)) ) } } @@ -459,6 +559,8 @@ sealed interface OudsTagAsset : OudsPolymorphicComponentContent { * An icon in an [OudsTag]. * This icon is non-clickable. No content description is needed because a tag always contains a label. */ + @Suppress("DEPRECATION") + @Deprecated("") class Icon private constructor( graphicsObject: Any, override val tinted: Boolean @@ -507,7 +609,6 @@ sealed interface OudsTagAsset : OudsPolymorphicComponentContent { * for other statuses because the tag's `label` should provide the necessary context. */ data object Default : OudsTagAsset, OudsComponentIcon( - OudsTagAsset.ExtraParameters::class.java, { icon -> with(icon.extraParameters) { status.getDefaultIconPainter(appearance, enabled).orElse { @@ -524,13 +625,12 @@ sealed interface OudsTagAsset : OudsPolymorphicComponentContent { } } - @ConsistentCopyVisibility - data class ExtraParameters internal constructor( - internal val tint: Color, + class ExtraParameters internal constructor( + tint: Color, + enabled: Boolean, internal val status: OudsTagStatus, - internal val appearance: OudsTagAppearance, - internal val enabled: Boolean - ) : OudsComponentContent.ExtraParameters() + internal val appearance: OudsTagAppearance + ) : OudsIcon.ExtraParameters(tint, enabled) } /** @@ -540,7 +640,11 @@ sealed interface OudsTagAsset : OudsPolymorphicComponentContent { * Values outside of this range are coerced into the range. * Set this value to `null` to display a circular indeterminate progress indicator. */ -data class OudsTagLoader(val progress: Float?) +@Deprecated("") +data class OudsTagLoader(val progress: Float?) { + + internal fun toLoader() = OudsLoader(progress) +} /** * Represents the size of an OUDS tag. @@ -584,8 +688,11 @@ sealed class OudsTagStatus(val asset: OudsTagAsset? = null) { /** * Creates an instance of [OudsTagStatus.Neutral] with an icon. */ + @Suppress("DEPRECATION") constructor(asset: OudsTagAsset.Icon) : this(asset as? OudsTagAsset) + constructor(asset: OudsIcon) : this(asset as? OudsTagAsset) + /** * Creates an instance of [OudsTagStatus.Neutral] with no asset. */ @@ -606,8 +713,11 @@ sealed class OudsTagStatus(val asset: OudsTagAsset? = null) { /** * Creates an instance of [OudsTagStatus.Accent] with an icon. */ + @Suppress("DEPRECATION") constructor(asset: OudsTagAsset.Icon) : this(asset as? OudsTagAsset) + constructor(asset: OudsIcon) : this(asset as? OudsTagAsset) + /** * Creates an instance of [OudsTagStatus.Accent] with no asset. */ @@ -627,8 +737,11 @@ sealed class OudsTagStatus(val asset: OudsTagAsset? = null) { /** * Creates an instance of [OudsTagStatus.Positive] with its default dedicated icon. */ + @Deprecated("") constructor(asset: OudsTagAsset.Icon.Default) : this(asset as? OudsTagAsset) + constructor(asset: OudsIcon.Default) : this(asset as? OudsTagAsset) + /** * Creates an instance of [OudsTagStatus.Positive] with no asset. */ @@ -652,8 +765,11 @@ sealed class OudsTagStatus(val asset: OudsTagAsset? = null) { /** * Creates an instance of [OudsTagStatus.Info] with its default dedicated icon. */ + @Deprecated("") constructor(asset: OudsTagAsset.Icon.Default) : this(asset as? OudsTagAsset) + constructor(asset: OudsIcon.Default) : this(asset as? OudsTagAsset) + /** * Creates an instance of [OudsTagStatus.Info] with no asset. */ @@ -677,8 +793,11 @@ sealed class OudsTagStatus(val asset: OudsTagAsset? = null) { /** * Creates an instance of [OudsTagStatus.Warning] with its default dedicated icon. */ + @Deprecated("") constructor(asset: OudsTagAsset.Icon.Default) : this(asset as? OudsTagAsset) + constructor(asset: OudsIcon.Default) : this(asset as? OudsTagAsset) + /** * Creates an instance of [OudsTagStatus.Warning] with no asset. */ @@ -716,8 +835,11 @@ sealed class OudsTagStatus(val asset: OudsTagAsset? = null) { /** * Creates an instance of [OudsTagStatus.Negative] with its default dedicated icon. */ + @Deprecated("") constructor(asset: OudsTagAsset.Icon.Default) : this(asset as? OudsTagAsset) + constructor(asset: OudsIcon.Default) : this(asset as? OudsTagAsset) + /** * Creates an instance of [OudsTagStatus.Negative] with no asset. */ @@ -799,8 +921,8 @@ internal fun PreviewOudsTag( icon && row in listOf( OudsTagStatus.Neutral::class.simpleName, OudsTagStatus.Accent::class.simpleName - ) -> OudsTagAsset.Icon(Icons.Outlined.FavoriteBorder) - icon -> OudsTagAsset.Icon.Default + ) -> OudsIcon(Icons.Outlined.FavoriteBorder) + icon -> OudsIcon.Default else -> null } val status = when (row) { @@ -844,7 +966,7 @@ internal fun PreviewOudsTagWithUntintedIcon(theme: OudsThemeContract) = OudsPrev ).map { it.simpleName.orEmpty() }, ) { column, row -> val size = enumValueOf(column) - val asset = OudsTagAsset.Icon(rememberRainbowHeartPainter(), false) + val asset = OudsIcon(rememberRainbowHeartPainter(), "", false) val status = when (row) { OudsTagStatus.Neutral::class.simpleName -> OudsTagStatus.Neutral(asset) OudsTagStatus.Accent::class.simpleName -> OudsTagStatus.Accent(asset) @@ -865,7 +987,7 @@ internal data class OudsTagPreviewParameter( val bullet: Boolean = false, val appearance: OudsTagAppearance = OudsTagDefaults.Appearance, val roundedCorners: Boolean = true, - val loader: OudsTagLoader? = null, + val loader: OudsLoader? = null, val enabled: Boolean = true ) @@ -877,7 +999,7 @@ private val previewParameterValues: List OudsTagPreviewParameter(bullet = true, appearance = OudsTagAppearance.Muted), OudsTagPreviewParameter(icon = true, appearance = OudsTagAppearance.Muted), OudsTagPreviewParameter(icon = true, roundedCorners = false), - OudsTagPreviewParameter(loader = OudsTagLoader(0.6f)), + OudsTagPreviewParameter(loader = OudsLoader(0.6f)), OudsTagPreviewParameter(enabled = false, appearance = OudsTagAppearance.Muted), ) diff --git a/core/src/main/java/com/orange/ouds/core/component/OudsTextArea.kt b/core/src/main/java/com/orange/ouds/core/component/OudsTextArea.kt index 660ed04e67..c3f1686ec9 100644 --- a/core/src/main/java/com/orange/ouds/core/component/OudsTextArea.kt +++ b/core/src/main/java/com/orange/ouds/core/component/OudsTextArea.kt @@ -154,7 +154,7 @@ fun OudsTextArea( placeholder: String? = null, enabled: Boolean = true, readOnly: Boolean = false, - loader: OudsTextInputLoader? = null, + loader: OudsLoader? = null, outlined: Boolean = false, error: OudsError? = null, helperText: String? = null, @@ -192,6 +192,113 @@ fun OudsTextArea( ) } +/** + * Text area is a UI element that allows to type, edit, or select longer blocks of textual data, such as comments, messages or descriptions; by expanding + * vertically and offering more space to input text. Text area includes features like a visible label, placeholder text, character limits and resize behavior; + * and is ideal for open-ended responses where users need to express detailed information. + * + * Rounded corners can be enabled or disabled using [OudsThemeSettings.roundedCornerTextInputs] property in the settings of the theme provided when calling + * the [com.orange.ouds.core.theme.OudsTheme] method. + * + * It is recommended to use state-based text areas rather than value-based ones, as they provide a more complete and reliable approach to managing + * the state of a text area. + * + * This variant, unlike the others, enables a vertical scrollbar when the input text exceeds the text area's maximum capacity. + * + * An overload accepting annotated types is available for rich text formatting. + * + * > Design guidelines: [unified-design-system.orange.com](https://r.orange.fr/r/S-ouds-doc-text-area) + * + * > Design name: Text Area + * + * > Design version: 1.2.1 + * + * @param textFieldState The editable text state of the text area, including both the text itself and position of the cursor or selection. + * @param modifier [Modifier] applied to the text area. + * @param label Label displayed above the text area. It describes the purpose of the input. + * @param placeholder Text displayed when the text area is empty. It provides a hint or guidance inside the field to suggest expected input. + * @param enabled Controls the enabled state of the text area. When `false`, this text area will not be focusable and will not react to input events. + * True by default. + * @param readOnly Controls the read-only state of the text area. When `true`, the text is visible but not editable. + * False by default. + * @param loader An optional loading progress indicator displayed in the text area to indicate an ongoing operation. + * @param outlined Controls the style of the text area. When `true`, it displays a minimalist text area with a transparent background and a visible + * stroke outlining the field. + * @param error Optional [OudsError] to indicate that the user input does not meet validation rules or expected formatting. Pass `null` if there is no error. + * @param helperText An optional helper text displayed below the text area. It conveys additional information about the input field, such as how it will be + * used. It should ideally only take up a single line, though it may wrap to multiple lines if required. + * @param helperLink An optional helper link displayed below or in place of the helper text. + * @param constrainedMaxWidth When `true`, the text area width is constrained to a maximum value defined by the design system. + * When `false`, no specific width constraint is applied, allowing the component to size itself or follow external modifiers. + * Defaults to `false`. + * @param keyboardOptions Software keyboard options that contain configurations such as [KeyboardType] and [ImeAction]. + * @param onKeyboardAction Called when the user presses the action button in the input method editor (IME), or by pressing the enter key on a hardware keyboard. + * By default, this parameter is null, and would execute the default behavior for a received IME Action e.g., [ImeAction.Done] would close the keyboard, + * [ImeAction.Next] would switch the focus to the next focusable item on the screen. + * @param onTextLayout Callback that is executed when the text layout becomes queryable. The callback receives a function that returns a [TextLayoutResult] if + * the layout can be calculated, or null if it cannot. The function reads the layout result from a snapshot state object, and will invalidate its caller when + * the layout result changes. A [TextLayoutResult] object contains paragraph information, size of the text, baselines and other details. The callback can be + * used to add additional decoration or functionality to the text. For example, to draw a cursor or selection around the text. [Density] scope is the one that + * was used while creating the given text layout. + * @param inputTransformation An optional [InputTransformation] that will be used to transform changes to the [TextFieldState] made by the user. The transformation + * will be applied to changes made by hardware and software keyboard events, pasting or dropping text, accessibility services, and tests. The transformation + * will _not_ be applied when changing the [textFieldState] programmatically, or when the transformation is changed. If the transformation is changed on an + * existing text field, it will be applied to the next user edit. The transformation will not immediately affect the current [textFieldState]. + * @param outputTransformation An optional [OutputTransformation] that transforms how the contents of the text field are presented. + * @param interactionSource An optional hoisted [MutableInteractionSource] for observing and emitting [Interaction]s for this text area. Note that if `null` + * is provided, interactions will still happen internally. + * @param autoResize Controls the height behavior of the text area. When `true`, the text area expands vertically to accommodate content up to its maximum height. + * When `false`, the height is fixed and will not expand as text is entered. Defaults to `true`. + * + * @sample com.orange.ouds.core.component.samples.OudsTextAreaStateBasedSample + * @sample com.orange.ouds.core.component.samples.OudsTextAreaStateBasedErrorSample + */ +@Deprecated("") +@Composable +fun OudsTextArea( + textFieldState: TextFieldState, + modifier: Modifier = Modifier, + label: String? = null, + placeholder: String? = null, + enabled: Boolean = true, + readOnly: Boolean = false, + @Suppress("DEPRECATION") loader: OudsTextInputLoader?, + outlined: Boolean = false, + error: OudsError? = null, + helperText: String? = null, + helperLink: OudsTextInputHelperLink? = null, + constrainedMaxWidth: Boolean = false, + keyboardOptions: KeyboardOptions = KeyboardOptions.Default, + onKeyboardAction: KeyboardActionHandler? = null, + onTextLayout: (Density.(getResult: () -> TextLayoutResult?) -> Unit)? = null, + inputTransformation: InputTransformation? = null, + outputTransformation: OutputTransformation? = null, + interactionSource: MutableInteractionSource? = null, + autoResize: Boolean = true +) { + OudsTextArea( + textFieldState = textFieldState, + modifier = modifier, + label = label, + placeholder = placeholder, + enabled = enabled, + readOnly = readOnly, + loader = loader?.toLoader(), + outlined = outlined, + error = error, + helperText = helperText, + helperLink = helperLink, + constrainedMaxWidth = constrainedMaxWidth, + keyboardOptions = keyboardOptions, + onKeyboardAction = onKeyboardAction, + onTextLayout = onTextLayout, + inputTransformation = inputTransformation, + outputTransformation = outputTransformation, + interactionSource = interactionSource, + autoResize = autoResize + ) +} + @Deprecated( "Maintained for binary compatibility. Use overload with additional parameters.", level = DeprecationLevel.HIDDEN @@ -204,7 +311,7 @@ fun OudsTextArea( placeholder: String? = null, enabled: Boolean = true, readOnly: Boolean = false, - loader: OudsTextInputLoader? = null, + @Suppress("DEPRECATION") loader: OudsTextInputLoader? = null, outlined: Boolean = false, error: OudsError? = null, helperText: String? = null, @@ -224,11 +331,10 @@ fun OudsTextArea( placeholder = placeholder, enabled = enabled, readOnly = readOnly, - loader = loader, + loader = loader?.toLoader(), outlined = outlined, error = error, helperText = helperText, - annotatedHelperText = null, helperLink = helperLink, constrainedMaxWidth = constrainedMaxWidth, keyboardOptions = keyboardOptions, @@ -311,7 +417,7 @@ fun OudsTextArea( placeholder: String? = null, enabled: Boolean = true, readOnly: Boolean = false, - loader: OudsTextInputLoader? = null, + loader: OudsLoader? = null, outlined: Boolean = false, error: OudsError? = null, helperText: OudsAnnotatedHelperText, @@ -349,6 +455,114 @@ fun OudsTextArea( ) } +/** + * Text area is a UI element that allows to type, edit, or select longer blocks of textual data, such as comments, messages or descriptions; by expanding + * vertically and offering more space to input text. Text area includes features like a visible label, placeholder text, character limits and resize behavior; + * and is ideal for open-ended responses where users need to express detailed information. + * + * Rounded corners can be enabled or disabled using [OudsThemeSettings.roundedCornerTextInputs] property in the settings of the theme provided when calling + * the [com.orange.ouds.core.theme.OudsTheme] method. + * + * It is recommended to use state-based text areas rather than value-based ones, as they provide a more complete and reliable approach to managing + * the state of a text area. + * + * This variant, unlike the others, enables a vertical scrollbar when the input text exceeds the text area's maximum capacity. + * + * An overload accepting plain types is available for simple text without formatting. + * + * > Design guidelines: [unified-design-system.orange.com](https://r.orange.fr/r/S-ouds-doc-text-area) + * + * > Design name: Text Area + * + * > Design version: 1.2.1 + * + * @param textFieldState The editable text state of the text area, including both the text itself and position of the cursor or selection. + * @param modifier [Modifier] applied to the text area. + * @param label Label displayed above the text area. It describes the purpose of the input. + * @param placeholder Text displayed when the text area is empty. It provides a hint or guidance inside the field to suggest expected input. + * @param enabled Controls the enabled state of the text area. When `false`, this text area will not be focusable and will not react to input events. + * True by default. + * @param readOnly Controls the read-only state of the text area. When `true`, the text is visible but not editable. + * False by default. + * @param loader An optional loading progress indicator displayed in the text area to indicate an ongoing operation. + * @param outlined Controls the style of the text area. When `true`, it displays a minimalist text area with a transparent background and a visible + * stroke outlining the field. + * @param error Optional [OudsError] to indicate that the user input does not meet validation rules or expected formatting. Pass `null` if there is no error. + * @param helperText An annotated helper text displayed below the text area. It conveys additional information about the input field, such as how it will be + * used. It should ideally only take up a single line, though it may wrap to multiple lines if required. + * @param helperLink An optional helper link displayed below or in place of the helper text. + * @param constrainedMaxWidth When `true`, the text area width is constrained to a maximum value defined by the design system. + * When `false`, no specific width constraint is applied, allowing the component to size itself or follow external modifiers. + * Defaults to `false`. + * @param keyboardOptions Software keyboard options that contain configurations such as [KeyboardType] and [ImeAction]. + * @param onKeyboardAction Called when the user presses the action button in the input method editor (IME), or by pressing the enter key on a hardware keyboard. + * By default, this parameter is null, and would execute the default behavior for a received IME Action e.g., [ImeAction.Done] would close the keyboard, + * [ImeAction.Next] would switch the focus to the next focusable item on the screen. + * @param onTextLayout Callback that is executed when the text layout becomes queryable. The callback receives a function that returns a [TextLayoutResult] if + * the layout can be calculated, or null if it cannot. The function reads the layout result from a snapshot state object, and will invalidate its caller when + * the layout result changes. A [TextLayoutResult] object contains paragraph information, size of the text, baselines and other details. The callback can be + * used to add additional decoration or functionality to the text. For example, to draw a cursor or selection around the text. [Density] scope is the one that + * was used while creating the given text layout. + * @param inputTransformation An optional [InputTransformation] that will be used to transform changes to the [TextFieldState] made by the user. The transformation + * will be applied to changes made by hardware and software keyboard events, pasting or dropping text, accessibility services, and tests. The transformation + * will _not_ be applied when changing the [textFieldState] programmatically, or when the transformation is changed. If the transformation is changed on an + * existing text field, it will be applied to the next user edit. The transformation will not immediately affect the current [textFieldState]. + * @param outputTransformation An optional [OutputTransformation] that transforms how the contents of the text field are presented. + * @param interactionSource An optional hoisted [MutableInteractionSource] for observing and emitting [Interaction]s for this text area. Note that if `null` + * is provided, interactions will still happen internally. + * @param autoResize Controls the height behavior of the text area. When `true`, the text area expands vertically to accommodate content up to its maximum height. + * When `false`, the height is fixed and will not expand as text is entered. Defaults to `true`. + * + * @sample com.orange.ouds.core.component.samples.OudsTextAreaStateBasedSample + * @sample com.orange.ouds.core.component.samples.OudsTextAreaStateBasedWithAnnotatedErrorMessageSample + * @sample com.orange.ouds.core.component.samples.OudsTextAreaStateBasedWithAnnotatedHelperTextSample + */ +@Deprecated("") +@Composable +fun OudsTextArea( + textFieldState: TextFieldState, + modifier: Modifier = Modifier, + label: String? = null, + placeholder: String? = null, + enabled: Boolean = true, + readOnly: Boolean = false, + @Suppress("DEPRECATION") loader: OudsTextInputLoader?, + outlined: Boolean = false, + error: OudsError? = null, + helperText: OudsAnnotatedHelperText, + helperLink: OudsTextInputHelperLink? = null, + constrainedMaxWidth: Boolean = false, + keyboardOptions: KeyboardOptions = KeyboardOptions.Default, + onKeyboardAction: KeyboardActionHandler? = null, + onTextLayout: (Density.(getResult: () -> TextLayoutResult?) -> Unit)? = null, + inputTransformation: InputTransformation? = null, + outputTransformation: OutputTransformation? = null, + interactionSource: MutableInteractionSource? = null, + autoResize: Boolean = true +) { + OudsTextArea( + textFieldState = textFieldState, + modifier = modifier, + label = label, + placeholder = placeholder, + enabled = enabled, + readOnly = readOnly, + loader = loader?.toLoader(), + outlined = outlined, + error = error, + helperText = helperText, + helperLink = helperLink, + constrainedMaxWidth = constrainedMaxWidth, + keyboardOptions = keyboardOptions, + onKeyboardAction = onKeyboardAction, + onTextLayout = onTextLayout, + inputTransformation = inputTransformation, + outputTransformation = outputTransformation, + interactionSource = interactionSource, + autoResize = autoResize + ) +} + @Deprecated( "Maintained for binary compatibility. Use overload with additional parameters.", level = DeprecationLevel.HIDDEN @@ -361,7 +575,7 @@ fun OudsTextArea( placeholder: String? = null, enabled: Boolean = true, readOnly: Boolean = false, - loader: OudsTextInputLoader? = null, + @Suppress("DEPRECATION") loader: OudsTextInputLoader? = null, outlined: Boolean = false, error: OudsError? = null, helperText: OudsAnnotatedHelperText, @@ -381,11 +595,10 @@ fun OudsTextArea( placeholder = placeholder, enabled = enabled, readOnly = readOnly, - loader = loader, + loader = loader?.toLoader(), outlined = outlined, error = error, - helperText = null, - annotatedHelperText = helperText, + helperText = helperText, helperLink = helperLink, constrainedMaxWidth = constrainedMaxWidth, keyboardOptions = keyboardOptions, @@ -406,7 +619,7 @@ private fun OudsTextArea( placeholder: String? = null, enabled: Boolean = true, readOnly: Boolean = false, - loader: OudsTextInputLoader? = null, + loader: OudsLoader? = null, outlined: Boolean = false, error: OudsError? = null, helperText: String? = null, @@ -537,7 +750,7 @@ fun OudsTextArea( placeholder: String? = null, enabled: Boolean = true, readOnly: Boolean = false, - loader: OudsTextInputLoader? = null, + loader: OudsLoader? = null, outlined: Boolean = false, error: OudsError? = null, helperText: String? = null, @@ -574,6 +787,108 @@ fun OudsTextArea( ) } +/** + * Text area is a UI element that allows to type, edit, or select longer blocks of textual data, such as comments, messages or descriptions; by expanding + * vertically and offering more space to input text. Text area includes features like a visible label, placeholder text, character limits and resize behavior; + * and is ideal for open-ended responses where users need to express detailed information. + * + * Rounded corners can be enabled or disabled using [OudsThemeSettings.roundedCornerTextInputs] property in the settings of the theme provided when calling + * the [com.orange.ouds.core.theme.OudsTheme] method. + * + * It is recommended to use state-based text areas rather than value-based ones, as they provide a more complete and reliable approach to managing + * the state of a text area. + * + * Note: This variant does not support a vertical scrollbar. For scrollbar functionality when text exceeds the available space, please use the state-based + * version of [OudsTextArea]. + * + * An overload accepting annotated types is available for rich text formatting. + * + * > Design guidelines: [unified-design-system.orange.com](https://r.orange.fr/r/S-ouds-doc-text-area) + * + * > Design name: Text Area + * + * > Design version: 1.2.1 + * + * @param value Input text to be shown in the text area. + * @param onValueChange Callback that is triggered when the input service updates the text. An updated text comes as a parameter of the callback. + * @param modifier [Modifier] applied to the text area. + * @param label Label displayed above the text area. It describes the purpose of the input. + * @param placeholder Text displayed when the text area is empty. It provides a hint or guidance inside the field to suggest expected input. + * @param enabled Controls the enabled state of the text area. When `false`, this text area will not be focusable and will not react to input events. + * True by default. + * @param readOnly Controls the read-only state of the text area. When `true`, the text is visible but not editable. + * False by default. + * @param loader An optional loading progress indicator displayed in the text area to indicate an ongoing operation. + * @param outlined Controls the style of the text area. When `true`, it displays a minimalist text area with a transparent background and a visible + * stroke outlining the field. + * @param error Optional [OudsError] to indicate that the user input does not meet validation rules or expected formatting. Pass `null` if there is no error. + * @param helperText An optional helper text displayed below the text area. It conveys additional information about the input field, such as how it will be + * used. It should ideally only take up a single line, though it may wrap to multiple lines if required. + * @param helperLink An optional helper link displayed below or in place of the helper text. + * @param constrainedMaxWidth When `true`, the text area width is constrained to a maximum value defined by the design system. + * When `false`, no specific width constraint is applied, allowing the component to size itself or follow external modifiers. + * Defaults to `false`. + * @param keyboardOptions Software keyboard options that contain configuration such as [KeyboardType] and [ImeAction]. + * @param keyboardActions When the input service emits an IME action, the corresponding callback is called. Note that this IME action may be different from what + * you specified in [KeyboardOptions.imeAction]. + * @param onTextLayout Callback that is executed when a new text layout is calculated. A [TextLayoutResult] object that callback provides contains paragraph + * information, size of the text, baselines and other details. The callback can be used to add additional decoration or functionality to the text. + * For example, to draw a cursor or selection around the text. + * @param visualTransformation The visual transformation filter for changing the visual representation of the input. By default, no visual transformation is applied. + * @param interactionSource An optional hoisted [MutableInteractionSource] for observing and emitting [Interaction]s for this text area. Note that if `null` + * is provided, interactions will still happen internally. + * @param autoResize Controls the height behavior of the text area. When `true`, the text area expands vertically to accommodate content up to its maximum height. + * When `false`, the height is fixed and will not expand as text is entered. Defaults to `true`. + * + * @sample com.orange.ouds.core.component.samples.OudsTextAreaValueBasedSample + * @sample com.orange.ouds.core.component.samples.OudsTextAreaValueBasedErrorSample + */ +@Deprecated("") +@Composable +fun OudsTextArea( + value: String, + onValueChange: (String) -> Unit, + modifier: Modifier = Modifier, + label: String? = null, + placeholder: String? = null, + enabled: Boolean = true, + readOnly: Boolean = false, + @Suppress("DEPRECATION") loader: OudsTextInputLoader?, + outlined: Boolean = false, + error: OudsError? = null, + helperText: String? = null, + helperLink: OudsTextInputHelperLink? = null, + constrainedMaxWidth: Boolean = false, + keyboardOptions: KeyboardOptions = KeyboardOptions.Default, + keyboardActions: KeyboardActions = KeyboardActions.Default, + onTextLayout: (TextLayoutResult) -> Unit = {}, + visualTransformation: VisualTransformation = VisualTransformation.None, + interactionSource: MutableInteractionSource? = null, + autoResize: Boolean = true +) { + OudsTextArea( + value = value, + onValueChange = onValueChange, + modifier = modifier, + label = label, + placeholder = placeholder, + enabled = enabled, + readOnly = readOnly, + loader = loader?.toLoader(), + outlined = outlined, + error = error, + helperText = helperText, + helperLink = helperLink, + constrainedMaxWidth = constrainedMaxWidth, + keyboardOptions = keyboardOptions, + keyboardActions = keyboardActions, + onTextLayout = onTextLayout, + visualTransformation = visualTransformation, + interactionSource = interactionSource, + autoResize = autoResize + ) +} + @Deprecated( "Maintained for binary compatibility. Use overload with additional parameters.", level = DeprecationLevel.HIDDEN @@ -587,17 +902,119 @@ fun OudsTextArea( placeholder: String? = null, enabled: Boolean = true, readOnly: Boolean = false, - loader: OudsTextInputLoader? = null, + @Suppress("DEPRECATION") loader: OudsTextInputLoader? = null, + outlined: Boolean = false, + error: OudsError? = null, + helperText: String? = null, + helperLink: OudsTextInputHelperLink? = null, + constrainedMaxWidth: Boolean = false, + keyboardOptions: KeyboardOptions = KeyboardOptions.Default, + keyboardActions: KeyboardActions = KeyboardActions.Default, + onTextLayout: (TextLayoutResult) -> Unit = {}, + visualTransformation: VisualTransformation = VisualTransformation.None, + interactionSource: MutableInteractionSource? = null +) { + OudsTextArea( + value = value, + onValueChange = onValueChange, + modifier = modifier, + label = label, + placeholder = placeholder, + enabled = enabled, + readOnly = readOnly, + loader = loader?.toLoader(), + outlined = outlined, + error = error, + helperText = helperText, + helperLink = helperLink, + constrainedMaxWidth = constrainedMaxWidth, + keyboardOptions = keyboardOptions, + keyboardActions = keyboardActions, + onTextLayout = onTextLayout, + visualTransformation = visualTransformation, + interactionSource = interactionSource, + autoResize = true + ) +} + +/** + * Text area is a UI element that allows to type, edit, or select longer blocks of textual data, such as comments, messages or descriptions; by expanding + * vertically and offering more space to input text. Text area includes features like a visible label, placeholder text, character limits and resize behavior; + * and is ideal for open-ended responses where users need to express detailed information. + * + * Rounded corners can be enabled or disabled using [OudsThemeSettings.roundedCornerTextInputs] property in the settings of the theme provided when calling + * the [com.orange.ouds.core.theme.OudsTheme] method. + * + * It is recommended to use state-based text areas rather than value-based ones, as they provide a more complete and reliable approach to managing + * the state of a text area. + * + * Note: This variant does not support a vertical scrollbar. For scrollbar functionality when text exceeds the available space, please use the state-based + * version of [OudsTextArea]. + * + * An overload accepting plain types is available for simple text without formatting. + * + * > Design guidelines: [unified-design-system.orange.com](https://r.orange.fr/r/S-ouds-doc-text-area) + * + * > Design name: Text Area + * + * > Design version: 1.2.1 + * + * @param value Input text to be shown in the text area. + * @param onValueChange Callback that is triggered when the input service updates the text. An updated text comes as a parameter of the callback. + * @param modifier [Modifier] applied to the text area. + * @param label Label displayed above the text area. It describes the purpose of the input. + * @param placeholder Text displayed when the text area is empty. It provides a hint or guidance inside the field to suggest expected input. + * @param enabled Controls the enabled state of the text area. When `false`, this text area will not be focusable and will not react to input events. + * True by default. + * @param readOnly Controls the read-only state of the text area. When `true`, the text is visible but not editable. + * False by default. + * @param loader An optional loading progress indicator displayed in the text area to indicate an ongoing operation. + * @param outlined Controls the style of the text area. When `true`, it displays a minimalist text area with a transparent background and a visible + * stroke outlining the field. + * @param error Optional [OudsError] to indicate that the user input does not meet validation rules or expected formatting. Pass `null` if there is no error. + * @param helperText An annotated helper text displayed below the text area. It conveys additional information about the input field, such as how it will be + * used. It should ideally only take up a single line, though it may wrap to multiple lines if required. + * @param helperLink An optional helper link displayed below or in place of the helper text. + * @param constrainedMaxWidth When `true`, the text area width is constrained to a maximum value defined by the design system. + * When `false`, no specific width constraint is applied, allowing the component to size itself or follow external modifiers. + * Defaults to `false`. + * @param keyboardOptions Software keyboard options that contain configuration such as [KeyboardType] and [ImeAction]. + * @param keyboardActions When the input service emits an IME action, the corresponding callback is called. Note that this IME action may be different from what + * you specified in [KeyboardOptions.imeAction]. + * @param onTextLayout Callback that is executed when a new text layout is calculated. A [TextLayoutResult] object that callback provides contains paragraph + * information, size of the text, baselines and other details. The callback can be used to add additional decoration or functionality to the text. + * For example, to draw a cursor or selection around the text. + * @param visualTransformation The visual transformation filter for changing the visual representation of the input. By default, no visual transformation is applied. + * @param interactionSource An optional hoisted [MutableInteractionSource] for observing and emitting [Interaction]s for this text area. Note that if `null` + * is provided, interactions will still happen internally. + * @param autoResize Controls the height behavior of the text area. When `true`, the text area expands vertically to accommodate content up to its maximum height. + * When `false`, the height is fixed and will not expand as text is entered. Defaults to `true`. + * + * @sample com.orange.ouds.core.component.samples.OudsTextAreaValueBasedSample + * @sample com.orange.ouds.core.component.samples.OudsTextAreaValueBasedWithAnnotatedErrorMessageSample + * @sample com.orange.ouds.core.component.samples.OudsTextAreaValueBasedWithAnnotatedHelperTextSample + */ +@Composable +fun OudsTextArea( + value: String, + onValueChange: (String) -> Unit, + modifier: Modifier = Modifier, + label: String? = null, + placeholder: String? = null, + enabled: Boolean = true, + readOnly: Boolean = false, + loader: OudsLoader? = null, outlined: Boolean = false, error: OudsError? = null, - helperText: String? = null, + helperText: OudsAnnotatedHelperText, helperLink: OudsTextInputHelperLink? = null, constrainedMaxWidth: Boolean = false, keyboardOptions: KeyboardOptions = KeyboardOptions.Default, keyboardActions: KeyboardActions = KeyboardActions.Default, onTextLayout: (TextLayoutResult) -> Unit = {}, visualTransformation: VisualTransformation = VisualTransformation.None, - interactionSource: MutableInteractionSource? = null + interactionSource: MutableInteractionSource? = null, + autoResize: Boolean = true ) { OudsTextArea( value = value, @@ -610,8 +1027,8 @@ fun OudsTextArea( loader = loader, outlined = outlined, error = error, - helperText = helperText, - annotatedHelperText = null, + helperText = null, + annotatedHelperText = helperText, helperLink = helperLink, constrainedMaxWidth = constrainedMaxWidth, keyboardOptions = keyboardOptions, @@ -619,7 +1036,7 @@ fun OudsTextArea( onTextLayout = onTextLayout, visualTransformation = visualTransformation, interactionSource = interactionSource, - autoResize = true + autoResize = autoResize ) } @@ -680,6 +1097,7 @@ fun OudsTextArea( * @sample com.orange.ouds.core.component.samples.OudsTextAreaValueBasedWithAnnotatedErrorMessageSample * @sample com.orange.ouds.core.component.samples.OudsTextAreaValueBasedWithAnnotatedHelperTextSample */ +@Deprecated("") @Composable fun OudsTextArea( value: String, @@ -689,7 +1107,7 @@ fun OudsTextArea( placeholder: String? = null, enabled: Boolean = true, readOnly: Boolean = false, - loader: OudsTextInputLoader? = null, + @Suppress("DEPRECATION") loader: OudsTextInputLoader?, outlined: Boolean = false, error: OudsError? = null, helperText: OudsAnnotatedHelperText, @@ -710,11 +1128,10 @@ fun OudsTextArea( placeholder = placeholder, enabled = enabled, readOnly = readOnly, - loader = loader, + loader = loader?.toLoader(), outlined = outlined, error = error, - helperText = null, - annotatedHelperText = helperText, + helperText = helperText, helperLink = helperLink, constrainedMaxWidth = constrainedMaxWidth, keyboardOptions = keyboardOptions, @@ -726,7 +1143,6 @@ fun OudsTextArea( ) } - @Deprecated( "Maintained for binary compatibility. Use overload with additional parameters.", level = DeprecationLevel.HIDDEN @@ -740,7 +1156,7 @@ fun OudsTextArea( placeholder: String? = null, enabled: Boolean = true, readOnly: Boolean = false, - loader: OudsTextInputLoader? = null, + @Suppress("DEPRECATION") loader: OudsTextInputLoader? = null, outlined: Boolean = false, error: OudsError? = null, helperText: OudsAnnotatedHelperText, @@ -760,11 +1176,10 @@ fun OudsTextArea( placeholder = placeholder, enabled = enabled, readOnly = readOnly, - loader = loader, + loader = loader?.toLoader(), outlined = outlined, error = error, - helperText = null, - annotatedHelperText = helperText, + helperText = helperText, helperLink = helperLink, constrainedMaxWidth = constrainedMaxWidth, keyboardOptions = keyboardOptions, @@ -785,7 +1200,7 @@ private fun OudsTextArea( placeholder: String? = null, enabled: Boolean = true, readOnly: Boolean = false, - loader: OudsTextInputLoader? = null, + loader: OudsLoader? = null, outlined: Boolean = false, error: OudsError? = null, helperText: String? = null, @@ -912,7 +1327,7 @@ fun OudsTextArea( placeholder: String? = null, enabled: Boolean = true, readOnly: Boolean = false, - loader: OudsTextInputLoader? = null, + loader: OudsLoader? = null, outlined: Boolean = false, error: OudsError? = null, helperText: String? = null, @@ -949,6 +1364,108 @@ fun OudsTextArea( ) } +/** + * Text area is a UI element that allows to type, edit, or select longer blocks of textual data, such as comments, messages or descriptions; by expanding + * vertically and offering more space to input text. Text area includes features like a visible label, placeholder text, character limits and resize behavior; + * and is ideal for open-ended responses where users need to express detailed information. + * + * Rounded corners can be enabled or disabled using [OudsThemeSettings.roundedCornerTextInputs] property in the settings of the theme provided when calling + * the [com.orange.ouds.core.theme.OudsTheme] method. + * + * It is recommended to use state-based text areas rather than value-based ones, as they provide a more complete and reliable approach to managing + * the state of a text area. + * + * Note: This variant does not support a vertical scrollbar. For scrollbar functionality when text exceeds the available space, please use the state-based + * version of [OudsTextArea]. + * + * An overload accepting annotated types is available for rich text formatting. + * + * > Design guidelines: [unified-design-system.orange.com](https://r.orange.fr/r/S-ouds-doc-text-area) + * + * > Design name: Text Area + * + * > Design version: 1.2.1 + * + * @param value The [androidx.compose.ui.text.input.TextFieldValue] to be shown in the text area. + * @param onValueChange Called when the input service updates the values in [TextFieldValue]. + * @param modifier [Modifier] applied to the text area. + * @param label Label displayed above the text area. It describes the purpose of the input. + * @param placeholder Text displayed when the text area is empty. It provides a hint or guidance inside the field to suggest expected input. + * @param enabled Controls the enabled state of the text area. When `false`, this text area will not be focusable and will not react to input events. + * True by default. + * @param readOnly Controls the read-only state of the text area. When `true`, the text is visible but not editable. + * False by default. + * @param loader An optional loading progress indicator displayed in the text area to indicate an ongoing operation. + * @param outlined Controls the style of the text area. When `true`, it displays a minimalist text area with a transparent background and a visible + * stroke outlining the field. + * @param error Optional [OudsError] to indicate that the user input does not meet validation rules or expected formatting. Pass `null` if there is no error. + * @param helperText An optional helper text displayed below the text area. It conveys additional information about the input field, such as how it will be + * used. It should ideally only take up a single line, though it may wrap to multiple lines if required. + * @param helperLink An optional helper link displayed below or in place of the helper text. + * @param constrainedMaxWidth When `true`, the text area width is constrained to a maximum value defined by the design system. + * When `false`, no specific width constraint is applied, allowing the component to size itself or follow external modifiers. + * Defaults to `false`. + * @param keyboardOptions Software keyboard options that contain configuration such as [KeyboardType] and [ImeAction]. + * @param keyboardActions When the input service emits an IME action, the corresponding callback is called. Note that this IME action may be different from what + * you specified in [KeyboardOptions.imeAction]. + * @param onTextLayout Callback that is executed when a new text layout is calculated. A [TextLayoutResult] object that callback provides contains paragraph + * information, size of the text, baselines and other details. The callback can be used to add additional decoration or functionality to the text. + * For example, to draw a cursor or selection around the text. + * @param visualTransformation The visual transformation filter for changing the visual representation of the input. By default, no visual transformation is applied. + * @param interactionSource An optional hoisted [MutableInteractionSource] for observing and emitting [Interaction]s for this text area. Note that if `null` + * is provided, interactions will still happen internally. + * @param autoResize Controls the height behavior of the text area. When `true`, the text area expands vertically to accommodate content up to its maximum height. + * When `false`, the height is fixed and will not expand as text is entered. Defaults to `true`. + * + * @sample com.orange.ouds.core.component.samples.OudsTextAreaValueBasedSample + * @sample com.orange.ouds.core.component.samples.OudsTextAreaValueBasedErrorSample + */ +@Deprecated("") +@Composable +fun OudsTextArea( + value: TextFieldValue, + onValueChange: (TextFieldValue) -> Unit, + modifier: Modifier = Modifier, + label: String? = null, + placeholder: String? = null, + enabled: Boolean = true, + readOnly: Boolean = false, + @Suppress("DEPRECATION") loader: OudsTextInputLoader?, + outlined: Boolean = false, + error: OudsError? = null, + helperText: String? = null, + helperLink: OudsTextInputHelperLink? = null, + constrainedMaxWidth: Boolean = false, + keyboardOptions: KeyboardOptions = KeyboardOptions.Default, + keyboardActions: KeyboardActions = KeyboardActions.Default, + onTextLayout: (TextLayoutResult) -> Unit = {}, + visualTransformation: VisualTransformation = VisualTransformation.None, + interactionSource: MutableInteractionSource? = null, + autoResize: Boolean = true +) { + OudsTextArea( + value = value, + onValueChange = onValueChange, + modifier = modifier, + label = label, + placeholder = placeholder, + enabled = enabled, + readOnly = readOnly, + loader = loader?.toLoader(), + outlined = outlined, + error = error, + helperText = helperText, + helperLink = helperLink, + constrainedMaxWidth = constrainedMaxWidth, + keyboardOptions = keyboardOptions, + keyboardActions = keyboardActions, + onTextLayout = onTextLayout, + visualTransformation = visualTransformation, + interactionSource = interactionSource, + autoResize = autoResize + ) +} + @Deprecated( "Maintained for binary compatibility. Use overload with additional parameters.", level = DeprecationLevel.HIDDEN @@ -962,7 +1479,7 @@ fun OudsTextArea( placeholder: String? = null, enabled: Boolean = true, readOnly: Boolean = false, - loader: OudsTextInputLoader? = null, + @Suppress("DEPRECATION") loader: OudsTextInputLoader? = null, outlined: Boolean = false, error: OudsError? = null, helperText: String? = null, @@ -982,11 +1499,10 @@ fun OudsTextArea( placeholder = placeholder, enabled = enabled, readOnly = readOnly, - loader = loader, + loader = loader?.toLoader(), outlined = outlined, error = error, helperText = helperText, - annotatedHelperText = null, helperLink = helperLink, constrainedMaxWidth = constrainedMaxWidth, keyboardOptions = keyboardOptions, @@ -1064,7 +1580,7 @@ fun OudsTextArea( placeholder: String? = null, enabled: Boolean = true, readOnly: Boolean = false, - loader: OudsTextInputLoader? = null, + loader: OudsLoader? = null, outlined: Boolean = false, error: OudsError? = null, helperText: OudsAnnotatedHelperText, @@ -1101,6 +1617,109 @@ fun OudsTextArea( ) } +/** + * Text area is a UI element that allows to type, edit, or select longer blocks of textual data, such as comments, messages or descriptions; by expanding + * vertically and offering more space to input text. Text area includes features like a visible label, placeholder text, character limits and resize behavior; + * and is ideal for open-ended responses where users need to express detailed information. + * + * Rounded corners can be enabled or disabled using [OudsThemeSettings.roundedCornerTextInputs] property in the settings of the theme provided when calling + * the [com.orange.ouds.core.theme.OudsTheme] method. + * + * It is recommended to use state-based text areas rather than value-based ones, as they provide a more complete and reliable approach to managing + * the state of a text area. + * + * Note: This variant does not support a vertical scrollbar. For scrollbar functionality when text exceeds the available space, please use the state-based + * version of [OudsTextArea]. + * + * An overload accepting plain types is available for simple text without formatting. + * + * > Design guidelines: [unified-design-system.orange.com](https://r.orange.fr/r/S-ouds-doc-text-area) + * + * > Design name: Text Area + * + * > Design version: 1.2.1 + * + * @param value The [androidx.compose.ui.text.input.TextFieldValue] to be shown in the text area. + * @param onValueChange Called when the input service updates the values in [TextFieldValue]. + * @param modifier [Modifier] applied to the text area. + * @param label Label displayed above the text area. It describes the purpose of the input. + * @param placeholder Text displayed when the text area is empty. It provides a hint or guidance inside the field to suggest expected input. + * @param enabled Controls the enabled state of the text area. When `false`, this text area will not be focusable and will not react to input events. + * True by default. + * @param readOnly Controls the read-only state of the text area. When `true`, the text is visible but not editable. + * False by default. + * @param loader An optional loading progress indicator displayed in the text area to indicate an ongoing operation. + * @param outlined Controls the style of the text area. When `true`, it displays a minimalist text area with a transparent background and a visible + * stroke outlining the field. + * @param error Optional [OudsError] to indicate that the user input does not meet validation rules or expected formatting. Pass `null` if there is no error. + * @param helperText An annotated helper text displayed below the text area. It conveys additional information about the input field, such as how it will be + * used. It should ideally only take up a single line, though it may wrap to multiple lines if required. + * @param helperLink An optional helper link displayed below or in place of the helper text. + * @param constrainedMaxWidth When `true`, the text area width is constrained to a maximum value defined by the design system. + * When `false`, no specific width constraint is applied, allowing the component to size itself or follow external modifiers. + * Defaults to `false`. + * @param keyboardOptions Software keyboard options that contain configuration such as [KeyboardType] and [ImeAction]. + * @param keyboardActions When the input service emits an IME action, the corresponding callback is called. Note that this IME action may be different from what + * you specified in [KeyboardOptions.imeAction]. + * @param onTextLayout Callback that is executed when a new text layout is calculated. A [TextLayoutResult] object that callback provides contains paragraph + * information, size of the text, baselines and other details. The callback can be used to add additional decoration or functionality to the text. + * For example, to draw a cursor or selection around the text. + * @param visualTransformation The visual transformation filter for changing the visual representation of the input. By default, no visual transformation is applied. + * @param interactionSource An optional hoisted [MutableInteractionSource] for observing and emitting [Interaction]s for this text area. Note that if `null` + * is provided, interactions will still happen internally. + * @param autoResize Controls the height behavior of the text area. When `true`, the text area expands vertically to accommodate content up to its maximum height. + * When `false`, the height is fixed and will not expand as text is entered. Defaults to `true`. + * + * @sample com.orange.ouds.core.component.samples.OudsTextAreaValueBasedSample + * @sample com.orange.ouds.core.component.samples.OudsTextAreaValueBasedWithAnnotatedErrorMessageSample + * @sample com.orange.ouds.core.component.samples.OudsTextAreaValueBasedWithAnnotatedHelperTextSample + */ +@Deprecated("") +@Composable +fun OudsTextArea( + value: TextFieldValue, + onValueChange: (TextFieldValue) -> Unit, + modifier: Modifier = Modifier, + label: String? = null, + placeholder: String? = null, + enabled: Boolean = true, + readOnly: Boolean = false, + @Suppress("DEPRECATION") loader: OudsTextInputLoader?, + outlined: Boolean = false, + error: OudsError? = null, + helperText: OudsAnnotatedHelperText, + helperLink: OudsTextInputHelperLink? = null, + constrainedMaxWidth: Boolean = false, + keyboardOptions: KeyboardOptions = KeyboardOptions.Default, + keyboardActions: KeyboardActions = KeyboardActions.Default, + onTextLayout: (TextLayoutResult) -> Unit = {}, + visualTransformation: VisualTransformation = VisualTransformation.None, + interactionSource: MutableInteractionSource? = null, + autoResize: Boolean = true +) { + OudsTextArea( + value = value, + onValueChange = onValueChange, + modifier = modifier, + label = label, + placeholder = placeholder, + enabled = enabled, + readOnly = readOnly, + loader = loader?.toLoader(), + outlined = outlined, + error = error, + helperText = helperText, + helperLink = helperLink, + constrainedMaxWidth = constrainedMaxWidth, + keyboardOptions = keyboardOptions, + keyboardActions = keyboardActions, + onTextLayout = onTextLayout, + visualTransformation = visualTransformation, + interactionSource = interactionSource, + autoResize = autoResize + ) +} + @Deprecated( "Maintained for binary compatibility. Use overload with additional parameters.", level = DeprecationLevel.HIDDEN @@ -1114,7 +1733,7 @@ fun OudsTextArea( placeholder: String? = null, enabled: Boolean = true, readOnly: Boolean = false, - loader: OudsTextInputLoader? = null, + @Suppress("DEPRECATION") loader: OudsTextInputLoader? = null, outlined: Boolean = false, error: OudsError? = null, helperText: OudsAnnotatedHelperText, @@ -1134,11 +1753,10 @@ fun OudsTextArea( placeholder = placeholder, enabled = enabled, readOnly = readOnly, - loader = loader, + loader = loader?.toLoader(), outlined = outlined, error = error, - helperText = null, - annotatedHelperText = helperText, + helperText = helperText, helperLink = helperLink, constrainedMaxWidth = constrainedMaxWidth, keyboardOptions = keyboardOptions, @@ -1159,7 +1777,7 @@ private fun OudsTextArea( placeholder: String? = null, enabled: Boolean = true, readOnly: Boolean = false, - loader: OudsTextInputLoader? = null, + loader: OudsLoader? = null, outlined: Boolean = false, error: OudsError? = null, helperText: String? = null, @@ -1247,7 +1865,7 @@ internal fun OudsTextAreaDecorator( state: OudsTextInputState, label: String?, placeholder: String?, - loader: OudsTextInputLoader?, + loader: OudsLoader?, outlined: Boolean, error: OudsError?, helperText: String?, @@ -1476,7 +2094,7 @@ internal fun PreviewOudsTextAreaAutoResize( OudsTextArea( textFieldState = rememberTextFieldState(List(lineCount) { "Line ${it + 1}" }.joinToString("\n")), label = "$lineCount lines", - loader = OudsTextInputLoader(progress = 0.75f), + loader = OudsLoader(progress = 0.75f), autoResize = autoResize ) } diff --git a/core/src/main/java/com/orange/ouds/core/component/OudsTextInput.kt b/core/src/main/java/com/orange/ouds/core/component/OudsTextInput.kt index d72dff20fa..cf60bc544b 100644 --- a/core/src/main/java/com/orange/ouds/core/component/OudsTextInput.kt +++ b/core/src/main/java/com/orange/ouds/core/component/OudsTextInput.kt @@ -174,27 +174,786 @@ fun OudsTextInput( modifier: Modifier = Modifier, label: String? = null, placeholder: String? = null, - leadingIcon: OudsTextInputLeadingIcon? = null, + leadingIcon: OudsIcon? = null, + trailingIconButton: OudsIconButton? = null, + prefix: String? = null, + suffix: String? = null, + enabled: Boolean = true, + readOnly: Boolean = false, + loader: OudsLoader? = null, + outlined: Boolean = false, + error: OudsError? = null, + helperText: String? = null, + helperLink: OudsTextInputHelperLink? = null, + constrainedMaxWidth: Boolean = false, + keyboardOptions: KeyboardOptions = KeyboardOptions.Default, + onKeyboardAction: KeyboardActionHandler? = null, + onTextLayout: (Density.(getResult: () -> TextLayoutResult?) -> Unit)? = null, + inputTransformation: InputTransformation? = null, + outputTransformation: OutputTransformation? = null, + interactionSource: MutableInteractionSource? = null +) { + OudsTextInput( + textFieldState = textFieldState, + modifier = modifier, + label = label, + placeholder = placeholder, + leadingIcon = leadingIcon, + trailingIconButton = trailingIconButton, + prefix = prefix, + suffix = suffix, + enabled = enabled, + readOnly = readOnly, + loader = loader, + outlined = outlined, + error = error, + helperText = helperText, + annotatedHelperText = null, + helperLink = helperLink, + constrainedMaxWidth = constrainedMaxWidth, + keyboardOptions = keyboardOptions, + onKeyboardAction = onKeyboardAction, + onTextLayout = onTextLayout, + inputTransformation = inputTransformation, + outputTransformation = outputTransformation, + interactionSource = interactionSource + ) +} + +/** + * Text input is a UI element that allows to enter, edit, or select single-line textual data. Text input is one of the most fundamental form elements used + * to capture user input such as names, emails, passwords, or search queries. It provides a visual and interactive affordance for text entry + * while supporting labels, placeholders, icons, descriptions, and validation feedback. + * + * Rounded corners can be enabled or disabled using [OudsThemeSettings.roundedCornerTextInputs] property in the settings of the theme provided when calling + * the [com.orange.ouds.core.theme.OudsTheme] method. + * + * It is recommended to use state-based text inputs rather than value-based ones, as they provide a more complete and reliable approach to managing + * the state of a text input. + * + * An overload accepting annotated types is available for rich text formatting. + * + * > Design guidelines: [unified-design-system.orange.com](https://r.orange.fr/r/S-ouds-doc-text-input) + * + * > Design name: Text Input + * + * > Design version: 1.4.1 + * + * @param textFieldState The editable text state of the text input, including both the text itself and position of the cursor or selection. + * @param modifier [Modifier] applied to the text input. + * @param label Label displayed above the text input. It describes the purpose of the input. + * @param placeholder Text displayed when the text input is empty. It provides a hint or guidance inside the field to suggest expected input. + * @param leadingIcon An optional leading icon displayed at the start of the text input. It helps indicate the purpose of the input (magnifying glass for search, + * envelope for email, etc.). Only use a leading icon if it adds clear functional or contextual value. + * @param trailingIconButton An optional trailing icon button displayed at the end of the text input. It is used to provide actions related to the field: + * clear input, toggle password visibility, etc. It can also indicate status or feedback (error checkmark, loading spinner). + * @param prefix Text placed before the user's input. Commonly used to indicate expected formatting such as a country code or a unit. + * @param suffix Text placed after the user's input, often used to display a currency or a unit (e.g., kg, %, cm). + * @param enabled Controls the enabled state of the text input. When `false`, this text input will not be focusable and will not react to input events. + * True by default. + * @param readOnly Controls the read-only state of the text input. When `true`, the text is visible but not editable. + * False by default. + * @param loader An optional loading progress indicator displayed in the text input to indicate an ongoing operation. + * @param outlined Controls the style of the text input. When `true`, it displays a minimalist text input with a transparent background and a visible + * stroke outlining the field. + * @param error Optional [OudsError] to indicate that the user input does not meet validation rules or expected formatting. Pass `null` if there is no error. + * @param helperText An optional helper text displayed below the text input. It conveys additional information about the input field, such as how it will be + * used. It should ideally only take up a single line, though it may wrap to multiple lines if required. + * @param helperLink An optional helper link displayed below or in place of the helper text. + * @param constrainedMaxWidth When `true`, the text input width is constrained to a maximum value defined by the design system. + * When `false`, no specific width constraint is applied, allowing the component to size itself or follow external modifiers. + * Defaults to `false`. + * @param keyboardOptions Software keyboard options that contain configurations such as [KeyboardType] and [ImeAction]. + * @param onKeyboardAction Called when the user presses the action button in the input method editor (IME), or by pressing the enter key on a hardware keyboard. + * By default, this parameter is null, and would execute the default behavior for a received IME Action e.g., [ImeAction.Done] would close the keyboard, + * [ImeAction.Next] would switch the focus to the next focusable item on the screen. + * @param onTextLayout Callback that is executed when the text layout becomes queryable. The callback receives a function that returns a [TextLayoutResult] if + * the layout can be calculated, or null if it cannot. The function reads the layout result from a snapshot state object, and will invalidate its caller when + * the layout result changes. A [TextLayoutResult] object contains paragraph information, size of the text, baselines and other details. The callback can be + * used to add additional decoration or functionality to the text. For example, to draw a cursor or selection around the text. [Density] scope is the one that + * was used while creating the given text layout. + * @param inputTransformation An optional [InputTransformation] that will be used to transform changes to the [TextFieldState] made by the user. The transformation + * will be applied to changes made by hardware and software keyboard events, pasting or dropping text, accessibility services, and tests. The transformation + * will _not_ be applied when changing the [textFieldState] programmatically, or when the transformation is changed. If the transformation is changed on an + * existing text field, it will be applied to the next user edit. The transformation will not immediately affect the current [textFieldState]. + * @param outputTransformation An optional [OutputTransformation] that transforms how the contents of the text field are presented. + * @param interactionSource An optional hoisted [MutableInteractionSource] for observing and emitting [Interaction]s for this text input. Note that if `null` + * is provided, interactions will still happen internally. + * + * @sample com.orange.ouds.core.component.samples.OudsTextInputStateBasedSample + * @sample com.orange.ouds.core.component.samples.OudsTextInputStateBasedErrorSample + * @sample com.orange.ouds.core.component.samples.OudsTextInputStateBasedWithUntintedLeadingIconSample + */ +@Suppress("DEPRECATION") +@Deprecated("") +@Composable +fun OudsTextInput( + textFieldState: TextFieldState, + modifier: Modifier = Modifier, + label: String? = null, + placeholder: String? = null, + leadingIcon: OudsTextInputLeadingIcon?, + trailingIconButton: OudsTextInputTrailingIconButton? = null, + prefix: String? = null, + suffix: String? = null, + enabled: Boolean = true, + readOnly: Boolean = false, + loader: OudsTextInputLoader? = null, + outlined: Boolean = false, + error: OudsError? = null, + helperText: String? = null, + helperLink: OudsTextInputHelperLink? = null, + constrainedMaxWidth: Boolean = false, + keyboardOptions: KeyboardOptions = KeyboardOptions.Default, + onKeyboardAction: KeyboardActionHandler? = null, + onTextLayout: (Density.(getResult: () -> TextLayoutResult?) -> Unit)? = null, + inputTransformation: InputTransformation? = null, + outputTransformation: OutputTransformation? = null, + interactionSource: MutableInteractionSource? = null +) { + OudsTextInput( + textFieldState = textFieldState, + modifier = modifier, + label = label, + placeholder = placeholder, + leadingIcon = leadingIcon?.toIcon(), + trailingIconButton = trailingIconButton?.toIconButton(), + prefix = prefix, + suffix = suffix, + enabled = enabled, + readOnly = readOnly, + loader = loader?.toLoader(), + outlined = outlined, + error = error, + helperText = helperText, + helperLink = helperLink, + constrainedMaxWidth = constrainedMaxWidth, + keyboardOptions = keyboardOptions, + onKeyboardAction = onKeyboardAction, + onTextLayout = onTextLayout, + inputTransformation = inputTransformation, + outputTransformation = outputTransformation, + interactionSource = interactionSource + ) +} + +/** + * Text input is a UI element that allows to enter, edit, or select single-line textual data. Text input is one of the most fundamental form elements used + * to capture user input such as names, emails, passwords, or search queries. It provides a visual and interactive affordance for text entry + * while supporting labels, placeholders, icons, descriptions, and validation feedback. + * + * Rounded corners can be enabled or disabled using [OudsThemeSettings.roundedCornerTextInputs] property in the settings of the theme provided when calling + * the [com.orange.ouds.core.theme.OudsTheme] method. + * + * It is recommended to use state-based text inputs rather than value-based ones, as they provide a more complete and reliable approach to managing + * the state of a text input. + * + * An overload accepting plain types is available for simple text without formatting. + * + * > Design guidelines: [unified-design-system.orange.com](https://r.orange.fr/r/S-ouds-doc-text-input) + * + * > Design name: Text Input + * + * > Design version: 1.4.1 + * + * @param textFieldState The editable text state of the text input, including both the text itself and position of the cursor or selection. + * @param modifier [Modifier] applied to the text input. + * @param label Label displayed above the text input. It describes the purpose of the input. + * @param placeholder Text displayed when the text input is empty. It provides a hint or guidance inside the field to suggest expected input. + * @param leadingIcon An optional leading icon displayed at the start of the text input. It helps indicate the purpose of the input (magnifying glass for search, + * envelope for email, etc.). Only use a leading icon if it adds clear functional or contextual value. + * @param trailingIconButton An optional trailing icon button displayed at the end of the text input. It is used to provide actions related to the field: + * clear input, toggle password visibility, etc. It can also indicate status or feedback (error checkmark, loading spinner). + * @param prefix Text placed before the user's input. Commonly used to indicate expected formatting such as a country code or a unit. + * @param suffix Text placed after the user's input, often used to display a currency or a unit (e.g., kg, %, cm). + * @param enabled Controls the enabled state of the text input. When `false`, this text input will not be focusable and will not react to input events. + * True by default. + * @param readOnly Controls the read-only state of the text input. When `true`, the text is visible but not editable. + * False by default. + * @param loader An optional loading progress indicator displayed in the text input to indicate an ongoing operation. + * @param outlined Controls the style of the text input. When `true`, it displays a minimalist text input with a transparent background and a visible + * stroke outlining the field. + * @param error Optional [OudsError] to indicate that the user input does not meet validation rules or expected formatting. Pass `null` if there is no error. + * @param helperText An annotated helper text displayed below the text input. It conveys additional information about the input field, such as how it will be + * used. It should ideally only take up a single line, though it may wrap to multiple lines if required. + * @param helperLink An optional helper link displayed below or in place of the helper text. + * @param constrainedMaxWidth When `true`, the text input width is constrained to a maximum value defined by the design system. + * When `false`, no specific width constraint is applied, allowing the component to size itself or follow external modifiers. + * Defaults to `false`. + * @param keyboardOptions Software keyboard options that contain configurations such as [KeyboardType] and [ImeAction]. + * @param onKeyboardAction Called when the user presses the action button in the input method editor (IME), or by pressing the enter key on a hardware keyboard. + * By default, this parameter is null, and would execute the default behavior for a received IME Action e.g., [ImeAction.Done] would close the keyboard, + * [ImeAction.Next] would switch the focus to the next focusable item on the screen. + * @param onTextLayout Callback that is executed when the text layout becomes queryable. The callback receives a function that returns a [TextLayoutResult] if + * the layout can be calculated, or null if it cannot. The function reads the layout result from a snapshot state object, and will invalidate its caller when + * the layout result changes. A [TextLayoutResult] object contains paragraph information, size of the text, baselines and other details. The callback can be + * used to add additional decoration or functionality to the text. For example, to draw a cursor or selection around the text. [Density] scope is the one that + * was used while creating the given text layout. + * @param inputTransformation An optional [InputTransformation] that will be used to transform changes to the [TextFieldState] made by the user. The transformation + * will be applied to changes made by hardware and software keyboard events, pasting or dropping text, accessibility services, and tests. The transformation + * will _not_ be applied when changing the [textFieldState] programmatically, or when the transformation is changed. If the transformation is changed on an + * existing text field, it will be applied to the next user edit. The transformation will not immediately affect the current [textFieldState]. + * @param outputTransformation An optional [OutputTransformation] that transforms how the contents of the text field are presented. + * @param interactionSource An optional hoisted [MutableInteractionSource] for observing and emitting [Interaction]s for this text input. Note that if `null` + * is provided, interactions will still happen internally. + * + * @sample com.orange.ouds.core.component.samples.OudsTextInputStateBasedSample + * @sample com.orange.ouds.core.component.samples.OudsTextInputStateBasedWithAnnotatedErrorMessageSample + * @sample com.orange.ouds.core.component.samples.OudsTextInputStateBasedWithAnnotatedHelperTextSample + */ +@Composable +fun OudsTextInput( + textFieldState: TextFieldState, + modifier: Modifier = Modifier, + label: String? = null, + placeholder: String? = null, + leadingIcon: OudsIcon? = null, + trailingIconButton: OudsIconButton? = null, + prefix: String? = null, + suffix: String? = null, + enabled: Boolean = true, + readOnly: Boolean = false, + loader: OudsLoader? = null, + outlined: Boolean = false, + error: OudsError? = null, + helperText: OudsAnnotatedHelperText, + helperLink: OudsTextInputHelperLink? = null, + constrainedMaxWidth: Boolean = false, + keyboardOptions: KeyboardOptions = KeyboardOptions.Default, + onKeyboardAction: KeyboardActionHandler? = null, + onTextLayout: (Density.(getResult: () -> TextLayoutResult?) -> Unit)? = null, + inputTransformation: InputTransformation? = null, + outputTransformation: OutputTransformation? = null, + interactionSource: MutableInteractionSource? = null +) { + OudsTextInput( + textFieldState = textFieldState, + modifier = modifier, + label = label, + placeholder = placeholder, + leadingIcon = leadingIcon, + trailingIconButton = trailingIconButton, + prefix = prefix, + suffix = suffix, + enabled = enabled, + readOnly = readOnly, + loader = loader, + outlined = outlined, + error = error, + helperText = null, + annotatedHelperText = helperText, + helperLink = helperLink, + constrainedMaxWidth = constrainedMaxWidth, + keyboardOptions = keyboardOptions, + onKeyboardAction = onKeyboardAction, + onTextLayout = onTextLayout, + inputTransformation = inputTransformation, + outputTransformation = outputTransformation, + interactionSource = interactionSource + ) +} + +/** + * Text input is a UI element that allows to enter, edit, or select single-line textual data. Text input is one of the most fundamental form elements used + * to capture user input such as names, emails, passwords, or search queries. It provides a visual and interactive affordance for text entry + * while supporting labels, placeholders, icons, descriptions, and validation feedback. + * + * Rounded corners can be enabled or disabled using [OudsThemeSettings.roundedCornerTextInputs] property in the settings of the theme provided when calling + * the [com.orange.ouds.core.theme.OudsTheme] method. + * + * It is recommended to use state-based text inputs rather than value-based ones, as they provide a more complete and reliable approach to managing + * the state of a text input. + * + * An overload accepting plain types is available for simple text without formatting. + * + * > Design guidelines: [unified-design-system.orange.com](https://r.orange.fr/r/S-ouds-doc-text-input) + * + * > Design name: Text Input + * + * > Design version: 1.4.1 + * + * @param textFieldState The editable text state of the text input, including both the text itself and position of the cursor or selection. + * @param modifier [Modifier] applied to the text input. + * @param label Label displayed above the text input. It describes the purpose of the input. + * @param placeholder Text displayed when the text input is empty. It provides a hint or guidance inside the field to suggest expected input. + * @param leadingIcon An optional leading icon displayed at the start of the text input. It helps indicate the purpose of the input (magnifying glass for search, + * envelope for email, etc.). Only use a leading icon if it adds clear functional or contextual value. + * @param trailingIconButton An optional trailing icon button displayed at the end of the text input. It is used to provide actions related to the field: + * clear input, toggle password visibility, etc. It can also indicate status or feedback (error checkmark, loading spinner). + * @param prefix Text placed before the user's input. Commonly used to indicate expected formatting such as a country code or a unit. + * @param suffix Text placed after the user's input, often used to display a currency or a unit (e.g., kg, %, cm). + * @param enabled Controls the enabled state of the text input. When `false`, this text input will not be focusable and will not react to input events. + * True by default. + * @param readOnly Controls the read-only state of the text input. When `true`, the text is visible but not editable. + * False by default. + * @param loader An optional loading progress indicator displayed in the text input to indicate an ongoing operation. + * @param outlined Controls the style of the text input. When `true`, it displays a minimalist text input with a transparent background and a visible + * stroke outlining the field. + * @param error Optional [OudsError] to indicate that the user input does not meet validation rules or expected formatting. Pass `null` if there is no error. + * @param helperText An annotated helper text displayed below the text input. It conveys additional information about the input field, such as how it will be + * used. It should ideally only take up a single line, though it may wrap to multiple lines if required. + * @param helperLink An optional helper link displayed below or in place of the helper text. + * @param constrainedMaxWidth When `true`, the text input width is constrained to a maximum value defined by the design system. + * When `false`, no specific width constraint is applied, allowing the component to size itself or follow external modifiers. + * Defaults to `false`. + * @param keyboardOptions Software keyboard options that contain configurations such as [KeyboardType] and [ImeAction]. + * @param onKeyboardAction Called when the user presses the action button in the input method editor (IME), or by pressing the enter key on a hardware keyboard. + * By default, this parameter is null, and would execute the default behavior for a received IME Action e.g., [ImeAction.Done] would close the keyboard, + * [ImeAction.Next] would switch the focus to the next focusable item on the screen. + * @param onTextLayout Callback that is executed when the text layout becomes queryable. The callback receives a function that returns a [TextLayoutResult] if + * the layout can be calculated, or null if it cannot. The function reads the layout result from a snapshot state object, and will invalidate its caller when + * the layout result changes. A [TextLayoutResult] object contains paragraph information, size of the text, baselines and other details. The callback can be + * used to add additional decoration or functionality to the text. For example, to draw a cursor or selection around the text. [Density] scope is the one that + * was used while creating the given text layout. + * @param inputTransformation An optional [InputTransformation] that will be used to transform changes to the [TextFieldState] made by the user. The transformation + * will be applied to changes made by hardware and software keyboard events, pasting or dropping text, accessibility services, and tests. The transformation + * will _not_ be applied when changing the [textFieldState] programmatically, or when the transformation is changed. If the transformation is changed on an + * existing text field, it will be applied to the next user edit. The transformation will not immediately affect the current [textFieldState]. + * @param outputTransformation An optional [OutputTransformation] that transforms how the contents of the text field are presented. + * @param interactionSource An optional hoisted [MutableInteractionSource] for observing and emitting [Interaction]s for this text input. Note that if `null` + * is provided, interactions will still happen internally. + * + * @sample com.orange.ouds.core.component.samples.OudsTextInputStateBasedSample + * @sample com.orange.ouds.core.component.samples.OudsTextInputStateBasedWithAnnotatedErrorMessageSample + * @sample com.orange.ouds.core.component.samples.OudsTextInputStateBasedWithAnnotatedHelperTextSample + */ +@Suppress("DEPRECATION") +@Deprecated("") +@Composable +fun OudsTextInput( + textFieldState: TextFieldState, + modifier: Modifier = Modifier, + label: String? = null, + placeholder: String? = null, + leadingIcon: OudsTextInputLeadingIcon?, + trailingIconButton: OudsTextInputTrailingIconButton? = null, + prefix: String? = null, + suffix: String? = null, + enabled: Boolean = true, + readOnly: Boolean = false, + loader: OudsTextInputLoader? = null, + outlined: Boolean = false, + error: OudsError? = null, + helperText: OudsAnnotatedHelperText, + helperLink: OudsTextInputHelperLink? = null, + constrainedMaxWidth: Boolean = false, + keyboardOptions: KeyboardOptions = KeyboardOptions.Default, + onKeyboardAction: KeyboardActionHandler? = null, + onTextLayout: (Density.(getResult: () -> TextLayoutResult?) -> Unit)? = null, + inputTransformation: InputTransformation? = null, + outputTransformation: OutputTransformation? = null, + interactionSource: MutableInteractionSource? = null +) { + OudsTextInput( + textFieldState = textFieldState, + modifier = modifier, + label = label, + placeholder = placeholder, + leadingIcon = leadingIcon?.toIcon(), + trailingIconButton = trailingIconButton?.toIconButton(), + prefix = prefix, + suffix = suffix, + enabled = enabled, + readOnly = readOnly, + loader = loader?.toLoader(), + outlined = outlined, + error = error, + helperText = helperText, + helperLink = helperLink, + constrainedMaxWidth = constrainedMaxWidth, + keyboardOptions = keyboardOptions, + onKeyboardAction = onKeyboardAction, + onTextLayout = onTextLayout, + inputTransformation = inputTransformation, + outputTransformation = outputTransformation, + interactionSource = interactionSource + ) +} + +@Composable +private fun OudsTextInput( + textFieldState: TextFieldState, + modifier: Modifier = Modifier, + label: String? = null, + placeholder: String? = null, + leadingIcon: OudsIcon? = null, + trailingIconButton: OudsIconButton? = null, + prefix: String? = null, + suffix: String? = null, + enabled: Boolean = true, + readOnly: Boolean = false, + loader: OudsLoader? = null, + outlined: Boolean = false, + error: OudsError? = null, + helperText: String? = null, + annotatedHelperText: OudsAnnotatedHelperText? = null, + helperLink: OudsTextInputHelperLink? = null, + constrainedMaxWidth: Boolean = false, + keyboardOptions: KeyboardOptions = KeyboardOptions.Default, + onKeyboardAction: KeyboardActionHandler? = null, + onTextLayout: (Density.(getResult: () -> TextLayoutResult?) -> Unit)? = null, + inputTransformation: InputTransformation? = null, + outputTransformation: OutputTransformation? = null, + interactionSource: MutableInteractionSource? = null +) { + @Suppress("NAME_SHADOWING") val interactionSource = interactionSource ?: remember { MutableInteractionSource() } + val interactionState by interactionSource.collectInteractionStateAsState() + val state = getTextInputState(enabled = enabled, readOnly = readOnly, loader = loader, interactionState = interactionState) + + val emptyText = textFieldState.text.isEmpty() + + OudsTextInput( + state = state, + emptyText = emptyText, + readOnly = readOnly, + error = error, + basicTextField = { + BasicTextField( + modifier = modifier.textInputSemantic(label), + state = textFieldState, + enabled = textInputEnabled(state = state), + readOnly = readOnly, + textStyle = textInputTextStyle(state = state), + lineLimits = TextFieldLineLimits.SingleLine, + cursorBrush = textInputCursorBrush(state = state, error = error != null), + keyboardOptions = keyboardOptions, + onKeyboardAction = onKeyboardAction, + onTextLayout = onTextLayout, + inputTransformation = inputTransformation, + outputTransformation = outputTransformation, + interactionSource = interactionSource, + decorator = { innerTextField -> + OudsTextInputDecorator( + innerTextField = innerTextField, + value = textFieldState.text.toString(), + state = state, + label = label, + placeholder = placeholder, + leadingIcon = leadingIcon, + trailingIconButton = trailingIconButton, + prefix = prefix, + suffix = suffix, + loader = loader, + outlined = outlined, + error = error, + helperText = helperText, + annotatedHelperText = annotatedHelperText, + helperLink = helperLink, + constrainedMaxWidth = constrainedMaxWidth + ) + } + ) + } + ) +} + +/** + * Text input is a UI element that allows to enter, edit, or select single-line textual data. Text input is one of the most fundamental form elements used + * to capture user input such as names, emails, passwords, or search queries. It provides a visual and interactive affordance for text entry + * while supporting labels, placeholders, icons, descriptions, and validation feedback. + * + * Rounded corners can be enabled or disabled using [OudsThemeSettings.roundedCornerTextInputs] property in the settings of the theme provided when calling + * the [com.orange.ouds.core.theme.OudsTheme] method. + * + * It is recommended to use state-based text inputs rather than value-based ones, as they provide a more complete and reliable approach to managing + * the state of a text input. + * + * An overload accepting annotated types is available for rich text formatting. + * + * > Design guidelines: [unified-design-system.orange.com](https://r.orange.fr/r/S-ouds-doc-text-input) + * + * > Design name: Text Input + * + * > Design version: 1.4.1 + * + * @param value Input text to be shown in the text field. + * @param onValueChange Callback that is triggered when the input service updates the text. An updated text comes as a parameter of the callback. + * @param modifier [Modifier] applied to the text input. + * @param label Label displayed above the text input. It describes the purpose of the input. + * @param placeholder Text displayed when the text input is empty. It provides a hint or guidance inside the field to suggest expected input. + * @param leadingIcon An optional leading icon displayed at the start of the text input. It helps indicate the purpose of the input (magnifying glass for search, + * envelope for email, etc.). Only use a leading icon if it adds clear functional or contextual value. + * @param trailingIconButton An optional trailing icon button displayed at the end of the text input. It is used to provide actions related to the field: + * clear input, toggle password visibility, etc. It can also indicate status or feedback (error checkmark, loading spinner). + * @param prefix Text placed before the user's input. Commonly used to indicate expected formatting such as a country code or a unit. + * @param suffix Text placed after the user's input, often used to display a currency or a unit (e.g., kg, %, cm). + * @param enabled Controls the enabled state of the text input. When `false`, this text input will not be focusable and will not react to input events. + * True by default. + * @param readOnly Controls the read-only state of the text input. When `true`, the text is visible but not editable. + * False by default. + * @param loader An optional loading progress indicator displayed in the text input to indicate an ongoing operation. + * @param outlined Controls the style of the text input. When `true`, it displays a minimalist text input with a transparent background and a visible + * stroke outlining the field. + * @param error Optional [OudsError] to indicate that the user input does not meet validation rules or expected formatting. Pass `null` if there is no error. + * @param helperText An optional helper text displayed below the text input. It conveys additional information about the input field, such as how it will be + * used. It should ideally only take up a single line, though it may wrap to multiple lines if required. + * @param helperLink An optional helper link displayed below or in place of the helper text. + * @param constrainedMaxWidth When `true`, the text input width is constrained to a maximum value defined by the design system. + * When `false`, no specific width constraint is applied, allowing the component to size itself or follow external modifiers. + * Defaults to `false`. + * @param keyboardOptions Software keyboard options that contain configuration such as [KeyboardType] and [ImeAction]. + * @param keyboardActions When the input service emits an IME action, the corresponding callback is called. Note that this IME action may be different from what + * you specified in [KeyboardOptions.imeAction]. + * @param onTextLayout Callback that is executed when a new text layout is calculated. A [TextLayoutResult] object that callback provides contains paragraph + * information, size of the text, baselines and other details. The callback can be used to add additional decoration or functionality to the text. + * For example, to draw a cursor or selection around the text. + * @param visualTransformation The visual transformation filter for changing the visual representation of the input. By default, no visual transformation is applied. + * @param interactionSource An optional hoisted [MutableInteractionSource] for observing and emitting [Interaction]s for this text input. Note that if `null` + * is provided, interactions will still happen internally. + * + * @sample com.orange.ouds.core.component.samples.OudsTextInputValueBasedSample + * @sample com.orange.ouds.core.component.samples.OudsTextInputValueBasedErrorSample + * @sample com.orange.ouds.core.component.samples.OudsTextInputValueBasedWithUntintedLeadingIconSample + */ +@Composable +fun OudsTextInput( + value: String, + onValueChange: (String) -> Unit, + modifier: Modifier = Modifier, + label: String? = null, + placeholder: String? = null, + leadingIcon: OudsIcon? = null, + trailingIconButton: OudsIconButton? = null, + prefix: String? = null, + suffix: String? = null, + enabled: Boolean = true, + readOnly: Boolean = false, + loader: OudsLoader? = null, + outlined: Boolean = false, + error: OudsError? = null, + helperText: String? = null, + helperLink: OudsTextInputHelperLink? = null, + constrainedMaxWidth: Boolean = false, + keyboardOptions: KeyboardOptions = KeyboardOptions.Default, + keyboardActions: KeyboardActions = KeyboardActions.Default, + onTextLayout: (TextLayoutResult) -> Unit = {}, + visualTransformation: VisualTransformation = VisualTransformation.None, + interactionSource: MutableInteractionSource? = null +) { + OudsTextInput( + value = value, + onValueChange = onValueChange, + modifier = modifier, + label = label, + placeholder = placeholder, + leadingIcon = leadingIcon, + trailingIconButton = trailingIconButton, + prefix = prefix, + suffix = suffix, + enabled = enabled, + readOnly = readOnly, + loader = loader, + outlined = outlined, + error = error, + helperText = helperText, + annotatedHelperText = null, + helperLink = helperLink, + constrainedMaxWidth = constrainedMaxWidth, + keyboardOptions = keyboardOptions, + keyboardActions = keyboardActions, + onTextLayout = onTextLayout, + visualTransformation = visualTransformation, + interactionSource = interactionSource + ) +} + +/** + * Text input is a UI element that allows to enter, edit, or select single-line textual data. Text input is one of the most fundamental form elements used + * to capture user input such as names, emails, passwords, or search queries. It provides a visual and interactive affordance for text entry + * while supporting labels, placeholders, icons, descriptions, and validation feedback. + * + * Rounded corners can be enabled or disabled using [OudsThemeSettings.roundedCornerTextInputs] property in the settings of the theme provided when calling + * the [com.orange.ouds.core.theme.OudsTheme] method. + * + * It is recommended to use state-based text inputs rather than value-based ones, as they provide a more complete and reliable approach to managing + * the state of a text input. + * + * An overload accepting annotated types is available for rich text formatting. + * + * > Design guidelines: [unified-design-system.orange.com](https://r.orange.fr/r/S-ouds-doc-text-input) + * + * > Design name: Text Input + * + * > Design version: 1.4.1 + * + * @param value Input text to be shown in the text field. + * @param onValueChange Callback that is triggered when the input service updates the text. An updated text comes as a parameter of the callback. + * @param modifier [Modifier] applied to the text input. + * @param label Label displayed above the text input. It describes the purpose of the input. + * @param placeholder Text displayed when the text input is empty. It provides a hint or guidance inside the field to suggest expected input. + * @param leadingIcon An optional leading icon displayed at the start of the text input. It helps indicate the purpose of the input (magnifying glass for search, + * envelope for email, etc.). Only use a leading icon if it adds clear functional or contextual value. + * @param trailingIconButton An optional trailing icon button displayed at the end of the text input. It is used to provide actions related to the field: + * clear input, toggle password visibility, etc. It can also indicate status or feedback (error checkmark, loading spinner). + * @param prefix Text placed before the user's input. Commonly used to indicate expected formatting such as a country code or a unit. + * @param suffix Text placed after the user's input, often used to display a currency or a unit (e.g., kg, %, cm). + * @param enabled Controls the enabled state of the text input. When `false`, this text input will not be focusable and will not react to input events. + * True by default. + * @param readOnly Controls the read-only state of the text input. When `true`, the text is visible but not editable. + * False by default. + * @param loader An optional loading progress indicator displayed in the text input to indicate an ongoing operation. + * @param outlined Controls the style of the text input. When `true`, it displays a minimalist text input with a transparent background and a visible + * stroke outlining the field. + * @param error Optional [OudsError] to indicate that the user input does not meet validation rules or expected formatting. Pass `null` if there is no error. + * @param helperText An optional helper text displayed below the text input. It conveys additional information about the input field, such as how it will be + * used. It should ideally only take up a single line, though it may wrap to multiple lines if required. + * @param helperLink An optional helper link displayed below or in place of the helper text. + * @param constrainedMaxWidth When `true`, the text input width is constrained to a maximum value defined by the design system. + * When `false`, no specific width constraint is applied, allowing the component to size itself or follow external modifiers. + * Defaults to `false`. + * @param keyboardOptions Software keyboard options that contain configuration such as [KeyboardType] and [ImeAction]. + * @param keyboardActions When the input service emits an IME action, the corresponding callback is called. Note that this IME action may be different from what + * you specified in [KeyboardOptions.imeAction]. + * @param onTextLayout Callback that is executed when a new text layout is calculated. A [TextLayoutResult] object that callback provides contains paragraph + * information, size of the text, baselines and other details. The callback can be used to add additional decoration or functionality to the text. + * For example, to draw a cursor or selection around the text. + * @param visualTransformation The visual transformation filter for changing the visual representation of the input. By default, no visual transformation is applied. + * @param interactionSource An optional hoisted [MutableInteractionSource] for observing and emitting [Interaction]s for this text input. Note that if `null` + * is provided, interactions will still happen internally. + * + * @sample com.orange.ouds.core.component.samples.OudsTextInputValueBasedSample + * @sample com.orange.ouds.core.component.samples.OudsTextInputValueBasedErrorSample + * @sample com.orange.ouds.core.component.samples.OudsTextInputValueBasedWithUntintedLeadingIconSample + */ +@Suppress("DEPRECATION") +@Deprecated("") +@Composable +fun OudsTextInput( + value: String, + onValueChange: (String) -> Unit, + modifier: Modifier = Modifier, + label: String? = null, + placeholder: String? = null, + leadingIcon: OudsTextInputLeadingIcon?, trailingIconButton: OudsTextInputTrailingIconButton? = null, prefix: String? = null, suffix: String? = null, enabled: Boolean = true, readOnly: Boolean = false, - loader: OudsTextInputLoader? = null, + loader: OudsTextInputLoader? = null, + outlined: Boolean = false, + error: OudsError? = null, + helperText: String? = null, + helperLink: OudsTextInputHelperLink? = null, + constrainedMaxWidth: Boolean = false, + keyboardOptions: KeyboardOptions = KeyboardOptions.Default, + keyboardActions: KeyboardActions = KeyboardActions.Default, + onTextLayout: (TextLayoutResult) -> Unit = {}, + visualTransformation: VisualTransformation = VisualTransformation.None, + interactionSource: MutableInteractionSource? = null +) { + OudsTextInput( + value = value, + onValueChange = onValueChange, + modifier = modifier, + label = label, + placeholder = placeholder, + leadingIcon = leadingIcon?.toIcon(), + trailingIconButton = trailingIconButton?.toIconButton(), + prefix = prefix, + suffix = suffix, + enabled = enabled, + readOnly = readOnly, + loader = loader?.toLoader(), + outlined = outlined, + error = error, + helperText = helperText, + helperLink = helperLink, + constrainedMaxWidth = constrainedMaxWidth, + keyboardOptions = keyboardOptions, + keyboardActions = keyboardActions, + onTextLayout = onTextLayout, + visualTransformation = visualTransformation, + interactionSource = interactionSource + ) +} + +/** + * Text input is a UI element that allows to enter, edit, or select single-line textual data. Text input is one of the most fundamental form elements used + * to capture user input such as names, emails, passwords, or search queries. It provides a visual and interactive affordance for text entry + * while supporting labels, placeholders, icons, descriptions, and validation feedback. + * + * Rounded corners can be enabled or disabled using [OudsThemeSettings.roundedCornerTextInputs] property in the settings of the theme provided when calling + * the [com.orange.ouds.core.theme.OudsTheme] method. + * + * It is recommended to use state-based text inputs rather than value-based ones, as they provide a more complete and reliable approach to managing + * the state of a text input. + * + * An overload accepting plain types is available for simple text without formatting. + * + * > Design guidelines: [unified-design-system.orange.com](https://r.orange.fr/r/S-ouds-doc-text-input) + * + * > Design name: Text Input + * + * > Design version: 1.4.1 + * + * @param value Input text to be shown in the text field. + * @param onValueChange Callback that is triggered when the input service updates the text. An updated text comes as a parameter of the callback. + * @param modifier [Modifier] applied to the text input. + * @param label Label displayed above the text input. It describes the purpose of the input. + * @param placeholder Text displayed when the text input is empty. It provides a hint or guidance inside the field to suggest expected input. + * @param leadingIcon An optional leading icon displayed at the start of the text input. It helps indicate the purpose of the input (magnifying glass for search, + * envelope for email, etc.). Only use a leading icon if it adds clear functional or contextual value. + * @param trailingIconButton An optional trailing icon button displayed at the end of the text input. It is used to provide actions related to the field: + * clear input, toggle password visibility, etc. It can also indicate status or feedback (error checkmark, loading spinner). + * @param prefix Text placed before the user's input. Commonly used to indicate expected formatting such as a country code or a unit. + * @param suffix Text placed after the user's input, often used to display a currency or a unit (e.g., kg, %, cm). + * @param enabled Controls the enabled state of the text input. When `false`, this text input will not be focusable and will not react to input events. + * True by default. + * @param readOnly Controls the read-only state of the text input. When `true`, the text is visible but not editable. + * False by default. + * @param loader An optional loading progress indicator displayed in the text input to indicate an ongoing operation. + * @param outlined Controls the style of the text input. When `true`, it displays a minimalist text input with a transparent background and a visible + * stroke outlining the field. + * @param error Optional [OudsError] to indicate that the user input does not meet validation rules or expected formatting. Pass `null` if there is no error. + * @param helperText An annotated helper text displayed below the text input. It conveys additional information about the input field, such as how it will be + * used. It should ideally only take up a single line, though it may wrap to multiple lines if required. + * @param helperLink An optional helper link displayed below or in place of the helper text. + * @param constrainedMaxWidth When `true`, the text input width is constrained to a maximum value defined by the design system. + * When `false`, no specific width constraint is applied, allowing the component to size itself or follow external modifiers. + * Defaults to `false`. + * @param keyboardOptions Software keyboard options that contain configuration such as [KeyboardType] and [ImeAction]. + * @param keyboardActions When the input service emits an IME action, the corresponding callback is called. Note that this IME action may be different from what + * you specified in [KeyboardOptions.imeAction]. + * @param onTextLayout Callback that is executed when a new text layout is calculated. A [TextLayoutResult] object that callback provides contains paragraph + * information, size of the text, baselines and other details. The callback can be used to add additional decoration or functionality to the text. + * For example, to draw a cursor or selection around the text. + * @param visualTransformation The visual transformation filter for changing the visual representation of the input. By default, no visual transformation is applied. + * @param interactionSource An optional hoisted [MutableInteractionSource] for observing and emitting [Interaction]s for this text input. Note that if `null` + * is provided, interactions will still happen internally. + * + * @sample com.orange.ouds.core.component.samples.OudsTextInputValueBasedSample + * @sample com.orange.ouds.core.component.samples.OudsTextInputValueBasedWithAnnotatedErrorMessageSample + * @sample com.orange.ouds.core.component.samples.OudsTextInputValueBasedWithAnnotatedHelperTextSample + */ +@Composable +fun OudsTextInput( + value: String, + onValueChange: (String) -> Unit, + modifier: Modifier = Modifier, + label: String? = null, + placeholder: String? = null, + leadingIcon: OudsIcon? = null, + trailingIconButton: OudsIconButton? = null, + prefix: String? = null, + suffix: String? = null, + enabled: Boolean = true, + readOnly: Boolean = false, + loader: OudsLoader? = null, outlined: Boolean = false, error: OudsError? = null, - helperText: String? = null, + helperText: OudsAnnotatedHelperText, helperLink: OudsTextInputHelperLink? = null, constrainedMaxWidth: Boolean = false, keyboardOptions: KeyboardOptions = KeyboardOptions.Default, - onKeyboardAction: KeyboardActionHandler? = null, - onTextLayout: (Density.(getResult: () -> TextLayoutResult?) -> Unit)? = null, - inputTransformation: InputTransformation? = null, - outputTransformation: OutputTransformation? = null, + keyboardActions: KeyboardActions = KeyboardActions.Default, + onTextLayout: (TextLayoutResult) -> Unit = {}, + visualTransformation: VisualTransformation = VisualTransformation.None, interactionSource: MutableInteractionSource? = null ) { OudsTextInput( - textFieldState = textFieldState, + value = value, + onValueChange = onValueChange, modifier = modifier, label = label, placeholder = placeholder, @@ -207,15 +966,14 @@ fun OudsTextInput( loader = loader, outlined = outlined, error = error, - helperText = helperText, - annotatedHelperText = null, + helperText = null, + annotatedHelperText = helperText, helperLink = helperLink, constrainedMaxWidth = constrainedMaxWidth, keyboardOptions = keyboardOptions, - onKeyboardAction = onKeyboardAction, + keyboardActions = keyboardActions, onTextLayout = onTextLayout, - inputTransformation = inputTransformation, - outputTransformation = outputTransformation, + visualTransformation = visualTransformation, interactionSource = interactionSource ) } @@ -239,7 +997,8 @@ fun OudsTextInput( * * > Design version: 1.4.1 * - * @param textFieldState The editable text state of the text input, including both the text itself and position of the cursor or selection. + * @param value Input text to be shown in the text field. + * @param onValueChange Callback that is triggered when the input service updates the text. An updated text comes as a parameter of the callback. * @param modifier [Modifier] applied to the text input. * @param label Label displayed above the text input. It describes the purpose of the input. * @param placeholder Text displayed when the text input is empty. It provides a hint or guidance inside the field to suggest expected input. @@ -263,34 +1022,30 @@ fun OudsTextInput( * @param constrainedMaxWidth When `true`, the text input width is constrained to a maximum value defined by the design system. * When `false`, no specific width constraint is applied, allowing the component to size itself or follow external modifiers. * Defaults to `false`. - * @param keyboardOptions Software keyboard options that contain configurations such as [KeyboardType] and [ImeAction]. - * @param onKeyboardAction Called when the user presses the action button in the input method editor (IME), or by pressing the enter key on a hardware keyboard. - * By default, this parameter is null, and would execute the default behavior for a received IME Action e.g., [ImeAction.Done] would close the keyboard, - * [ImeAction.Next] would switch the focus to the next focusable item on the screen. - * @param onTextLayout Callback that is executed when the text layout becomes queryable. The callback receives a function that returns a [TextLayoutResult] if - * the layout can be calculated, or null if it cannot. The function reads the layout result from a snapshot state object, and will invalidate its caller when - * the layout result changes. A [TextLayoutResult] object contains paragraph information, size of the text, baselines and other details. The callback can be - * used to add additional decoration or functionality to the text. For example, to draw a cursor or selection around the text. [Density] scope is the one that - * was used while creating the given text layout. - * @param inputTransformation An optional [InputTransformation] that will be used to transform changes to the [TextFieldState] made by the user. The transformation - * will be applied to changes made by hardware and software keyboard events, pasting or dropping text, accessibility services, and tests. The transformation - * will _not_ be applied when changing the [textFieldState] programmatically, or when the transformation is changed. If the transformation is changed on an - * existing text field, it will be applied to the next user edit. The transformation will not immediately affect the current [textFieldState]. - * @param outputTransformation An optional [OutputTransformation] that transforms how the contents of the text field are presented. + * @param keyboardOptions Software keyboard options that contain configuration such as [KeyboardType] and [ImeAction]. + * @param keyboardActions When the input service emits an IME action, the corresponding callback is called. Note that this IME action may be different from what + * you specified in [KeyboardOptions.imeAction]. + * @param onTextLayout Callback that is executed when a new text layout is calculated. A [TextLayoutResult] object that callback provides contains paragraph + * information, size of the text, baselines and other details. The callback can be used to add additional decoration or functionality to the text. + * For example, to draw a cursor or selection around the text. + * @param visualTransformation The visual transformation filter for changing the visual representation of the input. By default, no visual transformation is applied. * @param interactionSource An optional hoisted [MutableInteractionSource] for observing and emitting [Interaction]s for this text input. Note that if `null` * is provided, interactions will still happen internally. * - * @sample com.orange.ouds.core.component.samples.OudsTextInputStateBasedSample - * @sample com.orange.ouds.core.component.samples.OudsTextInputStateBasedWithAnnotatedErrorMessageSample - * @sample com.orange.ouds.core.component.samples.OudsTextInputStateBasedWithAnnotatedHelperTextSample + * @sample com.orange.ouds.core.component.samples.OudsTextInputValueBasedSample + * @sample com.orange.ouds.core.component.samples.OudsTextInputValueBasedWithAnnotatedErrorMessageSample + * @sample com.orange.ouds.core.component.samples.OudsTextInputValueBasedWithAnnotatedHelperTextSample */ +@Suppress("DEPRECATION") +@Deprecated("") @Composable fun OudsTextInput( - textFieldState: TextFieldState, + value: String, + onValueChange: (String) -> Unit, modifier: Modifier = Modifier, label: String? = null, placeholder: String? = null, - leadingIcon: OudsTextInputLeadingIcon? = null, + leadingIcon: OudsTextInputLeadingIcon?, trailingIconButton: OudsTextInputTrailingIconButton? = null, prefix: String? = null, suffix: String? = null, @@ -303,52 +1058,51 @@ fun OudsTextInput( helperLink: OudsTextInputHelperLink? = null, constrainedMaxWidth: Boolean = false, keyboardOptions: KeyboardOptions = KeyboardOptions.Default, - onKeyboardAction: KeyboardActionHandler? = null, - onTextLayout: (Density.(getResult: () -> TextLayoutResult?) -> Unit)? = null, - inputTransformation: InputTransformation? = null, - outputTransformation: OutputTransformation? = null, + keyboardActions: KeyboardActions = KeyboardActions.Default, + onTextLayout: (TextLayoutResult) -> Unit = {}, + visualTransformation: VisualTransformation = VisualTransformation.None, interactionSource: MutableInteractionSource? = null ) { OudsTextInput( - textFieldState = textFieldState, + value = value, + onValueChange = onValueChange, modifier = modifier, label = label, placeholder = placeholder, - leadingIcon = leadingIcon, - trailingIconButton = trailingIconButton, + leadingIcon = leadingIcon?.toIcon(), + trailingIconButton = trailingIconButton?.toIconButton(), prefix = prefix, suffix = suffix, enabled = enabled, readOnly = readOnly, - loader = loader, + loader = loader?.toLoader(), outlined = outlined, error = error, - helperText = null, - annotatedHelperText = helperText, + helperText = helperText, helperLink = helperLink, constrainedMaxWidth = constrainedMaxWidth, keyboardOptions = keyboardOptions, - onKeyboardAction = onKeyboardAction, + keyboardActions = keyboardActions, onTextLayout = onTextLayout, - inputTransformation = inputTransformation, - outputTransformation = outputTransformation, + visualTransformation = visualTransformation, interactionSource = interactionSource ) } @Composable private fun OudsTextInput( - textFieldState: TextFieldState, + value: String, + onValueChange: (String) -> Unit, modifier: Modifier = Modifier, label: String? = null, placeholder: String? = null, - leadingIcon: OudsTextInputLeadingIcon? = null, - trailingIconButton: OudsTextInputTrailingIconButton? = null, + leadingIcon: OudsIcon? = null, + trailingIconButton: OudsIconButton? = null, prefix: String? = null, suffix: String? = null, enabled: Boolean = true, readOnly: Boolean = false, - loader: OudsTextInputLoader? = null, + loader: OudsLoader? = null, outlined: Boolean = false, error: OudsError? = null, helperText: String? = null, @@ -356,17 +1110,16 @@ private fun OudsTextInput( helperLink: OudsTextInputHelperLink? = null, constrainedMaxWidth: Boolean = false, keyboardOptions: KeyboardOptions = KeyboardOptions.Default, - onKeyboardAction: KeyboardActionHandler? = null, - onTextLayout: (Density.(getResult: () -> TextLayoutResult?) -> Unit)? = null, - inputTransformation: InputTransformation? = null, - outputTransformation: OutputTransformation? = null, + keyboardActions: KeyboardActions = KeyboardActions.Default, + onTextLayout: (TextLayoutResult) -> Unit = {}, + visualTransformation: VisualTransformation = VisualTransformation.None, interactionSource: MutableInteractionSource? = null ) { @Suppress("NAME_SHADOWING") val interactionSource = interactionSource ?: remember { MutableInteractionSource() } val interactionState by interactionSource.collectInteractionStateAsState() val state = getTextInputState(enabled = enabled, readOnly = readOnly, loader = loader, interactionState = interactionState) - val emptyText = textFieldState.text.isEmpty() + val emptyText = value.isEmpty() OudsTextInput( state = state, @@ -376,22 +1129,22 @@ private fun OudsTextInput( basicTextField = { BasicTextField( modifier = modifier.textInputSemantic(label), - state = textFieldState, + value = value, + onValueChange = onValueChange, enabled = textInputEnabled(state = state), readOnly = readOnly, textStyle = textInputTextStyle(state = state), - lineLimits = TextFieldLineLimits.SingleLine, + singleLine = true, cursorBrush = textInputCursorBrush(state = state, error = error != null), keyboardOptions = keyboardOptions, - onKeyboardAction = onKeyboardAction, + keyboardActions = keyboardActions, onTextLayout = onTextLayout, - inputTransformation = inputTransformation, - outputTransformation = outputTransformation, + visualTransformation = visualTransformation, interactionSource = interactionSource, - decorator = { innerTextField -> + decorationBox = { innerTextField -> OudsTextInputDecorator( innerTextField = innerTextField, - value = textFieldState.text.toString(), + value = value, state = state, label = label, placeholder = placeholder, @@ -432,8 +1185,8 @@ private fun OudsTextInput( * * > Design version: 1.4.1 * - * @param value Input text to be shown in the text field. - * @param onValueChange Callback that is triggered when the input service updates the text. An updated text comes as a parameter of the callback. + * @param value The [androidx.compose.ui.text.input.TextFieldValue] to be shown in the text input. + * @param onValueChange Called when the input service updates the values in [TextFieldValue]. * @param modifier [Modifier] applied to the text input. * @param label Label displayed above the text input. It describes the purpose of the input. * @param placeholder Text displayed when the text input is empty. It provides a hint or guidance inside the field to suggest expected input. @@ -469,22 +1222,21 @@ private fun OudsTextInput( * * @sample com.orange.ouds.core.component.samples.OudsTextInputValueBasedSample * @sample com.orange.ouds.core.component.samples.OudsTextInputValueBasedErrorSample - * @sample com.orange.ouds.core.component.samples.OudsTextInputValueBasedWithUntintedLeadingIconSample */ @Composable fun OudsTextInput( - value: String, - onValueChange: (String) -> Unit, + value: TextFieldValue, + onValueChange: (TextFieldValue) -> Unit, modifier: Modifier = Modifier, label: String? = null, placeholder: String? = null, - leadingIcon: OudsTextInputLeadingIcon? = null, - trailingIconButton: OudsTextInputTrailingIconButton? = null, + leadingIcon: OudsIcon? = null, + trailingIconButton: OudsIconButton? = null, prefix: String? = null, suffix: String? = null, enabled: Boolean = true, readOnly: Boolean = false, - loader: OudsTextInputLoader? = null, + loader: OudsLoader? = null, outlined: Boolean = false, error: OudsError? = null, helperText: String? = null, @@ -534,7 +1286,7 @@ fun OudsTextInput( * It is recommended to use state-based text inputs rather than value-based ones, as they provide a more complete and reliable approach to managing * the state of a text input. * - * An overload accepting plain types is available for simple text without formatting. + * An overload accepting annotated types is available for rich text formatting. * * > Design guidelines: [unified-design-system.orange.com](https://r.orange.fr/r/S-ouds-doc-text-input) * @@ -542,8 +1294,8 @@ fun OudsTextInput( * * > Design version: 1.4.1 * - * @param value Input text to be shown in the text field. - * @param onValueChange Callback that is triggered when the input service updates the text. An updated text comes as a parameter of the callback. + * @param value The [androidx.compose.ui.text.input.TextFieldValue] to be shown in the text input. + * @param onValueChange Called when the input service updates the values in [TextFieldValue]. * @param modifier [Modifier] applied to the text input. * @param label Label displayed above the text input. It describes the purpose of the input. * @param placeholder Text displayed when the text input is empty. It provides a hint or guidance inside the field to suggest expected input. @@ -561,7 +1313,7 @@ fun OudsTextInput( * @param outlined Controls the style of the text input. When `true`, it displays a minimalist text input with a transparent background and a visible * stroke outlining the field. * @param error Optional [OudsError] to indicate that the user input does not meet validation rules or expected formatting. Pass `null` if there is no error. - * @param helperText An annotated helper text displayed below the text input. It conveys additional information about the input field, such as how it will be + * @param helperText An optional helper text displayed below the text input. It conveys additional information about the input field, such as how it will be * used. It should ideally only take up a single line, though it may wrap to multiple lines if required. * @param helperLink An optional helper link displayed below or in place of the helper text. * @param constrainedMaxWidth When `true`, the text input width is constrained to a maximum value defined by the design system. @@ -578,17 +1330,18 @@ fun OudsTextInput( * is provided, interactions will still happen internally. * * @sample com.orange.ouds.core.component.samples.OudsTextInputValueBasedSample - * @sample com.orange.ouds.core.component.samples.OudsTextInputValueBasedWithAnnotatedErrorMessageSample - * @sample com.orange.ouds.core.component.samples.OudsTextInputValueBasedWithAnnotatedHelperTextSample + * @sample com.orange.ouds.core.component.samples.OudsTextInputValueBasedErrorSample */ +@Suppress("DEPRECATION") +@Deprecated("") @Composable fun OudsTextInput( - value: String, - onValueChange: (String) -> Unit, + value: TextFieldValue, + onValueChange: (TextFieldValue) -> Unit, modifier: Modifier = Modifier, label: String? = null, placeholder: String? = null, - leadingIcon: OudsTextInputLeadingIcon? = null, + leadingIcon: OudsTextInputLeadingIcon?, trailingIconButton: OudsTextInputTrailingIconButton? = null, prefix: String? = null, suffix: String? = null, @@ -597,7 +1350,7 @@ fun OudsTextInput( loader: OudsTextInputLoader? = null, outlined: Boolean = false, error: OudsError? = null, - helperText: OudsAnnotatedHelperText, + helperText: String? = null, helperLink: OudsTextInputHelperLink? = null, constrainedMaxWidth: Boolean = false, keyboardOptions: KeyboardOptions = KeyboardOptions.Default, @@ -612,17 +1365,16 @@ fun OudsTextInput( modifier = modifier, label = label, placeholder = placeholder, - leadingIcon = leadingIcon, - trailingIconButton = trailingIconButton, + leadingIcon = leadingIcon?.toIcon(), + trailingIconButton = trailingIconButton?.toIconButton(), prefix = prefix, suffix = suffix, enabled = enabled, readOnly = readOnly, - loader = loader, + loader = loader?.toLoader(), outlined = outlined, error = error, - helperText = null, - annotatedHelperText = helperText, + helperText = helperText, helperLink = helperLink, constrainedMaxWidth = constrainedMaxWidth, keyboardOptions = keyboardOptions, @@ -633,83 +1385,6 @@ fun OudsTextInput( ) } -@Composable -private fun OudsTextInput( - value: String, - onValueChange: (String) -> Unit, - modifier: Modifier = Modifier, - label: String? = null, - placeholder: String? = null, - leadingIcon: OudsTextInputLeadingIcon? = null, - trailingIconButton: OudsTextInputTrailingIconButton? = null, - prefix: String? = null, - suffix: String? = null, - enabled: Boolean = true, - readOnly: Boolean = false, - loader: OudsTextInputLoader? = null, - outlined: Boolean = false, - error: OudsError? = null, - helperText: String? = null, - annotatedHelperText: OudsAnnotatedHelperText? = null, - helperLink: OudsTextInputHelperLink? = null, - constrainedMaxWidth: Boolean = false, - keyboardOptions: KeyboardOptions = KeyboardOptions.Default, - keyboardActions: KeyboardActions = KeyboardActions.Default, - onTextLayout: (TextLayoutResult) -> Unit = {}, - visualTransformation: VisualTransformation = VisualTransformation.None, - interactionSource: MutableInteractionSource? = null -) { - @Suppress("NAME_SHADOWING") val interactionSource = interactionSource ?: remember { MutableInteractionSource() } - val interactionState by interactionSource.collectInteractionStateAsState() - val state = getTextInputState(enabled = enabled, readOnly = readOnly, loader = loader, interactionState = interactionState) - - val emptyText = value.isEmpty() - - OudsTextInput( - state = state, - emptyText = emptyText, - readOnly = readOnly, - error = error, - basicTextField = { - BasicTextField( - modifier = modifier.textInputSemantic(label), - value = value, - onValueChange = onValueChange, - enabled = textInputEnabled(state = state), - readOnly = readOnly, - textStyle = textInputTextStyle(state = state), - singleLine = true, - cursorBrush = textInputCursorBrush(state = state, error = error != null), - keyboardOptions = keyboardOptions, - keyboardActions = keyboardActions, - onTextLayout = onTextLayout, - visualTransformation = visualTransformation, - interactionSource = interactionSource, - decorationBox = { innerTextField -> - OudsTextInputDecorator( - innerTextField = innerTextField, - value = value, - state = state, - label = label, - placeholder = placeholder, - leadingIcon = leadingIcon, - trailingIconButton = trailingIconButton, - prefix = prefix, - suffix = suffix, - loader = loader, - outlined = outlined, - error = error, - helperText = helperText, - annotatedHelperText = annotatedHelperText, - helperLink = helperLink, - constrainedMaxWidth = constrainedMaxWidth - ) - } - ) - } - ) -} - /** * Text input is a UI element that allows to enter, edit, or select single-line textual data. Text input is one of the most fundamental form elements used * to capture user input such as names, emails, passwords, or search queries. It provides a visual and interactive affordance for text entry @@ -721,7 +1396,7 @@ private fun OudsTextInput( * It is recommended to use state-based text inputs rather than value-based ones, as they provide a more complete and reliable approach to managing * the state of a text input. * - * An overload accepting annotated types is available for rich text formatting. + * An overload accepting plain types is available for simple text without formatting. * * > Design guidelines: [unified-design-system.orange.com](https://r.orange.fr/r/S-ouds-doc-text-input) * @@ -748,7 +1423,7 @@ private fun OudsTextInput( * @param outlined Controls the style of the text input. When `true`, it displays a minimalist text input with a transparent background and a visible * stroke outlining the field. * @param error Optional [OudsError] to indicate that the user input does not meet validation rules or expected formatting. Pass `null` if there is no error. - * @param helperText An optional helper text displayed below the text input. It conveys additional information about the input field, such as how it will be + * @param helperText An annotated helper text displayed below the text input. It conveys additional information about the input field, such as how it will be * used. It should ideally only take up a single line, though it may wrap to multiple lines if required. * @param helperLink An optional helper link displayed below or in place of the helper text. * @param constrainedMaxWidth When `true`, the text input width is constrained to a maximum value defined by the design system. @@ -765,7 +1440,8 @@ private fun OudsTextInput( * is provided, interactions will still happen internally. * * @sample com.orange.ouds.core.component.samples.OudsTextInputValueBasedSample - * @sample com.orange.ouds.core.component.samples.OudsTextInputValueBasedErrorSample + * @sample com.orange.ouds.core.component.samples.OudsTextInputValueBasedWithAnnotatedErrorMessageSample + * @sample com.orange.ouds.core.component.samples.OudsTextInputValueBasedWithAnnotatedHelperTextSample */ @Composable fun OudsTextInput( @@ -774,16 +1450,16 @@ fun OudsTextInput( modifier: Modifier = Modifier, label: String? = null, placeholder: String? = null, - leadingIcon: OudsTextInputLeadingIcon? = null, - trailingIconButton: OudsTextInputTrailingIconButton? = null, + leadingIcon: OudsIcon? = null, + trailingIconButton: OudsIconButton? = null, prefix: String? = null, suffix: String? = null, enabled: Boolean = true, readOnly: Boolean = false, - loader: OudsTextInputLoader? = null, + loader: OudsLoader? = null, outlined: Boolean = false, error: OudsError? = null, - helperText: String? = null, + helperText: OudsAnnotatedHelperText, helperLink: OudsTextInputHelperLink? = null, constrainedMaxWidth: Boolean = false, keyboardOptions: KeyboardOptions = KeyboardOptions.Default, @@ -807,8 +1483,8 @@ fun OudsTextInput( loader = loader, outlined = outlined, error = error, - helperText = helperText, - annotatedHelperText = null, + helperText = null, + annotatedHelperText = helperText, helperLink = helperLink, constrainedMaxWidth = constrainedMaxWidth, keyboardOptions = keyboardOptions, @@ -877,6 +1553,8 @@ fun OudsTextInput( * @sample com.orange.ouds.core.component.samples.OudsTextInputValueBasedWithAnnotatedErrorMessageSample * @sample com.orange.ouds.core.component.samples.OudsTextInputValueBasedWithAnnotatedHelperTextSample */ +@Suppress("DEPRECATION") +@Deprecated("") @Composable fun OudsTextInput( value: TextFieldValue, @@ -884,7 +1562,7 @@ fun OudsTextInput( modifier: Modifier = Modifier, label: String? = null, placeholder: String? = null, - leadingIcon: OudsTextInputLeadingIcon? = null, + leadingIcon: OudsTextInputLeadingIcon?, trailingIconButton: OudsTextInputTrailingIconButton? = null, prefix: String? = null, suffix: String? = null, @@ -908,17 +1586,16 @@ fun OudsTextInput( modifier = modifier, label = label, placeholder = placeholder, - leadingIcon = leadingIcon, - trailingIconButton = trailingIconButton, + leadingIcon = leadingIcon?.toIcon(), + trailingIconButton = trailingIconButton?.toIconButton(), prefix = prefix, suffix = suffix, enabled = enabled, readOnly = readOnly, - loader = loader, + loader = loader?.toLoader(), outlined = outlined, error = error, - helperText = null, - annotatedHelperText = helperText, + helperText = helperText, helperLink = helperLink, constrainedMaxWidth = constrainedMaxWidth, keyboardOptions = keyboardOptions, @@ -936,13 +1613,13 @@ private fun OudsTextInput( modifier: Modifier = Modifier, label: String? = null, placeholder: String? = null, - leadingIcon: OudsTextInputLeadingIcon? = null, - trailingIconButton: OudsTextInputTrailingIconButton? = null, + leadingIcon: OudsIcon? = null, + trailingIconButton: OudsIconButton? = null, prefix: String? = null, suffix: String? = null, enabled: Boolean = true, readOnly: Boolean = false, - loader: OudsTextInputLoader? = null, + loader: OudsLoader? = null, outlined: Boolean = false, error: OudsError? = null, helperText: String? = null, @@ -1054,11 +1731,11 @@ internal fun OudsTextInputDecorator( state: OudsTextInputState, label: String?, placeholder: String?, - leadingIcon: OudsTextInputLeadingIcon?, - trailingIconButton: OudsTextInputTrailingIconButton?, + leadingIcon: OudsIcon?, + trailingIconButton: OudsIconButton?, prefix: String?, suffix: String?, - loader: OudsTextInputLoader?, + loader: OudsLoader?, outlined: Boolean, error: OudsError?, helperText: String?, @@ -1088,7 +1765,7 @@ internal fun OudsTextInputDecorator( ) { // Leading icon leadingIcon?.Content( - extraParameters = OudsTextInputLeadingIcon.ExtraParameters(tint = decorativeContentColor(state = state)), + extraParameters = OudsIcon.ExtraParameters(tint = decorativeContentColor(state = state)), modifier = Modifier.iconSize(sizeLeadingIcon.value, leadingIcon.tinted) ) @@ -1200,7 +1877,7 @@ internal fun OudsTextInputDecorator( } } else { trailingIconButton?.Content( - extraParameters = OudsTextInputTrailingIconButton.ExtraParameters( + extraParameters = OudsIconButton.ExtraParameters( enabled = state !in listOf(OudsTextInputState.Disabled, OudsTextInputState.ReadOnly) ) ) @@ -1225,7 +1902,7 @@ internal fun OudsTextInputDecorator( } @Composable -internal fun OudsTextInputCircularProgressIndicator(loader: OudsTextInputLoader?) { +internal fun OudsTextInputCircularProgressIndicator(loader: OudsLoader?) { val fontScale = LocalConfiguration.current.fontScale val progressIndicatorModifier = Modifier .size(OudsTheme.components.button.size.progressIndicatorDefault * fontScale) @@ -1284,7 +1961,7 @@ internal fun OudsTextInputHelperTextErrorMessage( } @Composable -internal fun getTextInputState(enabled: Boolean, readOnly: Boolean, loader: OudsTextInputLoader?, interactionState: InteractionState): OudsTextInputState { +internal fun getTextInputState(enabled: Boolean, readOnly: Boolean, loader: OudsLoader?, interactionState: InteractionState): OudsTextInputState { return getPreviewEnumEntry().orElse { if (loader != null) { OudsTextInputState.Loading @@ -1443,7 +2120,7 @@ internal enum class OudsTextInputState { data class OudsTextInputHelperLink( val text: String, val onClick: () -> Unit -) : OudsComponentContent(OudsTextInputHelperLink.ExtraParameters::class.java) { +) : OudsComponentContent() { @ConsistentCopyVisibility data class ExtraParameters internal constructor( @@ -1473,18 +2150,25 @@ data class OudsTextInputHelperLink( * Values outside of this range are coerced into the range. * Set this value to `null` to display a circular indeterminate progress indicator. */ -data class OudsTextInputLoader(val progress: Float?) +@Deprecated("") +data class OudsTextInputLoader(val progress: Float?) { + + internal fun toLoader() = OudsLoader(progress) +} /** * A leading icon in an [OudsTextInput]. * This icon is non-clickable. */ +@Suppress("DEPRECATION") +@Deprecated("") class OudsTextInputLeadingIcon private constructor( graphicsObject: Any, - val contentDescription: String, + contentDescription: String, override val tinted: Boolean ) : OudsComponentIcon(ExtraParameters::class.java, graphicsObject, contentDescription) { + @Deprecated("") @ConsistentCopyVisibility data class ExtraParameters internal constructor( internal val tint: Color @@ -1532,9 +2216,11 @@ class OudsTextInputLeadingIcon private constructor( * A trailing icon button in an [OudsTextInput]. * Displays an icon-only [OudsButton]. */ +@Suppress("DEPRECATION") +@Deprecated("") class OudsTextInputTrailingIconButton private constructor( graphicsObject: Any, - val contentDescription: String, + contentDescription: String, val onClick: () -> Unit ) : OudsComponentIcon( ExtraParameters::class.java, @@ -1543,6 +2229,7 @@ class OudsTextInputTrailingIconButton private constructor( onClick ) { + @Deprecated("") @ConsistentCopyVisibility data class ExtraParameters internal constructor( internal val enabled: Boolean @@ -1643,7 +2330,7 @@ internal fun PreviewOudsTextInputWithRoundedCorners(theme: OudsThemeContract) = textFieldState = rememberTextFieldState(""), label = "Label", placeholder = "Placeholder", - leadingIcon = OudsTextInputLeadingIcon(Icons.Filled.FavoriteBorder, contentDescription = "Icon"), + leadingIcon = OudsIcon(Icons.Filled.FavoriteBorder, contentDescription = "Icon"), ) } } @@ -1726,7 +2413,7 @@ internal fun PreviewOudsTextInputWithUntintedLeadingIcon(theme: OudsThemeContrac OudsTextInput( textFieldState = rememberTextFieldState("Text"), label = "Label", - leadingIcon = OudsTextInputLeadingIcon(painter = rememberRainbowHeartPainter(), contentDescription = "", tinted = false) + leadingIcon = OudsIcon(painter = rememberRainbowHeartPainter(), tinted = false) ) } } @@ -1735,8 +2422,8 @@ internal data class OudsTextInputPreviewParameter( val value: String, val label: String? = null, val placeholder: String? = null, - val leadingIcon: OudsTextInputLeadingIcon? = null, - val trailingIconButton: OudsTextInputTrailingIconButton? = null, + val leadingIcon: OudsIcon? = null, + val trailingIconButton: OudsIconButton? = null, val prefix: String? = null, val suffix: String? = null, val enabled: Boolean = true, @@ -1761,8 +2448,8 @@ private val previewParameterValues: List val suffix = "€" val error = OudsError("Error message.") val helperText = "Helper text." - val leadingIcon = OudsTextInputLeadingIcon(Icons.Filled.FavoriteBorder, contentDescription = "Icon") - val trailingIconButton = OudsTextInputTrailingIconButton(Icons.Filled.FavoriteBorder, contentDescription = "Icon", onClick = {}) + val leadingIcon = OudsIcon(Icons.Filled.FavoriteBorder, contentDescription = "Icon") + val trailingIconButton = OudsIconButton(Icons.Filled.FavoriteBorder, contentDescription = "Icon", onClick = {}) return listOf( OudsTextInputPreviewParameter("", label = label), OudsTextInputPreviewParameter( @@ -1794,6 +2481,7 @@ private val previewParameterValues: List /** * @see OudsTextInput */ +@Suppress("DEPRECATION") @Composable @Deprecated( "Please use OudsTextInput composable instead, which is the equivalent of Material TextField in OUDS Android.", @@ -1858,6 +2546,7 @@ fun OudsTextField( /** * @see OudsTextInput */ +@Suppress("DEPRECATION") @Composable @Deprecated( "Please use OudsTextInput composable instead, which is the equivalent of Material TextField in OUDS Android.", @@ -1922,6 +2611,7 @@ fun OudsTextField( /** * @see OudsTextInput */ +@Suppress("DEPRECATION") @Composable @Deprecated( "Please use OudsTextInput composable instead, which is the equivalent of Material TextField in OUDS Android.", diff --git a/core/src/main/java/com/orange/ouds/core/component/OudsTopAppBar.kt b/core/src/main/java/com/orange/ouds/core/component/OudsTopAppBar.kt index 2a63411972..15b3ed2598 100644 --- a/core/src/main/java/com/orange/ouds/core/component/OudsTopAppBar.kt +++ b/core/src/main/java/com/orange/ouds/core/component/OudsTopAppBar.kt @@ -425,7 +425,7 @@ open class OudsTopAppBarNavigationIcon private constructor( graphicsObjectProvider: @Composable (OudsTopAppBarNavigationIcon) -> Any, contentDescriptionProvider: @Composable (OudsTopAppBarNavigationIcon) -> String, onClick: () -> Unit -) : OudsComponentIcon(Nothing::class.java, graphicsObjectProvider, contentDescriptionProvider, onClick) { +) : OudsComponentIcon(graphicsObjectProvider, contentDescriptionProvider, onClick) { /** * A predefined [OudsTopAppBarNavigationIcon] with a back icon. @@ -516,7 +516,7 @@ sealed interface OudsTopAppBarAction : OudsPolymorphicComponentContent { contentDescription: String, badge: OudsTopAppBarActionBadge?, onClick: () -> Unit - ) : OudsTopAppBarAction, OudsComponentIcon(Nothing::class.java, { graphicsObject }, { contentDescription }, onClick) { + ) : OudsTopAppBarAction, OudsComponentIcon({ graphicsObject }, { contentDescription }, onClick) { private val _badge = badge override val badge: OudsButtonIconBadge? @@ -586,7 +586,7 @@ sealed interface OudsTopAppBarAction : OudsPolymorphicComponentContent { private val monogramBackgroundColor: Color?, private val contentDescription: String, private val onClick: (() -> Unit)? - ) : OudsTopAppBarAction, OudsComponentContent(Nothing::class.java) { + ) : OudsTopAppBarAction, OudsComponentContent() { /** * Creates an instance of [OudsTopAppBarAction.Avatar]. diff --git a/core/src/main/java/com/orange/ouds/core/component/content/OudsComponentContent.kt b/core/src/main/java/com/orange/ouds/core/component/content/OudsComponentContent.kt index a0e9c4a0f4..2696443100 100644 --- a/core/src/main/java/com/orange/ouds/core/component/content/OudsComponentContent.kt +++ b/core/src/main/java/com/orange/ouds/core/component/content/OudsComponentContent.kt @@ -13,26 +13,10 @@ package com.orange.ouds.core.component.content import androidx.compose.runtime.Composable -import androidx.compose.runtime.CompositionLocalProvider -import androidx.compose.runtime.ProvidableCompositionLocal -import androidx.compose.runtime.staticCompositionLocalOf import androidx.compose.ui.Modifier import androidx.compose.ui.platform.testTag -import com.orange.ouds.foundation.extensions.asOrNull import com.orange.ouds.foundation.extensions.orElse - -private val LocalExtraParametersByClass = - mutableMapOf, ProvidableCompositionLocal>() - -internal fun getLocalExtraParameters(clazz: Class): ProvidableCompositionLocal where T : OudsComponentContent.ExtraParameters { - return LocalExtraParametersByClass[clazz]?.asOrNull>().orElse { - staticCompositionLocalOf { error("CompositionLocal LocalExtraParameters for class ${clazz.name} not present") }.also { compositionLocal -> - LocalExtraParametersByClass[clazz] = compositionLocal - } - } -} - /** * Content of a component. * @@ -41,12 +25,11 @@ internal fun getLocalExtraParameters(clazz: Class): ProvidableComposition * This also allows grouping parameters that are related to the same content inside a component. * For instance, it is possible to create an `Icon` subclass to replace both `icon: @Composable () -> Unit` and `onIconClick: () -> Unit` parameters with a single `icon: Icon` parameter. * - * @param extraParametersClass The extra parameters class. * @param T The type of extra parameters. * * @suppress */ -abstract class OudsComponentContent internal constructor(private val extraParametersClass: Class) where T : OudsComponentContent.ExtraParameters { +abstract class OudsComponentContent internal constructor() where T : OudsComponentContent.ExtraParameters { /** * Optional test tag for UI testing purposes. @@ -65,9 +48,7 @@ abstract class OudsComponentContent internal constructor(private val extraPar /** * The extra parameters. */ - protected val extraParameters: T - @Composable - get() = getLocalExtraParameters(extraParametersClass).current + internal lateinit var extraParameters: T /** * The Jetpack Compose UI for this component content. @@ -95,9 +76,8 @@ abstract class OudsComponentContent internal constructor(private val extraPar */ @Composable internal fun Content(modifier: Modifier, extraParameters: T) { - CompositionLocalProvider(getLocalExtraParameters(extraParametersClass) provides extraParameters) { - Content(modifier = modifier) - } + this.extraParameters = extraParameters + Content(modifier = modifier) } /** diff --git a/core/src/main/java/com/orange/ouds/core/component/content/OudsComponentIcon.kt b/core/src/main/java/com/orange/ouds/core/component/content/OudsComponentIcon.kt index 73bc229d02..be62ade131 100644 --- a/core/src/main/java/com/orange/ouds/core/component/content/OudsComponentIcon.kt +++ b/core/src/main/java/com/orange/ouds/core/component/content/OudsComponentIcon.kt @@ -22,8 +22,10 @@ import androidx.compose.ui.graphics.painter.Painter import androidx.compose.ui.graphics.vector.ImageVector import com.orange.ouds.core.component.OudsButton import com.orange.ouds.core.component.OudsButtonAppearance -import com.orange.ouds.core.component.OudsButtonIcon import com.orange.ouds.core.component.OudsButtonIconBadge +import com.orange.ouds.core.component.OudsIcon +import com.orange.ouds.core.component.OudsIconButton +import com.orange.ouds.foundation.InternalOudsApi import com.orange.ouds.foundation.extensions.orElse /** @@ -32,19 +34,27 @@ import com.orange.ouds.foundation.extensions.orElse * @suppress */ abstract class OudsComponentIcon internal constructor( - extraParametersClass: Class, private val graphicsObjectProvider: @Composable (S) -> Any, - private val contentDescriptionProvider: @Composable (S) -> String, + private val contentDescriptionProvider: @Composable (S) -> String?, private val onClick: (() -> Unit)? = null -) : OudsComponentContent(extraParametersClass) where T : OudsComponentContent.ExtraParameters, S : OudsComponentIcon { +) : OudsComponentContent() where T : OudsComponentContent.ExtraParameters, S : OudsComponentIcon { + @Deprecated("") + @InternalOudsApi protected constructor( extraParametersClass: Class, graphicsObject: Any, contentDescription: String, onClick: (() -> Unit)? = null - ) : this(extraParametersClass, { graphicsObject }, { contentDescription }, onClick) + ) : this({ graphicsObject }, { contentDescription }, onClick) + internal constructor( + graphicsObject: Any, + contentDescription: String?, + onClick: (() -> Unit)? = null + ) : this({ graphicsObject }, { contentDescription }, onClick) + + @InternalOudsApi protected open val tint: Color? @Composable get() = null @@ -65,16 +75,20 @@ abstract class OudsComponentIcon internal constructor( @Suppress("UNCHECKED_CAST") get() = graphicsObjectProvider(this as S) + internal val contentDescription: String? + @Composable + @Suppress("UNCHECKED_CAST") + get() = contentDescriptionProvider(this as S) + @Composable override fun Content(modifier: Modifier) { val iconTint = if (tinted) tint.orElse { LocalContentColor.current } else Color.Unspecified val iconModifier = modifier.componentContentTestTag() - @Suppress("UNCHECKED_CAST") val contentDescription = contentDescriptionProvider(this as S) onClick?.let { onClick -> when (val graphicsObject = graphicsObject) { - is Painter -> OudsButtonIcon(painter = graphicsObject, contentDescription = contentDescription, tinted = tinted) - is ImageVector -> OudsButtonIcon(imageVector = graphicsObject, contentDescription = contentDescription, tinted = tinted) - is ImageBitmap -> OudsButtonIcon(bitmap = graphicsObject, contentDescription = contentDescription, tinted = tinted) + is Painter -> OudsIcon(painter = graphicsObject, contentDescription = contentDescription, tinted = tinted) + is ImageVector -> OudsIcon(imageVector = graphicsObject, contentDescription = contentDescription, tinted = tinted) + is ImageBitmap -> OudsIcon(bitmap = graphicsObject, contentDescription = contentDescription, tinted = tinted) else -> null }?.let { buttonIcon -> OudsButton( @@ -95,4 +109,21 @@ abstract class OudsComponentIcon internal constructor( } } } + + internal fun toIcon(): OudsIcon { + return OudsIcon( + graphicsObjectProvider = { graphicsObject }, + contentDescriptionProvider = { contentDescription }, + tinted = tinted + ) + } + + internal fun toIconButton(): OudsIconButton { + return OudsIconButton( + graphicsObjectProvider = { graphicsObject }, + contentDescriptionProvider = { contentDescription }, + tinted = tinted, + onClick = requireNotNull(onClick) + ) + } } diff --git a/core/src/main/java/com/orange/ouds/core/component/content/OudsComponentImage.kt b/core/src/main/java/com/orange/ouds/core/component/content/OudsComponentImage.kt index 368b887022..cb546c6f74 100644 --- a/core/src/main/java/com/orange/ouds/core/component/content/OudsComponentImage.kt +++ b/core/src/main/java/com/orange/ouds/core/component/content/OudsComponentImage.kt @@ -22,12 +22,11 @@ import androidx.compose.ui.graphics.vector.ImageVector import androidx.compose.ui.layout.ContentScale abstract class OudsComponentImage internal constructor( - extraParametersClass: Class, private val graphicsObject: Any, private val contentDescription: String?, private val alignment: Alignment = Alignment.Center, private val contentScale: ContentScale = ContentScale.Fit -) : OudsComponentContent(extraParametersClass) where T : OudsComponentContent.ExtraParameters { +) : OudsComponentContent() where T : OudsComponentContent.ExtraParameters { @Composable override fun Content(modifier: Modifier) { diff --git a/core/src/main/java/com/orange/ouds/core/component/content/OudsPolymorphicComponentContent.kt b/core/src/main/java/com/orange/ouds/core/component/content/OudsPolymorphicComponentContent.kt index 4d2c56ca2d..854d8d5b46 100644 --- a/core/src/main/java/com/orange/ouds/core/component/content/OudsPolymorphicComponentContent.kt +++ b/core/src/main/java/com/orange/ouds/core/component/content/OudsPolymorphicComponentContent.kt @@ -20,26 +20,32 @@ import androidx.compose.ui.Modifier * This interface is typically implemented by sealed interface where subclasses are different implementations of [OudsComponentContent]. */ // Using extension methods instead of adding them to the interface allows to use the internal keyword -interface OudsPolymorphicComponentContent +interface OudsPolymorphicComponentContent { + + fun toComponentContent(): OudsComponentContent where T : OudsComponentContent.ExtraParameters { + @Suppress("UNCHECKED_CAST") + return this as OudsComponentContent + } +} @Composable internal fun OudsPolymorphicComponentContent.PolymorphicContent() { - return (this as OudsComponentContent<*>).Content() + return toComponentContent().Content() } @Composable internal fun OudsPolymorphicComponentContent.PolymorphicContent(modifier: Modifier) { - return (this as OudsComponentContent<*>).Content(modifier) + return toComponentContent().Content(modifier) } @Composable internal fun OudsPolymorphicComponentContent.PolymorphicContent(extraParameters: T) where T : OudsComponentContent.ExtraParameters { @Suppress("UNCHECKED_CAST") - return (this as OudsComponentContent).Content(extraParameters) + return toComponentContent().Content(extraParameters) } @Composable internal fun OudsPolymorphicComponentContent.PolymorphicContent(modifier: Modifier, extraParameters: T) where T : OudsComponentContent.ExtraParameters { @Suppress("UNCHECKED_CAST") - return (this as OudsComponentContent).Content(modifier, extraParameters) + return toComponentContent().Content(modifier, extraParameters) } diff --git a/core/src/main/java/com/orange/ouds/core/component/samples/OudsAlertMessageSamples.kt b/core/src/main/java/com/orange/ouds/core/component/samples/OudsAlertMessageSamples.kt index 348748b9fc..02a64733cb 100644 --- a/core/src/main/java/com/orange/ouds/core/component/samples/OudsAlertMessageSamples.kt +++ b/core/src/main/java/com/orange/ouds/core/component/samples/OudsAlertMessageSamples.kt @@ -16,11 +16,11 @@ import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.FavoriteBorder import androidx.compose.runtime.Composable import androidx.compose.ui.tooling.preview.PreviewLightDark -import com.orange.ouds.core.component.OudsAlertIcon import com.orange.ouds.core.component.OudsAlertMessage import com.orange.ouds.core.component.OudsAlertMessageActionLink import com.orange.ouds.core.component.OudsAlertMessageActionLinkPosition import com.orange.ouds.core.component.OudsAlertMessageStatus +import com.orange.ouds.core.component.OudsIcon import com.orange.ouds.core.component.common.text.OudsLinkAnnotation import com.orange.ouds.core.component.common.text.buildOudsAnnotatedAlertMessageBulletListLabel import com.orange.ouds.core.component.common.text.buildOudsAnnotatedAlertMessageDescription @@ -34,7 +34,7 @@ internal fun OudsAlertMessageSample() { OudsAlertMessage( label = "New features available", description = "We've added exciting new features to improve your experience.", - status = OudsAlertMessageStatus.Accent(OudsAlertIcon(imageVector = Icons.Filled.FavoriteBorder)), + status = OudsAlertMessageStatus.Accent(OudsIcon(imageVector = Icons.Filled.FavoriteBorder)), onClose = { /* Close the alert message */ }, actionLink = OudsAlertMessageActionLink(label = "Learn more", onClick = { /* Navigate to features page */ }), bulletList = listOf( @@ -52,7 +52,11 @@ internal fun OudsAlertMessageFunctionalWithTopEndActionLinkSample() { description = "Your account has been verified and is now fully activated.", status = OudsAlertMessageStatus.Positive, onClose = { /* Close the alert message */ }, - actionLink = OudsAlertMessageActionLink(label = "Details", onClick = { /* Navigate to account details */ }, position = OudsAlertMessageActionLinkPosition.TopEnd), + actionLink = OudsAlertMessageActionLink( + label = "Details", + onClick = { /* Navigate to account details */ }, + position = OudsAlertMessageActionLinkPosition.TopEnd + ), bulletList = listOf( "All features are now unlocked", "You can start using premium services", @@ -92,7 +96,7 @@ internal fun OudsAlertMessageWithAnnotatedTextSample() { OudsAlertMessage( label = "Before you continue", description = description, - status = OudsAlertMessageStatus.Accent(OudsAlertIcon(imageVector = Icons.Filled.FavoriteBorder)), + status = OudsAlertMessageStatus.Accent(OudsIcon(imageVector = Icons.Filled.FavoriteBorder)), onClose = { /* Close the alert message */ }, bulletList = bulletList ) @@ -103,7 +107,7 @@ internal fun OudsAlertMessageNonFunctionalWithUntintedIconSample() { OudsAlertMessage( label = "New features available", description = "We've added exciting new features to improve your experience.", - status = OudsAlertMessageStatus.Accent(OudsAlertIcon(painter = rememberRainbowHeartPainter(), tinted = false)), + status = OudsAlertMessageStatus.Accent(OudsIcon(painter = rememberRainbowHeartPainter(), tinted = false)), onClose = { /* Close the alert message */ } ) } diff --git a/core/src/main/java/com/orange/ouds/core/component/samples/OudsBadgeSamples.kt b/core/src/main/java/com/orange/ouds/core/component/samples/OudsBadgeSamples.kt index 5fb1c0197c..98b83de661 100644 --- a/core/src/main/java/com/orange/ouds/core/component/samples/OudsBadgeSamples.kt +++ b/core/src/main/java/com/orange/ouds/core/component/samples/OudsBadgeSamples.kt @@ -25,9 +25,9 @@ import androidx.compose.ui.semantics.contentDescription import androidx.compose.ui.semantics.semantics import androidx.compose.ui.tooling.preview.PreviewLightDark import com.orange.ouds.core.component.OudsBadge -import com.orange.ouds.core.component.OudsBadgeIcon import com.orange.ouds.core.component.OudsBadgeSize import com.orange.ouds.core.component.OudsBadgeStatus +import com.orange.ouds.core.component.OudsIcon import com.orange.ouds.core.component.OudsIconBadgeStatus import com.orange.ouds.core.utilities.OudsPreview import com.orange.ouds.core.utilities.rememberRainbowHeartPainter @@ -73,7 +73,7 @@ internal fun OudsBadgeWithCustomIconSample() { contentDescription = "Favorite" }, status = OudsIconBadgeStatus.Accent( - OudsBadgeIcon(imageVector = Icons.Filled.FavoriteBorder) + OudsIcon(imageVector = Icons.Filled.FavoriteBorder) ), size = OudsBadgeSize.Large ) @@ -115,7 +115,7 @@ internal fun OudsBadgeWithUntintedCustomIconSample() { contentDescription = "Favorite" }, status = OudsIconBadgeStatus.Neutral( - OudsBadgeIcon(painter = rememberRainbowHeartPainter(), tinted = false) + OudsIcon(painter = rememberRainbowHeartPainter(), tinted = false) ), size = OudsBadgeSize.Large ) diff --git a/core/src/main/java/com/orange/ouds/core/component/samples/OudsButtonSamples.kt b/core/src/main/java/com/orange/ouds/core/component/samples/OudsButtonSamples.kt index 88e153242b..40b958bcde 100644 --- a/core/src/main/java/com/orange/ouds/core/component/samples/OudsButtonSamples.kt +++ b/core/src/main/java/com/orange/ouds/core/component/samples/OudsButtonSamples.kt @@ -17,9 +17,9 @@ import androidx.compose.material.icons.filled.FavoriteBorder import androidx.compose.runtime.Composable import androidx.compose.ui.tooling.preview.PreviewLightDark import com.orange.ouds.core.component.OudsButton -import com.orange.ouds.core.component.OudsButtonIcon import com.orange.ouds.core.component.OudsColoredBox import com.orange.ouds.core.component.OudsColoredBoxColor +import com.orange.ouds.core.component.OudsIcon import com.orange.ouds.core.utilities.OudsPreview import com.orange.ouds.core.utilities.rememberRainbowHeartPainter @@ -45,7 +45,7 @@ internal fun OudsButtonTextOnlyOnColoredBackgroundSample() { @Composable internal fun OudsButtonIconOnlySample() { OudsButton( - icon = OudsButtonIcon( + icon = OudsIcon( imageVector = Icons.Filled.FavoriteBorder, contentDescription = "Content description" ), @@ -58,7 +58,7 @@ internal fun OudsButtonIconOnlyOnColoredBackgroundSample() { OudsColoredBox(color = OudsColoredBoxColor.StatusInfoEmphasized) { // The colors of this button are automatically adjusted to maximize the contrast with the colored background. OudsButton( - icon = OudsButtonIcon( + icon = OudsIcon( imageVector = Icons.Filled.FavoriteBorder, contentDescription = "Content description" ), @@ -70,10 +70,7 @@ internal fun OudsButtonIconOnlyOnColoredBackgroundSample() { @Composable internal fun OudsButtonTextAndIconSample() { OudsButton( - icon = OudsButtonIcon( - imageVector = Icons.Filled.FavoriteBorder, - contentDescription = "" - ), + icon = OudsIcon(imageVector = Icons.Filled.FavoriteBorder), label = "Label", onClick = { /* Do something! */ } ) @@ -84,10 +81,7 @@ internal fun OudsButtonTextAndIconOnColoredBackgroundSample() { OudsColoredBox(color = OudsColoredBoxColor.StatusInfoEmphasized) { // The colors of this button are automatically adjusted to maximize the contrast with the colored background. OudsButton( - icon = OudsButtonIcon( - imageVector = Icons.Filled.FavoriteBorder, - contentDescription = "" - ), + icon = OudsIcon(imageVector = Icons.Filled.FavoriteBorder), label = "Label", onClick = { /* Do something! */ } ) @@ -97,7 +91,7 @@ internal fun OudsButtonTextAndIconOnColoredBackgroundSample() { @Composable internal fun OudsButtonIconOnlyWithUntintedIconSample() { OudsButton( - icon = OudsButtonIcon( + icon = OudsIcon( painter = rememberRainbowHeartPainter(), contentDescription = "Content description", tinted = false @@ -109,9 +103,8 @@ internal fun OudsButtonIconOnlyWithUntintedIconSample() { @Composable internal fun OudsButtonTextAndIconWithUntintedIconSample() { OudsButton( - icon = OudsButtonIcon( + icon = OudsIcon( painter = rememberRainbowHeartPainter(), - contentDescription = "", tinted = false ), label = "Label", diff --git a/core/src/main/java/com/orange/ouds/core/component/samples/OudsCheckboxItemSamples.kt b/core/src/main/java/com/orange/ouds/core/component/samples/OudsCheckboxItemSamples.kt index ebec8e79e6..5042203de4 100644 --- a/core/src/main/java/com/orange/ouds/core/component/samples/OudsCheckboxItemSamples.kt +++ b/core/src/main/java/com/orange/ouds/core/component/samples/OudsCheckboxItemSamples.kt @@ -22,7 +22,7 @@ import androidx.compose.runtime.setValue import androidx.compose.ui.state.ToggleableState import androidx.compose.ui.tooling.preview.PreviewLightDark import com.orange.ouds.core.component.OudsCheckboxItem -import com.orange.ouds.core.component.OudsControlItemIcon +import com.orange.ouds.core.component.OudsIcon import com.orange.ouds.core.component.OudsTriStateCheckboxItem import com.orange.ouds.core.component.common.OudsError import com.orange.ouds.core.component.common.text.buildOudsAnnotatedErrorMessage @@ -38,7 +38,7 @@ internal fun OudsCheckboxItemSample() { checked = checked, label = "Terms of use", description = "By checking this box, I acknowledge having read the conditions of use.", - icon = OudsControlItemIcon(imageVector = Icons.Filled.FavoriteBorder), + icon = OudsIcon(imageVector = Icons.Filled.FavoriteBorder), onCheckedChange = { value -> checked = value } ) } @@ -51,7 +51,7 @@ internal fun OudsTriStateCheckboxItemSample() { state = toggleableState, label = "My hobbies", description = "Select the hobbies you practice regularly.", - icon = OudsControlItemIcon(imageVector = Icons.Filled.FavoriteBorder), + icon = OudsIcon(imageVector = Icons.Filled.FavoriteBorder), onClick = { toggleableState = when (toggleableState) { ToggleableState.On -> ToggleableState.Off @@ -118,7 +118,7 @@ internal fun OudsCheckboxItemWithUntintedIconSample() { checked = checked, label = "Terms of use", description = "By checking this box, I acknowledge having read the conditions of use.", - icon = OudsControlItemIcon(painter = rememberRainbowHeartPainter(), tinted = false), + icon = OudsIcon(painter = rememberRainbowHeartPainter(), tinted = false), onCheckedChange = { value -> checked = value } ) } @@ -131,7 +131,7 @@ internal fun OudsTriStateCheckboxItemWithUntintedIconSample() { state = toggleableState, label = "My hobbies", description = "Select the hobbies you practice regularly.", - icon = OudsControlItemIcon(painter = rememberRainbowHeartPainter(), tinted = false), + icon = OudsIcon(painter = rememberRainbowHeartPainter(), tinted = false), onClick = { toggleableState = when (toggleableState) { ToggleableState.On -> ToggleableState.Off diff --git a/core/src/main/java/com/orange/ouds/core/component/samples/OudsFilterChipSamples.kt b/core/src/main/java/com/orange/ouds/core/component/samples/OudsFilterChipSamples.kt index 35a83e6a0c..f9f44dfbda 100644 --- a/core/src/main/java/com/orange/ouds/core/component/samples/OudsFilterChipSamples.kt +++ b/core/src/main/java/com/orange/ouds/core/component/samples/OudsFilterChipSamples.kt @@ -20,8 +20,8 @@ import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.compose.ui.tooling.preview.PreviewLightDark -import com.orange.ouds.core.component.OudsChipIcon import com.orange.ouds.core.component.OudsFilterChip +import com.orange.ouds.core.component.OudsIcon import com.orange.ouds.core.utilities.OudsPreview import com.orange.ouds.core.utilities.rememberRainbowHeartPainter @@ -41,7 +41,7 @@ internal fun OudsFilterChipIconOnlySample() { OudsFilterChip( selected = selected, onClick = { selected = !selected }, - icon = OudsChipIcon( + icon = OudsIcon( imageVector = Icons.Filled.FavoriteBorder, contentDescription = "Content description" ) @@ -55,7 +55,7 @@ internal fun OudsFilterChipTextAndIconSample() { selected = selected, onClick = { selected = !selected }, label = "Label", - icon = OudsChipIcon( + icon = OudsIcon( imageVector = Icons.Filled.FavoriteBorder, contentDescription = "" ) @@ -68,7 +68,7 @@ internal fun OudsFilterChipIconOnlyWithUntintedIconSample() { OudsFilterChip( selected = selected, onClick = { selected = !selected }, - icon = OudsChipIcon( + icon = OudsIcon( painter = rememberRainbowHeartPainter(), contentDescription = "Content description", tinted = false @@ -83,7 +83,7 @@ internal fun OudsFilterChipTextAndIconWithUntintedIconSample() { selected = selected, onClick = { selected = !selected }, label = "Label", - icon = OudsChipIcon( + icon = OudsIcon( painter = rememberRainbowHeartPainter(), contentDescription = "", tinted = false diff --git a/core/src/main/java/com/orange/ouds/core/component/samples/OudsFloatingActionButtonSamples.kt b/core/src/main/java/com/orange/ouds/core/component/samples/OudsFloatingActionButtonSamples.kt index 88059a3b90..b71a0affa4 100644 --- a/core/src/main/java/com/orange/ouds/core/component/samples/OudsFloatingActionButtonSamples.kt +++ b/core/src/main/java/com/orange/ouds/core/component/samples/OudsFloatingActionButtonSamples.kt @@ -20,7 +20,7 @@ import androidx.compose.ui.tooling.preview.PreviewLightDark import com.orange.ouds.core.component.OudsExtendedFloatingActionButton import com.orange.ouds.core.component.OudsFloatingActionButton import com.orange.ouds.core.component.OudsFloatingActionButtonAppearance -import com.orange.ouds.core.component.OudsFloatingActionButtonIcon +import com.orange.ouds.core.component.OudsIcon import com.orange.ouds.core.component.OudsLargeFloatingActionButton import com.orange.ouds.core.component.OudsSmallFloatingActionButton import com.orange.ouds.core.utilities.OudsPreview @@ -29,7 +29,7 @@ import com.orange.ouds.core.utilities.rememberRainbowHeartPainter @Composable internal fun OudsFloatingActionButtonSample() { OudsFloatingActionButton( - icon = OudsFloatingActionButtonIcon( + icon = OudsIcon( imageVector = Icons.Filled.FavoriteBorder, contentDescription = "Content description" ), @@ -40,7 +40,7 @@ internal fun OudsFloatingActionButtonSample() { @Composable internal fun OudsSmallFloatingActionButtonSample() { OudsSmallFloatingActionButton( - icon = OudsFloatingActionButtonIcon( + icon = OudsIcon( imageVector = Icons.Filled.FavoriteBorder, contentDescription = "Content description" ), @@ -51,7 +51,7 @@ internal fun OudsSmallFloatingActionButtonSample() { @Composable internal fun OudsLargeFloatingActionButtonSample() { OudsLargeFloatingActionButton( - icon = OudsFloatingActionButtonIcon( + icon = OudsIcon( imageVector = Icons.Filled.Favorite, contentDescription = "Content description" ), @@ -71,10 +71,7 @@ internal fun OudsExtendedFloatingActionButtonSampleWithLabelOnly() { internal fun OudsExtendedFloatingActionButtonSampleWithLabelAndIcon() { OudsExtendedFloatingActionButton( label = "Label", - icon = OudsFloatingActionButtonIcon( - imageVector = Icons.Filled.FavoriteBorder, - contentDescription = "" - ), + icon = OudsIcon(imageVector = Icons.Filled.FavoriteBorder), onClick = { /* Do something! */ } ) } @@ -82,7 +79,7 @@ internal fun OudsExtendedFloatingActionButtonSampleWithLabelAndIcon() { @Composable internal fun OudsFloatingActionButtonWithUntintedIconSample() { OudsFloatingActionButton( - icon = OudsFloatingActionButtonIcon( + icon = OudsIcon( painter = rememberRainbowHeartPainter(), contentDescription = "Content description", tinted = false @@ -95,7 +92,7 @@ internal fun OudsFloatingActionButtonWithUntintedIconSample() { @Composable internal fun OudsSmallFloatingActionButtonWithUntintedIconSample() { OudsSmallFloatingActionButton( - icon = OudsFloatingActionButtonIcon( + icon = OudsIcon( painter = rememberRainbowHeartPainter(), contentDescription = "Content description", tinted = false @@ -108,7 +105,7 @@ internal fun OudsSmallFloatingActionButtonWithUntintedIconSample() { @Composable internal fun OudsLargeFloatingActionButtonWithUntintedIconSample() { OudsLargeFloatingActionButton( - icon = OudsFloatingActionButtonIcon( + icon = OudsIcon( painter = rememberRainbowHeartPainter(), contentDescription = "Content description", tinted = false @@ -122,9 +119,8 @@ internal fun OudsLargeFloatingActionButtonWithUntintedIconSample() { internal fun OudsExtendedFloatingActionButtonWithUntintedIconSample() { OudsExtendedFloatingActionButton( label = "Label", - icon = OudsFloatingActionButtonIcon( + icon = OudsIcon( painter = rememberRainbowHeartPainter(), - contentDescription = "", tinted = false ), onClick = { /* Do something! */ }, diff --git a/core/src/main/java/com/orange/ouds/core/component/samples/OudsInlineAlertSamples.kt b/core/src/main/java/com/orange/ouds/core/component/samples/OudsInlineAlertSamples.kt index 0b31e9976b..fa5afa7cb0 100644 --- a/core/src/main/java/com/orange/ouds/core/component/samples/OudsInlineAlertSamples.kt +++ b/core/src/main/java/com/orange/ouds/core/component/samples/OudsInlineAlertSamples.kt @@ -14,7 +14,7 @@ package com.orange.ouds.core.component.samples import androidx.compose.runtime.Composable import androidx.compose.ui.tooling.preview.PreviewLightDark -import com.orange.ouds.core.component.OudsAlertIcon +import com.orange.ouds.core.component.OudsIcon import com.orange.ouds.core.component.OudsInlineAlert import com.orange.ouds.core.component.OudsInlineAlertStatus import com.orange.ouds.core.utilities.OudsPreview @@ -24,7 +24,7 @@ import com.orange.ouds.core.utilities.rememberRainbowHeartPainter internal fun OudsInlineAlertNonFunctionalStatusSample() { OudsInlineAlert( label = "Label", - status = OudsInlineAlertStatus.Accent(OudsAlertIcon.Default) + status = OudsInlineAlertStatus.Accent(OudsIcon.Default) ) } @@ -40,7 +40,7 @@ internal fun OudsInlineAlertFunctionalStatusSample() { internal fun OudsInlineAlertNonFunctionalWithUntintedIconSample() { OudsInlineAlert( label = "Label", - status = OudsInlineAlertStatus.Accent(OudsAlertIcon(painter = rememberRainbowHeartPainter(), tinted = false)) + status = OudsInlineAlertStatus.Accent(OudsIcon(painter = rememberRainbowHeartPainter(), tinted = false)) ) } diff --git a/core/src/main/java/com/orange/ouds/core/component/samples/OudsLinkSamples.kt b/core/src/main/java/com/orange/ouds/core/component/samples/OudsLinkSamples.kt index 9f9323d23c..21d13ab41d 100644 --- a/core/src/main/java/com/orange/ouds/core/component/samples/OudsLinkSamples.kt +++ b/core/src/main/java/com/orange/ouds/core/component/samples/OudsLinkSamples.kt @@ -16,8 +16,8 @@ import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.FavoriteBorder import androidx.compose.runtime.Composable import androidx.compose.ui.tooling.preview.PreviewLightDark +import com.orange.ouds.core.component.OudsIcon import com.orange.ouds.core.component.OudsLink -import com.orange.ouds.core.component.OudsLinkIcon import com.orange.ouds.core.component.OudsLinkIndicator import com.orange.ouds.core.utilities.OudsPreview import com.orange.ouds.core.utilities.rememberRainbowHeartPainter @@ -34,7 +34,7 @@ internal fun OudsLinkSample() { internal fun OudsLinkWithIconSample() { OudsLink( label = "Link", - icon = OudsLinkIcon(imageVector = Icons.Filled.FavoriteBorder), + icon = OudsIcon(imageVector = Icons.Filled.FavoriteBorder), onClick = { /* Do something! */ }, ) } @@ -52,7 +52,7 @@ internal fun OudsLinkWithIndicatorSample() { internal fun OudsLinkWithUntintedIconSample() { OudsLink( label = "Link", - icon = OudsLinkIcon(painter = rememberRainbowHeartPainter(), tinted = false), + icon = OudsIcon(painter = rememberRainbowHeartPainter(), tinted = false), onClick = { /* Do something! */ }, ) } diff --git a/core/src/main/java/com/orange/ouds/core/component/samples/OudsNavigationBarSamples.kt b/core/src/main/java/com/orange/ouds/core/component/samples/OudsNavigationBarSamples.kt index 73322feb14..6ad97eef6d 100644 --- a/core/src/main/java/com/orange/ouds/core/component/samples/OudsNavigationBarSamples.kt +++ b/core/src/main/java/com/orange/ouds/core/component/samples/OudsNavigationBarSamples.kt @@ -24,10 +24,10 @@ import androidx.compose.runtime.saveable.rememberSaveable import androidx.compose.runtime.setValue import androidx.compose.ui.graphics.vector.ImageVector import androidx.compose.ui.tooling.preview.PreviewLightDark +import com.orange.ouds.core.component.OudsIcon import com.orange.ouds.core.component.OudsNavigationBar import com.orange.ouds.core.component.OudsNavigationBarItem import com.orange.ouds.core.component.OudsNavigationBarItemBadge -import com.orange.ouds.core.component.OudsNavigationBarItemIcon import com.orange.ouds.core.utilities.OudsPreview @Composable @@ -51,7 +51,7 @@ internal fun OudsNavigationBarSample() { selectedItemIndex = index // Do something else here }, - icon = OudsNavigationBarItemIcon(imageVector = item.imageVector), + icon = OudsIcon(imageVector = item.imageVector), label = item.label, badge = item.count?.let { count -> OudsNavigationBarItemBadge(contentDescription = "$count unread emails", count = count) diff --git a/core/src/main/java/com/orange/ouds/core/component/samples/OudsNavigationButtonSamples.kt b/core/src/main/java/com/orange/ouds/core/component/samples/OudsNavigationButtonSamples.kt index 5543f1542b..574b4e0d26 100644 --- a/core/src/main/java/com/orange/ouds/core/component/samples/OudsNavigationButtonSamples.kt +++ b/core/src/main/java/com/orange/ouds/core/component/samples/OudsNavigationButtonSamples.kt @@ -15,13 +15,13 @@ package com.orange.ouds.core.component.samples import androidx.compose.runtime.Composable import androidx.compose.ui.tooling.preview.PreviewLightDark import com.orange.ouds.core.component.OudsNavigationButton -import com.orange.ouds.core.component.OudsNavigationButtonChevron +import com.orange.ouds.core.component.OudsNavigationButtonIndicator import com.orange.ouds.core.utilities.OudsPreview @Composable internal fun OudsNavigationButtonIconOnlySample() { OudsNavigationButton( - chevron = OudsNavigationButtonChevron.Next, + indicator = OudsNavigationButtonIndicator.Next, onClick = { /* Navigate to next screen */ } ) } @@ -30,7 +30,7 @@ internal fun OudsNavigationButtonIconOnlySample() { internal fun OudsNavigationButtonTextAndIconSample() { OudsNavigationButton( label = "Next", - chevron = OudsNavigationButtonChevron.Next, + indicator = OudsNavigationButtonIndicator.Next, onClick = { /* Navigate to next screen */ } ) } diff --git a/core/src/main/java/com/orange/ouds/core/component/samples/OudsRadioButtonItemSamples.kt b/core/src/main/java/com/orange/ouds/core/component/samples/OudsRadioButtonItemSamples.kt index 7bc395c608..e6fef76cc3 100644 --- a/core/src/main/java/com/orange/ouds/core/component/samples/OudsRadioButtonItemSamples.kt +++ b/core/src/main/java/com/orange/ouds/core/component/samples/OudsRadioButtonItemSamples.kt @@ -23,7 +23,7 @@ import androidx.compose.runtime.saveable.rememberSaveable import androidx.compose.runtime.setValue import androidx.compose.ui.Modifier import androidx.compose.ui.tooling.preview.PreviewLightDark -import com.orange.ouds.core.component.OudsControlItemIcon +import com.orange.ouds.core.component.OudsIcon import com.orange.ouds.core.component.OudsRadioButtonItem import com.orange.ouds.core.component.common.OudsError import com.orange.ouds.core.component.common.text.buildOudsAnnotatedErrorMessage @@ -41,7 +41,7 @@ internal fun OudsRadioButtonItemSample() { OudsRadioButtonItem( selected = method == selectedMethod, label = method, - icon = OudsControlItemIcon(imageVector = Icons.Filled.FavoriteBorder), + icon = OudsIcon(imageVector = Icons.Filled.FavoriteBorder), onClick = { selectedMethod = method }, divider = true ) @@ -85,7 +85,7 @@ internal fun OudsRadioButtonItemWithUntintedIconSample() { OudsRadioButtonItem( selected = method == selectedMethod, label = method, - icon = OudsControlItemIcon(painter = rememberRainbowHeartPainter(), tinted = false), + icon = OudsIcon(painter = rememberRainbowHeartPainter(), tinted = false), onClick = { selectedMethod = method }, divider = true ) diff --git a/core/src/main/java/com/orange/ouds/core/component/samples/OudsSmallButtonSamples.kt b/core/src/main/java/com/orange/ouds/core/component/samples/OudsSmallButtonSamples.kt index 9310363ef4..85812f71ae 100644 --- a/core/src/main/java/com/orange/ouds/core/component/samples/OudsSmallButtonSamples.kt +++ b/core/src/main/java/com/orange/ouds/core/component/samples/OudsSmallButtonSamples.kt @@ -16,9 +16,9 @@ import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.FavoriteBorder import androidx.compose.runtime.Composable import androidx.compose.ui.tooling.preview.PreviewLightDark -import com.orange.ouds.core.component.OudsButtonIcon import com.orange.ouds.core.component.OudsColoredBox import com.orange.ouds.core.component.OudsColoredBoxColor +import com.orange.ouds.core.component.OudsIcon import com.orange.ouds.core.component.OudsSmallButton import com.orange.ouds.core.utilities.OudsPreview import com.orange.ouds.core.utilities.rememberRainbowHeartPainter @@ -45,7 +45,7 @@ internal fun OudsSmallButtonTextOnlyOnColoredBackgroundSample() { @Composable internal fun OudsSmallButtonIconOnlySample() { OudsSmallButton( - icon = OudsButtonIcon( + icon = OudsIcon( imageVector = Icons.Filled.FavoriteBorder, contentDescription = "Content description" ), @@ -58,7 +58,7 @@ internal fun OudsSmallButtonIconOnlyOnColoredBackgroundSample() { OudsColoredBox(color = OudsColoredBoxColor.StatusInfoEmphasized) { // The colors of this button are automatically adjusted to maximize the contrast with the colored background. OudsSmallButton( - icon = OudsButtonIcon( + icon = OudsIcon( imageVector = Icons.Filled.FavoriteBorder, contentDescription = "Content description" ), @@ -70,10 +70,7 @@ internal fun OudsSmallButtonIconOnlyOnColoredBackgroundSample() { @Composable internal fun OudsSmallButtonTextAndIconSample() { OudsSmallButton( - icon = OudsButtonIcon( - imageVector = Icons.Filled.FavoriteBorder, - contentDescription = "" - ), + icon = OudsIcon(imageVector = Icons.Filled.FavoriteBorder), label = "Label", onClick = { /* Do something! */ } ) @@ -84,10 +81,7 @@ internal fun OudsSmallButtonTextAndIconOnColoredBackgroundSample() { OudsColoredBox(color = OudsColoredBoxColor.StatusInfoEmphasized) { // The colors of this button are automatically adjusted to maximize the contrast with the colored background. OudsSmallButton( - icon = OudsButtonIcon( - imageVector = Icons.Filled.FavoriteBorder, - contentDescription = "" - ), + icon = OudsIcon(imageVector = Icons.Filled.FavoriteBorder), label = "Label", onClick = { /* Do something! */ } ) @@ -97,7 +91,7 @@ internal fun OudsSmallButtonTextAndIconOnColoredBackgroundSample() { @Composable internal fun OudsSmallButtonIconOnlyWithUntintedIconSample() { OudsSmallButton( - icon = OudsButtonIcon( + icon = OudsIcon( painter = rememberRainbowHeartPainter(), contentDescription = "Content description", tinted = false @@ -109,9 +103,8 @@ internal fun OudsSmallButtonIconOnlyWithUntintedIconSample() { @Composable internal fun OudsSmallButtonTextAndIconWithUntintedIconSample() { OudsSmallButton( - icon = OudsButtonIcon( + icon = OudsIcon( painter = rememberRainbowHeartPainter(), - contentDescription = "", tinted = false ), label = "Label", diff --git a/core/src/main/java/com/orange/ouds/core/component/samples/OudsSuggestionChipSamples.kt b/core/src/main/java/com/orange/ouds/core/component/samples/OudsSuggestionChipSamples.kt index ec0383123c..868b13e30c 100644 --- a/core/src/main/java/com/orange/ouds/core/component/samples/OudsSuggestionChipSamples.kt +++ b/core/src/main/java/com/orange/ouds/core/component/samples/OudsSuggestionChipSamples.kt @@ -25,7 +25,7 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.tooling.preview.PreviewLightDark import com.orange.ouds.core.component.OudsBasicSuggestionChip -import com.orange.ouds.core.component.OudsChipIcon +import com.orange.ouds.core.component.OudsIcon import com.orange.ouds.core.component.OudsSuggestionChip import com.orange.ouds.core.theme.OudsTheme import com.orange.ouds.core.utilities.OudsPreview @@ -43,7 +43,7 @@ internal fun OudsSuggestionChipTextOnlySample() { internal fun OudsSuggestionChipIconOnlySample() { OudsSuggestionChip( onClick = { /* Do something! */ }, - icon = OudsChipIcon( + icon = OudsIcon( imageVector = Icons.Filled.FavoriteBorder, contentDescription = "Content description" ) @@ -55,7 +55,7 @@ internal fun OudsSuggestionChipTextAndIconSample() { OudsSuggestionChip( onClick = { /* Do something! */ }, label = "Label", - icon = OudsChipIcon( + icon = OudsIcon( imageVector = Icons.Filled.FavoriteBorder, contentDescription = "" ) @@ -66,7 +66,7 @@ internal fun OudsSuggestionChipTextAndIconSample() { internal fun OudsSuggestionChipIconOnlyWithUntintedIconSample() { OudsSuggestionChip( onClick = { /* Do something! */ }, - icon = OudsChipIcon( + icon = OudsIcon( painter = rememberRainbowHeartPainter(), contentDescription = "Content description", tinted = false @@ -79,7 +79,7 @@ internal fun OudsSuggestionChipTextAndIconWithUntintedIconSample() { OudsSuggestionChip( onClick = { /* Do something! */ }, label = "Label", - icon = OudsChipIcon( + icon = OudsIcon( painter = rememberRainbowHeartPainter(), contentDescription = "", tinted = false @@ -108,7 +108,7 @@ internal fun OudsBasicSuggestionChipTextOnlySample() { internal fun OudsBasicSuggestionChipIconOnlySample() { OudsBasicSuggestionChip( onClick = { /* Do something! */ }, - icon = OudsChipIcon( + icon = OudsIcon( imageVector = Icons.Filled.FavoriteBorder, contentDescription = "Content description" ) @@ -122,7 +122,7 @@ internal fun OudsBasicSuggestionChipTextAndIconSample() { OudsBasicSuggestionChip( onClick = { /* Do something! */ }, label = "Label", - icon = OudsChipIcon( + icon = OudsIcon( imageVector = Icons.Filled.FavoriteBorder, contentDescription = "" ) diff --git a/core/src/main/java/com/orange/ouds/core/component/samples/OudsSwitchItemSamples.kt b/core/src/main/java/com/orange/ouds/core/component/samples/OudsSwitchItemSamples.kt index eb24fe754e..627d7c54bb 100644 --- a/core/src/main/java/com/orange/ouds/core/component/samples/OudsSwitchItemSamples.kt +++ b/core/src/main/java/com/orange/ouds/core/component/samples/OudsSwitchItemSamples.kt @@ -20,7 +20,7 @@ import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.compose.ui.tooling.preview.PreviewLightDark -import com.orange.ouds.core.component.OudsControlItemIcon +import com.orange.ouds.core.component.OudsIcon import com.orange.ouds.core.component.OudsSwitchItem import com.orange.ouds.core.component.common.OudsError import com.orange.ouds.core.component.common.text.buildOudsAnnotatedErrorMessage @@ -36,7 +36,7 @@ internal fun OudsSwitchItemSample() { checked = checked, label = "Notifications", description = "Display app notifications in the notification center", - icon = OudsControlItemIcon(imageVector = Icons.Filled.FavoriteBorder), + icon = OudsIcon(imageVector = Icons.Filled.FavoriteBorder), onCheckedChange = { value -> checked = value } ) } @@ -70,7 +70,7 @@ internal fun OudsSwitchItemWithUntintedIconSample() { checked = checked, label = "Notifications", description = "Display app notifications in the notification center", - icon = OudsControlItemIcon(painter = rememberRainbowHeartPainter(), tinted = false), + icon = OudsIcon(painter = rememberRainbowHeartPainter(), tinted = false), onCheckedChange = { value -> checked = value } ) } diff --git a/core/src/main/java/com/orange/ouds/core/component/samples/OudsTagSamples.kt b/core/src/main/java/com/orange/ouds/core/component/samples/OudsTagSamples.kt index 145f21ddd0..51e3714055 100644 --- a/core/src/main/java/com/orange/ouds/core/component/samples/OudsTagSamples.kt +++ b/core/src/main/java/com/orange/ouds/core/component/samples/OudsTagSamples.kt @@ -16,6 +16,7 @@ import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.FavoriteBorder import androidx.compose.runtime.Composable import androidx.compose.ui.tooling.preview.PreviewLightDark +import com.orange.ouds.core.component.OudsIcon import com.orange.ouds.core.component.OudsTag import com.orange.ouds.core.component.OudsTagAsset import com.orange.ouds.core.component.OudsTagSize @@ -44,7 +45,7 @@ internal fun OudsTagWithBulletSample() { internal fun OudsTagWithDefaultIconSample() { OudsTag( label = "Tag", - status = OudsTagStatus.Positive(asset = OudsTagAsset.Icon.Default) + status = OudsTagStatus.Positive(asset = OudsIcon.Default) ) } @@ -52,7 +53,7 @@ internal fun OudsTagWithDefaultIconSample() { internal fun OudsTagWithIconSample() { OudsTag( label = "Tag", - status = OudsTagStatus.Neutral(asset = OudsTagAsset.Icon(imageVector = Icons.Filled.FavoriteBorder)) + status = OudsTagStatus.Neutral(asset = OudsIcon(imageVector = Icons.Filled.FavoriteBorder)) ) } @@ -60,7 +61,7 @@ internal fun OudsTagWithIconSample() { internal fun OudsTagWithUntintedIconSample() { OudsTag( label = "Tag", - status = OudsTagStatus.Neutral(asset = OudsTagAsset.Icon(painter = rememberRainbowHeartPainter(), tinted = false)) + status = OudsTagStatus.Neutral(asset = OudsIcon(painter = rememberRainbowHeartPainter(), tinted = false)) ) } diff --git a/core/src/main/java/com/orange/ouds/core/component/samples/OudsTextAreaSamples.kt b/core/src/main/java/com/orange/ouds/core/component/samples/OudsTextAreaSamples.kt index c559c71811..596d96104a 100644 --- a/core/src/main/java/com/orange/ouds/core/component/samples/OudsTextAreaSamples.kt +++ b/core/src/main/java/com/orange/ouds/core/component/samples/OudsTextAreaSamples.kt @@ -19,9 +19,9 @@ import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.compose.ui.tooling.preview.PreviewLightDark +import com.orange.ouds.core.component.OudsLoader import com.orange.ouds.core.component.OudsTextArea import com.orange.ouds.core.component.OudsTextInputHelperLink -import com.orange.ouds.core.component.OudsTextInputLoader import com.orange.ouds.core.component.common.OudsError import com.orange.ouds.core.component.common.text.buildOudsAnnotatedErrorMessage import com.orange.ouds.core.component.common.text.buildOudsAnnotatedHelperText @@ -34,7 +34,7 @@ internal fun OudsTextAreaStateBasedSample() { textFieldState = rememberTextFieldState("I would like to report an issue with my recent order. The product arrived damaged and I would appreciate a replacement or refund."), label = "Feedback", placeholder = "Share your thoughts or report an issue", - loader = OudsTextInputLoader(null), + loader = OudsLoader(null), helperText = "Please provide as much detail as possible (minimum 20 characters)", helperLink = OudsTextInputHelperLink(text = "Guidelines", onClick = { /* Open guidelines */ }) ) @@ -48,7 +48,7 @@ internal fun OudsTextAreaValueBasedSample() { onValueChange = { value = it }, label = "Feedback", placeholder = "Share your thoughts or report an issue", - loader = OudsTextInputLoader(null), + loader = OudsLoader(null), helperText = "Please provide as much detail as possible (minimum 20 characters)", helperLink = OudsTextInputHelperLink(text = "Guidelines", onClick = { /* Open guidelines */ }) ) diff --git a/core/src/main/java/com/orange/ouds/core/component/samples/OudsTextInputSamples.kt b/core/src/main/java/com/orange/ouds/core/component/samples/OudsTextInputSamples.kt index ee1f6b624a..30f26dd19c 100644 --- a/core/src/main/java/com/orange/ouds/core/component/samples/OudsTextInputSamples.kt +++ b/core/src/main/java/com/orange/ouds/core/component/samples/OudsTextInputSamples.kt @@ -22,11 +22,11 @@ import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.compose.ui.tooling.preview.PreviewLightDark +import com.orange.ouds.core.component.OudsIcon +import com.orange.ouds.core.component.OudsIconButton +import com.orange.ouds.core.component.OudsLoader import com.orange.ouds.core.component.OudsTextInput import com.orange.ouds.core.component.OudsTextInputHelperLink -import com.orange.ouds.core.component.OudsTextInputLeadingIcon -import com.orange.ouds.core.component.OudsTextInputLoader -import com.orange.ouds.core.component.OudsTextInputTrailingIconButton import com.orange.ouds.core.component.common.OudsError import com.orange.ouds.core.component.common.text.buildOudsAnnotatedErrorMessage import com.orange.ouds.core.component.common.text.buildOudsAnnotatedHelperText @@ -40,9 +40,9 @@ internal fun OudsTextInputStateBasedSample() { textFieldState = rememberTextFieldState("Text"), label = "Label", placeholder = "Placeholder", - leadingIcon = OudsTextInputLeadingIcon( + leadingIcon = OudsIcon( imageVector = Icons.Filled.FavoriteBorder, - contentDescription = "" + contentDescription = "Content description" ), prefix = "Prefix", suffix = "Suffix", @@ -59,13 +59,13 @@ internal fun OudsTextInputValueBasedSample() { onValueChange = { value = it }, label = "Label", placeholder = "Placeholder", - leadingIcon = OudsTextInputLeadingIcon( + leadingIcon = OudsIcon( imageVector = Icons.Filled.FavoriteBorder, - contentDescription = "" + contentDescription = "Content description" ), prefix = "Prefix", suffix = "Suffix", - loader = OudsTextInputLoader(null), + loader = OudsLoader(null), helperText = "Helper text", helperLink = OudsTextInputHelperLink(text = "Helper link", onClick = { }) ) @@ -77,7 +77,7 @@ internal fun OudsTextInputStateBasedErrorSample() { textFieldState = rememberTextFieldState(), label = "Label", placeholder = "Placeholder", - trailingIconButton = OudsTextInputTrailingIconButton( + trailingIconButton = OudsIconButton( imageVector = Icons.Filled.DateRange, contentDescription = "Display calendar", onClick = { }), @@ -94,7 +94,7 @@ internal fun OudsTextInputValueBasedErrorSample() { onValueChange = { value = it }, label = "Label", placeholder = "Placeholder", - trailingIconButton = OudsTextInputTrailingIconButton( + trailingIconButton = OudsIconButton( imageVector = Icons.Filled.DateRange, contentDescription = "Display calendar", onClick = { }), @@ -187,9 +187,9 @@ internal fun OudsTextInputStateBasedWithUntintedLeadingIconSample() { textFieldState = rememberTextFieldState("Text"), label = "Label", placeholder = "Placeholder", - leadingIcon = OudsTextInputLeadingIcon( + leadingIcon = OudsIcon( painter = rememberRainbowHeartPainter(), - contentDescription = "", + contentDescription = "Content description", tinted = false ) ) @@ -203,9 +203,9 @@ internal fun OudsTextInputValueBasedWithUntintedLeadingIconSample() { onValueChange = { value = it }, label = "Label", placeholder = "Placeholder", - leadingIcon = OudsTextInputLeadingIcon( + leadingIcon = OudsIcon( painter = rememberRainbowHeartPainter(), - contentDescription = "", + contentDescription = "Content description", tinted = false ) ) diff --git a/foundation/src/main/java/com/orange/ouds/foundation/InternalOudsApi.kt b/foundation/src/main/java/com/orange/ouds/foundation/InternalOudsApi.kt index 0a71617d73..40d1987d5d 100644 --- a/foundation/src/main/java/com/orange/ouds/foundation/InternalOudsApi.kt +++ b/foundation/src/main/java/com/orange/ouds/foundation/InternalOudsApi.kt @@ -20,6 +20,7 @@ package com.orange.ouds.foundation @RequiresOptIn(message = "This API is internal to OUDS Android.") @Target( AnnotationTarget.CLASS, + AnnotationTarget.CONSTRUCTOR, AnnotationTarget.FUNCTION, AnnotationTarget.PROPERTY, AnnotationTarget.PROPERTY_GETTER,