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 e352e847..9a9e4b7c 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 @@ -89,16 +89,20 @@ internal fun ChunkEntity.add(roomId: String, var currentDisplayIndex = lastDisplayIndex(direction, 0) if (direction == PaginationDirection.FORWARDS) { currentDisplayIndex += 1 + forwardsDisplayIndex = currentDisplayIndex } else { currentDisplayIndex -= 1 + backwardsDisplayIndex = currentDisplayIndex } var currentStateIndex = lastStateIndex(direction, defaultValue = stateIndexOffset) if (direction == PaginationDirection.FORWARDS && EventType.isStateEvent(event.type)) { currentStateIndex += 1 + forwardsStateIndex = currentStateIndex } else if (direction == PaginationDirection.BACKWARDS && events.isNotEmpty()) { val lastEventType = events.last()?.type ?: "" if (EventType.isStateEvent(lastEventType)) { currentStateIndex -= 1 + backwardsStateIndex = currentStateIndex } } val eventEntity = event.toEntity(roomId).apply { @@ -119,14 +123,14 @@ private fun ChunkEntity.assertIsManaged() { internal fun ChunkEntity.lastDisplayIndex(direction: PaginationDirection, defaultValue: Int = 0): Int { return when (direction) { - PaginationDirection.FORWARDS -> events.where().sort(EventEntityFields.DISPLAY_INDEX, Sort.DESCENDING).findFirst()?.displayIndex - PaginationDirection.BACKWARDS -> events.where().sort(EventEntityFields.DISPLAY_INDEX, Sort.ASCENDING).findFirst()?.displayIndex - } ?: defaultValue + PaginationDirection.FORWARDS -> forwardsDisplayIndex + PaginationDirection.BACKWARDS -> backwardsDisplayIndex + } ?: defaultValue } internal fun ChunkEntity.lastStateIndex(direction: PaginationDirection, defaultValue: Int = 0): Int { return when (direction) { - PaginationDirection.FORWARDS -> events.where().sort(EventEntityFields.STATE_INDEX, Sort.DESCENDING).findFirst()?.stateIndex - PaginationDirection.BACKWARDS -> events.where().sort(EventEntityFields.STATE_INDEX, Sort.ASCENDING).findFirst()?.stateIndex - } ?: defaultValue + PaginationDirection.FORWARDS -> forwardsStateIndex + PaginationDirection.BACKWARDS -> backwardsStateIndex + } ?: defaultValue } \ No newline at end of file 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 dd3520e9..6f34fb03 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 @@ -26,7 +26,11 @@ internal open class ChunkEntity(@Index var prevToken: String? = null, @Index var nextToken: String? = null, var events: RealmList = RealmList(), @Index var isLastForward: Boolean = false, - @Index var isLastBackward: Boolean = false + @Index var isLastBackward: Boolean = false, + var backwardsDisplayIndex: Int? = null, + var forwardsDisplayIndex: Int? = null, + var backwardsStateIndex: Int? = null, + var forwardsStateIndex: Int? = null ) : RealmObject() { @LinkingObjects("chunks") diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/SessionModule.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/SessionModule.kt index 5bbbc6cb..510325fa 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/SessionModule.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/SessionModule.kt @@ -29,13 +29,11 @@ import im.vector.matrix.android.internal.session.group.DefaultGroupService import im.vector.matrix.android.internal.session.group.GroupSummaryUpdater import im.vector.matrix.android.internal.session.room.DefaultRoomService import im.vector.matrix.android.internal.session.room.RoomAvatarResolver -import im.vector.matrix.android.internal.session.room.RoomSummaryUpdater import im.vector.matrix.android.internal.session.room.members.RoomDisplayNameResolver import im.vector.matrix.android.internal.session.room.members.RoomMemberDisplayNameResolver import im.vector.matrix.android.internal.session.room.prune.EventsPruner import im.vector.matrix.android.internal.session.user.DefaultUserService import im.vector.matrix.android.internal.session.user.UserEntityUpdater -import im.vector.matrix.android.internal.session.user.UserModule import im.vector.matrix.android.internal.util.md5 import io.realm.RealmConfiguration import org.koin.dsl.module.module @@ -84,7 +82,7 @@ internal class SessionModule(private val sessionParams: SessionParams) { } scope(DefaultSession.SCOPE) { - RoomDisplayNameResolver(get(), get(), sessionParams.credentials) + RoomDisplayNameResolver(get(), get(), get(), sessionParams.credentials) } scope(DefaultSession.SCOPE) { @@ -112,11 +110,10 @@ internal class SessionModule(private val sessionParams: SessionParams) { } scope(DefaultSession.SCOPE) { - val roomSummaryUpdater = RoomSummaryUpdater(get(), get(), get(), get(), sessionParams.credentials) val groupSummaryUpdater = GroupSummaryUpdater(get()) val eventsPruner = EventsPruner(get()) val userEntityUpdater = UserEntityUpdater(get(), get(), get()) - listOf(roomSummaryUpdater, groupSummaryUpdater, eventsPruner, userEntityUpdater) + listOf(groupSummaryUpdater, eventsPruner, userEntityUpdater) } diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/RoomSummaryUpdater.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/RoomSummaryUpdater.kt deleted file mode 100644 index f847237a..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/RoomSummaryUpdater.kt +++ /dev/null @@ -1,74 +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 - -import android.content.Context -import com.zhuinden.monarchy.Monarchy -import im.vector.matrix.android.api.auth.data.Credentials -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.RoomTopicContent -import im.vector.matrix.android.internal.database.RealmLiveEntityObserver -import im.vector.matrix.android.internal.database.mapper.asDomain -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.model.RoomSummaryEntity -import im.vector.matrix.android.internal.database.query.latestEvent -import im.vector.matrix.android.internal.database.query.prev -import im.vector.matrix.android.internal.database.query.where -import im.vector.matrix.android.internal.session.room.members.RoomDisplayNameResolver -import im.vector.matrix.android.internal.session.room.members.RoomMembers -import io.realm.Realm -import io.realm.kotlin.createObject - -internal class RoomSummaryUpdater(monarchy: Monarchy, - private val roomDisplayNameResolver: RoomDisplayNameResolver, - private val roomAvatarResolver: RoomAvatarResolver, - private val context: Context, - private val credentials: Credentials -) : RealmLiveEntityObserver(monarchy) { - - override val query = Monarchy.Query { RoomEntity.where(it) } - - override fun processChanges(inserted: List, updated: List, deleted: List) { - val rooms = (inserted + updated).map { it.roomId } - monarchy.writeAsync { realm -> - rooms.forEach { updateRoom(realm, it) } - } - } - - private fun updateRoom(realm: Realm, roomId: String?) { - if (roomId == null) { - return - } - val roomSummary = RoomSummaryEntity.where(realm, roomId).findFirst() - ?: realm.createObject(roomId) - - val lastEvent = EventEntity.latestEvent(realm, roomId, includedTypes = listOf(EventType.MESSAGE)) - val lastTopicEvent = EventEntity.where(realm, roomId, EventType.STATE_ROOM_TOPIC).prev()?.asDomain() - - val otherRoomMembers = RoomMembers(realm, roomId).getLoaded().filterKeys { it != credentials.userId } - - roomSummary.displayName = roomDisplayNameResolver.resolve(context, roomId).toString() - roomSummary.avatarUrl = roomAvatarResolver.resolve(roomId) - roomSummary.topic = lastTopicEvent?.content.toModel()?.topic - roomSummary.lastMessage = lastEvent - roomSummary.otherMemberIds.clear() - roomSummary.otherMemberIds.addAll(otherRoomMembers.keys) - } - -} \ No newline at end of file diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/members/RoomDisplayNameResolver.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/members/RoomDisplayNameResolver.kt index f39dd300..7f19762c 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/members/RoomDisplayNameResolver.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/members/RoomDisplayNameResolver.kt @@ -36,7 +36,8 @@ import im.vector.matrix.android.internal.database.query.where /** * This class computes room display name */ -internal class RoomDisplayNameResolver(private val monarchy: Monarchy, +internal class RoomDisplayNameResolver(private val context: Context, + private val monarchy: Monarchy, private val roomMemberDisplayNameResolver: RoomMemberDisplayNameResolver, private val credentials: Credentials ) { @@ -44,11 +45,10 @@ internal class RoomDisplayNameResolver(private val monarchy: Monarchy, /** * Compute the room display name * - * @param context * @param roomId: the roomId to resolve the name of. * @return the room display name */ - fun resolve(context: Context, roomId: String): CharSequence { + fun resolve(roomId: String): CharSequence { // this algorithm is the one defined in // https://github.com/matrix-org/matrix-js-sdk/blob/develop/lib/models/room.js#L617 // calculateRoomName(room, userId) @@ -111,16 +111,16 @@ internal class RoomDisplayNameResolver(private val monarchy: Monarchy, val member1 = memberIds[0] val member2 = memberIds[1] name = context.getString(R.string.room_displayname_two_members, - roomMemberDisplayNameResolver.resolve(member1, otherRoomMembers), - roomMemberDisplayNameResolver.resolve(member2, otherRoomMembers) + roomMemberDisplayNameResolver.resolve(member1, otherRoomMembers), + roomMemberDisplayNameResolver.resolve(member2, otherRoomMembers) ) } else -> { val member = memberIds[0] name = context.resources.getQuantityString(R.plurals.room_displayname_three_and_more_members, - roomMembers.getNumberOfJoinedMembers() - 1, - roomMemberDisplayNameResolver.resolve(member, otherRoomMembers), - roomMembers.getNumberOfJoinedMembers() - 1) + roomMembers.getNumberOfJoinedMembers() - 1, + roomMemberDisplayNameResolver.resolve(member, otherRoomMembers), + roomMembers.getNumberOfJoinedMembers() - 1) } } } 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 51044646..cc29f99e 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 @@ -17,20 +17,29 @@ package im.vector.matrix.android.internal.session.sync import com.zhuinden.monarchy.Monarchy +import im.vector.matrix.android.api.auth.data.Credentials 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.MyMembership +import im.vector.matrix.android.api.session.room.model.RoomTopicContent import im.vector.matrix.android.api.session.room.model.tag.RoomTagContent import im.vector.matrix.android.internal.database.helper.addAll import im.vector.matrix.android.internal.database.helper.addOrUpdate import im.vector.matrix.android.internal.database.helper.addStateEvents import im.vector.matrix.android.internal.database.helper.lastStateIndex +import im.vector.matrix.android.internal.database.mapper.asDomain 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.RoomEntity import im.vector.matrix.android.internal.database.model.RoomSummaryEntity import im.vector.matrix.android.internal.database.query.findLastLiveChunkFromRoom +import im.vector.matrix.android.internal.database.query.latestEvent +import im.vector.matrix.android.internal.database.query.prev import im.vector.matrix.android.internal.database.query.where +import im.vector.matrix.android.internal.session.room.RoomAvatarResolver +import im.vector.matrix.android.internal.session.room.members.RoomDisplayNameResolver +import im.vector.matrix.android.internal.session.room.members.RoomMembers import im.vector.matrix.android.internal.session.room.timeline.PaginationDirection import im.vector.matrix.android.internal.session.sync.model.InvitedRoomSync import im.vector.matrix.android.internal.session.sync.model.RoomSync @@ -44,6 +53,9 @@ import io.realm.kotlin.createObject internal class RoomSyncHandler(private val monarchy: Monarchy, private val readReceiptHandler: ReadReceiptHandler, + private val roomDisplayNameResolver: RoomDisplayNameResolver, + private val roomAvatarResolver: RoomAvatarResolver, + private val credentials: Credentials, private val roomTagHandler: RoomTagHandler) { sealed class HandlingStrategy { @@ -51,6 +63,7 @@ internal class RoomSyncHandler(private val monarchy: Monarchy, data class INVITED(val data: Map) : HandlingStrategy() data class LEFT(val data: Map) : HandlingStrategy() } + fun handle(roomsSyncResponse: RoomsSyncResponse) { monarchy.runTransactionSync { realm -> handleRoomSync(realm, RoomSyncHandler.HandlingStrategy.JOINED(roomsSyncResponse.join)) @@ -107,9 +120,7 @@ internal class RoomSyncHandler(private val monarchy: Monarchy, roomEntity.addOrUpdate(chunkEntity) } - if (roomSync.summary != null) { - handleRoomSummary(realm, roomId, roomSync.summary) - } + handleRoomSummary(realm, roomId, roomSync.summary) if (roomSync.unreadNotifications != null) { handleUnreadNotifications(realm, roomId, roomSync.unreadNotifications) @@ -171,20 +182,33 @@ internal class RoomSyncHandler(private val monarchy: Monarchy, private fun handleRoomSummary(realm: Realm, roomId: String, - roomSummary: RoomSyncSummary) { + roomSummary: RoomSyncSummary?) { val roomSummaryEntity = RoomSummaryEntity.where(realm, roomId).findFirst() ?: RoomSummaryEntity(roomId) - if (roomSummary.heroes.isNotEmpty()) { - roomSummaryEntity.heroes.clear() - roomSummaryEntity.heroes.addAll(roomSummary.heroes) - } - if (roomSummary.invitedMembersCount != null) { - roomSummaryEntity.invitedMembersCount = roomSummary.invitedMembersCount - } - if (roomSummary.joinedMembersCount != null) { - roomSummaryEntity.joinedMembersCount = roomSummary.joinedMembersCount + val lastEvent = EventEntity.latestEvent(realm, roomId, includedTypes = listOf(EventType.MESSAGE)) + val lastTopicEvent = EventEntity.where(realm, roomId, EventType.STATE_ROOM_TOPIC).prev()?.asDomain() + + val otherRoomMembers = RoomMembers(realm, roomId).getLoaded().filterKeys { it != credentials.userId } + roomSummaryEntity.displayName = roomDisplayNameResolver.resolve(roomId).toString() + roomSummaryEntity.avatarUrl = roomAvatarResolver.resolve(roomId) + roomSummaryEntity.topic = lastTopicEvent?.content.toModel()?.topic + roomSummaryEntity.lastMessage = lastEvent + roomSummaryEntity.otherMemberIds.clear() + roomSummaryEntity.otherMemberIds.addAll(otherRoomMembers.keys) + + if (roomSummary != null) { + if (roomSummary.heroes.isNotEmpty()) { + roomSummaryEntity.heroes.clear() + roomSummaryEntity.heroes.addAll(roomSummary.heroes) + } + if (roomSummary.invitedMembersCount != null) { + roomSummaryEntity.invitedMembersCount = roomSummary.invitedMembersCount + } + if (roomSummary.joinedMembersCount != null) { + roomSummaryEntity.joinedMembersCount = roomSummary.joinedMembersCount + } } realm.insertOrUpdate(roomSummaryEntity) } diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/SyncModule.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/SyncModule.kt index c62bc2e1..b1926486 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/SyncModule.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/SyncModule.kt @@ -40,7 +40,7 @@ internal class SyncModule { } scope(DefaultSession.SCOPE) { - RoomSyncHandler(get(), get(), get()) + RoomSyncHandler(get(), get(), get(),get(),get(),get()) } scope(DefaultSession.SCOPE) { diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/SyncResponseHandler.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/SyncResponseHandler.kt index ef06471c..d9859526 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/SyncResponseHandler.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/SyncResponseHandler.kt @@ -19,6 +19,7 @@ package im.vector.matrix.android.internal.session.sync import arrow.core.Try import im.vector.matrix.android.internal.session.sync.model.SyncResponse import timber.log.Timber +import kotlin.system.measureTimeMillis internal class SyncResponseHandler(private val roomSyncHandler: RoomSyncHandler, private val userAccountDataSyncHandler: UserAccountDataSyncHandler, @@ -26,16 +27,19 @@ internal class SyncResponseHandler(private val roomSyncHandler: RoomSyncHandler, fun handleResponse(syncResponse: SyncResponse, fromToken: String?, isCatchingUp: Boolean): Try { return Try { - Timber.v("Handle sync response") - if (syncResponse.rooms != null) { - roomSyncHandler.handle(syncResponse.rooms) - } - if (syncResponse.groups != null) { - groupSyncHandler.handle(syncResponse.groups) - } - if (syncResponse.accountData != null) { - userAccountDataSyncHandler.handle(syncResponse.accountData) + Timber.v("Start handling sync") + val measure = measureTimeMillis { + if (syncResponse.rooms != null) { + roomSyncHandler.handle(syncResponse.rooms) + } + if (syncResponse.groups != null) { + groupSyncHandler.handle(syncResponse.groups) + } + if (syncResponse.accountData != null) { + userAccountDataSyncHandler.handle(syncResponse.accountData) + } } + Timber.v("Finish handling sync in $measure ms") syncResponse } }