Timeline merge: wait for both timeline to be ready

This commit is contained in:
ganfra 2021-06-14 18:46:15 +02:00
parent 99d05d8db3
commit 01d0d1a5ed
1 changed files with 14 additions and 8 deletions

View File

@ -26,7 +26,12 @@ import org.matrix.android.sdk.api.extensions.tryOrNull
import org.matrix.android.sdk.api.session.room.sender.SenderInfo import org.matrix.android.sdk.api.session.room.sender.SenderInfo
import org.matrix.android.sdk.api.session.room.timeline.Timeline import org.matrix.android.sdk.api.session.room.timeline.Timeline
import org.matrix.android.sdk.api.session.room.timeline.TimelineEvent import org.matrix.android.sdk.api.session.room.timeline.TimelineEvent
import kotlin.reflect.KMutableProperty0
/**
* This can be use to merge timeline tiles from 2 different rooms.
* Be aware it wont work properly with permalink.
*/
class MergedTimelines( class MergedTimelines(
private val coroutineScope: CoroutineScope, private val coroutineScope: CoroutineScope,
private val mainTimeline: Timeline, private val mainTimeline: Timeline,
@ -34,10 +39,13 @@ class MergedTimelines(
data class SecondaryTimelineParams( data class SecondaryTimelineParams(
val timeline: Timeline, val timeline: Timeline,
val disableReadReceipts: Boolean = true,
val shouldFilterTypes: Boolean = false, val shouldFilterTypes: Boolean = false,
val allowedTypes: List<String> = emptyList() val allowedTypes: List<String> = emptyList()
) )
private var mainIsInit = false
private var secondaryIsInit = false
private val secondaryTimeline = secondaryTimelineParams.timeline private val secondaryTimeline = secondaryTimelineParams.timeline
private val listenersMapping = HashMap<Timeline.Listener, List<ListenerInterceptor>>() private val listenersMapping = HashMap<Timeline.Listener, List<ListenerInterceptor>>()
@ -70,10 +78,10 @@ class MergedTimelines(
override fun addListener(listener: Timeline.Listener): Boolean { override fun addListener(listener: Timeline.Listener): Boolean {
val mainTimelineListener = ListenerInterceptor(mainTimeline, listener, false, emptyList()) { val mainTimelineListener = ListenerInterceptor(mainTimeline, listener, false, emptyList()) {
processTimelineUpdates(mainTimelineEvents, it) processTimelineUpdates(::mainIsInit, mainTimelineEvents, it)
} }
val secondaryTimelineListener = ListenerInterceptor(secondaryTimeline, listener, secondaryTimelineParams.shouldFilterTypes, secondaryTimelineParams.allowedTypes) { val secondaryTimelineListener = ListenerInterceptor(secondaryTimeline, listener, secondaryTimelineParams.shouldFilterTypes, secondaryTimelineParams.allowedTypes) {
processTimelineUpdates(secondaryTimelineEvents, it) processTimelineUpdates(::secondaryIsInit, secondaryTimelineEvents, it)
} }
listenersMapping[listener] = listOf(mainTimelineListener, secondaryTimelineListener) listenersMapping[listener] = listOf(mainTimelineListener, secondaryTimelineListener)
return mainTimeline.addListener(mainTimelineListener) && secondaryTimeline.addListener(secondaryTimelineListener) return mainTimeline.addListener(mainTimelineListener) && secondaryTimeline.addListener(secondaryTimelineListener)
@ -139,9 +147,10 @@ class MergedTimelines(
} }
} }
private fun processTimelineUpdates(eventsRef: MutableList<TimelineEvent>, newData: List<TimelineEvent>) { private fun processTimelineUpdates(isInit: KMutableProperty0<Boolean>, eventsRef: MutableList<TimelineEvent>, newData: List<TimelineEvent>) {
coroutineScope.launch(Dispatchers.Default) { coroutineScope.launch(Dispatchers.Default) {
processingSemaphore.withPermit { processingSemaphore.withPermit {
isInit.set(true)
eventsRef.apply { eventsRef.apply {
clear() clear()
addAll(newData) addAll(newData)
@ -157,10 +166,7 @@ class MergedTimelines(
val secondaryItr = secondaryTimelineEvents.toList().listIterator() val secondaryItr = secondaryTimelineEvents.toList().listIterator()
var index = 0 var index = 0
var correctedSenderInfo: SenderInfo? = mainTimelineEvents.firstOrNull()?.senderInfo var correctedSenderInfo: SenderInfo? = mainTimelineEvents.firstOrNull()?.senderInfo
if (mainTimelineEvents.isEmpty() && mainTimeline.hasMoreToLoad(Timeline.Direction.BACKWARDS)) { if (!mainIsInit || !secondaryIsInit) {
return
}
if (secondaryTimelineEvents.isEmpty() && secondaryTimeline.hasMoreToLoad(Timeline.Direction.BACKWARDS)) {
return return
} }
while (merged.size < mainTimelineEvents.size + secondaryTimelineEvents.size) { while (merged.size < mainTimelineEvents.size + secondaryTimelineEvents.size) {
@ -203,7 +209,7 @@ class MergedTimelines(
private fun TimelineEvent.correctBeforeMerging(correctedSenderInfo: SenderInfo?): TimelineEvent { private fun TimelineEvent.correctBeforeMerging(correctedSenderInfo: SenderInfo?): TimelineEvent {
return copy( return copy(
senderInfo = correctedSenderInfo ?: senderInfo, senderInfo = correctedSenderInfo ?: senderInfo,
readReceipts = emptyList() readReceipts = if (secondaryTimelineParams.disableReadReceipts) emptyList() else readReceipts
) )
} }
} }