Skip to content

Commit

Permalink
Merge pull request #8716 from element-hq/feature/fga/fix_event_editio…
Browse files Browse the repository at this point in the history
…n_reply

Fix a bunch of issues related to edition and reply #5969
  • Loading branch information
ganfra authored Jan 2, 2024
2 parents 7a2520b + 2ada4c8 commit e596196
Show file tree
Hide file tree
Showing 9 changed files with 63 additions and 47 deletions.
1 change: 1 addition & 0 deletions changelog.d/5969.bugfix
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Fix some issues related to edition and reply of events.
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ interface RelationService {
fun editReply(
replyToEdit: TimelineEvent,
originalTimelineEvent: TimelineEvent,
newBodyText: String,
newBodyText: CharSequence,
newFormattedBodyText: String? = null,
compatibilityBodyText: String = "* $newBodyText"
): Cancelable
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,13 +37,13 @@ import org.matrix.android.sdk.api.session.room.model.message.MessageBeaconLocati
import org.matrix.android.sdk.api.session.room.model.message.MessageContent
import org.matrix.android.sdk.api.session.room.model.message.MessageContentWithFormattedBody
import org.matrix.android.sdk.api.session.room.model.message.MessageEndPollContent
import org.matrix.android.sdk.api.session.room.model.message.MessageFormat
import org.matrix.android.sdk.api.session.room.model.message.MessagePollContent
import org.matrix.android.sdk.api.session.room.model.message.MessageStickerContent
import org.matrix.android.sdk.api.session.room.model.message.MessageTextContent
import org.matrix.android.sdk.api.session.room.model.relation.RelationDefaultContent
import org.matrix.android.sdk.api.session.room.sender.SenderInfo
import org.matrix.android.sdk.api.util.ContentUtils
import org.matrix.android.sdk.api.util.ContentUtils.ensureCorrectFormattedBodyInTextReply
import org.matrix.android.sdk.api.util.ContentUtils.extractUsefulTextFromReply

/**
Expand Down Expand Up @@ -160,37 +160,17 @@ fun TimelineEvent.getLastMessageContent(): MessageContent? {

fun TimelineEvent.getLastEditNewContent(): Content? {
val lastContent = annotations?.editSummary?.latestEdit?.getClearContent()?.toModel<MessageContent>()?.newContent
return if (isReply()) {
val previousFormattedBody = root.getClearContent().toModel<MessageTextContent>()?.formattedBody
if (previousFormattedBody?.isNotEmpty() == true) {
val lastMessageContent = lastContent.toModel<MessageTextContent>()
lastMessageContent?.let { ensureCorrectFormattedBodyInTextReply(it, previousFormattedBody) }?.toContent() ?: lastContent
} else {
lastContent
}
} else {
lastContent
}
}

private const val MX_REPLY_END_TAG = "</mx-reply>"

/**
* Not every client sends a formatted body in the last edited event since this is not required in the
* [Matrix specification](https://spec.matrix.org/v1.4/client-server-api/#applying-mnew_content).
* We must ensure there is one so that it is still considered as a reply when rendering the message.
*/
private fun ensureCorrectFormattedBodyInTextReply(messageTextContent: MessageTextContent, previousFormattedBody: String): MessageTextContent {
return when {
messageTextContent.formattedBody.isNullOrEmpty() && previousFormattedBody.contains(MX_REPLY_END_TAG) -> {
// take previous formatted body with the new body content
val newFormattedBody = previousFormattedBody.replaceAfterLast(MX_REPLY_END_TAG, messageTextContent.body)
messageTextContent.copy(
formattedBody = newFormattedBody,
format = MessageFormat.FORMAT_MATRIX_HTML,
)
isReply() -> {
val originalFormattedBody = root.getClearContent().toModel<MessageTextContent>()?.formattedBody
val lastMessageContent = lastContent.toModel<MessageTextContent>()
if (lastMessageContent != null && originalFormattedBody?.isNotEmpty() == true) {
ensureCorrectFormattedBodyInTextReply(lastMessageContent, originalFormattedBody).toContent()
} else {
lastContent
}
}
else -> messageTextContent
else -> lastContent
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@
*/
package org.matrix.android.sdk.api.util

import org.matrix.android.sdk.api.session.room.model.message.MessageFormat
import org.matrix.android.sdk.api.session.room.model.message.MessageTextContent
import org.matrix.android.sdk.internal.util.unescapeHtml

object ContentUtils {
Expand All @@ -38,15 +40,36 @@ object ContentUtils {
}

fun extractUsefulTextFromHtmlReply(repliedBody: String): String {
if (repliedBody.startsWith("<mx-reply>")) {
val closingTagIndex = repliedBody.lastIndexOf("</mx-reply>")
if (repliedBody.startsWith(MX_REPLY_START_TAG)) {
val closingTagIndex = repliedBody.lastIndexOf(MX_REPLY_END_TAG)
if (closingTagIndex != -1) {
return repliedBody.substring(closingTagIndex + "</mx-reply>".length).trim()
return repliedBody.substring(closingTagIndex + MX_REPLY_END_TAG.length).trim()
}
}
return repliedBody
}

/**
* Not every client sends a formatted body in the last edited event since this is not required in the
* [Matrix specification](https://spec.matrix.org/v1.4/client-server-api/#applying-mnew_content).
* We must ensure there is one so that it is still considered as a reply when rendering the message.
*/
fun ensureCorrectFormattedBodyInTextReply(messageTextContent: MessageTextContent, originalFormattedBody: String): MessageTextContent {
return when {
messageTextContent.formattedBody != null &&
!messageTextContent.formattedBody.contains(MX_REPLY_END_TAG) &&
originalFormattedBody.contains(MX_REPLY_END_TAG) -> {
// take previous formatted body with the new body content
val newFormattedBody = originalFormattedBody.replaceAfterLast(MX_REPLY_END_TAG, messageTextContent.body)
messageTextContent.copy(
formattedBody = newFormattedBody,
format = MessageFormat.FORMAT_MATRIX_HTML,
)
}
else -> messageTextContent
}
}

@Suppress("RegExpRedundantEscape")
fun formatSpoilerTextFromHtml(formattedBody: String): String {
// var reason = "",
Expand All @@ -57,4 +80,6 @@ object ContentUtils {
}

private const val SPOILER_CHAR = ""
private const val MX_REPLY_START_TAG = "<mx-reply>"
private const val MX_REPLY_END_TAG = "</mx-reply>"
}
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ internal class DefaultRelationService @AssistedInject constructor(
override fun editReply(
replyToEdit: TimelineEvent,
originalTimelineEvent: TimelineEvent,
newBodyText: String,
newBodyText: CharSequence,
newFormattedBodyText: String?,
compatibilityBodyText: String
): Cancelable {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ internal class EventEditor @Inject constructor(
fun editReply(
replyToEdit: TimelineEvent,
originalTimelineEvent: TimelineEvent,
newBodyText: String,
newBodyText: CharSequence,
newBodyFormattedText: String?,
compatibilityBodyText: String
): Cancelable {
Expand All @@ -131,6 +131,7 @@ internal class EventEditor @Inject constructor(
replyToEdit,
originalTimelineEvent,
newBodyText,
newBodyFormattedText,
true,
MessageType.MSGTYPE_TEXT,
compatibilityBodyText
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -312,7 +312,8 @@ internal class LocalEchoEventFactory @Inject constructor(
roomId: String,
eventReplaced: TimelineEvent,
originalEvent: TimelineEvent,
newBodyText: String,
replyText: CharSequence,
replyTextFormatted: String?,
autoMarkdown: Boolean,
msgType: String,
compatibilityText: String,
Expand All @@ -321,22 +322,23 @@ internal class LocalEchoEventFactory @Inject constructor(
val permalink = permalinkFactory.createPermalink(roomId, originalEvent.root.eventId ?: "", false)
val userLink = originalEvent.root.senderId?.let { permalinkFactory.createPermalink(it, false) } ?: ""

val body = bodyForReply(timelineEvent = originalEvent)
val bodyOfRepliedEvent = bodyForReply(timelineEvent = originalEvent)
// As we always supply formatted body for replies we should force the MarkdownParser to produce html.
val newBodyFormatted = markdownParser.parse(newBodyText, force = true, advanced = autoMarkdown).takeFormatted()
val newBodyFormatted = replyTextFormatted ?: markdownParser.parse(replyText, force = true, advanced = autoMarkdown).takeFormatted()
// Body of the original message may not have formatted version, so may also have to convert to html.
val bodyFormatted = body.formattedText ?: markdownParser.parse(body.text, force = true, advanced = autoMarkdown).takeFormatted()
val formattedBodyOfRepliedEvent =
bodyOfRepliedEvent.formattedText ?: markdownParser.parse(text = bodyOfRepliedEvent.text, force = true, advanced = autoMarkdown).takeFormatted()
val replyFormatted = buildFormattedReply(
permalink,
userLink,
originalEvent.senderInfo.disambiguatedDisplayName,
bodyFormatted,
formattedBodyOfRepliedEvent,
newBodyFormatted
)
//
// > <@alice:example.org> This is the original body
//
val replyFallback = buildReplyFallback(body, originalEvent.root.senderId ?: "", newBodyText)
val replyFallback = buildReplyFallback(bodyOfRepliedEvent, originalEvent.root.senderId ?: "", replyText.toString())

return createMessageEvent(
roomId,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -178,7 +178,8 @@ class MessageComposerViewModel @AssistedInject constructor(
private fun handleEnterEditMode(room: Room, action: MessageComposerAction.EnterEditMode) {
room.getTimelineEvent(action.eventId)?.let { timelineEvent ->
val formatted = vectorPreferences.isRichTextEditorEnabled()
setState { copy(sendMode = SendMode.Edit(timelineEvent, timelineEvent.getTextEditableContent(formatted))) }
val editableContent = timelineEvent.getTextEditableContent(formatted)
setState { copy(sendMode = SendMode.Edit(timelineEvent, editableContent)) }
}
}

Expand Down Expand Up @@ -578,7 +579,7 @@ class MessageComposerViewModel @AssistedInject constructor(
if (inReplyTo != null) {
// TODO check if same content?
room.getTimelineEvent(inReplyTo)?.let {
room.relationService().editReply(state.sendMode.timelineEvent, it, action.text.toString(), action.formattedText)
room.relationService().editReply(state.sendMode.timelineEvent, it, action.text, action.formattedText)
}
} else {
val messageContent = state.sendMode.timelineEvent.getVectorLastMessageContent()
Expand Down Expand Up @@ -624,14 +625,14 @@ class MessageComposerViewModel @AssistedInject constructor(
state.rootThreadEventId?.let {
room.relationService().replyInThread(
rootThreadEventId = it,
replyInThreadText = action.text.toString(),
replyInThreadText = action.text,
autoMarkdown = action.autoMarkdown,
formattedText = action.formattedText,
eventReplied = timelineEvent
)
} ?: room.relationService().replyToMessage(
eventReplied = timelineEvent,
replyText = action.text.toString(),
replyText = action.text,
replyFormattedText = action.formattedText,
autoMarkdown = action.autoMarkdown,
showInThread = showInThread,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ import org.matrix.android.sdk.api.session.room.model.message.MessageEndPollConte
import org.matrix.android.sdk.api.session.room.model.message.MessageFormat
import org.matrix.android.sdk.api.session.room.model.message.MessagePollContent
import org.matrix.android.sdk.api.session.room.model.message.MessageTextContent
import org.matrix.android.sdk.api.util.ContentUtils
import org.matrix.android.sdk.api.util.MatrixItem
import org.matrix.android.sdk.api.util.toMatrixItem
import javax.inject.Inject
Expand Down Expand Up @@ -188,7 +189,12 @@ class PlainTextComposerLayout @JvmOverloads constructor(
var formattedBody: CharSequence? = null
if (messageContent is MessageTextContent && messageContent.format == MessageFormat.FORMAT_MATRIX_HTML) {
val parser = Parser.builder().build()
val document = parser.parse(messageContent.formattedBody ?: messageContent.body)

val bodyToParse = messageContent.formattedBody?.let {
ContentUtils.extractUsefulTextFromHtmlReply(it)
} ?: ContentUtils.extractUsefulTextFromReply(messageContent.body)

val document = parser.parse(bodyToParse)
formattedBody = eventHtmlRenderer.render(document, pillsPostProcessor)
}
views.composerRelatedMessageContent.text = (formattedBody ?: nonFormattedBody)
Expand Down

0 comments on commit e596196

Please sign in to comment.