switch Tinter from using dispatch to a synchronous update when changing the colourscheme, to avoid CSS getting out of sync with SVG colours

This commit is contained in:
Matthew Hodgson 2016-04-16 01:00:10 +01:00
parent 4fb31662e1
commit 8db14bde60
4 changed files with 60 additions and 17 deletions

View file

@ -15,11 +15,14 @@ limitations under the License.
*/ */
var dis = require("./dispatcher"); var dis = require("./dispatcher");
var sdk = require("./index");
// FIXME: these vars should be bundled up and attached to // FIXME: these vars should be bundled up and attached to
// module.exports otherwise this will break when included by both // module.exports otherwise this will break when included by both
// react-sdk and apps layered on top. // react-sdk and apps layered on top.
var DEBUG = 0;
// The colour keys to be replaced as referred to in SVGs // The colour keys to be replaced as referred to in SVGs
var keyRgb = [ var keyRgb = [
"rgb(118, 207, 166)", // Vector Green "rgb(118, 207, 166)", // Vector Green
@ -75,6 +78,7 @@ var svgAttrs = [
var cached = false; var cached = false;
function calcCssFixups() { function calcCssFixups() {
if (DEBUG) console.log("calcSvgFixups start");
for (var i = 0; i < document.styleSheets.length; i++) { for (var i = 0; i < document.styleSheets.length; i++) {
var ss = document.styleSheets[i]; var ss = document.styleSheets[i];
if (!ss) continue; // well done safari >:( if (!ss) continue; // well done safari >:(
@ -105,13 +109,16 @@ function calcCssFixups() {
} }
} }
} }
if (DEBUG) console.log("calcSvgFixups end");
} }
function applyCssFixups() { function applyCssFixups() {
if (DEBUG) console.log("applyCssFixups start");
for (var i = 0; i < cssFixups.length; i++) { for (var i = 0; i < cssFixups.length; i++) {
var cssFixup = cssFixups[i]; var cssFixup = cssFixups[i];
cssFixup.style[cssFixup.attr] = colors[cssFixup.index]; cssFixup.style[cssFixup.attr] = colors[cssFixup.index];
} }
if (DEBUG) console.log("applyCssFixups end");
} }
function hexToRgb(color) { function hexToRgb(color) {
@ -135,6 +142,7 @@ function rgbToHex(rgb) {
module.exports = { module.exports = {
tint: function(primaryColor, secondaryColor, tertiaryColor) { tint: function(primaryColor, secondaryColor, tertiaryColor) {
if (!cached) { if (!cached) {
calcCssFixups(); calcCssFixups();
cached = true; cached = true;
@ -173,11 +181,19 @@ module.exports = {
colors = [primaryColor, secondaryColor, tertiaryColor]; colors = [primaryColor, secondaryColor, tertiaryColor];
if (DEBUG) console.log("Tinter.tint");
// go through manually fixing up the stylesheets. // go through manually fixing up the stylesheets.
applyCssFixups(); applyCssFixups();
// tell all the SVGs to go fix themselves up // tell all the SVGs to go fix themselves up
dis.dispatch({ action: 'tint_update' }); // we don't do this as a dispatch otherwise it will visually lag
var TintableSvg = sdk.getComponent("elements.TintableSvg");
if (TintableSvg.mounts) {
Object.keys(TintableSvg.mounts).forEach((id) => {
TintableSvg.mounts[id].tint();
});
}
}, },
// XXX: we could just move this all into TintableSvg, but as it's so similar // XXX: we could just move this all into TintableSvg, but as it's so similar
@ -189,6 +205,7 @@ module.exports = {
// updated would be a PITA, so just brute-force search for the // updated would be a PITA, so just brute-force search for the
// key colour; cache the element and apply. // key colour; cache the element and apply.
if (DEBUG) console.log("calcSvgFixups start for " + svgs);
var fixups = []; var fixups = [];
for (var i = 0; i < svgs.length; i++) { for (var i = 0; i < svgs.length; i++) {
var svgDoc; var svgDoc;
@ -223,14 +240,17 @@ module.exports = {
} }
} }
} }
if (DEBUG) console.log("calcSvgFixups end");
return fixups; return fixups;
}, },
applySvgFixups: function(fixups) { applySvgFixups: function(fixups) {
if (DEBUG) console.log("applySvgFixups start for " + fixups);
for (var i = 0; i < fixups.length; i++) { for (var i = 0; i < fixups.length; i++) {
var svgFixup = fixups[i]; var svgFixup = fixups[i];
svgFixup.node.setAttribute(svgFixup.attr, colors[svgFixup.index]); svgFixup.node.setAttribute(svgFixup.attr, colors[svgFixup.index]);
} }
if (DEBUG) console.log("applySvgFixups end");
}, },
}; };

View file

@ -600,13 +600,15 @@ module.exports = React.createClass({
var theAlias = MatrixTools.getCanonicalAliasForRoom(room); var theAlias = MatrixTools.getCanonicalAliasForRoom(room);
if (theAlias) presentedId = theAlias; if (theAlias) presentedId = theAlias;
var color_scheme_event = room.getAccountData("org.matrix.room.color_scheme"); // No need to do this given RoomView triggers it itself...
var color_scheme = {}; // var color_scheme_event = room.getAccountData("org.matrix.room.color_scheme");
if (color_scheme_event) { // var color_scheme = {};
color_scheme = color_scheme_event.getContent(); // if (color_scheme_event) {
// XXX: we should validate the event // color_scheme = color_scheme_event.getContent();
} // // XXX: we should validate the event
Tinter.tint(color_scheme.primary_color, color_scheme.secondary_color); // }
// console.log("Tinter.tint from _viewRoom");
// Tinter.tint(color_scheme.primary_color, color_scheme.secondary_color);
} }
if (eventId) { if (eventId) {

View file

@ -212,7 +212,9 @@ module.exports = React.createClass({
window.removeEventListener('resize', this.onResize); window.removeEventListener('resize', this.onResize);
Tinter.tint(); // reset colourscheme // no need to do this as Dir & Settings are now overlays. It just burnt CPU.
// console.log("Tinter.tint from RoomView.unmount");
// Tinter.tint(); // reset colourscheme
}, },
onAction: function(payload) { onAction: function(payload) {
@ -346,6 +348,7 @@ module.exports = React.createClass({
color_scheme = color_scheme_event.getContent(); color_scheme = color_scheme_event.getContent();
// XXX: we should validate the event // XXX: we should validate the event
} }
console.log("Tinter.tint from updateTint");
Tinter.tint(color_scheme.primary_color, color_scheme.secondary_color); Tinter.tint(color_scheme.primary_color, color_scheme.secondary_color);
}, },
@ -354,6 +357,7 @@ module.exports = React.createClass({
if (event.getType === "org.matrix.room.color_scheme") { if (event.getType === "org.matrix.room.color_scheme") {
var color_scheme = event.getContent(); var color_scheme = event.getContent();
// XXX: we should validate the event // XXX: we should validate the event
console.log("Tinter.tint from onRoomAccountData");
Tinter.tint(color_scheme.primary_color, color_scheme.secondary_color); Tinter.tint(color_scheme.primary_color, color_scheme.secondary_color);
} }
} }
@ -912,6 +916,7 @@ module.exports = React.createClass({
}, },
onCancelClick: function() { onCancelClick: function() {
console.log("updateTint from onCancelClick");
this.updateTint(); this.updateTint();
this.setState({editingRoomSettings: false}); this.setState({editingRoomSettings: false});
}, },
@ -1179,6 +1184,7 @@ module.exports = React.createClass({
_gatherTimelinePanelRef: function(r) { _gatherTimelinePanelRef: function(r) {
this.refs.messagePanel = r; this.refs.messagePanel = r;
if(r) { if(r) {
console.log("updateTint from RoomView._gatherTimelinePanelRef");
this.updateTint(); this.updateTint();
} }
}, },

View file

@ -18,10 +18,9 @@ limitations under the License.
var React = require('react'); var React = require('react');
var ReactDOM = require("react-dom"); var ReactDOM = require("react-dom");
var dis = require("../../../dispatcher");
var Tinter = require("../../../Tinter"); var Tinter = require("../../../Tinter");
module.exports = React.createClass({ var TintableSvg = React.createClass({
displayName: 'TintableSvg', displayName: 'TintableSvg',
propTypes: { propTypes: {
@ -31,28 +30,42 @@ module.exports = React.createClass({
className: React.PropTypes.string, className: React.PropTypes.string,
}, },
statics: {
// list of currently mounted TintableSvgs
mounts: {},
idSequence: 0,
},
componentWillMount: function() { componentWillMount: function() {
this.fixups = []; this.fixups = [];
this.dispatcherRef = dis.register(this.onAction);
}, },
componentDidMount: function() { componentDidMount: function() {
this.id = TintableSvg.idSequence++;
TintableSvg.mounts[this.id] = this;
// we can't use onLoad on object due to https://github.com/facebook/react/pull/5781 // we can't use onLoad on object due to https://github.com/facebook/react/pull/5781
// so handle it with pure DOM instead // so handle it with pure DOM instead
ReactDOM.findDOMNode(this).addEventListener('load', this.onLoad); ReactDOM.findDOMNode(this).addEventListener('load', this.onLoad);
}, },
componentWillUnmount: function() { componentWillUnmount: function() {
delete TintableSvg.mounts[this.id];
ReactDOM.findDOMNode(this).removeEventListener('load', this.onLoad); ReactDOM.findDOMNode(this).removeEventListener('load', this.onLoad);
dis.unregister(this.dispatcherRef);
}, },
onAction: function(payload) { shouldComponentUpdate: function(nextProps, nextState) {
if (payload.action !== 'tint_update') return; // XXX: no dynamic TintableSvgs for now; speed above all else
return false;
},
tint: function() {
// TODO: only bother running this if the global tint settings have changed
// since we loaded!
Tinter.applySvgFixups(this.fixups); Tinter.applySvgFixups(this.fixups);
}, },
onLoad: function(event) { onLoad: function(event) {
// console.log("TintableSvg.onLoad for " + this.props.src);
this.fixups = Tinter.calcSvgFixups([event.target]); this.fixups = Tinter.calcSvgFixups([event.target]);
Tinter.applySvgFixups(this.fixups); Tinter.applySvgFixups(this.fixups);
}, },
@ -67,3 +80,5 @@ module.exports = React.createClass({
); );
} }
}); });
module.exports = TintableSvg;