Fix a bunch of issues related to edition and reply #5969
This commit is contained in:
parent
c46b3148e4
commit
b72039e735
|
@ -0,0 +1 @@
|
|||
Fix some issues related to edition and reply of events.
|
|
@ -117,7 +117,7 @@ interface RelationService {
|
|||
fun editReply(
|
||||
replyToEdit: TimelineEvent,
|
||||
originalTimelineEvent: TimelineEvent,
|
||||
newBodyText: String,
|
||||
newBodyText: CharSequence,
|
||||
newFormattedBodyText: String? = null,
|
||||
compatibilityBodyText: String = "* $newBodyText"
|
||||
): Cancelable
|
||||
|
|
|
@ -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
|
||||
|
||||
/**
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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 {
|
||||
|
@ -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 = "",
|
||||
|
@ -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>"
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -106,7 +106,7 @@ internal class EventEditor @Inject constructor(
|
|||
fun editReply(
|
||||
replyToEdit: TimelineEvent,
|
||||
originalTimelineEvent: TimelineEvent,
|
||||
newBodyText: String,
|
||||
newBodyText: CharSequence,
|
||||
newBodyFormattedText: String?,
|
||||
compatibilityBodyText: String
|
||||
): Cancelable {
|
||||
|
|
|
@ -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,
|
||||
|
@ -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,
|
||||
|
|
|
@ -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)) }
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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()
|
||||
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
|
@ -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)
|
||||
|
|
Loading…
Reference in New Issue