mirror of
https://github.com/element-hq/element-android
synced 2024-11-23 09:55:40 +03:00
Timeline : introduce timeline data class to allow listening for isLoadingForward and isLoadingBackward
This commit is contained in:
parent
f5d64a5707
commit
1269715b5c
16 changed files with 192 additions and 94 deletions
|
@ -6,9 +6,9 @@ import android.support.v7.widget.LinearLayoutManager
|
|||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import com.airbnb.mvrx.Success
|
||||
import com.airbnb.mvrx.args
|
||||
import com.airbnb.mvrx.fragmentViewModel
|
||||
import im.vector.matrix.android.api.session.room.model.RoomSummary
|
||||
import im.vector.riotredesign.R
|
||||
import im.vector.riotredesign.core.platform.RiotFragment
|
||||
import im.vector.riotredesign.core.platform.ToolbarConfigurable
|
||||
|
@ -19,7 +19,6 @@ import kotlinx.android.parcel.Parcelize
|
|||
import kotlinx.android.synthetic.main.fragment_room_detail.*
|
||||
import org.koin.android.ext.android.inject
|
||||
import org.koin.core.parameter.parametersOf
|
||||
import timber.log.Timber
|
||||
|
||||
@Parcelize
|
||||
data class RoomDetailArgs(
|
||||
|
@ -72,7 +71,7 @@ class RoomDetailFragment : RiotFragment(), TimelineEventController.Callback {
|
|||
|
||||
private fun setupRecyclerView() {
|
||||
val layoutManager = LinearLayoutManager(context, LinearLayoutManager.VERTICAL, true)
|
||||
//scrollOnNewMessageCallback = ScrollOnNewMessageCallback(layoutManager)
|
||||
scrollOnNewMessageCallback = ScrollOnNewMessageCallback(layoutManager)
|
||||
recyclerView.layoutManager = layoutManager
|
||||
//timelineEventController.addModelBuildListener { it.dispatchTo(scrollOnNewMessageCallback) }
|
||||
recyclerView.setHasFixedSize(true)
|
||||
|
@ -82,16 +81,19 @@ class RoomDetailFragment : RiotFragment(), TimelineEventController.Callback {
|
|||
}
|
||||
|
||||
private fun renderState(state: RoomDetailViewState) {
|
||||
Timber.v("Render state")
|
||||
val timeline = state.asyncTimeline()
|
||||
if (timeline != null) {
|
||||
renderTimeline(timeline)
|
||||
}
|
||||
renderRoomSummary(state.asyncRoomSummary())
|
||||
renderRoomSummary(state)
|
||||
renderTimeline(state)
|
||||
}
|
||||
|
||||
private fun renderRoomSummary(roomSummary: RoomSummary?) {
|
||||
roomSummary?.let {
|
||||
private fun renderTimeline(state: RoomDetailViewState) {
|
||||
when (state.asyncTimelineData) {
|
||||
is Success -> timelineEventController.update(state.asyncTimelineData())
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private fun renderRoomSummary(state: RoomDetailViewState) {
|
||||
state.asyncRoomSummary()?.let {
|
||||
toolbarTitleView.text = it.displayName
|
||||
AvatarRenderer.render(it, toolbarAvatarImageView)
|
||||
if (it.topic.isNotEmpty()) {
|
||||
|
@ -103,11 +105,6 @@ class RoomDetailFragment : RiotFragment(), TimelineEventController.Callback {
|
|||
}
|
||||
}
|
||||
|
||||
private fun renderTimeline(timeline: Timeline?) {
|
||||
//scrollOnNewMessageCallback.hasBeenUpdated.set(true)
|
||||
timelineEventController.timeline = timeline
|
||||
}
|
||||
|
||||
// TimelineEventController.Callback ************************************************************
|
||||
|
||||
override fun onUrlClicked(url: String) {
|
||||
|
|
|
@ -53,9 +53,10 @@ class RoomDetailViewModel(initialState: RoomDetailViewState,
|
|||
|
||||
private fun observeTimeline() {
|
||||
room.rx().timeline(eventId)
|
||||
.execute { asyncTimeline ->
|
||||
copy(asyncTimeline = asyncTimeline)
|
||||
.execute { timelineData ->
|
||||
copy(asyncTimelineData= timelineData)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -1,19 +1,16 @@
|
|||
package im.vector.riotredesign.features.home.room.detail
|
||||
|
||||
import android.arch.paging.PagedList
|
||||
import com.airbnb.mvrx.Async
|
||||
import com.airbnb.mvrx.MvRxState
|
||||
import com.airbnb.mvrx.Uninitialized
|
||||
import im.vector.matrix.android.api.session.events.model.EnrichedEvent
|
||||
import im.vector.matrix.android.api.session.room.model.RoomSummary
|
||||
|
||||
typealias Timeline = PagedList<EnrichedEvent>
|
||||
import im.vector.matrix.android.api.session.room.timeline.TimelineData
|
||||
|
||||
data class RoomDetailViewState(
|
||||
val roomId: String,
|
||||
val eventId: String?,
|
||||
val asyncRoomSummary: Async<RoomSummary> = Uninitialized,
|
||||
val asyncTimeline: Async<Timeline> = Uninitialized
|
||||
val asyncTimelineData: Async<TimelineData> = Uninitialized
|
||||
) : MvRxState {
|
||||
|
||||
constructor(args: RoomDetailArgs) : this(roomId = args.roomId, eventId = args.eventId)
|
||||
|
|
|
@ -5,9 +5,9 @@ import com.airbnb.epoxy.EpoxyAsyncUtil
|
|||
import com.airbnb.epoxy.EpoxyController
|
||||
import im.vector.matrix.android.api.session.events.model.EnrichedEvent
|
||||
import im.vector.matrix.android.api.session.events.model.EventType
|
||||
import im.vector.matrix.android.api.session.room.timeline.TimelineData
|
||||
import im.vector.riotredesign.core.extensions.localDateTime
|
||||
import im.vector.riotredesign.features.home.LoadingItemModel_
|
||||
import im.vector.riotredesign.features.home.room.detail.Timeline
|
||||
|
||||
class TimelineEventController(private val roomId: String,
|
||||
private val messageItemFactory: MessageItemFactory,
|
||||
|
@ -36,28 +36,38 @@ class TimelineEventController(private val roomId: String,
|
|||
}
|
||||
}
|
||||
|
||||
private var snapshotList: List<EnrichedEvent>? = emptyList()
|
||||
var timeline: Timeline? = null
|
||||
set(value) {
|
||||
field?.removeWeakCallback(pagedListCallback)
|
||||
field = value
|
||||
field?.addWeakCallback(null, pagedListCallback)
|
||||
buildSnapshotList()
|
||||
}
|
||||
|
||||
private var snapshotList: List<EnrichedEvent> = emptyList()
|
||||
private var timelineData: TimelineData? = null
|
||||
var callback: Callback? = null
|
||||
|
||||
override fun buildModels() {
|
||||
buildModels(snapshotList)
|
||||
fun update(timelineData: TimelineData?) {
|
||||
timelineData?.events?.removeWeakCallback(pagedListCallback)
|
||||
this.timelineData = timelineData
|
||||
timelineData?.events?.addWeakCallback(null, pagedListCallback)
|
||||
buildSnapshotList()
|
||||
}
|
||||
|
||||
private fun buildModels(data: List<EnrichedEvent?>?) {
|
||||
if (data.isNullOrEmpty()) {
|
||||
override fun buildModels() {
|
||||
buildModelsWith(
|
||||
snapshotList,
|
||||
timelineData?.isLoadingForward ?: false,
|
||||
timelineData?.isLoadingBackward ?: false
|
||||
)
|
||||
}
|
||||
|
||||
private fun buildModelsWith(events: List<EnrichedEvent?>,
|
||||
isLoadingForward: Boolean,
|
||||
isLoadingBackward: Boolean) {
|
||||
if (events.isEmpty()) {
|
||||
return
|
||||
}
|
||||
for (index in 0 until data.size) {
|
||||
val event = data[index] ?: continue
|
||||
val nextEvent = if (index + 1 < data.size) data[index + 1] else null
|
||||
LoadingItemModel_()
|
||||
.id(roomId + "forward_loading_item")
|
||||
.addIf(isLoadingForward, this)
|
||||
|
||||
for (index in 0 until events.size) {
|
||||
val event = events[index] ?: continue
|
||||
val nextEvent = if (index + 1 < events.size) events[index + 1] else null
|
||||
|
||||
val date = event.root.localDateTime()
|
||||
val nextDate = nextEvent?.root?.localDateTime()
|
||||
|
@ -65,10 +75,13 @@ class TimelineEventController(private val roomId: String,
|
|||
|
||||
val item = when (event.root.type) {
|
||||
EventType.MESSAGE -> messageItemFactory.create(event, nextEvent, addDaySeparator, date, callback)
|
||||
else -> textItemFactory.create(event)
|
||||
else -> textItemFactory.create(event)
|
||||
}
|
||||
|
||||
item
|
||||
?.onBind { timeline?.loadAround(index) }
|
||||
?.onBind {
|
||||
timelineData?.events?.loadAround(index)
|
||||
}
|
||||
?.id(event.localId)
|
||||
?.addTo(this)
|
||||
|
||||
|
@ -78,15 +91,14 @@ class TimelineEventController(private val roomId: String,
|
|||
}
|
||||
}
|
||||
|
||||
//It's a hack at the moment
|
||||
val isLastEvent = data.last()?.root?.type == EventType.STATE_ROOM_CREATE
|
||||
LoadingItemModel_()
|
||||
.id(roomId + "backward_loading_item")
|
||||
.addIf(!isLastEvent, this)
|
||||
.addIf(isLoadingBackward, this)
|
||||
|
||||
}
|
||||
|
||||
private fun buildSnapshotList() {
|
||||
snapshotList = timeline?.snapshot() ?: emptyList()
|
||||
snapshotList = timelineData?.events?.snapshot() ?: emptyList()
|
||||
requestModelBuild()
|
||||
}
|
||||
|
||||
|
|
|
@ -1,9 +1,8 @@
|
|||
package im.vector.matrix.rx
|
||||
|
||||
import android.arch.paging.PagedList
|
||||
import im.vector.matrix.android.api.session.events.model.EnrichedEvent
|
||||
import im.vector.matrix.android.api.session.room.Room
|
||||
import im.vector.matrix.android.api.session.room.model.RoomSummary
|
||||
import im.vector.matrix.android.api.session.room.timeline.TimelineData
|
||||
import io.reactivex.Observable
|
||||
|
||||
class RxRoom(private val room: Room) {
|
||||
|
@ -12,7 +11,7 @@ class RxRoom(private val room: Room) {
|
|||
return room.roomSummary.asObservable()
|
||||
}
|
||||
|
||||
fun timeline(eventId: String? = null): Observable<PagedList<EnrichedEvent>> {
|
||||
fun timeline(eventId: String? = null): Observable<TimelineData> {
|
||||
return room.timeline(eventId).asObservable()
|
||||
}
|
||||
|
||||
|
|
|
@ -3,9 +3,10 @@ package im.vector.matrix.android.api.session.room
|
|||
import android.arch.lifecycle.LiveData
|
||||
import im.vector.matrix.android.api.session.room.model.MyMembership
|
||||
import im.vector.matrix.android.api.session.room.model.RoomSummary
|
||||
import im.vector.matrix.android.api.session.room.timeline.TimelineService
|
||||
import im.vector.matrix.android.api.util.Cancelable
|
||||
|
||||
interface Room : TimelineHolder, SendService {
|
||||
interface Room : TimelineService, SendService {
|
||||
|
||||
val roomId: String
|
||||
|
||||
|
|
|
@ -1,11 +0,0 @@
|
|||
package im.vector.matrix.android.api.session.room
|
||||
|
||||
import android.arch.lifecycle.LiveData
|
||||
import android.arch.paging.PagedList
|
||||
import im.vector.matrix.android.api.session.events.model.EnrichedEvent
|
||||
|
||||
interface TimelineHolder {
|
||||
|
||||
fun timeline(eventId: String? = null): LiveData<PagedList<EnrichedEvent>>
|
||||
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
package im.vector.matrix.android.api.session.room.timeline
|
||||
|
||||
import android.arch.paging.PagedList
|
||||
import im.vector.matrix.android.api.session.events.model.EnrichedEvent
|
||||
|
||||
data class TimelineData(
|
||||
val events: PagedList<EnrichedEvent>,
|
||||
val isLoadingForward: Boolean = false,
|
||||
val isLoadingBackward: Boolean = false
|
||||
)
|
|
@ -0,0 +1,9 @@
|
|||
package im.vector.matrix.android.api.session.room.timeline
|
||||
|
||||
import android.arch.lifecycle.LiveData
|
||||
|
||||
interface TimelineService {
|
||||
|
||||
fun timeline(eventId: String? = null): LiveData<TimelineData>
|
||||
|
||||
}
|
|
@ -9,10 +9,11 @@ import im.vector.matrix.android.api.session.events.model.EnrichedEvent
|
|||
import im.vector.matrix.android.api.session.events.model.Event
|
||||
import im.vector.matrix.android.api.session.room.Room
|
||||
import im.vector.matrix.android.api.session.room.SendService
|
||||
import im.vector.matrix.android.api.session.room.TimelineHolder
|
||||
import im.vector.matrix.android.api.session.room.timeline.TimelineService
|
||||
import im.vector.matrix.android.api.session.room.model.Membership
|
||||
import im.vector.matrix.android.api.session.room.model.MyMembership
|
||||
import im.vector.matrix.android.api.session.room.model.RoomSummary
|
||||
import im.vector.matrix.android.api.session.room.timeline.TimelineData
|
||||
import im.vector.matrix.android.api.util.Cancelable
|
||||
import im.vector.matrix.android.internal.database.mapper.asDomain
|
||||
import im.vector.matrix.android.internal.database.model.RoomSummaryEntity
|
||||
|
@ -32,7 +33,7 @@ internal data class DefaultRoom(
|
|||
|
||||
private val loadRoomMembersTask by inject<LoadRoomMembersTask>()
|
||||
private val monarchy by inject<Monarchy>()
|
||||
private val timelineHolder by inject<TimelineHolder> { parametersOf(roomId) }
|
||||
private val timelineService by inject<TimelineService> { parametersOf(roomId) }
|
||||
private val sendService by inject<SendService> { parametersOf(roomId) }
|
||||
private val taskExecutor by inject<TaskExecutor>()
|
||||
|
||||
|
@ -47,8 +48,8 @@ internal data class DefaultRoom(
|
|||
}
|
||||
}
|
||||
|
||||
override fun timeline(eventId: String?): LiveData<PagedList<EnrichedEvent>> {
|
||||
return timelineHolder.timeline(eventId)
|
||||
override fun timeline(eventId: String?): LiveData<TimelineData> {
|
||||
return timelineService.timeline(eventId)
|
||||
}
|
||||
|
||||
override fun loadRoomMembersIfNeeded(): Cancelable {
|
||||
|
|
|
@ -2,14 +2,20 @@ package im.vector.matrix.android.internal.session.room
|
|||
|
||||
import im.vector.matrix.android.api.auth.data.SessionParams
|
||||
import im.vector.matrix.android.api.session.room.SendService
|
||||
import im.vector.matrix.android.api.session.room.TimelineHolder
|
||||
import im.vector.matrix.android.api.session.room.send.EventFactory
|
||||
import im.vector.matrix.android.api.session.room.timeline.TimelineService
|
||||
import im.vector.matrix.android.internal.session.DefaultSession
|
||||
import im.vector.matrix.android.internal.session.room.members.DefaultLoadRoomMembersTask
|
||||
import im.vector.matrix.android.internal.session.room.members.LoadRoomMembersTask
|
||||
import im.vector.matrix.android.internal.session.room.members.RoomMemberExtractor
|
||||
import im.vector.matrix.android.internal.session.room.send.DefaultSendService
|
||||
import im.vector.matrix.android.internal.session.room.timeline.*
|
||||
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.DefaultTimelineService
|
||||
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.TimelineBoundaryCallback
|
||||
import im.vector.matrix.android.internal.session.room.timeline.TokenChunkEventPersistor
|
||||
import im.vector.matrix.android.internal.util.PagingRequestHelper
|
||||
import org.koin.dsl.module.module
|
||||
import retrofit2.Retrofit
|
||||
|
@ -50,7 +56,7 @@ class RoomModule {
|
|||
val helper = PagingRequestHelper(Executors.newSingleThreadExecutor())
|
||||
val timelineBoundaryCallback = TimelineBoundaryCallback(roomId, get(), get(), get(), helper)
|
||||
val roomMemberExtractor = RoomMemberExtractor(get(), roomId)
|
||||
DefaultTimelineHolder(roomId, get(), get(), timelineBoundaryCallback, get(), roomMemberExtractor) as TimelineHolder
|
||||
DefaultTimelineService(roomId, get(), get(), timelineBoundaryCallback, get(), roomMemberExtractor) as TimelineService
|
||||
}
|
||||
|
||||
factory { (roomId: String) ->
|
||||
|
|
|
@ -1,10 +1,9 @@
|
|||
package im.vector.matrix.android.internal.session.room.timeline
|
||||
|
||||
import arrow.core.Try
|
||||
import arrow.core.failure
|
||||
import im.vector.matrix.android.internal.task.Task
|
||||
import im.vector.matrix.android.internal.network.executeRequest
|
||||
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
|
||||
|
||||
|
||||
|
@ -12,7 +11,7 @@ internal interface PaginationTask : Task<PaginationTask.Params, TokenChunkEvent>
|
|||
|
||||
data class Params(
|
||||
val roomId: String,
|
||||
val from: String?,
|
||||
val from: String,
|
||||
val direction: PaginationDirection,
|
||||
val limit: Int
|
||||
)
|
||||
|
@ -24,9 +23,6 @@ internal class DefaultPaginationTask(private val roomAPI: RoomAPI,
|
|||
) : PaginationTask {
|
||||
|
||||
override fun execute(params: PaginationTask.Params): Try<TokenChunkEvent> {
|
||||
if (params.from == null) {
|
||||
return RuntimeException("From token shouldn't be null").failure()
|
||||
}
|
||||
val filter = FilterUtil.createRoomEventFilter(true)?.toJSONString()
|
||||
return executeRequest<PaginationResponse> {
|
||||
apiCall = roomAPI.getRoomMessagesFrom(params.roomId, params.from, params.direction.value, params.limit, filter)
|
||||
|
@ -36,4 +32,5 @@ internal class DefaultPaginationTask(private val roomAPI: RoomAPI,
|
|||
.map { chunk }
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -6,7 +6,8 @@ import android.arch.paging.PagedList
|
|||
import com.zhuinden.monarchy.Monarchy
|
||||
import im.vector.matrix.android.api.session.events.interceptor.EnrichedEventInterceptor
|
||||
import im.vector.matrix.android.api.session.events.model.EnrichedEvent
|
||||
import im.vector.matrix.android.api.session.room.TimelineHolder
|
||||
import im.vector.matrix.android.api.session.room.timeline.TimelineData
|
||||
import im.vector.matrix.android.api.session.room.timeline.TimelineService
|
||||
import im.vector.matrix.android.internal.database.mapper.asDomain
|
||||
import im.vector.matrix.android.internal.database.model.ChunkEntityFields
|
||||
import im.vector.matrix.android.internal.database.model.EventEntity
|
||||
|
@ -15,23 +16,25 @@ import im.vector.matrix.android.internal.database.query.where
|
|||
import im.vector.matrix.android.internal.session.room.members.RoomMemberExtractor
|
||||
import im.vector.matrix.android.internal.task.TaskExecutor
|
||||
import im.vector.matrix.android.internal.task.configureWith
|
||||
import im.vector.matrix.android.internal.util.LiveDataUtils
|
||||
import im.vector.matrix.android.internal.util.PagingRequestHelper
|
||||
import im.vector.matrix.android.internal.util.tryTransactionAsync
|
||||
import io.realm.Realm
|
||||
import io.realm.RealmQuery
|
||||
|
||||
private const val PAGE_SIZE = 30
|
||||
|
||||
internal class DefaultTimelineHolder(private val roomId: String,
|
||||
private val monarchy: Monarchy,
|
||||
private val taskExecutor: TaskExecutor,
|
||||
private val boundaryCallback: TimelineBoundaryCallback,
|
||||
private val contextOfEventTask: GetContextOfEventTask,
|
||||
private val roomMemberExtractor: RoomMemberExtractor
|
||||
) : TimelineHolder {
|
||||
internal class DefaultTimelineService(private val roomId: String,
|
||||
private val monarchy: Monarchy,
|
||||
private val taskExecutor: TaskExecutor,
|
||||
private val boundaryCallback: TimelineBoundaryCallback,
|
||||
private val contextOfEventTask: GetContextOfEventTask,
|
||||
private val roomMemberExtractor: RoomMemberExtractor
|
||||
) : TimelineService {
|
||||
|
||||
private val eventInterceptors = ArrayList<EnrichedEventInterceptor>()
|
||||
|
||||
override fun timeline(eventId: String?): LiveData<PagedList<EnrichedEvent>> {
|
||||
override fun timeline(eventId: String?): LiveData<TimelineData> {
|
||||
clearUnlinkedEvents()
|
||||
if (eventId != null) {
|
||||
fetchEventIfNeeded(eventId)
|
||||
|
@ -51,9 +54,16 @@ internal class DefaultTimelineHolder(private val roomId: String,
|
|||
.build()
|
||||
|
||||
val livePagedListBuilder = LivePagedListBuilder(domainSourceFactory, pagedListConfig).setBoundaryCallback(boundaryCallback)
|
||||
return monarchy.findAllPagedWithChanges(realmDataSourceFactory, livePagedListBuilder)
|
||||
val eventsLiveData = monarchy.findAllPagedWithChanges(realmDataSourceFactory, livePagedListBuilder)
|
||||
|
||||
return LiveDataUtils.combine(eventsLiveData, boundaryCallback.status) { events, status ->
|
||||
val isLoadingForward = status.before == PagingRequestHelper.Status.RUNNING
|
||||
val isLoadingBackward = status.after == PagingRequestHelper.Status.RUNNING
|
||||
TimelineData(events, isLoadingForward, isLoadingBackward)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private fun clearUnlinkedEvents() {
|
||||
monarchy.tryTransactionAsync { realm ->
|
||||
val unlinkedEvents = EventEntity
|
|
@ -1,5 +1,6 @@
|
|||
package im.vector.matrix.android.internal.session.room.timeline
|
||||
|
||||
import android.arch.lifecycle.LiveData
|
||||
import android.arch.paging.PagedList
|
||||
import com.zhuinden.monarchy.Monarchy
|
||||
import im.vector.matrix.android.api.MatrixCallback
|
||||
|
@ -20,35 +21,60 @@ internal class TimelineBoundaryCallback(private val roomId: String,
|
|||
|
||||
var limit = 30
|
||||
|
||||
val status = object : LiveData<PagingRequestHelper.StatusReport>() {
|
||||
|
||||
init {
|
||||
value = PagingRequestHelper.StatusReport.createDefault()
|
||||
}
|
||||
|
||||
val listener = PagingRequestHelper.Listener { postValue(it) }
|
||||
|
||||
override fun onActive() {
|
||||
helper.addListener(listener)
|
||||
}
|
||||
|
||||
override fun onInactive() {
|
||||
helper.removeListener(listener)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onZeroItemsLoaded() {
|
||||
// actually, it's not possible
|
||||
}
|
||||
|
||||
override fun onItemAtEndLoaded(itemAtEnd: EnrichedEvent) {
|
||||
val token = itemAtEnd.root.eventId?.let { getToken(it, PaginationDirection.BACKWARDS) }
|
||||
?: return
|
||||
|
||||
helper.runIfNotRunning(PagingRequestHelper.RequestType.AFTER) {
|
||||
runPaginationRequest(it, itemAtEnd, PaginationDirection.BACKWARDS)
|
||||
runPaginationRequest(it, token, PaginationDirection.BACKWARDS)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onItemAtFrontLoaded(itemAtFront: EnrichedEvent) {
|
||||
val token = itemAtFront.root.eventId?.let { getToken(it, PaginationDirection.FORWARDS) }
|
||||
?: return
|
||||
|
||||
helper.runIfNotRunning(PagingRequestHelper.RequestType.BEFORE) {
|
||||
runPaginationRequest(it, itemAtFront, PaginationDirection.FORWARDS)
|
||||
runPaginationRequest(it, token, PaginationDirection.FORWARDS)
|
||||
}
|
||||
}
|
||||
|
||||
private fun runPaginationRequest(requestCallback: PagingRequestHelper.Request.Callback,
|
||||
item: EnrichedEvent,
|
||||
direction: PaginationDirection) {
|
||||
private fun getToken(eventId: String, direction: PaginationDirection): String? {
|
||||
var token: String? = null
|
||||
monarchy.doWithRealm { realm ->
|
||||
if (item.root.eventId == null) {
|
||||
return@doWithRealm
|
||||
}
|
||||
val chunkEntity = ChunkEntity.findAllIncludingEvents(realm, Collections.singletonList(item.root.eventId)).firstOrNull()
|
||||
val chunkEntity = ChunkEntity.findAllIncludingEvents(realm, Collections.singletonList(eventId)).firstOrNull()
|
||||
token = if (direction == PaginationDirection.FORWARDS) chunkEntity?.nextToken else chunkEntity?.prevToken
|
||||
}
|
||||
return token
|
||||
}
|
||||
|
||||
private fun runPaginationRequest(requestCallback: PagingRequestHelper.Request.Callback,
|
||||
from: String,
|
||||
direction: PaginationDirection) {
|
||||
|
||||
val params = PaginationTask.Params(roomId = roomId,
|
||||
from = token,
|
||||
from = from,
|
||||
direction = direction,
|
||||
limit = limit)
|
||||
|
||||
|
|
|
@ -0,0 +1,38 @@
|
|||
package im.vector.matrix.android.internal.util
|
||||
|
||||
import android.arch.lifecycle.LiveData
|
||||
import android.arch.lifecycle.MediatorLiveData
|
||||
|
||||
object LiveDataUtils {
|
||||
|
||||
fun <FIRST, SECOND, OUT> combine(firstSource: LiveData<FIRST>,
|
||||
secondSource: LiveData<SECOND>,
|
||||
mapper: (FIRST, SECOND) -> OUT): LiveData<OUT> {
|
||||
|
||||
return MediatorLiveData<OUT>().apply {
|
||||
var firstValue: FIRST? = null
|
||||
var secondValue: SECOND? = null
|
||||
|
||||
val valueDispatcher = {
|
||||
firstValue?.let { safeFirst ->
|
||||
secondValue?.let { safeSecond ->
|
||||
val mappedValue = mapper(safeFirst, safeSecond)
|
||||
postValue(mappedValue)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
addSource(firstSource) {
|
||||
firstValue = it
|
||||
valueDispatcher()
|
||||
}
|
||||
|
||||
addSource(secondSource) {
|
||||
secondValue = it
|
||||
valueDispatcher()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -379,6 +379,11 @@ public class PagingRequestHelper {
|
|||
@NonNull
|
||||
private final Throwable[] mErrors;
|
||||
|
||||
public static StatusReport createDefault() {
|
||||
final Throwable[] errors = {};
|
||||
return new StatusReport(Status.SUCCESS, Status.SUCCESS, Status.SUCCESS, errors);
|
||||
}
|
||||
|
||||
StatusReport(@NonNull Status initial, @NonNull Status before, @NonNull Status after,
|
||||
@NonNull Throwable[] errors) {
|
||||
this.initial = initial;
|
||||
|
|
Loading…
Reference in a new issue