Right panel store refactor (#7313)
Co-authored-by: J. Ryan Stinnett <jryans@gmail.com>
This commit is contained in:
parent
8e881336ab
commit
325e2ba99b
42 changed files with 765 additions and 811 deletions
2
src/@types/global.d.ts
vendored
2
src/@types/global.d.ts
vendored
|
@ -32,7 +32,7 @@ import SettingsStore from "../settings/SettingsStore";
|
||||||
import { ActiveRoomObserver } from "../ActiveRoomObserver";
|
import { ActiveRoomObserver } from "../ActiveRoomObserver";
|
||||||
import { Notifier } from "../Notifier";
|
import { Notifier } from "../Notifier";
|
||||||
import type { Renderer } from "react-dom";
|
import type { Renderer } from "react-dom";
|
||||||
import RightPanelStore from "../stores/RightPanelStore";
|
import RightPanelStore from "../stores/right-panel/RightPanelStore";
|
||||||
import WidgetStore from "../stores/WidgetStore";
|
import WidgetStore from "../stores/WidgetStore";
|
||||||
import CallHandler from "../CallHandler";
|
import CallHandler from "../CallHandler";
|
||||||
import { Analytics } from "../Analytics";
|
import { Analytics } from "../Analytics";
|
||||||
|
|
|
@ -27,12 +27,12 @@ import { isValid3pidInvite } from "./RoomInvite";
|
||||||
import SettingsStore from "./settings/SettingsStore";
|
import SettingsStore from "./settings/SettingsStore";
|
||||||
import { ALL_RULE_TYPES, ROOM_RULE_TYPES, SERVER_RULE_TYPES, USER_RULE_TYPES } from "./mjolnir/BanList";
|
import { ALL_RULE_TYPES, ROOM_RULE_TYPES, SERVER_RULE_TYPES, USER_RULE_TYPES } from "./mjolnir/BanList";
|
||||||
import { WIDGET_LAYOUT_EVENT_TYPE } from "./stores/widgets/WidgetLayoutStore";
|
import { WIDGET_LAYOUT_EVENT_TYPE } from "./stores/widgets/WidgetLayoutStore";
|
||||||
import { RightPanelPhases } from './stores/RightPanelStorePhases';
|
import { RightPanelPhases } from './stores/right-panel/RightPanelStorePhases';
|
||||||
import { Action } from './dispatcher/actions';
|
import { Action } from './dispatcher/actions';
|
||||||
import defaultDispatcher from './dispatcher/dispatcher';
|
import defaultDispatcher from './dispatcher/dispatcher';
|
||||||
import { SetRightPanelPhasePayload } from './dispatcher/payloads/SetRightPanelPhasePayload';
|
|
||||||
import { MatrixClientPeg } from "./MatrixClientPeg";
|
import { MatrixClientPeg } from "./MatrixClientPeg";
|
||||||
import { ROOM_SECURITY_TAB } from "./components/views/dialogs/RoomSettingsDialog";
|
import { ROOM_SECURITY_TAB } from "./components/views/dialogs/RoomSettingsDialog";
|
||||||
|
import RightPanelStore from './stores/right-panel/RightPanelStore';
|
||||||
|
|
||||||
// These functions are frequently used just to check whether an event has
|
// These functions are frequently used just to check whether an event has
|
||||||
// any text to display at all. For this reason they return deferred values
|
// any text to display at all. For this reason they return deferred values
|
||||||
|
@ -503,11 +503,7 @@ const onPinnedOrUnpinnedMessageClick = (messageId: string, roomId: string): void
|
||||||
};
|
};
|
||||||
|
|
||||||
const onPinnedMessagesClick = (): void => {
|
const onPinnedMessagesClick = (): void => {
|
||||||
defaultDispatcher.dispatch<SetRightPanelPhasePayload>({
|
RightPanelStore.instance.setCard({ phase: RightPanelPhases.PinnedMessages }, false);
|
||||||
action: Action.SetRightPanelPhase,
|
|
||||||
phase: RightPanelPhases.PinnedMessages,
|
|
||||||
allowClose: false,
|
|
||||||
});
|
|
||||||
};
|
};
|
||||||
|
|
||||||
function textForPinnedEvent(event: MatrixEvent, allowJSX: boolean): () => string | JSX.Element | null {
|
function textForPinnedEvent(event: MatrixEvent, allowJSX: boolean): () => string | JSX.Element | null {
|
||||||
|
|
|
@ -27,9 +27,9 @@ import { logger } from "matrix-js-sdk/src/logger";
|
||||||
import { MatrixClientPeg } from '../../MatrixClientPeg';
|
import { MatrixClientPeg } from '../../MatrixClientPeg';
|
||||||
import EventIndexPeg from "../../indexing/EventIndexPeg";
|
import EventIndexPeg from "../../indexing/EventIndexPeg";
|
||||||
import { _t } from '../../languageHandler';
|
import { _t } from '../../languageHandler';
|
||||||
import BaseCard from "../views/right_panel/BaseCard";
|
import { RightPanelPhases } from "../../stores/right-panel/RightPanelStorePhases";
|
||||||
import { RightPanelPhases } from "../../stores/RightPanelStorePhases";
|
|
||||||
import DesktopBuildsNotice, { WarningKind } from "../views/elements/DesktopBuildsNotice";
|
import DesktopBuildsNotice, { WarningKind } from "../views/elements/DesktopBuildsNotice";
|
||||||
|
import BaseCard from "../views/right_panel/BaseCard";
|
||||||
import { replaceableComponent } from "../../utils/replaceableComponent";
|
import { replaceableComponent } from "../../utils/replaceableComponent";
|
||||||
import ResizeNotifier from '../../utils/ResizeNotifier';
|
import ResizeNotifier from '../../utils/ResizeNotifier';
|
||||||
import TimelinePanel from "./TimelinePanel";
|
import TimelinePanel from "./TimelinePanel";
|
||||||
|
|
|
@ -38,13 +38,14 @@ import GroupStore from '../../stores/GroupStore';
|
||||||
import FlairStore from '../../stores/FlairStore';
|
import FlairStore from '../../stores/FlairStore';
|
||||||
import { showGroupAddRoomDialog } from '../../GroupAddressPicker';
|
import { showGroupAddRoomDialog } from '../../GroupAddressPicker';
|
||||||
import { makeGroupPermalink, makeUserPermalink } from "../../utils/permalinks/Permalinks";
|
import { makeGroupPermalink, makeUserPermalink } from "../../utils/permalinks/Permalinks";
|
||||||
import RightPanelStore from "../../stores/RightPanelStore";
|
import RightPanelStore from "../../stores/right-panel/RightPanelStore";
|
||||||
import AutoHideScrollbar from "./AutoHideScrollbar";
|
import AutoHideScrollbar from "./AutoHideScrollbar";
|
||||||
import { mediaFromMxc } from "../../customisations/Media";
|
import { mediaFromMxc } from "../../customisations/Media";
|
||||||
import { replaceableComponent } from "../../utils/replaceableComponent";
|
import { replaceableComponent } from "../../utils/replaceableComponent";
|
||||||
import { createSpaceFromCommunity } from "../../utils/space";
|
import { createSpaceFromCommunity } from "../../utils/space";
|
||||||
import { Action } from "../../dispatcher/actions";
|
import { Action } from "../../dispatcher/actions";
|
||||||
import { RightPanelPhases } from "../../stores/RightPanelStorePhases";
|
import { RightPanelPhases } from "../../stores/right-panel/RightPanelStorePhases";
|
||||||
|
import { UPDATE_EVENT } from "../../stores/AsyncStore";
|
||||||
|
|
||||||
const LONG_DESC_PLACEHOLDER = _td(
|
const LONG_DESC_PLACEHOLDER = _td(
|
||||||
`<h1>HTML for your community's page</h1>
|
`<h1>HTML for your community's page</h1>
|
||||||
|
@ -427,7 +428,7 @@ export default class GroupView extends React.Component {
|
||||||
membershipBusy: false,
|
membershipBusy: false,
|
||||||
publicityBusy: false,
|
publicityBusy: false,
|
||||||
inviterProfile: null,
|
inviterProfile: null,
|
||||||
showRightPanel: RightPanelStore.getSharedInstance().isOpenForGroup,
|
showRightPanel: RightPanelStore.instance.isOpenForGroup,
|
||||||
showUpgradeNotice: !localStorage.getItem(UPGRADE_NOTICE_LS_KEY),
|
showUpgradeNotice: !localStorage.getItem(UPGRADE_NOTICE_LS_KEY),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -439,7 +440,7 @@ export default class GroupView extends React.Component {
|
||||||
this._initGroupStore(this.props.groupId, true);
|
this._initGroupStore(this.props.groupId, true);
|
||||||
|
|
||||||
this._dispatcherRef = dis.register(this._onAction);
|
this._dispatcherRef = dis.register(this._onAction);
|
||||||
this._rightPanelStoreToken = RightPanelStore.getSharedInstance().addListener(this._onRightPanelStoreUpdate);
|
RightPanelStore.instance.on(UPDATE_EVENT, this._onRightPanelStoreUpdate);
|
||||||
}
|
}
|
||||||
|
|
||||||
componentWillUnmount() {
|
componentWillUnmount() {
|
||||||
|
@ -447,10 +448,7 @@ export default class GroupView extends React.Component {
|
||||||
this._matrixClient.removeListener("Group.myMembership", this._onGroupMyMembership);
|
this._matrixClient.removeListener("Group.myMembership", this._onGroupMyMembership);
|
||||||
dis.unregister(this._dispatcherRef);
|
dis.unregister(this._dispatcherRef);
|
||||||
|
|
||||||
// Remove RightPanelStore listener
|
RightPanelStore.instance.off(UPDATE_EVENT, this._onRightPanelStoreUpdate);
|
||||||
if (this._rightPanelStoreToken) {
|
|
||||||
this._rightPanelStoreToken.remove();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: [REACT-WARNING] Replace with appropriate lifecycle event
|
// TODO: [REACT-WARNING] Replace with appropriate lifecycle event
|
||||||
|
@ -468,7 +466,7 @@ export default class GroupView extends React.Component {
|
||||||
|
|
||||||
_onRightPanelStoreUpdate = () => {
|
_onRightPanelStoreUpdate = () => {
|
||||||
this.setState({
|
this.setState({
|
||||||
showRightPanel: RightPanelStore.getSharedInstance().isOpenForGroup,
|
showRightPanel: RightPanelStore.instance.isOpenForGroup,
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -824,10 +822,7 @@ export default class GroupView extends React.Component {
|
||||||
};
|
};
|
||||||
|
|
||||||
_onAdminsLinkClick = () => {
|
_onAdminsLinkClick = () => {
|
||||||
dis.dispatch({
|
RightPanelStore.instance.setCard({ phase: RightPanelPhases.GroupMemberList });
|
||||||
action: Action.SetRightPanelPhase,
|
|
||||||
phase: RightPanelPhases.GroupMemberList,
|
|
||||||
});
|
|
||||||
};
|
};
|
||||||
|
|
||||||
_getGroupSection() {
|
_getGroupSection() {
|
||||||
|
|
|
@ -44,7 +44,6 @@ import CallContainer from '../views/voip/CallContainer';
|
||||||
import { ViewRoomDeltaPayload } from "../../dispatcher/payloads/ViewRoomDeltaPayload";
|
import { ViewRoomDeltaPayload } from "../../dispatcher/payloads/ViewRoomDeltaPayload";
|
||||||
import RoomListStore from "../../stores/room-list/RoomListStore";
|
import RoomListStore from "../../stores/room-list/RoomListStore";
|
||||||
import NonUrgentToastContainer from "./NonUrgentToastContainer";
|
import NonUrgentToastContainer from "./NonUrgentToastContainer";
|
||||||
import { ToggleRightPanelPayload } from "../../dispatcher/payloads/ToggleRightPanelPayload";
|
|
||||||
import { IOOBData, IThreepidInvite } from "../../stores/ThreepidInviteStore";
|
import { IOOBData, IThreepidInvite } from "../../stores/ThreepidInviteStore";
|
||||||
import Modal from "../../Modal";
|
import Modal from "../../Modal";
|
||||||
import { ICollapseConfig } from "../../resizer/distributors/collapse";
|
import { ICollapseConfig } from "../../resizer/distributors/collapse";
|
||||||
|
@ -68,6 +67,7 @@ import GroupFilterPanel from './GroupFilterPanel';
|
||||||
import CustomRoomTagPanel from './CustomRoomTagPanel';
|
import CustomRoomTagPanel from './CustomRoomTagPanel';
|
||||||
import { mediaFromMxc } from "../../customisations/Media";
|
import { mediaFromMxc } from "../../customisations/Media";
|
||||||
import LegacyCommunityPreview from "./LegacyCommunityPreview";
|
import LegacyCommunityPreview from "./LegacyCommunityPreview";
|
||||||
|
import RightPanelStore from '../../stores/right-panel/RightPanelStore';
|
||||||
|
|
||||||
// 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.
|
||||||
|
@ -489,10 +489,7 @@ class LoggedInView extends React.Component<IProps, IState> {
|
||||||
break;
|
break;
|
||||||
case NavigationAction.ToggleRoomSidePanel:
|
case NavigationAction.ToggleRoomSidePanel:
|
||||||
if (this.props.page_type === "room_view" || this.props.page_type === "group_view") {
|
if (this.props.page_type === "room_view" || this.props.page_type === "group_view") {
|
||||||
dis.dispatch<ToggleRightPanelPayload>({
|
RightPanelStore.instance.togglePanel();
|
||||||
action: Action.ToggleRightPanel,
|
|
||||||
type: this.props.page_type === "room_view" ? "room" : "group",
|
|
||||||
});
|
|
||||||
handled = true;
|
handled = true;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -20,17 +20,12 @@ import { Room } from "matrix-js-sdk/src/models/room";
|
||||||
import { RoomState } from "matrix-js-sdk/src/models/room-state";
|
import { RoomState } from "matrix-js-sdk/src/models/room-state";
|
||||||
import { RoomMember } from "matrix-js-sdk/src/models/room-member";
|
import { RoomMember } from "matrix-js-sdk/src/models/room-member";
|
||||||
import { MatrixEvent } from "matrix-js-sdk/src/models/event";
|
import { MatrixEvent } from "matrix-js-sdk/src/models/event";
|
||||||
import { VerificationRequest } from "matrix-js-sdk/src/crypto/verification/request/VerificationRequest";
|
|
||||||
import { throttle } from 'lodash';
|
import { throttle } from 'lodash';
|
||||||
|
|
||||||
import dis from '../../dispatcher/dispatcher';
|
import dis from '../../dispatcher/dispatcher';
|
||||||
import GroupStore from '../../stores/GroupStore';
|
import GroupStore from '../../stores/GroupStore';
|
||||||
import {
|
import { RightPanelPhases } from '../../stores/right-panel/RightPanelStorePhases';
|
||||||
RIGHT_PANEL_PHASES_NO_ARGS,
|
import RightPanelStore from "../../stores/right-panel/RightPanelStore";
|
||||||
RIGHT_PANEL_SPACE_PHASES,
|
|
||||||
RightPanelPhases,
|
|
||||||
} from "../../stores/RightPanelStorePhases";
|
|
||||||
import RightPanelStore from "../../stores/RightPanelStore";
|
|
||||||
import MatrixClientContext from "../../contexts/MatrixClientContext";
|
import MatrixClientContext from "../../contexts/MatrixClientContext";
|
||||||
import { Action } from "../../dispatcher/actions";
|
import { Action } from "../../dispatcher/actions";
|
||||||
import RoomSummaryCard from "../views/right_panel/RoomSummaryCard";
|
import RoomSummaryCard from "../views/right_panel/RoomSummaryCard";
|
||||||
|
@ -50,16 +45,17 @@ import ThreadPanel from "./ThreadPanel";
|
||||||
import NotificationPanel from "./NotificationPanel";
|
import NotificationPanel from "./NotificationPanel";
|
||||||
import ResizeNotifier from "../../utils/ResizeNotifier";
|
import ResizeNotifier from "../../utils/ResizeNotifier";
|
||||||
import PinnedMessagesCard from "../views/right_panel/PinnedMessagesCard";
|
import PinnedMessagesCard from "../views/right_panel/PinnedMessagesCard";
|
||||||
import SpaceStore from "../../stores/spaces/SpaceStore";
|
|
||||||
import { RoomPermalinkCreator } from '../../utils/permalinks/Permalinks';
|
import { RoomPermalinkCreator } from '../../utils/permalinks/Permalinks';
|
||||||
import { E2EStatus } from '../../utils/ShieldUtils';
|
import { E2EStatus } from '../../utils/ShieldUtils';
|
||||||
import { dispatchShowThreadsPanelEvent } from '../../dispatcher/dispatch-actions/threads';
|
import { dispatchShowThreadsPanelEvent } from '../../dispatcher/dispatch-actions/threads';
|
||||||
import TimelineCard from '../views/right_panel/TimelineCard';
|
import TimelineCard from '../views/right_panel/TimelineCard';
|
||||||
|
import { UPDATE_EVENT } from '../../stores/AsyncStore';
|
||||||
|
import { IRightPanelCard, IRightPanelCardState } from '../../stores/right-panel/RightPanelStoreIPanelState';
|
||||||
|
|
||||||
interface IProps {
|
interface IProps {
|
||||||
room?: Room; // if showing panels for a given room, this is set
|
room?: Room; // if showing panels for a given room, this is set
|
||||||
groupId?: string; // if showing panels for a given group, this is set
|
groupId?: string; // if showing panels for a given group, this is set
|
||||||
member?: RoomMember; // used if we know the room member ahead of opening the panel
|
overwriteCard?: IRightPanelCard; // used to display a custom card and ignoring the RightPanelStore (used for UserView)
|
||||||
resizeNotifier: ResizeNotifier;
|
resizeNotifier: ResizeNotifier;
|
||||||
permalinkCreator?: RoomPermalinkCreator;
|
permalinkCreator?: RoomPermalinkCreator;
|
||||||
e2eStatus?: E2EStatus;
|
e2eStatus?: E2EStatus;
|
||||||
|
@ -68,17 +64,8 @@ interface IProps {
|
||||||
interface IState {
|
interface IState {
|
||||||
phase: RightPanelPhases;
|
phase: RightPanelPhases;
|
||||||
isUserPrivilegedInGroup?: boolean;
|
isUserPrivilegedInGroup?: boolean;
|
||||||
member?: RoomMember;
|
|
||||||
verificationRequest?: VerificationRequest;
|
|
||||||
verificationRequestPromise?: Promise<VerificationRequest>;
|
|
||||||
space?: Room;
|
|
||||||
widgetId?: string;
|
|
||||||
groupRoomId?: string;
|
|
||||||
groupId?: string;
|
|
||||||
event: MatrixEvent;
|
|
||||||
initialEvent?: MatrixEvent;
|
|
||||||
initialEventHighlighted?: boolean;
|
|
||||||
searchQuery: string;
|
searchQuery: string;
|
||||||
|
cardState?: IRightPanelCardState;
|
||||||
}
|
}
|
||||||
|
|
||||||
@replaceableComponent("structures.RightPanel")
|
@replaceableComponent("structures.RightPanel")
|
||||||
|
@ -89,11 +76,11 @@ export default class RightPanel extends React.Component<IProps, IState> {
|
||||||
|
|
||||||
constructor(props, context) {
|
constructor(props, context) {
|
||||||
super(props, context);
|
super(props, context);
|
||||||
|
|
||||||
this.state = {
|
this.state = {
|
||||||
...RightPanelStore.getSharedInstance().roomPanelPhaseParams,
|
cardState: RightPanelStore.instance.currentCard?.state,
|
||||||
phase: this.getPhaseFromProps(),
|
phase: RightPanelStore.instance.currentCard?.phase,
|
||||||
isUserPrivilegedInGroup: null,
|
isUserPrivilegedInGroup: null,
|
||||||
member: this.getUserForPanel(),
|
|
||||||
searchQuery: "",
|
searchQuery: "",
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -102,56 +89,11 @@ export default class RightPanel extends React.Component<IProps, IState> {
|
||||||
this.forceUpdate();
|
this.forceUpdate();
|
||||||
}, 500, { leading: true, trailing: true });
|
}, 500, { leading: true, trailing: true });
|
||||||
|
|
||||||
// Helper function to split out the logic for getPhaseFromProps() and the constructor
|
|
||||||
// as both are called at the same time in the constructor.
|
|
||||||
private getUserForPanel(): RoomMember {
|
|
||||||
if (this.state && this.state.member) return this.state.member;
|
|
||||||
const lastParams = RightPanelStore.getSharedInstance().roomPanelPhaseParams;
|
|
||||||
return this.props.member || lastParams['member'];
|
|
||||||
}
|
|
||||||
|
|
||||||
// gets the current phase from the props and also maybe the store
|
|
||||||
private getPhaseFromProps() {
|
|
||||||
const rps = RightPanelStore.getSharedInstance();
|
|
||||||
const userForPanel = this.getUserForPanel();
|
|
||||||
if (this.props.groupId) {
|
|
||||||
if (!RIGHT_PANEL_PHASES_NO_ARGS.includes(rps.groupPanelPhase)) {
|
|
||||||
dis.dispatch({ action: Action.SetRightPanelPhase, phase: RightPanelPhases.GroupMemberList });
|
|
||||||
return RightPanelPhases.GroupMemberList;
|
|
||||||
}
|
|
||||||
return rps.groupPanelPhase;
|
|
||||||
} else if (SpaceStore.spacesEnabled && this.props.room?.isSpaceRoom()
|
|
||||||
&& !RIGHT_PANEL_SPACE_PHASES.includes(rps.roomPanelPhase)
|
|
||||||
) {
|
|
||||||
return RightPanelPhases.SpaceMemberList;
|
|
||||||
} else if (userForPanel) {
|
|
||||||
// XXX FIXME AAAAAARGH: What is going on with this class!? It takes some of its state
|
|
||||||
// from its props and some from a store, except if the contents of the store changes
|
|
||||||
// while it's mounted in which case it replaces all of its state with that of the store,
|
|
||||||
// except it uses a dispatch instead of a normal store listener?
|
|
||||||
// Unfortunately rewriting this would almost certainly break showing the right panel
|
|
||||||
// in some of the many cases, and I don't have time to re-architect it and test all
|
|
||||||
// the flows now, so adding yet another special case so if the store thinks there is
|
|
||||||
// a verification going on for the member we're displaying, we show that, otherwise
|
|
||||||
// we race if a verification is started while the panel isn't displayed because we're
|
|
||||||
// not mounted in time to get the dispatch.
|
|
||||||
// Until then, let this code serve as a warning from history.
|
|
||||||
if (
|
|
||||||
rps.roomPanelPhaseParams.member &&
|
|
||||||
userForPanel.userId === rps.roomPanelPhaseParams.member.userId &&
|
|
||||||
rps.roomPanelPhaseParams.verificationRequest
|
|
||||||
) {
|
|
||||||
return rps.roomPanelPhase;
|
|
||||||
}
|
|
||||||
return RightPanelPhases.RoomMemberInfo;
|
|
||||||
}
|
|
||||||
return rps.roomPanelPhase;
|
|
||||||
}
|
|
||||||
|
|
||||||
public componentDidMount(): void {
|
public componentDidMount(): void {
|
||||||
this.dispatcherRef = dis.register(this.onAction);
|
this.dispatcherRef = dis.register(this.onAction);
|
||||||
const cli = this.context;
|
const cli = this.context;
|
||||||
cli.on("RoomState.members", this.onRoomStateMember);
|
cli.on("RoomState.members", this.onRoomStateMember);
|
||||||
|
RightPanelStore.instance.on(UPDATE_EVENT, this.onRightPanelStoreUpdate);
|
||||||
this.initGroupStore(this.props.groupId);
|
this.initGroupStore(this.props.groupId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -160,6 +102,7 @@ export default class RightPanel extends React.Component<IProps, IState> {
|
||||||
if (this.context) {
|
if (this.context) {
|
||||||
this.context.removeListener("RoomState.members", this.onRoomStateMember);
|
this.context.removeListener("RoomState.members", this.onRoomStateMember);
|
||||||
}
|
}
|
||||||
|
RightPanelStore.instance.off(UPDATE_EVENT, this.onRightPanelStoreUpdate);
|
||||||
this.unregisterGroupStore();
|
this.unregisterGroupStore();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -193,42 +136,36 @@ export default class RightPanel extends React.Component<IProps, IState> {
|
||||||
// redraw the badge on the membership list
|
// redraw the badge on the membership list
|
||||||
if (this.state.phase === RightPanelPhases.RoomMemberList && member.roomId === this.props.room.roomId) {
|
if (this.state.phase === RightPanelPhases.RoomMemberList && member.roomId === this.props.room.roomId) {
|
||||||
this.delayedUpdate();
|
this.delayedUpdate();
|
||||||
} else if (this.state.phase === RightPanelPhases.RoomMemberInfo && member.roomId === this.props.room.roomId &&
|
} else if (
|
||||||
member.userId === this.state.member.userId) {
|
this.state.phase === RightPanelPhases.RoomMemberInfo && member.roomId === this.props.room.roomId &&
|
||||||
|
member.userId === this.state.cardState.member.userId
|
||||||
|
) {
|
||||||
// refresh the member info (e.g. new power level)
|
// refresh the member info (e.g. new power level)
|
||||||
this.delayedUpdate();
|
this.delayedUpdate();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
private onRightPanelStoreUpdate = () => {
|
||||||
|
const currentPanel = RightPanelStore.instance.currentCard;
|
||||||
|
this.setState({
|
||||||
|
cardState: currentPanel.state,
|
||||||
|
phase: currentPanel.phase,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
private onAction = (payload: ActionPayload) => {
|
private onAction = (payload: ActionPayload) => {
|
||||||
const isChangingRoom = payload.action === Action.ViewRoom && payload.room_id !== this.props.room.roomId;
|
const isChangingRoom = payload.action === Action.ViewRoom && payload.room_id !== this.props.room.roomId;
|
||||||
const isViewingThread = this.state.phase === RightPanelPhases.ThreadView;
|
const isViewingThread = this.state.phase === RightPanelPhases.ThreadView;
|
||||||
if (isChangingRoom && isViewingThread) {
|
if (isChangingRoom && isViewingThread) {
|
||||||
dispatchShowThreadsPanelEvent();
|
dispatchShowThreadsPanelEvent();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (payload.action === Action.AfterRightPanelPhaseChange) {
|
|
||||||
this.setState({
|
|
||||||
phase: payload.phase,
|
|
||||||
groupRoomId: payload.groupRoomId,
|
|
||||||
groupId: payload.groupId,
|
|
||||||
member: payload.member,
|
|
||||||
event: payload.event,
|
|
||||||
initialEvent: payload.initialEvent,
|
|
||||||
initialEventHighlighted: payload.highlighted,
|
|
||||||
verificationRequest: payload.verificationRequest,
|
|
||||||
verificationRequestPromise: payload.verificationRequestPromise,
|
|
||||||
widgetId: payload.widgetId,
|
|
||||||
space: payload.space,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
private onClose = () => {
|
private onClose = () => {
|
||||||
// XXX: There are three different ways of 'closing' this panel depending on what state
|
// XXX: There are three different ways of 'closing' this panel depending on what state
|
||||||
// things are in... this knows far more than it should do about the state of the rest
|
// things are in... this knows far more than it should do about the state of the rest
|
||||||
// of the app and is generally a bit silly.
|
// of the app and is generally a bit silly.
|
||||||
if (this.props.member) {
|
if (this.props.overwriteCard?.state?.member) {
|
||||||
// If we have a user prop then we're displaying a user from the 'user' page type
|
// If we have a user prop then we're displaying a user from the 'user' page type
|
||||||
// in LoggedInView, so need to change the page type to close the panel (we switch
|
// in LoggedInView, so need to change the page type to close the panel (we switch
|
||||||
// to the home page which is not obviously the correct thing to do, but I'm not sure
|
// to the home page which is not obviously the correct thing to do, but I'm not sure
|
||||||
|
@ -238,16 +175,12 @@ export default class RightPanel extends React.Component<IProps, IState> {
|
||||||
});
|
});
|
||||||
} else if (
|
} else if (
|
||||||
this.state.phase === RightPanelPhases.EncryptionPanel &&
|
this.state.phase === RightPanelPhases.EncryptionPanel &&
|
||||||
this.state.verificationRequest && this.state.verificationRequest.pending
|
this.state.cardState.verificationRequest && this.state.cardState.verificationRequest.pending
|
||||||
) {
|
) {
|
||||||
// When the user clicks close on the encryption panel cancel the pending request first if any
|
// When the user clicks close on the encryption panel cancel the pending request first if any
|
||||||
this.state.verificationRequest.cancel();
|
this.state.cardState.verificationRequest.cancel();
|
||||||
} else {
|
} else {
|
||||||
// the RightPanelStore has no way of knowing which mode room/group it is in, so we handle closing here
|
RightPanelStore.instance.togglePanel();
|
||||||
dis.dispatch({
|
|
||||||
action: Action.ToggleRightPanel,
|
|
||||||
type: this.props.groupId ? "group" : "room",
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -256,13 +189,14 @@ export default class RightPanel extends React.Component<IProps, IState> {
|
||||||
};
|
};
|
||||||
|
|
||||||
public render(): JSX.Element {
|
public render(): JSX.Element {
|
||||||
let panel = <div />;
|
let card = <div />;
|
||||||
const roomId = this.props.room ? this.props.room.roomId : undefined;
|
const roomId = this.props.room ? this.props.room.roomId : undefined;
|
||||||
|
const phase = this.props.overwriteCard?.phase ?? this.state.phase;
|
||||||
switch (this.state.phase) {
|
const cardState = this.props.overwriteCard?.state ?? this.state.cardState;
|
||||||
|
switch (phase) {
|
||||||
case RightPanelPhases.RoomMemberList:
|
case RightPanelPhases.RoomMemberList:
|
||||||
if (roomId) {
|
if (roomId) {
|
||||||
panel = <MemberList
|
card = <MemberList
|
||||||
roomId={roomId}
|
roomId={roomId}
|
||||||
key={roomId}
|
key={roomId}
|
||||||
onClose={this.onClose}
|
onClose={this.onClose}
|
||||||
|
@ -272,9 +206,9 @@ export default class RightPanel extends React.Component<IProps, IState> {
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case RightPanelPhases.SpaceMemberList:
|
case RightPanelPhases.SpaceMemberList:
|
||||||
panel = <MemberList
|
card = <MemberList
|
||||||
roomId={this.state.space ? this.state.space.roomId : roomId}
|
roomId={cardState.spaceId ? cardState.spaceId : roomId}
|
||||||
key={this.state.space ? this.state.space.roomId : roomId}
|
key={cardState.spaceId ? cardState.spaceId : roomId}
|
||||||
onClose={this.onClose}
|
onClose={this.onClose}
|
||||||
searchQuery={this.state.searchQuery}
|
searchQuery={this.state.searchQuery}
|
||||||
onSearchQueryChanged={this.onSearchQueryChanged}
|
onSearchQueryChanged={this.onSearchQueryChanged}
|
||||||
|
@ -283,61 +217,66 @@ export default class RightPanel extends React.Component<IProps, IState> {
|
||||||
|
|
||||||
case RightPanelPhases.GroupMemberList:
|
case RightPanelPhases.GroupMemberList:
|
||||||
if (this.props.groupId) {
|
if (this.props.groupId) {
|
||||||
panel = <GroupMemberList groupId={this.props.groupId} key={this.props.groupId} />;
|
card = <GroupMemberList groupId={this.props.groupId} key={this.props.groupId} />;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case RightPanelPhases.GroupRoomList:
|
case RightPanelPhases.GroupRoomList:
|
||||||
panel = <GroupRoomList groupId={this.props.groupId} key={this.props.groupId} />;
|
card = <GroupRoomList groupId={this.props.groupId} key={this.props.groupId} />;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case RightPanelPhases.RoomMemberInfo:
|
case RightPanelPhases.RoomMemberInfo:
|
||||||
case RightPanelPhases.SpaceMemberInfo:
|
case RightPanelPhases.SpaceMemberInfo:
|
||||||
case RightPanelPhases.EncryptionPanel:
|
case RightPanelPhases.EncryptionPanel: {
|
||||||
panel = <UserInfo
|
const roomMember = cardState.member instanceof RoomMember
|
||||||
user={this.state.member}
|
? cardState.member
|
||||||
room={this.context.getRoom(this.state.member.roomId) ?? this.props.room}
|
: undefined;
|
||||||
key={roomId || this.state.member.userId}
|
card = <UserInfo
|
||||||
|
user={cardState.member}
|
||||||
|
room={this.context.getRoom(roomMember?.roomId) ?? this.props.room}
|
||||||
|
key={roomId || cardState.member.userId}
|
||||||
onClose={this.onClose}
|
onClose={this.onClose}
|
||||||
phase={this.state.phase}
|
phase={phase}
|
||||||
verificationRequest={this.state.verificationRequest}
|
verificationRequest={cardState.verificationRequest}
|
||||||
verificationRequestPromise={this.state.verificationRequestPromise}
|
verificationRequestPromise={cardState.verificationRequestPromise}
|
||||||
/>;
|
/>;
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
case RightPanelPhases.Room3pidMemberInfo:
|
case RightPanelPhases.Room3pidMemberInfo:
|
||||||
case RightPanelPhases.Space3pidMemberInfo:
|
case RightPanelPhases.Space3pidMemberInfo:
|
||||||
panel = <ThirdPartyMemberInfo event={this.state.event} key={roomId} />;
|
card = <ThirdPartyMemberInfo event={cardState.memberInfoEvent} key={roomId} />;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case RightPanelPhases.GroupMemberInfo:
|
case RightPanelPhases.GroupMemberInfo:
|
||||||
panel = <UserInfo
|
card = <UserInfo
|
||||||
user={this.state.member}
|
user={cardState.member}
|
||||||
groupId={this.props.groupId}
|
groupId={this.props.groupId}
|
||||||
key={this.state.member.userId}
|
key={cardState.member.userId}
|
||||||
phase={this.state.phase}
|
phase={phase}
|
||||||
onClose={this.onClose} />;
|
onClose={this.onClose}
|
||||||
|
/>;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case RightPanelPhases.GroupRoomInfo:
|
case RightPanelPhases.GroupRoomInfo:
|
||||||
panel = <GroupRoomInfo
|
card = <GroupRoomInfo
|
||||||
groupRoomId={this.state.groupRoomId}
|
groupRoomId={cardState.groupRoomId}
|
||||||
groupId={this.props.groupId}
|
groupId={this.props.groupId}
|
||||||
key={this.state.groupRoomId} />;
|
key={cardState.groupRoomId}
|
||||||
|
/>;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case RightPanelPhases.NotificationPanel:
|
case RightPanelPhases.NotificationPanel:
|
||||||
panel = <NotificationPanel onClose={this.onClose} />;
|
card = <NotificationPanel onClose={this.onClose} />;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case RightPanelPhases.PinnedMessages:
|
case RightPanelPhases.PinnedMessages:
|
||||||
if (SettingsStore.getValue("feature_pinning")) {
|
if (SettingsStore.getValue("feature_pinning")) {
|
||||||
panel = <PinnedMessagesCard room={this.props.room} onClose={this.onClose} />;
|
card = <PinnedMessagesCard room={this.props.room} onClose={this.onClose} />;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case RightPanelPhases.Timeline:
|
case RightPanelPhases.Timeline:
|
||||||
if (!SettingsStore.getValue("feature_maximised_widgets")) break;
|
if (!SettingsStore.getValue("feature_maximised_widgets")) break;
|
||||||
panel = <TimelineCard
|
card = <TimelineCard
|
||||||
classNames="mx_ThreadPanel mx_TimelineCard"
|
classNames="mx_ThreadPanel mx_TimelineCard"
|
||||||
room={this.props.room}
|
room={this.props.room}
|
||||||
timelineSet={this.props.room.getUnfilteredTimelineSet()}
|
timelineSet={this.props.room.getUnfilteredTimelineSet()}
|
||||||
|
@ -348,23 +287,24 @@ export default class RightPanel extends React.Component<IProps, IState> {
|
||||||
/>;
|
/>;
|
||||||
break;
|
break;
|
||||||
case RightPanelPhases.FilePanel:
|
case RightPanelPhases.FilePanel:
|
||||||
panel = <FilePanel roomId={roomId} resizeNotifier={this.props.resizeNotifier} onClose={this.onClose} />;
|
card = <FilePanel roomId={roomId} resizeNotifier={this.props.resizeNotifier} onClose={this.onClose} />;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case RightPanelPhases.ThreadView:
|
case RightPanelPhases.ThreadView:
|
||||||
panel = <ThreadView
|
card = <ThreadView
|
||||||
room={this.props.room}
|
room={this.props.room}
|
||||||
resizeNotifier={this.props.resizeNotifier}
|
resizeNotifier={this.props.resizeNotifier}
|
||||||
onClose={this.onClose}
|
onClose={this.onClose}
|
||||||
mxEvent={this.state.event}
|
mxEvent={cardState.threadHeadEvent}
|
||||||
initialEvent={this.state.initialEvent}
|
initialEvent={cardState.initialEvent}
|
||||||
initialEventHighlighted={this.state.initialEventHighlighted}
|
isInitialEventHighlighted={cardState.isInitialEventHighlighted}
|
||||||
permalinkCreator={this.props.permalinkCreator}
|
permalinkCreator={this.props.permalinkCreator}
|
||||||
e2eStatus={this.props.e2eStatus} />;
|
e2eStatus={this.props.e2eStatus}
|
||||||
|
/>;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case RightPanelPhases.ThreadPanel:
|
case RightPanelPhases.ThreadPanel:
|
||||||
panel = <ThreadPanel
|
card = <ThreadPanel
|
||||||
roomId={roomId}
|
roomId={roomId}
|
||||||
resizeNotifier={this.props.resizeNotifier}
|
resizeNotifier={this.props.resizeNotifier}
|
||||||
onClose={this.onClose}
|
onClose={this.onClose}
|
||||||
|
@ -373,17 +313,21 @@ export default class RightPanel extends React.Component<IProps, IState> {
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case RightPanelPhases.RoomSummary:
|
case RightPanelPhases.RoomSummary:
|
||||||
panel = <RoomSummaryCard room={this.props.room} onClose={this.onClose} />;
|
card = <RoomSummaryCard room={this.props.room} onClose={this.onClose} />;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case RightPanelPhases.Widget:
|
case RightPanelPhases.Widget:
|
||||||
panel = <WidgetCard room={this.props.room} widgetId={this.state.widgetId} onClose={this.onClose} />;
|
card = <WidgetCard
|
||||||
|
room={this.props.room}
|
||||||
|
widgetId={cardState.widgetId}
|
||||||
|
onClose={this.onClose}
|
||||||
|
/>;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<aside className="mx_RightPanel dark-panel" id="mx_RightPanel">
|
<aside className="mx_RightPanel dark-panel" id="mx_RightPanel">
|
||||||
{ panel }
|
{ card }
|
||||||
</aside>
|
</aside>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -84,6 +84,7 @@ interface IState {
|
||||||
|
|
||||||
@replaceableComponent("structures.RoomStatusBar")
|
@replaceableComponent("structures.RoomStatusBar")
|
||||||
export default class RoomStatusBar extends React.PureComponent<IProps, IState> {
|
export default class RoomStatusBar extends React.PureComponent<IProps, IState> {
|
||||||
|
private unmounted = false;
|
||||||
public static contextType = MatrixClientContext;
|
public static contextType = MatrixClientContext;
|
||||||
|
|
||||||
constructor(props: IProps, context: typeof MatrixClientContext) {
|
constructor(props: IProps, context: typeof MatrixClientContext) {
|
||||||
|
@ -110,6 +111,7 @@ export default class RoomStatusBar extends React.PureComponent<IProps, IState> {
|
||||||
}
|
}
|
||||||
|
|
||||||
public componentWillUnmount(): void {
|
public componentWillUnmount(): void {
|
||||||
|
this.unmounted = true;
|
||||||
// we may have entirely lost our client as we're logging out before clicking login on the guest bar...
|
// we may have entirely lost our client as we're logging out before clicking login on the guest bar...
|
||||||
const client = this.context;
|
const client = this.context;
|
||||||
if (client) {
|
if (client) {
|
||||||
|
@ -122,6 +124,7 @@ export default class RoomStatusBar extends React.PureComponent<IProps, IState> {
|
||||||
if (state === "SYNCING" && prevState === "SYNCING") {
|
if (state === "SYNCING" && prevState === "SYNCING") {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if (this.unmounted) return;
|
||||||
this.setState({
|
this.setState({
|
||||||
syncState: state,
|
syncState: state,
|
||||||
syncStateData: data,
|
syncStateData: data,
|
||||||
|
|
|
@ -53,7 +53,7 @@ import WidgetEchoStore from '../../stores/WidgetEchoStore';
|
||||||
import SettingsStore from "../../settings/SettingsStore";
|
import SettingsStore from "../../settings/SettingsStore";
|
||||||
import { Layout } from "../../settings/enums/Layout";
|
import { Layout } from "../../settings/enums/Layout";
|
||||||
import AccessibleButton from "../views/elements/AccessibleButton";
|
import AccessibleButton from "../views/elements/AccessibleButton";
|
||||||
import RightPanelStore from "../../stores/RightPanelStore";
|
import RightPanelStore from "../../stores/right-panel/RightPanelStore";
|
||||||
import { haveTileForEvent } from "../views/rooms/EventTile";
|
import { haveTileForEvent } from "../views/rooms/EventTile";
|
||||||
import RoomContext, { TimelineRenderingType } from "../../contexts/RoomContext";
|
import RoomContext, { TimelineRenderingType } from "../../contexts/RoomContext";
|
||||||
import MatrixClientContext, { withMatrixClientHOC, MatrixClientProps } from "../../contexts/MatrixClientContext";
|
import MatrixClientContext, { withMatrixClientHOC, MatrixClientProps } from "../../contexts/MatrixClientContext";
|
||||||
|
@ -98,8 +98,7 @@ import { dispatchShowThreadEvent } from '../../dispatcher/dispatch-actions/threa
|
||||||
import { fetchInitialEvent } from "../../utils/EventUtils";
|
import { fetchInitialEvent } from "../../utils/EventUtils";
|
||||||
import { ComposerType } from "../../dispatcher/payloads/ComposerInsertPayload";
|
import { ComposerType } from "../../dispatcher/payloads/ComposerInsertPayload";
|
||||||
import AppsDrawer from '../views/rooms/AppsDrawer';
|
import AppsDrawer from '../views/rooms/AppsDrawer';
|
||||||
import { SetRightPanelPhasePayload } from '../../dispatcher/payloads/SetRightPanelPhasePayload';
|
import { RightPanelPhases } from '../../stores/right-panel/RightPanelStorePhases';
|
||||||
import { RightPanelPhases } from '../../stores/RightPanelStorePhases';
|
|
||||||
|
|
||||||
const DEBUG = false;
|
const DEBUG = false;
|
||||||
let debuglog = function(msg: string) {};
|
let debuglog = function(msg: string) {};
|
||||||
|
@ -214,7 +213,6 @@ export interface IRoomState {
|
||||||
export class RoomView extends React.Component<IRoomProps, IRoomState> {
|
export class RoomView extends React.Component<IRoomProps, IRoomState> {
|
||||||
private readonly dispatcherRef: string;
|
private readonly dispatcherRef: string;
|
||||||
private readonly roomStoreToken: EventSubscription;
|
private readonly roomStoreToken: EventSubscription;
|
||||||
private readonly rightPanelStoreToken: EventSubscription;
|
|
||||||
private settingWatchers: string[];
|
private settingWatchers: string[];
|
||||||
|
|
||||||
private unmounted = false;
|
private unmounted = false;
|
||||||
|
@ -246,7 +244,7 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
|
||||||
canPeek: false,
|
canPeek: false,
|
||||||
showApps: false,
|
showApps: false,
|
||||||
isPeeking: false,
|
isPeeking: false,
|
||||||
showRightPanel: RightPanelStore.getSharedInstance().isOpenForRoom,
|
showRightPanel: RightPanelStore.instance.isOpenForRoom,
|
||||||
joining: false,
|
joining: false,
|
||||||
atEndOfLiveTimeline: true,
|
atEndOfLiveTimeline: true,
|
||||||
atEndOfLiveTimelineInit: false,
|
atEndOfLiveTimelineInit: false,
|
||||||
|
@ -289,7 +287,8 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
|
||||||
this.context.on("Event.decrypted", this.onEventDecrypted);
|
this.context.on("Event.decrypted", this.onEventDecrypted);
|
||||||
// Start listening for RoomViewStore updates
|
// Start listening for RoomViewStore updates
|
||||||
this.roomStoreToken = RoomViewStore.addListener(this.onRoomViewStoreUpdate);
|
this.roomStoreToken = RoomViewStore.addListener(this.onRoomViewStoreUpdate);
|
||||||
this.rightPanelStoreToken = RightPanelStore.getSharedInstance().addListener(this.onRightPanelStoreUpdate);
|
|
||||||
|
RightPanelStore.instance.on(UPDATE_EVENT, this.onRightPanelStoreUpdate);
|
||||||
|
|
||||||
WidgetEchoStore.on(UPDATE_EVENT, this.onWidgetEchoStoreUpdate);
|
WidgetEchoStore.on(UPDATE_EVENT, this.onWidgetEchoStoreUpdate);
|
||||||
WidgetStore.instance.on(UPDATE_EVENT, this.onWidgetStoreUpdate);
|
WidgetStore.instance.on(UPDATE_EVENT, this.onWidgetStoreUpdate);
|
||||||
|
@ -337,13 +336,9 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
|
||||||
});
|
});
|
||||||
if (WidgetLayoutStore.instance.hasMaximisedWidget(this.state.room)) {
|
if (WidgetLayoutStore.instance.hasMaximisedWidget(this.state.room)) {
|
||||||
// Show chat in right panel when a widget is maximised
|
// Show chat in right panel when a widget is maximised
|
||||||
dis.dispatch<SetRightPanelPhasePayload>({
|
RightPanelStore.instance.setCard({ phase: RightPanelPhases.Timeline });
|
||||||
action: Action.SetRightPanelPhase,
|
|
||||||
phase: RightPanelPhases.Timeline,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
this.checkWidgets(this.state.room);
|
this.checkWidgets(this.state.room);
|
||||||
this.checkRightPanel(this.state.room);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
private checkWidgets = (room) => {
|
private checkWidgets = (room) => {
|
||||||
|
@ -361,22 +356,6 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
|
||||||
: MainSplitContentType.Timeline;
|
: MainSplitContentType.Timeline;
|
||||||
};
|
};
|
||||||
|
|
||||||
private checkRightPanel = (room) => {
|
|
||||||
// This is a hack to hide the chat. This should not be necessary once the right panel
|
|
||||||
// phase is stored per room. (need to be done after check widget so that mainSplitContentType is updated)
|
|
||||||
if (
|
|
||||||
RightPanelStore.getSharedInstance().roomPanelPhase === RightPanelPhases.Timeline &&
|
|
||||||
this.state.showRightPanel &&
|
|
||||||
!WidgetLayoutStore.instance.hasMaximisedWidget(this.state.room)
|
|
||||||
) {
|
|
||||||
// Two timelines are shown prevent this by hiding the right panel
|
|
||||||
dis.dispatch({
|
|
||||||
action: Action.ToggleRightPanel,
|
|
||||||
type: "room",
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
private onReadReceiptsChange = () => {
|
private onReadReceiptsChange = () => {
|
||||||
this.setState({
|
this.setState({
|
||||||
showReadReceipts: SettingsStore.getValue("showReadReceipts", this.state.roomId),
|
showReadReceipts: SettingsStore.getValue("showReadReceipts", this.state.roomId),
|
||||||
|
@ -754,11 +733,8 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
|
||||||
if (this.roomStoreToken) {
|
if (this.roomStoreToken) {
|
||||||
this.roomStoreToken.remove();
|
this.roomStoreToken.remove();
|
||||||
}
|
}
|
||||||
// Remove RightPanelStore listener
|
|
||||||
if (this.rightPanelStoreToken) {
|
|
||||||
this.rightPanelStoreToken.remove();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
RightPanelStore.instance.off(UPDATE_EVENT, this.onRightPanelStoreUpdate);
|
||||||
WidgetEchoStore.removeListener(UPDATE_EVENT, this.onWidgetEchoStoreUpdate);
|
WidgetEchoStore.removeListener(UPDATE_EVENT, this.onWidgetEchoStoreUpdate);
|
||||||
WidgetStore.instance.removeListener(UPDATE_EVENT, this.onWidgetStoreUpdate);
|
WidgetStore.instance.removeListener(UPDATE_EVENT, this.onWidgetStoreUpdate);
|
||||||
|
|
||||||
|
@ -793,7 +769,7 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
|
||||||
|
|
||||||
private onRightPanelStoreUpdate = () => {
|
private onRightPanelStoreUpdate = () => {
|
||||||
this.setState({
|
this.setState({
|
||||||
showRightPanel: RightPanelStore.getSharedInstance().isOpenForRoom,
|
showRightPanel: RightPanelStore.instance.isOpenForRoom,
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1039,7 +1015,6 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
|
||||||
this.updateE2EStatus(room);
|
this.updateE2EStatus(room);
|
||||||
this.updatePermissions(room);
|
this.updatePermissions(room);
|
||||||
this.checkWidgets(room);
|
this.checkWidgets(room);
|
||||||
this.checkRightPanel(room);
|
|
||||||
|
|
||||||
this.setState({
|
this.setState({
|
||||||
liveTimeline: room.getLiveTimeline(),
|
liveTimeline: room.getLiveTimeline(),
|
||||||
|
|
|
@ -18,7 +18,6 @@ import React, { RefObject, useContext, useRef, useState } from "react";
|
||||||
import { EventType } from "matrix-js-sdk/src/@types/event";
|
import { EventType } from "matrix-js-sdk/src/@types/event";
|
||||||
import { JoinRule, Preset } from "matrix-js-sdk/src/@types/partials";
|
import { JoinRule, Preset } from "matrix-js-sdk/src/@types/partials";
|
||||||
import { Room } from "matrix-js-sdk/src/models/room";
|
import { Room } from "matrix-js-sdk/src/models/room";
|
||||||
import { EventSubscription } from "fbemitter";
|
|
||||||
import { logger } from "matrix-js-sdk/src/logger";
|
import { logger } from "matrix-js-sdk/src/logger";
|
||||||
|
|
||||||
import MatrixClientContext from "../../contexts/MatrixClientContext";
|
import MatrixClientContext from "../../contexts/MatrixClientContext";
|
||||||
|
@ -43,9 +42,8 @@ import MainSplit from './MainSplit';
|
||||||
import ErrorBoundary from "../views/elements/ErrorBoundary";
|
import ErrorBoundary from "../views/elements/ErrorBoundary";
|
||||||
import { ActionPayload } from "../../dispatcher/payloads";
|
import { ActionPayload } from "../../dispatcher/payloads";
|
||||||
import RightPanel from "./RightPanel";
|
import RightPanel from "./RightPanel";
|
||||||
import RightPanelStore from "../../stores/RightPanelStore";
|
import RightPanelStore from "../../stores/right-panel/RightPanelStore";
|
||||||
import { RightPanelPhases } from "../../stores/RightPanelStorePhases";
|
import { RightPanelPhases } from "../../stores/right-panel/RightPanelStorePhases";
|
||||||
import { SetRightPanelPhasePayload } from "../../dispatcher/payloads/SetRightPanelPhasePayload";
|
|
||||||
import { useStateArray } from "../../hooks/useStateArray";
|
import { useStateArray } from "../../hooks/useStateArray";
|
||||||
import SpacePublicShare from "../views/spaces/SpacePublicShare";
|
import SpacePublicShare from "../views/spaces/SpacePublicShare";
|
||||||
import {
|
import {
|
||||||
|
@ -85,6 +83,7 @@ import { useDispatcher } from "../../hooks/useDispatcher";
|
||||||
import { useRoomState } from "../../hooks/useRoomState";
|
import { useRoomState } from "../../hooks/useRoomState";
|
||||||
import { shouldShowComponent } from "../../customisations/helpers/UIComponents";
|
import { shouldShowComponent } from "../../customisations/helpers/UIComponents";
|
||||||
import { UIComponent } from "../../settings/UIFeature";
|
import { UIComponent } from "../../settings/UIFeature";
|
||||||
|
import { UPDATE_EVENT } from "../../stores/AsyncStore";
|
||||||
|
|
||||||
interface IProps {
|
interface IProps {
|
||||||
space: Room;
|
space: Room;
|
||||||
|
@ -164,10 +163,9 @@ const SpaceInfo = ({ space }: { space: Room }) => {
|
||||||
kind="link"
|
kind="link"
|
||||||
className="mx_SpaceRoomView_info_memberCount"
|
className="mx_SpaceRoomView_info_memberCount"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
defaultDispatcher.dispatch<SetRightPanelPhasePayload>({
|
RightPanelStore.instance.setCard({
|
||||||
action: Action.SetRightPanelPhase,
|
|
||||||
phase: RightPanelPhases.RoomMemberList,
|
phase: RightPanelPhases.RoomMemberList,
|
||||||
refireParams: { space },
|
state: { spaceId: space.roomId },
|
||||||
});
|
});
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
|
@ -473,11 +471,7 @@ const SpaceLanding = ({ space }: { space: Room }) => {
|
||||||
}
|
}
|
||||||
|
|
||||||
const onMembersClick = () => {
|
const onMembersClick = () => {
|
||||||
defaultDispatcher.dispatch<SetRightPanelPhasePayload>({
|
RightPanelStore.instance.setCard({ phase: RightPanelPhases.RoomMemberList, state: { spaceId: space.roomId } });
|
||||||
action: Action.SetRightPanelPhase,
|
|
||||||
phase: RightPanelPhases.RoomMemberList,
|
|
||||||
refireParams: { space },
|
|
||||||
});
|
|
||||||
};
|
};
|
||||||
|
|
||||||
return <div className="mx_SpaceRoomView_landing">
|
return <div className="mx_SpaceRoomView_landing">
|
||||||
|
@ -796,7 +790,6 @@ export default class SpaceRoomView extends React.PureComponent<IProps, IState> {
|
||||||
|
|
||||||
private readonly creator: string;
|
private readonly creator: string;
|
||||||
private readonly dispatcherRef: string;
|
private readonly dispatcherRef: string;
|
||||||
private readonly rightPanelStoreToken: EventSubscription;
|
|
||||||
|
|
||||||
constructor(props, context) {
|
constructor(props, context) {
|
||||||
super(props, context);
|
super(props, context);
|
||||||
|
@ -813,18 +806,18 @@ export default class SpaceRoomView extends React.PureComponent<IProps, IState> {
|
||||||
|
|
||||||
this.state = {
|
this.state = {
|
||||||
phase,
|
phase,
|
||||||
showRightPanel: RightPanelStore.getSharedInstance().isOpenForRoom,
|
showRightPanel: RightPanelStore.instance.isOpenForRoom,
|
||||||
myMembership: this.props.space.getMyMembership(),
|
myMembership: this.props.space.getMyMembership(),
|
||||||
};
|
};
|
||||||
|
|
||||||
this.dispatcherRef = defaultDispatcher.register(this.onAction);
|
this.dispatcherRef = defaultDispatcher.register(this.onAction);
|
||||||
this.rightPanelStoreToken = RightPanelStore.getSharedInstance().addListener(this.onRightPanelStoreUpdate);
|
RightPanelStore.instance.on(UPDATE_EVENT, this.onRightPanelStoreUpdate);
|
||||||
this.context.on("Room.myMembership", this.onMyMembership);
|
this.context.on("Room.myMembership", this.onMyMembership);
|
||||||
}
|
}
|
||||||
|
|
||||||
componentWillUnmount() {
|
componentWillUnmount() {
|
||||||
defaultDispatcher.unregister(this.dispatcherRef);
|
defaultDispatcher.unregister(this.dispatcherRef);
|
||||||
this.rightPanelStoreToken.remove();
|
RightPanelStore.instance.off(UPDATE_EVENT, this.onRightPanelStoreUpdate);
|
||||||
this.context.off("Room.myMembership", this.onMyMembership);
|
this.context.off("Room.myMembership", this.onMyMembership);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -836,7 +829,7 @@ export default class SpaceRoomView extends React.PureComponent<IProps, IState> {
|
||||||
|
|
||||||
private onRightPanelStoreUpdate = () => {
|
private onRightPanelStoreUpdate = () => {
|
||||||
this.setState({
|
this.setState({
|
||||||
showRightPanel: RightPanelStore.getSharedInstance().isOpenForRoom,
|
showRightPanel: RightPanelStore.instance.isOpenForRoom,
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -849,28 +842,19 @@ export default class SpaceRoomView extends React.PureComponent<IProps, IState> {
|
||||||
if (payload.action !== Action.ViewUser && payload.action !== "view_3pid_invite") return;
|
if (payload.action !== Action.ViewUser && payload.action !== "view_3pid_invite") return;
|
||||||
|
|
||||||
if (payload.action === Action.ViewUser && payload.member) {
|
if (payload.action === Action.ViewUser && payload.member) {
|
||||||
defaultDispatcher.dispatch<SetRightPanelPhasePayload>({
|
RightPanelStore.instance.setCard({
|
||||||
action: Action.SetRightPanelPhase,
|
|
||||||
phase: RightPanelPhases.SpaceMemberInfo,
|
phase: RightPanelPhases.SpaceMemberInfo,
|
||||||
refireParams: {
|
state: { spaceId: this.props.space.roomId, member: payload.member },
|
||||||
space: this.props.space,
|
|
||||||
member: payload.member,
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
} else if (payload.action === "view_3pid_invite" && payload.event) {
|
} else if (payload.action === "view_3pid_invite" && payload.event) {
|
||||||
defaultDispatcher.dispatch<SetRightPanelPhasePayload>({
|
RightPanelStore.instance.setCard({
|
||||||
action: Action.SetRightPanelPhase,
|
|
||||||
phase: RightPanelPhases.Space3pidMemberInfo,
|
phase: RightPanelPhases.Space3pidMemberInfo,
|
||||||
refireParams: {
|
state: { spaceId: this.props.space.roomId, member: payload.member },
|
||||||
space: this.props.space,
|
|
||||||
event: payload.event,
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
defaultDispatcher.dispatch<SetRightPanelPhasePayload>({
|
RightPanelStore.instance.setCard({
|
||||||
action: Action.SetRightPanelPhase,
|
|
||||||
phase: RightPanelPhases.SpaceMemberList,
|
phase: RightPanelPhases.SpaceMemberList,
|
||||||
refireParams: { space: this.props.space },
|
state: { spaceId: this.props.space.roomId },
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -20,7 +20,7 @@ import { Thread, ThreadEvent } from 'matrix-js-sdk/src/models/thread';
|
||||||
import { RelationType } from 'matrix-js-sdk/src/@types/event';
|
import { RelationType } from 'matrix-js-sdk/src/@types/event';
|
||||||
|
|
||||||
import BaseCard from "../views/right_panel/BaseCard";
|
import BaseCard from "../views/right_panel/BaseCard";
|
||||||
import { RightPanelPhases } from "../../stores/RightPanelStorePhases";
|
import { RightPanelPhases } from "../../stores/right-panel/RightPanelStorePhases";
|
||||||
import { replaceableComponent } from "../../utils/replaceableComponent";
|
import { replaceableComponent } from "../../utils/replaceableComponent";
|
||||||
import ResizeNotifier from '../../utils/ResizeNotifier';
|
import ResizeNotifier from '../../utils/ResizeNotifier';
|
||||||
import { TileShape } from '../views/rooms/EventTile';
|
import { TileShape } from '../views/rooms/EventTile';
|
||||||
|
@ -30,7 +30,6 @@ import { Layout } from '../../settings/enums/Layout';
|
||||||
import TimelinePanel from './TimelinePanel';
|
import TimelinePanel from './TimelinePanel';
|
||||||
import dis from "../../dispatcher/dispatcher";
|
import dis from "../../dispatcher/dispatcher";
|
||||||
import { ActionPayload } from '../../dispatcher/payloads';
|
import { ActionPayload } from '../../dispatcher/payloads';
|
||||||
import { SetRightPanelPhasePayload } from '../../dispatcher/payloads/SetRightPanelPhasePayload';
|
|
||||||
import { Action } from '../../dispatcher/actions';
|
import { Action } from '../../dispatcher/actions';
|
||||||
import { MatrixClientPeg } from '../../MatrixClientPeg';
|
import { MatrixClientPeg } from '../../MatrixClientPeg';
|
||||||
import { E2EStatus } from '../../utils/ShieldUtils';
|
import { E2EStatus } from '../../utils/ShieldUtils';
|
||||||
|
@ -40,7 +39,7 @@ import ContentMessages from '../../ContentMessages';
|
||||||
import UploadBar from './UploadBar';
|
import UploadBar from './UploadBar';
|
||||||
import { _t } from '../../languageHandler';
|
import { _t } from '../../languageHandler';
|
||||||
import ThreadListContextMenu from '../views/context_menus/ThreadListContextMenu';
|
import ThreadListContextMenu from '../views/context_menus/ThreadListContextMenu';
|
||||||
import RightPanelStore from '../../stores/RightPanelStore';
|
import RightPanelStore from '../../stores/right-panel/RightPanelStore';
|
||||||
import SettingsStore from '../../settings/SettingsStore';
|
import SettingsStore from '../../settings/SettingsStore';
|
||||||
import { WidgetLayoutStore } from '../../stores/widgets/WidgetLayoutStore';
|
import { WidgetLayoutStore } from '../../stores/widgets/WidgetLayoutStore';
|
||||||
|
|
||||||
|
@ -52,7 +51,7 @@ interface IProps {
|
||||||
permalinkCreator?: RoomPermalinkCreator;
|
permalinkCreator?: RoomPermalinkCreator;
|
||||||
e2eStatus?: E2EStatus;
|
e2eStatus?: E2EStatus;
|
||||||
initialEvent?: MatrixEvent;
|
initialEvent?: MatrixEvent;
|
||||||
initialEventHighlighted?: boolean;
|
isInitialEventHighlighted?: boolean;
|
||||||
}
|
}
|
||||||
interface IState {
|
interface IState {
|
||||||
thread?: Thread;
|
thread?: Thread;
|
||||||
|
@ -94,10 +93,7 @@ export default class ThreadView extends React.Component<IProps, IState> {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (prevProps.room !== this.props.room) {
|
if (prevProps.room !== this.props.room) {
|
||||||
dis.dispatch<SetRightPanelPhasePayload>({
|
RightPanelStore.instance.setCard({ phase: RightPanelPhases.RoomSummary });
|
||||||
action: Action.SetRightPanelPhase,
|
|
||||||
phase: RightPanelPhases.RoomSummary,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -168,7 +164,7 @@ export default class ThreadView extends React.Component<IProps, IState> {
|
||||||
};
|
};
|
||||||
|
|
||||||
private onScroll = (): void => {
|
private onScroll = (): void => {
|
||||||
if (this.props.initialEvent && this.props.initialEventHighlighted) {
|
if (this.props.initialEvent && this.props.isInitialEventHighlighted) {
|
||||||
dis.dispatch({
|
dis.dispatch({
|
||||||
action: Action.ViewRoom,
|
action: Action.ViewRoom,
|
||||||
room_id: this.props.room.roomId,
|
room_id: this.props.room.roomId,
|
||||||
|
@ -189,7 +185,7 @@ export default class ThreadView extends React.Component<IProps, IState> {
|
||||||
};
|
};
|
||||||
|
|
||||||
public render(): JSX.Element {
|
public render(): JSX.Element {
|
||||||
const highlightedEventId = this.props.initialEventHighlighted
|
const highlightedEventId = this.props.isInitialEventHighlighted
|
||||||
? this.props.initialEvent?.getId()
|
? this.props.initialEvent?.getId()
|
||||||
: null;
|
: null;
|
||||||
|
|
||||||
|
@ -198,7 +194,7 @@ export default class ThreadView extends React.Component<IProps, IState> {
|
||||||
event_id: this.state.thread?.id,
|
event_id: this.state.thread?.id,
|
||||||
};
|
};
|
||||||
|
|
||||||
let previousPhase = RightPanelStore.getSharedInstance().previousPhase;
|
let previousPhase = RightPanelStore.instance.previousCard.phase;
|
||||||
if (!SettingsStore.getValue("feature_maximised_widgets")) {
|
if (!SettingsStore.getValue("feature_maximised_widgets")) {
|
||||||
previousPhase = RightPanelPhases.ThreadPanel;
|
previousPhase = RightPanelPhases.ThreadPanel;
|
||||||
}
|
}
|
||||||
|
|
|
@ -680,6 +680,7 @@ class TimelinePanel extends React.Component<IProps, IState> {
|
||||||
};
|
};
|
||||||
|
|
||||||
private onSync = (clientSyncState: SyncState, prevState: SyncState, data: object): void => {
|
private onSync = (clientSyncState: SyncState, prevState: SyncState, data: object): void => {
|
||||||
|
if (this.unmounted) return;
|
||||||
this.setState({ clientSyncState });
|
this.setState({ clientSyncState });
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -29,6 +29,7 @@ import MainSplit from "./MainSplit";
|
||||||
import RightPanel from "./RightPanel";
|
import RightPanel from "./RightPanel";
|
||||||
import Spinner from "../views/elements/Spinner";
|
import Spinner from "../views/elements/Spinner";
|
||||||
import ResizeNotifier from "../../utils/ResizeNotifier";
|
import ResizeNotifier from "../../utils/ResizeNotifier";
|
||||||
|
import { RightPanelPhases } from "../../stores/right-panel/RightPanelStorePhases";
|
||||||
|
|
||||||
interface IProps {
|
interface IProps {
|
||||||
userId?: string;
|
userId?: string;
|
||||||
|
@ -88,7 +89,10 @@ export default class UserView extends React.Component<IProps, IState> {
|
||||||
if (this.state.loading) {
|
if (this.state.loading) {
|
||||||
return <Spinner />;
|
return <Spinner />;
|
||||||
} else if (this.state.member) {
|
} else if (this.state.member) {
|
||||||
const panel = <RightPanel member={this.state.member} resizeNotifier={this.props.resizeNotifier} />;
|
const panel = <RightPanel
|
||||||
|
overwriteCard={{ phase: RightPanelPhases.RoomMemberInfo, state: { member: this.state.member } }}
|
||||||
|
resizeNotifier={this.props.resizeNotifier}
|
||||||
|
/>;
|
||||||
return (<MainSplit panel={panel} resizeNotifier={this.props.resizeNotifier}>
|
return (<MainSplit panel={panel} resizeNotifier={this.props.resizeNotifier}>
|
||||||
<HomePage />
|
<HomePage />
|
||||||
</MainSplit>);
|
</MainSplit>);
|
||||||
|
|
|
@ -38,12 +38,10 @@ import Modal from "../../../Modal";
|
||||||
import ExportDialog from "../dialogs/ExportDialog";
|
import ExportDialog from "../dialogs/ExportDialog";
|
||||||
import { onRoomFilesClick, onRoomMembersClick } from "../right_panel/RoomSummaryCard";
|
import { onRoomFilesClick, onRoomMembersClick } from "../right_panel/RoomSummaryCard";
|
||||||
import RoomViewStore from "../../../stores/RoomViewStore";
|
import RoomViewStore from "../../../stores/RoomViewStore";
|
||||||
import defaultDispatcher from "../../../dispatcher/dispatcher";
|
import { RightPanelPhases } from '../../../stores/right-panel/RightPanelStorePhases';
|
||||||
import { SetRightPanelPhasePayload } from "../../../dispatcher/payloads/SetRightPanelPhasePayload";
|
|
||||||
import { Action } from "../../../dispatcher/actions";
|
|
||||||
import { RightPanelPhases } from "../../../stores/RightPanelStorePhases";
|
|
||||||
import { ROOM_NOTIFICATIONS_TAB } from "../dialogs/RoomSettingsDialog";
|
import { ROOM_NOTIFICATIONS_TAB } from "../dialogs/RoomSettingsDialog";
|
||||||
import { useEventEmitterState } from "../../../hooks/useEventEmitter";
|
import { useEventEmitterState } from "../../../hooks/useEventEmitter";
|
||||||
|
import RightPanelStore from "../../../stores/right-panel/RightPanelStore";
|
||||||
import DMRoomMap from "../../../utils/DMRoomMap";
|
import DMRoomMap from "../../../utils/DMRoomMap";
|
||||||
|
|
||||||
interface IProps extends IContextMenuProps {
|
interface IProps extends IContextMenuProps {
|
||||||
|
@ -272,11 +270,7 @@ const RoomContextMenu = ({ room, onFinished, ...props }: IProps) => {
|
||||||
ev.stopPropagation();
|
ev.stopPropagation();
|
||||||
|
|
||||||
ensureViewingRoom();
|
ensureViewingRoom();
|
||||||
defaultDispatcher.dispatch<SetRightPanelPhasePayload>({
|
RightPanelStore.instance.setCard({ phase: RightPanelPhases.RoomSummary }, false);
|
||||||
action: Action.SetRightPanelPhase,
|
|
||||||
phase: RightPanelPhases.RoomSummary,
|
|
||||||
allowClose: false,
|
|
||||||
});
|
|
||||||
onFinished();
|
onFinished();
|
||||||
}}
|
}}
|
||||||
label={_t("Widgets")}
|
label={_t("Widgets")}
|
||||||
|
|
|
@ -26,19 +26,13 @@ import { formatCommaSeparatedList } from '../../../utils/FormattingUtils';
|
||||||
import { isValid3pidInvite } from "../../../RoomInvite";
|
import { isValid3pidInvite } from "../../../RoomInvite";
|
||||||
import EventListSummary from "./EventListSummary";
|
import EventListSummary from "./EventListSummary";
|
||||||
import { replaceableComponent } from "../../../utils/replaceableComponent";
|
import { replaceableComponent } from "../../../utils/replaceableComponent";
|
||||||
import defaultDispatcher from '../../../dispatcher/dispatcher';
|
import { RightPanelPhases } from '../../../stores/right-panel/RightPanelStorePhases';
|
||||||
import { RightPanelPhases } from '../../../stores/RightPanelStorePhases';
|
|
||||||
import { Action } from '../../../dispatcher/actions';
|
|
||||||
import { SetRightPanelPhasePayload } from '../../../dispatcher/payloads/SetRightPanelPhasePayload';
|
|
||||||
import { jsxJoin } from '../../../utils/ReactUtils';
|
import { jsxJoin } from '../../../utils/ReactUtils';
|
||||||
import { Layout } from '../../../settings/enums/Layout';
|
import { Layout } from '../../../settings/enums/Layout';
|
||||||
|
import RightPanelStore from '../../../stores/right-panel/RightPanelStore';
|
||||||
|
|
||||||
const onPinnedMessagesClick = (): void => {
|
const onPinnedMessagesClick = (): void => {
|
||||||
defaultDispatcher.dispatch<SetRightPanelPhasePayload>({
|
RightPanelStore.instance.setCard({ phase: RightPanelPhases.PinnedMessages }, false);
|
||||||
action: Action.SetRightPanelPhase,
|
|
||||||
phase: RightPanelPhases.PinnedMessages,
|
|
||||||
allowClose: false,
|
|
||||||
});
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const SENDER_AS_DISPLAY_NAME_EVENTS = [EventType.RoomServerAcl, EventType.RoomPinnedEvents];
|
const SENDER_AS_DISPLAY_NAME_EVENTS = [EventType.RoomServerAcl, EventType.RoomPinnedEvents];
|
||||||
|
|
|
@ -20,14 +20,13 @@ import PropTypes from 'prop-types';
|
||||||
|
|
||||||
import { _t } from '../../../languageHandler';
|
import { _t } from '../../../languageHandler';
|
||||||
import * as sdk from '../../../index';
|
import * as sdk from '../../../index';
|
||||||
import dis from '../../../dispatcher/dispatcher';
|
|
||||||
import GroupStore from '../../../stores/GroupStore';
|
import GroupStore from '../../../stores/GroupStore';
|
||||||
import { showGroupInviteDialog } from '../../../GroupAddressPicker';
|
import { showGroupInviteDialog } from '../../../GroupAddressPicker';
|
||||||
import AccessibleButton from '../elements/AccessibleButton';
|
import AccessibleButton from '../elements/AccessibleButton';
|
||||||
import { RightPanelPhases } from "../../../stores/RightPanelStorePhases";
|
import { RightPanelPhases } from '../../../stores/right-panel/RightPanelStorePhases';
|
||||||
import AutoHideScrollbar from "../../structures/AutoHideScrollbar";
|
import AutoHideScrollbar from "../../structures/AutoHideScrollbar";
|
||||||
import { Action } from "../../../dispatcher/actions";
|
|
||||||
import { replaceableComponent } from "../../../utils/replaceableComponent";
|
import { replaceableComponent } from "../../../utils/replaceableComponent";
|
||||||
|
import RightPanelStore from '../../../stores/right-panel/RightPanelStore';
|
||||||
|
|
||||||
const INITIAL_LOAD_NUM_MEMBERS = 30;
|
const INITIAL_LOAD_NUM_MEMBERS = 30;
|
||||||
|
|
||||||
|
@ -170,10 +169,9 @@ export default class GroupMemberList extends React.Component {
|
||||||
|
|
||||||
onInviteToGroupButtonClick = () => {
|
onInviteToGroupButtonClick = () => {
|
||||||
showGroupInviteDialog(this.props.groupId).then(() => {
|
showGroupInviteDialog(this.props.groupId).then(() => {
|
||||||
dis.dispatch({
|
RightPanelStore.instance.setCard({
|
||||||
action: Action.SetRightPanelPhase,
|
|
||||||
phase: RightPanelPhases.GroupMemberList,
|
phase: RightPanelPhases.GroupMemberList,
|
||||||
refireParams: { groupId: this.props.groupId },
|
state: { groupId: this.props.groupId },
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
|
@ -22,12 +22,11 @@ import { MatrixClientPeg } from '../../../MatrixClientPeg';
|
||||||
import { _t } from '../../../languageHandler';
|
import { _t } from '../../../languageHandler';
|
||||||
import { getNameForEventRoom, userLabelForEventRoom }
|
import { getNameForEventRoom, userLabelForEventRoom }
|
||||||
from '../../../utils/KeyVerificationStateObserver';
|
from '../../../utils/KeyVerificationStateObserver';
|
||||||
import dis from "../../../dispatcher/dispatcher";
|
import { RightPanelPhases } from '../../../stores/right-panel/RightPanelStorePhases';
|
||||||
import { RightPanelPhases } from "../../../stores/RightPanelStorePhases";
|
|
||||||
import { Action } from "../../../dispatcher/actions";
|
|
||||||
import EventTileBubble from "./EventTileBubble";
|
import EventTileBubble from "./EventTileBubble";
|
||||||
import { replaceableComponent } from "../../../utils/replaceableComponent";
|
import { replaceableComponent } from "../../../utils/replaceableComponent";
|
||||||
import AccessibleButton from '../elements/AccessibleButton';
|
import AccessibleButton from '../elements/AccessibleButton';
|
||||||
|
import RightPanelStore from '../../../stores/right-panel/RightPanelStore';
|
||||||
|
|
||||||
interface IProps {
|
interface IProps {
|
||||||
mxEvent: MatrixEvent;
|
mxEvent: MatrixEvent;
|
||||||
|
@ -52,10 +51,9 @@ export default class MKeyVerificationRequest extends React.Component<IProps> {
|
||||||
private openRequest = () => {
|
private openRequest = () => {
|
||||||
const { verificationRequest } = this.props.mxEvent;
|
const { verificationRequest } = this.props.mxEvent;
|
||||||
const member = MatrixClientPeg.get().getUser(verificationRequest.otherUserId);
|
const member = MatrixClientPeg.get().getUser(verificationRequest.otherUserId);
|
||||||
dis.dispatch({
|
RightPanelStore.instance.setCard({
|
||||||
action: Action.SetRightPanelPhase,
|
|
||||||
phase: RightPanelPhases.EncryptionPanel,
|
phase: RightPanelPhases.EncryptionPanel,
|
||||||
refireParams: { verificationRequest, member },
|
state: { verificationRequest, member },
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -20,10 +20,8 @@ import classNames from 'classnames';
|
||||||
import AutoHideScrollbar from "../../structures/AutoHideScrollbar";
|
import AutoHideScrollbar from "../../structures/AutoHideScrollbar";
|
||||||
import { _t } from "../../../languageHandler";
|
import { _t } from "../../../languageHandler";
|
||||||
import AccessibleButton from "../elements/AccessibleButton";
|
import AccessibleButton from "../elements/AccessibleButton";
|
||||||
import defaultDispatcher from "../../../dispatcher/dispatcher";
|
import { RightPanelPhases } from '../../../stores/right-panel/RightPanelStorePhases';
|
||||||
import { SetRightPanelPhasePayload } from "../../../dispatcher/payloads/SetRightPanelPhasePayload";
|
import RightPanelStore from '../../../stores/right-panel/RightPanelStore';
|
||||||
import { Action } from "../../../dispatcher/actions";
|
|
||||||
import { RightPanelPhases } from "../../../stores/RightPanelStorePhases";
|
|
||||||
|
|
||||||
interface IProps {
|
interface IProps {
|
||||||
header?: ReactNode;
|
header?: ReactNode;
|
||||||
|
@ -34,7 +32,7 @@ interface IProps {
|
||||||
previousPhaseLabel?: string;
|
previousPhaseLabel?: string;
|
||||||
closeLabel?: string;
|
closeLabel?: string;
|
||||||
onClose?(): void;
|
onClose?(): void;
|
||||||
refireParams?;
|
cardState?;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface IGroupProps {
|
interface IGroupProps {
|
||||||
|
@ -59,16 +57,15 @@ const BaseCard: React.FC<IProps> = ({
|
||||||
previousPhase,
|
previousPhase,
|
||||||
previousPhaseLabel,
|
previousPhaseLabel,
|
||||||
children,
|
children,
|
||||||
refireParams,
|
cardState,
|
||||||
}) => {
|
}) => {
|
||||||
let backButton;
|
let backButton;
|
||||||
if (previousPhase) {
|
if (previousPhase) {
|
||||||
const onBackClick = () => {
|
const onBackClick = () => {
|
||||||
defaultDispatcher.dispatch<SetRightPanelPhasePayload>({
|
// TODO RightPanelStore (will be addressed in a follow up PR): this should ideally be:
|
||||||
action: Action.SetRightPanelPhase,
|
// RightPanelStore.instance.popRightPanel();
|
||||||
phase: previousPhase,
|
|
||||||
refireParams: refireParams,
|
RightPanelStore.instance.setCard({ phase: previousPhase, state: cardState });
|
||||||
});
|
|
||||||
};
|
};
|
||||||
const label = previousPhaseLabel ?? _t("Back");
|
const label = previousPhaseLabel ?? _t("Back");
|
||||||
backButton = <AccessibleButton className="mx_BaseCard_back" onClick={onBackClick} title={label} />;
|
backButton = <AccessibleButton className="mx_BaseCard_back" onClick={onBackClick} title={label} />;
|
||||||
|
|
|
@ -31,9 +31,8 @@ import { useEventEmitter } from "../../../hooks/useEventEmitter";
|
||||||
import Modal from "../../../Modal";
|
import Modal from "../../../Modal";
|
||||||
import * as sdk from "../../../index";
|
import * as sdk from "../../../index";
|
||||||
import { _t } from "../../../languageHandler";
|
import { _t } from "../../../languageHandler";
|
||||||
import dis from "../../../dispatcher/dispatcher";
|
import { RightPanelPhases } from '../../../stores/right-panel/RightPanelStorePhases';
|
||||||
import { Action } from "../../../dispatcher/actions";
|
import RightPanelStore from "../../../stores/right-panel/RightPanelStore";
|
||||||
import { RightPanelPhases } from "../../../stores/RightPanelStorePhases";
|
|
||||||
|
|
||||||
// cancellation codes which constitute a key mismatch
|
// cancellation codes which constitute a key mismatch
|
||||||
const MISMATCHES = ["m.key_mismatch", "m.user_error", "m.mismatched_sas"];
|
const MISMATCHES = ["m.key_mismatch", "m.user_error", "m.mismatched_sas"];
|
||||||
|
@ -117,10 +116,9 @@ const EncryptionPanel: React.FC<IProps> = (props: IProps) => {
|
||||||
setRequest(verificationRequest_);
|
setRequest(verificationRequest_);
|
||||||
setPhase(verificationRequest_.phase);
|
setPhase(verificationRequest_.phase);
|
||||||
// Notify the RightPanelStore about this
|
// Notify the RightPanelStore about this
|
||||||
dis.dispatch({
|
RightPanelStore.instance.setCard({
|
||||||
action: Action.SetRightPanelPhase,
|
|
||||||
phase: RightPanelPhases.EncryptionPanel,
|
phase: RightPanelPhases.EncryptionPanel,
|
||||||
refireParams: { member, verificationRequest: verificationRequest_ },
|
state: { member, verificationRequest: verificationRequest_ },
|
||||||
});
|
});
|
||||||
}, [member]);
|
}, [member]);
|
||||||
|
|
||||||
|
|
|
@ -23,7 +23,7 @@ import React from 'react';
|
||||||
import { _t } from '../../../languageHandler';
|
import { _t } from '../../../languageHandler';
|
||||||
import HeaderButton from './HeaderButton';
|
import HeaderButton from './HeaderButton';
|
||||||
import HeaderButtons, { HeaderKind } from './HeaderButtons';
|
import HeaderButtons, { HeaderKind } from './HeaderButtons';
|
||||||
import { RightPanelPhases } from "../../../stores/RightPanelStorePhases";
|
import { RightPanelPhases } from '../../../stores/right-panel/RightPanelStorePhases';
|
||||||
import { Action } from "../../../dispatcher/actions";
|
import { Action } from "../../../dispatcher/actions";
|
||||||
import { ActionPayload } from "../../../dispatcher/payloads";
|
import { ActionPayload } from "../../../dispatcher/payloads";
|
||||||
import { ViewUserPayload } from "../../../dispatcher/payloads/ViewUserPayload";
|
import { ViewUserPayload } from "../../../dispatcher/payloads/ViewUserPayload";
|
||||||
|
|
|
@ -21,15 +21,11 @@ limitations under the License.
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
|
||||||
import dis from '../../../dispatcher/dispatcher';
|
import dis from '../../../dispatcher/dispatcher';
|
||||||
import RightPanelStore from "../../../stores/RightPanelStore";
|
import RightPanelStore from "../../../stores/right-panel/RightPanelStore";
|
||||||
import { RightPanelPhases } from "../../../stores/RightPanelStorePhases";
|
import { RightPanelPhases } from '../../../stores/right-panel/RightPanelStorePhases';
|
||||||
import { Action } from '../../../dispatcher/actions';
|
import { IRightPanelCardState } from '../../../stores/right-panel/RightPanelStoreIPanelState';
|
||||||
import {
|
|
||||||
SetRightPanelPhasePayload,
|
|
||||||
SetRightPanelPhaseRefireParams,
|
|
||||||
} from '../../../dispatcher/payloads/SetRightPanelPhasePayload';
|
|
||||||
import type { EventSubscription } from "fbemitter";
|
|
||||||
import { replaceableComponent } from "../../../utils/replaceableComponent";
|
import { replaceableComponent } from "../../../utils/replaceableComponent";
|
||||||
|
import { UPDATE_EVENT } from '../../../stores/AsyncStore';
|
||||||
import { NotificationColor } from '../../../stores/notifications/NotificationColor';
|
import { NotificationColor } from '../../../stores/notifications/NotificationColor';
|
||||||
|
|
||||||
export enum HeaderKind {
|
export enum HeaderKind {
|
||||||
|
@ -47,38 +43,35 @@ interface IProps {}
|
||||||
|
|
||||||
@replaceableComponent("views.right_panel.HeaderButtons")
|
@replaceableComponent("views.right_panel.HeaderButtons")
|
||||||
export default abstract class HeaderButtons<P = {}> extends React.Component<IProps & P, IState> {
|
export default abstract class HeaderButtons<P = {}> extends React.Component<IProps & P, IState> {
|
||||||
private storeToken: EventSubscription;
|
private unmounted = false;
|
||||||
private dispatcherRef: string;
|
private dispatcherRef: string;
|
||||||
|
|
||||||
constructor(props: IProps & P, kind: HeaderKind) {
|
constructor(props: IProps & P, kind: HeaderKind) {
|
||||||
super(props);
|
super(props);
|
||||||
|
|
||||||
const rps = RightPanelStore.getSharedInstance();
|
const rps = RightPanelStore.instance;
|
||||||
this.state = {
|
this.state = {
|
||||||
headerKind: kind,
|
headerKind: kind,
|
||||||
|
phase: rps.currentCard.phase,
|
||||||
threadNotificationColor: NotificationColor.None,
|
threadNotificationColor: NotificationColor.None,
|
||||||
phase: kind === HeaderKind.Room ? rps.visibleRoomPanelPhase : rps.visibleGroupPanelPhase,
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
public componentDidMount() {
|
public componentDidMount() {
|
||||||
this.storeToken = RightPanelStore.getSharedInstance().addListener(this.onRightPanelUpdate.bind(this));
|
RightPanelStore.instance.on(UPDATE_EVENT, this.onRightPanelStoreUpdate);
|
||||||
this.dispatcherRef = dis.register(this.onAction.bind(this)); // used by subclasses
|
this.dispatcherRef = dis.register(this.onAction.bind(this)); // used by subclasses
|
||||||
}
|
}
|
||||||
|
|
||||||
public componentWillUnmount() {
|
public componentWillUnmount() {
|
||||||
if (this.storeToken) this.storeToken.remove();
|
this.unmounted = true;
|
||||||
|
RightPanelStore.instance.off(UPDATE_EVENT, this.onRightPanelStoreUpdate);
|
||||||
if (this.dispatcherRef) dis.unregister(this.dispatcherRef);
|
if (this.dispatcherRef) dis.unregister(this.dispatcherRef);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected abstract onAction(payload);
|
protected abstract onAction(payload);
|
||||||
|
|
||||||
public setPhase(phase: RightPanelPhases, extras?: Partial<SetRightPanelPhaseRefireParams>) {
|
public setPhase(phase: RightPanelPhases, cardState?: Partial<IRightPanelCardState>) {
|
||||||
dis.dispatch<SetRightPanelPhasePayload>({
|
RightPanelStore.instance.setCard({ phase, state: cardState });
|
||||||
action: Action.SetRightPanelPhase,
|
|
||||||
phase: phase,
|
|
||||||
refireParams: extras,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public isPhase(phases: string | string[]) {
|
public isPhase(phases: string | string[]) {
|
||||||
|
@ -89,14 +82,12 @@ export default abstract class HeaderButtons<P = {}> extends React.Component<IPro
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private onRightPanelUpdate() {
|
private onRightPanelStoreUpdate = () => {
|
||||||
const rps = RightPanelStore.getSharedInstance();
|
if (this.unmounted) return;
|
||||||
if (this.state.headerKind === HeaderKind.Room) {
|
let phase = RightPanelStore.instance.currentCard.phase;
|
||||||
this.setState({ phase: rps.visibleRoomPanelPhase });
|
if (!RightPanelStore.instance.isOpenForGroup) {phase = null;}
|
||||||
} else if (this.state.headerKind === HeaderKind.Group) {
|
this.setState({ phase });
|
||||||
this.setState({ phase: rps.visibleGroupPanelPhase });
|
};
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// XXX: Make renderButtons a prop
|
// XXX: Make renderButtons a prop
|
||||||
public abstract renderButtons(): JSX.Element;
|
public abstract renderButtons(): JSX.Element;
|
||||||
|
|
|
@ -25,16 +25,15 @@ import { Room } from "matrix-js-sdk/src/models/room";
|
||||||
import { _t } from '../../../languageHandler';
|
import { _t } from '../../../languageHandler';
|
||||||
import HeaderButton from './HeaderButton';
|
import HeaderButton from './HeaderButton';
|
||||||
import HeaderButtons, { HeaderKind } from './HeaderButtons';
|
import HeaderButtons, { HeaderKind } from './HeaderButtons';
|
||||||
import { RightPanelPhases } from "../../../stores/RightPanelStorePhases";
|
import { RightPanelPhases } from '../../../stores/right-panel/RightPanelStorePhases';
|
||||||
import { Action } from "../../../dispatcher/actions";
|
import { Action } from "../../../dispatcher/actions";
|
||||||
import { ActionPayload } from "../../../dispatcher/payloads";
|
import { ActionPayload } from "../../../dispatcher/payloads";
|
||||||
import RightPanelStore from "../../../stores/RightPanelStore";
|
import RightPanelStore from "../../../stores/right-panel/RightPanelStore";
|
||||||
import { replaceableComponent } from "../../../utils/replaceableComponent";
|
import { replaceableComponent } from "../../../utils/replaceableComponent";
|
||||||
import { useSettingValue } from "../../../hooks/useSettings";
|
import { useSettingValue } from "../../../hooks/useSettings";
|
||||||
import { useReadPinnedEvents, usePinnedEvents } from './PinnedMessagesCard';
|
import { useReadPinnedEvents, usePinnedEvents } from './PinnedMessagesCard';
|
||||||
import { dispatchShowThreadsPanelEvent } from "../../../dispatcher/dispatch-actions/threads";
|
import { dispatchShowThreadsPanelEvent } from "../../../dispatcher/dispatch-actions/threads";
|
||||||
import SettingsStore from "../../../settings/SettingsStore";
|
import SettingsStore from "../../../settings/SettingsStore";
|
||||||
import dis from "../../../dispatcher/dispatcher";
|
|
||||||
import { RoomNotificationStateStore } from "../../../stores/notifications/RoomNotificationStateStore";
|
import { RoomNotificationStateStore } from "../../../stores/notifications/RoomNotificationStateStore";
|
||||||
import { NotificationColor } from "../../../stores/notifications/NotificationColor";
|
import { NotificationColor } from "../../../stores/notifications/NotificationColor";
|
||||||
import { ThreadsRoomNotificationState } from "../../../stores/notifications/ThreadsRoomNotificationState";
|
import { ThreadsRoomNotificationState } from "../../../stores/notifications/ThreadsRoomNotificationState";
|
||||||
|
@ -161,7 +160,7 @@ export default class RoomHeaderButtons extends HeaderButtons<IProps> {
|
||||||
}
|
}
|
||||||
} else if (payload.action === "view_3pid_invite") {
|
} else if (payload.action === "view_3pid_invite") {
|
||||||
if (payload.event) {
|
if (payload.event) {
|
||||||
this.setPhase(RightPanelPhases.Room3pidMemberInfo, { event: payload.event });
|
this.setPhase(RightPanelPhases.Room3pidMemberInfo, { memberInfoEvent: payload.event });
|
||||||
} else {
|
} else {
|
||||||
this.setPhase(RightPanelPhases.RoomMemberList);
|
this.setPhase(RightPanelPhases.RoomMemberList);
|
||||||
}
|
}
|
||||||
|
@ -170,12 +169,12 @@ export default class RoomHeaderButtons extends HeaderButtons<IProps> {
|
||||||
|
|
||||||
private onRoomSummaryClicked = () => {
|
private onRoomSummaryClicked = () => {
|
||||||
// use roomPanelPhase rather than this.state.phase as it remembers the latest one if we close
|
// use roomPanelPhase rather than this.state.phase as it remembers the latest one if we close
|
||||||
const lastPhase = RightPanelStore.getSharedInstance().roomPanelPhase;
|
const currentPhase = RightPanelStore.instance.currentCard.phase;
|
||||||
if (ROOM_INFO_PHASES.includes(lastPhase)) {
|
if (ROOM_INFO_PHASES.includes(currentPhase)) {
|
||||||
if (this.state.phase === lastPhase) {
|
if (this.state.phase === currentPhase) {
|
||||||
this.setPhase(lastPhase);
|
this.setPhase(currentPhase);
|
||||||
} else {
|
} else {
|
||||||
this.setPhase(lastPhase, RightPanelStore.getSharedInstance().roomPanelPhaseParams);
|
this.setPhase(currentPhase, RightPanelStore.instance.currentCard.state);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// This toggles for us, if needed
|
// This toggles for us, if needed
|
||||||
|
@ -198,10 +197,7 @@ export default class RoomHeaderButtons extends HeaderButtons<IProps> {
|
||||||
|
|
||||||
private onThreadsPanelClicked = () => {
|
private onThreadsPanelClicked = () => {
|
||||||
if (RoomHeaderButtons.THREAD_PHASES.includes(this.state.phase)) {
|
if (RoomHeaderButtons.THREAD_PHASES.includes(this.state.phase)) {
|
||||||
dis.dispatch({
|
RightPanelStore.instance.togglePanel();
|
||||||
action: Action.ToggleRightPanel,
|
|
||||||
type: "room",
|
|
||||||
});
|
|
||||||
} else {
|
} else {
|
||||||
dispatchShowThreadsPanelEvent();
|
dispatchShowThreadsPanelEvent();
|
||||||
}
|
}
|
||||||
|
@ -227,6 +223,7 @@ export default class RoomHeaderButtons extends HeaderButtons<IProps> {
|
||||||
rightPanelPhaseButtons.set(RightPanelPhases.ThreadPanel,
|
rightPanelPhaseButtons.set(RightPanelPhases.ThreadPanel,
|
||||||
SettingsStore.getValue("feature_thread")
|
SettingsStore.getValue("feature_thread")
|
||||||
? <HeaderButton
|
? <HeaderButton
|
||||||
|
key={RightPanelPhases.ThreadPanel}
|
||||||
name="threadsButton"
|
name="threadsButton"
|
||||||
title={_t("Threads")}
|
title={_t("Threads")}
|
||||||
onClick={this.onThreadsPanelClicked}
|
onClick={this.onThreadsPanelClicked}
|
||||||
|
|
|
@ -25,9 +25,7 @@ import { _t } from '../../../languageHandler';
|
||||||
import RoomAvatar from "../avatars/RoomAvatar";
|
import RoomAvatar from "../avatars/RoomAvatar";
|
||||||
import AccessibleButton from "../elements/AccessibleButton";
|
import AccessibleButton from "../elements/AccessibleButton";
|
||||||
import defaultDispatcher from "../../../dispatcher/dispatcher";
|
import defaultDispatcher from "../../../dispatcher/dispatcher";
|
||||||
import { Action } from "../../../dispatcher/actions";
|
import { RightPanelPhases } from '../../../stores/right-panel/RightPanelStorePhases';
|
||||||
import { RightPanelPhases } from "../../../stores/RightPanelStorePhases";
|
|
||||||
import { SetRightPanelPhasePayload } from "../../../dispatcher/payloads/SetRightPanelPhasePayload";
|
|
||||||
import Modal from "../../../Modal";
|
import Modal from "../../../Modal";
|
||||||
import ShareDialog from '../dialogs/ShareDialog';
|
import ShareDialog from '../dialogs/ShareDialog';
|
||||||
import { useEventEmitter } from "../../../hooks/useEventEmitter";
|
import { useEventEmitter } from "../../../hooks/useEventEmitter";
|
||||||
|
@ -48,6 +46,7 @@ import { Container, MAX_PINNED, WidgetLayoutStore } from "../../../stores/widget
|
||||||
import RoomName from "../elements/RoomName";
|
import RoomName from "../elements/RoomName";
|
||||||
import UIStore from "../../../stores/UIStore";
|
import UIStore from "../../../stores/UIStore";
|
||||||
import ExportDialog from "../dialogs/ExportDialog";
|
import ExportDialog from "../dialogs/ExportDialog";
|
||||||
|
import RightPanelStore from "../../../stores/right-panel/RightPanelStore";
|
||||||
|
|
||||||
interface IProps {
|
interface IProps {
|
||||||
room: Room;
|
room: Room;
|
||||||
|
@ -103,12 +102,10 @@ const AppRow: React.FC<IAppRowProps> = ({ app, room }) => {
|
||||||
}, [room.roomId]);
|
}, [room.roomId]);
|
||||||
|
|
||||||
const onOpenWidgetClick = () => {
|
const onOpenWidgetClick = () => {
|
||||||
defaultDispatcher.dispatch<SetRightPanelPhasePayload>({
|
// TODO RightPanelStore (will be addressed in a follow up PR): should push the widget
|
||||||
action: Action.SetRightPanelPhase,
|
RightPanelStore.instance.setCard({
|
||||||
phase: RightPanelPhases.Widget,
|
phase: RightPanelPhases.Widget,
|
||||||
refireParams: {
|
state: { widgetId: app.id },
|
||||||
widgetId: app.id,
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -237,19 +234,13 @@ const AppsSection: React.FC<IAppsSectionProps> = ({ room }) => {
|
||||||
};
|
};
|
||||||
|
|
||||||
export const onRoomMembersClick = (allowClose = true) => {
|
export const onRoomMembersClick = (allowClose = true) => {
|
||||||
defaultDispatcher.dispatch<SetRightPanelPhasePayload>({
|
// TODO RightPanelStore (will be addressed in a follow up PR): should push the phase
|
||||||
action: Action.SetRightPanelPhase,
|
RightPanelStore.instance.setCard({ phase: RightPanelPhases.RoomMemberList }, allowClose);
|
||||||
phase: RightPanelPhases.RoomMemberList,
|
|
||||||
allowClose,
|
|
||||||
});
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export const onRoomFilesClick = (allowClose = true) => {
|
export const onRoomFilesClick = (allowClose = true) => {
|
||||||
defaultDispatcher.dispatch<SetRightPanelPhasePayload>({
|
// TODO RightPanelStore (will be addressed in a follow up PR): should push the phase
|
||||||
action: Action.SetRightPanelPhase,
|
RightPanelStore.instance.setCard({ phase: RightPanelPhases.FilePanel }, allowClose);
|
||||||
phase: RightPanelPhases.FilePanel,
|
|
||||||
allowClose,
|
|
||||||
});
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const onRoomSettingsClick = () => {
|
const onRoomSettingsClick = () => {
|
||||||
|
|
|
@ -55,7 +55,7 @@ interface IState {
|
||||||
editState?: EditorStateTransfer;
|
editState?: EditorStateTransfer;
|
||||||
replyToEvent?: MatrixEvent;
|
replyToEvent?: MatrixEvent;
|
||||||
initialEventId?: string;
|
initialEventId?: string;
|
||||||
initialEventHighlighted?: boolean;
|
isInitialEventHighlighted?: boolean;
|
||||||
|
|
||||||
// settings:
|
// settings:
|
||||||
showReadReceipts?: boolean;
|
showReadReceipts?: boolean;
|
||||||
|
@ -103,7 +103,7 @@ export default class TimelineCard extends React.Component<IProps, IState> {
|
||||||
// roomLoadError: RoomViewStore.getRoomLoadError(),
|
// roomLoadError: RoomViewStore.getRoomLoadError(),
|
||||||
|
|
||||||
initialEventId: RoomViewStore.getInitialEventId(),
|
initialEventId: RoomViewStore.getInitialEventId(),
|
||||||
initialEventHighlighted: RoomViewStore.isInitialEventHighlighted(),
|
isInitialEventHighlighted: RoomViewStore.isInitialEventHighlighted(),
|
||||||
replyToEvent: RoomViewStore.getQuotingEvent(),
|
replyToEvent: RoomViewStore.getQuotingEvent(),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -127,7 +127,7 @@ export default class TimelineCard extends React.Component<IProps, IState> {
|
||||||
};
|
};
|
||||||
|
|
||||||
private onScroll = (): void => {
|
private onScroll = (): void => {
|
||||||
if (this.state.initialEventId && this.state.initialEventHighlighted) {
|
if (this.state.initialEventId && this.state.isInitialEventHighlighted) {
|
||||||
dis.dispatch({
|
dis.dispatch({
|
||||||
action: Action.ViewRoom,
|
action: Action.ViewRoom,
|
||||||
room_id: this.props.room.roomId,
|
room_id: this.props.room.roomId,
|
||||||
|
@ -145,7 +145,7 @@ export default class TimelineCard extends React.Component<IProps, IState> {
|
||||||
};
|
};
|
||||||
|
|
||||||
public render(): JSX.Element {
|
public render(): JSX.Element {
|
||||||
const highlightedEventId = this.state.initialEventHighlighted
|
const highlightedEventId = this.state.isInitialEventHighlighted
|
||||||
? this.state.initialEventId
|
? this.state.initialEventId
|
||||||
: null;
|
: null;
|
||||||
|
|
||||||
|
|
|
@ -44,7 +44,7 @@ import E2EIcon from "../rooms/E2EIcon";
|
||||||
import { useEventEmitter } from "../../../hooks/useEventEmitter";
|
import { useEventEmitter } from "../../../hooks/useEventEmitter";
|
||||||
import { textualPowerLevel } from '../../../Roles';
|
import { textualPowerLevel } from '../../../Roles';
|
||||||
import MatrixClientContext from "../../../contexts/MatrixClientContext";
|
import MatrixClientContext from "../../../contexts/MatrixClientContext";
|
||||||
import { RightPanelPhases } from "../../../stores/RightPanelStorePhases";
|
import { RightPanelPhases } from '../../../stores/right-panel/RightPanelStorePhases';
|
||||||
import EncryptionPanel from "./EncryptionPanel";
|
import EncryptionPanel from "./EncryptionPanel";
|
||||||
import { useAsyncMemo } from '../../../hooks/useAsyncMemo';
|
import { useAsyncMemo } from '../../../hooks/useAsyncMemo';
|
||||||
import { legacyVerifyUser, verifyDevice, verifyUser } from '../../../verification';
|
import { legacyVerifyUser, verifyDevice, verifyUser } from '../../../verification';
|
||||||
|
@ -63,7 +63,6 @@ import ErrorDialog from "../dialogs/ErrorDialog";
|
||||||
import QuestionDialog from "../dialogs/QuestionDialog";
|
import QuestionDialog from "../dialogs/QuestionDialog";
|
||||||
import ConfirmUserActionDialog from "../dialogs/ConfirmUserActionDialog";
|
import ConfirmUserActionDialog from "../dialogs/ConfirmUserActionDialog";
|
||||||
import InfoDialog from "../dialogs/InfoDialog";
|
import InfoDialog from "../dialogs/InfoDialog";
|
||||||
import { SetRightPanelPhasePayload } from "../../../dispatcher/payloads/SetRightPanelPhasePayload";
|
|
||||||
import RoomAvatar from "../avatars/RoomAvatar";
|
import RoomAvatar from "../avatars/RoomAvatar";
|
||||||
import RoomName from "../elements/RoomName";
|
import RoomName from "../elements/RoomName";
|
||||||
import { mediaFromMxc } from "../../../customisations/Media";
|
import { mediaFromMxc } from "../../../customisations/Media";
|
||||||
|
@ -75,6 +74,8 @@ import { bulkSpaceBehaviour } from "../../../utils/space";
|
||||||
import { shouldShowComponent } from "../../../customisations/helpers/UIComponents";
|
import { shouldShowComponent } from "../../../customisations/helpers/UIComponents";
|
||||||
import { UIComponent } from "../../../settings/UIFeature";
|
import { UIComponent } from "../../../settings/UIFeature";
|
||||||
import { TimelineRenderingType } from "../../../contexts/RoomContext";
|
import { TimelineRenderingType } from "../../../contexts/RoomContext";
|
||||||
|
import RightPanelStore from '../../../stores/right-panel/RightPanelStore';
|
||||||
|
import { IRightPanelCardState } from '../../../stores/right-panel/RightPanelStoreIPanelState';
|
||||||
import { useUserStatusMessage } from "../../../hooks/useUserStatusMessage";
|
import { useUserStatusMessage } from "../../../hooks/useUserStatusMessage";
|
||||||
|
|
||||||
export interface IDevice {
|
export interface IDevice {
|
||||||
|
@ -1649,25 +1650,22 @@ const UserInfo: React.FC<IProps> = ({
|
||||||
|
|
||||||
const classes = ["mx_UserInfo"];
|
const classes = ["mx_UserInfo"];
|
||||||
|
|
||||||
let refireParams;
|
let cardState: IRightPanelCardState;
|
||||||
let previousPhase: RightPanelPhases;
|
let previousPhase: RightPanelPhases;
|
||||||
// We have no previousPhase for when viewing a UserInfo from a Group or without a Room at this time
|
// We have no previousPhase for when viewing a UserInfo from a Group or without a Room at this time
|
||||||
if (room && phase === RightPanelPhases.EncryptionPanel) {
|
if (room && phase === RightPanelPhases.EncryptionPanel) {
|
||||||
previousPhase = RightPanelPhases.RoomMemberInfo;
|
previousPhase = RightPanelPhases.RoomMemberInfo;
|
||||||
refireParams = { member };
|
cardState = { member };
|
||||||
} else if (room?.isSpaceRoom() && SpaceStore.spacesEnabled) {
|
} else if (room?.isSpaceRoom() && SpaceStore.spacesEnabled) {
|
||||||
previousPhase = previousPhase = RightPanelPhases.SpaceMemberList;
|
previousPhase = RightPanelPhases.SpaceMemberList;
|
||||||
refireParams = { space: room };
|
cardState = { spaceId: room.roomId };
|
||||||
} else if (room) {
|
} else if (room) {
|
||||||
previousPhase = RightPanelPhases.RoomMemberList;
|
previousPhase = RightPanelPhases.RoomMemberList;
|
||||||
}
|
}
|
||||||
|
|
||||||
const onEncryptionPanelClose = () => {
|
const onEncryptionPanelClose = () => {
|
||||||
dis.dispatch<SetRightPanelPhasePayload>({
|
// TODO RightPanelStore (will be addressed in a follow up PR): here we want to pop the panel
|
||||||
action: Action.SetRightPanelPhase,
|
RightPanelStore.instance.setCard({ phase: previousPhase, state: cardState });
|
||||||
phase: previousPhase,
|
|
||||||
refireParams: refireParams,
|
|
||||||
});
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let content;
|
let content;
|
||||||
|
@ -1723,7 +1721,7 @@ const UserInfo: React.FC<IProps> = ({
|
||||||
onClose={onClose}
|
onClose={onClose}
|
||||||
closeLabel={closeLabel}
|
closeLabel={closeLabel}
|
||||||
previousPhase={previousPhase}
|
previousPhase={previousPhase}
|
||||||
refireParams={refireParams}
|
cardState={cardState}
|
||||||
>
|
>
|
||||||
{ content }
|
{ content }
|
||||||
</BaseCard>;
|
</BaseCard>;
|
||||||
|
|
|
@ -23,14 +23,12 @@ import WidgetUtils from "../../../utils/WidgetUtils";
|
||||||
import AppTile from "../elements/AppTile";
|
import AppTile from "../elements/AppTile";
|
||||||
import { _t } from "../../../languageHandler";
|
import { _t } from "../../../languageHandler";
|
||||||
import { useWidgets } from "./RoomSummaryCard";
|
import { useWidgets } from "./RoomSummaryCard";
|
||||||
import { RightPanelPhases } from "../../../stores/RightPanelStorePhases";
|
import { RightPanelPhases } from '../../../stores/right-panel/RightPanelStorePhases';
|
||||||
import defaultDispatcher from "../../../dispatcher/dispatcher";
|
|
||||||
import { SetRightPanelPhasePayload } from "../../../dispatcher/payloads/SetRightPanelPhasePayload";
|
|
||||||
import { Action } from "../../../dispatcher/actions";
|
|
||||||
import { ChevronFace, ContextMenuButton, useContextMenu } from "../../structures/ContextMenu";
|
import { ChevronFace, ContextMenuButton, useContextMenu } from "../../structures/ContextMenu";
|
||||||
import WidgetContextMenu from "../context_menus/WidgetContextMenu";
|
import WidgetContextMenu from "../context_menus/WidgetContextMenu";
|
||||||
import { Container, WidgetLayoutStore } from "../../../stores/widgets/WidgetLayoutStore";
|
import { Container, WidgetLayoutStore } from "../../../stores/widgets/WidgetLayoutStore";
|
||||||
import UIStore from "../../../stores/UIStore";
|
import UIStore from "../../../stores/UIStore";
|
||||||
|
import RightPanelStore from "../../../stores/right-panel/RightPanelStore";
|
||||||
|
|
||||||
interface IProps {
|
interface IProps {
|
||||||
room: Room;
|
room: Room;
|
||||||
|
@ -50,10 +48,9 @@ const WidgetCard: React.FC<IProps> = ({ room, widgetId, onClose }) => {
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!app || isPinned) {
|
if (!app || isPinned) {
|
||||||
// stop showing this card
|
// stop showing this card
|
||||||
defaultDispatcher.dispatch<SetRightPanelPhasePayload>({
|
|
||||||
action: Action.SetRightPanelPhase,
|
//TODO RightPanelStore (will be addressed in a follow up PR): here we want to just pop the widget card.
|
||||||
phase: RightPanelPhases.RoomSummary,
|
RightPanelStore.instance.setCard({ phase: RightPanelPhases.RoomSummary });
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}, [app, isPinned]);
|
}, [app, isPinned]);
|
||||||
|
|
||||||
|
|
|
@ -56,6 +56,7 @@ interface IState {
|
||||||
|
|
||||||
@replaceableComponent("views.rooms.AppsDrawer")
|
@replaceableComponent("views.rooms.AppsDrawer")
|
||||||
export default class AppsDrawer extends React.Component<IProps, IState> {
|
export default class AppsDrawer extends React.Component<IProps, IState> {
|
||||||
|
private unmounted = false;
|
||||||
private resizeContainer: HTMLDivElement;
|
private resizeContainer: HTMLDivElement;
|
||||||
private resizer: Resizer;
|
private resizer: Resizer;
|
||||||
private dispatcherRef: string;
|
private dispatcherRef: string;
|
||||||
|
@ -85,6 +86,7 @@ export default class AppsDrawer extends React.Component<IProps, IState> {
|
||||||
}
|
}
|
||||||
|
|
||||||
public componentWillUnmount(): void {
|
public componentWillUnmount(): void {
|
||||||
|
this.unmounted = true;
|
||||||
ScalarMessaging.stopListening();
|
ScalarMessaging.stopListening();
|
||||||
WidgetLayoutStore.instance.off(WidgetLayoutStore.emissionForRoom(this.props.room), this.updateApps);
|
WidgetLayoutStore.instance.off(WidgetLayoutStore.emissionForRoom(this.props.room), this.updateApps);
|
||||||
if (this.dispatcherRef) dis.unregister(this.dispatcherRef);
|
if (this.dispatcherRef) dis.unregister(this.dispatcherRef);
|
||||||
|
@ -213,6 +215,7 @@ export default class AppsDrawer extends React.Component<IProps, IState> {
|
||||||
private centerApps = (): IApp[] => this.state.apps[Container.Center];
|
private centerApps = (): IApp[] => this.state.apps[Container.Center];
|
||||||
|
|
||||||
private updateApps = (): void => {
|
private updateApps = (): void => {
|
||||||
|
if (this.unmounted) return;
|
||||||
this.setState({
|
this.setState({
|
||||||
apps: this.getApps(),
|
apps: this.getApps(),
|
||||||
});
|
});
|
||||||
|
|
|
@ -33,7 +33,7 @@ import { isValid3pidInvite } from "../../../RoomInvite";
|
||||||
import { MatrixClientPeg } from "../../../MatrixClientPeg";
|
import { MatrixClientPeg } from "../../../MatrixClientPeg";
|
||||||
import { CommunityPrototypeStore } from "../../../stores/CommunityPrototypeStore";
|
import { CommunityPrototypeStore } from "../../../stores/CommunityPrototypeStore";
|
||||||
import BaseCard from "../right_panel/BaseCard";
|
import BaseCard from "../right_panel/BaseCard";
|
||||||
import { RightPanelPhases } from "../../../stores/RightPanelStorePhases";
|
import { RightPanelPhases } from '../../../stores/right-panel/RightPanelStorePhases';
|
||||||
import RoomAvatar from "../avatars/RoomAvatar";
|
import RoomAvatar from "../avatars/RoomAvatar";
|
||||||
import RoomName from "../elements/RoomName";
|
import RoomName from "../elements/RoomName";
|
||||||
import { replaceableComponent } from "../../../utils/replaceableComponent";
|
import { replaceableComponent } from "../../../utils/replaceableComponent";
|
||||||
|
|
|
@ -38,7 +38,7 @@ import { ContextMenuTooltipButton } from '../../structures/ContextMenu';
|
||||||
import RoomContextMenu from "../context_menus/RoomContextMenu";
|
import RoomContextMenu from "../context_menus/RoomContextMenu";
|
||||||
import { contextMenuBelow } from './RoomTile';
|
import { contextMenuBelow } from './RoomTile';
|
||||||
import { RoomNotificationStateStore } from '../../../stores/notifications/RoomNotificationStateStore';
|
import { RoomNotificationStateStore } from '../../../stores/notifications/RoomNotificationStateStore';
|
||||||
import { RightPanelPhases } from '../../../stores/RightPanelStorePhases';
|
import { RightPanelPhases } from '../../../stores/right-panel/RightPanelStorePhases';
|
||||||
import { NotificationStateEvents } from '../../../stores/notifications/NotificationState';
|
import { NotificationStateEvents } from '../../../stores/notifications/NotificationState';
|
||||||
|
|
||||||
export interface ISearchInfo {
|
export interface ISearchInfo {
|
||||||
|
|
|
@ -36,7 +36,7 @@ import { ButtonEvent } from "../elements/AccessibleButton";
|
||||||
import Modal from "../../../Modal";
|
import Modal from "../../../Modal";
|
||||||
import EditCommunityPrototypeDialog from "../dialogs/EditCommunityPrototypeDialog";
|
import EditCommunityPrototypeDialog from "../dialogs/EditCommunityPrototypeDialog";
|
||||||
import { Action } from "../../../dispatcher/actions";
|
import { Action } from "../../../dispatcher/actions";
|
||||||
import { RightPanelPhases } from "../../../stores/RightPanelStorePhases";
|
import { RightPanelPhases } from "../../../stores/right-panel/RightPanelStorePhases";
|
||||||
import ErrorDialog from "../dialogs/ErrorDialog";
|
import ErrorDialog from "../dialogs/ErrorDialog";
|
||||||
import { showCommunityInviteDialog } from "../../../RoomInvite";
|
import { showCommunityInviteDialog } from "../../../RoomInvite";
|
||||||
import { useDispatcher } from "../../../hooks/useDispatcher";
|
import { useDispatcher } from "../../../hooks/useDispatcher";
|
||||||
|
@ -50,6 +50,7 @@ import {
|
||||||
UPDATE_HOME_BEHAVIOUR,
|
UPDATE_HOME_BEHAVIOUR,
|
||||||
UPDATE_SELECTED_SPACE,
|
UPDATE_SELECTED_SPACE,
|
||||||
} from "../../../stores/spaces";
|
} from "../../../stores/spaces";
|
||||||
|
import RightPanelStore from "../../../stores/right-panel/RightPanelStore";
|
||||||
import TooltipTarget from "../elements/TooltipTarget";
|
import TooltipTarget from "../elements/TooltipTarget";
|
||||||
|
|
||||||
const contextMenuBelow = (elementRect: DOMRect) => {
|
const contextMenuBelow = (elementRect: DOMRect) => {
|
||||||
|
@ -99,7 +100,7 @@ const PrototypeCommunityContextMenu = (props: ComponentProps<typeof SpaceContext
|
||||||
action: 'view_room',
|
action: 'view_room',
|
||||||
room_id: chat.roomId,
|
room_id: chat.roomId,
|
||||||
}, true);
|
}, true);
|
||||||
dis.dispatch({ action: Action.SetRightPanelPhase, phase: RightPanelPhases.RoomMemberList });
|
RightPanelStore.instance.setCard({ phase: RightPanelPhases.RoomMemberList }, undefined, chat.roomId);
|
||||||
} else {
|
} else {
|
||||||
// "This should never happen" clauses go here for the prototype.
|
// "This should never happen" clauses go here for the prototype.
|
||||||
Modal.createTrackedDialog('Failed to find general chat', '', ErrorDialog, {
|
Modal.createTrackedDialog('Failed to find general chat', '', ErrorDialog, {
|
||||||
|
|
|
@ -21,8 +21,7 @@ import { logger } from "matrix-js-sdk/src/logger";
|
||||||
|
|
||||||
import { _t } from '../../../languageHandler';
|
import { _t } from '../../../languageHandler';
|
||||||
import { MatrixClientPeg } from '../../../MatrixClientPeg';
|
import { MatrixClientPeg } from '../../../MatrixClientPeg';
|
||||||
import { RightPanelPhases } from "../../../stores/RightPanelStorePhases";
|
import { RightPanelPhases } from '../../../stores/right-panel/RightPanelStorePhases';
|
||||||
import { SetRightPanelPhasePayload } from "../../../dispatcher/payloads/SetRightPanelPhasePayload";
|
|
||||||
import { userLabelForEventRoom } from "../../../utils/KeyVerificationStateObserver";
|
import { userLabelForEventRoom } from "../../../utils/KeyVerificationStateObserver";
|
||||||
import dis from "../../../dispatcher/dispatcher";
|
import dis from "../../../dispatcher/dispatcher";
|
||||||
import ToastStore from "../../../stores/ToastStore";
|
import ToastStore from "../../../stores/ToastStore";
|
||||||
|
@ -31,6 +30,7 @@ import GenericToast from "./GenericToast";
|
||||||
import { Action } from "../../../dispatcher/actions";
|
import { Action } from "../../../dispatcher/actions";
|
||||||
import { replaceableComponent } from "../../../utils/replaceableComponent";
|
import { replaceableComponent } from "../../../utils/replaceableComponent";
|
||||||
import VerificationRequestDialog from "../dialogs/VerificationRequestDialog";
|
import VerificationRequestDialog from "../dialogs/VerificationRequestDialog";
|
||||||
|
import RightPanelStore from "../../../stores/right-panel/RightPanelStore";
|
||||||
|
|
||||||
interface IProps {
|
interface IProps {
|
||||||
toastKey: string;
|
toastKey: string;
|
||||||
|
@ -115,14 +115,14 @@ export default class VerificationRequestToast extends React.PureComponent<IProps
|
||||||
room_id: request.channel.roomId,
|
room_id: request.channel.roomId,
|
||||||
should_peek: false,
|
should_peek: false,
|
||||||
});
|
});
|
||||||
dis.dispatch<SetRightPanelPhasePayload>({
|
RightPanelStore.instance.setCard(
|
||||||
action: Action.SetRightPanelPhase,
|
{
|
||||||
phase: RightPanelPhases.EncryptionPanel,
|
phase: RightPanelPhases.EncryptionPanel,
|
||||||
refireParams: {
|
state: { verificationRequest: request, member: cli.getUser(request.otherUserId) },
|
||||||
verificationRequest: request,
|
|
||||||
member: cli.getUser(request.otherUserId),
|
|
||||||
},
|
},
|
||||||
});
|
undefined,
|
||||||
|
request.channel.roomId,
|
||||||
|
);
|
||||||
} else {
|
} else {
|
||||||
Modal.createTrackedDialog('Incoming Verification', '', VerificationRequestDialog, {
|
Modal.createTrackedDialog('Incoming Verification', '', VerificationRequestDialog, {
|
||||||
verificationRequest: request,
|
verificationRequest: request,
|
||||||
|
|
|
@ -102,16 +102,6 @@ export enum Action {
|
||||||
*/
|
*/
|
||||||
ViewRoomDelta = "view_room_delta",
|
ViewRoomDelta = "view_room_delta",
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets the phase for the right panel. Should be used with SetRightPanelPhasePayload.
|
|
||||||
*/
|
|
||||||
SetRightPanelPhase = "set_right_panel_phase",
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Toggles the right panel. Should be used with ToggleRightPanelPayload.
|
|
||||||
*/
|
|
||||||
ToggleRightPanel = "toggle_right_panel",
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Trigged after the phase of the right panel is set. Should be used with AfterRightPanelPhaseChangePayload.
|
* Trigged after the phase of the right panel is set. Should be used with AfterRightPanelPhaseChangePayload.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -15,31 +15,26 @@ limitations under the License.
|
||||||
*/
|
*/
|
||||||
import { MatrixEvent } from "matrix-js-sdk/src/models/event";
|
import { MatrixEvent } from "matrix-js-sdk/src/models/event";
|
||||||
|
|
||||||
import { RightPanelPhases } from "../../stores/RightPanelStorePhases";
|
import RightPanelStore from "../../stores/right-panel/RightPanelStore";
|
||||||
import { Action } from "../actions";
|
import { RightPanelPhases } from "../../stores/right-panel/RightPanelStorePhases";
|
||||||
import dis from '../dispatcher';
|
|
||||||
import { SetRightPanelPhasePayload } from "../payloads/SetRightPanelPhasePayload";
|
|
||||||
|
|
||||||
export const dispatchShowThreadEvent = (
|
export const dispatchShowThreadEvent = (
|
||||||
rootEvent: MatrixEvent,
|
rootEvent: MatrixEvent,
|
||||||
initialEvent?: MatrixEvent,
|
initialEvent?: MatrixEvent,
|
||||||
highlighted?: boolean,
|
highlighted?: boolean,
|
||||||
) => {
|
) => {
|
||||||
dis.dispatch({
|
// TODO RightPanelStore (will be addressed in a follow up PR): this should really be a push!
|
||||||
action: Action.SetRightPanelPhase,
|
RightPanelStore.instance.setCard({
|
||||||
phase: RightPanelPhases.ThreadView,
|
phase: RightPanelPhases.ThreadView,
|
||||||
refireParams: {
|
state: {
|
||||||
event: rootEvent,
|
threadHeadEvent: rootEvent,
|
||||||
initialEvent,
|
initialEvent,
|
||||||
highlighted,
|
isInitialEventHighlighted: highlighted,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
export const dispatchShowThreadsPanelEvent = () => {
|
export const dispatchShowThreadsPanelEvent = () => {
|
||||||
dis.dispatch<SetRightPanelPhasePayload>({
|
RightPanelStore.instance.setCard({ phase: RightPanelPhases.ThreadPanel });
|
||||||
action: Action.SetRightPanelPhase,
|
|
||||||
phase: RightPanelPhases.ThreadPanel,
|
|
||||||
});
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -1,31 +0,0 @@
|
||||||
/*
|
|
||||||
Copyright 2020 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 { VerificationRequest } from "matrix-js-sdk/src/crypto/verification/request/VerificationRequest";
|
|
||||||
|
|
||||||
import { RightPanelPhases } from "../../stores/RightPanelStorePhases";
|
|
||||||
import { SetRightPanelPhaseRefireParams } from "./SetRightPanelPhasePayload";
|
|
||||||
import { ActionPayload } from "../payloads";
|
|
||||||
import { Action } from "../actions";
|
|
||||||
|
|
||||||
interface AfterRightPanelPhaseChangeAction extends ActionPayload {
|
|
||||||
action: Action.AfterRightPanelPhaseChange;
|
|
||||||
phase: RightPanelPhases;
|
|
||||||
verificationRequestPromise?: Promise<VerificationRequest>;
|
|
||||||
}
|
|
||||||
|
|
||||||
export type AfterRightPanelPhaseChangePayload
|
|
||||||
= AfterRightPanelPhaseChangeAction & SetRightPanelPhaseRefireParams;
|
|
|
@ -1,47 +0,0 @@
|
||||||
/*
|
|
||||||
Copyright 2020 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 { VerificationRequest } from "matrix-js-sdk/src/crypto/verification/request/VerificationRequest";
|
|
||||||
import { Room } from "matrix-js-sdk/src/models/room";
|
|
||||||
import { RoomMember } from "matrix-js-sdk/src/models/room-member";
|
|
||||||
import { User } from "matrix-js-sdk/src/models/user";
|
|
||||||
|
|
||||||
import { RightPanelPhases } from "../../stores/RightPanelStorePhases";
|
|
||||||
import { ActionPayload } from "../payloads";
|
|
||||||
import { Action } from "../actions";
|
|
||||||
|
|
||||||
export interface SetRightPanelPhasePayload extends ActionPayload {
|
|
||||||
action: Action.SetRightPanelPhase;
|
|
||||||
|
|
||||||
phase: RightPanelPhases;
|
|
||||||
refireParams?: SetRightPanelPhaseRefireParams;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* By default SetRightPanelPhase can close the panel, this allows overriding that behaviour
|
|
||||||
*/
|
|
||||||
allowClose?: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface SetRightPanelPhaseRefireParams {
|
|
||||||
member?: RoomMember | User;
|
|
||||||
verificationRequest?: VerificationRequest;
|
|
||||||
groupId?: string;
|
|
||||||
groupRoomId?: string;
|
|
||||||
// XXX: The type for event should 'view_3pid_invite' action's payload
|
|
||||||
event?: any;
|
|
||||||
widgetId?: string;
|
|
||||||
space?: Room;
|
|
||||||
}
|
|
|
@ -1,27 +0,0 @@
|
||||||
/*
|
|
||||||
Copyright 2020 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 { ActionPayload } from "../payloads";
|
|
||||||
import { Action } from "../actions";
|
|
||||||
|
|
||||||
export interface ToggleRightPanelPayload extends ActionPayload {
|
|
||||||
action: Action.ToggleRightPanel;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The type of room that the panel is toggled in.
|
|
||||||
*/
|
|
||||||
type: "group" | "room";
|
|
||||||
}
|
|
|
@ -32,7 +32,6 @@ import SystemFontController from './controllers/SystemFontController';
|
||||||
import UseSystemFontController from './controllers/UseSystemFontController';
|
import UseSystemFontController from './controllers/UseSystemFontController';
|
||||||
import { SettingLevel } from "./SettingLevel";
|
import { SettingLevel } from "./SettingLevel";
|
||||||
import SettingController from "./controllers/SettingController";
|
import SettingController from "./controllers/SettingController";
|
||||||
import { RightPanelPhases } from "../stores/RightPanelStorePhases";
|
|
||||||
import { isMac } from '../Keyboard';
|
import { isMac } from '../Keyboard';
|
||||||
import UIFeatureController from "./controllers/UIFeatureController";
|
import UIFeatureController from "./controllers/UIFeatureController";
|
||||||
import { UIFeature } from "./UIFeature";
|
import { UIFeature } from "./UIFeature";
|
||||||
|
@ -771,21 +770,13 @@ export const SETTINGS: {[setting: string]: ISetting} = {
|
||||||
displayName: _td("Show previews/thumbnails for images"),
|
displayName: _td("Show previews/thumbnails for images"),
|
||||||
default: true,
|
default: true,
|
||||||
},
|
},
|
||||||
"showRightPanelInRoom": {
|
"RightPanel.phasesGlobal": {
|
||||||
supportedLevels: LEVELS_DEVICE_ONLY_SETTINGS,
|
supportedLevels: [SettingLevel.DEVICE],
|
||||||
default: false,
|
default: null,
|
||||||
},
|
},
|
||||||
"showRightPanelInGroup": {
|
"RightPanel.phases": {
|
||||||
supportedLevels: LEVELS_DEVICE_ONLY_SETTINGS,
|
supportedLevels: [SettingLevel.ROOM_DEVICE],
|
||||||
default: false,
|
default: null,
|
||||||
},
|
|
||||||
"lastRightPanelPhaseForRoom": {
|
|
||||||
supportedLevels: LEVELS_DEVICE_ONLY_SETTINGS,
|
|
||||||
default: RightPanelPhases.RoomSummary,
|
|
||||||
},
|
|
||||||
"lastRightPanelPhaseForGroup": {
|
|
||||||
supportedLevels: LEVELS_DEVICE_ONLY_SETTINGS,
|
|
||||||
default: RightPanelPhases.GroupMemberList,
|
|
||||||
},
|
},
|
||||||
"enableEventIndexing": {
|
"enableEventIndexing": {
|
||||||
supportedLevels: LEVELS_DEVICE_ONLY_SETTINGS,
|
supportedLevels: LEVELS_DEVICE_ONLY_SETTINGS,
|
||||||
|
|
|
@ -57,17 +57,6 @@ export default class DeviceSettingsHandler extends SettingsHandler {
|
||||||
return null; // wrong type or otherwise not set
|
return null; // wrong type or otherwise not set
|
||||||
}
|
}
|
||||||
|
|
||||||
// Special case the right panel - see `setValue` for rationale.
|
|
||||||
if ([
|
|
||||||
"showRightPanelInRoom",
|
|
||||||
"showRightPanelInGroup",
|
|
||||||
"lastRightPanelPhaseForRoom",
|
|
||||||
"lastRightPanelPhaseForGroup",
|
|
||||||
].includes(settingName)) {
|
|
||||||
const val = JSON.parse(localStorage.getItem(`mx_${settingName}`) || "{}");
|
|
||||||
return val['value'];
|
|
||||||
}
|
|
||||||
|
|
||||||
// Special case for old useIRCLayout setting
|
// Special case for old useIRCLayout setting
|
||||||
if (settingName === "layout") {
|
if (settingName === "layout") {
|
||||||
const settings = this.getSettings() || {};
|
const settings = this.getSettings() || {};
|
||||||
|
@ -106,20 +95,6 @@ export default class DeviceSettingsHandler extends SettingsHandler {
|
||||||
return Promise.resolve();
|
return Promise.resolve();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Special case the right panel because we want to be able to update these all
|
|
||||||
// concurrently without stomping on one another. We could use async/await, though
|
|
||||||
// that introduces just enough latency to be annoying.
|
|
||||||
if ([
|
|
||||||
"showRightPanelInRoom",
|
|
||||||
"showRightPanelInGroup",
|
|
||||||
"lastRightPanelPhaseForRoom",
|
|
||||||
"lastRightPanelPhaseForGroup",
|
|
||||||
].includes(settingName)) {
|
|
||||||
localStorage.setItem(`mx_${settingName}`, JSON.stringify({ value: newValue }));
|
|
||||||
this.watchers.notifyUpdate(settingName, null, SettingLevel.DEVICE, newValue);
|
|
||||||
return Promise.resolve();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Special case for old useIRCLayout setting
|
// Special case for old useIRCLayout setting
|
||||||
if (settingName === "layout") {
|
if (settingName === "layout") {
|
||||||
const settings = this.getSettings() || {};
|
const settings = this.getSettings() || {};
|
||||||
|
|
|
@ -1,245 +0,0 @@
|
||||||
/*
|
|
||||||
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 { Store } from 'flux/utils';
|
|
||||||
import { logger } from "matrix-js-sdk/src/logger";
|
|
||||||
|
|
||||||
import dis from '../dispatcher/dispatcher';
|
|
||||||
import { pendingVerificationRequestForUser } from '../verification';
|
|
||||||
import SettingsStore from "../settings/SettingsStore";
|
|
||||||
import { RightPanelPhases, RIGHT_PANEL_PHASES_NO_ARGS } from "./RightPanelStorePhases";
|
|
||||||
import { ActionPayload } from "../dispatcher/payloads";
|
|
||||||
import { Action } from '../dispatcher/actions';
|
|
||||||
import { SettingLevel } from "../settings/SettingLevel";
|
|
||||||
|
|
||||||
interface RightPanelStoreState {
|
|
||||||
// Whether or not to show the right panel at all. We split out rooms and groups
|
|
||||||
// because they're different flows for the user to follow.
|
|
||||||
showRoomPanel: boolean;
|
|
||||||
showGroupPanel: boolean;
|
|
||||||
|
|
||||||
// The last phase (screen) the right panel was showing
|
|
||||||
lastRoomPhase: RightPanelPhases;
|
|
||||||
lastGroupPhase: RightPanelPhases;
|
|
||||||
|
|
||||||
previousPhase?: RightPanelPhases;
|
|
||||||
|
|
||||||
// Extra information about the last phase
|
|
||||||
lastRoomPhaseParams: {[key: string]: any};
|
|
||||||
}
|
|
||||||
|
|
||||||
const INITIAL_STATE: RightPanelStoreState = {
|
|
||||||
showRoomPanel: SettingsStore.getValue("showRightPanelInRoom"),
|
|
||||||
showGroupPanel: SettingsStore.getValue("showRightPanelInGroup"),
|
|
||||||
lastRoomPhase: SettingsStore.getValue("lastRightPanelPhaseForRoom"),
|
|
||||||
lastGroupPhase: SettingsStore.getValue("lastRightPanelPhaseForGroup"),
|
|
||||||
lastRoomPhaseParams: {},
|
|
||||||
};
|
|
||||||
|
|
||||||
const GROUP_PHASES = [
|
|
||||||
RightPanelPhases.GroupMemberList,
|
|
||||||
RightPanelPhases.GroupRoomList,
|
|
||||||
RightPanelPhases.GroupRoomInfo,
|
|
||||||
RightPanelPhases.GroupMemberInfo,
|
|
||||||
];
|
|
||||||
|
|
||||||
const MEMBER_INFO_PHASES = [
|
|
||||||
RightPanelPhases.RoomMemberInfo,
|
|
||||||
RightPanelPhases.Room3pidMemberInfo,
|
|
||||||
RightPanelPhases.EncryptionPanel,
|
|
||||||
];
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A class for tracking the state of the right panel between layouts and
|
|
||||||
* sessions.
|
|
||||||
*/
|
|
||||||
export default class RightPanelStore extends Store<ActionPayload> {
|
|
||||||
private static instance: RightPanelStore;
|
|
||||||
private state: RightPanelStoreState;
|
|
||||||
private lastRoomId: string;
|
|
||||||
|
|
||||||
constructor() {
|
|
||||||
super(dis);
|
|
||||||
|
|
||||||
// Initialise state
|
|
||||||
this.state = INITIAL_STATE;
|
|
||||||
}
|
|
||||||
|
|
||||||
get isOpenForRoom(): boolean {
|
|
||||||
return this.state.showRoomPanel;
|
|
||||||
}
|
|
||||||
|
|
||||||
get isOpenForGroup(): boolean {
|
|
||||||
return this.state.showGroupPanel;
|
|
||||||
}
|
|
||||||
|
|
||||||
get roomPanelPhase(): RightPanelPhases {
|
|
||||||
return this.state.lastRoomPhase;
|
|
||||||
}
|
|
||||||
|
|
||||||
get groupPanelPhase(): RightPanelPhases {
|
|
||||||
return this.state.lastGroupPhase;
|
|
||||||
}
|
|
||||||
|
|
||||||
get previousPhase(): RightPanelPhases | null {
|
|
||||||
return RIGHT_PANEL_PHASES_NO_ARGS.includes(this.state.previousPhase) ? this.state.previousPhase : null;
|
|
||||||
}
|
|
||||||
|
|
||||||
get visibleRoomPanelPhase(): RightPanelPhases {
|
|
||||||
return this.isOpenForRoom ? this.roomPanelPhase : null;
|
|
||||||
}
|
|
||||||
|
|
||||||
get visibleGroupPanelPhase(): RightPanelPhases {
|
|
||||||
return this.isOpenForGroup ? this.groupPanelPhase : null;
|
|
||||||
}
|
|
||||||
|
|
||||||
get roomPanelPhaseParams(): any {
|
|
||||||
return this.state.lastRoomPhaseParams || {};
|
|
||||||
}
|
|
||||||
|
|
||||||
private setState(newState: Partial<RightPanelStoreState>) {
|
|
||||||
this.state = Object.assign(this.state, newState);
|
|
||||||
|
|
||||||
SettingsStore.setValue(
|
|
||||||
"showRightPanelInRoom",
|
|
||||||
null,
|
|
||||||
SettingLevel.DEVICE,
|
|
||||||
this.state.showRoomPanel,
|
|
||||||
);
|
|
||||||
SettingsStore.setValue(
|
|
||||||
"showRightPanelInGroup",
|
|
||||||
null,
|
|
||||||
SettingLevel.DEVICE,
|
|
||||||
this.state.showGroupPanel,
|
|
||||||
);
|
|
||||||
|
|
||||||
if (RIGHT_PANEL_PHASES_NO_ARGS.includes(this.state.lastRoomPhase)) {
|
|
||||||
SettingsStore.setValue(
|
|
||||||
"lastRightPanelPhaseForRoom",
|
|
||||||
null,
|
|
||||||
SettingLevel.DEVICE,
|
|
||||||
this.state.lastRoomPhase,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
if (RIGHT_PANEL_PHASES_NO_ARGS.includes(this.state.lastGroupPhase)) {
|
|
||||||
SettingsStore.setValue(
|
|
||||||
"lastRightPanelPhaseForGroup",
|
|
||||||
null,
|
|
||||||
SettingLevel.DEVICE,
|
|
||||||
this.state.lastGroupPhase,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
this.__emitChange();
|
|
||||||
}
|
|
||||||
|
|
||||||
__onDispatch(payload: ActionPayload) { // eslint-disable-line @typescript-eslint/naming-convention
|
|
||||||
switch (payload.action) {
|
|
||||||
case Action.ViewRoom:
|
|
||||||
if (payload.room_id === this.lastRoomId) break; // skip this transition, probably a permalink
|
|
||||||
// fallthrough
|
|
||||||
case 'view_group':
|
|
||||||
this.lastRoomId = payload.room_id;
|
|
||||||
|
|
||||||
// Reset to the member list if we're viewing member info
|
|
||||||
if (MEMBER_INFO_PHASES.includes(this.state.lastRoomPhase)) {
|
|
||||||
this.setState({ lastRoomPhase: RightPanelPhases.RoomMemberList, lastRoomPhaseParams: {} });
|
|
||||||
}
|
|
||||||
|
|
||||||
// Do the same for groups
|
|
||||||
if (this.state.lastGroupPhase === RightPanelPhases.GroupMemberInfo) {
|
|
||||||
this.setState({ lastGroupPhase: RightPanelPhases.GroupMemberList });
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case Action.SetRightPanelPhase: {
|
|
||||||
let targetPhase = payload.phase;
|
|
||||||
let refireParams = payload.refireParams;
|
|
||||||
const allowClose = payload.allowClose ?? true;
|
|
||||||
// redirect to EncryptionPanel if there is an ongoing verification request
|
|
||||||
if (targetPhase === RightPanelPhases.RoomMemberInfo && payload.refireParams) {
|
|
||||||
const { member } = payload.refireParams;
|
|
||||||
const pendingRequest = pendingVerificationRequestForUser(member);
|
|
||||||
if (pendingRequest) {
|
|
||||||
targetPhase = RightPanelPhases.EncryptionPanel;
|
|
||||||
refireParams = {
|
|
||||||
verificationRequest: pendingRequest,
|
|
||||||
member,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!RightPanelPhases[targetPhase]) {
|
|
||||||
logger.warn(`Tried to switch right panel to unknown phase: ${targetPhase}`);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (GROUP_PHASES.includes(targetPhase)) {
|
|
||||||
if (targetPhase === this.state.lastGroupPhase) {
|
|
||||||
this.setState({
|
|
||||||
showGroupPanel: !this.state.showGroupPanel,
|
|
||||||
previousPhase: null,
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
this.setState({
|
|
||||||
lastGroupPhase: targetPhase,
|
|
||||||
showGroupPanel: true,
|
|
||||||
previousPhase: this.state.lastGroupPhase,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (targetPhase === this.state.lastRoomPhase && !refireParams && allowClose) {
|
|
||||||
this.setState({
|
|
||||||
showRoomPanel: !this.state.showRoomPanel,
|
|
||||||
previousPhase: null,
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
this.setState({
|
|
||||||
lastRoomPhase: targetPhase,
|
|
||||||
showRoomPanel: true,
|
|
||||||
lastRoomPhaseParams: refireParams || {},
|
|
||||||
previousPhase: this.state.lastRoomPhase,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Let things like the member info panel actually open to the right member.
|
|
||||||
dis.dispatch({
|
|
||||||
action: Action.AfterRightPanelPhaseChange,
|
|
||||||
phase: targetPhase,
|
|
||||||
...(refireParams || {}),
|
|
||||||
});
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case Action.ToggleRightPanel:
|
|
||||||
if (payload.type === "room") {
|
|
||||||
this.setState({ showRoomPanel: !this.state.showRoomPanel });
|
|
||||||
} else { // group
|
|
||||||
this.setState({ showGroupPanel: !this.state.showGroupPanel });
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static getSharedInstance(): RightPanelStore {
|
|
||||||
if (!RightPanelStore.instance) {
|
|
||||||
RightPanelStore.instance = new RightPanelStore();
|
|
||||||
}
|
|
||||||
return RightPanelStore.instance;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
window.mxRightPanelStore = RightPanelStore.getSharedInstance();
|
|
370
src/stores/right-panel/RightPanelStore.ts
Normal file
370
src/stores/right-panel/RightPanelStore.ts
Normal file
|
@ -0,0 +1,370 @@
|
||||||
|
/*
|
||||||
|
Copyright 2019-2021 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 { logger } from "matrix-js-sdk/src/logger";
|
||||||
|
import { EventSubscription } from 'fbemitter';
|
||||||
|
|
||||||
|
import defaultDispatcher from '../../dispatcher/dispatcher';
|
||||||
|
import { pendingVerificationRequestForUser } from '../../verification';
|
||||||
|
import SettingsStore from "../../settings/SettingsStore";
|
||||||
|
import { RightPanelPhases } from "./RightPanelStorePhases";
|
||||||
|
import { ActionPayload } from "../../dispatcher/payloads";
|
||||||
|
import { Action } from '../../dispatcher/actions';
|
||||||
|
import { SettingLevel } from "../../settings/SettingLevel";
|
||||||
|
import { UPDATE_EVENT } from '../AsyncStore';
|
||||||
|
import { ReadyWatchingStore } from '../ReadyWatchingStore';
|
||||||
|
import {
|
||||||
|
IRightPanelCard,
|
||||||
|
convertToStatePanel,
|
||||||
|
convertToStorePanel,
|
||||||
|
IRightPanelForRoom,
|
||||||
|
convertCardToStore,
|
||||||
|
} from './RightPanelStoreIPanelState';
|
||||||
|
import { MatrixClientPeg } from "../../MatrixClientPeg";
|
||||||
|
// import RoomViewStore from '../RoomViewStore';
|
||||||
|
|
||||||
|
const GROUP_PHASES = [
|
||||||
|
RightPanelPhases.GroupMemberList,
|
||||||
|
RightPanelPhases.GroupRoomList,
|
||||||
|
RightPanelPhases.GroupRoomInfo,
|
||||||
|
RightPanelPhases.GroupMemberInfo,
|
||||||
|
];
|
||||||
|
|
||||||
|
const MEMBER_INFO_PHASES = [
|
||||||
|
RightPanelPhases.RoomMemberInfo,
|
||||||
|
RightPanelPhases.Room3pidMemberInfo,
|
||||||
|
RightPanelPhases.EncryptionPanel,
|
||||||
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A class for tracking the state of the right panel between layouts and
|
||||||
|
* sessions. This state includes a history for each room. Each history element
|
||||||
|
* contains the phase (e.g. RightPanelPhase.RoomMemberInfo) and the state (e.g.
|
||||||
|
* the member) associated with it.
|
||||||
|
* Groups are treated the same as rooms (they are also stored in the byRoom
|
||||||
|
* object). This is possible since the store keeps track of the opened
|
||||||
|
* room/group -> the store will provide the correct history for that group/room.
|
||||||
|
*/
|
||||||
|
export default class RightPanelStore extends ReadyWatchingStore {
|
||||||
|
private static internalInstance: RightPanelStore;
|
||||||
|
private viewedRoomId: string;
|
||||||
|
private isViewingRoom?: boolean;
|
||||||
|
private dispatcherRefRightPanelStore: string;
|
||||||
|
private roomStoreToken: EventSubscription;
|
||||||
|
|
||||||
|
private global?: IRightPanelForRoom = null;
|
||||||
|
private byRoom: {
|
||||||
|
[roomId: string]: IRightPanelForRoom;
|
||||||
|
} = {};
|
||||||
|
|
||||||
|
private constructor() {
|
||||||
|
super(defaultDispatcher);
|
||||||
|
this.dispatcherRefRightPanelStore = defaultDispatcher.register(this.onDispatch);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected async onReady(): Promise<any> {
|
||||||
|
// TODO RightPanelStore (will be addressed when dropping groups): This should be used instead of the onDispatch callback when groups are removed.
|
||||||
|
// RoomViewStore.on(UPDATE_EVENT, this.onRoomViewStoreUpdate);
|
||||||
|
MatrixClientPeg.get().on("crypto.verification.request", this.onVerificationRequestUpdate);
|
||||||
|
this.loadCacheFromSettings();
|
||||||
|
this.emitAndUpdateSettings();
|
||||||
|
}
|
||||||
|
public destroy() {
|
||||||
|
if (this.dispatcherRefRightPanelStore) {
|
||||||
|
defaultDispatcher.unregister(this.dispatcherRefRightPanelStore);
|
||||||
|
}
|
||||||
|
super.destroy();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected async onNotReady(): Promise<any> {
|
||||||
|
if (this.roomStoreToken) {
|
||||||
|
this.roomStoreToken.remove();
|
||||||
|
}
|
||||||
|
MatrixClientPeg.get().off("crypto.verification.request", this.onVerificationRequestUpdate);
|
||||||
|
// TODO RightPanelStore (will be addressed when dropping groups): User this instead of the dispatcher.
|
||||||
|
// RoomViewStore.off(UPDATE_EVENT, this.onRoomViewStoreUpdate);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Getters
|
||||||
|
public get isOpenForRoom(): boolean {
|
||||||
|
return this.byRoom[this.viewedRoomId]?.isOpen ?? false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get roomPhaseHistory(): Array<IRightPanelCard> {
|
||||||
|
return this.byRoom[this.viewedRoomId]?.history ?? [];
|
||||||
|
}
|
||||||
|
|
||||||
|
public get currentCard(): IRightPanelCard {
|
||||||
|
const hist = this.roomPhaseHistory;
|
||||||
|
if (hist.length >= 1) {
|
||||||
|
return hist[hist.length - 1];
|
||||||
|
}
|
||||||
|
return { state: {}, phase: null };
|
||||||
|
}
|
||||||
|
|
||||||
|
public currentCardForRoom(roomId: string): IRightPanelCard {
|
||||||
|
const hist = this.byRoom[roomId]?.history ?? [];
|
||||||
|
if (hist.length > 0) {
|
||||||
|
return hist[hist.length - 1];
|
||||||
|
}
|
||||||
|
return this.currentCard ?? { state: {}, phase: null };
|
||||||
|
}
|
||||||
|
|
||||||
|
public get previousCard(): IRightPanelCard {
|
||||||
|
const hist = this.roomPhaseHistory;
|
||||||
|
if (hist?.length >= 2) {
|
||||||
|
return hist[hist.length - 2];
|
||||||
|
}
|
||||||
|
return { state: {}, phase: null };
|
||||||
|
}
|
||||||
|
|
||||||
|
// The Group associated getters are just for backwards compatibility. Can be removed when deprecating groups.
|
||||||
|
public get isOpenForGroup(): boolean { return this.isOpenForRoom; }
|
||||||
|
public get groupPhaseHistory(): Array<IRightPanelCard> { return this.roomPhaseHistory; }
|
||||||
|
public get currentGroup(): IRightPanelCard { return this.currentCard; }
|
||||||
|
public get previousGroup(): IRightPanelCard { return this.previousCard; }
|
||||||
|
|
||||||
|
// Setters
|
||||||
|
public setCard(card: IRightPanelCard, allowClose = true, roomId?: string) {
|
||||||
|
const rId = roomId ?? this.viewedRoomId;
|
||||||
|
// this was previously a very multifunctional command:
|
||||||
|
// Toggle panel: if the same phase is send but without a state
|
||||||
|
// Update state: if the same phase is send but with a state
|
||||||
|
// Set right panel and erase history: if a "different to the current" phase is send (with or without a state)
|
||||||
|
const redirect = this.getVerificationRedirect(card);
|
||||||
|
const targetPhase = redirect?.phase ?? card.phase;
|
||||||
|
const cardState = redirect?.state ?? (Object.keys(card.state ?? {}).length === 0 ? null : card.state);
|
||||||
|
|
||||||
|
// Checks for wrong SetRightPanelPhase requests
|
||||||
|
if (!this.isPhaseActionIsValid(targetPhase)) return;
|
||||||
|
|
||||||
|
if (targetPhase === this.currentCard?.phase &&
|
||||||
|
allowClose &&
|
||||||
|
(this.compareCards({ phase: targetPhase, state: cardState }, this.currentCard) || !cardState)
|
||||||
|
) {
|
||||||
|
// Toggle panel: a toggle command needs to fullfil the following:
|
||||||
|
// - the same phase
|
||||||
|
// - the panel can be closed
|
||||||
|
// - does not contain any state information (state)
|
||||||
|
if (targetPhase != RightPanelPhases.EncryptionPanel) {
|
||||||
|
this.togglePanel(rId);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
} else if ((targetPhase === this.currentCardForRoom(rId)?.phase && !!cardState)) {
|
||||||
|
// Update state: set right panel with a new state but keep the phase (dont know it this is ever needed...)
|
||||||
|
const hist = this.byRoom[rId]?.history ?? [];
|
||||||
|
hist[hist.length - 1].state = cardState;
|
||||||
|
this.emitAndUpdateSettings();
|
||||||
|
return;
|
||||||
|
} else if (targetPhase !== this.currentCard?.phase) {
|
||||||
|
// Set right panel and erase history.
|
||||||
|
this.setRightPanelCache({ phase: targetPhase, state: cardState ?? {} }, rId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public pushCard(
|
||||||
|
card: IRightPanelCard,
|
||||||
|
allowClose = true,
|
||||||
|
roomId: string = null,
|
||||||
|
) {
|
||||||
|
const rId = roomId ?? this.viewedRoomId;
|
||||||
|
const redirect = this.getVerificationRedirect(card);
|
||||||
|
const targetPhase = redirect?.phase ?? card.phase;
|
||||||
|
const pState = redirect?.state ?? (Object.keys(card.state ?? {}).length === 0 ? null : card.state);
|
||||||
|
|
||||||
|
// Checks for wrong SetRightPanelPhase requests
|
||||||
|
if (!this.isPhaseActionIsValid(targetPhase)) return;
|
||||||
|
|
||||||
|
let roomCache = this.byRoom[rId];
|
||||||
|
if (!!roomCache) {
|
||||||
|
// append new phase
|
||||||
|
roomCache.history.push({ state: pState, phase: targetPhase });
|
||||||
|
roomCache.isOpen = allowClose ? roomCache.isOpen : true;
|
||||||
|
} else {
|
||||||
|
// setup room panel cache with the new card
|
||||||
|
roomCache = {
|
||||||
|
history: [{ phase: targetPhase, state: pState ?? {} }],
|
||||||
|
// if there was no right panel store object the the panel was closed -> keep it closed, except if allowClose==false
|
||||||
|
isOpen: !allowClose,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
this.emitAndUpdateSettings();
|
||||||
|
}
|
||||||
|
|
||||||
|
public popCard(roomId: string = null) {
|
||||||
|
const rId = roomId ?? this.viewedRoomId;
|
||||||
|
if (!this.byRoom[rId]) return;
|
||||||
|
|
||||||
|
const removedCard = this.byRoom[rId].history.pop();
|
||||||
|
this.emitAndUpdateSettings();
|
||||||
|
return removedCard;
|
||||||
|
}
|
||||||
|
|
||||||
|
public togglePanel(roomId: string = null) {
|
||||||
|
const rId = roomId ?? this.viewedRoomId;
|
||||||
|
if (!this.byRoom[rId]) return;
|
||||||
|
|
||||||
|
this.byRoom[rId].isOpen = !this.byRoom[rId].isOpen;
|
||||||
|
this.emitAndUpdateSettings();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Private
|
||||||
|
private loadCacheFromSettings() {
|
||||||
|
const room = this.mxClient?.getRoom(this.viewedRoomId);
|
||||||
|
if (!!room) {
|
||||||
|
this.global = this.global ??
|
||||||
|
convertToStatePanel(SettingsStore.getValue("RightPanel.phasesGlobal"), room);
|
||||||
|
this.byRoom[this.viewedRoomId] = this.byRoom[this.viewedRoomId] ??
|
||||||
|
convertToStatePanel(SettingsStore.getValue("RightPanel.phases", this.viewedRoomId), room);
|
||||||
|
} else {
|
||||||
|
console.warn("Could not restore the right panel after load because there was no associated room object." +
|
||||||
|
"The right panel can only be restored for rooms and spaces but not for groups");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private compareCards(a: IRightPanelCard, b: IRightPanelCard): boolean {
|
||||||
|
return JSON.stringify(convertCardToStore(a)) == JSON.stringify(convertCardToStore(b));
|
||||||
|
}
|
||||||
|
|
||||||
|
private emitAndUpdateSettings() {
|
||||||
|
const storePanelGlobal = convertToStorePanel(this.global);
|
||||||
|
SettingsStore.setValue("RightPanel.phasesGlobal", null, SettingLevel.DEVICE, storePanelGlobal);
|
||||||
|
|
||||||
|
if (!!this.viewedRoomId) {
|
||||||
|
const storePanelThisRoom = convertToStorePanel(this.byRoom[this.viewedRoomId]);
|
||||||
|
SettingsStore.setValue(
|
||||||
|
"RightPanel.phases",
|
||||||
|
this.viewedRoomId,
|
||||||
|
SettingLevel.ROOM_DEVICE,
|
||||||
|
storePanelThisRoom,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
this.emit(UPDATE_EVENT, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
private setRightPanelCache(card: IRightPanelCard, roomId?: string) {
|
||||||
|
this.byRoom[roomId ?? this.viewedRoomId] = {
|
||||||
|
history: [{ phase: card.phase, state: card.state ?? {} }],
|
||||||
|
isOpen: true,
|
||||||
|
};
|
||||||
|
this.emitAndUpdateSettings();
|
||||||
|
}
|
||||||
|
|
||||||
|
private getVerificationRedirect(card: IRightPanelCard): IRightPanelCard {
|
||||||
|
if (card.phase === RightPanelPhases.RoomMemberInfo && card.state) {
|
||||||
|
// RightPanelPhases.RoomMemberInfo -> needs to be changed to RightPanelPhases.EncryptionPanel if there is a pending verification request
|
||||||
|
const { member } = card.state;
|
||||||
|
const pendingRequest = pendingVerificationRequestForUser(member);
|
||||||
|
if (pendingRequest) {
|
||||||
|
return {
|
||||||
|
phase: RightPanelPhases.EncryptionPanel,
|
||||||
|
state: {
|
||||||
|
verificationRequest: pendingRequest,
|
||||||
|
member,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private isPhaseActionIsValid(targetPhase) {
|
||||||
|
if (!RightPanelPhases[targetPhase]) {
|
||||||
|
logger.warn(`Tried to switch right panel to unknown phase: ${targetPhase}`);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (GROUP_PHASES.includes(targetPhase) && this.isViewingRoom) {
|
||||||
|
logger.warn(
|
||||||
|
`Tried to switch right panel to a group phase: ${targetPhase}, ` +
|
||||||
|
`but we are currently not viewing a group`,
|
||||||
|
);
|
||||||
|
return false;
|
||||||
|
} else if (!GROUP_PHASES.includes(targetPhase) && !this.isViewingRoom) {
|
||||||
|
logger.warn(
|
||||||
|
`Tried to switch right panel to a room phase: ${targetPhase}, ` +
|
||||||
|
`but we are currently not viewing a room`,
|
||||||
|
);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private onVerificationRequestUpdate = () => {
|
||||||
|
const { member } = this.currentCard.state;
|
||||||
|
const pendingRequest = pendingVerificationRequestForUser(member);
|
||||||
|
if (pendingRequest) {
|
||||||
|
this.currentCard.state.verificationRequest = pendingRequest;
|
||||||
|
this.emitAndUpdateSettings();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
onRoomViewStoreUpdate() {
|
||||||
|
// TODO: use this function instead of the onDispatch (the whole onDispatch can get removed!) as soon groups are removed
|
||||||
|
// this.viewedRoomId = RoomViewStore.getRoomId();
|
||||||
|
// this.isViewingRoom = true; // Is viewing room will of course be removed when removing groups
|
||||||
|
// // load values from byRoomCache with the viewedRoomId.
|
||||||
|
// this.loadCacheFromSettings();
|
||||||
|
}
|
||||||
|
|
||||||
|
onDispatch(payload: ActionPayload) {
|
||||||
|
switch (payload.action) {
|
||||||
|
case 'view_group':
|
||||||
|
case Action.ViewRoom: {
|
||||||
|
const _this = RightPanelStore.instance;
|
||||||
|
if (payload.room_id === _this.viewedRoomId) break; // skip this transition, probably a permalink
|
||||||
|
|
||||||
|
// Put group in the same/similar view to what was open from the previously viewed room
|
||||||
|
// Is contradictory to the new "per room" philosophy but it is the legacy behavior for groups.
|
||||||
|
if ((_this.isViewingRoom ? Action.ViewRoom : "view_group") != payload.action) {
|
||||||
|
if (payload.action == Action.ViewRoom && MEMBER_INFO_PHASES.includes(_this.currentCard?.phase)) {
|
||||||
|
// switch from group to room
|
||||||
|
_this.setRightPanelCache({ phase: RightPanelPhases.RoomMemberList, state: {} });
|
||||||
|
} else if (
|
||||||
|
payload.action == "view_group" &&
|
||||||
|
_this.currentCard?.phase === RightPanelPhases.GroupMemberInfo
|
||||||
|
) {
|
||||||
|
// switch from room to group
|
||||||
|
_this.setRightPanelCache({ phase: RightPanelPhases.GroupMemberList, state: {} });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update the current room here, so that all the other functions dont need to be room dependant.
|
||||||
|
// The right panel store always will return the state for the current room.
|
||||||
|
_this.viewedRoomId = payload.room_id;
|
||||||
|
_this.isViewingRoom = payload.action == Action.ViewRoom;
|
||||||
|
// load values from byRoomCache with the viewedRoomId.
|
||||||
|
if (!!_this.roomStoreToken) {
|
||||||
|
// skip loading here since we need the client to be ready to get the events form the ids of the settings
|
||||||
|
// this loading will be done in the onReady function
|
||||||
|
// all the logic in this case is not necessary anymore as soon as groups are dropped and we use: onRoomViewStoreUpdate
|
||||||
|
_this.loadCacheFromSettings();
|
||||||
|
_this.emitAndUpdateSettings();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static get instance(): RightPanelStore {
|
||||||
|
if (!RightPanelStore.internalInstance) {
|
||||||
|
RightPanelStore.internalInstance = new RightPanelStore();
|
||||||
|
}
|
||||||
|
return RightPanelStore.internalInstance;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
window.mxRightPanelStore = RightPanelStore.instance;
|
136
src/stores/right-panel/RightPanelStoreIPanelState.ts
Normal file
136
src/stores/right-panel/RightPanelStoreIPanelState.ts
Normal file
|
@ -0,0 +1,136 @@
|
||||||
|
/*
|
||||||
|
Copyright 2021 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 { MatrixEvent } from "matrix-js-sdk/src/models/event";
|
||||||
|
import { User } from "matrix-js-sdk/src/models/user";
|
||||||
|
import { Room } from "matrix-js-sdk/src/models/room";
|
||||||
|
import { RoomMember } from "matrix-js-sdk/src/models/room-member";
|
||||||
|
import { VerificationRequest } from "matrix-js-sdk/src/crypto/verification/request/VerificationRequest";
|
||||||
|
|
||||||
|
import { GroupMember } from "../../components/views/right_panel/UserInfo";
|
||||||
|
import { RightPanelPhases } from "./RightPanelStorePhases";
|
||||||
|
|
||||||
|
export interface IRightPanelCardState {
|
||||||
|
member?: RoomMember | User | GroupMember;
|
||||||
|
verificationRequest?: VerificationRequest;
|
||||||
|
verificationRequestPromise?: Promise<VerificationRequest>;
|
||||||
|
// group
|
||||||
|
groupId?: string;
|
||||||
|
groupRoomId?: string;
|
||||||
|
widgetId?: string;
|
||||||
|
spaceId?: string;
|
||||||
|
// Room3pidMemberInfo, Space3pidMemberInfo,
|
||||||
|
memberInfoEvent?: MatrixEvent;
|
||||||
|
// threads
|
||||||
|
threadHeadEvent?: MatrixEvent;
|
||||||
|
initialEvent?: MatrixEvent;
|
||||||
|
isInitialEventHighlighted?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface IRightPanelCardStateStored {
|
||||||
|
memberId?: string;
|
||||||
|
// we do not store the things associated with verification
|
||||||
|
// group
|
||||||
|
groupId?: string;
|
||||||
|
groupRoomId?: string;
|
||||||
|
widgetId?: string;
|
||||||
|
spaceId?: string;
|
||||||
|
// 3pidMemberInfo
|
||||||
|
memberInfoEventId?: string;
|
||||||
|
// threads
|
||||||
|
threadHeadEventId?: string;
|
||||||
|
initialEventId?: string;
|
||||||
|
isInitialEventHighlighted?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface IRightPanelCard {
|
||||||
|
phase: RightPanelPhases;
|
||||||
|
state?: IRightPanelCardState;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface IRightPanelCardStored {
|
||||||
|
phase: RightPanelPhases;
|
||||||
|
state?: IRightPanelCardStateStored;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface IRightPanelForRoom {
|
||||||
|
isOpen: boolean;
|
||||||
|
history: Array<IRightPanelCard>;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface IRightPanelForRoomStored {
|
||||||
|
isOpen: boolean;
|
||||||
|
history: Array<IRightPanelCardStored>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function convertToStorePanel(cacheRoom: IRightPanelForRoom): IRightPanelForRoomStored {
|
||||||
|
if (!cacheRoom) return cacheRoom;
|
||||||
|
const storeHistory = [...cacheRoom.history].map(panelState => convertCardToStore(panelState));
|
||||||
|
return { isOpen: cacheRoom.isOpen, history: storeHistory };
|
||||||
|
}
|
||||||
|
|
||||||
|
export function convertToStatePanel(storeRoom: IRightPanelForRoomStored, room: Room): IRightPanelForRoom {
|
||||||
|
if (!storeRoom) return storeRoom;
|
||||||
|
const stateHistory = [...storeRoom.history].map(panelStateStore => convertStoreToCard(panelStateStore, room));
|
||||||
|
return { history: stateHistory, isOpen: storeRoom.isOpen };
|
||||||
|
}
|
||||||
|
|
||||||
|
export function convertCardToStore(panelState: IRightPanelCard): IRightPanelCardStored {
|
||||||
|
const panelStateThisRoomStored = { ...panelState.state } as any;
|
||||||
|
if (!!panelState?.state?.threadHeadEvent?.getId()) {
|
||||||
|
panelStateThisRoomStored.threadHeadEventId = panelState.state.threadHeadEvent.getId();
|
||||||
|
}
|
||||||
|
if (!!panelState?.state?.memberInfoEvent?.getId()) {
|
||||||
|
panelStateThisRoomStored.memberInfoEventId = panelState.state.memberInfoEvent.getId();
|
||||||
|
}
|
||||||
|
if (!!panelState?.state?.initialEvent?.getId()) {
|
||||||
|
panelStateThisRoomStored.initialEventId = panelState.state.initialEvent.getId();
|
||||||
|
}
|
||||||
|
if (!!panelState?.state?.member?.userId) {
|
||||||
|
panelStateThisRoomStored.memberId = panelState.state.member.userId;
|
||||||
|
}
|
||||||
|
delete panelStateThisRoomStored.threadHeadEvent;
|
||||||
|
delete panelStateThisRoomStored.initialEvent;
|
||||||
|
delete panelStateThisRoomStored.memberInfoEvent;
|
||||||
|
delete panelStateThisRoomStored.verificationRequest;
|
||||||
|
delete panelStateThisRoomStored.verificationRequestPromise;
|
||||||
|
delete panelStateThisRoomStored.member;
|
||||||
|
|
||||||
|
const storedCard = { state: panelStateThisRoomStored as IRightPanelCardStored, phase: panelState.phase };
|
||||||
|
return storedCard as IRightPanelCardStored;
|
||||||
|
}
|
||||||
|
|
||||||
|
function convertStoreToCard(panelStateStore: IRightPanelCardStored, room: Room): IRightPanelCard {
|
||||||
|
const panelStateThisRoom = { ...panelStateStore?.state } as any;
|
||||||
|
if (!!panelStateThisRoom.threadHeadEventId) {
|
||||||
|
panelStateThisRoom.threadHeadEvent = room.findEventById(panelStateThisRoom.threadHeadEventId);
|
||||||
|
}
|
||||||
|
if (!!panelStateThisRoom.memberInfoEventId) {
|
||||||
|
panelStateThisRoom.memberInfoEvent = room.findEventById(panelStateThisRoom.memberInfoEventId);
|
||||||
|
}
|
||||||
|
if (!!panelStateThisRoom.initialEventId) {
|
||||||
|
panelStateThisRoom.initialEvent = room.findEventById(panelStateThisRoom.initialEventId);
|
||||||
|
}
|
||||||
|
if (!!panelStateThisRoom.memberId) {
|
||||||
|
panelStateThisRoom.member = room.getMember(panelStateThisRoom.memberId);
|
||||||
|
}
|
||||||
|
delete panelStateThisRoom.threadHeadEventId;
|
||||||
|
delete panelStateThisRoom.initialEventId;
|
||||||
|
delete panelStateThisRoom.memberInfoEventId;
|
||||||
|
delete panelStateThisRoom.memberId;
|
||||||
|
|
||||||
|
return { state: panelStateThisRoom as IRightPanelCardState, phase: panelStateStore.phase } as IRightPanelCard;
|
||||||
|
}
|
|
@ -16,17 +16,18 @@ limitations under the License.
|
||||||
|
|
||||||
import { User } from "matrix-js-sdk/src/models/user";
|
import { User } from "matrix-js-sdk/src/models/user";
|
||||||
import { verificationMethods as VerificationMethods } from 'matrix-js-sdk/src/crypto';
|
import { verificationMethods as VerificationMethods } from 'matrix-js-sdk/src/crypto';
|
||||||
|
import { RoomMember } from "matrix-js-sdk/src/matrix";
|
||||||
|
|
||||||
import { MatrixClientPeg } from './MatrixClientPeg';
|
import { MatrixClientPeg } from './MatrixClientPeg';
|
||||||
import dis from "./dispatcher/dispatcher";
|
import dis from "./dispatcher/dispatcher";
|
||||||
import Modal from './Modal';
|
import Modal from './Modal';
|
||||||
import { RightPanelPhases } from "./stores/RightPanelStorePhases";
|
import { RightPanelPhases } from "./stores/right-panel/RightPanelStorePhases";
|
||||||
import { findDMForUser } from './createRoom';
|
import { findDMForUser } from './createRoom';
|
||||||
import { accessSecretStorage } from './SecurityManager';
|
import { accessSecretStorage } from './SecurityManager';
|
||||||
import { Action } from './dispatcher/actions';
|
|
||||||
import UntrustedDeviceDialog from "./components/views/dialogs/UntrustedDeviceDialog";
|
import UntrustedDeviceDialog from "./components/views/dialogs/UntrustedDeviceDialog";
|
||||||
import { IDevice } from "./components/views/right_panel/UserInfo";
|
import { GroupMember, IDevice } from "./components/views/right_panel/UserInfo";
|
||||||
import ManualDeviceKeyVerificationDialog from "./components/views/dialogs/ManualDeviceKeyVerificationDialog";
|
import ManualDeviceKeyVerificationDialog from "./components/views/dialogs/ManualDeviceKeyVerificationDialog";
|
||||||
|
import RightPanelStore from "./stores/right-panel/RightPanelStore";
|
||||||
|
|
||||||
async function enable4SIfNeeded() {
|
async function enable4SIfNeeded() {
|
||||||
const cli = MatrixClientPeg.get();
|
const cli = MatrixClientPeg.get();
|
||||||
|
@ -65,10 +66,9 @@ export async function verifyDevice(user: User, device: IDevice) {
|
||||||
device.deviceId,
|
device.deviceId,
|
||||||
VerificationMethods.SAS,
|
VerificationMethods.SAS,
|
||||||
);
|
);
|
||||||
dis.dispatch({
|
RightPanelStore.instance.setCard({
|
||||||
action: Action.SetRightPanelPhase,
|
|
||||||
phase: RightPanelPhases.EncryptionPanel,
|
phase: RightPanelPhases.EncryptionPanel,
|
||||||
refireParams: { member: user, verificationRequestPromise },
|
state: { member: user, verificationRequestPromise },
|
||||||
});
|
});
|
||||||
} else if (action === "legacy") {
|
} else if (action === "legacy") {
|
||||||
Modal.createTrackedDialog("Legacy verify session", "legacy verify session",
|
Modal.createTrackedDialog("Legacy verify session", "legacy verify session",
|
||||||
|
@ -96,10 +96,9 @@ export async function legacyVerifyUser(user: User) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const verificationRequestPromise = cli.requestVerification(user.userId);
|
const verificationRequestPromise = cli.requestVerification(user.userId);
|
||||||
dis.dispatch({
|
RightPanelStore.instance.setCard({
|
||||||
action: Action.SetRightPanelPhase,
|
|
||||||
phase: RightPanelPhases.EncryptionPanel,
|
phase: RightPanelPhases.EncryptionPanel,
|
||||||
refireParams: { member: user, verificationRequestPromise },
|
state: { member: user, verificationRequestPromise },
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -113,17 +112,13 @@ export async function verifyUser(user: User) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const existingRequest = pendingVerificationRequestForUser(user);
|
const existingRequest = pendingVerificationRequestForUser(user);
|
||||||
dis.dispatch({
|
RightPanelStore.instance.setCard({
|
||||||
action: Action.SetRightPanelPhase,
|
|
||||||
phase: RightPanelPhases.EncryptionPanel,
|
phase: RightPanelPhases.EncryptionPanel,
|
||||||
refireParams: {
|
state: { member: user, verificationRequest: existingRequest },
|
||||||
member: user,
|
|
||||||
verificationRequest: existingRequest,
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export function pendingVerificationRequestForUser(user: User) {
|
export function pendingVerificationRequestForUser(user: User | RoomMember | GroupMember ) {
|
||||||
const cli = MatrixClientPeg.get();
|
const cli = MatrixClientPeg.get();
|
||||||
const dmRoom = findDMForUser(cli, user.userId);
|
const dmRoom = findDMForUser(cli, user.userId);
|
||||||
if (dmRoom) {
|
if (dmRoom) {
|
||||||
|
|
Loading…
Reference in a new issue