From f7acb7fcd7b0dad2ccbaccf39e8aed288b38fa71 Mon Sep 17 00:00:00 2001
From: FX192 <120828496+FX192@users.noreply.github.com>
Date: Fri, 23 Oct 2026 04:50:32 +0300
Subject: [PATCH] Inner Gamer RGB theme with a speed slider; keep the colour
picker's hex box in view above the keyboard
The hex box sat at the bottom of the picker, so with the keyboard up the dialog
was cut off and the field could not be seen. While the box has focus the dialog
now scrolls to its end, and again whenever the visible height changes, so the
hex box and OK / Cancel stay above the keyboard.
Inner Gamer is a new theme just above Gradient. Its accent walks round the
colour wheel on a Compose infinite transition, so Android's animation clock
drives it and it holds still when animations are off. The hue moves in 3 degree
steps so the app restyles only when the colour visibly changes. Setup shows a
Speed slider (1 to 10) while it is selected. The palette comes from
ThemeColors.palette, so button text stays readable at every hue.
---
.../launcher/session/SessionPrefs.kt | 8 +++
.../com/droiddeck/launcher/ui/AddAppDialog.kt | 3 +-
.../launcher/ui/ColorPickerDialog.kt | 7 ++-
.../droiddeck/launcher/ui/FrontEndSetup.kt | 8 +++
.../java/com/droiddeck/launcher/ui/Theme.kt | 55 +++++++++++++++++++
.../com/droiddeck/launcher/ui/ThemeColors.kt | 4 +-
app/src/main/res/values-ar/strings.xml | 4 ++
app/src/main/res/values-b+es+419/strings.xml | 4 ++
app/src/main/res/values-bg/strings.xml | 4 ++
app/src/main/res/values-cs/strings.xml | 4 ++
app/src/main/res/values-da/strings.xml | 4 ++
app/src/main/res/values-de/strings.xml | 4 ++
app/src/main/res/values-el/strings.xml | 4 ++
app/src/main/res/values-es/strings.xml | 4 ++
app/src/main/res/values-fi/strings.xml | 4 ++
app/src/main/res/values-fr/strings.xml | 4 ++
app/src/main/res/values-hi/strings.xml | 4 ++
app/src/main/res/values-hu/strings.xml | 4 ++
app/src/main/res/values-in/strings.xml | 4 ++
app/src/main/res/values-it/strings.xml | 4 ++
app/src/main/res/values-ja/strings.xml | 4 ++
app/src/main/res/values-ko/strings.xml | 4 ++
app/src/main/res/values-ms/strings.xml | 4 ++
app/src/main/res/values-nb/strings.xml | 4 ++
app/src/main/res/values-nl/strings.xml | 4 ++
app/src/main/res/values-pl/strings.xml | 4 ++
app/src/main/res/values-pt-rPT/strings.xml | 4 ++
app/src/main/res/values-pt/strings.xml | 4 ++
app/src/main/res/values-ro/strings.xml | 4 ++
app/src/main/res/values-ru/strings.xml | 4 ++
app/src/main/res/values-sv/strings.xml | 4 ++
app/src/main/res/values-th/strings.xml | 4 ++
app/src/main/res/values-tr/strings.xml | 4 ++
app/src/main/res/values-uk/strings.xml | 4 ++
app/src/main/res/values-vi/strings.xml | 4 ++
app/src/main/res/values-zh-rCN/strings.xml | 4 ++
app/src/main/res/values-zh-rHK/strings.xml | 4 ++
app/src/main/res/values-zh-rTW/strings.xml | 4 ++
app/src/main/res/values/strings.xml | 4 ++
.../droiddeck/launcher/ui/ThemeColorsTest.kt | 36 ++++++++++++
docs/development/themes.md | 14 +++++
41 files changed, 263 insertions(+), 4 deletions(-)
diff --git a/app/src/main/java/com/droiddeck/launcher/session/SessionPrefs.kt b/app/src/main/java/com/droiddeck/launcher/session/SessionPrefs.kt
index d9d2d8e1d..f28c68734 100644
--- a/app/src/main/java/com/droiddeck/launcher/session/SessionPrefs.kt
+++ b/app/src/main/java/com/droiddeck/launcher/session/SessionPrefs.kt
@@ -764,6 +764,14 @@ object SessionPrefs {
it.getInt("gradientSecondary", com.droiddeck.launcher.ui.Themes.DEFAULT_SECONDARY)
}
+ /** How fast the Inner Gamer theme cycles its colours, 1 to 10. */
+ fun rgbSpeed(context: Context): Int =
+ prefs(context).getInt("innerGamerSpeed", com.droiddeck.launcher.ui.Themes.DEFAULT_RGB_SPEED).coerceIn(1, com.droiddeck.launcher.ui.Themes.RGB_SPEEDS)
+
+ fun setRgbSpeed(context: Context, speed: Int) {
+ prefs(context).edit().putInt("innerGamerSpeed", speed.coerceIn(1, com.droiddeck.launcher.ui.Themes.RGB_SPEEDS)).apply()
+ }
+
fun setGradientColors(context: Context, primary: Int, secondary: Int) {
prefs(context).edit().putInt("gradientPrimary", primary).putInt("gradientSecondary", secondary).apply()
}
diff --git a/app/src/main/java/com/droiddeck/launcher/ui/AddAppDialog.kt b/app/src/main/java/com/droiddeck/launcher/ui/AddAppDialog.kt
index 5e63d7b0f..b3b88f0aa 100644
--- a/app/src/main/java/com/droiddeck/launcher/ui/AddAppDialog.kt
+++ b/app/src/main/java/com/droiddeck/launcher/ui/AddAppDialog.kt
@@ -308,6 +308,7 @@ internal fun AppDialog(
width: Dp? = null, fitContent: Boolean = false,
back: (() -> Unit)? = null,
scrollable: Boolean = true,
+ scrollState: androidx.compose.foundation.ScrollState = rememberScrollState(),
content: @Composable ColumnScope.() -> Unit,
) {
val pal = LocalPalette.current
@@ -345,7 +346,7 @@ internal fun AppDialog(
.blockTouches()
.controllerBack(back ?: close)
.then(modifier)
- .then(if (scrollable) Modifier.verticalScroll(rememberScrollState()) else Modifier)
+ .then(if (scrollable) Modifier.verticalScroll(scrollState) else Modifier)
.padding(horizontal = 18.dp, vertical = 16.dp),
content = content,
)
diff --git a/app/src/main/java/com/droiddeck/launcher/ui/ColorPickerDialog.kt b/app/src/main/java/com/droiddeck/launcher/ui/ColorPickerDialog.kt
index e94f193e9..d83e1abe1 100644
--- a/app/src/main/java/com/droiddeck/launcher/ui/ColorPickerDialog.kt
+++ b/app/src/main/java/com/droiddeck/launcher/ui/ColorPickerDialog.kt
@@ -13,6 +13,7 @@ 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.rememberScrollState
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.MaterialTheme
import androidx.compose.runtime.Composable
@@ -70,12 +71,15 @@ internal fun ColorPickerDialog(title: String, initial: Int, onDismiss: () -> Uni
var hexText by remember { mutableStateOf(ThemeColors.hex(initial)) }
val current = ThemeColors.fromHsv(hue, sat, value)
val first = remember { FocusRequester() }
+ val scroll = rememberScrollState()
+ var typingHex by remember { mutableStateOf(false) }
LaunchedEffect(Unit) { focusSoon { first } }
+ LaunchedEffect(typingHex, scroll.maxValue) { if (typingHex) scroll.animateScrollTo(scroll.maxValue) }
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) {
+ AppDialog(shown, close, "colorPicker", wide = false, maxWidth = 460.dp, scrollState = scroll) {
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) }
@@ -95,6 +99,7 @@ internal fun ColorPickerDialog(title: String, initial: Int, onDismiss: () -> Uni
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),
+ onFocusChange = { typingHex = it },
onDone = { ThemeColors.parseHex(hexText)?.let { onApply(it); close() } },
)
Row(horizontalArrangement = Arrangement.spacedBy(8.dp), modifier = Modifier.fillMaxWidth()) {
diff --git a/app/src/main/java/com/droiddeck/launcher/ui/FrontEndSetup.kt b/app/src/main/java/com/droiddeck/launcher/ui/FrontEndSetup.kt
index b5bbaa2e9..c2582837f 100644
--- a/app/src/main/java/com/droiddeck/launcher/ui/FrontEndSetup.kt
+++ b/app/src/main/java/com/droiddeck/launcher/ui/FrontEndSetup.kt
@@ -359,6 +359,7 @@ internal fun SetupPanel(
}
}
}
+ if (s.theme == Themes.INNER_GAMER) RgbSpeedRow()
if (s.theme == Themes.GRADIENT) GradientColorRows()
ChoiceRow(
host, "app-scale", stringResource(R.string.setup_app_scale), stringResource(R.string.setup_app_scale_hint),
@@ -792,6 +793,13 @@ private fun LanguageRow(host: MenuHost, chosen: String, onPick: (String) -> Unit
}
}
+/** How fast Inner Gamer cycles its colours. */
+@Composable
+private fun RgbSpeedRow() {
+ val ctx = androidx.compose.ui.platform.LocalContext.current.applicationContext
+ SliderRow(stringResource(R.string.theme_rgb_speed), stringResource(R.string.theme_rgb_speed_hint), Themes.rgbSpeed, 1..Themes.RGB_SPEEDS) { Themes.setRgbSpeed(ctx, it) }
+}
+
/** The two colours of the Gradient theme, each a small square that opens the colour picker. */
@Composable
private fun GradientColorRows() {
diff --git a/app/src/main/java/com/droiddeck/launcher/ui/Theme.kt b/app/src/main/java/com/droiddeck/launcher/ui/Theme.kt
index 0f3843fca..4eae384e2 100644
--- a/app/src/main/java/com/droiddeck/launcher/ui/Theme.kt
+++ b/app/src/main/java/com/droiddeck/launcher/ui/Theme.kt
@@ -3,7 +3,14 @@ package com.droiddeck.launcher.ui
import androidx.annotation.StringRes
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.darkColorScheme
+import androidx.compose.animation.core.LinearEasing
+import androidx.compose.animation.core.RepeatMode
+import androidx.compose.animation.core.animateFloat
+import androidx.compose.animation.core.infiniteRepeatable
+import androidx.compose.animation.core.rememberInfiniteTransition
+import androidx.compose.animation.core.tween
import androidx.compose.runtime.Composable
+import androidx.compose.runtime.SideEffect
import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.runtime.staticCompositionLocalOf
import androidx.compose.runtime.getValue
@@ -13,6 +20,7 @@ import android.content.Context
import androidx.compose.runtime.remember
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.luminance
+import androidx.compose.ui.graphics.toArgb
import androidx.compose.ui.platform.LocalContext
import com.droiddeck.launcher.R
import androidx.compose.ui.platform.LocalConfiguration
@@ -33,6 +41,7 @@ object Themes {
const val PAPER = "paper"
const val ICON_BLUE = "blue"
const val ELECTRIC = "electric"
+ const val INNER_GAMER = "inner_gamer"
const val GRADIENT = "gradient"
const val DEFAULT_PRIMARY = 0xFF8B5CF6.toInt()
@@ -42,10 +51,42 @@ object Themes {
var gradientColors by mutableStateOf(DEFAULT_PRIMARY to DEFAULT_SECONDARY)
private set
+ const val RGB_SPEEDS = 10
+ const val DEFAULT_RGB_SPEED = 3
+ const val RGB_HUE_STEP = 3f
+
+ /** How fast Inner Gamer cycles, 1 (slow) to [RGB_SPEEDS] (fast). */
+ var rgbSpeed by mutableStateOf(DEFAULT_RGB_SPEED)
+ private set
+
+ /** Where Inner Gamer is on the colour wheel, in whole [RGB_HUE_STEP] steps so the app restyles only when the colour visibly moves. */
+ var rgbHue by mutableStateOf(0f)
+ private set
+
+ fun setRgbHue(hue: Float) {
+ rgbHue = hue
+ }
+
+ fun setRgbSpeed(context: Context, speed: Int) {
+ val value = speed.coerceIn(1, RGB_SPEEDS)
+ SessionPrefs.setRgbSpeed(context, value)
+ rgbSpeed = value
+ }
+
+ /** Milliseconds for one trip round the colour wheel. */
+ fun rgbCycleMillis(speed: Int): Int = 30_000 / speed.coerceIn(1, RGB_SPEEDS)
+
fun loadGradient(context: Context) {
gradientColors = SessionPrefs.gradientColors(context)
+ rgbSpeed = SessionPrefs.rgbSpeed(context)
}
+ /** The Inner Gamer palette at one point on the colour wheel. */
+ fun innerGamer(hue: Float): Palette = ThemeColors.palette(
+ Color.hsv(hue % 360f, 0.9f, 1f).toArgb(), Color.hsv((hue + 60f) % 360f, 0.9f, 1f).toArgb(),
+ R.string.theme_inner_gamer, R.string.theme_inner_gamer_detail, INNER_GAMER,
+ )
+
fun setGradient(context: Context, primary: Int, secondary: Int) {
SessionPrefs.setGradientColors(context, primary, secondary)
gradientColors = primary to secondary
@@ -87,10 +128,12 @@ object Themes {
primary = Color(0xFF2E86FF), primary2 = Color(0xFF2684FF), onPrimary = Color(0xFF03111F), signal = Color(0xFF2E86FF),
good = Color(0xFF4CD37F),
),
+ innerGamer(0f),
ThemeColors.palette(DEFAULT_PRIMARY, DEFAULT_SECONDARY, R.string.theme_gradient, R.string.theme_gradient_detail),
)
fun byId(id: String): Palette {
+ if (id == INNER_GAMER) return innerGamer(rgbHue)
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]
}
@@ -103,6 +146,7 @@ val Palette.onSignal: Color get() = if (signal.luminance() > 0.18f) Color(0xFF03
@Composable
fun DroidDeckTheme(theme: String? = null, appScale: Int = AppUiPrefs.DEFAULT_SCALE, content: @Composable () -> Unit) {
val id = theme ?: SessionPrefs.theme(LocalContext.current)
+ if (id == Themes.INNER_GAMER) InnerGamerHue(Themes.rgbSpeed)
val p = Themes.byId(id)
val scheme = darkColorScheme(
primary = p.primary, onPrimary = p.onPrimary, secondary = p.onSurfaceVariant,
@@ -121,3 +165,14 @@ fun DroidDeckTheme(theme: String? = null, appScale: Int = AppUiPrefs.DEFAULT_SCA
LocalConfiguration provides configuration,
) { MaterialTheme(colorScheme = scheme, content = content) }
}
+
+/** Turns the colour wheel on the system's own animation clock; with animations off, in the app or in Android, the colour holds still. */
+@Composable
+private fun InnerGamerHue(speed: Int) {
+ if (Motion.scale == 0f) return
+ val hue by rememberInfiniteTransition(label = "innerGamer").animateFloat(
+ 0f, 360f, infiniteRepeatable(tween(Motion.ms(Themes.rgbCycleMillis(speed)).coerceAtLeast(1), easing = LinearEasing), RepeatMode.Restart), label = "hue",
+ )
+ val step = Themes.RGB_HUE_STEP
+ SideEffect { Themes.setRgbHue((hue / step).toInt() * step) }
+}
diff --git a/app/src/main/java/com/droiddeck/launcher/ui/ThemeColors.kt b/app/src/main/java/com/droiddeck/launcher/ui/ThemeColors.kt
index b4b57737e..b2db63562 100644
--- a/app/src/main/java/com/droiddeck/launcher/ui/ThemeColors.kt
+++ b/app/src/main/java/com/droiddeck/launcher/ui/ThemeColors.kt
@@ -132,7 +132,7 @@ internal object ThemeColors {
}
}
- fun palette(primary: Int, secondary: Int, label: Int, detail: Int): Palette {
+ fun palette(primary: Int, secondary: Int, label: Int, detail: Int, id: String = Themes.GRADIENT): Palette {
val seen = readable(primary)
val seenSecond = readable(secondary)
val ink = inkFor(seen, seenSecond)
@@ -146,7 +146,7 @@ internal object ThemeColors {
second = nextSecond
}
return Palette(
- Themes.GRADIENT, label, detail,
+ id, 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),
diff --git a/app/src/main/res/values-ar/strings.xml b/app/src/main/res/values-ar/strings.xml
index c7528035f..c3d790b84 100644
--- a/app/src/main/res/values-ar/strings.xml
+++ b/app/src/main/res/values-ar/strings.xml
@@ -1457,6 +1457,10 @@
خلفية سوداء ونص أبيض، والأزرق لكل عنصر محدَّد أو مُركَّز عليه أو مضغوط.
كحلي كهربائي
أزرق أكثر سطوعًا، على أسطح تميل إلى الكحلي بدلاً من الرمادي.
+ Inner Gamer
+ ألوان تتدرّج عبر ألوان قوس قزح. تتبع إعدادات الرسوم المتحركة في Android.
+ السرعة
+ مدى سرعة تغيّر الألوان.
تدرج لوني
لونك الأساسي والثانوي، ممزوجان على الأزرار وعناصر التمييز.
الأساسي
diff --git a/app/src/main/res/values-b+es+419/strings.xml b/app/src/main/res/values-b+es+419/strings.xml
index d6a7aa64e..0464089bd 100644
--- a/app/src/main/res/values-b+es+419/strings.xml
+++ b/app/src/main/res/values-b+es+419/strings.xml
@@ -1466,6 +1466,10 @@
Fondo negro, texto blanco y el azul para todo lo seleccionado, enfocado o presionado.
Azul marino eléctrico
Un azul más vivo, sobre superficies que tiran a azul marino en vez de gris.
+ Inner Gamer
+ Colores que recorren el arcoíris. Respeta los ajustes de animación de Android.
+ Velocidad
+ Qué tan rápido cambian los colores.
Degradado
Tus propios colores primario y secundario, combinados en botones y resaltados.
Primario
diff --git a/app/src/main/res/values-bg/strings.xml b/app/src/main/res/values-bg/strings.xml
index e5ec507d7..97b824670 100644
--- a/app/src/main/res/values-bg/strings.xml
+++ b/app/src/main/res/values-bg/strings.xml
@@ -1401,6 +1401,10 @@
Черен фон, бял текст, синьото за всичко избрано, на фокус или натиснато.
Яркосиньо
По-яркото синьо, върху повърхности, по-близки до тъмносиньо, вместо сиво.
+ Inner Gamer
+ Цветове, които преминават през дъгата. Следва настройките за анимации на Android.
+ Скорост
+ Колко бързо се сменят цветовете.
Градиент
Вашите основен и вторичен цвят, смесени в бутоните и акцентите.
Основен
diff --git a/app/src/main/res/values-cs/strings.xml b/app/src/main/res/values-cs/strings.xml
index 7ff26b087..f8f659b8a 100644
--- a/app/src/main/res/values-cs/strings.xml
+++ b/app/src/main/res/values-cs/strings.xml
@@ -1429,6 +1429,10 @@
Černé pozadí, bílé písmo, modrá pro vše vybrané, zaměřené nebo stisknuté.
Elektrická modř
Jasnější modrá na povrchách, které jsou spíše tmavomodré než šedé.
+ Inner Gamer
+ Barvy, které procházejí celou duhu. Respektuje nastavení animací v Androidu.
+ Rychlost
+ Jak rychle se barvy střídají.
Přechod
Vaše vlastní primární a sekundární barva, prolnuté na tlačítkách a zvýrazněních.
Primární
diff --git a/app/src/main/res/values-da/strings.xml b/app/src/main/res/values-da/strings.xml
index dbe459497..a2686e54e 100644
--- a/app/src/main/res/values-da/strings.xml
+++ b/app/src/main/res/values-da/strings.xml
@@ -1401,6 +1401,10 @@
Sort baggrund, hvid skrift, blå til alt, der er valgt, fokuseret eller trykket.
Elektrisk marineblå
Den blå er klarere, på overflader der trækker mod marineblåt i stedet for gråt.
+ Inner Gamer
+ Farver, der skifter gennem regnbuen. Følger Androids animationsindstillinger.
+ Hastighed
+ Hvor hurtigt farverne skifter.
Gradient
Dine egne primære og sekundære farver, blandet på knapper og fremhævninger.
Primær
diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml
index 73fa6ae85..e68671239 100644
--- a/app/src/main/res/values-de/strings.xml
+++ b/app/src/main/res/values-de/strings.xml
@@ -1393,6 +1393,10 @@
Schwarzer Grund, weiße Schrift, das Blau für alles Ausgewählte, Fokussierte oder Gedrückte.
Elektrisches Marineblau
Das Blau heller, auf Flächen, die eher zu Marineblau als zu Grau tendieren.
+ Inner Gamer
+ Farben, die durch den Regenbogen wechseln. Folgt den Animationseinstellungen von Android.
+ Geschwindigkeit
+ Wie schnell die Farben wechseln.
Farbverlauf
Eigene Primär- und Sekundärfarbe, als Verlauf auf Schaltflächen und Hervorhebungen.
Primär
diff --git a/app/src/main/res/values-el/strings.xml b/app/src/main/res/values-el/strings.xml
index 097d18c2b..0667040d4 100644
--- a/app/src/main/res/values-el/strings.xml
+++ b/app/src/main/res/values-el/strings.xml
@@ -1401,6 +1401,10 @@
Μαύρο φόντο, λευκά γράμματα, το μπλε για ό,τι είναι επιλεγμένο, εστιασμένο ή πατημένο.
Ηλεκτρικό ναυτικό μπλε
Το μπλε πιο έντονο, σε επιφάνειες που τείνουν προς το ναυτικό μπλε αντί για γκρι.
+ Inner Gamer
+ Χρώματα που διατρέχουν το ουράνιο τόξο. Ακολουθεί τις ρυθμίσεις animation του Android.
+ Ταχύτητα
+ Πόσο γρήγορα αλλάζουν τα χρώματα.
Διαβάθμιση
Δικά σας πρωτεύον και δευτερεύον χρώμα, σε μίξη στα κουμπιά και τις επισημάνσεις.
Πρωτεύον
diff --git a/app/src/main/res/values-es/strings.xml b/app/src/main/res/values-es/strings.xml
index edbccd44d..57b09bf6b 100644
--- a/app/src/main/res/values-es/strings.xml
+++ b/app/src/main/res/values-es/strings.xml
@@ -1417,6 +1417,10 @@
Fondo negro, texto blanco y el azul para todo lo seleccionado, enfocado o pulsado.
Azul marino eléctrico
Un azul más vivo, sobre superficies que tiran a azul marino en vez de gris.
+ Inner Gamer
+ Colores que recorren el arcoíris. Respeta los ajustes de animación de Android.
+ Velocidad
+ Con qué rapidez cambian los colores.
Degradado
Tus propios colores primario y secundario, combinados en botones y resaltados.
Primario
diff --git a/app/src/main/res/values-fi/strings.xml b/app/src/main/res/values-fi/strings.xml
index 2d8d8a12b..2b462ab88 100644
--- a/app/src/main/res/values-fi/strings.xml
+++ b/app/src/main/res/values-fi/strings.xml
@@ -1401,6 +1401,10 @@
Musta pohja, valkoinen teksti, sininen kaikessa valitussa, kohdistetussa tai painetussa.
Sähköinen laivastonsininen
Sininen kirkkaampana pinnoilla, jotka taittuvat harmaan sijaan laivastonsiniseen.
+ Inner Gamer
+ Värit, jotka kiertävät sateenkaaren läpi. Noudattaa Androidin animaatioasetuksia.
+ Nopeus
+ Kuinka nopeasti värit vaihtuvat.
Liukuväri
Omat ensisijainen ja toissijainen värisi, sulautettuina painikkeisiin ja korostuksiin.
Ensisijainen
diff --git a/app/src/main/res/values-fr/strings.xml b/app/src/main/res/values-fr/strings.xml
index b268e9efd..54342beae 100644
--- a/app/src/main/res/values-fr/strings.xml
+++ b/app/src/main/res/values-fr/strings.xml
@@ -1417,6 +1417,10 @@
Fond noir, texte blanc, et le bleu pour tout élément sélectionné, ciblé ou pressé.
Marine électrique
Un bleu plus vif, sur des surfaces qui tirent vers le marine plutôt que vers le gris.
+ Inner Gamer
+ Des couleurs qui parcourent l\'arc-en-ciel. Respecte les réglages d\'animation d\'Android.
+ Vitesse
+ La vitesse de défilement des couleurs.
Dégradé
Vos propres couleurs primaire et secondaire, fondues sur les boutons et les éléments en surbrillance.
Primaire
diff --git a/app/src/main/res/values-hi/strings.xml b/app/src/main/res/values-hi/strings.xml
index d08626be6..5113e7764 100644
--- a/app/src/main/res/values-hi/strings.xml
+++ b/app/src/main/res/values-hi/strings.xml
@@ -1401,6 +1401,10 @@
काली ज़मीन, सफ़ेद टाइप, चुने, फ़ोकस या दबाए गए हर चीज़ के लिए ब्लू रंग।
इलेक्ट्रिक नेवी
ब्लू रंग ज़्यादा चमकीला, उन सतहों पर जो ग्रे के बजाय नेवी की ओर झुकती हैं।
+ Inner Gamer
+ इंद्रधनुष के रंगों में बदलते रंग। Android की एनिमेशन सेटिंग का पालन करता है।
+ गति
+ रंग कितनी तेज़ी से बदलें।
ग्रेडिएंट
आपके अपने प्राथमिक और द्वितीयक रंग, बटनों और हाइलाइट पर मिश्रित।
प्राथमिक
diff --git a/app/src/main/res/values-hu/strings.xml b/app/src/main/res/values-hu/strings.xml
index 6be57ffd2..5e26a3d04 100644
--- a/app/src/main/res/values-hu/strings.xml
+++ b/app/src/main/res/values-hu/strings.xml
@@ -1401,6 +1401,10 @@
Fekete alap, fehér betűk, a kék minden kijelölt, fókuszált vagy lenyomott elemhez.
Elektromos tengerészkék
Fényesebb kék, szürke helyett tengerészkék felületeken.
+ Inner Gamer
+ A szivárvány színein végigfutó színek. Követi az Android animációs beállításait.
+ Sebesség
+ Milyen gyorsan váltanak a színek.
Színátmenet
Saját elsődleges és másodlagos színed, átmenettel a gombokon és a kiemeléseken.
Elsődleges
diff --git a/app/src/main/res/values-in/strings.xml b/app/src/main/res/values-in/strings.xml
index 776885a84..89e8a72da 100644
--- a/app/src/main/res/values-in/strings.xml
+++ b/app/src/main/res/values-in/strings.xml
@@ -1387,6 +1387,10 @@
Dasar hitam, tipe putih, biru untuk semua yang dipilih, difokuskan, atau ditekan.
Navy elektrik
Biru yang lebih cerah, pada permukaan yang condong ke navy, bukan abu-abu.
+ Inner Gamer
+ Warna yang berganti menyusuri pelangi. Mengikuti pengaturan animasi Android.
+ Kecepatan
+ Seberapa cepat warna berganti.
Gradasi
Warna primer dan sekunder pilihan Anda, dipadukan pada tombol dan sorotan.
Primer
diff --git a/app/src/main/res/values-it/strings.xml b/app/src/main/res/values-it/strings.xml
index d5fde44e5..38bafda84 100644
--- a/app/src/main/res/values-it/strings.xml
+++ b/app/src/main/res/values-it/strings.xml
@@ -1407,6 +1407,10 @@
Fondo nero, testo bianco, il blu per tutto ciò che è selezionato, attivo o premuto.
Blu elettrico
Il blu più brillante, su superfici che tendono al blu navy invece che al grigio.
+ Inner Gamer
+ Colori che scorrono lungo l\'arcobaleno. Rispetta le impostazioni di animazione di Android.
+ Velocità
+ Quanto velocemente cambiano i colori.
Gradiente
I tuoi colori primario e secondario, sfumati su pulsanti ed evidenziazioni.
Primario
diff --git a/app/src/main/res/values-ja/strings.xml b/app/src/main/res/values-ja/strings.xml
index 962a16946..18db0ce6f 100644
--- a/app/src/main/res/values-ja/strings.xml
+++ b/app/src/main/res/values-ja/strings.xml
@@ -1389,6 +1389,10 @@
黒の背景に白の文字、選択・フォーカス・押下時には青を使用します。
エレクトリックネイビー
より明るい青を、グレーではなくネイビー寄りの画面に使用します。
+ Inner Gamer
+ 虹色に変化し続けるカラー。Android のアニメーション設定に従います。
+ 速度
+ 色が切り替わる速さ。
グラデーション
自分で選んだプライマリとセカンダリの色を、ボタンやハイライトにグラデーションで使います。
プライマリ
diff --git a/app/src/main/res/values-ko/strings.xml b/app/src/main/res/values-ko/strings.xml
index 7d58f7a91..70e71aeba 100644
--- a/app/src/main/res/values-ko/strings.xml
+++ b/app/src/main/res/values-ko/strings.xml
@@ -1389,6 +1389,10 @@
검은색 배경에 흰색 글자, 선택·포커스·누름 상태에는 파란색을 사용합니다.
일렉트릭 네이비
회색 대신 네이비 톤의 화면에 더 밝은 파란색을 사용합니다.
+ Inner Gamer
+ 무지개 색으로 계속 바뀌는 색상입니다. Android의 애니메이션 설정을 따릅니다.
+ 속도
+ 색상이 바뀌는 속도입니다.
그라데이션
직접 고른 기본색과 보조색이 버튼과 강조 표시에 섞여 적용됩니다.
기본색
diff --git a/app/src/main/res/values-ms/strings.xml b/app/src/main/res/values-ms/strings.xml
index 3309b0ce8..37ec6b6cb 100644
--- a/app/src/main/res/values-ms/strings.xml
+++ b/app/src/main/res/values-ms/strings.xml
@@ -1387,6 +1387,10 @@
Latar hitam, teks putih, biru untuk semua yang dipilih, difokus atau ditekan.
Navy elektrik
Biru lebih cerah, pada permukaan yang lebih cenderung navy daripada kelabu.
+ Inner Gamer
+ Warna yang bertukar merentasi pelangi. Mengikut tetapan animasi Android.
+ Kelajuan
+ Seberapa pantas warna bertukar.
Kecerunan
Warna utama dan sekunder pilihan anda, diadun pada butang dan sorotan.
Utama
diff --git a/app/src/main/res/values-nb/strings.xml b/app/src/main/res/values-nb/strings.xml
index 67ba109eb..d0ba1beaf 100644
--- a/app/src/main/res/values-nb/strings.xml
+++ b/app/src/main/res/values-nb/strings.xml
@@ -1401,6 +1401,10 @@
Svart bakgrunn, hvit skrift, det blå for alt som er valgt, fokusert eller trykket.
Elektrisk marineblå
Det blå lysere, på flater som lener mer mot marineblått enn grått.
+ Inner Gamer
+ Farger som går gjennom regnbuen. Følger Androids animasjonsinnstillinger.
+ Hastighet
+ Hvor raskt fargene skifter.
Gradient
Dine egne primær- og sekundærfarger, blandet på knapper og uthevinger.
Primær
diff --git a/app/src/main/res/values-nl/strings.xml b/app/src/main/res/values-nl/strings.xml
index 183254ed4..a004d04e6 100644
--- a/app/src/main/res/values-nl/strings.xml
+++ b/app/src/main/res/values-nl/strings.xml
@@ -1401,6 +1401,10 @@
Zwarte achtergrond, witte tekst, het blauw voor alles wat geselecteerd, gefocust of ingedrukt is.
Elektrisch marineblauw
Het blauw feller, op vlakken die naar marineblauw neigen in plaats van grijs.
+ Inner Gamer
+ Kleuren die door de regenboog lopen. Volgt de animatie-instellingen van Android.
+ Snelheid
+ Hoe snel de kleuren wisselen.
Kleurverloop
Je eigen primaire en secundaire kleur, doorlopend op knoppen en accenten.
Primair
diff --git a/app/src/main/res/values-pl/strings.xml b/app/src/main/res/values-pl/strings.xml
index 92c261d45..776ec2150 100644
--- a/app/src/main/res/values-pl/strings.xml
+++ b/app/src/main/res/values-pl/strings.xml
@@ -1429,6 +1429,10 @@
Czarne tło, biały tekst i niebieski dla wszystkiego, co zaznaczone, aktywne lub naciśnięte.
Elektryczny granat
Jaśniejszy niebieski na powierzchniach wpadających w granat zamiast w szarość.
+ Inner Gamer
+ Kolory przechodzące przez całą tęczę. Szanuje ustawienia animacji Androida.
+ Prędkość
+ Jak szybko zmieniają się kolory.
Gradient
Własny kolor podstawowy i dodatkowy, płynnie przechodzące na przyciskach i wyróżnieniach.
Podstawowy
diff --git a/app/src/main/res/values-pt-rPT/strings.xml b/app/src/main/res/values-pt-rPT/strings.xml
index c5dc17cb0..5c0b03809 100644
--- a/app/src/main/res/values-pt-rPT/strings.xml
+++ b/app/src/main/res/values-pt-rPT/strings.xml
@@ -1407,6 +1407,10 @@
Fundo preto, texto branco e o azul para tudo o que está selecionado, focado ou premido.
Azul-marinho elétrico
O azul mais vivo, em superfícies que tendem para o azul-marinho em vez do cinzento.
+ Inner Gamer
+ Cores que percorrem o arco-íris. Respeita as definições de animação do Android.
+ Velocidade
+ Com que rapidez as cores mudam.
Gradiente
As suas próprias cores primária e secundária, combinadas nos botões e destaques.
Primária
diff --git a/app/src/main/res/values-pt/strings.xml b/app/src/main/res/values-pt/strings.xml
index a94b36b00..1af04d01d 100644
--- a/app/src/main/res/values-pt/strings.xml
+++ b/app/src/main/res/values-pt/strings.xml
@@ -1407,6 +1407,10 @@
Fundo preto, texto branco e o azul em tudo que estiver selecionado, em foco ou pressionado.
Marinho elétrico
O azul mais vivo, sobre superfícies puxadas para o marinho em vez do cinza.
+ Inner Gamer
+ Cores que percorrem o arco-íris. Respeita as configurações de animação do Android.
+ Velocidade
+ Com que rapidez as cores mudam.
Gradiente
Suas próprias cores primária e secundária, combinadas em botões e destaques.
Primária
diff --git a/app/src/main/res/values-ro/strings.xml b/app/src/main/res/values-ro/strings.xml
index 1fdb69d8e..5295bc5b9 100644
--- a/app/src/main/res/values-ro/strings.xml
+++ b/app/src/main/res/values-ro/strings.xml
@@ -1415,6 +1415,10 @@
Fundal negru, text alb, albastrul pentru tot ce este selectat, focalizat sau apăsat.
Bleumarin electric
Albastrul mai strălucitor, pe suprafețe care tind spre bleumarin în loc de gri.
+ Inner Gamer
+ Culori care parcurg curcubeul. Respectă setările de animație din Android.
+ Viteză
+ Cât de repede se schimbă culorile.
Gradient
Culorile tale primară și secundară, combinate pe butoane și evidențieri.
Primară
diff --git a/app/src/main/res/values-ru/strings.xml b/app/src/main/res/values-ru/strings.xml
index c782aae6b..f03db3687 100644
--- a/app/src/main/res/values-ru/strings.xml
+++ b/app/src/main/res/values-ru/strings.xml
@@ -1431,6 +1431,10 @@
Черный фон, белый текст, синий — для всего выбранного, активного или нажатого.
Электрик
Более яркий синий на поверхностях темно-синего, а не серого оттенка.
+ Inner Gamer
+ Цвета, плавно переходящие по всей радуге. Учитывает настройки анимации Android.
+ Скорость
+ Как быстро меняются цвета.
Градиент
Ваши основной и дополнительный цвета, плавно переходящие на кнопках и выделениях.
Основной
diff --git a/app/src/main/res/values-sv/strings.xml b/app/src/main/res/values-sv/strings.xml
index c6659abfd..4f50f51a0 100644
--- a/app/src/main/res/values-sv/strings.xml
+++ b/app/src/main/res/values-sv/strings.xml
@@ -1401,6 +1401,10 @@
Svart bakgrund, vit text, den blå färgen för allt som är markerat, i fokus eller nedtryckt.
Elektrisk marinblå
Den blå färgen klarare, på ytor som lutar åt marinblått i stället för grått.
+ Inner Gamer
+ Färger som växlar genom regnbågen. Följer Androids animationsinställningar.
+ Hastighet
+ Hur snabbt färgerna växlar.
Gradient
Dina egna primära och sekundära färger, blandade på knappar och markeringar.
Primär
diff --git a/app/src/main/res/values-th/strings.xml b/app/src/main/res/values-th/strings.xml
index 7dd606217..f486774a5 100644
--- a/app/src/main/res/values-th/strings.xml
+++ b/app/src/main/res/values-th/strings.xml
@@ -1387,6 +1387,10 @@
พื้นดำ ตัวอักษรขาว สีฟ้าสำหรับทุกสิ่งที่ถูกเลือก โฟกัส หรือกด
กรมท่าไฟฟ้า
สีฟ้าสว่างขึ้น บนพื้นผิวที่เอียงไปทางกรมท่ามากกว่าเทา
+ Inner Gamer
+ สีที่เปลี่ยนวนไปตามสายรุ้ง ทำงานตามการตั้งค่าแอนิเมชันของ Android
+ ความเร็ว
+ สีเปลี่ยนเร็วแค่ไหน
ไล่เฉดสี
สีหลักและสีรองที่คุณเลือกเอง ผสมกันบนปุ่มและส่วนที่เน้น
สีหลัก
diff --git a/app/src/main/res/values-tr/strings.xml b/app/src/main/res/values-tr/strings.xml
index 5422b926c..c112dd6b6 100644
--- a/app/src/main/res/values-tr/strings.xml
+++ b/app/src/main/res/values-tr/strings.xml
@@ -1395,6 +1395,10 @@
Siyah zemin, beyaz yazı; seçilen, odaklanan veya basılan her şey için mavi.
Elektrik laciverti
Daha parlak mavi; gri yerine laciverte çalan yüzeylerde.
+ Inner Gamer
+ Gökkuşağında dolaşan renkler. Android\'in animasyon ayarlarına uyar.
+ Hız
+ Renklerin ne kadar hızlı değiştiği.
Geçiş
Kendi birincil ve ikincil renklerin, düğmelerde ve vurgularda harmanlanır.
Birincil
diff --git a/app/src/main/res/values-uk/strings.xml b/app/src/main/res/values-uk/strings.xml
index e1753cba3..b361c61fa 100644
--- a/app/src/main/res/values-uk/strings.xml
+++ b/app/src/main/res/values-uk/strings.xml
@@ -1429,6 +1429,10 @@
Чорне тло, білий текст і синій для всього вибраного, у фокусі чи натиснутого.
Електричний темно-синій
Яскравіший синій на поверхнях із темно-синім відтінком замість сірого.
+ Inner Gamer
+ Кольори, що плавно змінюються по всій веселці. Враховує налаштування анімації Android.
+ Швидкість
+ Як швидко змінюються кольори.
Градієнт
Ваші основний і додатковий кольори, що плавно переходять на кнопках і виділеннях.
Основний
diff --git a/app/src/main/res/values-vi/strings.xml b/app/src/main/res/values-vi/strings.xml
index 91bf30f13..a5aa6f9ff 100644
--- a/app/src/main/res/values-vi/strings.xml
+++ b/app/src/main/res/values-vi/strings.xml
@@ -1387,6 +1387,10 @@
Nền đen, chữ trắng, xanh cho mọi thứ được chọn, lấy nét hoặc nhấn.
Xanh điện navy
Màu xanh sáng hơn, trên các bề mặt nghiêng về navy thay vì xám.
+ Inner Gamer
+ Màu sắc chuyển dần qua cả dải cầu vồng. Tuân theo cài đặt hiệu ứng động của Android.
+ Tốc độ
+ Màu đổi nhanh đến mức nào.
Chuyển màu
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.
Chính
diff --git a/app/src/main/res/values-zh-rCN/strings.xml b/app/src/main/res/values-zh-rCN/strings.xml
index e4a6c6933..ca9a75287 100644
--- a/app/src/main/res/values-zh-rCN/strings.xml
+++ b/app/src/main/res/values-zh-rCN/strings.xml
@@ -1465,6 +1465,10 @@
黑色背景、白色文字,选中、聚焦或按下的元素使用蓝色。
电光藏青
更明亮的蓝色,配以偏藏青而非灰色的界面。
+ Inner Gamer
+ 在彩虹色之间循环变化的颜色。遵循 Android 的动画设置。
+ 速度
+ 颜色循环的快慢。
渐变
你自己选择的主色和辅色,在按钮和高亮处渐变呈现。
主色
diff --git a/app/src/main/res/values-zh-rHK/strings.xml b/app/src/main/res/values-zh-rHK/strings.xml
index 72cc6cdda..74460d151 100644
--- a/app/src/main/res/values-zh-rHK/strings.xml
+++ b/app/src/main/res/values-zh-rHK/strings.xml
@@ -1389,6 +1389,10 @@
黑色背景、白色文字,所有已選取、焦點所在或按下的項目都使用藍色。
電光海軍藍
更明亮的藍色,搭配偏海軍藍而非灰色的介面。
+ Inner Gamer
+ 在彩虹色之間循環變化的顏色。遵循 Android 的動畫設定。
+ 速度
+ 顏色循環的快慢。
漸層
你自行選擇的主色與輔色,在按鈕與強調處以漸層呈現。
主色
diff --git a/app/src/main/res/values-zh-rTW/strings.xml b/app/src/main/res/values-zh-rTW/strings.xml
index 19d11a7e8..795be8c5e 100644
--- a/app/src/main/res/values-zh-rTW/strings.xml
+++ b/app/src/main/res/values-zh-rTW/strings.xml
@@ -1389,6 +1389,10 @@
黑色背景、白色文字,選取、聚焦或按下的項目使用藍色。
電光藏青
更亮的藍色,搭配偏藏青而非灰色的介面。
+ Inner Gamer
+ 在彩虹色之間循環變化的顏色。遵循 Android 的動畫設定。
+ 速度
+ 顏色循環的快慢。
漸層
你自行選擇的主色與輔色,在按鈕與強調處以漸層呈現。
主色
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index cf80262af..e62952c4f 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -1458,6 +1458,10 @@
Black ground, white type, the blue for everything selected, focused or pressed.
Electric navy
The blue brighter, on surfaces that lean navy instead of grey.
+ Inner Gamer
+ Colors that cycle through the rainbow. Follows Android\'s animation settings.
+ Speed
+ How fast the colors cycle.
Gradient
Your own primary and secondary colors, blended on buttons and highlights.
Primary
diff --git a/app/src/test/java/com/droiddeck/launcher/ui/ThemeColorsTest.kt b/app/src/test/java/com/droiddeck/launcher/ui/ThemeColorsTest.kt
index b6f4de204..851c3dfc4 100644
--- a/app/src/test/java/com/droiddeck/launcher/ui/ThemeColorsTest.kt
+++ b/app/src/test/java/com/droiddeck/launcher/ui/ThemeColorsTest.kt
@@ -132,4 +132,40 @@ class ThemeColorsTest {
assertTrue(Themes.all.any { it.id == Themes.GRADIENT })
assertEquals(Themes.GRAPHITE, Themes.byId("nonsense").id)
}
+
+ @Test fun innerGamerSitsJustAboveGradientInTheThemeList() {
+ val ids = Themes.all.map { it.id }
+ assertEquals(ids.indexOf(Themes.GRADIENT) - 1, ids.indexOf(Themes.INNER_GAMER))
+ }
+
+ @Test fun innerGamerButtonTextIsReadableAlongTheGradientAtEveryHue() {
+ var hue = 0f
+ while (hue < 360f) {
+ val p = Themes.innerGamer(hue)
+ assertEquals(Themes.INNER_GAMER, p.id)
+ for (i in 0..100) {
+ val f = i / 100f
+ val blend = Color(
+ p.primary.red + (p.primary2.red - p.primary.red) * f,
+ p.primary.green + (p.primary2.green - p.primary.green) * f,
+ p.primary.blue + (p.primary2.blue - p.primary.blue) * f,
+ )
+ assertTrue("hue $hue at $f", contrast(p.onPrimary, blend) >= 4.49f)
+ }
+ hue += Themes.RGB_HUE_STEP
+ }
+ }
+
+ @Test fun innerGamerFollowsTheHueAndTheSpeedIsSavedAndKeptInRange() {
+ Themes.setRgbHue(120f)
+ assertEquals(Themes.innerGamer(120f).primary, Themes.byId(Themes.INNER_GAMER).primary)
+ Themes.setRgbSpeed(app, 7)
+ assertEquals(7, SessionPrefs.rgbSpeed(app))
+ Themes.setRgbSpeed(app, 99)
+ assertEquals(Themes.RGB_SPEEDS, Themes.rgbSpeed)
+ Themes.setRgbSpeed(app, 0)
+ assertEquals(1, SessionPrefs.rgbSpeed(app))
+ Themes.setRgbSpeed(app, 1)
+ assertTrue(Themes.rgbCycleMillis(1) > Themes.rgbCycleMillis(10))
+ }
}
diff --git a/docs/development/themes.md b/docs/development/themes.md
index b7f1a01eb..e7855c43f 100644
--- a/docs/development/themes.md
+++ b/docs/development/themes.md
@@ -23,3 +23,17 @@ Setup shows Primary and Secondary under the theme when Gradient is chosen, each
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.
+
+## Inner Gamer theme
+
+`Themes.INNER_GAMER` is an RGB theme: the accent walks round the colour wheel. It sits just above
+Gradient in the list, and Setup shows a Speed slider (1 to 10, `SessionPrefs.rgbSpeed`) under the
+theme while it is chosen.
+
+`Themes.innerGamer(hue)` builds the palette for one hue through `ThemeColors.palette`, so button text
+keeps the same contrast along the gradient at every hue. `DroidDeckTheme` runs one
+`rememberInfiniteTransition` while Inner Gamer is chosen, so the system's animation clock drives it.
+The duration goes through `Motion.ms`, so the colour holds still when animations are off in the app
+or in Android's own settings. The hue is written to `Themes.rgbHue` in 3° steps, which restyles the
+app only when the colour visibly moves; a slow cycle costs few recompositions.
+