Skip to content

Commit

Permalink
Fix a bunch of issues related to edition and reply #5969
Browse files Browse the repository at this point in the history
  • Loading branch information
ganfra committed Dec 20, 2023
1 parent 6feee61 commit 5d4e6f4
Show file tree
Hide file tree
Showing 9 changed files with 57 additions and 44 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 Down
Original file line number Diff line number Diff line change
Expand Up @@ -312,7 +312,7 @@ internal class LocalEchoEventFactory @Inject constructor(
roomId: String,
eventReplaced: TimelineEvent,
originalEvent: TimelineEvent,
newBodyText: String,
newBodyText: CharSequence,
autoMarkdown: Boolean,
msgType: String,
compatibilityText: String,
Expand All @@ -336,7 +336,7 @@ internal class LocalEchoEventFactory @Inject constructor(
//
// > <@alice:example.org> This is the original body
//
val replyFallback = buildReplyFallback(body, originalEvent.root.senderId ?: "", newBodyText)
val replyFallback = buildReplyFallback(body, originalEvent.root.senderId ?: "", newBodyText.toString())

return createMessageEvent(
roomId,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,7 @@ class MessageComposerViewModel @AssistedInject constructor(
}

private fun handleOnTextChanged(action: MessageComposerAction.OnTextChanged) {
val needsSendButtonVisibilityUpdate = currentComposerText.isBlank() != action.text.isBlank()
val needsSendButtonVisibilityUpdate = currentComposerText.isBlank() != action.text.isBlank()
currentComposerText = SpannableString(action.text)
if (needsSendButtonVisibilityUpdate) {
updateIsSendButtonVisibility(true)
Expand Down 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 @@ -579,7 +580,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 @@ -625,14 +626,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 5d4e6f4

Please sign in to comment.