diff --git a/matrix-sdk-android/build.gradle b/matrix-sdk-android/build.gradle index 3eaf43eb..b62b3fea 100644 --- a/matrix-sdk-android/build.gradle +++ b/matrix-sdk-android/build.gradle @@ -99,14 +99,14 @@ dependencies { implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:$coroutines_version" implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:$coroutines_version" - implementation "androidx.appcompat:appcompat:1.1.0-beta01" - implementation "androidx.recyclerview:recyclerview:1.1.0-alpha06" + implementation "androidx.appcompat:appcompat:1.1.0-rc01" + implementation "androidx.recyclerview:recyclerview:1.1.0-beta01" implementation "androidx.lifecycle:lifecycle-extensions:$lifecycle_version" kapt "androidx.lifecycle:lifecycle-compiler:$lifecycle_version" // Network - implementation 'com.squareup.retrofit2:retrofit:2.4.0' + implementation 'com.squareup.retrofit2:retrofit:2.6.0' implementation 'com.squareup.retrofit2:converter-moshi:2.4.0' implementation 'com.squareup.okhttp3:okhttp:3.14.1' implementation 'com.squareup.okhttp3:logging-interceptor:3.10.0' 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 70615293..3bda568d 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,7 +16,6 @@ package im.vector.matrix.android.internal.database.helper -import androidx.annotation.VisibleForTesting 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 @@ -103,7 +102,6 @@ internal fun ChunkEntity.updateSenderDataFor(eventIds: List) { } } -@VisibleForTesting internal fun ChunkEntity.add(roomId: String, event: Event, direction: PaginationDirection, @@ -134,7 +132,7 @@ internal fun ChunkEntity.add(roomId: String, } } - val localId = TimelineEventEntity.nextId(realm) + val localId = TimelineEventEntity.nextId(realm) val eventEntity = TimelineEventEntity(localId).also { it.root = event.toEntity(roomId).apply { this.stateIndex = currentStateIndex 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 01d95eb2..948af2af 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 @@ -37,25 +37,22 @@ internal fun RoomEntity.addOrUpdate(chunkEntity: ChunkEntity) { } } -internal fun RoomEntity.addStateEvents(stateEvents: List, - stateIndex: Int = Int.MIN_VALUE, - filterDuplicates: Boolean = false, - isUnlinked: Boolean = false) { +internal fun RoomEntity.addStateEvent(stateEvent: Event, + stateIndex: Int = Int.MIN_VALUE, + filterDuplicates: Boolean = false, + isUnlinked: Boolean = false) { assertIsManaged() - - stateEvents.forEach { event -> - if (event.eventId == null || (filterDuplicates && fastContains(event.eventId))) { - return@forEach - } - val eventEntity = event.toEntity(roomId).apply { + if (stateEvent.eventId == null || (filterDuplicates && fastContains(stateEvent.eventId))) { + return + } else { + val entity = stateEvent.toEntity(roomId).apply { this.stateIndex = stateIndex this.isUnlinked = isUnlinked this.sendState = SendState.SYNCED } - untimelinedStateEvents.add(0, eventEntity) + untimelinedStateEvents.add(entity) } } - internal fun RoomEntity.addSendingEvent(event: Event) { assertIsManaged() val senderId = event.senderId ?: return @@ -64,7 +61,7 @@ internal fun RoomEntity.addSendingEvent(event: Event) { } val roomMembers = RoomMembers(realm, roomId) val myUser = roomMembers.get(senderId) - val localId = TimelineEventEntity.nextId(realm) + val localId = TimelineEventEntity.nextId(realm) val timelineEventEntity = TimelineEventEntity(localId).also { it.root = eventEntity it.eventId = event.eventId ?: "" diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/model/TimelineEventEntity.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/model/TimelineEventEntity.kt index c811ece1..a1e58c90 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/model/TimelineEventEntity.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/model/TimelineEventEntity.kt @@ -20,8 +20,6 @@ import io.realm.RealmObject import io.realm.RealmResults import io.realm.annotations.Index import io.realm.annotations.LinkingObjects -import io.realm.annotations.PrimaryKey -import java.util.* internal open class TimelineEventEntity(var localId: Long = 0, diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/network/Request.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/network/Request.kt index bbd5859b..4dfc5810 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/network/Request.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/network/Request.kt @@ -19,21 +19,15 @@ package im.vector.matrix.android.internal.network import arrow.core.Try import arrow.core.failure import arrow.core.recoverWith -import arrow.effects.IO -import arrow.effects.fix -import arrow.effects.instances.io.async.async -import arrow.integrations.retrofit.adapter.runAsync import com.squareup.moshi.JsonDataException import com.squareup.moshi.Moshi import im.vector.matrix.android.api.failure.Failure import im.vector.matrix.android.api.failure.MatrixError import im.vector.matrix.android.internal.di.MoshiProvider -import kotlinx.coroutines.suspendCancellableCoroutine import okhttp3.ResponseBody import retrofit2.Call import timber.log.Timber import java.io.IOException -import kotlin.coroutines.resume internal suspend inline fun executeRequest(block: Request.() -> Unit) = Request().apply(block).execute() @@ -43,30 +37,22 @@ internal class Request { lateinit var apiCall: Call suspend fun execute(): Try { - return suspendCancellableCoroutine { continuation -> - continuation.invokeOnCancellation { - Timber.v("Request is canceled") - apiCall.cancel() + return Try { + val response = apiCall.awaitResponse() + if (response.isSuccessful) { + response.body() + ?: throw IllegalStateException("The request returned a null body") + } else { + throw manageFailure(response.errorBody(), response.code()) } - val result = Try { - val response = apiCall.runAsync(IO.async()).fix().unsafeRunSync() - if (response.isSuccessful) { - response.body() - ?: throw IllegalStateException("The request returned a null body") - } else { - throw manageFailure(response.errorBody(), response.code()) - } - }.recoverWith { - when (it) { - is IOException -> Failure.NetworkConnection(it) - is Failure.ServerError, - is Failure.OtherServerError -> it - else -> Failure.Unknown(it) - }.failure() - } - continuation.resume(result) + }.recoverWith { + when (it) { + is IOException -> Failure.NetworkConnection(it) + is Failure.ServerError, + is Failure.OtherServerError -> it + else -> Failure.Unknown(it) + }.failure() } - } private fun manageFailure(errorBody: ResponseBody?, httpCode: Int): Throwable { diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/network/RetrofitExtensions.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/network/RetrofitExtensions.kt new file mode 100644 index 00000000..7528dee2 --- /dev/null +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/network/RetrofitExtensions.kt @@ -0,0 +1,41 @@ +/* + * + * * 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.network + +import kotlinx.coroutines.suspendCancellableCoroutine +import retrofit2.* +import kotlin.coroutines.resume +import kotlin.coroutines.resumeWithException + +suspend fun Call.awaitResponse(): Response { + return suspendCancellableCoroutine { continuation -> + continuation.invokeOnCancellation { + cancel() + } + enqueue(object : Callback { + override fun onResponse(call: Call, response: Response) { + continuation.resume(response) + } + + override fun onFailure(call: Call, t: Throwable) { + continuation.resumeWithException(t) + } + }) + } +} \ No newline at end of file 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 d1673bfe..f2e61e8c 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 @@ -38,7 +38,6 @@ import im.vector.matrix.android.internal.network.RetrofitFactory import im.vector.matrix.android.internal.session.group.GroupSummaryUpdater import im.vector.matrix.android.internal.session.room.EventRelationsAggregationUpdater import im.vector.matrix.android.internal.session.room.prune.EventsPruner -import im.vector.matrix.android.internal.session.user.UserEntityUpdater import im.vector.matrix.android.internal.util.md5 import io.realm.RealmConfiguration import okhttp3.OkHttpClient @@ -129,10 +128,6 @@ internal abstract class SessionModule { @IntoSet abstract fun bindEventRelationsAggregationUpdater(groupSummaryUpdater: EventRelationsAggregationUpdater): LiveEntityObserver - @Binds - @IntoSet - abstract fun bindUserEntityUpdater(groupSummaryUpdater: UserEntityUpdater): LiveEntityObserver - @Binds abstract fun bindInitialSyncProgressService(initialSyncProgressService: DefaultInitialSyncProgressService): InitialSyncProgressService 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 3ed2fa43..9161fb25 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 @@ -20,14 +20,13 @@ 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.Membership import im.vector.matrix.android.api.session.room.model.RoomAvatarContent +import im.vector.matrix.android.api.session.room.model.RoomMember 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.EventEntityFields 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.SessionScope import im.vector.matrix.android.internal.session.room.membership.RoomMembers import javax.inject.Inject @@ -42,32 +41,25 @@ internal class RoomAvatarResolver @Inject constructor(private val monarchy: Mona fun resolve(roomId: String): String? { var res: String? = null monarchy.doWithRealm { realm -> - val roomEntity = RoomEntity.where(realm, roomId).findFirst() val roomName = EventEntity.where(realm, roomId, EventType.STATE_ROOM_AVATAR).prev()?.asDomain() res = roomName?.content.toModel()?.avatarUrl if (!res.isNullOrEmpty()) { return@doWithRealm } val roomMembers = RoomMembers(realm, roomId) - val members = roomMembers.getLoaded() - if (roomEntity?.membership == Membership.INVITE) { - if (members.size == 1) { - res = members.entries.first().value.avatarUrl - } else if (members.size > 1) { - val firstOtherMember = members.filterKeys { it != credentials.userId }.values.firstOrNull() - res = firstOtherMember?.avatarUrl - } - } else { - // 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.entries.first().value.avatarUrl - } else if (members.size == 2) { - val firstOtherMember = members.filterKeys { it != credentials.userId }.values.firstOrNull() - res = firstOtherMember?.avatarUrl - } + val members = roomMembers.queryRoomMembersEvent().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()?.toRoomMember()?.avatarUrl + } else if (members.size == 2) { + val firstOtherMember = members.where().notEqualTo(EventEntityFields.STATE_KEY, credentials.userId).findFirst() + res = firstOtherMember?.toRoomMember()?.avatarUrl } - } return res } + + private fun EventEntity?.toRoomMember(): RoomMember? { + return this?.asDomain()?.content?.toModel() + } } 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 index 8fdb5fe9..6bcac9b8 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/RoomSummaryUpdater.kt @@ -23,6 +23,7 @@ import im.vector.matrix.android.api.session.room.model.Membership import im.vector.matrix.android.api.session.room.model.RoomTopicContent 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.EventEntityFields import im.vector.matrix.android.internal.database.model.RoomSummaryEntity import im.vector.matrix.android.internal.database.model.TimelineEventEntity import im.vector.matrix.android.internal.database.query.latestEvent @@ -86,12 +87,20 @@ internal class RoomSummaryUpdater @Inject constructor(private val credentials: C val latestEvent = TimelineEventEntity.latestEvent(realm, roomId, includedTypes = PREVIEWABLE_TYPES) val lastTopicEvent = EventEntity.where(realm, roomId, EventType.STATE_ROOM_TOPIC).prev()?.asDomain() - val otherRoomMembers = RoomMembers(realm, roomId).getLoaded().filterKeys { it != credentials.userId } + + val otherRoomMembers = RoomMembers(realm, roomId) + .queryRoomMembersEvent() + .notEqualTo(EventEntityFields.STATE_KEY, credentials.userId) + .findAll() + .asSequence() + .map { it.stateKey } + roomSummaryEntity.displayName = roomDisplayNameResolver.resolve(roomId).toString() roomSummaryEntity.avatarUrl = roomAvatarResolver.resolve(roomId) roomSummaryEntity.topic = lastTopicEvent?.content.toModel()?.topic roomSummaryEntity.latestEvent = latestEvent roomSummaryEntity.otherMemberIds.clear() - roomSummaryEntity.otherMemberIds.addAll(otherRoomMembers.keys) + roomSummaryEntity.otherMemberIds.addAll(otherRoomMembers) + } } \ No newline at end of file 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 d98436a7..a3090605 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 @@ -17,9 +17,10 @@ package im.vector.matrix.android.internal.session.room.membership import arrow.core.Try +import com.squareup.moshi.JsonReader import com.zhuinden.monarchy.Monarchy import im.vector.matrix.android.api.session.room.model.Membership -import im.vector.matrix.android.internal.database.helper.addStateEvents +import im.vector.matrix.android.internal.database.helper.addStateEvent import im.vector.matrix.android.internal.database.helper.updateSenderData import im.vector.matrix.android.internal.database.model.RoomEntity import im.vector.matrix.android.internal.database.query.where @@ -27,10 +28,13 @@ 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.sync.SyncTokenStore +import im.vector.matrix.android.internal.session.user.UserEntityFactory import im.vector.matrix.android.internal.task.Task import im.vector.matrix.android.internal.util.tryTransactionSync import io.realm.Realm import io.realm.kotlin.createObject +import okhttp3.ResponseBody +import okio.Okio import javax.inject.Inject internal interface LoadRoomMembersTask : Task { @@ -60,23 +64,26 @@ internal class DefaultLoadRoomMembersTask @Inject constructor(private val roomAP } } - private fun insertInDb(response: RoomMembersResponse, roomId: String): Try { + private fun insertInDb(response: RoomMembersResponse, roomId: String): Try { return monarchy .tryTransactionSync { realm -> // We ignore all the already known members val roomEntity = RoomEntity.where(realm, roomId).findFirst() - ?: realm.createObject(roomId) + ?: realm.createObject(roomId) - val roomMembers = RoomMembers(realm, roomId).getLoaded() - val eventsToInsert = response.roomMemberEvents.filter { !roomMembers.containsKey(it.stateKey) } - roomEntity.addStateEvents(eventsToInsert) + + for (roomMemberEvent in response.roomMemberEvents) { + roomEntity.addStateEvent(roomMemberEvent) + UserEntityFactory.createOrNull(roomMemberEvent)?.also { + realm.insertOrUpdate(it) + } + } roomEntity.chunks.flatMap { it.timelineEvents }.forEach { it.updateSenderData() } roomEntity.areAllMembersLoaded = true roomSummaryUpdater.update(realm, roomId) } - .map { response } } private fun areAllMembersAlreadyLoaded(roomId: String): Boolean { @@ -85,4 +92,4 @@ internal class DefaultLoadRoomMembersTask @Inject constructor(private val roomAP } } -} \ No newline at end of file +} 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 01ae4394..c27b0a74 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 @@ -25,13 +25,16 @@ import im.vector.matrix.android.api.session.events.model.toModel import im.vector.matrix.android.api.session.room.model.Membership import im.vector.matrix.android.api.session.room.model.RoomAliasesContent import im.vector.matrix.android.api.session.room.model.RoomCanonicalAliasContent +import im.vector.matrix.android.api.session.room.model.RoomMember import im.vector.matrix.android.api.session.room.model.RoomNameContent 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.EventEntityFields 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.prev import im.vector.matrix.android.internal.database.query.where +import io.realm.RealmResults import javax.inject.Inject /** @@ -39,7 +42,6 @@ import javax.inject.Inject */ internal class RoomDisplayNameResolver @Inject constructor(private val context: Context, private val monarchy: Monarchy, - private val roomMemberDisplayNameResolver: RoomMemberDisplayNameResolver, private val credentials: Credentials ) { @@ -78,48 +80,59 @@ internal class RoomDisplayNameResolver @Inject constructor(private val context: } val roomMembers = RoomMembers(realm, roomId) - val loadedMembers = roomMembers.getLoaded() - val otherRoomMembers = loadedMembers.filterKeys { it != credentials.userId } + val loadedMembers = roomMembers.queryRoomMembersEvent().findAll() + val otherMembersSubset = loadedMembers.where() + .notEqualTo(EventEntityFields.STATE_KEY, credentials.userId) + .limit(3) + .findAll() + if (roomEntity?.membership == Membership.INVITE) { val inviteMeEvent = roomMembers.queryRoomMemberEvent(credentials.userId).findFirst() val inviterId = inviteMeEvent?.sender - name = if (inviterId != null && otherRoomMembers.containsKey(inviterId)) { - roomMemberDisplayNameResolver.resolve(inviterId, otherRoomMembers) + name = if (inviterId != null) { + val inviterMemberEvent = loadedMembers.where().equalTo(EventEntityFields.STATE_KEY, inviterId).findFirst() + inviterMemberEvent?.toRoomMember()?.displayName } else { context.getString(R.string.room_displayname_room_invite) } } else { val roomSummary = RoomSummaryEntity.where(realm, roomId).findFirst() - val memberIds = if (roomSummary?.heroes?.isNotEmpty() == true) { + val memberIds: List = if (roomSummary?.heroes?.isNotEmpty() == true) { roomSummary.heroes } else { - otherRoomMembers.keys.toList() + otherMembersSubset.mapNotNull { it.stateKey } } - - val nbOfOtherMembers = memberIds.size - - when (nbOfOtherMembers) { - 0 -> name = context.getString(R.string.room_displayname_empty_room) - 1 -> name = roomMemberDisplayNameResolver.resolve(memberIds[0], otherRoomMembers) - 2 -> { - 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) - ) - } - 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) - } + name = when (memberIds.size) { + 0 -> context.getString(R.string.room_displayname_empty_room) + 1 -> resolveRoomMember(otherMembersSubset[0], roomMembers) + 2 -> context.getString(R.string.room_displayname_two_members, + resolveRoomMember(otherMembersSubset[0], roomMembers), + resolveRoomMember(otherMembersSubset[1], roomMembers) + ) + else -> context.resources.getQuantityString(R.plurals.room_displayname_three_and_more_members, + roomMembers.getNumberOfJoinedMembers() - 1, + resolveRoomMember(otherMembersSubset[0], roomMembers), + roomMembers.getNumberOfJoinedMembers() - 1) } } return@doWithRealm } return name ?: roomId } + + private fun resolveRoomMember(eventEntity: EventEntity?, + roomMembers: RoomMembers): String? { + if (eventEntity == null) return null + val roomMember = eventEntity.toRoomMember() ?: return null + val isUnique = roomMembers.isUniqueDisplayName(roomMember.displayName) + return if (isUnique) { + roomMember.displayName + } else { + "${roomMember.displayName} ( ${eventEntity.stateKey} )" + } + } + + private fun EventEntity?.toRoomMember(): RoomMember? { + return this?.asDomain()?.content?.toModel() + } } diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/membership/RoomMemberDisplayNameResolver.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/membership/RoomMemberDisplayNameResolver.kt deleted file mode 100644 index 5d64a632..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/membership/RoomMemberDisplayNameResolver.kt +++ /dev/null @@ -1,54 +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 - -import im.vector.matrix.android.api.session.room.model.RoomMember -import javax.inject.Inject - -internal class RoomMemberDisplayNameResolver @Inject constructor() { - - fun resolve(userId: String, members: Map): String? { - val currentMember = members[userId] - var displayName = currentMember?.displayName - // Get the user display name from the member list of the room - // Do not consider null display name - - if (currentMember != null && !currentMember.displayName.isNullOrEmpty()) { - val hasNameCollision = members - .filterValues { it != currentMember && it.displayName == currentMember.displayName } - .isNotEmpty() - if (hasNameCollision) { - displayName = "${currentMember.displayName} ( $userId )" - } - } - - // TODO handle invited users - /*else if (null != member && TextUtils.equals(member!!.membership, RoomMember.MEMBERSHIP_INVITE)) { - val user = (mDataHandler as MXDataHandler).getUser(userId) - if (null != user) { - displayName = user!!.displayname - } - } - */ - if (displayName == null) { - // By default, use the user ID - displayName = userId - } - return displayName - } - -} \ No newline at end of file diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/membership/RoomMembers.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/membership/RoomMembers.kt index 72b2695e..fb8326f2 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/membership/RoomMembers.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/membership/RoomMembers.kt @@ -33,6 +33,7 @@ import io.realm.Sort * This class is an helper around STATE_ROOM_MEMBER events. * It allows to get the live membership of a user. */ + internal class RoomMembers(private val realm: Realm, private val roomId: String ) { @@ -72,27 +73,27 @@ internal class RoomMembers(private val realm: Realm, .isNotNull(EventEntityFields.CONTENT) } + fun queryJoinedRoomMembersEvent(): RealmQuery { + return queryRoomMembersEvent().contains(EventEntityFields.CONTENT, "\"membership\":\"join\"") + } + + fun queryInvitedRoomMembersEvent(): RealmQuery { + return queryRoomMembersEvent().contains(EventEntityFields.CONTENT, "\"membership\":\"invite\"") + } + fun queryRoomMemberEvent(userId: String): RealmQuery { return queryRoomMembersEvent() .equalTo(EventEntityFields.STATE_KEY, userId) } - fun getLoaded(): Map { - return queryRoomMembersEvent() - .findAll() - .map { it.asDomain() } - .associateBy { it.stateKey!! } - .mapValues { it.value.content.toModel()!! } - } - fun getNumberOfJoinedMembers(): Int { return roomSummary?.joinedMembersCount - ?: getLoaded().filterValues { it.membership == Membership.JOIN }.size + ?: queryJoinedRoomMembersEvent().findAll().size } fun getNumberOfInvitedMembers(): Int { return roomSummary?.invitedMembersCount - ?: getLoaded().filterValues { it.membership == Membership.INVITE }.size + ?: queryInvitedRoomMembersEvent().findAll().size } fun getNumberOfMembers(): Int { @@ -133,4 +134,4 @@ internal class RoomMembers(private val realm: Realm, .toList() } -} \ No newline at end of file +} 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 87f78224..e1a8bdd7 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 @@ -43,7 +43,7 @@ import kotlin.collections.ArrayList import kotlin.collections.HashMap -private const val INITIAL_LOAD_SIZE = 10 +private const val INITIAL_LOAD_SIZE = 30 private const val MIN_FETCHING_COUNT = 30 private const val DISPLAY_INDEX_UNKNOWN = Int.MIN_VALUE 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 ae60969b..fb8b6271 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 @@ -18,18 +18,14 @@ package im.vector.matrix.android.internal.session.room.timeline import arrow.core.Try import com.zhuinden.monarchy.Monarchy -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.deleteOnCascade -import im.vector.matrix.android.internal.database.helper.isUnlinked -import im.vector.matrix.android.internal.database.helper.merge +import im.vector.matrix.android.internal.database.helper.* import im.vector.matrix.android.internal.database.model.ChunkEntity import im.vector.matrix.android.internal.database.model.RoomEntity import im.vector.matrix.android.internal.database.query.create import im.vector.matrix.android.internal.database.query.find import im.vector.matrix.android.internal.database.query.findAllIncludingEvents import im.vector.matrix.android.internal.database.query.where +import im.vector.matrix.android.internal.session.user.UserEntityFactory import im.vector.matrix.android.internal.util.tryTransactionSync import io.realm.kotlin.createObject import timber.log.Timber @@ -117,7 +113,7 @@ internal class TokenChunkEventPersistor @Inject constructor(private val monarchy Timber.v("Start persisting ${receivedChunk.events.size} events in $roomId towards $direction") val roomEntity = RoomEntity.where(realm, roomId).findFirst() - ?: realm.createObject(roomId) + ?: realm.createObject(roomId) val nextToken: String? val prevToken: String? @@ -146,15 +142,21 @@ internal class TokenChunkEventPersistor @Inject constructor(private val monarchy } else { nextChunk?.apply { this.prevToken = prevToken } } - ?: ChunkEntity.create(realm, prevToken, nextToken) + ?: ChunkEntity.create(realm, prevToken, nextToken) if (receivedChunk.events.isEmpty() && receivedChunk.end == receivedChunk.start) { Timber.v("Reach end of $roomId") currentChunk.isLastBackward = true } else { Timber.v("Add ${receivedChunk.events.size} events in chunk(${currentChunk.nextToken} | ${currentChunk.prevToken}") - currentChunk.addAll(roomId, receivedChunk.events, direction, isUnlinked = currentChunk.isUnlinked()) - + val eventIds = ArrayList(receivedChunk.events.size) + for (event in receivedChunk.events) { + event.eventId?.also { eventIds.add(it) } + currentChunk.add(roomId, event, direction, isUnlinked = currentChunk.isUnlinked()) + UserEntityFactory.createOrNull(event)?.also { + realm.insertOrUpdate(it) + } + } // Then we merge chunks if needed if (currentChunk != prevChunk && prevChunk != null) { currentChunk = handleMerge(roomEntity, direction, currentChunk, prevChunk) @@ -170,7 +172,13 @@ internal class TokenChunkEventPersistor @Inject constructor(private val monarchy } } roomEntity.addOrUpdate(currentChunk) - roomEntity.addStateEvents(receivedChunk.stateEvents, isUnlinked = currentChunk.isUnlinked()) + for (stateEvent in receivedChunk.stateEvents) { + roomEntity.addStateEvent(stateEvent, isUnlinked = currentChunk.isUnlinked()) + UserEntityFactory.createOrNull(stateEvent)?.also { + realm.insertOrUpdate(it) + } + } + currentChunk.updateSenderDataFor(eventIds) } } .map { 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 bdf81064..215321bd 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 @@ -24,12 +24,11 @@ import im.vector.matrix.android.api.session.events.model.toModel import im.vector.matrix.android.api.session.room.model.Membership import im.vector.matrix.android.api.session.room.model.tag.RoomTagContent import im.vector.matrix.android.internal.crypto.CryptoManager -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.helper.* import im.vector.matrix.android.internal.database.model.ChunkEntity +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.UserEntity import im.vector.matrix.android.internal.database.query.find import im.vector.matrix.android.internal.database.query.findLastLiveChunkFromRoom import im.vector.matrix.android.internal.database.query.where @@ -40,6 +39,7 @@ import im.vector.matrix.android.internal.session.notification.ProcessEventForPus import im.vector.matrix.android.internal.session.room.RoomSummaryUpdater import im.vector.matrix.android.internal.session.room.timeline.PaginationDirection import im.vector.matrix.android.internal.session.sync.model.* +import im.vector.matrix.android.internal.session.user.UserEntityFactory import im.vector.matrix.android.internal.task.TaskExecutor import im.vector.matrix.android.internal.task.configureWith import io.realm.Realm @@ -125,51 +125,31 @@ internal class RoomSyncHandler @Inject constructor(private val monarchy: Monarch } roomEntity.membership = Membership.JOIN - val lastChunk = ChunkEntity.findLastLiveChunkFromRoom(realm, roomId) - val isInitialSync = lastChunk == null - val lastStateIndex = lastChunk?.lastStateIndex(PaginationDirection.FORWARDS) ?: 0 - val numberOfStateEvents = roomSync.state?.events?.size ?: 0 - val stateIndexOffset = lastStateIndex + numberOfStateEvents - // State event if (roomSync.state != null && roomSync.state.events.isNotEmpty()) { - val untimelinedStateIndex = if (isInitialSync) Int.MIN_VALUE else stateIndexOffset - roomEntity.addStateEvents(roomSync.state.events, filterDuplicates = true, stateIndex = untimelinedStateIndex) - - // Give info to crypto module - roomSync.state.events.forEach { - cryptoManager.onStateEvent(roomId, it) + val minStateIndex = roomEntity.untimelinedStateEvents.where().min(EventEntityFields.STATE_INDEX)?.toInt() + ?: Int.MIN_VALUE + val untimelinedStateIndex = minStateIndex + 1 + roomSync.state.events.forEach { event -> + roomEntity.addStateEvent(event, filterDuplicates = true, stateIndex = untimelinedStateIndex) + // Give info to crypto module + cryptoManager.onStateEvent(roomId, event) + UserEntityFactory.createOrNull(event)?.also { + realm.insertOrUpdate(it) + } } } if (roomSync.timeline != null && roomSync.timeline.events.isNotEmpty()) { - val timelineStateOffset = if (isInitialSync || roomSync.timeline.limited.not()) 0 else stateIndexOffset val chunkEntity = handleTimelineEvents( realm, - roomId, + roomEntity, roomSync.timeline.events, roomSync.timeline.prevToken, roomSync.timeline.limited, - timelineStateOffset + 0 ) roomEntity.addOrUpdate(chunkEntity) - - // Give info to crypto module - roomSync.timeline.events.forEach { - cryptoManager.onLiveEvent(roomId, it) - } - - // Try to remove local echo - val transactionIds = roomSync.timeline.events.mapNotNull { it.unsignedData?.transactionId } - transactionIds.forEach { - val sendingEventEntity = roomEntity.sendingTimelineEvents.find(it) - if (sendingEventEntity != null) { - Timber.v("Remove local echo for tx:$it") - roomEntity.sendingTimelineEvents.remove(sendingEventEntity) - } else { - Timber.v("Can't find corresponding local echo for tx:$it") - } - } } roomSummaryUpdater.update(realm, roomId, Membership.JOIN, roomSync.summary, roomSync.unreadNotifications) @@ -192,7 +172,7 @@ internal class RoomSyncHandler @Inject constructor(private val monarchy: Monarch ?: realm.createObject(roomId) roomEntity.membership = Membership.INVITE if (roomSync.inviteState != null && roomSync.inviteState.events.isNotEmpty()) { - val chunkEntity = handleTimelineEvents(realm, roomId, roomSync.inviteState.events) + val chunkEntity = handleTimelineEvents(realm, roomEntity, roomSync.inviteState.events) roomEntity.addOrUpdate(chunkEntity) } roomSummaryUpdater.update(realm, roomId, Membership.INVITE) @@ -212,13 +192,13 @@ internal class RoomSyncHandler @Inject constructor(private val monarchy: Monarch } private fun handleTimelineEvents(realm: Realm, - roomId: String, + roomEntity: RoomEntity, eventList: List, prevToken: String? = null, isLimited: Boolean = true, stateIndexOffset: Int = 0): ChunkEntity { - val lastChunk = ChunkEntity.findLastLiveChunkFromRoom(realm, roomId) + val lastChunk = ChunkEntity.findLastLiveChunkFromRoom(realm, roomEntity.roomId) val chunkEntity = if (!isLimited && lastChunk != null) { lastChunk } else { @@ -226,13 +206,32 @@ internal class RoomSyncHandler @Inject constructor(private val monarchy: Monarch } lastChunk?.isLastForward = false chunkEntity.isLastForward = true - chunkEntity.addAll(roomId, eventList, PaginationDirection.FORWARDS, stateIndexOffset) - - //update eventAnnotationSummary here? + val eventIds = ArrayList(eventList.size) + for (event in eventList) { + event.eventId?.also { eventIds.add(it) } + chunkEntity.add(roomEntity.roomId, event, PaginationDirection.FORWARDS, stateIndexOffset) + // Give info to crypto module + cryptoManager.onLiveEvent(roomEntity.roomId, event) + // Try to remove local echo + event.unsignedData?.transactionId?.also { + val sendingEventEntity = roomEntity.sendingTimelineEvents.find(it) + if (sendingEventEntity != null) { + Timber.v("Remove local echo for tx:$it") + roomEntity.sendingTimelineEvents.remove(sendingEventEntity) + } else { + Timber.v("Can't find corresponding local echo for tx:$it") + } + } + UserEntityFactory.createOrNull(event)?.also { + realm.insertOrUpdate(it) + } + } + chunkEntity.updateSenderDataFor(eventIds) return chunkEntity } + private fun handleEphemeral(realm: Realm, roomId: String, ephemeral: RoomSyncEphemeral) { 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 3d84d63e..598d5f07 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 @@ -20,8 +20,6 @@ import dagger.Binds import dagger.Module import dagger.Provides import im.vector.matrix.android.internal.session.SessionScope -import im.vector.matrix.android.internal.session.user.DefaultUpdateUserTask -import im.vector.matrix.android.internal.session.user.UpdateUserTask import retrofit2.Retrofit @Module diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/user/UpdateUserTask.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/user/UpdateUserTask.kt deleted file mode 100644 index eb331e41..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/user/UpdateUserTask.kt +++ /dev/null @@ -1,58 +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.user - -import arrow.core.Try -import com.zhuinden.monarchy.Monarchy -import im.vector.matrix.android.api.session.room.model.Membership -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.UserEntity -import im.vector.matrix.android.internal.database.query.where -import im.vector.matrix.android.internal.session.SessionScope -import im.vector.matrix.android.internal.session.room.membership.RoomMembers -import im.vector.matrix.android.internal.task.Task -import im.vector.matrix.android.internal.util.tryTransactionSync -import javax.inject.Inject - -internal interface UpdateUserTask : Task { - - data class Params(val eventIds: List) - -} - -internal class DefaultUpdateUserTask @Inject constructor(private val monarchy: Monarchy) : UpdateUserTask { - - override suspend fun execute(params: UpdateUserTask.Params): Try { - return monarchy.tryTransactionSync { realm -> - params.eventIds.forEach { eventId -> - val event = EventEntity.where(realm, eventId).findFirst()?.asDomain() - ?: return@forEach - val roomId = event.roomId ?: return@forEach - val userId = event.stateKey ?: return@forEach - val roomMember = RoomMembers(realm, roomId).get(userId) ?: return@forEach - if (roomMember.membership != Membership.JOIN) return@forEach - - val userEntity = UserEntity.where(realm, userId).findFirst() - ?: realm.createObject(UserEntity::class.java, userId) - userEntity.displayName = roomMember.displayName ?: "" - userEntity.avatarUrl = roomMember.avatarUrl ?: "" - } - } - } - -} \ No newline at end of file diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/user/UserEntityFactory.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/user/UserEntityFactory.kt new file mode 100644 index 00000000..188c7d84 --- /dev/null +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/user/UserEntityFactory.kt @@ -0,0 +1,39 @@ +/* + * 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.user + +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.internal.database.model.UserEntity + +internal object UserEntityFactory { + + fun createOrNull(event: Event): UserEntity? { + if (event.type != EventType.STATE_ROOM_MEMBER) { + return null + } + val roomMember = event.content.toModel() ?: return null + return UserEntity(event.stateKey ?: "", + roomMember.displayName ?: "", + roomMember.avatarUrl ?: "" + ) + } + + +} \ No newline at end of file diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/user/UserEntityUpdater.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/user/UserEntityUpdater.kt deleted file mode 100644 index 5c722863..00000000 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/user/UserEntityUpdater.kt +++ /dev/null @@ -1,60 +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.user - -import com.zhuinden.monarchy.Monarchy -import im.vector.matrix.android.api.session.events.model.EventType -import im.vector.matrix.android.internal.database.RealmLiveEntityObserver -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.query.types -import im.vector.matrix.android.internal.di.SessionDatabase -import im.vector.matrix.android.internal.task.TaskExecutor -import im.vector.matrix.android.internal.task.TaskThread -import im.vector.matrix.android.internal.task.configureWith -import io.realm.OrderedCollectionChangeSet -import io.realm.RealmConfiguration -import io.realm.RealmResults -import io.realm.Sort -import javax.inject.Inject - -internal class UserEntityUpdater @Inject constructor(@SessionDatabase realmConfiguration: RealmConfiguration, - private val updateUserTask: UpdateUserTask, - private val taskExecutor: TaskExecutor) - : RealmLiveEntityObserver(realmConfiguration) { - - override val query = Monarchy.Query { - EventEntity - .types(it, listOf(EventType.STATE_ROOM_MEMBER)) - .sort(EventEntityFields.STATE_INDEX, Sort.DESCENDING) - .distinct(EventEntityFields.STATE_KEY) - } - - override fun onChange(results: RealmResults, changeSet: OrderedCollectionChangeSet) { - val roomMembersEvents = changeSet.insertions - .asSequence() - .mapNotNull { results[it]?.eventId } - .toList() - - val taskParams = UpdateUserTask.Params(roomMembersEvents) - updateUserTask - .configureWith(taskParams) - .executeOn(TaskThread.IO) - .executeBy(taskExecutor) - } - -} \ No newline at end of file diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/user/UserModule.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/user/UserModule.kt index a35f5a3b..00368dfa 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/user/UserModule.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/user/UserModule.kt @@ -26,7 +26,4 @@ internal abstract class UserModule { @Binds abstract fun bindUserService(userService: DefaultUserService): UserService - @Binds - abstract fun bindUpdateUserTask(updateUserTask: DefaultUpdateUserTask): UpdateUserTask - } \ No newline at end of file diff --git a/vector/src/main/java/im/vector/riotx/core/platform/VectorViewModel.kt b/vector/src/main/java/im/vector/riotx/core/platform/VectorViewModel.kt index 7a79bf37..1570a7f8 100644 --- a/vector/src/main/java/im/vector/riotx/core/platform/VectorViewModel.kt +++ b/vector/src/main/java/im/vector/riotx/core/platform/VectorViewModel.kt @@ -18,7 +18,18 @@ package im.vector.riotx.core.platform import com.airbnb.mvrx.BaseMvRxViewModel import com.airbnb.mvrx.MvRxState +import im.vector.matrix.android.api.util.CancelableBag import im.vector.riotx.BuildConfig abstract class VectorViewModel(initialState: S) - : BaseMvRxViewModel(initialState, false) \ No newline at end of file + : BaseMvRxViewModel(initialState, false) { + + protected val cancelableBag = CancelableBag() + + override fun onCleared() { + super.onCleared() + cancelableBag.cancel() + } + + +} \ No newline at end of file diff --git a/vector/src/main/java/im/vector/riotx/features/home/room/detail/RoomDetailViewModel.kt b/vector/src/main/java/im/vector/riotx/features/home/room/detail/RoomDetailViewModel.kt index 20512c28..a15eae5b 100644 --- a/vector/src/main/java/im/vector/riotx/features/home/room/detail/RoomDetailViewModel.kt +++ b/vector/src/main/java/im/vector/riotx/features/home/room/detail/RoomDetailViewModel.kt @@ -94,7 +94,7 @@ class RoomDetailViewModel @AssistedInject constructor(@Assisted initialState: Ro observeRoomSummary() observeEventDisplayedActions() observeInvitationState() - room.loadRoomMembersIfNeeded() + cancelableBag += room.loadRoomMembersIfNeeded() timeline.start() setState { copy(timeline = this@RoomDetailViewModel.timeline) } }