mirror of
https://github.com/element-hq/element-android
synced 2024-11-28 05:31:21 +03:00
Group: rework a bit how and when we fetch data about groups
This commit is contained in:
parent
32d2cea7f8
commit
9ebf87df62
17 changed files with 212 additions and 184 deletions
|
@ -16,9 +16,20 @@
|
|||
|
||||
package im.vector.matrix.android.api.session.group
|
||||
|
||||
import im.vector.matrix.android.api.MatrixCallback
|
||||
import im.vector.matrix.android.api.util.Cancelable
|
||||
|
||||
/**
|
||||
* This interface defines methods to interact within a group.
|
||||
*/
|
||||
interface Group {
|
||||
val groupId: String
|
||||
|
||||
/**
|
||||
* This methods allows you to refresh data about this group. It will be reflected on the GroupSummary.
|
||||
* The SDK also takes care of refreshing group data every hour.
|
||||
* @param callback : the matrix callback to be notified of success or failure
|
||||
* @return a Cancelable to be able to cancel requests.
|
||||
*/
|
||||
fun fetchGroupData(callback: MatrixCallback<Unit>): Cancelable
|
||||
}
|
||||
|
|
|
@ -1,34 +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.database.mapper
|
||||
|
||||
import im.vector.matrix.android.api.session.group.Group
|
||||
import im.vector.matrix.android.internal.database.model.GroupEntity
|
||||
import im.vector.matrix.android.internal.session.group.DefaultGroup
|
||||
|
||||
internal object GroupMapper {
|
||||
|
||||
fun map(groupEntity: GroupEntity): Group {
|
||||
return DefaultGroup(
|
||||
groupEntity.groupId
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
internal fun GroupEntity.asDomain(): Group {
|
||||
return GroupMapper.map(this)
|
||||
}
|
|
@ -22,8 +22,7 @@ import io.realm.annotations.PrimaryKey
|
|||
|
||||
/**
|
||||
* 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
|
||||
* Then GetGroupDataTask is called regularly to fetch group information from the homeserver.
|
||||
*/
|
||||
internal open class GroupEntity(@PrimaryKey var groupId: String = "")
|
||||
: RealmObject() {
|
||||
|
|
|
@ -19,6 +19,7 @@ package im.vector.matrix.android.internal.database.query
|
|||
import im.vector.matrix.android.api.session.room.model.Membership
|
||||
import im.vector.matrix.android.internal.database.model.GroupEntity
|
||||
import im.vector.matrix.android.internal.database.model.GroupEntityFields
|
||||
import im.vector.matrix.android.internal.query.process
|
||||
import io.realm.Realm
|
||||
import io.realm.RealmQuery
|
||||
import io.realm.kotlin.where
|
||||
|
@ -28,10 +29,6 @@ internal fun GroupEntity.Companion.where(realm: Realm, groupId: String): RealmQu
|
|||
.equalTo(GroupEntityFields.GROUP_ID, groupId)
|
||||
}
|
||||
|
||||
internal fun GroupEntity.Companion.where(realm: Realm, membership: Membership? = null): RealmQuery<GroupEntity> {
|
||||
val query = realm.where<GroupEntity>()
|
||||
if (membership != null) {
|
||||
query.equalTo(GroupEntityFields.MEMBERSHIP_STR, membership.name)
|
||||
}
|
||||
return query
|
||||
internal fun GroupEntity.Companion.where(realm: Realm, memberships: List<Membership>): RealmQuery<GroupEntity> {
|
||||
return realm.where<GroupEntity>().process(GroupEntityFields.MEMBERSHIP_STR, memberships)
|
||||
}
|
||||
|
|
|
@ -18,8 +18,10 @@ package im.vector.matrix.android.internal.database.query
|
|||
|
||||
import im.vector.matrix.android.internal.database.model.GroupSummaryEntity
|
||||
import im.vector.matrix.android.internal.database.model.GroupSummaryEntityFields
|
||||
import im.vector.matrix.android.internal.database.model.RoomSummaryEntity
|
||||
import io.realm.Realm
|
||||
import io.realm.RealmQuery
|
||||
import io.realm.kotlin.createObject
|
||||
import io.realm.kotlin.where
|
||||
|
||||
internal fun GroupSummaryEntity.Companion.where(realm: Realm, groupId: String? = null): RealmQuery<GroupSummaryEntity> {
|
||||
|
@ -34,3 +36,7 @@ internal fun GroupSummaryEntity.Companion.where(realm: Realm, groupIds: List<Str
|
|||
return realm.where<GroupSummaryEntity>()
|
||||
.`in`(GroupSummaryEntityFields.GROUP_ID, groupIds.toTypedArray())
|
||||
}
|
||||
|
||||
internal fun GroupSummaryEntity.Companion.getOrCreate(realm: Realm, groupId: String): GroupSummaryEntity {
|
||||
return where(realm, groupId).findFirst() ?: realm.createObject(groupId)
|
||||
}
|
||||
|
|
|
@ -21,7 +21,10 @@ import androidx.work.Constraints
|
|||
import androidx.work.ListenableWorker
|
||||
import androidx.work.NetworkType
|
||||
import androidx.work.OneTimeWorkRequestBuilder
|
||||
import androidx.work.PeriodicWorkRequestBuilder
|
||||
import androidx.work.WorkManager
|
||||
import java.time.Duration
|
||||
import java.util.concurrent.TimeUnit
|
||||
import javax.inject.Inject
|
||||
|
||||
internal class WorkManagerProvider @Inject constructor(
|
||||
|
@ -39,6 +42,15 @@ internal class WorkManagerProvider @Inject constructor(
|
|||
OneTimeWorkRequestBuilder<W>()
|
||||
.addTag(tag)
|
||||
|
||||
/**
|
||||
* Create a PeriodicWorkRequestBuilder, with the Matrix SDK tag
|
||||
*/
|
||||
inline fun <reified W : ListenableWorker> matrixPeriodicWorkRequestBuilder(repeatInterval: Long,
|
||||
repeatIntervalTimeUnit: TimeUnit) =
|
||||
PeriodicWorkRequestBuilder<W>(repeatInterval, repeatIntervalTimeUnit)
|
||||
.addTag(tag)
|
||||
|
||||
|
||||
/**
|
||||
* Cancel all works instantiated by the Matrix SDK for the current session, and not those from the SDK client, or for other sessions
|
||||
*/
|
||||
|
|
|
@ -68,7 +68,6 @@ import im.vector.matrix.android.internal.network.token.AccessTokenProvider
|
|||
import im.vector.matrix.android.internal.network.token.HomeserverAccessTokenProvider
|
||||
import im.vector.matrix.android.internal.session.call.CallEventProcessor
|
||||
import im.vector.matrix.android.internal.session.download.DownloadProgressInterceptor
|
||||
import im.vector.matrix.android.internal.session.group.GroupSummaryUpdater
|
||||
import im.vector.matrix.android.internal.session.homeserver.DefaultHomeServerCapabilitiesService
|
||||
import im.vector.matrix.android.internal.session.identity.DefaultIdentityService
|
||||
import im.vector.matrix.android.internal.session.integrationmanager.IntegrationManager
|
||||
|
@ -293,10 +292,6 @@ internal abstract class SessionModule {
|
|||
@Binds
|
||||
abstract fun bindNetworkConnectivityChecker(checker: DefaultNetworkConnectivityChecker): NetworkConnectivityChecker
|
||||
|
||||
@Binds
|
||||
@IntoSet
|
||||
abstract fun bindGroupSummaryUpdater(updater: GroupSummaryUpdater): SessionLifecycleObserver
|
||||
|
||||
@Binds
|
||||
@IntoSet
|
||||
abstract fun bindEventRedactionProcessor(processor: RedactionEventProcessor): EventInsertLiveProcessor
|
||||
|
|
|
@ -18,7 +18,9 @@ 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.GroupEntity
|
||||
import im.vector.matrix.android.internal.database.model.GroupSummaryEntity
|
||||
import im.vector.matrix.android.internal.database.query.getOrCreate
|
||||
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
|
||||
|
@ -28,11 +30,14 @@ import im.vector.matrix.android.internal.session.group.model.GroupUsers
|
|||
import im.vector.matrix.android.internal.task.Task
|
||||
import im.vector.matrix.android.internal.util.awaitTransaction
|
||||
import org.greenrobot.eventbus.EventBus
|
||||
import timber.log.Timber
|
||||
import javax.inject.Inject
|
||||
|
||||
internal interface GetGroupDataTask : Task<GetGroupDataTask.Params, Unit> {
|
||||
|
||||
data class Params(val groupId: String)
|
||||
sealed class Params {
|
||||
object FetchAllActive : Params()
|
||||
data class FetchWithIds(val groupIds: List<String>) : Params()
|
||||
}
|
||||
}
|
||||
|
||||
internal class DefaultGetGroupDataTask @Inject constructor(
|
||||
|
@ -41,44 +46,64 @@ internal class DefaultGetGroupDataTask @Inject constructor(
|
|||
private val eventBus: EventBus
|
||||
) : GetGroupDataTask {
|
||||
|
||||
private data class GroupData(
|
||||
val groupId: String,
|
||||
val groupSummary: GroupSummaryResponse,
|
||||
val groupRooms: GroupRooms,
|
||||
val groupUsers: GroupUsers
|
||||
)
|
||||
|
||||
override suspend fun execute(params: GetGroupDataTask.Params) {
|
||||
val groupId = params.groupId
|
||||
val groupSummary = executeRequest<GroupSummaryResponse>(eventBus) {
|
||||
apiCall = groupAPI.getSummary(groupId)
|
||||
val groupIds = when (params) {
|
||||
is GetGroupDataTask.Params.FetchAllActive -> {
|
||||
getActiveGroupIds()
|
||||
}
|
||||
is GetGroupDataTask.Params.FetchWithIds -> {
|
||||
params.groupIds
|
||||
}
|
||||
}
|
||||
val groupRooms = executeRequest<GroupRooms>(eventBus) {
|
||||
apiCall = groupAPI.getRooms(groupId)
|
||||
Timber.v("Fetch data for group with ids: ${groupIds.joinToString(";")}")
|
||||
val data = groupIds.map { groupId ->
|
||||
val groupSummary = executeRequest<GroupSummaryResponse>(eventBus) {
|
||||
apiCall = groupAPI.getSummary(groupId)
|
||||
}
|
||||
val groupRooms = executeRequest<GroupRooms>(eventBus) {
|
||||
apiCall = groupAPI.getRooms(groupId)
|
||||
}
|
||||
val groupUsers = executeRequest<GroupUsers>(eventBus) {
|
||||
apiCall = groupAPI.getUsers(groupId)
|
||||
}
|
||||
GroupData(groupId, groupSummary, groupRooms, groupUsers)
|
||||
}
|
||||
val groupUsers = executeRequest<GroupUsers>(eventBus) {
|
||||
apiCall = groupAPI.getUsers(groupId)
|
||||
}
|
||||
insertInDb(groupSummary, groupRooms, groupUsers, groupId)
|
||||
insertInDb(data)
|
||||
}
|
||||
|
||||
private suspend fun insertInDb(groupSummary: GroupSummaryResponse,
|
||||
groupRooms: GroupRooms,
|
||||
groupUsers: GroupUsers,
|
||||
groupId: String) {
|
||||
private fun getActiveGroupIds(): List<String> {
|
||||
return monarchy.fetchAllMappedSync(
|
||||
{ realm ->
|
||||
GroupEntity.where(realm, Membership.activeMemberships())
|
||||
},
|
||||
{ it.groupId }
|
||||
)
|
||||
}
|
||||
|
||||
private suspend fun insertInDb(groupDataList: List<GroupData>) {
|
||||
monarchy
|
||||
.awaitTransaction { realm ->
|
||||
val groupSummaryEntity = GroupSummaryEntity.where(realm, groupId).findFirst()
|
||||
?: realm.createObject(GroupSummaryEntity::class.java, groupId)
|
||||
groupDataList.forEach { groupData ->
|
||||
|
||||
groupSummaryEntity.avatarUrl = groupSummary.profile?.avatarUrl ?: ""
|
||||
val name = groupSummary.profile?.name
|
||||
groupSummaryEntity.displayName = if (name.isNullOrEmpty()) groupId else name
|
||||
groupSummaryEntity.shortDescription = groupSummary.profile?.shortDescription ?: ""
|
||||
val groupSummaryEntity = GroupSummaryEntity.getOrCreate(realm, groupData.groupId)
|
||||
|
||||
groupSummaryEntity.roomIds.clear()
|
||||
groupRooms.rooms.mapTo(groupSummaryEntity.roomIds) { it.roomId }
|
||||
groupSummaryEntity.avatarUrl = groupData.groupSummary.profile?.avatarUrl ?: ""
|
||||
val name = groupData.groupSummary.profile?.name
|
||||
groupSummaryEntity.displayName = if (name.isNullOrEmpty()) groupData.groupId else name
|
||||
groupSummaryEntity.shortDescription = groupData.groupSummary.profile?.shortDescription ?: ""
|
||||
|
||||
groupSummaryEntity.userIds.clear()
|
||||
groupUsers.users.mapTo(groupSummaryEntity.userIds) { it.userId }
|
||||
groupSummaryEntity.roomIds.clear()
|
||||
groupData.groupRooms.rooms.mapTo(groupSummaryEntity.roomIds) { it.roomId }
|
||||
|
||||
groupSummaryEntity.membership = when (groupSummary.user?.membership) {
|
||||
Membership.JOIN.value -> Membership.JOIN
|
||||
Membership.INVITE.value -> Membership.INVITE
|
||||
else -> Membership.LEAVE
|
||||
groupSummaryEntity.userIds.clear()
|
||||
groupData.groupUsers.users.mapTo(groupSummaryEntity.userIds) { it.userId }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,6 +16,20 @@
|
|||
|
||||
package im.vector.matrix.android.internal.session.group
|
||||
|
||||
import im.vector.matrix.android.api.MatrixCallback
|
||||
import im.vector.matrix.android.api.session.group.Group
|
||||
import im.vector.matrix.android.api.util.Cancelable
|
||||
import im.vector.matrix.android.internal.task.TaskExecutor
|
||||
import im.vector.matrix.android.internal.task.configureWith
|
||||
|
||||
internal class DefaultGroup(override val groupId: String) : Group
|
||||
internal class DefaultGroup(override val groupId: String,
|
||||
private val taskExecutor: TaskExecutor,
|
||||
private val getGroupDataTask: GetGroupDataTask) : Group {
|
||||
|
||||
override fun fetchGroupData(callback: MatrixCallback<Unit>): Cancelable {
|
||||
val params = GetGroupDataTask.Params.FetchWithIds(listOf(groupId))
|
||||
return getGroupDataTask.configureWith(params) {
|
||||
this.callback = callback
|
||||
}.executeBy(taskExecutor)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -23,6 +23,7 @@ import im.vector.matrix.android.api.session.group.GroupService
|
|||
import im.vector.matrix.android.api.session.group.GroupSummaryQueryParams
|
||||
import im.vector.matrix.android.api.session.group.model.GroupSummary
|
||||
import im.vector.matrix.android.internal.database.mapper.asDomain
|
||||
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.model.GroupSummaryEntityFields
|
||||
import im.vector.matrix.android.internal.database.query.where
|
||||
|
@ -33,10 +34,15 @@ import io.realm.Realm
|
|||
import io.realm.RealmQuery
|
||||
import javax.inject.Inject
|
||||
|
||||
internal class DefaultGroupService @Inject constructor(@SessionDatabase private val monarchy: Monarchy) : GroupService {
|
||||
internal class DefaultGroupService @Inject constructor(@SessionDatabase private val monarchy: Monarchy,
|
||||
private val groupFactory: GroupFactory) : GroupService {
|
||||
|
||||
override fun getGroup(groupId: String): Group? {
|
||||
return null
|
||||
return Realm.getInstance(monarchy.realmConfiguration).use { realm ->
|
||||
GroupEntity.where(realm, groupId).findFirst()?.let {
|
||||
groupFactory.create(groupId)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun getGroupSummary(groupId: String): GroupSummary? {
|
||||
|
|
|
@ -35,7 +35,6 @@ internal class GetGroupDataWorker(context: Context, params: WorkerParameters) :
|
|||
@JsonClass(generateAdapter = true)
|
||||
internal data class Params(
|
||||
override val sessionId: String,
|
||||
val groupIds: List<String>,
|
||||
override val lastFailureMessage: String? = null
|
||||
) : SessionWorkerParams
|
||||
|
||||
|
@ -48,14 +47,11 @@ internal class GetGroupDataWorker(context: Context, params: WorkerParameters) :
|
|||
|
||||
val sessionComponent = getSessionComponent(params.sessionId) ?: return Result.success()
|
||||
sessionComponent.inject(this)
|
||||
val results = params.groupIds.map { groupId ->
|
||||
runCatching { fetchGroupData(groupId) }
|
||||
}
|
||||
val isSuccessful = results.none { it.isFailure }
|
||||
return if (isSuccessful) Result.success() else Result.retry()
|
||||
}
|
||||
|
||||
private suspend fun fetchGroupData(groupId: String) {
|
||||
getGroupDataTask.execute(GetGroupDataTask.Params(groupId))
|
||||
return runCatching {
|
||||
getGroupDataTask.execute(GetGroupDataTask.Params.FetchAllActive)
|
||||
}.fold(
|
||||
{ Result.success() },
|
||||
{ Result.retry() }
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,40 @@
|
|||
/*
|
||||
* 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.group
|
||||
|
||||
import im.vector.matrix.android.api.session.group.Group
|
||||
import im.vector.matrix.android.internal.session.SessionScope
|
||||
import im.vector.matrix.android.internal.task.TaskExecutor
|
||||
import javax.inject.Inject
|
||||
|
||||
internal interface GroupFactory {
|
||||
fun create(groupId: String): Group
|
||||
}
|
||||
|
||||
@SessionScope
|
||||
internal class DefaultGroupFactory @Inject constructor(private val getGroupDataTask: GetGroupDataTask,
|
||||
private val taskExecutor: TaskExecutor) :
|
||||
GroupFactory {
|
||||
|
||||
override fun create(groupId: String): Group {
|
||||
return DefaultGroup(
|
||||
groupId = groupId,
|
||||
taskExecutor = taskExecutor,
|
||||
getGroupDataTask = getGroupDataTask
|
||||
)
|
||||
}
|
||||
}
|
|
@ -21,6 +21,8 @@ import dagger.Module
|
|||
import dagger.Provides
|
||||
import im.vector.matrix.android.api.session.group.GroupService
|
||||
import im.vector.matrix.android.internal.session.SessionScope
|
||||
import im.vector.matrix.android.internal.session.room.DefaultRoomFactory
|
||||
import im.vector.matrix.android.internal.session.room.RoomFactory
|
||||
import retrofit2.Retrofit
|
||||
|
||||
@Module
|
||||
|
@ -36,6 +38,9 @@ internal abstract class GroupModule {
|
|||
}
|
||||
}
|
||||
|
||||
@Binds
|
||||
abstract fun bindGroupFactory(factory: DefaultGroupFactory): GroupFactory
|
||||
|
||||
@Binds
|
||||
abstract fun bindGetGroupDataTask(task: DefaultGetGroupDataTask): GetGroupDataTask
|
||||
|
||||
|
|
|
@ -1,93 +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.group
|
||||
|
||||
import androidx.work.ExistingWorkPolicy
|
||||
import com.zhuinden.monarchy.Monarchy
|
||||
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.awaitTransaction
|
||||
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.di.SessionId
|
||||
import im.vector.matrix.android.internal.di.WorkManagerProvider
|
||||
import im.vector.matrix.android.internal.worker.WorkerParamsFactory
|
||||
import io.realm.OrderedCollectionChangeSet
|
||||
import io.realm.RealmResults
|
||||
import kotlinx.coroutines.launch
|
||||
import javax.inject.Inject
|
||||
|
||||
private const val GET_GROUP_DATA_WORKER = "GET_GROUP_DATA_WORKER"
|
||||
|
||||
internal class GroupSummaryUpdater @Inject constructor(
|
||||
private val workManagerProvider: WorkManagerProvider,
|
||||
@SessionId private val sessionId: String,
|
||||
@SessionDatabase private val monarchy: Monarchy)
|
||||
: RealmLiveEntityObserver<GroupEntity>(monarchy.realmConfiguration) {
|
||||
|
||||
override val query = Monarchy.Query { GroupEntity.where(it) }
|
||||
|
||||
override fun onChange(results: RealmResults<GroupEntity>) {
|
||||
/*
|
||||
// `insertions` for new groups and `changes` to handle left groups
|
||||
val modifiedGroupEntity = (changeSet.insertions + changeSet.changes)
|
||||
.asSequence()
|
||||
.mapNotNull { results[it] }
|
||||
|
||||
fetchGroupsData(modifiedGroupEntity
|
||||
.filter { it.membership == Membership.JOIN || it.membership == Membership.INVITE }
|
||||
.map { it.groupId }
|
||||
.toList())
|
||||
|
||||
modifiedGroupEntity
|
||||
.filter { it.membership == Membership.LEAVE }
|
||||
.map { it.groupId }
|
||||
.toList()
|
||||
.also {
|
||||
observerScope.launch {
|
||||
deleteGroups(it)
|
||||
}
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
private fun fetchGroupsData(groupIds: List<String>) {
|
||||
val getGroupDataWorkerParams = GetGroupDataWorker.Params(sessionId, groupIds)
|
||||
|
||||
val workData = WorkerParamsFactory.toData(getGroupDataWorkerParams)
|
||||
|
||||
val getGroupWork = workManagerProvider.matrixOneTimeWorkRequestBuilder<GetGroupDataWorker>()
|
||||
.setInputData(workData)
|
||||
.setConstraints(WorkManagerProvider.workConstraints)
|
||||
.build()
|
||||
|
||||
workManagerProvider.workManager
|
||||
.beginUniqueWork(GET_GROUP_DATA_WORKER, ExistingWorkPolicy.APPEND, getGroupWork)
|
||||
.enqueue()
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete the GroupSummaryEntity of left groups
|
||||
*/
|
||||
private suspend fun deleteGroups(groupIds: List<String>) = awaitTransaction(monarchy.realmConfiguration) { realm ->
|
||||
GroupSummaryEntity.where(realm, groupIds)
|
||||
.findAll()
|
||||
.deleteAllFromRealm()
|
||||
}
|
||||
}
|
|
@ -19,6 +19,8 @@ package im.vector.matrix.android.internal.session.sync
|
|||
import im.vector.matrix.android.R
|
||||
import im.vector.matrix.android.api.session.room.model.Membership
|
||||
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.getOrCreate
|
||||
import im.vector.matrix.android.internal.database.query.where
|
||||
import im.vector.matrix.android.internal.session.DefaultInitialSyncProgressService
|
||||
import im.vector.matrix.android.internal.session.mapWithProgress
|
||||
|
@ -64,29 +66,33 @@ internal class GroupSyncHandler @Inject constructor() {
|
|||
handleLeftGroup(realm, it.key)
|
||||
}
|
||||
}
|
||||
|
||||
/** 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)
|
||||
val groupSummaryEntity = GroupSummaryEntity.getOrCreate(realm, groupId)
|
||||
groupEntity.membership = Membership.JOIN
|
||||
groupSummaryEntity.membership = Membership.JOIN
|
||||
return groupEntity
|
||||
}
|
||||
|
||||
private fun handleInvitedGroup(realm: Realm,
|
||||
groupId: String): GroupEntity {
|
||||
val groupEntity = GroupEntity.where(realm, groupId).findFirst() ?: GroupEntity(groupId)
|
||||
val groupSummaryEntity = GroupSummaryEntity.getOrCreate(realm, groupId)
|
||||
groupEntity.membership = Membership.INVITE
|
||||
groupSummaryEntity.membership = Membership.INVITE
|
||||
return groupEntity
|
||||
}
|
||||
|
||||
private fun handleLeftGroup(realm: Realm,
|
||||
groupId: String): GroupEntity {
|
||||
val groupEntity = GroupEntity.where(realm, groupId).findFirst() ?: GroupEntity(groupId)
|
||||
val groupSummaryEntity = GroupSummaryEntity.getOrCreate(realm, groupId)
|
||||
groupEntity.membership = Membership.LEAVE
|
||||
groupSummaryEntity.membership = Membership.LEAVE
|
||||
return groupEntity
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,23 +16,34 @@
|
|||
|
||||
package im.vector.matrix.android.internal.session.sync
|
||||
|
||||
import androidx.work.ExistingPeriodicWorkPolicy
|
||||
import com.zhuinden.monarchy.Monarchy
|
||||
import im.vector.matrix.android.R
|
||||
import im.vector.matrix.android.api.pushrules.PushRuleService
|
||||
import im.vector.matrix.android.api.pushrules.RuleScope
|
||||
import im.vector.matrix.android.internal.crypto.DefaultCryptoService
|
||||
import im.vector.matrix.android.internal.di.SessionDatabase
|
||||
import im.vector.matrix.android.internal.di.SessionId
|
||||
import im.vector.matrix.android.internal.di.WorkManagerProvider
|
||||
import im.vector.matrix.android.internal.session.DefaultInitialSyncProgressService
|
||||
import im.vector.matrix.android.internal.session.group.GetGroupDataWorker
|
||||
import im.vector.matrix.android.internal.session.notification.ProcessEventForPushTask
|
||||
import im.vector.matrix.android.internal.session.reportSubtask
|
||||
import im.vector.matrix.android.internal.session.sync.model.GroupsSyncResponse
|
||||
import im.vector.matrix.android.internal.session.sync.model.RoomsSyncResponse
|
||||
import im.vector.matrix.android.internal.session.sync.model.SyncResponse
|
||||
import im.vector.matrix.android.internal.util.awaitTransaction
|
||||
import im.vector.matrix.android.internal.worker.WorkerParamsFactory
|
||||
import timber.log.Timber
|
||||
import java.util.concurrent.TimeUnit
|
||||
import javax.inject.Inject
|
||||
import kotlin.system.measureTimeMillis
|
||||
|
||||
private const val GET_GROUP_DATA_WORKER = "GET_GROUP_DATA_WORKER"
|
||||
|
||||
internal class SyncResponseHandler @Inject constructor(@SessionDatabase private val monarchy: Monarchy,
|
||||
@SessionId private val sessionId: String,
|
||||
private val workManagerProvider: WorkManagerProvider,
|
||||
private val roomSyncHandler: RoomSyncHandler,
|
||||
private val userAccountDataSyncHandler: UserAccountDataSyncHandler,
|
||||
private val groupSyncHandler: GroupSyncHandler,
|
||||
|
@ -109,10 +120,39 @@ internal class SyncResponseHandler @Inject constructor(@SessionDatabase private
|
|||
checkPushRules(it, isInitialSync)
|
||||
userAccountDataSyncHandler.synchronizeWithServerIfNeeded(it.invite)
|
||||
}
|
||||
syncResponse.groups?.also {
|
||||
scheduleGroupDataFetchingIfNeeded(it)
|
||||
}
|
||||
|
||||
Timber.v("On sync completed")
|
||||
cryptoSyncHandler.onSyncCompleted(syncResponse)
|
||||
}
|
||||
|
||||
/**
|
||||
* At the moment we don't get any group data through the sync, so we poll where every hour.
|
||||
You can also force to refetch group data using [Group] API.
|
||||
*/
|
||||
private fun scheduleGroupDataFetchingIfNeeded(groupsSyncResponse: GroupsSyncResponse) {
|
||||
val groupIds = ArrayList<String>()
|
||||
groupIds.addAll(groupsSyncResponse.join.keys)
|
||||
groupIds.addAll(groupsSyncResponse.invite.keys)
|
||||
if (groupIds.isEmpty()) {
|
||||
Timber.v("No new groups to fetch data for.")
|
||||
return
|
||||
}
|
||||
Timber.v("There are ${groupIds.size} new groups to fetch data for.")
|
||||
val getGroupDataWorkerParams = GetGroupDataWorker.Params(sessionId)
|
||||
val workData = WorkerParamsFactory.toData(getGroupDataWorkerParams)
|
||||
|
||||
val getGroupWork = workManagerProvider.matrixPeriodicWorkRequestBuilder<GetGroupDataWorker>(1, TimeUnit.HOURS)
|
||||
.setInputData(workData)
|
||||
.setConstraints(WorkManagerProvider.workConstraints)
|
||||
.build()
|
||||
|
||||
workManagerProvider.workManager
|
||||
.enqueueUniquePeriodicWork(GET_GROUP_DATA_WORKER, ExistingPeriodicWorkPolicy.REPLACE, getGroupWork)
|
||||
}
|
||||
|
||||
private suspend fun checkPushRules(roomsSyncResponse: RoomsSyncResponse, isInitialSync: Boolean) {
|
||||
Timber.v("[PushRules] --> checkPushRules")
|
||||
if (isInitialSync) {
|
||||
|
|
|
@ -23,6 +23,7 @@ import com.airbnb.mvrx.MvRxViewModelFactory
|
|||
import com.airbnb.mvrx.ViewModelContext
|
||||
import com.squareup.inject.assisted.Assisted
|
||||
import com.squareup.inject.assisted.AssistedInject
|
||||
import im.vector.matrix.android.api.NoOpMatrixCallback
|
||||
import im.vector.matrix.android.api.query.QueryStringValue
|
||||
import im.vector.matrix.android.api.session.Session
|
||||
import im.vector.matrix.android.api.session.group.groupSummaryQueryParams
|
||||
|
@ -88,6 +89,8 @@ class GroupListViewModel @AssistedInject constructor(@Assisted initialState: Gro
|
|||
|
||||
private fun handleSelectGroup(action: GroupListAction.SelectGroup) = withState { state ->
|
||||
if (state.selectedGroup?.groupId != action.groupSummary.groupId) {
|
||||
// We take care of refreshing group data when selecting to be sure we get all the rooms and users
|
||||
session.getGroup(action.groupSummary.groupId)?.fetchGroupData(NoOpMatrixCallback())
|
||||
setState { copy(selectedGroup = action.groupSummary) }
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue