Skip to content

feat(settings): wire "Use wallpaper colors" switch to AppPreferences#117

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

feat(settings): wire "Use wallpaper colors" switch to AppPreferences#117
ilmoniemi merged 3 commits into
mainfrom
feature/89

Conversation

@ilmoniemi
Copy link
Copy Markdown
Contributor

Summary

  • Replaces the local-only materialYou placeholder row in Settings → Appearance with a VM-backed, SDK-gated switch row bound to AppPreferences.useWallpaperColors.
  • Extends SettingsViewModel with useWallpaperColors: StateFlow<Boolean> and onToggleUseWallpaperColors(enabled), mirroring the existing themeMode / onSelectTheme pair line-for-line.
  • On Android 12+: switch is enabled, reflects persisted state, and toggling fans out via the existing composition-root collector wired in feat(theme): persist useWallpaperColors preference + dynamic ColorScheme branching #88 — live theme update, no restart.
  • On Android < 12: switch renders disabled with helper text "Requires Android 12 or newer" (structurally unreachable today since Min SDK 33 > S, but implemented per AC feat(data): add ConversationRepository interface #3).
  • Label diverges from Figma node 17-2 per the spec's documented decision: ticket body says "Use wallpaper colors"; Figma still shows the older "Use Material You dynamic color" copy.

Issue

Closes #89

Testing

  • ./gradlew :app:testDebugUnitTest — pass. Three new tests in SettingsViewModelTest covering: initial state when no stored value, initial state mirrors persisted true, and a single round-trip test asserting both persistence and flow re-emission on toggle (true then false).
  • ./gradlew :app:lintDebug — pass.
  • ./gradlew :app:assembleDebug — pass.
  • ./gradlew connectedAndroidTest — not run (no device/emulator connected in this worktree).
  • ./gradlew spotlessCheck — pre-existing failures in ThemePickerDialog.kt and Theme.kt (both unchanged on this branch and failing on main already); my five modified files are clean. Out of scope per CLAUDE.md ("don't refactor adjacent code").

Architecture compliance

Implements the spec at docs/specs/architecture/89-settings-use-wallpaper-colors-switch-row.md verbatim:

  • VM gains the documented StateFlow + event method with WhileSubscribed(STOP_TIMEOUT_MILLIS) and initialValue = false.
  • SettingsScreen signature adds useWallpaperColors: Boolean and onToggleUseWallpaperColors: (Boolean) -> Unit in the order specified (state values, event callbacks, nav callbacks, modifier).
  • SDK gate computed once at composition build with Build.VERSION.SDK_INT >= Build.VERSION_CODES.S — no remember.
  • MainActivity settings route adds the second collectAsStateWithLifecycle() and wires both new params; the root-level dynamicColor collector at lines 62-63 is untouched.
  • New strings extracted to strings.xml; no fake AppPreferences introduced (real DataStore via TemporaryFolder).
  • No sealed SettingsState/SettingsEvent — deferred per the spec's premature-abstraction note.

🤖 Generated with Claude Code

ilmoniemi and others added 2 commits May 14, 2026 10:41
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Replaces the local-only `materialYou` placeholder in the Appearance
section with a VM-backed, SDK-gated row that mirrors and writes
`AppPreferences.useWallpaperColors`. On Android < 12 the switch is
disabled with helper text "Requires Android 12 or newer"; on Android
12+ toggling persists through DataStore and the composition root's
existing collector re-renders `PyrycodeMobileTheme(dynamicColor=...)`
live.

Closes #89

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

Code Review: #89

Decision: PASS

Findings

No MUST FIX or SHOULD FIX issues.

  • VM additions in SettingsViewModel.kt:22-27, 33-35 mirror the existing themeMode / onSelectTheme pair line-for-line, including reuse of STOP_TIMEOUT_MILLIS and initialValue = false (matches AppPreferences.useWallpaperColors's default-when-absent, so no one-frame flash).
  • Row replacement in SettingsScreen.kt:120-135 follows the spec exactly: SDK gate evaluated once at composition build (val dynamicColorSupported = Build.VERSION.SDK_INT >= Build.VERSION_CODES.S at line 59 — no unnecessary remember), enabled = dynamicColorSupported on the Switch gates taps via M3 idiom rather than nulling the callback, helper text routed through the existing supporting slot on the disabled-pre-S branch only.
  • The deleted var materialYou by remember { mutableStateOf(true) } removes the placeholder cleanly; no orphaned imports left behind. MainActivity.kt:200-213 wires the new state + event correctly without disturbing the root-level useWallpaperColors collector at lines 62-63 (the load-bearing piece for AC feat(data): add Conversation, Session, Message data classes #2's live re-theme).
  • Strings extracted to R.string.settings_use_wallpaper_colors and R.string.settings_use_wallpaper_colors_unsupported; the other inline-string switch rows on the screen are correctly left out of scope.
  • Tests in SettingsViewModelTest.kt:120-160 cover the three scenarios from the spec exactly (initial-false-when-absent, mirrors-persisted-true, toggle persists + flow re-emits), reusing the existing TemporaryFolder rig and the real AppPreferences. The combined persistence + re-emission test is the right call — splitting would just be noise.
  • Both @Preview composables updated with useWallpaperColors = false and onToggleUseWallpaperColors = {}. No third preview for the disabled-pre-S state (correct — Min SDK 33 > S, the branch is structurally unreachable today).
  • Figma fidelity (node 17-2): row layout, height, surface container, trailing Switch all match. Label divergence ("Use wallpaper colors" vs. Figma's "Use Material You dynamic color") is explicitly justified in the spec's Context section — ticket body is authoritative.
  • M3 token usage clean: ListItemDefaults.colors(containerColor = MaterialTheme.colorScheme.surface) via the existing SettingsRow; no hardcoded colors, typography, or shape values in the diff.

Summary

Implementation matches the architecture spec exactly. The row is properly VM-driven, the SDK gate uses the M3 enabled idiom (cleaner than null-ing onCheckedChange), and the tests exercise the full DataStore round-trip rather than mocking the layer under test. The independent VM-side collector pairs naturally with #88's composition-root collector — one DataStore write fans out to both subscribers, giving the live re-theme behavior AC #2 calls for. Ready to merge.

Documents the VM-backed, SDK-gated Material You switch added to
Settings → Appearance. New per-ticket file at codebase/89.md; updates
the Settings screen, Settings ViewModel, and App preferences feature
docs plus their INDEX summaries to reflect the second persisted
preference pair on SettingsViewModel and the second sibling collector
on appPreferences.useWallpaperColors.

Also fixes the instrumented SettingsScreenTest's two setContent blocks
that the developer commit (4089bd2) left calling SettingsScreen
without the new required useWallpaperColors / onToggleUseWallpaperColors
parameters — compileDebugAndroidTestKotlin was failing. Lesson
captured in codebase/89.md.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@ilmoniemi ilmoniemi merged commit 99ad592 into main May 14, 2026
1 check failed
@ilmoniemi ilmoniemi deleted the feature/89 branch May 14, 2026 07:56
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(ui): Settings — "Use wallpaper colors" switch row

1 participant