2020-05-28 15:55:07 +03:00
|
|
|
/*
|
|
|
|
Copyright 2019 Michael Telatynski <7t3chguy@gmail.com>
|
|
|
|
Copyright 2019, 2020 The Matrix.org Foundation C.I.C.
|
|
|
|
|
|
|
|
Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
you may not use this file except in compliance with the License.
|
|
|
|
You may obtain a copy of the License at
|
|
|
|
|
|
|
|
http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
|
|
|
|
Unless required by applicable law or agreed to in writing, software
|
|
|
|
distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
See the License for the specific language governing permissions and
|
|
|
|
limitations under the License.
|
|
|
|
*/
|
|
|
|
|
2020-07-29 01:37:09 +03:00
|
|
|
import SettingsStore from '../SettingsStore';
|
2020-05-28 15:55:07 +03:00
|
|
|
import dis from '../../dispatcher/dispatcher';
|
|
|
|
import { Action } from '../../dispatcher/actions';
|
|
|
|
import ThemeController from "../controllers/ThemeController";
|
|
|
|
import { setTheme } from "../../theme";
|
|
|
|
import { ActionPayload } from '../../dispatcher/payloads';
|
2020-07-28 20:53:43 +03:00
|
|
|
import { SettingLevel } from "../SettingLevel";
|
2020-05-28 15:55:07 +03:00
|
|
|
|
|
|
|
export default class ThemeWatcher {
|
|
|
|
private themeWatchRef: string;
|
|
|
|
private systemThemeWatchRef: string;
|
|
|
|
private dispatcherRef: string;
|
|
|
|
|
|
|
|
private preferDark: MediaQueryList;
|
|
|
|
private preferLight: MediaQueryList;
|
|
|
|
|
|
|
|
private currentTheme: string;
|
|
|
|
|
|
|
|
constructor() {
|
|
|
|
this.themeWatchRef = null;
|
|
|
|
this.systemThemeWatchRef = null;
|
|
|
|
this.dispatcherRef = null;
|
|
|
|
|
|
|
|
// we have both here as each may either match or not match, so by having both
|
|
|
|
// we can get the tristate of dark/light/unsupported
|
|
|
|
this.preferDark = (<any>global).matchMedia("(prefers-color-scheme: dark)");
|
|
|
|
this.preferLight = (<any>global).matchMedia("(prefers-color-scheme: light)");
|
|
|
|
|
|
|
|
this.currentTheme = this.getEffectiveTheme();
|
|
|
|
}
|
|
|
|
|
|
|
|
public start() {
|
|
|
|
this.themeWatchRef = SettingsStore.watchSetting("theme", null, this.onChange);
|
|
|
|
this.systemThemeWatchRef = SettingsStore.watchSetting("use_system_theme", null, this.onChange);
|
|
|
|
if (this.preferDark.addEventListener) {
|
|
|
|
this.preferDark.addEventListener('change', this.onChange);
|
|
|
|
this.preferLight.addEventListener('change', this.onChange);
|
|
|
|
}
|
|
|
|
this.dispatcherRef = dis.register(this.onAction);
|
|
|
|
}
|
|
|
|
|
|
|
|
public stop() {
|
|
|
|
if (this.preferDark.addEventListener) {
|
|
|
|
this.preferDark.removeEventListener('change', this.onChange);
|
|
|
|
this.preferLight.removeEventListener('change', this.onChange);
|
|
|
|
}
|
|
|
|
SettingsStore.unwatchSetting(this.systemThemeWatchRef);
|
|
|
|
SettingsStore.unwatchSetting(this.themeWatchRef);
|
|
|
|
dis.unregister(this.dispatcherRef);
|
|
|
|
}
|
|
|
|
|
|
|
|
private onChange = () => {
|
|
|
|
this.recheck();
|
|
|
|
};
|
|
|
|
|
|
|
|
private onAction = (payload: ActionPayload) => {
|
|
|
|
if (payload.action === Action.RecheckTheme) {
|
|
|
|
// XXX forceTheme
|
|
|
|
this.recheck(payload.forceTheme);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
// XXX: forceTheme param added here as local echo appears to be unreliable
|
2020-08-03 18:02:26 +03:00
|
|
|
// https://github.com/vector-im/element-web/issues/11443
|
2020-05-28 15:55:07 +03:00
|
|
|
public recheck(forceTheme?: string) {
|
|
|
|
const oldTheme = this.currentTheme;
|
|
|
|
this.currentTheme = forceTheme === undefined ? this.getEffectiveTheme() : forceTheme;
|
|
|
|
if (oldTheme !== this.currentTheme) {
|
|
|
|
setTheme(this.currentTheme);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public getEffectiveTheme(): string {
|
|
|
|
// Dev note: Much of this logic is replicated in the AppearanceUserSettingsTab
|
|
|
|
|
|
|
|
// XXX: checking the isLight flag here makes checking it in the ThemeController
|
|
|
|
// itself completely redundant since we just override the result here and we're
|
|
|
|
// now effectively just using the ThemeController as a place to store the static
|
|
|
|
// variable. The system theme setting probably ought to have an equivalent
|
|
|
|
// controller that honours the same flag, although probablt better would be to
|
|
|
|
// have the theme logic in one place rather than split between however many
|
|
|
|
// different places.
|
2020-07-14 19:23:06 +03:00
|
|
|
if (ThemeController.isLogin) return 'light';
|
2020-05-28 15:55:07 +03:00
|
|
|
|
|
|
|
// If the user has specifically enabled the system matching option (excluding default),
|
|
|
|
// then use that over anything else. We pick the lowest possible level for the setting
|
|
|
|
// to ensure the ordering otherwise works.
|
|
|
|
const systemThemeExplicit = SettingsStore.getValueAt(
|
|
|
|
SettingLevel.DEVICE, "use_system_theme", null, false, true);
|
|
|
|
if (systemThemeExplicit) {
|
|
|
|
console.log("returning explicit system theme");
|
2020-07-14 19:23:06 +03:00
|
|
|
if (this.preferDark.matches) return 'dark';
|
|
|
|
if (this.preferLight.matches) return 'light';
|
2020-05-28 15:55:07 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
// If the user has specifically enabled the theme (without the system matching option being
|
|
|
|
// enabled specifically and excluding the default), use that theme. We pick the lowest possible
|
|
|
|
// level for the setting to ensure the ordering otherwise works.
|
|
|
|
const themeExplicit = SettingsStore.getValueAt(
|
|
|
|
SettingLevel.DEVICE, "theme", null, false, true);
|
|
|
|
if (themeExplicit) {
|
|
|
|
console.log("returning explicit theme: " + themeExplicit);
|
|
|
|
return themeExplicit;
|
|
|
|
}
|
|
|
|
|
|
|
|
// If the user hasn't really made a preference in either direction, assume the defaults of the
|
|
|
|
// settings and use those.
|
|
|
|
if (SettingsStore.getValue('use_system_theme')) {
|
2020-07-14 19:23:06 +03:00
|
|
|
if (this.preferDark.matches) return 'dark';
|
|
|
|
if (this.preferLight.matches) return 'light';
|
2020-05-28 15:55:07 +03:00
|
|
|
}
|
|
|
|
console.log("returning theme value");
|
|
|
|
return SettingsStore.getValue('theme');
|
|
|
|
}
|
|
|
|
|
|
|
|
public isSystemThemeSupported() {
|
|
|
|
return this.preferDark.matches || this.preferLight.matches;
|
|
|
|
}
|
|
|
|
}
|