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 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 primaryGreen = Color(0xFF31F196)
val primaryBlue = Color(0xFF57C9FA) val primaryBlue = Color(0xFF57C9FA)
val primaryPurple = Color(0xFFC993FF) val primaryPurple = Color(0xFFC993FF)
@ -97,77 +73,6 @@ val dangerLight = Color(0xFFE12D19)
val disabledDark = Color(0xFFA1A2A1) val disabledDark = Color(0xFFA1A2A1)
val disabledLight = Color(0xFF6D6D6D) 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 @Composable
fun transparentButtonColors() = ButtonDefaults.buttonColors(backgroundColor = Color.Transparent) fun transparentButtonColors() = ButtonDefaults.buttonColors(backgroundColor = Color.Transparent)
@ -175,55 +80,6 @@ fun transparentButtonColors() = ButtonDefaults.buttonColors(backgroundColor = Co
@Composable @Composable
fun destructiveButtonColors() = ButtonDefaults.buttonColors(backgroundColor = Color.Transparent, contentColor = LocalColors.current.danger) 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 @Composable
fun outlinedTextFieldColors( fun outlinedTextFieldColors(
isError: Boolean isError: Boolean
@ -234,13 +90,3 @@ fun outlinedTextFieldColors(
unfocusedBorderColor = LocalColors.current.borders, unfocusedBorderColor = LocalColors.current.borders,
placeholderColor = if (isError) LocalColors.current.danger else LocalColors.current.textSecondary 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.background
import androidx.compose.foundation.isSystemInDarkTheme import androidx.compose.foundation.isSystemInDarkTheme
import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.foundation.text.selection.LocalTextSelectionColors import androidx.compose.foundation.text.selection.LocalTextSelectionColors
import androidx.compose.foundation.text.selection.TextSelectionColors 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.LocalContentColor
import androidx.compose.material.MaterialTheme import androidx.compose.material.MaterialTheme
import androidx.compose.material.Shapes import androidx.compose.material.Shapes
import androidx.compose.material.Text
import androidx.compose.material.primarySurface
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.runtime.compositionLocalOf
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalContext 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 androidx.compose.ui.tooling.preview.PreviewParameterProvider
import network.loki.messenger.R
import org.session.libsession.utilities.AppTextSecurePreferences import org.session.libsession.utilities.AppTextSecurePreferences
import org.session.libsession.utilities.TextSecurePreferences
import org.thoughtcrime.securesms.util.ThemeState import org.thoughtcrime.securesms.util.ThemeState
import org.thoughtcrime.securesms.util.themeState import org.thoughtcrime.securesms.util.themeState
@ -27,7 +36,7 @@ import org.thoughtcrime.securesms.util.themeState
fun SessionMaterialTheme( fun SessionMaterialTheme(
content: @Composable () -> Unit content: @Composable () -> Unit
) { ) {
SessionMaterialTheme(LocalContext.current.sessionColors()) { content() } SessionMaterialTheme(LocalContext.current.composeTheme()) { content() }
} }
/** /**
@ -58,24 +67,104 @@ fun SessionMaterialTheme(
} }
} }
private fun SessionColors.toMaterialColors() = Colors( // Compose theme holder
primary = background, val LocalColors = compositionLocalOf { classicDark }
primaryVariant = backgroundSecondary,
secondary = background, // Our themes
secondaryVariant = background, val classicDark = SessionColors(
background = background, isLight = false,
surface = background, primary = primaryGreen,
error = danger, danger = dangerDark,
onPrimary = text, disabled = disabledDark,
onSecondary = text, background = Color.Black,
onBackground = text, backgroundSecondary = classicDark1,
onSurface = text, text = Color.White,
onError = text, textSecondary = classicDark5,
isLight = isLight borders = classicDark3,
textBubbleSent = Color.Black,
backgroundBubbleReceived = classicDark2,
textBubbleReceived = Color.White,
) )
@Composable private fun Context.sessionColors() = AppTextSecurePreferences(this).themeState().sessionColors() val classicLight = SessionColors(
@Composable private fun ThemeState.sessionColors() = sessionColors(if (followSystem) !isSystemInDarkTheme() else isLight, isClassic, accent) 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( val sessionShapes = Shapes(
small = RoundedCornerShape(50) small = RoundedCornerShape(50)
@ -98,9 +187,44 @@ fun PreviewTheme(
class SessionColorsParameterProvider : PreviewParameterProvider<SessionColors> { class SessionColorsParameterProvider : PreviewParameterProvider<SessionColors> {
override val values = sequenceOf( override val values = sequenceOf(
sessionColors(isLight = false, isClassic = true), classicDark, classicLight, oceanDark, oceanLight
sessionColors(isLight = true, isClassic = true),
sessionColors(isLight = false, isClassic = false),
sessionColors(isLight = true, isClassic = false),
) )
} }
@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)
}
}
}