mirror of
https://github.com/element-hq/element-android
synced 2024-11-27 03:48:12 +03:00
Start introducing a way to open timeline around an event
This commit is contained in:
parent
40fa326771
commit
d250d2bd27
10 changed files with 260 additions and 27 deletions
|
@ -6,21 +6,22 @@ import android.support.v4.app.BundleCompat
|
||||||
import android.support.v4.app.Fragment
|
import android.support.v4.app.Fragment
|
||||||
import kotlin.reflect.KProperty
|
import kotlin.reflect.KProperty
|
||||||
|
|
||||||
class FragmentArgumentDelegate<T : Any> : kotlin.properties.ReadWriteProperty<Fragment, T> {
|
class FragmentArgumentDelegate<T : Any> : kotlin.properties.ReadWriteProperty<Fragment, T?> {
|
||||||
|
|
||||||
var value: T? = null
|
var value: T? = null
|
||||||
|
|
||||||
override operator fun getValue(thisRef: android.support.v4.app.Fragment, property: kotlin.reflect.KProperty<*>): T {
|
override operator fun getValue(thisRef: android.support.v4.app.Fragment, property: kotlin.reflect.KProperty<*>): T? {
|
||||||
if (value == null) {
|
if (value == null) {
|
||||||
val args = thisRef.arguments
|
val args = thisRef.arguments
|
||||||
?: throw IllegalStateException("Cannot read property ${property.name} if no arguments have been set")
|
|
||||||
@Suppress("UNCHECKED_CAST")
|
@Suppress("UNCHECKED_CAST")
|
||||||
value = args.get(property.name) as T
|
value = args?.get(property.name) as T?
|
||||||
}
|
}
|
||||||
return value ?: throw IllegalStateException("Property ${property.name} could not be read")
|
return value
|
||||||
}
|
}
|
||||||
|
|
||||||
override operator fun setValue(thisRef: Fragment, property: KProperty<*>, value: T) {
|
override operator fun setValue(thisRef: Fragment, property: KProperty<*>, value: T?) {
|
||||||
|
if (value == null) return
|
||||||
|
|
||||||
if (thisRef.arguments == null) {
|
if (thisRef.arguments == null) {
|
||||||
thisRef.arguments = Bundle()
|
thisRef.arguments = Bundle()
|
||||||
}
|
}
|
||||||
|
@ -42,7 +43,21 @@ class FragmentArgumentDelegate<T : Any> : kotlin.properties.ReadWriteProperty<Fr
|
||||||
is Binder -> BundleCompat.putBinder(args, key, value)
|
is Binder -> BundleCompat.putBinder(args, key, value)
|
||||||
is android.os.Parcelable -> args.putParcelable(key, value)
|
is android.os.Parcelable -> args.putParcelable(key, value)
|
||||||
is java.io.Serializable -> args.putSerializable(key, value)
|
is java.io.Serializable -> args.putSerializable(key, value)
|
||||||
else -> throw IllegalStateException("Type ${value.javaClass.canonicalName} of property ${property.name} is not supported")
|
else -> throw IllegalStateException("Type ${value.javaClass.name} of property ${property.name} is not supported")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class UnsafeFragmentArgumentDelegate<T : Any> : kotlin.properties.ReadWriteProperty<Fragment, T> {
|
||||||
|
|
||||||
|
private val innerDelegate = FragmentArgumentDelegate<T>()
|
||||||
|
|
||||||
|
override fun setValue(thisRef: Fragment, property: KProperty<*>, value: T) {
|
||||||
|
innerDelegate.setValue(thisRef, property, value)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getValue(thisRef: Fragment, property: KProperty<*>): T {
|
||||||
|
return innerDelegate.getValue(thisRef, property)!!
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -15,6 +15,7 @@ import im.vector.riotredesign.R
|
||||||
import im.vector.riotredesign.core.platform.RiotFragment
|
import im.vector.riotredesign.core.platform.RiotFragment
|
||||||
import im.vector.riotredesign.core.platform.ToolbarConfigurable
|
import im.vector.riotredesign.core.platform.ToolbarConfigurable
|
||||||
import im.vector.riotredesign.core.utils.FragmentArgumentDelegate
|
import im.vector.riotredesign.core.utils.FragmentArgumentDelegate
|
||||||
|
import im.vector.riotredesign.core.utils.UnsafeFragmentArgumentDelegate
|
||||||
import im.vector.riotredesign.features.home.AvatarRenderer
|
import im.vector.riotredesign.features.home.AvatarRenderer
|
||||||
import im.vector.riotredesign.features.home.room.detail.timeline.TimelineEventController
|
import im.vector.riotredesign.features.home.room.detail.timeline.TimelineEventController
|
||||||
import kotlinx.android.synthetic.main.fragment_room_detail.*
|
import kotlinx.android.synthetic.main.fragment_room_detail.*
|
||||||
|
@ -25,16 +26,18 @@ class RoomDetailFragment : RiotFragment() {
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
|
||||||
fun newInstance(roomId: String): RoomDetailFragment {
|
fun newInstance(roomId: String, eventId: String? = null): RoomDetailFragment {
|
||||||
return RoomDetailFragment().apply {
|
return RoomDetailFragment().apply {
|
||||||
this.roomId = roomId
|
this.roomId = roomId
|
||||||
|
this.eventId = eventId
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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: String by UnsafeFragmentArgumentDelegate()
|
||||||
|
private var eventId: String? by FragmentArgumentDelegate()
|
||||||
private val timelineEventController by inject<TimelineEventController>(parameters = { ParameterList(roomId) })
|
private val timelineEventController by inject<TimelineEventController>(parameters = { ParameterList(roomId) })
|
||||||
private lateinit var room: Room
|
private lateinit var room: Room
|
||||||
|
|
||||||
|
@ -48,7 +51,7 @@ class RoomDetailFragment : RiotFragment() {
|
||||||
setupRecyclerView()
|
setupRecyclerView()
|
||||||
setupToolbar()
|
setupToolbar()
|
||||||
room.loadRoomMembersIfNeeded()
|
room.loadRoomMembersIfNeeded()
|
||||||
room.liveTimeline().observe(this, Observer { renderEvents(it) })
|
room.timeline(eventId).observe(this, Observer { renderEvents(it) })
|
||||||
room.roomSummary.observe(this, Observer { renderRoomSummary(it) })
|
room.roomSummary.observe(this, Observer { renderRoomSummary(it) })
|
||||||
sendButton.setOnClickListener {
|
sendButton.setOnClickListener {
|
||||||
val textMessage = composerEditText.text.toString()
|
val textMessage = composerEditText.text.toString()
|
||||||
|
|
|
@ -6,6 +6,6 @@ import im.vector.matrix.android.api.session.events.model.EnrichedEvent
|
||||||
|
|
||||||
interface TimelineHolder {
|
interface TimelineHolder {
|
||||||
|
|
||||||
fun liveTimeline(): LiveData<PagedList<EnrichedEvent>>
|
fun timeline(eventId: String? = null): LiveData<PagedList<EnrichedEvent>>
|
||||||
|
|
||||||
}
|
}
|
|
@ -12,8 +12,10 @@ import im.vector.matrix.android.internal.session.room.timeline.PaginationDirecti
|
||||||
internal fun ChunkEntity.merge(chunkEntity: ChunkEntity,
|
internal fun ChunkEntity.merge(chunkEntity: ChunkEntity,
|
||||||
direction: PaginationDirection) {
|
direction: PaginationDirection) {
|
||||||
|
|
||||||
val events = chunkEntity.events.map { it.asDomain() }
|
|
||||||
addAll(events, direction)
|
chunkEntity.events.forEach {
|
||||||
|
addOrUpdate(it.asDomain(), direction)
|
||||||
|
}
|
||||||
if (direction == PaginationDirection.FORWARDS) {
|
if (direction == PaginationDirection.FORWARDS) {
|
||||||
nextToken = chunkEntity.nextToken
|
nextToken = chunkEntity.nextToken
|
||||||
} else {
|
} else {
|
||||||
|
@ -26,15 +28,13 @@ internal fun ChunkEntity.addAll(events: List<Event>,
|
||||||
updateStateIndex: Boolean = true) {
|
updateStateIndex: Boolean = true) {
|
||||||
|
|
||||||
events.forEach { event ->
|
events.forEach { event ->
|
||||||
if (updateStateIndex && event.isStateEvent()) {
|
addOrUpdate(event, direction, updateStateIndex)
|
||||||
updateStateIndex(direction)
|
|
||||||
}
|
|
||||||
addOrUpdate(event, direction)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal fun ChunkEntity.addOrUpdate(event: Event,
|
internal fun ChunkEntity.addOrUpdate(event: Event,
|
||||||
direction: PaginationDirection) {
|
direction: PaginationDirection,
|
||||||
|
updateStateIndex: Boolean = true) {
|
||||||
if (!isManaged) {
|
if (!isManaged) {
|
||||||
throw IllegalStateException("Chunk entity should be managed to use fast contains")
|
throw IllegalStateException("Chunk entity should be managed to use fast contains")
|
||||||
}
|
}
|
||||||
|
@ -43,6 +43,10 @@ internal fun ChunkEntity.addOrUpdate(event: Event,
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (updateStateIndex && event.isStateEvent()) {
|
||||||
|
updateStateIndex(direction)
|
||||||
|
}
|
||||||
|
|
||||||
val currentStateIndex = stateIndex(direction)
|
val currentStateIndex = stateIndex(direction)
|
||||||
if (!events.fastContains(event.eventId)) {
|
if (!events.fastContains(event.eventId)) {
|
||||||
val eventEntity = event.asEntity()
|
val eventEntity = event.asEntity()
|
||||||
|
|
|
@ -46,8 +46,8 @@ internal data class DefaultRoom(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun liveTimeline(): LiveData<PagedList<EnrichedEvent>> {
|
override fun timeline(eventId: String?): LiveData<PagedList<EnrichedEvent>> {
|
||||||
return timelineHolder.liveTimeline()
|
return timelineHolder.timeline(eventId)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun loadRoomMembersIfNeeded(): Cancelable {
|
override fun loadRoomMembersIfNeeded(): Cancelable {
|
||||||
|
|
|
@ -1,9 +1,11 @@
|
||||||
package im.vector.matrix.android.internal.session.room
|
package im.vector.matrix.android.internal.session.room
|
||||||
|
|
||||||
|
import im.vector.matrix.android.api.session.events.model.Event
|
||||||
import im.vector.matrix.android.api.session.room.model.MessageContent
|
import im.vector.matrix.android.api.session.room.model.MessageContent
|
||||||
import im.vector.matrix.android.internal.network.NetworkConstants
|
import im.vector.matrix.android.internal.network.NetworkConstants
|
||||||
import im.vector.matrix.android.internal.session.room.members.RoomMembersResponse
|
import im.vector.matrix.android.internal.session.room.members.RoomMembersResponse
|
||||||
import im.vector.matrix.android.internal.session.room.send.SendResponse
|
import im.vector.matrix.android.internal.session.room.send.SendResponse
|
||||||
|
import im.vector.matrix.android.internal.session.room.timeline.EventContextResponse
|
||||||
import im.vector.matrix.android.internal.session.room.timeline.TokenChunkEvent
|
import im.vector.matrix.android.internal.session.room.timeline.TokenChunkEvent
|
||||||
import retrofit2.Call
|
import retrofit2.Call
|
||||||
import retrofit2.http.Body
|
import retrofit2.http.Body
|
||||||
|
@ -63,5 +65,28 @@ internal interface RoomAPI {
|
||||||
@Body content: MessageContent
|
@Body content: MessageContent
|
||||||
): Call<SendResponse>
|
): Call<SendResponse>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the context surrounding an event.
|
||||||
|
*
|
||||||
|
* @param roomId the room id
|
||||||
|
* @param eventId the event Id
|
||||||
|
* @param limit the maximum number of messages to retrieve
|
||||||
|
* @param filter A JSON RoomEventFilter to filter returned events with. Optional.
|
||||||
|
*/
|
||||||
|
@GET(NetworkConstants.URI_API_PREFIX_PATH_R0 + "rooms/{roomId}/context/{eventId}")
|
||||||
|
fun getContextOfEvent(@Path("roomId") roomId: String,
|
||||||
|
@Path("eventId") eventId: String,
|
||||||
|
@Query("limit") limit: Int,
|
||||||
|
@Query("filter") filter: String? = null): Call<EventContextResponse>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve an event from its room id / events id
|
||||||
|
*
|
||||||
|
* @param roomId the room id
|
||||||
|
* @param eventId the event Id
|
||||||
|
*/
|
||||||
|
@GET(NetworkConstants.URI_API_PREFIX_PATH_R0 + "rooms/{roomId}/event/{eventId}")
|
||||||
|
fun getEvent(@Path("roomId") roomId: String, @Path("eventId") eventId: String): Call<Event>
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
|
@ -13,6 +13,8 @@ import im.vector.matrix.android.internal.database.model.EventEntity
|
||||||
import im.vector.matrix.android.internal.database.model.EventEntityFields
|
import im.vector.matrix.android.internal.database.model.EventEntityFields
|
||||||
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.events.interceptor.MessageEventInterceptor
|
import im.vector.matrix.android.internal.session.events.interceptor.MessageEventInterceptor
|
||||||
|
import io.realm.Realm
|
||||||
|
import io.realm.RealmQuery
|
||||||
|
|
||||||
private const val PAGE_SIZE = 30
|
private const val PAGE_SIZE = 30
|
||||||
|
|
||||||
|
@ -28,12 +30,12 @@ internal class DefaultTimelineHolder(private val roomId: String,
|
||||||
eventInterceptors.add(MessageEventInterceptor(monarchy, roomId))
|
eventInterceptors.add(MessageEventInterceptor(monarchy, roomId))
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun liveTimeline(): LiveData<PagedList<EnrichedEvent>> {
|
override fun timeline(eventId: String?): LiveData<PagedList<EnrichedEvent>> {
|
||||||
val realmDataSourceFactory = monarchy.createDataSourceFactory { realm ->
|
if (eventId != null) {
|
||||||
EventEntity
|
fetchEventIfNeeded()
|
||||||
.where(realm, roomId = roomId)
|
}
|
||||||
.equalTo("${EventEntityFields.CHUNK}.${ChunkEntityFields.IS_LAST}", true)
|
val realmDataSourceFactory = monarchy.createDataSourceFactory {
|
||||||
.sort(EventEntityFields.DISPLAY_INDEX)
|
buildDataSourceFactoryQuery(it, eventId)
|
||||||
}
|
}
|
||||||
val domainSourceFactory = realmDataSourceFactory
|
val domainSourceFactory = realmDataSourceFactory
|
||||||
.map { it.asDomain() }
|
.map { it.asDomain() }
|
||||||
|
@ -59,4 +61,23 @@ internal class DefaultTimelineHolder(private val roomId: String,
|
||||||
val livePagedListBuilder = LivePagedListBuilder(domainSourceFactory, pagedListConfig).setBoundaryCallback(boundaryCallback)
|
val livePagedListBuilder = LivePagedListBuilder(domainSourceFactory, pagedListConfig).setBoundaryCallback(boundaryCallback)
|
||||||
return monarchy.findAllPagedWithChanges(realmDataSourceFactory, livePagedListBuilder)
|
return monarchy.findAllPagedWithChanges(realmDataSourceFactory, livePagedListBuilder)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun fetchEventIfNeeded() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun buildDataSourceFactoryQuery(realm: Realm, eventId: String?): RealmQuery<EventEntity> {
|
||||||
|
val query = if (eventId == null) {
|
||||||
|
EventEntity
|
||||||
|
.where(realm, roomId = roomId)
|
||||||
|
.equalTo("${EventEntityFields.CHUNK}.${ChunkEntityFields.IS_LAST}", true)
|
||||||
|
} else {
|
||||||
|
EventEntity
|
||||||
|
.where(realm, roomId = roomId)
|
||||||
|
.`in`("${EventEntityFields.CHUNK}.${ChunkEntityFields.EVENTS.EVENT_ID}", arrayOf(eventId))
|
||||||
|
}
|
||||||
|
return query.sort(EventEntityFields.DISPLAY_INDEX)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
|
@ -0,0 +1,22 @@
|
||||||
|
package im.vector.matrix.android.internal.session.room.timeline
|
||||||
|
|
||||||
|
import com.squareup.moshi.Json
|
||||||
|
import com.squareup.moshi.JsonClass
|
||||||
|
import im.vector.matrix.android.api.session.events.model.Event
|
||||||
|
|
||||||
|
@JsonClass(generateAdapter = true)
|
||||||
|
data class EventContextResponse(
|
||||||
|
@Json(name = "event") val event: Event,
|
||||||
|
@Json(name = "start") val prevToken: String? = null,
|
||||||
|
@Json(name = "events_before") val eventsBefore: List<Event> = emptyList(),
|
||||||
|
@Json(name = "events_after") val eventsAfter: List<Event> = emptyList(),
|
||||||
|
@Json(name = "end") val nextToken: String? = null,
|
||||||
|
@Json(name = "state") val stateEvents: List<Event> = emptyList()
|
||||||
|
) {
|
||||||
|
|
||||||
|
val timelineEvents: List<Event> by lazy {
|
||||||
|
eventsBefore + event + eventsAfter
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,102 @@
|
||||||
|
package im.vector.matrix.android.internal.session.room.timeline
|
||||||
|
|
||||||
|
import arrow.core.Try
|
||||||
|
import com.zhuinden.monarchy.Monarchy
|
||||||
|
import im.vector.matrix.android.api.MatrixCallback
|
||||||
|
import im.vector.matrix.android.api.util.Cancelable
|
||||||
|
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.deleteOnCascade
|
||||||
|
import im.vector.matrix.android.internal.database.helper.merge
|
||||||
|
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.find
|
||||||
|
import im.vector.matrix.android.internal.database.query.where
|
||||||
|
import im.vector.matrix.android.internal.legacy.util.FilterUtil
|
||||||
|
import im.vector.matrix.android.internal.network.executeRequest
|
||||||
|
import im.vector.matrix.android.internal.session.room.RoomAPI
|
||||||
|
import im.vector.matrix.android.internal.session.sync.StateEventsChunkHandler
|
||||||
|
import im.vector.matrix.android.internal.util.CancelableCoroutine
|
||||||
|
import im.vector.matrix.android.internal.util.MatrixCoroutineDispatchers
|
||||||
|
import im.vector.matrix.android.internal.util.tryTransactionSync
|
||||||
|
import io.realm.kotlin.createObject
|
||||||
|
import kotlinx.coroutines.GlobalScope
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
import kotlinx.coroutines.withContext
|
||||||
|
|
||||||
|
internal class GetContextOfEventRequest(private val roomAPI: RoomAPI,
|
||||||
|
private val monarchy: Monarchy,
|
||||||
|
private val coroutineDispatchers: MatrixCoroutineDispatchers,
|
||||||
|
private val stateEventsChunkHandler: StateEventsChunkHandler
|
||||||
|
) {
|
||||||
|
|
||||||
|
fun execute(roomId: String,
|
||||||
|
eventId: String,
|
||||||
|
callback: MatrixCallback<EventContextResponse>
|
||||||
|
): Cancelable {
|
||||||
|
val job = GlobalScope.launch(coroutineDispatchers.main) {
|
||||||
|
val filter = FilterUtil.createRoomEventFilter(true)?.toJSONString()
|
||||||
|
val contextOrFailure = execute(roomId, eventId, filter)
|
||||||
|
contextOrFailure.fold({ callback.onFailure(it) }, { callback.onSuccess(it) })
|
||||||
|
}
|
||||||
|
return CancelableCoroutine(job)
|
||||||
|
}
|
||||||
|
|
||||||
|
private suspend fun execute(roomId: String,
|
||||||
|
eventId: String,
|
||||||
|
filter: String?) = withContext(coroutineDispatchers.io) {
|
||||||
|
|
||||||
|
executeRequest<EventContextResponse> {
|
||||||
|
apiCall = roomAPI.getContextOfEvent(roomId, eventId, 1, filter)
|
||||||
|
}.flatMap { response ->
|
||||||
|
insertInDb(response, roomId)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun insertInDb(response: EventContextResponse, roomId: String): Try<EventContextResponse> {
|
||||||
|
return monarchy
|
||||||
|
.tryTransactionSync { realm ->
|
||||||
|
val roomEntity = RoomEntity.where(realm, roomId).findFirst()
|
||||||
|
?: throw IllegalStateException("You shouldn't use this method without a room")
|
||||||
|
|
||||||
|
val currentChunk = realm.createObject<ChunkEntity>().apply {
|
||||||
|
prevToken = response.prevToken
|
||||||
|
nextToken = response.nextToken
|
||||||
|
}
|
||||||
|
|
||||||
|
currentChunk.addOrUpdate(response.event, PaginationDirection.FORWARDS)
|
||||||
|
currentChunk.addAll(response.eventsAfter, PaginationDirection.FORWARDS)
|
||||||
|
currentChunk.addAll(response.eventsBefore, PaginationDirection.BACKWARDS)
|
||||||
|
|
||||||
|
// Now, handles chunk merge
|
||||||
|
val prevChunk = ChunkEntity.find(realm, roomId, nextToken = response.prevToken)
|
||||||
|
val nextChunk = ChunkEntity.find(realm, roomId, prevToken = response.nextToken)
|
||||||
|
|
||||||
|
if (prevChunk != null) {
|
||||||
|
currentChunk.merge(prevChunk, PaginationDirection.BACKWARDS)
|
||||||
|
roomEntity.deleteOnCascade(prevChunk)
|
||||||
|
}
|
||||||
|
if (nextChunk != null) {
|
||||||
|
currentChunk.merge(nextChunk, PaginationDirection.FORWARDS)
|
||||||
|
roomEntity.deleteOnCascade(nextChunk)
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
val eventIds = response.timelineEvents.mapNotNull { it.eventId }
|
||||||
|
ChunkEntity
|
||||||
|
.findAllIncludingEvents(realm, eventIds)
|
||||||
|
.filter { it != currentChunk }
|
||||||
|
.forEach { overlapped ->
|
||||||
|
currentChunk.merge(overlapped, direction)
|
||||||
|
roomEntity.deleteOnCascade(overlapped)
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
roomEntity.addOrUpdate(currentChunk)
|
||||||
|
|
||||||
|
val stateEventsChunk = stateEventsChunkHandler.handle(realm, roomId, response.stateEvents)
|
||||||
|
roomEntity.addOrUpdate(stateEventsChunk)
|
||||||
|
}
|
||||||
|
.map { response }
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,41 @@
|
||||||
|
package im.vector.matrix.android.internal.session.room.timeline
|
||||||
|
|
||||||
|
import com.zhuinden.monarchy.Monarchy
|
||||||
|
import im.vector.matrix.android.api.MatrixCallback
|
||||||
|
import im.vector.matrix.android.api.session.events.model.Event
|
||||||
|
import im.vector.matrix.android.api.util.Cancelable
|
||||||
|
import im.vector.matrix.android.internal.network.executeRequest
|
||||||
|
import im.vector.matrix.android.internal.session.room.RoomAPI
|
||||||
|
import im.vector.matrix.android.internal.session.sync.StateEventsChunkHandler
|
||||||
|
import im.vector.matrix.android.internal.util.CancelableCoroutine
|
||||||
|
import im.vector.matrix.android.internal.util.MatrixCoroutineDispatchers
|
||||||
|
import kotlinx.coroutines.GlobalScope
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
import kotlinx.coroutines.withContext
|
||||||
|
|
||||||
|
internal class GetEventRequest(private val roomAPI: RoomAPI,
|
||||||
|
private val monarchy: Monarchy,
|
||||||
|
private val coroutineDispatchers: MatrixCoroutineDispatchers,
|
||||||
|
private val stateEventsChunkHandler: StateEventsChunkHandler
|
||||||
|
) {
|
||||||
|
|
||||||
|
fun execute(roomId: String,
|
||||||
|
eventId: String,
|
||||||
|
callback: MatrixCallback<Event>
|
||||||
|
): Cancelable {
|
||||||
|
val job = GlobalScope.launch(coroutineDispatchers.main) {
|
||||||
|
val eventOrFailure = execute(roomId, eventId)
|
||||||
|
eventOrFailure.fold({ callback.onFailure(it) }, { callback.onSuccess(it) })
|
||||||
|
}
|
||||||
|
return CancelableCoroutine(job)
|
||||||
|
}
|
||||||
|
|
||||||
|
private suspend fun execute(roomId: String,
|
||||||
|
eventId: String) = withContext(coroutineDispatchers.io) {
|
||||||
|
|
||||||
|
executeRequest<Event> {
|
||||||
|
apiCall = roomAPI.getEvent(roomId, eventId)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in a new issue