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 5fd7e07b89..1ae381e014 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 @@ -16,12 +16,14 @@ package im.vector.matrix.android.internal.database.helper -import im.vector.matrix.android.api.session.events.model.Event import im.vector.matrix.android.api.session.events.model.toModel import im.vector.matrix.android.api.session.room.model.RoomMemberContent +import im.vector.matrix.android.internal.database.mapper.ContentMapper import im.vector.matrix.android.internal.database.model.ChunkEntity +import im.vector.matrix.android.internal.database.model.CurrentStateEventEntityFields import im.vector.matrix.android.internal.database.model.EventAnnotationsSummaryEntity import im.vector.matrix.android.internal.database.model.EventEntity +import im.vector.matrix.android.internal.database.model.EventEntityFields import im.vector.matrix.android.internal.database.model.ReadReceiptEntity import im.vector.matrix.android.internal.database.model.ReadReceiptsSummaryEntity import im.vector.matrix.android.internal.database.model.TimelineEventEntity @@ -33,6 +35,7 @@ import im.vector.matrix.android.internal.extensions.assertIsManaged import im.vector.matrix.android.internal.session.room.timeline.PaginationDirection import io.realm.Sort import io.realm.kotlin.createObject +import timber.log.Timber internal fun ChunkEntity.deleteOnCascade() { assertIsManaged() @@ -40,7 +43,7 @@ internal fun ChunkEntity.deleteOnCascade() { this.deleteFromRealm() } -internal fun ChunkEntity.merge(chunkToMerge: ChunkEntity, direction: PaginationDirection) { +internal fun ChunkEntity.merge(roomId: String, chunkToMerge: ChunkEntity, direction: PaginationDirection) { assertIsManaged() val eventsToMerge: List if (direction == PaginationDirection.FORWARDS) { @@ -52,6 +55,9 @@ internal fun ChunkEntity.merge(chunkToMerge: ChunkEntity, direction: PaginationD this.isLastBackward = chunkToMerge.isLastBackward eventsToMerge = chunkToMerge.timelineEvents.sort(TimelineEventEntityFields.DISPLAY_INDEX, Sort.DESCENDING) } + chunkToMerge.stateEvents.forEach { stateEvent -> + addStateEvent(roomId, stateEvent, direction) + } return eventsToMerge .forEach { if (timelineEvents.find(it.eventId) == null) { @@ -61,10 +67,29 @@ internal fun ChunkEntity.merge(chunkToMerge: ChunkEntity, direction: PaginationD } } +internal fun ChunkEntity.addStateEvent(roomId: String, stateEvent: EventEntity, direction: PaginationDirection) { + if (direction == PaginationDirection.FORWARDS) { + Timber.v("We don't keep chunk state events when paginating forward") + } else { + val stateKey = stateEvent.stateKey ?: return + val type = stateEvent.type + val pastStateEvent = stateEvents.where() + .equalTo(EventEntityFields.ROOM_ID, roomId) + .equalTo(EventEntityFields.STATE_KEY, stateKey) + .equalTo(CurrentStateEventEntityFields.TYPE, type) + .findFirst() + + if (pastStateEvent != null) { + stateEvents.remove(pastStateEvent) + } + stateEvents.add(stateEvent) + } +} + internal fun ChunkEntity.addTimelineEvent(roomId: String, eventEntity: EventEntity, direction: PaginationDirection, - roomMemberEvent: Event?) { + roomMemberEvent: EventEntity?) { val eventId = eventEntity.eventId if (timelineEvents.find(eventId) != null) { @@ -104,10 +129,9 @@ internal fun ChunkEntity.addTimelineEvent(roomId: String, this.readReceipts = readReceiptsSummaryEntity this.displayIndex = displayIndex if (roomMemberEvent != null) { - val roomMemberContent = roomMemberEvent.content.toModel() + val roomMemberContent = ContentMapper.map(roomMemberEvent.content).toModel() this.senderAvatar = roomMemberContent?.avatarUrl this.senderName = roomMemberContent?.displayName - this.isUniqueDisplayName = false this.senderMembershipEventId = roomMemberEvent.eventId } } diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/model/ChunkEntity.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/model/ChunkEntity.kt index eb4086e1d6..2d294e6783 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/model/ChunkEntity.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/model/ChunkEntity.kt @@ -24,6 +24,7 @@ import io.realm.annotations.LinkingObjects internal open class ChunkEntity(@Index var prevToken: String? = null, @Index var nextToken: String? = null, + var stateEvents: RealmList = RealmList(), var timelineEvents: RealmList = RealmList(), @Index var isLastForward: Boolean = false, @Index var isLastBackward: Boolean = false 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 167d047ef3..4362f5d84d 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 @@ -21,6 +21,7 @@ import im.vector.matrix.android.api.session.events.model.Event import im.vector.matrix.android.api.session.events.model.EventType import im.vector.matrix.android.api.session.room.send.SendState import im.vector.matrix.android.internal.database.helper.addOrUpdate +import im.vector.matrix.android.internal.database.helper.addStateEvent import im.vector.matrix.android.internal.database.helper.addTimelineEvent import im.vector.matrix.android.internal.database.helper.deleteOnCascade import im.vector.matrix.android.internal.database.helper.merge @@ -192,7 +193,7 @@ internal class TokenChunkEventPersistor @Inject constructor(private val monarchy currentChunk: ChunkEntity ) { Timber.v("Add ${receivedChunk.events.size} events in chunk(${currentChunk.nextToken} | ${currentChunk.prevToken}") - val roomMemberEventsByUser = HashMap() + val roomMemberEventsByUser = HashMap() val eventList = if (direction == PaginationDirection.FORWARDS) { receivedChunk.events } else { @@ -200,8 +201,12 @@ internal class TokenChunkEventPersistor @Inject constructor(private val monarchy } val stateEvents = receivedChunk.stateEvents for (stateEvent in stateEvents) { + val stateEventEntity = stateEvent.toEntity(roomId, SendState.SYNCED).let { + realm.copyToRealmOrUpdate(it) + } + currentChunk.addStateEvent(roomId, stateEventEntity, direction) if (stateEvent.type == EventType.STATE_ROOM_MEMBER && stateEvent.stateKey != null && !stateEvent.isRedacted()) { - roomMemberEventsByUser[stateEvent.stateKey] = stateEvent + roomMemberEventsByUser[stateEvent.stateKey] = stateEventEntity } } val eventIds = ArrayList(eventList.size) @@ -220,13 +225,13 @@ internal class TokenChunkEventPersistor @Inject constructor(private val monarchy eventEntities.add(0, eventEntity) } if (event.type == EventType.STATE_ROOM_MEMBER && event.stateKey != null && !event.isRedacted()) { - roomMemberEventsByUser[event.stateKey] = event + roomMemberEventsByUser[event.stateKey] = eventEntity } } for (eventEntity in eventEntities) { val senderId = eventEntity.sender ?: continue val roomMemberEvent = roomMemberEventsByUser.getOrPut(senderId) { - CurrentStateEventEntity.getOrNull(realm, roomId, senderId, EventType.STATE_ROOM_MEMBER)?.root?.asDomain() + CurrentStateEventEntity.getOrNull(realm, roomId, senderId, EventType.STATE_ROOM_MEMBER)?.root } currentChunk.addTimelineEvent(roomId, eventEntity, direction, roomMemberEvent) } @@ -235,7 +240,7 @@ internal class TokenChunkEventPersistor @Inject constructor(private val monarchy val chunksToDelete = ArrayList() chunks.forEach { if (it != currentChunk) { - currentChunk.merge(it, direction) + currentChunk.merge(roomId, it, direction) chunksToDelete.add(it) } } diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/RoomSyncHandler.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/RoomSyncHandler.kt index c6f8525a42..670529074e 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/RoomSyncHandler.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/RoomSyncHandler.kt @@ -29,6 +29,7 @@ import im.vector.matrix.android.internal.database.mapper.asDomain import im.vector.matrix.android.internal.database.mapper.toEntity import im.vector.matrix.android.internal.database.model.ChunkEntity import im.vector.matrix.android.internal.database.model.CurrentStateEventEntity +import im.vector.matrix.android.internal.database.model.EventEntity import im.vector.matrix.android.internal.database.model.RoomEntity import im.vector.matrix.android.internal.database.query.find import im.vector.matrix.android.internal.database.query.findLastLiveChunkFromRoom @@ -210,7 +211,7 @@ internal class RoomSyncHandler @Inject constructor(private val readReceiptHandle chunkEntity.isLastForward = true val eventIds = ArrayList(eventList.size) - val roomMemberEventsByUser = HashMap() + val roomMemberEventsByUser = HashMap() for (event in eventList) { if (event.eventId == null || event.senderId == null) { @@ -226,12 +227,12 @@ internal class RoomSyncHandler @Inject constructor(private val readReceiptHandle root = eventEntity } if (event.type == EventType.STATE_ROOM_MEMBER) { - roomMemberEventsByUser[event.stateKey] = event + roomMemberEventsByUser[event.stateKey] = eventEntity roomMemberEventHandler.handle(realm, roomEntity.roomId, event) } } val roomMemberEvent = roomMemberEventsByUser.getOrPut(event.senderId) { - CurrentStateEventEntity.getOrNull(realm, roomId, event.senderId, EventType.STATE_ROOM_MEMBER)?.root?.asDomain() + CurrentStateEventEntity.getOrNull(realm, roomId, event.senderId, EventType.STATE_ROOM_MEMBER)?.root } chunkEntity.addTimelineEvent(roomId, eventEntity, PaginationDirection.FORWARDS, roomMemberEvent) // Give info to crypto module