From b2a7b1d0ba17553f92e06c9a76b13082f396b737 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Olivier=20L=C3=A9obal?= Date: Mon, 15 May 2023 23:12:53 +0200 Subject: [PATCH] feat: add auto dark mode (#259) Add detection for theme preferences given by the browser. This works by replacing the "dark mode" setting with a new selector that defaults to "auto" (losing old settings, sorry). You can try this out by opening the dev console and using the dedicated button (Inspector > sun/moon -shaped in Firefox, Elements > paint brush -shaped in Chromium). I tried to match the project style but I'm not too good at frontend, I hope this is OK! --- src/App.tsx | 27 ++++++++++++++++++++++++++- src/Settings/index.tsx | 28 +++++++++++----------------- src/store/reducers.ts | 4 ++-- 3 files changed, 39 insertions(+), 20 deletions(-) diff --git a/src/App.tsx b/src/App.tsx index 6d638932..e3b2aa3a 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -146,10 +146,35 @@ export default function App() { const [errorsDialog, setErrorsDialog] = React.useState(false); const dispatch = useDispatch(); const etebase = useCredentials(); - const darkMode = useSelector((state: store.StoreState) => state.settings.darkMode); + const darkModeUserSelection = useSelector((state: store.StoreState) => state.settings.darkModeUserSelection); const fetchCount = useSelector((state: store.StoreState) => state.fetchCount); const errors = useSelector((state: store.StoreState) => state.errors); + function shouldBeDark(userSelection: string, browserPreference: boolean): boolean { + if (userSelection === "auto") { + return browserPreference; + } else if (userSelection === "dark") { + return true; + } + return false; + } + + const [darkModeBrowserPreference, setDarkModeBrowserPreference] = React.useState(Boolean(window.matchMedia?.("(prefers-color-scheme: dark)").matches)); + const handleBrowserDarkModePreferenceChange = React.useCallback((e) => { + setDarkModeBrowserPreference(e.matches); + }, []); + React.useEffect(() => { + window.matchMedia?.("(prefers-color-scheme: dark)").addEventListener("change", handleBrowserDarkModePreferenceChange); + return () => { + window.matchMedia?.("(prefers-color-scheme: dark)").removeEventListener("change", handleBrowserDarkModePreferenceChange); + }; + }, [handleBrowserDarkModePreferenceChange]); + + const [darkMode, setDarkMode] = React.useState(() => shouldBeDark(darkModeUserSelection, darkModeBrowserPreference)); + React.useEffect(() => { + setDarkMode(shouldBeDark(darkModeUserSelection, darkModeBrowserPreference)); + }, [darkModeUserSelection, darkModeBrowserPreference]); + async function refresh() { const syncManager = SyncManager.getManager(etebase!); const sync = syncManager.sync(); diff --git a/src/Settings/index.tsx b/src/Settings/index.tsx index 77b23f1f..44133f45 100644 --- a/src/Settings/index.tsx +++ b/src/Settings/index.tsx @@ -8,9 +8,6 @@ import { useSelector, useDispatch } from "react-redux"; import Select from "@material-ui/core/Select"; import MenuItem from "@material-ui/core/MenuItem"; import FormControl from "@material-ui/core/FormControl"; -import FormControlLabel from "@material-ui/core/FormControlLabel"; -import FormGroup from "@material-ui/core/FormGroup"; -import Switch from "@material-ui/core/Switch"; import InputLabel from "@material-ui/core/InputLabel"; import { StoreState } from "../store"; @@ -173,8 +170,6 @@ export default React.memo(function Settings() { const dispatch = useDispatch(); const settings = useSelector((state: StoreState) => state.settings); - const darkMode = !!settings.darkMode; - function handleChange(event: React.ChangeEvent) { const name = event.target.name; const value = event.target.value; @@ -228,18 +223,17 @@ export default React.memo(function Settings() {

Dark mode

- - dispatch(setSettings({ ...settings, darkMode: !darkMode }))} - /> - } - label="Dark mode" - /> - + + + ); diff --git a/src/store/reducers.ts b/src/store/reducers.ts index 2376905d..11b31741 100644 --- a/src/store/reducers.ts +++ b/src/store/reducers.ts @@ -240,7 +240,7 @@ export const messagesReducer = handleActions( // FIXME Move all the below (potentially the fetchCount ones too) to their own file export interface SettingsType { locale: string; - darkMode?: boolean; + darkModeUserSelection: string; taskSettings: { filterBy: string | null; sortBy: string; @@ -255,7 +255,7 @@ export const settingsReducer = handleActions( }, { locale: "en-gb", - darkMode: false, + darkModeUserSelection: "auto", taskSettings: { filterBy: null, sortBy: "smart",