diff options
| author | Peter Stone <thepeterstone@gmail.com> | 2026-07-13 09:55:32 +0000 |
|---|---|---|
| committer | Peter Stone <thepeterstone@gmail.com> | 2026-07-16 02:39:57 +0000 |
| commit | 2c041a9d1e370f14fffd15e9f4a6113002f05b1b (patch) | |
| tree | b6b0070d8e3866834c787755bd6a8cdb65d3d35f /android | |
| parent | b3176c0ba3acdeb5de973dfef7712bdc9dfab785 (diff) | |
feat(widget): add WidgetTextSize enum with independent header/content scaling
Diffstat (limited to 'android')
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")) + } +} |
