summaryrefslogtreecommitdiff
path: root/android/app/src
diff options
context:
space:
mode:
authorPeter Stone <thepeterstone@gmail.com>2026-07-13 09:55:32 +0000
committerPeter Stone <thepeterstone@gmail.com>2026-07-16 02:39:57 +0000
commit2c041a9d1e370f14fffd15e9f4a6113002f05b1b (patch)
treeb6b0070d8e3866834c787755bd6a8cdb65d3d35f /android/app/src
parentb3176c0ba3acdeb5de973dfef7712bdc9dfab785 (diff)
feat(widget): add WidgetTextSize enum with independent header/content scaling
Diffstat (limited to 'android/app/src')
-rw-r--r--android/app/src/main/java/org/terst/doot/widget/data/DataStore.kt1
-rw-r--r--android/app/src/main/java/org/terst/doot/widget/ui/WidgetTextSize.kt38
-rw-r--r--android/app/src/test/java/org/terst/doot/widget/ui/WidgetTextSizeTest.kt42
3 files changed, 81 insertions, 0 deletions
diff --git a/android/app/src/main/java/org/terst/doot/widget/data/DataStore.kt b/android/app/src/main/java/org/terst/doot/widget/data/DataStore.kt
index d2f2cbb..7153cf8 100644
--- a/android/app/src/main/java/org/terst/doot/widget/data/DataStore.kt
+++ b/android/app/src/main/java/org/terst/doot/widget/data/DataStore.kt
@@ -17,4 +17,5 @@ object Keys {
val NOW = stringPreferencesKey("now")
val LAST_UPDATED = longPreferencesKey("last_updated")
val IS_REFRESHING = booleanPreferencesKey("is_refreshing")
+ val TEXT_SIZE = stringPreferencesKey("text_size")
}
diff --git a/android/app/src/main/java/org/terst/doot/widget/ui/WidgetTextSize.kt b/android/app/src/main/java/org/terst/doot/widget/ui/WidgetTextSize.kt
new file mode 100644
index 0000000..e44b983
--- /dev/null
+++ b/android/app/src/main/java/org/terst/doot/widget/ui/WidgetTextSize.kt
@@ -0,0 +1,38 @@
+package org.terst.doot.widget.ui
+
+import androidx.compose.ui.unit.TextUnit
+import androidx.compose.ui.unit.sp
+import androidx.glance.text.FontWeight
+
+/**
+ * Header and content are independent knobs (currently seeded with the same
+ * numbers) so either can be retuned later without affecting the other.
+ * SMALL reproduces the widget's original, pre-setting appearance exactly.
+ */
+enum class WidgetTextSize(
+ val headerScale: Float,
+ val headerWeightBump: Int,
+ val contentScale: Float,
+ val contentWeightBump: Int
+) {
+ SMALL(1.0f, 0, 1.0f, 0),
+ NORMAL(1.15f, 1, 1.15f, 1),
+ LARGE(1.3f, 2, 1.3f, 2);
+
+ companion object {
+ fun fromPref(raw: String?): WidgetTextSize =
+ raw?.let { name -> entries.find { it.name == name } } ?: NORMAL
+ }
+}
+
+private val weightLadder = listOf(FontWeight.Normal, FontWeight.Medium, FontWeight.Bold)
+
+private fun bumpWeight(base: FontWeight, bump: Int): FontWeight {
+ val idx = weightLadder.indexOf(base).coerceAtLeast(0)
+ return weightLadder[(idx + bump).coerceAtMost(weightLadder.lastIndex)]
+}
+
+fun WidgetTextSize.scaledHeaderSize(baseSp: Int): TextUnit = (baseSp * headerScale).sp
+fun WidgetTextSize.scaledHeaderWeight(base: FontWeight): FontWeight = bumpWeight(base, headerWeightBump)
+fun WidgetTextSize.scaledContentSize(baseSp: Int): TextUnit = (baseSp * contentScale).sp
+fun WidgetTextSize.scaledContentWeight(base: FontWeight): FontWeight = bumpWeight(base, contentWeightBump)
diff --git a/android/app/src/test/java/org/terst/doot/widget/ui/WidgetTextSizeTest.kt b/android/app/src/test/java/org/terst/doot/widget/ui/WidgetTextSizeTest.kt
new file mode 100644
index 0000000..b0826b5
--- /dev/null
+++ b/android/app/src/test/java/org/terst/doot/widget/ui/WidgetTextSizeTest.kt
@@ -0,0 +1,42 @@
+package org.terst.doot.widget.ui
+
+import androidx.glance.text.FontWeight
+import org.junit.Assert.assertEquals
+import org.junit.Test
+
+class WidgetTextSizeTest {
+
+ @Test
+ fun `SMALL reproduces base size and weight unchanged`() {
+ assertEquals(14f, WidgetTextSize.SMALL.scaledContentSize(14).value, 0.001f)
+ assertEquals(FontWeight.Normal, WidgetTextSize.SMALL.scaledContentWeight(FontWeight.Normal))
+ assertEquals(FontWeight.Bold, WidgetTextSize.SMALL.scaledHeaderWeight(FontWeight.Bold))
+ }
+
+ @Test
+ fun `NORMAL scales size by 1_15x and bumps weight one step`() {
+ assertEquals(16.1f, WidgetTextSize.NORMAL.scaledContentSize(14).value, 0.001f)
+ assertEquals(FontWeight.Medium, WidgetTextSize.NORMAL.scaledContentWeight(FontWeight.Normal))
+ assertEquals(FontWeight.Bold, WidgetTextSize.NORMAL.scaledHeaderWeight(FontWeight.Medium))
+ }
+
+ @Test
+ fun `LARGE scales size by 1_3x and bumps weight two steps`() {
+ assertEquals(18.2f, WidgetTextSize.LARGE.scaledContentSize(14).value, 0.001f)
+ assertEquals(FontWeight.Bold, WidgetTextSize.LARGE.scaledContentWeight(FontWeight.Normal))
+ }
+
+ @Test
+ fun `weight bump caps at Bold instead of overflowing`() {
+ assertEquals(FontWeight.Bold, WidgetTextSize.LARGE.scaledContentWeight(FontWeight.Bold))
+ assertEquals(FontWeight.Bold, WidgetTextSize.LARGE.scaledHeaderWeight(FontWeight.Medium))
+ }
+
+ @Test
+ fun `fromPref falls back to NORMAL for missing or invalid values, else parses by name`() {
+ assertEquals(WidgetTextSize.NORMAL, WidgetTextSize.fromPref(null))
+ assertEquals(WidgetTextSize.NORMAL, WidgetTextSize.fromPref("bogus"))
+ assertEquals(WidgetTextSize.SMALL, WidgetTextSize.fromPref("SMALL"))
+ assertEquals(WidgetTextSize.LARGE, WidgetTextSize.fromPref("LARGE"))
+ }
+}