diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/membership/RoomMemberEventHandler.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/membership/RoomMemberEventHandler.kt index 2ecacf335b..7528f80cc2 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/membership/RoomMemberEventHandler.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/membership/RoomMemberEventHandler.kt @@ -20,22 +20,30 @@ import io.realm.Realm import org.matrix.android.sdk.api.session.events.model.Event import org.matrix.android.sdk.api.session.events.model.EventType import org.matrix.android.sdk.api.session.room.model.RoomMemberContent +import org.matrix.android.sdk.internal.di.UserId import org.matrix.android.sdk.internal.session.events.getFixedRoomMemberContent +import org.matrix.android.sdk.internal.session.sync.SyncResponsePostTreatmentAggregator import org.matrix.android.sdk.internal.session.user.UserEntityFactory import javax.inject.Inject -internal class RoomMemberEventHandler @Inject constructor() { +internal class RoomMemberEventHandler @Inject constructor( + @UserId private val myUserId: String +) { - fun handle(realm: Realm, roomId: String, event: Event): Boolean { + fun handle(realm: Realm, roomId: String, event: Event, aggregator: SyncResponsePostTreatmentAggregator? = null): Boolean { if (event.type != EventType.STATE_ROOM_MEMBER) { return false } val userId = event.stateKey ?: return false val roomMember = event.getFixedRoomMemberContent() - return handle(realm, roomId, userId, roomMember) + return handle(realm, roomId, userId, roomMember, aggregator) } - fun handle(realm: Realm, roomId: String, userId: String, roomMember: RoomMemberContent?): Boolean { + fun handle(realm: Realm, + roomId: String, + userId: String, + roomMember: RoomMemberContent?, + aggregator: SyncResponsePostTreatmentAggregator? = null): Boolean { if (roomMember == null) { return false } @@ -45,6 +53,14 @@ internal class RoomMemberEventHandler @Inject constructor() { val userEntity = UserEntityFactory.create(userId, roomMember) realm.insertOrUpdate(userEntity) } + + // check whether this new room member event may be used to update the directs dictionary in account data + // this is required to handle correctly invite by email in DM + val mxId = roomMember.thirdPartyInvite?.signed?.mxid + if (mxId != null && mxId != myUserId) { + aggregator?.directChatsToCheck?.put(roomId, mxId) + } + return true } } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/RoomSyncHandler.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/RoomSyncHandler.kt index c3586bcea7..830e666c95 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/RoomSyncHandler.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/RoomSyncHandler.kt @@ -221,7 +221,7 @@ internal class RoomSyncHandler @Inject constructor(private val readReceiptHandle } // Give info to crypto module cryptoService.onStateEvent(roomId, event) - roomMemberEventHandler.handle(realm, roomId, event) + roomMemberEventHandler.handle(realm, roomId, event, aggregator) } } if (roomSync.timeline?.events?.isNotEmpty() == true) { @@ -233,7 +233,8 @@ internal class RoomSyncHandler @Inject constructor(private val readReceiptHandle roomSync.timeline.prevToken, roomSync.timeline.limited, insertType, - syncLocalTimestampMillis + syncLocalTimestampMillis, + aggregator ) roomEntity.addIfNecessary(chunkEntity) } @@ -337,7 +338,8 @@ internal class RoomSyncHandler @Inject constructor(private val readReceiptHandle prevToken: String? = null, isLimited: Boolean = true, insertType: EventInsertType, - syncLocalTimestampMillis: Long): ChunkEntity { + syncLocalTimestampMillis: Long, + aggregator: SyncResponsePostTreatmentAggregator): ChunkEntity { val lastChunk = ChunkEntity.findLastForwardChunkOfRoom(realm, roomEntity.roomId) val chunkEntity = if (!isLimited && lastChunk != null) { lastChunk @@ -371,7 +373,7 @@ internal class RoomSyncHandler @Inject constructor(private val readReceiptHandle if (event.type == EventType.STATE_ROOM_MEMBER) { val fixedContent = event.getFixedRoomMemberContent() roomMemberContentsByUser[event.stateKey] = fixedContent - roomMemberEventHandler.handle(realm, roomEntity.roomId, event.stateKey, fixedContent) + roomMemberEventHandler.handle(realm, roomEntity.roomId, event.stateKey, fixedContent, aggregator) } } roomMemberContentsByUser.getOrPut(event.senderId) { diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/SyncResponsePostTreatmentAggregator.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/SyncResponsePostTreatmentAggregator.kt index ea10a32f3e..9bb2bfc9b1 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/SyncResponsePostTreatmentAggregator.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/SyncResponsePostTreatmentAggregator.kt @@ -19,4 +19,6 @@ package org.matrix.android.sdk.internal.session.sync internal class SyncResponsePostTreatmentAggregator { // List of RoomId val ephemeralFilesToDelete = mutableListOf() + // Map of roomId to directUserId + val directChatsToCheck = mutableMapOf() } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/SyncResponsePostTreatmentAggregatorHandler.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/SyncResponsePostTreatmentAggregatorHandler.kt index 12b77c706b..e074cddc1f 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/SyncResponsePostTreatmentAggregatorHandler.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/SyncResponsePostTreatmentAggregatorHandler.kt @@ -16,13 +16,19 @@ package org.matrix.android.sdk.internal.session.sync +import org.matrix.android.sdk.api.MatrixPatterns +import org.matrix.android.sdk.internal.session.user.accountdata.DirectChatsHelper +import org.matrix.android.sdk.internal.session.user.accountdata.UpdateUserAccountDataTask import javax.inject.Inject internal class SyncResponsePostTreatmentAggregatorHandler @Inject constructor( - private val ephemeralTemporaryStore: RoomSyncEphemeralTemporaryStore + private val directChatsHelper: DirectChatsHelper, + private val ephemeralTemporaryStore: RoomSyncEphemeralTemporaryStore, + private val updateUserAccountDataTask: UpdateUserAccountDataTask ) { - fun handle(synResHaResponsePostTreatmentAggregator: SyncResponsePostTreatmentAggregator) { + suspend fun handle(synResHaResponsePostTreatmentAggregator: SyncResponsePostTreatmentAggregator) { cleanupEphemeralFiles(synResHaResponsePostTreatmentAggregator.ephemeralFilesToDelete) + updateDirectUserIds(synResHaResponsePostTreatmentAggregator.directChatsToCheck) } private fun cleanupEphemeralFiles(ephemeralFilesToDelete: List) { @@ -30,4 +36,33 @@ internal class SyncResponsePostTreatmentAggregatorHandler @Inject constructor( ephemeralTemporaryStore.delete(it) } } + + private suspend fun updateDirectUserIds(directUserIdsToUpdate: Map) { + val directChats = directChatsHelper.getLocalDirectMessages() + var hasUpdate = false + directUserIdsToUpdate.forEach { (roomId, candidateUserId) -> + // consider room is a DM if referenced in the DM dictionary + val currentDirectUserId = directChats.firstNotNullOfOrNull { (userId, roomIds) -> userId.takeIf { roomId in roomIds } } + // update directUserId with the given candidateUserId if it mismatches the current one + if (currentDirectUserId != null && !MatrixPatterns.isUserId(currentDirectUserId)) { + // link roomId with the matrix id + directChats + .getOrPut(candidateUserId) { arrayListOf() } + .apply { + if (!contains(roomId)) { + hasUpdate = true + add(roomId) + } + } + + // remove roomId from currentDirectUserId entry + hasUpdate = hasUpdate or(directChats[currentDirectUserId]?.remove(roomId) == true) + // remove currentDirectUserId entry if there is no attached room anymore + hasUpdate = hasUpdate or(directChats.takeIf { it[currentDirectUserId].isNullOrEmpty() }?.remove(currentDirectUserId) != null) + } + } + if (hasUpdate) { + updateUserAccountDataTask.execute(UpdateUserAccountDataTask.DirectChatParams(directMessages = directChats)) + } + } }