2016-11-03 18:42:26 +00:00
|
|
|
/*
|
2022-03-09 12:05:16 +00:00
|
|
|
Copyright 2015 - 2022 The Matrix.org Foundation C.I.C.
|
2016-11-03 18:42:26 +00:00
|
|
|
|
|
|
|
|
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.
|
|
|
|
|
*/
|
|
|
|
|
|
2021-11-19 17:15:15 +00:00
|
|
|
import React, { ClipboardEvent } from "react";
|
2022-02-22 12:18:08 +00:00
|
|
|
import { ClientEvent, MatrixClient } from "matrix-js-sdk/src/client";
|
2021-07-19 22:43:11 +01:00
|
|
|
import { MatrixEvent } from "matrix-js-sdk/src/models/event";
|
2021-12-09 09:10:23 +00:00
|
|
|
import { MatrixCall } from "matrix-js-sdk/src/webrtc/call";
|
|
|
|
|
import classNames from "classnames";
|
2021-12-16 09:57:10 +00:00
|
|
|
import { ISyncStateData, SyncState } from "matrix-js-sdk/src/sync";
|
|
|
|
|
import { IUsageLimit } from "matrix-js-sdk/src/@types/partials";
|
2022-02-22 12:18:08 +00:00
|
|
|
import { RoomStateEvent } from "matrix-js-sdk/src/models/room-state";
|
2022-10-21 11:44:33 +01:00
|
|
|
import { MatrixError } from "matrix-js-sdk/src/matrix";
|
2022-12-12 12:24:14 +01:00
|
|
|
|
2022-02-23 10:12:04 +01:00
|
|
|
import { isOnlyCtrlOrCmdKeyEvent, Key } from "../../Keyboard";
|
2016-11-03 18:42:26 +00:00
|
|
|
import PageTypes from "../../PageTypes";
|
2021-06-23 09:26:33 +02:00
|
|
|
import MediaDeviceHandler from "../../MediaDeviceHandler";
|
2020-04-16 09:25:18 +00:00
|
|
|
import { fixupColorFonts } from "../../utils/FontManager";
|
2020-05-13 20:41:41 -06:00
|
|
|
import dis from "../../dispatcher/dispatcher";
|
2021-05-17 15:05:20 +01:00
|
|
|
import { IMatrixClientCreds } from "../../MatrixClientPeg";
|
2017-10-29 01:43:52 -06:00
|
|
|
import SettingsStore from "../../settings/SettingsStore";
|
2022-01-26 17:50:47 +01:00
|
|
|
import { SettingLevel } from "../../settings/SettingLevel";
|
2018-09-24 16:07:42 +01:00
|
|
|
import ResizeHandle from "../views/elements/ResizeHandle";
|
2021-12-07 09:32:00 +00:00
|
|
|
import { CollapseDistributor, Resizer } from "../../resizer";
|
2019-12-17 17:26:12 +00:00
|
|
|
import MatrixClientContext from "../../contexts/MatrixClientContext";
|
2020-04-13 14:29:00 +01:00
|
|
|
import ResizeNotifier from "../../utils/ResizeNotifier";
|
2020-04-11 18:57:59 +01:00
|
|
|
import PlatformPeg from "../../PlatformPeg";
|
2020-03-20 14:38:20 -06:00
|
|
|
import { DefaultTagID } from "../../stores/room-list/models";
|
2021-12-07 09:32:00 +00:00
|
|
|
import { hideToast as hideServerLimitToast, showToast as showServerLimitToast } from "../../toasts/ServerLimitToast";
|
2020-06-02 19:07:46 -06:00
|
|
|
import { Action } from "../../dispatcher/actions";
|
2020-07-17 15:22:18 -06:00
|
|
|
import LeftPanel from "./LeftPanel";
|
2020-07-06 17:57:40 +01:00
|
|
|
import { ViewRoomDeltaPayload } from "../../dispatcher/payloads/ViewRoomDeltaPayload";
|
2020-07-17 15:11:34 -06:00
|
|
|
import RoomListStore from "../../stores/room-list/RoomListStore";
|
2020-07-29 12:43:35 -06:00
|
|
|
import NonUrgentToastContainer from "./NonUrgentToastContainer";
|
2021-07-01 19:54:05 +01:00
|
|
|
import { IOOBData, IThreepidInvite } from "../../stores/ThreepidInviteStore";
|
2020-10-13 18:26:48 +02:00
|
|
|
import Modal from "../../Modal";
|
2020-10-20 11:03:03 +01:00
|
|
|
import { ICollapseConfig } from "../../resizer/distributors/collapse";
|
2021-01-14 11:53:20 +02:00
|
|
|
import HostSignupContainer from "../views/host_signup/HostSignupContainer";
|
2022-01-31 16:55:45 +01:00
|
|
|
import { getKeyBindingsManager } from "../../KeyBindingsManager";
|
2021-03-01 17:54:53 +00:00
|
|
|
import { IOpts } from "../../createRoom";
|
2021-03-16 10:53:27 +00:00
|
|
|
import SpacePanel from "../views/spaces/SpacePanel";
|
2022-08-30 15:13:39 -04:00
|
|
|
import LegacyCallHandler, { LegacyCallHandlerEvent } from "../../LegacyCallHandler";
|
|
|
|
|
import AudioFeedArrayForLegacyCall from "../views/voip/AudioFeedArrayForLegacyCall";
|
2021-06-24 17:51:11 +01:00
|
|
|
import { OwnProfileStore } from "../../stores/OwnProfileStore";
|
|
|
|
|
import { UPDATE_EVENT } from "../../stores/AsyncStore";
|
2021-07-03 11:51:23 +02:00
|
|
|
import RoomView from "./RoomView";
|
2022-03-09 12:05:16 +00:00
|
|
|
import type { RoomView as RoomViewType } from "./RoomView";
|
2021-07-03 11:51:23 +02:00
|
|
|
import ToastContainer from "./ToastContainer";
|
|
|
|
|
import UserView from "./UserView";
|
2021-07-12 13:51:46 +02:00
|
|
|
import BackdropPanel from "./BackdropPanel";
|
2021-08-23 20:39:46 -06:00
|
|
|
import { mediaFromMxc } from "../../customisations/Media";
|
2022-03-24 16:42:53 -06:00
|
|
|
import { UserTab } from "../views/dialogs/UserTab";
|
2022-01-17 12:53:10 +01:00
|
|
|
import { OpenToTabPayload } from "../../dispatcher/payloads/OpenToTabPayload";
|
2022-01-05 16:14:44 +01:00
|
|
|
import RightPanelStore from "../../stores/right-panel/RightPanelStore";
|
2022-01-26 09:04:19 +00:00
|
|
|
import { TimelineRenderingType } from "../../contexts/RoomContext";
|
2022-01-31 16:55:45 +01:00
|
|
|
import { KeyBindingAction } from "../../accessibility/KeyboardShortcuts";
|
2022-02-23 10:12:04 +01:00
|
|
|
import { SwitchSpacePayload } from "../../dispatcher/payloads/SwitchSpacePayload";
|
2022-03-18 10:12:36 -06:00
|
|
|
import { IConfigOptions } from "../../IConfigOptions";
|
2022-03-17 09:25:57 +01:00
|
|
|
import LeftPanelLiveShareWarning from "../views/beacon/LeftPanelLiveShareWarning";
|
2022-07-29 13:43:29 +02:00
|
|
|
import { UserOnboardingPage } from "../views/user-onboarding/UserOnboardingPage";
|
2023-01-03 23:44:38 -05:00
|
|
|
import { PipContainer } from "./PipContainer";
|
2020-05-22 22:15:22 +01:00
|
|
|
|
2018-08-07 17:04:37 +01:00
|
|
|
// 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.
|
|
|
|
|
// NB. this is just for server notices rather than pinned messages in general.
|
|
|
|
|
const MAX_PINNED_NOTICES_PER_ROOM = 2;
|
|
|
|
|
|
2021-12-17 11:08:56 -06:00
|
|
|
// Used to find the closest inputable thing. Because of how our composer works,
|
|
|
|
|
// your caret might be within a paragraph/font/div/whatever within the
|
|
|
|
|
// contenteditable rather than directly in something inputable.
|
|
|
|
|
function getInputableElement(el: HTMLElement): HTMLElement | null {
|
2021-11-22 17:09:16 +00:00
|
|
|
return el.closest("input, textarea, select, [contenteditable=true]");
|
2019-07-19 17:49:04 +02:00
|
|
|
}
|
|
|
|
|
|
2020-04-13 14:29:00 +01:00
|
|
|
interface IProps {
|
|
|
|
|
matrixClient: MatrixClient;
|
2021-07-19 22:43:11 +01:00
|
|
|
// Called with the credentials of a registered user (if they were a ROU that
|
|
|
|
|
// transitioned to PWLU)
|
2020-05-25 15:59:15 -06:00
|
|
|
onRegistered: (credentials: IMatrixClientCreds) => Promise<MatrixClient>;
|
2020-04-13 14:29:00 +01:00
|
|
|
hideToSRUsers: boolean;
|
|
|
|
|
resizeNotifier: ResizeNotifier;
|
2020-08-29 01:11:08 +01:00
|
|
|
// eslint-disable-next-line camelcase
|
2021-07-03 11:57:05 +02:00
|
|
|
page_type?: string;
|
|
|
|
|
autoJoin?: boolean;
|
2020-09-11 19:49:48 -06:00
|
|
|
threepidInvite?: IThreepidInvite;
|
2021-07-01 19:54:05 +01:00
|
|
|
roomOobData?: IOOBData;
|
2020-04-13 14:29:00 +01:00
|
|
|
currentRoomId: string;
|
|
|
|
|
collapseLhs: boolean;
|
2022-03-18 10:12:36 -06:00
|
|
|
config: IConfigOptions;
|
2020-04-13 14:29:00 +01:00
|
|
|
currentUserId?: string;
|
2020-11-02 17:24:47 +00:00
|
|
|
justRegistered?: boolean;
|
2021-03-01 17:54:53 +00:00
|
|
|
roomJustCreatedOpts?: IOpts;
|
2021-10-20 06:55:22 -06:00
|
|
|
forceTimeline?: boolean; // see props on MatrixChat
|
2020-04-13 14:29:00 +01:00
|
|
|
}
|
2020-05-22 23:08:45 +01:00
|
|
|
|
2020-04-13 14:29:00 +01:00
|
|
|
interface IState {
|
2021-12-16 09:57:10 +00:00
|
|
|
syncErrorData?: ISyncStateData;
|
2021-02-23 12:51:47 +00:00
|
|
|
usageLimitDismissed: boolean;
|
2020-06-03 16:17:31 +01:00
|
|
|
usageLimitEventContent?: IUsageLimit;
|
2021-02-23 12:51:17 +00:00
|
|
|
usageLimitEventTs?: number;
|
2020-04-13 14:29:00 +01:00
|
|
|
useCompactLayout: boolean;
|
2021-04-27 11:59:08 +02:00
|
|
|
activeCalls: Array<MatrixCall>;
|
2021-08-23 19:26:57 +02:00
|
|
|
backgroundImage?: string;
|
2020-04-13 14:29:00 +01:00
|
|
|
}
|
|
|
|
|
|
2016-11-03 18:42:26 +00:00
|
|
|
/**
|
|
|
|
|
* This is what our MatrixChat shows when we are logged in. The precise view is
|
|
|
|
|
* determined by the page_type property.
|
|
|
|
|
*
|
2021-12-01 10:54:14 +00:00
|
|
|
* Currently, it's very tightly coupled with MatrixChat. We should try to do
|
2016-11-03 18:42:26 +00:00
|
|
|
* something about that.
|
2016-11-03 18:54:30 +00:00
|
|
|
*
|
|
|
|
|
* Components mounted below us can access the matrix client via the react context.
|
2016-11-03 18:42:26 +00:00
|
|
|
*/
|
2020-06-25 07:14:02 -06:00
|
|
|
class LoggedInView extends React.Component<IProps, IState> {
|
2022-12-16 12:29:59 +00:00
|
|
|
public static displayName = "LoggedInView";
|
2016-11-03 18:42:26 +00:00
|
|
|
|
2020-04-13 14:30:52 +01:00
|
|
|
protected readonly _matrixClient: MatrixClient;
|
2022-03-09 12:05:16 +00:00
|
|
|
protected readonly _roomView: React.RefObject<RoomViewType>;
|
2021-08-24 13:05:46 +02:00
|
|
|
protected readonly _resizeContainer: React.RefObject<HTMLDivElement>;
|
|
|
|
|
protected readonly resizeHandler: React.RefObject<HTMLDivElement>;
|
2021-12-15 16:27:02 +00:00
|
|
|
protected layoutWatcherRef: string;
|
2021-01-15 11:42:30 +00:00
|
|
|
protected compactLayoutWatcherRef: string;
|
2021-08-20 15:55:52 +02:00
|
|
|
protected backgroundImageWatcherRef: string;
|
2020-04-13 14:30:52 +01:00
|
|
|
protected resizer: Resizer;
|
2020-04-13 14:29:00 +01:00
|
|
|
|
2022-12-16 12:29:59 +00:00
|
|
|
public constructor(props, context) {
|
2020-04-13 14:13:27 +01:00
|
|
|
super(props, context);
|
|
|
|
|
|
|
|
|
|
this.state = {
|
2020-04-13 14:29:00 +01:00
|
|
|
syncErrorData: undefined,
|
2017-05-31 22:00:30 -04:00
|
|
|
// use compact timeline view
|
2017-10-29 01:43:52 -06:00
|
|
|
useCompactLayout: SettingsStore.getValue("useCompactLayout"),
|
2021-02-23 12:51:47 +00:00
|
|
|
usageLimitDismissed: false,
|
2022-08-30 15:13:39 -04:00
|
|
|
activeCalls: LegacyCallHandler.instance.getAllActiveCalls(),
|
2017-05-31 22:00:30 -04:00
|
|
|
};
|
2018-09-24 16:07:42 +01:00
|
|
|
|
2016-11-03 18:54:30 +00:00
|
|
|
// stash the MatrixClient in case we log out before we are unmounted
|
|
|
|
|
this._matrixClient = this.props.matrixClient;
|
|
|
|
|
|
2021-06-23 09:26:33 +02:00
|
|
|
MediaDeviceHandler.loadDevices();
|
2017-04-28 18:21:22 +01:00
|
|
|
|
2021-01-15 11:42:30 +00:00
|
|
|
fixupColorFonts();
|
|
|
|
|
|
|
|
|
|
this._roomView = React.createRef();
|
|
|
|
|
this._resizeContainer = React.createRef();
|
2021-08-24 13:05:46 +02:00
|
|
|
this.resizeHandler = React.createRef();
|
2021-01-15 11:42:30 +00:00
|
|
|
}
|
|
|
|
|
|
2022-12-16 12:29:59 +00:00
|
|
|
public componentDidMount() {
|
2021-07-19 22:43:11 +01:00
|
|
|
document.addEventListener("keydown", this.onNativeKeyDown, false);
|
2022-08-30 15:13:39 -04:00
|
|
|
LegacyCallHandler.instance.addListener(LegacyCallHandlerEvent.CallState, this.onCallState);
|
2017-05-15 14:56:05 +01:00
|
|
|
|
2021-07-19 22:43:11 +01:00
|
|
|
this.updateServerNoticeEvents();
|
2018-08-07 17:04:37 +01:00
|
|
|
|
2022-02-22 12:18:08 +00:00
|
|
|
this._matrixClient.on(ClientEvent.AccountData, this.onAccountData);
|
|
|
|
|
this._matrixClient.on(ClientEvent.Sync, this.onSync);
|
2021-01-15 11:42:30 +00:00
|
|
|
// Call `onSync` with the current state as well
|
|
|
|
|
this.onSync(this._matrixClient.getSyncState(), null, this._matrixClient.getSyncStateData());
|
2022-02-22 12:18:08 +00:00
|
|
|
this._matrixClient.on(RoomStateEvent.Events, this.onRoomStateEvents);
|
2019-05-22 02:31:24 +01:00
|
|
|
|
2021-12-15 16:27:02 +00:00
|
|
|
this.layoutWatcherRef = SettingsStore.watchSetting("layout", null, this.onCompactLayoutChanged);
|
2021-01-15 11:42:30 +00:00
|
|
|
this.compactLayoutWatcherRef = SettingsStore.watchSetting(
|
2020-07-03 12:06:00 +01:00
|
|
|
"useCompactLayout",
|
|
|
|
|
null,
|
|
|
|
|
this.onCompactLayoutChanged,
|
|
|
|
|
);
|
2021-08-20 15:55:52 +02:00
|
|
|
this.backgroundImageWatcherRef = SettingsStore.watchSetting(
|
|
|
|
|
"RoomList.backgroundImage",
|
|
|
|
|
null,
|
|
|
|
|
this.refreshBackgroundImage,
|
|
|
|
|
);
|
2020-07-03 12:06:00 +01:00
|
|
|
|
2021-07-19 22:43:11 +01:00
|
|
|
this.resizer = this.createResizer();
|
2020-04-13 14:13:27 +01:00
|
|
|
this.resizer.attach();
|
2021-06-24 17:51:11 +01:00
|
|
|
|
|
|
|
|
OwnProfileStore.instance.on(UPDATE_EVENT, this.refreshBackgroundImage);
|
2021-07-19 22:43:11 +01:00
|
|
|
this.loadResizerPreferences();
|
2021-08-17 19:45:52 +02:00
|
|
|
this.refreshBackgroundImage();
|
2020-04-13 14:13:27 +01:00
|
|
|
}
|
2016-11-03 18:42:26 +00:00
|
|
|
|
2022-12-16 12:29:59 +00:00
|
|
|
public componentWillUnmount() {
|
2021-07-19 22:43:11 +01:00
|
|
|
document.removeEventListener("keydown", this.onNativeKeyDown, false);
|
2022-08-30 15:13:39 -04:00
|
|
|
LegacyCallHandler.instance.removeListener(LegacyCallHandlerEvent.CallState, this.onCallState);
|
2022-02-22 12:18:08 +00:00
|
|
|
this._matrixClient.removeListener(ClientEvent.AccountData, this.onAccountData);
|
|
|
|
|
this._matrixClient.removeListener(ClientEvent.Sync, this.onSync);
|
|
|
|
|
this._matrixClient.removeListener(RoomStateEvent.Events, this.onRoomStateEvents);
|
2021-06-24 17:51:11 +01:00
|
|
|
OwnProfileStore.instance.off(UPDATE_EVENT, this.refreshBackgroundImage);
|
2021-12-15 16:27:02 +00:00
|
|
|
SettingsStore.unwatchSetting(this.layoutWatcherRef);
|
2021-01-15 11:42:30 +00:00
|
|
|
SettingsStore.unwatchSetting(this.compactLayoutWatcherRef);
|
2021-08-20 15:55:52 +02:00
|
|
|
SettingsStore.unwatchSetting(this.backgroundImageWatcherRef);
|
2018-10-16 18:43:40 +02:00
|
|
|
this.resizer.detach();
|
2020-04-13 14:13:27 +01:00
|
|
|
}
|
2016-11-03 18:42:26 +00:00
|
|
|
|
2021-11-30 19:09:13 +01:00
|
|
|
private onCallState = (): void => {
|
2022-08-30 15:13:39 -04:00
|
|
|
const activeCalls = LegacyCallHandler.instance.getAllActiveCalls();
|
2021-11-30 19:09:13 +01:00
|
|
|
if (activeCalls === this.state.activeCalls) return;
|
|
|
|
|
this.setState({ activeCalls });
|
|
|
|
|
};
|
|
|
|
|
|
2021-06-24 17:51:11 +01:00
|
|
|
private refreshBackgroundImage = async (): Promise<void> => {
|
2021-08-23 20:39:46 -06:00
|
|
|
let backgroundImage = SettingsStore.getValue("RoomList.backgroundImage");
|
|
|
|
|
if (backgroundImage) {
|
|
|
|
|
// convert to http before going much further
|
|
|
|
|
backgroundImage = mediaFromMxc(backgroundImage).srcHttp;
|
|
|
|
|
} else {
|
|
|
|
|
backgroundImage = OwnProfileStore.instance.getHttpAvatarUrl();
|
|
|
|
|
}
|
|
|
|
|
this.setState({ backgroundImage });
|
2021-07-06 10:19:25 +02:00
|
|
|
};
|
2021-06-24 17:51:11 +01:00
|
|
|
|
2021-07-19 22:43:11 +01:00
|
|
|
public canResetTimelineInRoom = (roomId: string) => {
|
2019-12-08 12:16:17 +00:00
|
|
|
if (!this._roomView.current) {
|
2017-03-22 15:06:52 +00:00
|
|
|
return true;
|
|
|
|
|
}
|
2019-12-08 12:16:17 +00:00
|
|
|
return this._roomView.current.canResetTimeline();
|
2020-04-13 14:13:27 +01:00
|
|
|
};
|
2017-03-22 15:06:52 +00:00
|
|
|
|
2021-07-19 22:43:11 +01:00
|
|
|
private createResizer() {
|
|
|
|
|
let panelSize;
|
|
|
|
|
let panelCollapsed;
|
2020-10-20 11:03:03 +01:00
|
|
|
const collapseConfig: ICollapseConfig = {
|
2021-03-16 11:11:44 +00:00
|
|
|
// TODO decrease this once Spaces launches as it'll no longer need to include the 56px Community Panel
|
|
|
|
|
toggleSize: 206 - 50,
|
2021-07-19 22:43:11 +01:00
|
|
|
onCollapsed: (collapsed) => {
|
|
|
|
|
panelCollapsed = collapsed;
|
|
|
|
|
if (collapsed) {
|
2021-06-29 13:11:58 +01:00
|
|
|
dis.dispatch({ action: "hide_left_panel" });
|
2018-11-26 16:45:55 +01:00
|
|
|
window.localStorage.setItem("mx_lhs_size", "0");
|
2019-01-31 10:15:27 +01:00
|
|
|
} else {
|
2021-06-29 13:11:58 +01:00
|
|
|
dis.dispatch({ action: "show_left_panel" });
|
2018-10-16 18:43:40 +02:00
|
|
|
}
|
|
|
|
|
},
|
2021-07-19 22:43:11 +01:00
|
|
|
onResized: (size) => {
|
|
|
|
|
panelSize = size;
|
2019-03-12 16:36:12 +01:00
|
|
|
this.props.resizeNotifier.notifyLeftHandleResized();
|
2018-10-16 18:43:40 +02:00
|
|
|
},
|
2020-09-02 12:00:35 +01:00
|
|
|
onResizeStart: () => {
|
|
|
|
|
this.props.resizeNotifier.startResizing();
|
|
|
|
|
},
|
|
|
|
|
onResizeStop: () => {
|
2021-07-19 22:43:11 +01:00
|
|
|
if (!panelCollapsed) window.localStorage.setItem("mx_lhs_size", "" + panelSize);
|
2020-09-02 12:00:35 +01:00
|
|
|
this.props.resizeNotifier.stopResizing();
|
|
|
|
|
},
|
2021-03-02 14:02:03 +00:00
|
|
|
isItemCollapsed: (domNode) => {
|
|
|
|
|
return domNode.classList.contains("mx_LeftPanel_minimized");
|
|
|
|
|
},
|
2021-08-24 13:05:46 +02:00
|
|
|
handler: this.resizeHandler.current,
|
2018-10-16 18:43:40 +02:00
|
|
|
};
|
2020-10-13 10:30:52 +01:00
|
|
|
const resizer = new Resizer(this._resizeContainer.current, CollapseDistributor, collapseConfig);
|
2020-10-20 11:03:03 +01:00
|
|
|
resizer.setClassNames({
|
|
|
|
|
handle: "mx_ResizeHandle",
|
|
|
|
|
vertical: "mx_ResizeHandle_vertical",
|
|
|
|
|
reverse: "mx_ResizeHandle_reverse",
|
|
|
|
|
});
|
2018-10-16 18:43:40 +02:00
|
|
|
return resizer;
|
2020-04-13 14:13:27 +01:00
|
|
|
}
|
2018-10-16 18:43:40 +02:00
|
|
|
|
2021-07-19 22:43:11 +01:00
|
|
|
private loadResizerPreferences() {
|
2020-04-13 14:29:00 +01:00
|
|
|
let lhsSize = parseInt(window.localStorage.getItem("mx_lhs_size"), 10);
|
|
|
|
|
if (isNaN(lhsSize)) {
|
2019-01-22 16:40:11 +01:00
|
|
|
lhsSize = 350;
|
2018-10-16 18:43:40 +02:00
|
|
|
}
|
2021-08-23 16:18:40 +02:00
|
|
|
this.resizer.forHandleWithId("lp-resizer").resize(lhsSize);
|
2020-04-13 14:13:27 +01:00
|
|
|
}
|
2018-10-16 18:43:40 +02:00
|
|
|
|
2021-07-19 22:43:11 +01:00
|
|
|
private onAccountData = (event: MatrixEvent) => {
|
2017-09-14 20:16:56 -06:00
|
|
|
if (event.getType() === "m.ignored_user_list") {
|
2021-06-29 13:11:58 +01:00
|
|
|
dis.dispatch({ action: "ignore_state_changed" });
|
2017-09-14 20:16:56 -06:00
|
|
|
}
|
2020-04-13 14:13:27 +01:00
|
|
|
};
|
2017-05-31 22:00:30 -04:00
|
|
|
|
2021-12-15 16:27:02 +00:00
|
|
|
private onCompactLayoutChanged = () => {
|
2020-07-03 12:06:00 +01:00
|
|
|
this.setState({
|
2021-12-15 16:27:02 +00:00
|
|
|
useCompactLayout: SettingsStore.getValue("useCompactLayout"),
|
2020-07-03 12:06:00 +01:00
|
|
|
});
|
|
|
|
|
};
|
|
|
|
|
|
2021-12-16 09:57:10 +00:00
|
|
|
private onSync = (syncState: SyncState, oldSyncState?: SyncState, data?: ISyncStateData): void => {
|
2022-10-21 11:44:33 +01:00
|
|
|
const oldErrCode = (this.state.syncErrorData?.error as MatrixError)?.errcode;
|
|
|
|
|
const newErrCode = (data?.error as MatrixError)?.errcode;
|
2018-08-03 18:02:09 +01:00
|
|
|
if (syncState === oldSyncState && oldErrCode === newErrCode) return;
|
2018-08-03 14:54:52 +01:00
|
|
|
|
2021-12-16 09:57:10 +00:00
|
|
|
this.setState({
|
|
|
|
|
syncErrorData: syncState === SyncState.Error ? data : null,
|
|
|
|
|
});
|
2018-08-07 17:04:37 +01:00
|
|
|
|
2021-12-16 09:57:10 +00:00
|
|
|
if (oldSyncState === SyncState.Prepared && syncState === SyncState.Syncing) {
|
2021-07-19 22:43:11 +01:00
|
|
|
this.updateServerNoticeEvents();
|
2020-05-22 22:27:19 +01:00
|
|
|
} else {
|
2021-07-19 22:43:11 +01:00
|
|
|
this.calculateServerLimitToast(this.state.syncErrorData, this.state.usageLimitEventContent);
|
2018-08-07 17:04:37 +01:00
|
|
|
}
|
2020-04-13 14:13:27 +01:00
|
|
|
};
|
2018-08-03 14:54:52 +01:00
|
|
|
|
2021-12-16 09:57:10 +00:00
|
|
|
private onRoomStateEvents = (ev: MatrixEvent): void => {
|
2020-07-17 14:25:09 -06:00
|
|
|
const serverNoticeList = RoomListStore.instance.orderedLists[DefaultTagID.ServerNotice];
|
2022-02-24 14:39:25 +00:00
|
|
|
if (serverNoticeList?.some((r) => r.roomId === ev.getRoomId())) {
|
2021-07-19 22:43:11 +01:00
|
|
|
this.updateServerNoticeEvents();
|
2018-08-07 17:04:37 +01:00
|
|
|
}
|
2020-04-13 14:13:27 +01:00
|
|
|
};
|
2018-08-07 17:04:37 +01:00
|
|
|
|
2021-02-24 17:32:00 +00:00
|
|
|
private onUsageLimitDismissed = () => {
|
2021-02-23 12:51:47 +00:00
|
|
|
this.setState({
|
|
|
|
|
usageLimitDismissed: true,
|
|
|
|
|
});
|
2021-06-29 13:11:58 +01:00
|
|
|
};
|
2021-02-23 12:51:47 +00:00
|
|
|
|
2021-07-19 22:43:11 +01:00
|
|
|
private calculateServerLimitToast(syncError: IState["syncErrorData"], usageLimitEventContent?: IUsageLimit) {
|
2022-10-21 11:44:33 +01:00
|
|
|
const error = (syncError?.error as MatrixError)?.errcode === "M_RESOURCE_LIMIT_EXCEEDED";
|
2020-05-22 22:27:19 +01:00
|
|
|
if (error) {
|
2022-10-21 11:44:33 +01:00
|
|
|
usageLimitEventContent = (syncError?.error as MatrixError).data as IUsageLimit;
|
2020-05-22 22:27:19 +01:00
|
|
|
}
|
|
|
|
|
|
2021-02-23 12:51:47 +00:00
|
|
|
// usageLimitDismissed is true when the user has explicitly hidden the toast
|
|
|
|
|
// and it will be reset to false if a *new* usage alert comes in.
|
|
|
|
|
if (usageLimitEventContent && this.state.usageLimitDismissed) {
|
|
|
|
|
showServerLimitToast(
|
|
|
|
|
usageLimitEventContent.limit_type,
|
2021-02-24 17:32:00 +00:00
|
|
|
this.onUsageLimitDismissed,
|
2021-02-23 12:51:47 +00:00
|
|
|
usageLimitEventContent.admin_contact,
|
|
|
|
|
error,
|
|
|
|
|
);
|
2020-05-22 22:27:19 +01:00
|
|
|
} else {
|
|
|
|
|
hideServerLimitToast();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-07-19 22:43:11 +01:00
|
|
|
private updateServerNoticeEvents = async () => {
|
2020-07-17 14:25:09 -06:00
|
|
|
const serverNoticeList = RoomListStore.instance.orderedLists[DefaultTagID.ServerNotice];
|
|
|
|
|
if (!serverNoticeList) return [];
|
2018-09-24 16:07:42 +01:00
|
|
|
|
2020-05-22 22:27:19 +01:00
|
|
|
const events = [];
|
2021-02-23 13:00:05 +00:00
|
|
|
let pinnedEventTs = 0;
|
2020-07-17 14:25:09 -06:00
|
|
|
for (const room of serverNoticeList) {
|
2018-08-07 17:04:37 +01:00
|
|
|
const pinStateEvent = room.currentState.getStateEvents("m.room.pinned_events", "");
|
|
|
|
|
|
|
|
|
|
if (!pinStateEvent || !pinStateEvent.getContent().pinned) continue;
|
2021-02-23 13:00:05 +00:00
|
|
|
pinnedEventTs = pinStateEvent.getTs();
|
2018-09-24 16:07:42 +01:00
|
|
|
|
2018-08-07 17:04:37 +01:00
|
|
|
const pinnedEventIds = pinStateEvent.getContent().pinned.slice(0, MAX_PINNED_NOTICES_PER_ROOM);
|
|
|
|
|
for (const eventId of pinnedEventIds) {
|
2021-06-01 22:21:04 -06:00
|
|
|
const timeline = await this._matrixClient.getEventTimeline(room.getUnfilteredTimelineSet(), eventId);
|
2020-04-13 14:33:45 +01:00
|
|
|
const event = timeline.getEvents().find((ev) => ev.getId() === eventId);
|
2020-05-22 22:27:19 +01:00
|
|
|
if (event) events.push(event);
|
2018-08-07 17:04:37 +01:00
|
|
|
}
|
|
|
|
|
}
|
2020-05-22 22:27:19 +01:00
|
|
|
|
2021-02-23 13:00:05 +00:00
|
|
|
if (pinnedEventTs && this.state.usageLimitEventTs > pinnedEventTs) {
|
|
|
|
|
// We've processed a newer event than this one, so ignore it.
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2020-05-22 22:27:19 +01:00
|
|
|
const usageLimitEvent = events.find((e) => {
|
|
|
|
|
return (
|
|
|
|
|
e &&
|
|
|
|
|
e.getType() === "m.room.message" &&
|
|
|
|
|
e.getContent()["server_notice_type"] === "m.server_notice.usage_limit_reached"
|
|
|
|
|
);
|
2018-08-07 17:04:37 +01:00
|
|
|
});
|
2020-06-03 16:17:31 +01:00
|
|
|
const usageLimitEventContent = usageLimitEvent && usageLimitEvent.getContent();
|
2021-07-19 22:43:11 +01:00
|
|
|
this.calculateServerLimitToast(this.state.syncErrorData, usageLimitEventContent);
|
2021-02-23 12:51:17 +00:00
|
|
|
this.setState({
|
|
|
|
|
usageLimitEventContent,
|
2021-02-23 13:00:05 +00:00
|
|
|
usageLimitEventTs: pinnedEventTs,
|
2021-02-23 12:51:17 +00:00
|
|
|
// This is a fresh toast, we can show toasts again
|
|
|
|
|
usageLimitDismissed: false,
|
|
|
|
|
});
|
2020-04-13 14:13:27 +01:00
|
|
|
};
|
2018-09-24 16:07:42 +01:00
|
|
|
|
2021-11-19 17:15:15 +00:00
|
|
|
private onPaste = (ev: ClipboardEvent) => {
|
2021-11-22 17:09:16 +00:00
|
|
|
const element = ev.target as HTMLElement;
|
2022-01-26 09:04:19 +00:00
|
|
|
const inputableElement = getInputableElement(element);
|
|
|
|
|
if (inputableElement === document.activeElement) return; // nothing to do
|
2021-11-22 17:09:16 +00:00
|
|
|
|
2022-01-14 12:49:09 +00:00
|
|
|
if (inputableElement?.focus) {
|
2021-11-22 17:09:16 +00:00
|
|
|
inputableElement.focus();
|
|
|
|
|
} else {
|
2022-01-26 09:04:19 +00:00
|
|
|
const inThread = !!document.activeElement.closest(".mx_ThreadView");
|
2022-02-22 11:14:56 +00:00
|
|
|
// refocusing during a paste event will make the paste end up in the newly focused element,
|
2019-07-23 09:44:17 +02:00
|
|
|
// so dispatch synchronously before paste happens
|
2022-01-26 09:04:19 +00:00
|
|
|
dis.dispatch(
|
|
|
|
|
{
|
|
|
|
|
action: Action.FocusSendMessageComposer,
|
|
|
|
|
context: inThread ? TimelineRenderingType.Thread : TimelineRenderingType.Room,
|
|
|
|
|
},
|
|
|
|
|
true,
|
|
|
|
|
);
|
2019-07-19 17:49:04 +02:00
|
|
|
}
|
2020-04-13 14:13:27 +01:00
|
|
|
};
|
2019-07-19 17:49:04 +02:00
|
|
|
|
2019-07-17 16:50:05 +02:00
|
|
|
/*
|
|
|
|
|
SOME HACKERY BELOW:
|
|
|
|
|
React optimizes event handlers, by always attaching only 1 handler to the document for a given type.
|
|
|
|
|
It then internally determines the order in which React event handlers should be called,
|
|
|
|
|
emulating the capture and bubbling phases the DOM also has.
|
|
|
|
|
|
|
|
|
|
But, as the native handler for React is always attached on the document,
|
|
|
|
|
it will always run last for bubbling (first for capturing) handlers,
|
|
|
|
|
and thus React basically has its own event phases, and will always run
|
|
|
|
|
after (before for capturing) any native other event handlers (as they tend to be attached last).
|
|
|
|
|
|
|
|
|
|
So ideally one wouldn't mix React and native event handlers to have bubbling working as expected,
|
|
|
|
|
but we do need a native event handler here on the document,
|
|
|
|
|
to get keydown events when there is no focused element (target=body).
|
|
|
|
|
|
|
|
|
|
We also do need bubbling here to give child components a chance to call `stopPropagation()`,
|
|
|
|
|
for keydown events it can handle itself, and shouldn't be redirected to the composer.
|
|
|
|
|
|
|
|
|
|
So we listen with React on this component to get any events on focused elements, and get bubbling working as expected.
|
|
|
|
|
We also listen with a native listener on the document to get keydown events when no element is focused.
|
|
|
|
|
Bubbling is irrelevant here as the target is the body element.
|
|
|
|
|
*/
|
2021-07-19 22:43:11 +01:00
|
|
|
private onReactKeyDown = (ev) => {
|
2019-07-17 16:50:05 +02:00
|
|
|
// events caught while bubbling up on the root element
|
|
|
|
|
// of this component, so something must be focused.
|
2021-07-19 22:43:11 +01:00
|
|
|
this.onKeyDown(ev);
|
2020-04-13 14:13:27 +01:00
|
|
|
};
|
2019-07-17 16:50:05 +02:00
|
|
|
|
2021-07-19 22:43:11 +01:00
|
|
|
private onNativeKeyDown = (ev) => {
|
2019-07-17 16:50:05 +02:00
|
|
|
// only pass this if there is no focused element.
|
2021-07-19 22:43:11 +01:00
|
|
|
// if there is, onKeyDown will be called by the
|
2019-07-17 16:50:05 +02:00
|
|
|
// react keydown handler that respects the react bubbling order.
|
|
|
|
|
if (ev.target === document.body) {
|
2021-07-19 22:43:11 +01:00
|
|
|
this.onKeyDown(ev);
|
2019-07-17 16:50:05 +02:00
|
|
|
}
|
2020-04-13 14:13:27 +01:00
|
|
|
};
|
2018-08-07 17:04:37 +01:00
|
|
|
|
2021-07-19 22:43:11 +01:00
|
|
|
private onKeyDown = (ev) => {
|
2017-07-12 17:12:57 +01:00
|
|
|
let handled = false;
|
2016-11-03 18:42:26 +00:00
|
|
|
|
2021-03-01 21:43:00 +13:00
|
|
|
const roomAction = getKeyBindingsManager().getRoomAction(ev);
|
2021-02-28 20:13:34 +13:00
|
|
|
switch (roomAction) {
|
2022-01-31 16:55:45 +01:00
|
|
|
case KeyBindingAction.ScrollUp:
|
|
|
|
|
case KeyBindingAction.ScrollDown:
|
|
|
|
|
case KeyBindingAction.JumpToFirstMessage:
|
|
|
|
|
case KeyBindingAction.JumpToLatestMessage:
|
2021-03-28 22:26:05 +13:00
|
|
|
// pass the event down to the scroll panel
|
2021-07-19 22:43:11 +01:00
|
|
|
this.onScrollKeyPressed(ev);
|
2021-02-28 20:13:34 +13:00
|
|
|
handled = true;
|
2016-11-03 18:42:26 +00:00
|
|
|
break;
|
2022-01-31 16:55:45 +01:00
|
|
|
case KeyBindingAction.SearchInRoom:
|
2021-02-28 20:13:34 +13:00
|
|
|
dis.dispatch({
|
|
|
|
|
action: "focus_search",
|
|
|
|
|
});
|
|
|
|
|
handled = true;
|
2019-05-17 15:28:12 -06:00
|
|
|
break;
|
2021-02-28 20:13:34 +13:00
|
|
|
}
|
|
|
|
|
if (handled) {
|
|
|
|
|
ev.stopPropagation();
|
|
|
|
|
ev.preventDefault();
|
|
|
|
|
return;
|
|
|
|
|
}
|
2020-03-18 16:40:21 +00:00
|
|
|
|
2021-03-01 21:43:00 +13:00
|
|
|
const navAction = getKeyBindingsManager().getNavigationAction(ev);
|
2021-02-28 20:13:34 +13:00
|
|
|
switch (navAction) {
|
2022-01-31 16:55:45 +01:00
|
|
|
case KeyBindingAction.FilterRooms:
|
2021-03-12 19:40:28 +13:00
|
|
|
dis.dispatch({
|
|
|
|
|
action: "focus_room_filter",
|
|
|
|
|
});
|
|
|
|
|
handled = true;
|
2020-03-18 16:40:21 +00:00
|
|
|
break;
|
2022-01-31 16:55:45 +01:00
|
|
|
case KeyBindingAction.ToggleUserMenu:
|
2021-02-28 20:13:34 +13:00
|
|
|
dis.fire(Action.ToggleUserMenu);
|
|
|
|
|
handled = true;
|
2020-09-26 23:21:16 +02:00
|
|
|
break;
|
2022-01-31 16:55:45 +01:00
|
|
|
case KeyBindingAction.ShowKeyboardSettings:
|
2022-01-17 12:53:10 +01:00
|
|
|
dis.dispatch<OpenToTabPayload>({
|
|
|
|
|
action: Action.ViewUserSettings,
|
|
|
|
|
initialTabId: UserTab.Keyboard,
|
|
|
|
|
});
|
2021-02-28 20:13:34 +13:00
|
|
|
handled = true;
|
2020-03-19 19:07:33 +00:00
|
|
|
break;
|
2022-01-31 16:55:45 +01:00
|
|
|
case KeyBindingAction.GoToHome:
|
2021-02-28 20:13:34 +13:00
|
|
|
dis.dispatch({
|
2022-02-22 11:04:27 +01:00
|
|
|
action: Action.ViewHomePage,
|
2021-02-28 20:13:34 +13:00
|
|
|
});
|
|
|
|
|
Modal.closeCurrentModal("homeKeyboardShortcut");
|
|
|
|
|
handled = true;
|
2020-03-19 19:07:33 +00:00
|
|
|
break;
|
2022-01-31 16:55:45 +01:00
|
|
|
case KeyBindingAction.ToggleSpacePanel:
|
2021-12-07 09:32:00 +00:00
|
|
|
dis.fire(Action.ToggleSpacePanel);
|
|
|
|
|
handled = true;
|
|
|
|
|
break;
|
2022-01-31 16:55:45 +01:00
|
|
|
case KeyBindingAction.ToggleRoomSidePanel:
|
2022-03-22 17:07:37 -06:00
|
|
|
if (this.props.page_type === "room_view") {
|
2022-06-17 16:57:40 -04:00
|
|
|
RightPanelStore.instance.togglePanel(null);
|
2020-03-20 00:18:24 +00:00
|
|
|
handled = true;
|
|
|
|
|
}
|
2020-04-11 18:57:59 +01:00
|
|
|
break;
|
2022-01-31 16:55:45 +01:00
|
|
|
case KeyBindingAction.SelectPrevRoom:
|
2021-02-28 20:13:34 +13:00
|
|
|
dis.dispatch<ViewRoomDeltaPayload>({
|
|
|
|
|
action: Action.ViewRoomDelta,
|
|
|
|
|
delta: -1,
|
|
|
|
|
unread: false,
|
|
|
|
|
});
|
|
|
|
|
handled = true;
|
|
|
|
|
break;
|
2022-01-31 16:55:45 +01:00
|
|
|
case KeyBindingAction.SelectNextRoom:
|
2021-02-28 20:13:34 +13:00
|
|
|
dis.dispatch<ViewRoomDeltaPayload>({
|
|
|
|
|
action: Action.ViewRoomDelta,
|
|
|
|
|
delta: 1,
|
|
|
|
|
unread: false,
|
|
|
|
|
});
|
|
|
|
|
handled = true;
|
|
|
|
|
break;
|
2022-01-31 16:55:45 +01:00
|
|
|
case KeyBindingAction.SelectPrevUnreadRoom:
|
2021-02-28 20:13:34 +13:00
|
|
|
dis.dispatch<ViewRoomDeltaPayload>({
|
|
|
|
|
action: Action.ViewRoomDelta,
|
|
|
|
|
delta: -1,
|
|
|
|
|
unread: true,
|
|
|
|
|
});
|
|
|
|
|
break;
|
2022-01-31 16:55:45 +01:00
|
|
|
case KeyBindingAction.SelectNextUnreadRoom:
|
2021-02-28 20:13:34 +13:00
|
|
|
dis.dispatch<ViewRoomDeltaPayload>({
|
|
|
|
|
action: Action.ViewRoomDelta,
|
|
|
|
|
delta: 1,
|
|
|
|
|
unread: true,
|
|
|
|
|
});
|
|
|
|
|
break;
|
2022-03-23 07:52:05 +00:00
|
|
|
case KeyBindingAction.PreviousVisitedRoomOrSpace:
|
2022-02-23 10:12:04 +01:00
|
|
|
PlatformPeg.get().navigateForwardBack(true);
|
|
|
|
|
handled = true;
|
|
|
|
|
break;
|
2022-03-23 07:52:05 +00:00
|
|
|
case KeyBindingAction.NextVisitedRoomOrSpace:
|
2022-02-23 10:12:04 +01:00
|
|
|
PlatformPeg.get().navigateForwardBack(false);
|
|
|
|
|
handled = true;
|
|
|
|
|
break;
|
2016-11-03 18:42:26 +00:00
|
|
|
}
|
2022-01-26 17:50:47 +01:00
|
|
|
|
|
|
|
|
// Handle labs actions here, as they apply within the same scope
|
|
|
|
|
if (!handled) {
|
|
|
|
|
const labsAction = getKeyBindingsManager().getLabsAction(ev);
|
|
|
|
|
switch (labsAction) {
|
2022-01-31 16:55:45 +01:00
|
|
|
case KeyBindingAction.ToggleHiddenEventVisibility: {
|
2022-01-26 17:50:47 +01:00
|
|
|
const hiddenEventVisibility = SettingsStore.getValueAt(
|
|
|
|
|
SettingLevel.DEVICE,
|
|
|
|
|
"showHiddenEventsInTimeline",
|
|
|
|
|
undefined,
|
|
|
|
|
false,
|
|
|
|
|
);
|
|
|
|
|
SettingsStore.setValue(
|
|
|
|
|
"showHiddenEventsInTimeline",
|
|
|
|
|
undefined,
|
|
|
|
|
SettingLevel.DEVICE,
|
|
|
|
|
!hiddenEventVisibility,
|
|
|
|
|
);
|
|
|
|
|
handled = true;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-02-23 10:12:04 +01:00
|
|
|
if (
|
|
|
|
|
!handled &&
|
|
|
|
|
PlatformPeg.get().overrideBrowserShortcuts() &&
|
|
|
|
|
ev.code.startsWith("Digit") &&
|
|
|
|
|
ev.code !== "Digit0" && // this is the shortcut for reset zoom, don't override it
|
|
|
|
|
isOnlyCtrlOrCmdKeyEvent(ev)
|
|
|
|
|
) {
|
|
|
|
|
dis.dispatch<SwitchSpacePayload>({
|
|
|
|
|
action: Action.SwitchSpace,
|
|
|
|
|
num: ev.code.slice(5), // Cut off the first 5 characters - "Digit"
|
|
|
|
|
});
|
|
|
|
|
handled = true;
|
|
|
|
|
}
|
|
|
|
|
|
2016-11-03 18:42:26 +00:00
|
|
|
if (handled) {
|
|
|
|
|
ev.stopPropagation();
|
|
|
|
|
ev.preventDefault();
|
2021-02-28 20:13:34 +13:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const isModifier = ev.key === Key.ALT || ev.key === Key.CONTROL || ev.key === Key.META || ev.key === Key.SHIFT;
|
2021-05-11 10:59:22 +01:00
|
|
|
if (!isModifier && !ev.ctrlKey && !ev.metaKey) {
|
2020-03-13 22:21:34 +00:00
|
|
|
// The above condition is crafted to _allow_ characters with Shift
|
|
|
|
|
// already pressed (but not the Shift key down itself).
|
2019-07-17 16:53:12 +02:00
|
|
|
const isClickShortcut = ev.target !== document.body && (ev.key === Key.SPACE || ev.key === Key.ENTER);
|
|
|
|
|
|
2021-02-18 10:25:25 +00:00
|
|
|
// We explicitly allow alt to be held due to it being a common accent modifier.
|
|
|
|
|
// XXX: Forwarding Dead keys in this way does not work as intended but better to at least
|
|
|
|
|
// move focus to the composer so the user can re-type the dead key correctly.
|
|
|
|
|
const isPrintable = ev.key.length === 1 || ev.key === "Dead";
|
2019-12-02 10:01:08 +00:00
|
|
|
|
2021-02-18 10:25:25 +00:00
|
|
|
// If the user is entering a printable character outside of an input field
|
|
|
|
|
// redirect it to the composer for them.
|
2021-11-22 17:09:16 +00:00
|
|
|
if (!isClickShortcut && isPrintable && !getInputableElement(ev.target as HTMLElement)) {
|
2022-01-26 09:04:19 +00:00
|
|
|
const inThread = !!document.activeElement.closest(".mx_ThreadView");
|
2019-07-23 09:44:17 +02:00
|
|
|
// synchronous dispatch so we focus before key generates input
|
2022-01-26 09:04:19 +00:00
|
|
|
dis.dispatch(
|
|
|
|
|
{
|
|
|
|
|
action: Action.FocusSendMessageComposer,
|
|
|
|
|
context: inThread ? TimelineRenderingType.Thread : TimelineRenderingType.Room,
|
|
|
|
|
},
|
|
|
|
|
true,
|
|
|
|
|
);
|
2019-07-15 18:12:45 +02:00
|
|
|
ev.stopPropagation();
|
2021-02-18 10:25:25 +00:00
|
|
|
// we should *not* preventDefault() here as that would prevent typing in the now-focused composer
|
2019-07-15 18:12:45 +02:00
|
|
|
}
|
2016-11-03 18:42:26 +00:00
|
|
|
}
|
2020-04-13 14:13:27 +01:00
|
|
|
};
|
2016-11-03 18:42:26 +00:00
|
|
|
|
2019-01-21 19:32:57 +00:00
|
|
|
/**
|
|
|
|
|
* dispatch a page-up/page-down/etc to the appropriate component
|
|
|
|
|
* @param {Object} ev The key event
|
|
|
|
|
*/
|
2021-07-19 22:43:11 +01:00
|
|
|
private onScrollKeyPressed = (ev) => {
|
2019-12-08 12:16:17 +00:00
|
|
|
if (this._roomView.current) {
|
|
|
|
|
this._roomView.current.handleScrollKey(ev);
|
2017-04-23 01:00:44 +01:00
|
|
|
}
|
2020-04-13 14:13:27 +01:00
|
|
|
};
|
2016-11-03 18:42:26 +00:00
|
|
|
|
2022-12-16 12:29:59 +00:00
|
|
|
public render() {
|
2019-01-21 19:32:57 +00:00
|
|
|
let pageElement;
|
2016-11-03 18:42:26 +00:00
|
|
|
|
|
|
|
|
switch (this.props.page_type) {
|
|
|
|
|
case PageTypes.RoomView:
|
2019-01-21 19:32:57 +00:00
|
|
|
pageElement = (
|
|
|
|
|
<RoomView
|
2020-08-29 01:11:08 +01:00
|
|
|
ref={this._roomView}
|
|
|
|
|
onRegistered={this.props.onRegistered}
|
2020-09-11 19:49:48 -06:00
|
|
|
threepidInvite={this.props.threepidInvite}
|
2020-08-29 01:11:08 +01:00
|
|
|
oobData={this.props.roomOobData}
|
|
|
|
|
key={this.props.currentRoomId || "roomview"}
|
|
|
|
|
resizeNotifier={this.props.resizeNotifier}
|
2021-03-01 17:54:53 +00:00
|
|
|
justCreatedOpts={this.props.roomJustCreatedOpts}
|
2021-10-20 06:55:22 -06:00
|
|
|
forceTimeline={this.props.forceTimeline}
|
2020-08-29 01:11:08 +01:00
|
|
|
/>
|
|
|
|
|
);
|
2016-11-03 18:42:26 +00:00
|
|
|
break;
|
2019-01-17 10:29:37 +01:00
|
|
|
|
2016-11-13 14:10:46 +00:00
|
|
|
case PageTypes.HomePage:
|
2022-07-29 13:43:29 +02:00
|
|
|
pageElement = <UserOnboardingPage justRegistered={this.props.justRegistered} />;
|
2016-11-13 14:10:46 +00:00
|
|
|
break;
|
|
|
|
|
|
2016-11-03 18:42:26 +00:00
|
|
|
case PageTypes.UserView:
|
2020-09-02 12:00:35 +01:00
|
|
|
pageElement = <UserView userId={this.props.currentUserId} resizeNotifier={this.props.resizeNotifier} />;
|
2016-11-03 18:42:26 +00:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
2021-08-20 13:03:08 +02:00
|
|
|
const wrapperClasses = classNames({
|
|
|
|
|
mx_MatrixChat_wrapper: true,
|
|
|
|
|
mx_MatrixChat_useCompactLayout: this.state.useCompactLayout,
|
|
|
|
|
});
|
2021-08-17 18:56:19 +02:00
|
|
|
const bodyClasses = classNames({
|
|
|
|
|
"mx_MatrixChat": true,
|
|
|
|
|
"mx_MatrixChat--with-avatar": this.state.backgroundImage,
|
|
|
|
|
});
|
2016-11-03 18:42:26 +00:00
|
|
|
|
2021-04-27 11:59:08 +02:00
|
|
|
const audioFeedArraysForCalls = this.state.activeCalls.map((call) => {
|
2022-08-30 15:13:39 -04:00
|
|
|
return <AudioFeedArrayForLegacyCall call={call} key={call.callId} />;
|
2021-04-27 11:59:08 +02:00
|
|
|
});
|
|
|
|
|
|
2016-11-03 18:42:26 +00:00
|
|
|
return (
|
2019-12-17 17:26:12 +00:00
|
|
|
<MatrixClientContext.Provider value={this._matrixClient}>
|
|
|
|
|
<div
|
2021-07-19 22:43:11 +01:00
|
|
|
onPaste={this.onPaste}
|
|
|
|
|
onKeyDown={this.onReactKeyDown}
|
2021-08-20 13:03:08 +02:00
|
|
|
className={wrapperClasses}
|
2019-12-17 17:26:12 +00:00
|
|
|
aria-hidden={this.props.hideToSRUsers}
|
|
|
|
|
>
|
|
|
|
|
<ToastContainer />
|
2021-08-19 16:10:09 +02:00
|
|
|
<div className={bodyClasses}>
|
2022-03-17 09:25:57 +01:00
|
|
|
<div className="mx_LeftPanel_outerWrapper">
|
|
|
|
|
<LeftPanelLiveShareWarning isMinimized={this.props.collapseLhs || false} />
|
2022-08-01 08:31:14 +01:00
|
|
|
<nav className="mx_LeftPanel_wrapper">
|
2022-03-22 17:07:37 -06:00
|
|
|
<BackdropPanel blurMultiplier={0.5} backgroundImage={this.state.backgroundImage} />
|
|
|
|
|
<SpacePanel />
|
2021-08-23 19:26:57 +02:00
|
|
|
<BackdropPanel backgroundImage={this.state.backgroundImage} />
|
2022-03-17 09:25:57 +01:00
|
|
|
<div
|
|
|
|
|
className="mx_LeftPanel_wrapper--user"
|
|
|
|
|
ref={this._resizeContainer}
|
|
|
|
|
data-collapsed={this.props.collapseLhs ? true : undefined}
|
|
|
|
|
>
|
|
|
|
|
<LeftPanel
|
2022-08-12 12:55:31 +02:00
|
|
|
pageType={this.props.page_type as PageTypes}
|
2022-03-17 09:25:57 +01:00
|
|
|
isMinimized={this.props.collapseLhs || false}
|
|
|
|
|
resizeNotifier={this.props.resizeNotifier}
|
|
|
|
|
/>
|
|
|
|
|
</div>
|
2022-08-01 08:31:14 +01:00
|
|
|
</nav>
|
2021-08-19 16:10:09 +02:00
|
|
|
</div>
|
2021-08-24 13:05:46 +02:00
|
|
|
<ResizeHandle passRef={this.resizeHandler} id="lp-resizer" />
|
2021-08-20 15:57:22 +02:00
|
|
|
<div className="mx_RoomView_wrapper">{pageElement}</div>
|
2021-06-01 17:30:57 +01:00
|
|
|
</div>
|
2019-12-17 17:26:12 +00:00
|
|
|
</div>
|
2022-01-13 12:10:41 +01:00
|
|
|
<PipContainer />
|
2020-07-29 12:43:35 -06:00
|
|
|
<NonUrgentToastContainer />
|
2021-01-14 11:53:20 +02:00
|
|
|
<HostSignupContainer />
|
2021-07-19 22:43:11 +01:00
|
|
|
{audioFeedArraysForCalls}
|
2019-12-17 17:26:12 +00:00
|
|
|
</MatrixClientContext.Provider>
|
2016-11-03 18:42:26 +00:00
|
|
|
);
|
2020-04-13 14:13:27 +01:00
|
|
|
}
|
|
|
|
|
}
|
2017-12-06 15:01:16 +00:00
|
|
|
|
2018-01-19 13:34:56 +00:00
|
|
|
export default LoggedInView;
|