mirror of
https://github.com/element-hq/element-android
synced 2024-11-23 09:55:40 +03:00
saving sync filter changed (#7627)
This commit is contained in:
parent
9349b1ae15
commit
5aeca1f81a
30 changed files with 736 additions and 159 deletions
2
changelog.d/7626.sdk
Normal file
2
changelog.d/7626.sdk
Normal file
|
@ -0,0 +1,2 @@
|
|||
Sync Filter now taking in account homeserver capabilities to not pass unsupported parameters.
|
||||
Sync Filter is now configured by providing SyncFilterBuilder class instance, instead of Filter to identify Filter changes related to homeserver capabilities
|
|
@ -50,6 +50,7 @@ import org.matrix.android.sdk.api.session.room.send.SendState
|
|||
import org.matrix.android.sdk.api.session.room.timeline.Timeline
|
||||
import org.matrix.android.sdk.api.session.room.timeline.TimelineEvent
|
||||
import org.matrix.android.sdk.api.session.room.timeline.TimelineSettings
|
||||
import org.matrix.android.sdk.api.session.sync.filter.SyncFilterBuilder
|
||||
import timber.log.Timber
|
||||
import java.util.UUID
|
||||
import java.util.concurrent.CountDownLatch
|
||||
|
@ -346,6 +347,10 @@ class CommonTestHelper internal constructor(context: Context, val cryptoConfig:
|
|||
assertTrue(registrationResult is RegistrationResult.Success)
|
||||
val session = (registrationResult as RegistrationResult.Success).session
|
||||
session.open()
|
||||
session.filterService().setSyncFilter(
|
||||
SyncFilterBuilder()
|
||||
.lazyLoadMembersForStateEvents(true)
|
||||
)
|
||||
if (sessionTestParams.withInitialSync) {
|
||||
syncSession(session, 120_000)
|
||||
}
|
||||
|
|
|
@ -16,19 +16,12 @@
|
|||
|
||||
package org.matrix.android.sdk.api.session.sync
|
||||
|
||||
import org.matrix.android.sdk.api.session.sync.filter.SyncFilterBuilder
|
||||
|
||||
interface FilterService {
|
||||
|
||||
enum class FilterPreset {
|
||||
NoFilter,
|
||||
|
||||
/**
|
||||
* Filter for Element, will include only known event type.
|
||||
*/
|
||||
ElementFilter
|
||||
}
|
||||
|
||||
/**
|
||||
* Configure the filter for the sync.
|
||||
*/
|
||||
fun setFilter(filterPreset: FilterPreset)
|
||||
suspend fun setSyncFilter(filterBuilder: SyncFilterBuilder)
|
||||
}
|
||||
|
|
|
@ -0,0 +1,129 @@
|
|||
/*
|
||||
* Copyright 2022 The Matrix.org Foundation C.I.C.
|
||||
*
|
||||
* 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 org.matrix.android.sdk.api.session.sync.filter
|
||||
|
||||
import org.matrix.android.sdk.api.session.homeserver.HomeServerCapabilities
|
||||
import org.matrix.android.sdk.internal.session.filter.Filter
|
||||
import org.matrix.android.sdk.internal.session.filter.RoomEventFilter
|
||||
import org.matrix.android.sdk.internal.session.filter.RoomFilter
|
||||
import org.matrix.android.sdk.internal.sync.filter.SyncFilterParams
|
||||
|
||||
class SyncFilterBuilder {
|
||||
private var lazyLoadMembersForStateEvents: Boolean? = null
|
||||
private var lazyLoadMembersForMessageEvents: Boolean? = null
|
||||
private var useThreadNotifications: Boolean? = null
|
||||
private var listOfSupportedEventTypes: List<String>? = null
|
||||
private var listOfSupportedStateEventTypes: List<String>? = null
|
||||
|
||||
fun lazyLoadMembersForStateEvents(lazyLoadMembersForStateEvents: Boolean) = apply { this.lazyLoadMembersForStateEvents = lazyLoadMembersForStateEvents }
|
||||
|
||||
fun lazyLoadMembersForMessageEvents(lazyLoadMembersForMessageEvents: Boolean) =
|
||||
apply { this.lazyLoadMembersForMessageEvents = lazyLoadMembersForMessageEvents }
|
||||
|
||||
fun useThreadNotifications(useThreadNotifications: Boolean) =
|
||||
apply { this.useThreadNotifications = useThreadNotifications }
|
||||
|
||||
fun listOfSupportedStateEventTypes(listOfSupportedStateEventTypes: List<String>) =
|
||||
apply { this.listOfSupportedStateEventTypes = listOfSupportedStateEventTypes }
|
||||
|
||||
fun listOfSupportedTimelineEventTypes(listOfSupportedEventTypes: List<String>) =
|
||||
apply { this.listOfSupportedEventTypes = listOfSupportedEventTypes }
|
||||
|
||||
internal fun with(currentFilterParams: SyncFilterParams?) =
|
||||
apply {
|
||||
currentFilterParams?.let {
|
||||
useThreadNotifications = currentFilterParams.useThreadNotifications
|
||||
lazyLoadMembersForMessageEvents = currentFilterParams.lazyLoadMembersForMessageEvents
|
||||
lazyLoadMembersForStateEvents = currentFilterParams.lazyLoadMembersForStateEvents
|
||||
listOfSupportedEventTypes = currentFilterParams.listOfSupportedEventTypes?.toList()
|
||||
listOfSupportedStateEventTypes = currentFilterParams.listOfSupportedStateEventTypes?.toList()
|
||||
}
|
||||
}
|
||||
|
||||
internal fun extractParams(): SyncFilterParams {
|
||||
return SyncFilterParams(
|
||||
useThreadNotifications = useThreadNotifications,
|
||||
lazyLoadMembersForMessageEvents = lazyLoadMembersForMessageEvents,
|
||||
lazyLoadMembersForStateEvents = lazyLoadMembersForStateEvents,
|
||||
listOfSupportedEventTypes = listOfSupportedEventTypes,
|
||||
listOfSupportedStateEventTypes = listOfSupportedStateEventTypes,
|
||||
)
|
||||
}
|
||||
|
||||
internal fun build(homeServerCapabilities: HomeServerCapabilities): Filter {
|
||||
return Filter(
|
||||
room = buildRoomFilter(homeServerCapabilities)
|
||||
)
|
||||
}
|
||||
|
||||
private fun buildRoomFilter(homeServerCapabilities: HomeServerCapabilities): RoomFilter {
|
||||
return RoomFilter(
|
||||
timeline = buildTimelineFilter(homeServerCapabilities),
|
||||
state = buildStateFilter()
|
||||
)
|
||||
}
|
||||
|
||||
private fun buildTimelineFilter(homeServerCapabilities: HomeServerCapabilities): RoomEventFilter? {
|
||||
val resolvedUseThreadNotifications = if (homeServerCapabilities.canUseThreadReadReceiptsAndNotifications) {
|
||||
useThreadNotifications
|
||||
} else {
|
||||
null
|
||||
}
|
||||
return RoomEventFilter(
|
||||
enableUnreadThreadNotifications = resolvedUseThreadNotifications,
|
||||
lazyLoadMembers = lazyLoadMembersForMessageEvents
|
||||
).orNullIfEmpty()
|
||||
}
|
||||
|
||||
private fun buildStateFilter(): RoomEventFilter? =
|
||||
RoomEventFilter(
|
||||
lazyLoadMembers = lazyLoadMembersForStateEvents,
|
||||
types = listOfSupportedStateEventTypes
|
||||
).orNullIfEmpty()
|
||||
|
||||
private fun RoomEventFilter.orNullIfEmpty(): RoomEventFilter? {
|
||||
return if (hasData()) {
|
||||
this
|
||||
} else {
|
||||
null
|
||||
}
|
||||
}
|
||||
|
||||
override fun equals(other: Any?): Boolean {
|
||||
if (this === other) return true
|
||||
if (javaClass != other?.javaClass) return false
|
||||
|
||||
other as SyncFilterBuilder
|
||||
|
||||
if (lazyLoadMembersForStateEvents != other.lazyLoadMembersForStateEvents) return false
|
||||
if (lazyLoadMembersForMessageEvents != other.lazyLoadMembersForMessageEvents) return false
|
||||
if (useThreadNotifications != other.useThreadNotifications) return false
|
||||
if (listOfSupportedEventTypes != other.listOfSupportedEventTypes) return false
|
||||
if (listOfSupportedStateEventTypes != other.listOfSupportedStateEventTypes) return false
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
override fun hashCode(): Int {
|
||||
var result = lazyLoadMembersForStateEvents?.hashCode() ?: 0
|
||||
result = 31 * result + (lazyLoadMembersForMessageEvents?.hashCode() ?: 0)
|
||||
result = 31 * result + (useThreadNotifications?.hashCode() ?: 0)
|
||||
result = 31 * result + (listOfSupportedEventTypes?.hashCode() ?: 0)
|
||||
result = 31 * result + (listOfSupportedStateEventTypes?.hashCode() ?: 0)
|
||||
return result
|
||||
}
|
||||
}
|
|
@ -61,6 +61,7 @@ import org.matrix.android.sdk.internal.database.migration.MigrateSessionTo041
|
|||
import org.matrix.android.sdk.internal.database.migration.MigrateSessionTo042
|
||||
import org.matrix.android.sdk.internal.database.migration.MigrateSessionTo043
|
||||
import org.matrix.android.sdk.internal.database.migration.MigrateSessionTo044
|
||||
import org.matrix.android.sdk.internal.database.migration.MigrateSessionTo045
|
||||
import org.matrix.android.sdk.internal.util.Normalizer
|
||||
import org.matrix.android.sdk.internal.util.database.MatrixRealmMigration
|
||||
import javax.inject.Inject
|
||||
|
@ -69,7 +70,7 @@ internal class RealmSessionStoreMigration @Inject constructor(
|
|||
private val normalizer: Normalizer
|
||||
) : MatrixRealmMigration(
|
||||
dbName = "Session",
|
||||
schemaVersion = 44L,
|
||||
schemaVersion = 45L,
|
||||
) {
|
||||
/**
|
||||
* Forces all RealmSessionStoreMigration instances to be equal.
|
||||
|
@ -123,5 +124,6 @@ internal class RealmSessionStoreMigration @Inject constructor(
|
|||
if (oldVersion < 42) MigrateSessionTo042(realm).perform()
|
||||
if (oldVersion < 43) MigrateSessionTo043(realm).perform()
|
||||
if (oldVersion < 44) MigrateSessionTo044(realm).perform()
|
||||
if (oldVersion < 45) MigrateSessionTo045(realm).perform()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,61 @@
|
|||
/*
|
||||
* Copyright 2022 The Matrix.org Foundation C.I.C.
|
||||
*
|
||||
* 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 org.matrix.android.sdk.internal.database.mapper
|
||||
|
||||
import io.realm.RealmList
|
||||
import org.matrix.android.sdk.internal.database.model.SyncFilterParamsEntity
|
||||
import org.matrix.android.sdk.internal.sync.filter.SyncFilterParams
|
||||
import javax.inject.Inject
|
||||
|
||||
internal class FilterParamsMapper @Inject constructor() {
|
||||
|
||||
fun map(entity: SyncFilterParamsEntity): SyncFilterParams {
|
||||
val eventTypes = if (entity.listOfSupportedEventTypesHasBeenSet) {
|
||||
entity.listOfSupportedEventTypes?.toList()
|
||||
} else {
|
||||
null
|
||||
}
|
||||
val stateEventTypes = if (entity.listOfSupportedStateEventTypesHasBeenSet) {
|
||||
entity.listOfSupportedStateEventTypes?.toList()
|
||||
} else {
|
||||
null
|
||||
}
|
||||
return SyncFilterParams(
|
||||
useThreadNotifications = entity.useThreadNotifications,
|
||||
lazyLoadMembersForMessageEvents = entity.lazyLoadMembersForMessageEvents,
|
||||
lazyLoadMembersForStateEvents = entity.lazyLoadMembersForStateEvents,
|
||||
listOfSupportedEventTypes = eventTypes,
|
||||
listOfSupportedStateEventTypes = stateEventTypes,
|
||||
)
|
||||
}
|
||||
|
||||
fun map(params: SyncFilterParams): SyncFilterParamsEntity {
|
||||
return SyncFilterParamsEntity(
|
||||
useThreadNotifications = params.useThreadNotifications,
|
||||
lazyLoadMembersForMessageEvents = params.lazyLoadMembersForMessageEvents,
|
||||
lazyLoadMembersForStateEvents = params.lazyLoadMembersForStateEvents,
|
||||
listOfSupportedEventTypes = params.listOfSupportedEventTypes.toRealmList(),
|
||||
listOfSupportedEventTypesHasBeenSet = params.listOfSupportedEventTypes != null,
|
||||
listOfSupportedStateEventTypes = params.listOfSupportedStateEventTypes.toRealmList(),
|
||||
listOfSupportedStateEventTypesHasBeenSet = params.listOfSupportedStateEventTypes != null,
|
||||
)
|
||||
}
|
||||
|
||||
private fun List<String>?.toRealmList(): RealmList<String>? {
|
||||
return this?.toTypedArray()?.let { RealmList(*it) }
|
||||
}
|
||||
}
|
|
@ -19,7 +19,6 @@ package org.matrix.android.sdk.internal.database.migration
|
|||
import io.realm.DynamicRealm
|
||||
import org.matrix.android.sdk.internal.database.model.EditionOfEventFields
|
||||
import org.matrix.android.sdk.internal.database.model.EventEntityFields
|
||||
import org.matrix.android.sdk.internal.database.query.where
|
||||
import org.matrix.android.sdk.internal.util.database.RealmMigrator
|
||||
|
||||
internal class MigrateSessionTo043(realm: DynamicRealm) : RealmMigrator(realm, 43) {
|
||||
|
|
|
@ -0,0 +1,38 @@
|
|||
/*
|
||||
* Copyright (c) 2022 The Matrix.org Foundation C.I.C.
|
||||
*
|
||||
* 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 org.matrix.android.sdk.internal.database.migration
|
||||
|
||||
import io.realm.DynamicRealm
|
||||
import org.matrix.android.sdk.internal.database.model.SyncFilterParamsEntityFields
|
||||
import org.matrix.android.sdk.internal.util.database.RealmMigrator
|
||||
|
||||
internal class MigrateSessionTo045(realm: DynamicRealm) : RealmMigrator(realm, 45) {
|
||||
|
||||
override fun doMigrate(realm: DynamicRealm) {
|
||||
realm.schema.create("SyncFilterParamsEntity")
|
||||
.addField(SyncFilterParamsEntityFields.LAZY_LOAD_MEMBERS_FOR_STATE_EVENTS, Boolean::class.java)
|
||||
.setNullable(SyncFilterParamsEntityFields.LAZY_LOAD_MEMBERS_FOR_STATE_EVENTS, true)
|
||||
.addField(SyncFilterParamsEntityFields.LAZY_LOAD_MEMBERS_FOR_MESSAGE_EVENTS, Boolean::class.java)
|
||||
.setNullable(SyncFilterParamsEntityFields.LAZY_LOAD_MEMBERS_FOR_MESSAGE_EVENTS, true)
|
||||
.addField(SyncFilterParamsEntityFields.LIST_OF_SUPPORTED_EVENT_TYPES_HAS_BEEN_SET, Boolean::class.java)
|
||||
.addField(SyncFilterParamsEntityFields.LIST_OF_SUPPORTED_STATE_EVENT_TYPES_HAS_BEEN_SET, Boolean::class.java)
|
||||
.addField(SyncFilterParamsEntityFields.USE_THREAD_NOTIFICATIONS, Boolean::class.java)
|
||||
.setNullable(SyncFilterParamsEntityFields.USE_THREAD_NOTIFICATIONS, true)
|
||||
.addRealmListField(SyncFilterParamsEntityFields.LIST_OF_SUPPORTED_EVENT_TYPES.`$`, String::class.java)
|
||||
.addRealmListField(SyncFilterParamsEntityFields.LIST_OF_SUPPORTED_STATE_EVENT_TYPES.`$`, String::class.java)
|
||||
}
|
||||
}
|
|
@ -70,7 +70,8 @@ import org.matrix.android.sdk.internal.database.model.threads.ThreadSummaryEntit
|
|||
SpaceChildSummaryEntity::class,
|
||||
SpaceParentSummaryEntity::class,
|
||||
UserPresenceEntity::class,
|
||||
ThreadSummaryEntity::class
|
||||
ThreadSummaryEntity::class,
|
||||
SyncFilterParamsEntity::class,
|
||||
]
|
||||
)
|
||||
internal class SessionRealmModule
|
||||
|
|
|
@ -0,0 +1,36 @@
|
|||
/*
|
||||
* Copyright 2022 The Matrix.org Foundation C.I.C.
|
||||
*
|
||||
* 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 org.matrix.android.sdk.internal.database.model
|
||||
|
||||
import io.realm.RealmList
|
||||
import io.realm.RealmObject
|
||||
|
||||
/**
|
||||
* This entity stores Sync Filter configuration data, provided by the client.
|
||||
*/
|
||||
internal open class SyncFilterParamsEntity(
|
||||
var lazyLoadMembersForStateEvents: Boolean? = null,
|
||||
var lazyLoadMembersForMessageEvents: Boolean? = null,
|
||||
var useThreadNotifications: Boolean? = null,
|
||||
var listOfSupportedEventTypes: RealmList<String>? = null,
|
||||
var listOfSupportedEventTypesHasBeenSet: Boolean = false,
|
||||
var listOfSupportedStateEventTypes: RealmList<String>? = null,
|
||||
var listOfSupportedStateEventTypesHasBeenSet: Boolean = false,
|
||||
) : RealmObject() {
|
||||
|
||||
companion object
|
||||
}
|
|
@ -17,74 +17,71 @@
|
|||
package org.matrix.android.sdk.internal.session.filter
|
||||
|
||||
import com.zhuinden.monarchy.Monarchy
|
||||
import io.realm.Realm
|
||||
import io.realm.kotlin.where
|
||||
import org.matrix.android.sdk.internal.database.mapper.FilterParamsMapper
|
||||
import org.matrix.android.sdk.internal.database.model.FilterEntity
|
||||
import org.matrix.android.sdk.internal.database.model.FilterEntityFields
|
||||
import org.matrix.android.sdk.internal.database.model.SyncFilterParamsEntity
|
||||
import org.matrix.android.sdk.internal.database.query.get
|
||||
import org.matrix.android.sdk.internal.database.query.getOrCreate
|
||||
import org.matrix.android.sdk.internal.di.SessionDatabase
|
||||
import org.matrix.android.sdk.internal.sync.filter.SyncFilterParams
|
||||
import org.matrix.android.sdk.internal.util.awaitTransaction
|
||||
import javax.inject.Inject
|
||||
|
||||
internal class DefaultFilterRepository @Inject constructor(@SessionDatabase private val monarchy: Monarchy) : FilterRepository {
|
||||
internal class DefaultFilterRepository @Inject constructor(
|
||||
@SessionDatabase private val monarchy: Monarchy,
|
||||
private val filterParamsMapper: FilterParamsMapper
|
||||
) : FilterRepository {
|
||||
|
||||
override suspend fun storeFilter(filter: Filter, roomEventFilter: RoomEventFilter): Boolean {
|
||||
return Realm.getInstance(monarchy.realmConfiguration).use { realm ->
|
||||
val filterEntity = FilterEntity.get(realm)
|
||||
// Filter has changed, or no filter Id yet
|
||||
filterEntity == null ||
|
||||
filterEntity.filterBodyJson != filter.toJSONString() ||
|
||||
filterEntity.filterId.isBlank()
|
||||
}.also { hasChanged ->
|
||||
if (hasChanged) {
|
||||
// Filter is new or has changed, store it and reset the filter Id.
|
||||
// This has to be done outside of the Realm.use(), because awaitTransaction change the current thread
|
||||
monarchy.awaitTransaction { realm ->
|
||||
// We manage only one filter for now
|
||||
val filterJson = filter.toJSONString()
|
||||
val roomEventFilterJson = roomEventFilter.toJSONString()
|
||||
|
||||
val filterEntity = FilterEntity.getOrCreate(realm)
|
||||
|
||||
filterEntity.filterBodyJson = filterJson
|
||||
filterEntity.roomEventFilterJson = roomEventFilterJson
|
||||
// Reset filterId
|
||||
filterEntity.filterId = ""
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun storeFilterId(filter: Filter, filterId: String) {
|
||||
monarchy.awaitTransaction {
|
||||
override suspend fun storeSyncFilter(filter: Filter, filterId: String, roomEventFilter: RoomEventFilter) {
|
||||
monarchy.awaitTransaction { realm ->
|
||||
// We manage only one filter for now
|
||||
val filterJson = filter.toJSONString()
|
||||
val roomEventFilterJson = roomEventFilter.toJSONString()
|
||||
|
||||
// Update the filter id, only if the filter body matches
|
||||
it.where<FilterEntity>()
|
||||
.equalTo(FilterEntityFields.FILTER_BODY_JSON, filterJson)
|
||||
?.findFirst()
|
||||
?.filterId = filterId
|
||||
val filterEntity = FilterEntity.getOrCreate(realm)
|
||||
|
||||
filterEntity.filterBodyJson = filterJson
|
||||
filterEntity.roomEventFilterJson = roomEventFilterJson
|
||||
filterEntity.filterId = filterId
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun getFilter(): String {
|
||||
override suspend fun getStoredSyncFilterBody(): String {
|
||||
return monarchy.awaitTransaction {
|
||||
val filter = FilterEntity.getOrCreate(it)
|
||||
if (filter.filterId.isBlank()) {
|
||||
// Use the Json format
|
||||
filter.filterBodyJson
|
||||
FilterEntity.getOrCreate(it).filterBodyJson
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun getStoredSyncFilterId(): String? {
|
||||
return monarchy.awaitTransaction {
|
||||
val id = FilterEntity.get(it)?.filterId
|
||||
if (id.isNullOrBlank()) {
|
||||
null
|
||||
} else {
|
||||
// Use FilterId
|
||||
filter.filterId
|
||||
id
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun getRoomFilter(): String {
|
||||
override suspend fun getRoomFilterBody(): String {
|
||||
return monarchy.awaitTransaction {
|
||||
FilterEntity.getOrCreate(it).roomEventFilterJson
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun getStoredFilterParams(): SyncFilterParams? {
|
||||
return monarchy.awaitTransaction { realm ->
|
||||
realm.where<SyncFilterParamsEntity>().findFirst()?.let {
|
||||
filterParamsMapper.map(it)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun storeFilterParams(params: SyncFilterParams) {
|
||||
return monarchy.awaitTransaction { realm ->
|
||||
val entity = filterParamsMapper.map(params)
|
||||
realm.insertOrUpdate(entity)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,19 +17,27 @@
|
|||
package org.matrix.android.sdk.internal.session.filter
|
||||
|
||||
import org.matrix.android.sdk.api.session.sync.FilterService
|
||||
import org.matrix.android.sdk.internal.task.TaskExecutor
|
||||
import org.matrix.android.sdk.internal.task.configureWith
|
||||
import org.matrix.android.sdk.api.session.sync.filter.SyncFilterBuilder
|
||||
import org.matrix.android.sdk.internal.session.homeserver.HomeServerCapabilitiesDataSource
|
||||
import javax.inject.Inject
|
||||
|
||||
internal class DefaultFilterService @Inject constructor(
|
||||
private val saveFilterTask: SaveFilterTask,
|
||||
private val taskExecutor: TaskExecutor
|
||||
private val filterRepository: FilterRepository,
|
||||
private val homeServerCapabilitiesDataSource: HomeServerCapabilitiesDataSource,
|
||||
) : FilterService {
|
||||
|
||||
// TODO Pass a list of support events instead
|
||||
override fun setFilter(filterPreset: FilterService.FilterPreset) {
|
||||
saveFilterTask
|
||||
.configureWith(SaveFilterTask.Params(filterPreset))
|
||||
.executeBy(taskExecutor)
|
||||
override suspend fun setSyncFilter(filterBuilder: SyncFilterBuilder) {
|
||||
filterRepository.storeFilterParams(filterBuilder.extractParams())
|
||||
|
||||
// don't upload/store filter until homeserver capabilities are fetched
|
||||
homeServerCapabilitiesDataSource.getHomeServerCapabilities()?.let { homeServerCapabilities ->
|
||||
saveFilterTask.execute(
|
||||
SaveFilterTask.Params(
|
||||
filter = filterBuilder.build(homeServerCapabilities)
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -45,46 +45,7 @@ internal object FilterFactory {
|
|||
return FilterUtil.enableLazyLoading(Filter(), true)
|
||||
}
|
||||
|
||||
fun createElementFilter(): Filter {
|
||||
return Filter(
|
||||
room = RoomFilter(
|
||||
timeline = createElementTimelineFilter(),
|
||||
state = createElementStateFilter()
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
fun createDefaultRoomFilter(): RoomEventFilter {
|
||||
return RoomEventFilter(lazyLoadMembers = true)
|
||||
}
|
||||
|
||||
fun createElementRoomFilter(): RoomEventFilter {
|
||||
return RoomEventFilter(
|
||||
lazyLoadMembers = true,
|
||||
// TODO Enable this for optimization
|
||||
// types = (listOfSupportedEventTypes + listOfSupportedStateEventTypes).toMutableList()
|
||||
)
|
||||
}
|
||||
|
||||
private fun createElementTimelineFilter(): RoomEventFilter? {
|
||||
// we need to check if homeserver supports thread notifications before setting this param
|
||||
// return RoomEventFilter(enableUnreadThreadNotifications = true)
|
||||
return null
|
||||
}
|
||||
|
||||
private fun createElementStateFilter(): RoomEventFilter {
|
||||
return RoomEventFilter(lazyLoadMembers = true)
|
||||
}
|
||||
|
||||
// Get only managed types by Element
|
||||
private val listOfSupportedEventTypes = listOf(
|
||||
// TODO Complete the list
|
||||
EventType.MESSAGE
|
||||
)
|
||||
|
||||
// Get only managed types by Element
|
||||
private val listOfSupportedStateEventTypes = listOf(
|
||||
// TODO Complete the list
|
||||
EventType.STATE_ROOM_MEMBER
|
||||
)
|
||||
}
|
||||
|
|
|
@ -44,4 +44,7 @@ internal abstract class FilterModule {
|
|||
|
||||
@Binds
|
||||
abstract fun bindSaveFilterTask(task: DefaultSaveFilterTask): SaveFilterTask
|
||||
|
||||
@Binds
|
||||
abstract fun bindGetCurrentFilterTask(task: DefaultGetCurrentFilterTask): GetCurrentFilterTask
|
||||
}
|
||||
|
|
|
@ -16,25 +16,42 @@
|
|||
|
||||
package org.matrix.android.sdk.internal.session.filter
|
||||
|
||||
import org.matrix.android.sdk.internal.sync.filter.SyncFilterParams
|
||||
|
||||
/**
|
||||
* Repository for request filters.
|
||||
*/
|
||||
internal interface FilterRepository {
|
||||
|
||||
/**
|
||||
* Return true if the filterBody has changed, or need to be sent to the server.
|
||||
* Stores sync filter and room filter.
|
||||
* Note: It looks like we could use [Filter.room.timeline] instead of a separate [RoomEventFilter], but it's not clear if it's safe, so research is needed
|
||||
* @return true if the filterBody has changed, or need to be sent to the server.
|
||||
*/
|
||||
suspend fun storeFilter(filter: Filter, roomEventFilter: RoomEventFilter): Boolean
|
||||
suspend fun storeSyncFilter(filter: Filter, filterId: String, roomEventFilter: RoomEventFilter)
|
||||
|
||||
/**
|
||||
* Set the filterId of this filter.
|
||||
* Returns stored sync filter's JSON body if it exists.
|
||||
*/
|
||||
suspend fun storeFilterId(filter: Filter, filterId: String)
|
||||
suspend fun getStoredSyncFilterBody(): String?
|
||||
|
||||
/**
|
||||
* Return filter json or filter id.
|
||||
* Returns stored sync filter's ID if it exists.
|
||||
*/
|
||||
suspend fun getFilter(): String
|
||||
suspend fun getStoredSyncFilterId(): String?
|
||||
|
||||
/**
|
||||
* Return the room filter.
|
||||
*/
|
||||
suspend fun getRoomFilter(): String
|
||||
suspend fun getRoomFilterBody(): String
|
||||
|
||||
/**
|
||||
* Returns filter params stored in local storage if it exists.
|
||||
*/
|
||||
suspend fun getStoredFilterParams(): SyncFilterParams?
|
||||
|
||||
/**
|
||||
* Stores filter params to local storage.
|
||||
*/
|
||||
suspend fun storeFilterParams(params: SyncFilterParams)
|
||||
}
|
||||
|
|
|
@ -0,0 +1,55 @@
|
|||
/*
|
||||
* Copyright 2022 The Matrix.org Foundation C.I.C.
|
||||
*
|
||||
* 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 org.matrix.android.sdk.internal.session.filter
|
||||
|
||||
import org.matrix.android.sdk.api.session.homeserver.HomeServerCapabilities
|
||||
import org.matrix.android.sdk.api.session.sync.filter.SyncFilterBuilder
|
||||
import org.matrix.android.sdk.internal.session.homeserver.HomeServerCapabilitiesDataSource
|
||||
import org.matrix.android.sdk.internal.task.Task
|
||||
import javax.inject.Inject
|
||||
|
||||
internal interface GetCurrentFilterTask : Task<Unit, String>
|
||||
|
||||
internal class DefaultGetCurrentFilterTask @Inject constructor(
|
||||
private val filterRepository: FilterRepository,
|
||||
private val homeServerCapabilitiesDataSource: HomeServerCapabilitiesDataSource,
|
||||
private val saveFilterTask: SaveFilterTask
|
||||
) : GetCurrentFilterTask {
|
||||
|
||||
override suspend fun execute(params: Unit): String {
|
||||
val storedFilterId = filterRepository.getStoredSyncFilterId()
|
||||
val storedFilterBody = filterRepository.getStoredSyncFilterBody()
|
||||
val homeServerCapabilities = homeServerCapabilitiesDataSource.getHomeServerCapabilities() ?: HomeServerCapabilities()
|
||||
val currentFilter = SyncFilterBuilder()
|
||||
.with(filterRepository.getStoredFilterParams())
|
||||
.build(homeServerCapabilities)
|
||||
|
||||
val currentFilterBody = currentFilter.toJSONString()
|
||||
|
||||
return when (storedFilterBody) {
|
||||
currentFilterBody -> storedFilterId ?: storedFilterBody
|
||||
else -> saveFilter(currentFilter)
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun saveFilter(filter: Filter) = saveFilterTask
|
||||
.execute(
|
||||
SaveFilterTask.Params(
|
||||
filter = filter
|
||||
)
|
||||
)
|
||||
}
|
|
@ -16,7 +16,6 @@
|
|||
|
||||
package org.matrix.android.sdk.internal.session.filter
|
||||
|
||||
import org.matrix.android.sdk.api.session.sync.FilterService
|
||||
import org.matrix.android.sdk.internal.di.UserId
|
||||
import org.matrix.android.sdk.internal.network.GlobalErrorReceiver
|
||||
import org.matrix.android.sdk.internal.network.executeRequest
|
||||
|
@ -26,10 +25,10 @@ import javax.inject.Inject
|
|||
/**
|
||||
* Save a filter, in db and if any changes, upload to the server.
|
||||
*/
|
||||
internal interface SaveFilterTask : Task<SaveFilterTask.Params, Unit> {
|
||||
internal interface SaveFilterTask : Task<SaveFilterTask.Params, String> {
|
||||
|
||||
data class Params(
|
||||
val filterPreset: FilterService.FilterPreset
|
||||
val filter: Filter
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -37,33 +36,21 @@ internal class DefaultSaveFilterTask @Inject constructor(
|
|||
@UserId private val userId: String,
|
||||
private val filterAPI: FilterApi,
|
||||
private val filterRepository: FilterRepository,
|
||||
private val globalErrorReceiver: GlobalErrorReceiver
|
||||
private val globalErrorReceiver: GlobalErrorReceiver,
|
||||
) : SaveFilterTask {
|
||||
|
||||
override suspend fun execute(params: SaveFilterTask.Params) {
|
||||
val filterBody = when (params.filterPreset) {
|
||||
FilterService.FilterPreset.ElementFilter -> {
|
||||
FilterFactory.createElementFilter()
|
||||
}
|
||||
FilterService.FilterPreset.NoFilter -> {
|
||||
FilterFactory.createDefaultFilter()
|
||||
}
|
||||
}
|
||||
val roomFilter = when (params.filterPreset) {
|
||||
FilterService.FilterPreset.ElementFilter -> {
|
||||
FilterFactory.createElementRoomFilter()
|
||||
}
|
||||
FilterService.FilterPreset.NoFilter -> {
|
||||
FilterFactory.createDefaultRoomFilter()
|
||||
}
|
||||
}
|
||||
val updated = filterRepository.storeFilter(filterBody, roomFilter)
|
||||
if (updated) {
|
||||
val filterResponse = executeRequest(globalErrorReceiver) {
|
||||
// TODO auto retry
|
||||
filterAPI.uploadFilter(userId, filterBody)
|
||||
}
|
||||
filterRepository.storeFilterId(filterBody, filterResponse.filterId)
|
||||
override suspend fun execute(params: SaveFilterTask.Params): String {
|
||||
val filter = params.filter
|
||||
val filterResponse = executeRequest(globalErrorReceiver) {
|
||||
// TODO auto retry
|
||||
filterAPI.uploadFilter(userId, filter)
|
||||
}
|
||||
|
||||
filterRepository.storeSyncFilter(
|
||||
filter = filter,
|
||||
filterId = filterResponse.filterId,
|
||||
roomEventFilter = FilterFactory.createDefaultRoomFilter()
|
||||
)
|
||||
return filterResponse.filterId
|
||||
}
|
||||
}
|
||||
|
|
|
@ -47,7 +47,7 @@ internal class DefaultFetchTokenAndPaginateTask @Inject constructor(
|
|||
) : FetchTokenAndPaginateTask {
|
||||
|
||||
override suspend fun execute(params: FetchTokenAndPaginateTask.Params): TokenChunkEventPersistor.Result {
|
||||
val filter = filterRepository.getRoomFilter()
|
||||
val filter = filterRepository.getRoomFilterBody()
|
||||
val response = executeRequest(globalErrorReceiver) {
|
||||
roomAPI.getContextOfEvent(params.roomId, params.lastKnownEventId, 0, filter)
|
||||
}
|
||||
|
|
|
@ -39,7 +39,7 @@ internal class DefaultGetContextOfEventTask @Inject constructor(
|
|||
) : GetContextOfEventTask {
|
||||
|
||||
override suspend fun execute(params: GetContextOfEventTask.Params): TokenChunkEventPersistor.Result {
|
||||
val filter = filterRepository.getRoomFilter()
|
||||
val filter = filterRepository.getRoomFilterBody()
|
||||
val response = executeRequest(globalErrorReceiver) {
|
||||
// We are limiting the response to the event with eventId to be sure we don't have any issue with potential merging process.
|
||||
roomAPI.getContextOfEvent(params.roomId, params.eventId, 0, filter)
|
||||
|
|
|
@ -41,7 +41,7 @@ internal class DefaultPaginationTask @Inject constructor(
|
|||
) : PaginationTask {
|
||||
|
||||
override suspend fun execute(params: PaginationTask.Params): TokenChunkEventPersistor.Result {
|
||||
val filter = filterRepository.getRoomFilter()
|
||||
val filter = filterRepository.getRoomFilterBody()
|
||||
val chunk = executeRequest(
|
||||
globalErrorReceiver,
|
||||
canRetry = true
|
||||
|
|
|
@ -36,7 +36,7 @@ import org.matrix.android.sdk.internal.network.executeRequest
|
|||
import org.matrix.android.sdk.internal.network.toFailure
|
||||
import org.matrix.android.sdk.internal.session.SessionListeners
|
||||
import org.matrix.android.sdk.internal.session.dispatchTo
|
||||
import org.matrix.android.sdk.internal.session.filter.FilterRepository
|
||||
import org.matrix.android.sdk.internal.session.filter.GetCurrentFilterTask
|
||||
import org.matrix.android.sdk.internal.session.homeserver.GetHomeServerCapabilitiesTask
|
||||
import org.matrix.android.sdk.internal.session.sync.parsing.InitialSyncResponseParser
|
||||
import org.matrix.android.sdk.internal.session.user.UserStore
|
||||
|
@ -64,11 +64,9 @@ internal interface SyncTask : Task<SyncTask.Params, SyncResponse> {
|
|||
internal class DefaultSyncTask @Inject constructor(
|
||||
private val syncAPI: SyncAPI,
|
||||
@UserId private val userId: String,
|
||||
private val filterRepository: FilterRepository,
|
||||
private val syncResponseHandler: SyncResponseHandler,
|
||||
private val syncRequestStateTracker: SyncRequestStateTracker,
|
||||
private val syncTokenStore: SyncTokenStore,
|
||||
private val getHomeServerCapabilitiesTask: GetHomeServerCapabilitiesTask,
|
||||
private val userStore: UserStore,
|
||||
private val session: Session,
|
||||
private val sessionListeners: SessionListeners,
|
||||
|
@ -79,6 +77,8 @@ internal class DefaultSyncTask @Inject constructor(
|
|||
private val syncResponseParser: InitialSyncResponseParser,
|
||||
private val roomSyncEphemeralTemporaryStore: RoomSyncEphemeralTemporaryStore,
|
||||
private val clock: Clock,
|
||||
private val getHomeServerCapabilitiesTask: GetHomeServerCapabilitiesTask,
|
||||
private val getCurrentFilterTask: GetCurrentFilterTask
|
||||
) : SyncTask {
|
||||
|
||||
private val workingDir = File(fileDirectory, "is")
|
||||
|
@ -100,8 +100,13 @@ internal class DefaultSyncTask @Inject constructor(
|
|||
requestParams["since"] = token
|
||||
timeout = params.timeout
|
||||
}
|
||||
|
||||
// Maybe refresh the homeserver capabilities data we know
|
||||
getHomeServerCapabilitiesTask.execute(GetHomeServerCapabilitiesTask.Params(forceRefresh = false))
|
||||
val filter = getCurrentFilterTask.execute(Unit)
|
||||
|
||||
requestParams["timeout"] = timeout.toString()
|
||||
requestParams["filter"] = filterRepository.getFilter()
|
||||
requestParams["filter"] = filter
|
||||
params.presence?.let { requestParams["set_presence"] = it.value }
|
||||
|
||||
val isInitialSync = token == null
|
||||
|
@ -115,8 +120,6 @@ internal class DefaultSyncTask @Inject constructor(
|
|||
)
|
||||
syncRequestStateTracker.startRoot(InitialSyncStep.ImportingAccount, 100)
|
||||
}
|
||||
// Maybe refresh the homeserver capabilities data we know
|
||||
getHomeServerCapabilitiesTask.execute(GetHomeServerCapabilitiesTask.Params(forceRefresh = false))
|
||||
|
||||
val readTimeOut = (params.timeout + TIMEOUT_MARGIN).coerceAtLeast(TimeOutInterceptor.DEFAULT_LONG_TIMEOUT)
|
||||
|
||||
|
|
|
@ -0,0 +1,25 @@
|
|||
/*
|
||||
* Copyright 2022 The Matrix.org Foundation C.I.C.
|
||||
*
|
||||
* 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 org.matrix.android.sdk.internal.sync.filter
|
||||
|
||||
internal data class SyncFilterParams(
|
||||
val lazyLoadMembersForStateEvents: Boolean? = null,
|
||||
val lazyLoadMembersForMessageEvents: Boolean? = null,
|
||||
val useThreadNotifications: Boolean? = null,
|
||||
val listOfSupportedEventTypes: List<String>? = null,
|
||||
val listOfSupportedStateEventTypes: List<String>? = null,
|
||||
)
|
|
@ -0,0 +1,100 @@
|
|||
/*
|
||||
* Copyright 2022 The Matrix.org Foundation C.I.C.
|
||||
*
|
||||
* 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 org.matrix.android.sdk.internal.sync
|
||||
|
||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||
import kotlinx.coroutines.test.runTest
|
||||
import org.amshove.kluent.shouldBeEqualTo
|
||||
import org.junit.Test
|
||||
import org.matrix.android.sdk.api.session.homeserver.HomeServerCapabilities
|
||||
import org.matrix.android.sdk.api.session.sync.filter.SyncFilterBuilder
|
||||
import org.matrix.android.sdk.internal.session.filter.DefaultGetCurrentFilterTask
|
||||
import org.matrix.android.sdk.internal.sync.filter.SyncFilterParams
|
||||
import org.matrix.android.sdk.test.fakes.FakeFilterRepository
|
||||
import org.matrix.android.sdk.test.fakes.FakeHomeServerCapabilitiesDataSource
|
||||
import org.matrix.android.sdk.test.fakes.FakeSaveFilterTask
|
||||
|
||||
private const val A_FILTER_ID = "filter-id"
|
||||
private val A_HOMESERVER_CAPABILITIES = HomeServerCapabilities()
|
||||
private val A_SYNC_FILTER_PARAMS = SyncFilterParams(
|
||||
lazyLoadMembersForMessageEvents = true,
|
||||
lazyLoadMembersForStateEvents = true,
|
||||
useThreadNotifications = true
|
||||
)
|
||||
|
||||
@ExperimentalCoroutinesApi
|
||||
class DefaultGetCurrentFilterTaskTest {
|
||||
|
||||
private val filterRepository = FakeFilterRepository()
|
||||
private val homeServerCapabilitiesDataSource = FakeHomeServerCapabilitiesDataSource()
|
||||
private val saveFilterTask = FakeSaveFilterTask()
|
||||
|
||||
private val getCurrentFilterTask = DefaultGetCurrentFilterTask(
|
||||
filterRepository = filterRepository,
|
||||
homeServerCapabilitiesDataSource = homeServerCapabilitiesDataSource.instance,
|
||||
saveFilterTask = saveFilterTask
|
||||
)
|
||||
|
||||
@Test
|
||||
fun `given no filter is stored, when execute, then executes task to save new filter`() = runTest {
|
||||
filterRepository.givenFilterParamsAreStored(A_SYNC_FILTER_PARAMS)
|
||||
|
||||
homeServerCapabilitiesDataSource.givenHomeServerCapabilities(A_HOMESERVER_CAPABILITIES)
|
||||
|
||||
filterRepository.givenFilterStored(null, null)
|
||||
|
||||
getCurrentFilterTask.execute(Unit)
|
||||
|
||||
val filter = SyncFilterBuilder()
|
||||
.with(A_SYNC_FILTER_PARAMS)
|
||||
.build(A_HOMESERVER_CAPABILITIES)
|
||||
|
||||
saveFilterTask.verifyExecution(filter)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `given filter is stored and didn't change, when execute, then returns stored filter id`() = runTest {
|
||||
filterRepository.givenFilterParamsAreStored(A_SYNC_FILTER_PARAMS)
|
||||
|
||||
homeServerCapabilitiesDataSource.givenHomeServerCapabilities(A_HOMESERVER_CAPABILITIES)
|
||||
|
||||
val filter = SyncFilterBuilder().with(A_SYNC_FILTER_PARAMS).build(A_HOMESERVER_CAPABILITIES)
|
||||
filterRepository.givenFilterStored(A_FILTER_ID, filter.toJSONString())
|
||||
|
||||
val result = getCurrentFilterTask.execute(Unit)
|
||||
|
||||
result shouldBeEqualTo A_FILTER_ID
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `given filter is set and home server capabilities has changed, when execute, then executes task to save new filter`() = runTest {
|
||||
filterRepository.givenFilterParamsAreStored(A_SYNC_FILTER_PARAMS)
|
||||
|
||||
homeServerCapabilitiesDataSource.givenHomeServerCapabilities(A_HOMESERVER_CAPABILITIES)
|
||||
|
||||
val filter = SyncFilterBuilder().with(A_SYNC_FILTER_PARAMS).build(A_HOMESERVER_CAPABILITIES)
|
||||
filterRepository.givenFilterStored(A_FILTER_ID, filter.toJSONString())
|
||||
|
||||
val newHomeServerCapabilities = HomeServerCapabilities(canUseThreadReadReceiptsAndNotifications = true)
|
||||
homeServerCapabilitiesDataSource.givenHomeServerCapabilities(newHomeServerCapabilities)
|
||||
val newFilter = SyncFilterBuilder().with(A_SYNC_FILTER_PARAMS).build(newHomeServerCapabilities)
|
||||
|
||||
getCurrentFilterTask.execute(Unit)
|
||||
|
||||
saveFilterTask.verifyExecution(newFilter)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
/*
|
||||
* Copyright 2022 The Matrix.org Foundation C.I.C.
|
||||
*
|
||||
* 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 org.matrix.android.sdk.test.fakes
|
||||
|
||||
import io.mockk.coEvery
|
||||
import io.mockk.mockk
|
||||
import org.matrix.android.sdk.internal.session.filter.FilterRepository
|
||||
import org.matrix.android.sdk.internal.sync.filter.SyncFilterParams
|
||||
|
||||
internal class FakeFilterRepository : FilterRepository by mockk() {
|
||||
|
||||
fun givenFilterStored(filterId: String?, filterBody: String?) {
|
||||
coEvery { getStoredSyncFilterId() } returns filterId
|
||||
coEvery { getStoredSyncFilterBody() } returns filterBody
|
||||
}
|
||||
|
||||
fun givenFilterParamsAreStored(syncFilterParams: SyncFilterParams?) {
|
||||
coEvery { getStoredFilterParams() } returns syncFilterParams
|
||||
}
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
/*
|
||||
* Copyright 2022 The Matrix.org Foundation C.I.C.
|
||||
*
|
||||
* 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 org.matrix.android.sdk.test.fakes
|
||||
|
||||
import io.mockk.every
|
||||
import io.mockk.mockk
|
||||
import org.matrix.android.sdk.api.session.homeserver.HomeServerCapabilities
|
||||
import org.matrix.android.sdk.internal.session.homeserver.HomeServerCapabilitiesDataSource
|
||||
|
||||
internal class FakeHomeServerCapabilitiesDataSource {
|
||||
val instance = mockk<HomeServerCapabilitiesDataSource>()
|
||||
|
||||
fun givenHomeServerCapabilities(homeServerCapabilities: HomeServerCapabilities) {
|
||||
every { instance.getHomeServerCapabilities() } returns homeServerCapabilities
|
||||
}
|
||||
}
|
|
@ -0,0 +1,40 @@
|
|||
/*
|
||||
* Copyright 2022 The Matrix.org Foundation C.I.C.
|
||||
*
|
||||
* 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 org.matrix.android.sdk.test.fakes
|
||||
|
||||
import io.mockk.coEvery
|
||||
import io.mockk.coVerify
|
||||
import io.mockk.mockk
|
||||
import io.mockk.slot
|
||||
import org.amshove.kluent.shouldBeEqualTo
|
||||
import org.matrix.android.sdk.internal.session.filter.Filter
|
||||
import org.matrix.android.sdk.internal.session.filter.SaveFilterTask
|
||||
import java.util.UUID
|
||||
|
||||
internal class FakeSaveFilterTask : SaveFilterTask by mockk() {
|
||||
|
||||
init {
|
||||
coEvery { execute(any()) } returns UUID.randomUUID().toString()
|
||||
}
|
||||
|
||||
fun verifyExecution(filter: Filter) {
|
||||
val slot = slot<SaveFilterTask.Params>()
|
||||
coVerify { execute(capture(slot)) }
|
||||
val params = slot.captured
|
||||
params.filter shouldBeEqualTo filter
|
||||
}
|
||||
}
|
|
@ -24,9 +24,9 @@ import im.vector.app.core.session.clientinfo.UpdateMatrixClientInfoUseCase
|
|||
import im.vector.app.features.call.webrtc.WebRtcCallManager
|
||||
import im.vector.app.features.session.coroutineScope
|
||||
import im.vector.app.features.settings.VectorPreferences
|
||||
import im.vector.app.features.sync.SyncUtils
|
||||
import kotlinx.coroutines.launch
|
||||
import org.matrix.android.sdk.api.session.Session
|
||||
import org.matrix.android.sdk.api.session.sync.FilterService
|
||||
import timber.log.Timber
|
||||
import javax.inject.Inject
|
||||
|
||||
|
@ -41,7 +41,9 @@ class ConfigureAndStartSessionUseCase @Inject constructor(
|
|||
fun execute(session: Session, startSyncing: Boolean = true) {
|
||||
Timber.i("Configure and start session for ${session.myUserId}. startSyncing: $startSyncing")
|
||||
session.open()
|
||||
session.filterService().setFilter(FilterService.FilterPreset.ElementFilter)
|
||||
session.coroutineScope.launch {
|
||||
session.filterService().setSyncFilter(SyncUtils.getSyncFilterBuilder())
|
||||
}
|
||||
if (startSyncing) {
|
||||
session.startSyncing(context)
|
||||
}
|
||||
|
|
|
@ -0,0 +1,48 @@
|
|||
/*
|
||||
* Copyright (c) 2022 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.app.features.sync
|
||||
|
||||
import org.matrix.android.sdk.api.session.events.model.EventType
|
||||
import org.matrix.android.sdk.api.session.sync.filter.SyncFilterBuilder
|
||||
|
||||
object SyncUtils {
|
||||
// Get only managed types by Element
|
||||
private val listOfSupportedTimelineEventTypes = listOf(
|
||||
// TODO Complete the list
|
||||
EventType.MESSAGE
|
||||
)
|
||||
|
||||
// Get only managed types by Element
|
||||
private val listOfSupportedStateEventTypes = listOf(
|
||||
// TODO Complete the list
|
||||
EventType.STATE_ROOM_MEMBER
|
||||
)
|
||||
|
||||
fun getSyncFilterBuilder(): SyncFilterBuilder {
|
||||
return SyncFilterBuilder()
|
||||
.useThreadNotifications(true)
|
||||
.lazyLoadMembersForStateEvents(true)
|
||||
/**
|
||||
* Currently we don't set [lazy_load_members = true] for Filter.room.timeline even though we set it for RoomFilter which is used later to
|
||||
* fetch messages in a room. It's not clear if it's done so by mistake or intentionally, so changing it could case side effects and need
|
||||
* careful testing
|
||||
* */
|
||||
// .lazyLoadMembersForMessageEvents(true)
|
||||
// .listOfSupportedStateEventTypes(listOfSupportedStateEventTypes)
|
||||
// .listOfSupportedTimelineEventTypes(listOfSupportedTimelineEventTypes)
|
||||
}
|
||||
}
|
|
@ -19,6 +19,7 @@ package im.vector.app.core.session
|
|||
import im.vector.app.core.extensions.startSyncing
|
||||
import im.vector.app.core.session.clientinfo.UpdateMatrixClientInfoUseCase
|
||||
import im.vector.app.features.session.coroutineScope
|
||||
import im.vector.app.features.sync.SyncUtils
|
||||
import im.vector.app.test.fakes.FakeContext
|
||||
import im.vector.app.test.fakes.FakeEnableNotificationsSettingUpdater
|
||||
import im.vector.app.test.fakes.FakeSession
|
||||
|
@ -38,7 +39,6 @@ import kotlinx.coroutines.test.runTest
|
|||
import org.junit.After
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
import org.matrix.android.sdk.api.session.sync.FilterService
|
||||
|
||||
class ConfigureAndStartSessionUseCaseTest {
|
||||
|
||||
|
@ -83,7 +83,7 @@ class ConfigureAndStartSessionUseCaseTest {
|
|||
|
||||
// Then
|
||||
verify { fakeSession.startSyncing(fakeContext.instance) }
|
||||
fakeSession.fakeFilterService.verifySetFilter(FilterService.FilterPreset.ElementFilter)
|
||||
fakeSession.fakeFilterService.verifySetSyncFilter(SyncUtils.getSyncFilterBuilder())
|
||||
fakeSession.fakePushersService.verifyRefreshPushers()
|
||||
fakeWebRtcCallManager.verifyCheckForProtocolsSupportIfNeeded()
|
||||
coVerify { fakeUpdateMatrixClientInfoUseCase.execute(fakeSession) }
|
||||
|
@ -105,7 +105,7 @@ class ConfigureAndStartSessionUseCaseTest {
|
|||
|
||||
// Then
|
||||
verify { fakeSession.startSyncing(fakeContext.instance) }
|
||||
fakeSession.fakeFilterService.verifySetFilter(FilterService.FilterPreset.ElementFilter)
|
||||
fakeSession.fakeFilterService.verifySetSyncFilter(SyncUtils.getSyncFilterBuilder())
|
||||
fakeSession.fakePushersService.verifyRefreshPushers()
|
||||
fakeWebRtcCallManager.verifyCheckForProtocolsSupportIfNeeded()
|
||||
coVerify(inverse = true) { fakeUpdateMatrixClientInfoUseCase.execute(fakeSession) }
|
||||
|
@ -127,7 +127,7 @@ class ConfigureAndStartSessionUseCaseTest {
|
|||
|
||||
// Then
|
||||
verify(inverse = true) { fakeSession.startSyncing(fakeContext.instance) }
|
||||
fakeSession.fakeFilterService.verifySetFilter(FilterService.FilterPreset.ElementFilter)
|
||||
fakeSession.fakeFilterService.verifySetSyncFilter(SyncUtils.getSyncFilterBuilder())
|
||||
fakeSession.fakePushersService.verifyRefreshPushers()
|
||||
fakeWebRtcCallManager.verifyCheckForProtocolsSupportIfNeeded()
|
||||
coVerify { fakeUpdateMatrixClientInfoUseCase.execute(fakeSession) }
|
||||
|
|
|
@ -16,20 +16,21 @@
|
|||
|
||||
package im.vector.app.test.fakes
|
||||
|
||||
import io.mockk.every
|
||||
import io.mockk.coEvery
|
||||
import io.mockk.coVerify
|
||||
import io.mockk.just
|
||||
import io.mockk.mockk
|
||||
import io.mockk.runs
|
||||
import io.mockk.verify
|
||||
import org.matrix.android.sdk.api.session.sync.FilterService
|
||||
import org.matrix.android.sdk.api.session.sync.filter.SyncFilterBuilder
|
||||
|
||||
class FakeFilterService : FilterService by mockk() {
|
||||
|
||||
fun givenSetFilterSucceeds() {
|
||||
every { setFilter(any()) } just runs
|
||||
coEvery { setSyncFilter(any()) } just runs
|
||||
}
|
||||
|
||||
fun verifySetFilter(filterPreset: FilterService.FilterPreset) {
|
||||
verify { setFilter(filterPreset) }
|
||||
fun verifySetSyncFilter(filterBuilder: SyncFilterBuilder) {
|
||||
coVerify { setSyncFilter(filterBuilder) }
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue