From d3040e726ace5efb5cd5fe48f14409c4c9241972 Mon Sep 17 00:00:00 2001 From: Factory Agent Date: Fri, 23 Oct 2026 16:55:47 +0700 Subject: [PATCH 1/3] Follow the Windows app theme in Settings under auto --- apps/desktop-tauri/scripts/proof-check.mjs | 9 +- .../scripts/proof-scenarios.json | 22 ++++ .../src-tauri/src/commands/system.rs | 49 +++++++ apps/desktop-tauri/src-tauri/src/main.rs | 1 + apps/desktop-tauri/src/App.tsx | 6 +- apps/desktop-tauri/src/hooks/useTheme.test.ts | 123 +++++++++++++++++- apps/desktop-tauri/src/hooks/useTheme.ts | 75 ++++++++++- apps/desktop-tauri/src/lib/tauri.ts | 5 + apps/desktop-tauri/src/proof/install.ts | 7 +- apps/desktop-tauri/src/proof/params.ts | 11 ++ apps/desktop-tauri/src/proof/router.test.ts | 27 +++- apps/desktop-tauri/src/proof/router.ts | 3 + docs/WINDOWS_PROOF.md | 1 + 13 files changed, 321 insertions(+), 18 deletions(-) diff --git a/apps/desktop-tauri/scripts/proof-check.mjs b/apps/desktop-tauri/scripts/proof-check.mjs index d54851a31ea..a7a62a9abce 100644 --- a/apps/desktop-tauri/scripts/proof-check.mjs +++ b/apps/desktop-tauri/scripts/proof-check.mjs @@ -15,7 +15,7 @@ // Scenario steps (scripts/proof-scenarios.json), run in order: // expectText / expectNoText page text includes / excludes each string // expectSelector a DOM selector matches -// expectTheme documentElement dataset.theme +// expectTheme documentElement dataset.theme (waits for the value) // expectField a native ` popups keep their pinned dark theme. + ## Drive the app Drive the app without taking the user's focus or keyboard. Don't use cua-driver's `bring_to_front`, foreground mode, `hotkey` or `type_text`. From 5616e5c9f27eb2be4d44f0505e2912c46da10fc9 Mon Sep 17 00:00:00 2001 From: Factory Agent Date: Sat, 24 Oct 2026 06:44:38 +0700 Subject: [PATCH 3/3] Apply only the latest Windows theme read in Settings --- apps/desktop-tauri/src/hooks/useTheme.test.ts | 26 +++++++++++++++++++ apps/desktop-tauri/src/hooks/useTheme.ts | 5 +++- 2 files changed, 30 insertions(+), 1 deletion(-) diff --git a/apps/desktop-tauri/src/hooks/useTheme.test.ts b/apps/desktop-tauri/src/hooks/useTheme.test.ts index 8ce09b1eb19..0e1cee2d008 100644 --- a/apps/desktop-tauri/src/hooks/useTheme.test.ts +++ b/apps/desktop-tauri/src/hooks/useTheme.test.ts @@ -138,4 +138,30 @@ describe("useTheme", () => { await waitFor(() => expect(document.documentElement.dataset.theme).toBe("light")); }); + + it("does not let an older read that finishes last replace a newer one", async () => { + setTauriBridge(true); + let resolveFirst: (theme: "light" | "dark") => void = () => {}; + mockedGetSystemTheme + .mockImplementationOnce( + () => + new Promise((resolve) => { + resolveFirst = resolve; + }), + ) + .mockResolvedValueOnce("light"); + + renderHook(() => useTheme("auto", { followSystem: true })); + act(() => { + window.dispatchEvent(new Event("focus")); + }); + await waitFor(() => expect(document.documentElement.dataset.theme).toBe("light")); + + await act(async () => { + resolveFirst("dark"); + await Promise.resolve(); + }); + + expect(document.documentElement.dataset.theme).toBe("light"); + }); }); diff --git a/apps/desktop-tauri/src/hooks/useTheme.ts b/apps/desktop-tauri/src/hooks/useTheme.ts index ec33eac7e61..b957db9c90d 100644 --- a/apps/desktop-tauri/src/hooks/useTheme.ts +++ b/apps/desktop-tauri/src/hooks/useTheme.ts @@ -44,10 +44,13 @@ function apply(theme: ResolvedTheme) { */ function followWindowsTheme(): () => void { let cancelled = false; + // Reads can overlap (focus during a poll); only the latest one may apply. + let latestRequest = 0; const sync = () => { + const request = ++latestRequest; getSystemTheme() .then((theme) => { - if (!cancelled) apply(theme); + if (!cancelled && request === latestRequest) apply(theme); }) .catch(() => {}); };