diff --git a/src/ContentMessages.tsx b/src/ContentMessages.tsx index 3e37f292d1..78a91efaf4 100644 --- a/src/ContentMessages.tsx +++ b/src/ContentMessages.tsx @@ -24,7 +24,7 @@ import encrypt from "browser-encrypt-attachment"; import extractPngChunks from "png-chunks-extract"; import { IAbortablePromise, IImageInfo } from "matrix-js-sdk/src/@types/partials"; import { logger } from "matrix-js-sdk/src/logger"; -import { IEventRelation } from "matrix-js-sdk/src"; +import { IEventRelation, ISendEventResponse } from "matrix-js-sdk/src"; import { IEncryptedFile, IMediaEventInfo } from "./customisations/models/IMediaEventContent"; import dis from './dispatcher/dispatcher'; @@ -46,6 +46,7 @@ import { IUpload } from "./models/IUpload"; import { BlurhashEncoder } from "./BlurhashEncoder"; import SettingsStore from "./settings/SettingsStore"; import { decorateStartSendingTime, sendRoundTripMetric } from "./sendTimePerformanceMetrics"; +import { TimelineRenderingType } from "./contexts/RoomContext"; const MAX_WIDTH = 800; const MAX_HEIGHT = 600; @@ -421,14 +422,14 @@ export default class ContentMessages { private inprogress: IUpload[] = []; private mediaConfig: IMediaConfig = null; - sendStickerContentToRoom( + public sendStickerContentToRoom( url: string, roomId: string, threadId: string | null, info: IImageInfo, text: string, matrixClient: MatrixClient, - ) { + ): Promise { const startTime = CountlyAnalytics.getTimestamp(); const prom = matrixClient.sendStickerMessage(roomId, threadId, url, info, text).catch((e) => { logger.warn(`Failed to send content with URL ${url} to room ${roomId}`, e); @@ -438,7 +439,7 @@ export default class ContentMessages { return prom; } - getUploadLimit() { + public getUploadLimit(): number | null { if (this.mediaConfig !== null && this.mediaConfig["m.upload.size"] !== undefined) { return this.mediaConfig["m.upload.size"]; } else { @@ -446,12 +447,13 @@ export default class ContentMessages { } } - async sendContentListToRoom( + public async sendContentListToRoom( files: File[], roomId: string, relation: IEventRelation | null, matrixClient: MatrixClient, - ) { + context = TimelineRenderingType.Room, + ): Promise { if (matrixClient.isGuest()) { dis.dispatch({ action: 'require_registration' }); return; @@ -530,9 +532,15 @@ export default class ContentMessages { promBefore = this.sendContentToRoom(file, roomId, relation, matrixClient, promBefore); } + + // Focus the correct composer + dis.dispatch({ + action: Action.FocusSendMessageComposer, + context, + }); } - getCurrentUploads(relation?: IEventRelation) { + public getCurrentUploads(relation?: IEventRelation): IUpload[] { return this.inprogress.filter(upload => { const noRelation = !relation && !upload.relation; const matchingRelation = relation && upload.relation @@ -543,7 +551,7 @@ export default class ContentMessages { }); } - cancelUpload(promise: Promise, matrixClient: MatrixClient) { + public cancelUpload(promise: Promise, matrixClient: MatrixClient): void { let upload: IUpload; for (let i = 0; i < this.inprogress.length; ++i) { if (this.inprogress[i].promise === promise) { @@ -632,9 +640,6 @@ export default class ContentMessages { this.inprogress.push(upload); dis.dispatch({ action: Action.UploadStarted, upload }); - // Focus the composer view - dis.fire(Action.FocusSendMessageComposer); - function onProgress(ev) { upload.total = ev.total; upload.loaded = ev.loaded; diff --git a/src/components/structures/LoggedInView.tsx b/src/components/structures/LoggedInView.tsx index ee25d58589..e98e8c05bc 100644 --- a/src/components/structures/LoggedInView.tsx +++ b/src/components/structures/LoggedInView.tsx @@ -69,6 +69,7 @@ import LegacyCommunityPreview from "./LegacyCommunityPreview"; import { UserTab } from "../views/dialogs/UserSettingsDialog"; import { OpenToTabPayload } from "../../dispatcher/payloads/OpenToTabPayload"; import RightPanelStore from '../../stores/right-panel/RightPanelStore'; +import { TimelineRenderingType } from "../../contexts/RoomContext"; // 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. @@ -386,15 +387,20 @@ class LoggedInView extends React.Component { private onPaste = (ev: ClipboardEvent) => { const element = ev.target as HTMLElement; - const inputableElement = getInputableElement(element) || document.activeElement as HTMLElement; + const inputableElement = getInputableElement(element); + if (inputableElement === document.activeElement) return; // nothing to do if (inputableElement?.focus) { inputableElement.focus(); } else { + const inThread = !!document.activeElement.closest(".mx_ThreadView"); // refocusing during a paste event will make the // paste end up in the newly focused element, // so dispatch synchronously before paste happens - dis.fire(Action.FocusSendMessageComposer, true); + dis.dispatch({ + action: Action.FocusSendMessageComposer, + context: inThread ? TimelineRenderingType.Thread : TimelineRenderingType.Room, + }, true); } }; @@ -552,8 +558,12 @@ class LoggedInView extends React.Component { // If the user is entering a printable character outside of an input field // redirect it to the composer for them. if (!isClickShortcut && isPrintable && !getInputableElement(ev.target as HTMLElement)) { + const inThread = !!document.activeElement.closest(".mx_ThreadView"); // synchronous dispatch so we focus before key generates input - dis.fire(Action.FocusSendMessageComposer, true); + dis.dispatch({ + action: Action.FocusSendMessageComposer, + context: inThread ? TimelineRenderingType.Thread : TimelineRenderingType.Room, + }, true); ev.stopPropagation(); // we should *not* preventDefault() here as that would prevent typing in the now-focused composer } diff --git a/src/components/views/rooms/MessageComposer.tsx b/src/components/views/rooms/MessageComposer.tsx index e553fb26ac..1ae8e3cdd8 100644 --- a/src/components/views/rooms/MessageComposer.tsx +++ b/src/components/views/rooms/MessageComposer.tsx @@ -160,7 +160,11 @@ class UploadButton extends React.Component { } ContentMessages.sharedInstance().sendContentListToRoom( - tfiles, this.props.roomId, this.props.relation, MatrixClientPeg.get(), + tfiles, + this.props.roomId, + this.props.relation, + MatrixClientPeg.get(), + this.context.timelineRenderingType, ); // This is the onChange handler for a file form control, but we're diff --git a/src/components/views/rooms/SendMessageComposer.tsx b/src/components/views/rooms/SendMessageComposer.tsx index 967291d79f..6cbd86179b 100644 --- a/src/components/views/rooms/SendMessageComposer.tsx +++ b/src/components/views/rooms/SendMessageComposer.tsx @@ -560,7 +560,11 @@ export class SendMessageComposer extends React.Component