diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/EventAnnotationsSummary.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/EventAnnotationsSummary.kt index 89fca26aef..f729e69055 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/EventAnnotationsSummary.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/room/model/EventAnnotationsSummary.kt @@ -17,8 +17,8 @@ package im.vector.matrix.android.api.session.room.model data class EventAnnotationsSummary( var eventId: String, - var reactionsSummary: List, - var editSummary: EditAggregatedSummary?, - var pollResponseSummary: PollResponseAggregatedSummary?, + var reactionsSummary: List = emptyList(), + var editSummary: EditAggregatedSummary?= null, + var pollResponseSummary: PollResponseAggregatedSummary? = null, var referencesAggregatedSummary: ReferencesAggregatedSummary? = null ) diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/crosssigning/ShieldTrustUpdater.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/crosssigning/ShieldTrustUpdater.kt index 16457ba95e..cadcf3d855 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/crosssigning/ShieldTrustUpdater.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/crosssigning/ShieldTrustUpdater.kt @@ -22,7 +22,7 @@ import im.vector.matrix.android.internal.database.model.RoomSummaryEntity import im.vector.matrix.android.internal.database.query.where import im.vector.matrix.android.internal.di.SessionDatabase import im.vector.matrix.android.internal.session.SessionLifecycleObserver -import im.vector.matrix.android.internal.session.room.RoomSummaryUpdater +import im.vector.matrix.android.internal.session.room.summary.RoomSummaryUpdater import im.vector.matrix.android.internal.session.room.membership.RoomMemberHelper import im.vector.matrix.android.internal.task.TaskExecutor import im.vector.matrix.android.internal.util.createBackgroundHandler diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/query/ReadQueries.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/query/ReadQueries.kt index 9c73dff1dd..4d312522f0 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/query/ReadQueries.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/query/ReadQueries.kt @@ -22,8 +22,9 @@ import im.vector.matrix.android.internal.database.model.ReadMarkerEntity import im.vector.matrix.android.internal.database.model.ReadReceiptEntity import im.vector.matrix.android.internal.database.model.TimelineEventEntity import io.realm.Realm +import io.realm.RealmConfiguration -internal fun isEventRead(monarchy: Monarchy, +internal fun isEventRead(realmConfiguration: RealmConfiguration, userId: String?, roomId: String?, eventId: String?): Boolean { @@ -35,14 +36,14 @@ internal fun isEventRead(monarchy: Monarchy, } var isEventRead = false - monarchy.doWithRealm { realm -> - val liveChunk = ChunkEntity.findLastForwardChunkOfRoom(realm, roomId) ?: return@doWithRealm + Realm.getInstance(realmConfiguration).use{ realm -> + val liveChunk = ChunkEntity.findLastForwardChunkOfRoom(realm, roomId) ?: return@use val eventToCheck = liveChunk.timelineEvents.find(eventId) isEventRead = if (eventToCheck == null || eventToCheck.root?.sender == userId) { true } else { val readReceipt = ReadReceiptEntity.where(realm, roomId, userId).findFirst() - ?: return@doWithRealm + ?: return@use val readReceiptIndex = liveChunk.timelineEvents.find(readReceipt.eventId)?.displayIndex ?: Int.MIN_VALUE val eventToCheckIndex = eventToCheck.displayIndex @@ -54,13 +55,13 @@ internal fun isEventRead(monarchy: Monarchy, return isEventRead } -internal fun isReadMarkerMoreRecent(monarchy: Monarchy, +internal fun isReadMarkerMoreRecent(realmConfiguration: RealmConfiguration, roomId: String?, eventId: String?): Boolean { if (roomId.isNullOrBlank() || eventId.isNullOrBlank()) { return false } - return Realm.getInstance(monarchy.realmConfiguration).use { realm -> + return Realm.getInstance(realmConfiguration).use { realm -> val eventToCheck = TimelineEventEntity.where(realm, roomId = roomId, eventId = eventId).findFirst() val eventToCheckChunk = eventToCheck?.chunk?.firstOrNull() val readMarker = ReadMarkerEntity.where(realm, roomId).findFirst() ?: return false 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 e911d720aa..e1df1d3654 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 @@ -37,15 +37,12 @@ import im.vector.matrix.android.api.session.homeserver.HomeServerCapabilitiesSer import im.vector.matrix.android.api.session.securestorage.SecureStorageService import im.vector.matrix.android.api.session.securestorage.SharedSecretStorageService import im.vector.matrix.android.api.session.typing.TypingUsersTracker -import im.vector.matrix.android.api.session.widgets.WidgetURLFormatter import im.vector.matrix.android.internal.crypto.crosssigning.ShieldTrustUpdater import im.vector.matrix.android.internal.crypto.secrets.DefaultSharedSecretStorageService import im.vector.matrix.android.internal.crypto.verification.VerificationMessageLiveObserver -import im.vector.matrix.android.internal.database.LiveEntityObserver import im.vector.matrix.android.internal.database.SessionRealmConfigurationFactory import im.vector.matrix.android.internal.di.Authenticated import im.vector.matrix.android.internal.di.DeviceId -import im.vector.matrix.android.internal.di.InMemorySessionDatabase import im.vector.matrix.android.internal.di.SessionCacheDirectory import im.vector.matrix.android.internal.di.SessionDatabase import im.vector.matrix.android.internal.di.SessionFilesDirectory @@ -284,7 +281,6 @@ internal abstract class SessionModule { @IntoSet abstract fun bindIdentityService(observer: DefaultIdentityService): SessionLifecycleObserver - @Binds abstract fun bindInitialSyncProgressService(service: DefaultInitialSyncProgressService): InitialSyncProgressService diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/DefaultRoom.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/DefaultRoom.kt index 6f902eab91..0fa2be7055 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/DefaultRoom.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/DefaultRoom.kt @@ -17,8 +17,6 @@ package im.vector.matrix.android.internal.session.room import androidx.lifecycle.LiveData -import androidx.lifecycle.Transformations -import com.zhuinden.monarchy.Monarchy import im.vector.matrix.android.api.MatrixCallback import im.vector.matrix.android.api.session.crypto.CryptoService import im.vector.matrix.android.api.session.events.model.EventType @@ -37,22 +35,16 @@ import im.vector.matrix.android.api.session.room.timeline.TimelineService import im.vector.matrix.android.api.session.room.typing.TypingService import im.vector.matrix.android.api.session.room.uploads.UploadsService import im.vector.matrix.android.api.util.Optional -import im.vector.matrix.android.api.util.toOptional import im.vector.matrix.android.internal.crypto.MXCRYPTO_ALGORITHM_MEGOLM -import im.vector.matrix.android.internal.database.mapper.RoomSummaryMapper -import im.vector.matrix.android.internal.database.model.RoomSummaryEntity -import im.vector.matrix.android.internal.database.model.RoomSummaryEntityFields -import im.vector.matrix.android.internal.database.query.where -import im.vector.matrix.android.internal.di.SessionDatabase import im.vector.matrix.android.internal.session.room.state.SendStateTask +import im.vector.matrix.android.internal.session.room.summary.RoomSummaryDataSource import im.vector.matrix.android.internal.task.TaskExecutor import im.vector.matrix.android.internal.task.configureWith import java.security.InvalidParameterException import javax.inject.Inject internal class DefaultRoom @Inject constructor(override val roomId: String, - @SessionDatabase private val monarchy: Monarchy, - private val roomSummaryMapper: RoomSummaryMapper, + private val roomSummaryDataSource: RoomSummaryDataSource, private val timelineService: TimelineService, private val sendService: SendService, private val draftService: DraftService, @@ -83,20 +75,11 @@ internal class DefaultRoom @Inject constructor(override val roomId: String, RoomPushRuleService by roomPushRuleService { override fun getRoomSummaryLive(): LiveData> { - val liveData = monarchy.findAllMappedWithChanges( - { realm -> RoomSummaryEntity.where(realm, roomId).isNotEmpty(RoomSummaryEntityFields.DISPLAY_NAME) }, - { roomSummaryMapper.map(it) } - ) - return Transformations.map(liveData) { results -> - results.firstOrNull().toOptional() - } + return roomSummaryDataSource.getRoomSummaryLive(roomId) } override fun roomSummary(): RoomSummary? { - return monarchy.fetchAllMappedSync( - { realm -> RoomSummaryEntity.where(realm, roomId).isNotEmpty(RoomSummaryEntityFields.DISPLAY_NAME) }, - { roomSummaryMapper.map(it) } - ).firstOrNull() + return roomSummaryDataSource.getRoomSummary(roomId) } override fun isEncrypted(): Boolean { diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/DefaultRoomService.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/DefaultRoomService.kt index 0ce5f132fd..177f803ab3 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/DefaultRoomService.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/DefaultRoomService.kt @@ -23,38 +23,29 @@ import im.vector.matrix.android.api.session.room.Room import im.vector.matrix.android.api.session.room.RoomService import im.vector.matrix.android.api.session.room.RoomSummaryQueryParams import im.vector.matrix.android.api.session.room.model.RoomSummary -import im.vector.matrix.android.api.session.room.model.VersioningState import im.vector.matrix.android.api.session.room.model.create.CreateRoomParams import im.vector.matrix.android.api.util.Cancelable import im.vector.matrix.android.api.util.Optional import im.vector.matrix.android.internal.database.mapper.RoomSummaryMapper -import im.vector.matrix.android.internal.database.model.RoomSummaryEntity -import im.vector.matrix.android.internal.database.model.RoomSummaryEntityFields -import im.vector.matrix.android.internal.database.query.findByAlias -import im.vector.matrix.android.internal.database.query.where import im.vector.matrix.android.internal.di.SessionDatabase -import im.vector.matrix.android.internal.query.process import im.vector.matrix.android.internal.session.room.alias.GetRoomIdByAliasTask import im.vector.matrix.android.internal.session.room.create.CreateRoomTask import im.vector.matrix.android.internal.session.room.membership.joining.JoinRoomTask import im.vector.matrix.android.internal.session.room.read.MarkAllRoomsReadTask +import im.vector.matrix.android.internal.session.room.summary.RoomSummaryDataSource import im.vector.matrix.android.internal.session.user.accountdata.UpdateBreadcrumbsTask import im.vector.matrix.android.internal.task.TaskExecutor import im.vector.matrix.android.internal.task.configureWith -import im.vector.matrix.android.internal.util.fetchCopyMap -import io.realm.Realm -import io.realm.RealmQuery import javax.inject.Inject internal class DefaultRoomService @Inject constructor( - @SessionDatabase private val monarchy: Monarchy, - private val roomSummaryMapper: RoomSummaryMapper, private val createRoomTask: CreateRoomTask, private val joinRoomTask: JoinRoomTask, private val markAllRoomsReadTask: MarkAllRoomsReadTask, private val updateBreadcrumbsTask: UpdateBreadcrumbsTask, private val roomIdByAliasTask: GetRoomIdByAliasTask, private val roomGetter: RoomGetter, + private val roomSummaryDataSource: RoomSummaryDataSource, private val taskExecutor: TaskExecutor ) : RoomService { @@ -75,61 +66,23 @@ internal class DefaultRoomService @Inject constructor( } override fun getRoomSummary(roomIdOrAlias: String): RoomSummary? { - return monarchy - .fetchCopyMap({ - if (roomIdOrAlias.startsWith("!")) { - // It's a roomId - RoomSummaryEntity.where(it, roomId = roomIdOrAlias).findFirst() - } else { - // Assume it's a room alias - RoomSummaryEntity.findByAlias(it, roomIdOrAlias) - } - }, { entity, _ -> - roomSummaryMapper.map(entity) - }) + return roomSummaryDataSource.getRoomSummary(roomIdOrAlias) } override fun getRoomSummaries(queryParams: RoomSummaryQueryParams): List { - return monarchy.fetchAllMappedSync( - { roomSummariesQuery(it, queryParams) }, - { roomSummaryMapper.map(it) } - ) + return roomSummaryDataSource.getRoomSummaries(queryParams) } override fun getRoomSummariesLive(queryParams: RoomSummaryQueryParams): LiveData> { - return monarchy.findAllMappedWithChanges( - { roomSummariesQuery(it, queryParams) }, - { roomSummaryMapper.map(it) } - ) - } - - private fun roomSummariesQuery(realm: Realm, queryParams: RoomSummaryQueryParams): RealmQuery { - val query = RoomSummaryEntity.where(realm) - query.process(RoomSummaryEntityFields.DISPLAY_NAME, queryParams.displayName) - query.process(RoomSummaryEntityFields.CANONICAL_ALIAS, queryParams.canonicalAlias) - query.process(RoomSummaryEntityFields.MEMBERSHIP_STR, queryParams.memberships) - query.notEqualTo(RoomSummaryEntityFields.VERSIONING_STATE_STR, VersioningState.UPGRADED_ROOM_JOINED.name) - return query + return roomSummaryDataSource.getRoomSummariesLive(queryParams) } override fun getBreadcrumbs(queryParams: RoomSummaryQueryParams): List { - return monarchy.fetchAllMappedSync( - { breadcrumbsQuery(it, queryParams) }, - { roomSummaryMapper.map(it) } - ) + return roomSummaryDataSource.getBreadcrumbs(queryParams) } override fun getBreadcrumbsLive(queryParams: RoomSummaryQueryParams): LiveData> { - return monarchy.findAllMappedWithChanges( - { breadcrumbsQuery(it, queryParams) }, - { roomSummaryMapper.map(it) } - ) - } - - private fun breadcrumbsQuery(realm: Realm, queryParams: RoomSummaryQueryParams): RealmQuery { - return roomSummariesQuery(realm, queryParams) - .greaterThan(RoomSummaryEntityFields.BREADCRUMBS_INDEX, RoomSummary.NOT_IN_BREADCRUMBS) - .sort(RoomSummaryEntityFields.BREADCRUMBS_INDEX) + return roomSummaryDataSource.getBreadcrumbsLive(queryParams) } override fun onRoomDisplayed(roomId: String): Cancelable { diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/RoomAvatarResolver.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/RoomAvatarResolver.kt index e91d91d1ce..1c395ec647 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/RoomAvatarResolver.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/RoomAvatarResolver.kt @@ -16,7 +16,6 @@ package im.vector.matrix.android.internal.session.room -import com.zhuinden.monarchy.Monarchy 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.RoomAvatarContent @@ -24,36 +23,34 @@ import im.vector.matrix.android.internal.database.mapper.ContentMapper import im.vector.matrix.android.internal.database.model.CurrentStateEventEntity import im.vector.matrix.android.internal.database.model.RoomMemberSummaryEntityFields import im.vector.matrix.android.internal.database.query.getOrNull -import im.vector.matrix.android.internal.di.SessionDatabase import im.vector.matrix.android.internal.di.UserId import im.vector.matrix.android.internal.session.room.membership.RoomMemberHelper +import io.realm.Realm import javax.inject.Inject -internal class RoomAvatarResolver @Inject constructor(@SessionDatabase private val monarchy: Monarchy, - @UserId private val userId: String) { +internal class RoomAvatarResolver @Inject constructor(@UserId private val userId: String) { /** * Compute the room avatar url + * @param realm: the current instance of realm * @param roomId the roomId of the room to resolve avatar * @return the room avatar url, can be a fallback to a room member avatar or null */ - fun resolve(roomId: String): String? { - var res: String? = null - monarchy.doWithRealm { realm -> - val roomName = CurrentStateEventEntity.getOrNull(realm, roomId, type = EventType.STATE_ROOM_AVATAR, stateKey = "")?.root - res = ContentMapper.map(roomName?.content).toModel()?.avatarUrl - if (!res.isNullOrEmpty()) { - return@doWithRealm - } - val roomMembers = RoomMemberHelper(realm, roomId) - val members = roomMembers.queryActiveRoomMembersEvent().findAll() - // detect if it is a room with no more than 2 members (i.e. an alone or a 1:1 chat) - if (members.size == 1) { - res = members.firstOrNull()?.avatarUrl - } else if (members.size == 2) { - val firstOtherMember = members.where().notEqualTo(RoomMemberSummaryEntityFields.USER_ID, userId).findFirst() - res = firstOtherMember?.avatarUrl - } + fun resolve(realm: Realm, roomId: String): String? { + var res: String? + val roomName = CurrentStateEventEntity.getOrNull(realm, roomId, type = EventType.STATE_ROOM_AVATAR, stateKey = "")?.root + res = ContentMapper.map(roomName?.content).toModel()?.avatarUrl + if (!res.isNullOrEmpty()) { + return res + } + val roomMembers = RoomMemberHelper(realm, roomId) + val members = roomMembers.queryActiveRoomMembersEvent().findAll() + // detect if it is a room with no more than 2 members (i.e. an alone or a 1:1 chat) + if (members.size == 1) { + res = members.firstOrNull()?.avatarUrl + } else if (members.size == 2) { + val firstOtherMember = members.where().notEqualTo(RoomMemberSummaryEntityFields.USER_ID, userId).findFirst() + res = firstOtherMember?.avatarUrl } return res } 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 e4ca42e549..ea6e9a86c8 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 @@ -16,11 +16,8 @@ package im.vector.matrix.android.internal.session.room -import com.zhuinden.monarchy.Monarchy import im.vector.matrix.android.api.session.crypto.CryptoService import im.vector.matrix.android.api.session.room.Room -import im.vector.matrix.android.internal.database.mapper.RoomSummaryMapper -import im.vector.matrix.android.internal.di.SessionDatabase import im.vector.matrix.android.internal.session.SessionScope import im.vector.matrix.android.internal.session.room.draft.DefaultDraftService import im.vector.matrix.android.internal.session.room.membership.DefaultMembershipService @@ -31,6 +28,7 @@ import im.vector.matrix.android.internal.session.room.reporting.DefaultReporting import im.vector.matrix.android.internal.session.room.send.DefaultSendService import im.vector.matrix.android.internal.session.room.state.DefaultStateService import im.vector.matrix.android.internal.session.room.state.SendStateTask +import im.vector.matrix.android.internal.session.room.summary.RoomSummaryDataSource import im.vector.matrix.android.internal.session.room.tags.DefaultTagsService import im.vector.matrix.android.internal.session.room.timeline.DefaultTimelineService import im.vector.matrix.android.internal.session.room.typing.DefaultTypingService @@ -43,9 +41,8 @@ internal interface RoomFactory { } @SessionScope -internal class DefaultRoomFactory @Inject constructor(@SessionDatabase private val monarchy: Monarchy, - private val roomSummaryMapper: RoomSummaryMapper, - private val cryptoService: CryptoService, +internal class DefaultRoomFactory @Inject constructor(private val cryptoService: CryptoService, + private val roomSummaryDataSource: RoomSummaryDataSource, private val timelineServiceFactory: DefaultTimelineService.Factory, private val sendServiceFactory: DefaultSendService.Factory, private val draftServiceFactory: DefaultDraftService.Factory, @@ -65,8 +62,7 @@ internal class DefaultRoomFactory @Inject constructor(@SessionDatabase private v override fun create(roomId: String): Room { return DefaultRoom( roomId = roomId, - monarchy = monarchy, - roomSummaryMapper = roomSummaryMapper, + roomSummaryDataSource = roomSummaryDataSource, timelineService = timelineServiceFactory.create(roomId), sendService = sendServiceFactory.create(roomId), draftService = draftServiceFactory.create(roomId), diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/membership/LoadRoomMembersTask.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/membership/LoadRoomMembersTask.kt index 8726eebb18..fa4a17ba34 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/membership/LoadRoomMembersTask.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/membership/LoadRoomMembersTask.kt @@ -28,7 +28,7 @@ import im.vector.matrix.android.internal.database.query.where import im.vector.matrix.android.internal.di.SessionDatabase import im.vector.matrix.android.internal.network.executeRequest import im.vector.matrix.android.internal.session.room.RoomAPI -import im.vector.matrix.android.internal.session.room.RoomSummaryUpdater +import im.vector.matrix.android.internal.session.room.summary.RoomSummaryUpdater import im.vector.matrix.android.internal.session.sync.SyncTokenStore import im.vector.matrix.android.internal.task.Task import im.vector.matrix.android.internal.util.awaitTransaction diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/membership/RoomDisplayNameResolver.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/membership/RoomDisplayNameResolver.kt index b124a21968..55474df2bb 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/membership/RoomDisplayNameResolver.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/membership/RoomDisplayNameResolver.kt @@ -17,7 +17,6 @@ package im.vector.matrix.android.internal.session.room.membership import android.content.Context -import com.zhuinden.monarchy.Monarchy import im.vector.matrix.android.R import im.vector.matrix.android.api.session.events.model.EventType import im.vector.matrix.android.api.session.events.model.toModel @@ -33,96 +32,92 @@ import im.vector.matrix.android.internal.database.model.RoomMemberSummaryEntityF import im.vector.matrix.android.internal.database.model.RoomSummaryEntity import im.vector.matrix.android.internal.database.query.getOrNull import im.vector.matrix.android.internal.database.query.where -import im.vector.matrix.android.internal.di.SessionDatabase import im.vector.matrix.android.internal.di.UserId +import io.realm.Realm import javax.inject.Inject /** * This class computes room display name */ internal class RoomDisplayNameResolver @Inject constructor(private val context: Context, - @SessionDatabase private val monarchy: Monarchy, @UserId private val userId: String ) { /** * Compute the room display name * + * @param realm: the current instance of realm * @param roomId: the roomId to resolve the name of. * @return the room display name */ - fun resolve(roomId: String): CharSequence { + fun resolve(realm: Realm, 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) // For Lazy Loaded room, see algorithm here: // https://docs.google.com/document/d/11i14UI1cUz-OJ0knD5BFu7fmT6Fo327zvMYqfSAR7xs/edit#heading=h.qif6pkqyjgzn - var name: CharSequence? = null - monarchy.doWithRealm { realm -> - val roomEntity = RoomEntity.where(realm, roomId = roomId).findFirst() - val roomName = CurrentStateEventEntity.getOrNull(realm, roomId, type = EventType.STATE_ROOM_NAME, stateKey = "")?.root - name = ContentMapper.map(roomName?.content).toModel()?.name - if (!name.isNullOrEmpty()) { - return@doWithRealm + var name: CharSequence? + val roomEntity = RoomEntity.where(realm, roomId = roomId).findFirst() + val roomName = CurrentStateEventEntity.getOrNull(realm, roomId, type = EventType.STATE_ROOM_NAME, stateKey = "")?.root + name = ContentMapper.map(roomName?.content).toModel()?.name + if (!name.isNullOrEmpty()) { + return name + } + val canonicalAlias = CurrentStateEventEntity.getOrNull(realm, roomId, type = EventType.STATE_ROOM_CANONICAL_ALIAS, stateKey = "")?.root + name = ContentMapper.map(canonicalAlias?.content).toModel()?.canonicalAlias + if (!name.isNullOrEmpty()) { + return name + } + + val aliases = CurrentStateEventEntity.getOrNull(realm, roomId, type = EventType.STATE_ROOM_ALIASES, stateKey = "")?.root + name = ContentMapper.map(aliases?.content).toModel()?.aliases?.firstOrNull() + if (!name.isNullOrEmpty()) { + return name + } + + val roomMembers = RoomMemberHelper(realm, roomId) + val activeMembers = roomMembers.queryActiveRoomMembersEvent().findAll() + + if (roomEntity?.membership == Membership.INVITE) { + val inviteMeEvent = roomMembers.getLastStateEvent(userId) + val inviterId = inviteMeEvent?.sender + name = if (inviterId != null) { + activeMembers.where() + .equalTo(RoomMemberSummaryEntityFields.USER_ID, inviterId) + .findFirst() + ?.displayName + } else { + context.getString(R.string.room_displayname_room_invite) } - - val canonicalAlias = CurrentStateEventEntity.getOrNull(realm, roomId, type = EventType.STATE_ROOM_CANONICAL_ALIAS, stateKey = "")?.root - name = ContentMapper.map(canonicalAlias?.content).toModel()?.canonicalAlias - if (!name.isNullOrEmpty()) { - return@doWithRealm - } - - val aliases = CurrentStateEventEntity.getOrNull(realm, roomId, type = EventType.STATE_ROOM_ALIASES, stateKey = "")?.root - name = ContentMapper.map(aliases?.content).toModel()?.aliases?.firstOrNull() - if (!name.isNullOrEmpty()) { - return@doWithRealm - } - - val roomMembers = RoomMemberHelper(realm, roomId) - val activeMembers = roomMembers.queryActiveRoomMembersEvent().findAll() - - if (roomEntity?.membership == Membership.INVITE) { - val inviteMeEvent = roomMembers.getLastStateEvent(userId) - val inviterId = inviteMeEvent?.sender - name = if (inviterId != null) { - activeMembers.where() - .equalTo(RoomMemberSummaryEntityFields.USER_ID, inviterId) - .findFirst() - ?.displayName - } else { - context.getString(R.string.room_displayname_room_invite) - } - } else if (roomEntity?.membership == Membership.JOIN) { - val roomSummary = RoomSummaryEntity.where(realm, roomId).findFirst() - val otherMembersSubset: List = if (roomSummary?.heroes?.isNotEmpty() == true) { - roomSummary.heroes.mapNotNull { userId -> - roomMembers.getLastRoomMember(userId)?.takeIf { - it.membership == Membership.INVITE || it.membership == Membership.JOIN - } + } else if (roomEntity?.membership == Membership.JOIN) { + val roomSummary = RoomSummaryEntity.where(realm, roomId).findFirst() + val otherMembersSubset: List = if (roomSummary?.heroes?.isNotEmpty() == true) { + roomSummary.heroes.mapNotNull { userId -> + roomMembers.getLastRoomMember(userId)?.takeIf { + it.membership == Membership.INVITE || it.membership == Membership.JOIN } - } else { - activeMembers.where() - .notEqualTo(RoomMemberSummaryEntityFields.USER_ID, userId) - .limit(3) - .findAll() - .createSnapshot() - } - val otherMembersCount = otherMembersSubset.count() - name = when (otherMembersCount) { - 0 -> context.getString(R.string.room_displayname_empty_room) - 1 -> resolveRoomMemberName(otherMembersSubset[0], roomMembers) - 2 -> context.getString(R.string.room_displayname_two_members, - resolveRoomMemberName(otherMembersSubset[0], roomMembers), - resolveRoomMemberName(otherMembersSubset[1], roomMembers) - ) - else -> context.resources.getQuantityString(R.plurals.room_displayname_three_and_more_members, - roomMembers.getNumberOfJoinedMembers() - 1, - resolveRoomMemberName(otherMembersSubset[0], roomMembers), - roomMembers.getNumberOfJoinedMembers() - 1) } + } else { + activeMembers.where() + .notEqualTo(RoomMemberSummaryEntityFields.USER_ID, userId) + .limit(3) + .findAll() + .createSnapshot() + } + val otherMembersCount = otherMembersSubset.count() + name = when (otherMembersCount) { + 0 -> context.getString(R.string.room_displayname_empty_room) + 1 -> resolveRoomMemberName(otherMembersSubset[0], roomMembers) + 2 -> context.getString(R.string.room_displayname_two_members, + resolveRoomMemberName(otherMembersSubset[0], roomMembers), + resolveRoomMemberName(otherMembersSubset[1], roomMembers) + ) + else -> context.resources.getQuantityString(R.plurals.room_displayname_three_and_more_members, + roomMembers.getNumberOfJoinedMembers() - 1, + resolveRoomMemberName(otherMembersSubset[0], roomMembers), + roomMembers.getNumberOfJoinedMembers() - 1) } - return@doWithRealm } return name ?: roomId } diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/read/DefaultReadService.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/read/DefaultReadService.kt index 5a0602bd9b..29331e5646 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/read/DefaultReadService.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/read/DefaultReadService.kt @@ -83,7 +83,7 @@ internal class DefaultReadService @AssistedInject constructor( } override fun isEventRead(eventId: String): Boolean { - return isEventRead(monarchy, userId, roomId, eventId) + return isEventRead(monarchy.realmConfiguration, userId, roomId, eventId) } override fun getReadMarkerLive(): LiveData> { diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/read/SetReadMarkersTask.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/read/SetReadMarkersTask.kt index dfd07cde10..9b27335287 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/read/SetReadMarkersTask.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/read/SetReadMarkersTask.kt @@ -75,7 +75,7 @@ internal class DefaultSetReadMarkersTask @Inject constructor( } else { params.readReceiptEventId } - if (fullyReadEventId != null && !isReadMarkerMoreRecent(monarchy, params.roomId, fullyReadEventId)) { + if (fullyReadEventId != null && !isReadMarkerMoreRecent(monarchy.realmConfiguration, params.roomId, fullyReadEventId)) { if (LocalEcho.isLocalEchoId(fullyReadEventId)) { Timber.w("Can't set read marker for local event $fullyReadEventId") } else { @@ -83,7 +83,7 @@ internal class DefaultSetReadMarkersTask @Inject constructor( } } if (readReceiptEventId != null - && !isEventRead(monarchy, userId, params.roomId, readReceiptEventId)) { + && !isEventRead(monarchy.realmConfiguration, userId, params.roomId, readReceiptEventId)) { if (LocalEcho.isLocalEchoId(readReceiptEventId)) { Timber.w("Can't set read receipt for local event $readReceiptEventId") } else { diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/send/LocalEchoRepository.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/send/LocalEchoRepository.kt index dac19c56fb..fbfa95b4a7 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/send/LocalEchoRepository.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/send/LocalEchoRepository.kt @@ -34,7 +34,7 @@ import im.vector.matrix.android.internal.database.model.TimelineEventEntity import im.vector.matrix.android.internal.database.query.findAllInRoomWithSendStates import im.vector.matrix.android.internal.database.query.where import im.vector.matrix.android.internal.di.SessionDatabase -import im.vector.matrix.android.internal.session.room.RoomSummaryUpdater +import im.vector.matrix.android.internal.session.room.summary.RoomSummaryUpdater import im.vector.matrix.android.internal.session.room.membership.RoomMemberHelper import im.vector.matrix.android.internal.session.room.timeline.DefaultTimeline import im.vector.matrix.android.internal.util.awaitTransaction diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/summary/RoomSummaryDataSource.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/summary/RoomSummaryDataSource.kt new file mode 100644 index 0000000000..56fc9083c6 --- /dev/null +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/summary/RoomSummaryDataSource.kt @@ -0,0 +1,109 @@ +/* + * Copyright (c) 2020 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.summary + +import androidx.lifecycle.LiveData +import androidx.lifecycle.Transformations +import com.zhuinden.monarchy.Monarchy +import im.vector.matrix.android.api.session.room.RoomSummaryQueryParams +import im.vector.matrix.android.api.session.room.model.RoomSummary +import im.vector.matrix.android.api.session.room.model.VersioningState +import im.vector.matrix.android.api.util.Optional +import im.vector.matrix.android.api.util.toOptional +import im.vector.matrix.android.internal.database.mapper.RoomSummaryMapper +import im.vector.matrix.android.internal.database.model.RoomSummaryEntity +import im.vector.matrix.android.internal.database.model.RoomSummaryEntityFields +import im.vector.matrix.android.internal.database.query.findByAlias +import im.vector.matrix.android.internal.database.query.where +import im.vector.matrix.android.internal.di.SessionDatabase +import im.vector.matrix.android.internal.query.process +import im.vector.matrix.android.internal.util.fetchCopyMap +import io.realm.Realm +import io.realm.RealmQuery +import javax.inject.Inject + +internal class RoomSummaryDataSource @Inject constructor(@SessionDatabase private val monarchy: Monarchy, + private val roomSummaryMapper: RoomSummaryMapper) { + + fun getRoomSummary(roomIdOrAlias: String): RoomSummary? { + return monarchy + .fetchCopyMap({ + if (roomIdOrAlias.startsWith("!")) { + // It's a roomId + RoomSummaryEntity.where(it, roomId = roomIdOrAlias).findFirst() + } else { + // Assume it's a room alias + RoomSummaryEntity.findByAlias(it, roomIdOrAlias) + } + }, { entity, _ -> + roomSummaryMapper.map(entity) + }) + } + + fun getRoomSummaryLive(roomId: String): LiveData>{ + val liveData = monarchy.findAllMappedWithChanges( + { realm -> RoomSummaryEntity.where(realm, roomId).isNotEmpty(RoomSummaryEntityFields.DISPLAY_NAME) }, + { roomSummaryMapper.map(it) } + ) + return Transformations.map(liveData) { results -> + results.firstOrNull().toOptional() + } + } + + fun getRoomSummaries(queryParams: RoomSummaryQueryParams): List { + return monarchy.fetchAllMappedSync( + { roomSummariesQuery(it, queryParams) }, + { roomSummaryMapper.map(it) } + ) + } + + fun getRoomSummariesLive(queryParams: RoomSummaryQueryParams): LiveData> { + return monarchy.findAllMappedWithChanges( + { roomSummariesQuery(it, queryParams) }, + { roomSummaryMapper.map(it) } + ) + } + + fun getBreadcrumbs(queryParams: RoomSummaryQueryParams): List { + return monarchy.fetchAllMappedSync( + { breadcrumbsQuery(it, queryParams) }, + { roomSummaryMapper.map(it) } + ) + } + + fun getBreadcrumbsLive(queryParams: RoomSummaryQueryParams): LiveData> { + return monarchy.findAllMappedWithChanges( + { breadcrumbsQuery(it, queryParams) }, + { roomSummaryMapper.map(it) } + ) + } + + private fun breadcrumbsQuery(realm: Realm, queryParams: RoomSummaryQueryParams): RealmQuery { + return roomSummariesQuery(realm, queryParams) + .greaterThan(RoomSummaryEntityFields.BREADCRUMBS_INDEX, RoomSummary.NOT_IN_BREADCRUMBS) + .sort(RoomSummaryEntityFields.BREADCRUMBS_INDEX) + } + + private fun roomSummariesQuery(realm: Realm, queryParams: RoomSummaryQueryParams): RealmQuery { + val query = RoomSummaryEntity.where(realm) + query.process(RoomSummaryEntityFields.DISPLAY_NAME, queryParams.displayName) + query.process(RoomSummaryEntityFields.CANONICAL_ALIAS, queryParams.canonicalAlias) + query.process(RoomSummaryEntityFields.MEMBERSHIP_STR, queryParams.memberships) + query.notEqualTo(RoomSummaryEntityFields.VERSIONING_STATE_STR, VersioningState.UPGRADED_ROOM_JOINED.name) + return query + } +} 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/summary/RoomSummaryUpdater.kt similarity index 94% rename from matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/RoomSummaryUpdater.kt rename to matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/summary/RoomSummaryUpdater.kt index 55594a6c1c..82b2cf3658 100644 --- 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/summary/RoomSummaryUpdater.kt @@ -14,9 +14,8 @@ * limitations under the License. */ -package im.vector.matrix.android.internal.session.room +package im.vector.matrix.android.internal.session.room.summary -import com.zhuinden.monarchy.Monarchy import dagger.Lazy import im.vector.matrix.android.api.crypto.RoomEncryptionTrustLevel import im.vector.matrix.android.api.session.events.model.EventType @@ -39,12 +38,11 @@ import im.vector.matrix.android.internal.database.query.getOrNull import im.vector.matrix.android.internal.database.query.isEventRead import im.vector.matrix.android.internal.database.query.latestEvent import im.vector.matrix.android.internal.database.query.whereType -import im.vector.matrix.android.internal.di.SessionDatabase import im.vector.matrix.android.internal.di.UserId +import im.vector.matrix.android.internal.session.room.RoomAvatarResolver import im.vector.matrix.android.internal.session.room.membership.RoomDisplayNameResolver import im.vector.matrix.android.internal.session.room.membership.RoomMemberHelper import im.vector.matrix.android.internal.session.room.timeline.TimelineEventDecryptor -import im.vector.matrix.android.internal.session.sync.RoomSyncHandler import im.vector.matrix.android.internal.session.sync.model.RoomSyncSummary import im.vector.matrix.android.internal.session.sync.model.RoomSyncUnreadNotifications import io.realm.Realm @@ -57,8 +55,7 @@ internal class RoomSummaryUpdater @Inject constructor( private val roomDisplayNameResolver: RoomDisplayNameResolver, private val roomAvatarResolver: RoomAvatarResolver, private val timelineEventDecryptor: Lazy, - private val eventBus: EventBus, - @SessionDatabase private val monarchy: Monarchy) { + private val eventBus: EventBus) { companion object { // TODO: maybe allow user of SDK to give that list @@ -121,17 +118,17 @@ internal class RoomSummaryUpdater @Inject constructor( roomSummaryEntity.hasUnreadMessages = roomSummaryEntity.notificationCount > 0 // avoid this call if we are sure there are unread events - || !isEventRead(monarchy, userId, roomId, latestPreviewableEvent?.eventId) + || !isEventRead(realm.configuration, userId, roomId, latestPreviewableEvent?.eventId) - roomSummaryEntity.displayName = roomDisplayNameResolver.resolve(roomId).toString() - roomSummaryEntity.avatarUrl = roomAvatarResolver.resolve(roomId) + roomSummaryEntity.displayName = roomDisplayNameResolver.resolve(realm, roomId).toString() + roomSummaryEntity.avatarUrl = roomAvatarResolver.resolve(realm, roomId) roomSummaryEntity.topic = ContentMapper.map(lastTopicEvent?.content).toModel()?.topic roomSummaryEntity.latestPreviewableEvent = latestPreviewableEvent roomSummaryEntity.canonicalAlias = ContentMapper.map(lastCanonicalAliasEvent?.content).toModel() ?.canonicalAlias val roomAliases = ContentMapper.map(lastAliasesEvent?.content).toModel()?.aliases - .orEmpty() + .orEmpty() roomSummaryEntity.aliases.clear() roomSummaryEntity.aliases.addAll(roomAliases) roomSummaryEntity.flatAliases = roomAliases.joinToString(separator = "|", prefix = "|") 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 0b4729aa6d..f6a65457d5 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 @@ -21,8 +21,11 @@ import im.vector.matrix.android.api.extensions.orFalse import im.vector.matrix.android.api.session.events.model.EventType import im.vector.matrix.android.api.session.events.model.RelationType import im.vector.matrix.android.api.session.events.model.toModel +import im.vector.matrix.android.api.session.room.model.EventAnnotationsSummary +import im.vector.matrix.android.api.session.room.model.ReactionAggregatedSummary import im.vector.matrix.android.api.session.room.model.ReadReceipt import im.vector.matrix.android.api.session.room.model.message.MessageContent +import im.vector.matrix.android.api.session.room.model.relation.ReactionContent import im.vector.matrix.android.api.session.room.send.SendState import im.vector.matrix.android.api.session.room.timeline.Timeline import im.vector.matrix.android.api.session.room.timeline.TimelineEvent @@ -341,6 +344,7 @@ internal class DefaultTimeline( listeners.forEach { it.onNewTimelineEvents(listOf(onLocalEchoCreated.timelineEvent.eventId)) } + Timber.v("On local echo created: $onLocalEchoCreated") inMemorySendingEvents.add(0, onLocalEchoCreated.timelineEvent) postSnapshot() } 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 ea6f7e3d23..1756c948b0 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 @@ -40,7 +40,7 @@ import im.vector.matrix.android.internal.database.query.getOrCreate import im.vector.matrix.android.internal.database.query.latestEvent import im.vector.matrix.android.internal.database.query.where import im.vector.matrix.android.internal.di.SessionDatabase -import im.vector.matrix.android.internal.session.room.RoomSummaryUpdater +import im.vector.matrix.android.internal.session.room.summary.RoomSummaryUpdater import im.vector.matrix.android.internal.util.awaitTransaction import io.realm.Realm import timber.log.Timber 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 6dd655e267..b2fdf6045d 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 @@ -46,7 +46,7 @@ import im.vector.matrix.android.internal.di.MoshiProvider import im.vector.matrix.android.internal.di.UserId import im.vector.matrix.android.internal.session.DefaultInitialSyncProgressService import im.vector.matrix.android.internal.session.mapWithProgress -import im.vector.matrix.android.internal.session.room.RoomSummaryUpdater +import im.vector.matrix.android.internal.session.room.summary.RoomSummaryUpdater import im.vector.matrix.android.internal.session.room.membership.RoomMemberEventHandler import im.vector.matrix.android.internal.session.room.read.FullyReadContent import im.vector.matrix.android.internal.session.room.timeline.DefaultTimeline 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 579f4fb0e1..b4c29be4da 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 @@ -69,7 +69,6 @@ internal class SyncResponseHandler @Inject constructor(@SessionDatabase private }.also { Timber.v("Finish handling toDevice in $it ms") } - // Start one big transaction monarchy.awaitTransaction { realm -> measureTimeMillis { @@ -104,7 +103,6 @@ internal class SyncResponseHandler @Inject constructor(@SessionDatabase private } tokenStore.saveToken(realm, syncResponse.nextBatch) } - // Everything else we need to do outside the transaction syncResponse.rooms?.also { checkPushRules(it, isInitialSync)