diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/helper/ChunkEntityHelper.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/helper/ChunkEntityHelper.kt index d55e1f01d8..3fe0796b89 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/helper/ChunkEntityHelper.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/helper/ChunkEntityHelper.kt @@ -51,36 +51,6 @@ internal fun ChunkEntity.deleteOnCascade() { this.deleteFromRealm() } -internal fun ChunkEntity.merge(roomId: String, - chunkToMerge: ChunkEntity, - direction: PaginationDirection) { - assertIsManaged() - val isChunkToMergeUnlinked = chunkToMerge.isUnlinked() - val isCurrentChunkUnlinked = this.isUnlinked() - val isUnlinked = isCurrentChunkUnlinked && isChunkToMergeUnlinked - - if (isCurrentChunkUnlinked && !isChunkToMergeUnlinked) { - this.timelineEvents.forEach { it.root?.isUnlinked = false } - } - val eventsToMerge: List - if (direction == PaginationDirection.FORWARDS) { - this.nextToken = chunkToMerge.nextToken - this.isLastForward = chunkToMerge.isLastForward - eventsToMerge = chunkToMerge.timelineEvents.sort(TimelineEventEntityFields.ROOT.DISPLAY_INDEX, Sort.ASCENDING) - } else { - this.prevToken = chunkToMerge.prevToken - this.isLastBackward = chunkToMerge.isLastBackward - eventsToMerge = chunkToMerge.timelineEvents.sort(TimelineEventEntityFields.ROOT.DISPLAY_INDEX, Sort.DESCENDING) - } - val events = eventsToMerge.mapNotNull { it.root?.asDomain() } - val eventIds = ArrayList() - events.forEach { event -> - add(realm, roomId, event, direction, isUnlinked = isUnlinked) - if (event.eventId != null) { - eventIds.add(event.eventId) - } - } -} internal fun ChunkEntity.add(localRealm: Realm, roomId: String, @@ -115,7 +85,7 @@ internal fun ChunkEntity.add(localRealm: Realm, val senderId = event.senderId ?: "" val readReceiptsSummaryEntity = ReadReceiptsSummaryEntity.where(localRealm, eventId).findFirst() - ?: ReadReceiptsSummaryEntity(eventId, roomId) + ?: ReadReceiptsSummaryEntity(eventId, roomId) // Update RR for the sender of a new message with a dummy one @@ -152,14 +122,14 @@ internal fun ChunkEntity.add(localRealm: Realm, internal fun ChunkEntity.lastDisplayIndex(direction: PaginationDirection, defaultValue: Int = 0): Int { return when (direction) { - PaginationDirection.FORWARDS -> forwardsDisplayIndex - PaginationDirection.BACKWARDS -> backwardsDisplayIndex - } ?: defaultValue + PaginationDirection.FORWARDS -> forwardsDisplayIndex + PaginationDirection.BACKWARDS -> backwardsDisplayIndex + } ?: defaultValue } internal fun ChunkEntity.lastStateIndex(direction: PaginationDirection, defaultValue: Int = 0): Int { return when (direction) { - PaginationDirection.FORWARDS -> forwardsStateIndex - PaginationDirection.BACKWARDS -> backwardsStateIndex - } ?: defaultValue + PaginationDirection.FORWARDS -> forwardsStateIndex + PaginationDirection.BACKWARDS -> backwardsStateIndex + } ?: defaultValue } diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/helper/RoomEntityHelper.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/helper/RoomEntityHelper.kt index c07803bf4a..ee8d168c5e 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/helper/RoomEntityHelper.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/helper/RoomEntityHelper.kt @@ -26,11 +26,6 @@ import im.vector.matrix.android.internal.database.query.fastContains import im.vector.matrix.android.internal.extensions.assertIsManaged import im.vector.matrix.android.internal.session.room.membership.RoomMembers -internal fun RoomEntity.deleteOnCascade(chunkEntity: ChunkEntity) { - chunks.remove(chunkEntity) - chunkEntity.deleteOnCascade() -} - internal fun RoomEntity.addOrUpdate(chunkEntity: ChunkEntity) { if (!chunks.contains(chunkEntity)) { chunks.add(chunkEntity) diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/query/ChunkEntityQueries.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/query/ChunkEntityQueries.kt index 543f40b226..09800c5111 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/query/ChunkEntityQueries.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/query/ChunkEntityQueries.kt @@ -57,7 +57,7 @@ internal fun ChunkEntity.Companion.findIncludingEvent(realm: Realm, eventId: Str return findAllIncludingEvents(realm, listOf(eventId)).firstOrNull() } -internal fun ChunkEntity.Companion.create(realm: Realm, roomId: String, prevToken: String?, nextToken: String?): ChunkEntity { +internal fun ChunkEntity.Companion.create(realm: Realm, roomId: String, prevToken: String? = null, nextToken: String? = null): ChunkEntity { return realm.createObject().apply { this.roomId = roomId this.prevToken = prevToken diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/timeline/DefaultTimeline.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/timeline/DefaultTimeline.kt index 4127e43540..e8ad8d07e6 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/timeline/DefaultTimeline.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/timeline/DefaultTimeline.kt @@ -470,13 +470,13 @@ internal class DefaultTimeline( Pair(filteredEvents[range.startIndex]!!.root!!.displayIndex, Timeline.Direction.BACKWARDS) } val state = getState(direction) - if (state.isPaginating) { + postSnapshot = if (state.isPaginating) { // We are getting new items from pagination - postSnapshot = paginateInternal(startDisplayIndex, direction, state.requestedPaginationCount) + paginateInternal(startDisplayIndex, direction, state.requestedPaginationCount) } else { // We are getting new items from sync buildTimelineEvents(startDisplayIndex, direction, range.length.toLong()) - postSnapshot = true + true } } changeSet.changes.forEach { index -> diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/timeline/TokenChunkEventPersistor.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/timeline/TokenChunkEventPersistor.kt index 956b75c9cf..8770e53079 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/timeline/TokenChunkEventPersistor.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/timeline/TokenChunkEventPersistor.kt @@ -23,7 +23,9 @@ import im.vector.matrix.android.internal.database.model.RoomEntity import im.vector.matrix.android.internal.database.query.create import im.vector.matrix.android.internal.database.query.find import im.vector.matrix.android.internal.database.query.findAllIncludingEvents +import im.vector.matrix.android.internal.database.query.findLastLiveChunkFromRoom import im.vector.matrix.android.internal.database.query.where +import im.vector.matrix.android.internal.session.room.RoomSummaryUpdater import im.vector.matrix.android.internal.session.user.UserEntityFactory import im.vector.matrix.android.internal.util.awaitTransaction import io.realm.kotlin.createObject @@ -33,7 +35,8 @@ import javax.inject.Inject /** * Insert Chunk in DB, and eventually merge with existing chunk event */ -internal class TokenChunkEventPersistor @Inject constructor(private val monarchy: Monarchy) { +internal class TokenChunkEventPersistor @Inject constructor(private val monarchy: Monarchy, + private val roomSummaryUpdater: RoomSummaryUpdater) { /** *
@@ -112,7 +115,7 @@ internal class TokenChunkEventPersistor @Inject constructor(private val monarchy
                     Timber.v("Start persisting ${receivedChunk.events.size} events in $roomId towards $direction")
 
                     val roomEntity = RoomEntity.where(realm, roomId).findFirst()
-                            ?: realm.createObject(roomId)
+                                     ?: realm.createObject(roomId)
 
                     val nextToken: String?
                     val prevToken: String?
@@ -127,7 +130,6 @@ internal class TokenChunkEventPersistor @Inject constructor(private val monarchy
                     val prevChunk = ChunkEntity.find(realm, roomId, nextToken = prevToken)
                     val nextChunk = ChunkEntity.find(realm, roomId, prevToken = nextToken)
 
-                    // The current chunk is the one we will keep all along the merge processChanges.
                     // We try to look for a chunk next to the token,
                     // otherwise we create a whole new one
 
@@ -136,22 +138,34 @@ internal class TokenChunkEventPersistor @Inject constructor(private val monarchy
                     } else {
                         nextChunk?.apply { this.prevToken = prevToken }
                     }
-                            ?: ChunkEntity().apply {
-                                this.roomId = roomId
-                                this.prevToken = prevToken
-                                this.nextToken = nextToken
-                            }
+                                       ?: realm.createObject().apply {
+                                           this.roomId = roomId
+                                           this.prevToken = prevToken
+                                           this.nextToken = nextToken
+                                       }
 
                     if (receivedChunk.events.isEmpty() && receivedChunk.end == receivedChunk.start) {
-                        Timber.v("Reach end of $roomId")
-                        currentChunk.isLastBackward = true
+                        if (direction == PaginationDirection.FORWARDS) {
+                            Timber.v("Reach live state of $roomId")
+                            // We make sure we only have one live chunk
+                            ChunkEntity.findLastLiveChunkFromRoom(realm, roomId)?.deleteOnCascade()
+                            currentChunk.isLastForward = true
+                            currentChunk.nextToken = null
+                            currentChunk.timelineEvents.forEach {
+                                it.root?.isUnlinked = false
+                            }
+                            roomSummaryUpdater.update(realm, roomId, updateMembers = false)
+                        } else {
+                            Timber.v("Reach end of $roomId")
+                            currentChunk.isLastBackward = true
+                        }
                     } else {
                         Timber.v("Add ${receivedChunk.events.size} events in chunk(${currentChunk.nextToken} | ${currentChunk.prevToken}")
                         for (event in receivedChunk.events) {
                             currentChunk.add(realm, roomId, event, direction, isUnlinked = !currentChunk.isLastForward)
                         }
-                        roomEntity.addOrUpdate(currentChunk)
                     }
+                    roomEntity.addOrUpdate(currentChunk)
                 }
         return if (receivedChunk.events.isEmpty()) {
             if (receivedChunk.start != receivedChunk.end) {
diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/ChunkEntityFactory.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/ChunkEntityFactory.kt
index 1b6822e76b..b1294835f7 100644
--- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/ChunkEntityFactory.kt
+++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/ChunkEntityFactory.kt
@@ -20,9 +20,11 @@ package im.vector.matrix.android.internal.session.sync
 import im.vector.matrix.android.api.session.events.model.Event
 import im.vector.matrix.android.internal.crypto.DefaultCryptoService
 import im.vector.matrix.android.internal.database.helper.add
+import im.vector.matrix.android.internal.database.helper.deleteOnCascade
 import im.vector.matrix.android.internal.database.helper.lastStateIndex
 import im.vector.matrix.android.internal.database.model.ChunkEntity
 import im.vector.matrix.android.internal.database.model.RoomEntity
+import im.vector.matrix.android.internal.database.query.create
 import im.vector.matrix.android.internal.database.query.find
 import im.vector.matrix.android.internal.database.query.findLastLiveChunkFromRoom
 import im.vector.matrix.android.internal.database.query.where
@@ -52,10 +54,8 @@ internal class ChunkEntityFactory @Inject constructor(private val cryptoService:
                                     roomId: String,
                                     eventList: List,
                                     prevToken: String?): ChunkEntity {
-        val chunkEntity = realm.createObject().apply {
-            this.roomId = roomId
-            this.prevToken = prevToken
-            this.isLastForward = true
+        val chunkEntity = ChunkEntity.create(realm, roomId, prevToken = prevToken).apply {
+            isLastForward = true
         }
         for (event in eventList) {
             chunkEntity.add(realm, roomId, event, PaginationDirection.FORWARDS)
@@ -76,14 +76,15 @@ internal class ChunkEntityFactory @Inject constructor(private val cryptoService:
         val lastChunk = ChunkEntity.findLastLiveChunkFromRoom(realm, roomId)
         val stateIndexOffset = lastChunk?.lastStateIndex(PaginationDirection.FORWARDS) ?: 0
         val chunkEntity = if (isLimited || lastChunk == null) {
-            realm.createObject().apply {
-                this.roomId = roomId
-                this.prevToken = prevToken
-                this.isLastForward = true
+            ChunkEntity.create(realm, roomId, prevToken = prevToken).apply {
+                isLastForward = true
             }
         } else {
             lastChunk
         }
+        if (lastChunk != chunkEntity) {
+            lastChunk?.deleteOnCascade()
+        }
         for (event in eventList) {
             chunkEntity.add(realm, roomId, event, PaginationDirection.FORWARDS, stateIndexOffset)
             // Give info to crypto module