Add primary color to TasksTheme

pull/2948/head
Alex Baker 3 months ago
parent 0b76553122
commit 9f7dfc11ec

@ -36,7 +36,7 @@ private fun Invite() = TasksTheme {
@Preview(showBackground = true, backgroundColor = 0x202124)
@Composable
private fun InviteDark() = TasksTheme(useDarkTheme = true) {
private fun InviteDark() = TasksTheme(theme = 2) {
ShareInvite(false, remember { mutableStateOf("") })
}
@ -48,7 +48,7 @@ private fun InviteFilled() = TasksTheme {
@Preview(showBackground = true, backgroundColor = 0x202124)
@Composable
private fun InviteDarkFilled() = TasksTheme(useDarkTheme = true) {
private fun InviteDarkFilled() = TasksTheme(theme = 2) {
ShareInvite(false, remember { mutableStateOf("user@example.com") })
}

@ -1,6 +1,7 @@
package org.tasks.themes;
import static com.todoroo.andlib.utility.AndroidUtilities.atLeastOreo;
import static org.tasks.themes.ColorUtilsKt.calculateContrast;
import android.app.Activity;
import android.app.ActivityManager;
@ -14,7 +15,6 @@ import android.view.View;
import androidx.annotation.ColorInt;
import androidx.annotation.RequiresApi;
import androidx.core.graphics.ColorUtils;
import androidx.core.os.ParcelCompat;
import com.google.android.material.bottomappbar.BottomAppBar;
@ -155,9 +155,6 @@ public class ThemeColor implements Pickable {
}
};
private static final int BLUE = -14575885;
private static final int WHITE = -1;
private final int original;
private final int colorOnPrimary;
private final int colorPrimary;
@ -170,18 +167,18 @@ public class ThemeColor implements Pickable {
public ThemeColor(Context context, int original, int color) {
this.original = original;
if (color == 0) {
color = BLUE;
color = TasksThemeKt.BLUE;
} else {
color |= 0xFF000000; // remove alpha
}
colorPrimary = color;
double contrast = ColorUtils.calculateContrast(WHITE, colorPrimary);
double contrast = calculateContrast(TasksThemeKt.WHITE, colorPrimary);
isDark = contrast < 3;
if (isDark) {
colorOnPrimary = context.getColor(R.color.black_87);
} else {
colorOnPrimary = WHITE;
colorOnPrimary = TasksThemeKt.WHITE;
}
}

@ -0,0 +1,90 @@
package org.tasks.themes
import kotlin.math.max
import kotlin.math.min
import kotlin.math.pow
fun calculateContrast(foreground: Int, background: Int): Double {
var foreground = foreground
require(alpha(background) == 255) {
("background can not be translucent: #" + Integer.toHexString(background))
}
if (alpha(foreground) < 255) {
// If the foreground is translucent, composite the foreground over the background
foreground = compositeColors(foreground, background)
}
val luminance1: Double = calculateLuminance(foreground) + 0.05
val luminance2: Double = calculateLuminance(background) + 0.05
// Now return the lighter luminance divided by the darker luminance
return max(luminance1, luminance2) / min(luminance1, luminance2)
}
private fun compositeAlpha(foregroundAlpha: Int, backgroundAlpha: Int): Int =
0xFF - (((0xFF - backgroundAlpha) * (0xFF - foregroundAlpha)) / 0xFF)
private fun compositeComponent(fgC: Int, fgA: Int, bgC: Int, bgA: Int, a: Int): Int {
if (a == 0) return 0
return ((0xFF * fgC * fgA) + (bgC * bgA * (0xFF - fgA))) / (a * 0xFF)
}
private fun compositeColors(foreground: Int, background: Int): Int {
val bgAlpha = alpha(background)
val fgAlpha = alpha(foreground)
val a = compositeAlpha(fgAlpha, bgAlpha)
return argb(
alpha = a,
red = compositeComponent(red(foreground), fgAlpha, red(background), bgAlpha, a),
green = compositeComponent(green(foreground), fgAlpha, green(background), bgAlpha, a),
blue = compositeComponent(blue(foreground), fgAlpha, blue(background), bgAlpha, a)
)
}
private fun alpha(color: Int): Int = color ushr 24
private fun red(color: Int): Int = (color shr 16) and 0xFF
private fun green(color: Int): Int = (color shr 8) and 0xFF
private fun blue(color: Int): Int = color and 0xFF
private fun argb(alpha: Int, red: Int, green: Int, blue: Int) =
(alpha shl 24) or (red shl 16) or (green shl 8) or blue
private fun calculateLuminance(color: Int): Double {
val result: DoubleArray = getTempDouble3Array()
colorToXYZ(color, result)
// Luminance is the Y component
return result[1] / 100
}
private fun getTempDouble3Array(): DoubleArray {
var result: DoubleArray? = TEMP_ARRAY.get()
if (result == null) {
result = DoubleArray(3)
TEMP_ARRAY.set(result)
}
return result
}
private val TEMP_ARRAY = ThreadLocal<DoubleArray>()
private fun colorToXYZ(color: Int, outXyz: DoubleArray) {
RGBToXYZ(red(color), green(color), blue(color), outXyz)
}
private fun RGBToXYZ(r: Int, g: Int, b: Int, outXyz: DoubleArray) {
require(outXyz.size == 3) { "outXyz must have a length of 3." }
var sr = r / 255.0
sr = if (sr < 0.04045) sr / 12.92 else ((sr + 0.055) / 1.055).pow(2.4)
var sg = g / 255.0
sg = if (sg < 0.04045) sg / 12.92 else ((sg + 0.055) / 1.055).pow(2.4)
var sb = b / 255.0
sb = if (sb < 0.04045) sb / 12.92 else ((sb + 0.055) / 1.055).pow(2.4)
outXyz[0] = 100 * (sr * 0.4124 + sg * 0.3576 + sb * 0.1805)
outXyz[1] = 100 * (sr * 0.2126 + sg * 0.7152 + sb * 0.0722)
outXyz[2] = 100 * (sr * 0.0193 + sg * 0.1192 + sb * 0.9505)
}

@ -1,18 +1,50 @@
package org.tasks.themes
import androidx.compose.foundation.isSystemInDarkTheme
import androidx.compose.material3.ColorScheme
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.darkColorScheme
import androidx.compose.material3.lightColorScheme
import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.luminance
const val BLUE = -14575885
const val WHITE = -1
@Composable
fun ColorScheme.isDark() = this.background.luminance() <= 0.5
@Composable
fun TasksTheme(
useDarkTheme: Boolean = isSystemInDarkTheme(),
theme: Int = 5,
primary: Int = BLUE,
content: @Composable () -> Unit,
) {
val colorScheme = when (theme) {
0 -> lightColorScheme()
1 -> darkColorScheme(
surface = Color.Black,
background = Color.Black,
)
2, 3 -> darkColorScheme()
else -> if (isSystemInDarkTheme()) darkColorScheme() else lightColorScheme()
}
val colorOnPrimary = remember(primary) {
if (calculateContrast(WHITE, primary) < 3) {
Color.Black
} else {
Color.White
}
}
MaterialTheme(
colorScheme = if (useDarkTheme) darkColorScheme() else lightColorScheme(),
colorScheme = colorScheme.copy(
primary = Color(primary),
onPrimary = colorOnPrimary,
),
) {
content()
}

Loading…
Cancel
Save