support custom themes from setting

also move theme setting code from MatrixChat to own file.
This commit is contained in:
Bruno Windels 2019-10-01 15:21:22 +02:00
parent 79d4434c9f
commit 558f8daeeb
6 changed files with 151 additions and 107 deletions

View file

@ -56,6 +56,7 @@ import { ValidatedServerConfig } from "../../utils/AutoDiscoveryUtils";
import AutoDiscoveryUtils from "../../utils/AutoDiscoveryUtils";
import DMRoomMap from '../../utils/DMRoomMap';
import { countRoomsWithNotif } from '../../RoomNotifs';
import { setTheme } from "../../theme";
// Disable warnings for now: we use deprecated bluebird functions
// and need to migrate, but they spam the console with warnings.
@ -658,7 +659,7 @@ export default createReactClass({
break;
}
case 'set_theme':
this._onSetTheme(payload.value);
setTheme(payload.value);
break;
case 'on_logging_in':
// We are now logging in, so set the state to reflect that
@ -1102,82 +1103,6 @@ export default createReactClass({
});
},
/**
* Called whenever someone changes the theme
*
* @param {string} theme new theme
*/
_onSetTheme: function(theme) {
if (!theme) {
theme = SettingsStore.getValue("theme");
}
// look for the stylesheet elements.
// styleElements is a map from style name to HTMLLinkElement.
const styleElements = Object.create(null);
let a;
for (let i = 0; (a = document.getElementsByTagName("link")[i]); i++) {
const href = a.getAttribute("href");
// shouldn't we be using the 'title' tag rather than the href?
const match = href.match(/^bundles\/.*\/theme-(.*)\.css$/);
if (match) {
styleElements[match[1]] = a;
}
}
if (!(theme in styleElements)) {
throw new Error("Unknown theme " + theme);
}
// disable all of them first, then enable the one we want. Chrome only
// bothers to do an update on a true->false transition, so this ensures
// that we get exactly one update, at the right time.
//
// ^ This comment was true when we used to use alternative stylesheets
// for the CSS. Nowadays we just set them all as disabled in index.html
// and enable them as needed. It might be cleaner to disable them all
// at the same time to prevent loading two themes simultaneously and
// having them interact badly... but this causes a flash of unstyled app
// which is even uglier. So we don't.
styleElements[theme].disabled = false;
const switchTheme = function() {
// we re-enable our theme here just in case we raced with another
// theme set request as per https://github.com/vector-im/riot-web/issues/5601.
// We could alternatively lock or similar to stop the race, but
// this is probably good enough for now.
styleElements[theme].disabled = false;
Object.values(styleElements).forEach((a) => {
if (a == styleElements[theme]) return;
a.disabled = true;
});
Tinter.setTheme(theme);
};
// turns out that Firefox preloads the CSS for link elements with
// the disabled attribute, but Chrome doesn't.
let cssLoaded = false;
styleElements[theme].onload = () => {
switchTheme();
};
for (let i = 0; i < document.styleSheets.length; i++) {
const ss = document.styleSheets[i];
if (ss && ss.href === styleElements[theme].href) {
cssLoaded = true;
break;
}
}
if (cssLoaded) {
styleElements[theme].onload = undefined;
switchTheme();
}
},
/**
* Starts a chat with the welcome user, if the user doesn't already have one
* @returns {string} The room ID of the new room, or null if no room was created