Timeline : try to get a better PagedList/Epoxy integration. Still need to be refined.

This commit is contained in:
ganfra
2019-01-10 11:37:14 +01:00
committed by ganfra
parent de90cbe73e
commit 922609cb57
14 changed files with 381 additions and 98 deletions

View File

@ -37,6 +37,10 @@ internal fun ChunkEntity.Companion.findAllIncludingEvents(realm: Realm, eventIds
.findAll()
}
internal fun ChunkEntity.Companion.findIncludingEvent(realm: Realm, eventId: String): ChunkEntity? {
return findAllIncludingEvents(realm, listOf(eventId)).firstOrNull()
}
internal fun ChunkEntity.Companion.create(realm: Realm, prevToken: String?, nextToken: String?): ChunkEntity {
return realm.createObject<ChunkEntity>().apply {
this.prevToken = prevToken

View File

@ -15,7 +15,12 @@ import io.realm.RealmQuery
internal class RoomMemberExtractor(private val monarchy: Monarchy,
private val roomId: String) {
private val cached = HashMap<String, RoomMember?>()
fun extractFrom(event: EventEntity): RoomMember? {
if (cached.containsKey(event.eventId)) {
return cached[event.eventId]
}
val sender = event.sender ?: return null
// If the event is unlinked we want to fetch unlinked state events
val unlinked = event.isUnlinked
@ -23,11 +28,13 @@ internal class RoomMemberExtractor(private val monarchy: Monarchy,
// If prevContent is null we fallback to the Int.MIN state events content()
val content = if (event.stateIndex <= 0) {
baseQuery(monarchy, roomId, sender, unlinked).next(from = event.stateIndex)?.prevContent
?: baseQuery(monarchy, roomId, sender, unlinked).last(since = event.stateIndex)?.content
?: baseQuery(monarchy, roomId, sender, unlinked).last(since = event.stateIndex)?.content
} else {
baseQuery(monarchy, roomId, sender, unlinked).last(since = event.stateIndex)?.content
}
return ContentMapper.map(content).toModel()
val roomMember: RoomMember? = ContentMapper.map(content).toModel()
cached[event.eventId] = roomMember
return roomMember
}
private fun baseQuery(monarchy: Monarchy,

View File

@ -7,7 +7,7 @@ import im.vector.matrix.android.internal.task.Task
import im.vector.matrix.android.internal.util.FilterUtil
internal interface PaginationTask : Task<PaginationTask.Params, TokenChunkEvent> {
internal interface PaginationTask : Task<PaginationTask.Params, Boolean> {
data class Params(
val roomId: String,
@ -22,14 +22,13 @@ internal class DefaultPaginationTask(private val roomAPI: RoomAPI,
private val tokenChunkEventPersistor: TokenChunkEventPersistor
) : PaginationTask {
override fun execute(params: PaginationTask.Params): Try<TokenChunkEvent> {
override fun execute(params: PaginationTask.Params): Try<Boolean> {
val filter = FilterUtil.createRoomEventFilter(true)?.toJSONString()
return executeRequest<PaginationResponse> {
apiCall = roomAPI.getRoomMessagesFrom(params.roomId, params.from, params.direction.value, params.limit, filter)
}.flatMap { chunk ->
tokenChunkEventPersistor
.insertInDb(chunk, params.roomId, params.direction)
.map { chunk }
}
}

View File

@ -22,7 +22,8 @@ import im.vector.matrix.android.internal.util.tryTransactionAsync
import io.realm.Realm
import io.realm.RealmQuery
private const val PAGE_SIZE = 30
private const val PAGE_SIZE = 50
private const val PREFETCH_DISTANCE = 20
internal class DefaultTimelineService(private val roomId: String,
private val monarchy: Monarchy,
@ -51,6 +52,7 @@ internal class DefaultTimelineService(private val roomId: String,
val pagedListConfig = PagedList.Config.Builder()
.setEnablePlaceholders(false)
.setPageSize(PAGE_SIZE)
.setPrefetchDistance(PREFETCH_DISTANCE)
.build()
val livePagedListBuilder = LivePagedListBuilder(domainSourceFactory, pagedListConfig).setBoundaryCallback(boundaryCallback)

View File

@ -6,11 +6,11 @@ import com.zhuinden.monarchy.Monarchy
import im.vector.matrix.android.api.MatrixCallback
import im.vector.matrix.android.api.session.events.model.EnrichedEvent
import im.vector.matrix.android.internal.database.model.ChunkEntity
import im.vector.matrix.android.internal.database.query.findAllIncludingEvents
import im.vector.matrix.android.internal.database.query.findIncludingEvent
import im.vector.matrix.android.internal.task.TaskExecutor
import im.vector.matrix.android.internal.task.configureWith
import im.vector.matrix.android.internal.util.PagingRequestHelper
import java.util.*
import timber.log.Timber
internal class TimelineBoundaryCallback(private val roomId: String,
private val taskExecutor: TaskExecutor,
@ -43,8 +43,9 @@ internal class TimelineBoundaryCallback(private val roomId: String,
}
override fun onItemAtEndLoaded(itemAtEnd: EnrichedEvent) {
Timber.v("On item at end loaded")
val token = itemAtEnd.root.eventId?.let { getToken(it, PaginationDirection.BACKWARDS) }
?: return
?: return
helper.runIfNotRunning(PagingRequestHelper.RequestType.AFTER) {
runPaginationRequest(it, token, PaginationDirection.BACKWARDS)
@ -52,8 +53,9 @@ internal class TimelineBoundaryCallback(private val roomId: String,
}
override fun onItemAtFrontLoaded(itemAtFront: EnrichedEvent) {
Timber.v("On item at front loaded")
val token = itemAtFront.root.eventId?.let { getToken(it, PaginationDirection.FORWARDS) }
?: return
?: return
helper.runIfNotRunning(PagingRequestHelper.RequestType.BEFORE) {
runPaginationRequest(it, token, PaginationDirection.FORWARDS)
@ -63,7 +65,7 @@ internal class TimelineBoundaryCallback(private val roomId: String,
private fun getToken(eventId: String, direction: PaginationDirection): String? {
var token: String? = null
monarchy.doWithRealm { realm ->
val chunkEntity = ChunkEntity.findAllIncludingEvents(realm, Collections.singletonList(eventId)).firstOrNull()
val chunkEntity = ChunkEntity.findIncludingEvent(realm, eventId)
token = if (direction == PaginationDirection.FORWARDS) chunkEntity?.nextToken else chunkEntity?.prevToken
}
return token
@ -74,14 +76,14 @@ internal class TimelineBoundaryCallback(private val roomId: String,
direction: PaginationDirection) {
val params = PaginationTask.Params(roomId = roomId,
from = from,
direction = direction,
limit = limit)
from = from,
direction = direction,
limit = limit)
paginationTask.configureWith(params)
.enableRetry()
.dispatchTo(object : MatrixCallback<TokenChunkEvent> {
override fun onSuccess(data: TokenChunkEvent) {
.dispatchTo(object : MatrixCallback<Boolean> {
override fun onSuccess(data: Boolean) {
requestCallback.recordSuccess()
}

View File

@ -2,12 +2,7 @@ package im.vector.matrix.android.internal.session.room.timeline
import arrow.core.Try
import com.zhuinden.monarchy.Monarchy
import im.vector.matrix.android.internal.database.helper.addAll
import im.vector.matrix.android.internal.database.helper.addOrUpdate
import im.vector.matrix.android.internal.database.helper.addStateEvents
import im.vector.matrix.android.internal.database.helper.deleteOnCascade
import im.vector.matrix.android.internal.database.helper.isUnlinked
import im.vector.matrix.android.internal.database.helper.merge
import im.vector.matrix.android.internal.database.helper.*
import im.vector.matrix.android.internal.database.model.ChunkEntity
import im.vector.matrix.android.internal.database.model.RoomEntity
import im.vector.matrix.android.internal.database.query.create
@ -21,12 +16,15 @@ internal class TokenChunkEventPersistor(private val monarchy: Monarchy) {
fun insertInDb(receivedChunk: TokenChunkEvent,
roomId: String,
direction: PaginationDirection): Try<Unit> {
direction: PaginationDirection): Try<Boolean> {
if (receivedChunk.events.isEmpty() && receivedChunk.stateEvents.isEmpty()) {
return Try.just(false)
}
return monarchy
.tryTransactionSync { realm ->
val roomEntity = RoomEntity.where(realm, roomId).findFirst()
?: throw IllegalStateException("You shouldn't use this method without a room")
?: throw IllegalStateException("You shouldn't use this method without a room")
val nextToken: String?
val prevToken: String?
@ -46,10 +44,10 @@ internal class TokenChunkEventPersistor(private val monarchy: Monarchy) {
var currentChunk = if (direction == PaginationDirection.FORWARDS) {
prevChunk?.apply { this.nextToken = nextToken }
?: ChunkEntity.create(realm, prevToken, nextToken)
?: ChunkEntity.create(realm, prevToken, nextToken)
} else {
nextChunk?.apply { this.prevToken = prevToken }
?: ChunkEntity.create(realm, prevToken, nextToken)
?: ChunkEntity.create(realm, prevToken, nextToken)
}
currentChunk.addAll(roomId, receivedChunk.events, direction, isUnlinked = currentChunk.isUnlinked())
@ -71,6 +69,7 @@ internal class TokenChunkEventPersistor(private val monarchy: Monarchy) {
roomEntity.addOrUpdate(currentChunk)
roomEntity.addStateEvents(receivedChunk.stateEvents, isUnlinked = currentChunk.isUnlinked())
}
.map { true }
}
private fun handleMerge(roomEntity: RoomEntity,