Don't hammer on the layout engine with avatar updates for the background

Changing the property on every render of the left panel (which is basically all the time) is super bad on the GPU and for our CPU. We should only do that when something changes.
This commit is contained in:
Travis Ralston 2020-07-21 15:02:59 -06:00
parent cbe4f04cd7
commit 0a846cb1b5
3 changed files with 26 additions and 3 deletions

View file

@ -35,6 +35,8 @@ import RoomListStore, { LISTS_UPDATE_EVENT } from "../../stores/room-list/RoomLi
import {Key} from "../../Keyboard"; import {Key} from "../../Keyboard";
import IndicatorScrollbar from "../structures/IndicatorScrollbar"; import IndicatorScrollbar from "../structures/IndicatorScrollbar";
import AccessibleTooltipButton from "../views/elements/AccessibleTooltipButton"; import AccessibleTooltipButton from "../views/elements/AccessibleTooltipButton";
import { OwnProfileStore } from "../../stores/OwnProfileStore";
import { MatrixClientPeg } from "../../MatrixClientPeg";
interface IProps { interface IProps {
isMinimized: boolean; isMinimized: boolean;
@ -59,6 +61,7 @@ const cssClasses = [
export default class LeftPanel extends React.Component<IProps, IState> { export default class LeftPanel extends React.Component<IProps, IState> {
private listContainerRef: React.RefObject<HTMLDivElement> = createRef(); private listContainerRef: React.RefObject<HTMLDivElement> = createRef();
private tagPanelWatcherRef: string; private tagPanelWatcherRef: string;
private bgImageWatcherRef: string;
private focusedElement = null; private focusedElement = null;
private isDoingStickyHeaders = false; private isDoingStickyHeaders = false;
@ -73,6 +76,9 @@ export default class LeftPanel extends React.Component<IProps, IState> {
BreadcrumbsStore.instance.on(UPDATE_EVENT, this.onBreadcrumbsUpdate); BreadcrumbsStore.instance.on(UPDATE_EVENT, this.onBreadcrumbsUpdate);
RoomListStore.instance.on(LISTS_UPDATE_EVENT, this.onBreadcrumbsUpdate); RoomListStore.instance.on(LISTS_UPDATE_EVENT, this.onBreadcrumbsUpdate);
OwnProfileStore.instance.on(UPDATE_EVENT, this.onBackgroundImageUpdate);
this.bgImageWatcherRef = SettingsStore.watchSetting(
"RoomList.backgroundImage", null, this.onBackgroundImageUpdate);
this.tagPanelWatcherRef = SettingsStore.watchSetting("TagPanel.enableTagPanel", null, () => { this.tagPanelWatcherRef = SettingsStore.watchSetting("TagPanel.enableTagPanel", null, () => {
this.setState({showTagPanel: SettingsStore.getValue("TagPanel.enableTagPanel")}); this.setState({showTagPanel: SettingsStore.getValue("TagPanel.enableTagPanel")});
}); });
@ -84,8 +90,10 @@ export default class LeftPanel extends React.Component<IProps, IState> {
public componentWillUnmount() { public componentWillUnmount() {
SettingsStore.unwatchSetting(this.tagPanelWatcherRef); SettingsStore.unwatchSetting(this.tagPanelWatcherRef);
SettingsStore.unwatchSetting(this.bgImageWatcherRef);
BreadcrumbsStore.instance.off(UPDATE_EVENT, this.onBreadcrumbsUpdate); BreadcrumbsStore.instance.off(UPDATE_EVENT, this.onBreadcrumbsUpdate);
RoomListStore.instance.off(LISTS_UPDATE_EVENT, this.onBreadcrumbsUpdate); RoomListStore.instance.off(LISTS_UPDATE_EVENT, this.onBreadcrumbsUpdate);
OwnProfileStore.instance.off(UPDATE_EVENT, this.onBackgroundImageUpdate);
this.props.resizeNotifier.off("middlePanelResizedNoisy", this.onResize); this.props.resizeNotifier.off("middlePanelResizedNoisy", this.onResize);
} }
@ -108,6 +116,20 @@ export default class LeftPanel extends React.Component<IProps, IState> {
} }
}; };
private onBackgroundImageUpdate = () => {
// Note: we do this in the LeftPanel as it uses this variable most prominently.
const avatarSize = 32; // arbitrary
let avatarUrl = OwnProfileStore.instance.getHttpAvatarUrl(avatarSize);
const settingBgMxc = SettingsStore.getValue("RoomList.backgroundImage");
if (settingBgMxc) {
avatarUrl = MatrixClientPeg.get().mxcUrlToHttp(settingBgMxc, avatarSize, avatarSize);
}
const avatarUrlProp = `url(${avatarUrl})`;
if (document.body.style.getPropertyValue("--avatar-url") !== avatarUrlProp) {
document.body.style.setProperty("--avatar-url", avatarUrlProp);
}
};
private handleStickyHeaders(list: HTMLDivElement) { private handleStickyHeaders(list: HTMLDivElement) {
if (this.isDoingStickyHeaders) return; if (this.isDoingStickyHeaders) return;
this.isDoingStickyHeaders = true; this.isDoingStickyHeaders = true;

View file

@ -306,9 +306,6 @@ export default class UserMenu extends React.Component<IProps, IState> {
public render() { public render() {
const avatarSize = 32; // should match border-radius of the avatar const avatarSize = 32; // should match border-radius of the avatar
const {body} = document;
const avatarUrl = OwnProfileStore.instance.getHttpAvatarUrl(avatarSize);
body.style.setProperty("--avatar-url", `url('${avatarUrl}')`);
let name = <span className="mx_UserMenu_userName">{OwnProfileStore.instance.displayName}</span>; let name = <span className="mx_UserMenu_userName">{OwnProfileStore.instance.displayName}</span>;
let buttons = ( let buttons = (

View file

@ -166,6 +166,10 @@ export const SETTINGS = {
displayName: _td("Show info about bridges in room settings"), displayName: _td("Show info about bridges in room settings"),
default: false, default: false,
}, },
"RoomList.backgroundImage": {
supportedLevels: LEVELS_ACCOUNT_SETTINGS,
default: null,
},
"baseFontSize": { "baseFontSize": {
displayName: _td("Font size"), displayName: _td("Font size"),
supportedLevels: LEVELS_ACCOUNT_SETTINGS, supportedLevels: LEVELS_ACCOUNT_SETTINGS,