Prevent layout trashing when resizing the window
This commit is contained in:
parent
2710062df7
commit
ac93cc514f
6 changed files with 11 additions and 43 deletions
|
@ -90,10 +90,6 @@ export default class LeftPanel extends React.Component<IProps, IState> {
|
||||||
this.groupFilterPanelWatcherRef = SettingsStore.watchSetting("TagPanel.enableTagPanel", null, () => {
|
this.groupFilterPanelWatcherRef = SettingsStore.watchSetting("TagPanel.enableTagPanel", null, () => {
|
||||||
this.setState({showGroupFilterPanel: SettingsStore.getValue("TagPanel.enableTagPanel")});
|
this.setState({showGroupFilterPanel: SettingsStore.getValue("TagPanel.enableTagPanel")});
|
||||||
});
|
});
|
||||||
|
|
||||||
// We watch the middle panel because we don't actually get resized, the middle panel does.
|
|
||||||
// We listen to the noisy channel to avoid choppy reaction times.
|
|
||||||
this.props.resizeNotifier.on("middlePanelResizedNoisy", this.onResize);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public componentWillUnmount() {
|
public componentWillUnmount() {
|
||||||
|
@ -103,7 +99,6 @@ export default class LeftPanel extends React.Component<IProps, IState> {
|
||||||
RoomListStore.instance.off(LISTS_UPDATE_EVENT, this.onBreadcrumbsUpdate);
|
RoomListStore.instance.off(LISTS_UPDATE_EVENT, this.onBreadcrumbsUpdate);
|
||||||
OwnProfileStore.instance.off(UPDATE_EVENT, this.onBackgroundImageUpdate);
|
OwnProfileStore.instance.off(UPDATE_EVENT, this.onBackgroundImageUpdate);
|
||||||
SpaceStore.instance.off(UPDATE_SELECTED_SPACE, this.updateActiveSpace);
|
SpaceStore.instance.off(UPDATE_SELECTED_SPACE, this.updateActiveSpace);
|
||||||
this.props.resizeNotifier.off("middlePanelResizedNoisy", this.onResize);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private updateActiveSpace = (activeSpace: Room) => {
|
private updateActiveSpace = (activeSpace: Room) => {
|
||||||
|
@ -281,11 +276,6 @@ export default class LeftPanel extends React.Component<IProps, IState> {
|
||||||
this.handleStickyHeaders(list);
|
this.handleStickyHeaders(list);
|
||||||
};
|
};
|
||||||
|
|
||||||
private onResize = () => {
|
|
||||||
if (!this.listContainerRef.current) return; // ignore: no headers to sticky
|
|
||||||
this.handleStickyHeaders(this.listContainerRef.current);
|
|
||||||
};
|
|
||||||
|
|
||||||
private onFocus = (ev: React.FocusEvent) => {
|
private onFocus = (ev: React.FocusEvent) => {
|
||||||
this.focusedElement = ev.target;
|
this.focusedElement = ev.target;
|
||||||
};
|
};
|
||||||
|
@ -420,7 +410,6 @@ export default class LeftPanel extends React.Component<IProps, IState> {
|
||||||
onFocus={this.onFocus}
|
onFocus={this.onFocus}
|
||||||
onBlur={this.onBlur}
|
onBlur={this.onBlur}
|
||||||
isMinimized={this.props.isMinimized}
|
isMinimized={this.props.isMinimized}
|
||||||
onResize={this.onResize}
|
|
||||||
activeSpace={this.state.activeSpace}
|
activeSpace={this.state.activeSpace}
|
||||||
/>;
|
/>;
|
||||||
|
|
||||||
|
@ -454,7 +443,7 @@ export default class LeftPanel extends React.Component<IProps, IState> {
|
||||||
{roomList}
|
{roomList}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{ !this.props.isMinimized && <LeftPanelWidget onResize={this.onResize} /> }
|
{ !this.props.isMinimized && <LeftPanelWidget /> }
|
||||||
</aside>
|
</aside>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
|
@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
|
||||||
limitations under the License.
|
limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import React, {useContext, useEffect, useMemo} from "react";
|
import React, {useContext, useMemo} from "react";
|
||||||
import {Resizable} from "re-resizable";
|
import {Resizable} from "re-resizable";
|
||||||
import classNames from "classnames";
|
import classNames from "classnames";
|
||||||
|
|
||||||
|
@ -28,15 +28,11 @@ import {useAccountData} from "../../hooks/useAccountData";
|
||||||
import AppTile from "../views/elements/AppTile";
|
import AppTile from "../views/elements/AppTile";
|
||||||
import {useSettingValue} from "../../hooks/useSettings";
|
import {useSettingValue} from "../../hooks/useSettings";
|
||||||
|
|
||||||
interface IProps {
|
|
||||||
onResize(): void;
|
|
||||||
}
|
|
||||||
|
|
||||||
const MIN_HEIGHT = 100;
|
const MIN_HEIGHT = 100;
|
||||||
const MAX_HEIGHT = 500; // or 50% of the window height
|
const MAX_HEIGHT = 500; // or 50% of the window height
|
||||||
const INITIAL_HEIGHT = 280;
|
const INITIAL_HEIGHT = 280;
|
||||||
|
|
||||||
const LeftPanelWidget: React.FC<IProps> = ({ onResize }) => {
|
const LeftPanelWidget: React.FC = () => {
|
||||||
const cli = useContext(MatrixClientContext);
|
const cli = useContext(MatrixClientContext);
|
||||||
|
|
||||||
const mWidgetsEvent = useAccountData<Record<string, IWidgetEvent>>(cli, "m.widgets");
|
const mWidgetsEvent = useAccountData<Record<string, IWidgetEvent>>(cli, "m.widgets");
|
||||||
|
@ -56,7 +52,6 @@ const LeftPanelWidget: React.FC<IProps> = ({ onResize }) => {
|
||||||
|
|
||||||
const [height, setHeight] = useLocalStorageState("left-panel-widget-height", INITIAL_HEIGHT);
|
const [height, setHeight] = useLocalStorageState("left-panel-widget-height", INITIAL_HEIGHT);
|
||||||
const [expanded, setExpanded] = useLocalStorageState("left-panel-widget-expanded", true);
|
const [expanded, setExpanded] = useLocalStorageState("left-panel-widget-expanded", true);
|
||||||
useEffect(onResize, [expanded, onResize]);
|
|
||||||
|
|
||||||
const [onFocus, isActive, ref] = useRovingTabIndex();
|
const [onFocus, isActive, ref] = useRovingTabIndex();
|
||||||
const tabIndex = isActive ? 0 : -1;
|
const tabIndex = isActive ? 0 : -1;
|
||||||
|
@ -69,7 +64,6 @@ const LeftPanelWidget: React.FC<IProps> = ({ onResize }) => {
|
||||||
size={{height} as any}
|
size={{height} as any}
|
||||||
minHeight={MIN_HEIGHT}
|
minHeight={MIN_HEIGHT}
|
||||||
maxHeight={Math.min(window.innerHeight / 2, MAX_HEIGHT)}
|
maxHeight={Math.min(window.innerHeight / 2, MAX_HEIGHT)}
|
||||||
onResize={onResize}
|
|
||||||
onResizeStop={(e, dir, ref, d) => {
|
onResizeStop={(e, dir, ref, d) => {
|
||||||
setHeight(height + d.height);
|
setHeight(height + d.height);
|
||||||
}}
|
}}
|
||||||
|
|
|
@ -87,6 +87,7 @@ import defaultDispatcher from "../../dispatcher/dispatcher";
|
||||||
import SecurityCustomisations from "../../customisations/Security";
|
import SecurityCustomisations from "../../customisations/Security";
|
||||||
|
|
||||||
import PerformanceMonitor, { PerformanceEntryNames } from "../../performance";
|
import PerformanceMonitor, { PerformanceEntryNames } from "../../performance";
|
||||||
|
import UIStore, { UI_EVENTS } from "../../stores/UIStore";
|
||||||
|
|
||||||
/** constants for MatrixChat.state.view */
|
/** constants for MatrixChat.state.view */
|
||||||
export enum Views {
|
export enum Views {
|
||||||
|
@ -225,7 +226,6 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
|
||||||
firstSyncPromise: IDeferred<void>;
|
firstSyncPromise: IDeferred<void>;
|
||||||
|
|
||||||
private screenAfterLogin?: IScreen;
|
private screenAfterLogin?: IScreen;
|
||||||
private windowWidth: number;
|
|
||||||
private pageChanging: boolean;
|
private pageChanging: boolean;
|
||||||
private tokenLogin?: boolean;
|
private tokenLogin?: boolean;
|
||||||
private accountPassword?: string;
|
private accountPassword?: string;
|
||||||
|
@ -277,9 +277,7 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
this.windowWidth = 10000;
|
UIStore.instance.on(UI_EVENTS.Resize, this.handleResize);
|
||||||
this.handleResize();
|
|
||||||
window.addEventListener('resize', this.handleResize);
|
|
||||||
|
|
||||||
this.pageChanging = false;
|
this.pageChanging = false;
|
||||||
|
|
||||||
|
@ -436,7 +434,7 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
|
||||||
dis.unregister(this.dispatcherRef);
|
dis.unregister(this.dispatcherRef);
|
||||||
this.themeWatcher.stop();
|
this.themeWatcher.stop();
|
||||||
this.fontWatcher.stop();
|
this.fontWatcher.stop();
|
||||||
window.removeEventListener('resize', this.handleResize);
|
UIStore.destroy();
|
||||||
this.state.resizeNotifier.removeListener("middlePanelResized", this.dispatchTimelineResize);
|
this.state.resizeNotifier.removeListener("middlePanelResized", this.dispatchTimelineResize);
|
||||||
|
|
||||||
if (this.accountPasswordTimer !== null) clearTimeout(this.accountPasswordTimer);
|
if (this.accountPasswordTimer !== null) clearTimeout(this.accountPasswordTimer);
|
||||||
|
@ -1820,18 +1818,17 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
|
||||||
}
|
}
|
||||||
|
|
||||||
handleResize = () => {
|
handleResize = () => {
|
||||||
const hideLhsThreshold = 1000;
|
const LHS_THRESHOLD = 1000;
|
||||||
const showLhsThreshold = 1000;
|
const width = UIStore.instance.windowWith;
|
||||||
|
|
||||||
if (this.windowWidth > hideLhsThreshold && window.innerWidth <= hideLhsThreshold) {
|
if (width <= LHS_THRESHOLD && !this.state.collapseLhs) {
|
||||||
dis.dispatch({ action: 'hide_left_panel' });
|
dis.dispatch({ action: 'hide_left_panel' });
|
||||||
}
|
}
|
||||||
if (this.windowWidth <= showLhsThreshold && window.innerWidth > showLhsThreshold) {
|
if (width > LHS_THRESHOLD && this.state.collapseLhs) {
|
||||||
dis.dispatch({ action: 'show_left_panel' });
|
dis.dispatch({ action: 'show_left_panel' });
|
||||||
}
|
}
|
||||||
|
|
||||||
this.state.resizeNotifier.notifyWindowResized();
|
this.state.resizeNotifier.notifyWindowResized();
|
||||||
this.windowWidth = window.innerWidth;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
private dispatchTimelineResize() {
|
private dispatchTimelineResize() {
|
||||||
|
|
|
@ -55,7 +55,6 @@ interface IProps {
|
||||||
onKeyDown: (ev: React.KeyboardEvent) => void;
|
onKeyDown: (ev: React.KeyboardEvent) => void;
|
||||||
onFocus: (ev: React.FocusEvent) => void;
|
onFocus: (ev: React.FocusEvent) => void;
|
||||||
onBlur: (ev: React.FocusEvent) => void;
|
onBlur: (ev: React.FocusEvent) => void;
|
||||||
onResize: () => void;
|
|
||||||
resizeNotifier: ResizeNotifier;
|
resizeNotifier: ResizeNotifier;
|
||||||
isMinimized: boolean;
|
isMinimized: boolean;
|
||||||
activeSpace: Room;
|
activeSpace: Room;
|
||||||
|
@ -404,9 +403,7 @@ export default class RoomList extends React.PureComponent<IProps, IState> {
|
||||||
const newSublists = objectWithOnly(newLists, newListIds);
|
const newSublists = objectWithOnly(newLists, newListIds);
|
||||||
const sublists = objectShallowClone(newSublists, (k, v) => arrayFastClone(v));
|
const sublists = objectShallowClone(newSublists, (k, v) => arrayFastClone(v));
|
||||||
|
|
||||||
this.setState({sublists, isNameFiltering}, () => {
|
this.setState({sublists, isNameFiltering});
|
||||||
this.props.onResize();
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -537,7 +534,6 @@ export default class RoomList extends React.PureComponent<IProps, IState> {
|
||||||
addRoomLabel={aesthetics.addRoomLabel ? _t(aesthetics.addRoomLabel) : aesthetics.addRoomLabel}
|
addRoomLabel={aesthetics.addRoomLabel ? _t(aesthetics.addRoomLabel) : aesthetics.addRoomLabel}
|
||||||
addRoomContextMenu={aesthetics.addRoomContextMenu}
|
addRoomContextMenu={aesthetics.addRoomContextMenu}
|
||||||
isMinimized={this.props.isMinimized}
|
isMinimized={this.props.isMinimized}
|
||||||
onResize={this.props.onResize}
|
|
||||||
showSkeleton={showSkeleton}
|
showSkeleton={showSkeleton}
|
||||||
extraTiles={extraTiles}
|
extraTiles={extraTiles}
|
||||||
resizeNotifier={this.props.resizeNotifier}
|
resizeNotifier={this.props.resizeNotifier}
|
||||||
|
|
|
@ -74,7 +74,6 @@ interface IProps {
|
||||||
addRoomLabel: string;
|
addRoomLabel: string;
|
||||||
isMinimized: boolean;
|
isMinimized: boolean;
|
||||||
tagId: TagID;
|
tagId: TagID;
|
||||||
onResize: () => void;
|
|
||||||
showSkeleton?: boolean;
|
showSkeleton?: boolean;
|
||||||
alwaysVisible?: boolean;
|
alwaysVisible?: boolean;
|
||||||
resizeNotifier: ResizeNotifier;
|
resizeNotifier: ResizeNotifier;
|
||||||
|
@ -473,7 +472,6 @@ export default class RoomSublist extends React.Component<IProps, IState> {
|
||||||
private toggleCollapsed = () => {
|
private toggleCollapsed = () => {
|
||||||
this.layout.isCollapsed = this.state.isExpanded;
|
this.layout.isCollapsed = this.state.isExpanded;
|
||||||
this.setState({isExpanded: !this.layout.isCollapsed});
|
this.setState({isExpanded: !this.layout.isCollapsed});
|
||||||
setImmediate(() => this.props.onResize()); // needs to happen when the DOM is updated
|
|
||||||
};
|
};
|
||||||
|
|
||||||
private onHeaderKeyDown = (ev: React.KeyboardEvent) => {
|
private onHeaderKeyDown = (ev: React.KeyboardEvent) => {
|
||||||
|
|
|
@ -74,12 +74,6 @@ export default class ResizeNotifier extends EventEmitter {
|
||||||
|
|
||||||
// can be called in quick succession
|
// can be called in quick succession
|
||||||
notifyWindowResized() {
|
notifyWindowResized() {
|
||||||
// no need to throttle this one,
|
|
||||||
// also it could make scrollbars appear for
|
|
||||||
// a split second when the room list manual layout is now
|
|
||||||
// taller than the available space
|
|
||||||
this.emit("leftPanelResized");
|
|
||||||
|
|
||||||
this._updateMiddlePanel();
|
this._updateMiddlePanel();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue