Merge pull request #106 from vector-im/feature/apis

Handle filter for sync
This commit is contained in:
Benoit Marty 2019-04-17 12:35:31 +02:00 committed by GitHub
commit 65e2abf402
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
26 changed files with 666 additions and 67 deletions

View File

@ -53,6 +53,7 @@ class Matrix private constructor(context: Context) : MatrixKoinComponent {
authenticator.getLastActiveSession()?.also {
currentSession = it
it.open()
it.startSync()
}
}


View File

@ -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.
*/

View File

@ -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)
}

View File

@ -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

View File

@ -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

View File

@ -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
}

View File

@ -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

View File

@ -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
}

View File

@ -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? {

View File

@ -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())

View File

@ -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
}
}

View File

@ -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)
}
}
}

View File

@ -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)
}
}
}

}

View File

@ -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>
}

View File

@ -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
)
}

View File

@ -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
}

View File

@ -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
}
}

View File

@ -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) {

View File

@ -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 ->

View File

@ -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 ->

View File

@ -56,7 +56,7 @@ internal class SyncModule {
}

scope(DefaultSession.SCOPE) {
DefaultSyncTask(get(), get()) as SyncTask
DefaultSyncTask(get(), get(), get()) as SyncTask
}

scope(DefaultSession.SCOPE) {

View File

@ -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)

View File

@ -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)
}

View File

@ -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()

View File

@ -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 -> {

View File

@ -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()
}