mirror of
https://github.com/vector-im/element-web.git
synced 2024-11-16 05:04:57 +08:00
Deprecate Tinter and TintableSVG
This commit is contained in:
parent
a8f5b7ebae
commit
6607294573
458
src/Tinter.js
458
src/Tinter.js
@ -1,458 +0,0 @@
|
|||||||
/*
|
|
||||||
Copyright 2015 OpenMarket Ltd
|
|
||||||
Copyright 2017 New Vector Ltd
|
|
||||||
|
|
||||||
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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
const DEBUG = 0;
|
|
||||||
|
|
||||||
// utility to turn #rrggbb or rgb(r,g,b) into [red,green,blue]
|
|
||||||
function colorToRgb(color) {
|
|
||||||
if (!color) {
|
|
||||||
return [0, 0, 0];
|
|
||||||
}
|
|
||||||
|
|
||||||
if (color[0] === '#') {
|
|
||||||
color = color.slice(1);
|
|
||||||
if (color.length === 3) {
|
|
||||||
color = color[0] + color[0] +
|
|
||||||
color[1] + color[1] +
|
|
||||||
color[2] + color[2];
|
|
||||||
}
|
|
||||||
const val = parseInt(color, 16);
|
|
||||||
const r = (val >> 16) & 255;
|
|
||||||
const g = (val >> 8) & 255;
|
|
||||||
const b = val & 255;
|
|
||||||
return [r, g, b];
|
|
||||||
} else {
|
|
||||||
const match = color.match(/rgb\((.*?),(.*?),(.*?)\)/);
|
|
||||||
if (match) {
|
|
||||||
return [
|
|
||||||
parseInt(match[1]),
|
|
||||||
parseInt(match[2]),
|
|
||||||
parseInt(match[3]),
|
|
||||||
];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return [0, 0, 0];
|
|
||||||
}
|
|
||||||
|
|
||||||
// utility to turn [red,green,blue] into #rrggbb
|
|
||||||
function rgbToColor(rgb) {
|
|
||||||
const val = (rgb[0] << 16) | (rgb[1] << 8) | rgb[2];
|
|
||||||
return '#' + (0x1000000 + val).toString(16).slice(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
class Tinter {
|
|
||||||
constructor() {
|
|
||||||
// The default colour keys to be replaced as referred to in CSS
|
|
||||||
// (should be overridden by .mx_theme_accentColor and .mx_theme_secondaryAccentColor)
|
|
||||||
this.keyRgb = [
|
|
||||||
"rgb(118, 207, 166)", // Vector Green
|
|
||||||
"rgb(234, 245, 240)", // Vector Light Green
|
|
||||||
"rgb(211, 239, 225)", // roomsublist-label-bg-color (20% Green overlaid on Light Green)
|
|
||||||
];
|
|
||||||
|
|
||||||
// Some algebra workings for calculating the tint % of Vector Green & Light Green
|
|
||||||
// x * 118 + (1 - x) * 255 = 234
|
|
||||||
// x * 118 + 255 - 255 * x = 234
|
|
||||||
// x * 118 - x * 255 = 234 - 255
|
|
||||||
// (255 - 118) x = 255 - 234
|
|
||||||
// x = (255 - 234) / (255 - 118) = 0.16
|
|
||||||
|
|
||||||
// The colour keys to be replaced as referred to in SVGs
|
|
||||||
this.keyHex = [
|
|
||||||
"#76CFA6", // Vector Green
|
|
||||||
"#EAF5F0", // Vector Light Green
|
|
||||||
"#D3EFE1", // roomsublist-label-bg-color (20% Green overlaid on Light Green)
|
|
||||||
"#FFFFFF", // white highlights of the SVGs (for switching to dark theme)
|
|
||||||
"#000000", // black lowlights of the SVGs (for switching to dark theme)
|
|
||||||
];
|
|
||||||
|
|
||||||
// track the replacement colours actually being used
|
|
||||||
// defaults to our keys.
|
|
||||||
this.colors = [
|
|
||||||
this.keyHex[0],
|
|
||||||
this.keyHex[1],
|
|
||||||
this.keyHex[2],
|
|
||||||
this.keyHex[3],
|
|
||||||
this.keyHex[4],
|
|
||||||
];
|
|
||||||
|
|
||||||
// track the most current tint request inputs (which may differ from the
|
|
||||||
// end result stored in this.colors
|
|
||||||
this.currentTint = [
|
|
||||||
undefined,
|
|
||||||
undefined,
|
|
||||||
undefined,
|
|
||||||
undefined,
|
|
||||||
undefined,
|
|
||||||
];
|
|
||||||
|
|
||||||
this.cssFixups = [
|
|
||||||
// { theme: {
|
|
||||||
// style: a style object that should be fixed up taken from a stylesheet
|
|
||||||
// attr: name of the attribute to be clobbered, e.g. 'color'
|
|
||||||
// index: ordinal of primary, secondary or tertiary
|
|
||||||
// },
|
|
||||||
// }
|
|
||||||
];
|
|
||||||
|
|
||||||
// CSS attributes to be fixed up
|
|
||||||
this.cssAttrs = [
|
|
||||||
"color",
|
|
||||||
"backgroundColor",
|
|
||||||
"borderColor",
|
|
||||||
"borderTopColor",
|
|
||||||
"borderBottomColor",
|
|
||||||
"borderLeftColor",
|
|
||||||
];
|
|
||||||
|
|
||||||
this.svgAttrs = [
|
|
||||||
"fill",
|
|
||||||
"stroke",
|
|
||||||
];
|
|
||||||
|
|
||||||
// List of functions to call when the tint changes.
|
|
||||||
this.tintables = [];
|
|
||||||
|
|
||||||
// the currently loaded theme (if any)
|
|
||||||
this.theme = undefined;
|
|
||||||
|
|
||||||
// whether to force a tint (e.g. after changing theme)
|
|
||||||
this.forceTint = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Register a callback to fire when the tint changes.
|
|
||||||
* This is used to rewrite the tintable SVGs with the new tint.
|
|
||||||
*
|
|
||||||
* It's not possible to unregister a tintable callback. So this can only be
|
|
||||||
* used to register a static callback. If a set of tintables will change
|
|
||||||
* over time then the best bet is to register a single callback for the
|
|
||||||
* entire set.
|
|
||||||
*
|
|
||||||
* To ensure the tintable work happens at least once, it is also called as
|
|
||||||
* part of registration.
|
|
||||||
*
|
|
||||||
* @param {Function} tintable Function to call when the tint changes.
|
|
||||||
*/
|
|
||||||
registerTintable(tintable) {
|
|
||||||
this.tintables.push(tintable);
|
|
||||||
tintable();
|
|
||||||
}
|
|
||||||
|
|
||||||
getKeyRgb() {
|
|
||||||
return this.keyRgb;
|
|
||||||
}
|
|
||||||
|
|
||||||
tint(primaryColor, secondaryColor, tertiaryColor) {
|
|
||||||
return;
|
|
||||||
// eslint-disable-next-line no-unreachable
|
|
||||||
this.currentTint[0] = primaryColor;
|
|
||||||
this.currentTint[1] = secondaryColor;
|
|
||||||
this.currentTint[2] = tertiaryColor;
|
|
||||||
|
|
||||||
this.calcCssFixups();
|
|
||||||
|
|
||||||
if (DEBUG) {
|
|
||||||
console.log("Tinter.tint(" + primaryColor + ", " +
|
|
||||||
secondaryColor + ", " +
|
|
||||||
tertiaryColor + ")");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!primaryColor) {
|
|
||||||
primaryColor = this.keyRgb[0];
|
|
||||||
secondaryColor = this.keyRgb[1];
|
|
||||||
tertiaryColor = this.keyRgb[2];
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!secondaryColor) {
|
|
||||||
const x = 0.16; // average weighting factor calculated from vector green & light green
|
|
||||||
const rgb = colorToRgb(primaryColor);
|
|
||||||
rgb[0] = x * rgb[0] + (1 - x) * 255;
|
|
||||||
rgb[1] = x * rgb[1] + (1 - x) * 255;
|
|
||||||
rgb[2] = x * rgb[2] + (1 - x) * 255;
|
|
||||||
secondaryColor = rgbToColor(rgb);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!tertiaryColor) {
|
|
||||||
const x = 0.19;
|
|
||||||
const rgb1 = colorToRgb(primaryColor);
|
|
||||||
const rgb2 = colorToRgb(secondaryColor);
|
|
||||||
rgb1[0] = x * rgb1[0] + (1 - x) * rgb2[0];
|
|
||||||
rgb1[1] = x * rgb1[1] + (1 - x) * rgb2[1];
|
|
||||||
rgb1[2] = x * rgb1[2] + (1 - x) * rgb2[2];
|
|
||||||
tertiaryColor = rgbToColor(rgb1);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.forceTint == false &&
|
|
||||||
this.colors[0] === primaryColor &&
|
|
||||||
this.colors[1] === secondaryColor &&
|
|
||||||
this.colors[2] === tertiaryColor) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.forceTint = false;
|
|
||||||
|
|
||||||
this.colors[0] = primaryColor;
|
|
||||||
this.colors[1] = secondaryColor;
|
|
||||||
this.colors[2] = tertiaryColor;
|
|
||||||
|
|
||||||
if (DEBUG) {
|
|
||||||
console.log("Tinter.tint final: (" + primaryColor + ", " +
|
|
||||||
secondaryColor + ", " +
|
|
||||||
tertiaryColor + ")");
|
|
||||||
}
|
|
||||||
|
|
||||||
// go through manually fixing up the stylesheets.
|
|
||||||
this.applyCssFixups();
|
|
||||||
|
|
||||||
// tell all the SVGs to go fix themselves up
|
|
||||||
// we don't do this as a dispatch otherwise it will visually lag
|
|
||||||
this.tintables.forEach(function(tintable) {
|
|
||||||
tintable();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
tintSvgWhite(whiteColor) {
|
|
||||||
this.currentTint[3] = whiteColor;
|
|
||||||
|
|
||||||
if (!whiteColor) {
|
|
||||||
whiteColor = this.colors[3];
|
|
||||||
}
|
|
||||||
if (this.colors[3] === whiteColor) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
this.colors[3] = whiteColor;
|
|
||||||
this.tintables.forEach(function(tintable) {
|
|
||||||
tintable();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
tintSvgBlack(blackColor) {
|
|
||||||
this.currentTint[4] = blackColor;
|
|
||||||
|
|
||||||
if (!blackColor) {
|
|
||||||
blackColor = this.colors[4];
|
|
||||||
}
|
|
||||||
if (this.colors[4] === blackColor) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
this.colors[4] = blackColor;
|
|
||||||
this.tintables.forEach(function(tintable) {
|
|
||||||
tintable();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
setTheme(theme) {
|
|
||||||
this.theme = theme;
|
|
||||||
|
|
||||||
// update keyRgb from the current theme CSS itself, if it defines it
|
|
||||||
if (document.getElementById('mx_theme_accentColor')) {
|
|
||||||
this.keyRgb[0] = window.getComputedStyle(
|
|
||||||
document.getElementById('mx_theme_accentColor')).color;
|
|
||||||
}
|
|
||||||
if (document.getElementById('mx_theme_secondaryAccentColor')) {
|
|
||||||
this.keyRgb[1] = window.getComputedStyle(
|
|
||||||
document.getElementById('mx_theme_secondaryAccentColor')).color;
|
|
||||||
}
|
|
||||||
if (document.getElementById('mx_theme_tertiaryAccentColor')) {
|
|
||||||
this.keyRgb[2] = window.getComputedStyle(
|
|
||||||
document.getElementById('mx_theme_tertiaryAccentColor')).color;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.calcCssFixups();
|
|
||||||
this.forceTint = true;
|
|
||||||
|
|
||||||
this.tint(this.currentTint[0], this.currentTint[1], this.currentTint[2]);
|
|
||||||
|
|
||||||
if (theme === 'dark') {
|
|
||||||
// abuse the tinter to change all the SVG's #fff to #2d2d2d
|
|
||||||
// XXX: obviously this shouldn't be hardcoded here.
|
|
||||||
this.tintSvgWhite('#2d2d2d');
|
|
||||||
this.tintSvgBlack('#dddddd');
|
|
||||||
} else {
|
|
||||||
this.tintSvgWhite('#ffffff');
|
|
||||||
this.tintSvgBlack('#000000');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
calcCssFixups() {
|
|
||||||
// cache our fixups
|
|
||||||
if (this.cssFixups[this.theme]) return;
|
|
||||||
|
|
||||||
if (DEBUG) {
|
|
||||||
console.debug("calcCssFixups start for " + this.theme + " (checking " +
|
|
||||||
document.styleSheets.length +
|
|
||||||
" stylesheets)");
|
|
||||||
}
|
|
||||||
|
|
||||||
this.cssFixups[this.theme] = [];
|
|
||||||
|
|
||||||
for (let i = 0; i < document.styleSheets.length; i++) {
|
|
||||||
const ss = document.styleSheets[i];
|
|
||||||
try {
|
|
||||||
if (!ss) continue; // well done safari >:(
|
|
||||||
// Chromium apparently sometimes returns null here; unsure why.
|
|
||||||
// see $14534907369972FRXBx:matrix.org in HQ
|
|
||||||
// ...ah, it's because there's a third party extension like
|
|
||||||
// privacybadger inserting its own stylesheet in there with a
|
|
||||||
// resource:// URI or something which results in a XSS error.
|
|
||||||
// See also #vector:matrix.org/$145357669685386ebCfr:matrix.org
|
|
||||||
// ...except some browsers apparently return stylesheets without
|
|
||||||
// hrefs, which we have no choice but ignore right now
|
|
||||||
|
|
||||||
// XXX seriously? we are hardcoding the name of vector's CSS file in
|
|
||||||
// here?
|
|
||||||
//
|
|
||||||
// Why do we need to limit it to vector's CSS file anyway - if there
|
|
||||||
// are other CSS files affecting the doc don't we want to apply the
|
|
||||||
// same transformations to them?
|
|
||||||
//
|
|
||||||
// Iterating through the CSS looking for matches to hack on feels
|
|
||||||
// pretty horrible anyway. And what if the application skin doesn't use
|
|
||||||
// Vector Green as its primary color?
|
|
||||||
// --richvdh
|
|
||||||
|
|
||||||
// Yes, tinting assumes that you are using the Element skin for now.
|
|
||||||
// The right solution will be to move the CSS over to react-sdk.
|
|
||||||
// And yes, the default assets for the base skin might as well use
|
|
||||||
// Vector Green as any other colour.
|
|
||||||
// --matthew
|
|
||||||
|
|
||||||
// stylesheets we don't have permission to access (eg. ones from extensions) have a null
|
|
||||||
// href and will throw exceptions if we try to access their rules.
|
|
||||||
if (!ss.href || !ss.href.match(new RegExp('/theme-' + this.theme + '.css$'))) continue;
|
|
||||||
if (ss.disabled) continue;
|
|
||||||
if (!ss.cssRules) continue;
|
|
||||||
|
|
||||||
if (DEBUG) console.debug("calcCssFixups checking " + ss.cssRules.length + " rules for " + ss.href);
|
|
||||||
|
|
||||||
for (let j = 0; j < ss.cssRules.length; j++) {
|
|
||||||
const rule = ss.cssRules[j];
|
|
||||||
if (!rule.style) continue;
|
|
||||||
if (rule.selectorText && rule.selectorText.match(/#mx_theme/)) continue;
|
|
||||||
for (let k = 0; k < this.cssAttrs.length; k++) {
|
|
||||||
const attr = this.cssAttrs[k];
|
|
||||||
for (let l = 0; l < this.keyRgb.length; l++) {
|
|
||||||
if (rule.style[attr] === this.keyRgb[l]) {
|
|
||||||
this.cssFixups[this.theme].push({
|
|
||||||
style: rule.style,
|
|
||||||
attr: attr,
|
|
||||||
index: l,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (e) {
|
|
||||||
// Catch any random exceptions that happen here: all sorts of things can go
|
|
||||||
// wrong with this (nulls, SecurityErrors) and mostly it's for other
|
|
||||||
// stylesheets that we don't want to proces anyway. We should not propagate an
|
|
||||||
// exception out since this will cause the app to fail to start.
|
|
||||||
console.log("Failed to calculate CSS fixups for a stylesheet: " + ss.href, e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (DEBUG) {
|
|
||||||
console.log("calcCssFixups end (" +
|
|
||||||
this.cssFixups[this.theme].length +
|
|
||||||
" fixups)");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
applyCssFixups() {
|
|
||||||
if (DEBUG) {
|
|
||||||
console.log("applyCssFixups start (" +
|
|
||||||
this.cssFixups[this.theme].length +
|
|
||||||
" fixups)");
|
|
||||||
}
|
|
||||||
for (let i = 0; i < this.cssFixups[this.theme].length; i++) {
|
|
||||||
const cssFixup = this.cssFixups[this.theme][i];
|
|
||||||
try {
|
|
||||||
cssFixup.style[cssFixup.attr] = this.colors[cssFixup.index];
|
|
||||||
} catch (e) {
|
|
||||||
// Firefox Quantum explodes if you manually edit the CSS in the
|
|
||||||
// inspector and then try to do a tint, as apparently all the
|
|
||||||
// fixups are then stale.
|
|
||||||
console.error("Failed to apply cssFixup in Tinter! ", e.name);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (DEBUG) console.log("applyCssFixups end");
|
|
||||||
}
|
|
||||||
|
|
||||||
// XXX: we could just move this all into TintableSvg, but as it's so similar
|
|
||||||
// to the CSS fixup stuff in Tinter (just that the fixups are stored in TintableSvg)
|
|
||||||
// keeping it here for now.
|
|
||||||
calcSvgFixups(svgs) {
|
|
||||||
// go through manually fixing up SVG colours.
|
|
||||||
// we could do this by stylesheets, but keeping the stylesheets
|
|
||||||
// updated would be a PITA, so just brute-force search for the
|
|
||||||
// key colour; cache the element and apply.
|
|
||||||
|
|
||||||
if (DEBUG) console.log("calcSvgFixups start for " + svgs);
|
|
||||||
const fixups = [];
|
|
||||||
for (let i = 0; i < svgs.length; i++) {
|
|
||||||
let svgDoc;
|
|
||||||
try {
|
|
||||||
svgDoc = svgs[i].contentDocument;
|
|
||||||
} catch (e) {
|
|
||||||
let msg = 'Failed to get svg.contentDocument of ' + svgs[i].toString();
|
|
||||||
if (e.message) {
|
|
||||||
msg += e.message;
|
|
||||||
}
|
|
||||||
if (e.stack) {
|
|
||||||
msg += ' | stack: ' + e.stack;
|
|
||||||
}
|
|
||||||
console.error(msg);
|
|
||||||
}
|
|
||||||
if (!svgDoc) continue;
|
|
||||||
const tags = svgDoc.getElementsByTagName("*");
|
|
||||||
for (let j = 0; j < tags.length; j++) {
|
|
||||||
const tag = tags[j];
|
|
||||||
for (let k = 0; k < this.svgAttrs.length; k++) {
|
|
||||||
const attr = this.svgAttrs[k];
|
|
||||||
for (let l = 0; l < this.keyHex.length; l++) {
|
|
||||||
if (tag.getAttribute(attr) &&
|
|
||||||
tag.getAttribute(attr).toUpperCase() === this.keyHex[l]) {
|
|
||||||
fixups.push({
|
|
||||||
node: tag,
|
|
||||||
attr: attr,
|
|
||||||
index: l,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (DEBUG) console.log("calcSvgFixups end");
|
|
||||||
|
|
||||||
return fixups;
|
|
||||||
}
|
|
||||||
|
|
||||||
applySvgFixups(fixups) {
|
|
||||||
if (DEBUG) console.log("applySvgFixups start for " + fixups);
|
|
||||||
for (let i = 0; i < fixups.length; i++) {
|
|
||||||
const svgFixup = fixups[i];
|
|
||||||
svgFixup.node.setAttribute(svgFixup.attr, this.colors[svgFixup.index]);
|
|
||||||
}
|
|
||||||
if (DEBUG) console.log("applySvgFixups end");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (global.singletonTinter === undefined) {
|
|
||||||
global.singletonTinter = new Tinter();
|
|
||||||
}
|
|
||||||
export default global.singletonTinter;
|
|
@ -126,12 +126,11 @@ class CategoryRoomList extends React.Component {
|
|||||||
};
|
};
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const TintableSvg = sdk.getComponent("elements.TintableSvg");
|
|
||||||
const addButton = this.props.editing ?
|
const addButton = this.props.editing ?
|
||||||
(<AccessibleButton className="mx_GroupView_featuredThings_addButton"
|
(<AccessibleButton className="mx_GroupView_featuredThings_addButton"
|
||||||
onClick={this.onAddRoomsToSummaryClicked}
|
onClick={this.onAddRoomsToSummaryClicked}
|
||||||
>
|
>
|
||||||
<TintableSvg src={require("../../../res/img/icons-create-room.svg")} width="64" height="64" />
|
<img src={require("../../../res/img/icons-create-room.svg")} width="64" height="64" />
|
||||||
<div className="mx_GroupView_featuredThings_addButton_label">
|
<div className="mx_GroupView_featuredThings_addButton_label">
|
||||||
{ _t('Add a Room') }
|
{ _t('Add a Room') }
|
||||||
</div>
|
</div>
|
||||||
@ -300,10 +299,9 @@ class RoleUserList extends React.Component {
|
|||||||
};
|
};
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const TintableSvg = sdk.getComponent("elements.TintableSvg");
|
|
||||||
const addButton = this.props.editing ?
|
const addButton = this.props.editing ?
|
||||||
(<AccessibleButton className="mx_GroupView_featuredThings_addButton" onClick={this.onAddUsersClicked}>
|
(<AccessibleButton className="mx_GroupView_featuredThings_addButton" onClick={this.onAddUsersClicked}>
|
||||||
<TintableSvg src={require("../../../res/img/icons-create-room.svg")} width="64" height="64" />
|
<img src={require("../../../res/img/icons-create-room.svg")} width="64" height="64" />
|
||||||
<div className="mx_GroupView_featuredThings_addButton_label">
|
<div className="mx_GroupView_featuredThings_addButton_label">
|
||||||
{ _t('Add a User') }
|
{ _t('Add a User') }
|
||||||
</div>
|
</div>
|
||||||
@ -855,7 +853,6 @@ export default class GroupView extends React.Component {
|
|||||||
_getRoomsNode() {
|
_getRoomsNode() {
|
||||||
const RoomDetailList = sdk.getComponent('rooms.RoomDetailList');
|
const RoomDetailList = sdk.getComponent('rooms.RoomDetailList');
|
||||||
const AccessibleButton = sdk.getComponent('elements.AccessibleButton');
|
const AccessibleButton = sdk.getComponent('elements.AccessibleButton');
|
||||||
const TintableSvg = sdk.getComponent('elements.TintableSvg');
|
|
||||||
const Spinner = sdk.getComponent('elements.Spinner');
|
const Spinner = sdk.getComponent('elements.Spinner');
|
||||||
const TooltipButton = sdk.getComponent('elements.TooltipButton');
|
const TooltipButton = sdk.getComponent('elements.TooltipButton');
|
||||||
|
|
||||||
@ -871,7 +868,7 @@ export default class GroupView extends React.Component {
|
|||||||
onClick={this._onAddRoomsClick}
|
onClick={this._onAddRoomsClick}
|
||||||
>
|
>
|
||||||
<div className="mx_GroupView_rooms_header_addRow_button">
|
<div className="mx_GroupView_rooms_header_addRow_button">
|
||||||
<TintableSvg src={require("../../../res/img/icons-room-add.svg")} width="24" height="24" />
|
<img src={require("../../../res/img/icons-room-add.svg")} width="24" height="24" />
|
||||||
</div>
|
</div>
|
||||||
<div className="mx_GroupView_rooms_header_addRow_label">
|
<div className="mx_GroupView_rooms_header_addRow_label">
|
||||||
{ _t('Add rooms to this community') }
|
{ _t('Add rooms to this community') }
|
||||||
|
@ -34,7 +34,6 @@ import dis from "../../dispatcher/dispatcher";
|
|||||||
import Notifier from '../../Notifier';
|
import Notifier from '../../Notifier';
|
||||||
|
|
||||||
import Modal from "../../Modal";
|
import Modal from "../../Modal";
|
||||||
import Tinter from "../../Tinter";
|
|
||||||
import * as sdk from '../../index';
|
import * as sdk from '../../index';
|
||||||
import { showRoomInviteDialog, showStartChatInviteDialog } from '../../RoomInvite';
|
import { showRoomInviteDialog, showStartChatInviteDialog } from '../../RoomInvite';
|
||||||
import * as Rooms from '../../Rooms';
|
import * as Rooms from '../../Rooms';
|
||||||
@ -283,11 +282,6 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
|
|||||||
|
|
||||||
this.pageChanging = false;
|
this.pageChanging = false;
|
||||||
|
|
||||||
// check we have the right tint applied for this theme.
|
|
||||||
// N.B. we don't call the whole of setTheme() here as we may be
|
|
||||||
// racing with the theme CSS download finishing from index.js
|
|
||||||
Tinter.tint();
|
|
||||||
|
|
||||||
// For PersistentElement
|
// For PersistentElement
|
||||||
this.state.resizeNotifier.on("middlePanelResized", this.dispatchTimelineResize);
|
this.state.resizeNotifier.on("middlePanelResized", this.dispatchTimelineResize);
|
||||||
|
|
||||||
@ -1573,10 +1567,6 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
// Fire the tinter right on startup to ensure the default theme is applied
|
|
||||||
// A later sync can/will correct the tint to be the right value for the user
|
|
||||||
const colorScheme = SettingsStore.getValue("roomColor");
|
|
||||||
Tinter.tint(colorScheme.primary_color, colorScheme.secondary_color);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -123,7 +123,7 @@ export default class MyGroups extends React.Component {
|
|||||||
</div>
|
</div>
|
||||||
{/*<div className="mx_MyGroups_joinBox mx_MyGroups_headerCard">
|
{/*<div className="mx_MyGroups_joinBox mx_MyGroups_headerCard">
|
||||||
<AccessibleButton className='mx_MyGroups_headerCard_button' onClick={this._onJoinGroupClick}>
|
<AccessibleButton className='mx_MyGroups_headerCard_button' onClick={this._onJoinGroupClick}>
|
||||||
<TintableSvg src={require("../../../res/img/icons-create-room.svg")} width="50" height="50" />
|
<img src={require("../../../res/img/icons-create-room.svg")} width="50" height="50" />
|
||||||
</AccessibleButton>
|
</AccessibleButton>
|
||||||
<div className="mx_MyGroups_headerCard_content">
|
<div className="mx_MyGroups_headerCard_content">
|
||||||
<div className="mx_MyGroups_headerCard_header">
|
<div className="mx_MyGroups_headerCard_header">
|
||||||
|
@ -37,7 +37,6 @@ import Modal from '../../Modal';
|
|||||||
import * as sdk from '../../index';
|
import * as sdk from '../../index';
|
||||||
import CallHandler, { PlaceCallType } from '../../CallHandler';
|
import CallHandler, { PlaceCallType } from '../../CallHandler';
|
||||||
import dis from '../../dispatcher/dispatcher';
|
import dis from '../../dispatcher/dispatcher';
|
||||||
import Tinter from '../../Tinter';
|
|
||||||
import rateLimitedFunc from '../../ratelimitedfunc';
|
import rateLimitedFunc from '../../ratelimitedfunc';
|
||||||
import * as Rooms from '../../Rooms';
|
import * as Rooms from '../../Rooms';
|
||||||
import eventSearch, { searchPagination } from '../../Searching';
|
import eventSearch, { searchPagination } from '../../Searching';
|
||||||
@ -677,10 +676,6 @@ export default class RoomView extends React.Component<IProps, IState> {
|
|||||||
// cancel any pending calls to the rate_limited_funcs
|
// cancel any pending calls to the rate_limited_funcs
|
||||||
this.updateRoomMembers.cancelPendingCall();
|
this.updateRoomMembers.cancelPendingCall();
|
||||||
|
|
||||||
// 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
|
|
||||||
|
|
||||||
for (const watcher of this.settingWatchers) {
|
for (const watcher of this.settingWatchers) {
|
||||||
SettingsStore.unwatchSetting(watcher);
|
SettingsStore.unwatchSetting(watcher);
|
||||||
}
|
}
|
||||||
@ -1030,10 +1025,6 @@ export default class RoomView extends React.Component<IProps, IState> {
|
|||||||
private updateTint() {
|
private updateTint() {
|
||||||
const room = this.state.room;
|
const room = this.state.room;
|
||||||
if (!room) return;
|
if (!room) return;
|
||||||
|
|
||||||
console.log("Tinter.tint from updateTint");
|
|
||||||
const colorScheme = SettingsStore.getValue("roomColor", room.roomId);
|
|
||||||
Tinter.tint(colorScheme.primary_color, colorScheme.secondary_color);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private onAccountData = (event: MatrixEvent) => {
|
private onAccountData = (event: MatrixEvent) => {
|
||||||
@ -1047,12 +1038,7 @@ export default class RoomView extends React.Component<IProps, IState> {
|
|||||||
private onRoomAccountData = (event: MatrixEvent, room: Room) => {
|
private onRoomAccountData = (event: MatrixEvent, room: Room) => {
|
||||||
if (room.roomId == this.state.roomId) {
|
if (room.roomId == this.state.roomId) {
|
||||||
const type = event.getType();
|
const type = event.getType();
|
||||||
if (type === "org.matrix.room.color_scheme") {
|
if (type === "org.matrix.room.preview_urls" || type === "im.vector.web.settings") {
|
||||||
const colorScheme = event.getContent();
|
|
||||||
// XXX: we should validate the event
|
|
||||||
console.log("Tinter.tint from onRoomAccountData");
|
|
||||||
Tinter.tint(colorScheme.primary_color, colorScheme.secondary_color);
|
|
||||||
} else if (type === "org.matrix.room.preview_urls" || type === "im.vector.web.settings") {
|
|
||||||
// non-e2ee url previews are stored in legacy event type `org.matrix.room.preview_urls`
|
// non-e2ee url previews are stored in legacy event type `org.matrix.room.preview_urls`
|
||||||
this.updatePreviewUrlVisibility(room);
|
this.updatePreviewUrlVisibility(room);
|
||||||
}
|
}
|
||||||
|
@ -62,8 +62,6 @@ export default class ActionButton extends React.Component {
|
|||||||
};
|
};
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const TintableSvg = sdk.getComponent("elements.TintableSvg");
|
|
||||||
|
|
||||||
let tooltip;
|
let tooltip;
|
||||||
if (this.state.showTooltip) {
|
if (this.state.showTooltip) {
|
||||||
const Tooltip = sdk.getComponent("elements.Tooltip");
|
const Tooltip = sdk.getComponent("elements.Tooltip");
|
||||||
@ -71,7 +69,7 @@ export default class ActionButton extends React.Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const icon = this.props.iconPath ?
|
const icon = this.props.iconPath ?
|
||||||
(<TintableSvg src={this.props.iconPath} width={this.props.size} height={this.props.size} />) :
|
(<img src={this.props.iconPath} width={this.props.size} height={this.props.size} />) :
|
||||||
undefined;
|
undefined;
|
||||||
|
|
||||||
const classNames = ["mx_RoleButton"];
|
const classNames = ["mx_RoleButton"];
|
||||||
|
@ -53,7 +53,6 @@ export default class AddressTile extends React.Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const BaseAvatar = sdk.getComponent('avatars.BaseAvatar');
|
const BaseAvatar = sdk.getComponent('avatars.BaseAvatar');
|
||||||
const TintableSvg = sdk.getComponent("elements.TintableSvg");
|
|
||||||
|
|
||||||
const nameClasses = classNames({
|
const nameClasses = classNames({
|
||||||
"mx_AddressTile_name": true,
|
"mx_AddressTile_name": true,
|
||||||
@ -124,7 +123,7 @@ export default class AddressTile extends React.Component {
|
|||||||
if (this.props.canDismiss) {
|
if (this.props.canDismiss) {
|
||||||
dismiss = (
|
dismiss = (
|
||||||
<div className="mx_AddressTile_dismiss" onClick={this.props.onDismissed} >
|
<div className="mx_AddressTile_dismiss" onClick={this.props.onDismissed} >
|
||||||
<TintableSvg src={require("../../../../res/img/icon-address-delete.svg")} width="9" height="9" />
|
<img src={require("../../../../res/img/icon-address-delete.svg")} width="9" height="9" />
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -1,82 +0,0 @@
|
|||||||
/*
|
|
||||||
Copyright 2015 OpenMarket Ltd
|
|
||||||
Copyright 2019 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
import React from 'react';
|
|
||||||
import PropTypes from 'prop-types';
|
|
||||||
import Tinter from "../../../Tinter";
|
|
||||||
import {replaceableComponent} from "../../../utils/replaceableComponent";
|
|
||||||
|
|
||||||
@replaceableComponent("views.elements.TintableSvg")
|
|
||||||
class TintableSvg extends React.Component {
|
|
||||||
static propTypes = {
|
|
||||||
src: PropTypes.string.isRequired,
|
|
||||||
width: PropTypes.string.isRequired,
|
|
||||||
height: PropTypes.string.isRequired,
|
|
||||||
className: PropTypes.string,
|
|
||||||
};
|
|
||||||
|
|
||||||
// list of currently mounted TintableSvgs
|
|
||||||
static mounts = {};
|
|
||||||
static idSequence = 0;
|
|
||||||
|
|
||||||
componentDidMount() {
|
|
||||||
this.fixups = [];
|
|
||||||
|
|
||||||
this.id = TintableSvg.idSequence++;
|
|
||||||
TintableSvg.mounts[this.id] = this;
|
|
||||||
}
|
|
||||||
|
|
||||||
componentWillUnmount() {
|
|
||||||
delete TintableSvg.mounts[this.id];
|
|
||||||
}
|
|
||||||
|
|
||||||
tint = () => {
|
|
||||||
// TODO: only bother running this if the global tint settings have changed
|
|
||||||
// since we loaded!
|
|
||||||
Tinter.applySvgFixups(this.fixups);
|
|
||||||
};
|
|
||||||
|
|
||||||
onLoad = event => {
|
|
||||||
// console.log("TintableSvg.onLoad for " + this.props.src);
|
|
||||||
this.fixups = Tinter.calcSvgFixups([event.target]);
|
|
||||||
Tinter.applySvgFixups(this.fixups);
|
|
||||||
};
|
|
||||||
|
|
||||||
render() {
|
|
||||||
return (
|
|
||||||
<object className={"mx_TintableSvg " + (this.props.className ? this.props.className : "")}
|
|
||||||
type="image/svg+xml"
|
|
||||||
data={this.props.src}
|
|
||||||
width={this.props.width}
|
|
||||||
height={this.props.height}
|
|
||||||
onLoad={this.onLoad}
|
|
||||||
tabIndex="-1"
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Register with the Tinter so that we will be told if the tint changes
|
|
||||||
Tinter.registerTintable(function() {
|
|
||||||
if (TintableSvg.mounts) {
|
|
||||||
Object.keys(TintableSvg.mounts).forEach((id) => {
|
|
||||||
TintableSvg.mounts[id].tint();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
export default TintableSvg;
|
|
@ -16,7 +16,6 @@ limitations under the License.
|
|||||||
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import * as sdk from '../../../index';
|
|
||||||
import {replaceableComponent} from "../../../utils/replaceableComponent";
|
import {replaceableComponent} from "../../../utils/replaceableComponent";
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -35,8 +34,7 @@ export default class SimpleRoomHeader extends React.Component {
|
|||||||
render() {
|
render() {
|
||||||
let icon;
|
let icon;
|
||||||
if (this.props.icon) {
|
if (this.props.icon) {
|
||||||
const TintableSvg = sdk.getComponent('elements.TintableSvg');
|
icon = <img
|
||||||
icon = <TintableSvg
|
|
||||||
className="mx_RoomHeader_icon" src={this.props.icon}
|
className="mx_RoomHeader_icon" src={this.props.icon}
|
||||||
width="25" height="25"
|
width="25" height="25"
|
||||||
/>;
|
/>;
|
||||||
|
@ -857,7 +857,6 @@
|
|||||||
"Enable inline URL previews by default": "Enable inline URL previews by default",
|
"Enable inline URL previews by default": "Enable inline URL previews by default",
|
||||||
"Enable URL previews for this room (only affects you)": "Enable URL previews for this room (only affects you)",
|
"Enable URL previews for this room (only affects you)": "Enable URL previews for this room (only affects you)",
|
||||||
"Enable URL previews by default for participants in this room": "Enable URL previews by default for participants in this room",
|
"Enable URL previews by default for participants in this room": "Enable URL previews by default for participants in this room",
|
||||||
"Room Colour": "Room Colour",
|
|
||||||
"Enable widget screenshots on supported widgets": "Enable widget screenshots on supported widgets",
|
"Enable widget screenshots on supported widgets": "Enable widget screenshots on supported widgets",
|
||||||
"Prompt before sending invites to potentially invalid matrix IDs": "Prompt before sending invites to potentially invalid matrix IDs",
|
"Prompt before sending invites to potentially invalid matrix IDs": "Prompt before sending invites to potentially invalid matrix IDs",
|
||||||
"Show developer tools": "Show developer tools",
|
"Show developer tools": "Show developer tools",
|
||||||
|
@ -606,14 +606,6 @@ export const SETTINGS: {[setting: string]: ISetting} = {
|
|||||||
default: false,
|
default: false,
|
||||||
controller: new UIFeatureController(UIFeature.URLPreviews),
|
controller: new UIFeatureController(UIFeature.URLPreviews),
|
||||||
},
|
},
|
||||||
"roomColor": {
|
|
||||||
supportedLevels: LEVELS_ROOM_SETTINGS_WITH_ROOM,
|
|
||||||
displayName: _td("Room Colour"),
|
|
||||||
default: {
|
|
||||||
primary_color: null, // Hex string, eg: #000000
|
|
||||||
secondary_color: null, // Hex string, eg: #000000
|
|
||||||
},
|
|
||||||
},
|
|
||||||
"notificationsEnabled": {
|
"notificationsEnabled": {
|
||||||
supportedLevels: LEVELS_DEVICE_ONLY_SETTINGS,
|
supportedLevels: LEVELS_DEVICE_ONLY_SETTINGS,
|
||||||
default: false,
|
default: false,
|
||||||
|
@ -54,8 +54,6 @@ export default class RoomAccountSettingsHandler extends MatrixClientBackedSettin
|
|||||||
}
|
}
|
||||||
|
|
||||||
this.watchers.notifyUpdate("urlPreviewsEnabled", roomId, SettingLevel.ROOM_ACCOUNT, val);
|
this.watchers.notifyUpdate("urlPreviewsEnabled", roomId, SettingLevel.ROOM_ACCOUNT, val);
|
||||||
} else if (event.getType() === "org.matrix.room.color_scheme") {
|
|
||||||
this.watchers.notifyUpdate("roomColor", roomId, SettingLevel.ROOM_ACCOUNT, event.getContent());
|
|
||||||
} else if (event.getType() === "im.vector.web.settings") {
|
} else if (event.getType() === "im.vector.web.settings") {
|
||||||
// Figure out what changed and fire those updates
|
// Figure out what changed and fire those updates
|
||||||
const prevContent = prevEvent ? prevEvent.getContent() : {};
|
const prevContent = prevEvent ? prevEvent.getContent() : {};
|
||||||
@ -79,14 +77,6 @@ export default class RoomAccountSettingsHandler extends MatrixClientBackedSettin
|
|||||||
return !content['disable'];
|
return !content['disable'];
|
||||||
}
|
}
|
||||||
|
|
||||||
// Special case room color
|
|
||||||
if (settingName === "roomColor") {
|
|
||||||
// The event content should already be in an appropriate format, we just need
|
|
||||||
// to get the right value.
|
|
||||||
// don't fallback to {} because thats truthy and would imply there is an event specifying tint
|
|
||||||
return this.getSettings(roomId, "org.matrix.room.color_scheme");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Special case allowed widgets
|
// Special case allowed widgets
|
||||||
if (settingName === "allowedWidgets") {
|
if (settingName === "allowedWidgets") {
|
||||||
return this.getSettings(roomId, ALLOWED_WIDGETS_EVENT_TYPE);
|
return this.getSettings(roomId, ALLOWED_WIDGETS_EVENT_TYPE);
|
||||||
@ -104,12 +94,6 @@ export default class RoomAccountSettingsHandler extends MatrixClientBackedSettin
|
|||||||
return MatrixClientPeg.get().setRoomAccountData(roomId, "org.matrix.room.preview_urls", content);
|
return MatrixClientPeg.get().setRoomAccountData(roomId, "org.matrix.room.preview_urls", content);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Special case room color
|
|
||||||
if (settingName === "roomColor") {
|
|
||||||
// The new value should match our requirements, we just need to store it in the right place.
|
|
||||||
return MatrixClientPeg.get().setRoomAccountData(roomId, "org.matrix.room.color_scheme", newValue);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Special case allowed widgets
|
// Special case allowed widgets
|
||||||
if (settingName === "allowedWidgets") {
|
if (settingName === "allowedWidgets") {
|
||||||
return MatrixClientPeg.get().setRoomAccountData(roomId, ALLOWED_WIDGETS_EVENT_TYPE, newValue);
|
return MatrixClientPeg.get().setRoomAccountData(roomId, ALLOWED_WIDGETS_EVENT_TYPE, newValue);
|
||||||
|
@ -18,7 +18,6 @@ limitations under the License.
|
|||||||
import {_t} from "./languageHandler";
|
import {_t} from "./languageHandler";
|
||||||
|
|
||||||
export const DEFAULT_THEME = "light";
|
export const DEFAULT_THEME = "light";
|
||||||
import Tinter from "./Tinter";
|
|
||||||
import SettingsStore from "./settings/SettingsStore";
|
import SettingsStore from "./settings/SettingsStore";
|
||||||
import ThemeWatcher from "./settings/watchers/ThemeWatcher";
|
import ThemeWatcher from "./settings/watchers/ThemeWatcher";
|
||||||
|
|
||||||
@ -214,7 +213,6 @@ export async function setTheme(theme) {
|
|||||||
if (bodyStyles.backgroundColor) {
|
if (bodyStyles.backgroundColor) {
|
||||||
document.querySelector('meta[name="theme-color"]').content = bodyStyles.backgroundColor;
|
document.querySelector('meta[name="theme-color"]').content = bodyStyles.backgroundColor;
|
||||||
}
|
}
|
||||||
Tinter.setTheme(theme);
|
|
||||||
resolve();
|
resolve();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user