mirror of
https://github.com/SchildiChat/SchildiChat-android.git
synced 2024-11-23 09:56:00 +03:00
Timeline: fetch next token with the help of getContext when required
This commit is contained in:
parent
ffeae7ec83
commit
458e3ee5e8
5 changed files with 138 additions and 55 deletions
|
@ -56,8 +56,10 @@ import im.vector.matrix.android.internal.session.room.reporting.DefaultReportCon
|
||||||
import im.vector.matrix.android.internal.session.room.reporting.ReportContentTask
|
import im.vector.matrix.android.internal.session.room.reporting.ReportContentTask
|
||||||
import im.vector.matrix.android.internal.session.room.state.DefaultSendStateTask
|
import im.vector.matrix.android.internal.session.room.state.DefaultSendStateTask
|
||||||
import im.vector.matrix.android.internal.session.room.state.SendStateTask
|
import im.vector.matrix.android.internal.session.room.state.SendStateTask
|
||||||
|
import im.vector.matrix.android.internal.session.room.timeline.DefaultFetchNextTokenAndPaginateTask
|
||||||
import im.vector.matrix.android.internal.session.room.timeline.DefaultGetContextOfEventTask
|
import im.vector.matrix.android.internal.session.room.timeline.DefaultGetContextOfEventTask
|
||||||
import im.vector.matrix.android.internal.session.room.timeline.DefaultPaginationTask
|
import im.vector.matrix.android.internal.session.room.timeline.DefaultPaginationTask
|
||||||
|
import im.vector.matrix.android.internal.session.room.timeline.FetchNextTokenAndPaginateTask
|
||||||
import im.vector.matrix.android.internal.session.room.timeline.GetContextOfEventTask
|
import im.vector.matrix.android.internal.session.room.timeline.GetContextOfEventTask
|
||||||
import im.vector.matrix.android.internal.session.room.timeline.PaginationTask
|
import im.vector.matrix.android.internal.session.room.timeline.PaginationTask
|
||||||
import im.vector.matrix.android.internal.session.room.typing.DefaultSendTypingTask
|
import im.vector.matrix.android.internal.session.room.typing.DefaultSendTypingTask
|
||||||
|
@ -143,6 +145,9 @@ internal abstract class RoomModule {
|
||||||
@Binds
|
@Binds
|
||||||
abstract fun bindPaginationTask(task: DefaultPaginationTask): PaginationTask
|
abstract fun bindPaginationTask(task: DefaultPaginationTask): PaginationTask
|
||||||
|
|
||||||
|
@Binds
|
||||||
|
abstract fun bindFetchNextTokenAndPaginateTask(task: DefaultFetchNextTokenAndPaginateTask): FetchNextTokenAndPaginateTask
|
||||||
|
|
||||||
@Binds
|
@Binds
|
||||||
abstract fun bindFetchEditHistoryTask(task: DefaultFetchEditHistoryTask): FetchEditHistoryTask
|
abstract fun bindFetchEditHistoryTask(task: DefaultFetchEditHistoryTask): FetchEditHistoryTask
|
||||||
|
|
||||||
|
|
|
@ -17,6 +17,7 @@
|
||||||
package im.vector.matrix.android.internal.session.room.timeline
|
package im.vector.matrix.android.internal.session.room.timeline
|
||||||
|
|
||||||
import im.vector.matrix.android.api.MatrixCallback
|
import im.vector.matrix.android.api.MatrixCallback
|
||||||
|
import im.vector.matrix.android.api.extensions.orFalse
|
||||||
import im.vector.matrix.android.api.session.events.model.EventType
|
import im.vector.matrix.android.api.session.events.model.EventType
|
||||||
import im.vector.matrix.android.api.session.events.model.RelationType
|
import im.vector.matrix.android.api.session.events.model.RelationType
|
||||||
import im.vector.matrix.android.api.session.events.model.toModel
|
import im.vector.matrix.android.api.session.events.model.toModel
|
||||||
|
@ -71,6 +72,7 @@ internal class DefaultTimeline(
|
||||||
private val realmConfiguration: RealmConfiguration,
|
private val realmConfiguration: RealmConfiguration,
|
||||||
private val taskExecutor: TaskExecutor,
|
private val taskExecutor: TaskExecutor,
|
||||||
private val contextOfEventTask: GetContextOfEventTask,
|
private val contextOfEventTask: GetContextOfEventTask,
|
||||||
|
private val fetchNextTokenAndPaginateTask: FetchNextTokenAndPaginateTask,
|
||||||
private val paginationTask: PaginationTask,
|
private val paginationTask: PaginationTask,
|
||||||
private val timelineEventMapper: TimelineEventMapper,
|
private val timelineEventMapper: TimelineEventMapper,
|
||||||
private val settings: TimelineSettings,
|
private val settings: TimelineSettings,
|
||||||
|
@ -519,50 +521,44 @@ internal class DefaultTimeline(
|
||||||
* This has to be called on TimelineThread as it accesses realm live results
|
* This has to be called on TimelineThread as it accesses realm live results
|
||||||
*/
|
*/
|
||||||
private fun executePaginationTask(direction: Timeline.Direction, limit: Int) {
|
private fun executePaginationTask(direction: Timeline.Direction, limit: Int) {
|
||||||
val token = getTokenLive(direction)
|
val currentChunk = getLiveChunk()
|
||||||
|
val token = if (direction == Timeline.Direction.BACKWARDS) currentChunk?.prevToken else currentChunk?.nextToken
|
||||||
if (token == null) {
|
if (token == null) {
|
||||||
val currentChunk = getLiveChunk()
|
if (direction == Timeline.Direction.FORWARDS && currentChunk?.hasBeenALastForwardChunk().orFalse()) {
|
||||||
if (direction == Timeline.Direction.FORWARDS && currentChunk?.hasBeenALastForwardChunk() == true) {
|
|
||||||
// We are in the case that next event exists, but we do not know the next token.
|
// We are in the case that next event exists, but we do not know the next token.
|
||||||
// Fetch (again) the last event to get a nextToken
|
// Fetch (again) the last event to get a nextToken
|
||||||
currentChunk.timelineEvents.lastOrNull()?.eventId?.let { fetchEvent(it) }
|
val lastKnownEventId = nonFilteredEvents.firstOrNull()?.eventId
|
||||||
}
|
if (lastKnownEventId == null) {
|
||||||
updateState(direction) { it.copy(isPaginating = false, requestedPaginationCount = 0) }
|
updateState(direction) { it.copy(isPaginating = false, requestedPaginationCount = 0) }
|
||||||
return
|
} else {
|
||||||
}
|
val params = FetchNextTokenAndPaginateTask.Params(
|
||||||
val params = PaginationTask.Params(roomId = roomId,
|
roomId = roomId,
|
||||||
from = token,
|
limit = limit,
|
||||||
direction = direction.toPaginationDirection(),
|
lastKnownEventId = lastKnownEventId
|
||||||
limit = limit)
|
)
|
||||||
|
cancelableBag += fetchNextTokenAndPaginateTask
|
||||||
Timber.v("Should fetch $limit items $direction")
|
.configureWith(params) {
|
||||||
cancelableBag += paginationTask
|
this.callback = createPaginationCallback(limit, direction)
|
||||||
.configureWith(params) {
|
|
||||||
this.callback = object : MatrixCallback<TokenChunkEventPersistor.Result> {
|
|
||||||
override fun onSuccess(data: TokenChunkEventPersistor.Result) {
|
|
||||||
when (data) {
|
|
||||||
TokenChunkEventPersistor.Result.SUCCESS -> {
|
|
||||||
Timber.v("Success fetching $limit items $direction from pagination request")
|
|
||||||
}
|
|
||||||
TokenChunkEventPersistor.Result.REACHED_END -> {
|
|
||||||
postSnapshot()
|
|
||||||
}
|
|
||||||
TokenChunkEventPersistor.Result.SHOULD_FETCH_MORE ->
|
|
||||||
// Database won't be updated, so we force pagination request
|
|
||||||
BACKGROUND_HANDLER.post {
|
|
||||||
executePaginationTask(direction, limit)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
.executeBy(taskExecutor)
|
||||||
|
|
||||||
override fun onFailure(failure: Throwable) {
|
|
||||||
updateState(direction) { it.copy(isPaginating = false, requestedPaginationCount = 0) }
|
|
||||||
postSnapshot()
|
|
||||||
Timber.v("Failure fetching $limit items $direction from pagination request")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
.executeBy(taskExecutor)
|
} else {
|
||||||
|
updateState(direction) { it.copy(isPaginating = false, requestedPaginationCount = 0) }
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
val params = PaginationTask.Params(
|
||||||
|
roomId = roomId,
|
||||||
|
from = token,
|
||||||
|
direction = direction.toPaginationDirection(),
|
||||||
|
limit = limit
|
||||||
|
)
|
||||||
|
Timber.v("Should fetch $limit items $direction")
|
||||||
|
cancelableBag += paginationTask
|
||||||
|
.configureWith(params) {
|
||||||
|
this.callback = createPaginationCallback(limit, direction)
|
||||||
|
}
|
||||||
|
.executeBy(taskExecutor)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// For debug purpose only
|
// For debug purpose only
|
||||||
|
@ -743,6 +739,32 @@ internal class DefaultTimeline(
|
||||||
forwardsState.set(State())
|
forwardsState.set(State())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun createPaginationCallback(limit: Int, direction: Timeline.Direction): MatrixCallback<TokenChunkEventPersistor.Result> {
|
||||||
|
return object : MatrixCallback<TokenChunkEventPersistor.Result> {
|
||||||
|
override fun onSuccess(data: TokenChunkEventPersistor.Result) {
|
||||||
|
when (data) {
|
||||||
|
TokenChunkEventPersistor.Result.SUCCESS -> {
|
||||||
|
Timber.v("Success fetching $limit items $direction from pagination request")
|
||||||
|
}
|
||||||
|
TokenChunkEventPersistor.Result.REACHED_END -> {
|
||||||
|
postSnapshot()
|
||||||
|
}
|
||||||
|
TokenChunkEventPersistor.Result.SHOULD_FETCH_MORE ->
|
||||||
|
// Database won't be updated, so we force pagination request
|
||||||
|
BACKGROUND_HANDLER.post {
|
||||||
|
executePaginationTask(direction, limit)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onFailure(failure: Throwable) {
|
||||||
|
updateState(direction) { it.copy(isPaginating = false, requestedPaginationCount = 0) }
|
||||||
|
postSnapshot()
|
||||||
|
Timber.v("Failure fetching $limit items $direction from pagination request")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Extension methods ***************************************************************************
|
// Extension methods ***************************************************************************
|
||||||
|
|
||||||
private fun Timeline.Direction.toPaginationDirection(): PaginationDirection {
|
private fun Timeline.Direction.toPaginationDirection(): PaginationDirection {
|
||||||
|
|
|
@ -42,6 +42,7 @@ internal class DefaultTimelineService @AssistedInject constructor(@Assisted priv
|
||||||
private val contextOfEventTask: GetContextOfEventTask,
|
private val contextOfEventTask: GetContextOfEventTask,
|
||||||
private val eventDecryptor: TimelineEventDecryptor,
|
private val eventDecryptor: TimelineEventDecryptor,
|
||||||
private val paginationTask: PaginationTask,
|
private val paginationTask: PaginationTask,
|
||||||
|
private val fetchNextTokenAndPaginateTask: FetchNextTokenAndPaginateTask,
|
||||||
private val timelineEventMapper: TimelineEventMapper,
|
private val timelineEventMapper: TimelineEventMapper,
|
||||||
private val readReceiptsSummaryMapper: ReadReceiptsSummaryMapper
|
private val readReceiptsSummaryMapper: ReadReceiptsSummaryMapper
|
||||||
) : TimelineService {
|
) : TimelineService {
|
||||||
|
@ -63,7 +64,8 @@ internal class DefaultTimelineService @AssistedInject constructor(@Assisted priv
|
||||||
settings = settings,
|
settings = settings,
|
||||||
hiddenReadReceipts = TimelineHiddenReadReceipts(readReceiptsSummaryMapper, roomId, settings),
|
hiddenReadReceipts = TimelineHiddenReadReceipts(readReceiptsSummaryMapper, roomId, settings),
|
||||||
eventBus = eventBus,
|
eventBus = eventBus,
|
||||||
eventDecryptor = eventDecryptor
|
eventDecryptor = eventDecryptor,
|
||||||
|
fetchNextTokenAndPaginateTask = fetchNextTokenAndPaginateTask
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,66 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2020 New Vector Ltd
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package im.vector.matrix.android.internal.session.room.timeline
|
||||||
|
|
||||||
|
import com.zhuinden.monarchy.Monarchy
|
||||||
|
import im.vector.matrix.android.internal.database.model.ChunkEntity
|
||||||
|
import im.vector.matrix.android.internal.database.query.findIncludingEvent
|
||||||
|
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.awaitTransaction
|
||||||
|
import org.greenrobot.eventbus.EventBus
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
internal interface FetchNextTokenAndPaginateTask : Task<FetchNextTokenAndPaginateTask.Params, TokenChunkEventPersistor.Result> {
|
||||||
|
|
||||||
|
data class Params(
|
||||||
|
val roomId: String,
|
||||||
|
val lastKnownEventId: String,
|
||||||
|
val limit: Int
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
internal class DefaultFetchNextTokenAndPaginateTask @Inject constructor(
|
||||||
|
private val roomAPI: RoomAPI,
|
||||||
|
private val monarchy: Monarchy,
|
||||||
|
private val filterRepository: FilterRepository,
|
||||||
|
private val paginationTask: PaginationTask,
|
||||||
|
private val eventBus: EventBus
|
||||||
|
) : FetchNextTokenAndPaginateTask {
|
||||||
|
|
||||||
|
override suspend fun execute(params: FetchNextTokenAndPaginateTask.Params): TokenChunkEventPersistor.Result {
|
||||||
|
val filter = filterRepository.getRoomFilter()
|
||||||
|
val response = executeRequest<EventContextResponse>(eventBus) {
|
||||||
|
apiCall = roomAPI.getContextOfEvent(params.roomId, params.lastKnownEventId, 0, filter)
|
||||||
|
}
|
||||||
|
if (response.end == null) {
|
||||||
|
throw IllegalStateException("No next token found")
|
||||||
|
}
|
||||||
|
monarchy.awaitTransaction {
|
||||||
|
ChunkEntity.findIncludingEvent(it, params.lastKnownEventId)?.nextToken = response.end
|
||||||
|
}
|
||||||
|
val paginationParams = PaginationTask.Params(
|
||||||
|
roomId = params.roomId,
|
||||||
|
from = response.end,
|
||||||
|
direction = PaginationDirection.FORWARDS,
|
||||||
|
limit = params.limit
|
||||||
|
)
|
||||||
|
return paginationTask.execute(paginationParams)
|
||||||
|
}
|
||||||
|
}
|
|
@ -230,21 +230,9 @@ internal class TokenChunkEventPersistor @Inject constructor(private val monarchy
|
||||||
val chunksToDelete = ArrayList<ChunkEntity>()
|
val chunksToDelete = ArrayList<ChunkEntity>()
|
||||||
chunks.forEach {
|
chunks.forEach {
|
||||||
if (it != currentChunk) {
|
if (it != currentChunk) {
|
||||||
if (direction == PaginationDirection.FORWARDS && it.hasBeenALastForwardChunk()) {
|
Timber.d("Merge $it")
|
||||||
// Maybe it was a trick to get a nextToken
|
currentChunk.merge(roomId, it, direction)
|
||||||
if (receivedChunk.events.size == 1) {
|
chunksToDelete.add(it)
|
||||||
Timber.d("Receiving a new nextToken")
|
|
||||||
it.nextToken = receivedChunk.end
|
|
||||||
chunksToDelete.add(currentChunk)
|
|
||||||
} else {
|
|
||||||
Timber.d("Do not merge $it")
|
|
||||||
chunksToDelete.add(it)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
Timber.d("Merge $it")
|
|
||||||
currentChunk.merge(roomId, it, direction)
|
|
||||||
chunksToDelete.add(it)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
val shouldUpdateSummary = chunksToDelete.isNotEmpty() && currentChunk.isLastForward && direction == PaginationDirection.FORWARDS
|
val shouldUpdateSummary = chunksToDelete.isNotEmpty() && currentChunk.isLastForward && direction == PaginationDirection.FORWARDS
|
||||||
|
|
Loading…
Reference in a new issue