Merge pull request #106 from vector-im/feature/apis
Handle filter for sync
This commit is contained in:
commit
65e2abf402
|
@ -53,6 +53,7 @@ class Matrix private constructor(context: Context) : MatrixKoinComponent {
|
|||
authenticator.getLastActiveSession()?.also {
|
||||
currentSession = it
|
||||
it.open()
|
||||
it.startSync()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -24,6 +24,7 @@ import im.vector.matrix.android.api.session.crypto.CryptoService
|
|||
import im.vector.matrix.android.api.session.group.GroupService
|
||||
import im.vector.matrix.android.api.session.room.RoomService
|
||||
import im.vector.matrix.android.api.session.signout.SignOutService
|
||||
import im.vector.matrix.android.api.session.sync.FilterService
|
||||
import im.vector.matrix.android.api.session.user.UserService
|
||||
|
||||
/**
|
||||
|
@ -35,7 +36,8 @@ interface Session :
|
|||
GroupService,
|
||||
UserService,
|
||||
CryptoService,
|
||||
SignOutService {
|
||||
SignOutService,
|
||||
FilterService {
|
||||
|
||||
/**
|
||||
* The params associated to the session
|
||||
|
@ -48,6 +50,18 @@ interface Session :
|
|||
@MainThread
|
||||
fun open()
|
||||
|
||||
/**
|
||||
* This method start the sync thread.
|
||||
*/
|
||||
@MainThread
|
||||
fun startSync()
|
||||
|
||||
/**
|
||||
* This method stop the sync thread.
|
||||
*/
|
||||
@MainThread
|
||||
fun stopSync()
|
||||
|
||||
/**
|
||||
* This method allow to close a session. It does stop some services.
|
||||
*/
|
||||
|
|
|
@ -0,0 +1,33 @@
|
|||
/*
|
||||
* 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.api.session.sync
|
||||
|
||||
interface FilterService {
|
||||
|
||||
enum class FilterPreset {
|
||||
NoFilter,
|
||||
/**
|
||||
* Filter for Riot, will include only known event type
|
||||
*/
|
||||
RiotFilter
|
||||
}
|
||||
|
||||
/**
|
||||
* Configure the filter for the sync
|
||||
*/
|
||||
fun setFilter(filterPreset: FilterPreset)
|
||||
}
|
|
@ -18,6 +18,7 @@ package im.vector.matrix.android.internal.auth
|
|||
|
||||
import android.content.Context
|
||||
import im.vector.matrix.android.api.auth.Authenticator
|
||||
import im.vector.matrix.android.internal.auth.db.AuthRealmModule
|
||||
import im.vector.matrix.android.internal.auth.db.RealmSessionParamsStore
|
||||
import im.vector.matrix.android.internal.auth.db.SessionParamsMapper
|
||||
import io.realm.RealmConfiguration
|
||||
|
@ -43,6 +44,7 @@ class AuthModule {
|
|||
val mapper = SessionParamsMapper((get()))
|
||||
val realmConfiguration = RealmConfiguration.Builder()
|
||||
.name("matrix-sdk-auth.realm")
|
||||
.modules(AuthRealmModule())
|
||||
.deleteRealmIfMigrationNeeded()
|
||||
.build()
|
||||
RealmSessionParamsStore(mapper, realmConfiguration) as SessionParamsStore
|
||||
|
|
|
@ -0,0 +1,28 @@
|
|||
/*
|
||||
* 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.auth.db
|
||||
|
||||
import io.realm.annotations.RealmModule
|
||||
|
||||
/**
|
||||
* Realm module for authentication classes
|
||||
*/
|
||||
@RealmModule(library = true,
|
||||
classes = [
|
||||
SessionParamsEntity::class
|
||||
])
|
||||
internal class AuthRealmModule
|
|
@ -0,0 +1,36 @@
|
|||
/*
|
||||
* 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.model
|
||||
|
||||
import io.realm.RealmObject
|
||||
|
||||
/**
|
||||
* Contain a map between Json filter string and filterId (from Homeserver)
|
||||
* Currently there is only one object in this table
|
||||
*/
|
||||
internal open class FilterEntity(
|
||||
// The serialized FilterBody
|
||||
var filterBodyJson: String = "",
|
||||
// The serialized room event filter for pagination
|
||||
var roomEventFilterJson: String = "",
|
||||
// the id server side of the filterBodyJson, can be used instead of filterBodyJson if not blank
|
||||
var filterId: String = ""
|
||||
|
||||
) : RealmObject() {
|
||||
|
||||
companion object
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
/*
|
||||
* 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.model
|
||||
|
||||
import io.realm.annotations.RealmModule
|
||||
|
||||
/**
|
||||
* Realm module for Session
|
||||
*/
|
||||
@RealmModule(library = true,
|
||||
classes = [
|
||||
ChunkEntity::class,
|
||||
EventEntity::class,
|
||||
FilterEntity::class,
|
||||
GroupEntity::class,
|
||||
GroupSummaryEntity::class,
|
||||
ReadReceiptEntity::class,
|
||||
RoomEntity::class,
|
||||
RoomSummaryEntity::class,
|
||||
RoomTagEntity::class,
|
||||
SyncEntity::class,
|
||||
UserEntity::class
|
||||
])
|
||||
internal class SessionRealmModule
|
|
@ -0,0 +1,44 @@
|
|||
/*
|
||||
* 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.query
|
||||
|
||||
import im.vector.matrix.android.internal.database.model.FilterEntity
|
||||
import im.vector.matrix.android.internal.session.filter.FilterFactory
|
||||
import io.realm.Realm
|
||||
import io.realm.kotlin.createObject
|
||||
import io.realm.kotlin.where
|
||||
|
||||
/**
|
||||
* Get the current filter, create one if it does not exist
|
||||
*/
|
||||
internal fun FilterEntity.Companion.getFilter(realm: Realm): FilterEntity {
|
||||
var filter = realm.where<FilterEntity>().findFirst()
|
||||
|
||||
if (filter == null) {
|
||||
realm.executeTransaction {
|
||||
realm.createObject<FilterEntity>().apply {
|
||||
filterBodyJson = FilterFactory.createDefaultFilterBody().toJSONString()
|
||||
roomEventFilterJson = FilterFactory.createDefaultRoomFilter().toJSONString()
|
||||
filterId = ""
|
||||
}
|
||||
}
|
||||
|
||||
filter = realm.where<FilterEntity>().findFirst()!!
|
||||
}
|
||||
|
||||
return filter
|
||||
}
|
|
@ -33,6 +33,7 @@ import im.vector.matrix.android.api.session.room.RoomService
|
|||
import im.vector.matrix.android.api.session.room.model.RoomSummary
|
||||
import im.vector.matrix.android.api.session.room.model.create.CreateRoomParams
|
||||
import im.vector.matrix.android.api.session.signout.SignOutService
|
||||
import im.vector.matrix.android.api.session.sync.FilterService
|
||||
import im.vector.matrix.android.api.session.user.UserService
|
||||
import im.vector.matrix.android.api.session.user.model.User
|
||||
import im.vector.matrix.android.internal.database.LiveEntityObserver
|
||||
|
@ -63,6 +64,7 @@ internal class DefaultSession(override val sessionParams: SessionParams) : Sessi
|
|||
private val roomService by inject<RoomService>()
|
||||
private val groupService by inject<GroupService>()
|
||||
private val userService by inject<UserService>()
|
||||
private val filterService by inject<FilterService>()
|
||||
private val signOutService by inject<SignOutService>()
|
||||
private val syncThread by inject<SyncThread>()
|
||||
private val contentUrlResolver by inject<ContentUrlResolver>()
|
||||
|
@ -87,15 +89,24 @@ internal class DefaultSession(override val sessionParams: SessionParams) : Sessi
|
|||
monarchy.openManually()
|
||||
}
|
||||
liveEntityUpdaters.forEach { it.start() }
|
||||
}
|
||||
|
||||
@MainThread
|
||||
override fun startSync() {
|
||||
assert(isOpen)
|
||||
syncThread.start()
|
||||
}
|
||||
|
||||
@MainThread
|
||||
override fun stopSync() {
|
||||
assert(isOpen)
|
||||
syncThread.kill()
|
||||
}
|
||||
|
||||
@MainThread
|
||||
override fun close() {
|
||||
assertMainThread()
|
||||
assert(isOpen)
|
||||
syncThread.kill()
|
||||
liveEntityUpdaters.forEach { it.dispose() }
|
||||
if (monarchy.isMonarchyThreadOpen) {
|
||||
monarchy.closeManually()
|
||||
|
@ -110,6 +121,7 @@ internal class DefaultSession(override val sessionParams: SessionParams) : Sessi
|
|||
return signOutService.signOut(object : MatrixCallback<Unit> {
|
||||
override fun onSuccess(data: Unit) {
|
||||
// Close the session
|
||||
stopSync()
|
||||
close()
|
||||
|
||||
callback.onSuccess(data)
|
||||
|
@ -167,6 +179,11 @@ internal class DefaultSession(override val sessionParams: SessionParams) : Sessi
|
|||
return groupService.liveGroupSummaries()
|
||||
}
|
||||
|
||||
override fun setFilter(filterPreset: FilterService.FilterPreset) {
|
||||
assert(isOpen)
|
||||
return filterService.setFilter(filterPreset)
|
||||
}
|
||||
|
||||
// USER SERVICE
|
||||
|
||||
override fun getUser(userId: String): User? {
|
||||
|
|
|
@ -22,8 +22,11 @@ import im.vector.matrix.android.api.auth.data.SessionParams
|
|||
import im.vector.matrix.android.api.session.group.GroupService
|
||||
import im.vector.matrix.android.api.session.room.RoomService
|
||||
import im.vector.matrix.android.api.session.signout.SignOutService
|
||||
import im.vector.matrix.android.api.session.sync.FilterService
|
||||
import im.vector.matrix.android.api.session.user.UserService
|
||||
import im.vector.matrix.android.internal.database.LiveEntityObserver
|
||||
import im.vector.matrix.android.internal.database.model.SessionRealmModule
|
||||
import im.vector.matrix.android.internal.session.filter.*
|
||||
import im.vector.matrix.android.internal.session.group.DefaultGroupService
|
||||
import im.vector.matrix.android.internal.session.group.GroupSummaryUpdater
|
||||
import im.vector.matrix.android.internal.session.room.DefaultRoomService
|
||||
|
@ -61,6 +64,7 @@ internal class SessionModule(private val sessionParams: SessionParams) {
|
|||
RealmConfiguration.Builder()
|
||||
.directory(directory)
|
||||
.name("disk_store.realm")
|
||||
.modules(SessionRealmModule())
|
||||
.deleteRealmIfMigrationNeeded()
|
||||
.build()
|
||||
}
|
||||
|
@ -87,7 +91,7 @@ internal class SessionModule(private val sessionParams: SessionParams) {
|
|||
}
|
||||
|
||||
scope(DefaultSession.SCOPE) {
|
||||
RoomAvatarResolver(get(), sessionParams.credentials)
|
||||
RoomAvatarResolver(get(), get())
|
||||
}
|
||||
|
||||
scope(DefaultSession.SCOPE) {
|
||||
|
@ -114,6 +118,23 @@ internal class SessionModule(private val sessionParams: SessionParams) {
|
|||
SessionListeners()
|
||||
}
|
||||
|
||||
scope(DefaultSession.SCOPE) {
|
||||
DefaultFilterRepository(get()) as FilterRepository
|
||||
}
|
||||
|
||||
scope(DefaultSession.SCOPE) {
|
||||
DefaultSaveFilterTask(get(), get(), get()) as SaveFilterTask
|
||||
}
|
||||
|
||||
scope(DefaultSession.SCOPE) {
|
||||
DefaultFilterService(get(), get(), get()) as FilterService
|
||||
}
|
||||
|
||||
scope(DefaultSession.SCOPE) {
|
||||
val retrofit: Retrofit = get()
|
||||
retrofit.create(FilterApi::class.java)
|
||||
}
|
||||
|
||||
scope(DefaultSession.SCOPE) {
|
||||
val groupSummaryUpdater = GroupSummaryUpdater(get())
|
||||
val eventsPruner = EventsPruner(get())
|
||||
|
|
|
@ -0,0 +1,107 @@
|
|||
/*
|
||||
* 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.filter
|
||||
|
||||
import im.vector.matrix.android.internal.database.model.FilterEntity
|
||||
import im.vector.matrix.android.internal.database.model.FilterEntityFields
|
||||
import im.vector.matrix.android.internal.database.query.getFilter
|
||||
import io.realm.Realm
|
||||
import io.realm.RealmConfiguration
|
||||
import io.realm.kotlin.where
|
||||
|
||||
internal class DefaultFilterRepository(val realmConfiguration: RealmConfiguration) : FilterRepository {
|
||||
|
||||
override fun storeFilter(filterBody: FilterBody, roomEventFilter: RoomEventFilter): Boolean {
|
||||
val result: Boolean
|
||||
|
||||
val realm = Realm.getInstance(realmConfiguration)
|
||||
|
||||
val filter = FilterEntity.getFilter(realm)
|
||||
|
||||
if (filter.filterBodyJson != filterBody.toJSONString()) {
|
||||
// Filter has changed, store it and reset the filter Id
|
||||
realm.executeTransaction {
|
||||
// We manage only one filter for now
|
||||
val filterBodyJson = filterBody.toJSONString()
|
||||
val roomEventFilterJson = roomEventFilter.toJSONString()
|
||||
|
||||
val filterEntity = FilterEntity.getFilter(it)
|
||||
|
||||
filterEntity.filterBodyJson = filterBodyJson
|
||||
filterEntity.roomEventFilterJson = roomEventFilterJson
|
||||
// Reset filterId
|
||||
filterEntity.filterId = ""
|
||||
}
|
||||
result = true
|
||||
} else {
|
||||
result = filter.filterId.isBlank()
|
||||
}
|
||||
|
||||
realm.close()
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
override fun storeFilterId(filterBody: FilterBody, filterId: String) {
|
||||
val realm = Realm.getInstance(realmConfiguration)
|
||||
|
||||
realm.executeTransaction {
|
||||
// We manage only one filter for now
|
||||
val filterBodyJson = filterBody.toJSONString()
|
||||
|
||||
// Update the filter id, only if the filter body matches
|
||||
it.where<FilterEntity>()
|
||||
.equalTo(FilterEntityFields.FILTER_BODY_JSON, filterBodyJson)
|
||||
?.findFirst()
|
||||
?.filterId = filterId
|
||||
}
|
||||
|
||||
realm.close()
|
||||
}
|
||||
|
||||
override fun getFilter(): String {
|
||||
val result: String
|
||||
|
||||
val realm = Realm.getInstance(realmConfiguration)
|
||||
|
||||
val filter = FilterEntity.getFilter(realm)
|
||||
|
||||
result = if (filter.filterId.isBlank()) {
|
||||
// Use the Json format
|
||||
filter.filterBodyJson
|
||||
} else {
|
||||
// Use FilterId
|
||||
filter.filterId
|
||||
}
|
||||
|
||||
realm.close()
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
override fun getRoomFilter(): String {
|
||||
val realm = Realm.getInstance(realmConfiguration)
|
||||
|
||||
val filter = FilterEntity.getFilter(realm)
|
||||
|
||||
val result = filter.roomEventFilterJson
|
||||
|
||||
realm.close()
|
||||
|
||||
return result
|
||||
}
|
||||
}
|
|
@ -0,0 +1,55 @@
|
|||
/*
|
||||
* 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.filter
|
||||
|
||||
import im.vector.matrix.android.api.session.sync.FilterService
|
||||
import im.vector.matrix.android.internal.task.TaskExecutor
|
||||
import im.vector.matrix.android.internal.task.configureWith
|
||||
|
||||
internal class DefaultFilterService(private val filterRepository: FilterRepository,
|
||||
private val saveFilterTask: SaveFilterTask,
|
||||
private val taskExecutor: TaskExecutor) : FilterService {
|
||||
|
||||
// TODO Pass a list of support events instead
|
||||
override fun setFilter(filterPreset: FilterService.FilterPreset) {
|
||||
val filterBody = when (filterPreset) {
|
||||
FilterService.FilterPreset.RiotFilter -> {
|
||||
FilterFactory.createRiotFilterBody()
|
||||
}
|
||||
FilterService.FilterPreset.NoFilter -> {
|
||||
FilterFactory.createDefaultFilterBody()
|
||||
}
|
||||
}
|
||||
|
||||
val roomFilter = when (filterPreset) {
|
||||
FilterService.FilterPreset.RiotFilter -> {
|
||||
FilterFactory.createRiotRoomFilter()
|
||||
}
|
||||
FilterService.FilterPreset.NoFilter -> {
|
||||
FilterFactory.createDefaultRoomFilter()
|
||||
}
|
||||
}
|
||||
|
||||
val updated = filterRepository.storeFilter(filterBody, roomFilter)
|
||||
|
||||
if (updated) {
|
||||
saveFilterTask
|
||||
.configureWith(SaveFilterTask.Params(filterBody))
|
||||
.executeBy(taskExecutor)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,52 @@
|
|||
/*
|
||||
* 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.filter
|
||||
|
||||
import arrow.core.Try
|
||||
import im.vector.matrix.android.api.auth.data.SessionParams
|
||||
import im.vector.matrix.android.internal.network.executeRequest
|
||||
import im.vector.matrix.android.internal.task.Task
|
||||
|
||||
|
||||
/**
|
||||
* Save a filter to the server
|
||||
*/
|
||||
internal interface SaveFilterTask : Task<SaveFilterTask.Params, Unit> {
|
||||
|
||||
data class Params(
|
||||
val filter: FilterBody
|
||||
)
|
||||
|
||||
}
|
||||
|
||||
internal class DefaultSaveFilterTask(private val sessionParams: SessionParams,
|
||||
private val filterAPI: FilterApi,
|
||||
private val filterRepository: FilterRepository
|
||||
) : SaveFilterTask {
|
||||
|
||||
override fun execute(params: SaveFilterTask.Params): Try<Unit> {
|
||||
return executeRequest<FilterResponse> {
|
||||
// TODO auto retry
|
||||
apiCall = filterAPI.uploadFilter(sessionParams.credentials.userId, params.filter)
|
||||
}.flatMap { filterResponse ->
|
||||
Try {
|
||||
filterRepository.storeFilterId(params.filter, filterResponse.filterId)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,46 @@
|
|||
/*
|
||||
* Copyright 2018 Matthias Kesler
|
||||
* Copyright 2018 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.filter
|
||||
|
||||
import im.vector.matrix.android.internal.network.NetworkConstants
|
||||
import retrofit2.Call
|
||||
import retrofit2.http.Body
|
||||
import retrofit2.http.GET
|
||||
import retrofit2.http.POST
|
||||
import retrofit2.http.Path
|
||||
|
||||
internal interface FilterApi {
|
||||
|
||||
/**
|
||||
* Upload FilterBody to get a filter_id which can be used for /sync requests
|
||||
*
|
||||
* @param userId the user id
|
||||
* @param body the Json representation of a FilterBody object
|
||||
*/
|
||||
@POST(NetworkConstants.URI_API_PREFIX_PATH_R0 + "user/{userId}/filter")
|
||||
fun uploadFilter(@Path("userId") userId: String, @Body body: FilterBody): Call<FilterResponse>
|
||||
|
||||
/**
|
||||
* Gets a filter with a given filterId from the homeserver
|
||||
*
|
||||
* @param userId the user id
|
||||
* @param filterId the filterID
|
||||
* @return Filter
|
||||
*/
|
||||
@GET(NetworkConstants.URI_API_PREFIX_PATH_R0 + "user/{userId}/filter/{filterId}")
|
||||
fun getFilterById(@Path("userId") userId: String, @Path("filterId") filterId: String): Call<FilterBody>
|
||||
}
|
|
@ -0,0 +1,81 @@
|
|||
/*
|
||||
* 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.filter
|
||||
|
||||
import im.vector.matrix.android.api.session.events.model.EventType
|
||||
|
||||
internal object FilterFactory {
|
||||
|
||||
fun createDefaultFilterBody(): FilterBody {
|
||||
val filterBody = FilterBody()
|
||||
FilterUtil.enableLazyLoading(filterBody, true)
|
||||
|
||||
return filterBody
|
||||
}
|
||||
|
||||
fun createRiotFilterBody(): FilterBody {
|
||||
val filterBody = FilterBody()
|
||||
|
||||
filterBody.room = RoomFilter().apply {
|
||||
timeline = createRiotTimelineFilter()
|
||||
// TODO Enable this for optimization
|
||||
// state = createRiotStateFilter()
|
||||
}
|
||||
|
||||
return filterBody
|
||||
}
|
||||
|
||||
fun createDefaultRoomFilter(): RoomEventFilter {
|
||||
return RoomEventFilter().apply {
|
||||
lazyLoadMembers = true
|
||||
}
|
||||
}
|
||||
|
||||
fun createRiotRoomFilter(): RoomEventFilter {
|
||||
return RoomEventFilter().apply {
|
||||
lazyLoadMembers = true
|
||||
// TODO Enable this for optimization
|
||||
// types = (listOfSupportedEventTypes + listOfSupportedStateEventTypes).toMutableList()
|
||||
}
|
||||
}
|
||||
|
||||
private fun createRiotTimelineFilter(): RoomEventFilter {
|
||||
return RoomEventFilter().apply {
|
||||
lazyLoadMembers = true
|
||||
// TODO Enable this for optimization
|
||||
// types = listOfSupportedEventTypes.toMutableList()
|
||||
}
|
||||
}
|
||||
|
||||
private fun createRiotStateFilter(): RoomEventFilter {
|
||||
return RoomEventFilter().apply {
|
||||
types = listOfSupportedStateEventTypes.toMutableList()
|
||||
}
|
||||
}
|
||||
|
||||
// Get only managed types by Riot
|
||||
private val listOfSupportedEventTypes = listOf(
|
||||
// TODO Complete the list
|
||||
EventType.MESSAGE
|
||||
)
|
||||
|
||||
// Get only managed types by Riot
|
||||
private val listOfSupportedStateEventTypes = listOf(
|
||||
// TODO Complete the list
|
||||
EventType.STATE_ROOM_MEMBER
|
||||
)
|
||||
}
|
|
@ -0,0 +1,40 @@
|
|||
/*
|
||||
* 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.filter
|
||||
|
||||
internal interface FilterRepository {
|
||||
|
||||
/**
|
||||
* Return true if the filterBody has changed, or need to be sent to the server
|
||||
*/
|
||||
fun storeFilter(filterBody: FilterBody, roomEventFilter: RoomEventFilter): Boolean
|
||||
|
||||
/**
|
||||
* Set the filterId of this filter
|
||||
*/
|
||||
fun storeFilterId(filterBody: FilterBody, filterId: String)
|
||||
|
||||
/**
|
||||
* Return filter json or filter id
|
||||
*/
|
||||
fun getFilter(): String
|
||||
|
||||
/**
|
||||
* Return the room filter
|
||||
*/
|
||||
fun getRoomFilter(): String
|
||||
}
|
|
@ -14,12 +14,7 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package im.vector.matrix.android.internal.util
|
||||
|
||||
import im.vector.matrix.android.internal.session.filter.Filter
|
||||
import im.vector.matrix.android.internal.session.filter.FilterBody
|
||||
import im.vector.matrix.android.internal.session.filter.RoomEventFilter
|
||||
import im.vector.matrix.android.internal.session.filter.RoomFilter
|
||||
package im.vector.matrix.android.internal.session.filter
|
||||
|
||||
internal object FilterUtil {
|
||||
|
||||
|
@ -121,21 +116,4 @@ internal object FilterUtil {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a RoomEventFilter
|
||||
*
|
||||
* @param withLazyLoading true when lazy loading is enabled
|
||||
* @return a RoomEventFilter or null if lazy loading if OFF
|
||||
*/
|
||||
fun createRoomEventFilter(withLazyLoading: Boolean): RoomEventFilter? {
|
||||
var roomEventFilter: RoomEventFilter? = null
|
||||
|
||||
if (withLazyLoading) {
|
||||
roomEventFilter = RoomEventFilter()
|
||||
roomEventFilter.lazyLoadMembers = true
|
||||
}
|
||||
|
||||
return roomEventFilter
|
||||
}
|
||||
}
|
|
@ -55,11 +55,11 @@ class RoomModule {
|
|||
}
|
||||
|
||||
scope(DefaultSession.SCOPE) {
|
||||
DefaultPaginationTask(get(), get()) as PaginationTask
|
||||
DefaultPaginationTask(get(), get(), get()) as PaginationTask
|
||||
}
|
||||
|
||||
scope(DefaultSession.SCOPE) {
|
||||
DefaultGetContextOfEventTask(get(), get()) as GetContextOfEventTask
|
||||
DefaultGetContextOfEventTask(get(), get(), get()) as GetContextOfEventTask
|
||||
}
|
||||
|
||||
scope(DefaultSession.SCOPE) {
|
||||
|
|
|
@ -18,9 +18,9 @@ package im.vector.matrix.android.internal.session.room.timeline
|
|||
|
||||
import arrow.core.Try
|
||||
import im.vector.matrix.android.internal.network.executeRequest
|
||||
import im.vector.matrix.android.internal.session.filter.FilterRepository
|
||||
import im.vector.matrix.android.internal.session.room.RoomAPI
|
||||
import im.vector.matrix.android.internal.task.Task
|
||||
import im.vector.matrix.android.internal.util.FilterUtil
|
||||
|
||||
internal interface GetContextOfEventTask : Task<GetContextOfEventTask.Params, TokenChunkEventPersistor.Result> {
|
||||
|
||||
|
@ -32,11 +32,12 @@ internal interface GetContextOfEventTask : Task<GetContextOfEventTask.Params, To
|
|||
}
|
||||
|
||||
internal class DefaultGetContextOfEventTask(private val roomAPI: RoomAPI,
|
||||
private val filterRepository: FilterRepository,
|
||||
private val tokenChunkEventPersistor: TokenChunkEventPersistor
|
||||
) : GetContextOfEventTask {
|
||||
|
||||
override fun execute(params: GetContextOfEventTask.Params): Try<TokenChunkEventPersistor.Result> {
|
||||
val filter = FilterUtil.createRoomEventFilter(true)?.toJSONString()
|
||||
val filter = filterRepository.getRoomFilter()
|
||||
return executeRequest<EventContextResponse> {
|
||||
apiCall = roomAPI.getContextOfEvent(params.roomId, params.eventId, 0, filter)
|
||||
}.flatMap { response ->
|
||||
|
|
|
@ -18,9 +18,9 @@ package im.vector.matrix.android.internal.session.room.timeline
|
|||
|
||||
import arrow.core.Try
|
||||
import im.vector.matrix.android.internal.network.executeRequest
|
||||
import im.vector.matrix.android.internal.session.filter.FilterRepository
|
||||
import im.vector.matrix.android.internal.session.room.RoomAPI
|
||||
import im.vector.matrix.android.internal.task.Task
|
||||
import im.vector.matrix.android.internal.util.FilterUtil
|
||||
|
||||
|
||||
internal interface PaginationTask : Task<PaginationTask.Params, TokenChunkEventPersistor.Result> {
|
||||
|
@ -35,11 +35,12 @@ internal interface PaginationTask : Task<PaginationTask.Params, TokenChunkEventP
|
|||
}
|
||||
|
||||
internal class DefaultPaginationTask(private val roomAPI: RoomAPI,
|
||||
private val filterRepository: FilterRepository,
|
||||
private val tokenChunkEventPersistor: TokenChunkEventPersistor
|
||||
) : PaginationTask {
|
||||
|
||||
override fun execute(params: PaginationTask.Params): Try<TokenChunkEventPersistor.Result> {
|
||||
val filter = FilterUtil.createRoomEventFilter(true)?.toJSONString()
|
||||
val filter = filterRepository.getRoomFilter()
|
||||
return executeRequest<PaginationResponse> {
|
||||
apiCall = roomAPI.getRoomMessagesFrom(params.roomId, params.from, params.direction.value, params.limit, filter)
|
||||
}.flatMap { chunk ->
|
||||
|
|
|
@ -56,7 +56,7 @@ internal class SyncModule {
|
|||
}
|
||||
|
||||
scope(DefaultSession.SCOPE) {
|
||||
DefaultSyncTask(get(), get()) as SyncTask
|
||||
DefaultSyncTask(get(), get(), get()) as SyncTask
|
||||
}
|
||||
|
||||
scope(DefaultSession.SCOPE) {
|
||||
|
|
|
@ -17,11 +17,10 @@
|
|||
package im.vector.matrix.android.internal.session.sync
|
||||
|
||||
import arrow.core.Try
|
||||
import im.vector.matrix.android.internal.task.Task
|
||||
import im.vector.matrix.android.internal.network.executeRequest
|
||||
import im.vector.matrix.android.internal.session.filter.FilterBody
|
||||
import im.vector.matrix.android.internal.session.filter.FilterRepository
|
||||
import im.vector.matrix.android.internal.session.sync.model.SyncResponse
|
||||
import im.vector.matrix.android.internal.util.FilterUtil
|
||||
import im.vector.matrix.android.internal.task.Task
|
||||
|
||||
internal interface SyncTask : Task<SyncTask.Params, SyncResponse> {
|
||||
|
||||
|
@ -30,21 +29,20 @@ internal interface SyncTask : Task<SyncTask.Params, SyncResponse> {
|
|||
}
|
||||
|
||||
internal class DefaultSyncTask(private val syncAPI: SyncAPI,
|
||||
private val filterRepository: FilterRepository,
|
||||
private val syncResponseHandler: SyncResponseHandler
|
||||
) : SyncTask {
|
||||
|
||||
|
||||
override fun execute(params: SyncTask.Params): Try<SyncResponse> {
|
||||
val requestParams = HashMap<String, String>()
|
||||
val filterBody = FilterBody()
|
||||
FilterUtil.enableLazyLoading(filterBody, true)
|
||||
var timeout = 0
|
||||
if (params.token != null) {
|
||||
requestParams["since"] = params.token
|
||||
timeout = 30000
|
||||
}
|
||||
requestParams["timeout"] = timeout.toString()
|
||||
requestParams["filter"] = filterBody.toJSONString()
|
||||
requestParams["filter"] = filterRepository.getFilter()
|
||||
|
||||
return executeRequest<SyncResponse> {
|
||||
apiCall = syncAPI.sync(requestParams)
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
|
||||
package im.vector.matrix.android.internal.session.sync.job
|
||||
|
||||
import com.squareup.moshi.JsonEncodingException
|
||||
import im.vector.matrix.android.api.MatrixCallback
|
||||
import im.vector.matrix.android.api.failure.Failure
|
||||
import im.vector.matrix.android.api.util.Cancelable
|
||||
|
@ -118,7 +119,8 @@ internal class SyncThread(private val syncTask: SyncTask,
|
|||
Timber.e(failure)
|
||||
}
|
||||
|
||||
if (failure !is Failure.NetworkConnection) {
|
||||
if (failure !is Failure.NetworkConnection
|
||||
|| failure.cause is JsonEncodingException) {
|
||||
// Wait 10s before retrying
|
||||
sleep(RETRY_WAIT_TIME_MS)
|
||||
}
|
||||
|
|
|
@ -25,6 +25,7 @@ import im.vector.matrix.android.api.Matrix
|
|||
import im.vector.matrix.android.api.MatrixCallback
|
||||
import im.vector.matrix.android.api.session.Session
|
||||
import im.vector.matrix.android.api.session.room.model.create.CreateRoomParams
|
||||
import im.vector.matrix.android.api.session.sync.FilterService
|
||||
import im.vector.matrix.rx.rx
|
||||
import im.vector.riotredesign.core.platform.VectorViewModel
|
||||
import im.vector.riotredesign.core.utils.LiveEvent
|
||||
|
@ -58,6 +59,9 @@ class HomeActivityViewModel(state: EmptyState,
|
|||
get() = _openRoomLiveData
|
||||
|
||||
init {
|
||||
// TODO Move this else where, it's too late when we are here to change the filter
|
||||
session.setFilter(FilterService.FilterPreset.RiotFilter)
|
||||
|
||||
val lastSelectedRoomId = roomSelectionRepository.lastSelectedRoom()
|
||||
if (lastSelectedRoomId == null || session.getRoom(lastSelectedRoomId) == null) {
|
||||
getTheFirstRoomWhenAvailable()
|
||||
|
|
|
@ -30,9 +30,6 @@ import androidx.recyclerview.widget.LinearLayoutManager
|
|||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.airbnb.epoxy.EpoxyVisibilityTracker
|
||||
import com.airbnb.mvrx.fragmentViewModel
|
||||
import com.jaiselrahman.filepicker.activity.FilePickerActivity
|
||||
import com.jaiselrahman.filepicker.config.Configurations
|
||||
import com.jaiselrahman.filepicker.model.MediaFile
|
||||
import com.otaliastudios.autocomplete.Autocomplete
|
||||
import com.otaliastudios.autocomplete.AutocompleteCallback
|
||||
import com.otaliastudios.autocomplete.CharPolicy
|
||||
|
@ -46,12 +43,7 @@ import im.vector.riotredesign.core.extensions.observeEvent
|
|||
import im.vector.riotredesign.core.glide.GlideApp
|
||||
import im.vector.riotredesign.core.platform.ToolbarConfigurable
|
||||
import im.vector.riotredesign.core.platform.VectorBaseFragment
|
||||
import im.vector.riotredesign.core.utils.PERMISSIONS_FOR_TAKING_PHOTO
|
||||
import im.vector.riotredesign.core.utils.PERMISSION_REQUEST_CODE_LAUNCH_CAMERA
|
||||
import im.vector.riotredesign.core.utils.PERMISSION_REQUEST_CODE_LAUNCH_NATIVE_CAMERA
|
||||
import im.vector.riotredesign.core.utils.PERMISSION_REQUEST_CODE_LAUNCH_NATIVE_VIDEO_CAMERA
|
||||
import im.vector.riotredesign.core.utils.checkPermissions
|
||||
import im.vector.riotredesign.core.utils.openCamera
|
||||
import im.vector.riotredesign.core.utils.*
|
||||
import im.vector.riotredesign.features.autocomplete.command.AutocompleteCommandPresenter
|
||||
import im.vector.riotredesign.features.autocomplete.command.CommandAutocompletePolicy
|
||||
import im.vector.riotredesign.features.autocomplete.user.AutocompleteUserPresenter
|
||||
|
@ -288,24 +280,27 @@ class RoomDetailFragment : VectorBaseFragment(), TimelineEventController.Callbac
|
|||
private fun onSendChoiceClicked(dialogListItem: DialogListItem) {
|
||||
Timber.v("On send choice clicked: $dialogListItem")
|
||||
when (dialogListItem) {
|
||||
is DialogListItem.SendFile -> {
|
||||
is DialogListItem.SendFile -> {
|
||||
// launchFileIntent
|
||||
}
|
||||
is DialogListItem.SendVoice -> {
|
||||
is DialogListItem.SendVoice -> {
|
||||
//launchAudioRecorderIntent()
|
||||
}
|
||||
is DialogListItem.SendSticker -> {
|
||||
is DialogListItem.SendSticker -> {
|
||||
//startStickerPickerActivity()
|
||||
}
|
||||
is DialogListItem.TakePhotoVideo -> if (checkPermissions(PERMISSIONS_FOR_TAKING_PHOTO, requireActivity(), PERMISSION_REQUEST_CODE_LAUNCH_CAMERA)) {
|
||||
// launchCamera()
|
||||
}
|
||||
is DialogListItem.TakePhoto -> if (checkPermissions(PERMISSIONS_FOR_TAKING_PHOTO, requireActivity(), PERMISSION_REQUEST_CODE_LAUNCH_NATIVE_CAMERA)) {
|
||||
openCamera(requireActivity(), CAMERA_VALUE_TITLE, TAKE_IMAGE_REQUEST_CODE)
|
||||
}
|
||||
is DialogListItem.TakeVideo -> if (checkPermissions(PERMISSIONS_FOR_TAKING_PHOTO, requireActivity(), PERMISSION_REQUEST_CODE_LAUNCH_NATIVE_VIDEO_CAMERA)) {
|
||||
// launchNativeVideoRecorder()
|
||||
}
|
||||
is DialogListItem.TakePhotoVideo ->
|
||||
if (checkPermissions(PERMISSIONS_FOR_TAKING_PHOTO, requireActivity(), PERMISSION_REQUEST_CODE_LAUNCH_CAMERA)) {
|
||||
// launchCamera()
|
||||
}
|
||||
is DialogListItem.TakePhoto ->
|
||||
if (checkPermissions(PERMISSIONS_FOR_TAKING_PHOTO, requireActivity(), PERMISSION_REQUEST_CODE_LAUNCH_NATIVE_CAMERA)) {
|
||||
openCamera(requireActivity(), CAMERA_VALUE_TITLE, TAKE_IMAGE_REQUEST_CODE)
|
||||
}
|
||||
is DialogListItem.TakeVideo ->
|
||||
if (checkPermissions(PERMISSIONS_FOR_TAKING_PHOTO, requireActivity(), PERMISSION_REQUEST_CODE_LAUNCH_NATIVE_VIDEO_CAMERA)) {
|
||||
// launchNativeVideoRecorder()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -339,20 +334,20 @@ class RoomDetailFragment : VectorBaseFragment(), TimelineEventController.Callbac
|
|||
private fun renderSendMessageResult(sendMessageResult: SendMessageResult) {
|
||||
when (sendMessageResult) {
|
||||
is SendMessageResult.MessageSent,
|
||||
is SendMessageResult.SlashCommandHandled -> {
|
||||
is SendMessageResult.SlashCommandHandled -> {
|
||||
// Clear composer
|
||||
composerEditText.text = null
|
||||
}
|
||||
is SendMessageResult.SlashCommandError -> {
|
||||
is SendMessageResult.SlashCommandError -> {
|
||||
displayCommandError(getString(R.string.command_problem_with_parameters, sendMessageResult.command.command))
|
||||
}
|
||||
is SendMessageResult.SlashCommandUnknown -> {
|
||||
is SendMessageResult.SlashCommandUnknown -> {
|
||||
displayCommandError(getString(R.string.unrecognized_command, sendMessageResult.command))
|
||||
}
|
||||
is SendMessageResult.SlashCommandResultOk -> {
|
||||
is SendMessageResult.SlashCommandResultOk -> {
|
||||
// Ignore
|
||||
}
|
||||
is SendMessageResult.SlashCommandResultError -> {
|
||||
is SendMessageResult.SlashCommandResultError -> {
|
||||
displayCommandError(sendMessageResult.throwable.localizedMessage)
|
||||
}
|
||||
is SendMessageResult.SlashCommandNotImplemented -> {
|
||||
|
|
|
@ -27,6 +27,7 @@ import im.vector.matrix.android.api.Matrix
|
|||
import im.vector.matrix.android.api.MatrixCallback
|
||||
import im.vector.matrix.android.api.auth.data.HomeServerConnectionConfig
|
||||
import im.vector.matrix.android.api.session.Session
|
||||
import im.vector.matrix.android.api.session.sync.FilterService
|
||||
import im.vector.riotredesign.R
|
||||
import im.vector.riotredesign.core.platform.VectorBaseActivity
|
||||
import im.vector.riotredesign.features.home.HomeActivity
|
||||
|
@ -63,7 +64,11 @@ class LoginActivity : VectorBaseActivity() {
|
|||
progressBar.visibility = View.VISIBLE
|
||||
authenticator.authenticate(homeServerConnectionConfig, login, password, object : MatrixCallback<Session> {
|
||||
override fun onSuccess(data: Session) {
|
||||
Matrix.getInstance().currentSession = data.apply { open() }
|
||||
Matrix.getInstance().currentSession = data
|
||||
data.open()
|
||||
data.setFilter(FilterService.FilterPreset.RiotFilter)
|
||||
data.startSync()
|
||||
|
||||
goToHome()
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue