diff --git a/src/components/structures/RoomView.tsx b/src/components/structures/RoomView.tsx index db7d7acd90..c2e071b836 100644 --- a/src/components/structures/RoomView.tsx +++ b/src/components/structures/RoomView.tsx @@ -779,7 +779,10 @@ export class RoomView extends React.Component { }); break; case 'reply_to_event': - if (this.state.searchResults && payload.event.getRoomId() === this.state.roomId && !this.unmounted) { + if (this.state.searchResults + && payload.event.getRoomId() === this.state.roomId + && !this.unmounted + && payload.context === TimelineRenderingType.Room) { this.onCancelSearchClick(); } break; diff --git a/src/components/structures/ThreadPanel.tsx b/src/components/structures/ThreadPanel.tsx index 40e9479251..2c3cba683b 100644 --- a/src/components/structures/ThreadPanel.tsx +++ b/src/components/structures/ThreadPanel.tsx @@ -15,7 +15,6 @@ limitations under the License. */ import React, { useContext, useEffect, useMemo, useRef, useState } from 'react'; -import { MatrixEvent } from 'matrix-js-sdk/src/models/event'; import { Thread, ThreadEvent } from 'matrix-js-sdk/src/models/thread'; import { EventTimelineSet } from 'matrix-js-sdk/src/models/event-timeline-set'; import { Room } from 'matrix-js-sdk/src/models/room'; @@ -24,7 +23,6 @@ import BaseCard from "../views/right_panel/BaseCard"; import { RightPanelPhases } from "../../stores/RightPanelStorePhases"; import ResizeNotifier from '../../utils/ResizeNotifier'; -import EventTile, { TileShape } from '../views/rooms/EventTile'; import MatrixClientContext from '../../contexts/MatrixClientContext'; import { _t } from '../../languageHandler'; import { ContextMenuButton } from '../../accessibility/context_menu/ContextMenuButton'; @@ -34,6 +32,7 @@ import TimelinePanel from './TimelinePanel'; import { Layout } from '../../settings/Layout'; import { useEventEmitter } from '../../hooks/useEventEmitter'; import AccessibleButton from '../views/elements/AccessibleButton'; +import { TileShape } from '../views/rooms/EventTile'; interface IProps { roomId: string; @@ -41,18 +40,6 @@ interface IProps { resizeNotifier: ResizeNotifier; } -export const ThreadPanelItem: React.FC<{ event: MatrixEvent }> = ({ event }) => { - return ; -}; - export enum ThreadFilterType { "My", "All" @@ -230,7 +217,7 @@ const ThreadPanel: React.FC = ({ roomId, onClose }) => { showReactions={true} className="mx_RoomView_messagePanel mx_GroupLayout" membersLoaded={true} - tileShape={TileShape.ThreadPanel} + tileShape={TileShape.Thread} /> diff --git a/src/components/structures/ThreadView.tsx b/src/components/structures/ThreadView.tsx index 7bd6415cd3..b0851665a7 100644 --- a/src/components/structures/ThreadView.tsx +++ b/src/components/structures/ThreadView.tsx @@ -50,6 +50,7 @@ interface IProps { interface IState { thread?: Thread; editState?: EditorStateTransfer; + replyToEvent?: MatrixEvent; } @replaceableComponent("structures.ThreadView") @@ -114,6 +115,13 @@ export default class ThreadView extends React.Component { }); break; } + case 'reply_to_event': + if (payload.context === TimelineRenderingType.Thread) { + this.setState({ + replyToEvent: payload.event, + }); + } + break; default: break; } @@ -199,7 +207,7 @@ export default class ThreadView extends React.Component { rel_type: RelationType.Thread, event_id: this.state.thread.id, }} - showReplyPreview={false} + replyToEvent={this.state.replyToEvent} permalinkCreator={this.props.permalinkCreator} e2eStatus={this.props.e2eStatus} compact={true} diff --git a/src/components/views/messages/MessageActionBar.tsx b/src/components/views/messages/MessageActionBar.tsx index dffe8be7a6..56ae08453c 100644 --- a/src/components/views/messages/MessageActionBar.tsx +++ b/src/components/views/messages/MessageActionBar.tsx @@ -63,7 +63,7 @@ const OptionsButton: React.FC = let contextMenu; if (menuDisplayed) { const tile = getTile && getTile(); - const replyThread = getReplyChain && getReplyChain(); + const replyChain = getReplyChain && getReplyChain(); const buttonRect = button.current.getBoundingClientRect(); contextMenu = = mxEvent={mxEvent} permalinkCreator={permalinkCreator} eventTileOps={tile && tile.getEventTileOps ? tile.getEventTileOps() : undefined} - collapseReplyChain={replyThread && replyThread.canCollapse() ? replyThread.collapse : undefined} + collapseReplyChain={replyChain && replyChain.canCollapse() ? replyChain.collapse : undefined} onFinished={closeMenu} />; } @@ -191,6 +191,7 @@ export default class MessageActionBar extends React.PureComponent - { SettingsStore.getValue("feature_thread") && ( + { (SettingsStore.getValue("feature_thread") + && this.context.timelineRenderingType !== TimelineRenderingType.Thread) && ( { private isListeningForReceipts: boolean; // TODO: Types private tile = React.createRef(); - private replyThread = React.createRef(); + private replyChain = React.createRef(); public readonly ref = createRef(); @@ -933,7 +933,7 @@ export default class EventTile extends React.Component { // TODO: Types getTile: () => any | null = () => this.tile.current; - getReplyChain = () => this.replyThread.current; + getReplyChain = () => this.replyChain.current; getReactions = () => { if ( @@ -1214,12 +1214,26 @@ export default class EventTile extends React.Component { ]); } case TileShape.Thread: { + const thread = haveTileForEvent(this.props.mxEvent) && + ReplyChain.hasReply(this.props.mxEvent) ? ( + ) : null; const room = this.context.getRoom(this.props.mxEvent.getRoomId()); return React.createElement(this.props.as || "li", { "className": classes, "aria-live": ariaLive, "aria-atomic": true, "data-scroll-tokens": scrollToken, + "data-has-reply": !!thread, }, [
@@ -1235,6 +1249,7 @@ export default class EventTile extends React.Component {
,
+ { thread } { { private ref: React.RefObject = createRef(); private instanceId: number; + public static contextType = RoomContext; + static defaultProps = { - showReplyPreview: true, compact: false, }; @@ -294,7 +295,7 @@ export default class MessageComposer extends React.Component { }; private onAction = (payload: ActionPayload) => { - if (payload.action === 'reply_to_event') { + if (payload.action === 'reply_to_event' && payload.context === this.context.timelineRenderingType) { // add a timeout for the reply preview to be rendered, so // that the ScrollPanel listening to the resizeNotifier can // correctly measure it's new height and scroll down to keep @@ -633,9 +634,9 @@ export default class MessageComposer extends React.Component {
{ recordingTooltip }
- { this.props.showReplyPreview && ( - - ) } +
{ controls } { this.renderButtons(menuPosition) } diff --git a/src/components/views/rooms/ReplyPreview.tsx b/src/components/views/rooms/ReplyPreview.tsx index 41b3d2460c..a1dfddfe19 100644 --- a/src/components/views/rooms/ReplyPreview.tsx +++ b/src/components/views/rooms/ReplyPreview.tsx @@ -17,63 +17,31 @@ limitations under the License. import React from 'react'; import dis from '../../../dispatcher/dispatcher'; import { _t } from '../../../languageHandler'; -import RoomViewStore from '../../../stores/RoomViewStore'; import { RoomPermalinkCreator } from "../../../utils/permalinks/Permalinks"; import { replaceableComponent } from "../../../utils/replaceableComponent"; import ReplyTile from './ReplyTile'; import { MatrixEvent } from 'matrix-js-sdk/src/models/event'; -import { EventSubscription } from 'fbemitter'; +import RoomContext, { TimelineRenderingType } from '../../../contexts/RoomContext'; -function cancelQuoting() { +function cancelQuoting(context: TimelineRenderingType) { dis.dispatch({ action: 'reply_to_event', event: null, + context, }); } interface IProps { permalinkCreator: RoomPermalinkCreator; -} - -interface IState { - event: MatrixEvent; + replyToEvent: MatrixEvent; } @replaceableComponent("views.rooms.ReplyPreview") -export default class ReplyPreview extends React.Component { - private unmounted = false; - private readonly roomStoreToken: EventSubscription; +export default class ReplyPreview extends React.Component { + public static contextType = RoomContext; - constructor(props) { - super(props); - - this.state = { - event: RoomViewStore.getQuotingEvent(), - }; - - this.roomStoreToken = RoomViewStore.addListener(this.onRoomViewStoreUpdate); - } - - componentWillUnmount() { - this.unmounted = true; - - // Remove RoomStore listener - if (this.roomStoreToken) { - this.roomStoreToken.remove(); - } - } - - private onRoomViewStoreUpdate = (): void => { - if (this.unmounted) return; - - const event = RoomViewStore.getQuotingEvent(); - if (this.state.event !== event) { - this.setState({ event }); - } - }; - - render() { - if (!this.state.event) return null; + public render(): JSX.Element { + if (!this.props.replyToEvent) return null; return
@@ -86,13 +54,13 @@ export default class ReplyPreview extends React.Component { src={require("../../../../res/img/cancel.svg")} width="18" height="18" - onClick={cancelQuoting} + onClick={() => cancelQuoting(this.context.timelineRenderingType)} />
diff --git a/src/components/views/rooms/SendMessageComposer.tsx b/src/components/views/rooms/SendMessageComposer.tsx index 12458d201f..c32a31f249 100644 --- a/src/components/views/rooms/SendMessageComposer.tsx +++ b/src/components/views/rooms/SendMessageComposer.tsx @@ -238,6 +238,7 @@ export class SendMessageComposer extends React.Component({ diff --git a/src/stores/RoomViewStore.tsx b/src/stores/RoomViewStore.tsx index b949ccabcf..1a44b4fb32 100644 --- a/src/stores/RoomViewStore.tsx +++ b/src/stores/RoomViewStore.tsx @@ -32,6 +32,7 @@ import { retry } from "../utils/promise"; import CountlyAnalytics from "../CountlyAnalytics"; import { logger } from "matrix-js-sdk/src/logger"; +import { TimelineRenderingType } from "../contexts/RoomContext"; const NUM_JOIN_RETRY = 5; @@ -153,16 +154,19 @@ class RoomViewStore extends Store { case 'reply_to_event': // If currently viewed room does not match the room in which we wish to reply then change rooms // this can happen when performing a search across all rooms - if (payload.event && payload.event.getRoomId() !== this.state.roomId) { - dis.dispatch({ - action: 'view_room', - room_id: payload.event.getRoomId(), - replyingToEvent: payload.event, - }); - } else { - this.setState({ - replyingToEvent: payload.event, - }); + if (payload.context === TimelineRenderingType.Room) { + if (payload.event + && payload.event.getRoomId() !== this.state.roomId) { + dis.dispatch({ + action: 'view_room', + room_id: payload.event.getRoomId(), + replyingToEvent: payload.event, + }); + } else { + this.setState({ + replyingToEvent: payload.event, + }); + } } break; case 'open_room_settings': { diff --git a/test/components/views/rooms/SendMessageComposer-test.tsx b/test/components/views/rooms/SendMessageComposer-test.tsx index e6bac2b96e..ec4894719e 100644 --- a/test/components/views/rooms/SendMessageComposer-test.tsx +++ b/test/components/views/rooms/SendMessageComposer-test.tsx @@ -216,6 +216,7 @@ describe('', () => { expect(spyDispatcher).toHaveBeenCalledWith({ action: "reply_to_event", event: mockEvent, + context: TimelineRenderingType.Room, }); // now try with localStorage wiped out @@ -277,6 +278,7 @@ describe('', () => { expect(spyDispatcher).toHaveBeenCalledWith({ action: "reply_to_event", event: null, + context: TimelineRenderingType.Room, }); expect(wrapper.text()).toBe("");