Add primary color to TasksTheme

pull/2948/head
Alex Baker 1 year ago
parent 0b76553122
commit 9f7dfc11ec

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

@ -1,6 +1,7 @@
package org.tasks.themes; package org.tasks.themes;
import static com.todoroo.andlib.utility.AndroidUtilities.atLeastOreo; import static com.todoroo.andlib.utility.AndroidUtilities.atLeastOreo;
import static org.tasks.themes.ColorUtilsKt.calculateContrast;
import android.app.Activity; import android.app.Activity;
import android.app.ActivityManager; import android.app.ActivityManager;
@ -14,7 +15,6 @@ import android.view.View;
import androidx.annotation.ColorInt; import androidx.annotation.ColorInt;
import androidx.annotation.RequiresApi; import androidx.annotation.RequiresApi;
import androidx.core.graphics.ColorUtils;
import androidx.core.os.ParcelCompat; import androidx.core.os.ParcelCompat;
import com.google.android.material.bottomappbar.BottomAppBar; 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 original;
private final int colorOnPrimary; private final int colorOnPrimary;
private final int colorPrimary; private final int colorPrimary;
@ -170,18 +167,18 @@ public class ThemeColor implements Pickable {
public ThemeColor(Context context, int original, int color) { public ThemeColor(Context context, int original, int color) {
this.original = original; this.original = original;
if (color == 0) { if (color == 0) {
color = BLUE; color = TasksThemeKt.BLUE;
} else { } else {
color |= 0xFF000000; // remove alpha color |= 0xFF000000; // remove alpha
} }
colorPrimary = color; colorPrimary = color;
double contrast = ColorUtils.calculateContrast(WHITE, colorPrimary); double contrast = calculateContrast(TasksThemeKt.WHITE, colorPrimary);
isDark = contrast < 3; isDark = contrast < 3;
if (isDark) { if (isDark) {
colorOnPrimary = context.getColor(R.color.black_87); colorOnPrimary = context.getColor(R.color.black_87);
} else { } 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 package org.tasks.themes
import androidx.compose.foundation.isSystemInDarkTheme import androidx.compose.foundation.isSystemInDarkTheme
import androidx.compose.material3.ColorScheme
import androidx.compose.material3.MaterialTheme import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.darkColorScheme import androidx.compose.material3.darkColorScheme
import androidx.compose.material3.lightColorScheme import androidx.compose.material3.lightColorScheme
import androidx.compose.runtime.Composable 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 @Composable
fun TasksTheme( fun TasksTheme(
useDarkTheme: Boolean = isSystemInDarkTheme(), theme: Int = 5,
primary: Int = BLUE,
content: @Composable () -> Unit, 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( MaterialTheme(
colorScheme = if (useDarkTheme) darkColorScheme() else lightColorScheme(), colorScheme = colorScheme.copy(
primary = Color(primary),
onPrimary = colorOnPrimary,
),
) { ) {
content() content()
} }

Loading…
Cancel
Save