diff --git a/changelog.d/7938.bugfix b/changelog.d/7938.bugfix new file mode 100644 index 0000000000..70218edf8a --- /dev/null +++ b/changelog.d/7938.bugfix @@ -0,0 +1 @@ +Fix rendering of edited polls diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/timeline/TimelineEvent.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/timeline/TimelineEvent.kt index 6320ea964d..3aa480094c 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/timeline/TimelineEvent.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/timeline/TimelineEvent.kt @@ -148,8 +148,8 @@ fun TimelineEvent.getLastMessageContent(): MessageContent? { // Polls/Beacon are not message contents like others as there is no msgtype subtype to discriminate moshi parsing // so toModel won't parse them correctly // It's discriminated on event type instead. Maybe it shouldn't be MessageContent at all to avoid confusion? - in EventType.POLL_START.values -> (getLastEditNewContent() ?: root.getClearContent()).toModel() - in EventType.POLL_END.values -> (getLastEditNewContent() ?: root.getClearContent()).toModel() + in EventType.POLL_START.values -> (getLastPollEditNewContent() ?: root.getClearContent()).toModel() + in EventType.POLL_END.values -> (getLastPollEditNewContent() ?: root.getClearContent()).toModel() in EventType.STATE_ROOM_BEACON_INFO.values -> (getLastEditNewContent() ?: root.getClearContent()).toModel() in EventType.BEACON_LOCATION_DATA.values -> (getLastEditNewContent() ?: root.getClearContent()).toModel() else -> (getLastEditNewContent() ?: root.getClearContent()).toModel() @@ -160,6 +160,10 @@ fun TimelineEvent.getLastEditNewContent(): Content? { return annotations?.editSummary?.latestEdit?.getClearContent()?.toModel()?.newContent } +private fun TimelineEvent.getLastPollEditNewContent(): Content? { + return annotations?.editSummary?.latestEdit?.getClearContent()?.toModel()?.newContent +} + /** * Returns true if it's a reply. */ diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/EventEditValidator.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/EventEditValidator.kt index 41d0c3f6ab..5a66e7e62d 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/EventEditValidator.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/EventEditValidator.kt @@ -16,13 +16,16 @@ package org.matrix.android.sdk.internal.session.room +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.EventType import org.matrix.android.sdk.api.session.events.model.LocalEcho import org.matrix.android.sdk.api.session.events.model.RelationType import org.matrix.android.sdk.api.session.events.model.getRelationContent import org.matrix.android.sdk.api.session.events.model.toModel import org.matrix.android.sdk.api.session.events.model.toValidDecryptedEvent import org.matrix.android.sdk.api.session.room.model.message.MessageContent +import org.matrix.android.sdk.api.session.room.model.message.MessagePollContent import org.matrix.android.sdk.internal.crypto.store.IMXCryptoStore import timber.log.Timber import javax.inject.Inject @@ -101,7 +104,7 @@ internal class EventEditValidator @Inject constructor(val cryptoStore: IMXCrypto if (originalDecrypted.type != replaceDecrypted.type) { return EditValidity.Invalid("replacement and original events must have the same type") } - if (replaceDecrypted.clearContent.toModel()?.newContent == null) { + if (!hasNewContent(replaceDecrypted.type, replaceDecrypted.clearContent)) { return EditValidity.Invalid("replacement event must have an m.new_content property") } } else { @@ -116,11 +119,18 @@ internal class EventEditValidator @Inject constructor(val cryptoStore: IMXCrypto if (originalEvent.type != replaceEvent.type) { return EditValidity.Invalid("replacement and original events must have the same type") } - if (replaceEvent.content.toModel()?.newContent == null) { + if (!hasNewContent(replaceEvent.type, replaceEvent.content)) { return EditValidity.Invalid("replacement event must have an m.new_content property") } } return EditValidity.Valid } + + private fun hasNewContent(eventType: String?, content: Content?): Boolean { + return when (eventType) { + in EventType.POLL_START.values -> content.toModel()?.newContent != null + else -> content.toModel()?.newContent != null + } + } } diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/action/MessageActionsViewModel.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/action/MessageActionsViewModel.kt index 646cfa50d2..d442c1f1ba 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/action/MessageActionsViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/action/MessageActionsViewModel.kt @@ -216,8 +216,8 @@ class MessageActionsViewModel @AssistedInject constructor( noticeEventFormatter.format(timelineEvent, room?.roomSummary()?.isDirect.orFalse()) } in EventType.POLL_START.values -> { - timelineEvent.root.getClearContent().toModel(catchError = true) - ?.getBestPollCreationInfo()?.question?.getBestQuestion() ?: "" + (timelineEvent.getVectorLastMessageContent() as? MessagePollContent)?.getBestPollCreationInfo()?.question?.getBestQuestion() + ?: stringProvider.getString(R.string.message_reply_to_poll_preview) } else -> null } diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/format/DisplayableEventFormatter.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/format/DisplayableEventFormatter.kt index 5fa9576dd4..ef4846d822 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/format/DisplayableEventFormatter.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/format/DisplayableEventFormatter.kt @@ -130,7 +130,7 @@ class DisplayableEventFormatter @Inject constructor( span { } } in EventType.POLL_START.values -> { - timelineEvent.root.getClearContent().toModel(catchError = true)?.getBestPollCreationInfo()?.question?.getBestQuestion() + (timelineEvent.getVectorLastMessageContent() as? MessagePollContent)?.getBestPollCreationInfo()?.question?.getBestQuestion() ?: stringProvider.getString(R.string.sent_a_poll) } in EventType.POLL_RESPONSE.values -> {