From fbf242756ef384326a705c4fcdf7375ca252c7b7 Mon Sep 17 00:00:00 2001 From: Florian Renaud Date: Tue, 18 Oct 2022 14:34:31 +0200 Subject: [PATCH] Allow additional content when sending an event --- .../sdk/api/session/room/send/SendService.kt | 34 ++++-- .../session/content/UploadContentWorker.kt | 8 +- .../session/room/send/DefaultSendService.kt | 36 ++++--- .../room/send/LocalEchoEventFactory.kt | 102 ++++++++++++------ 4 files changed, 122 insertions(+), 58 deletions(-) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/send/SendService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/send/SendService.kt index 53b49129c4..6a6fadc95a 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/send/SendService.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/send/SendService.kt @@ -45,18 +45,30 @@ interface SendService { * @param text the text message to send * @param msgType the message type: MessageType.MSGTYPE_TEXT (default) or MessageType.MSGTYPE_EMOTE * @param autoMarkdown If true, the SDK will generate a formatted HTML message from the body text if markdown syntax is present + * @param additionalContent additional content to put in the event content * @return a [Cancelable] */ - fun sendTextMessage(text: CharSequence, msgType: String = MessageType.MSGTYPE_TEXT, autoMarkdown: Boolean = false): Cancelable + fun sendTextMessage( + text: CharSequence, + msgType: String = MessageType.MSGTYPE_TEXT, + autoMarkdown: Boolean = false, + additionalContent: Content? = null, + ): Cancelable /** * Method to send a text message with a formatted body. * @param text the text message to send * @param formattedText The formatted body using MessageType#FORMAT_MATRIX_HTML * @param msgType the message type: MessageType.MSGTYPE_TEXT (default) or MessageType.MSGTYPE_EMOTE + * @param additionalContent additional content to put in the event content * @return a [Cancelable] */ - fun sendFormattedTextMessage(text: String, formattedText: String, msgType: String = MessageType.MSGTYPE_TEXT): Cancelable + fun sendFormattedTextMessage( + text: String, + formattedText: String, + msgType: String = MessageType.MSGTYPE_TEXT, + additionalContent: Content? = null, + ): Cancelable /** * Method to quote an events content. @@ -65,6 +77,7 @@ interface SendService { * @param formattedText the formatted text message to send * @param autoMarkdown If true, the SDK will generate a formatted HTML message from the body text if markdown syntax is present * @param rootThreadEventId when this param is not null, the message will be sent in this specific thread + * @param additionalContent additional content to put in the event content * @return a [Cancelable] */ fun sendQuotedTextMessage( @@ -73,6 +86,7 @@ interface SendService { formattedText: String? = null, autoMarkdown: Boolean, rootThreadEventId: String? = null, + additionalContent: Content? = null, ): Cancelable /** @@ -83,6 +97,7 @@ interface SendService { * It can be useful to send media to multiple room. It's safe to include the current roomId in this set * @param rootThreadEventId when this param is not null, the Media will be sent in this specific thread * @param relatesTo add a relation content to the media event + * @param additionalContent additional content to put in the event content * @return a [Cancelable] */ fun sendMedia( @@ -91,6 +106,7 @@ interface SendService { roomIds: Set, rootThreadEventId: String? = null, relatesTo: RelationDefaultContent? = null, + additionalContent: Content? = null, ): Cancelable /** @@ -100,6 +116,7 @@ interface SendService { * @param roomIds set of roomIds to where the media will be sent. The current roomId will be add to this set if not present. * It can be useful to send media to multiple room. It's safe to include the current roomId in this set * @param rootThreadEventId when this param is not null, all the Media will be sent in this specific thread + * @param additionalContent additional content to put in the event content * @return a [Cancelable] */ fun sendMedias( @@ -107,6 +124,7 @@ interface SendService { compressBeforeSending: Boolean, roomIds: Set, rootThreadEventId: String? = null, + additionalContent: Content? = null, ): Cancelable /** @@ -114,31 +132,35 @@ interface SendService { * @param pollType indicates open or closed polls * @param question the question * @param options list of options + * @param additionalContent additional content to put in the event content * @return a [Cancelable] */ - fun sendPoll(pollType: PollType, question: String, options: List): Cancelable + fun sendPoll(pollType: PollType, question: String, options: List, additionalContent: Content? = null): Cancelable /** * Method to send a poll response. * @param pollEventId the poll currently replied to * @param answerId The id of the answer + * @param additionalContent additional content to put in the event content * @return a [Cancelable] */ - fun voteToPoll(pollEventId: String, answerId: String): Cancelable + fun voteToPoll(pollEventId: String, answerId: String, additionalContent: Content? = null): Cancelable /** * End a poll in the room. * @param pollEventId event id of the poll + * @param additionalContent additional content to put in the event content * @return a [Cancelable] */ - fun endPoll(pollEventId: String): Cancelable + fun endPoll(pollEventId: String, additionalContent: Content? = null): Cancelable /** * Redact (delete) the given event. * @param event The event to redact * @param reason Optional reason string + * @param additionalContent additional content to put in the event content */ - fun redactEvent(event: Event, reason: String?): Cancelable + fun redactEvent(event: Event, reason: String?, additionalContent: Content? = null): Cancelable /** * Schedule this message to be resent. diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/content/UploadContentWorker.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/content/UploadContentWorker.kt index 1e62b5d7f5..db1cd1b33b 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/content/UploadContentWorker.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/content/UploadContentWorker.kt @@ -26,6 +26,7 @@ import org.matrix.android.sdk.api.extensions.tryOrNull import org.matrix.android.sdk.api.listeners.ProgressListener import org.matrix.android.sdk.api.session.content.ContentAttachmentData import org.matrix.android.sdk.api.session.crypto.model.EncryptedFileInfo +import org.matrix.android.sdk.api.session.events.model.Content import org.matrix.android.sdk.api.session.events.model.toContent import org.matrix.android.sdk.api.session.events.model.toModel import org.matrix.android.sdk.api.session.room.model.message.MessageAudioContent @@ -407,7 +408,10 @@ internal class UploadContentWorker(val context: Context, params: WorkerParameter newAttachmentAttributes: NewAttachmentAttributes ) { localEchoRepository.updateEcho(eventId) { _, event -> - val messageContent: MessageContent? = event.asDomain().content.toModel() + val content: Content? = event.asDomain().content + val messageContent: MessageContent? = content.toModel() + // Retrieve potential additional content from the original event + val additionalContent = content.orEmpty() - messageContent?.toContent().orEmpty().keys val updatedContent = when (messageContent) { is MessageImageContent -> messageContent.update(url, encryptedFileInfo, newAttachmentAttributes) is MessageVideoContent -> messageContent.update(url, encryptedFileInfo, thumbnailUrl, thumbnailEncryptedFileInfo, newAttachmentAttributes) @@ -415,7 +419,7 @@ internal class UploadContentWorker(val context: Context, params: WorkerParameter is MessageAudioContent -> messageContent.update(url, encryptedFileInfo, newAttachmentAttributes.newFileSize) else -> messageContent } - event.content = ContentMapper.map(updatedContent.toContent()) + event.content = ContentMapper.map(updatedContent.toContent().plus(additionalContent)) } } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/DefaultSendService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/DefaultSendService.kt index aa305e6067..9cdbc7ff46 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/DefaultSendService.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/DefaultSendService.kt @@ -27,6 +27,7 @@ import dagger.assisted.AssistedInject import kotlinx.coroutines.launch import org.matrix.android.sdk.api.MatrixUrls.isMxcUrl import org.matrix.android.sdk.api.session.content.ContentAttachmentData +import org.matrix.android.sdk.api.session.events.model.Content import org.matrix.android.sdk.api.session.events.model.Event import org.matrix.android.sdk.api.session.events.model.isAttachmentMessage import org.matrix.android.sdk.api.session.events.model.isTextMessage @@ -88,14 +89,14 @@ internal class DefaultSendService @AssistedInject constructor( .let { sendEvent(it) } } - override fun sendTextMessage(text: CharSequence, msgType: String, autoMarkdown: Boolean): Cancelable { - return localEchoEventFactory.createTextEvent(roomId, msgType, text, autoMarkdown) + override fun sendTextMessage(text: CharSequence, msgType: String, autoMarkdown: Boolean, additionalContent: Content?): Cancelable { + return localEchoEventFactory.createTextEvent(roomId, msgType, text, autoMarkdown, additionalContent) .also { createLocalEcho(it) } .let { sendEvent(it) } } - override fun sendFormattedTextMessage(text: String, formattedText: String, msgType: String): Cancelable { - return localEchoEventFactory.createFormattedTextEvent(roomId, TextContent(text, formattedText), msgType) + override fun sendFormattedTextMessage(text: String, formattedText: String, msgType: String, additionalContent: Content?): Cancelable { + return localEchoEventFactory.createFormattedTextEvent(roomId, TextContent(text, formattedText), msgType, additionalContent) .also { createLocalEcho(it) } .let { sendEvent(it) } } @@ -105,7 +106,8 @@ internal class DefaultSendService @AssistedInject constructor( text: String, formattedText: String?, autoMarkdown: Boolean, - rootThreadEventId: String? + rootThreadEventId: String?, + additionalContent: Content?, ): Cancelable { return localEchoEventFactory.createQuotedTextEvent( roomId = roomId, @@ -113,33 +115,34 @@ internal class DefaultSendService @AssistedInject constructor( text = text, formattedText = formattedText, autoMarkdown = autoMarkdown, - rootThreadEventId = rootThreadEventId + rootThreadEventId = rootThreadEventId, + additionalContent = additionalContent, ) .also { createLocalEcho(it) } .let { sendEvent(it) } } - override fun sendPoll(pollType: PollType, question: String, options: List): Cancelable { - return localEchoEventFactory.createPollEvent(roomId, pollType, question, options) + override fun sendPoll(pollType: PollType, question: String, options: List, additionalContent: Content?): Cancelable { + return localEchoEventFactory.createPollEvent(roomId, pollType, question, options, additionalContent) .also { createLocalEcho(it) } .let { sendEvent(it) } } - override fun voteToPoll(pollEventId: String, answerId: String): Cancelable { - return localEchoEventFactory.createPollReplyEvent(roomId, pollEventId, answerId) + override fun voteToPoll(pollEventId: String, answerId: String, additionalContent: Content?): Cancelable { + return localEchoEventFactory.createPollReplyEvent(roomId, pollEventId, answerId, additionalContent) .also { createLocalEcho(it) } .let { sendEvent(it) } } - override fun endPoll(pollEventId: String): Cancelable { - return localEchoEventFactory.createEndPollEvent(roomId, pollEventId) + override fun endPoll(pollEventId: String, additionalContent: Content?): Cancelable { + return localEchoEventFactory.createEndPollEvent(roomId, pollEventId, additionalContent) .also { createLocalEcho(it) } .let { sendEvent(it) } } - override fun redactEvent(event: Event, reason: String?): Cancelable { + override fun redactEvent(event: Event, reason: String?, additionalContent: Content?): Cancelable { // TODO manage media/attachements? - val redactionEcho = localEchoEventFactory.createRedactEvent(roomId, event.eventId!!, reason) + val redactionEcho = localEchoEventFactory.createRedactEvent(roomId, event.eventId!!, reason, additionalContent) .also { createLocalEcho(it) } return eventSenderProcessor.postRedaction(redactionEcho, reason) } @@ -265,7 +268,8 @@ internal class DefaultSendService @AssistedInject constructor( attachments: List, compressBeforeSending: Boolean, roomIds: Set, - rootThreadEventId: String? + rootThreadEventId: String?, + additionalContent: Content?, ): Cancelable { return attachments.mapTo(CancelableBag()) { sendMedia( @@ -283,6 +287,7 @@ internal class DefaultSendService @AssistedInject constructor( roomIds: Set, rootThreadEventId: String?, relatesTo: RelationDefaultContent?, + additionalContent: Content?, ): Cancelable { // Ensure that the event will not be send in a thread if we are a different flow. // Like sending files to multiple rooms @@ -299,6 +304,7 @@ internal class DefaultSendService @AssistedInject constructor( attachment = attachment, rootThreadEventId = rootThreadId, relatesTo, + additionalContent, ).also { event -> createLocalEcho(event) } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/LocalEchoEventFactory.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/LocalEchoEventFactory.kt index 1d7f624eba..7d8605c2bd 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/LocalEchoEventFactory.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/LocalEchoEventFactory.kt @@ -95,12 +95,12 @@ internal class LocalEchoEventFactory @Inject constructor( private val permalinkFactory: PermalinkFactory, private val clock: Clock, ) { - fun createTextEvent(roomId: String, msgType: String, text: CharSequence, autoMarkdown: Boolean): Event { + fun createTextEvent(roomId: String, msgType: String, text: CharSequence, autoMarkdown: Boolean, additionalContent: Content? = null): Event { if (msgType == MessageType.MSGTYPE_TEXT || msgType == MessageType.MSGTYPE_EMOTE) { - return createFormattedTextEvent(roomId, createTextContent(text, autoMarkdown), msgType) + return createFormattedTextEvent(roomId, createTextContent(text, autoMarkdown), msgType, additionalContent) } val content = MessageTextContent(msgType = msgType, body = text.toString()) - return createMessageEvent(roomId, content) + return createMessageEvent(roomId, content, additionalContent) } private fun createTextContent(text: CharSequence, autoMarkdown: Boolean): TextContent { @@ -116,8 +116,8 @@ internal class LocalEchoEventFactory @Inject constructor( return TextContent(text.toString()) } - fun createFormattedTextEvent(roomId: String, textContent: TextContent, msgType: String): Event { - return createMessageEvent(roomId, textContent.toMessageTextContent(msgType)) + fun createFormattedTextEvent(roomId: String, textContent: TextContent, msgType: String, additionalContent: Content? = null): Event { + return createMessageEvent(roomId, textContent.toMessageTextContent(msgType), additionalContent) } fun createReplaceTextEvent( @@ -128,6 +128,7 @@ internal class LocalEchoEventFactory @Inject constructor( newBodyAutoMarkdown: Boolean, msgType: String, compatibilityText: String, + additionalContent: Content? = null, ): Event { val content = if (newBodyFormattedText != null) { TextContent(newBodyText.toString(), newBodyFormattedText.toString()).toMessageTextContent(msgType) @@ -141,7 +142,8 @@ internal class LocalEchoEventFactory @Inject constructor( body = compatibilityText, relatesTo = RelationDefaultContent(RelationType.REPLACE, targetEventId), newContent = content, - ) + ), + additionalContent, ) } @@ -167,6 +169,7 @@ internal class LocalEchoEventFactory @Inject constructor( targetEventId: String, question: String, options: List, + additionalContent: Content? = null, ): Event { val newContent = MessagePollContent( relatesTo = RelationDefaultContent(RelationType.REPLACE, targetEventId), @@ -179,7 +182,7 @@ internal class LocalEchoEventFactory @Inject constructor( senderId = userId, eventId = localId, type = EventType.POLL_START.first(), - content = newContent.toContent() + content = newContent.toContent().plus(additionalContent.orEmpty()) ) } @@ -187,6 +190,7 @@ internal class LocalEchoEventFactory @Inject constructor( roomId: String, pollEventId: String, answerId: String, + additionalContent: Content? = null, ): Event { val content = MessagePollResponseContent( body = answerId, @@ -203,7 +207,7 @@ internal class LocalEchoEventFactory @Inject constructor( senderId = userId, eventId = localId, type = EventType.POLL_RESPONSE.first(), - content = content.toContent(), + content = content.toContent().plus(additionalContent.orEmpty()), unsignedData = UnsignedData(age = null, transactionId = localId) ) } @@ -213,6 +217,7 @@ internal class LocalEchoEventFactory @Inject constructor( pollType: PollType, question: String, options: List, + additionalContent: Content? = null, ): Event { val content = createPollContent(question, options, pollType) val localId = LocalEcho.createLocalEchoId() @@ -222,7 +227,7 @@ internal class LocalEchoEventFactory @Inject constructor( senderId = userId, eventId = localId, type = EventType.POLL_START.first(), - content = content.toContent(), + content = content.toContent().plus(additionalContent.orEmpty()), unsignedData = UnsignedData(age = null, transactionId = localId) ) } @@ -230,6 +235,7 @@ internal class LocalEchoEventFactory @Inject constructor( fun createEndPollEvent( roomId: String, eventId: String, + additionalContent: Content? = null, ): Event { val content = MessageEndPollContent( relatesTo = RelationDefaultContent( @@ -244,7 +250,7 @@ internal class LocalEchoEventFactory @Inject constructor( senderId = userId, eventId = localId, type = EventType.POLL_END.first(), - content = content.toContent(), + content = content.toContent().plus(additionalContent.orEmpty()), unsignedData = UnsignedData(age = null, transactionId = localId) ) } @@ -255,6 +261,7 @@ internal class LocalEchoEventFactory @Inject constructor( longitude: Double, uncertainty: Double?, isUserLocation: Boolean, + additionalContent: Content? = null, ): Event { val geoUri = buildGeoUri(latitude, longitude, uncertainty) val assetType = if (isUserLocation) LocationAssetType.SELF else LocationAssetType.PIN @@ -266,7 +273,7 @@ internal class LocalEchoEventFactory @Inject constructor( unstableTimestampMillis = clock.epochMillis(), unstableText = geoUri ) - return createMessageEvent(roomId, content) + return createMessageEvent(roomId, content, additionalContent) } fun createLiveLocationEvent( @@ -275,6 +282,7 @@ internal class LocalEchoEventFactory @Inject constructor( latitude: Double, longitude: Double, uncertainty: Double?, + additionalContent: Content? = null, ): Event { val geoUri = buildGeoUri(latitude, longitude, uncertainty) val content = MessageBeaconLocationDataContent( @@ -293,7 +301,7 @@ internal class LocalEchoEventFactory @Inject constructor( senderId = userId, eventId = localId, type = EventType.BEACON_LOCATION_DATA.first(), - content = content.toContent(), + content = content.toContent().plus(additionalContent.orEmpty()), unsignedData = UnsignedData(age = null, transactionId = localId) ) } @@ -306,6 +314,7 @@ internal class LocalEchoEventFactory @Inject constructor( autoMarkdown: Boolean, msgType: String, compatibilityText: String, + additionalContent: Content? = null, ): Event { val permalink = permalinkFactory.createPermalink(roomId, originalEvent.root.eventId ?: "", false) val userLink = originalEvent.root.senderId?.let { permalinkFactory.createPermalink(it, false) } ?: "" @@ -340,7 +349,8 @@ internal class LocalEchoEventFactory @Inject constructor( formattedBody = replyFormatted ) .toContent() - ) + ), + additionalContent, ) } @@ -349,23 +359,32 @@ internal class LocalEchoEventFactory @Inject constructor( attachment: ContentAttachmentData, rootThreadEventId: String?, relatesTo: RelationDefaultContent?, + additionalContent: Content? = null, ): Event { return when (attachment.type) { - ContentAttachmentData.Type.IMAGE -> createImageEvent(roomId, attachment, rootThreadEventId, relatesTo) - ContentAttachmentData.Type.VIDEO -> createVideoEvent(roomId, attachment, rootThreadEventId, relatesTo) - ContentAttachmentData.Type.AUDIO -> createAudioEvent(roomId, attachment, isVoiceMessage = false, rootThreadEventId = rootThreadEventId, relatesTo) + ContentAttachmentData.Type.IMAGE -> createImageEvent(roomId, attachment, rootThreadEventId, relatesTo, additionalContent) + ContentAttachmentData.Type.VIDEO -> createVideoEvent(roomId, attachment, rootThreadEventId, relatesTo, additionalContent) + ContentAttachmentData.Type.AUDIO -> createAudioEvent( + roomId, + attachment, + isVoiceMessage = false, + rootThreadEventId = rootThreadEventId, + relatesTo, + additionalContent + ) ContentAttachmentData.Type.VOICE_MESSAGE -> createAudioEvent( roomId, attachment, isVoiceMessage = true, rootThreadEventId = rootThreadEventId, relatesTo, + additionalContent, ) - ContentAttachmentData.Type.FILE -> createFileEvent(roomId, attachment, rootThreadEventId, relatesTo) + ContentAttachmentData.Type.FILE -> createFileEvent(roomId, attachment, rootThreadEventId, relatesTo, additionalContent) } } - fun createReactionEvent(roomId: String, targetEventId: String, reaction: String): Event { + fun createReactionEvent(roomId: String, targetEventId: String, reaction: String, additionalContent: Content? = null): Event { val content = ReactionContent( ReactionInfo( RelationType.ANNOTATION, @@ -380,7 +399,7 @@ internal class LocalEchoEventFactory @Inject constructor( senderId = userId, eventId = localId, type = EventType.REACTION, - content = content.toContent(), + content = content.toContent().plus(additionalContent.orEmpty()), unsignedData = UnsignedData(age = null, transactionId = localId) ) } @@ -390,6 +409,7 @@ internal class LocalEchoEventFactory @Inject constructor( attachment: ContentAttachmentData, rootThreadEventId: String?, relatesTo: RelationDefaultContent?, + additionalContent: Content?, ): Event { var width = attachment.width var height = attachment.height @@ -417,7 +437,7 @@ internal class LocalEchoEventFactory @Inject constructor( url = attachment.queryUri.toString(), relatesTo = relatesTo ?: rootThreadEventId?.let { generateThreadRelationContent(it) } ) - return createMessageEvent(roomId, content) + return createMessageEvent(roomId, content, additionalContent) } private fun createVideoEvent( @@ -425,6 +445,7 @@ internal class LocalEchoEventFactory @Inject constructor( attachment: ContentAttachmentData, rootThreadEventId: String?, relatesTo: RelationDefaultContent?, + additionalContent: Content?, ): Event { val mediaDataRetriever = MediaMetadataRetriever() mediaDataRetriever.setDataSource(context, attachment.queryUri) @@ -459,7 +480,7 @@ internal class LocalEchoEventFactory @Inject constructor( url = attachment.queryUri.toString(), relatesTo = relatesTo ?: rootThreadEventId?.let { generateThreadRelationContent(it) } ) - return createMessageEvent(roomId, content) + return createMessageEvent(roomId, content, additionalContent) } private fun createAudioEvent( @@ -468,6 +489,7 @@ internal class LocalEchoEventFactory @Inject constructor( isVoiceMessage: Boolean, rootThreadEventId: String?, relatesTo: RelationDefaultContent?, + additionalContent: Content? ): Event { val content = MessageAudioContent( msgType = MessageType.MSGTYPE_AUDIO, @@ -485,7 +507,7 @@ internal class LocalEchoEventFactory @Inject constructor( voiceMessageIndicator = if (!isVoiceMessage) null else emptyMap(), relatesTo = relatesTo ?: rootThreadEventId?.let { generateThreadRelationContent(it) } ) - return createMessageEvent(roomId, content) + return createMessageEvent(roomId, content, additionalContent) } private fun createFileEvent( @@ -493,6 +515,7 @@ internal class LocalEchoEventFactory @Inject constructor( attachment: ContentAttachmentData, rootThreadEventId: String?, relatesTo: RelationDefaultContent?, + additionalContent: Content? ): Event { val content = MessageFileContent( msgType = MessageType.MSGTYPE_FILE, @@ -504,15 +527,16 @@ internal class LocalEchoEventFactory @Inject constructor( url = attachment.queryUri.toString(), relatesTo = relatesTo ?: rootThreadEventId?.let { generateThreadRelationContent(it) } ) - return createMessageEvent(roomId, content) + return createMessageEvent(roomId, content, additionalContent) } - private fun createMessageEvent(roomId: String, content: MessageContent? = null): Event { - return createEvent(roomId, EventType.MESSAGE, content.toContent()) + private fun createMessageEvent(roomId: String, content: MessageContent, additionalContent: Content?): Event { + return createEvent(roomId, EventType.MESSAGE, content.toContent(), additionalContent) } - fun createEvent(roomId: String, type: String, content: Content?): Event { + fun createEvent(roomId: String, type: String, content: Content?, additionalContent: Content? = null): Event { val newContent = enhanceStickerIfNeeded(type, content) ?: content + val updatedNewContent = newContent?.plus(additionalContent.orEmpty()) ?: additionalContent val localId = LocalEcho.createLocalEchoId() return Event( roomId = roomId, @@ -520,7 +544,7 @@ internal class LocalEchoEventFactory @Inject constructor( senderId = userId, eventId = localId, type = type, - content = newContent, + content = updatedNewContent, unsignedData = UnsignedData(age = null, transactionId = localId) ) } @@ -555,6 +579,7 @@ internal class LocalEchoEventFactory @Inject constructor( msgType: String, autoMarkdown: Boolean, formattedText: String?, + additionalContent: Content? = null, ): Event { val content = formattedText?.let { TextContent(text.toString(), it) } ?: createTextContent(text, autoMarkdown) return createEvent( @@ -564,8 +589,7 @@ internal class LocalEchoEventFactory @Inject constructor( rootThreadEventId = rootThreadEventId, latestThreadEventId = localEchoRepository.getLatestThreadEvent(rootThreadEventId), msgType = msgType - ) - .toContent() + ).toContent().plus(additionalContent.orEmpty()) ) } @@ -584,6 +608,7 @@ internal class LocalEchoEventFactory @Inject constructor( autoMarkdown: Boolean, rootThreadEventId: String? = null, showInThread: Boolean, + additionalContent: Content? = null ): Event? { // Fallbacks and event representation // TODO Add error/warning logs when any of this is null @@ -621,7 +646,7 @@ internal class LocalEchoEventFactory @Inject constructor( showInThread = showInThread ) ) - return createMessageEvent(roomId, content) + return createMessageEvent(roomId, content, additionalContent) } private fun generateThreadRelationContent(rootThreadEventId: String) = @@ -750,7 +775,7 @@ internal class LocalEchoEventFactory @Inject constructor( } } */ - fun createRedactEvent(roomId: String, eventId: String, reason: String?): Event { + fun createRedactEvent(roomId: String, eventId: String, reason: String?, additionalContent: Content? = null): Event { val localId = LocalEcho.createLocalEchoId() return Event( roomId = roomId, @@ -759,7 +784,7 @@ internal class LocalEchoEventFactory @Inject constructor( eventId = localId, type = EventType.REDACTION, redacts = eventId, - content = reason?.let { mapOf("reason" to it).toContent() }, + content = reason?.let { mapOf("reason" to it).toContent().plus(additionalContent.orEmpty()) } ?: additionalContent, unsignedData = UnsignedData(age = null, transactionId = localId) ) } @@ -776,9 +801,14 @@ internal class LocalEchoEventFactory @Inject constructor( formattedText: String?, autoMarkdown: Boolean, rootThreadEventId: String?, + additionalContent: Content? = null, ): Event { val messageContent = quotedEvent.getLastMessageContent() - val textMsg = if (messageContent is MessageContentWithFormattedBody) { messageContent.formattedBody } else { messageContent?.body } + val textMsg = if (messageContent is MessageContentWithFormattedBody) { + messageContent.formattedBody + } else { + messageContent?.body + } val quoteText = legacyRiotQuoteText(textMsg, text) val quoteFormattedText = "
$textMsg
$formattedText" @@ -791,13 +821,15 @@ internal class LocalEchoEventFactory @Inject constructor( rootThreadEventId = rootThreadEventId, latestThreadEventId = localEchoRepository.getLatestThreadEvent(rootThreadEventId), msgType = MessageType.MSGTYPE_TEXT - ) + ), + additionalContent, ) } else { createFormattedTextEvent( roomId, markdownParser.parse(quoteText, force = true, advanced = autoMarkdown).copy(formattedText = quoteFormattedText), - MessageType.MSGTYPE_TEXT + MessageType.MSGTYPE_TEXT, + additionalContent, ) } }