Skip to content

[18.0][IMP] web_dark_mode: appearance in the preferences, follow the device - #3754

Open
klodr wants to merge 1 commit into
OCA:18.0from
klodr:18.0-imp-web_dark_mode-appearance
Open

klodr wants to merge 1 commit into
OCA:18.0from
klodr:18.0-imp-web_dark_mode-appearance

Conversation

@klodr

@klodr klodr commented Oct 25, 2026

Copy link
Copy Markdown

Why

The dark mode is binary today. Once a user clicks the Dark Mode switch, there is no way back to following the device from the interface, and the Device Dependent Dark Mode box is only read on the very first visit (when there is no color_scheme cookie yet). A device that switches to dark in the evening (automatic appearance of macOS, iOS, Android) is therefore not followed.

What changes

  • Preferences: an Appearance choice — Default (follows the device), Light, Dark — next to the language and the time zone, instead of the Device Dependent Dark Mode box. It is a computed field over dark_mode and dark_mode_device_dependent, written back on change, self-readable and self-writeable.
  • Saving the Preferences reloads the page, so the new appearance applies at once (it is read when the page loads: cookie and style sheets). Any other action returned by preference_save is left unchanged.
  • Following the device: when the user follows the device (dark_mode_device_dependent, now sent in session_info), the theme follows it at every page load and as soon as prefers-color-scheme changes. It only reloads when the cookie differs, so there is no reload loop.
  • Dark Mode switch of the user menu: kept (same place, same id), it now stores a choice made by hand (dark_mode and dark_mode_device_dependent = False). If the write fails, the cookie goes back to what it was, without blocking the UI nor reloading.
  • Defaults and compatibility: the default of dark_mode_device_dependent is unchanged (False); existing users keep their settings (they see Light or Dark, or Default if they had checked the box). darkModeSwitchItem, colorSchemeService and env.services.color_scheme.switchColorScheme() are kept.
  • The request pushed on the request stack by the existing Python test is now popped after the class.

Version 18.0.1.1.0. Translations will go through Weblate.

Tests

  • Python (6): appearance over the two settings, one's own appearance only, the Preferences view and page reload, other actions untouched, and a real HTTP session: Dark then Default with a cookie still dark → the server no longer forces it and the session tells the web client to follow the device; Light/Dark are applied to the cookie at once.
  • Hoot (8, 28 assertions): the switch stores a choice made by hand (on the current user); a refused write gives the cookie back (with and without a previous cookie), no block, no reload; Default on a light device turns light with one reload; first load without cookie on a dark device, then the next load; the theme follows the device when it switches; a choice made by hand never follows the device.
  • Each new rule removed on purpose makes at least one of these tests fail.
  • Checked by hand on a fresh 18.0 database with web_dark_mode only: Preferences → Dark → reloaded in dark; → Default → back to the light device theme.

Related, not overlapping: #3458 (new tabs at the root URL), and the 19.0 work that follows the device on load and stores the settings in res.users.settings.

The dark mode was binary: once the switch was used, the user could not go
back to following the device from the interface, and "Device Dependent Dark
Mode" was only read on the very first visit (no cookie yet), so the theme did
not follow a device switching to dark in the evening.

- Preferences: an "Appearance" choice (Default = follow the device, Light,
  Dark), next to the language and the time zone, instead of the "Device
  Dependent Dark Mode" box. It is a view of dark_mode and
  dark_mode_device_dependent, written back on change; self-readable and
  writeable. Saving the Preferences reloads the page, so the new appearance
  applies at once.
- When the user follows the device, the theme follows it at every page load
  and as soon as prefers-color-scheme changes (no reload loop).
- The "Dark Mode" switch of the user menu is kept and stores a choice made by
  hand (dark_mode and dark_mode_device_dependent = False); if the write
  fails, the cookie goes back to what it was, without blocking nor reloading.
- The default of dark_mode_device_dependent is unchanged (False).
- Tests: Python (appearance, rights, view, page reload, real HTTP session with
  the color_scheme cookie) and Hoot; the request pushed by the existing test
  is now popped after the class.

Signed-off-by: Claude Perrin <klodr@users.noreply.github.com>

@ljmnoonan ljmnoonan left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hello @klodr, and thank you for your contribution.

I am a little bit leery of letting the system just reload the page without asking. Take filters for example: you are trying to find a specific record and have spent considerable time narrowing down your filters. Suddenly, your system decides it's bedtime and poof, the page has reloaded and you need to start all over again.

Another example: you start a sale, but the customer has not told you who he is yet. You enter some items that he wants to buy, but before you can select the customer the page reloads and you need to start all over again.

Odoo even prevents you from accidentally reloading from the front end when a form is dirty without all required fields by triggering a popup. Maybe this would be a solution; trigger a popup asking if you want to reload instead of just doing it

Image

Overall, I think it would be a better idea to simply do what I proposed here #3458 (comment) but which I have still not gotten the time to implement. Indeed, I do not actually use 18.0 anymore, so i have no motivation to do so.

Some more comments:

Did this involve AI? If so, please read and conform to https://github.com/OCA/.github/blob/master/AI_POLICY.md

I don't know if it is an official policy or not, but I have not noticed @author: being inserted into the copyright section anywhere else. Probably best to get rid of that.

Why is dark_mode_device_dependent still existing if you now use color_scheme_mode?

Default theme should probably be renamed to System

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants