Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adding Dynamic Colors Material 3 Material You Theme #21

Draft
wants to merge 3 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,20 @@

package io.element.android.libraries.designsystem.theme

import android.os.Build
import androidx.annotation.RequiresApi
import androidx.compose.material3.ColorScheme
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.MaterialTheme.colorScheme
import androidx.compose.material3.darkColorScheme
import androidx.compose.material3.dynamicDarkColorScheme
import androidx.compose.material3.dynamicLightColorScheme
import androidx.compose.material3.lightColorScheme
import androidx.compose.runtime.Composable
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalContext
import chat.schildi.lib.preferences.ScPrefs
import chat.schildi.lib.preferences.value
import io.element.android.compound.annotations.CoreColorToken
import io.element.android.compound.previews.ColorListPreview
import io.element.android.compound.theme.ElementTheme
Expand All @@ -29,6 +40,22 @@ import io.element.android.libraries.designsystem.preview.ElementPreview
import io.element.android.libraries.designsystem.preview.PreviewsDayNight
import kotlinx.collections.immutable.persistentMapOf

object DynamicColorPreferences {
val isDynamicColorEnabled: Boolean
@Composable
get() = ScPrefs.SC_DYNAMICCOLORS.value()
}

@RequiresApi(Build.VERSION_CODES.S)
@Composable
fun getDynamicColorScheme(isDark: Boolean): ColorScheme {
val context = LocalContext.current
return if (DynamicColorPreferences.isDynamicColorEnabled) {
if (isDark) dynamicDarkColorScheme(context) else dynamicLightColorScheme(context)
} else {
if (isDark) darkColorScheme() else lightColorScheme()
}
}
/**
* Room list.
*/
Expand All @@ -47,138 +74,173 @@ val SemanticColors.unreadIndicator
val SemanticColors.placeholderBackground
get() = bgSubtleSecondary

// This color is not present in Semantic color, so put hard-coded value for now
val SemanticColors.messageFromMeBackground
get() = if (isLight) {
// We want LightDesignTokens.colorGray400
@Composable
get() = if (DynamicColorPreferences.isDynamicColorEnabled) {
colorScheme.primaryContainer
} else if (isLight) {
Color(0xFFE1E6EC)
} else {
// We want DarkDesignTokens.colorGray500
Color(0xFF323539)
}

// This color is not present in Semantic color, so put hard-coded value for now

val SemanticColors.messageFromOtherBackground
get() = if (isLight) {
// We want LightDesignTokens.colorGray300
@Composable
get() = if (DynamicColorPreferences.isDynamicColorEnabled) {
colorScheme.secondaryContainer
} else if (isLight) {
Color(0xFFF0F2F5)
} else {
// We want DarkDesignTokens.colorGray400
Color(0xFF26282D)
}

// This color is not present in Semantic color, so put hard-coded value for now
val SemanticColors.progressIndicatorTrackColor
get() = if (isLight) {
// We want LightDesignTokens.colorAlphaGray500
@Composable
get() = if (DynamicColorPreferences.isDynamicColorEnabled) {
colorScheme.onSurfaceVariant
} else if (isLight) {
Color(0x33052448)
} else {
// We want DarkDesignTokens.colorAlphaGray500
Color(0x25F4F7FA)
}

// This color is not present in Semantic color, so put hard-coded value for now
val SemanticColors.iconSuccessPrimaryBackground
get() = if (isLight) {
// We want LightDesignTokens.colorGreen300
@Composable
get() = if (DynamicColorPreferences.isDynamicColorEnabled) {
colorScheme.tertiaryContainer
} else if (isLight) {
Color(0xffe3f7ed)
} else {
// We want DarkDesignTokens.colorGreen300
Color(0xff002513)
}

// This color is not present in Semantic color, so put hard-coded value for now
val SemanticColors.bgSubtleTertiary
get() = if (isLight) {
// We want LightDesignTokens.colorGray100
@Composable
get() = if (DynamicColorPreferences.isDynamicColorEnabled) {
colorScheme.surfaceVariant
} else if (isLight) {
Color(0xfffbfcfd)
} else {
// We want DarkDesignTokens.colorGray100
Color(0xff14171b)
}

// Temporary color, which is not in the token right now
val SemanticColors.temporaryColorBgSpecial
get() = if (isLight) Color(0xFFE4E8F0) else Color(0xFF3A4048)
@Composable
get() = if (DynamicColorPreferences.isDynamicColorEnabled) {
colorScheme.background
} else if (isLight) Color(0xFFE4E8F0) else Color(0xFF3A4048)

// This color is not present in Semantic color, so put hard-coded value for now
val SemanticColors.pinDigitBg
get() = if (isLight) {
// We want LightDesignTokens.colorGray300
@Composable
get() = if (DynamicColorPreferences.isDynamicColorEnabled) {
colorScheme.onPrimaryContainer
} else if (isLight) {
Color(0xFFF0F2F5)
} else {
// We want DarkDesignTokens.colorGray400
Color(0xFF26282D)
}

val SemanticColors.currentUserMentionPillText
get() = if (isLight) {
// We want LightDesignTokens.colorGreen1100
@Composable
get() = if (DynamicColorPreferences.isDynamicColorEnabled) {
colorScheme.onTertiaryContainer
} else if (isLight) {
Color(0xff005c45)
} else {
// We want DarkDesignTokens.colorGreen1100
Color(0xff1fc090)
}

val SemanticColors.currentUserMentionPillBackground
get() = if (isLight) {
// We want LightDesignTokens.colorGreenAlpha400
@Composable
get() = if (DynamicColorPreferences.isDynamicColorEnabled) {
colorScheme.tertiary
} else if (isLight) {
Color(0x3b07b661)
} else {
// We want DarkDesignTokens.colorGreenAlpha500
Color(0xff003d29)
}

val SemanticColors.mentionPillText
get() = textPrimary
@Composable
get() = if (DynamicColorPreferences.isDynamicColorEnabled) {
colorScheme.onSecondaryContainer
} else textPrimary

val SemanticColors.mentionPillBackground
get() = if (isLight) {
// We want LightDesignTokens.colorGray400
@Composable
get() = if (DynamicColorPreferences.isDynamicColorEnabled) {
colorScheme.secondary
} else if (isLight) {
Color(0x1f052e61)
} else {
// We want DarkDesignTokens.colorGray500
Color(0x26f4f7fa)
}

@OptIn(CoreColorToken::class)
val SemanticColors.bigIconDefaultBackgroundColor
get() = if (isLight) LightColorTokens.colorAlphaGray300 else DarkColorTokens.colorAlphaGray300
@Composable
get() = if (DynamicColorPreferences.isDynamicColorEnabled) {
colorScheme.onSurface
} else if (isLight) LightColorTokens.colorAlphaGray300 else DarkColorTokens.colorAlphaGray300

@OptIn(CoreColorToken::class)
val SemanticColors.bigCheckmarkBorderColor
get() = if (isLight) LightColorTokens.colorGray400 else DarkColorTokens.colorGray400
@Composable
get() = if (DynamicColorPreferences.isDynamicColorEnabled) {
colorScheme.outline
} else if (isLight) LightColorTokens.colorGray400 else DarkColorTokens.colorGray400

@OptIn(CoreColorToken::class)
val SemanticColors.highlightedMessageBackgroundColor
get() = if (isLight) LightColorTokens.colorGreen300 else DarkColorTokens.colorGreen300
@Composable
get() = if (DynamicColorPreferences.isDynamicColorEnabled) {
colorScheme.primary
} else if (isLight) LightColorTokens.colorGreen300 else DarkColorTokens.colorGreen300

// Badge colors

@OptIn(CoreColorToken::class)
val SemanticColors.badgePositiveBackgroundColor
get() = if (isLight) LightColorTokens.colorAlphaGreen300 else DarkColorTokens.colorAlphaGreen300
@Composable
get() = if (DynamicColorPreferences.isDynamicColorEnabled) {
colorScheme.primaryContainer
} else if (isLight) LightColorTokens.colorAlphaGreen300 else DarkColorTokens.colorAlphaGreen300

@OptIn(CoreColorToken::class)
val SemanticColors.badgePositiveContentColor
get() = if (isLight) LightColorTokens.colorGreen1100 else DarkColorTokens.colorGreen1100
@Composable
get() = if (DynamicColorPreferences.isDynamicColorEnabled) {
colorScheme.onPrimaryContainer
} else if (isLight) LightColorTokens.colorGreen1100 else DarkColorTokens.colorGreen1100

@OptIn(CoreColorToken::class)
val SemanticColors.badgeNeutralBackgroundColor
get() = if (isLight) LightColorTokens.colorAlphaGray300 else DarkColorTokens.colorAlphaGray300
@Composable
get() = if (DynamicColorPreferences.isDynamicColorEnabled) {
colorScheme.surfaceVariant
} else if (isLight) LightColorTokens.colorAlphaGray300 else DarkColorTokens.colorAlphaGray300

@OptIn(CoreColorToken::class)
val SemanticColors.badgeNeutralContentColor
get() = if (isLight) LightColorTokens.colorGray1100 else DarkColorTokens.colorGray1100
@Composable
get() = if (DynamicColorPreferences.isDynamicColorEnabled) {
colorScheme.onSurfaceVariant
} else if (isLight) LightColorTokens.colorGray1100 else DarkColorTokens.colorGray1100

@OptIn(CoreColorToken::class)
val SemanticColors.badgeNegativeBackgroundColor
get() = if (isLight) LightColorTokens.colorAlphaRed300 else DarkColorTokens.colorAlphaRed300
@Composable
get() = if (DynamicColorPreferences.isDynamicColorEnabled) {
colorScheme.errorContainer
} else if (isLight) LightColorTokens.colorAlphaRed300 else DarkColorTokens.colorAlphaRed300

@OptIn(CoreColorToken::class)
val SemanticColors.badgeNegativeContentColor
get() = if (isLight) LightColorTokens.colorRed1100 else DarkColorTokens.colorRed1100

@Composable
get() = if (DynamicColorPreferences.isDynamicColorEnabled) {
colorScheme.onErrorContainer
} else if (isLight) LightColorTokens.colorRed1100 else DarkColorTokens.colorRed1100
@PreviewsDayNight
@Composable
internal fun ColorAliasesPreview() = ElementPreview {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ object ScPrefs {

// Appearance
val SC_THEME = ScBoolPref("SC_THEMES", true, R.string.sc_pref_sc_themes_title, upstreamChoice = false)
val SC_DYNAMICCOLORS = ScBoolPref("SC_DYNAMICCOLORS", true, R.string.sc_pref_sc_dynamic_colors_title, upstreamChoice = false)
val EL_TYPOGRAPHY = ScBoolPref("EL_TYPOGRAPHY", false, R.string.sc_pref_el_typography_title, R.string.sc_pref_el_typography_summary, upstreamChoice = true)

// General behavior
Expand Down Expand Up @@ -82,6 +83,7 @@ object ScPrefs {
val scTweaks = ScPrefScreen(R.string.sc_pref_tweaks_title, null, listOf<AbstractScPref>(
ScPrefCategory(R.string.sc_pref_category_general_appearance, null, listOf(
SC_THEME,
SC_DYNAMICCOLORS,
EL_TYPOGRAPHY,
)),
ScPrefCategory(R.string.sc_pref_category_general_behaviour, null, listOf(
Expand Down Expand Up @@ -167,6 +169,7 @@ object ScPrefs {
)),
ScPrefCategory(R.string.sc_pref_category_general_appearance, null, listOf(
SC_THEME,
SC_DYNAMICCOLORS,
SC_OVERVIEW_LAYOUT.copy(titleRes = R.string.sc_pref_sc_layout_title),
EL_TYPOGRAPHY,
COMPACT_APP_BAR,
Expand All @@ -191,6 +194,7 @@ object ScPrefs {

val devQuickTweaksTimeline = listOf(
SC_THEME,
SC_DYNAMICCOLORS,
EL_TYPOGRAPHY,
SC_TIMELINE_LAYOUT.copy(titleRes = R.string.sc_pref_sc_layout_title),
ScPrefCategory(R.string.sc_pref_screen_experimental_title, null, listOf(
Expand Down
1 change: 1 addition & 0 deletions schildi/lib/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
<!-- SchildiChat settings -->
<string name="sc_pref_tweaks_title">Turtle tweaks</string>
<string name="sc_pref_sc_themes_title">SC theme</string>
<string name="sc_pref_sc_dynamic_colors_title">Material You</string>
<string name="sc_pref_sc_layout_title">SC layout</string>
<string name="sc_pref_sc_overview_layout_title">SC overview layout</string>
<string name="sc_pref_sc_timeline_layout_title">SC conversation layout</string>
Expand Down
11 changes: 11 additions & 0 deletions schildi/theme/src/main/kotlin/chat/schildi/theme/ScDark.kt
Original file line number Diff line number Diff line change
@@ -1,7 +1,13 @@
package chat.schildi.theme

import android.os.Build
import androidx.annotation.RequiresApi
import androidx.compose.material3.DividerDefaults
import androidx.compose.material3.darkColorScheme
import androidx.compose.material3.dynamicDarkColorScheme
import androidx.compose.material3.dynamicLightColorScheme
import androidx.compose.runtime.Composable
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.unit.dp
import io.element.android.compound.annotations.CoreColorToken
import io.element.android.compound.tokens.generated.SemanticColors
Expand Down Expand Up @@ -64,8 +70,10 @@ internal val scdMaterialColorScheme = darkColorScheme(
scrim = ScColors.colorBlackAlpha_1f,
)


internal val scdExposures = ScThemeExposures(
isScTheme = true,
isDynamicColor = true,
horizontalDividerThickness = DividerDefaults.Thickness,
colorOnAccent = ScColors.colorWhite,
bubbleBgIncoming = scd_bgFloating,
Expand Down Expand Up @@ -158,3 +166,6 @@ internal val scdSemanticColors = SemanticColors(
// TODO-end
isLight = false,
)



Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ internal val sclMaterialColorScheme = lightColorScheme(

internal val sclExposures = ScThemeExposures(
isScTheme = true,
isDynamicColor = true,
horizontalDividerThickness = DividerDefaults.Thickness,
colorOnAccent = ScColors.colorWhite,
bubbleBgIncoming = ScColors.colorWhite_ee,
Expand Down
Loading