mirror of
https://github.com/vector-im/element-android.git
synced 2024-11-15 01:35:07 +08:00
Continue to work on timeline/pagination. WIP
This commit is contained in:
parent
6e3992e70e
commit
702abccb38
@ -9,4 +9,8 @@ fun AppCompatActivity.addFragment(fragment: Fragment, frameId: Int) {
|
|||||||
|
|
||||||
fun AppCompatActivity.replaceFragment(fragment: Fragment, frameId: Int) {
|
fun AppCompatActivity.replaceFragment(fragment: Fragment, frameId: Int) {
|
||||||
supportFragmentManager.inTransaction { replace(frameId, fragment) }
|
supportFragmentManager.inTransaction { replace(frameId, fragment) }
|
||||||
|
}
|
||||||
|
|
||||||
|
fun AppCompatActivity.addFragmentToBackstack(fragment: Fragment, frameId: Int, tag: String? = null) {
|
||||||
|
supportFragmentManager.inTransaction { replace(frameId, fragment).addToBackStack(tag) }
|
||||||
}
|
}
|
@ -16,4 +16,12 @@ fun Fragment.addChildFragment(fragment: Fragment, frameId: Int) {
|
|||||||
|
|
||||||
fun Fragment.replaceChildFragment(fragment: Fragment, frameId: Int) {
|
fun Fragment.replaceChildFragment(fragment: Fragment, frameId: Int) {
|
||||||
childFragmentManager.inTransaction { replace(frameId, fragment) }
|
childFragmentManager.inTransaction { replace(frameId, fragment) }
|
||||||
|
}
|
||||||
|
|
||||||
|
fun Fragment.addFragmentToBackstack(fragment: Fragment, frameId: Int, tag: String? = null) {
|
||||||
|
fragmentManager?.inTransaction { replace(frameId, fragment).addToBackStack(tag) }
|
||||||
|
}
|
||||||
|
|
||||||
|
fun Fragment.addChildFragmentToBackstack(fragment: Fragment, frameId: Int, tag: String? = null) {
|
||||||
|
childFragmentManager.inTransaction { replace(frameId, fragment).addToBackStack(tag) }
|
||||||
}
|
}
|
@ -3,19 +3,21 @@ package im.vector.riotredesign.features.home
|
|||||||
import android.arch.lifecycle.Observer
|
import android.arch.lifecycle.Observer
|
||||||
import android.arch.paging.PagedList
|
import android.arch.paging.PagedList
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
|
import android.support.v7.widget.LinearLayoutManager
|
||||||
|
import android.support.v7.widget.RecyclerView
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import android.widget.Toast
|
|
||||||
import im.vector.matrix.android.api.Matrix
|
import im.vector.matrix.android.api.Matrix
|
||||||
import im.vector.matrix.android.api.session.events.model.Event
|
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.Room
|
||||||
import im.vector.riotredesign.R
|
import im.vector.riotredesign.R
|
||||||
import im.vector.riotredesign.core.platform.RiotFragment
|
import im.vector.riotredesign.core.platform.RiotFragment
|
||||||
import im.vector.riotredesign.core.utils.FragmentArgumentDelegate
|
import im.vector.riotredesign.core.utils.FragmentArgumentDelegate
|
||||||
|
import kotlinx.android.synthetic.main.fragment_room_list.*
|
||||||
import org.koin.android.ext.android.inject
|
import org.koin.android.ext.android.inject
|
||||||
|
|
||||||
class RoomDetailFragment : RiotFragment(), RoomController.Callback {
|
class RoomDetailFragment : RiotFragment() {
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
|
||||||
@ -29,11 +31,8 @@ class RoomDetailFragment : RiotFragment(), RoomController.Callback {
|
|||||||
private val matrix by inject<Matrix>()
|
private val matrix by inject<Matrix>()
|
||||||
private val currentSession = matrix.currentSession!!
|
private val currentSession = matrix.currentSession!!
|
||||||
private var roomId by FragmentArgumentDelegate<String>()
|
private var roomId by FragmentArgumentDelegate<String>()
|
||||||
|
|
||||||
private val timelineController = TimelineEventController()
|
private val timelineController = TimelineEventController()
|
||||||
private val room: Room? by lazy {
|
private lateinit var room: Room
|
||||||
currentSession.getRoom(roomId)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
|
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
|
||||||
return inflater.inflate(R.layout.fragment_room_detail, container, false)
|
return inflater.inflate(R.layout.fragment_room_detail, container, false)
|
||||||
@ -41,19 +40,20 @@ class RoomDetailFragment : RiotFragment(), RoomController.Callback {
|
|||||||
|
|
||||||
override fun onActivityCreated(savedInstanceState: Bundle?) {
|
override fun onActivityCreated(savedInstanceState: Bundle?) {
|
||||||
super.onActivityCreated(savedInstanceState)
|
super.onActivityCreated(savedInstanceState)
|
||||||
if (room == null) {
|
setupRecyclerView()
|
||||||
activity?.onBackPressed()
|
room = currentSession.getRoom(roomId)!!
|
||||||
return
|
room.liveTimeline().observe(this, Observer { renderEvents(it) })
|
||||||
}
|
|
||||||
room?.liveTimeline()?.observe(this, Observer { renderEvents(it) })
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun renderEvents(events: PagedList<Event>?) {
|
private fun renderEvents(events: PagedList<Event>?) {
|
||||||
timelineController.submitList(events)
|
timelineController.submitList(events)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onRoomSelected(room: Room) {
|
private fun setupRecyclerView() {
|
||||||
Toast.makeText(context, "Room ${room.roomId} clicked", Toast.LENGTH_SHORT).show()
|
val linearLayoutManager = LinearLayoutManager(context, RecyclerView.VERTICAL, false)
|
||||||
|
linearLayoutManager.stackFromEnd = true
|
||||||
|
epoxyRecyclerView.layoutManager = linearLayoutManager
|
||||||
|
epoxyRecyclerView.setController(timelineController)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -2,13 +2,14 @@ package im.vector.riotredesign.features.home
|
|||||||
|
|
||||||
import android.arch.lifecycle.Observer
|
import android.arch.lifecycle.Observer
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
|
import android.support.v7.widget.LinearLayoutManager
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import im.vector.matrix.android.api.Matrix
|
import im.vector.matrix.android.api.Matrix
|
||||||
import im.vector.matrix.android.api.session.room.Room
|
import im.vector.matrix.android.api.session.room.Room
|
||||||
import im.vector.riotredesign.R
|
import im.vector.riotredesign.R
|
||||||
import im.vector.riotredesign.core.extensions.replaceFragment
|
import im.vector.riotredesign.core.extensions.addFragmentToBackstack
|
||||||
import im.vector.riotredesign.core.platform.RiotFragment
|
import im.vector.riotredesign.core.platform.RiotFragment
|
||||||
import kotlinx.android.synthetic.main.fragment_room_list.*
|
import kotlinx.android.synthetic.main.fragment_room_list.*
|
||||||
import org.koin.android.ext.android.inject
|
import org.koin.android.ext.android.inject
|
||||||
@ -43,7 +44,7 @@ class RoomListFragment : RiotFragment(), RoomController.Callback {
|
|||||||
|
|
||||||
override fun onRoomSelected(room: Room) {
|
override fun onRoomSelected(room: Room) {
|
||||||
val detailFragment = RoomDetailFragment.newInstance(room.roomId)
|
val detailFragment = RoomDetailFragment.newInstance(room.roomId)
|
||||||
replaceFragment(detailFragment, R.id.homeFragmentContainer)
|
addFragmentToBackstack(detailFragment, R.id.homeFragmentContainer)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -6,14 +6,15 @@ import com.airbnb.epoxy.paging.PagedListEpoxyController
|
|||||||
import im.vector.matrix.android.api.session.events.model.Event
|
import im.vector.matrix.android.api.session.events.model.Event
|
||||||
|
|
||||||
class TimelineEventController : PagedListEpoxyController<Event>(
|
class TimelineEventController : PagedListEpoxyController<Event>(
|
||||||
modelBuildingHandler = EpoxyAsyncUtil.getAsyncBackgroundHandler()
|
modelBuildingHandler = EpoxyAsyncUtil.getAsyncBackgroundHandler(),
|
||||||
|
diffingHandler = EpoxyAsyncUtil.getAsyncBackgroundHandler()
|
||||||
) {
|
) {
|
||||||
|
|
||||||
override fun buildItemModel(currentPosition: Int, item: Event?): EpoxyModel<*> {
|
override fun buildItemModel(currentPosition: Int, item: Event?): EpoxyModel<*> {
|
||||||
return if (item == null) {
|
return if (item == null) {
|
||||||
LoadingItemModel_().id(-currentPosition)
|
LoadingItemModel_().id(-currentPosition)
|
||||||
} else {
|
} else {
|
||||||
TimelineEventItem(item.eventId ?: "$currentPosition").id(currentPosition)
|
TimelineEventItem(item.toString()).id(currentPosition)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,10 +1,9 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
|
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
|
||||||
android:id="@+id/titleView"
|
android:id="@+id/titleView"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="80dp"
|
android:layout_height="wrap_content"
|
||||||
android:gravity="center_vertical"
|
android:gravity="center_vertical"
|
||||||
|
android:minHeight="80dp"
|
||||||
android:padding="16dp"
|
android:padding="16dp"
|
||||||
android:textSize="14sp"
|
android:textSize="14sp" />
|
||||||
tools:text="Room name" />
|
|
@ -1,5 +1,6 @@
|
|||||||
package im.vector.matrix.android.internal.database.query
|
package im.vector.matrix.android.internal.database.query
|
||||||
|
|
||||||
|
import im.vector.matrix.android.internal.database.DBConstants
|
||||||
import im.vector.matrix.android.internal.database.model.ChunkEntity
|
import im.vector.matrix.android.internal.database.model.ChunkEntity
|
||||||
import io.realm.Realm
|
import io.realm.Realm
|
||||||
import io.realm.RealmQuery
|
import io.realm.RealmQuery
|
||||||
@ -40,5 +41,7 @@ fun ChunkEntity.Companion.findLastFromRoom(realm: Realm, roomId: String): ChunkE
|
|||||||
fun ChunkEntity.Companion.findAllIncludingEvents(realm: Realm, eventIds: List<String>): RealmResults<ChunkEntity> {
|
fun ChunkEntity.Companion.findAllIncludingEvents(realm: Realm, eventIds: List<String>): RealmResults<ChunkEntity> {
|
||||||
return realm.where(ChunkEntity::class.java)
|
return realm.where(ChunkEntity::class.java)
|
||||||
.`in`("events.eventId", eventIds.toTypedArray())
|
.`in`("events.eventId", eventIds.toTypedArray())
|
||||||
|
.notEqualTo("prevToken", DBConstants.STATE_EVENTS_CHUNK_TOKEN)
|
||||||
|
.notEqualTo("nextToken", DBConstants.STATE_EVENTS_CHUNK_TOKEN)
|
||||||
.findAll()
|
.findAll()
|
||||||
}
|
}
|
@ -11,11 +11,15 @@ fun EventEntity.Companion.where(realm: Realm, roomId: String): RealmQuery<EventE
|
|||||||
.equalTo("chunk.room.roomId", roomId)
|
.equalTo("chunk.room.roomId", roomId)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun EventEntity.Companion.where(realm: Realm, chunk: ChunkEntity): RealmQuery<EventEntity> {
|
fun EventEntity.Companion.where(realm: Realm, chunk: ChunkEntity?): RealmQuery<EventEntity> {
|
||||||
return realm.where(EventEntity::class.java)
|
var query = realm.where(EventEntity::class.java)
|
||||||
.equalTo("chunk.prevToken", chunk.prevToken)
|
if (chunk?.prevToken != null) {
|
||||||
.and()
|
query = query.equalTo("chunk.prevToken", chunk.prevToken)
|
||||||
.equalTo("chunk.nextToken", chunk.nextToken)
|
}
|
||||||
|
if (chunk?.nextToken != null) {
|
||||||
|
query = query.equalTo("chunk.nextToken", chunk.nextToken)
|
||||||
|
}
|
||||||
|
return query
|
||||||
}
|
}
|
||||||
|
|
||||||
fun RealmResults<EventEntity>.getLast(type: String? = null): EventEntity? {
|
fun RealmResults<EventEntity>.getLast(type: String? = null): EventEntity? {
|
||||||
@ -23,5 +27,5 @@ fun RealmResults<EventEntity>.getLast(type: String? = null): EventEntity? {
|
|||||||
if (type != null) {
|
if (type != null) {
|
||||||
query = query.equalTo("type", type)
|
query = query.equalTo("type", type)
|
||||||
}
|
}
|
||||||
return query.findAll().sort("age").last(null)
|
return query.findAll().last(null)
|
||||||
}
|
}
|
@ -5,7 +5,9 @@ import im.vector.matrix.android.internal.network.parsing.UriMoshiAdapter
|
|||||||
|
|
||||||
object MoshiProvider {
|
object MoshiProvider {
|
||||||
|
|
||||||
private val moshi: Moshi = Moshi.Builder().add(UriMoshiAdapter()).build()
|
private val moshi: Moshi = Moshi.Builder()
|
||||||
|
.add(UriMoshiAdapter())
|
||||||
|
.build()
|
||||||
|
|
||||||
fun providesMoshi(): Moshi {
|
fun providesMoshi(): Moshi {
|
||||||
return moshi
|
return moshi
|
||||||
|
@ -8,7 +8,6 @@ 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.Room
|
||||||
import im.vector.matrix.android.internal.database.mapper.EventMapper
|
import im.vector.matrix.android.internal.database.mapper.EventMapper
|
||||||
import im.vector.matrix.android.internal.database.model.ChunkEntity
|
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.query.where
|
import im.vector.matrix.android.internal.database.query.where
|
||||||
import im.vector.matrix.android.internal.session.room.timeline.PaginationRequest
|
import im.vector.matrix.android.internal.session.room.timeline.PaginationRequest
|
||||||
import im.vector.matrix.android.internal.session.room.timeline.TimelineBoundaryCallback
|
import im.vector.matrix.android.internal.session.room.timeline.TimelineBoundaryCallback
|
||||||
@ -26,15 +25,17 @@ data class DefaultRoom(
|
|||||||
|
|
||||||
override fun liveTimeline(): LiveData<PagedList<Event>> {
|
override fun liveTimeline(): LiveData<PagedList<Event>> {
|
||||||
val realmDataSourceFactory = monarchy.createDataSourceFactory { realm ->
|
val realmDataSourceFactory = monarchy.createDataSourceFactory { realm ->
|
||||||
val lastChunk = ChunkEntity.where(realm, roomId).findAll().last(null)
|
ChunkEntity.where(realm, roomId).findAll().last(null).let { it?.events }?.where()
|
||||||
if (lastChunk == null) {
|
|
||||||
EventEntity.where(realm, roomId)
|
|
||||||
} else {
|
|
||||||
EventEntity.where(realm, lastChunk)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
val domainSourceFactory = realmDataSourceFactory.map { EventMapper.map(it) }
|
val domainSourceFactory = realmDataSourceFactory.map { EventMapper.map(it) }
|
||||||
val livePagedListBuilder = LivePagedListBuilder(domainSourceFactory, 20).setBoundaryCallback(boundaryCallback)
|
|
||||||
|
val pagedListConfig = PagedList.Config.Builder()
|
||||||
|
.setEnablePlaceholders(false)
|
||||||
|
.setPageSize(10)
|
||||||
|
.setPrefetchDistance(5)
|
||||||
|
.build()
|
||||||
|
|
||||||
|
val livePagedListBuilder = LivePagedListBuilder(domainSourceFactory, pagedListConfig).setBoundaryCallback(boundaryCallback)
|
||||||
return monarchy.findAllPagedWithChanges(realmDataSourceFactory, livePagedListBuilder)
|
return monarchy.findAllPagedWithChanges(realmDataSourceFactory, livePagedListBuilder)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
package im.vector.matrix.android.internal.session.room
|
package im.vector.matrix.android.internal.session.room
|
||||||
|
|
||||||
|
import im.vector.matrix.android.internal.network.NetworkConstants
|
||||||
import im.vector.matrix.android.internal.session.room.model.TokenChunkEvent
|
import im.vector.matrix.android.internal.session.room.model.TokenChunkEvent
|
||||||
import kotlinx.coroutines.Deferred
|
import kotlinx.coroutines.Deferred
|
||||||
import retrofit2.Response
|
import retrofit2.Response
|
||||||
@ -18,12 +19,13 @@ interface RoomAPI {
|
|||||||
* @param limit the maximum number of messages to retrieve. Optional.
|
* @param limit the maximum number of messages to retrieve. Optional.
|
||||||
* @param filter A JSON RoomEventFilter to filter returned events with. Optional.
|
* @param filter A JSON RoomEventFilter to filter returned events with. Optional.
|
||||||
*/
|
*/
|
||||||
@GET("rooms/{roomId}/messages")
|
@GET(NetworkConstants.URI_API_PREFIX_PATH_R0 + "rooms/{roomId}/messages")
|
||||||
fun getRoomMessagesFrom(@Path("roomId") roomId: String,
|
fun getRoomMessagesFrom(@Path("roomId") roomId: String,
|
||||||
@Query("from") from: String,
|
@Query("from") from: String,
|
||||||
@Query("dir") dir: String,
|
@Query("dir") dir: String,
|
||||||
@Query("limit") limit: Int,
|
@Query("limit") limit: Int,
|
||||||
@Query("filter") filter: String?): Deferred<Response<TokenChunkEvent>>
|
@Query("filter") filter: String?
|
||||||
|
): Deferred<Response<TokenChunkEvent>>
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
@ -0,0 +1,15 @@
|
|||||||
|
package im.vector.matrix.android.internal.session.room.model
|
||||||
|
|
||||||
|
enum class PaginationDirection(val value: String) {
|
||||||
|
/**
|
||||||
|
* Forwards when the event is added to the end of the timeline.
|
||||||
|
* These events come from the /sync stream or from forwards pagination.
|
||||||
|
*/
|
||||||
|
FORWARDS("f"),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Backwards when the event is added to the start of the timeline.
|
||||||
|
* These events come from a back pagination.
|
||||||
|
*/
|
||||||
|
BACKWARDS("b")
|
||||||
|
}
|
@ -6,8 +6,8 @@ import im.vector.matrix.android.api.session.events.model.Event
|
|||||||
|
|
||||||
@JsonClass(generateAdapter = true)
|
@JsonClass(generateAdapter = true)
|
||||||
data class TokenChunkEvent(
|
data class TokenChunkEvent(
|
||||||
@Json(name = "start") val prevToken: String? = null,
|
@Json(name = "start") val nextToken: String? = null,
|
||||||
@Json(name = "end") val nextToken: String? = null,
|
@Json(name = "end") val prevToken: String? = null,
|
||||||
@Json(name = "chunks") val chunk: List<Event> = emptyList(),
|
@Json(name = "chunk") val chunk: List<Event> = emptyList(),
|
||||||
@Json(name = "state") val stateEvents: List<Event> = emptyList()
|
@Json(name = "state") val stateEvents: List<Event> = emptyList()
|
||||||
)
|
)
|
@ -9,6 +9,7 @@ import im.vector.matrix.android.api.failure.Failure
|
|||||||
import im.vector.matrix.android.api.util.Cancelable
|
import im.vector.matrix.android.api.util.Cancelable
|
||||||
import im.vector.matrix.android.internal.database.mapper.asEntity
|
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.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.model.RoomEntity
|
||||||
import im.vector.matrix.android.internal.database.query.findAllIncludingEvents
|
import im.vector.matrix.android.internal.database.query.findAllIncludingEvents
|
||||||
import im.vector.matrix.android.internal.database.query.findWithNextToken
|
import im.vector.matrix.android.internal.database.query.findWithNextToken
|
||||||
@ -16,6 +17,7 @@ import im.vector.matrix.android.internal.database.query.findWithPrevToken
|
|||||||
import im.vector.matrix.android.internal.database.query.where
|
import im.vector.matrix.android.internal.database.query.where
|
||||||
import im.vector.matrix.android.internal.network.executeRequest
|
import im.vector.matrix.android.internal.network.executeRequest
|
||||||
import im.vector.matrix.android.internal.session.room.RoomAPI
|
import im.vector.matrix.android.internal.session.room.RoomAPI
|
||||||
|
import im.vector.matrix.android.internal.session.room.model.PaginationDirection
|
||||||
import im.vector.matrix.android.internal.session.room.model.TokenChunkEvent
|
import im.vector.matrix.android.internal.session.room.model.TokenChunkEvent
|
||||||
import im.vector.matrix.android.internal.util.CancelableCoroutine
|
import im.vector.matrix.android.internal.util.CancelableCoroutine
|
||||||
import im.vector.matrix.android.internal.util.MatrixCoroutineDispatchers
|
import im.vector.matrix.android.internal.util.MatrixCoroutineDispatchers
|
||||||
@ -28,8 +30,8 @@ class PaginationRequest(private val roomAPI: RoomAPI,
|
|||||||
private val coroutineDispatchers: MatrixCoroutineDispatchers) {
|
private val coroutineDispatchers: MatrixCoroutineDispatchers) {
|
||||||
|
|
||||||
fun execute(roomId: String,
|
fun execute(roomId: String,
|
||||||
from: String? = null,
|
from: String?,
|
||||||
direction: String,
|
direction: PaginationDirection,
|
||||||
limit: Int = 10,
|
limit: Int = 10,
|
||||||
filter: String? = null,
|
filter: String? = null,
|
||||||
callback: MatrixCallback<TokenChunkEvent>
|
callback: MatrixCallback<TokenChunkEvent>
|
||||||
@ -42,22 +44,24 @@ class PaginationRequest(private val roomAPI: RoomAPI,
|
|||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun execute(roomId: String,
|
private suspend fun execute(roomId: String,
|
||||||
from: String? = null,
|
from: String?,
|
||||||
direction: String,
|
direction: PaginationDirection,
|
||||||
limit: Int = 10,
|
limit: Int = 10,
|
||||||
filter: String? = null) = withContext(coroutineDispatchers.io) {
|
filter: String?) = withContext(coroutineDispatchers.io) {
|
||||||
|
|
||||||
if (from == null) {
|
if (from == null) {
|
||||||
return@withContext Either.left(Failure.Unknown(RuntimeException("From token can't be null")))
|
return@withContext Either.left(
|
||||||
|
Failure.Unknown(RuntimeException("From token shouldn't be null"))
|
||||||
|
)
|
||||||
}
|
}
|
||||||
executeRequest<TokenChunkEvent> {
|
return@withContext executeRequest<TokenChunkEvent> {
|
||||||
apiCall = roomAPI.getRoomMessagesFrom(roomId, from, direction, limit, filter)
|
apiCall = roomAPI.getRoomMessagesFrom(roomId, from, direction.value, limit, filter)
|
||||||
}.leftIfNull {
|
}.leftIfNull {
|
||||||
Failure.Unknown(RuntimeException("TokenChunkEvent shouldn't be null"))
|
Failure.Unknown(RuntimeException("TokenChunkEvent shouldn't be null"))
|
||||||
}.flatMap {
|
}.flatMap { chunk ->
|
||||||
try {
|
try {
|
||||||
insertInDb(it, roomId)
|
insertInDb(chunk, roomId)
|
||||||
Either.right(it)
|
Either.right(chunk)
|
||||||
} catch (exception: Exception) {
|
} catch (exception: Exception) {
|
||||||
Either.Left(Failure.Unknown(exception))
|
Either.Left(Failure.Unknown(exception))
|
||||||
}
|
}
|
||||||
@ -67,7 +71,7 @@ class PaginationRequest(private val roomAPI: RoomAPI,
|
|||||||
private fun insertInDb(chunkEvent: TokenChunkEvent, roomId: String) {
|
private fun insertInDb(chunkEvent: TokenChunkEvent, roomId: String) {
|
||||||
monarchy.runTransactionSync { realm ->
|
monarchy.runTransactionSync { realm ->
|
||||||
val roomEntity = RoomEntity.where(realm, roomId).findFirst()
|
val roomEntity = RoomEntity.where(realm, roomId).findFirst()
|
||||||
?: return@runTransactionSync
|
?: return@runTransactionSync
|
||||||
|
|
||||||
val nextChunk = ChunkEntity.findWithPrevToken(realm, roomId, chunkEvent.nextToken)
|
val nextChunk = ChunkEntity.findWithPrevToken(realm, roomId, chunkEvent.nextToken)
|
||||||
val prevChunk = ChunkEntity.findWithNextToken(realm, roomId, chunkEvent.prevToken)
|
val prevChunk = ChunkEntity.findWithNextToken(realm, roomId, chunkEvent.prevToken)
|
||||||
@ -75,38 +79,42 @@ class PaginationRequest(private val roomAPI: RoomAPI,
|
|||||||
val mergedEvents = chunkEvent.chunk + chunkEvent.stateEvents
|
val mergedEvents = chunkEvent.chunk + chunkEvent.stateEvents
|
||||||
val mergedEventIds = mergedEvents.filter { it.eventId != null }.map { it.eventId!! }
|
val mergedEventIds = mergedEvents.filter { it.eventId != null }.map { it.eventId!! }
|
||||||
val chunksOverlapped = ChunkEntity.findAllIncludingEvents(realm, mergedEventIds)
|
val chunksOverlapped = ChunkEntity.findAllIncludingEvents(realm, mergedEventIds)
|
||||||
|
val hasOverlapped = chunksOverlapped.isNotEmpty()
|
||||||
|
|
||||||
val currentChunk: ChunkEntity
|
val currentChunk = if (nextChunk != null) {
|
||||||
if (nextChunk != null) {
|
nextChunk
|
||||||
currentChunk = nextChunk
|
|
||||||
} else {
|
} else {
|
||||||
currentChunk = ChunkEntity()
|
ChunkEntity()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
val eventsToAdd = ArrayList<EventEntity>()
|
||||||
|
|
||||||
currentChunk.prevToken = chunkEvent.prevToken
|
currentChunk.prevToken = chunkEvent.prevToken
|
||||||
mergedEvents.forEach { event ->
|
mergedEvents.forEach { event ->
|
||||||
val eventEntity = event.asEntity().let {
|
val eventEntity = event.asEntity().let {
|
||||||
realm.copyToRealmOrUpdate(it)
|
realm.copyToRealmOrUpdate(it)
|
||||||
}
|
}
|
||||||
if (!currentChunk.events.contains(eventEntity)) {
|
if (!currentChunk.events.contains(eventEntity)) {
|
||||||
currentChunk.events.add(eventEntity)
|
eventsToAdd.add(0, eventEntity)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (prevChunk != null) {
|
if (prevChunk != null) {
|
||||||
currentChunk.events.addAll(prevChunk.events)
|
eventsToAdd.addAll(0, prevChunk.events)
|
||||||
roomEntity.chunks.remove(prevChunk)
|
roomEntity.chunks.remove(prevChunk)
|
||||||
|
|
||||||
} else if (chunksOverlapped.isNotEmpty()) {
|
} else if (hasOverlapped) {
|
||||||
chunksOverlapped.forEach { chunk ->
|
chunksOverlapped.forEach { chunk ->
|
||||||
chunk.events.forEach { event ->
|
chunk.events.forEach { event ->
|
||||||
if (!currentChunk.events.contains(event)) {
|
if (!currentChunk.events.contains(event)) {
|
||||||
currentChunk.events.add(event)
|
eventsToAdd.add(0, event)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
roomEntity.chunks.remove(chunk)
|
roomEntity.chunks.remove(chunk)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
currentChunk.events.addAll(0, eventsToAdd)
|
||||||
if (!roomEntity.chunks.contains(currentChunk)) {
|
if (!roomEntity.chunks.contains(currentChunk)) {
|
||||||
roomEntity.chunks.add(currentChunk)
|
roomEntity.chunks.add(currentChunk)
|
||||||
}
|
}
|
||||||
|
@ -7,6 +7,7 @@ import im.vector.matrix.android.api.failure.Failure
|
|||||||
import im.vector.matrix.android.api.session.events.model.Event
|
import im.vector.matrix.android.api.session.events.model.Event
|
||||||
import im.vector.matrix.android.internal.database.model.ChunkEntity
|
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.findAllIncludingEvents
|
||||||
|
import im.vector.matrix.android.internal.session.room.model.PaginationDirection
|
||||||
import im.vector.matrix.android.internal.session.room.model.TokenChunkEvent
|
import im.vector.matrix.android.internal.session.room.model.TokenChunkEvent
|
||||||
import im.vector.matrix.android.internal.util.PagingRequestHelper
|
import im.vector.matrix.android.internal.util.PagingRequestHelper
|
||||||
import java.util.*
|
import java.util.*
|
||||||
@ -25,19 +26,20 @@ class TimelineBoundaryCallback(private val paginationRequest: PaginationRequest,
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun onItemAtEndLoaded(itemAtEnd: Event) {
|
override fun onItemAtEndLoaded(itemAtEnd: Event) {
|
||||||
helper.runIfNotRunning(PagingRequestHelper.RequestType.AFTER) {
|
//Todo handle forward pagination
|
||||||
monarchy.doWithRealm { realm ->
|
|
||||||
if (itemAtEnd.eventId == null) {
|
|
||||||
return@doWithRealm
|
|
||||||
}
|
|
||||||
val chunkEntity = ChunkEntity.findAllIncludingEvents(realm, Collections.singletonList(itemAtEnd.eventId)).firstOrNull()
|
|
||||||
paginationRequest.execute(roomId, chunkEntity?.prevToken, "forward", callback = createCallback(it))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onItemAtFrontLoaded(itemAtFront: Event) {
|
override fun onItemAtFrontLoaded(itemAtFront: Event) {
|
||||||
//Todo handle forward pagination
|
helper.runIfNotRunning(PagingRequestHelper.RequestType.BEFORE) {
|
||||||
|
monarchy.doWithRealm { realm ->
|
||||||
|
if (itemAtFront.eventId == null) {
|
||||||
|
return@doWithRealm
|
||||||
|
}
|
||||||
|
val chunkEntity = ChunkEntity.findAllIncludingEvents(realm, Collections.singletonList(itemAtFront.eventId)).firstOrNull()
|
||||||
|
paginationRequest.execute(roomId, chunkEntity?.prevToken, PaginationDirection.BACKWARDS, callback = createCallback(it))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun createCallback(pagingRequestCallback: PagingRequestHelper.Request.Callback) = object : MatrixCallback<TokenChunkEvent> {
|
private fun createCallback(pagingRequestCallback: PagingRequestHelper.Request.Callback) = object : MatrixCallback<TokenChunkEvent> {
|
||||||
|
Loading…
Reference in New Issue
Block a user