diff --git a/src/components/views/messages/MessageActionBar.tsx b/src/components/views/messages/MessageActionBar.tsx
index f76fa32ddc..06817b910a 100644
--- a/src/components/views/messages/MessageActionBar.tsx
+++ b/src/components/views/messages/MessageActionBar.tsx
@@ -17,7 +17,8 @@ limitations under the License.
*/
import React, { useEffect } from 'react';
-import { MatrixEvent, EventStatus } from 'matrix-js-sdk/src/models/event';
+import { EventStatus, MatrixEvent } from 'matrix-js-sdk/src/models/event';
+import type { Relations } from 'matrix-js-sdk/src/models/relations';
import { _t } from '../../../languageHandler';
import * as sdk from '../../../index';
@@ -35,13 +36,17 @@ import Resend from "../../../Resend";
import { MatrixClientPeg } from "../../../MatrixClientPeg";
import { MediaEventHelper } from "../../../utils/MediaEventHelper";
import DownloadActionButton from "./DownloadActionButton";
+import MessageContextMenu from "../context_menus/MessageContextMenu";
+import classNames from 'classnames';
+
import SettingsStore from '../../../settings/SettingsStore';
import { RoomPermalinkCreator } from '../../../utils/permalinks/Permalinks';
import ReplyThread from '../elements/ReplyThread';
interface IOptionsButtonProps {
mxEvent: MatrixEvent;
- getTile: () => any; // TODO: FIXME, haven't figured out what the return type is here
+ // TODO: Types
+ getTile: () => any | null;
getReplyThread: () => ReplyThread;
permalinkCreator: RoomPermalinkCreator;
onFocusChange: (menuDisplayed: boolean) => void;
@@ -57,8 +62,6 @@ const OptionsButton: React.FC
=
let contextMenu;
if (menuDisplayed) {
- const MessageContextMenu = sdk.getComponent('context_menus.MessageContextMenu');
-
const tile = getTile && getTile();
const replyThread = getReplyThread && getReplyThread();
@@ -90,7 +93,7 @@ const OptionsButton: React.FC =
interface IReactButtonProps {
mxEvent: MatrixEvent;
- reactions: any; // TODO: types
+ reactions: Relations;
onFocusChange: (menuDisplayed: boolean) => void;
}
@@ -125,20 +128,32 @@ const ReactButton: React.FC = ({ mxEvent, reactions, onFocusC
;
};
+export enum ActionBarRenderingContext {
+ Room,
+ Thread
+}
+
interface IMessageActionBarProps {
mxEvent: MatrixEvent;
- // The Relations model from the JS SDK for reactions to `mxEvent`
- reactions?: any; // TODO: types
+ reactions?: Relations;
+ // TODO: Types
+ getTile: () => any | null;
+ getReplyThread: () => ReplyThread | undefined;
permalinkCreator?: RoomPermalinkCreator;
- getTile: () => any; // TODO: FIXME, haven't figured out what the return type is here
- getReplyThread?: () => ReplyThread;
onFocusChange?: (menuDisplayed: boolean) => void;
+ toggleThreadExpanded: () => void;
+ renderingContext?: ActionBarRenderingContext;
+ isQuoteExpanded?: boolean;
}
@replaceableComponent("views.messages.MessageActionBar")
export default class MessageActionBar extends React.PureComponent {
public static contextType = RoomContext;
+ public static defaultProps = {
+ renderingContext: ActionBarRenderingContext.Room,
+ };
+
public componentDidMount(): void {
if (this.props.mxEvent.status && this.props.mxEvent.status !== EventStatus.SENT) {
this.props.mxEvent.on("Event.status", this.onSent);
@@ -283,7 +298,7 @@ export default class MessageActionBar extends React.PureComponent
);
+ }
+
// The menu button should be last, so dump it there.
toolbarOpts.push( {
// If it's less than 30% we don't add the expansion button.
// We also round the number as it sometimes can be 29.99...
const percentageOfViewport = Math.round(pre.offsetHeight / UIStore.instance.windowHeight * 100);
+ // TODO: additionally show the button if it's an expanded quoted message
if (percentageOfViewport < 30) return;
const button = document.createElement("span");
diff --git a/src/components/views/rooms/AuxPanel.tsx b/src/components/views/rooms/AuxPanel.tsx
index 4a62d6711e..7afa29624a 100644
--- a/src/components/views/rooms/AuxPanel.tsx
+++ b/src/components/views/rooms/AuxPanel.tsx
@@ -15,7 +15,6 @@ limitations under the License.
*/
import React from 'react';
-import classNames from 'classnames';
import { lexicographicCompare } from 'matrix-js-sdk/src/utils';
import { Room } from 'matrix-js-sdk/src/models/room';
@@ -35,16 +34,6 @@ interface IProps {
room: Room;
userId: string;
showApps: boolean; // Render apps
-
- // maxHeight attribute for the aux panel and the video
- // therein
- maxHeight: number;
-
- // a callback which is called when the content of the aux panel changes
- // content in a way that is likely to make it change size.
- onResize: () => void;
- fullHeight: boolean;
-
resizeNotifier: ResizeNotifier;
}
@@ -92,13 +81,6 @@ export default class AuxPanel extends React.Component {
return objectHasDiff(this.props, nextProps) || objectHasDiff(this.state, nextState);
}
- componentDidUpdate(prevProps, prevState) {
- // most changes are likely to cause a resize
- if (this.props.onResize) {
- this.props.onResize();
- }
- }
-
private rateLimitedUpdate = throttle(() => {
this.setState({ counters: this.computeCounters() });
}, 500, { leading: true, trailing: true });
@@ -138,7 +120,6 @@ export default class AuxPanel extends React.Component {
const callView = (
);
@@ -148,7 +129,6 @@ export default class AuxPanel extends React.Component {
appsDrawer = ;
@@ -204,21 +184,12 @@ export default class AuxPanel extends React.Component {
}
}
- const classes = classNames({
- "mx_RoomView_auxPanel": true,
- "mx_RoomView_auxPanel_fullHeight": this.props.fullHeight,
- });
- const style: React.CSSProperties = {};
- if (!this.props.fullHeight) {
- style.maxHeight = this.props.maxHeight;
- }
-
return (
-
+
{ stateViews }
+ { this.props.children }
{ appsDrawer }
{ callView }
- { this.props.children }
);
}
diff --git a/src/components/views/rooms/EditMessageComposer.tsx b/src/components/views/rooms/EditMessageComposer.tsx
index f2f80b7670..33273f1f95 100644
--- a/src/components/views/rooms/EditMessageComposer.tsx
+++ b/src/components/views/rooms/EditMessageComposer.tsx
@@ -42,6 +42,7 @@ import ErrorDialog from "../dialogs/ErrorDialog";
import QuestionDialog from "../dialogs/QuestionDialog";
import { ActionPayload } from "../../../dispatcher/payloads";
import AccessibleButton from '../elements/AccessibleButton';
+import { createRedactEventDialog } from '../dialogs/ConfirmRedactDialog';
import SettingsStore from "../../../settings/SettingsStore";
import { logger } from "matrix-js-sdk/src/logger";
@@ -331,6 +332,14 @@ export default class EditMessageComposer extends React.Component
let shouldSend = true;
+ if (newContent?.body === '') {
+ this.cancelPreviousPendingEdit();
+ createRedactEventDialog({
+ mxEvent: editedEvent,
+ });
+ return;
+ }
+
// If content is modified then send an updated event into the room
if (this.isContentModified(newContent)) {
const roomId = editedEvent.getRoomId();
diff --git a/src/components/views/rooms/EventTile.tsx b/src/components/views/rooms/EventTile.tsx
index d1ac06b199..27cf7d761f 100644
--- a/src/components/views/rooms/EventTile.tsx
+++ b/src/components/views/rooms/EventTile.tsx
@@ -53,7 +53,7 @@ import SenderProfile from '../messages/SenderProfile';
import MessageTimestamp from '../messages/MessageTimestamp';
import TooltipButton from '../elements/TooltipButton';
import ReadReceiptMarker from "./ReadReceiptMarker";
-import MessageActionBar from "../messages/MessageActionBar";
+import MessageActionBar, { ActionBarRenderingContext } from "../messages/MessageActionBar";
import ReactionsRow from '../messages/ReactionsRow';
import { getEventDisplayInfo } from '../../../utils/EventUtils';
import { RightPanelPhases } from "../../../stores/RightPanelStorePhases";
@@ -192,6 +192,7 @@ export enum TileShape {
Notif = "notif",
FileGrid = "file_grid",
Pinned = "pinned",
+ Thread = "thread",
}
interface IProps {
@@ -322,7 +323,7 @@ interface IState {
reactions: Relations;
hover: boolean;
-
+ isQuoteExpanded?: boolean;
thread?: Thread;
}
@@ -330,7 +331,8 @@ interface IState {
export default class EventTile extends React.Component {
private suppressReadReceiptAnimation: boolean;
private isListeningForReceipts: boolean;
- private tile = React.createRef();
+ // TODO: Types
+ private tile = React.createRef();
private replyThread = React.createRef();
public readonly ref = createRef();
@@ -888,8 +890,8 @@ export default class EventTile extends React.Component {
actionBarFocused: focused,
});
};
-
- getTile = () => this.tile.current;
+ // TODO: Types
+ getTile: () => any | null = () => this.tile.current;
getReplyThread = () => this.replyThread.current;
@@ -914,6 +916,11 @@ export default class EventTile extends React.Component {
});
};
+ private setQuoteExpanded = (expanded: boolean) => {
+ this.setState({
+ isQuoteExpanded: expanded,
+ });
+ };
render() {
const msgtype = this.props.mxEvent.getContent().msgtype;
const eventType = this.props.mxEvent.getType() as EventType;
@@ -923,6 +930,7 @@ export default class EventTile extends React.Component {
isInfoMessage,
isLeftAlignedBubbleMessage,
} = getEventDisplayInfo(this.props.mxEvent);
+ const { isQuoteExpanded } = this.state;
// This shouldn't happen: the caller should check we support this type
// before trying to instantiate us
@@ -935,6 +943,7 @@ export default class EventTile extends React.Component {
;
}
+
const EventTileType = sdk.getComponent(tileHandler);
const isSending = (['sending', 'queued', 'encrypting'].indexOf(this.props.eventSendStatus) !== -1);
@@ -1047,6 +1056,9 @@ export default class EventTile extends React.Component