forked from GitHub-Mirror/riotX-android
Still WIP for Paging integration
This commit is contained in:
parent
702abccb38
commit
d71ae02162
Binary file not shown.
@ -0,0 +1,14 @@
|
||||
package im.vector.riotredesign.features.home
|
||||
|
||||
import android.support.v7.util.DiffUtil
|
||||
import im.vector.matrix.android.api.session.events.model.Event
|
||||
|
||||
class EventDiffUtilCallback : DiffUtil.ItemCallback<Event>() {
|
||||
override fun areItemsTheSame(p0: Event, p1: Event): Boolean {
|
||||
return p0.eventId == p1.eventId
|
||||
}
|
||||
|
||||
override fun areContentsTheSame(p0: Event, p1: Event): Boolean {
|
||||
return p0 == p1
|
||||
}
|
||||
}
|
@ -14,10 +14,10 @@ import im.vector.matrix.android.api.session.room.Room
|
||||
import im.vector.riotredesign.R
|
||||
import im.vector.riotredesign.core.platform.RiotFragment
|
||||
import im.vector.riotredesign.core.utils.FragmentArgumentDelegate
|
||||
import kotlinx.android.synthetic.main.fragment_room_list.*
|
||||
import kotlinx.android.synthetic.main.fragment_room_detail.*
|
||||
import org.koin.android.ext.android.inject
|
||||
|
||||
class RoomDetailFragment : RiotFragment() {
|
||||
class RoomDetailFragment : RiotFragment(), TimelineAdapter.Callback {
|
||||
|
||||
companion object {
|
||||
|
||||
@ -31,7 +31,7 @@ class RoomDetailFragment : RiotFragment() {
|
||||
private val matrix by inject<Matrix>()
|
||||
private val currentSession = matrix.currentSession!!
|
||||
private var roomId by FragmentArgumentDelegate<String>()
|
||||
private val timelineController = TimelineEventController()
|
||||
private val adapter = TimelineAdapter(this)
|
||||
private lateinit var room: Room
|
||||
|
||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
|
||||
@ -46,14 +46,27 @@ class RoomDetailFragment : RiotFragment() {
|
||||
}
|
||||
|
||||
private fun renderEvents(events: PagedList<Event>?) {
|
||||
timelineController.submitList(events)
|
||||
adapter.submitList(events)
|
||||
}
|
||||
|
||||
private fun setupRecyclerView() {
|
||||
val linearLayoutManager = LinearLayoutManager(context, RecyclerView.VERTICAL, false)
|
||||
linearLayoutManager.stackFromEnd = true
|
||||
epoxyRecyclerView.layoutManager = linearLayoutManager
|
||||
epoxyRecyclerView.setController(timelineController)
|
||||
val layoutManager = LinearLayoutManager(context, LinearLayoutManager.VERTICAL, false)
|
||||
adapter.registerAdapterDataObserver(object : RecyclerView.AdapterDataObserver() {
|
||||
override fun onItemRangeInserted(positionStart: Int, itemCount: Int) {
|
||||
if (layoutManager.findLastCompletelyVisibleItemPosition() == positionStart - itemCount) {
|
||||
layoutManager.scrollToPosition(adapter.itemCount - 1)
|
||||
}
|
||||
}
|
||||
})
|
||||
recyclerView.layoutManager = layoutManager
|
||||
recyclerView.adapter = adapter
|
||||
recyclerView.setHasFixedSize(true)
|
||||
}
|
||||
|
||||
override fun onEventsListChanged(oldList: List<Event>?, newList: List<Event>?) {
|
||||
if (oldList == null && newList != null) {
|
||||
recyclerView.scrollToPosition(newList.size - 1)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -0,0 +1,57 @@
|
||||
package im.vector.riotredesign.features.home
|
||||
|
||||
import android.arch.paging.PagedList
|
||||
import android.arch.paging.PagedListAdapter
|
||||
import android.support.v7.widget.RecyclerView
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.TextView
|
||||
import im.vector.matrix.android.api.session.events.model.Event
|
||||
import im.vector.riotredesign.R
|
||||
|
||||
/**
|
||||
* Created by francois on 14/05/2018.
|
||||
*/
|
||||
|
||||
class TimelineAdapter(private val callback: Callback? = null)
|
||||
: PagedListAdapter<Event, TimelineAdapter.ViewHolder>(EventDiffUtilCallback()) {
|
||||
|
||||
|
||||
private var currentList: List<Event>? = null
|
||||
|
||||
override fun onCreateViewHolder(parent: ViewGroup, position: Int): ViewHolder {
|
||||
val view = LayoutInflater.from(parent.context).inflate(R.layout.item_event, parent, false)
|
||||
return ViewHolder(view)
|
||||
}
|
||||
|
||||
override fun onBindViewHolder(viewHolder: ViewHolder, position: Int) {
|
||||
val event = getItem(position)
|
||||
viewHolder.bind(event)
|
||||
}
|
||||
|
||||
|
||||
class ViewHolder(view: View) : RecyclerView.ViewHolder(view) {
|
||||
|
||||
val titleView = view.findViewById<TextView>(R.id.titleView)!!
|
||||
|
||||
fun bind(event: Event?) {
|
||||
if (event == null) {
|
||||
|
||||
} else {
|
||||
titleView.text = event.toString()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onCurrentListChanged(newList: PagedList<Event>?) {
|
||||
callback?.onEventsListChanged(currentList, newList)
|
||||
currentList = newList
|
||||
}
|
||||
|
||||
interface Callback {
|
||||
fun onEventsListChanged(oldList: List<Event>?, newList: List<Event>?)
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -6,7 +6,6 @@ import com.airbnb.epoxy.paging.PagedListEpoxyController
|
||||
import im.vector.matrix.android.api.session.events.model.Event
|
||||
|
||||
class TimelineEventController : PagedListEpoxyController<Event>(
|
||||
modelBuildingHandler = EpoxyAsyncUtil.getAsyncBackgroundHandler(),
|
||||
diffingHandler = EpoxyAsyncUtil.getAsyncBackgroundHandler()
|
||||
) {
|
||||
|
||||
|
@ -11,13 +11,14 @@
|
||||
android:id="@+id/loginField"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:layout_marginStart="16dp"
|
||||
android:layout_marginTop="16dp"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:ems="10"
|
||||
android:hint="Name"
|
||||
android:inputType="textPersonName"
|
||||
android:inputType="text"
|
||||
android:singleLine="false"
|
||||
android:text="ganfra07086"
|
||||
app:layout_constraintBottom_toTopOf="@+id/passwordField"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintHorizontal_bias="0.503"
|
||||
@ -32,6 +33,7 @@
|
||||
android:ems="10"
|
||||
android:hint="Password"
|
||||
android:inputType="textPassword"
|
||||
android:text="111111"
|
||||
app:layout_constraintEnd_toEndOf="@+id/loginField"
|
||||
app:layout_constraintStart_toStartOf="@+id/loginField"
|
||||
app:layout_constraintTop_toBottomOf="@+id/loginField" />
|
||||
@ -40,10 +42,10 @@
|
||||
android:id="@+id/progressBar"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="8dp"
|
||||
android:layout_marginEnd="8dp"
|
||||
android:layout_marginStart="8dp"
|
||||
android:layout_marginTop="8dp"
|
||||
android:layout_marginEnd="8dp"
|
||||
android:layout_marginBottom="8dp"
|
||||
android:visibility="gone"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
@ -55,9 +57,9 @@
|
||||
android:id="@+id/authenticateButton"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="8dp"
|
||||
android:layout_marginEnd="32dp"
|
||||
android:layout_marginStart="32dp"
|
||||
android:layout_marginEnd="32dp"
|
||||
android:layout_marginBottom="8dp"
|
||||
android:text="Authenticate"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
|
@ -1,10 +1,10 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<android.support.constraint.ConstraintLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent"
|
||||
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<com.airbnb.epoxy.EpoxyRecyclerView
|
||||
android:id="@+id/epoxyRecyclerView"
|
||||
<android.support.v7.widget.RecyclerView
|
||||
android:id="@+id/recyclerView"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent" />
|
||||
|
||||
|
@ -7,7 +7,10 @@ import io.realm.RealmQuery
|
||||
import io.realm.RealmResults
|
||||
|
||||
fun ChunkEntity.Companion.where(realm: Realm, roomId: String): RealmQuery<ChunkEntity> {
|
||||
return realm.where(ChunkEntity::class.java).equalTo("room.roomId", roomId)
|
||||
return realm.where(ChunkEntity::class.java)
|
||||
.equalTo("room.roomId", roomId)
|
||||
.notEqualTo("prevToken", DBConstants.STATE_EVENTS_CHUNK_TOKEN)
|
||||
.notEqualTo("nextToken", DBConstants.STATE_EVENTS_CHUNK_TOKEN)
|
||||
}
|
||||
|
||||
fun ChunkEntity.Companion.findWithPrevToken(realm: Realm, roomId: String, prevToken: String?): ChunkEntity? {
|
||||
|
@ -25,13 +25,19 @@ data class DefaultRoom(
|
||||
|
||||
override fun liveTimeline(): LiveData<PagedList<Event>> {
|
||||
val realmDataSourceFactory = monarchy.createDataSourceFactory { realm ->
|
||||
ChunkEntity.where(realm, roomId).findAll().last(null).let { it?.events }?.where()
|
||||
ChunkEntity.where(realm, roomId)
|
||||
.findAll()
|
||||
.last(null)
|
||||
?.let { it.events }
|
||||
?.where()
|
||||
?.sort("originServerTs")
|
||||
}
|
||||
val domainSourceFactory = realmDataSourceFactory.map { EventMapper.map(it) }
|
||||
|
||||
val pagedListConfig = PagedList.Config.Builder()
|
||||
.setEnablePlaceholders(false)
|
||||
.setPageSize(10)
|
||||
.setInitialLoadSizeHint(30)
|
||||
.setPrefetchDistance(5)
|
||||
.build()
|
||||
|
||||
|
@ -9,7 +9,6 @@ import im.vector.matrix.android.api.failure.Failure
|
||||
import im.vector.matrix.android.api.util.Cancelable
|
||||
import im.vector.matrix.android.internal.database.mapper.asEntity
|
||||
import im.vector.matrix.android.internal.database.model.ChunkEntity
|
||||
import im.vector.matrix.android.internal.database.model.EventEntity
|
||||
import im.vector.matrix.android.internal.database.model.RoomEntity
|
||||
import im.vector.matrix.android.internal.database.query.findAllIncludingEvents
|
||||
import im.vector.matrix.android.internal.database.query.findWithNextToken
|
||||
@ -87,34 +86,30 @@ class PaginationRequest(private val roomAPI: RoomAPI,
|
||||
ChunkEntity()
|
||||
}
|
||||
|
||||
|
||||
val eventsToAdd = ArrayList<EventEntity>()
|
||||
|
||||
currentChunk.prevToken = chunkEvent.prevToken
|
||||
mergedEvents.forEach { event ->
|
||||
val eventEntity = event.asEntity().let {
|
||||
realm.copyToRealmOrUpdate(it)
|
||||
}
|
||||
if (!currentChunk.events.contains(eventEntity)) {
|
||||
eventsToAdd.add(0, eventEntity)
|
||||
currentChunk.events.add(0, eventEntity)
|
||||
}
|
||||
}
|
||||
|
||||
if (prevChunk != null) {
|
||||
eventsToAdd.addAll(0, prevChunk.events)
|
||||
currentChunk.events.addAll(prevChunk.events)
|
||||
roomEntity.chunks.remove(prevChunk)
|
||||
|
||||
} else if (hasOverlapped) {
|
||||
chunksOverlapped.forEach { chunk ->
|
||||
chunk.events.forEach { event ->
|
||||
if (!currentChunk.events.contains(event)) {
|
||||
eventsToAdd.add(0, event)
|
||||
currentChunk.events.add(0, event)
|
||||
}
|
||||
}
|
||||
roomEntity.chunks.remove(chunk)
|
||||
}
|
||||
}
|
||||
currentChunk.events.addAll(0, eventsToAdd)
|
||||
if (!roomEntity.chunks.contains(currentChunk)) {
|
||||
roomEntity.chunks.add(currentChunk)
|
||||
}
|
||||
|
@ -26,7 +26,15 @@ class TimelineBoundaryCallback(private val paginationRequest: PaginationRequest,
|
||||
}
|
||||
|
||||
override fun onItemAtEndLoaded(itemAtEnd: Event) {
|
||||
//Todo handle forward pagination
|
||||
helper.runIfNotRunning(PagingRequestHelper.RequestType.AFTER) {
|
||||
monarchy.doWithRealm { realm ->
|
||||
if (itemAtEnd.eventId == null) {
|
||||
return@doWithRealm
|
||||
}
|
||||
val chunkEntity = ChunkEntity.findAllIncludingEvents(realm, Collections.singletonList(itemAtEnd.eventId)).firstOrNull()
|
||||
paginationRequest.execute(roomId, chunkEntity?.nextToken, PaginationDirection.FORWARDS, callback = createCallback(it))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onItemAtFrontLoaded(itemAtFront: Event) {
|
||||
@ -39,7 +47,6 @@ class TimelineBoundaryCallback(private val paginationRequest: PaginationRequest,
|
||||
paginationRequest.execute(roomId, chunkEntity?.prevToken, PaginationDirection.BACKWARDS, callback = createCallback(it))
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private fun createCallback(pagingRequestCallback: PagingRequestHelper.Request.Callback) = object : MatrixCallback<TokenChunkEvent> {
|
||||
|
Loading…
Reference in New Issue
Block a user