mirror of
https://github.com/Droid-Deck/DroidDeck.git
synced 2026-11-13 03:51:10 +00:00
feat: custom Gradient theme with primary and secondary colors (#1309)
* feat: a custom Gradient theme with a primary and a secondary colour, picked with a wheel, sliders and a hex box * Gradient theme: OK waits for a valid hex, deep blues are made paler, button text suits the worse gradient colour * Gradient theme: nudge only the gradient colour that button text cannot read on * fix: meet readable contrast across gradient themes * fix: preserve contrast through gradient interpolation --------- Co-authored-by: xXJsonDeruloXx <danielhimebauch@gmail.com>
This commit is contained in:
1 parent
d2abaef2a3
commit
7482f797c7
43 files changed
+789
-5
No files matched your search
@@ -16,6 +16,7 @@ class App : Application() {
|
||||
|
||||
override fun onCreate() {
|
||||
super.onCreate()
|
||||
com.droiddeck.launcher.ui.Themes.loadGradient(this)
|
||||
// Helper processes must not initialize the main USB provider or guest graphics context.
|
||||
val process = if (android.os.Build.VERSION.SDK_INT >= 28) Application.getProcessName()
|
||||
else (getSystemService(ACTIVITY_SERVICE) as android.app.ActivityManager)
|
||||
|
||||
@@ -3418,7 +3418,7 @@ class SessionActivity : ComponentActivity(), SurfaceHolder.Callback {
|
||||
|
||||
private fun finishFlooded() {
|
||||
if (isFinishing) return
|
||||
val signal = com.droiddeck.launcher.ui.Themes.byId(SessionPrefs.theme(this)).signal
|
||||
val signal = com.droiddeck.launcher.ui.Themes.current(this).signal
|
||||
com.droiddeck.launcher.ui.QuitFlood.mark(signal.toArgb())
|
||||
window.setBackgroundDrawable(android.graphics.drawable.ColorDrawable(signal.toArgb()))
|
||||
quitFlooded = true
|
||||
@@ -3449,7 +3449,7 @@ class SessionActivity : ComponentActivity(), SurfaceHolder.Callback {
|
||||
|
||||
private fun completeLeave() {
|
||||
if (isFinishing) return
|
||||
val signal = com.droiddeck.launcher.ui.Themes.byId(SessionPrefs.theme(this)).signal
|
||||
val signal = com.droiddeck.launcher.ui.Themes.current(this).signal
|
||||
com.droiddeck.launcher.ui.QuitFlood.mark(signal.toArgb())
|
||||
window.setBackgroundDrawable(android.graphics.drawable.ColorDrawable(signal.toArgb()))
|
||||
quitFlooded = true
|
||||
|
||||
@@ -759,6 +759,16 @@ object SessionPrefs {
|
||||
prefs(context).edit().putString("theme", id).apply()
|
||||
}
|
||||
|
||||
/** The custom Gradient theme's primary and secondary colours (ARGB). */
|
||||
fun gradientColors(context: Context): Pair<Int, Int> = prefs(context).let {
|
||||
it.getInt("gradientPrimary", com.droiddeck.launcher.ui.Themes.DEFAULT_PRIMARY) to
|
||||
it.getInt("gradientSecondary", com.droiddeck.launcher.ui.Themes.DEFAULT_SECONDARY)
|
||||
}
|
||||
|
||||
fun setGradientColors(context: Context, primary: Int, secondary: Int) {
|
||||
prefs(context).edit().putInt("gradientPrimary", primary).putInt("gradientSecondary", secondary).apply()
|
||||
}
|
||||
|
||||
private fun customResolution(context: Context, mode: String): Pair<Int, Int>? =
|
||||
parseResolution(prefs(context).getString("customRes.$mode", null))
|
||||
|
||||
|
||||
@@ -0,0 +1,141 @@
|
||||
package com.droiddeck.launcher.ui
|
||||
|
||||
import androidx.compose.foundation.Canvas
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.border
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.gestures.detectDragGestures
|
||||
import androidx.compose.foundation.gestures.detectTapGestures
|
||||
import androidx.compose.foundation.hoverable
|
||||
import androidx.compose.foundation.interaction.MutableInteractionSource
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.focus.FocusRequester
|
||||
import androidx.compose.ui.focus.focusRequester
|
||||
import androidx.compose.ui.geometry.Offset
|
||||
import androidx.compose.ui.graphics.Brush
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.input.pointer.pointerInput
|
||||
import androidx.compose.ui.semantics.contentDescription
|
||||
import androidx.compose.ui.semantics.semantics
|
||||
import androidx.compose.ui.semantics.Role
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.text.input.ImeAction
|
||||
import androidx.compose.ui.text.input.KeyboardType
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.droiddeck.launcher.R
|
||||
import kotlin.math.atan2
|
||||
import kotlin.math.hypot
|
||||
import kotlin.math.min
|
||||
|
||||
/** A small colour square; pressing it opens the colour picker. */
|
||||
@Composable
|
||||
internal fun ColorCube(color: Color, description: String, focus: FocusRequester? = null, onClick: () -> Unit) {
|
||||
val pal = LocalPalette.current
|
||||
val src = remember { MutableInteractionSource() }
|
||||
val hot = rememberHot(src)
|
||||
val shape = RoundedCornerShape(10.dp)
|
||||
Box(
|
||||
Modifier.then(if (focus != null) Modifier.focusRequester(focus) else Modifier).size(44.dp).clip(shape).background(color)
|
||||
.border(1.dp, pal.line2, shape).glideBorder(hot, shape, pal.signal)
|
||||
.hoverable(src).clickable(interactionSource = src, indication = androidx.compose.foundation.LocalIndication.current, role = Role.Button, onClick = onClick)
|
||||
.controllerConfirm(onClick = onClick)
|
||||
.semantics { contentDescription = description },
|
||||
)
|
||||
}
|
||||
|
||||
/** Colour wheel (touch), hue / saturation / brightness sliders (controller and touch) and a hex box for one colour. */
|
||||
@Composable
|
||||
internal fun ColorPickerDialog(title: String, initial: Int, onDismiss: () -> Unit, onApply: (Int) -> Unit) {
|
||||
val shown = rememberShown(onDismiss)
|
||||
val close = { shown.targetState = false }
|
||||
val start = remember { ThemeColors.toHsv(initial) }
|
||||
var hue by remember { mutableStateOf(start.h) }
|
||||
var sat by remember { mutableStateOf(start.s) }
|
||||
var value by remember { mutableStateOf(start.v) }
|
||||
var hexText by remember { mutableStateOf(ThemeColors.hex(initial)) }
|
||||
val current = ThemeColors.fromHsv(hue, sat, value)
|
||||
val first = remember { FocusRequester() }
|
||||
LaunchedEffect(Unit) { focusSoon { first } }
|
||||
fun picked(h: Float = hue, s: Float = sat, v: Float = value) {
|
||||
hue = h.coerceIn(0f, 360f); sat = s.coerceIn(0f, 1f); value = v.coerceIn(0f, 1f)
|
||||
hexText = ThemeColors.hex(ThemeColors.fromHsv(hue, sat, value))
|
||||
}
|
||||
AppDialog(shown, close, "colorPicker", wide = false, maxWidth = 460.dp) {
|
||||
DialogTitleRow(title, close)
|
||||
Row(horizontalArrangement = Arrangement.spacedBy(14.dp), verticalAlignment = Alignment.CenterVertically, modifier = Modifier.fillMaxWidth()) {
|
||||
ColorWheel(hue, sat, value) { h, s -> picked(h = h, s = s) }
|
||||
Row(horizontalArrangement = Arrangement.spacedBy(8.dp)) {
|
||||
Swatch(Color(initial))
|
||||
Swatch(Color(current))
|
||||
}
|
||||
}
|
||||
ValueSlider(hue.toInt(), 0..360, step = 5, enabled = true, label = stringResource(R.string.theme_color_hue), format = { "$it°" },
|
||||
modifier = Modifier.focusRequester(first)) { picked(h = it.toFloat()) }
|
||||
ValueSlider((sat * 100).toInt(), 0..100, step = 2, enabled = true, label = stringResource(R.string.theme_color_saturation), format = { "$it%" }) { picked(s = it / 100f) }
|
||||
ValueSlider((value * 100).toInt(), 0..100, step = 2, enabled = true, label = stringResource(R.string.theme_color_brightness), format = { "$it%" }) { picked(v = it / 100f) }
|
||||
AdbTextField(
|
||||
value = hexText,
|
||||
onValueChange = { text ->
|
||||
hexText = text
|
||||
ThemeColors.parseHex(text)?.let { argb -> ThemeColors.toHsv(argb).let { hsv -> hue = hsv.h; sat = hsv.s; value = hsv.v } }
|
||||
},
|
||||
label = "", keyboardType = KeyboardType.Ascii, imeAction = ImeAction.Done, placeholder = stringResource(R.string.theme_color_hex),
|
||||
onDone = { ThemeColors.parseHex(hexText)?.let { onApply(it); close() } },
|
||||
)
|
||||
Row(horizontalArrangement = Arrangement.spacedBy(8.dp), modifier = Modifier.fillMaxWidth()) {
|
||||
SecondaryButton(stringResource(R.string.common_cancel), modifier = Modifier.weight(1f), onClick = close)
|
||||
PrimaryButton(stringResource(R.string.common_ok), enabled = ThemeColors.parseHex(hexText) != null, modifier = Modifier.weight(1f)) {
|
||||
ThemeColors.parseHex(hexText)?.let { onApply(it); close() }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun Swatch(color: Color) {
|
||||
val shape = RoundedCornerShape(10.dp)
|
||||
Box(Modifier.size(48.dp).clip(shape).background(color).border(1.dp, LocalPalette.current.line2, shape))
|
||||
}
|
||||
|
||||
/** Hue around the circle and saturation out from the middle, at full brightness; brightness has its own slider. */
|
||||
@Composable
|
||||
private fun ColorWheel(hue: Float, sat: Float, value: Float, onPick: (hue: Float, sat: Float) -> Unit) {
|
||||
val rim = MaterialTheme.colorScheme.onBackground
|
||||
val size = 168.dp
|
||||
fun at(offset: Offset, side: Float) {
|
||||
val center = side / 2f
|
||||
val dx = offset.x - center
|
||||
val dy = offset.y - center
|
||||
val angle = Math.toDegrees(atan2(dy, dx).toDouble()).toFloat()
|
||||
onPick((angle + 360f) % 360f, min(1f, hypot(dx, dy) / center))
|
||||
}
|
||||
Canvas(
|
||||
Modifier.size(size)
|
||||
.pointerInput(Unit) { detectTapGestures { at(it, this.size.width.toFloat()) } }
|
||||
.pointerInput(Unit) { detectDragGestures { change, _ -> at(change.position, this.size.width.toFloat()); change.consume() } },
|
||||
) {
|
||||
val radius = this.size.minDimension / 2f
|
||||
drawCircle(Brush.sweepGradient(List(7) { Color.hsv(it * 60f, 1f, 1f) }), radius)
|
||||
drawCircle(Brush.radialGradient(listOf(Color.White, Color.Transparent), radius = radius), radius)
|
||||
val theta = Math.toRadians(hue.toDouble())
|
||||
val marker = Offset(radius + (kotlin.math.cos(theta) * sat * radius).toFloat(), radius + (kotlin.math.sin(theta) * sat * radius).toFloat())
|
||||
drawCircle(Color.Black.copy(alpha = 0.55f), 9.dp.toPx(), marker)
|
||||
drawCircle(rim, 7.dp.toPx(), marker)
|
||||
drawCircle(Color.hsv(hue, sat, value), 5.dp.toPx(), marker)
|
||||
}
|
||||
}
|
||||
@@ -359,6 +359,7 @@ internal fun SetupPanel(
|
||||
}
|
||||
}
|
||||
}
|
||||
if (s.theme == Themes.GRADIENT) GradientColorRows()
|
||||
ChoiceRow(
|
||||
host, "app-scale", stringResource(R.string.setup_app_scale), stringResource(R.string.setup_app_scale_hint),
|
||||
com.droiddeck.launcher.core.AppUiPrefs.scales.map { percent ->
|
||||
@@ -790,3 +791,21 @@ private fun LanguageRow(host: MenuHost, chosen: String, onPick: (String) -> Unit
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** The two colours of the Gradient theme, each a small square that opens the colour picker. */
|
||||
@Composable
|
||||
private fun GradientColorRows() {
|
||||
val ctx = androidx.compose.ui.platform.LocalContext.current.applicationContext
|
||||
val (primary, secondary) = Themes.gradientColors
|
||||
var picking by remember { androidx.compose.runtime.mutableIntStateOf(0) }
|
||||
val primaryLabel = stringResource(R.string.theme_gradient_primary)
|
||||
val secondaryLabel = stringResource(R.string.theme_gradient_secondary)
|
||||
SettingsRow(primaryLabel, null) { ColorCube(androidx.compose.ui.graphics.Color(primary), primaryLabel) { picking = 1 } }
|
||||
SettingsRow(secondaryLabel, null) { ColorCube(androidx.compose.ui.graphics.Color(secondary), secondaryLabel) { picking = 2 } }
|
||||
if (picking != 0) ColorPickerDialog(
|
||||
if (picking == 1) primaryLabel else secondaryLabel, if (picking == 1) primary else secondary,
|
||||
onDismiss = { picking = 0 },
|
||||
) { argb ->
|
||||
if (picking == 1) Themes.setGradient(ctx, argb, secondary) else Themes.setGradient(ctx, primary, argb)
|
||||
}
|
||||
}
|
||||
@@ -6,6 +6,10 @@ import androidx.compose.material3.darkColorScheme
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.CompositionLocalProvider
|
||||
import androidx.compose.runtime.staticCompositionLocalOf
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.setValue
|
||||
import android.content.Context
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.luminance
|
||||
@@ -29,6 +33,30 @@ object Themes {
|
||||
const val PAPER = "paper"
|
||||
const val ICON_BLUE = "blue"
|
||||
const val ELECTRIC = "electric"
|
||||
const val GRADIENT = "gradient"
|
||||
|
||||
const val DEFAULT_PRIMARY = 0xFF8B5CF6.toInt()
|
||||
const val DEFAULT_SECONDARY = 0xFF22D3EE.toInt()
|
||||
|
||||
/** The two colours of the custom Gradient theme: primary, then secondary. Changing them restyles the app at once. */
|
||||
var gradientColors by mutableStateOf(DEFAULT_PRIMARY to DEFAULT_SECONDARY)
|
||||
private set
|
||||
|
||||
fun loadGradient(context: Context) {
|
||||
gradientColors = SessionPrefs.gradientColors(context)
|
||||
}
|
||||
|
||||
fun setGradient(context: Context, primary: Int, secondary: Int) {
|
||||
SessionPrefs.setGradientColors(context, primary, secondary)
|
||||
gradientColors = primary to secondary
|
||||
}
|
||||
|
||||
/** The theme the person chose, with the custom colours read first; for code that is not in a composition. */
|
||||
fun current(context: Context): Palette {
|
||||
val id = SessionPrefs.theme(context)
|
||||
if (id == GRADIENT) loadGradient(context)
|
||||
return byId(id)
|
||||
}
|
||||
|
||||
val all: List<Palette> = listOf(
|
||||
Palette(
|
||||
@@ -59,9 +87,13 @@ object Themes {
|
||||
primary = Color(0xFF2E86FF), primary2 = Color(0xFF2684FF), onPrimary = Color(0xFF03111F), signal = Color(0xFF2E86FF),
|
||||
good = Color(0xFF4CD37F),
|
||||
),
|
||||
ThemeColors.palette(DEFAULT_PRIMARY, DEFAULT_SECONDARY, R.string.theme_gradient, R.string.theme_gradient_detail),
|
||||
)
|
||||
|
||||
fun byId(id: String): Palette = all.firstOrNull { it.id == id } ?: all[0]
|
||||
fun byId(id: String): Palette {
|
||||
if (id == GRADIENT) return ThemeColors.palette(gradientColors.first, gradientColors.second, R.string.theme_gradient, R.string.theme_gradient_detail)
|
||||
return all.firstOrNull { it.id == id } ?: all[0]
|
||||
}
|
||||
}
|
||||
|
||||
val LocalPalette = staticCompositionLocalOf { Themes.byId(Themes.GRAPHITE) }
|
||||
|
||||
@@ -0,0 +1,157 @@
|
||||
package com.droiddeck.launcher.ui
|
||||
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.luminance
|
||||
import androidx.compose.ui.graphics.toArgb
|
||||
import kotlin.math.max
|
||||
import kotlin.math.min
|
||||
import kotlin.math.roundToInt
|
||||
|
||||
/** Colour maths for the custom gradient theme: hue, saturation and brightness in, a readable palette out. */
|
||||
internal object ThemeColors {
|
||||
/** Hue 0..360, saturation and brightness 0..1. */
|
||||
class Hsv(val h: Float, val s: Float, val v: Float)
|
||||
|
||||
fun toHsv(argb: Int): Hsv {
|
||||
val r = (argb shr 16 and 0xFF) / 255f
|
||||
val g = (argb shr 8 and 0xFF) / 255f
|
||||
val b = (argb and 0xFF) / 255f
|
||||
val top = max(r, max(g, b))
|
||||
val delta = top - min(r, min(g, b))
|
||||
val hue = when {
|
||||
delta == 0f -> 0f
|
||||
top == r -> 60f * (((g - b) / delta) % 6f)
|
||||
top == g -> 60f * ((b - r) / delta + 2f)
|
||||
else -> 60f * ((r - g) / delta + 4f)
|
||||
}
|
||||
return Hsv(if (hue < 0f) hue + 360f else hue, if (top == 0f) 0f else delta / top, top)
|
||||
}
|
||||
|
||||
fun fromHsv(h: Float, s: Float, v: Float): Int =
|
||||
Color.hsv(h.mod(360f), s.coerceIn(0f, 1f), v.coerceIn(0f, 1f)).toArgb()
|
||||
|
||||
fun hex(argb: Int): String = "#%06X".format(argb and 0xFFFFFF)
|
||||
|
||||
/** `#RRGGBB`, `RRGGBB` or `#RGB`; null for anything else. */
|
||||
fun parseHex(text: String): Int? {
|
||||
val digits = text.trim().removePrefix("#")
|
||||
if (!digits.all { it in '0'..'9' || it in 'a'..'f' || it in 'A'..'F' }) return null
|
||||
val full = when (digits.length) {
|
||||
3 -> digits.map { "$it$it" }.joinToString("")
|
||||
6 -> digits
|
||||
else -> return null
|
||||
}
|
||||
return 0xFF000000.toInt() or full.toInt(16)
|
||||
}
|
||||
|
||||
private const val MIN_LUMINANCE = 0.10f
|
||||
|
||||
/** The colour, made brighter (then paler, for a deep blue that brightness alone cannot lift) when it is too dark to show on the dark background. */
|
||||
fun readable(argb: Int): Int {
|
||||
if (Color(argb).luminance() >= MIN_LUMINANCE) return argb or 0xFF000000.toInt()
|
||||
val hsv = toHsv(argb)
|
||||
var v = hsv.v
|
||||
var s = hsv.s
|
||||
var out = argb
|
||||
while (v < 1f && Color(out).luminance() < MIN_LUMINANCE) {
|
||||
v = min(1f, v + 0.04f)
|
||||
out = fromHsv(hsv.h, s, v)
|
||||
}
|
||||
while (s > 0f && Color(out).luminance() < MIN_LUMINANCE) {
|
||||
s = max(0f, s - 0.04f)
|
||||
out = fromHsv(hsv.h, s, v)
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
/** A dark neutral tinted with the primary's hue; plain greys stay grey. */
|
||||
fun tint(primary: Int, saturation: Float, brightness: Float): Color {
|
||||
val hsv = toHsv(primary)
|
||||
val strength = (hsv.s / 0.35f).coerceIn(0f, 1f)
|
||||
return Color(fromHsv(hsv.h, saturation * strength, brightness))
|
||||
}
|
||||
|
||||
private val DARK_INK = Color(0xFF03111F)
|
||||
|
||||
private fun contrast(a: Color, b: Color): Float {
|
||||
val x = a.luminance()
|
||||
val y = b.luminance()
|
||||
return (max(x, y) + 0.05f) / (min(x, y) + 0.05f)
|
||||
}
|
||||
|
||||
/** Dark or white text, whichever reads better on the worse of the two gradient colours. */
|
||||
internal fun inkFor(first: Int, second: Int): Color {
|
||||
fun worst(ink: Color) = min(contrast(ink, Color(first)), contrast(ink, Color(second)))
|
||||
return if (worst(DARK_INK) >= worst(Color.White)) DARK_INK else Color.White
|
||||
}
|
||||
|
||||
private const val MIN_CONTRAST = 4.5f
|
||||
|
||||
/** The colour nudged just enough, lighter for dark text and darker for white text, to give [ink] a readable contrast on it. */
|
||||
private fun fitTo(ink: Color, argb: Int): Int {
|
||||
fun short(color: Int) = contrast(ink, Color(color)) < MIN_CONTRAST
|
||||
if (!short(argb)) return argb
|
||||
val hsv = toHsv(argb)
|
||||
var v = hsv.v
|
||||
var s = hsv.s
|
||||
var out = argb
|
||||
if (ink == DARK_INK) {
|
||||
while (v < 1f && short(out)) { v = min(1f, v + 0.04f); out = fromHsv(hsv.h, s, v) }
|
||||
while (s > 0f && short(out)) { s = max(0f, s - 0.04f); out = fromHsv(hsv.h, s, v) }
|
||||
} else {
|
||||
while (v > 0f && short(out)) { v = max(0f, v - 0.04f); out = fromHsv(hsv.h, s, v) }
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
private fun gradientColor(first: Int, second: Int, fraction: Float): Int {
|
||||
fun channel(shift: Int): Int {
|
||||
val a = first shr shift and 0xFF
|
||||
val b = second shr shift and 0xFF
|
||||
return (a + (b - a) * fraction).roundToInt().coerceIn(0, 255)
|
||||
}
|
||||
return (0xFF shl 24) or (channel(16) shl 16) or (channel(8) shl 8) or channel(0)
|
||||
}
|
||||
|
||||
private fun gradientFits(ink: Color, first: Int, second: Int): Boolean =
|
||||
(0..32).all { step ->
|
||||
val color = gradientColor(first, second, step / 32f)
|
||||
contrast(ink, Color(color)) >= MIN_CONTRAST + 0.02f
|
||||
}
|
||||
|
||||
private fun moveTowardContrast(ink: Color, argb: Int): Int {
|
||||
val hsv = toHsv(argb)
|
||||
return if (ink == DARK_INK) {
|
||||
when {
|
||||
hsv.v < 1f -> fromHsv(hsv.h, hsv.s, min(1f, hsv.v + 0.04f))
|
||||
hsv.s > 0f -> fromHsv(hsv.h, max(0f, hsv.s - 0.04f), hsv.v)
|
||||
else -> argb
|
||||
}
|
||||
} else {
|
||||
fromHsv(hsv.h, hsv.s, max(0f, hsv.v - 0.04f))
|
||||
}
|
||||
}
|
||||
|
||||
fun palette(primary: Int, secondary: Int, label: Int, detail: Int): Palette {
|
||||
val seen = readable(primary)
|
||||
val seenSecond = readable(secondary)
|
||||
val ink = inkFor(seen, seenSecond)
|
||||
var first = fitTo(ink, seen)
|
||||
var second = fitTo(ink, seenSecond)
|
||||
while (!gradientFits(ink, first, second)) {
|
||||
val nextFirst = moveTowardContrast(ink, first)
|
||||
val nextSecond = moveTowardContrast(ink, second)
|
||||
if (nextFirst == first && nextSecond == second) break
|
||||
first = nextFirst
|
||||
second = nextSecond
|
||||
}
|
||||
return Palette(
|
||||
Themes.GRADIENT, label, detail,
|
||||
background = tint(first, 0.50f, 0.045f), surface = tint(first, 0.45f, 0.075f), surfaceVariant = tint(first, 0.42f, 0.115f),
|
||||
line = tint(first, 0.40f, 0.16f), line2 = tint(first, 0.36f, 0.22f),
|
||||
onBackground = tint(first, 0.05f, 0.97f), onSurfaceVariant = tint(first, 0.16f, 0.68f),
|
||||
primary = Color(first), primary2 = Color(second), onPrimary = ink, signal = Color(first),
|
||||
good = Color(0xFF4CD37F),
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -16,7 +16,7 @@ import com.droiddeck.launcher.session.SessionPrefs
|
||||
internal class TrackingRecoveryView(context: Context) : View(context) {
|
||||
private var recovery: TrackingRecovery? = null
|
||||
private var stereo = false
|
||||
private var palette = Themes.byId(SessionPrefs.theme(context))
|
||||
private var palette = Themes.current(context)
|
||||
private val paint = Paint(Paint.ANTI_ALIAS_FLAG)
|
||||
private var blocks = emptyList<StaticLayout>()
|
||||
|
||||
@@ -26,7 +26,7 @@ internal class TrackingRecoveryView(context: Context) : View(context) {
|
||||
importantForAccessibility = IMPORTANT_FOR_ACCESSIBILITY_YES
|
||||
}
|
||||
|
||||
fun update(state: TrackingRecovery?, stereo: Boolean, palette: Palette = Themes.byId(SessionPrefs.theme(context))) {
|
||||
fun update(state: TrackingRecovery?, stereo: Boolean, palette: Palette = Themes.current(context)) {
|
||||
if (recovery == state && this.stereo == stereo && this.palette == palette) return
|
||||
recovery = state
|
||||
this.stereo = stereo
|
||||
|
||||
@@ -1460,6 +1460,14 @@
|
||||
<string name="theme_icon_blue_detail">خلفية سوداء ونص أبيض، والأزرق لكل عنصر محدَّد أو مُركَّز عليه أو مضغوط.</string>
|
||||
<string name="theme_electric">كحلي كهربائي</string>
|
||||
<string name="theme_electric_detail">أزرق أكثر سطوعًا، على أسطح تميل إلى الكحلي بدلاً من الرمادي.</string>
|
||||
<string name="theme_gradient">تدرج لوني</string>
|
||||
<string name="theme_gradient_detail">لونك الأساسي والثانوي، ممزوجان على الأزرار وعناصر التمييز.</string>
|
||||
<string name="theme_gradient_primary">الأساسي</string>
|
||||
<string name="theme_gradient_secondary">الثانوي</string>
|
||||
<string name="theme_color_hue">درجة اللون</string>
|
||||
<string name="theme_color_saturation">التشبع</string>
|
||||
<string name="theme_color_brightness">السطوع</string>
|
||||
<string name="theme_color_hex">لون سداسي (Hex)</string>
|
||||
<string name="pckb_key_esc">Esc</string>
|
||||
<string name="pckb_key_ins">Ins</string>
|
||||
<string name="pckb_key_del">Del</string>
|
||||
|
||||
@@ -1468,6 +1468,14 @@
|
||||
<string name="theme_icon_blue_detail">Fondo negro, texto blanco y el azul para todo lo seleccionado, enfocado o presionado.</string>
|
||||
<string name="theme_electric">Azul marino eléctrico</string>
|
||||
<string name="theme_electric_detail">Un azul más vivo, sobre superficies que tiran a azul marino en vez de gris.</string>
|
||||
<string name="theme_gradient">Degradado</string>
|
||||
<string name="theme_gradient_detail">Tus propios colores primario y secundario, combinados en botones y resaltados.</string>
|
||||
<string name="theme_gradient_primary">Primario</string>
|
||||
<string name="theme_gradient_secondary">Secundario</string>
|
||||
<string name="theme_color_hue">Tono</string>
|
||||
<string name="theme_color_saturation">Saturación</string>
|
||||
<string name="theme_color_brightness">Brillo</string>
|
||||
<string name="theme_color_hex">Color hexadecimal</string>
|
||||
<string name="pckb_key_esc">Esc</string>
|
||||
<string name="pckb_key_ins">Insert</string>
|
||||
<string name="pckb_key_del">Supr</string>
|
||||
|
||||
@@ -1404,6 +1404,14 @@
|
||||
<string name="theme_icon_blue_detail">Черен фон, бял текст, синьото за всичко избрано, на фокус или натиснато.</string>
|
||||
<string name="theme_electric">Яркосиньо</string>
|
||||
<string name="theme_electric_detail">По-яркото синьо, върху повърхности, по-близки до тъмносиньо, вместо сиво.</string>
|
||||
<string name="theme_gradient">Градиент</string>
|
||||
<string name="theme_gradient_detail">Вашите основен и вторичен цвят, смесени в бутоните и акцентите.</string>
|
||||
<string name="theme_gradient_primary">Основен</string>
|
||||
<string name="theme_gradient_secondary">Вторичен</string>
|
||||
<string name="theme_color_hue">Нюанс</string>
|
||||
<string name="theme_color_saturation">Наситеност</string>
|
||||
<string name="theme_color_brightness">Яркост</string>
|
||||
<string name="theme_color_hex">Hex цвят</string>
|
||||
<string name="pckb_key_esc">Esc</string>
|
||||
<string name="pckb_key_ins">Ins</string>
|
||||
<string name="pckb_key_del">Del</string>
|
||||
|
||||
@@ -1432,6 +1432,14 @@
|
||||
<string name="theme_icon_blue_detail">Černé pozadí, bílé písmo, modrá pro vše vybrané, zaměřené nebo stisknuté.</string>
|
||||
<string name="theme_electric">Elektrická modř</string>
|
||||
<string name="theme_electric_detail">Jasnější modrá na povrchách, které jsou spíše tmavomodré než šedé.</string>
|
||||
<string name="theme_gradient">Přechod</string>
|
||||
<string name="theme_gradient_detail">Vaše vlastní primární a sekundární barva, prolnuté na tlačítkách a zvýrazněních.</string>
|
||||
<string name="theme_gradient_primary">Primární</string>
|
||||
<string name="theme_gradient_secondary">Sekundární</string>
|
||||
<string name="theme_color_hue">Odstín</string>
|
||||
<string name="theme_color_saturation">Sytost</string>
|
||||
<string name="theme_color_brightness">Jas</string>
|
||||
<string name="theme_color_hex">Barva hex</string>
|
||||
<string name="pckb_key_esc">Esc</string>
|
||||
<string name="pckb_key_ins">Ins</string>
|
||||
<string name="pckb_key_del">Del</string>
|
||||
|
||||
@@ -1404,6 +1404,14 @@
|
||||
<string name="theme_icon_blue_detail">Sort baggrund, hvid skrift, blå til alt, der er valgt, fokuseret eller trykket.</string>
|
||||
<string name="theme_electric">Elektrisk marineblå</string>
|
||||
<string name="theme_electric_detail">Den blå er klarere, på overflader der trækker mod marineblåt i stedet for gråt.</string>
|
||||
<string name="theme_gradient">Gradient</string>
|
||||
<string name="theme_gradient_detail">Dine egne primære og sekundære farver, blandet på knapper og fremhævninger.</string>
|
||||
<string name="theme_gradient_primary">Primær</string>
|
||||
<string name="theme_gradient_secondary">Sekundær</string>
|
||||
<string name="theme_color_hue">Farvetone</string>
|
||||
<string name="theme_color_saturation">Mætning</string>
|
||||
<string name="theme_color_brightness">Lysstyrke</string>
|
||||
<string name="theme_color_hex">Hex-farve</string>
|
||||
<string name="pckb_key_esc">Esc</string>
|
||||
<string name="pckb_key_ins">Ins</string>
|
||||
<string name="pckb_key_del">Del</string>
|
||||
|
||||
@@ -1393,6 +1393,14 @@
|
||||
<string name="theme_icon_blue_detail">Schwarzer Grund, weiße Schrift, das Blau für alles Ausgewählte, Fokussierte oder Gedrückte.</string>
|
||||
<string name="theme_electric">Elektrisches Marineblau</string>
|
||||
<string name="theme_electric_detail">Das Blau heller, auf Flächen, die eher zu Marineblau als zu Grau tendieren.</string>
|
||||
<string name="theme_gradient">Farbverlauf</string>
|
||||
<string name="theme_gradient_detail">Eigene Primär- und Sekundärfarbe, als Verlauf auf Schaltflächen und Hervorhebungen.</string>
|
||||
<string name="theme_gradient_primary">Primär</string>
|
||||
<string name="theme_gradient_secondary">Sekundär</string>
|
||||
<string name="theme_color_hue">Farbton</string>
|
||||
<string name="theme_color_saturation">Sättigung</string>
|
||||
<string name="theme_color_brightness">Helligkeit</string>
|
||||
<string name="theme_color_hex">Hex-Farbe</string>
|
||||
<string name="pckb_key_esc">Esc</string>
|
||||
<string name="pckb_key_ins">Einfg</string>
|
||||
<string name="pckb_key_del">Entf</string>
|
||||
|
||||
@@ -1404,6 +1404,14 @@
|
||||
<string name="theme_icon_blue_detail">Μαύρο φόντο, λευκά γράμματα, το μπλε για ό,τι είναι επιλεγμένο, εστιασμένο ή πατημένο.</string>
|
||||
<string name="theme_electric">Ηλεκτρικό ναυτικό μπλε</string>
|
||||
<string name="theme_electric_detail">Το μπλε πιο έντονο, σε επιφάνειες που τείνουν προς το ναυτικό μπλε αντί για γκρι.</string>
|
||||
<string name="theme_gradient">Διαβάθμιση</string>
|
||||
<string name="theme_gradient_detail">Δικά σας πρωτεύον και δευτερεύον χρώμα, σε μίξη στα κουμπιά και τις επισημάνσεις.</string>
|
||||
<string name="theme_gradient_primary">Πρωτεύον</string>
|
||||
<string name="theme_gradient_secondary">Δευτερεύον</string>
|
||||
<string name="theme_color_hue">Απόχρωση</string>
|
||||
<string name="theme_color_saturation">Κορεσμός</string>
|
||||
<string name="theme_color_brightness">Φωτεινότητα</string>
|
||||
<string name="theme_color_hex">Χρώμα hex</string>
|
||||
<string name="pckb_key_esc">Esc</string>
|
||||
<string name="pckb_key_ins">Ins</string>
|
||||
<string name="pckb_key_del">Del</string>
|
||||
|
||||
@@ -1417,6 +1417,14 @@
|
||||
<string name="theme_icon_blue_detail">Fondo negro, texto blanco y el azul para todo lo seleccionado, enfocado o pulsado.</string>
|
||||
<string name="theme_electric">Azul marino eléctrico</string>
|
||||
<string name="theme_electric_detail">Un azul más vivo, sobre superficies que tiran a azul marino en vez de gris.</string>
|
||||
<string name="theme_gradient">Degradado</string>
|
||||
<string name="theme_gradient_detail">Tus propios colores primario y secundario, combinados en botones y resaltados.</string>
|
||||
<string name="theme_gradient_primary">Primario</string>
|
||||
<string name="theme_gradient_secondary">Secundario</string>
|
||||
<string name="theme_color_hue">Tono</string>
|
||||
<string name="theme_color_saturation">Saturación</string>
|
||||
<string name="theme_color_brightness">Brillo</string>
|
||||
<string name="theme_color_hex">Color hexadecimal</string>
|
||||
<string name="pckb_key_esc">Esc</string>
|
||||
<string name="pckb_key_ins">Insert</string>
|
||||
<string name="pckb_key_del">Supr</string>
|
||||
|
||||
@@ -1404,6 +1404,14 @@
|
||||
<string name="theme_icon_blue_detail">Musta pohja, valkoinen teksti, sininen kaikessa valitussa, kohdistetussa tai painetussa.</string>
|
||||
<string name="theme_electric">Sähköinen laivastonsininen</string>
|
||||
<string name="theme_electric_detail">Sininen kirkkaampana pinnoilla, jotka taittuvat harmaan sijaan laivastonsiniseen.</string>
|
||||
<string name="theme_gradient">Liukuväri</string>
|
||||
<string name="theme_gradient_detail">Omat ensisijainen ja toissijainen värisi, sulautettuina painikkeisiin ja korostuksiin.</string>
|
||||
<string name="theme_gradient_primary">Ensisijainen</string>
|
||||
<string name="theme_gradient_secondary">Toissijainen</string>
|
||||
<string name="theme_color_hue">Sävy</string>
|
||||
<string name="theme_color_saturation">Kylläisyys</string>
|
||||
<string name="theme_color_brightness">Kirkkaus</string>
|
||||
<string name="theme_color_hex">Hex-väri</string>
|
||||
<string name="pckb_key_esc">Esc</string>
|
||||
<string name="pckb_key_ins">Ins</string>
|
||||
<string name="pckb_key_del">Del</string>
|
||||
|
||||
@@ -1417,6 +1417,14 @@
|
||||
<string name="theme_icon_blue_detail">Fond noir, texte blanc, et le bleu pour tout élément sélectionné, ciblé ou pressé.</string>
|
||||
<string name="theme_electric">Marine électrique</string>
|
||||
<string name="theme_electric_detail">Un bleu plus vif, sur des surfaces qui tirent vers le marine plutôt que vers le gris.</string>
|
||||
<string name="theme_gradient">Dégradé</string>
|
||||
<string name="theme_gradient_detail">Vos propres couleurs primaire et secondaire, fondues sur les boutons et les éléments en surbrillance.</string>
|
||||
<string name="theme_gradient_primary">Primaire</string>
|
||||
<string name="theme_gradient_secondary">Secondaire</string>
|
||||
<string name="theme_color_hue">Teinte</string>
|
||||
<string name="theme_color_saturation">Saturation</string>
|
||||
<string name="theme_color_brightness">Luminosité</string>
|
||||
<string name="theme_color_hex">Couleur hex</string>
|
||||
<string name="pckb_key_esc">Échap</string>
|
||||
<string name="pckb_key_ins">Inser</string>
|
||||
<string name="pckb_key_del">Suppr</string>
|
||||
|
||||
@@ -1404,6 +1404,14 @@
|
||||
<string name="theme_icon_blue_detail">काली ज़मीन, सफ़ेद टाइप, चुने, फ़ोकस या दबाए गए हर चीज़ के लिए ब्लू रंग।</string>
|
||||
<string name="theme_electric">इलेक्ट्रिक नेवी</string>
|
||||
<string name="theme_electric_detail">ब्लू रंग ज़्यादा चमकीला, उन सतहों पर जो ग्रे के बजाय नेवी की ओर झुकती हैं।</string>
|
||||
<string name="theme_gradient">ग्रेडिएंट</string>
|
||||
<string name="theme_gradient_detail">आपके अपने प्राथमिक और द्वितीयक रंग, बटनों और हाइलाइट पर मिश्रित।</string>
|
||||
<string name="theme_gradient_primary">प्राथमिक</string>
|
||||
<string name="theme_gradient_secondary">द्वितीयक</string>
|
||||
<string name="theme_color_hue">रंगत</string>
|
||||
<string name="theme_color_saturation">संतृप्ति</string>
|
||||
<string name="theme_color_brightness">चमक</string>
|
||||
<string name="theme_color_hex">हेक्स रंग</string>
|
||||
<string name="pckb_key_esc">Esc</string>
|
||||
<string name="pckb_key_ins">Ins</string>
|
||||
<string name="pckb_key_del">Del</string>
|
||||
|
||||
@@ -1404,6 +1404,14 @@
|
||||
<string name="theme_icon_blue_detail">Fekete alap, fehér betűk, a kék minden kijelölt, fókuszált vagy lenyomott elemhez.</string>
|
||||
<string name="theme_electric">Elektromos tengerészkék</string>
|
||||
<string name="theme_electric_detail">Fényesebb kék, szürke helyett tengerészkék felületeken.</string>
|
||||
<string name="theme_gradient">Színátmenet</string>
|
||||
<string name="theme_gradient_detail">Saját elsődleges és másodlagos színed, átmenettel a gombokon és a kiemeléseken.</string>
|
||||
<string name="theme_gradient_primary">Elsődleges</string>
|
||||
<string name="theme_gradient_secondary">Másodlagos</string>
|
||||
<string name="theme_color_hue">Színárnyalat</string>
|
||||
<string name="theme_color_saturation">Telítettség</string>
|
||||
<string name="theme_color_brightness">Fényerő</string>
|
||||
<string name="theme_color_hex">Hex szín</string>
|
||||
<string name="pckb_key_esc">Esc</string>
|
||||
<string name="pckb_key_ins">Ins</string>
|
||||
<string name="pckb_key_del">Del</string>
|
||||
|
||||
@@ -1390,6 +1390,14 @@
|
||||
<string name="theme_icon_blue_detail">Dasar hitam, tipe putih, biru untuk semua yang dipilih, difokuskan, atau ditekan.</string>
|
||||
<string name="theme_electric">Navy elektrik</string>
|
||||
<string name="theme_electric_detail">Biru yang lebih cerah, pada permukaan yang condong ke navy, bukan abu-abu.</string>
|
||||
<string name="theme_gradient">Gradasi</string>
|
||||
<string name="theme_gradient_detail">Warna primer dan sekunder pilihan Anda, dipadukan pada tombol dan sorotan.</string>
|
||||
<string name="theme_gradient_primary">Primer</string>
|
||||
<string name="theme_gradient_secondary">Sekunder</string>
|
||||
<string name="theme_color_hue">Rona</string>
|
||||
<string name="theme_color_saturation">Saturasi</string>
|
||||
<string name="theme_color_brightness">Kecerahan</string>
|
||||
<string name="theme_color_hex">Warna hex</string>
|
||||
<string name="pckb_key_esc">Esc</string>
|
||||
<string name="pckb_key_ins">Ins</string>
|
||||
<string name="pckb_key_del">Del</string>
|
||||
|
||||
@@ -1407,6 +1407,14 @@
|
||||
<string name="theme_icon_blue_detail">Fondo nero, testo bianco, il blu per tutto ciò che è selezionato, attivo o premuto.</string>
|
||||
<string name="theme_electric">Blu elettrico</string>
|
||||
<string name="theme_electric_detail">Il blu più brillante, su superfici che tendono al blu navy invece che al grigio.</string>
|
||||
<string name="theme_gradient">Gradiente</string>
|
||||
<string name="theme_gradient_detail">I tuoi colori primario e secondario, sfumati su pulsanti ed evidenziazioni.</string>
|
||||
<string name="theme_gradient_primary">Primario</string>
|
||||
<string name="theme_gradient_secondary">Secondario</string>
|
||||
<string name="theme_color_hue">Tonalità</string>
|
||||
<string name="theme_color_saturation">Saturazione</string>
|
||||
<string name="theme_color_brightness">Luminosità</string>
|
||||
<string name="theme_color_hex">Colore esadecimale</string>
|
||||
<string name="pckb_key_esc">Esc</string>
|
||||
<string name="pckb_key_ins">Ins</string>
|
||||
<string name="pckb_key_del">Canc</string>
|
||||
|
||||
@@ -1392,6 +1392,14 @@
|
||||
<string name="theme_icon_blue_detail">黒の背景に白の文字、選択・フォーカス・押下時には青を使用します。</string>
|
||||
<string name="theme_electric">エレクトリックネイビー</string>
|
||||
<string name="theme_electric_detail">より明るい青を、グレーではなくネイビー寄りの画面に使用します。</string>
|
||||
<string name="theme_gradient">グラデーション</string>
|
||||
<string name="theme_gradient_detail">自分で選んだプライマリとセカンダリの色を、ボタンやハイライトにグラデーションで使います。</string>
|
||||
<string name="theme_gradient_primary">プライマリ</string>
|
||||
<string name="theme_gradient_secondary">セカンダリ</string>
|
||||
<string name="theme_color_hue">色相</string>
|
||||
<string name="theme_color_saturation">彩度</string>
|
||||
<string name="theme_color_brightness">明度</string>
|
||||
<string name="theme_color_hex">16進カラー</string>
|
||||
<string name="pckb_key_esc">Esc</string>
|
||||
<string name="pckb_key_ins">Ins</string>
|
||||
<string name="pckb_key_del">Del</string>
|
||||
|
||||
@@ -1392,6 +1392,14 @@
|
||||
<string name="theme_icon_blue_detail">검은색 배경에 흰색 글자, 선택·포커스·누름 상태에는 파란색을 사용합니다.</string>
|
||||
<string name="theme_electric">일렉트릭 네이비</string>
|
||||
<string name="theme_electric_detail">회색 대신 네이비 톤의 화면에 더 밝은 파란색을 사용합니다.</string>
|
||||
<string name="theme_gradient">그라데이션</string>
|
||||
<string name="theme_gradient_detail">직접 고른 기본색과 보조색이 버튼과 강조 표시에 섞여 적용됩니다.</string>
|
||||
<string name="theme_gradient_primary">기본색</string>
|
||||
<string name="theme_gradient_secondary">보조색</string>
|
||||
<string name="theme_color_hue">색조</string>
|
||||
<string name="theme_color_saturation">채도</string>
|
||||
<string name="theme_color_brightness">명도</string>
|
||||
<string name="theme_color_hex">16진수 색상</string>
|
||||
<string name="pckb_key_esc">Esc</string>
|
||||
<string name="pckb_key_ins">Ins</string>
|
||||
<string name="pckb_key_del">Del</string>
|
||||
|
||||
@@ -1390,6 +1390,14 @@
|
||||
<string name="theme_icon_blue_detail">Latar hitam, teks putih, biru untuk semua yang dipilih, difokus atau ditekan.</string>
|
||||
<string name="theme_electric">Navy elektrik</string>
|
||||
<string name="theme_electric_detail">Biru lebih cerah, pada permukaan yang lebih cenderung navy daripada kelabu.</string>
|
||||
<string name="theme_gradient">Kecerunan</string>
|
||||
<string name="theme_gradient_detail">Warna utama dan sekunder pilihan anda, diadun pada butang dan sorotan.</string>
|
||||
<string name="theme_gradient_primary">Utama</string>
|
||||
<string name="theme_gradient_secondary">Sekunder</string>
|
||||
<string name="theme_color_hue">Rona</string>
|
||||
<string name="theme_color_saturation">Ketepuan</string>
|
||||
<string name="theme_color_brightness">Kecerahan</string>
|
||||
<string name="theme_color_hex">Warna hex</string>
|
||||
<string name="pckb_key_esc">Esc</string>
|
||||
<string name="pckb_key_ins">Ins</string>
|
||||
<string name="pckb_key_del">Del</string>
|
||||
|
||||
@@ -1404,6 +1404,14 @@
|
||||
<string name="theme_icon_blue_detail">Svart bakgrunn, hvit skrift, det blå for alt som er valgt, fokusert eller trykket.</string>
|
||||
<string name="theme_electric">Elektrisk marineblå</string>
|
||||
<string name="theme_electric_detail">Det blå lysere, på flater som lener mer mot marineblått enn grått.</string>
|
||||
<string name="theme_gradient">Gradient</string>
|
||||
<string name="theme_gradient_detail">Dine egne primær- og sekundærfarger, blandet på knapper og uthevinger.</string>
|
||||
<string name="theme_gradient_primary">Primær</string>
|
||||
<string name="theme_gradient_secondary">Sekundær</string>
|
||||
<string name="theme_color_hue">Fargetone</string>
|
||||
<string name="theme_color_saturation">Metning</string>
|
||||
<string name="theme_color_brightness">Lysstyrke</string>
|
||||
<string name="theme_color_hex">Hex-farge</string>
|
||||
<string name="pckb_key_esc">Esc</string>
|
||||
<string name="pckb_key_ins">Ins</string>
|
||||
<string name="pckb_key_del">Del</string>
|
||||
|
||||
@@ -1404,6 +1404,14 @@
|
||||
<string name="theme_icon_blue_detail">Zwarte achtergrond, witte tekst, het blauw voor alles wat geselecteerd, gefocust of ingedrukt is.</string>
|
||||
<string name="theme_electric">Elektrisch marineblauw</string>
|
||||
<string name="theme_electric_detail">Het blauw feller, op vlakken die naar marineblauw neigen in plaats van grijs.</string>
|
||||
<string name="theme_gradient">Kleurverloop</string>
|
||||
<string name="theme_gradient_detail">Je eigen primaire en secundaire kleur, doorlopend op knoppen en accenten.</string>
|
||||
<string name="theme_gradient_primary">Primair</string>
|
||||
<string name="theme_gradient_secondary">Secundair</string>
|
||||
<string name="theme_color_hue">Tint</string>
|
||||
<string name="theme_color_saturation">Verzadiging</string>
|
||||
<string name="theme_color_brightness">Helderheid</string>
|
||||
<string name="theme_color_hex">Hex-kleur</string>
|
||||
<string name="pckb_key_esc">Esc</string>
|
||||
<string name="pckb_key_ins">Ins</string>
|
||||
<string name="pckb_key_del">Del</string>
|
||||
|
||||
@@ -1432,6 +1432,14 @@
|
||||
<string name="theme_icon_blue_detail">Czarne tło, biały tekst i niebieski dla wszystkiego, co zaznaczone, aktywne lub naciśnięte.</string>
|
||||
<string name="theme_electric">Elektryczny granat</string>
|
||||
<string name="theme_electric_detail">Jaśniejszy niebieski na powierzchniach wpadających w granat zamiast w szarość.</string>
|
||||
<string name="theme_gradient">Gradient</string>
|
||||
<string name="theme_gradient_detail">Własny kolor podstawowy i dodatkowy, płynnie przechodzące na przyciskach i wyróżnieniach.</string>
|
||||
<string name="theme_gradient_primary">Podstawowy</string>
|
||||
<string name="theme_gradient_secondary">Dodatkowy</string>
|
||||
<string name="theme_color_hue">Odcień</string>
|
||||
<string name="theme_color_saturation">Nasycenie</string>
|
||||
<string name="theme_color_brightness">Jasność</string>
|
||||
<string name="theme_color_hex">Kolor hex</string>
|
||||
<string name="pckb_key_esc">Esc</string>
|
||||
<string name="pckb_key_ins">Ins</string>
|
||||
<string name="pckb_key_del">Del</string>
|
||||
|
||||
@@ -1407,6 +1407,14 @@
|
||||
<string name="theme_icon_blue_detail">Fundo preto, texto branco e o azul para tudo o que está selecionado, focado ou premido.</string>
|
||||
<string name="theme_electric">Azul-marinho elétrico</string>
|
||||
<string name="theme_electric_detail">O azul mais vivo, em superfícies que tendem para o azul-marinho em vez do cinzento.</string>
|
||||
<string name="theme_gradient">Gradiente</string>
|
||||
<string name="theme_gradient_detail">As suas próprias cores primária e secundária, combinadas nos botões e destaques.</string>
|
||||
<string name="theme_gradient_primary">Primária</string>
|
||||
<string name="theme_gradient_secondary">Secundária</string>
|
||||
<string name="theme_color_hue">Matiz</string>
|
||||
<string name="theme_color_saturation">Saturação</string>
|
||||
<string name="theme_color_brightness">Brilho</string>
|
||||
<string name="theme_color_hex">Cor hexadecimal</string>
|
||||
<string name="pckb_key_esc">Esc</string>
|
||||
<string name="pckb_key_ins">Ins</string>
|
||||
<string name="pckb_key_del">Del</string>
|
||||
|
||||
@@ -1407,6 +1407,14 @@
|
||||
<string name="theme_icon_blue_detail">Fundo preto, texto branco e o azul em tudo que estiver selecionado, em foco ou pressionado.</string>
|
||||
<string name="theme_electric">Marinho elétrico</string>
|
||||
<string name="theme_electric_detail">O azul mais vivo, sobre superfícies puxadas para o marinho em vez do cinza.</string>
|
||||
<string name="theme_gradient">Gradiente</string>
|
||||
<string name="theme_gradient_detail">Suas próprias cores primária e secundária, combinadas em botões e destaques.</string>
|
||||
<string name="theme_gradient_primary">Primária</string>
|
||||
<string name="theme_gradient_secondary">Secundária</string>
|
||||
<string name="theme_color_hue">Matiz</string>
|
||||
<string name="theme_color_saturation">Saturação</string>
|
||||
<string name="theme_color_brightness">Brilho</string>
|
||||
<string name="theme_color_hex">Cor hexadecimal</string>
|
||||
<string name="pckb_key_esc">Esc</string>
|
||||
<string name="pckb_key_ins">Ins</string>
|
||||
<string name="pckb_key_del">Del</string>
|
||||
|
||||
@@ -1418,6 +1418,14 @@
|
||||
<string name="theme_icon_blue_detail">Fundal negru, text alb, albastrul pentru tot ce este selectat, focalizat sau apăsat.</string>
|
||||
<string name="theme_electric">Bleumarin electric</string>
|
||||
<string name="theme_electric_detail">Albastrul mai strălucitor, pe suprafețe care tind spre bleumarin în loc de gri.</string>
|
||||
<string name="theme_gradient">Gradient</string>
|
||||
<string name="theme_gradient_detail">Culorile tale primară și secundară, combinate pe butoane și evidențieri.</string>
|
||||
<string name="theme_gradient_primary">Primară</string>
|
||||
<string name="theme_gradient_secondary">Secundară</string>
|
||||
<string name="theme_color_hue">Nuanță</string>
|
||||
<string name="theme_color_saturation">Saturație</string>
|
||||
<string name="theme_color_brightness">Luminozitate</string>
|
||||
<string name="theme_color_hex">Culoare hex</string>
|
||||
<string name="pckb_key_esc">Esc</string>
|
||||
<string name="pckb_key_ins">Ins</string>
|
||||
<string name="pckb_key_del">Del</string>
|
||||
|
||||
@@ -1431,6 +1431,14 @@
|
||||
<string name="theme_icon_blue_detail">Черный фон, белый текст, синий — для всего выбранного, активного или нажатого.</string>
|
||||
<string name="theme_electric">Электрик</string>
|
||||
<string name="theme_electric_detail">Более яркий синий на поверхностях темно-синего, а не серого оттенка.</string>
|
||||
<string name="theme_gradient">Градиент</string>
|
||||
<string name="theme_gradient_detail">Ваши основной и дополнительный цвета, плавно переходящие на кнопках и выделениях.</string>
|
||||
<string name="theme_gradient_primary">Основной</string>
|
||||
<string name="theme_gradient_secondary">Дополнительный</string>
|
||||
<string name="theme_color_hue">Оттенок</string>
|
||||
<string name="theme_color_saturation">Насыщенность</string>
|
||||
<string name="theme_color_brightness">Яркость</string>
|
||||
<string name="theme_color_hex">Цвет hex</string>
|
||||
<string name="pckb_key_esc">Esc</string>
|
||||
<string name="pckb_key_ins">Ins</string>
|
||||
<string name="pckb_key_del">Del</string>
|
||||
|
||||
@@ -1404,6 +1404,14 @@
|
||||
<string name="theme_icon_blue_detail">Svart bakgrund, vit text, den blå färgen för allt som är markerat, i fokus eller nedtryckt.</string>
|
||||
<string name="theme_electric">Elektrisk marinblå</string>
|
||||
<string name="theme_electric_detail">Den blå färgen klarare, på ytor som lutar åt marinblått i stället för grått.</string>
|
||||
<string name="theme_gradient">Gradient</string>
|
||||
<string name="theme_gradient_detail">Dina egna primära och sekundära färger, blandade på knappar och markeringar.</string>
|
||||
<string name="theme_gradient_primary">Primär</string>
|
||||
<string name="theme_gradient_secondary">Sekundär</string>
|
||||
<string name="theme_color_hue">Nyans</string>
|
||||
<string name="theme_color_saturation">Mättnad</string>
|
||||
<string name="theme_color_brightness">Ljusstyrka</string>
|
||||
<string name="theme_color_hex">Hex-färg</string>
|
||||
<string name="pckb_key_esc">Esc</string>
|
||||
<string name="pckb_key_ins">Ins</string>
|
||||
<string name="pckb_key_del">Del</string>
|
||||
|
||||
@@ -1390,6 +1390,14 @@
|
||||
<string name="theme_icon_blue_detail">พื้นดำ ตัวอักษรขาว สีฟ้าสำหรับทุกสิ่งที่ถูกเลือก โฟกัส หรือกด</string>
|
||||
<string name="theme_electric">กรมท่าไฟฟ้า</string>
|
||||
<string name="theme_electric_detail">สีฟ้าสว่างขึ้น บนพื้นผิวที่เอียงไปทางกรมท่ามากกว่าเทา</string>
|
||||
<string name="theme_gradient">ไล่เฉดสี</string>
|
||||
<string name="theme_gradient_detail">สีหลักและสีรองที่คุณเลือกเอง ผสมกันบนปุ่มและส่วนที่เน้น</string>
|
||||
<string name="theme_gradient_primary">สีหลัก</string>
|
||||
<string name="theme_gradient_secondary">สีรอง</string>
|
||||
<string name="theme_color_hue">เฉดสี</string>
|
||||
<string name="theme_color_saturation">ความอิ่มตัว</string>
|
||||
<string name="theme_color_brightness">ความสว่าง</string>
|
||||
<string name="theme_color_hex">สีเลขฐานสิบหก</string>
|
||||
<string name="pckb_key_esc">Esc</string>
|
||||
<string name="pckb_key_ins">Ins</string>
|
||||
<string name="pckb_key_del">Del</string>
|
||||
|
||||
@@ -1393,6 +1393,14 @@
|
||||
<string name="theme_icon_blue_detail">Siyah zemin, beyaz yazı; seçilen, odaklanan veya basılan her şey için mavi.</string>
|
||||
<string name="theme_electric">Elektrik laciverti</string>
|
||||
<string name="theme_electric_detail">Daha parlak mavi; gri yerine laciverte çalan yüzeylerde.</string>
|
||||
<string name="theme_gradient">Geçiş</string>
|
||||
<string name="theme_gradient_detail">Kendi birincil ve ikincil renklerin, düğmelerde ve vurgularda harmanlanır.</string>
|
||||
<string name="theme_gradient_primary">Birincil</string>
|
||||
<string name="theme_gradient_secondary">İkincil</string>
|
||||
<string name="theme_color_hue">Ton</string>
|
||||
<string name="theme_color_saturation">Doygunluk</string>
|
||||
<string name="theme_color_brightness">Parlaklık</string>
|
||||
<string name="theme_color_hex">Hex rengi</string>
|
||||
<string name="pckb_key_esc">Esc</string>
|
||||
<string name="pckb_key_ins">Ins</string>
|
||||
<string name="pckb_key_del">Del</string>
|
||||
|
||||
@@ -1432,6 +1432,14 @@
|
||||
<string name="theme_icon_blue_detail">Чорне тло, білий текст і синій для всього вибраного, у фокусі чи натиснутого.</string>
|
||||
<string name="theme_electric">Електричний темно-синій</string>
|
||||
<string name="theme_electric_detail">Яскравіший синій на поверхнях із темно-синім відтінком замість сірого.</string>
|
||||
<string name="theme_gradient">Градієнт</string>
|
||||
<string name="theme_gradient_detail">Ваші основний і додатковий кольори, що плавно переходять на кнопках і виділеннях.</string>
|
||||
<string name="theme_gradient_primary">Основний</string>
|
||||
<string name="theme_gradient_secondary">Додатковий</string>
|
||||
<string name="theme_color_hue">Відтінок</string>
|
||||
<string name="theme_color_saturation">Насиченість</string>
|
||||
<string name="theme_color_brightness">Яскравість</string>
|
||||
<string name="theme_color_hex">Колір hex</string>
|
||||
<string name="pckb_key_esc">Esc</string>
|
||||
<string name="pckb_key_ins">Ins</string>
|
||||
<string name="pckb_key_del">Del</string>
|
||||
|
||||
@@ -1390,6 +1390,14 @@
|
||||
<string name="theme_icon_blue_detail">Nền đen, chữ trắng, xanh cho mọi thứ được chọn, lấy nét hoặc nhấn.</string>
|
||||
<string name="theme_electric">Xanh điện navy</string>
|
||||
<string name="theme_electric_detail">Màu xanh sáng hơn, trên các bề mặt nghiêng về navy thay vì xám.</string>
|
||||
<string name="theme_gradient">Chuyển màu</string>
|
||||
<string name="theme_gradient_detail">Màu chính và màu phụ do bạn chọn, hòa trộn trên các nút và phần nổi bật.</string>
|
||||
<string name="theme_gradient_primary">Chính</string>
|
||||
<string name="theme_gradient_secondary">Phụ</string>
|
||||
<string name="theme_color_hue">Sắc độ</string>
|
||||
<string name="theme_color_saturation">Độ bão hòa</string>
|
||||
<string name="theme_color_brightness">Độ sáng</string>
|
||||
<string name="theme_color_hex">Màu hex</string>
|
||||
<string name="pckb_key_esc">Esc</string>
|
||||
<string name="pckb_key_ins">Ins</string>
|
||||
<string name="pckb_key_del">Del</string>
|
||||
|
||||
@@ -1468,6 +1468,14 @@
|
||||
<string name="theme_icon_blue_detail">黑色背景、白色文字,选中、聚焦或按下的元素使用蓝色。</string>
|
||||
<string name="theme_electric">电光藏青</string>
|
||||
<string name="theme_electric_detail">更明亮的蓝色,配以偏藏青而非灰色的界面。</string>
|
||||
<string name="theme_gradient">渐变</string>
|
||||
<string name="theme_gradient_detail">你自己选择的主色和辅色,在按钮和高亮处渐变呈现。</string>
|
||||
<string name="theme_gradient_primary">主色</string>
|
||||
<string name="theme_gradient_secondary">辅色</string>
|
||||
<string name="theme_color_hue">色相</string>
|
||||
<string name="theme_color_saturation">饱和度</string>
|
||||
<string name="theme_color_brightness">亮度</string>
|
||||
<string name="theme_color_hex">十六进制颜色</string>
|
||||
<string name="pckb_key_esc">Esc</string>
|
||||
<string name="pckb_key_ins">Ins</string>
|
||||
<string name="pckb_key_del">Del</string>
|
||||
|
||||
@@ -1392,6 +1392,14 @@
|
||||
<string name="theme_icon_blue_detail">黑色背景、白色文字,所有已選取、焦點所在或按下的項目都使用藍色。</string>
|
||||
<string name="theme_electric">電光海軍藍</string>
|
||||
<string name="theme_electric_detail">更明亮的藍色,搭配偏海軍藍而非灰色的介面。</string>
|
||||
<string name="theme_gradient">漸層</string>
|
||||
<string name="theme_gradient_detail">你自行選擇的主色與輔色,在按鈕與強調處以漸層呈現。</string>
|
||||
<string name="theme_gradient_primary">主色</string>
|
||||
<string name="theme_gradient_secondary">輔色</string>
|
||||
<string name="theme_color_hue">色相</string>
|
||||
<string name="theme_color_saturation">飽和度</string>
|
||||
<string name="theme_color_brightness">亮度</string>
|
||||
<string name="theme_color_hex">十六進位色彩</string>
|
||||
<string name="pckb_key_esc">Esc</string>
|
||||
<string name="pckb_key_ins">Ins</string>
|
||||
<string name="pckb_key_del">Del</string>
|
||||
|
||||
@@ -1392,6 +1392,14 @@
|
||||
<string name="theme_icon_blue_detail">黑色背景、白色文字,選取、聚焦或按下的項目使用藍色。</string>
|
||||
<string name="theme_electric">電光藏青</string>
|
||||
<string name="theme_electric_detail">更亮的藍色,搭配偏藏青而非灰色的介面。</string>
|
||||
<string name="theme_gradient">漸層</string>
|
||||
<string name="theme_gradient_detail">你自行選擇的主色與輔色,在按鈕與強調處以漸層呈現。</string>
|
||||
<string name="theme_gradient_primary">主色</string>
|
||||
<string name="theme_gradient_secondary">輔色</string>
|
||||
<string name="theme_color_hue">色相</string>
|
||||
<string name="theme_color_saturation">飽和度</string>
|
||||
<string name="theme_color_brightness">亮度</string>
|
||||
<string name="theme_color_hex">十六進位色彩</string>
|
||||
<string name="pckb_key_esc">Esc</string>
|
||||
<string name="pckb_key_ins">Ins</string>
|
||||
<string name="pckb_key_del">Del</string>
|
||||
|
||||
@@ -1459,6 +1459,14 @@
|
||||
<string name="theme_icon_blue_detail">Black ground, white type, the blue for everything selected, focused or pressed.</string>
|
||||
<string name="theme_electric">Electric navy</string>
|
||||
<string name="theme_electric_detail">The blue brighter, on surfaces that lean navy instead of grey.</string>
|
||||
<string name="theme_gradient">Gradient</string>
|
||||
<string name="theme_gradient_detail">Your own primary and secondary colors, blended on buttons and highlights.</string>
|
||||
<string name="theme_gradient_primary">Primary</string>
|
||||
<string name="theme_gradient_secondary">Secondary</string>
|
||||
<string name="theme_color_hue">Hue</string>
|
||||
<string name="theme_color_saturation">Saturation</string>
|
||||
<string name="theme_color_brightness">Brightness</string>
|
||||
<string name="theme_color_hex">Hex color</string>
|
||||
<string name="pckb_key_esc">Esc</string>
|
||||
<string name="pckb_key_ins">Ins</string>
|
||||
<string name="pckb_key_del">Del</string>
|
||||
|
||||
@@ -0,0 +1,135 @@
|
||||
package com.droiddeck.launcher.ui
|
||||
|
||||
import android.content.Context
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.luminance
|
||||
import androidx.compose.ui.graphics.toArgb
|
||||
import com.droiddeck.launcher.session.SessionPrefs
|
||||
import org.junit.Assert.assertEquals
|
||||
import org.junit.Assert.assertNull
|
||||
import org.junit.Assert.assertTrue
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.robolectric.RobolectricTestRunner
|
||||
import org.robolectric.RuntimeEnvironment
|
||||
import org.robolectric.annotation.Config
|
||||
|
||||
@RunWith(RobolectricTestRunner::class)
|
||||
@Config(sdk = [33])
|
||||
class ThemeColorsTest {
|
||||
private val app get() = RuntimeEnvironment.getApplication()
|
||||
|
||||
@Before fun clear() {
|
||||
app.getSharedPreferences("session", Context.MODE_PRIVATE).edit().clear().commit()
|
||||
}
|
||||
|
||||
private fun near(expected: Int, actual: Int) {
|
||||
for (shift in listOf(16, 8, 0)) assertTrue("${ThemeColors.hex(expected)} vs ${ThemeColors.hex(actual)}", Math.abs((expected shr shift and 0xFF) - (actual shr shift and 0xFF)) <= 1)
|
||||
}
|
||||
|
||||
@Test fun hueSaturationAndBrightnessComeBackAsTheSameColour() {
|
||||
for (argb in listOf(0xFF8B5CF6.toInt(), 0xFF22D3EE.toInt(), 0xFFFF0000.toInt(), 0xFF336699.toInt(), 0xFF808080.toInt(), 0xFF000000.toInt(), 0xFFFFFFFF.toInt())) {
|
||||
val hsv = ThemeColors.toHsv(argb)
|
||||
near(argb, ThemeColors.fromHsv(hsv.h, hsv.s, hsv.v))
|
||||
}
|
||||
}
|
||||
|
||||
@Test fun hexIsReadWithOrWithoutTheHashAndInShortForm() {
|
||||
assertEquals(0xFF8B5CF6.toInt(), ThemeColors.parseHex("#8B5CF6"))
|
||||
assertEquals(0xFF8B5CF6.toInt(), ThemeColors.parseHex("8b5cf6"))
|
||||
assertEquals(0xFFFF00AA.toInt(), ThemeColors.parseHex(" #f0a "))
|
||||
assertEquals("#8B5CF6", ThemeColors.hex(0xFF8B5CF6.toInt()))
|
||||
for (bad in listOf("", "#", "#12", "#1234", "#1234567", "zzzzzz", "#12345g")) assertNull(bad, ThemeColors.parseHex(bad))
|
||||
}
|
||||
|
||||
@Test fun aTooDarkColourIsLiftedAndABrightOneIsLeftAlone() {
|
||||
val dark = ThemeColors.readable(0xFF050505.toInt())
|
||||
assertTrue(Color(dark).luminance() >= 0.10f)
|
||||
assertEquals(0xFF8B5CF6.toInt(), ThemeColors.readable(0xFF8B5CF6.toInt()))
|
||||
}
|
||||
|
||||
@Test fun aDeepBlueThatBrightnessAloneCannotLiftIsMadePaler() {
|
||||
assertTrue(Color(ThemeColors.readable(0xFF0000FF.toInt())).luminance() >= 0.10f)
|
||||
assertTrue(Color(ThemeColors.readable(0xFF000000.toInt())).luminance() >= 0.10f)
|
||||
}
|
||||
|
||||
@Test fun theTextColourSuitsTheWorseOfTheTwoGradientColours() {
|
||||
assertEquals(Color(0xFF03111F), ThemeColors.inkFor(0xFFFFEB3B.toInt(), 0xFF3B4FA8.toInt()))
|
||||
assertEquals(Color.White, ThemeColors.inkFor(0xFF3B4FA8.toInt(), 0xFF5B2FA8.toInt()))
|
||||
assertEquals(Color(0xFF03111F), ThemeColors.inkFor(0xFFFFFFFF.toInt(), 0xFFFFEB3B.toInt()))
|
||||
}
|
||||
|
||||
private fun contrast(a: Color, b: Color) = (maxOf(a.luminance(), b.luminance()) + 0.05f) / (minOf(a.luminance(), b.luminance()) + 0.05f)
|
||||
|
||||
@Test fun buttonTextIsReadableOnBothGradientColoursForAnyPair() {
|
||||
val picks = listOf(0xFFFFEB3B, 0xFF1E3A8A, 0xFF0000FF, 0xFFFF0000, 0xFF00FF00, 0xFF808080, 0xFFFFFFFF, 0xFF000000, 0xFF8B5CF6, 0xFF22D3EE, 0xFFFF5722, 0xFF3F51B5)
|
||||
for (a in picks) for (b in picks) {
|
||||
val p = ThemeColors.palette(a.toInt(), b.toInt(), 0, 0)
|
||||
val first = p.primary.toArgb()
|
||||
val second = p.primary2.toArgb()
|
||||
for (step in 0..100) {
|
||||
val fraction = step / 100f
|
||||
val color = Color(
|
||||
0xFF000000.toInt() or
|
||||
(channel(first, 16, second, fraction) shl 16) or
|
||||
(channel(first, 8, second, fraction) shl 8) or
|
||||
channel(first, 0, second, fraction),
|
||||
)
|
||||
assertTrue(
|
||||
"${ThemeColors.hex(first)} ${ThemeColors.hex(second)} at $fraction",
|
||||
contrast(p.onPrimary, color) >= 4.5f,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun channel(first: Int, shift: Int, second: Int, fraction: Float): Int {
|
||||
val start = first shr shift and 0xFF
|
||||
val end = second shr shift and 0xFF
|
||||
return (start + (end - start) * fraction).toInt().coerceIn(0, 255)
|
||||
}
|
||||
|
||||
@Test fun onlyTheStopThatFailsIsNudged() {
|
||||
val p = ThemeColors.palette(0xFFFFEB3B.toInt(), 0xFF1E3A8A.toInt(), 0, 0)
|
||||
assertEquals(Color(0xFFFFEB3B), p.primary)
|
||||
assertTrue(p.primary2 != Color(0xFF1E3A8A))
|
||||
assertEquals(Color(0xFF03111F), p.onPrimary)
|
||||
}
|
||||
|
||||
@Test fun thePaletteKeepsTheTwoColoursAndStaysDarkAndReadable() {
|
||||
val p = ThemeColors.palette(0xFF8B5CF6.toInt(), 0xFF22D3EE.toInt(), 0, 0)
|
||||
assertEquals(p.primary, p.signal)
|
||||
assertEquals(Color(0xFF22D3EE), p.primary2)
|
||||
assertTrue(contrast(p.onPrimary, p.primary) >= 4.5f)
|
||||
assertTrue(contrast(p.onPrimary, p.primary2) >= 4.5f)
|
||||
assertTrue(p.background.luminance() < p.surface.luminance())
|
||||
assertTrue(p.surface.luminance() < p.surfaceVariant.luminance())
|
||||
assertTrue(p.background.luminance() < 0.02f)
|
||||
assertTrue(p.onBackground.luminance() > 0.8f)
|
||||
assertEquals(Color(0xFF03111F), ThemeColors.palette(0xFFFFEB3B.toInt(), 0xFFFFFFFF.toInt(), 0, 0).onPrimary)
|
||||
assertEquals(Color.White, ThemeColors.palette(0xFF1E40AF.toInt(), 0xFF1D4ED8.toInt(), 0, 0).onPrimary)
|
||||
}
|
||||
|
||||
@Test fun aGreyPrimaryGivesGreyNeutrals() {
|
||||
val p = ThemeColors.palette(0xFFB0B0B0.toInt(), 0xFFFFFFFF.toInt(), 0, 0)
|
||||
assertEquals(p.background.red, p.background.blue, 0.002f)
|
||||
}
|
||||
|
||||
@Test fun theGradientThemeFollowsTheSavedColoursAndComesBackAfterARestart() {
|
||||
Themes.setGradient(app, 0xFFFF5722.toInt(), 0xFF3F51B5.toInt())
|
||||
val live = Themes.byId(Themes.GRADIENT)
|
||||
assertEquals(0xFFFF5722.toInt() to 0xFF3F51B5.toInt(), SessionPrefs.gradientColors(app))
|
||||
assertTrue(contrast(live.onPrimary, live.primary) >= 4.5f)
|
||||
assertTrue(contrast(live.onPrimary, live.primary2) >= 4.5f)
|
||||
SessionPrefs.setTheme(app, Themes.GRADIENT)
|
||||
Themes.setGradient(app, Themes.DEFAULT_PRIMARY, Themes.DEFAULT_SECONDARY)
|
||||
SessionPrefs.setGradientColors(app, 0xFF00FF00.toInt(), 0xFF0000FF.toInt())
|
||||
assertEquals(Color(0xFF00FF00), Themes.current(app).primary)
|
||||
}
|
||||
|
||||
@Test fun theGradientIsAChoiceInTheThemeList() {
|
||||
assertTrue(Themes.all.any { it.id == Themes.GRADIENT })
|
||||
assertEquals(Themes.GRAPHITE, Themes.byId("nonsense").id)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
# Themes
|
||||
|
||||
A theme is a `Palette` (`ui/Theme.kt`): a dark background scale (`background`, `surface`,
|
||||
`surfaceVariant`, `line`, `line2`), two text colours, and the accent: `primary` / `signal`
|
||||
(flat accent, also Material's primary), `primary2` (the darker or second accent) and
|
||||
`onPrimary`. `PrimaryButton` and the launch flood already draw a gradient from `primary` to
|
||||
`primary2`. The choice is stored as an id (`SessionPrefs.theme`) and picked in Setup › Launcher.
|
||||
|
||||
## Gradient theme
|
||||
|
||||
`Themes.GRADIENT` is the one theme whose colours the person picks: a primary and a secondary,
|
||||
kept in `SessionPrefs.gradientColors` and in `Themes.gradientColors`, a Compose state, so a change
|
||||
restyles the whole app at once. `App.onCreate` loads the saved colours; code outside a composition
|
||||
uses `Themes.current(context)`.
|
||||
|
||||
`ThemeColors.palette` builds the full palette from the two colours: primary becomes
|
||||
`primary` / `signal`, secondary becomes `primary2`, the background scale is a dark neutral tinted with
|
||||
the primary's hue (plain grey for a grey primary), and `onPrimary` is dark or white by the
|
||||
luminance of the pair. A colour too dark to show on the dark background is lifted
|
||||
(`ThemeColors.readable`) rather than refused.
|
||||
|
||||
Setup shows Primary and Secondary under the theme when Gradient is chosen, each a small colour
|
||||
square. It opens `ColorPickerDialog`: a wheel (hue and saturation, touch), hue / saturation /
|
||||
brightness sliders (they work with a controller) and a hex box, with the old and new colour side by
|
||||
side. OK applies it.
|
||||
Reference in new issue
Block a user