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 b74fcdcf..d5979723 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 @@ -18,17 +18,28 @@ 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.EventType +import im.vector.matrix.android.api.session.events.model.toModel +import im.vector.matrix.android.api.session.room.model.RoomMember import im.vector.matrix.android.api.session.room.send.SendState +import im.vector.matrix.android.internal.database.mapper.ContentMapper 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.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.RoomEntity import im.vector.matrix.android.internal.database.model.TimelineEventEntity import im.vector.matrix.android.internal.database.model.TimelineEventEntityFields import im.vector.matrix.android.internal.database.query.find +import im.vector.matrix.android.internal.database.query.next +import im.vector.matrix.android.internal.database.query.prev import im.vector.matrix.android.internal.database.query.where import im.vector.matrix.android.internal.extensions.assertIsManaged +import im.vector.matrix.android.internal.session.room.membership.RoomMembers import im.vector.matrix.android.internal.session.room.timeline.PaginationDirection +import io.realm.RealmList +import io.realm.RealmQuery import io.realm.Sort // By default if a chunk is empty we consider it unlinked @@ -64,11 +75,11 @@ internal fun ChunkEntity.merge(roomId: String, this.isLastBackward = chunkToMerge.isLastBackward eventsToMerge = chunkToMerge.timelineEvents.sort(TimelineEventEntityFields.ROOT.DISPLAY_INDEX, Sort.DESCENDING) } - eventsToMerge.forEach { - it.root?.let { root -> - add(roomId, root.asDomain(), direction, isUnlinked = isUnlinked) - } + val events = eventsToMerge.mapNotNull { it.root?.asDomain() } + events.forEach { event -> + add(roomId, event, direction, isUnlinked = isUnlinked) } + updateSenderDataFor(roomId, isUnlinked, events) } internal fun ChunkEntity.addAll(roomId: String, @@ -81,13 +92,35 @@ internal fun ChunkEntity.addAll(roomId: String, events.forEach { event -> add(roomId, event, direction, stateIndexOffset, isUnlinked) } + updateSenderDataFor(roomId, isUnlinked, events) } -internal fun ChunkEntity.add(roomId: String, - event: Event, - direction: PaginationDirection, - stateIndexOffset: Int = 0, - isUnlinked: Boolean = false) { +private fun ChunkEntity.updateSenderDataFor(roomId: String, isUnlinked: Boolean, events: List) { + for (event in events) { + val eventId = event.eventId ?: continue + val timelineEventEntity = timelineEvents.find(eventId) ?: continue + val roomEntity = RoomEntity.where(realm, roomId = roomId).findFirst() ?: continue + val stateIndex = timelineEventEntity.root?.stateIndex ?: continue + val senderId = timelineEventEntity.root?.sender ?: continue + + val senderRoomMemberContent = when { + stateIndex <= 0 -> timelineEvents.build(senderId, isUnlinked).next(from = stateIndex)?.root?.prevContent + else -> timelineEvents.build(senderId, isUnlinked).prev(since = stateIndex)?.root?.content + } + val fallbackContent = senderRoomMemberContent + ?: roomEntity.untimelinedStateEvents.build(senderId).prev(since = stateIndex)?.content + val senderRoomMember: RoomMember? = ContentMapper.map(fallbackContent).toModel() + timelineEventEntity.senderAvatar = senderRoomMember?.avatarUrl + timelineEventEntity.senderName = senderRoomMember?.displayName + timelineEventEntity.isUniqueDisplayName = RoomMembers(realm, roomId).isUniqueDisplayName(senderRoomMember?.displayName) + } +} + +private fun ChunkEntity.add(roomId: String, + event: Event, + direction: PaginationDirection, + stateIndexOffset: Int = 0, + isUnlinked: Boolean = false) { assertIsManaged() if (event.eventId != null && timelineEvents.find(event.eventId) != null) { @@ -128,6 +161,19 @@ internal fun ChunkEntity.add(roomId: String, timelineEvents.add(position, eventEntity) } +private fun RealmList.build(sender: String, isUnlinked: Boolean): RealmQuery { + return where() + .equalTo(TimelineEventEntityFields.ROOT.STATE_KEY, sender) + .equalTo(TimelineEventEntityFields.ROOT.TYPE, EventType.STATE_ROOM_MEMBER) + .equalTo(TimelineEventEntityFields.ROOT.IS_UNLINKED, isUnlinked) +} + +private fun RealmList.build(sender: String): RealmQuery { + return where() + .equalTo(EventEntityFields.STATE_KEY, sender) + .equalTo(EventEntityFields.TYPE, EventType.STATE_ROOM_MEMBER) +} + internal fun ChunkEntity.lastDisplayIndex(direction: PaginationDirection, defaultValue: Int = 0): Int { return when (direction) { PaginationDirection.FORWARDS -> forwardsDisplayIndex 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 885b25c7..f694953e 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 @@ -24,6 +24,7 @@ import im.vector.matrix.android.internal.database.model.RoomEntity import im.vector.matrix.android.internal.database.model.TimelineEventEntity 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) { @@ -58,13 +59,19 @@ internal fun RoomEntity.addStateEvents(stateEvents: List, internal fun RoomEntity.addSendingEvent(event: Event) { assertIsManaged() + val senderId = event.senderId ?: return val eventEntity = event.toEntity(roomId).apply { this.sendState = SendState.UNSENT } + val roomMembers = RoomMembers(realm, roomId) + val myUser = roomMembers.get(senderId) val timelineEventEntity = TimelineEventEntity().also { it.root = eventEntity it.eventId = event.eventId ?: "" it.roomId = roomId + it.senderName = myUser?.displayName + it.senderAvatar = myUser?.avatarUrl + it.isUniqueDisplayName = roomMembers.isUniqueDisplayName(myUser?.displayName) } sendingTimelineEvents.add(0, timelineEventEntity) } diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/query/EventEntityQueries.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/query/EventEntityQueries.kt index cf0f845b..4327b6ee 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/query/EventEntityQueries.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/query/EventEntityQueries.kt @@ -16,13 +16,9 @@ package im.vector.matrix.android.internal.database.query -import im.vector.matrix.android.internal.database.model.ChunkEntity import im.vector.matrix.android.internal.database.model.EventEntity import im.vector.matrix.android.internal.database.model.EventEntity.LinkFilterMode.* import im.vector.matrix.android.internal.database.model.EventEntityFields -import im.vector.matrix.android.internal.database.model.RoomEntity -import im.vector.matrix.android.internal.database.model.TimelineEventEntity -import im.vector.matrix.android.internal.database.model.TimelineEventEntityFields import io.realm.Realm import io.realm.RealmList import io.realm.RealmQuery diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/query/TimelineEventEntityQueries.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/query/TimelineEventEntityQueries.kt index 5367603c..620f47be 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/query/TimelineEventEntityQueries.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/query/TimelineEventEntityQueries.kt @@ -19,7 +19,6 @@ package im.vector.matrix.android.internal.database.query import im.vector.matrix.android.internal.database.model.ChunkEntity import im.vector.matrix.android.internal.database.model.EventEntity import im.vector.matrix.android.internal.database.model.EventEntity.LinkFilterMode.* -import im.vector.matrix.android.internal.database.model.EventEntityFields import im.vector.matrix.android.internal.database.model.RoomEntity import im.vector.matrix.android.internal.database.model.TimelineEventEntity import im.vector.matrix.android.internal.database.model.TimelineEventEntityFields @@ -38,9 +37,9 @@ internal fun TimelineEventEntity.Companion.where(realm: Realm, eventIds: List { + roomId: String? = null, + type: String? = null, + linkFilterMode: EventEntity.LinkFilterMode = LINKED_ONLY): RealmQuery { val query = realm.where() if (roomId != null) { query.equalTo(TimelineEventEntityFields.ROOM_ID, roomId) @@ -78,6 +77,33 @@ internal fun TimelineEventEntity.Companion.latestEvent(realm: Realm, ?.findFirst() } +internal fun RealmQuery.next(from: Int? = null, strict: Boolean = true): TimelineEventEntity? { + if (from != null) { + if (strict) { + this.greaterThan(TimelineEventEntityFields.ROOT.STATE_INDEX, from) + } else { + this.greaterThanOrEqualTo(TimelineEventEntityFields.ROOT.STATE_INDEX, from) + } + } + return this + .sort(TimelineEventEntityFields.ROOT.STATE_INDEX, Sort.ASCENDING) + .findFirst() +} + +internal fun RealmQuery.prev(since: Int? = null, strict: Boolean = false): TimelineEventEntity? { + if (since != null) { + if (strict) { + this.lessThan(TimelineEventEntityFields.ROOT.STATE_INDEX, since) + } else { + this.lessThanOrEqualTo(TimelineEventEntityFields.ROOT.STATE_INDEX, since) + } + } + return this + .sort(TimelineEventEntityFields.ROOT.STATE_INDEX, Sort.DESCENDING) + .findFirst() +} + + internal fun RealmList.find(eventId: String): TimelineEventEntity? { return this.where().equalTo(TimelineEventEntityFields.ROOT.EVENT_ID, eventId).findFirst() } diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/RoomFactory.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/RoomFactory.kt index 13ca4e67..dddcd37f 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/RoomFactory.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/RoomFactory.kt @@ -24,7 +24,6 @@ import im.vector.matrix.android.api.session.room.Room import im.vector.matrix.android.internal.database.mapper.RoomSummaryMapper import im.vector.matrix.android.internal.session.room.membership.DefaultMembershipService import im.vector.matrix.android.internal.session.room.membership.LoadRoomMembersTask -import im.vector.matrix.android.internal.session.room.membership.SenderRoomMemberExtractor import im.vector.matrix.android.internal.session.room.membership.joining.InviteTask import im.vector.matrix.android.internal.session.room.membership.joining.JoinRoomTask import im.vector.matrix.android.internal.session.room.membership.leaving.LeaveRoomTask diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/membership/SenderRoomMemberExtractor.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/membership/SenderRoomMemberExtractor.kt deleted file mode 100644 index f2629f4d..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/membership/SenderRoomMemberExtractor.kt +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright 2019 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.matrix.android.internal.session.room.membership - -internal object SenderRoomMemberExtractor { - - /* - fun extractFrom(event: Event, realm: Realm): RoomMember? { - val roomId = event.roomId - val sender = event.senderId ?: return null - // If the event is unlinked we want to fetch unlinked state events - val unlinked = event.isUnlinked - val roomEntity = RoomEntity.where(realm, roomId = roomId).findFirst() ?: return null - - // When not synced, we should grab the live RoomMember event - return if (event.sendState != SendState.SYNCED) { - RoomMembers(realm, roomId).get(sender) - } else { - val chunkEntity = ChunkEntity.findIncludingEvent(realm, event.eventId) - val content = when { - chunkEntity == null -> null - event.stateIndex <= 0 -> baseQuery(chunkEntity.events, sender, unlinked).next(from = event.stateIndex)?.prevContent - else -> baseQuery(chunkEntity.events, sender, unlinked).prev(since = event.stateIndex)?.content - } - val fallbackContent = content - ?: baseQuery(roomEntity.untimelinedStateEvents, sender, unlinked).prev(since = event.stateIndex)?.content - ContentMapper.map(fallbackContent).toModel() - } - } - - private fun baseQuery(list: RealmList, - sender: String, - isUnlinked: Boolean): RealmQuery { - return list - .where() - .equalTo(EventEntityFields.STATE_KEY, sender) - .equalTo(EventEntityFields.TYPE, EventType.STATE_ROOM_MEMBER) - .equalTo(EventEntityFields.IS_UNLINKED, isUnlinked) - } - -*/ -} \ No newline at end of file