Introduce "Black" theme and refactor theme handling

* Add `Theme.Black` to the `Theme` enum and update `isDark()` to include it.
* Refactor `ElementTheme` to accept a `Theme` object instead of a `darkTheme` boolean, allowing for more specific color mapping (e.g., setting `bgCanvasDefault` to `Color.Black` for the Black theme).
* Update `AdvancedSettingsPresenter` and `AdvancedSettingsState` to include "Black" as a user-selectable theme option.
* Adjust `ElementThemeApp` and `MaterialTextPreview` to handle the expanded theme selection.
* Add `ElementPreviewBlack` and update existing preview components to support the new theme.
* Update Konsist tests to ensure `@PreviewsDayNight` annotated functions don't have "BlackPreview" suffix.
This commit is contained in:
Timur Gilfanov 2026-03-23 15:26:16 +04:00
parent 3eae82890c
commit bed8a554bf
23 changed files with 121 additions and 36 deletions

View file

@ -26,6 +26,7 @@ import androidx.compose.ui.semantics.Role
import androidx.compose.ui.tooling.preview.PreviewParameter import androidx.compose.ui.tooling.preview.PreviewParameter
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import io.element.android.compound.theme.ElementTheme import io.element.android.compound.theme.ElementTheme
import io.element.android.compound.theme.Theme
import io.element.android.features.messages.impl.timeline.components.event.TimelineItemAspectRatioBox import io.element.android.features.messages.impl.timeline.components.event.TimelineItemAspectRatioBox
import io.element.android.libraries.designsystem.components.blurhash.blurHashBackground import io.element.android.libraries.designsystem.components.blurhash.blurHashBackground
import io.element.android.libraries.designsystem.preview.ElementPreview import io.element.android.libraries.designsystem.preview.ElementPreview
@ -49,7 +50,7 @@ fun ProtectedView(
.background(Color(0x99000000)), .background(Color(0x99000000)),
contentAlignment = Alignment.Center, contentAlignment = Alignment.Center,
) { ) {
ElementTheme(darkTheme = false, applySystemBarsUpdate = false) { ElementTheme(theme = Theme.Light, applySystemBarsUpdate = false) {
// Not using a button to be able to have correct size // Not using a button to be able to have correct size
Text( Text(
modifier = Modifier modifier = Modifier

View file

@ -56,6 +56,7 @@ class AdvancedSettingsPresenter(
when (theme.value) { when (theme.value) {
Theme.System -> ThemeOption.System Theme.System -> ThemeOption.System
Theme.Dark -> ThemeOption.Dark Theme.Dark -> ThemeOption.Dark
Theme.Black -> ThemeOption.Black
Theme.Light -> ThemeOption.Light Theme.Light -> ThemeOption.Light
} }
} }
@ -98,6 +99,7 @@ class AdvancedSettingsPresenter(
when (event.theme) { when (event.theme) {
ThemeOption.System -> appPreferencesStore.setTheme(Theme.System.name) ThemeOption.System -> appPreferencesStore.setTheme(Theme.System.name)
ThemeOption.Dark -> appPreferencesStore.setTheme(Theme.Dark.name) ThemeOption.Dark -> appPreferencesStore.setTheme(Theme.Dark.name)
ThemeOption.Black -> appPreferencesStore.setTheme(Theme.Black.name)
ThemeOption.Light -> appPreferencesStore.setTheme(Theme.Light.name) ThemeOption.Light -> appPreferencesStore.setTheme(Theme.Light.name)
} }
} }

View file

@ -48,6 +48,13 @@ enum class ThemeOption : DropdownOption {
@ReadOnlyComposable @ReadOnlyComposable
override fun getText(): String = stringResource(CommonStrings.common_dark) override fun getText(): String = stringResource(CommonStrings.common_dark)
}, },
Black {
@Composable
@ReadOnlyComposable
override fun getText(): String = stringResource(CommonStrings.common_black)
},
Light { Light {
@Composable @Composable
@ReadOnlyComposable @ReadOnlyComposable

View file

@ -29,6 +29,7 @@ import io.element.android.libraries.designsystem.components.preferences.Preferen
import io.element.android.libraries.designsystem.components.preferences.PreferenceSwitch import io.element.android.libraries.designsystem.components.preferences.PreferenceSwitch
import io.element.android.libraries.designsystem.preview.ElementPreview import io.element.android.libraries.designsystem.preview.ElementPreview
import io.element.android.libraries.designsystem.preview.ElementPreviewDark import io.element.android.libraries.designsystem.preview.ElementPreviewDark
import io.element.android.libraries.designsystem.preview.ElementPreviewBlack
import io.element.android.libraries.designsystem.preview.ElementPreviewLight import io.element.android.libraries.designsystem.preview.ElementPreviewLight
import io.element.android.libraries.designsystem.preview.PreviewWithLargeHeight import io.element.android.libraries.designsystem.preview.PreviewWithLargeHeight
import io.element.android.libraries.designsystem.preview.PreviewsDayNight import io.element.android.libraries.designsystem.preview.PreviewsDayNight
@ -324,6 +325,11 @@ internal fun AdvancedSettingsViewLightPreview(@PreviewParameter(AdvancedSettings
internal fun AdvancedSettingsViewDarkPreview(@PreviewParameter(AdvancedSettingsStateProvider::class) state: AdvancedSettingsState) = internal fun AdvancedSettingsViewDarkPreview(@PreviewParameter(AdvancedSettingsStateProvider::class) state: AdvancedSettingsState) =
ElementPreviewDark { ContentToPreview(state) } ElementPreviewDark { ContentToPreview(state) }
@PreviewWithLargeHeight
@Composable
internal fun AdvancedSettingsViewBlackPreview(@PreviewParameter(AdvancedSettingsStateProvider::class) state: AdvancedSettingsState) =
ElementPreviewBlack { ContentToPreview(state) }
@ExcludeFromCoverage @ExcludeFromCoverage
@Composable @Composable
private fun ContentToPreview(state: AdvancedSettingsState) { private fun ContentToPreview(state: AdvancedSettingsState) {

View file

@ -38,6 +38,7 @@ import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.LayoutDirection import androidx.compose.ui.unit.LayoutDirection
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import io.element.android.compound.theme.ElementTheme import io.element.android.compound.theme.ElementTheme
import io.element.android.compound.theme.Theme
import io.element.android.compound.tokens.generated.CompoundIcons import io.element.android.compound.tokens.generated.CompoundIcons
import kotlinx.collections.immutable.ImmutableList import kotlinx.collections.immutable.ImmutableList
import kotlinx.collections.immutable.toImmutableList import kotlinx.collections.immutable.toImmutableList
@ -62,7 +63,7 @@ internal fun IconsCompoundPreviewRtl() = ElementTheme {
@Preview(widthDp = 730, heightDp = 1920) @Preview(widthDp = 730, heightDp = 1920)
@Composable @Composable
internal fun IconsCompoundPreviewDark() = ElementTheme(darkTheme = true) { internal fun IconsCompoundPreviewDark() = ElementTheme(theme = Theme.Dark) {
IconsCompoundPreview() IconsCompoundPreview()
} }

View file

@ -19,6 +19,7 @@ import androidx.compose.ui.graphics.Color
import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import io.element.android.compound.theme.ElementTheme import io.element.android.compound.theme.ElementTheme
import io.element.android.compound.theme.Theme
import io.element.android.compound.tokens.generated.compoundColorsHcDark import io.element.android.compound.tokens.generated.compoundColorsHcDark
import kotlinx.collections.immutable.ImmutableMap import kotlinx.collections.immutable.ImmutableMap
import kotlinx.collections.immutable.persistentMapOf import kotlinx.collections.immutable.persistentMapOf
@ -65,7 +66,7 @@ internal fun CompoundSemanticColorsLightHc() = ElementTheme(
@Preview(heightDp = 2000) @Preview(heightDp = 2000)
@Composable @Composable
internal fun CompoundSemanticColorsDark() = ElementTheme(darkTheme = true) { internal fun CompoundSemanticColorsDark() = ElementTheme(theme = Theme.Dark) {
Surface { Surface {
Column( Column(
modifier = Modifier.padding(16.dp), modifier = Modifier.padding(16.dp),
@ -85,7 +86,7 @@ internal fun CompoundSemanticColorsDark() = ElementTheme(darkTheme = true) {
@Preview(heightDp = 2000) @Preview(heightDp = 2000)
@Composable @Composable
internal fun CompoundSemanticColorsDarkHc() = ElementTheme( internal fun CompoundSemanticColorsDarkHc() = ElementTheme(
darkTheme = true, theme = Theme.Dark,
compoundDark = compoundColorsHcDark, compoundDark = compoundColorsHcDark,
) { ) {
Surface { Surface {

View file

@ -65,7 +65,7 @@ internal fun AvatarColorsPreviewLight() {
@Preview @Preview
@Composable @Composable
internal fun AvatarColorsPreviewDark() { internal fun AvatarColorsPreviewDark() {
ElementTheme(darkTheme = true) { ElementTheme(theme = Theme.Dark) {
val chunks = avatarColors().chunked(4) val chunks = avatarColors().chunked(4)
Column(verticalArrangement = Arrangement.spacedBy(8.dp)) { Column(verticalArrangement = Arrangement.spacedBy(8.dp)) {
for (chunk in chunks) { for (chunk in chunks) {

View file

@ -77,10 +77,10 @@ internal val LocalCompoundColors = staticCompositionLocalOf { compoundColorsLigh
/** /**
* Sets up the theme for the application, or a part of it. * Sets up the theme for the application, or a part of it.
* *
* @param darkTheme whether to use the dark theme or not. If `true`, the dark theme will be used. * @param theme the [Theme] to use. Defaults to [Theme.Dark] or [Theme.Light] based on the system setting.
* @param applySystemBarsUpdate whether to update the system bars color scheme or not when the theme changes. It's `true` by default. * @param applySystemBarsUpdate whether to update the system bars color scheme or not when the theme changes. It's `true` by default.
* This is specially useful when you want to apply an alternate theme to a part of the app but don't want it to affect the system bars. * This is specially useful when you want to apply an alternate theme to a part of the app but don't want it to affect the system bars.
* @param lightStatusBar whether to use a light status bar color scheme or not. By default, it's the opposite of [darkTheme]. * @param lightStatusBar whether to use a light status bar color scheme or not. By default, it's `true` for light themes and `false` for dark ones.
* @param dynamicColor whether to enable MaterialYou or not. It's `false` by default. * @param dynamicColor whether to enable MaterialYou or not. It's `false` by default.
* @param compoundLight the [SemanticColors] to use in light theme. * @param compoundLight the [SemanticColors] to use in light theme.
* @param compoundDark the [SemanticColors] to use in dark theme. * @param compoundDark the [SemanticColors] to use in dark theme.
@ -91,9 +91,9 @@ internal val LocalCompoundColors = staticCompositionLocalOf { compoundColorsLigh
*/ */
@Composable @Composable
fun ElementTheme( fun ElementTheme(
darkTheme: Boolean = isSystemInDarkTheme(), theme: Theme = if (isSystemInDarkTheme()) Theme.Dark else Theme.Light,
applySystemBarsUpdate: Boolean = true, applySystemBarsUpdate: Boolean = true,
lightStatusBar: Boolean = !darkTheme, lightStatusBar: Boolean = !theme.isDark(),
// true to enable MaterialYou // true to enable MaterialYou
dynamicColor: Boolean = false, dynamicColor: Boolean = false,
compoundLight: SemanticColors = compoundColorsLight, compoundLight: SemanticColors = compoundColorsLight,
@ -103,8 +103,13 @@ fun ElementTheme(
typography: Typography = compoundTypography, typography: Typography = compoundTypography,
content: @Composable () -> Unit, content: @Composable () -> Unit,
) { ) {
val darkTheme = theme.isDark()
val currentCompoundColor = when { val currentCompoundColor = when {
darkTheme -> compoundDark darkTheme -> if (theme == Theme.Black) {
compoundDark.copy(bgCanvasDefault = Color.Black)
} else {
compoundDark
}
else -> compoundLight else -> compoundLight
} }
@ -113,7 +118,11 @@ fun ElementTheme(
val context = LocalContext.current val context = LocalContext.current
if (darkTheme) dynamicDarkColorScheme(context) else dynamicLightColorScheme(context) if (darkTheme) dynamicDarkColorScheme(context) else dynamicLightColorScheme(context)
} }
darkTheme -> materialColorsDark darkTheme -> if (theme == Theme.Black) {
currentCompoundColor.toMaterialColorScheme()
} else {
materialColorsDark
}
else -> materialColorsLight else -> materialColorsLight
} }
@ -130,7 +139,7 @@ fun ElementTheme(
if (applySystemBarsUpdate) { if (applySystemBarsUpdate) {
val activity = LocalActivity.current as? ComponentActivity val activity = LocalActivity.current as? ComponentActivity
LaunchedEffect(statusBarColorScheme, darkTheme, lightStatusBar) { LaunchedEffect(statusBarColorScheme, theme, lightStatusBar) {
activity?.enableEdgeToEdge( activity?.enableEdgeToEdge(
// For Status bar use the background color of the app // For Status bar use the background color of the app
statusBarStyle = SystemBarStyle.auto( statusBarStyle = SystemBarStyle.auto(

View file

@ -51,7 +51,7 @@ fun ForcedDarkElementTheme(
} }
} }
ElementTheme( ElementTheme(
darkTheme = true, theme = Theme.Dark,
compoundLight = colors.light, compoundLight = colors.light,
compoundDark = colors.dark, compoundDark = colors.dark,
lightStatusBar = lightStatusBar, lightStatusBar = lightStatusBar,

View file

@ -36,11 +36,15 @@ internal fun MaterialTextPreview() = Row(
) { ) {
MaterialPreview( MaterialPreview(
modifier = Modifier.weight(1f), modifier = Modifier.weight(1f),
darkTheme = false, theme = Theme.Light,
) )
MaterialPreview( MaterialPreview(
modifier = Modifier.weight(1f), modifier = Modifier.weight(1f),
darkTheme = true, theme = Theme.Dark,
)
MaterialPreview(
modifier = Modifier.weight(1f),
theme = Theme.Black,
) )
} }
@ -52,7 +56,7 @@ private data class Model(
@Composable @Composable
private fun MaterialPreview( private fun MaterialPreview(
darkTheme: Boolean, theme: Theme,
modifier: Modifier = Modifier, modifier: Modifier = Modifier,
) = Column(modifier = modifier) { ) = Column(modifier = modifier) {
Text( Text(
@ -60,13 +64,13 @@ private fun MaterialPreview(
.fillMaxWidth() .fillMaxWidth()
.padding(8.dp), .padding(8.dp),
textAlign = TextAlign.Center, textAlign = TextAlign.Center,
text = if (darkTheme) "Dark" else "Light", text = theme.name,
color = Color.Black, color = Color.Black,
fontSize = 18.sp, fontSize = 18.sp,
fontWeight = FontWeight.Bold, fontWeight = FontWeight.Bold,
) )
ElementTheme( ElementTheme(
darkTheme = darkTheme, theme = theme,
) { ) {
Column( Column(
modifier = Modifier.fillMaxSize() modifier = Modifier.fillMaxSize()

View file

@ -50,7 +50,7 @@ internal fun ColorsSchemeLightHcPreview() = ElementTheme(
@Preview(heightDp = 1200) @Preview(heightDp = 1200)
@Composable @Composable
internal fun ColorsSchemeDarkPreview() = ElementTheme( internal fun ColorsSchemeDarkPreview() = ElementTheme(
darkTheme = true, theme = Theme.Dark,
) { ) {
ColorsSchemePreview( ColorsSchemePreview(
Color.White, Color.White,
@ -62,7 +62,7 @@ internal fun ColorsSchemeDarkPreview() = ElementTheme(
@Preview(heightDp = 1200) @Preview(heightDp = 1200)
@Composable @Composable
internal fun ColorsSchemeDarkHcPreview() = ElementTheme( internal fun ColorsSchemeDarkHcPreview() = ElementTheme(
darkTheme = true, theme = Theme.Dark,
compoundDark = compoundColorsHcDark, compoundDark = compoundColorsHcDark,
) { ) {
ColorsSchemePreview( ColorsSchemePreview(
@ -71,3 +71,15 @@ internal fun ColorsSchemeDarkHcPreview() = ElementTheme(
ElementTheme.materialColors, ElementTheme.materialColors,
) )
} }
@Preview(heightDp = 1200)
@Composable
internal fun ColorsSchemeBlackPreview() = ElementTheme(
theme = Theme.Black
) {
ColorsSchemePreview(
Color.White,
Color.Black,
ElementTheme.materialColors,
)
}

View file

@ -16,6 +16,7 @@ import kotlinx.coroutines.flow.map
enum class Theme { enum class Theme {
System, System,
Dark, Dark,
Black,
Light, Light,
} }
@ -23,7 +24,7 @@ enum class Theme {
fun Theme.isDark(): Boolean { fun Theme.isDark(): Boolean {
return when (this) { return when (this) {
Theme.System -> isSystemInDarkTheme() Theme.System -> isSystemInDarkTheme()
Theme.Dark -> true Theme.Dark, Theme.Black -> true
Theme.Light -> false Theme.Light -> false
} }
} }

View file

@ -19,6 +19,7 @@ import io.element.android.compound.previews.IconsCompoundPreviewRtl
import io.element.android.compound.previews.IconsPreview import io.element.android.compound.previews.IconsPreview
import io.element.android.compound.screenshot.utils.screenshotFile import io.element.android.compound.screenshot.utils.screenshotFile
import io.element.android.compound.theme.ElementTheme import io.element.android.compound.theme.ElementTheme
import io.element.android.compound.theme.Theme
import io.element.android.compound.tokens.generated.CompoundIcons import io.element.android.compound.tokens.generated.CompoundIcons
import kotlinx.collections.immutable.toImmutableList import kotlinx.collections.immutable.toImmutableList
import org.junit.Test import org.junit.Test
@ -56,7 +57,7 @@ class CompoundIconTest {
val content: List<@Composable ColumnScope.() -> Unit> = CompoundIcons.all.map { val content: List<@Composable ColumnScope.() -> Unit> = CompoundIcons.all.map {
@Composable { Icon(imageVector = it, contentDescription = null) } @Composable { Icon(imageVector = it, contentDescription = null) }
} }
ElementTheme(darkTheme = true) { ElementTheme(theme = Theme.Dark) {
IconsPreview( IconsPreview(
title = "Compound Vector Icons", title = "Compound Vector Icons",
content = content.toImmutableList() content = content.toImmutableList()

View file

@ -24,6 +24,7 @@ import com.github.takahirom.roborazzi.captureRoboImage
import io.element.android.compound.previews.ColorsSchemePreview import io.element.android.compound.previews.ColorsSchemePreview
import io.element.android.compound.screenshot.utils.screenshotFile import io.element.android.compound.screenshot.utils.screenshotFile
import io.element.android.compound.theme.ElementTheme import io.element.android.compound.theme.ElementTheme
import io.element.android.compound.theme.Theme
import org.junit.Test import org.junit.Test
import org.junit.runner.RunWith import org.junit.runner.RunWith
import org.robolectric.annotation.Config import org.robolectric.annotation.Config
@ -51,7 +52,7 @@ class MaterialYouThemeTest {
} }
} }
captureRoboImage(file = screenshotFile("MaterialYou Theme - Dark.png")) { captureRoboImage(file = screenshotFile("MaterialYou Theme - Dark.png")) {
ElementTheme(dynamicColor = true, darkTheme = true) { ElementTheme(dynamicColor = true, theme = Theme.Dark) {
Surface { Surface {
Column( Column(
modifier = Modifier.padding(16.dp), modifier = Modifier.padding(16.dp),

View file

@ -31,6 +31,7 @@ import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import io.element.android.compound.annotations.CoreColorToken import io.element.android.compound.annotations.CoreColorToken
import io.element.android.compound.theme.ElementTheme import io.element.android.compound.theme.ElementTheme
import io.element.android.compound.theme.Theme
import io.element.android.compound.tokens.generated.internal.DarkColorTokens import io.element.android.compound.tokens.generated.internal.DarkColorTokens
import io.element.android.compound.tokens.generated.internal.LightColorTokens import io.element.android.compound.tokens.generated.internal.LightColorTokens
import io.element.android.libraries.designsystem.R import io.element.android.libraries.designsystem.R
@ -50,7 +51,7 @@ fun SunsetPage(
) { ) {
ElementTheme( ElementTheme(
// Always use the opposite value of the current theme // Always use the opposite value of the current theme
darkTheme = ElementTheme.isLightTheme, theme = if (ElementTheme.isLightTheme) Theme.Dark else Theme.Light,
applySystemBarsUpdate = false, applySystemBarsUpdate = false,
) { ) {
Box( Box(

View file

@ -19,6 +19,7 @@ import coil3.asImage
import coil3.compose.AsyncImagePreviewHandler import coil3.compose.AsyncImagePreviewHandler
import coil3.compose.LocalAsyncImagePreviewHandler import coil3.compose.LocalAsyncImagePreviewHandler
import io.element.android.compound.theme.ElementTheme import io.element.android.compound.theme.ElementTheme
import io.element.android.compound.theme.Theme
import io.element.android.libraries.designsystem.theme.components.Surface import io.element.android.libraries.designsystem.theme.components.Surface
import io.element.android.libraries.designsystem.utils.CommonDrawables import io.element.android.libraries.designsystem.utils.CommonDrawables
@ -26,7 +27,7 @@ import io.element.android.libraries.designsystem.utils.CommonDrawables
@Composable @Composable
@Suppress("ModifierMissing") @Suppress("ModifierMissing")
fun ElementPreview( fun ElementPreview(
darkTheme: Boolean = isSystemInDarkTheme(), theme: Theme = if (isSystemInDarkTheme()) Theme.Dark else Theme.Light,
showBackground: Boolean = true, showBackground: Boolean = true,
@DrawableRes @DrawableRes
drawableFallbackForImages: Int = CommonDrawables.sample_background, drawableFallbackForImages: Int = CommonDrawables.sample_background,
@ -38,7 +39,7 @@ fun ElementPreview(
ResourcesCompat.getDrawable(context.resources, drawableFallbackForImages, null)!!.asImage() ResourcesCompat.getDrawable(context.resources, drawableFallbackForImages, null)!!.asImage()
} }
) { ) {
ElementTheme(darkTheme = darkTheme) { ElementTheme(theme = theme) {
if (showBackground) { if (showBackground) {
// If we have a proper contentColor applied we need a Surface instead of a Box // If we have a proper contentColor applied we need a Surface instead of a Box
Surface(content = content) Surface(content = content)

View file

@ -0,0 +1,24 @@
/*
* Copyright (c) 2025 Element Creations Ltd.
* Copyright 2023-2025 New Vector Ltd.
*
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
* Please see LICENSE files in the repository root for full details.
*/
package io.element.android.libraries.designsystem.preview
import androidx.compose.runtime.Composable
import io.element.android.compound.theme.Theme
@Composable
fun ElementPreviewBlack(
showBackground: Boolean = true,
content: @Composable () -> Unit
) {
ElementPreview(
theme = Theme.Black,
showBackground = showBackground,
content = content
)
}

View file

@ -9,6 +9,7 @@
package io.element.android.libraries.designsystem.preview package io.element.android.libraries.designsystem.preview
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import io.element.android.compound.theme.Theme
@Composable @Composable
fun ElementPreviewDark( fun ElementPreviewDark(
@ -16,7 +17,7 @@ fun ElementPreviewDark(
content: @Composable () -> Unit content: @Composable () -> Unit
) { ) {
ElementPreview( ElementPreview(
darkTheme = true, theme = Theme.Dark,
showBackground = showBackground, showBackground = showBackground,
content = content content = content
) )

View file

@ -9,6 +9,7 @@
package io.element.android.libraries.designsystem.preview package io.element.android.libraries.designsystem.preview
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import io.element.android.compound.theme.Theme
@Composable @Composable
fun ElementPreviewLight( fun ElementPreviewLight(
@ -16,7 +17,7 @@ fun ElementPreviewLight(
content: @Composable () -> Unit content: @Composable () -> Unit
) { ) {
ElementPreview( ElementPreview(
darkTheme = false, theme = Theme.Light,
showBackground = showBackground, showBackground = showBackground,
content = content content = content
) )

View file

@ -21,6 +21,7 @@ import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.Color
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import io.element.android.compound.theme.Theme
import io.element.android.libraries.designsystem.utils.CommonDrawables import io.element.android.libraries.designsystem.utils.CommonDrawables
@Composable @Composable
@ -40,14 +41,14 @@ fun ElementThemedPreview(
if (vertical) { if (vertical) {
Column { Column {
ElementPreview( ElementPreview(
darkTheme = false, theme = Theme.Light,
showBackground = showBackground, showBackground = showBackground,
drawableFallbackForImages = drawableFallbackForImages, drawableFallbackForImages = drawableFallbackForImages,
content = content, content = content,
) )
Spacer(modifier = Modifier.height(4.dp)) Spacer(modifier = Modifier.height(4.dp))
ElementPreview( ElementPreview(
darkTheme = true, theme = Theme.Dark,
showBackground = showBackground, showBackground = showBackground,
drawableFallbackForImages = drawableFallbackForImages, drawableFallbackForImages = drawableFallbackForImages,
content = content content = content
@ -56,14 +57,14 @@ fun ElementThemedPreview(
} else { } else {
Row { Row {
ElementPreview( ElementPreview(
darkTheme = false, theme = Theme.Light,
showBackground = showBackground, showBackground = showBackground,
drawableFallbackForImages = drawableFallbackForImages, drawableFallbackForImages = drawableFallbackForImages,
content = content, content = content,
) )
Spacer(modifier = Modifier.width(4.dp)) Spacer(modifier = Modifier.width(4.dp))
ElementPreview( ElementPreview(
darkTheme = true, theme = Theme.Dark,
showBackground = showBackground, showBackground = showBackground,
drawableFallbackForImages = drawableFallbackForImages, drawableFallbackForImages = drawableFallbackForImages,
content = content content = content

View file

@ -18,7 +18,6 @@ import androidx.compose.runtime.remember
import androidx.compose.runtime.staticCompositionLocalOf import androidx.compose.runtime.staticCompositionLocalOf
import io.element.android.compound.theme.ElementTheme import io.element.android.compound.theme.ElementTheme
import io.element.android.compound.theme.Theme import io.element.android.compound.theme.Theme
import io.element.android.compound.theme.isDark
import io.element.android.compound.theme.mapToTheme import io.element.android.compound.theme.mapToTheme
import io.element.android.compound.tokens.generated.SemanticColors import io.element.android.compound.tokens.generated.SemanticColors
import io.element.android.libraries.core.meta.BuildMeta import io.element.android.libraries.core.meta.BuildMeta
@ -68,7 +67,7 @@ fun ElementThemeApp(
when (theme) { when (theme) {
Theme.System -> AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM Theme.System -> AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM
Theme.Light -> AppCompatDelegate.MODE_NIGHT_NO Theme.Light -> AppCompatDelegate.MODE_NIGHT_NO
Theme.Dark -> AppCompatDelegate.MODE_NIGHT_YES Theme.Dark, Theme.Black -> AppCompatDelegate.MODE_NIGHT_YES
} }
) )
} }
@ -76,7 +75,7 @@ fun ElementThemeApp(
LocalBuildMeta provides buildMeta, LocalBuildMeta provides buildMeta,
) { ) {
ElementTheme( ElementTheme(
darkTheme = theme.isDark(), theme = theme,
content = content, content = content,
compoundLight = compoundLight, compoundLight = compoundLight,
compoundDark = compoundDark, compoundDark = compoundDark,

View file

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?><!--
~ Copyright (c) 2026 Element Creations Ltd.
~
~ SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
~ Please see LICENSE files in the repository root for full details.
-->
<resources>
<string name="common_black">"Black"</string>
</resources>

View file

@ -30,7 +30,8 @@ class KonsistPreviewTest {
.assertTrue { .assertTrue {
it.hasNameEndingWith("Preview") && it.hasNameEndingWith("Preview") &&
it.hasNameEndingWith("LightPreview").not() && it.hasNameEndingWith("LightPreview").not() &&
it.hasNameEndingWith("DarkPreview").not() it.hasNameEndingWith("DarkPreview").not() &&
it.hasNameEndingWith("BlackPreview").not()
} }
} }