Cleaning up the code for theming and decoupling the isClassic logic

This commit is contained in:
ThomasSession 2024-06-13 15:56:48 +10:00
parent 96157d65a6
commit 17c381b5f7
4 changed files with 201 additions and 175 deletions

View File

@ -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<Color>) {
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
}

View File

@ -0,0 +1,6 @@
package org.thoughtcrime.securesms.ui
data class SessionColorSet(
val lightTheme: SessionColors,
val darkTheme: SessionColors
)

View File

@ -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
)
}

View File

@ -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<SessionColors> {
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)
}
}
}