Skip to content

fix(android): window theme follows the app's light/dark choice - #4446

Merged
stamp-build[bot] merged 4 commits into
mainfrom
agent/lagoon/window-theme-follows-app
Nov 8, 2026
Merged

stamp-build[bot] merged 4 commits into
mainfrom
agent/lagoon/window-theme-follows-app

Conversation

@stamp-build

@stamp-build stamp-build Bot commented Nov 8, 2026

Copy link
Copy Markdown
Contributor

Lagoon from raft opened this pull request through Stamp
View in Stamp →


Root fix for Android embedded web pages / system dialogs ignoring dark mode (artin, dm:@⁠raft:artin (@bytemain):#91): Theme.Raft was android:Theme.Material.Light, so the window, WebView prefers-color-scheme, dialogs and pickers were always light.

  • Theme.Raft is day/night (values-night Base.Theme.Raft); the app appearance setting is the only source of truth, synced into the configuration night bits via RaftAppAppearanceRuntime host listener.
  • API 31+: UiModeManager.setApplicationNightMode (NO/YES/AUTO). API 29-30: per-Activity override config + in-place update on switch (no recreate).
  • Kept-alive WebViews built in the other mode are dropped, not reused.
  • Robolectric tests: mode mapping; Theme.Raft / Translucent / AppShellStarting resolve isLightTheme, bar icons, background on SDK 29/30/34 in both modes.

Needs a device check (Alpha) before merge; candidate for 1.22 only on artin OK.

🤖 Generated with Claude Code

Lagoon and others added 4 commits November 8, 2026 19:19
Theme.Raft was android:Theme.Material.Light, so the window was always light:
WebViews (prefers-color-scheme from android:isLightTheme), AlertDialogs,
pickers and the first frame's bar icons stayed light in the app's dark theme.

- Theme.Raft is now day/night: Base.Theme.Raft is Material Light in values/
  and Material (dark) in values-night/, with the bar-icon flags per mode;
  the shared items (no action bar, window background, accent, forceDark off)
  stay on Theme.Raft, so Translucent, Starting/AppShellStarting (and v31)
  inherit both modes. The window background was already night-qualified.
- RaftAndroidNightMode (installed in RaftApplication, driven by
  RaftAppAppearanceRuntime's host listener) puts the Settings > Appearance
  choice into the configuration's night bits: API 31+
  UiModeManager.setApplicationNightMode (NO / YES / AUTO for System),
  persisted by the system (also for the next cold start's splash); API 29-30
  per-Activity resources before onCreate (onActivityPreCreated + theme
  rebase), updated in place on a switch (views and Activity
  onConfigurationChanged, no recreation since hosts handle uiMode) and put
  back after system config changes and on start.
- RaftCmpActivity reads the mode from its resources after super in
  onConfigurationChanged, so Compose and the window agree.
- WebView keep-alive: prewarm builds on the page's context (theme carries the
  mode) before parking on the application context; a parked view built in
  the other mode is dropped instead of reused.
- RaftAndroidNightModeTest: night-bit mapping, and Theme.Raft /
  Translucent / AppShellStarting resolve light vs dark (isLightTheme, bar
  flags, window background) with the shared items kept (Robolectric 29/30/34).
- Changeset 1.22.0 android-window-follows-app-theme.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The window now follows the app's dark choice; black labels were unreadable on it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@stamp-build
stamp-build Bot merged commit 590aade into main Nov 8, 2026
10 checks passed
stamp-build Bot added a commit that referenced this pull request Nov 8, 2026
* fix(android): window theme follows the app's light/dark choice

Theme.Raft was android:Theme.Material.Light, so the window was always light:
WebViews (prefers-color-scheme from android:isLightTheme), AlertDialogs,
pickers and the first frame's bar icons stayed light in the app's dark theme.

- Theme.Raft is now day/night: Base.Theme.Raft is Material Light in values/
  and Material (dark) in values-night/, with the bar-icon flags per mode;
  the shared items (no action bar, window background, accent, forceDark off)
  stay on Theme.Raft, so Translucent, Starting/AppShellStarting (and v31)
  inherit both modes. The window background was already night-qualified.
- RaftAndroidNightMode (installed in RaftApplication, driven by
  RaftAppAppearanceRuntime's host listener) puts the Settings > Appearance
  choice into the configuration's night bits: API 31+
  UiModeManager.setApplicationNightMode (NO / YES / AUTO for System),
  persisted by the system (also for the next cold start's splash); API 29-30
  per-Activity resources before onCreate (onActivityPreCreated + theme
  rebase), updated in place on a switch (views and Activity
  onConfigurationChanged, no recreation since hosts handle uiMode) and put
  back after system config changes and on start.
- RaftCmpActivity reads the mode from its resources after super in
  onConfigurationChanged, so Compose and the window agree.
- WebView keep-alive: prewarm builds on the page's context (theme carries the
  mode) before parking on the application context; a parked view built in
  the other mode is dropped instead of reused.
- RaftAndroidNightModeTest: night-bit mapping, and Theme.Raft /
  Translucent / AppShellStarting resolve light vs dark (isLightTheme, bar
  flags, window background) with the shared items kept (Robolectric 29/30/34).
- Changeset 1.22.0 android-window-follows-app-theme.

* fix(android): widget setup labels use the theme's text colour

The window now follows the app's dark choice; black labels were unreadable on it.

* docs(changeset): window theme PR number

* Merge main into window-theme-follows-app

Co-authored-by: Lagoon <raft+lagoon@agents.stamp.build>
(cherry picked from commit 590aade)
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.

0 participants