mirror of https://github.com/vector-im/riot-web
Merge pull request #6659 from matrix-org/palid/fix/backdrop-blur
Optimize background image from avatar on left panelpull/21833/head
commit
6205cbbdec
|
@ -64,7 +64,6 @@
|
||||||
"cheerio": "^1.0.0-rc.9",
|
"cheerio": "^1.0.0-rc.9",
|
||||||
"classnames": "^2.2.6",
|
"classnames": "^2.2.6",
|
||||||
"commonmark": "^0.29.3",
|
"commonmark": "^0.29.3",
|
||||||
"context-filter-polyfill": "^0.2.4",
|
|
||||||
"counterpart": "^0.18.6",
|
"counterpart": "^0.18.6",
|
||||||
"diff-dom": "^4.2.2",
|
"diff-dom": "^4.2.2",
|
||||||
"diff-match-patch": "^1.0.5",
|
"diff-match-patch": "^1.0.5",
|
||||||
|
@ -196,7 +195,6 @@
|
||||||
"decoderWorker\\.min\\.js": "<rootDir>/__mocks__/empty.js",
|
"decoderWorker\\.min\\.js": "<rootDir>/__mocks__/empty.js",
|
||||||
"decoderWorker\\.min\\.wasm": "<rootDir>/__mocks__/empty.js",
|
"decoderWorker\\.min\\.wasm": "<rootDir>/__mocks__/empty.js",
|
||||||
"waveWorker\\.min\\.js": "<rootDir>/__mocks__/empty.js",
|
"waveWorker\\.min\\.js": "<rootDir>/__mocks__/empty.js",
|
||||||
"context-filter-polyfill": "<rootDir>/__mocks__/empty.js",
|
|
||||||
"workers/(.+)\\.worker\\.ts": "<rootDir>/__mocks__/workerMock.js",
|
"workers/(.+)\\.worker\\.ts": "<rootDir>/__mocks__/workerMock.js",
|
||||||
"RecorderWorklet": "<rootDir>/__mocks__/empty.js"
|
"RecorderWorklet": "<rootDir>/__mocks__/empty.js"
|
||||||
},
|
},
|
||||||
|
|
|
@ -21,19 +21,10 @@ limitations under the License.
|
||||||
height: 100vh;
|
height: 100vh;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
|
filter: blur(var(--lp-background-blur));
|
||||||
&::before {
|
|
||||||
content: " ";
|
|
||||||
position: absolute;
|
|
||||||
left: 0;
|
|
||||||
top: 0;
|
|
||||||
height: 100vh;
|
|
||||||
width: 100%;
|
|
||||||
background-color: var(--lp-background-overlay);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.mx_BackdropPanel--canvas {
|
.mx_BackdropPanel--image {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 0;
|
top: 0;
|
||||||
left: 0;
|
left: 0;
|
||||||
|
@ -41,11 +32,4 @@ limitations under the License.
|
||||||
z-index: 0;
|
z-index: 0;
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
|
|
||||||
&:nth-of-type(2n-1) {
|
|
||||||
opacity: 0.2;
|
|
||||||
}
|
|
||||||
&:nth-of-type(2n) {
|
|
||||||
opacity: 0.1;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,13 +14,23 @@ See the License for the specific language governing permissions and
|
||||||
limitations under the License.
|
limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
.mx_MatrixChat--with-avatar {
|
$groupFilterPanelWidth: 56px; // only applies in this file, used for calculations
|
||||||
.mx_GroupFilterPanel {
|
|
||||||
background-color: transparent;
|
.mx_GroupFilterPanelContainer {
|
||||||
}
|
flex-grow: 0;
|
||||||
|
flex-shrink: 0;
|
||||||
|
width: $groupFilterPanelWidth;
|
||||||
|
height: 100%;
|
||||||
|
|
||||||
|
// Create another flexbox so the GroupFilterPanel fills the container
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
|
||||||
|
// GroupFilterPanel handles its own CSS
|
||||||
}
|
}
|
||||||
|
|
||||||
.mx_GroupFilterPanel {
|
.mx_GroupFilterPanel {
|
||||||
|
z-index: 1;
|
||||||
background-color: $groupFilterPanel-bg-color;
|
background-color: $groupFilterPanel-bg-color;
|
||||||
flex: 1;
|
flex: 1;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
|
|
@ -14,7 +14,6 @@ See the License for the specific language governing permissions and
|
||||||
limitations under the License.
|
limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
$groupFilterPanelWidth: 56px; // only applies in this file, used for calculations
|
|
||||||
$roomListCollapsedWidth: 68px;
|
$roomListCollapsedWidth: 68px;
|
||||||
|
|
||||||
.mx_MatrixChat--with-avatar {
|
.mx_MatrixChat--with-avatar {
|
||||||
|
@ -27,8 +26,17 @@ $roomListCollapsedWidth: 68px;
|
||||||
.mx_LeftPanel_wrapper {
|
.mx_LeftPanel_wrapper {
|
||||||
display: flex;
|
display: flex;
|
||||||
max-width: 50%;
|
max-width: 50%;
|
||||||
|
|
||||||
|
.mx_LeftPanel_wrapper--user {
|
||||||
|
background-color: $roomlist-bg-color;
|
||||||
|
display: flex;
|
||||||
|
overflow: hidden;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
.mx_LeftPanel {
|
.mx_LeftPanel {
|
||||||
background-color: $roomlist-bg-color;
|
background-color: $roomlist-bg-color;
|
||||||
// TODO decrease this once Spaces launches as it'll no longer need to include the 56px Community Panel
|
// TODO decrease this once Spaces launches as it'll no longer need to include the 56px Community Panel
|
||||||
|
@ -39,19 +47,6 @@ $roomListCollapsedWidth: 68px;
|
||||||
contain: content;
|
contain: content;
|
||||||
position: relative;
|
position: relative;
|
||||||
|
|
||||||
.mx_LeftPanel_GroupFilterPanelContainer {
|
|
||||||
flex-grow: 0;
|
|
||||||
flex-shrink: 0;
|
|
||||||
flex-basis: $groupFilterPanelWidth;
|
|
||||||
height: 100%;
|
|
||||||
|
|
||||||
// Create another flexbox so the GroupFilterPanel fills the container
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
|
|
||||||
// GroupFilterPanel handles its own CSS
|
|
||||||
}
|
|
||||||
|
|
||||||
// Note: The 'room list' in this context is actually everything that isn't the tag
|
// Note: The 'room list' in this context is actually everything that isn't the tag
|
||||||
// panel, such as the menu options, breadcrumbs, filtering, etc
|
// panel, such as the menu options, breadcrumbs, filtering, etc
|
||||||
.mx_LeftPanel_roomListContainer {
|
.mx_LeftPanel_roomListContainer {
|
||||||
|
|
|
@ -22,18 +22,14 @@ $activeBorderTransparentGap: 1px;
|
||||||
$activeBackgroundColor: $roomtile-selected-bg-color;
|
$activeBackgroundColor: $roomtile-selected-bg-color;
|
||||||
$activeBorderColor: $secondary-fg-color;
|
$activeBorderColor: $secondary-fg-color;
|
||||||
|
|
||||||
.mx_MatrixChat--with-avatar {
|
|
||||||
.mx_SpacePanel {
|
|
||||||
background-color: transparent;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.mx_SpacePanel {
|
.mx_SpacePanel {
|
||||||
background-color: $groupFilterPanel-bg-color;
|
background-color: $groupFilterPanel-bg-color;
|
||||||
flex: 0 0 auto;
|
flex: 0 0 auto;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
position: relative;
|
position: relative;
|
||||||
|
// Fix for the blurred avatar-background
|
||||||
|
z-index: 1;
|
||||||
|
|
||||||
// Create another flexbox so the Panel fills the container
|
// Create another flexbox so the Panel fills the container
|
||||||
display: flex;
|
display: flex;
|
||||||
|
|
|
@ -240,9 +240,7 @@ $appearance-tab-border-color: $room-highlight-color;
|
||||||
|
|
||||||
// blur amounts for left left panel (only for element theme)
|
// blur amounts for left left panel (only for element theme)
|
||||||
:root {
|
:root {
|
||||||
--llp-background-blur: 160px;
|
--lp-background-blur: 45px;
|
||||||
--lp-background-blur: 90px;
|
|
||||||
--lp-background-overlay: rgba(255, 255, 255, 0.055);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$composer-shadow-color: rgba(0, 0, 0, 0.28);
|
$composer-shadow-color: rgba(0, 0, 0, 0.28);
|
||||||
|
|
|
@ -363,9 +363,7 @@ $appearance-tab-border-color: $input-darker-bg-color;
|
||||||
|
|
||||||
// blur amounts for left left panel (only for element theme)
|
// blur amounts for left left panel (only for element theme)
|
||||||
:root {
|
:root {
|
||||||
--llp-background-blur: 120px;
|
--lp-background-blur: 30px;
|
||||||
--lp-background-blur: 60px;
|
|
||||||
--lp-background-overlay: rgba(0, 0, 0, 0.055);
|
|
||||||
}
|
}
|
||||||
$composer-shadow-color: rgba(0, 0, 0, 0.04);
|
$composer-shadow-color: rgba(0, 0, 0, 0.04);
|
||||||
|
|
||||||
|
|
|
@ -14,153 +14,31 @@ See the License for the specific language governing permissions and
|
||||||
limitations under the License.
|
limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import React, { createRef } from "react";
|
import React, { CSSProperties } from "react";
|
||||||
import "context-filter-polyfill";
|
|
||||||
|
|
||||||
import UIStore from "../../stores/UIStore";
|
|
||||||
|
|
||||||
interface IProps {
|
interface IProps {
|
||||||
backgroundImage?: CanvasImageSource;
|
backgroundImage?: string;
|
||||||
|
blurMultiplier?: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface IState {
|
export const BackdropPanel: React.FC<IProps> = ({ backgroundImage, blurMultiplier }) => {
|
||||||
// Left Panel image
|
if (!backgroundImage) return null;
|
||||||
lpImage?: string;
|
|
||||||
// Left-left panel image
|
|
||||||
llpImage?: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export default class BackdropPanel extends React.PureComponent<IProps, IState> {
|
const styles: CSSProperties = {};
|
||||||
private leftLeftPanelRef = createRef<HTMLCanvasElement>();
|
if (blurMultiplier) {
|
||||||
private leftPanelRef = createRef<HTMLCanvasElement>();
|
const rootStyle = getComputedStyle(document.documentElement);
|
||||||
|
const blurValue = rootStyle.getPropertyValue('--lp-background-blur');
|
||||||
private sizes = {
|
const pixelsValue = blurValue.replace('px', '');
|
||||||
leftLeftPanelWidth: 0,
|
const parsed = parseInt(pixelsValue, 10);
|
||||||
leftPanelWidth: 0,
|
if (!isNaN(parsed)) {
|
||||||
height: 0,
|
styles.filter = `blur(${parsed * blurMultiplier}px)`;
|
||||||
};
|
|
||||||
private style = getComputedStyle(document.documentElement);
|
|
||||||
|
|
||||||
public state: IState = {};
|
|
||||||
|
|
||||||
public componentDidMount() {
|
|
||||||
UIStore.instance.on("SpacePanel", this.onResize);
|
|
||||||
UIStore.instance.on("GroupFilterPanelContainer", this.onResize);
|
|
||||||
this.onResize();
|
|
||||||
}
|
|
||||||
|
|
||||||
public componentWillUnmount() {
|
|
||||||
UIStore.instance.off("SpacePanel", this.onResize);
|
|
||||||
UIStore.instance.on("GroupFilterPanelContainer", this.onResize);
|
|
||||||
}
|
|
||||||
|
|
||||||
public componentDidUpdate(prevProps: IProps) {
|
|
||||||
if (prevProps.backgroundImage !== this.props.backgroundImage) {
|
|
||||||
this.setState({});
|
|
||||||
this.onResize();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return <div className="mx_BackdropPanel">
|
||||||
private onResize = () => {
|
<img
|
||||||
if (this.props.backgroundImage) {
|
style={styles}
|
||||||
const groupFilterPanelDimensions = UIStore.instance.getElementDimensions("GroupFilterPanelContainer");
|
className="mx_BackdropPanel--image"
|
||||||
const spacePanelDimensions = UIStore.instance.getElementDimensions("SpacePanel");
|
src={backgroundImage} />
|
||||||
const roomListDimensions = UIStore.instance.getElementDimensions("LeftPanel");
|
</div>;
|
||||||
this.sizes = {
|
};
|
||||||
leftLeftPanelWidth: spacePanelDimensions?.width ?? groupFilterPanelDimensions?.width ?? 0,
|
export default BackdropPanel;
|
||||||
leftPanelWidth: roomListDimensions?.width ?? 0,
|
|
||||||
height: UIStore.instance.windowHeight,
|
|
||||||
};
|
|
||||||
this.refreshBackdropImage();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
private refreshBackdropImage = (): void => {
|
|
||||||
const leftLeftPanelContext = this.leftLeftPanelRef.current.getContext("2d");
|
|
||||||
const leftPanelContext = this.leftPanelRef.current.getContext("2d");
|
|
||||||
const { leftLeftPanelWidth, leftPanelWidth, height } = this.sizes;
|
|
||||||
const width = leftLeftPanelWidth + leftPanelWidth;
|
|
||||||
const { backgroundImage } = this.props;
|
|
||||||
|
|
||||||
const imageWidth = (backgroundImage as ImageBitmap).width;
|
|
||||||
const imageHeight = (backgroundImage as ImageBitmap).height;
|
|
||||||
|
|
||||||
const contentRatio = imageWidth / imageHeight;
|
|
||||||
const containerRatio = width / height;
|
|
||||||
let resultHeight;
|
|
||||||
let resultWidth;
|
|
||||||
if (contentRatio > containerRatio) {
|
|
||||||
resultHeight = height;
|
|
||||||
resultWidth = height * contentRatio;
|
|
||||||
} else {
|
|
||||||
resultWidth = width;
|
|
||||||
resultHeight = width / contentRatio;
|
|
||||||
}
|
|
||||||
|
|
||||||
// This value has been chosen to be as close with rendering as the css-only
|
|
||||||
// backdrop-filter: blur effect was, mostly takes effect for vertical pictures.
|
|
||||||
const x = width * 0.1;
|
|
||||||
const y = (height - resultHeight) / 2;
|
|
||||||
|
|
||||||
this.leftLeftPanelRef.current.width = leftLeftPanelWidth;
|
|
||||||
this.leftLeftPanelRef.current.height = height;
|
|
||||||
this.leftPanelRef.current.width = (window.screen.width * 0.5);
|
|
||||||
this.leftPanelRef.current.height = height;
|
|
||||||
|
|
||||||
const spacesBlur = this.style.getPropertyValue('--llp-background-blur');
|
|
||||||
const roomListBlur = this.style.getPropertyValue('--lp-background-blur');
|
|
||||||
|
|
||||||
leftLeftPanelContext.filter = `blur(${spacesBlur})`;
|
|
||||||
leftPanelContext.filter = `blur(${roomListBlur})`;
|
|
||||||
leftLeftPanelContext.drawImage(
|
|
||||||
backgroundImage,
|
|
||||||
0, 0,
|
|
||||||
imageWidth, imageHeight,
|
|
||||||
x,
|
|
||||||
y,
|
|
||||||
resultWidth,
|
|
||||||
resultHeight,
|
|
||||||
);
|
|
||||||
leftPanelContext.drawImage(
|
|
||||||
backgroundImage,
|
|
||||||
0, 0,
|
|
||||||
imageWidth, imageHeight,
|
|
||||||
x - leftLeftPanelWidth,
|
|
||||||
y,
|
|
||||||
resultWidth,
|
|
||||||
resultHeight,
|
|
||||||
);
|
|
||||||
this.setState({
|
|
||||||
lpImage: this.leftPanelRef.current.toDataURL('image/jpeg', 1),
|
|
||||||
llpImage: this.leftLeftPanelRef.current.toDataURL('image/jpeg', 1),
|
|
||||||
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
public render() {
|
|
||||||
if (!this.props.backgroundImage) return null;
|
|
||||||
return <div className="mx_BackdropPanel">
|
|
||||||
{ this.state?.llpImage !== 'data:,' && <img
|
|
||||||
className="mx_BackdropPanel--canvas"
|
|
||||||
src={this.state.llpImage} /> }
|
|
||||||
|
|
||||||
{ this.state?.lpImage !== 'data:,' && <img
|
|
||||||
className="mx_BackdropPanel--canvas"
|
|
||||||
src={this.state.lpImage} /> }
|
|
||||||
<canvas
|
|
||||||
ref={this.leftLeftPanelRef}
|
|
||||||
className="mx_BackdropPanel--canvas"
|
|
||||||
style={{
|
|
||||||
display: this.state.lpImage ? 'none' : 'block',
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
<canvas
|
|
||||||
style={{
|
|
||||||
display: this.state.lpImage ? 'none' : 'block',
|
|
||||||
}}
|
|
||||||
ref={this.leftPanelRef}
|
|
||||||
className="mx_BackdropPanel--canvas"
|
|
||||||
/>
|
|
||||||
</div>;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -19,8 +19,6 @@ import { createRef } from "react";
|
||||||
import classNames from "classnames";
|
import classNames from "classnames";
|
||||||
import { Room } from "matrix-js-sdk/src/models/room";
|
import { Room } from "matrix-js-sdk/src/models/room";
|
||||||
|
|
||||||
import GroupFilterPanel from "./GroupFilterPanel";
|
|
||||||
import CustomRoomTagPanel from "./CustomRoomTagPanel";
|
|
||||||
import dis from "../../dispatcher/dispatcher";
|
import dis from "../../dispatcher/dispatcher";
|
||||||
import { _t } from "../../languageHandler";
|
import { _t } from "../../languageHandler";
|
||||||
import RoomList from "../views/rooms/RoomList";
|
import RoomList from "../views/rooms/RoomList";
|
||||||
|
@ -33,7 +31,6 @@ import RoomBreadcrumbs from "../views/rooms/RoomBreadcrumbs";
|
||||||
import { BreadcrumbsStore } from "../../stores/BreadcrumbsStore";
|
import { BreadcrumbsStore } from "../../stores/BreadcrumbsStore";
|
||||||
import { UPDATE_EVENT } from "../../stores/AsyncStore";
|
import { UPDATE_EVENT } from "../../stores/AsyncStore";
|
||||||
import ResizeNotifier from "../../utils/ResizeNotifier";
|
import ResizeNotifier from "../../utils/ResizeNotifier";
|
||||||
import SettingsStore from "../../settings/SettingsStore";
|
|
||||||
import RoomListStore, { LISTS_UPDATE_EVENT } from "../../stores/room-list/RoomListStore";
|
import RoomListStore, { LISTS_UPDATE_EVENT } from "../../stores/room-list/RoomListStore";
|
||||||
import IndicatorScrollbar from "../structures/IndicatorScrollbar";
|
import IndicatorScrollbar from "../structures/IndicatorScrollbar";
|
||||||
import AccessibleTooltipButton from "../views/elements/AccessibleTooltipButton";
|
import AccessibleTooltipButton from "../views/elements/AccessibleTooltipButton";
|
||||||
|
@ -51,7 +48,6 @@ interface IProps {
|
||||||
|
|
||||||
interface IState {
|
interface IState {
|
||||||
showBreadcrumbs: boolean;
|
showBreadcrumbs: boolean;
|
||||||
showGroupFilterPanel: boolean;
|
|
||||||
activeSpace?: Room;
|
activeSpace?: Room;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -68,9 +64,6 @@ const cssClasses = [
|
||||||
export default class LeftPanel extends React.Component<IProps, IState> {
|
export default class LeftPanel extends React.Component<IProps, IState> {
|
||||||
private ref: React.RefObject<HTMLDivElement> = createRef();
|
private ref: React.RefObject<HTMLDivElement> = createRef();
|
||||||
private listContainerRef: React.RefObject<HTMLDivElement> = createRef();
|
private listContainerRef: React.RefObject<HTMLDivElement> = createRef();
|
||||||
private groupFilterPanelWatcherRef: string;
|
|
||||||
private groupFilterPanelContainer = createRef<HTMLDivElement>();
|
|
||||||
private bgImageWatcherRef: string;
|
|
||||||
private focusedElement = null;
|
private focusedElement = null;
|
||||||
private isDoingStickyHeaders = false;
|
private isDoingStickyHeaders = false;
|
||||||
|
|
||||||
|
@ -79,25 +72,17 @@ export default class LeftPanel extends React.Component<IProps, IState> {
|
||||||
|
|
||||||
this.state = {
|
this.state = {
|
||||||
showBreadcrumbs: BreadcrumbsStore.instance.visible,
|
showBreadcrumbs: BreadcrumbsStore.instance.visible,
|
||||||
showGroupFilterPanel: SettingsStore.getValue('TagPanel.enableTagPanel'),
|
|
||||||
activeSpace: SpaceStore.instance.activeSpace,
|
activeSpace: SpaceStore.instance.activeSpace,
|
||||||
};
|
};
|
||||||
|
|
||||||
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);
|
||||||
SpaceStore.instance.on(UPDATE_SELECTED_SPACE, this.updateActiveSpace);
|
SpaceStore.instance.on(UPDATE_SELECTED_SPACE, this.updateActiveSpace);
|
||||||
this.groupFilterPanelWatcherRef = SettingsStore.watchSetting("TagPanel.enableTagPanel", null, () => {
|
|
||||||
this.setState({ showGroupFilterPanel: SettingsStore.getValue("TagPanel.enableTagPanel") });
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public componentDidMount() {
|
public componentDidMount() {
|
||||||
UIStore.instance.trackElementDimensions("LeftPanel", this.ref.current);
|
UIStore.instance.trackElementDimensions("LeftPanel", this.ref.current);
|
||||||
UIStore.instance.trackElementDimensions("ListContainer", this.listContainerRef.current);
|
UIStore.instance.trackElementDimensions("ListContainer", this.listContainerRef.current);
|
||||||
if (this.groupFilterPanelContainer.current) {
|
|
||||||
const componentName = "GroupFilterPanelContainer";
|
|
||||||
UIStore.instance.trackElementDimensions(componentName, this.groupFilterPanelContainer.current);
|
|
||||||
}
|
|
||||||
UIStore.instance.on("ListContainer", this.refreshStickyHeaders);
|
UIStore.instance.on("ListContainer", this.refreshStickyHeaders);
|
||||||
// Using the passive option to not block the main thread
|
// Using the passive option to not block the main thread
|
||||||
// https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener#improving_scrolling_performance_with_passive_listeners
|
// https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener#improving_scrolling_performance_with_passive_listeners
|
||||||
|
@ -105,7 +90,6 @@ export default class LeftPanel extends React.Component<IProps, IState> {
|
||||||
}
|
}
|
||||||
|
|
||||||
public componentWillUnmount() {
|
public componentWillUnmount() {
|
||||||
SettingsStore.unwatchSetting(this.groupFilterPanelWatcherRef);
|
|
||||||
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);
|
||||||
SpaceStore.instance.off(UPDATE_SELECTED_SPACE, this.updateActiveSpace);
|
SpaceStore.instance.off(UPDATE_SELECTED_SPACE, this.updateActiveSpace);
|
||||||
|
@ -422,16 +406,6 @@ export default class LeftPanel extends React.Component<IProps, IState> {
|
||||||
}
|
}
|
||||||
|
|
||||||
public render(): React.ReactNode {
|
public render(): React.ReactNode {
|
||||||
let leftLeftPanel;
|
|
||||||
if (this.state.showGroupFilterPanel) {
|
|
||||||
leftLeftPanel = (
|
|
||||||
<div className="mx_LeftPanel_GroupFilterPanelContainer" ref={this.groupFilterPanelContainer}>
|
|
||||||
<GroupFilterPanel />
|
|
||||||
{ SettingsStore.getValue("feature_custom_tags") ? <CustomRoomTagPanel /> : null }
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
const roomList = <RoomList
|
const roomList = <RoomList
|
||||||
onKeyDown={this.onKeyDown}
|
onKeyDown={this.onKeyDown}
|
||||||
resizeNotifier={this.props.resizeNotifier}
|
resizeNotifier={this.props.resizeNotifier}
|
||||||
|
@ -455,7 +429,6 @@ export default class LeftPanel extends React.Component<IProps, IState> {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={containerClasses} ref={this.ref}>
|
<div className={containerClasses} ref={this.ref}>
|
||||||
{ leftLeftPanel }
|
|
||||||
<aside className="mx_LeftPanel_roomListContainer">
|
<aside className="mx_LeftPanel_roomListContainer">
|
||||||
{ this.renderHeader() }
|
{ this.renderHeader() }
|
||||||
{ this.renderSearchDialExplore() }
|
{ this.renderSearchDialExplore() }
|
||||||
|
|
|
@ -68,6 +68,8 @@ import GroupView from "./GroupView";
|
||||||
import BackdropPanel from "./BackdropPanel";
|
import BackdropPanel from "./BackdropPanel";
|
||||||
import SpaceStore from "../../stores/SpaceStore";
|
import SpaceStore from "../../stores/SpaceStore";
|
||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
|
import GroupFilterPanel from './GroupFilterPanel';
|
||||||
|
import CustomRoomTagPanel from './CustomRoomTagPanel';
|
||||||
|
|
||||||
// We need to fetch each pinned message individually (if we don't already have it)
|
// We need to fetch each pinned message individually (if we don't already have it)
|
||||||
// so each pinned message may trigger a request. Limit the number per room for sanity.
|
// so each pinned message may trigger a request. Limit the number per room for sanity.
|
||||||
|
@ -131,7 +133,7 @@ interface IState {
|
||||||
usageLimitEventTs?: number;
|
usageLimitEventTs?: number;
|
||||||
useCompactLayout: boolean;
|
useCompactLayout: boolean;
|
||||||
activeCalls: Array<MatrixCall>;
|
activeCalls: Array<MatrixCall>;
|
||||||
backgroundImage?: CanvasImageSource;
|
backgroundImage?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -222,7 +224,7 @@ class LoggedInView extends React.Component<IProps, IState> {
|
||||||
|
|
||||||
private refreshBackgroundImage = async (): Promise<void> => {
|
private refreshBackgroundImage = async (): Promise<void> => {
|
||||||
this.setState({
|
this.setState({
|
||||||
backgroundImage: await OwnProfileStore.instance.getAvatarBitmap(),
|
backgroundImage: OwnProfileStore.instance.getHttpAvatarUrl(),
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -289,7 +291,7 @@ class LoggedInView extends React.Component<IProps, IState> {
|
||||||
if (isNaN(lhsSize)) {
|
if (isNaN(lhsSize)) {
|
||||||
lhsSize = 350;
|
lhsSize = 350;
|
||||||
}
|
}
|
||||||
this.resizer.forHandleAt(0).resize(lhsSize);
|
this.resizer.forHandleWithId('lp-resizer').resize(lhsSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
private onAccountData = (event: MatrixEvent) => {
|
private onAccountData = (event: MatrixEvent) => {
|
||||||
|
@ -653,16 +655,37 @@ class LoggedInView extends React.Component<IProps, IState> {
|
||||||
>
|
>
|
||||||
<ToastContainer />
|
<ToastContainer />
|
||||||
<div className={bodyClasses}>
|
<div className={bodyClasses}>
|
||||||
<div ref={this._resizeContainer} className='mx_LeftPanel_wrapper'>
|
<div className='mx_LeftPanel_wrapper'>
|
||||||
|
{ SettingsStore.getValue('TagPanel.enableTagPanel') &&
|
||||||
|
(<div className="mx_GroupFilterPanelContainer">
|
||||||
|
<BackdropPanel
|
||||||
|
blurMultiplier={0.5}
|
||||||
|
backgroundImage={this.state.backgroundImage}
|
||||||
|
/>
|
||||||
|
<GroupFilterPanel />
|
||||||
|
{ SettingsStore.getValue("feature_custom_tags") ? <CustomRoomTagPanel /> : null }
|
||||||
|
</div>)
|
||||||
|
}
|
||||||
|
{ SpaceStore.spacesEnabled ? <>
|
||||||
|
<BackdropPanel
|
||||||
|
blurMultiplier={0.5}
|
||||||
|
backgroundImage={this.state.backgroundImage}
|
||||||
|
/>
|
||||||
|
<SpacePanel />
|
||||||
|
</> : null }
|
||||||
<BackdropPanel
|
<BackdropPanel
|
||||||
backgroundImage={this.state.backgroundImage}
|
backgroundImage={this.state.backgroundImage}
|
||||||
/>
|
/>
|
||||||
{ SpaceStore.spacesEnabled ? <SpacePanel /> : null }
|
<div
|
||||||
<LeftPanel
|
ref={this._resizeContainer}
|
||||||
isMinimized={this.props.collapseLhs || false}
|
className="mx_LeftPanel_wrapper--user"
|
||||||
resizeNotifier={this.props.resizeNotifier}
|
>
|
||||||
/>
|
<LeftPanel
|
||||||
<ResizeHandle />
|
isMinimized={this.props.collapseLhs || false}
|
||||||
|
resizeNotifier={this.props.resizeNotifier}
|
||||||
|
/>
|
||||||
|
<ResizeHandle id="lp-resizer" />
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="mx_RoomView_wrapper">
|
<div className="mx_RoomView_wrapper">
|
||||||
{ pageElement }
|
{ pageElement }
|
||||||
|
|
|
@ -182,8 +182,6 @@ export default class Resizer<C extends IConfig = IConfig> {
|
||||||
|
|
||||||
private getResizeHandles() {
|
private getResizeHandles() {
|
||||||
if (!this.container.children) return [];
|
if (!this.container.children) return [];
|
||||||
return Array.from(this.container.children).filter(el => {
|
return Array.from(this.container.querySelectorAll(`.${this.classNames.handle}`)) as HTMLElement[];
|
||||||
return this.isResizeHandle(<HTMLElement>el);
|
|
||||||
}) as HTMLElement[];
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,12 +19,10 @@ import { AsyncStoreWithClient } from "./AsyncStoreWithClient";
|
||||||
import defaultDispatcher from "../dispatcher/dispatcher";
|
import defaultDispatcher from "../dispatcher/dispatcher";
|
||||||
import { MatrixEvent } from "matrix-js-sdk/src/models/event";
|
import { MatrixEvent } from "matrix-js-sdk/src/models/event";
|
||||||
import { User } from "matrix-js-sdk/src/models/user";
|
import { User } from "matrix-js-sdk/src/models/user";
|
||||||
import { memoize, throttle } from "lodash";
|
import { throttle } from "lodash";
|
||||||
import { MatrixClientPeg } from "../MatrixClientPeg";
|
import { MatrixClientPeg } from "../MatrixClientPeg";
|
||||||
import { _t } from "../languageHandler";
|
import { _t } from "../languageHandler";
|
||||||
import { mediaFromMxc } from "../customisations/Media";
|
import { mediaFromMxc } from "../customisations/Media";
|
||||||
import SettingsStore from "../settings/SettingsStore";
|
|
||||||
import { getDrawable } from "../utils/drawable";
|
|
||||||
|
|
||||||
interface IState {
|
interface IState {
|
||||||
displayName?: string;
|
displayName?: string;
|
||||||
|
@ -139,22 +137,6 @@ export class OwnProfileStore extends AsyncStoreWithClient<IState> {
|
||||||
await this.updateState({ displayName: profileInfo.displayname, avatarUrl: profileInfo.avatar_url });
|
await this.updateState({ displayName: profileInfo.displayname, avatarUrl: profileInfo.avatar_url });
|
||||||
};
|
};
|
||||||
|
|
||||||
public async getAvatarBitmap(avatarSize = 32): Promise<CanvasImageSource> {
|
|
||||||
let avatarUrl = this.getHttpAvatarUrl(avatarSize);
|
|
||||||
const settingBgMxc = SettingsStore.getValue("RoomList.backgroundImage");
|
|
||||||
if (settingBgMxc) {
|
|
||||||
avatarUrl = mediaFromMxc(settingBgMxc).getSquareThumbnailHttp(avatarSize);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (avatarUrl) {
|
|
||||||
return await this.buildBitmap(avatarUrl);
|
|
||||||
} else {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private buildBitmap = memoize(getDrawable);
|
|
||||||
|
|
||||||
private onStateEvents = throttle(async (ev: MatrixEvent) => {
|
private onStateEvents = throttle(async (ev: MatrixEvent) => {
|
||||||
const myUserId = MatrixClientPeg.get().getUserId();
|
const myUserId = MatrixClientPeg.get().getUserId();
|
||||||
if (ev.getType() === 'm.room.member' && ev.getSender() === myUserId && ev.getStateKey() === myUserId) {
|
if (ev.getType() === 'm.room.member' && ev.getSender() === myUserId && ev.getStateKey() === myUserId) {
|
||||||
|
|
|
@ -2917,11 +2917,6 @@ content-type@^1.0.4:
|
||||||
resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.4.tgz#e138cc75e040c727b1966fe5e5f8c9aee256fe3b"
|
resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.4.tgz#e138cc75e040c727b1966fe5e5f8c9aee256fe3b"
|
||||||
integrity sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==
|
integrity sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==
|
||||||
|
|
||||||
context-filter-polyfill@^0.2.4:
|
|
||||||
version "0.2.4"
|
|
||||||
resolved "https://registry.yarnpkg.com/context-filter-polyfill/-/context-filter-polyfill-0.2.4.tgz#ecf88d3197e7c3a47e9a7ae2d5167b703945a5d4"
|
|
||||||
integrity sha512-LDZ3WiTzo6kIeJM7j8kPSgZf+gbD1cV1GaLyYO8RWvAg25cO3zUo3d2KizO0w9hAezNwz7tTbuWKpPdvLWzKqQ==
|
|
||||||
|
|
||||||
convert-source-map@^1.1.0, convert-source-map@^1.4.0, convert-source-map@^1.6.0, convert-source-map@^1.7.0:
|
convert-source-map@^1.1.0, convert-source-map@^1.4.0, convert-source-map@^1.6.0, convert-source-map@^1.7.0:
|
||||||
version "1.8.0"
|
version "1.8.0"
|
||||||
resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.8.0.tgz#f3373c32d21b4d780dd8004514684fb791ca4369"
|
resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.8.0.tgz#f3373c32d21b4d780dd8004514684fb791ca4369"
|
||||||
|
|
Loading…
Reference in New Issue