You've already forked matrix-react-sdk
							
							
				mirror of
				https://github.com/matrix-org/matrix-react-sdk.git
				synced 2025-10-31 01:45:39 +03:00 
			
		
		
		
	Allow sending files as replies as per MSC3676 (#8020)
This commit is contained in:
		
				
					committed by
					
						 GitHub
						GitHub
					
				
			
			
				
	
			
			
			
						parent
						
							14653d1378
						
					
				
				
					commit
					dd53b226eb
				
			| @@ -16,7 +16,6 @@ See the License for the specific language governing permissions and | |||||||
| limitations under the License. | limitations under the License. | ||||||
| */ | */ | ||||||
| 
 | 
 | ||||||
| import React from "react"; |  | ||||||
| import { MatrixClient } from "matrix-js-sdk/src/client"; | import { MatrixClient } from "matrix-js-sdk/src/client"; | ||||||
| import { IUploadOpts } from "matrix-js-sdk/src/@types/requests"; | import { IUploadOpts } from "matrix-js-sdk/src/@types/requests"; | ||||||
| import { MsgType } from "matrix-js-sdk/src/@types/event"; | 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 extractPngChunks from "png-chunks-extract"; | ||||||
| import { IAbortablePromise, IImageInfo } from "matrix-js-sdk/src/@types/partials"; | import { IAbortablePromise, IImageInfo } from "matrix-js-sdk/src/@types/partials"; | ||||||
| import { logger } from "matrix-js-sdk/src/logger"; | 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 { THREAD_RELATION_TYPE } from "matrix-js-sdk/src/models/thread"; | ||||||
| 
 | 
 | ||||||
| import { IEncryptedFile, IMediaEventInfo } from "./customisations/models/IMediaEventContent"; | import { IEncryptedFile, IMediaEventInfo } from "./customisations/models/IMediaEventContent"; | ||||||
| @@ -32,7 +31,6 @@ import dis from './dispatcher/dispatcher'; | |||||||
| import * as sdk from './index'; | import * as sdk from './index'; | ||||||
| import { _t } from './languageHandler'; | import { _t } from './languageHandler'; | ||||||
| import Modal from './Modal'; | import Modal from './Modal'; | ||||||
| import RoomViewStore from './stores/RoomViewStore'; |  | ||||||
| import Spinner from "./components/views/elements/Spinner"; | import Spinner from "./components/views/elements/Spinner"; | ||||||
| import { Action } from "./dispatcher/actions"; | import { Action } from "./dispatcher/actions"; | ||||||
| import { | import { | ||||||
| @@ -47,6 +45,8 @@ import { BlurhashEncoder } from "./BlurhashEncoder"; | |||||||
| import SettingsStore from "./settings/SettingsStore"; | import SettingsStore from "./settings/SettingsStore"; | ||||||
| import { decorateStartSendingTime, sendRoundTripMetric } from "./sendTimePerformanceMetrics"; | import { decorateStartSendingTime, sendRoundTripMetric } from "./sendTimePerformanceMetrics"; | ||||||
| import { TimelineRenderingType } from "./contexts/RoomContext"; | import { TimelineRenderingType } from "./contexts/RoomContext"; | ||||||
|  | import RoomViewStore from "./stores/RoomViewStore"; | ||||||
|  | import { addReplyToMessageContent } from "./utils/Reply"; | ||||||
| 
 | 
 | ||||||
| const MAX_WIDTH = 800; | const MAX_WIDTH = 800; | ||||||
| const MAX_HEIGHT = 600; | const MAX_HEIGHT = 600; | ||||||
| @@ -457,25 +457,7 @@ export default class ContentMessages { | |||||||
|             return; |             return; | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         const isQuoting = Boolean(RoomViewStore.getQuotingEvent()); |         const replyToEvent = 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: ( |  | ||||||
|                     <div>{ _t( |  | ||||||
|                         'At this time it is not possible to reply with a file. ' + |  | ||||||
|                         'Would you like to upload this file without replying?', |  | ||||||
|                     ) }</div> |  | ||||||
|                 ), |  | ||||||
|                 hasCancelButton: true, |  | ||||||
|                 button: _t("Continue"), |  | ||||||
|             }); |  | ||||||
|             const [shouldUpload] = await finished; |  | ||||||
|             if (!shouldUpload) return; |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         if (!this.mediaConfig) { // hot-path optimization to not flash a spinner if we don't need to
 |         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'); |             const modal = Modal.createDialog(Spinner, null, 'mx_Dialog_spinner'); | ||||||
|             await this.ensureMediaConfigFetched(matrixClient); |             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
 |         // Focus the correct composer
 | ||||||
| @@ -569,6 +560,7 @@ export default class ContentMessages { | |||||||
|         roomId: string, |         roomId: string, | ||||||
|         relation: IEventRelation | undefined, |         relation: IEventRelation | undefined, | ||||||
|         matrixClient: MatrixClient, |         matrixClient: MatrixClient, | ||||||
|  |         replyToEvent: MatrixEvent | undefined, | ||||||
|         promBefore: Promise<any>, |         promBefore: Promise<any>, | ||||||
|     ) { |     ) { | ||||||
|         const content: IContent = { |         const content: IContent = { | ||||||
| @@ -583,6 +575,12 @@ export default class ContentMessages { | |||||||
|             content["m.relates_to"] = relation; |             content["m.relates_to"] = relation; | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|  |         if (replyToEvent) { | ||||||
|  |             addReplyToMessageContent(content, replyToEvent, { | ||||||
|  |                 includeLegacyFallback: false, | ||||||
|  |             }); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|         if (SettingsStore.getValue("Performance.addSendMessageTimingMetadata")) { |         if (SettingsStore.getValue("Performance.addSendMessageTimingMetadata")) { | ||||||
|             decorateStartSendingTime(content); |             decorateStartSendingTime(content); | ||||||
|         } |         } | ||||||
| @@ -58,35 +58,7 @@ import { ComposerType } from "../../../dispatcher/payloads/ComposerInsertPayload | |||||||
| import { getSlashCommand, isSlashCommand, runSlashCommand, shouldSendAnyway } from "../../../editor/commands"; | import { getSlashCommand, isSlashCommand, runSlashCommand, shouldSendAnyway } from "../../../editor/commands"; | ||||||
| import { KeyBindingAction } from "../../../accessibility/KeyboardShortcuts"; | import { KeyBindingAction } from "../../../accessibility/KeyboardShortcuts"; | ||||||
| import { PosthogAnalytics } from "../../../PosthogAnalytics"; | import { PosthogAnalytics } from "../../../PosthogAnalytics"; | ||||||
| import { getNestedReplyText, makeReplyMixIn } from '../../../utils/Reply'; | import { addReplyToMessageContent } 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; |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| } |  | ||||||
|  |  | ||||||
| export function attachRelation( | export function attachRelation( | ||||||
|     content: IContent, |     content: IContent, | ||||||
|   | |||||||
| @@ -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", |     "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", |     "End conference": "End conference", | ||||||
|     "This will end the conference for everyone. Continue?": "This will end the conference for everyone. Continue?", |     "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' 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", |     "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", |     "Upload Failed": "Upload Failed", | ||||||
| @@ -455,6 +452,7 @@ | |||||||
|     "Invites user with given id to current room": "Invites user with given id to current room", |     "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": "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.", |     "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.", |     "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", |     "Joins room with given address": "Joins room with given address", | ||||||
|     "Leave room": "Leave room", |     "Leave room": "Leave room", | ||||||
|   | |||||||
| @@ -184,3 +184,31 @@ export function shouldDisplayReply(event: MatrixEvent): boolean { | |||||||
|  |  | ||||||
|     return !!inReplyTo.event_id; |     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; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user