stylus/background/color-scheme.js
eight 6c13db1468
Add: toggle dark/night mode styles automatically (#736)
* Add: color-scheme.js

* Add: handle color scheme

* Add: styleManager.setMeta

* Add: make setupLivePrefs work with radio

* Change: drop setupRadioButtons

* Add: UI for schemeSwitcher

* Add: prefer-scheme select in installation page

* Fix: add alarm listener

* Add: display excluded reason in popup

* Fix: rely on data-value-type instead of input name

* Fix: oldValue and newValue should have the same type

* Change: detect media change in content script

* Fix: duplicate capitalize

* Fix: minor

* Update web-ext

* Fix: valueAsNumber doesn't work for all inputs

* Fix: disable colorscheme selection after install

* Fix: API error
2021-12-03 00:49:03 +08:00

101 lines
2.5 KiB
JavaScript

/* global prefs */
/* exported colorScheme */
'use strict';
const colorScheme = (() => {
let systemPreferDark = false;
let timePreferDark = false;
const changeListeners = new Set();
const checkTime = ['schemeSwitcher.nightStart', 'schemeSwitcher.nightEnd'];
prefs.subscribe(checkTime, (key, value) => {
updateTimePreferDark();
createAlarm(key, value);
});
checkTime.forEach(key => createAlarm(key, prefs.get(key)));
prefs.subscribe(['schemeSwitcher.enabled'], emitChange);
chrome.alarms.onAlarm.addListener(info => {
if (checkTime.includes(info.name)) {
updateTimePreferDark();
}
});
updateSystemPreferDark();
updateTimePreferDark();
return {shouldIncludeStyle, onChange, updateSystemPreferDark};
function createAlarm(key, value) {
const date = new Date();
applyDate(date, value);
if (date.getTime() < Date.now()) {
date.setDate(date.getDate() + 1);
}
chrome.alarms.create(key, {
when: date.getTime(),
periodInMinutes: 24 * 60,
});
}
function shouldIncludeStyle(style) {
const isDark = style.preferScheme === 'dark';
const isLight = style.preferScheme === 'light';
if (!isDark && !isLight) {
return true;
}
const switcherState = prefs.get('schemeSwitcher.enabled');
if (switcherState === 'never') {
return true;
}
if (switcherState === 'system') {
return systemPreferDark && isDark ||
!systemPreferDark && isLight;
}
return timePreferDark && isDark ||
!timePreferDark && isLight;
}
function updateSystemPreferDark() {
const oldValue = systemPreferDark;
systemPreferDark = window.matchMedia('(prefers-color-scheme: dark)').matches;
if (systemPreferDark !== oldValue) {
emitChange();
}
return true;
}
function updateTimePreferDark() {
const oldValue = timePreferDark;
const date = new Date();
const now = date.getTime();
applyDate(date, prefs.get('schemeSwitcher.nightStart'));
const start = date.getTime();
applyDate(date, prefs.get('schemeSwitcher.nightEnd'));
const end = date.getTime();
timePreferDark = start > end ?
now >= start || now < end :
now >= start && now < end;
if (timePreferDark !== oldValue) {
emitChange();
}
}
function applyDate(date, time) {
const [h, m] = time.split(':').map(Number);
date.setHours(h, m, 0, 0);
}
function onChange(listener) {
changeListeners.add(listener);
}
function emitChange() {
for (const listener of changeListeners) {
listener();
}
}
})();