From 17c381b5f7a99c69da79547aab00dd94d4ce3fa4 Mon Sep 17 00:00:00 2001 From: ThomasSession Date: Thu, 13 Jun 2024 15:56:48 +1000 Subject: [PATCH] Cleaning up the code for theming and decoupling the isClassic logic --- .../org/thoughtcrime/securesms/ui/Colors.kt | 154 ---------------- .../securesms/ui/SessionColorSet.kt | 6 + .../securesms/ui/SessionColors.kt | 50 ++++++ .../org/thoughtcrime/securesms/ui/Themes.kt | 166 +++++++++++++++--- 4 files changed, 201 insertions(+), 175 deletions(-) create mode 100644 app/src/main/java/org/thoughtcrime/securesms/ui/SessionColorSet.kt create mode 100644 app/src/main/java/org/thoughtcrime/securesms/ui/SessionColors.kt diff --git a/app/src/main/java/org/thoughtcrime/securesms/ui/Colors.kt b/app/src/main/java/org/thoughtcrime/securesms/ui/Colors.kt index e080d8dcea..c3b3f67ac9 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/ui/Colors.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/ui/Colors.kt @@ -60,30 +60,6 @@ val Colors.disabled @Composable get() = onSurface.copy(alpha = ContentAlpha.disa val blackAlpha40 = Color.Black.copy(alpha = 0.4f) -val LocalColors = staticCompositionLocalOf { sessionColors(isLight = false, isClassic = true) } - -data class SessionColors( - val isLight: Boolean = false, - val primary: Color = Color.Unspecified, - val danger: Color = Color.Unspecified, - val disabled: Color = Color.Unspecified, - val background: Color = Color.Unspecified, - val backgroundSecondary: Color = Color.Unspecified, - val text: Color = Color.Unspecified, - val textSecondary: Color = Color.Unspecified, - val borders: Color = Color.Unspecified, - val textBubbleSent: Color = Color.Unspecified, - val backgroundBubbleReceived: Color = Color.Unspecified, - val textBubbleReceived: Color = Color.Unspecified, -) { - val backgroundLight get() = if (isLight) backgroundSecondary else Color.White - val onBackgroundLight get() = if (isLight) text else background - val button get() = if (isLight) text else primary - val divider get() = text.copy(alpha = TabRowDefaults.DividerOpacity) - val backgroundBubbleSent get() = primary - @Composable fun radioButtonColors() = RadioButtonDefaults.colors(selectedColor = primary, unselectedColor = text, disabledColor = disabled) -} - val primaryGreen = Color(0xFF31F196) val primaryBlue = Color(0xFF57C9FA) val primaryPurple = Color(0xFFC993FF) @@ -97,77 +73,6 @@ val dangerLight = Color(0xFFE12D19) val disabledDark = Color(0xFFA1A2A1) val disabledLight = Color(0xFF6D6D6D) -fun sessionColors( - isLight: Boolean, - isClassic: Boolean, - primary: Color = if (isClassic) primaryGreen else primaryBlue -): SessionColors = if (isClassic) { - if (isLight) classicLight else classicDark -} else { - if (isLight) oceanLight else oceanDark -}.copy( - primary = primary -) - -val classicDark = SessionColors( - isLight = false, - primary = primaryGreen, - danger = dangerDark, - disabled = disabledDark, - background = Color.Black, - backgroundSecondary = classicDark1, - text = Color.White, - textSecondary = classicDark5, - borders = classicDark3, - textBubbleSent = Color.Black, - backgroundBubbleReceived = classicDark2, - textBubbleReceived = Color.White, -) - -val classicLight = SessionColors( - isLight = true, - primary = primaryGreen, - danger = dangerLight, - disabled = disabledLight, - background = Color.White, - backgroundSecondary = classicLight5, - text = Color.Black, - textSecondary = classicLight1, - borders = classicLight3, - textBubbleSent = Color.Black, - backgroundBubbleReceived = classicLight4, - textBubbleReceived = classicLight4, -) - -val oceanDark = SessionColors( - isLight = false, - primary = primaryBlue, - danger = dangerDark, - disabled = disabledDark, - background = oceanDark2, - backgroundSecondary = oceanDark1, - text = Color.White, - textSecondary = oceanDark5, - borders = oceanDark4, - textBubbleSent = Color.Black, - backgroundBubbleReceived = oceanDark4, - textBubbleReceived = oceanDark4, -) - -val oceanLight = SessionColors( - isLight = true, - primary = primaryBlue, - danger = dangerLight, - disabled = disabledLight, - background = oceanLight7, - backgroundSecondary = oceanLight6, - text = oceanLight1, - textSecondary = oceanLight2, - borders = oceanLight3, - textBubbleSent = oceanLight1, - backgroundBubbleReceived = oceanLight4, - textBubbleReceived = oceanLight4 -) @Composable fun transparentButtonColors() = ButtonDefaults.buttonColors(backgroundColor = Color.Transparent) @@ -175,55 +80,6 @@ fun transparentButtonColors() = ButtonDefaults.buttonColors(backgroundColor = Co @Composable fun destructiveButtonColors() = ButtonDefaults.buttonColors(backgroundColor = Color.Transparent, contentColor = LocalColors.current.danger) -@Composable -fun Colors(name: String, colors: List) { - Column { - colors.forEachIndexed { i, it -> - Box(Modifier.background(it)) { - Text("$name: $i") - } - } - } -} - -@Preview -@Composable -fun PreviewThemeColors( - @PreviewParameter(SessionColorsParameterProvider::class) sessionColors: SessionColors -) { - PreviewTheme(sessionColors) { ThemeColors() } -} - -@Composable -private fun ThemeColors() { - Column { - Box(Modifier.background(MaterialTheme.colors.primary)) { - Text("primary", style = MaterialTheme.typography.base) - } - Box(Modifier.background(MaterialTheme.colors.primaryVariant)) { - Text("primaryVariant", style = MaterialTheme.typography.base) - } - Box(Modifier.background(MaterialTheme.colors.secondary)) { - Text("secondary", style = MaterialTheme.typography.base) - } - Box(Modifier.background(MaterialTheme.colors.secondaryVariant)) { - Text("secondaryVariant", style = MaterialTheme.typography.base) - } - Box(Modifier.background(MaterialTheme.colors.surface)) { - Text("surface", style = MaterialTheme.typography.base) - } - Box(Modifier.background(MaterialTheme.colors.primarySurface)) { - Text("primarySurface", style = MaterialTheme.typography.base) - } - Box(Modifier.background(MaterialTheme.colors.background)) { - Text("background", style = MaterialTheme.typography.base) - } - Box(Modifier.background(MaterialTheme.colors.error)) { - Text("error", style = MaterialTheme.typography.base) - } - } -} - @Composable fun outlinedTextFieldColors( isError: Boolean @@ -234,13 +90,3 @@ fun outlinedTextFieldColors( unfocusedBorderColor = LocalColors.current.borders, placeholderColor = if (isError) LocalColors.current.danger else LocalColors.current.textSecondary ) - -fun TextSecurePreferences.Companion.getAccentColor(context: Context): Color = when (getAccentColorName(context)) { - BLUE_ACCENT -> primaryBlue - PURPLE_ACCENT -> primaryPurple - PINK_ACCENT -> primaryPink - RED_ACCENT -> primaryRed - ORANGE_ACCENT -> primaryOrange - YELLOW_ACCENT -> primaryYellow - else -> primaryGreen -} diff --git a/app/src/main/java/org/thoughtcrime/securesms/ui/SessionColorSet.kt b/app/src/main/java/org/thoughtcrime/securesms/ui/SessionColorSet.kt new file mode 100644 index 0000000000..a310da7d12 --- /dev/null +++ b/app/src/main/java/org/thoughtcrime/securesms/ui/SessionColorSet.kt @@ -0,0 +1,6 @@ +package org.thoughtcrime.securesms.ui + +data class SessionColorSet( + val lightTheme: SessionColors, + val darkTheme: SessionColors +) \ No newline at end of file diff --git a/app/src/main/java/org/thoughtcrime/securesms/ui/SessionColors.kt b/app/src/main/java/org/thoughtcrime/securesms/ui/SessionColors.kt new file mode 100644 index 0000000000..d34cbf391c --- /dev/null +++ b/app/src/main/java/org/thoughtcrime/securesms/ui/SessionColors.kt @@ -0,0 +1,50 @@ +package org.thoughtcrime.securesms.ui + +import androidx.compose.material.Colors +import androidx.compose.material.RadioButtonDefaults +import androidx.compose.material.TabRowDefaults +import androidx.compose.runtime.Composable +import androidx.compose.ui.graphics.Color + +data class SessionColors( + val isLight: Boolean = false, + val primary: Color = Color.Unspecified, + val danger: Color = Color.Unspecified, + val disabled: Color = Color.Unspecified, + val background: Color = Color.Unspecified, + val backgroundSecondary: Color = Color.Unspecified, + val text: Color = Color.Unspecified, + val textSecondary: Color = Color.Unspecified, + val borders: Color = Color.Unspecified, + val textBubbleSent: Color = Color.Unspecified, + val backgroundBubbleReceived: Color = Color.Unspecified, + val textBubbleReceived: Color = Color.Unspecified, +) { + // To delete and instead use figma terms and add them to the data class above ------ + val backgroundLight get() = if (isLight) backgroundSecondary else Color.White + val onBackgroundLight get() = if (isLight) text else background + val button get() = if (isLight) text else primary + val backgroundBubbleSent get() = primary + // -------------------------------------------------------------------------------- + + @Composable + fun radioButtonColors() = RadioButtonDefaults.colors(selectedColor = primary, unselectedColor = text, disabledColor = disabled) + + val divider get() = text.copy(alpha = TabRowDefaults.DividerOpacity) + + fun toMaterialColors() = Colors( + primary = background, + primaryVariant = backgroundSecondary, + secondary = background, + secondaryVariant = background, + background = background, + surface = background, + error = danger, + onPrimary = text, + onSecondary = text, + onBackground = text, + onSurface = text, + onError = text, + isLight = isLight + ) +} \ No newline at end of file diff --git a/app/src/main/java/org/thoughtcrime/securesms/ui/Themes.kt b/app/src/main/java/org/thoughtcrime/securesms/ui/Themes.kt index 4ce77260c4..a0e684c5d7 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/ui/Themes.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/ui/Themes.kt @@ -4,6 +4,7 @@ import android.content.Context import androidx.compose.foundation.background import androidx.compose.foundation.isSystemInDarkTheme import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.foundation.text.selection.LocalTextSelectionColors import androidx.compose.foundation.text.selection.TextSelectionColors @@ -11,12 +12,20 @@ import androidx.compose.material.Colors import androidx.compose.material.LocalContentColor import androidx.compose.material.MaterialTheme import androidx.compose.material.Shapes +import androidx.compose.material.Text +import androidx.compose.material.primarySurface import androidx.compose.runtime.Composable import androidx.compose.runtime.CompositionLocalProvider +import androidx.compose.runtime.compositionLocalOf import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.tooling.preview.PreviewParameter import androidx.compose.ui.tooling.preview.PreviewParameterProvider +import network.loki.messenger.R import org.session.libsession.utilities.AppTextSecurePreferences +import org.session.libsession.utilities.TextSecurePreferences import org.thoughtcrime.securesms.util.ThemeState import org.thoughtcrime.securesms.util.themeState @@ -27,7 +36,7 @@ import org.thoughtcrime.securesms.util.themeState fun SessionMaterialTheme( content: @Composable () -> Unit ) { - SessionMaterialTheme(LocalContext.current.sessionColors()) { content() } + SessionMaterialTheme(LocalContext.current.composeTheme()) { content() } } /** @@ -58,24 +67,104 @@ fun SessionMaterialTheme( } } -private fun SessionColors.toMaterialColors() = Colors( - primary = background, - primaryVariant = backgroundSecondary, - secondary = background, - secondaryVariant = background, - background = background, - surface = background, - error = danger, - onPrimary = text, - onSecondary = text, - onBackground = text, - onSurface = text, - onError = text, - isLight = isLight +// Compose theme holder +val LocalColors = compositionLocalOf { classicDark } + +// Our themes +val classicDark = SessionColors( + isLight = false, + primary = primaryGreen, + danger = dangerDark, + disabled = disabledDark, + background = Color.Black, + backgroundSecondary = classicDark1, + text = Color.White, + textSecondary = classicDark5, + borders = classicDark3, + textBubbleSent = Color.Black, + backgroundBubbleReceived = classicDark2, + textBubbleReceived = Color.White, ) -@Composable private fun Context.sessionColors() = AppTextSecurePreferences(this).themeState().sessionColors() -@Composable private fun ThemeState.sessionColors() = sessionColors(if (followSystem) !isSystemInDarkTheme() else isLight, isClassic, accent) +val classicLight = SessionColors( + isLight = true, + primary = primaryGreen, + danger = dangerLight, + disabled = disabledLight, + background = Color.White, + backgroundSecondary = classicLight5, + text = Color.Black, + textSecondary = classicLight1, + borders = classicLight3, + textBubbleSent = Color.Black, + backgroundBubbleReceived = classicLight4, + textBubbleReceived = classicLight4, +) + +val oceanDark = SessionColors( + isLight = false, + primary = primaryBlue, + danger = dangerDark, + disabled = disabledDark, + background = oceanDark2, + backgroundSecondary = oceanDark1, + text = Color.White, + textSecondary = oceanDark5, + borders = oceanDark4, + textBubbleSent = Color.Black, + backgroundBubbleReceived = oceanDark4, + textBubbleReceived = oceanDark4, +) + +val oceanLight = SessionColors( + isLight = true, + primary = primaryBlue, + danger = dangerLight, + disabled = disabledLight, + background = oceanLight7, + backgroundSecondary = oceanLight6, + text = oceanLight1, + textSecondary = oceanLight2, + borders = oceanLight3, + textBubbleSent = oceanLight1, + backgroundBubbleReceived = oceanLight4, + textBubbleReceived = oceanLight4 +) + +val classicTheme = SessionColorSet( + lightTheme = classicLight, + darkTheme = classicDark +) + +val oceanTheme = SessionColorSet( + lightTheme = oceanLight, + darkTheme = oceanDark +) + +@Composable private fun Context.composeTheme() = AppTextSecurePreferences(this).themeState().composeTheme() +// We still need to match xml values for now but once we go full Compose all of this can go +@Composable private fun ThemeState.composeTheme(): SessionColors { + // pick the theme based on xml value + val colorSet = when (theme) { + R.style.Ocean_Light, + R.style.Ocean_Dark -> oceanTheme + + else -> classicTheme + } + + // get the mode (light/dark/system) from settings + val colorMode = + when { + followSystem -> { // user decided to 'match system settings' + if(isSystemInDarkTheme()) colorSet.darkTheme else colorSet.lightTheme + } + isLight -> colorSet.lightTheme + else -> colorSet.darkTheme + } + + // set the accent as per user choice + return colorMode.copy(primary = accent) +} val sessionShapes = Shapes( small = RoundedCornerShape(50) @@ -98,9 +187,44 @@ fun PreviewTheme( class SessionColorsParameterProvider : PreviewParameterProvider { override val values = sequenceOf( - sessionColors(isLight = false, isClassic = true), - sessionColors(isLight = true, isClassic = true), - sessionColors(isLight = false, isClassic = false), - sessionColors(isLight = true, isClassic = false), + classicDark, classicLight, oceanDark, oceanLight ) } + +@Preview +@Composable +fun PreviewThemeColors( + @PreviewParameter(SessionColorsParameterProvider::class) sessionColors: SessionColors +) { + PreviewTheme(sessionColors) { ThemeColors() } +} + +@Composable +private fun ThemeColors() { + Column { + Box(Modifier.background(MaterialTheme.colors.primary)) { + Text("primary", style = MaterialTheme.typography.base) + } + Box(Modifier.background(MaterialTheme.colors.primaryVariant)) { + Text("primaryVariant", style = MaterialTheme.typography.base) + } + Box(Modifier.background(MaterialTheme.colors.secondary)) { + Text("secondary", style = MaterialTheme.typography.base) + } + Box(Modifier.background(MaterialTheme.colors.secondaryVariant)) { + Text("secondaryVariant", style = MaterialTheme.typography.base) + } + Box(Modifier.background(MaterialTheme.colors.surface)) { + Text("surface", style = MaterialTheme.typography.base) + } + Box(Modifier.background(MaterialTheme.colors.primarySurface)) { + Text("primarySurface", style = MaterialTheme.typography.base) + } + Box(Modifier.background(MaterialTheme.colors.background)) { + Text("background", style = MaterialTheme.typography.base) + } + Box(Modifier.background(MaterialTheme.colors.error)) { + Text("error", style = MaterialTheme.typography.base) + } + } +}