From dd53b226ebed1d99da5098f558d1360ddb0342e4 Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Mon, 21 Mar 2022 12:03:59 +0000 Subject: [PATCH] Allow sending files as replies as per MSC3676 (#8020) --- ...ContentMessages.tsx => ContentMessages.ts} | 44 +++++++++---------- .../views/rooms/SendMessageComposer.tsx | 30 +------------ src/i18n/strings/en_EN.json | 4 +- src/utils/Reply.ts | 28 ++++++++++++ 4 files changed, 51 insertions(+), 55 deletions(-) rename src/{ContentMessages.tsx => ContentMessages.ts} (96%) diff --git a/src/ContentMessages.tsx b/src/ContentMessages.ts similarity index 96% rename from src/ContentMessages.tsx rename to src/ContentMessages.ts index 9a2b9ac79c..09b080496d 100644 --- a/src/ContentMessages.tsx +++ b/src/ContentMessages.ts @@ -16,7 +16,6 @@ See the License for the specific language governing permissions and limitations under the License. */ -import React from "react"; import { MatrixClient } from "matrix-js-sdk/src/client"; import { IUploadOpts } from "matrix-js-sdk/src/@types/requests"; import { MsgType } from "matrix-js-sdk/src/@types/event"; @@ -24,7 +23,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, ISendEventResponse } from "matrix-js-sdk/src/matrix"; +import { IEventRelation, ISendEventResponse, MatrixEvent } from "matrix-js-sdk/src/matrix"; import { THREAD_RELATION_TYPE } from "matrix-js-sdk/src/models/thread"; import { IEncryptedFile, IMediaEventInfo } from "./customisations/models/IMediaEventContent"; @@ -32,7 +31,6 @@ import dis from './dispatcher/dispatcher'; import * as sdk from './index'; import { _t } from './languageHandler'; import Modal from './Modal'; -import RoomViewStore from './stores/RoomViewStore'; import Spinner from "./components/views/elements/Spinner"; import { Action } from "./dispatcher/actions"; import { @@ -47,6 +45,8 @@ import { BlurhashEncoder } from "./BlurhashEncoder"; import SettingsStore from "./settings/SettingsStore"; import { decorateStartSendingTime, sendRoundTripMetric } from "./sendTimePerformanceMetrics"; import { TimelineRenderingType } from "./contexts/RoomContext"; +import RoomViewStore from "./stores/RoomViewStore"; +import { addReplyToMessageContent } from "./utils/Reply"; const MAX_WIDTH = 800; const MAX_HEIGHT = 600; @@ -457,25 +457,7 @@ export default class ContentMessages { return; } - const isQuoting = Boolean(RoomViewStore.getQuotingEvent()); - if (isQuoting) { - // FIXME: Using an import will result in Element crashing - const QuestionDialog = sdk.getComponent("dialogs.QuestionDialog"); - const { finished } = Modal.createTrackedDialog<[boolean]>('Upload Reply Warning', '', QuestionDialog, { - title: _t('Replying With Files'), - description: ( -
{ _t( - 'At this time it is not possible to reply with a file. ' + - 'Would you like to upload this file without replying?', - ) }
- ), - hasCancelButton: true, - button: _t("Continue"), - }); - const [shouldUpload] = await finished; - if (!shouldUpload) return; - } - + const replyToEvent = RoomViewStore.getQuotingEvent(); if (!this.mediaConfig) { // hot-path optimization to not flash a spinner if we don't need to const modal = Modal.createDialog(Spinner, null, 'mx_Dialog_spinner'); await this.ensureMediaConfigFetched(matrixClient); @@ -528,7 +510,16 @@ export default class ContentMessages { } } - promBefore = this.sendContentToRoom(file, roomId, relation, matrixClient, promBefore); + promBefore = this.sendContentToRoom(file, roomId, relation, matrixClient, replyToEvent, promBefore); + } + + if (replyToEvent) { + // Clear event being replied to + dis.dispatch({ + action: "reply_to_event", + event: null, + context, + }); } // Focus the correct composer @@ -569,6 +560,7 @@ export default class ContentMessages { roomId: string, relation: IEventRelation | undefined, matrixClient: MatrixClient, + replyToEvent: MatrixEvent | undefined, promBefore: Promise, ) { const content: IContent = { @@ -583,6 +575,12 @@ export default class ContentMessages { content["m.relates_to"] = relation; } + if (replyToEvent) { + addReplyToMessageContent(content, replyToEvent, { + includeLegacyFallback: false, + }); + } + if (SettingsStore.getValue("Performance.addSendMessageTimingMetadata")) { decorateStartSendingTime(content); } diff --git a/src/components/views/rooms/SendMessageComposer.tsx b/src/components/views/rooms/SendMessageComposer.tsx index b6d06f26b1..2bbf8294f7 100644 --- a/src/components/views/rooms/SendMessageComposer.tsx +++ b/src/components/views/rooms/SendMessageComposer.tsx @@ -58,35 +58,7 @@ import { ComposerType } from "../../../dispatcher/payloads/ComposerInsertPayload import { getSlashCommand, isSlashCommand, runSlashCommand, shouldSendAnyway } from "../../../editor/commands"; import { KeyBindingAction } from "../../../accessibility/KeyboardShortcuts"; import { PosthogAnalytics } from "../../../PosthogAnalytics"; -import { getNestedReplyText, makeReplyMixIn } from '../../../utils/Reply'; - -interface IAddReplyOpts { - permalinkCreator?: RoomPermalinkCreator; - includeLegacyFallback?: boolean; -} - -function addReplyToMessageContent( - content: IContent, - replyToEvent: MatrixEvent, - opts: IAddReplyOpts = { - includeLegacyFallback: true, - }, -): void { - const replyContent = makeReplyMixIn(replyToEvent); - Object.assign(content, replyContent); - - if (opts.includeLegacyFallback) { - // Part of Replies fallback support - prepend the text we're sending - // with the text we're replying to - const nestedReply = getNestedReplyText(replyToEvent, opts.permalinkCreator); - if (nestedReply) { - if (content.formatted_body) { - content.formatted_body = nestedReply.html + content.formatted_body; - } - content.body = nestedReply.body + content.body; - } - } -} +import { addReplyToMessageContent } from '../../../utils/Reply'; export function attachRelation( content: IContent, diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json index ba3f4ce88d..08332fecda 100644 --- a/src/i18n/strings/en_EN.json +++ b/src/i18n/strings/en_EN.json @@ -71,9 +71,6 @@ "You do not have permission to start a conference call in this room": "You do not have permission to start a conference call in this room", "End conference": "End conference", "This will end the conference for everyone. Continue?": "This will end the conference for everyone. Continue?", - "Replying With Files": "Replying With Files", - "At this time it is not possible to reply with a file. Would you like to upload this file without replying?": "At this time it is not possible to reply with a file. Would you like to upload this file without replying?", - "Continue": "Continue", "The file '%(fileName)s' failed to upload.": "The file '%(fileName)s' failed to upload.", "The file '%(fileName)s' exceeds this homeserver's size limit for uploads": "The file '%(fileName)s' exceeds this homeserver's size limit for uploads", "Upload Failed": "Upload Failed", @@ -455,6 +452,7 @@ "Invites user with given id to current room": "Invites user with given id to current room", "Use an identity server": "Use an identity server", "Use an identity server to invite by email. Click continue to use the default identity server (%(defaultIdentityServerName)s) or manage in Settings.": "Use an identity server to invite by email. Click continue to use the default identity server (%(defaultIdentityServerName)s) or manage in Settings.", + "Continue": "Continue", "Use an identity server to invite by email. Manage in Settings.": "Use an identity server to invite by email. Manage in Settings.", "Joins room with given address": "Joins room with given address", "Leave room": "Leave room", diff --git a/src/utils/Reply.ts b/src/utils/Reply.ts index f36a526aa6..7c5d92fc46 100644 --- a/src/utils/Reply.ts +++ b/src/utils/Reply.ts @@ -184,3 +184,31 @@ export function shouldDisplayReply(event: MatrixEvent): boolean { return !!inReplyTo.event_id; } + +interface IAddReplyOpts { + permalinkCreator?: RoomPermalinkCreator; + includeLegacyFallback?: boolean; +} + +export function addReplyToMessageContent( + content: IContent, + replyToEvent: MatrixEvent, + opts: IAddReplyOpts = { + includeLegacyFallback: true, + }, +): void { + const replyContent = makeReplyMixIn(replyToEvent); + Object.assign(content, replyContent); + + if (opts.includeLegacyFallback) { + // Part of Replies fallback support - prepend the text we're sending + // with the text we're replying to + const nestedReply = getNestedReplyText(replyToEvent, opts.permalinkCreator); + if (nestedReply) { + if (content.formatted_body) { + content.formatted_body = nestedReply.html + content.formatted_body; + } + content.body = nestedReply.body + content.body; + } + } +}