Skip to content

feat(theme): persist useWallpaperColors preference + dynamic ColorScheme branching#116

Merged
ilmoniemi merged 3 commits into
mainfrom
feature/88
May 14, 2026
Merged

feat(theme): persist useWallpaperColors preference + dynamic ColorScheme branching#116
ilmoniemi merged 3 commits into
mainfrom
feature/88

Conversation

@ilmoniemi
Copy link
Copy Markdown
Contributor

What

Adds a third DataStore-backed preference (use_wallpaper_colors, default false) on AppPreferences, with a Flow<Boolean> and suspend setUseWallpaperColors. MainActivity.setContent collects it next to themeMode and passes it into the existing dynamicColor: Boolean parameter on PyrycodeMobileTheme. The theme's internal Build.VERSION.SDK_INT >= S gate already routes pre-S devices to the brand palette even when dynamicColor = true, so no extra SDK check is needed at the call site. Theme.kt is untouched.

This slice is invisible-by-default — the only way to flip the preference is programmatically. The visible Settings switch row lands in #89.

Issue

Closes #88

Testing

  • ./gradlew test — passes; adds useWallpaperColors_defaultsToFalse and setUseWallpaperColors_roundTripsBothValues to AppPreferencesTest (real PreferenceDataStoreFactory + TemporaryFolder, mirroring the existing pairedServerExists / themeMode tests). Confirmed RED → GREEN before commit.
  • ./gradlew lint — clean.
  • ./gradlew assembleDebug — succeeds.
  • ./gradlew connectedAndroidTest — not run (no device/emulator attached in this worktree); no instrumented tests added in this slice.
  • ./gradlew spotlessCheck — fails on a pre-existing violation in ui/settings/ThemePickerDialog.kt (from feat(theme): persist ThemeMode preference + reactive PyrycodeMobileTheme wiring #86) that is outside this ticket's scope. The files in this diff are spotless-clean.

Manual smoke test (re-collection re-renders without process restart)

Per AC: collectAsStateWithLifecycle(initialValue = false) makes dynamicColor a state read inside the setContent composition, so writes via setUseWallpaperColors trigger recomposition and the when block inside PyrycodeMobileTheme re-resolves the ColorScheme. I did not run an emulator-side toggle in this PR because there is no caller for the setter yet (#89 wires it). The setter is exercised by the round-trip unit test, and the live-re-theme behavior is the standard semantics of collectAsStateWithLifecycle already used for themeMode in #86.

Architecture compliance

Follows docs/specs/architecture/88-use-wallpaper-colors-preference.md exactly:

  • Mirrors pairedServerExists's shape for the new key + flow + setter.
  • New companion constant USE_WALLPAPER_COLORS = booleanPreferencesKey("use_wallpaper_colors").
  • Composition-root collection added next to themeMode; theme call gains dynamicColor = useWallpaperColors.
  • Theme.kt not edited — extends the feat(theme): persist ThemeMode preference + reactive PyrycodeMobileTheme wiring #86 convention of "caller passes a Boolean, theme function resolves internally."
  • No DI changes (per spec — AppPreferences is already a Koin single).

🤖 Generated with Claude Code

ilmoniemi and others added 2 commits May 14, 2026 10:28
…eme branching

Adds a third DataStore key (use_wallpaper_colors, default false) with a
Flow<Boolean> + suspend setter on AppPreferences, then collects it at the
composition root and threads it into PyrycodeMobileTheme's existing
dynamicColor parameter. The theme's internal SDK gate (Build.VERSION.SDK_INT
>= S) already falls back to the brand palette on pre-S devices when the
preference is true, so no Android-version branching is needed at the call
site. Theme.kt is untouched — its 18+ @Preview composables continue to use
the default dynamicColor = false.

Invisible-by-default: the only path to flip the preference programmatically
is the new setter, consumed by sibling ticket #89 (Settings switch row).

Closes #88

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@ilmoniemi
Copy link
Copy Markdown
Contributor Author

Code Review: #88

Decision: PASS

Findings

Summary

The diff matches docs/specs/architecture/88-use-wallpaper-colors-preference.md exactly:

  • AppPreferences.kt:31-36,41 — new boolean key + flow + suspend setter cloned verbatim from the pairedServerExists shape, as the spec prescribed. booleanPreferencesKey("use_wallpaper_colors") with a ?: false default. No new imports.
  • MainActivity.kt:62-63,70 — flow collected with collectAsStateWithLifecycle(initialValue = false) right next to the existing themeMode collection; PyrycodeMobileTheme call gains one named arg dynamicColor = useWallpaperColors. Initial value matches persisted default — no first-frame flash.
  • Theme.kt correctly not edited. Reuses the existing dynamicColor: Boolean = false parameter whose internal Build.VERSION.SDK_INT >= S gate (Theme.kt:275) handles the pre-S fallthrough to the brand palette. This is the right call: changing PyrycodeMobileTheme's signature would have rippled through 18+ @Preview composables, and the spec explicitly forbade it.
  • AppPreferencesTest.kt:80-95useWallpaperColors_defaultsToFalse + setUseWallpaperColors_roundTripsBothValues (with an extra true → false step at the end so the final state is non-default). Mirrors the existing pairedServerExists test pattern. The spec's third optional test (flowReemitsAfterWrite) was correctly dropped as redundant — each first() resubscribes, so the round-trip already exercises re-emission.

Mechanical / blast-radius checks

  • Diff is purely additive — no signature changes, no removals. Zero call sites to update.
  • No Color(0xFF…) / TextStyle() literals introduced (invisible-by-default slice; no UI surface).
  • No android.* imports in data/ (portability rule respected).
  • No !!, no GlobalScope, no runBlocking outside tests, no direct Dispatchers.IO.
  • No new dependencies in gradle/libs.versions.toml.

Architecture compliance

Matches the convention #86 established (caller passes a Boolean, theme function resolves internally). State + concurrency model is identical to themeMode and pairedServerExists. The decision to skip error handling at this layer is consistent with existing precedent and the spec's evidence-based-fix call-out.

…nching (#88)

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@ilmoniemi ilmoniemi merged commit fa08500 into main May 14, 2026
1 check failed
@ilmoniemi ilmoniemi deleted the feature/88 branch May 14, 2026 07:36
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat(theme): persist useWallpaperColors preference + dynamic ColorScheme branching

1 participant