diff --git a/CHANGES.md b/CHANGES.md
index 43563f71aa..ea78fcaf7d 100644
--- a/CHANGES.md
+++ b/CHANGES.md
@@ -30,7 +30,7 @@ Test:
-
Other changes:
- -
+ - Rework edition of event management
Changes in Element 1.1.0 (2021-02-19)
===================================================
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
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..54276a6b51
--- /dev/null
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/crypto/VerificationState.kt
@@ -0,0 +1,29 @@
+/*
+ * 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
+}
+
+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/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/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/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..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
@@ -92,8 +91,11 @@ 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)
*/
- 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/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/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..0617f32c24
--- /dev/null
+++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/verification/VerificationStateExt.kt
@@ -0,0 +1,35 @@
+/*
+ * 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/database/RealmSessionStoreMigration.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/RealmSessionStoreMigration.kt
index 57002b5a60..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
@@ -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,28 @@ 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 b4935cfdcc..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
@@ -97,7 +97,8 @@ 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()
+ ?.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..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
@@ -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 {
@@ -40,14 +36,18 @@ internal object EventAnnotationsSummaryMapper {
it.sourceLocalEcho.toList()
)
},
- editSummary = annotationsSummary.editSummary?.let {
- EditAggregatedSummary(
- ContentMapper.map(it.aggregatedContent),
- it.sourceEvents.toList(),
- it.sourceLocalEchoEvents.toList(),
- it.lastEditTs
- )
- },
+ editSummary = annotationsSummary.editSummary
+ ?.let {
+ val latestEdition = it.editions.maxByOrNull { editionOfEvent -> editionOfEvent.timestamp } ?: return@let null
+ EditAggregatedSummary(
+ latestContent = 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,
@@ -62,46 +62,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/database/query/EventAnnotationsSummaryEntityQuery.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/query/EventAnnotationsSummaryEntityQuery.kt
index 9a298b7e79..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()
- ?: EventAnnotationsSummaryEntity.create(realm, roomId, eventId).apply { this.roomId = roomId }
+ 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 d090ba5296..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
@@ -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
@@ -31,9 +32,11 @@ 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
+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
@@ -50,33 +53,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
-}
-
-// 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 {
@@ -118,13 +94,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()
@@ -216,63 +190,78 @@ 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.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
+ )
+ )
}
}
}
@@ -290,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)
@@ -370,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)
@@ -454,46 +443,29 @@ 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
}
- 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()
}
- 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..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? {
@@ -159,7 +154,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 +163,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/FetchEditHistoryTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/relation/FetchEditHistoryTask.kt
index 854585ca29..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,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, and redacted editions
+ val originalSenderId = response.originalEvent?.senderId
+ val events = response.chunks
+ .filter { it.senderId == originalSenderId }
+ .filter { !it.isRedacted() }
+ return events + listOfNotNull(response.originalEvent)
}
}
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
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 935b4ca2f8..f293eadf50 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
@@ -85,7 +85,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
@@ -95,6 +94,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
@@ -825,9 +825,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 ?: "",
@@ -842,9 +840,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 {
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..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
@@ -15,42 +15,28 @@
*/
package im.vector.app.features.home.room.detail.timeline.edithistory
-import com.airbnb.mvrx.Async
+import androidx.lifecycle.viewModelScope
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 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
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,
@@ -82,48 +68,48 @@ 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()
- }
+ data.forEach { event ->
+ val timelineID = event.roomId + UUID.randomUUID().toString()
+ // 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")
}
}
- setState {
- copy(
- editList = Success(events),
- isOriginalAReply = originalIsReply
- )
+
+ if (event.eventId == eventId) {
+ originalIsReply = event.isReply()
}
}
- })
+ setState {
+ copy(
+ editList = Success(data),
+ isOriginalAReply = originalIsReply
+ )
+ }
+ }
}
override fun handle(action: EmptyAction) {
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)
+}
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() {
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) {