From 8b34caa0b1b773b2e62c433ec0e2f0ea48d91cb8 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Mon, 1 Mar 2021 11:51:56 +0100 Subject: [PATCH 01/17] Move capability section above Server name and version section --- .../settings/homeserver/HomeserverSettingsController.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vector/src/main/java/im/vector/app/features/settings/homeserver/HomeserverSettingsController.kt b/vector/src/main/java/im/vector/app/features/settings/homeserver/HomeserverSettingsController.kt index e90f711edc..514311315d 100644 --- a/vector/src/main/java/im/vector/app/features/settings/homeserver/HomeserverSettingsController.kt +++ b/vector/src/main/java/im/vector/app/features/settings/homeserver/HomeserverSettingsController.kt @@ -48,6 +48,7 @@ class HomeserverSettingsController @Inject constructor( data ?: return buildHeader(data) + buildCapabilities(data) when (val federationVersion = data.federationVersion) { is Loading, is Uninitialized -> @@ -63,7 +64,6 @@ class HomeserverSettingsController @Inject constructor( is Success -> buildFederationVersion(federationVersion()) } - buildCapabilities(data) } private fun buildHeader(state: HomeServerSettingsViewState) { From d3b2306b3d8c45183bf66ba774dec4044469fdc4 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Mon, 1 Mar 2021 14:33:52 +0100 Subject: [PATCH 02/17] Remove unused file --- .../main/res/layout/view_image_attachment.xml | 17 ----------------- 1 file changed, 17 deletions(-) delete mode 100644 attachment-viewer/src/main/res/layout/view_image_attachment.xml diff --git a/attachment-viewer/src/main/res/layout/view_image_attachment.xml b/attachment-viewer/src/main/res/layout/view_image_attachment.xml deleted file mode 100644 index 3518a4472d..0000000000 --- a/attachment-viewer/src/main/res/layout/view_image_attachment.xml +++ /dev/null @@ -1,17 +0,0 @@ - - - - - - - \ No newline at end of file From 9a635dd906e31c8033626da4e927d951b380d9af Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Mon, 1 Mar 2021 15:10:27 +0100 Subject: [PATCH 03/17] Move VerificationState to a dedicated file and in the correct package --- .../sdk/api/crypto/VerificationState.kt | 25 +++++++++++++++++++ .../room/model/ReferencesAggregatedContent.kt | 2 +- .../EventRelationsAggregationProcessor.kt | 9 +------ .../factory/VerificationItemFactory.kt | 2 +- .../helper/MessageInformationDataFactory.kt | 2 +- .../timeline/item/MessageInformationData.kt | 2 +- .../timeline/item/VerificationRequestItem.kt | 2 +- 7 files changed, 31 insertions(+), 13 deletions(-) create mode 100644 matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/crypto/VerificationState.kt diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/crypto/VerificationState.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/crypto/VerificationState.kt new file mode 100644 index 0000000000..8a3515740b --- /dev/null +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/crypto/VerificationState.kt @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2021 The Matrix.org Foundation C.I.C. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.matrix.android.sdk.api.crypto + +enum class VerificationState { + REQUEST, + WAITING, + CANCELED_BY_ME, + CANCELED_BY_OTHER, + DONE +} diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/ReferencesAggregatedContent.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/ReferencesAggregatedContent.kt index 0947c96bb0..664d042e18 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/ReferencesAggregatedContent.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/ReferencesAggregatedContent.kt @@ -17,7 +17,7 @@ package org.matrix.android.sdk.api.session.room.model import com.squareup.moshi.Json import com.squareup.moshi.JsonClass -import org.matrix.android.sdk.internal.session.room.VerificationState +import org.matrix.android.sdk.api.crypto.VerificationState /** * Contains an aggregated summary info of the references. diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/EventRelationsAggregationProcessor.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/EventRelationsAggregationProcessor.kt index d090ba5296..eefab74136 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/EventRelationsAggregationProcessor.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/EventRelationsAggregationProcessor.kt @@ -16,6 +16,7 @@ package org.matrix.android.sdk.internal.session.room import io.realm.Realm +import org.matrix.android.sdk.api.crypto.VerificationState import org.matrix.android.sdk.api.session.events.model.AggregatedAnnotation import org.matrix.android.sdk.api.session.events.model.Event import org.matrix.android.sdk.api.session.events.model.EventType @@ -50,14 +51,6 @@ import org.matrix.android.sdk.internal.session.EventInsertLiveProcessor import timber.log.Timber import javax.inject.Inject -enum class VerificationState { - REQUEST, - WAITING, - CANCELED_BY_ME, - CANCELED_BY_OTHER, - DONE -} - fun VerificationState.isCanceled(): Boolean { return this == VerificationState.CANCELED_BY_ME || this == VerificationState.CANCELED_BY_OTHER } diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/factory/VerificationItemFactory.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/factory/VerificationItemFactory.kt index 0b623d78f1..eb539d2b8a 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/factory/VerificationItemFactory.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/factory/VerificationItemFactory.kt @@ -26,6 +26,7 @@ import im.vector.app.features.home.room.detail.timeline.helper.MessageInformatio import im.vector.app.features.home.room.detail.timeline.helper.MessageItemAttributesFactory import im.vector.app.features.home.room.detail.timeline.item.StatusTileTimelineItem import im.vector.app.features.home.room.detail.timeline.item.StatusTileTimelineItem_ +import org.matrix.android.sdk.api.crypto.VerificationState import org.matrix.android.sdk.api.session.Session import org.matrix.android.sdk.api.session.crypto.verification.CancelCode import org.matrix.android.sdk.api.session.crypto.verification.safeValueOf @@ -35,7 +36,6 @@ import org.matrix.android.sdk.api.session.events.model.toModel import org.matrix.android.sdk.api.session.room.model.message.MessageRelationContent import org.matrix.android.sdk.api.session.room.model.message.MessageVerificationCancelContent import org.matrix.android.sdk.api.session.room.timeline.TimelineEvent -import org.matrix.android.sdk.internal.session.room.VerificationState import javax.inject.Inject /** diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/helper/MessageInformationDataFactory.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/helper/MessageInformationDataFactory.kt index 802c177197..951a4d3fa0 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/helper/MessageInformationDataFactory.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/helper/MessageInformationDataFactory.kt @@ -26,6 +26,7 @@ import im.vector.app.features.home.room.detail.timeline.item.ReactionInfoData import im.vector.app.features.home.room.detail.timeline.item.ReadReceiptData import im.vector.app.features.home.room.detail.timeline.item.ReferencesInfoData import im.vector.app.features.settings.VectorPreferences +import org.matrix.android.sdk.api.crypto.VerificationState import org.matrix.android.sdk.api.extensions.orFalse import org.matrix.android.sdk.api.session.Session import org.matrix.android.sdk.api.session.events.model.EventType @@ -37,7 +38,6 @@ import org.matrix.android.sdk.api.session.room.timeline.TimelineEvent import org.matrix.android.sdk.api.session.room.timeline.getLastMessageContent import org.matrix.android.sdk.api.session.room.timeline.hasBeenEdited import org.matrix.android.sdk.internal.crypto.model.event.EncryptedEventContent -import org.matrix.android.sdk.internal.session.room.VerificationState import javax.inject.Inject /** diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/item/MessageInformationData.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/item/MessageInformationData.kt index 38575f0cc9..48bd4db94c 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/item/MessageInformationData.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/item/MessageInformationData.kt @@ -18,9 +18,9 @@ package im.vector.app.features.home.room.detail.timeline.item import android.os.Parcelable import kotlinx.parcelize.Parcelize +import org.matrix.android.sdk.api.crypto.VerificationState import org.matrix.android.sdk.api.session.room.send.SendState import org.matrix.android.sdk.api.util.MatrixItem -import org.matrix.android.sdk.internal.session.room.VerificationState @Parcelize data class MessageInformationData( diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/item/VerificationRequestItem.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/item/VerificationRequestItem.kt index c7a279979b..9ec1d825df 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/item/VerificationRequestItem.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/item/VerificationRequestItem.kt @@ -35,8 +35,8 @@ import im.vector.app.features.home.AvatarRenderer import im.vector.app.features.home.room.detail.RoomDetailAction import im.vector.app.features.home.room.detail.timeline.MessageColorProvider import im.vector.app.features.home.room.detail.timeline.TimelineEventController +import org.matrix.android.sdk.api.crypto.VerificationState import org.matrix.android.sdk.api.session.crypto.verification.VerificationService -import org.matrix.android.sdk.internal.session.room.VerificationState @EpoxyModelClass(layout = R.layout.item_timeline_event_base_state) abstract class VerificationRequestItem : AbsBaseMessageItem() { From c7e7bf4d2c6debc327e0ddd86da0bcf9fd099c1a Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Mon, 1 Mar 2021 15:14:03 +0100 Subject: [PATCH 04/17] Move VerificationState?.toState() to a dedicated file and in the correct package --- .../sdk/api/crypto/VerificationState.kt | 4 +++ .../verification/VerificationStateExt.kt | 36 +++++++++++++++++++ .../EventRelationsAggregationProcessor.kt | 20 +---------- 3 files changed, 41 insertions(+), 19 deletions(-) create mode 100644 matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/verification/VerificationStateExt.kt diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/crypto/VerificationState.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/crypto/VerificationState.kt index 8a3515740b..54276a6b51 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/crypto/VerificationState.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/crypto/VerificationState.kt @@ -23,3 +23,7 @@ enum class VerificationState { CANCELED_BY_OTHER, DONE } + +fun VerificationState.isCanceled(): Boolean { + return this == VerificationState.CANCELED_BY_ME || this == VerificationState.CANCELED_BY_OTHER +} diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/verification/VerificationStateExt.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/verification/VerificationStateExt.kt new file mode 100644 index 0000000000..b5fba0d54c --- /dev/null +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/verification/VerificationStateExt.kt @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2021 The Matrix.org Foundation C.I.C. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.matrix.android.sdk.internal.crypto.verification + +import org.matrix.android.sdk.api.crypto.VerificationState +import org.matrix.android.sdk.api.crypto.isCanceled + +// State transition with control +internal fun VerificationState?.toState(newState: VerificationState): VerificationState { + // Cancel is always prioritary ? + // Eg id i found that mac or keys mismatch and send a cancel and the other send a done, i have to + // consider as canceled + if (newState.isCanceled()) { + return newState + } + // never move out of cancel + if (this?.isCanceled() == true) { + return this + } + return newState +} + diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/EventRelationsAggregationProcessor.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/EventRelationsAggregationProcessor.kt index eefab74136..8df865b104 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/EventRelationsAggregationProcessor.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/EventRelationsAggregationProcessor.kt @@ -32,6 +32,7 @@ import org.matrix.android.sdk.api.session.room.model.message.MessagePollResponse import org.matrix.android.sdk.api.session.room.model.message.MessageRelationContent import org.matrix.android.sdk.api.session.room.model.relation.ReactionContent import org.matrix.android.sdk.internal.crypto.model.event.EncryptedEventContent +import org.matrix.android.sdk.internal.crypto.verification.toState import org.matrix.android.sdk.internal.database.mapper.ContentMapper import org.matrix.android.sdk.internal.database.mapper.EventMapper import org.matrix.android.sdk.internal.database.model.EditAggregatedSummaryEntity @@ -51,25 +52,6 @@ import org.matrix.android.sdk.internal.session.EventInsertLiveProcessor import timber.log.Timber import javax.inject.Inject -fun VerificationState.isCanceled(): Boolean { - return this == VerificationState.CANCELED_BY_ME || this == VerificationState.CANCELED_BY_OTHER -} - -// State transition with control -private fun VerificationState?.toState(newState: VerificationState): VerificationState { - // Cancel is always prioritary ? - // Eg id i found that mac or keys mismatch and send a cancel and the other send a done, i have to - // consider as canceled - if (newState.isCanceled()) { - return newState - } - // never move out of cancel - if (this?.isCanceled() == true) { - return this - } - return newState -} - internal class EventRelationsAggregationProcessor @Inject constructor(@UserId private val userId: String) : EventInsertLiveProcessor { From bdec23f740608915538b0d164b05f86926918d2c Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Mon, 1 Mar 2021 15:03:47 +0100 Subject: [PATCH 05/17] Rework edition of event management --- .../EventAnnotationsSummaryEntityQuery.kt | 2 +- .../EventRelationsAggregationProcessor.kt | 44 +++++++++++++------ 2 files changed, 31 insertions(+), 15 deletions(-) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/query/EventAnnotationsSummaryEntityQuery.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/query/EventAnnotationsSummaryEntityQuery.kt index 9a298b7e79..b96fc54a42 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/query/EventAnnotationsSummaryEntityQuery.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/query/EventAnnotationsSummaryEntityQuery.kt @@ -50,5 +50,5 @@ internal fun EventAnnotationsSummaryEntity.Companion.create(realm: Realm, roomId internal fun EventAnnotationsSummaryEntity.Companion.getOrCreate(realm: Realm, roomId: String, eventId: String): EventAnnotationsSummaryEntity { return EventAnnotationsSummaryEntity.where(realm, eventId).findFirst() - ?: EventAnnotationsSummaryEntity.create(realm, roomId, eventId).apply { this.roomId = roomId } + ?: EventAnnotationsSummaryEntity.create(realm, roomId, eventId) } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/EventRelationsAggregationProcessor.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/EventRelationsAggregationProcessor.kt index 8df865b104..dd6b16de59 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/EventRelationsAggregationProcessor.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/EventRelationsAggregationProcessor.kt @@ -191,29 +191,45 @@ internal class EventRelationsAggregationProcessor @Inject constructor(@UserId pr // OPT OUT serer aggregation until API mature enough private val SHOULD_HANDLE_SERVER_AGREGGATION = false - private fun handleReplace(realm: Realm, event: Event, content: MessageContent, roomId: String, isLocalEcho: Boolean, relatedEventId: String? = null) { + private fun handleReplace(realm: Realm, + event: Event, + content: MessageContent, + roomId: String, + isLocalEcho: Boolean, + relatedEventId: String? = null) { val eventId = event.eventId ?: return val targetEventId = relatedEventId ?: content.relatesTo?.eventId ?: return val newContent = content.newContent ?: return + + // Check that the sender is the same + val editedEvent = EventEntity.where(realm, targetEventId).findFirst() + if (editedEvent == null) { + // We do not know yet about the edited event + } else if (editedEvent.sender != event.senderId) { + // Edited by someone else, ignore + Timber.w("Ignore edition by someone else") + return + } + // ok, this is a replace - val existing = EventAnnotationsSummaryEntity.getOrCreate(realm, roomId, targetEventId) + val eventAnnotationsSummaryEntity = EventAnnotationsSummaryEntity.getOrCreate(realm, roomId, targetEventId) // we have it - val existingSummary = existing.editSummary + val existingSummary = eventAnnotationsSummaryEntity.editSummary if (existingSummary == null) { Timber.v("###REPLACE new edit summary for $targetEventId, creating one (localEcho:$isLocalEcho)") // create the edit summary - val editSummary = realm.createObject(EditAggregatedSummaryEntity::class.java) - editSummary.aggregatedContent = ContentMapper.map(newContent) - if (isLocalEcho) { - editSummary.lastEditTs = 0 - editSummary.sourceLocalEchoEvents.add(eventId) - } else { - editSummary.lastEditTs = event.originServerTs ?: 0 - editSummary.sourceEvents.add(eventId) - } - - existing.editSummary = editSummary + eventAnnotationsSummaryEntity.editSummary = realm.createObject(EditAggregatedSummaryEntity::class.java) + .also { editSummary -> + editSummary.aggregatedContent = ContentMapper.map(newContent) + if (isLocalEcho) { + editSummary.lastEditTs = 0 + editSummary.sourceLocalEchoEvents.add(eventId) + } else { + editSummary.lastEditTs = event.originServerTs ?: 0 + editSummary.sourceEvents.add(eventId) + } + } } else { if (existingSummary.sourceEvents.contains(eventId)) { // ignore this event, we already know it (??) From 1bfd78753a825d8739b98fb0030eeb3fa705d567 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Mon, 1 Mar 2021 17:52:56 +0100 Subject: [PATCH 06/17] Ensure we do not edit an Event from another room --- .../database/helper/ChunkEntityHelper.kt | 2 +- .../EventAnnotationsSummaryEntityQuery.kt | 18 ++++--------- .../EventRelationsAggregationProcessor.kt | 25 ++++++++----------- .../room/relation/DefaultRelationService.kt | 4 +-- .../relation/FindReactionEventForUndoTask.kt | 8 +++--- .../room/relation/UpdateQuickReactionTask.kt | 14 +++++------ 6 files changed, 30 insertions(+), 41 deletions(-) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/helper/ChunkEntityHelper.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/helper/ChunkEntityHelper.kt index b4935cfdcc..c2b729e593 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/helper/ChunkEntityHelper.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/helper/ChunkEntityHelper.kt @@ -97,7 +97,7 @@ internal fun ChunkEntity.addTimelineEvent(roomId: String, this.root = eventEntity this.eventId = eventId this.roomId = roomId - this.annotations = EventAnnotationsSummaryEntity.where(realm, eventId).findFirst() + this.annotations = EventAnnotationsSummaryEntity.where(realm, roomId, eventId).findFirst() this.readReceipts = readReceiptsSummaryEntity this.displayIndex = displayIndex val roomMemberContent = roomMemberContentsByUser[senderId] diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/query/EventAnnotationsSummaryEntityQuery.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/query/EventAnnotationsSummaryEntityQuery.kt index b96fc54a42..c3cae3d268 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/query/EventAnnotationsSummaryEntityQuery.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/query/EventAnnotationsSummaryEntityQuery.kt @@ -23,18 +23,10 @@ import io.realm.Realm import io.realm.RealmQuery import io.realm.kotlin.where -internal fun EventAnnotationsSummaryEntity.Companion.where(realm: Realm, eventId: String): RealmQuery { - val query = realm.where() - query.equalTo(EventAnnotationsSummaryEntityFields.EVENT_ID, eventId) - return query -} - -internal fun EventAnnotationsSummaryEntity.Companion.whereInRoom(realm: Realm, roomId: String?): RealmQuery { - val query = realm.where() - if (roomId != null) { - query.equalTo(EventAnnotationsSummaryEntityFields.ROOM_ID, roomId) - } - return query +internal fun EventAnnotationsSummaryEntity.Companion.where(realm: Realm, roomId: String, eventId: String): RealmQuery { + return realm.where() + .equalTo(EventAnnotationsSummaryEntityFields.ROOM_ID, roomId) + .equalTo(EventAnnotationsSummaryEntityFields.EVENT_ID, eventId) } internal fun EventAnnotationsSummaryEntity.Companion.create(realm: Realm, roomId: String, eventId: String): EventAnnotationsSummaryEntity { @@ -49,6 +41,6 @@ internal fun EventAnnotationsSummaryEntity.Companion.create(realm: Realm, roomId } internal fun EventAnnotationsSummaryEntity.Companion.getOrCreate(realm: Realm, roomId: String, eventId: String): EventAnnotationsSummaryEntity { - return EventAnnotationsSummaryEntity.where(realm, eventId).findFirst() + return EventAnnotationsSummaryEntity.where(realm, roomId, eventId).findFirst() ?: EventAnnotationsSummaryEntity.create(realm, roomId, eventId) } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/EventRelationsAggregationProcessor.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/EventRelationsAggregationProcessor.kt index dd6b16de59..c274ccb244 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/EventRelationsAggregationProcessor.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/EventRelationsAggregationProcessor.kt @@ -93,13 +93,11 @@ internal class EventRelationsAggregationProcessor @Inject constructor(@UserId pr Timber.v("###REACTION Agreggation in room $roomId for event ${event.eventId}") handleInitialAggregatedRelations(event, roomId, event.unsignedData.relations.annotations, realm) - EventAnnotationsSummaryEntity.where(realm, event.eventId - ?: "").findFirst()?.let { - TimelineEventEntity.where(realm, roomId = roomId, eventId = event.eventId - ?: "").findFirst()?.let { tet -> - tet.annotations = it - } - } + EventAnnotationsSummaryEntity.where(realm, roomId, event.eventId ?: "").findFirst() + ?.let { + TimelineEventEntity.where(realm, roomId = roomId, eventId = event.eventId ?: "").findFirst() + ?.let { tet -> tet.annotations = it } + } } val content: MessageContent? = event.content.toModel() @@ -281,7 +279,7 @@ internal class EventRelationsAggregationProcessor @Inject constructor(@UserId pr val eventTimestamp = event.originServerTs ?: return // ok, this is a poll response - var existing = EventAnnotationsSummaryEntity.where(realm, targetEventId).findFirst() + var existing = EventAnnotationsSummaryEntity.where(realm, roomId, targetEventId).findFirst() if (existing == null) { Timber.v("## POLL creating new relation summary for $targetEventId") existing = EventAnnotationsSummaryEntity.create(realm, roomId, targetEventId) @@ -361,7 +359,7 @@ internal class EventRelationsAggregationProcessor @Inject constructor(@UserId pr aggregation.chunk?.forEach { if (it.type == EventType.REACTION) { val eventId = event.eventId ?: "" - val existing = EventAnnotationsSummaryEntity.where(realm, eventId).findFirst() + val existing = EventAnnotationsSummaryEntity.where(realm, roomId, eventId).findFirst() if (existing == null) { val eventSummary = EventAnnotationsSummaryEntity.create(realm, roomId, eventId) val sum = realm.createObject(ReactionAggregatedSummaryEntity::class.java) @@ -445,7 +443,7 @@ internal class EventRelationsAggregationProcessor @Inject constructor(@UserId pr */ private fun handleRedactionOfReplace(redacted: EventEntity, relatedEventId: String, realm: Realm) { Timber.d("Handle redaction of m.replace") - val eventSummary = EventAnnotationsSummaryEntity.where(realm, relatedEventId).findFirst() + val eventSummary = EventAnnotationsSummaryEntity.where(realm, redacted.roomId, relatedEventId).findFirst() if (eventSummary == null) { Timber.w("Redaction of a replace targeting an unknown event $relatedEventId") return @@ -475,16 +473,15 @@ internal class EventRelationsAggregationProcessor @Inject constructor(@UserId pr } } - fun handleReactionRedact(eventToPrune: EventEntity, realm: Realm, userId: String) { + private fun handleReactionRedact(eventToPrune: EventEntity, realm: Realm, userId: String) { Timber.v("REDACTION of reaction ${eventToPrune.eventId}") // delete a reaction, need to update the annotation summary if any - val reactionContent: ReactionContent = EventMapper.map(eventToPrune).content.toModel() - ?: return + val reactionContent: ReactionContent = EventMapper.map(eventToPrune).content.toModel() ?: return val eventThatWasReacted = reactionContent.relatesTo?.eventId ?: return val reactionKey = reactionContent.relatesTo.key Timber.v("REMOVE reaction for key $reactionKey") - val summary = EventAnnotationsSummaryEntity.where(realm, eventThatWasReacted).findFirst() + val summary = EventAnnotationsSummaryEntity.where(realm, eventToPrune.roomId, eventThatWasReacted).findFirst() if (summary != null) { summary.reactionsSummary.where() .equalTo(ReactionAggregatedSummaryEntityFields.KEY, reactionKey) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/relation/DefaultRelationService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/relation/DefaultRelationService.kt index b7caf62865..bbcad3a4fe 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/relation/DefaultRelationService.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/relation/DefaultRelationService.kt @@ -159,7 +159,7 @@ internal class DefaultRelationService @AssistedInject constructor( override fun getEventAnnotationsSummary(eventId: String): EventAnnotationsSummary? { return monarchy.fetchCopyMap( - { EventAnnotationsSummaryEntity.where(it, eventId).findFirst() }, + { EventAnnotationsSummaryEntity.where(it, roomId, eventId).findFirst() }, { entity, _ -> entity.asDomain() } @@ -168,7 +168,7 @@ internal class DefaultRelationService @AssistedInject constructor( override fun getEventAnnotationsSummaryLive(eventId: String): LiveData> { val liveData = monarchy.findAllMappedWithChanges( - { EventAnnotationsSummaryEntity.where(it, eventId) }, + { EventAnnotationsSummaryEntity.where(it, roomId, eventId) }, { it.asDomain() } ) return Transformations.map(liveData) { results -> diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/relation/FindReactionEventForUndoTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/relation/FindReactionEventForUndoTask.kt index fa6db2ee37..863ae4f5ce 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/relation/FindReactionEventForUndoTask.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/relation/FindReactionEventForUndoTask.kt @@ -45,16 +45,16 @@ internal class DefaultFindReactionEventForUndoTask @Inject constructor( override suspend fun execute(params: FindReactionEventForUndoTask.Params): FindReactionEventForUndoTask.Result { val eventId = Realm.getInstance(monarchy.realmConfiguration).use { realm -> - getReactionToRedact(realm, params.reaction, params.eventId)?.eventId + getReactionToRedact(realm, params)?.eventId } return FindReactionEventForUndoTask.Result(eventId) } - private fun getReactionToRedact(realm: Realm, reaction: String, eventId: String): EventEntity? { - val summary = EventAnnotationsSummaryEntity.where(realm, eventId).findFirst() ?: return null + private fun getReactionToRedact(realm: Realm, params: FindReactionEventForUndoTask.Params): EventEntity? { + val summary = EventAnnotationsSummaryEntity.where(realm, params.roomId, params.eventId).findFirst() ?: return null val rase = summary.reactionsSummary.where() - .equalTo(ReactionAggregatedSummaryEntityFields.KEY, reaction) + .equalTo(ReactionAggregatedSummaryEntityFields.KEY, params.reaction) .findFirst() ?: return null // want to find the event originated by me! diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/relation/UpdateQuickReactionTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/relation/UpdateQuickReactionTask.kt index 1f68a700ad..32d6c5aa7e 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/relation/UpdateQuickReactionTask.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/relation/UpdateQuickReactionTask.kt @@ -47,22 +47,22 @@ internal class DefaultUpdateQuickReactionTask @Inject constructor(@SessionDataba override suspend fun execute(params: UpdateQuickReactionTask.Params): UpdateQuickReactionTask.Result { var res: Pair?>? = null monarchy.doWithRealm { realm -> - res = updateQuickReaction(realm, params.reaction, params.oppositeReaction, params.eventId) + res = updateQuickReaction(realm, params) } return UpdateQuickReactionTask.Result(res?.first, res?.second.orEmpty()) } - private fun updateQuickReaction(realm: Realm, reaction: String, oppositeReaction: String, eventId: String): Pair?> { + private fun updateQuickReaction(realm: Realm, params: UpdateQuickReactionTask.Params): Pair?> { // the emoji reaction has been selected, we need to check if we have reacted it or not - val existingSummary = EventAnnotationsSummaryEntity.where(realm, eventId).findFirst() - ?: return Pair(reaction, null) + val existingSummary = EventAnnotationsSummaryEntity.where(realm, params.roomId, params.eventId).findFirst() + ?: return Pair(params.reaction, null) // Ok there is already reactions on this event, have we reacted to it val aggregationForReaction = existingSummary.reactionsSummary.where() - .equalTo(ReactionAggregatedSummaryEntityFields.KEY, reaction) + .equalTo(ReactionAggregatedSummaryEntityFields.KEY, params.reaction) .findFirst() val aggregationForOppositeReaction = existingSummary.reactionsSummary.where() - .equalTo(ReactionAggregatedSummaryEntityFields.KEY, oppositeReaction) + .equalTo(ReactionAggregatedSummaryEntityFields.KEY, params.oppositeReaction) .findFirst() if (aggregationForReaction == null || !aggregationForReaction.addedByMe) { @@ -72,7 +72,7 @@ internal class DefaultUpdateQuickReactionTask @Inject constructor(@SessionDataba val entity = EventEntity.where(realm, it).findFirst() if (entity?.sender == userId) entity.eventId else null } - return Pair(reaction, toRedact) + return Pair(params.reaction, toRedact) } else { // I already added it, so i need to undo it (like a toggle) // find all m.redaction coming from me to readact them From 097668b762d7426c4e1ca175f1e09ac0c9e2e4ce Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Mon, 1 Mar 2021 19:59:55 +0100 Subject: [PATCH 07/17] Rework edition of event management - step 2 --- CHANGES.md | 2 +- .../database/RealmSessionStoreMigration.kt | 30 ++++++- .../database/helper/ChunkEntityHelper.kt | 1 + .../mapper/EventAnnotationsSummaryMapper.kt | 55 ++---------- .../model/EditAggregatedSummaryEntity.kt | 19 +++-- .../model/EventAnnotationsSummaryEntity.kt | 16 ++++ .../database/model/SessionRealmModule.kt | 1 + .../EventRelationsAggregationProcessor.kt | 84 ++++++++----------- 8 files changed, 102 insertions(+), 106 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index 5125d158ec..d9c2c01bea 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -25,7 +25,7 @@ Test: - Other changes: - - + - Rework edition of event management Changes in Element 1.1.0 (2021-02-19) =================================================== diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/RealmSessionStoreMigration.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/RealmSessionStoreMigration.kt index 57002b5a60..820588b1ab 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/RealmSessionStoreMigration.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/RealmSessionStoreMigration.kt @@ -18,6 +18,8 @@ package org.matrix.android.sdk.internal.database import io.realm.DynamicRealm import io.realm.RealmMigration +import org.matrix.android.sdk.internal.database.model.EditAggregatedSummaryEntityFields +import org.matrix.android.sdk.internal.database.model.EditionOfEventFields import org.matrix.android.sdk.internal.database.model.HomeServerCapabilitiesEntityFields import org.matrix.android.sdk.internal.database.model.PendingThreePidEntityFields import org.matrix.android.sdk.internal.database.model.PreviewUrlCacheEntityFields @@ -30,7 +32,7 @@ import javax.inject.Inject class RealmSessionStoreMigration @Inject constructor() : RealmMigration { companion object { - const val SESSION_STORE_SCHEMA_VERSION = 7L + const val SESSION_STORE_SCHEMA_VERSION = 8L } override fun migrate(realm: DynamicRealm, oldVersion: Long, newVersion: Long) { @@ -43,6 +45,7 @@ class RealmSessionStoreMigration @Inject constructor() : RealmMigration { if (oldVersion <= 4) migrateTo5(realm) if (oldVersion <= 5) migrateTo6(realm) if (oldVersion <= 6) migrateTo7(realm) + if (oldVersion <= 7) migrateTo8(realm) } private fun migrateTo1(realm: DynamicRealm) { @@ -122,4 +125,29 @@ class RealmSessionStoreMigration @Inject constructor() : RealmMigration { } ?.removeField("areAllMembersLoaded") } + + private fun migrateTo8(realm: DynamicRealm) { + Timber.d("Step 7 -> 8") + + val editionOfEventSchema = realm.schema.create("EditionOfEvent") + .apply { + // setEmbedded does not return `this`... + isEmbedded = true + } + .addField(EditionOfEventFields.CONTENT, String::class.java) + .addField(EditionOfEventFields.EVENT_ID, String::class.java) + .setRequired(EditionOfEventFields.EVENT_ID, true) + .addField(EditionOfEventFields.SENDER_ID, String::class.java) + .setRequired(EditionOfEventFields.SENDER_ID, true) + .addField(EditionOfEventFields.TIMESTAMP, Long::class.java) + .addField(EditionOfEventFields.IS_LOCAL_ECHO, Boolean::class.java) + + + realm.schema.get("EditAggregatedSummaryEntity") + ?.removeField("aggregatedContent") + ?.removeField("sourceEvents") + ?.removeField("lastEditTs") + ?.removeField("sourceLocalEchoEvents") + ?.addRealmListField(EditAggregatedSummaryEntityFields.EDITIONS.`$`, editionOfEventSchema) + } } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/helper/ChunkEntityHelper.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/helper/ChunkEntityHelper.kt index c2b729e593..e262b40419 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/helper/ChunkEntityHelper.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/helper/ChunkEntityHelper.kt @@ -98,6 +98,7 @@ internal fun ChunkEntity.addTimelineEvent(roomId: String, this.eventId = eventId this.roomId = roomId this.annotations = EventAnnotationsSummaryEntity.where(realm, roomId, eventId).findFirst() + ?.also { it.cleanUp(eventEntity.sender) } this.readReceipts = readReceiptsSummaryEntity this.displayIndex = displayIndex val roomMemberContent = roomMemberContentsByUser[senderId] diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/mapper/EventAnnotationsSummaryMapper.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/mapper/EventAnnotationsSummaryMapper.kt index 9ed2664068..f4d3d74150 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/mapper/EventAnnotationsSummaryMapper.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/mapper/EventAnnotationsSummaryMapper.kt @@ -20,11 +20,7 @@ import org.matrix.android.sdk.api.session.room.model.EditAggregatedSummary import org.matrix.android.sdk.api.session.room.model.EventAnnotationsSummary import org.matrix.android.sdk.api.session.room.model.ReactionAggregatedSummary import org.matrix.android.sdk.api.session.room.model.ReferencesAggregatedSummary -import org.matrix.android.sdk.internal.database.model.EditAggregatedSummaryEntity import org.matrix.android.sdk.internal.database.model.EventAnnotationsSummaryEntity -import org.matrix.android.sdk.internal.database.model.ReactionAggregatedSummaryEntity -import org.matrix.android.sdk.internal.database.model.ReferencesAggregatedSummaryEntity -import io.realm.RealmList internal object EventAnnotationsSummaryMapper { fun map(annotationsSummary: EventAnnotationsSummaryEntity): EventAnnotationsSummary { @@ -41,11 +37,14 @@ internal object EventAnnotationsSummaryMapper { ) }, editSummary = annotationsSummary.editSummary?.let { + val latestEdition = it.editions.maxByOrNull { editionOfEvent -> editionOfEvent.timestamp } EditAggregatedSummary( - ContentMapper.map(it.aggregatedContent), - it.sourceEvents.toList(), - it.sourceLocalEchoEvents.toList(), - it.lastEditTs + ContentMapper.map(latestEdition?.content), + it.editions.filter { editionOfEvent -> !editionOfEvent.isLocalEcho } + .map { editionOfEvent -> editionOfEvent.eventId }, + it.editions.filter { editionOfEvent -> editionOfEvent.isLocalEcho } + .map { editionOfEvent -> editionOfEvent.eventId }, + latestEdition?.timestamp ?: 0L ) }, referencesAggregatedSummary = annotationsSummary.referencesSummaryEntity?.let { @@ -62,46 +61,6 @@ internal object EventAnnotationsSummaryMapper { ) } - - fun map(annotationsSummary: EventAnnotationsSummary, roomId: String): EventAnnotationsSummaryEntity { - val eventAnnotationsSummaryEntity = EventAnnotationsSummaryEntity() - eventAnnotationsSummaryEntity.eventId = annotationsSummary.eventId - eventAnnotationsSummaryEntity.roomId = roomId - eventAnnotationsSummaryEntity.editSummary = annotationsSummary.editSummary?.let { - EditAggregatedSummaryEntity( - ContentMapper.map(it.aggregatedContent), - RealmList().apply { addAll(it.sourceEvents) }, - RealmList().apply { addAll(it.localEchos) }, - it.lastEditTs - ) - } - eventAnnotationsSummaryEntity.reactionsSummary = annotationsSummary.reactionsSummary.let { - RealmList().apply { - addAll(it.map { - ReactionAggregatedSummaryEntity( - it.key, - it.count, - it.addedByMe, - it.firstTimestamp, - RealmList().apply { addAll(it.sourceEvents) }, - RealmList().apply { addAll(it.localEchoEvents) } - ) - }) - } - } - eventAnnotationsSummaryEntity.referencesSummaryEntity = annotationsSummary.referencesAggregatedSummary?.let { - ReferencesAggregatedSummaryEntity( - it.eventId, - ContentMapper.map(it.content), - RealmList().apply { addAll(it.sourceEvents) }, - RealmList().apply { addAll(it.localEchos) } - ) - } - eventAnnotationsSummaryEntity.pollResponseSummary = annotationsSummary.pollResponseSummary?.let { - PollResponseAggregatedSummaryEntityMapper.map(it) - } - return eventAnnotationsSummaryEntity - } } internal fun EventAnnotationsSummaryEntity.asDomain(): EventAnnotationsSummary { diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/EditAggregatedSummaryEntity.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/EditAggregatedSummaryEntity.kt index 604afc1ab1..0ed927a6b8 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/EditAggregatedSummaryEntity.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/EditAggregatedSummaryEntity.kt @@ -17,17 +17,24 @@ package org.matrix.android.sdk.internal.database.model import io.realm.RealmList import io.realm.RealmObject +import io.realm.annotations.RealmClass /** - * Keep the latest state of edition of a message + * Keep all the editions of a message */ internal open class EditAggregatedSummaryEntity( - var aggregatedContent: String? = null, - // The list of the eventIDs used to build the summary (might be out of sync if chunked received from message chunk) - var sourceEvents: RealmList = RealmList(), - var sourceLocalEchoEvents: RealmList = RealmList(), - var lastEditTs: Long = 0 + // The list of the editions used to build the summary (might be out of sync if chunked received from message chunk) + var editions: RealmList = RealmList() ) : RealmObject() { companion object } + +@RealmClass(embedded = true) +internal open class EditionOfEvent( + var senderId: String = "", + var eventId: String = "", + var content: String? = null, + var timestamp: Long = 0, + var isLocalEcho: Boolean = false +) : RealmObject() diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/EventAnnotationsSummaryEntity.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/EventAnnotationsSummaryEntity.kt index 33f26d439f..3e88130420 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/EventAnnotationsSummaryEntity.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/EventAnnotationsSummaryEntity.kt @@ -18,6 +18,7 @@ package org.matrix.android.sdk.internal.database.model import io.realm.RealmList import io.realm.RealmObject import io.realm.annotations.PrimaryKey +import timber.log.Timber internal open class EventAnnotationsSummaryEntity( @PrimaryKey @@ -29,6 +30,21 @@ internal open class EventAnnotationsSummaryEntity( var pollResponseSummary: PollResponseAggregatedSummaryEntity? = null ) : RealmObject() { + /** + * Cleanup undesired editions, done by users different from the originalEventSender + */ + fun cleanUp(originalEventSenderId: String?) { + originalEventSenderId ?: return + + editSummary?.editions?.filter { + it.senderId != originalEventSenderId + } + ?.forEach { + Timber.w("Deleting an edition from ${it.senderId} of event sent by $originalEventSenderId") + it.deleteFromRealm() + } + } + companion object } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/SessionRealmModule.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/SessionRealmModule.kt index bca2c42c9e..6e6096cf8a 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/SessionRealmModule.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/SessionRealmModule.kt @@ -43,6 +43,7 @@ import io.realm.annotations.RealmModule EventAnnotationsSummaryEntity::class, ReactionAggregatedSummaryEntity::class, EditAggregatedSummaryEntity::class, + EditionOfEvent::class, PollResponseAggregatedSummaryEntity::class, ReferencesAggregatedSummaryEntity::class, PushRulesEntity::class, diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/EventRelationsAggregationProcessor.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/EventRelationsAggregationProcessor.kt index c274ccb244..8269643d39 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/EventRelationsAggregationProcessor.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/EventRelationsAggregationProcessor.kt @@ -36,6 +36,7 @@ import org.matrix.android.sdk.internal.crypto.verification.toState import org.matrix.android.sdk.internal.database.mapper.ContentMapper import org.matrix.android.sdk.internal.database.mapper.EventMapper import org.matrix.android.sdk.internal.database.model.EditAggregatedSummaryEntity +import org.matrix.android.sdk.internal.database.model.EditionOfEvent import org.matrix.android.sdk.internal.database.model.EventAnnotationsSummaryEntity import org.matrix.android.sdk.internal.database.model.EventEntity import org.matrix.android.sdk.internal.database.model.EventInsertType @@ -219,49 +220,48 @@ internal class EventRelationsAggregationProcessor @Inject constructor(@UserId pr // create the edit summary eventAnnotationsSummaryEntity.editSummary = realm.createObject(EditAggregatedSummaryEntity::class.java) .also { editSummary -> - editSummary.aggregatedContent = ContentMapper.map(newContent) - if (isLocalEcho) { - editSummary.lastEditTs = 0 - editSummary.sourceLocalEchoEvents.add(eventId) - } else { - editSummary.lastEditTs = event.originServerTs ?: 0 - editSummary.sourceEvents.add(eventId) - } + editSummary.editions.add( + EditionOfEvent( + senderId = event.senderId ?: "", + eventId = event.eventId, + content = ContentMapper.map(newContent), + timestamp = if (isLocalEcho) 0 else event.originServerTs ?: 0, + isLocalEcho = isLocalEcho + ) + ) } } else { - if (existingSummary.sourceEvents.contains(eventId)) { + if (existingSummary.editions.any { it.eventId == eventId }) { // ignore this event, we already know it (??) Timber.v("###REPLACE ignoring event for summary, it's known $eventId") return } val txId = event.unsignedData?.transactionId // is it a remote echo? - if (!isLocalEcho && existingSummary.sourceLocalEchoEvents.contains(txId)) { + if (!isLocalEcho && existingSummary.editions.any { it.eventId == txId }) { // ok it has already been managed Timber.v("###REPLACE Receiving remote echo of edit (edit already done)") - existingSummary.sourceLocalEchoEvents.remove(txId) - existingSummary.sourceEvents.add(event.eventId) - } else if ( - isLocalEcho // do not rely on ts for local echo, take it - || event.originServerTs ?: 0 >= existingSummary.lastEditTs - ) { - Timber.v("###REPLACE Computing aggregated edit summary (isLocalEcho:$isLocalEcho)") - if (!isLocalEcho) { - // Do not take local echo originServerTs here, could mess up ordering (keep old ts) - existingSummary.lastEditTs = event.originServerTs ?: System.currentTimeMillis() - } - existingSummary.aggregatedContent = ContentMapper.map(newContent) - if (isLocalEcho) { - existingSummary.sourceLocalEchoEvents.add(eventId) - } else { - existingSummary.sourceEvents.add(eventId) + existingSummary.editions.firstOrNull { it.eventId == txId }?.let { + it.eventId = event.eventId + it.timestamp = event.originServerTs ?: System.currentTimeMillis() + it.isLocalEcho = false } } else { - // ignore this event for the summary (back paginate) - if (!isLocalEcho) { - existingSummary.sourceEvents.add(eventId) - } - Timber.v("###REPLACE ignoring event for summary, it's to old $eventId") + Timber.v("###REPLACE Computing aggregated edit summary (isLocalEcho:$isLocalEcho)") + existingSummary.editions.add( + EditionOfEvent( + senderId = event.senderId ?: "", + eventId = event.eventId, + content = ContentMapper.map(newContent), + timestamp = if (isLocalEcho) { + System.currentTimeMillis() + } else { + // Do not take local echo originServerTs here, could mess up ordering (keep old ts) + event.originServerTs ?: System.currentTimeMillis() + }, + isLocalEcho = isLocalEcho + ) + ) } } } @@ -448,29 +448,13 @@ internal class EventRelationsAggregationProcessor @Inject constructor(@UserId pr Timber.w("Redaction of a replace targeting an unknown event $relatedEventId") return } - val sourceEvents = eventSummary.editSummary?.sourceEvents - val sourceToDiscard = sourceEvents?.indexOf(redacted.eventId) + val sourceToDiscard = eventSummary.editSummary?.editions?.firstOrNull {it.eventId == redacted.eventId } if (sourceToDiscard == null) { Timber.w("Redaction of a replace that was not known in aggregation $sourceToDiscard") return } - // Need to remove this event from the redaction list and compute new aggregation state - sourceEvents.removeAt(sourceToDiscard) - val previousEdit = sourceEvents.mapNotNull { EventEntity.where(realm, it).findFirst() }.sortedBy { it.originServerTs }.lastOrNull() - if (previousEdit == null) { - // revert to original - eventSummary.editSummary?.deleteFromRealm() - } else { - // I have the last event - ContentMapper.map(previousEdit.content)?.toModel()?.newContent?.let { newContent -> - eventSummary.editSummary?.lastEditTs = previousEdit.originServerTs - ?: System.currentTimeMillis() - eventSummary.editSummary?.aggregatedContent = ContentMapper.map(newContent) - } ?: run { - Timber.e("Failed to udate edited summary") - // TODO how to reccover that - } - } + // Need to remove this event from the edition list + sourceToDiscard.deleteFromRealm() } private fun handleReactionRedact(eventToPrune: EventEntity, realm: Realm, userId: String) { From fc468564dcb22115b6b1bb5d879ee77fbb164292 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Tue, 2 Mar 2021 10:46:11 +0100 Subject: [PATCH 08/17] Extract state from view model --- .../edithistory/ViewEditHistoryViewModel.kt | 16 +-------- .../edithistory/ViewEditHistoryViewState.kt | 33 +++++++++++++++++++ 2 files changed, 34 insertions(+), 15 deletions(-) create mode 100644 vector/src/main/java/im/vector/app/features/home/room/detail/timeline/edithistory/ViewEditHistoryViewState.kt diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/edithistory/ViewEditHistoryViewModel.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/edithistory/ViewEditHistoryViewModel.kt index fff1c8a0ff..02fb8c66f2 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/edithistory/ViewEditHistoryViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/edithistory/ViewEditHistoryViewModel.kt @@ -15,23 +15,19 @@ */ package im.vector.app.features.home.room.detail.timeline.edithistory -import com.airbnb.mvrx.Async import com.airbnb.mvrx.Fail import com.airbnb.mvrx.FragmentViewModelContext import com.airbnb.mvrx.Loading -import com.airbnb.mvrx.MvRxState import com.airbnb.mvrx.MvRxViewModelFactory import com.airbnb.mvrx.Success -import com.airbnb.mvrx.Uninitialized import com.airbnb.mvrx.ViewModelContext import dagger.assisted.Assisted -import dagger.assisted.AssistedInject import dagger.assisted.AssistedFactory +import dagger.assisted.AssistedInject import im.vector.app.core.date.VectorDateFormatter import im.vector.app.core.platform.EmptyAction import im.vector.app.core.platform.EmptyViewEvents import im.vector.app.core.platform.VectorViewModel -import im.vector.app.features.home.room.detail.timeline.action.TimelineEventFragmentArgs import org.matrix.android.sdk.api.MatrixCallback import org.matrix.android.sdk.api.session.Session import org.matrix.android.sdk.api.session.crypto.MXCryptoError @@ -41,16 +37,6 @@ import org.matrix.android.sdk.internal.crypto.algorithms.olm.OlmDecryptionResult import timber.log.Timber import java.util.UUID -data class ViewEditHistoryViewState( - val eventId: String, - val roomId: String, - val isOriginalAReply: Boolean = false, - val editList: Async> = Uninitialized) - : MvRxState { - - constructor(args: TimelineEventFragmentArgs) : this(roomId = args.roomId, eventId = args.eventId) -} - class ViewEditHistoryViewModel @AssistedInject constructor(@Assisted initialState: ViewEditHistoryViewState, val session: Session, diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/edithistory/ViewEditHistoryViewState.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/edithistory/ViewEditHistoryViewState.kt new file mode 100644 index 0000000000..62f08eef7f --- /dev/null +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/edithistory/ViewEditHistoryViewState.kt @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2021 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package im.vector.app.features.home.room.detail.timeline.edithistory + +import com.airbnb.mvrx.Async +import com.airbnb.mvrx.MvRxState +import com.airbnb.mvrx.Uninitialized +import im.vector.app.features.home.room.detail.timeline.action.TimelineEventFragmentArgs +import org.matrix.android.sdk.api.session.events.model.Event + +data class ViewEditHistoryViewState( + val eventId: String, + val roomId: String, + val isOriginalAReply: Boolean = false, + val editList: Async> = Uninitialized) + : MvRxState { + + constructor(args: TimelineEventFragmentArgs) : this(roomId = args.roomId, eventId = args.eventId) +} From d2b39e5cb86ac29bb87c559273d9e73cdebd2b69 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Tue, 2 Mar 2021 10:52:03 +0100 Subject: [PATCH 09/17] Convert RelationService to suspend (#2449) --- .../room/model/relation/RelationService.kt | 2 +- .../room/relation/DefaultRelationService.kt | 9 +-- .../edithistory/ViewEditHistoryViewModel.kt | 70 ++++++++++--------- 3 files changed, 39 insertions(+), 42 deletions(-) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/relation/RelationService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/relation/RelationService.kt index 49aa95924c..4638dd204a 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/relation/RelationService.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/relation/RelationService.kt @@ -93,7 +93,7 @@ interface RelationService { /** * Get the edit history of the given event */ - fun fetchEditHistory(eventId: String, callback: MatrixCallback>) + suspend fun fetchEditHistory(eventId: String): List /** * Reply to an event in the timeline (must be in same room) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/relation/DefaultRelationService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/relation/DefaultRelationService.kt index bbcad3a4fe..da0cf45946 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/relation/DefaultRelationService.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/relation/DefaultRelationService.kt @@ -140,13 +140,8 @@ internal class DefaultRelationService @AssistedInject constructor( return eventSenderProcessor.postEvent(event, cryptoSessionInfoProvider.isRoomEncrypted(roomId)) } - override fun fetchEditHistory(eventId: String, callback: MatrixCallback>) { - val params = FetchEditHistoryTask.Params(roomId, eventId) - fetchEditHistoryTask - .configureWith(params) { - this.callback = callback - } - .executeBy(taskExecutor) + override suspend fun fetchEditHistory(eventId: String): List { + return fetchEditHistoryTask.execute(FetchEditHistoryTask.Params(roomId, eventId)) } override fun replyToMessage(eventReplied: TimelineEvent, replyText: CharSequence, autoMarkdown: Boolean): Cancelable? { diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/edithistory/ViewEditHistoryViewModel.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/edithistory/ViewEditHistoryViewModel.kt index 02fb8c66f2..061743e163 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/edithistory/ViewEditHistoryViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/edithistory/ViewEditHistoryViewModel.kt @@ -15,6 +15,7 @@ */ package im.vector.app.features.home.room.detail.timeline.edithistory +import androidx.lifecycle.viewModelScope import com.airbnb.mvrx.Fail import com.airbnb.mvrx.FragmentViewModelContext import com.airbnb.mvrx.Loading @@ -28,10 +29,9 @@ import im.vector.app.core.date.VectorDateFormatter import im.vector.app.core.platform.EmptyAction import im.vector.app.core.platform.EmptyViewEvents import im.vector.app.core.platform.VectorViewModel -import org.matrix.android.sdk.api.MatrixCallback +import kotlinx.coroutines.launch import org.matrix.android.sdk.api.session.Session import org.matrix.android.sdk.api.session.crypto.MXCryptoError -import org.matrix.android.sdk.api.session.events.model.Event import org.matrix.android.sdk.api.session.events.model.isReply import org.matrix.android.sdk.internal.crypto.algorithms.olm.OlmDecryptionResult import timber.log.Timber @@ -68,48 +68,50 @@ class ViewEditHistoryViewModel @AssistedInject constructor(@Assisted private fun loadHistory() { setState { copy(editList = Loading()) } - room.fetchEditHistory(eventId, object : MatrixCallback> { - override fun onFailure(failure: Throwable) { + + viewModelScope.launch { + val data = try { + room.fetchEditHistory(eventId) + } catch (failure: Throwable) { setState { copy(editList = Fail(failure)) } + return@launch } - override fun onSuccess(data: List) { - var originalIsReply = false + var originalIsReply = false - val events = data.map { event -> - val timelineID = event.roomId + UUID.randomUUID().toString() - event.also { - // We need to check encryption - if (it.isEncrypted() && it.mxDecryptionResult == null) { - // for now decrypt sync - try { - val result = session.cryptoService().decryptEvent(it, timelineID) - it.mxDecryptionResult = OlmDecryptionResult( - payload = result.clearEvent, - senderKey = result.senderCurve25519Key, - keysClaimed = result.claimedEd25519Key?.let { k -> mapOf("ed25519" to k) }, - forwardingCurve25519KeyChain = result.forwardingCurve25519KeyChain - ) - } catch (e: MXCryptoError) { - Timber.w("Failed to decrypt event in history") - } - } - - if (event.eventId == it.eventId) { - originalIsReply = it.isReply() + val events = data.map { event -> + val timelineID = event.roomId + UUID.randomUUID().toString() + event.also { + // We need to check encryption + if (it.isEncrypted() && it.mxDecryptionResult == null) { + // for now decrypt sync + try { + val result = session.cryptoService().decryptEvent(it, timelineID) + it.mxDecryptionResult = OlmDecryptionResult( + payload = result.clearEvent, + senderKey = result.senderCurve25519Key, + keysClaimed = result.claimedEd25519Key?.let { k -> mapOf("ed25519" to k) }, + forwardingCurve25519KeyChain = result.forwardingCurve25519KeyChain + ) + } catch (e: MXCryptoError) { + Timber.w("Failed to decrypt event in history") } } - } - setState { - copy( - editList = Success(events), - isOriginalAReply = originalIsReply - ) + + if (event.eventId == it.eventId) { + originalIsReply = it.isReply() + } } } - }) + setState { + copy( + editList = Success(events), + isOriginalAReply = originalIsReply + ) + } + } } override fun handle(action: EmptyAction) { From 7c0acc8ccf3e63ad43cff6477de69a28505c53d1 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Tue, 2 Mar 2021 10:54:37 +0100 Subject: [PATCH 10/17] Simplify code --- .../edithistory/ViewEditHistoryViewModel.kt | 34 +++++++++---------- 1 file changed, 16 insertions(+), 18 deletions(-) diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/edithistory/ViewEditHistoryViewModel.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/edithistory/ViewEditHistoryViewModel.kt index 061743e163..1307341446 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/edithistory/ViewEditHistoryViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/edithistory/ViewEditHistoryViewModel.kt @@ -83,26 +83,24 @@ class ViewEditHistoryViewModel @AssistedInject constructor(@Assisted val events = data.map { event -> val timelineID = event.roomId + UUID.randomUUID().toString() - event.also { - // We need to check encryption - if (it.isEncrypted() && it.mxDecryptionResult == null) { - // for now decrypt sync - try { - val result = session.cryptoService().decryptEvent(it, timelineID) - it.mxDecryptionResult = OlmDecryptionResult( - payload = result.clearEvent, - senderKey = result.senderCurve25519Key, - keysClaimed = result.claimedEd25519Key?.let { k -> mapOf("ed25519" to k) }, - forwardingCurve25519KeyChain = result.forwardingCurve25519KeyChain - ) - } catch (e: MXCryptoError) { - Timber.w("Failed to decrypt event in history") - } + // We need to check encryption + if (event.isEncrypted() && event.mxDecryptionResult == null) { + // for now decrypt sync + try { + val result = session.cryptoService().decryptEvent(event, timelineID) + event.mxDecryptionResult = OlmDecryptionResult( + payload = result.clearEvent, + senderKey = result.senderCurve25519Key, + keysClaimed = result.claimedEd25519Key?.let { k -> mapOf("ed25519" to k) }, + forwardingCurve25519KeyChain = result.forwardingCurve25519KeyChain + ) + } catch (e: MXCryptoError) { + Timber.w("Failed to decrypt event in history") } + } - if (event.eventId == it.eventId) { - originalIsReply = it.isReply() - } + if (event.eventId == event.eventId) { + originalIsReply = event.isReply() } } setState { From 237545622fe1952b1aaeedd979cca649e103f43d Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Tue, 2 Mar 2021 10:55:22 +0100 Subject: [PATCH 11/17] Fix a bug I can see thanks to rework --- .../detail/timeline/edithistory/ViewEditHistoryViewModel.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/edithistory/ViewEditHistoryViewModel.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/edithistory/ViewEditHistoryViewModel.kt index 1307341446..3ce4a44812 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/edithistory/ViewEditHistoryViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/edithistory/ViewEditHistoryViewModel.kt @@ -99,7 +99,7 @@ class ViewEditHistoryViewModel @AssistedInject constructor(@Assisted } } - if (event.eventId == event.eventId) { + if (event.eventId == eventId) { originalIsReply = event.isReply() } } From f5fad8a0828e4491ce479e228b14622435d4aa55 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Tue, 2 Mar 2021 11:00:29 +0100 Subject: [PATCH 12/17] Make it compiles --- .../detail/timeline/edithistory/ViewEditHistoryViewModel.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/edithistory/ViewEditHistoryViewModel.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/edithistory/ViewEditHistoryViewModel.kt index 3ce4a44812..af814f5856 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/edithistory/ViewEditHistoryViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/edithistory/ViewEditHistoryViewModel.kt @@ -81,7 +81,7 @@ class ViewEditHistoryViewModel @AssistedInject constructor(@Assisted var originalIsReply = false - val events = data.map { event -> + data.forEach { event -> val timelineID = event.roomId + UUID.randomUUID().toString() // We need to check encryption if (event.isEncrypted() && event.mxDecryptionResult == null) { @@ -105,7 +105,7 @@ class ViewEditHistoryViewModel @AssistedInject constructor(@Assisted } setState { copy( - editList = Success(events), + editList = Success(data), isOriginalAReply = originalIsReply ) } From c33af6de6a9f1adda23cfbf33cadc177a96d0265 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Tue, 2 Mar 2021 11:11:28 +0100 Subject: [PATCH 13/17] Do not show edition from other users --- .../api/session/room/model/relation/RelationService.kt | 3 +++ .../session/room/relation/FetchEditHistoryTask.kt | 9 ++++++--- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/relation/RelationService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/relation/RelationService.kt index 4638dd204a..b83391fa06 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/relation/RelationService.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/relation/RelationService.kt @@ -92,6 +92,9 @@ interface RelationService { /** * Get the edit history of the given event + * The return list will contain the original event and all the editions of this event, done by the + * same sender, sorted in the reverse order (so the original event is the latest element, and the + * latest edition is the first element of the list) */ suspend fun fetchEditHistory(eventId: String): List diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/relation/FetchEditHistoryTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/relation/FetchEditHistoryTask.kt index 854585ca29..f1c8fd49a4 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/relation/FetchEditHistoryTask.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/relation/FetchEditHistoryTask.kt @@ -49,8 +49,11 @@ internal class DefaultFetchEditHistoryTask @Inject constructor( ) } - val events = response.chunks.toMutableList() - response.originalEvent?.let { events.add(it) } - return events + // Filter out edition form other users + val originalSenderId = response.originalEvent?.senderId + val events = response.chunks.filter { + it.senderId == originalSenderId + } + return events + listOfNotNull(response.originalEvent) } } From 95395945f21397bef9bba407a1b2a3f79eb0e3b2 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Tue, 2 Mar 2021 11:18:06 +0100 Subject: [PATCH 14/17] Also filter redacted events --- .../session/room/relation/FetchEditHistoryTask.kt | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/relation/FetchEditHistoryTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/relation/FetchEditHistoryTask.kt index f1c8fd49a4..f9fd5f9348 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/relation/FetchEditHistoryTask.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/relation/FetchEditHistoryTask.kt @@ -49,11 +49,11 @@ internal class DefaultFetchEditHistoryTask @Inject constructor( ) } - // Filter out edition form other users + // Filter out edition form other users, and redacted editions val originalSenderId = response.originalEvent?.senderId - val events = response.chunks.filter { - it.senderId == originalSenderId - } + val events = response.chunks + .filter { it.senderId == originalSenderId } + .filter { !it.isRedacted() } return events + listOfNotNull(response.originalEvent) } } From 5d69a1ab919457fe0e4e8358720de2d38807cb2f Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Tue, 2 Mar 2021 11:30:30 +0100 Subject: [PATCH 15/17] Fix a last bug when all editions has been deleted --- .../mapper/EventAnnotationsSummaryMapper.kt | 23 ++++++++++--------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/mapper/EventAnnotationsSummaryMapper.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/mapper/EventAnnotationsSummaryMapper.kt index f4d3d74150..08d98ce3b8 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/mapper/EventAnnotationsSummaryMapper.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/mapper/EventAnnotationsSummaryMapper.kt @@ -36,17 +36,18 @@ internal object EventAnnotationsSummaryMapper { it.sourceLocalEcho.toList() ) }, - editSummary = annotationsSummary.editSummary?.let { - val latestEdition = it.editions.maxByOrNull { editionOfEvent -> editionOfEvent.timestamp } - EditAggregatedSummary( - ContentMapper.map(latestEdition?.content), - it.editions.filter { editionOfEvent -> !editionOfEvent.isLocalEcho } - .map { editionOfEvent -> editionOfEvent.eventId }, - it.editions.filter { editionOfEvent -> editionOfEvent.isLocalEcho } - .map { editionOfEvent -> editionOfEvent.eventId }, - latestEdition?.timestamp ?: 0L - ) - }, + editSummary = annotationsSummary.editSummary + ?.let { + val latestEdition = it.editions.maxByOrNull { editionOfEvent -> editionOfEvent.timestamp } ?: return@let null + EditAggregatedSummary( + aggregatedContent = ContentMapper.map(latestEdition.content), + sourceEvents = it.editions.filter { editionOfEvent -> !editionOfEvent.isLocalEcho } + .map { editionOfEvent -> editionOfEvent.eventId }, + localEchos = it.editions.filter { editionOfEvent -> editionOfEvent.isLocalEcho } + .map { editionOfEvent -> editionOfEvent.eventId }, + lastEditTs = latestEdition.timestamp + ) + }, referencesAggregatedSummary = annotationsSummary.referencesSummaryEntity?.let { ReferencesAggregatedSummary( it.eventId, From a8ba125bd2ad7f78483df16107ec063dc8d18db1 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Tue, 2 Mar 2021 11:37:13 +0100 Subject: [PATCH 16/17] Rename val for code clarity, and use facility --- .../sdk/api/session/room/model/EditAggregatedSummary.kt | 2 +- .../sdk/api/session/room/timeline/TimelineEvent.kt | 3 +-- .../database/mapper/EventAnnotationsSummaryMapper.kt | 2 +- .../app/features/home/room/detail/RoomDetailViewModel.kt | 9 +++------ .../detail/timeline/action/MessageActionsViewModel.kt | 3 +-- 5 files changed, 7 insertions(+), 12 deletions(-) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/EditAggregatedSummary.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/EditAggregatedSummary.kt index 10fb81dc7f..67bab626cb 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/EditAggregatedSummary.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/EditAggregatedSummary.kt @@ -18,7 +18,7 @@ package org.matrix.android.sdk.api.session.room.model import org.matrix.android.sdk.api.session.events.model.Content data class EditAggregatedSummary( - val aggregatedContent: Content? = null, + val latestContent: Content? = null, // The list of the eventIDs used to build the summary (might be out of sync if chunked received from message chunk) val sourceEvents: List, val localEchos: List, 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 53f0e5a8d3..7010a80233 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 @@ -123,8 +123,7 @@ fun TimelineEvent.getLastMessageContent(): MessageContent? { return if (root.getClearType() == EventType.STICKER) { root.getClearContent().toModel() } else { - annotations?.editSummary?.aggregatedContent?.toModel() - ?: root.getClearContent().toModel() + (annotations?.editSummary?.latestContent ?: root.getClearContent()).toModel() } } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/mapper/EventAnnotationsSummaryMapper.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/mapper/EventAnnotationsSummaryMapper.kt index 08d98ce3b8..4a26b4c4bf 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/mapper/EventAnnotationsSummaryMapper.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/mapper/EventAnnotationsSummaryMapper.kt @@ -40,7 +40,7 @@ internal object EventAnnotationsSummaryMapper { ?.let { val latestEdition = it.editions.maxByOrNull { editionOfEvent -> editionOfEvent.timestamp } ?: return@let null EditAggregatedSummary( - aggregatedContent = ContentMapper.map(latestEdition.content), + latestContent = ContentMapper.map(latestEdition.content), sourceEvents = it.editions.filter { editionOfEvent -> !editionOfEvent.isLocalEcho } .map { editionOfEvent -> editionOfEvent.eventId }, localEchos = it.editions.filter { editionOfEvent -> editionOfEvent.isLocalEcho } diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailViewModel.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailViewModel.kt index 601891b15a..bb700bcb0d 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailViewModel.kt @@ -89,6 +89,7 @@ import org.matrix.android.sdk.api.session.room.read.ReadService import org.matrix.android.sdk.api.session.room.send.UserDraft import org.matrix.android.sdk.api.session.room.timeline.Timeline import org.matrix.android.sdk.api.session.room.timeline.TimelineEvent +import org.matrix.android.sdk.api.session.room.timeline.getLastMessageContent import org.matrix.android.sdk.api.session.room.timeline.getRelationContent import org.matrix.android.sdk.api.session.room.timeline.getTextEditableContent import org.matrix.android.sdk.api.session.widgets.model.Widget @@ -785,9 +786,7 @@ class RoomDetailViewModel @AssistedInject constructor( room.editReply(state.sendMode.timelineEvent, it, action.text.toString()) } } else { - val messageContent: MessageContent? = - state.sendMode.timelineEvent.annotations?.editSummary?.aggregatedContent.toModel() - ?: state.sendMode.timelineEvent.root.getClearContent().toModel() + val messageContent = state.sendMode.timelineEvent.getLastMessageContent() val existingBody = messageContent?.body ?: "" if (existingBody != action.text) { room.editTextMessage(state.sendMode.timelineEvent.root.eventId ?: "", @@ -802,9 +801,7 @@ class RoomDetailViewModel @AssistedInject constructor( popDraft() } is SendMode.QUOTE -> { - val messageContent: MessageContent? = - state.sendMode.timelineEvent.annotations?.editSummary?.aggregatedContent.toModel() - ?: state.sendMode.timelineEvent.root.getClearContent().toModel() + val messageContent = state.sendMode.timelineEvent.getLastMessageContent() val textMsg = messageContent?.body val finalText = legacyRiotQuoteText(textMsg, action.text.toString()) 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 1697d9250e..363899c4f9 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 @@ -229,8 +229,7 @@ class MessageActionsViewModel @AssistedInject constructor(@Assisted } private fun actionsForEvent(timelineEvent: TimelineEvent, actionPermissions: ActionPermissions): List { - val messageContent: MessageContent? = timelineEvent.annotations?.editSummary?.aggregatedContent.toModel() - ?: timelineEvent.root.getClearContent().toModel() + val messageContent = timelineEvent.getLastMessageContent() val msgType = messageContent?.msgType return arrayListOf().apply { From b027e43615d4bbbd46333e844256156e98532a14 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Tue, 2 Mar 2021 11:41:20 +0100 Subject: [PATCH 17/17] Cleanup --- .../sdk/api/session/room/model/relation/RelationService.kt | 1 - .../sdk/internal/crypto/verification/VerificationStateExt.kt | 1 - .../android/sdk/internal/database/RealmSessionStoreMigration.kt | 1 - .../internal/session/room/EventRelationsAggregationProcessor.kt | 2 +- .../vector/app/features/home/room/detail/RoomDetailViewModel.kt | 1 - 5 files changed, 1 insertion(+), 5 deletions(-) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/relation/RelationService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/relation/RelationService.kt index b83391fa06..2c0e378efb 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/relation/RelationService.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/relation/RelationService.kt @@ -16,7 +16,6 @@ package org.matrix.android.sdk.api.session.room.model.relation import androidx.lifecycle.LiveData -import org.matrix.android.sdk.api.MatrixCallback import org.matrix.android.sdk.api.session.events.model.Event import org.matrix.android.sdk.api.session.room.model.EventAnnotationsSummary import org.matrix.android.sdk.api.session.room.timeline.TimelineEvent diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/verification/VerificationStateExt.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/verification/VerificationStateExt.kt index b5fba0d54c..0617f32c24 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/verification/VerificationStateExt.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/verification/VerificationStateExt.kt @@ -33,4 +33,3 @@ internal fun VerificationState?.toState(newState: VerificationState): Verificati } return newState } - diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/RealmSessionStoreMigration.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/RealmSessionStoreMigration.kt index 820588b1ab..c7fe7ab447 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/RealmSessionStoreMigration.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/RealmSessionStoreMigration.kt @@ -142,7 +142,6 @@ class RealmSessionStoreMigration @Inject constructor() : RealmMigration { .addField(EditionOfEventFields.TIMESTAMP, Long::class.java) .addField(EditionOfEventFields.IS_LOCAL_ECHO, Boolean::class.java) - realm.schema.get("EditAggregatedSummaryEntity") ?.removeField("aggregatedContent") ?.removeField("sourceEvents") diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/EventRelationsAggregationProcessor.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/EventRelationsAggregationProcessor.kt index 8269643d39..60440c6359 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/EventRelationsAggregationProcessor.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/EventRelationsAggregationProcessor.kt @@ -448,7 +448,7 @@ internal class EventRelationsAggregationProcessor @Inject constructor(@UserId pr Timber.w("Redaction of a replace targeting an unknown event $relatedEventId") return } - val sourceToDiscard = eventSummary.editSummary?.editions?.firstOrNull {it.eventId == redacted.eventId } + val sourceToDiscard = eventSummary.editSummary?.editions?.firstOrNull { it.eventId == redacted.eventId } if (sourceToDiscard == null) { Timber.w("Redaction of a replace that was not known in aggregation $sourceToDiscard") return diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailViewModel.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailViewModel.kt index bb700bcb0d..4247ffdd54 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailViewModel.kt @@ -79,7 +79,6 @@ import org.matrix.android.sdk.api.session.room.model.Membership import org.matrix.android.sdk.api.session.room.model.PowerLevelsContent import org.matrix.android.sdk.api.session.room.model.RoomMemberSummary import org.matrix.android.sdk.api.session.room.model.RoomSummary -import org.matrix.android.sdk.api.session.room.model.message.MessageContent import org.matrix.android.sdk.api.session.room.model.message.MessageType import org.matrix.android.sdk.api.session.room.model.message.OptionItem import org.matrix.android.sdk.api.session.room.model.message.getFileUrl