Skip to content

Commit

Permalink
feat: add dimension tokens in the demo app (#147)
Browse files Browse the repository at this point in the history
  • Loading branch information
paulinea authored Nov 8, 2024
1 parent 741e11e commit a8bb875
Showing 30 changed files with 2,015 additions and 1,210 deletions.
3 changes: 3 additions & 0 deletions NOTICE.txt
Original file line number Diff line number Diff line change
@@ -9,8 +9,11 @@ and reproducing the content of the NOTICE and DOCUMENTATION files.
Any use or displaying shall constitute an infringement under intellectual property laws of France and international conventions.

app/src/main/res/drawable/ic_border.xml
app/src/main/res/drawable/ic_chevron_down.xml
app/src/main/res/drawable/ic_component_atom.xml
app/src/main/res/drawable/ic_design_token_figma.xml
app/src/main/res/drawable/ic_design_token_figma_no_padding.xml
app/src/main/res/drawable/ic_dimension.xml
app/src/main/res/drawable/ic_filter_effects.xml
app/src/main/res/drawable/ic_info.xml
app/src/main/res/drawable/ic_layers.xml
11 changes: 6 additions & 5 deletions app/src/main/java/com/orange/ouds/app/ui/MainScreen.kt
Original file line number Diff line number Diff line change
@@ -49,13 +49,15 @@ import com.orange.ouds.app.R
import com.orange.ouds.app.ui.navigation.appNavGraph
import com.orange.ouds.app.ui.utilities.isDarkModeEnabled
import com.orange.ouds.core.theme.OudsTheme
import com.orange.ouds.core.theme.value
import com.orange.ouds.core.utilities.OudsPreview
import com.orange.ouds.foundation.extensions.orElse
import com.orange.ouds.foundation.utilities.UiModePreviews
import com.orange.ouds.theme.OudsThemeContract
import com.orange.ouds.theme.orange.ORANGE_THEME_NAME
import com.orange.ouds.theme.orange.OrangeTheme
import com.orange.ouds.theme.orangecountry.OrangeCountryTheme
import com.orange.ouds.theme.tokens.OudsSpaceKeyToken
import com.orange.ouds.theme.whitelabel.WhiteLabelTheme

@Composable
@@ -155,12 +157,11 @@ private fun ChangeThemeDialog(themeManager: ThemeManager, dismissDialog: () -> U
.background(OudsTheme.colorScheme.surfaceVariant)
.selectableGroup()
) {
//TODO Replace hard coded values by tokens when available and use OUDS typography
Text(
text = stringResource(R.string.app_themeDialog_label),
modifier = Modifier
.padding(top = 16.dp, bottom = 8.dp)
.padding(horizontal = 16.dp),
.padding(top = OudsSpaceKeyToken.Fixed.Medium.value, bottom = OudsSpaceKeyToken.Fixed.Short.value)
.padding(horizontal = OudsSpaceKeyToken.Fixed.Medium.value),
style = MaterialTheme.typography.titleLarge
)
themeManager.availableThemes.forEach { theme ->
@@ -180,7 +181,7 @@ private fun ChangeThemeDialog(themeManager: ThemeManager, dismissDialog: () -> U
},
role = Role.RadioButton
)
.padding(horizontal = 16.dp),
.padding(horizontal = OudsSpaceKeyToken.Fixed.Medium.value),
verticalAlignment = Alignment.CenterVertically
) {
RadioButton(
@@ -190,7 +191,7 @@ private fun ChangeThemeDialog(themeManager: ThemeManager, dismissDialog: () -> U
Text(
text = theme.name,
style = MaterialTheme.typography.bodyLarge,
modifier = Modifier.padding(start = 16.dp)
modifier = Modifier.padding(start = OudsSpaceKeyToken.Fixed.Medium.value)
)
}
}
Original file line number Diff line number Diff line change
@@ -32,7 +32,7 @@ import com.orange.ouds.core.theme.value
import com.orange.ouds.core.utilities.OudsPreview
import com.orange.ouds.foundation.utilities.UiModePreviews
import com.orange.ouds.theme.tokens.OudsGridKeyToken
import com.orange.ouds.theme.tokens.OudsSpacingFixedKeyToken
import com.orange.ouds.theme.tokens.OudsSpaceKeyToken

@Composable
fun ComponentsScreen() {
@@ -49,7 +49,7 @@ fun ComponentsScreen() {

Box(
modifier = Modifier
.padding(top = OudsSpacingFixedKeyToken.Medium.value)
.padding(top = OudsSpaceKeyToken.Fixed.Medium.value)
.width(OudsGridKeyToken.Margin.value)
.height(OudsGridKeyToken.ColumnGap.value)
.background(OudsTheme.colorScheme.primary)
Original file line number Diff line number Diff line change
@@ -28,7 +28,7 @@ import com.orange.ouds.app.ui.tokens.addTokensNavGraph
* Root navigation graph of the application
*/
fun NavGraphBuilder.appNavGraph(navController: NavController) {
addTokensNavGraph()
addTokensNavGraph(navController)
addAboutNavGraph()
addBottomBarNavGraph(navController)
}
@@ -38,7 +38,7 @@ fun NavGraphBuilder.appNavGraph(navController: NavController) {
*/
private fun NavGraphBuilder.addBottomBarNavGraph(navController: NavController) {
composable(BottomBarItem.Tokens.route) { from ->
TokensScreen(onTokenClick = { id -> navController.navigateToElement(TokensNavigation.TokenCategoryDetailRoute, id, from) })
TokensScreen(onTokenCategoryClick = { id -> navController.navigateToElement(TokensNavigation.TokenCategoryDetailRoute, id, from) })
}
composable(BottomBarItem.Components.route) { _ ->
ComponentsScreen()
30 changes: 30 additions & 0 deletions app/src/main/java/com/orange/ouds/app/ui/tokens/Token.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
/*
* Software Name: OUDS Android
* SPDX-FileCopyrightText: Copyright (c) Orange SA
* SPDX-License-Identifier: MIT
*
* This software is distributed under the MIT license,
* the text of which is available at https://opensource.org/license/MIT/
* or see the "LICENSE" file for more details.
*
* Software description: Android library of reusable graphical components
*/

package com.orange.ouds.app.ui.tokens

import androidx.compose.runtime.Composable
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.unit.Dp
import com.orange.ouds.app.R

data class Token<T>(val name: String, val value: T) {
val literalValue: String
@Composable
get() = when (value) {
is Float -> stringResource(id = R.string.app_tokens_floatFormat_label, value)
is Dp -> stringResource(id = R.string.app_tokens_dpFormat_label, value.toString().replace(".0.dp", "").substringBeforeLast(".dp"))
is TextStyle -> stringResource(id = R.string.app_tokens_spFormat_label, value.fontSize.toString().replace(".0.sp", "").substringBeforeLast(".sp"))
else -> value.toString()
}
}
183 changes: 39 additions & 144 deletions app/src/main/java/com/orange/ouds/app/ui/tokens/TokenCategory.kt
Original file line number Diff line number Diff line change
@@ -14,35 +14,8 @@ package com.orange.ouds.app.ui.tokens

import androidx.annotation.DrawableRes
import androidx.annotation.StringRes
import androidx.compose.foundation.Image
import androidx.compose.foundation.background
import androidx.compose.foundation.border
import androidx.compose.foundation.isSystemInDarkTheme
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.Surface
import androidx.compose.runtime.Composable
import androidx.compose.runtime.Immutable
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
import com.orange.ouds.app.R
import com.orange.ouds.core.theme.value
import com.orange.ouds.theme.OudsBorderStyle
import com.orange.ouds.theme.dashedBorder
import com.orange.ouds.theme.dottedBorder
import com.orange.ouds.theme.tokens.OudsBorderKeyToken
import com.orange.ouds.theme.tokens.OudsElevationKeyToken
import com.orange.ouds.theme.tokens.OudsOpacityKeyToken
import com.orange.ouds.theme.tokens.OudsSpacingFixedKeyToken
import com.orange.ouds.theme.tokens.OudsTypographyKeyToken
import com.orange.ouds.theme.tokens.semantic.OudsColorKeyToken

val tokenCategories = TokenCategory::class.sealedSubclasses.mapNotNull { it.objectInstance }

@@ -51,14 +24,17 @@ sealed class TokenCategory(
@StringRes val nameRes: Int,
@DrawableRes val imageRes: Int,
@StringRes val descriptionRes: Int,
val properties: List<TokenProperty>
val properties: List<TokenProperty> = emptyList(),
val subcategories: List<TokenCategory> = emptyList(),
) {

companion object {
fun fromId(tokenId: Long) = tokenCategories.firstOrNull { token -> token.id == tokenId }
}

val id: Long = TokenCategory::class.sealedSubclasses.indexOf(this::class).toLong()
val isSubcategory: Boolean
get() = tokenCategories.any { it.subcategories.contains(this) }

data object Border : TokenCategory(
R.string.app_tokens_border_label,
@@ -67,6 +43,41 @@ sealed class TokenCategory(
listOf(TokenProperty.BorderWidth, TokenProperty.BorderRadius, TokenProperty.BorderStyle)
)

data object Dimension : TokenCategory(
R.string.app_tokens_dimension_label,
R.drawable.ic_dimension,
R.string.app_tokens_dimension_description_text,
subcategories = listOf(Space, Size)
) {
data object Space : TokenCategory(
R.string.app_tokens_dimension_space_label,
R.drawable.ic_dimension,
R.string.app_tokens_dimension_space_description_text,
listOf(
TokenProperty.SpaceScaled,
TokenProperty.SpaceFixed,
TokenProperty.SpacePaddingInline,
TokenProperty.SpacePaddingInlineWithIcon,
TokenProperty.SpacePaddingInlineWithArrow,
TokenProperty.SpacePaddingStack,
TokenProperty.SpacePaddingStackWithIcon,
TokenProperty.SpacePaddingInset,
TokenProperty.SpaceColumnGap,
TokenProperty.SpaceColumnGapWithIcon,
TokenProperty.SpaceColumnGapWithArrow,
TokenProperty.SpaceRowGap,
TokenProperty.SpaceRowGapWithIcon
),
)

data object Size : TokenCategory(
R.string.app_tokens_dimension_size_label,
R.drawable.ic_dimension,
R.string.app_tokens_dimension_size_description_text,
listOf(TokenProperty.SizeIconDecorative, TokenProperty.SizeIconWithText),
)
}

data object Elevation : TokenCategory(
R.string.app_tokens_elevation_label,
R.drawable.ic_layers,
@@ -87,120 +98,4 @@ sealed class TokenCategory(
R.string.app_tokens_typography_description_text,
listOf(TokenProperty.Typography)
)

}

sealed class TokenProperty(
@StringRes val nameRes: Int?,
val tokens: @Composable () -> List<Token<Any>>
) {
protected companion object {
val defaultIllustrationSize = 64.dp
}

data object BorderRadius : TokenProperty(
nameRes = R.string.app_tokens_border_radius_label,
tokens = { OudsBorderKeyToken.Radius.entries.map { Token(it.name, it.value) } }
) {
@Composable
fun Illustration(radius: Dp) {
Box(
modifier = Modifier
.size(defaultIllustrationSize)
.border(
width = 1.dp,
color = OudsColorKeyToken.OnSurface.value,
shape = RoundedCornerShape(radius)
) //TODO use ContentDefault token when available
.background(color = OudsColorKeyToken.Surface.value), //TODO use BgDefaultSecondary token when available
)
}
}

data object BorderStyle : TokenProperty(
nameRes = R.string.app_tokens_border_style_label,
tokens = { OudsBorderKeyToken.Style.entries.map { Token(it.name, it.value) } }
) {
@Composable
fun Illustration(style: OudsBorderStyle) {
val borderColor = OudsColorKeyToken.OnSurface.value //TODO use ContentDefault token when available
val borderWidth = 1.dp
val modifier = when (style) {
OudsBorderStyle.None -> Modifier
OudsBorderStyle.Solid -> Modifier.border(width = borderWidth, color = borderColor)
OudsBorderStyle.Dashed -> Modifier.dashedBorder(width = borderWidth, color = borderColor)
OudsBorderStyle.Dotted -> Modifier.dottedBorder(width = borderWidth, color = borderColor)
}
Box(
modifier = modifier
.size(defaultIllustrationSize)
.background(color = OudsColorKeyToken.Surface.value), //TODO use BgDefaultSecondary token when available
)
}
}

data object BorderWidth : TokenProperty(
nameRes = R.string.app_tokens_border_width_label,
tokens = { OudsBorderKeyToken.Width.entries.map { Token(it.name, it.value) } }
) {
@Composable
fun Illustration(width: Dp) {
val borderColor = OudsColorKeyToken.OnSurface.value //TODO use ContentDefault token when available
Box(
modifier = Modifier
.size(defaultIllustrationSize)
.border(width = width, color = borderColor)
.background(color = OudsColorKeyToken.Surface.value), //TODO use BgDefaultSecondary token when available
)
}
}

data object Elevation : TokenProperty(
nameRes = null,
tokens = { OudsElevationKeyToken.entries.map { Token(it.name, it.value) } }
) {
@Composable
fun Illustration(elevation: Dp) {
Surface(shadowElevation = elevation) {
Box(
modifier = Modifier
.size(defaultIllustrationSize)
.background(color = OudsColorKeyToken.Surface.value), //TODO use BgDefaultSecondary token when available
)
}
}
}

data object Opacity : TokenProperty(
nameRes = null,
tokens = { OudsOpacityKeyToken.entries.map { Token(it.name, it.value) } }
) {
@Composable
fun Illustration(opacity: Float) {
val squareColor = if (isSystemInDarkTheme()) Color.White else Color.Black
Box {
Image(painter = painterResource(id = R.drawable.il_opacity_union), contentDescription = null)
Box(
modifier = Modifier
.padding(top = OudsSpacingFixedKeyToken.Medium.value, start = OudsSpacingFixedKeyToken.Medium.value)
.size(48.dp)
.background(color = squareColor.copy(alpha = opacity))
.border(width = 1.dp, color = squareColor)
)
}
}
}

data object Typography : TokenProperty(nameRes = null, tokens = { OudsTypographyKeyToken.entries.map { Token(it.name, it.value) } })
}

data class Token<T>(val name: String, val value: T) {
val literalValue: String
@Composable
get() = when (value) {
is Dp -> stringResource(id = R.string.app_tokens_dpFormat_label, value.toString().replace(".0.dp", "").substringBeforeLast(".dp"))
is Float -> stringResource(id = R.string.app_tokens_floatFormat_label, value)
is TextStyle -> stringResource(id = R.string.app_tokens_spFormat_label, value.fontSize.toString().replace(".0.sp", "").substringBeforeLast(".sp"))
else -> value.toString()
}
}
Loading

0 comments on commit a8bb875

Please sign in to comment.