[Compound] Integrate compound tokens (#586)

* Added tokens.

* Apply color to MaterialTheme, also add typography.

* Map colors to the right ones in the themes.

* Create and improve previews of some components

* More preview improvements

* Add `tertiary` and `onTertiary` colors, remove some unused ones.

* Fix usage of deleted color token

* Fix bug in Switch previews

* Create a separate `:libraries:theme` module to keep everything related to colors, typography and Compound in general.

* Fix `DatePickerPreview`

* Add missing Compound generated files by fixing their package name

* Move `ElementTheme` to the `:libraries:theme` module, make some variables internal.

---------

Co-authored-by: ElementBot <benoitm+elementbot@element.io>
This commit is contained in:
Jorge Martin Espinosa 2023-06-27 18:15:40 +02:00 committed by GitHub
parent 8c7183807c
commit 02dc447624
691 changed files with 3460 additions and 1460 deletions

View file

@ -1,87 +0,0 @@
/*
* Copyright (c) 2023 New Vector Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.element.android.libraries.designsystem
import androidx.compose.ui.graphics.Color
import com.airbnb.android.showkase.annotation.ShowkaseColor
@ShowkaseColor(name = "LightGrey", group = "Material Design")
val LightGrey = Color(0x993C3C43)
@ShowkaseColor(name = "DarkGrey", group = "Material Design")
val DarkGrey = Color(0x99EBEBF5)
val AvatarGradientStart = Color(0xFF4CA1AF)
val AvatarGradientEnd = Color(0xFFC4E0E5)
val SystemGreyLight = Color(0xFF8E8E93)
val SystemGreyDark = Color(0xFF8E8E93)
val SystemGrey2Light = Color(0xFFAEAEB2)
val SystemGrey2Dark = Color(0xFF636366)
val SystemGrey3Light = Color(0xFFC7C7CC)
val SystemGrey3Dark = Color(0xFF48484A)
val SystemGrey4Light = Color(0xFFD1D1D6)
val SystemGrey4Dark = Color(0xFF3A3A3C)
val SystemGrey5Light = Color(0xFFE5E5EA)
val SystemGrey5Dark = Color(0xFF2C2C2E)
val SystemGrey6Light = Color(0xFFF2F2F7)
val SystemGrey6Dark = Color(0xFF1C1C1E)
// For light themes
val Gray_25 = Color(0xFFF4F6FA)
val Gray_50 = Color(0xFFE3E8F0)
val Gray_100 = Color(0xFFC1C6CD)
val Gray_150 = Color(0xFF8D97A5)
val Gray_200 = Color(0xFF737D8C)
val Black_900 = Color(0xFF17191C)
// For dark themes
val Gray_250 = Color(0xFFA9B2BC)
val Gray_300 = Color(0xFF8E99A4)
val Gray_400 = Color(0xFF6F7882)
val Gray_450 = Color(0xFF394049)
val Black_800 = Color(0xFF15191E)
val Black_950 = Color(0xFF21262C)
val Azure = Color(0xFF368BD6)
val Kiwi = Color(0xFF74D12C)
val Grape = Color(0xFFAC3BA8)
val Verde = Color(0xFF03B381)
val Polly = Color(0xFFE64F7A)
val Melon = Color(0xFFFF812D)
val ElementGreen = Color(0xFF0DBD8B)
val ElementOrange = Color(0xFFD9B072)
val Vermilion = Color(0xFFFF5B55)
val LinkColor = Color(0xFF0086E6)
// Compound colors
val TextColorCriticalLight = Color(0xFFD51928)
val TextColorCriticalDark = Color(0xfffd3e3c)
val Compound_Gray_300_Light = Color(0xFFF0F2F5)
val Compound_Gray_300_Dark = Color(0xFF1D1F24)
val Compound_Gray_400_Light = Color(0xFFE1E6EC)
val Compound_Gray_400_Dark = Color(0xFF26282D)
val Compound_Gray_800_Light = Color(0xFF818A95)
val Compound_Gray_800_Dark = Color(0xFF656C76)
val Compound_Gray_1400_Light = Color(0xFF1B1D22)
val Compound_Gray_1400_Dark = Color(0xFFEBEEF2)

View file

@ -35,7 +35,7 @@ import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
import io.element.android.libraries.designsystem.preview.ElementPreviewDark
import io.element.android.libraries.designsystem.preview.ElementPreviewLight
import io.element.android.libraries.designsystem.theme.LocalColors
import io.element.android.libraries.theme.LocalColors
import io.element.android.libraries.designsystem.theme.components.Icon
/**

View file

@ -32,12 +32,12 @@ import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.tooling.preview.PreviewParameter
import androidx.compose.ui.unit.sp
import coil.compose.AsyncImage
import io.element.android.libraries.designsystem.AvatarGradientEnd
import io.element.android.libraries.designsystem.AvatarGradientStart
import io.element.android.libraries.designsystem.preview.ElementThemedPreview
import io.element.android.libraries.designsystem.preview.PreviewGroup
import io.element.android.libraries.designsystem.preview.debugPlaceholderAvatar
import io.element.android.libraries.designsystem.theme.components.Text
import io.element.android.libraries.theme.AvatarGradientEnd
import io.element.android.libraries.theme.AvatarGradientStart
import timber.log.Timber
@Composable

View file

@ -28,7 +28,7 @@ import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.unit.dp
import io.element.android.libraries.designsystem.theme.ElementTheme
import io.element.android.libraries.theme.ElementTheme
import io.element.android.libraries.designsystem.theme.components.Surface
@Composable

View file

@ -21,10 +21,12 @@ object PreviewGroup {
const val Avatars = "Avatars"
const val BottomSheets = "Bottom Sheets"
const val Buttons = "Buttons"
const val DateTimePickers = "DateTime pickers"
const val Dialogs = "Dialogs"
const val Dividers = "Dividers"
const val FABs = "Floating Action Buttons"
const val Icons = "Icons"
const val Menus = "Menus"
const val Preferences = "Preferences"
const val Progress = "Progress Indicators"
const val Search = "Search views"

View file

@ -31,7 +31,7 @@ import androidx.compose.ui.text.buildAnnotatedString
import androidx.compose.ui.text.font.FontStyle
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextDecoration
import io.element.android.libraries.designsystem.LinkColor
import io.element.android.libraries.theme.LinkColor
fun String.toAnnotatedString(): AnnotatedString = buildAnnotatedString {
append(this@toAnnotatedString)

View file

@ -20,11 +20,13 @@ import androidx.compose.material3.MaterialTheme
import androidx.compose.runtime.Composable
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.tooling.preview.Preview
import io.element.android.libraries.designsystem.SystemGrey4Dark
import io.element.android.libraries.designsystem.SystemGrey6Light
import io.element.android.libraries.designsystem.preview.ElementPreviewDark
import io.element.android.libraries.designsystem.preview.ElementPreviewLight
import io.element.android.libraries.designsystem.theme.previews.ColorListPreview
import io.element.android.libraries.theme.ElementColors
import io.element.android.libraries.theme.ElementTheme
import io.element.android.libraries.theme.SystemGrey4Dark
import io.element.android.libraries.theme.SystemGrey6Light
import io.element.android.libraries.theme.previews.ColorListPreview
import kotlinx.collections.immutable.persistentMapOf
/**

View file

@ -1,93 +0,0 @@
/*
* Copyright (c) 2023 New Vector Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.element.android.libraries.designsystem.theme
import androidx.compose.material3.darkColorScheme
import androidx.compose.runtime.Composable
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.tooling.preview.Preview
import io.element.android.libraries.designsystem.Azure
import io.element.android.libraries.designsystem.Black_800
import io.element.android.libraries.designsystem.Black_950
import io.element.android.libraries.designsystem.Compound_Gray_300_Dark
import io.element.android.libraries.designsystem.DarkGrey
import io.element.android.libraries.designsystem.Compound_Gray_1400_Dark
import io.element.android.libraries.designsystem.Gray_300
import io.element.android.libraries.designsystem.Gray_400
import io.element.android.libraries.designsystem.Compound_Gray_400_Dark
import io.element.android.libraries.designsystem.Compound_Gray_800_Dark
import io.element.android.libraries.designsystem.Gray_450
import io.element.android.libraries.designsystem.SystemGrey5Dark
import io.element.android.libraries.designsystem.SystemGrey6Dark
import io.element.android.libraries.designsystem.TextColorCriticalDark
import io.element.android.libraries.designsystem.theme.previews.ColorsSchemePreview
fun elementColorsDark() = ElementColors(
messageFromMeBackground = SystemGrey5Dark,
messageFromOtherBackground = SystemGrey6Dark,
messageHighlightedBackground = Azure,
quaternary = Gray_400,
quinary = Gray_450,
gray300 = Compound_Gray_300_Dark,
gray400 = Compound_Gray_400_Dark,
gray1400 = Compound_Gray_1400_Dark,
textActionCritical = TextColorCriticalDark,
accentColor = Color(0xFF0DBD8B),
placeholder = Compound_Gray_800_Dark,
isLight = false,
)
// TODO Lots of colors are missing
val materialColorSchemeDark = darkColorScheme(
primary = Color.White,
onPrimary = Color.Black,
// TODO primaryContainer = ColorDarkTokens.PrimaryContainer,
// TODO onPrimaryContainer = ColorDarkTokens.OnPrimaryContainer,
// TODO inversePrimary = ColorDarkTokens.InversePrimary,
secondary = DarkGrey,
// TODO onSecondary = ColorDarkTokens.OnSecondary,
// TODO secondaryContainer = ColorDarkTokens.SecondaryContainer,
// TODO onSecondaryContainer = ColorDarkTokens.OnSecondaryContainer,
tertiary = Gray_300,
// TODO onTertiary = ColorDarkTokens.OnTertiary,
// TODO tertiaryContainer = ColorDarkTokens.TertiaryContainer,
// TODO onTertiaryContainer = ColorDarkTokens.OnTertiaryContainer,
background = Black_800,
onBackground = Color.White,
surface = Black_800,
onSurface = Color.White,
surfaceVariant = Black_950,
onSurfaceVariant = Gray_300,
// TODO surfaceTint = primary,
// TODO inverseSurface = ColorDarkTokens.InverseSurface,
// TODO inverseOnSurface = ColorDarkTokens.InverseOnSurface,
// TODO error = ColorDarkTokens.Error,
// TODO onError = ColorDarkTokens.OnError,
// TODO errorContainer = ColorDarkTokens.ErrorContainer,
// TODO onErrorContainer = ColorDarkTokens.OnErrorContainer,
// TODO outline = ColorDarkTokens.Outline,
outlineVariant = Gray_450,
// TODO scrim = ColorDarkTokens.Scrim,
)
@Preview
@Composable
fun ColorsSchemePreviewDark() = ColorsSchemePreview(
Color.White,
Color.Black,
materialColorSchemeDark,
)

View file

@ -1,93 +0,0 @@
/*
* Copyright (c) 2023 New Vector Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.element.android.libraries.designsystem.theme
import androidx.compose.material3.lightColorScheme
import androidx.compose.runtime.Composable
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.tooling.preview.Preview
import io.element.android.libraries.designsystem.Azure
import io.element.android.libraries.designsystem.Black_900
import io.element.android.libraries.designsystem.Compound_Gray_300_Light
import io.element.android.libraries.designsystem.Compound_Gray_400_Light
import io.element.android.libraries.designsystem.Compound_Gray_800_Light
import io.element.android.libraries.designsystem.Gray_100
import io.element.android.libraries.designsystem.Compound_Gray_1400_Light
import io.element.android.libraries.designsystem.Gray_150
import io.element.android.libraries.designsystem.Gray_200
import io.element.android.libraries.designsystem.Gray_25
import io.element.android.libraries.designsystem.Gray_50
import io.element.android.libraries.designsystem.SystemGrey5Light
import io.element.android.libraries.designsystem.SystemGrey6Light
import io.element.android.libraries.designsystem.TextColorCriticalLight
import io.element.android.libraries.designsystem.theme.previews.ColorsSchemePreview
fun elementColorsLight() = ElementColors(
messageFromMeBackground = SystemGrey5Light,
messageFromOtherBackground = SystemGrey6Light,
messageHighlightedBackground = Azure,
quaternary = Gray_100,
quinary = Gray_50,
gray300 = Compound_Gray_300_Light,
gray400 = Compound_Gray_400_Light,
gray1400 = Compound_Gray_1400_Light,
textActionCritical = TextColorCriticalLight,
accentColor = Color(0xFF0DBD8B),
placeholder = Compound_Gray_800_Light,
isLight = true,
)
// TODO Lots of colors are missing
val materialColorSchemeLight = lightColorScheme(
primary = Black_900,
onPrimary = Color.White,
// TODO primaryContainer = ColorLightTokens.PrimaryContainer,
// TODO onPrimaryContainer = ColorLightTokens.OnPrimaryContainer,
// TODO inversePrimary = ColorLightTokens.InversePrimary,
secondary = Gray_200,
// TODO onSecondary = ColorLightTokens.OnSecondary,
// TODO secondaryContainer = ColorLightTokens.SecondaryContainer,
// TODO onSecondaryContainer = ColorLightTokens.OnSecondaryContainer,
tertiary = Gray_150,
// TODO onTertiary = ColorLightTokens.OnTertiary,
// TODO tertiaryContainer = ColorLightTokens.TertiaryContainer,
// TODO onTertiaryContainer = ColorLightTokens.OnTertiaryContainer,
background = Color.White,
onBackground = Color.Black,
surface = Color.White,
onSurface = Color.Black,
surfaceVariant = Gray_25,
onSurfaceVariant = Gray_200,
// TODO surfaceTint = primary,
// TODO inverseSurface = ColorLightTokens.InverseSurface,
// TODO inverseOnSurface = ColorLightTokens.InverseOnSurface,
// TODO error = ColorLightTokens.Error,
// TODO onError = ColorLightTokens.OnError,
// TODO errorContainer = ColorLightTokens.ErrorContainer,
// TODO onErrorContainer = ColorLightTokens.OnErrorContainer,
// TODO outline = ColorLightTokens.Outline,
outlineVariant = Gray_50,
// TODO scrim = ColorLightTokens.Scrim,
)
@Preview
@Composable
fun ColorsSchemePreviewLight() = ColorsSchemePreview(
Color.Black,
Color.White,
materialColorSchemeLight,
)

View file

@ -1,116 +0,0 @@
/*
* Copyright (c) 2023 New Vector Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.element.android.libraries.designsystem.theme
import androidx.compose.runtime.Stable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.setValue
import androidx.compose.ui.graphics.Color
@Stable
class ElementColors(
messageFromMeBackground: Color,
messageFromOtherBackground: Color,
messageHighlightedBackground: Color,
quaternary: Color,
quinary: Color,
gray300: Color,
gray400: Color,
gray1400: Color,
textActionCritical: Color,
accentColor: Color,
placeholder: Color,
isLight: Boolean
) {
var messageFromMeBackground by mutableStateOf(messageFromMeBackground)
private set
var messageFromOtherBackground by mutableStateOf(messageFromOtherBackground)
private set
var messageHighlightedBackground by mutableStateOf(messageHighlightedBackground)
private set
var quaternary by mutableStateOf(quaternary)
private set
var quinary by mutableStateOf(quinary)
private set
var gray300 by mutableStateOf(gray400)
private set
var gray400 by mutableStateOf(gray400)
private set
var gray1400 by mutableStateOf(gray1400)
private set
var textActionCritical by mutableStateOf(textActionCritical)
private set
var accentColor by mutableStateOf(accentColor)
private set
var placeholder by mutableStateOf(placeholder)
private set
var isLight by mutableStateOf(isLight)
private set
fun copy(
messageFromMeBackground: Color = this.messageFromMeBackground,
messageFromOtherBackground: Color = this.messageFromOtherBackground,
messageHighlightedBackground: Color = this.messageHighlightedBackground,
quaternary: Color = this.quaternary,
quinary: Color = this.quinary,
gray300: Color = this.gray300,
gray400: Color = this.gray400,
gray1400: Color = this.gray1400,
textActionCritical: Color = this.textActionCritical,
accentColor: Color = this.accentColor,
placeholder: Color = this.placeholder,
isLight: Boolean = this.isLight,
) = ElementColors(
messageFromMeBackground = messageFromMeBackground,
messageFromOtherBackground = messageFromOtherBackground,
messageHighlightedBackground = messageHighlightedBackground,
quaternary = quaternary,
quinary = quinary,
gray300 = gray300,
gray400 = gray400,
gray1400 = gray1400,
textActionCritical = textActionCritical,
accentColor = accentColor,
placeholder = placeholder,
isLight = isLight,
)
fun updateColorsFrom(other: ElementColors) {
messageFromMeBackground = other.messageFromMeBackground
messageFromOtherBackground = other.messageFromOtherBackground
messageHighlightedBackground = other.messageHighlightedBackground
quaternary = other.quaternary
quinary = other.quinary
gray300 = other.gray300
gray400 = other.gray400
gray1400 = other.gray1400
textActionCritical = other.textActionCritical
accentColor = other.accentColor
placeholder = other.placeholder
isLight = other.isLight
}
}

View file

@ -1,116 +0,0 @@
/*
* Copyright (c) 2023 New Vector Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.element.android.libraries.designsystem.theme
import android.os.Build
import androidx.compose.foundation.isSystemInDarkTheme
import androidx.compose.material3.ColorScheme
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.dynamicDarkColorScheme
import androidx.compose.material3.dynamicLightColorScheme
import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.runtime.DisposableEffect
import androidx.compose.runtime.ReadOnlyComposable
import androidx.compose.runtime.SideEffect
import androidx.compose.runtime.remember
import androidx.compose.runtime.staticCompositionLocalOf
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalContext
import com.google.accompanist.systemuicontroller.SystemUiController
import com.google.accompanist.systemuicontroller.rememberSystemUiController
/**
* Inspired from https://medium.com/@lucasyujideveloper/54cbcbde1ace
*/
object ElementTheme {
val colors: ElementColors
@Composable
@ReadOnlyComposable
get() = LocalColors.current
}
/* Global variables (application level) */
val LocalColors = staticCompositionLocalOf { elementColorsLight() }
@Composable
fun ElementTheme(
darkTheme: Boolean = isSystemInDarkTheme(),
dynamicColor: Boolean = false, /* true to enable MaterialYou */
colors: ElementColors = if (darkTheme) elementColorsDark() else elementColorsLight(),
materialLightColors: ColorScheme = materialColorSchemeLight,
materialDarkColors: ColorScheme = materialColorSchemeDark,
content: @Composable () -> Unit,
) {
val systemUiController = rememberSystemUiController()
val currentColor = remember(darkTheme) {
colors.copy()
}.apply { updateColorsFrom(colors) }
val colorScheme = when {
dynamicColor && Build.VERSION.SDK_INT >= Build.VERSION_CODES.S -> {
val context = LocalContext.current
if (darkTheme) dynamicDarkColorScheme(context) else dynamicLightColorScheme(context)
}
darkTheme -> materialDarkColors
else -> materialLightColors
}
SideEffect {
systemUiController.applyTheme(colorScheme = colorScheme, darkTheme = darkTheme)
}
CompositionLocalProvider(
LocalColors provides currentColor,
) {
MaterialTheme(
colorScheme = colorScheme,
// TODO typography =
content = content
)
}
}
/**
* Can be used to force a composable in dark theme.
* It will automatically change the system ui colors back to normal when leaving the composition.
*/
@Composable
fun ForcedDarkElementTheme(
content: @Composable () -> Unit,
) {
val systemUiController = rememberSystemUiController()
val colorScheme = MaterialTheme.colorScheme
val wasDarkTheme = !ElementTheme.colors.isLight
DisposableEffect(Unit) {
onDispose {
systemUiController.applyTheme(colorScheme, wasDarkTheme)
}
}
ElementTheme(darkTheme = true, content = content)
}
private fun SystemUiController.applyTheme(
colorScheme: ColorScheme,
darkTheme: Boolean,
) {
val useDarkIcons = !darkTheme
setStatusBarColor(
color = colorScheme.background
)
setSystemBarsColor(
color = Color.Transparent,
darkIcons = useDarkIcons
)
}

View file

@ -17,6 +17,7 @@
package io.element.android.libraries.designsystem.theme.components
import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.foundation.layout.Row
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Close
import androidx.compose.material3.IconButtonDefaults
@ -52,7 +53,12 @@ internal fun IconButtonPreview() =
@Composable
private fun ContentToPreview() {
IconButton(onClick = {}) {
Icon(imageVector = Icons.Filled.Close, contentDescription = "")
Row {
IconButton(onClick = {}) {
Icon(imageVector = Icons.Filled.Close, contentDescription = "")
}
IconButton(enabled = false, onClick = {}) {
Icon(imageVector = Icons.Filled.Close, contentDescription = "")
}
}
}

View file

@ -102,7 +102,6 @@ private fun ContentToPreview() {
sheetState = SheetState(
skipPartiallyExpanded = true,
initialValue = SheetValue.Expanded,
skipHiddenState = true,
),
) {
Text(

View file

@ -18,6 +18,7 @@ package io.element.android.libraries.designsystem.theme.components
import androidx.compose.foundation.BorderStroke
import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.RowScope
@ -79,7 +80,7 @@ internal fun OutlinedButtonsPreview() = ElementThemedPreview { ContentToPreview(
@Composable
private fun ContentToPreview() {
Column {
Column(verticalArrangement = Arrangement.spacedBy(8.dp)) {
OutlinedButton(onClick = {}, enabled = true) {
Text(text = "Click me! - Enabled")
}

View file

@ -55,5 +55,7 @@ private fun ContentToPreview() {
Column {
RadioButton(selected = false, onClick = {})
RadioButton(selected = true, onClick = {})
RadioButton(selected = false, enabled = false, onClick = {})
RadioButton(selected = true, enabled = false, onClick = {})
}
}

View file

@ -46,7 +46,7 @@ import androidx.compose.ui.unit.dp
import io.element.android.libraries.designsystem.components.button.BackButton
import io.element.android.libraries.designsystem.preview.ElementThemedPreview
import io.element.android.libraries.designsystem.preview.PreviewGroup
import io.element.android.libraries.designsystem.theme.LocalColors
import io.element.android.libraries.theme.LocalColors
import io.element.android.libraries.ui.strings.CommonStrings
@OptIn(ExperimentalMaterial3Api::class)

View file

@ -21,7 +21,10 @@ import androidx.compose.foundation.layout.Column
import androidx.compose.material3.SliderColors
import androidx.compose.material3.SliderDefaults
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.tooling.preview.Preview
import io.element.android.libraries.designsystem.preview.ElementThemedPreview
@ -59,8 +62,10 @@ internal fun SlidersPreview() = ElementThemedPreview { ContentToPreview() }
@Composable
private fun ContentToPreview() {
var value by remember { mutableStateOf(0.33f) }
Column {
Slider(onValueChange = {}, value = 0.33f, enabled = true)
Slider(onValueChange = {}, value = 0.33f, enabled = false)
Slider(onValueChange = { value = it }, value = value, enabled = true)
Slider(steps = 10, onValueChange = { value = it }, value = value, enabled = true)
Slider(onValueChange = { value = it }, value = value, enabled = false)
}
}

View file

@ -47,7 +47,7 @@ import androidx.compose.ui.unit.dp
import io.element.android.libraries.designsystem.preview.ElementPreviewDark
import io.element.android.libraries.designsystem.preview.ElementPreviewLight
import io.element.android.libraries.designsystem.preview.PreviewGroup
import io.element.android.libraries.designsystem.utils.toHrf
import io.element.android.libraries.theme.utils.toHrf
import kotlinx.collections.immutable.ImmutableMap
import kotlinx.collections.immutable.persistentMapOf

View file

@ -0,0 +1,62 @@
/*
* Copyright (c) 2023 New Vector Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.element.android.libraries.designsystem.theme.components.previews
import androidx.compose.material3.AlertDialogDefaults
import androidx.compose.material3.DatePicker
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.rememberDatePickerState
import androidx.compose.runtime.Composable
import androidx.compose.ui.tooling.preview.Preview
import io.element.android.libraries.designsystem.components.dialogs.AlertDialogContent
import io.element.android.libraries.designsystem.preview.ElementPreviewDark
import io.element.android.libraries.designsystem.preview.ElementPreviewLight
import io.element.android.libraries.designsystem.preview.PreviewGroup
@Preview(group = PreviewGroup.DateTimePickers)
@Composable
internal fun DatePickerPreviewLight() {
ElementPreviewLight { ContentToPreview() }
}
@Preview(group = PreviewGroup.DateTimePickers)
@Composable
internal fun DatePickerPreviewDark() {
ElementPreviewDark { ContentToPreview() }
}
@OptIn(ExperimentalMaterial3Api::class)
@Composable
private fun ContentToPreview() {
val state = rememberDatePickerState(
initialSelectedDateMillis = 1672578000000L,
)
AlertDialogContent(
buttons = { /*TODO*/ },
icon = { /*TODO*/ },
title = { /*TODO*/ },
text = { DatePicker(state = state, showModeToggle = true) },
shape = AlertDialogDefaults.shape,
containerColor = AlertDialogDefaults.containerColor,
tonalElevation = AlertDialogDefaults.TonalElevation,
buttonContentColor = MaterialTheme.colorScheme.primary,
iconContentColor = AlertDialogDefaults.iconContentColor,
titleContentColor = AlertDialogDefaults.titleContentColor,
textContentColor = AlertDialogDefaults.textContentColor,
)
}

View file

@ -0,0 +1,70 @@
/*
* Copyright (c) 2023 New Vector Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.element.android.libraries.designsystem.theme.components.previews
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.ArrowRight
import androidx.compose.material.icons.filled.Favorite
import androidx.compose.material3.DropdownMenu
import androidx.compose.material3.DropdownMenuItem
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.tooling.preview.Preview
import io.element.android.libraries.designsystem.preview.ElementThemedPreview
import io.element.android.libraries.designsystem.preview.PreviewGroup
import io.element.android.libraries.designsystem.theme.components.Button
import io.element.android.libraries.designsystem.theme.components.Icon
import io.element.android.libraries.designsystem.theme.components.Text
@Preview(group = PreviewGroup.Menus)
@Composable
internal fun MenuPreview() {
ElementThemedPreview {
var isExpanded by remember { mutableStateOf(false) }
Button(onClick = { isExpanded = !isExpanded }) {
Text("Toggle")
}
DropdownMenu(expanded = isExpanded, onDismissRequest = { isExpanded = false }) {
for (i in 0..5) {
val leadingIcon: @Composable (() -> Unit)? = if (i in 2..3) {
@Composable {
Icon(Icons.Filled.Favorite, contentDescription = "Favorite")
}
} else {
null
}
val trailingIcon: @Composable (() -> Unit)? = if (i in 3..4) {
@Composable {
Icon(Icons.Filled.ArrowRight, contentDescription = "Favorite")
}
} else {
null
}
DropdownMenuItem(
text = { Text(text = "Item $i") },
onClick = { isExpanded = false },
leadingIcon = leadingIcon,
trailingIcon = trailingIcon,
)
}
}
}
}

View file

@ -0,0 +1,51 @@
/*
* Copyright (c) 2023 New Vector Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.element.android.libraries.designsystem.theme.components.previews
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Row
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.outlined.Check
import androidx.compose.material3.Switch
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.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import io.element.android.libraries.designsystem.preview.ElementThemedPreview
import io.element.android.libraries.designsystem.preview.PreviewGroup
import io.element.android.libraries.designsystem.theme.components.Icon
@Preview(group = PreviewGroup.Toggles)
@Composable
internal fun SwitchPreview() {
ElementThemedPreview {
Row(horizontalArrangement = Arrangement.spacedBy(8.dp)) {
var checked by remember { mutableStateOf(false) }
Switch(checked = checked, onCheckedChange = { checked = !checked })
Switch(checked = checked, onCheckedChange = { checked = !checked }, thumbContent = {
Icon(imageVector = Icons.Outlined.Check, contentDescription = null)
})
Switch(checked = checked, enabled = false, onCheckedChange = { checked = !checked })
Switch(checked = checked, enabled = false, onCheckedChange = { checked = !checked }, thumbContent = {
Icon(imageVector = Icons.Outlined.Check, contentDescription = null)
})
}
}
}

View file

@ -0,0 +1,98 @@
/*
* Copyright (c) 2023 New Vector Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.element.android.libraries.designsystem.theme.components.previews
import androidx.compose.material3.AlertDialogDefaults
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.TimePicker
import androidx.compose.material3.TimePickerLayoutType
import androidx.compose.material3.rememberTimePickerState
import androidx.compose.runtime.Composable
import androidx.compose.ui.tooling.preview.Preview
import io.element.android.libraries.designsystem.components.dialogs.AlertDialogContent
import io.element.android.libraries.designsystem.preview.ElementPreviewDark
import io.element.android.libraries.designsystem.preview.ElementPreviewLight
import io.element.android.libraries.designsystem.preview.ElementThemedPreview
import io.element.android.libraries.designsystem.preview.PreviewGroup
@OptIn(ExperimentalMaterial3Api::class)
@Preview(widthDp = 600, group = PreviewGroup.DateTimePickers)
@Composable
internal fun TimePickerHorizontalPreview() {
ElementThemedPreview {
AlertDialogContent(
buttons = { /*TODO*/ },
icon = { /*TODO*/ },
title = { /*TODO*/ },
text = { TimePicker(state = rememberTimePickerState(), layoutType = TimePickerLayoutType.Horizontal) },
shape = AlertDialogDefaults.shape,
containerColor = AlertDialogDefaults.containerColor,
tonalElevation = AlertDialogDefaults.TonalElevation,
buttonContentColor = MaterialTheme.colorScheme.primary,
iconContentColor = AlertDialogDefaults.iconContentColor,
titleContentColor = AlertDialogDefaults.titleContentColor,
textContentColor = AlertDialogDefaults.textContentColor,
)
}
}
@OptIn(ExperimentalMaterial3Api::class)
@Preview(group = PreviewGroup.DateTimePickers)
@Composable
internal fun TimePickerVerticalPreviewLight() {
ElementPreviewLight {
AlertDialogContent(
buttons = { /*TODO*/ },
icon = { /*TODO*/ },
title = { /*TODO*/ },
text = { TimePicker(state = rememberTimePickerState(), layoutType = TimePickerLayoutType.Vertical) },
shape = AlertDialogDefaults.shape,
containerColor = AlertDialogDefaults.containerColor,
tonalElevation = AlertDialogDefaults.TonalElevation,
buttonContentColor = MaterialTheme.colorScheme.primary,
iconContentColor = AlertDialogDefaults.iconContentColor,
titleContentColor = AlertDialogDefaults.titleContentColor,
textContentColor = AlertDialogDefaults.textContentColor,
)
}
}
@OptIn(ExperimentalMaterial3Api::class)
@Preview(group = PreviewGroup.DateTimePickers)
@Composable
internal fun TimePickerVerticalPreviewDark() {
val pickerState = rememberTimePickerState(
initialHour = 12,
initialMinute = 0,
)
ElementPreviewDark {
AlertDialogContent(
buttons = { /*TODO*/ },
icon = { /*TODO*/ },
title = { /*TODO*/ },
text = { TimePicker(state = pickerState, layoutType = TimePickerLayoutType.Vertical) },
shape = AlertDialogDefaults.shape,
containerColor = AlertDialogDefaults.containerColor,
tonalElevation = AlertDialogDefaults.TonalElevation,
buttonContentColor = MaterialTheme.colorScheme.primary,
iconContentColor = AlertDialogDefaults.iconContentColor,
titleContentColor = AlertDialogDefaults.titleContentColor,
textContentColor = AlertDialogDefaults.textContentColor,
)
}
}

View file

@ -1,48 +0,0 @@
/*
* Copyright (c) 2023 New Vector Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.element.android.libraries.designsystem.theme.previews
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.unit.dp
import kotlinx.collections.immutable.ImmutableMap
@Composable
internal fun ColorListPreview(
backgroundColor: Color,
foregroundColor: Color,
colors: ImmutableMap<String, Color>,
modifier: Modifier = Modifier,
) {
Column(
modifier = modifier
.background(color = backgroundColor)
.fillMaxWidth()
) {
colors.keys.forEach { name ->
val color = colors[name]!!
ColorPreview(backgroundColor = backgroundColor, foregroundColor = foregroundColor, name = name, color = color)
}
Spacer(modifier = Modifier.height(2.dp))
}
}

View file

@ -1,64 +0,0 @@
/*
* Copyright (c) 2023 New Vector Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.element.android.libraries.designsystem.theme.previews
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Brush
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import io.element.android.libraries.designsystem.theme.components.Text
import io.element.android.libraries.designsystem.utils.toHrf
@Composable
internal fun ColorPreview(
backgroundColor: Color,
foregroundColor: Color,
name: String, color: Color,
modifier: Modifier = Modifier,
) {
Column(modifier = modifier.fillMaxWidth()) {
Text(text = name + " " + color.toHrf(), fontSize = 6.sp, color = foregroundColor)
val backgroundBrush = Brush.linearGradient(
listOf(
backgroundColor,
foregroundColor,
)
)
Row(
modifier = Modifier.background(backgroundBrush)
) {
repeat(2) {
Box(
modifier = Modifier
.padding(1.dp)
.background(color = color)
.height(10.dp)
.weight(1f)
)
}
}
}
}

View file

@ -1,69 +0,0 @@
/*
* Copyright (c) 2023 New Vector Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.element.android.libraries.designsystem.theme.previews
import androidx.compose.material3.ColorScheme
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import kotlinx.collections.immutable.persistentMapOf
@Composable
internal fun ColorsSchemePreview(
backgroundColor: Color,
foregroundColor: Color,
colorScheme: ColorScheme,
modifier: Modifier = Modifier,
) {
val colors = persistentMapOf(
"primary" to colorScheme.primary,
"onPrimary" to colorScheme.onPrimary,
"primaryContainer" to colorScheme.primaryContainer,
"onPrimaryContainer" to colorScheme.onPrimaryContainer,
"inversePrimary" to colorScheme.inversePrimary,
"secondary" to colorScheme.secondary,
"onSecondary" to colorScheme.onSecondary,
"secondaryContainer" to colorScheme.secondaryContainer,
"onSecondaryContainer" to colorScheme.onSecondaryContainer,
"tertiary" to colorScheme.tertiary,
"onTertiary" to colorScheme.onTertiary,
"tertiaryContainer" to colorScheme.tertiaryContainer,
"onTertiaryContainer" to colorScheme.onTertiaryContainer,
"background" to colorScheme.background,
"onBackground" to colorScheme.onBackground,
"surface" to colorScheme.surface,
"onSurface" to colorScheme.onSurface,
"surfaceVariant" to colorScheme.surfaceVariant,
"onSurfaceVariant" to colorScheme.onSurfaceVariant,
"surfaceTint" to colorScheme.surfaceTint,
"inverseSurface" to colorScheme.inverseSurface,
"inverseOnSurface" to colorScheme.inverseOnSurface,
"error" to colorScheme.error,
"onError" to colorScheme.onError,
"errorContainer" to colorScheme.errorContainer,
"onErrorContainer" to colorScheme.onErrorContainer,
"outline" to colorScheme.outline,
"outlineVariant" to colorScheme.outlineVariant,
"scrim" to colorScheme.scrim,
)
ColorListPreview(
backgroundColor = backgroundColor,
foregroundColor = foregroundColor,
colors = colors,
modifier = modifier,
)
}

View file

@ -1,26 +0,0 @@
/*
* Copyright (c) 2023 New Vector Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.element.android.libraries.designsystem.utils
import androidx.compose.ui.graphics.Color
/**
* Convert color to Human Readable Format.
*/
internal fun Color.toHrf(): String {
return "0x" + value.toString(16).take(8).uppercase()
}