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 25f199a9d..29c3e96cf 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 @@ -13,6 +13,7 @@ package com.orange.ouds.app.ui.components import androidx.annotation.DrawableRes +import androidx.annotation.PluralsRes import androidx.annotation.StringRes import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.toArgb @@ -49,7 +50,11 @@ fun FunctionCall.Builder.stringArgument(name: String, @StringRes id: Int) = form fun FunctionCall.Builder.contentDescriptionArgument(@StringRes id: Int) = stringArgument(Argument.ContentDescription, id) fun FunctionCall.Builder.contentDescriptionArgument(@StringRes id: Int, vararg formatArgs: Any) = - stringResourceArgument(Argument.ContentDescription, id, formatArgs) + stringResourceArgument(Argument.ContentDescription, id, *formatArgs) + +fun FunctionCall.Builder.contentDescriptionArgument(@PluralsRes id: Int, count: Int, vararg formatArgs: Any) = + pluralStringResourceArgument(Argument.ContentDescription, id, count, *formatArgs) + fun FunctionCall.Builder.enabledArgument(value: Boolean) = typedArgument(Argument.Enabled, value) 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 bb387d9bc..4b7e7b68d 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 @@ -24,6 +24,7 @@ import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.PreviewLightDark import com.orange.ouds.app.R import com.orange.ouds.app.ui.components.Component +import com.orange.ouds.app.ui.components.contentDescriptionArgument import com.orange.ouds.app.ui.components.labelArgument import com.orange.ouds.app.ui.components.navigationbar.NavigationBarDemoState.Companion.ItemBadgeCount import com.orange.ouds.app.ui.components.navigationbar.NavigationBarDemoState.Companion.MaxNavigationBarItemCount @@ -88,9 +89,6 @@ private fun NavigationBarDemoContent(state: NavigationBarDemoState) { items = navigationBarItems.take(itemCount).mapIndexed { index, item -> val label = stringResource(id = item.labelRes) val isLastItem = index == itemCount - 1 - val standardBadgeContentDescription = stringResource(id = R.string.app_components_common_unreadNotificationsBadge_a11y) - val countBadgeContentDescription = - pluralStringResource(id = R.plurals.app_components_common_unreadMessageCountBadge_a11y, count = ItemBadgeCount, ItemBadgeCount) OudsNavigationBarItem( selected = selectedItemId == index, onClick = { selectedItemId = index }, @@ -99,9 +97,9 @@ private fun NavigationBarDemoContent(state: NavigationBarDemoState) { badge = if (isLastItem) { when (lastItemBadge) { NavigationBarDemoState.ItemBadge.None -> null - NavigationBarDemoState.ItemBadge.Standard -> OudsNavigationBarItemBadge(standardBadgeContentDescription) + NavigationBarDemoState.ItemBadge.Standard -> OudsNavigationBarItemBadge(stringResource(id = R.string.app_components_common_unreadNotificationsBadge_a11y)) NavigationBarDemoState.ItemBadge.Count -> OudsNavigationBarItemBadge( - contentDescription = countBadgeContentDescription, + contentDescription = pluralStringResource(id = R.plurals.app_components_common_unreadMessageCountBadge_a11y, count = ItemBadgeCount, ItemBadgeCount), count = ItemBadgeCount ) } @@ -131,6 +129,15 @@ private fun Code.Builder.navigationBarDemoCodeSnippet(state: NavigationBarDemoSt } if (isLastItem && lastItemBadge != NavigationBarDemoState.ItemBadge.None) { functionCallArgument("badge", OudsNavigationBarItemBadge::class.simpleName.orEmpty()) { + when (lastItemBadge) { + NavigationBarDemoState.ItemBadge.None -> {} + NavigationBarDemoState.ItemBadge.Standard -> contentDescriptionArgument(id = R.string.app_components_common_unreadNotificationsBadge_a11y) + NavigationBarDemoState.ItemBadge.Count -> contentDescriptionArgument( + id = R.plurals.app_components_common_unreadMessageCountBadge_a11y, + count = ItemBadgeCount, + ItemBadgeCount + ) + } if (lastItemBadge == NavigationBarDemoState.ItemBadge.Count) { typedArgument("count", ItemBadgeCount) } diff --git a/app/src/main/java/com/orange/ouds/app/ui/components/topappbar/TopAppBarDemoScreen.kt b/app/src/main/java/com/orange/ouds/app/ui/components/topappbar/TopAppBarDemoScreen.kt index 59b8fd481..fe5b95031 100644 --- a/app/src/main/java/com/orange/ouds/app/ui/components/topappbar/TopAppBarDemoScreen.kt +++ b/app/src/main/java/com/orange/ouds/app/ui/components/topappbar/TopAppBarDemoScreen.kt @@ -17,6 +17,7 @@ import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.runtime.Composable import androidx.compose.ui.graphics.Color import androidx.compose.ui.res.painterResource +import androidx.compose.ui.res.pluralStringResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.PreviewLightDark import com.orange.ouds.app.R @@ -25,6 +26,7 @@ import com.orange.ouds.app.ui.components.colorArgument import com.orange.ouds.app.ui.components.contentDescriptionArgument import com.orange.ouds.app.ui.components.onClickArgument import com.orange.ouds.app.ui.components.painterArgument +import com.orange.ouds.app.ui.components.topappbar.TopAppBarDemoState.Companion.ActionIconBadgeCount import com.orange.ouds.app.ui.utilities.Code import com.orange.ouds.app.ui.utilities.LocalThemeDrawableResources import com.orange.ouds.app.ui.utilities.ThemeDrawableResources @@ -39,6 +41,7 @@ import com.orange.ouds.core.component.OudsLargeTopAppBar import com.orange.ouds.core.component.OudsMediumTopAppBar import com.orange.ouds.core.component.OudsTopAppBar import com.orange.ouds.core.component.OudsTopAppBarAction +import com.orange.ouds.core.component.OudsTopAppBarActionBadge import com.orange.ouds.core.component.OudsTopAppBarNavigationIcon import com.orange.ouds.core.theme.OudsTheme import com.orange.ouds.foundation.extensions.orElse @@ -88,16 +91,23 @@ private fun TopAppBarDemoBottomSheetContent(state: TopAppBarDemoState) { ) CustomizationFilterChips( applyTopPadding = true, - label = stringResource(R.string.app_components_topAppBar_avatar_label), - chipLabels = TopAppBarDemoState.Avatar.entries.map { stringResource(it.labelRes) }, - selectedChipIndex = TopAppBarDemoState.Avatar.entries.indexOf(avatar), - onSelectionChange = { id -> avatar = TopAppBarDemoState.Avatar.entries[id] } + label = stringResource(R.string.app_components_topAppBar_actionIconBadge_label), + chipLabels = TopAppBarDemoState.ActionIconBadge.entries.map { it.name }, + selectedChipIndex = TopAppBarDemoState.ActionIconBadge.entries.indexOf(actionIconBadge), + onSelectionChange = { id -> actionIconBadge = TopAppBarDemoState.ActionIconBadge.entries[id] } + ) + CustomizationFilterChips( + applyTopPadding = true, + label = stringResource(R.string.app_components_topAppBar_actionAvatar_label), + chipLabels = TopAppBarDemoState.ActionAvatar.entries.map { stringResource(it.labelRes) }, + selectedChipIndex = TopAppBarDemoState.ActionAvatar.entries.indexOf(actionAvatar), + onSelectionChange = { id -> actionAvatar = TopAppBarDemoState.ActionAvatar.entries[id] } ) CustomizationTextField( - label = stringResource(R.string.app_components_topAppBar_avatarMonogram_label), - value = avatarMonogram.toString().trim(), - onValueChange = { value -> avatarMonogram = value.firstOrNull().orElse { ' ' } }, - enabled = avatarMonogramTextFieldEnabled + label = stringResource(R.string.app_components_topAppBar_actionAvatarMonogram_label), + value = actionAvatarMonogram.toString().trim(), + onValueChange = { value -> actionAvatarMonogram = value.firstOrNull().orElse { ' ' } }, + enabled = actionAvatarMonogramTextFieldEnabled ) } } @@ -118,29 +128,41 @@ private fun TopAppBarDemoContent(state: TopAppBarDemoState) { onClick = {} ) } - val avatarContentDescription = stringResource(R.string.app_components_topAppBar_secondAction_a11y) - val avatarAction = when (avatar) { - TopAppBarDemoState.Avatar.Image -> OudsTopAppBarAction.Avatar( + + val firstAction = OudsTopAppBarAction.Icon( + painter = painterResource(id = LocalThemeDrawableResources.current.tipsAndTricks), + contentDescription = stringResource(R.string.app_components_topAppBar_firstAction_a11y), + badge = when (actionIconBadge) { + TopAppBarDemoState.ActionIconBadge.None -> null + TopAppBarDemoState.ActionIconBadge.Standard -> OudsTopAppBarActionBadge(contentDescription = stringResource(id = R.string.app_components_common_unreadNotificationsBadge_a11y)) + TopAppBarDemoState.ActionIconBadge.Count -> OudsTopAppBarActionBadge( + contentDescription = pluralStringResource( + id = R.plurals.app_components_common_unreadMessageCountBadge_a11y, + count = ActionIconBadgeCount, + ActionIconBadgeCount + ), + count = ActionIconBadgeCount + ) + }, + onClick = {} + ) + val secondActionContentDescription = stringResource(R.string.app_components_topAppBar_secondAction_a11y) + val secondAction = when (actionAvatar) { + TopAppBarDemoState.ActionAvatar.Image -> OudsTopAppBarAction.Avatar( painter = painterResource(id = R.drawable.il_top_app_bar_avatar), - contentDescription = avatarContentDescription, + contentDescription = secondActionContentDescription, onClick = {} ) - TopAppBarDemoState.Avatar.Monogram -> OudsTopAppBarAction.Avatar( - monogram = avatarMonogram, + TopAppBarDemoState.ActionAvatar.Monogram -> OudsTopAppBarAction.Avatar( + monogram = actionAvatarMonogram, color = Color.White, backgroundColor = Color(0xff138126), - contentDescription = avatarContentDescription, + contentDescription = secondActionContentDescription, onClick = {} ) } - val actions = listOf( - OudsTopAppBarAction.Icon( - painter = painterResource(id = LocalThemeDrawableResources.current.tipsAndTricks), - contentDescription = stringResource(R.string.app_components_topAppBar_firstAction_a11y), - onClick = {} - ), - avatarAction - ) + val actions = listOf(firstAction, secondAction) + when (size) { TopAppBarDemoState.Size.Small -> { if (centerAligned) { @@ -205,15 +227,31 @@ private fun Code.Builder.topAppBarDemoCodeSnippet(state: TopAppBarDemoState, the constructorCallArgument(null) { painterArgument(themeDrawableResources.tipsAndTricks) contentDescriptionArgument(R.string.app_components_topAppBar_firstAction_a11y) + if (actionIconBadge != TopAppBarDemoState.ActionIconBadge.None) { + functionCallArgument("badge", OudsTopAppBarActionBadge::class.simpleName.orEmpty()) { + when (actionIconBadge) { + TopAppBarDemoState.ActionIconBadge.None -> {} + TopAppBarDemoState.ActionIconBadge.Standard -> contentDescriptionArgument(id = R.string.app_components_common_unreadNotificationsBadge_a11y) + TopAppBarDemoState.ActionIconBadge.Count -> contentDescriptionArgument( + id = R.plurals.app_components_common_unreadMessageCountBadge_a11y, + count = ActionIconBadgeCount, + ActionIconBadgeCount + ) + } + if (actionIconBadge == TopAppBarDemoState.ActionIconBadge.Count) { + typedArgument("count", ActionIconBadgeCount) + } + } + } onClickArgument() } constructorCallArgument(null) { - when (avatar) { - TopAppBarDemoState.Avatar.Image -> { + when (actionAvatar) { + TopAppBarDemoState.ActionAvatar.Image -> { painterArgument(R.drawable.il_top_app_bar_avatar) } - TopAppBarDemoState.Avatar.Monogram -> { - typedArgument("monogram", avatarMonogram) + TopAppBarDemoState.ActionAvatar.Monogram -> { + typedArgument("monogram", actionAvatarMonogram) colorArgument("color", Color.White) colorArgument("backgroundColor", Color(0xff138126)) } diff --git a/app/src/main/java/com/orange/ouds/app/ui/components/topappbar/TopAppBarDemoState.kt b/app/src/main/java/com/orange/ouds/app/ui/components/topappbar/TopAppBarDemoState.kt index 85c41781b..9e985681b 100644 --- a/app/src/main/java/com/orange/ouds/app/ui/components/topappbar/TopAppBarDemoState.kt +++ b/app/src/main/java/com/orange/ouds/app/ui/components/topappbar/TopAppBarDemoState.kt @@ -27,10 +27,11 @@ fun rememberTopAppBarDemoState( centerAligned: Boolean = false, navigationIcon: TopAppBarDemoState.NavigationIcon = TopAppBarDemoState.NavigationIcon.None, title: String = "Title", - avatar: TopAppBarDemoState.Avatar = TopAppBarDemoState.Avatar.Image, - avatarMonogram: Char = 'A' -) = rememberSaveable(size, centerAligned, navigationIcon, title, avatar, avatarMonogram, saver = TopAppBarDemoState.Saver) { - TopAppBarDemoState(size, centerAligned, navigationIcon, title, avatar, avatarMonogram) + actionIconBadge: TopAppBarDemoState.ActionIconBadge = TopAppBarDemoState.ActionIconBadge.None, + actionAvatar: TopAppBarDemoState.ActionAvatar = TopAppBarDemoState.ActionAvatar.Image, + actionAvatarMonogram: Char = 'A' +) = rememberSaveable(size, centerAligned, navigationIcon, title, actionIconBadge, actionAvatar, actionAvatarMonogram, saver = TopAppBarDemoState.Saver) { + TopAppBarDemoState(size, centerAligned, navigationIcon, title, actionIconBadge, actionAvatar, actionAvatarMonogram) } class TopAppBarDemoState( @@ -38,11 +39,14 @@ class TopAppBarDemoState( centerAligned: Boolean, navigationIcon: NavigationIcon, title: String, - avatar: Avatar, - avatarMonogram: Char + actionIconBadge: ActionIconBadge, + actionAvatar: ActionAvatar, + actionAvatarMonogram: Char ) { companion object { + const val ActionIconBadgeCount = 1 + val Saver = listSaver( save = { state -> with(state) { @@ -51,8 +55,9 @@ class TopAppBarDemoState( centerAligned, navigationIcon, title, - avatar, - avatarMonogram + actionIconBadge, + actionAvatar, + actionAvatarMonogram ) } }, @@ -62,8 +67,9 @@ class TopAppBarDemoState( list[1] as Boolean, list[2] as NavigationIcon, list[3] as String, - list[4] as Avatar, - list[5] as Char + list[4] as ActionIconBadge, + list[5] as ActionAvatar, + list[6] as Char ) } ) @@ -85,15 +91,17 @@ class TopAppBarDemoState( var title: String by mutableStateOf(title) - var avatar: Avatar by mutableStateOf(avatar) + var actionIconBadge: ActionIconBadge by mutableStateOf(actionIconBadge) + + var actionAvatar: ActionAvatar by mutableStateOf(actionAvatar) - var avatarMonogram: Char by mutableStateOf(avatarMonogram) + var actionAvatarMonogram: Char by mutableStateOf(actionAvatarMonogram) val centerAlignedSwitchEnabled: Boolean get() = size == Size.Small - val avatarMonogramTextFieldEnabled: Boolean - get() = avatar == Avatar.Monogram + val actionAvatarMonogramTextFieldEnabled: Boolean + get() = actionAvatar == ActionAvatar.Monogram enum class Size(@StringRes val labelRes: Int) { Small(R.string.app_components_topAppBar_smallSize_label), @@ -101,11 +109,6 @@ class TopAppBarDemoState( Large(R.string.app_components_topAppBar_largeSize_label) } - enum class Avatar(@StringRes val labelRes: Int) { - Image(R.string.app_components_topAppBar_imageAvatar_label), - Monogram(R.string.app_components_topAppBar_monogramAvatar_label) - } - enum class NavigationIcon(@StringRes val labelRes: Int) { None(R.string.app_components_common_none_label), Back(R.string.app_components_topAppBar_backNavigationIcon_label), @@ -113,4 +116,15 @@ class TopAppBarDemoState( Menu(R.string.app_components_topAppBar_menuNavigationIcon_label), Custom(R.string.app_components_topAppBar_customNavigationIcon_label) } + + enum class ActionIconBadge(@StringRes val labelRes: Int) { + None(R.string.app_components_common_none_label), + Standard(R.string.app_components_badge_standardType_label), + Count(R.string.app_components_badge_countType_label) + } + + enum class ActionAvatar(@StringRes val labelRes: Int) { + Image(R.string.app_components_topAppBar_imageActionAvatar_label), + Monogram(R.string.app_components_topAppBar_monogramActionAvatar_label) + } } 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 9281076e8..c13a7155e 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 @@ -13,6 +13,7 @@ package com.orange.ouds.app.ui.utilities import android.content.Context +import androidx.annotation.PluralsRes import androidx.annotation.StringRes import androidx.compose.material3.Text import androidx.compose.runtime.Composable @@ -139,7 +140,11 @@ data class FunctionCall(val name: String, val elements: List, val i fun rawArgument(name: String?, value: String) = formattableArgument(name) { value } fun stringResourceArgument(name: String?, @StringRes id: Int, vararg formatArgs: Any) { - formattableArgument(name) { "\"${it.getString(id, formatArgs)}\"" } + formattableArgument(name) { "\"${it.getString(id, *formatArgs)}\"" } + } + + fun pluralStringResourceArgument(name: String?, @PluralsRes id: Int, count: Int, vararg formatArgs: Any) { + formattableArgument(name) { "\"${it.resources.getQuantityString(id, count, *formatArgs)}\"" } } fun lambdaArgument(name: String?, init: Code.Builder.() -> Unit = {}) { @@ -232,19 +237,24 @@ internal fun PreviewCode() = AppPreview { comment("click") { isMultiline = true } } } + comment("Single line argument") functionCallArgument("list", "listOf") { isMultiline = false - rawArgument(null, "OudsTheme.shapes") // Raw - stringResourceArgument(null, R.string.app_name) - typedArgument(null, "Text") // String - typedArgument(null, 1.234) // Double - comment("Comment") { isMultiline = true } - typedArgument(null, 1.234f) // Float - typedArgument(null, 1234) // Int - typedArgument(null, true) // Boolean - typedArgument(null, BottomBarItem.Tokens) // Enum - typedArgument(null, null) // null + rawArgument(null, "1") + rawArgument(null, "2") + rawArgument(null, "3") } + comment("Different types of arguments") + rawArgument("raw", "OudsTheme.shapes") + stringResourceArgument("stringResource", R.string.app_name) + pluralStringResourceArgument("pluralStringResource", R.plurals.app_components_common_unreadMessageCountBadge_a11y, 1, 1) + typedArgument("string", "Text") + typedArgument("double", 1.234) + typedArgument("float", 1.234f) + typedArgument("int", 1234) + typedArgument("boolean", true) + typedArgument("enum", BottomBarItem.Tokens) + typedArgument("null", null) lambdaArgument("content") { comment("Single line comment") functionCall("content") diff --git a/app/src/main/res/values-ar/strings.xml b/app/src/main/res/values-ar/strings.xml index d7356136a..1e91c5410 100644 --- a/app/src/main/res/values-ar/strings.xml +++ b/app/src/main/res/values-ar/strings.xml @@ -250,10 +250,11 @@ Menu Custom Title - Avatar - Image - Monogram - Avatar monogram + Action icon badge + Action avatar + Image + Monogram + Avatar monogram أدوات نظام التصميم diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 5e745f609..df229aee8 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -258,10 +258,11 @@ Menu Custom Title - Avatar - Image - Monogram - Avatar monogram + Action icon badge + Action avatar + Image + Monogram + Action avatar monogram Design System Toolbox diff --git a/core-test/src/main/java/com/orange/ouds/core/test/OudsButtonTest.kt b/core-test/src/main/java/com/orange/ouds/core/test/OudsButtonTest.kt index 5ec07d18a..17f0b3365 100644 --- a/core-test/src/main/java/com/orange/ouds/core/test/OudsButtonTest.kt +++ b/core-test/src/main/java/com/orange/ouds/core/test/OudsButtonTest.kt @@ -39,4 +39,18 @@ class OudsButtonTest { parameter = null, OudsComponentTestSuite.theme ) + + @RunWith(Parameterized::class) + class WithIconBadge(parameter: Any) : OudsComponentSnapshotTest( + OudsPreviewableComponent.Button.WithIconBadge, + parameter, + OudsComponentTestSuite.theme + ) { + + companion object { + @JvmStatic + @Parameterized.Parameters + internal fun data() = OudsPreviewableComponent.Button.WithIconBadge.parameters + } + } } diff --git a/core/build.gradle.kts b/core/build.gradle.kts index d89068ad7..f4b5ed76c 100644 --- a/core/build.gradle.kts +++ b/core/build.gradle.kts @@ -51,6 +51,7 @@ dependencies { implementation(libs.androidx.constraintlayout.compose) implementation(libs.material) + testImplementation(project(":core-test")) testImplementation(project(":theme-orange")) androidTestImplementation(project(":theme-orange")) androidTestImplementation(libs.androidx.compose.ui.test.junit4) 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 88e0ae37a..b25f7c6cc 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 @@ -42,6 +42,7 @@ import androidx.compose.ui.semantics.contentDescription import androidx.compose.ui.semantics.semantics import androidx.compose.ui.text.TextStyle import androidx.compose.ui.text.style.LineHeightStyle +import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.tooling.preview.PreviewParameter import androidx.compose.ui.unit.Dp @@ -254,7 +255,9 @@ private fun OudsBadge( modifier = Modifier.clearAndSetSemantics {}, text = text, color = contentColor, - style = textStyle + style = textStyle, + maxLines = 1, + overflow = TextOverflow.Ellipsis ) } } 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 new file mode 100644 index 000000000..4664b7bfc --- /dev/null +++ b/core/src/main/java/com/orange/ouds/core/component/OudsBadgedIcon.kt @@ -0,0 +1,179 @@ +/* + * 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.foundation.isSystemInDarkTheme +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.BoxScope +import androidx.compose.foundation.layout.IntrinsicSize +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.requiredWidth +import androidx.compose.foundation.layout.size +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.FavoriteBorder +import androidx.compose.material3.BadgedBox +import androidx.compose.material3.Icon +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.layout.onSizeChanged +import androidx.compose.ui.platform.LocalDensity +import androidx.compose.ui.semantics.clearAndSetSemantics +import androidx.compose.ui.tooling.preview.PreviewLightDark +import androidx.compose.ui.tooling.preview.PreviewParameter +import androidx.compose.ui.unit.Dp +import androidx.compose.ui.unit.IntOffset +import androidx.compose.ui.unit.IntSize +import androidx.compose.ui.unit.LayoutDirection +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.isUnspecified +import com.orange.ouds.core.theme.OudsTheme +import com.orange.ouds.core.theme.outerBorder +import com.orange.ouds.core.utilities.OudsPreview +import com.orange.ouds.core.utilities.getPreviewTheme +import com.orange.ouds.foundation.extensions.orElse +import com.orange.ouds.foundation.utilities.BasicPreviewParameterProvider +import com.orange.ouds.theme.OudsThemeContract + +/** + * An OUDS equivalent of the Material [BadgedBox] which is restricted to icons. + * Please note that the size of the [OudsBadgedIcon] must be explicitly set to the size of the contained icon, + * otherwise the size of the [OudsBadgedIcon] may be bigger than expected when the badge is displayed outside of the icon. + * + * @param modifier The Modifier to be applied to this [OudsBadgedIcon]. + * @param badgeCount The badge count. + * @param badgeBorderColor The badge border color. + * @param badgeMaximumEndOverflow The maximum amount of space that the badge can overflow to the end of the icon. + * This allows to constrain the badge layout when space is limited, for instance in an [OudsButton]. + * @param icon The icon to be displayed. + */ +@Composable +internal fun OudsBadgedIcon( + modifier: Modifier = Modifier, + badgeCount: Int? = null, + badgeBorderColor: Color = Color.Unspecified, + badgeMaximumEndOverflow: Dp = Dp.Unspecified, + icon: @Composable BoxScope.() -> Unit +) { + Box(modifier = modifier) { + icon() + val badgeMaximumEndOverflowPx = with(LocalDensity.current) { badgeMaximumEndOverflow.toPx() } + var badgeSize by remember { mutableStateOf(IntSize.Zero) } + val badgeModifier = Modifier + .requiredWidth(IntrinsicSize.Min) // This allows to make the badge bigger than it's parent box if needed + // We should use the first IntSize parameter of the align lambda below to retrieve the badge size + // but the value is incorrect and coerced to the parent size when the badge is bigger than it's parent + // That is why we retrieve the icon badge size using the onSizeChanged modifier + .onSizeChanged { badgeSize = it } + .align { _, parentSize, layoutDirection -> + // Important: hypothesis for the calculations below is that the box content alignment is equal to Alignment.TopStart + // Note: parentSize is equal to icon size + if (badgeCount == null) { + val xOffset = if (layoutDirection == LayoutDirection.Ltr) parentSize.width - badgeSize.width else 0 + IntOffset(x = xOffset, y = 0) + } else { + // Compose layouts the badge differently if its width is bigger than the icon width or not + val initialXOffset = if (badgeSize.width > parentSize.width) (parentSize.width - badgeSize.width) / 2 else 0 + + val xOffset = when { + // 1. Badge has enough space to be displayed at it's expected location + // i.e. start at the horizontal center of the icon and bottom at the vertical center of the icon + badgeMaximumEndOverflow.isUnspecified || (badgeSize.width < parentSize.width / 2 + badgeMaximumEndOverflowPx.toInt()) -> if (layoutDirection == LayoutDirection.Ltr) { + -initialXOffset + parentSize.width / 2 + } else { + -initialXOffset + parentSize.width / 2 - badgeSize.width + } + // 2. Badge does not have enough space to be displayed at it's expected location + // There are two cases: + // 2.1. Badge width is bigger than the icon width + // In that case Compose layouts the badge so that the horizontal center of the badge is the same as the horizontal center of the icon + // i.e. The initial offset of the badge is equal to (parentSize.width - badgeSize.width) / 2 in LTR + badgeSize.width > parentSize.width -> if (layoutDirection == LayoutDirection.Ltr) { + initialXOffset + badgeMaximumEndOverflowPx.toInt() + } else { + -initialXOffset - badgeMaximumEndOverflowPx.toInt() + } + // 2.2. Badge width is smaller than the icon width + // In that case Compose layouts the badge so that it starts at the start of the icon + else -> if (layoutDirection == LayoutDirection.Ltr) { + parentSize.width + badgeMaximumEndOverflowPx.toInt() - badgeSize.width + } else { + -badgeMaximumEndOverflowPx.toInt() + } + } + IntOffset(x = xOffset, y = parentSize.height / 2 - badgeSize.height) + } + } + .outerBorder(1.dp, color = badgeBorderColor, shape = OudsBadgeShape, innerOffsetPx = -1f) + .clearAndSetSemantics {} + + val status = OudsBadgeStatus.Negative // A badge always has a negative status on an icon + badgeCount?.let { + OudsBadge(modifier = badgeModifier, count = badgeCount, status = status, size = OudsBadgeSize.Medium) + }.orElse { + OudsBadge(modifier = badgeModifier, status = status, size = OudsBadgeSize.ExtraSmall) + } + } +} + +@PreviewLightDark +@Composable +@Suppress("PreviewShouldNotBeCalledRecursively") +private fun PreviewOudsBadgedIcon(@PreviewParameter(OudsBadgedIconPreviewParameterProvider::class) parameter: OudsBadgedIconPreviewParameter) { + PreviewOudsBadgedIcon(theme = getPreviewTheme(), darkThemeEnabled = isSystemInDarkTheme(), parameter = parameter) +} + +@Composable +internal fun PreviewOudsBadgedIcon( + theme: OudsThemeContract, + darkThemeEnabled: Boolean, + parameter: OudsBadgedIconPreviewParameter +) = OudsPreview(theme = theme, modifier = Modifier.padding(8.dp), darkThemeEnabled = darkThemeEnabled) { + with(parameter) { + val size = 26.dp + OudsBadgedIcon( + modifier = Modifier.size(size), + badgeCount = badgeCount, + badgeBorderColor = badgeBorderColor, + badgeMaximumEndOverflow = badgeMaximumEndOverflow + ) { + Icon( + modifier = Modifier.size(size), + imageVector = Icons.Filled.FavoriteBorder, + contentDescription = "", + tint = OudsTheme.colorScheme.content.default + ) + } + } +} + +internal data class OudsBadgedIconPreviewParameter( + val badgeCount: Int? = null, + val badgeBorderColor: Color = Color.Unspecified, + val badgeMaximumEndOverflow: Dp = Dp.Unspecified +) + +internal class OudsBadgedIconPreviewParameterProvider : BasicPreviewParameterProvider(*previewParameterValues.toTypedArray()) + +private val previewParameterValues: List + get() = listOf( + OudsBadgedIconPreviewParameter(badgeBorderColor = Color.White), + OudsBadgedIconPreviewParameter(badgeCount = 1), // Case 1 when computing x offset + OudsBadgedIconPreviewParameter(badgeCount = 100), // Case 1 when computing x offset + OudsBadgedIconPreviewParameter(badgeCount = 100, badgeBorderColor = Color.White, badgeMaximumEndOverflow = 8.dp), // Case 2.1 when computing x offset + OudsBadgedIconPreviewParameter(badgeCount = 20, badgeMaximumEndOverflow = 8.dp), // Case 2.2 when computing x offset + ) 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 7e44f4d28..11552d2ea 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 @@ -22,6 +22,7 @@ import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.calculateEndPadding import androidx.compose.foundation.layout.heightIn import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size @@ -41,6 +42,8 @@ import androidx.compose.ui.graphics.ImageBitmap import androidx.compose.ui.graphics.painter.Painter import androidx.compose.ui.graphics.vector.ImageVector import androidx.compose.ui.platform.LocalConfiguration +import androidx.compose.ui.platform.LocalDensity +import androidx.compose.ui.platform.LocalLayoutDirection import androidx.compose.ui.res.stringResource import androidx.compose.ui.semantics.Role import androidx.compose.ui.semantics.contentDescription @@ -245,7 +248,7 @@ fun OudsButton( @Composable @JvmName("OudsButtonNullableIconAndLabel") -private fun OudsButton( +internal fun OudsButton( nullableIcon: OudsButtonIcon?, nullableLabel: String?, onClick: () -> Unit, @@ -253,6 +256,7 @@ private fun OudsButton( enabled: Boolean = true, loader: OudsButtonLoader? = null, appearance: OudsButtonAppearance = OudsButtonDefaults.Appearance, + iconOnlyBadge: OudsButtonIconBadge? = null, interactionSource: MutableInteractionSource? = null ) { val icon = nullableIcon @@ -326,23 +330,54 @@ private fun OudsButton( } val alpha = if (state == OudsButtonState.Loading) 0f else 1f + val paddingValues = contentPadding(icon = icon, label = label) Row( modifier = Modifier .alpha(alpha = alpha) - .padding(contentPadding(icon = icon, label = label)), + .padding(paddingValues), horizontalArrangement = Arrangement.spacedBy(buttonTokens.spaceColumnGapIcon.value), verticalAlignment = Alignment.CenterVertically ) { if (icon != null) { val size = if (label == null) buttonTokens.sizeIconOnly else buttonTokens.sizeIcon - icon.Content( - modifier = Modifier - .size(size.value * iconScale) - .semantics { - contentDescription = if (label == null) icon.contentDescription else "" - }, - extraParameters = OudsButtonIcon.ExtraParameters(tint = contentColor.value) - ) + val iconContent: @Composable () -> Unit = { + icon.Content( + modifier = Modifier + .size(size.value * iconScale) + .semantics { + contentDescription = when { + // Ugly workaround to make TalkBack read badge and icon content descriptions correctly + label == null && iconOnlyBadge != null -> "${iconOnlyBadge.contentDescription}, ${icon.contentDescription}" + label == null -> icon.contentDescription + else -> "" + } + }, + extraParameters = OudsButtonIcon.ExtraParameters(tint = contentColor.value) + ) + } + + if (iconOnlyBadge != null && label == null) { + val buttonEndPadding = paddingValues.calculateEndPadding(LocalLayoutDirection.current) + val maximumBorderWidth = OudsButtonAppearance.entries.flatMap { appearance -> + OudsButtonState.entries.mapNotNull { state -> + borderWidth(appearance, state) + } + }.maxOrNull().orElse { 0.dp } + val maximumEndOverflow = with(LocalDensity.current) { + val iconBadgeEndPadding = OudsTheme.spaces.paddingInline.fourExtraSmall + return@with buttonEndPadding - maximumBorderWidth - iconBadgeEndPadding + } + OudsBadgedIcon( + modifier = Modifier.size(size.value * iconScale), + badgeCount = iconOnlyBadge.count, + badgeBorderColor = iconOnlyBadge.borderColor, + badgeMaximumEndOverflow = maximumEndOverflow, + ) { + iconContent() + } + } else { + iconContent() + } } if (label != null) { Text( @@ -724,6 +759,8 @@ enum class OudsButtonAppearance { */ data class OudsButtonLoader(val progress: Float?) +internal data class OudsButtonIconBadge(val contentDescription: String, val borderColor: Color, val count: Int? = null) + internal enum class OudsButtonState { Enabled, Hovered, Pressed, Loading, Disabled, Focused } @@ -746,7 +783,12 @@ internal fun PreviewOudsButton( val icon = if (hasIcon) OudsButtonIcon(Icons.Filled.FavoriteBorder, "") else null val content: @Composable () -> Unit = { PreviewEnumEntries(columnCount = 2) { - OudsButton(nullableIcon = icon, nullableLabel = label, onClick = {}, appearance = appearance) + OudsButton( + nullableIcon = icon, + nullableLabel = label, + onClick = {}, + appearance = appearance + ) } } if (onColoredBox) { @@ -768,7 +810,7 @@ private fun PreviewOudsButtonWithRoundedCorners() = PreviewOudsButtonWithRounded internal fun PreviewOudsButtonWithRoundedCorners(theme: OudsThemeContract) = OudsPreview(theme = theme.mapSettings { it.copy(roundedCornerButtons = true) }) { val appearance = OudsButtonAppearance.Default - PreviewEnumEntries(columnCount = 2) { state -> + PreviewEnumEntries(columnCount = 2) { OudsButton( nullableIcon = OudsButtonIcon(Icons.Filled.FavoriteBorder, ""), nullableLabel = appearance.name, @@ -778,6 +820,25 @@ internal fun PreviewOudsButtonWithRoundedCorners(theme: OudsThemeContract) = } } +@Preview +@Composable +@Suppress("PreviewShouldNotBeCalledRecursively") +private fun PreviewOudsButtonWithIconBadge(@PreviewParameter(OudsButtonWithIconBadgePreviewParameterProvider::class) count: Int) = + PreviewOudsButtonWithIconBadge(theme = getPreviewTheme(), count = count) + +@Composable +internal fun PreviewOudsButtonWithIconBadge(theme: OudsThemeContract, count: Int) = OudsPreview(theme = theme) { + PreviewEnumEntries(columnCount = 2) { + OudsButton( + nullableIcon = OudsButtonIcon(Icons.Filled.FavoriteBorder, ""), + nullableLabel = null, + onClick = {}, + appearance = OudsButtonAppearance.Minimal, + iconOnlyBadge = OudsButtonIconBadge("", OudsTheme.componentsTokens.bar.colorBorderBadge.value, count = count) + ) + } +} + internal data class OudsButtonPreviewParameter( val appearance: OudsButtonAppearance, val hasLabel: Boolean, @@ -799,3 +860,5 @@ private val previewParameterValues: List addAll(parameters.map { it.copy(onColoredBox = true) }) } } + +internal class OudsButtonWithIconBadgePreviewParameterProvider : BasicPreviewParameterProvider(1, OudsBadgeMaxCount + 1) 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 486e2d467..d351750d4 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 @@ -23,8 +23,6 @@ import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.RowScope import androidx.compose.foundation.layout.WindowInsets -import androidx.compose.foundation.layout.offset -import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.foundation.selection.selectable import androidx.compose.foundation.shape.RoundedCornerShape @@ -35,7 +33,6 @@ import androidx.compose.material.icons.filled.DateRange import androidx.compose.material.icons.filled.Email import androidx.compose.material.icons.filled.Settings import androidx.compose.material.icons.filled.Star -import androidx.compose.material3.BadgedBox import androidx.compose.material3.LocalRippleConfiguration import androidx.compose.material3.NavigationBar import androidx.compose.material3.NavigationBarDefaults @@ -245,8 +242,10 @@ data class OudsNavigationBarItem( onClick = onClick, icon = { if (badge != null) { - BadgedBox( - badge = { badge.Content() }, + OudsBadgedIcon( + modifier = Modifier.size(OudsNavigationBarItemIcon.Size), + badgeCount = badge.count, + badgeBorderColor = OudsTheme.componentsTokens.bar.colorBorderBadge.value ) { icon.Content() } @@ -380,34 +379,7 @@ class OudsNavigationBarItemIcon private constructor( * @property contentDescription Content description of the badge, needed for accessibility support (vocalized by Talkback). * @property count Optional number displayed in the badge. If not null, the badge has an [OudsBadgeSize.Medium] size. Otherwise, it has an [OudsBadgeSize.ExtraSmall] size. */ -class OudsNavigationBarItemBadge(val contentDescription: String, val count: Int? = null) : OudsComponentContent(Nothing::class.java) { - - @Composable - override fun Content(modifier: Modifier) { - val status = OudsBadgeStatus.Negative // In a navigation bar a badge has always a negative status. - val positionModifier = if (count != null) { - Modifier - } else { - val startPosition = OudsNavigationBarItemIcon.Size / 2 - val badgeSize = OudsTheme.componentsTokens.badge.sizeXsmall.dp - val xOffset = startPosition - badgeSize - val yOffset = (startPosition - badgeSize) + 2.dp - Modifier.offset(x = xOffset, y = -yOffset) - } - - Box( - modifier = positionModifier - .background(color = OudsTheme.componentsTokens.bar.colorBorderBadge.value, shape = OudsBadgeShape) - .padding(1.dp) - ) { - count?.let { - OudsBadge(count = count, modifier = modifier, status = status, size = OudsBadgeSize.Medium) - }.orElse { - OudsBadge(modifier = modifier, status = status, size = OudsBadgeSize.ExtraSmall) - } - } - } -} +data class OudsNavigationBarItemBadge(val contentDescription: String, val count: Int? = null) internal enum class OudsNavigationBarItemState { Enabled, Hovered, Pressed, Focused 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 050f31cb9..aeba6c50b 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 @@ -521,47 +521,65 @@ sealed interface OudsTopAppBarAction : OudsPolymorphicComponentContent { class Icon private constructor( graphicsObject: Any, contentDescription: String, + badge: OudsTopAppBarActionBadge?, onClick: () -> Unit - ) : OudsTopAppBarAction, OudsComponentIcon(Nothing::class.java, graphicsObject, contentDescription, onClick) { + ) : OudsTopAppBarAction, OudsComponentIcon(Nothing::class.java, { graphicsObject }, { contentDescription }, onClick) { + + private val _badge = badge + override val badge: OudsButtonIconBadge? + @Composable + get() = _badge?.let { badge -> + OudsButtonIconBadge( + contentDescription = badge.contentDescription, + count = badge.count, + borderColor = OudsTheme.componentsTokens.bar.colorBorderBadge.value + ) + } /** * Creates an instance of [OudsTopAppBarAction.Icon]. * * @param painter Painter of the icon. * @param contentDescription The content description associated with this [OudsTopAppBarAction.Icon]. + * @param badge Optional badge displayed on the icon. * @param onClick Callback invoked when the icon is clicked. */ constructor( painter: Painter, contentDescription: String, + badge: OudsTopAppBarActionBadge? = null, onClick: () -> Unit - ) : this(painter as Any, contentDescription, onClick) + ) : this(painter as Any, contentDescription, badge, onClick) /** * Creates an instance of [OudsTopAppBarAction.Icon]. * * @param imageVector Image vector of the icon. * @param contentDescription The content description associated with this [OudsTopAppBarAction.Icon]. + * @param badge Optional badge displayed on the icon. * @param onClick Callback invoked when the icon is clicked. */ constructor( imageVector: ImageVector, contentDescription: String, + badge: OudsTopAppBarActionBadge? = null, onClick: () -> Unit - ) : this(imageVector as Any, contentDescription, onClick) + ) : this(imageVector as Any, contentDescription, badge, onClick) /** * Creates an instance of [OudsTopAppBarAction.Icon]. * * @param bitmap Image bitmap of the icon. * @param contentDescription The content description associated with this [OudsTopAppBarAction.Icon]. + * @param badge Optional badge displayed on the icon. * @param onClick Callback invoked when the icon is clicked. */ constructor( bitmap: ImageBitmap, contentDescription: String, + badge: OudsTopAppBarActionBadge? = null, onClick: () -> Unit - ) : this(bitmap as Any, contentDescription, onClick) + ) : this(bitmap as Any, contentDescription, badge, onClick) } /** @@ -695,6 +713,16 @@ sealed interface OudsTopAppBarAction : OudsPolymorphicComponentContent { } } +/** + * A badge in an [OudsTopAppBarAction]. + * + * @see [OudsBadge] + * + * @property contentDescription Content description of the badge, needed for accessibility support (vocalized by Talkback). + * @property count Optional number displayed in the badge. If not null, the badge has an [OudsBadgeSize.Medium] size. Otherwise, it has an [OudsBadgeSize.ExtraSmall] size. + */ +data class OudsTopAppBarActionBadge(val contentDescription: String, val count: Int? = null) + private enum class OudsTopAppBarSize { Small, Medium, Large @@ -810,7 +838,12 @@ private val previewParameterValues: List OudsTopAppBarPreviewParameter( navigationIcon = OudsTopAppBarNavigationIcon(imageVector = Icons.Outlined.Settings, contentDescription = "", onClick = {}), actions = listOf( - OudsTopAppBarAction.Icon(imageVector = Icons.Outlined.AccountCircle, contentDescription = "", onClick = {}), + OudsTopAppBarAction.Icon( + imageVector = Icons.Outlined.AccountCircle, + contentDescription = "", + badge = OudsTopAppBarActionBadge(contentDescription = "", count = 10), + onClick = {} + ), OudsTopAppBarAction.Avatar( painter = PreviewCheckerboardPainter( squareSize = 6.dp, 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 c10a09108..f753d58c8 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 @@ -23,6 +23,7 @@ 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.foundation.extensions.orElse /** @@ -48,6 +49,11 @@ abstract class OudsComponentIcon protected constructor( @Composable get() = null + // The badge is not displayed if onClick is null + internal open val badge: OudsButtonIconBadge? + @Composable + get() = null + protected open val enabled: Boolean? @Composable get() = null @@ -69,11 +75,13 @@ abstract class OudsComponentIcon protected constructor( else -> null }?.let { buttonIcon -> OudsButton( - icon = buttonIcon, + nullableIcon = buttonIcon, + nullableLabel = null, appearance = OudsButtonAppearance.Minimal, onClick = onClick, modifier = modifier, enabled = enabled.orElse { true }, + iconOnlyBadge = badge ) } }.orElse { diff --git a/core/src/main/java/com/orange/ouds/core/theme/OudsBorders.kt b/core/src/main/java/com/orange/ouds/core/theme/OudsBorders.kt index e91bfeb2a..071740936 100644 --- a/core/src/main/java/com/orange/ouds/core/theme/OudsBorders.kt +++ b/core/src/main/java/com/orange/ouds/core/theme/OudsBorders.kt @@ -269,20 +269,26 @@ fun Modifier.dottedBorder( * @param shape The shape of the border. * @param insetWidth The width of the border inset in dp. Use [Dp.Hairline] for a hairline border inset. * @param insetColor The color to paint the border inset with. + * @param innerOffsetPx An offset applied to the inner side of the border, in pixels. + * The offset is applied to the border inset if it exists, or to the border itself otherwise. + * Use this parameter to avoid graphical glitches when drawing borders. */ -fun Modifier.outerBorder( +internal fun Modifier.outerBorder( width: Dp, color: Color, shape: Shape = RectangleShape, insetWidth: Dp = Dp.Unspecified, - insetColor: Color = Color.Unspecified + insetColor: Color = Color.Unspecified, + innerOffsetPx: Float = 0f ) = drawWithContent { + val hasInset = insetWidth.isSpecified && insetWidth > 0.dp && insetColor.alpha != 0f + // Make the border 1 pixel smaller on the inner side if there is an inset, otherwise for some reason the border can be visible behind the inset on the inner side + // If there is no inset, apply the innerOffsetPx parameter + val borderInnerOffsetPx = if (hasInset) 1f else innerOffsetPx + val insetInnerOffsetPx = if (hasInset) innerOffsetPx else 0f + drawOuterBorder(width, color, shape, borderInnerOffsetPx) + drawOuterBorder(insetWidth, insetColor, shape, insetInnerOffsetPx) drawContent() - // Make the border 1 pixel smaller on the inner side if there is an inset - // Otherwise, for some reason the border can be visible behind the inset on the inner side - val innerOffsetPx = if (insetWidth.isSpecified && insetWidth > 0.dp && insetColor.alpha != 0f) 1f else 0f - drawOuterBorder(width, color, shape, innerOffsetPx) - drawOuterBorder(insetWidth, insetColor, shape) } private fun DrawScope.drawOuterBorder(width: Dp, color: Color, shape: Shape, innerOffsetPx: Float = 0f) { diff --git a/core/src/main/java/com/orange/ouds/core/utilities/OudsPreviewableComponent.kt b/core/src/main/java/com/orange/ouds/core/utilities/OudsPreviewableComponent.kt index a55ffac58..9cd3862d7 100644 --- a/core/src/main/java/com/orange/ouds/core/utilities/OudsPreviewableComponent.kt +++ b/core/src/main/java/com/orange/ouds/core/utilities/OudsPreviewableComponent.kt @@ -19,6 +19,7 @@ import com.orange.ouds.core.component.OudsBadgeWithIconPreviewParameter import com.orange.ouds.core.component.OudsBadgeWithIconPreviewParameterProvider import com.orange.ouds.core.component.OudsButtonPreviewParameter import com.orange.ouds.core.component.OudsButtonPreviewParameterProvider +import com.orange.ouds.core.component.OudsButtonWithIconBadgePreviewParameterProvider import com.orange.ouds.core.component.OudsCheckboxItemHighContrastModePreviewParameter import com.orange.ouds.core.component.OudsCheckboxItemHighContrastModePreviewParameterProvider import com.orange.ouds.core.component.OudsCheckboxItemPreviewParameter @@ -56,6 +57,7 @@ import com.orange.ouds.core.component.OudsTopAppBarPreviewParameterProvider import com.orange.ouds.core.component.PreviewOudsBadge import com.orange.ouds.core.component.PreviewOudsBadgeWithIcon import com.orange.ouds.core.component.PreviewOudsButton +import com.orange.ouds.core.component.PreviewOudsButtonWithIconBadge import com.orange.ouds.core.component.PreviewOudsButtonWithRoundedCorners import com.orange.ouds.core.component.PreviewOudsCenterAlignedTopAppBar import com.orange.ouds.core.component.PreviewOudsCheckbox @@ -160,6 +162,21 @@ interface OudsPreviewableComponent { override fun isPreviewAvailable(darkThemeEnabled: Boolean, highContrastModeEnabled: Boolean) = !darkThemeEnabled && !highContrastModeEnabled } + + object WithIconBadge : OudsPreviewableComponent { + + override val parameters: List = OudsButtonWithIconBadgePreviewParameterProvider().values.toList() + + @Composable + override fun Preview(theme: OudsThemeContract, darkThemeEnabled: Boolean, highContrastModeEnabled: Boolean, parameter: Any?) { + PreviewOudsButtonWithIconBadge( + theme = theme, + count = parameter as Int + ) + } + + override fun isPreviewAvailable(darkThemeEnabled: Boolean, highContrastModeEnabled: Boolean) = !darkThemeEnabled && !highContrastModeEnabled + } } object CheckboxItem { diff --git a/core/src/test/java/com/orange/ouds/core/component/OudsBadgedIconTest.kt b/core/src/test/java/com/orange/ouds/core/component/OudsBadgedIconTest.kt new file mode 100644 index 000000000..9d3d16b3d --- /dev/null +++ b/core/src/test/java/com/orange/ouds/core/component/OudsBadgedIconTest.kt @@ -0,0 +1,38 @@ +/* + * 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 com.orange.ouds.core.test.OudsSnapshotTest +import com.orange.ouds.theme.orange.OrangeTheme +import org.junit.runner.RunWith +import org.junit.runners.Parameterized + +@RunWith(Parameterized::class) +internal class OudsBadgedIconTest(val parameter: OudsBadgedIconPreviewParameter) : OudsSnapshotTest(theme = OrangeTheme()) { + + companion object { + @JvmStatic + @Parameterized.Parameters + internal fun data() = OudsBadgedIconPreviewParameterProvider().values.toList() + } + + @Composable + override fun Snapshot(darkThemeEnabled: Boolean, highContrastModeEnabled: Boolean) { + PreviewOudsBadgedIcon( + theme = theme, + darkThemeEnabled = darkThemeEnabled, + parameter = parameter + ) + } +} diff --git a/core/src/test/snapshots/images/com.orange.ouds.core.component_OudsBadgedIconTest_takeDarkThemeSnapshot[0].png b/core/src/test/snapshots/images/com.orange.ouds.core.component_OudsBadgedIconTest_takeDarkThemeSnapshot[0].png new file mode 100644 index 000000000..38a535e5d Binary files /dev/null and b/core/src/test/snapshots/images/com.orange.ouds.core.component_OudsBadgedIconTest_takeDarkThemeSnapshot[0].png differ diff --git a/core/src/test/snapshots/images/com.orange.ouds.core.component_OudsBadgedIconTest_takeDarkThemeSnapshot[1].png b/core/src/test/snapshots/images/com.orange.ouds.core.component_OudsBadgedIconTest_takeDarkThemeSnapshot[1].png new file mode 100644 index 000000000..4312f8185 Binary files /dev/null and b/core/src/test/snapshots/images/com.orange.ouds.core.component_OudsBadgedIconTest_takeDarkThemeSnapshot[1].png differ diff --git a/core/src/test/snapshots/images/com.orange.ouds.core.component_OudsBadgedIconTest_takeDarkThemeSnapshot[2].png b/core/src/test/snapshots/images/com.orange.ouds.core.component_OudsBadgedIconTest_takeDarkThemeSnapshot[2].png new file mode 100644 index 000000000..14f5f0f1e Binary files /dev/null and b/core/src/test/snapshots/images/com.orange.ouds.core.component_OudsBadgedIconTest_takeDarkThemeSnapshot[2].png differ diff --git a/core/src/test/snapshots/images/com.orange.ouds.core.component_OudsBadgedIconTest_takeDarkThemeSnapshot[3].png b/core/src/test/snapshots/images/com.orange.ouds.core.component_OudsBadgedIconTest_takeDarkThemeSnapshot[3].png new file mode 100644 index 000000000..e0c41a018 Binary files /dev/null and b/core/src/test/snapshots/images/com.orange.ouds.core.component_OudsBadgedIconTest_takeDarkThemeSnapshot[3].png differ diff --git a/core/src/test/snapshots/images/com.orange.ouds.core.component_OudsBadgedIconTest_takeDarkThemeSnapshot[4].png b/core/src/test/snapshots/images/com.orange.ouds.core.component_OudsBadgedIconTest_takeDarkThemeSnapshot[4].png new file mode 100644 index 000000000..1f8796309 Binary files /dev/null and b/core/src/test/snapshots/images/com.orange.ouds.core.component_OudsBadgedIconTest_takeDarkThemeSnapshot[4].png differ diff --git a/core/src/test/snapshots/images/com.orange.ouds.core.component_OudsBadgedIconTest_takeLightThemeSnapshot[0].png b/core/src/test/snapshots/images/com.orange.ouds.core.component_OudsBadgedIconTest_takeLightThemeSnapshot[0].png new file mode 100644 index 000000000..2c2cf2275 Binary files /dev/null and b/core/src/test/snapshots/images/com.orange.ouds.core.component_OudsBadgedIconTest_takeLightThemeSnapshot[0].png differ diff --git a/core/src/test/snapshots/images/com.orange.ouds.core.component_OudsBadgedIconTest_takeLightThemeSnapshot[1].png b/core/src/test/snapshots/images/com.orange.ouds.core.component_OudsBadgedIconTest_takeLightThemeSnapshot[1].png new file mode 100644 index 000000000..841416ee5 Binary files /dev/null and b/core/src/test/snapshots/images/com.orange.ouds.core.component_OudsBadgedIconTest_takeLightThemeSnapshot[1].png differ diff --git a/core/src/test/snapshots/images/com.orange.ouds.core.component_OudsBadgedIconTest_takeLightThemeSnapshot[2].png b/core/src/test/snapshots/images/com.orange.ouds.core.component_OudsBadgedIconTest_takeLightThemeSnapshot[2].png new file mode 100644 index 000000000..be1474d40 Binary files /dev/null and b/core/src/test/snapshots/images/com.orange.ouds.core.component_OudsBadgedIconTest_takeLightThemeSnapshot[2].png differ diff --git a/core/src/test/snapshots/images/com.orange.ouds.core.component_OudsBadgedIconTest_takeLightThemeSnapshot[3].png b/core/src/test/snapshots/images/com.orange.ouds.core.component_OudsBadgedIconTest_takeLightThemeSnapshot[3].png new file mode 100644 index 000000000..73c55712b Binary files /dev/null and b/core/src/test/snapshots/images/com.orange.ouds.core.component_OudsBadgedIconTest_takeLightThemeSnapshot[3].png differ diff --git a/core/src/test/snapshots/images/com.orange.ouds.core.component_OudsBadgedIconTest_takeLightThemeSnapshot[4].png b/core/src/test/snapshots/images/com.orange.ouds.core.component_OudsBadgedIconTest_takeLightThemeSnapshot[4].png new file mode 100644 index 000000000..e8af0df4f Binary files /dev/null and b/core/src/test/snapshots/images/com.orange.ouds.core.component_OudsBadgedIconTest_takeLightThemeSnapshot[4].png differ diff --git a/theme-orange/src/test/snapshots/images/com.orange.ouds.core.test_OudsButtonTest$WithIconBadge_takeLightThemeSnapshot[0].png b/theme-orange/src/test/snapshots/images/com.orange.ouds.core.test_OudsButtonTest$WithIconBadge_takeLightThemeSnapshot[0].png new file mode 100644 index 000000000..d82ef4b68 Binary files /dev/null and b/theme-orange/src/test/snapshots/images/com.orange.ouds.core.test_OudsButtonTest$WithIconBadge_takeLightThemeSnapshot[0].png differ diff --git a/theme-orange/src/test/snapshots/images/com.orange.ouds.core.test_OudsButtonTest$WithIconBadge_takeLightThemeSnapshot[1].png b/theme-orange/src/test/snapshots/images/com.orange.ouds.core.test_OudsButtonTest$WithIconBadge_takeLightThemeSnapshot[1].png new file mode 100644 index 000000000..77b86836d Binary files /dev/null and b/theme-orange/src/test/snapshots/images/com.orange.ouds.core.test_OudsButtonTest$WithIconBadge_takeLightThemeSnapshot[1].png differ diff --git a/theme-orange/src/test/snapshots/images/com.orange.ouds.core.test_OudsNavigationBarTest_takeDarkThemeSnapshot[0].png b/theme-orange/src/test/snapshots/images/com.orange.ouds.core.test_OudsNavigationBarTest_takeDarkThemeSnapshot[0].png index 3ea5435d4..89e71d833 100644 Binary files a/theme-orange/src/test/snapshots/images/com.orange.ouds.core.test_OudsNavigationBarTest_takeDarkThemeSnapshot[0].png and b/theme-orange/src/test/snapshots/images/com.orange.ouds.core.test_OudsNavigationBarTest_takeDarkThemeSnapshot[0].png differ diff --git a/theme-orange/src/test/snapshots/images/com.orange.ouds.core.test_OudsNavigationBarTest_takeDarkThemeSnapshot[1].png b/theme-orange/src/test/snapshots/images/com.orange.ouds.core.test_OudsNavigationBarTest_takeDarkThemeSnapshot[1].png index 8767aee57..b72792fe4 100644 Binary files a/theme-orange/src/test/snapshots/images/com.orange.ouds.core.test_OudsNavigationBarTest_takeDarkThemeSnapshot[1].png and b/theme-orange/src/test/snapshots/images/com.orange.ouds.core.test_OudsNavigationBarTest_takeDarkThemeSnapshot[1].png differ diff --git a/theme-orange/src/test/snapshots/images/com.orange.ouds.core.test_OudsNavigationBarTest_takeLightThemeSnapshot[0].png b/theme-orange/src/test/snapshots/images/com.orange.ouds.core.test_OudsNavigationBarTest_takeLightThemeSnapshot[0].png index 53a29dd90..64892e67d 100644 Binary files a/theme-orange/src/test/snapshots/images/com.orange.ouds.core.test_OudsNavigationBarTest_takeLightThemeSnapshot[0].png and b/theme-orange/src/test/snapshots/images/com.orange.ouds.core.test_OudsNavigationBarTest_takeLightThemeSnapshot[0].png differ diff --git a/theme-orange/src/test/snapshots/images/com.orange.ouds.core.test_OudsNavigationBarTest_takeLightThemeSnapshot[1].png b/theme-orange/src/test/snapshots/images/com.orange.ouds.core.test_OudsNavigationBarTest_takeLightThemeSnapshot[1].png index 13f71c445..c74121d0a 100644 Binary files a/theme-orange/src/test/snapshots/images/com.orange.ouds.core.test_OudsNavigationBarTest_takeLightThemeSnapshot[1].png and b/theme-orange/src/test/snapshots/images/com.orange.ouds.core.test_OudsNavigationBarTest_takeLightThemeSnapshot[1].png differ diff --git a/theme-orange/src/test/snapshots/images/com.orange.ouds.core.test_OudsTopAppBarTest$CenterAligned_takeDarkThemeSnapshot[2].png b/theme-orange/src/test/snapshots/images/com.orange.ouds.core.test_OudsTopAppBarTest$CenterAligned_takeDarkThemeSnapshot[2].png index cd9efbe56..24e92541e 100644 Binary files a/theme-orange/src/test/snapshots/images/com.orange.ouds.core.test_OudsTopAppBarTest$CenterAligned_takeDarkThemeSnapshot[2].png and b/theme-orange/src/test/snapshots/images/com.orange.ouds.core.test_OudsTopAppBarTest$CenterAligned_takeDarkThemeSnapshot[2].png differ diff --git a/theme-orange/src/test/snapshots/images/com.orange.ouds.core.test_OudsTopAppBarTest$CenterAligned_takeLightThemeSnapshot[2].png b/theme-orange/src/test/snapshots/images/com.orange.ouds.core.test_OudsTopAppBarTest$CenterAligned_takeLightThemeSnapshot[2].png index 2f6d42271..98812d7a3 100644 Binary files a/theme-orange/src/test/snapshots/images/com.orange.ouds.core.test_OudsTopAppBarTest$CenterAligned_takeLightThemeSnapshot[2].png and b/theme-orange/src/test/snapshots/images/com.orange.ouds.core.test_OudsTopAppBarTest$CenterAligned_takeLightThemeSnapshot[2].png differ diff --git a/theme-orange/src/test/snapshots/images/com.orange.ouds.core.test_OudsTopAppBarTest$Default_takeDarkThemeSnapshot[2].png b/theme-orange/src/test/snapshots/images/com.orange.ouds.core.test_OudsTopAppBarTest$Default_takeDarkThemeSnapshot[2].png index a424e68c1..f52c758e4 100644 Binary files a/theme-orange/src/test/snapshots/images/com.orange.ouds.core.test_OudsTopAppBarTest$Default_takeDarkThemeSnapshot[2].png and b/theme-orange/src/test/snapshots/images/com.orange.ouds.core.test_OudsTopAppBarTest$Default_takeDarkThemeSnapshot[2].png differ diff --git a/theme-orange/src/test/snapshots/images/com.orange.ouds.core.test_OudsTopAppBarTest$Default_takeLightThemeSnapshot[2].png b/theme-orange/src/test/snapshots/images/com.orange.ouds.core.test_OudsTopAppBarTest$Default_takeLightThemeSnapshot[2].png index fcedd938f..d49cc5cb8 100644 Binary files a/theme-orange/src/test/snapshots/images/com.orange.ouds.core.test_OudsTopAppBarTest$Default_takeLightThemeSnapshot[2].png and b/theme-orange/src/test/snapshots/images/com.orange.ouds.core.test_OudsTopAppBarTest$Default_takeLightThemeSnapshot[2].png differ diff --git a/theme-orange/src/test/snapshots/images/com.orange.ouds.core.test_OudsTopAppBarTest$Large_takeDarkThemeSnapshot[2].png b/theme-orange/src/test/snapshots/images/com.orange.ouds.core.test_OudsTopAppBarTest$Large_takeDarkThemeSnapshot[2].png index 1d95f7e34..96bc5ab49 100644 Binary files a/theme-orange/src/test/snapshots/images/com.orange.ouds.core.test_OudsTopAppBarTest$Large_takeDarkThemeSnapshot[2].png and b/theme-orange/src/test/snapshots/images/com.orange.ouds.core.test_OudsTopAppBarTest$Large_takeDarkThemeSnapshot[2].png differ diff --git a/theme-orange/src/test/snapshots/images/com.orange.ouds.core.test_OudsTopAppBarTest$Large_takeLightThemeSnapshot[2].png b/theme-orange/src/test/snapshots/images/com.orange.ouds.core.test_OudsTopAppBarTest$Large_takeLightThemeSnapshot[2].png index 24f38f949..0a9d37bb7 100644 Binary files a/theme-orange/src/test/snapshots/images/com.orange.ouds.core.test_OudsTopAppBarTest$Large_takeLightThemeSnapshot[2].png and b/theme-orange/src/test/snapshots/images/com.orange.ouds.core.test_OudsTopAppBarTest$Large_takeLightThemeSnapshot[2].png differ diff --git a/theme-orange/src/test/snapshots/images/com.orange.ouds.core.test_OudsTopAppBarTest$Medium_takeDarkThemeSnapshot[2].png b/theme-orange/src/test/snapshots/images/com.orange.ouds.core.test_OudsTopAppBarTest$Medium_takeDarkThemeSnapshot[2].png index c4bdfb44c..465df1eb8 100644 Binary files a/theme-orange/src/test/snapshots/images/com.orange.ouds.core.test_OudsTopAppBarTest$Medium_takeDarkThemeSnapshot[2].png and b/theme-orange/src/test/snapshots/images/com.orange.ouds.core.test_OudsTopAppBarTest$Medium_takeDarkThemeSnapshot[2].png differ diff --git a/theme-orange/src/test/snapshots/images/com.orange.ouds.core.test_OudsTopAppBarTest$Medium_takeLightThemeSnapshot[2].png b/theme-orange/src/test/snapshots/images/com.orange.ouds.core.test_OudsTopAppBarTest$Medium_takeLightThemeSnapshot[2].png index 5b1eb6963..eb839a831 100644 Binary files a/theme-orange/src/test/snapshots/images/com.orange.ouds.core.test_OudsTopAppBarTest$Medium_takeLightThemeSnapshot[2].png and b/theme-orange/src/test/snapshots/images/com.orange.ouds.core.test_OudsTopAppBarTest$Medium_takeLightThemeSnapshot[2].png differ diff --git a/theme-sosh/src/test/snapshots/images/com.orange.ouds.core.test_OudsButtonTest$WithIconBadge_takeLightThemeSnapshot[0].png b/theme-sosh/src/test/snapshots/images/com.orange.ouds.core.test_OudsButtonTest$WithIconBadge_takeLightThemeSnapshot[0].png new file mode 100644 index 000000000..56f53e547 Binary files /dev/null and b/theme-sosh/src/test/snapshots/images/com.orange.ouds.core.test_OudsButtonTest$WithIconBadge_takeLightThemeSnapshot[0].png differ diff --git a/theme-sosh/src/test/snapshots/images/com.orange.ouds.core.test_OudsButtonTest$WithIconBadge_takeLightThemeSnapshot[1].png b/theme-sosh/src/test/snapshots/images/com.orange.ouds.core.test_OudsButtonTest$WithIconBadge_takeLightThemeSnapshot[1].png new file mode 100644 index 000000000..da75626e9 Binary files /dev/null and b/theme-sosh/src/test/snapshots/images/com.orange.ouds.core.test_OudsButtonTest$WithIconBadge_takeLightThemeSnapshot[1].png differ diff --git a/theme-sosh/src/test/snapshots/images/com.orange.ouds.core.test_OudsNavigationBarTest_takeDarkThemeSnapshot[0].png b/theme-sosh/src/test/snapshots/images/com.orange.ouds.core.test_OudsNavigationBarTest_takeDarkThemeSnapshot[0].png index 0e8af1149..0aec188be 100644 Binary files a/theme-sosh/src/test/snapshots/images/com.orange.ouds.core.test_OudsNavigationBarTest_takeDarkThemeSnapshot[0].png and b/theme-sosh/src/test/snapshots/images/com.orange.ouds.core.test_OudsNavigationBarTest_takeDarkThemeSnapshot[0].png differ diff --git a/theme-sosh/src/test/snapshots/images/com.orange.ouds.core.test_OudsNavigationBarTest_takeDarkThemeSnapshot[1].png b/theme-sosh/src/test/snapshots/images/com.orange.ouds.core.test_OudsNavigationBarTest_takeDarkThemeSnapshot[1].png index a14c66d2f..53b9e804a 100644 Binary files a/theme-sosh/src/test/snapshots/images/com.orange.ouds.core.test_OudsNavigationBarTest_takeDarkThemeSnapshot[1].png and b/theme-sosh/src/test/snapshots/images/com.orange.ouds.core.test_OudsNavigationBarTest_takeDarkThemeSnapshot[1].png differ diff --git a/theme-sosh/src/test/snapshots/images/com.orange.ouds.core.test_OudsNavigationBarTest_takeLightThemeSnapshot[0].png b/theme-sosh/src/test/snapshots/images/com.orange.ouds.core.test_OudsNavigationBarTest_takeLightThemeSnapshot[0].png index 1d4cbed85..87bec3c26 100644 Binary files a/theme-sosh/src/test/snapshots/images/com.orange.ouds.core.test_OudsNavigationBarTest_takeLightThemeSnapshot[0].png and b/theme-sosh/src/test/snapshots/images/com.orange.ouds.core.test_OudsNavigationBarTest_takeLightThemeSnapshot[0].png differ diff --git a/theme-sosh/src/test/snapshots/images/com.orange.ouds.core.test_OudsNavigationBarTest_takeLightThemeSnapshot[1].png b/theme-sosh/src/test/snapshots/images/com.orange.ouds.core.test_OudsNavigationBarTest_takeLightThemeSnapshot[1].png index e104e5821..5cc808e56 100644 Binary files a/theme-sosh/src/test/snapshots/images/com.orange.ouds.core.test_OudsNavigationBarTest_takeLightThemeSnapshot[1].png and b/theme-sosh/src/test/snapshots/images/com.orange.ouds.core.test_OudsNavigationBarTest_takeLightThemeSnapshot[1].png differ diff --git a/theme-sosh/src/test/snapshots/images/com.orange.ouds.core.test_OudsTopAppBarTest$CenterAligned_takeDarkThemeSnapshot[2].png b/theme-sosh/src/test/snapshots/images/com.orange.ouds.core.test_OudsTopAppBarTest$CenterAligned_takeDarkThemeSnapshot[2].png index 9fe991730..7112e08cf 100644 Binary files a/theme-sosh/src/test/snapshots/images/com.orange.ouds.core.test_OudsTopAppBarTest$CenterAligned_takeDarkThemeSnapshot[2].png and b/theme-sosh/src/test/snapshots/images/com.orange.ouds.core.test_OudsTopAppBarTest$CenterAligned_takeDarkThemeSnapshot[2].png differ diff --git a/theme-sosh/src/test/snapshots/images/com.orange.ouds.core.test_OudsTopAppBarTest$CenterAligned_takeLightThemeSnapshot[2].png b/theme-sosh/src/test/snapshots/images/com.orange.ouds.core.test_OudsTopAppBarTest$CenterAligned_takeLightThemeSnapshot[2].png index a42492d76..8ab5e13d8 100644 Binary files a/theme-sosh/src/test/snapshots/images/com.orange.ouds.core.test_OudsTopAppBarTest$CenterAligned_takeLightThemeSnapshot[2].png and b/theme-sosh/src/test/snapshots/images/com.orange.ouds.core.test_OudsTopAppBarTest$CenterAligned_takeLightThemeSnapshot[2].png differ diff --git a/theme-sosh/src/test/snapshots/images/com.orange.ouds.core.test_OudsTopAppBarTest$Default_takeDarkThemeSnapshot[2].png b/theme-sosh/src/test/snapshots/images/com.orange.ouds.core.test_OudsTopAppBarTest$Default_takeDarkThemeSnapshot[2].png index 1d360e8c2..6b2d26413 100644 Binary files a/theme-sosh/src/test/snapshots/images/com.orange.ouds.core.test_OudsTopAppBarTest$Default_takeDarkThemeSnapshot[2].png and b/theme-sosh/src/test/snapshots/images/com.orange.ouds.core.test_OudsTopAppBarTest$Default_takeDarkThemeSnapshot[2].png differ diff --git a/theme-sosh/src/test/snapshots/images/com.orange.ouds.core.test_OudsTopAppBarTest$Default_takeLightThemeSnapshot[2].png b/theme-sosh/src/test/snapshots/images/com.orange.ouds.core.test_OudsTopAppBarTest$Default_takeLightThemeSnapshot[2].png index 00bad84ae..f41086b02 100644 Binary files a/theme-sosh/src/test/snapshots/images/com.orange.ouds.core.test_OudsTopAppBarTest$Default_takeLightThemeSnapshot[2].png and b/theme-sosh/src/test/snapshots/images/com.orange.ouds.core.test_OudsTopAppBarTest$Default_takeLightThemeSnapshot[2].png differ diff --git a/theme-sosh/src/test/snapshots/images/com.orange.ouds.core.test_OudsTopAppBarTest$Large_takeDarkThemeSnapshot[2].png b/theme-sosh/src/test/snapshots/images/com.orange.ouds.core.test_OudsTopAppBarTest$Large_takeDarkThemeSnapshot[2].png index e1a58ec26..401e6e32a 100644 Binary files a/theme-sosh/src/test/snapshots/images/com.orange.ouds.core.test_OudsTopAppBarTest$Large_takeDarkThemeSnapshot[2].png and b/theme-sosh/src/test/snapshots/images/com.orange.ouds.core.test_OudsTopAppBarTest$Large_takeDarkThemeSnapshot[2].png differ diff --git a/theme-sosh/src/test/snapshots/images/com.orange.ouds.core.test_OudsTopAppBarTest$Large_takeLightThemeSnapshot[2].png b/theme-sosh/src/test/snapshots/images/com.orange.ouds.core.test_OudsTopAppBarTest$Large_takeLightThemeSnapshot[2].png index 7087d6860..2f13ccc36 100644 Binary files a/theme-sosh/src/test/snapshots/images/com.orange.ouds.core.test_OudsTopAppBarTest$Large_takeLightThemeSnapshot[2].png and b/theme-sosh/src/test/snapshots/images/com.orange.ouds.core.test_OudsTopAppBarTest$Large_takeLightThemeSnapshot[2].png differ diff --git a/theme-sosh/src/test/snapshots/images/com.orange.ouds.core.test_OudsTopAppBarTest$Medium_takeDarkThemeSnapshot[2].png b/theme-sosh/src/test/snapshots/images/com.orange.ouds.core.test_OudsTopAppBarTest$Medium_takeDarkThemeSnapshot[2].png index 5c0007fd9..efb19558c 100644 Binary files a/theme-sosh/src/test/snapshots/images/com.orange.ouds.core.test_OudsTopAppBarTest$Medium_takeDarkThemeSnapshot[2].png and b/theme-sosh/src/test/snapshots/images/com.orange.ouds.core.test_OudsTopAppBarTest$Medium_takeDarkThemeSnapshot[2].png differ diff --git a/theme-sosh/src/test/snapshots/images/com.orange.ouds.core.test_OudsTopAppBarTest$Medium_takeLightThemeSnapshot[2].png b/theme-sosh/src/test/snapshots/images/com.orange.ouds.core.test_OudsTopAppBarTest$Medium_takeLightThemeSnapshot[2].png index 02a7b8f3b..32bf667c9 100644 Binary files a/theme-sosh/src/test/snapshots/images/com.orange.ouds.core.test_OudsTopAppBarTest$Medium_takeLightThemeSnapshot[2].png and b/theme-sosh/src/test/snapshots/images/com.orange.ouds.core.test_OudsTopAppBarTest$Medium_takeLightThemeSnapshot[2].png differ diff --git a/theme-wireframe/src/test/snapshots/images/com.orange.ouds.core.test_OudsButtonTest$WithIconBadge_takeLightThemeSnapshot[0].png b/theme-wireframe/src/test/snapshots/images/com.orange.ouds.core.test_OudsButtonTest$WithIconBadge_takeLightThemeSnapshot[0].png new file mode 100644 index 000000000..dedfe4f85 Binary files /dev/null and b/theme-wireframe/src/test/snapshots/images/com.orange.ouds.core.test_OudsButtonTest$WithIconBadge_takeLightThemeSnapshot[0].png differ diff --git a/theme-wireframe/src/test/snapshots/images/com.orange.ouds.core.test_OudsButtonTest$WithIconBadge_takeLightThemeSnapshot[1].png b/theme-wireframe/src/test/snapshots/images/com.orange.ouds.core.test_OudsButtonTest$WithIconBadge_takeLightThemeSnapshot[1].png new file mode 100644 index 000000000..0cd5b0be7 Binary files /dev/null and b/theme-wireframe/src/test/snapshots/images/com.orange.ouds.core.test_OudsButtonTest$WithIconBadge_takeLightThemeSnapshot[1].png differ diff --git a/theme-wireframe/src/test/snapshots/images/com.orange.ouds.core.test_OudsNavigationBarTest_takeDarkThemeSnapshot[0].png b/theme-wireframe/src/test/snapshots/images/com.orange.ouds.core.test_OudsNavigationBarTest_takeDarkThemeSnapshot[0].png index 7bfa64bce..0e15f908a 100644 Binary files a/theme-wireframe/src/test/snapshots/images/com.orange.ouds.core.test_OudsNavigationBarTest_takeDarkThemeSnapshot[0].png and b/theme-wireframe/src/test/snapshots/images/com.orange.ouds.core.test_OudsNavigationBarTest_takeDarkThemeSnapshot[0].png differ diff --git a/theme-wireframe/src/test/snapshots/images/com.orange.ouds.core.test_OudsNavigationBarTest_takeDarkThemeSnapshot[1].png b/theme-wireframe/src/test/snapshots/images/com.orange.ouds.core.test_OudsNavigationBarTest_takeDarkThemeSnapshot[1].png index 897f300cc..b8770218f 100644 Binary files a/theme-wireframe/src/test/snapshots/images/com.orange.ouds.core.test_OudsNavigationBarTest_takeDarkThemeSnapshot[1].png and b/theme-wireframe/src/test/snapshots/images/com.orange.ouds.core.test_OudsNavigationBarTest_takeDarkThemeSnapshot[1].png differ diff --git a/theme-wireframe/src/test/snapshots/images/com.orange.ouds.core.test_OudsNavigationBarTest_takeLightThemeSnapshot[0].png b/theme-wireframe/src/test/snapshots/images/com.orange.ouds.core.test_OudsNavigationBarTest_takeLightThemeSnapshot[0].png index d592ca39d..4732afbc7 100644 Binary files a/theme-wireframe/src/test/snapshots/images/com.orange.ouds.core.test_OudsNavigationBarTest_takeLightThemeSnapshot[0].png and b/theme-wireframe/src/test/snapshots/images/com.orange.ouds.core.test_OudsNavigationBarTest_takeLightThemeSnapshot[0].png differ diff --git a/theme-wireframe/src/test/snapshots/images/com.orange.ouds.core.test_OudsNavigationBarTest_takeLightThemeSnapshot[1].png b/theme-wireframe/src/test/snapshots/images/com.orange.ouds.core.test_OudsNavigationBarTest_takeLightThemeSnapshot[1].png index cec1fef3b..c7ef5968a 100644 Binary files a/theme-wireframe/src/test/snapshots/images/com.orange.ouds.core.test_OudsNavigationBarTest_takeLightThemeSnapshot[1].png and b/theme-wireframe/src/test/snapshots/images/com.orange.ouds.core.test_OudsNavigationBarTest_takeLightThemeSnapshot[1].png differ diff --git a/theme-wireframe/src/test/snapshots/images/com.orange.ouds.core.test_OudsTopAppBarTest$CenterAligned_takeDarkThemeSnapshot[2].png b/theme-wireframe/src/test/snapshots/images/com.orange.ouds.core.test_OudsTopAppBarTest$CenterAligned_takeDarkThemeSnapshot[2].png index 46208c7b9..1b38294a5 100644 Binary files a/theme-wireframe/src/test/snapshots/images/com.orange.ouds.core.test_OudsTopAppBarTest$CenterAligned_takeDarkThemeSnapshot[2].png and b/theme-wireframe/src/test/snapshots/images/com.orange.ouds.core.test_OudsTopAppBarTest$CenterAligned_takeDarkThemeSnapshot[2].png differ diff --git a/theme-wireframe/src/test/snapshots/images/com.orange.ouds.core.test_OudsTopAppBarTest$CenterAligned_takeLightThemeSnapshot[2].png b/theme-wireframe/src/test/snapshots/images/com.orange.ouds.core.test_OudsTopAppBarTest$CenterAligned_takeLightThemeSnapshot[2].png index ae449d571..6dcd50a1e 100644 Binary files a/theme-wireframe/src/test/snapshots/images/com.orange.ouds.core.test_OudsTopAppBarTest$CenterAligned_takeLightThemeSnapshot[2].png and b/theme-wireframe/src/test/snapshots/images/com.orange.ouds.core.test_OudsTopAppBarTest$CenterAligned_takeLightThemeSnapshot[2].png differ diff --git a/theme-wireframe/src/test/snapshots/images/com.orange.ouds.core.test_OudsTopAppBarTest$Default_takeDarkThemeSnapshot[2].png b/theme-wireframe/src/test/snapshots/images/com.orange.ouds.core.test_OudsTopAppBarTest$Default_takeDarkThemeSnapshot[2].png index b47b16ab7..add8e1a1d 100644 Binary files a/theme-wireframe/src/test/snapshots/images/com.orange.ouds.core.test_OudsTopAppBarTest$Default_takeDarkThemeSnapshot[2].png and b/theme-wireframe/src/test/snapshots/images/com.orange.ouds.core.test_OudsTopAppBarTest$Default_takeDarkThemeSnapshot[2].png differ diff --git a/theme-wireframe/src/test/snapshots/images/com.orange.ouds.core.test_OudsTopAppBarTest$Default_takeLightThemeSnapshot[2].png b/theme-wireframe/src/test/snapshots/images/com.orange.ouds.core.test_OudsTopAppBarTest$Default_takeLightThemeSnapshot[2].png index 369f4f92c..5fc597486 100644 Binary files a/theme-wireframe/src/test/snapshots/images/com.orange.ouds.core.test_OudsTopAppBarTest$Default_takeLightThemeSnapshot[2].png and b/theme-wireframe/src/test/snapshots/images/com.orange.ouds.core.test_OudsTopAppBarTest$Default_takeLightThemeSnapshot[2].png differ diff --git a/theme-wireframe/src/test/snapshots/images/com.orange.ouds.core.test_OudsTopAppBarTest$Large_takeDarkThemeSnapshot[2].png b/theme-wireframe/src/test/snapshots/images/com.orange.ouds.core.test_OudsTopAppBarTest$Large_takeDarkThemeSnapshot[2].png index 669ae7741..64cc75de8 100644 Binary files a/theme-wireframe/src/test/snapshots/images/com.orange.ouds.core.test_OudsTopAppBarTest$Large_takeDarkThemeSnapshot[2].png and b/theme-wireframe/src/test/snapshots/images/com.orange.ouds.core.test_OudsTopAppBarTest$Large_takeDarkThemeSnapshot[2].png differ diff --git a/theme-wireframe/src/test/snapshots/images/com.orange.ouds.core.test_OudsTopAppBarTest$Large_takeLightThemeSnapshot[2].png b/theme-wireframe/src/test/snapshots/images/com.orange.ouds.core.test_OudsTopAppBarTest$Large_takeLightThemeSnapshot[2].png index 909b4d46f..7a56344c1 100644 Binary files a/theme-wireframe/src/test/snapshots/images/com.orange.ouds.core.test_OudsTopAppBarTest$Large_takeLightThemeSnapshot[2].png and b/theme-wireframe/src/test/snapshots/images/com.orange.ouds.core.test_OudsTopAppBarTest$Large_takeLightThemeSnapshot[2].png differ diff --git a/theme-wireframe/src/test/snapshots/images/com.orange.ouds.core.test_OudsTopAppBarTest$Medium_takeDarkThemeSnapshot[2].png b/theme-wireframe/src/test/snapshots/images/com.orange.ouds.core.test_OudsTopAppBarTest$Medium_takeDarkThemeSnapshot[2].png index ab8644c33..d34ea0bb1 100644 Binary files a/theme-wireframe/src/test/snapshots/images/com.orange.ouds.core.test_OudsTopAppBarTest$Medium_takeDarkThemeSnapshot[2].png and b/theme-wireframe/src/test/snapshots/images/com.orange.ouds.core.test_OudsTopAppBarTest$Medium_takeDarkThemeSnapshot[2].png differ diff --git a/theme-wireframe/src/test/snapshots/images/com.orange.ouds.core.test_OudsTopAppBarTest$Medium_takeLightThemeSnapshot[2].png b/theme-wireframe/src/test/snapshots/images/com.orange.ouds.core.test_OudsTopAppBarTest$Medium_takeLightThemeSnapshot[2].png index 2f240a271..d32dfba05 100644 Binary files a/theme-wireframe/src/test/snapshots/images/com.orange.ouds.core.test_OudsTopAppBarTest$Medium_takeLightThemeSnapshot[2].png and b/theme-wireframe/src/test/snapshots/images/com.orange.ouds.core.test_OudsTopAppBarTest$Medium_takeLightThemeSnapshot[2].png differ