From a993a302036d81a9cde76aa15d7672796eaebe0a Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Thu, 19 Sep 2019 17:08:22 +0200 Subject: [PATCH] Handle left group from sync --- CHANGES.md | 1 + .../api/session/group/model/GroupSummary.kt | 3 ++ .../database/mapper/GroupSummaryMapper.kt | 1 + .../internal/database/model/GroupEntity.kt | 10 +++-- .../database/model/GroupSummaryEntity.kt | 20 +++++++--- .../database/query/GroupEntityQueries.kt | 4 +- .../query/GroupSummaryEntityQueries.kt | 4 ++ .../session/group/DefaultGetGroupDataTask.kt | 12 ++++-- .../session/group/GroupSummaryUpdater.kt | 38 +++++++++++++++---- .../internal/session/sync/GroupSyncHandler.kt | 8 +--- .../features/home/group/GroupListViewModel.kt | 7 ++-- 11 files changed, 77 insertions(+), 31 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index 63ccaea83a..78dbb72ebd 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -15,6 +15,7 @@ Other changes: Bugfix: - Fix characters erased from the Search field when the result are coming (#545) - "No connection" banner was displayed by mistake + - Leaving community (from another client) has no effect on RiotX (#497) Translations: - diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/group/model/GroupSummary.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/group/model/GroupSummary.kt index 3089d83dde..328ca746a6 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/group/model/GroupSummary.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/group/model/GroupSummary.kt @@ -16,12 +16,15 @@ package im.vector.matrix.android.api.session.group.model +import im.vector.matrix.android.api.session.room.model.Membership + /** * This class holds some data of a group. * It can be retrieved through [im.vector.matrix.android.api.session.group.GroupService] */ data class GroupSummary( val groupId: String, + val membership: Membership, val displayName: String = "", val shortDescription: String = "", val avatarUrl: String = "", diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/mapper/GroupSummaryMapper.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/mapper/GroupSummaryMapper.kt index 83252352a8..5ab97d8050 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/mapper/GroupSummaryMapper.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/mapper/GroupSummaryMapper.kt @@ -25,6 +25,7 @@ internal object GroupSummaryMapper { fun map(roomSummaryEntity: GroupSummaryEntity): GroupSummary { return GroupSummary( roomSummaryEntity.groupId, + roomSummaryEntity.membership, roomSummaryEntity.displayName, roomSummaryEntity.shortDescription, roomSummaryEntity.avatarUrl, diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/model/GroupEntity.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/model/GroupEntity.kt index dea36343d5..433f209501 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/model/GroupEntity.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/model/GroupEntity.kt @@ -20,9 +20,13 @@ import im.vector.matrix.android.api.session.room.model.Membership import io.realm.RealmObject import io.realm.annotations.PrimaryKey -internal open class GroupEntity(@PrimaryKey var groupId: String = "" - -) : RealmObject() { +/** + * This class is used to store group info (groupId and membership) from the sync response. + * Then [im.vector.matrix.android.internal.session.group.GroupSummaryUpdater] observes change and + * makes requests to fetch group information from the homeserver + */ +internal open class GroupEntity(@PrimaryKey var groupId: String = "") + : RealmObject() { private var membershipStr: String = Membership.NONE.name var membership: Membership diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/model/GroupSummaryEntity.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/model/GroupSummaryEntity.kt index 5ed8c7f059..7ab67b6ab0 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/model/GroupSummaryEntity.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/model/GroupSummaryEntity.kt @@ -16,18 +16,28 @@ package im.vector.matrix.android.internal.database.model +import im.vector.matrix.android.api.session.room.model.Membership import io.realm.RealmList import io.realm.RealmObject import io.realm.annotations.PrimaryKey internal open class GroupSummaryEntity(@PrimaryKey var groupId: String = "", - var displayName: String = "", - var shortDescription: String = "", - var avatarUrl: String = "", - var roomIds: RealmList = RealmList(), - var userIds: RealmList = RealmList() + var displayName: String = "", + var shortDescription: String = "", + var avatarUrl: String = "", + var roomIds: RealmList = RealmList(), + var userIds: RealmList = RealmList() ) : RealmObject() { + private var membershipStr: String = Membership.NONE.name + var membership: Membership + get() { + return Membership.valueOf(membershipStr) + } + set(value) { + membershipStr = value.name + } + companion object } \ No newline at end of file diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/query/GroupEntityQueries.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/query/GroupEntityQueries.kt index 33c9d868e1..802bfbeae6 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/query/GroupEntityQueries.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/query/GroupEntityQueries.kt @@ -23,9 +23,9 @@ import io.realm.Realm import io.realm.RealmQuery import io.realm.kotlin.where -internal fun GroupEntity.Companion.where(realm: Realm, roomId: String): RealmQuery { +internal fun GroupEntity.Companion.where(realm: Realm, groupId: String): RealmQuery { return realm.where() - .equalTo(GroupEntityFields.GROUP_ID, roomId) + .equalTo(GroupEntityFields.GROUP_ID, groupId) } internal fun GroupEntity.Companion.where(realm: Realm, membership: Membership? = null): RealmQuery { diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/query/GroupSummaryEntityQueries.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/query/GroupSummaryEntityQueries.kt index d0351eec54..601da098ca 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/query/GroupSummaryEntityQueries.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/query/GroupSummaryEntityQueries.kt @@ -30,3 +30,7 @@ internal fun GroupSummaryEntity.Companion.where(realm: Realm, groupId: String? = return query } +internal fun GroupSummaryEntity.Companion.where(realm: Realm, groupIds: List): RealmQuery { + return realm.where() + .`in`(GroupSummaryEntityFields.GROUP_ID, groupIds.toTypedArray()) +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/group/DefaultGetGroupDataTask.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/group/DefaultGetGroupDataTask.kt index 6964ccf83c..003f6a8c61 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/group/DefaultGetGroupDataTask.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/group/DefaultGetGroupDataTask.kt @@ -17,6 +17,7 @@ package im.vector.matrix.android.internal.session.group import com.zhuinden.monarchy.Monarchy +import im.vector.matrix.android.api.session.room.model.Membership import im.vector.matrix.android.internal.database.model.GroupSummaryEntity import im.vector.matrix.android.internal.database.query.where import im.vector.matrix.android.internal.network.executeRequest @@ -64,8 +65,7 @@ internal class DefaultGetGroupDataTask @Inject constructor( groupSummaryEntity.avatarUrl = groupSummary.profile?.avatarUrl ?: "" val name = groupSummary.profile?.name groupSummaryEntity.displayName = if (name.isNullOrEmpty()) groupId else name - groupSummaryEntity.shortDescription = groupSummary.profile?.shortDescription - ?: "" + groupSummaryEntity.shortDescription = groupSummary.profile?.shortDescription ?: "" val roomIds = groupRooms.rooms.map { it.roomId } groupSummaryEntity.roomIds.clear() @@ -74,8 +74,12 @@ internal class DefaultGetGroupDataTask @Inject constructor( val userIds = groupUsers.users.map { it.userId } groupSummaryEntity.userIds.clear() groupSummaryEntity.userIds.addAll(userIds) + + groupSummaryEntity.membership = when (groupSummary.user?.membership) { + Membership.JOIN.value -> Membership.JOIN + Membership.INVITE.value -> Membership.INVITE + else -> Membership.LEAVE + } } } - - } \ No newline at end of file diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/group/GroupSummaryUpdater.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/group/GroupSummaryUpdater.kt index 47905ecc37..e92df8067b 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/group/GroupSummaryUpdater.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/group/GroupSummaryUpdater.kt @@ -21,15 +21,15 @@ import androidx.work.ExistingWorkPolicy import androidx.work.WorkManager import com.zhuinden.monarchy.Monarchy import im.vector.matrix.android.api.auth.data.Credentials +import im.vector.matrix.android.api.session.room.model.Membership import im.vector.matrix.android.internal.database.RealmLiveEntityObserver import im.vector.matrix.android.internal.database.model.GroupEntity +import im.vector.matrix.android.internal.database.model.GroupSummaryEntity import im.vector.matrix.android.internal.database.query.where -import im.vector.matrix.android.internal.di.SessionDatabase import im.vector.matrix.android.internal.worker.WorkManagerUtil import im.vector.matrix.android.internal.worker.WorkManagerUtil.matrixOneTimeWorkRequestBuilder import im.vector.matrix.android.internal.worker.WorkerParamsFactory import io.realm.OrderedCollectionChangeSet -import io.realm.RealmConfiguration import io.realm.RealmResults import javax.inject.Inject @@ -37,18 +37,29 @@ private const val GET_GROUP_DATA_WORKER = "GET_GROUP_DATA_WORKER" internal class GroupSummaryUpdater @Inject constructor(private val context: Context, private val credentials: Credentials, - @SessionDatabase realmConfiguration: RealmConfiguration) - : RealmLiveEntityObserver(realmConfiguration) { + private val monarchy: Monarchy) + : RealmLiveEntityObserver(monarchy.realmConfiguration) { - override val query = Monarchy.Query { GroupEntity.where(it) } + override val query = Monarchy.Query { GroupEntity.where(it) } override fun onChange(results: RealmResults, changeSet: OrderedCollectionChangeSet) { - val newGroupIds = changeSet.insertions + // `insertions` for new groups and `changes` to handle left groups + val modifiedGroupEntity = (changeSet.insertions + changeSet.changes) .asSequence() - .mapNotNull { results[it]?.groupId} + .mapNotNull { results[it] } .toList() - val getGroupDataWorkerParams = GetGroupDataWorker.Params(credentials.userId, newGroupIds) + fetchGroupsData(modifiedGroupEntity + .filter { it.membership == Membership.JOIN || it.membership == Membership.INVITE } + .map { it.groupId }) + + deleteGroups(modifiedGroupEntity + .filter { it.membership == Membership.LEAVE } + .map { it.groupId }) + } + + private fun fetchGroupsData(groupIds: List) { + val getGroupDataWorkerParams = GetGroupDataWorker.Params(credentials.userId, groupIds) val workData = WorkerParamsFactory.toData(getGroupDataWorkerParams) val sendWork = matrixOneTimeWorkRequestBuilder() @@ -61,4 +72,15 @@ internal class GroupSummaryUpdater @Inject constructor(private val context: Cont .enqueue() } + /** + * Delete the GroupSummaryEntity of left groups + */ + private fun deleteGroups(groupIds: List) { + monarchy + .writeAsync { realm -> + GroupSummaryEntity.where(realm, groupIds) + .findAll() + .deleteAllFromRealm() + } + } } \ No newline at end of file diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/GroupSyncHandler.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/GroupSyncHandler.kt index 29b119dd15..9355384ef5 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/GroupSyncHandler.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/GroupSyncHandler.kt @@ -64,12 +64,13 @@ internal class GroupSyncHandler @Inject constructor(private val monarchy: Monarc } } + + /** Note: [im.vector.matrix.android.internal.session.group.GroupSummaryUpdater] is observing changes */ realm.insertOrUpdate(groups) } private fun handleJoinedGroup(realm: Realm, groupId: String): GroupEntity { - val groupEntity = GroupEntity.where(realm, groupId).findFirst() ?: GroupEntity(groupId) groupEntity.membership = Membership.JOIN return groupEntity @@ -77,21 +78,16 @@ internal class GroupSyncHandler @Inject constructor(private val monarchy: Monarc private fun handleInvitedGroup(realm: Realm, groupId: String): GroupEntity { - val groupEntity = GroupEntity.where(realm, groupId).findFirst() ?: GroupEntity(groupId) groupEntity.membership = Membership.INVITE return groupEntity } - // TODO : handle it private fun handleLeftGroup(realm: Realm, groupId: String): GroupEntity { - val groupEntity = GroupEntity.where(realm, groupId).findFirst() ?: GroupEntity(groupId) groupEntity.membership = Membership.LEAVE return groupEntity } - - } \ No newline at end of file diff --git a/vector/src/main/java/im/vector/riotx/features/home/group/GroupListViewModel.kt b/vector/src/main/java/im/vector/riotx/features/home/group/GroupListViewModel.kt index 7aff4a327d..0be22e411e 100644 --- a/vector/src/main/java/im/vector/riotx/features/home/group/GroupListViewModel.kt +++ b/vector/src/main/java/im/vector/riotx/features/home/group/GroupListViewModel.kt @@ -26,6 +26,7 @@ import com.squareup.inject.assisted.Assisted import com.squareup.inject.assisted.AssistedInject import im.vector.matrix.android.api.session.Session import im.vector.matrix.android.api.session.group.model.GroupSummary +import im.vector.matrix.android.api.session.room.model.Membership import im.vector.matrix.rx.rx import im.vector.riotx.R import im.vector.riotx.core.extensions.postLiveEvent @@ -93,20 +94,20 @@ class GroupListViewModel @AssistedInject constructor(@Assisted initialState: Gro session .rx() .liveGroupSummaries() + // Keep only joined groups. Group invitations will be managed later + .map { it.filter { groupSummary -> groupSummary.membership == Membership.JOIN } } .map { val myUser = session.getUser(session.myUserId) val allCommunityGroup = GroupSummary( groupId = ALL_COMMUNITIES_GROUP_ID, + membership = Membership.JOIN, displayName = stringProvider.getString(R.string.group_all_communities), avatarUrl = myUser?.avatarUrl ?: "") listOf(allCommunityGroup) + it } .execute { async -> - // TODO Phase2 Handle the case where the selected group is deleted on another client val newSelectedGroup = selectedGroup ?: async()?.firstOrNull() copy(asyncGroups = async, selectedGroup = newSelectedGroup) } } - - } \ No newline at end of file