/* * * * 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.riotredesign.features.home.room.detail.timeline import com.airbnb.epoxy.EpoxyAsyncUtil import com.airbnb.epoxy.EpoxyModel import im.vector.matrix.android.api.session.events.model.EventType import im.vector.matrix.android.api.session.room.timeline.TimelineEvent 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.paging.PagedListEpoxyController class TimelineEventController(private val roomId: String, private val dateFormatter: TimelineDateFormatter, private val timelineItemFactory: TimelineItemFactory ) : PagedListEpoxyController( EpoxyAsyncUtil.getAsyncBackgroundHandler(), EpoxyAsyncUtil.getAsyncBackgroundHandler() ) { init { setFilterDuplicates(true) } private var isLoadingForward: Boolean = false private var isLoadingBackward: Boolean = false private var hasReachedEnd: Boolean = false var callback: Callback? = null fun update(timelineData: TimelineData?) { timelineData?.let { isLoadingForward = it.isLoadingForward isLoadingBackward = it.isLoadingBackward hasReachedEnd = it.events.lastOrNull()?.root?.type == EventType.STATE_ROOM_CREATE submitList(it.events) requestModelBuild() } } override fun buildItemModels(currentPosition: Int, items: List): List> { if (items.isNullOrEmpty()) { return emptyList() } val epoxyModels = ArrayList>() val event = items[currentPosition] ?: return emptyList() val nextEvent = if (currentPosition + 1 < items.size) items[currentPosition + 1] else null val date = event.root.localDateTime() val nextDate = nextEvent?.root?.localDateTime() val addDaySeparator = date.toLocalDate() != nextDate?.toLocalDate() timelineItemFactory.create(event, nextEvent, callback)?.also { it.id(event.localId) epoxyModels.add(it) } if (addDaySeparator) { val formattedDay = dateFormatter.formatMessageDay(date) val daySeparatorItem = DaySeparatorItem(formattedDay).id(roomId + formattedDay) epoxyModels.add(daySeparatorItem) } return epoxyModels } override fun addModels(models: List>) { LoadingItemModel_() .id(roomId + "forward_loading_item") .addIf(isLoadingForward, this) super.add(models) LoadingItemModel_() .id(roomId + "backward_loading_item") .addIf(!hasReachedEnd, this) } interface Callback { fun onUrlClicked(url: String) } }