From b7dd7ef3e0c988c23b9829b5d5714cdbaea89051 Mon Sep 17 00:00:00 2001
From: ganfra <francoisg@element.io>
Date: Fri, 11 Jun 2021 19:27:07 +0200
Subject: [PATCH] Timeline merging: branch virtual room (still some issues to
 deal with)

---
 .../features/call/lookup/CallUserMapper.kt    |  2 ++
 .../home/room/detail/RoomDetailFragment.kt    |  3 +--
 .../timeline/factory/CallItemFactory.kt       |  6 ++++-
 .../timeline/factory/TimelineFactory.kt       | 14 +++++------
 .../detail/timeline/merged/MergedTimelines.kt | 23 +++++++++++++++----
 5 files changed, 34 insertions(+), 14 deletions(-)

diff --git a/vector/src/main/java/im/vector/app/features/call/lookup/CallUserMapper.kt b/vector/src/main/java/im/vector/app/features/call/lookup/CallUserMapper.kt
index e55d70d79c..161b6d59c8 100644
--- a/vector/src/main/java/im/vector/app/features/call/lookup/CallUserMapper.kt
+++ b/vector/src/main/java/im/vector/app/features/call/lookup/CallUserMapper.kt
@@ -27,12 +27,14 @@ import org.matrix.android.sdk.api.session.room.model.create.CreateRoomParams
 class CallUserMapper(private val session: Session, private val protocolsChecker: CallProtocolsChecker) {
 
     fun nativeRoomForVirtualRoom(roomId: String): String? {
+        if(!protocolsChecker.supportVirtualRooms) return null
         val virtualRoom = session.getRoom(roomId) ?: return null
         val virtualRoomEvent = virtualRoom.getAccountDataEvent(RoomAccountDataTypes.EVENT_TYPE_VIRTUAL_ROOM)
         return virtualRoomEvent?.content?.toModel<RoomVirtualContent>()?.nativeRoomId
     }
 
     fun virtualRoomForNativeRoom(roomId: String): String? {
+        if(!protocolsChecker.supportVirtualRooms) return null
         val virtualRoomEvents = session.accountDataService().getRoomAccountDataEvents(setOf(RoomAccountDataTypes.EVENT_TYPE_VIRTUAL_ROOM))
         return virtualRoomEvents.firstOrNull {
             val virtualRoomContent = it.content.toModel<RoomVirtualContent>()
diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailFragment.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailFragment.kt
index 8307e93576..024ce9e6d5 100644
--- a/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailFragment.kt
+++ b/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailFragment.kt
@@ -1614,8 +1614,7 @@ class RoomDetailFragment @Inject constructor(
 
     override fun onEventLongClicked(informationData: MessageInformationData, messageContent: Any?, view: View): Boolean {
         view.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS)
-        val roomId = roomDetailArgs.roomId
-
+        val roomId = roomDetailViewModel.timeline.getTimelineEventWithId(informationData.eventId)?.roomId ?: return false
         this.view?.hideKeyboard()
 
         MessageActionsBottomSheet
diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/factory/CallItemFactory.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/factory/CallItemFactory.kt
index 9dcc3e8182..bb6b61e8e9 100644
--- a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/factory/CallItemFactory.kt
+++ b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/factory/CallItemFactory.kt
@@ -16,6 +16,7 @@
 package im.vector.app.features.home.room.detail.timeline.factory
 
 import im.vector.app.core.epoxy.VectorEpoxyModel
+import im.vector.app.features.call.vectorCallService
 import im.vector.app.features.call.webrtc.WebRtcCallManager
 import im.vector.app.features.home.room.detail.timeline.MessageColorProvider
 import im.vector.app.features.home.room.detail.timeline.TimelineEventController
@@ -26,6 +27,7 @@ import im.vector.app.features.home.room.detail.timeline.helper.RoomSummariesHold
 import im.vector.app.features.home.room.detail.timeline.item.CallTileTimelineItem
 import im.vector.app.features.home.room.detail.timeline.item.CallTileTimelineItem_
 import im.vector.app.features.home.room.detail.timeline.item.MessageInformationData
+import org.matrix.android.sdk.api.session.Session
 import org.matrix.android.sdk.api.session.events.model.EventType
 import org.matrix.android.sdk.api.session.events.model.toModel
 import org.matrix.android.sdk.api.session.room.model.call.CallAnswerContent
@@ -38,6 +40,7 @@ import org.matrix.android.sdk.api.util.toMatrixItem
 import javax.inject.Inject
 
 class CallItemFactory @Inject constructor(
+        private val session: Session,
         private val messageColorProvider: MessageColorProvider,
         private val messageInformationDataFactory: MessageInformationDataFactory,
         private val messageItemAttributesFactory: MessageItemAttributesFactory,
@@ -132,7 +135,8 @@ class CallItemFactory @Inject constructor(
             isStillActive: Boolean,
             callback: TimelineEventController.Callback?
     ): CallTileTimelineItem? {
-        val userOfInterest = roomSummariesHolder.get(roomId)?.toMatrixItem() ?: return null
+        val correctedRoomId = session.vectorCallService.userMapper.nativeRoomForVirtualRoom(roomId) ?:roomId
+        val userOfInterest = roomSummariesHolder.get(correctedRoomId)?.toMatrixItem() ?: return null
         val attributes = messageItemAttributesFactory.create(null, informationData, callback).let {
             CallTileTimelineItem.Attributes(
                     callId = callId,
diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/factory/TimelineFactory.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/factory/TimelineFactory.kt
index c10fd5065a..b57e39b3cf 100644
--- a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/factory/TimelineFactory.kt
+++ b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/factory/TimelineFactory.kt
@@ -35,21 +35,21 @@ private val secondaryTimelineAllowedTypes = listOf(
 
 class TimelineFactory @Inject constructor(private val session: Session, private val timelineSettingsFactory: TimelineSettingsFactory) {
 
-    fun createTimeline(coroutineScope: CoroutineScope, room: Room, eventId: String?): Timeline {
+    fun createTimeline(coroutineScope: CoroutineScope, mainRoom: Room, eventId: String?): Timeline {
         val settings = timelineSettingsFactory.create()
         if (!session.vectorCallService.protocolChecker.supportVirtualRooms) {
-            return room.createTimeline(eventId, settings)
+            return mainRoom.createTimeline(eventId, settings)
         }
-        val virtualRoomId = session.vectorCallService.userMapper.virtualRoomForNativeRoom(room.roomId)
+        val virtualRoomId = session.vectorCallService.userMapper.virtualRoomForNativeRoom(mainRoom.roomId)
         return if (virtualRoomId == null) {
-            room.createTimeline(eventId, settings)
+            mainRoom.createTimeline(eventId, settings)
         } else {
             val virtualRoom = session.getRoom(virtualRoomId)!!
             MergedTimelines(
-                    coroutineScope,
-                    room.createTimeline(eventId, settings),
+                    coroutineScope = coroutineScope,
+                    mainTimeline = mainRoom.createTimeline(eventId, settings),
                     secondaryTimelineParams = MergedTimelines.SecondaryTimelineParams(
-                            virtualRoom.createTimeline(null, settings),
+                            timeline = virtualRoom.createTimeline(null, settings),
                             shouldFilterTypes = true,
                             allowedTypes = secondaryTimelineAllowedTypes
                     )
diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/merged/MergedTimelines.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/merged/MergedTimelines.kt
index 5bc5ea0803..6058f2e34b 100644
--- a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/merged/MergedTimelines.kt
+++ b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/merged/MergedTimelines.kt
@@ -23,6 +23,7 @@ import kotlinx.coroutines.sync.Semaphore
 import kotlinx.coroutines.sync.withPermit
 import kotlinx.coroutines.withContext
 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.timeline.Timeline
 import org.matrix.android.sdk.api.session.room.timeline.TimelineEvent
 
@@ -155,15 +156,22 @@ class MergedTimelines(
         val mainItr = mainTimelineEvents.toList().listIterator()
         val secondaryItr = secondaryTimelineEvents.toList().listIterator()
         var index = 0
-
+        var correctedSenderInfo: SenderInfo? = mainTimelineEvents.firstOrNull()?.senderInfo
+        if (mainTimelineEvents.isEmpty() && mainTimeline.hasMoreToLoad(Timeline.Direction.BACKWARDS)) {
+            return
+        }
+        if (secondaryTimelineEvents.isEmpty() && secondaryTimeline.hasMoreToLoad(Timeline.Direction.BACKWARDS)) {
+            return
+        }
         while (merged.size < mainTimelineEvents.size + secondaryTimelineEvents.size) {
             if (mainItr.hasNext()) {
                 val nextMain = mainItr.next()
+                correctedSenderInfo = nextMain.senderInfo
                 if (secondaryItr.hasNext()) {
                     val nextSecondary = secondaryItr.next()
                     if (nextSecondary.root.originServerTs ?: 0 > nextMain.root.originServerTs ?: 0) {
                         positionsMapping[nextSecondary.eventId] = index
-                        merged.add(nextSecondary)
+                        merged.add(nextSecondary.correctBeforeMerging(correctedSenderInfo))
                         mainItr.previous()
                     } else {
                         positionsMapping[nextMain.eventId] = index
@@ -177,13 +185,13 @@ class MergedTimelines(
             } else if (secondaryItr.hasNext()) {
                 val nextSecondary = secondaryItr.next()
                 positionsMapping[nextSecondary.eventId] = index
-                merged.add(nextSecondary)
+                merged.add(nextSecondary.correctBeforeMerging(correctedSenderInfo))
             }
             index++
         }
         mergedEvents.apply {
             clear()
-            addAll(mergedEvents)
+            addAll(merged)
         }
         withContext(Dispatchers.Main) {
             listenersMapping.keys.forEach { listener ->
@@ -191,4 +199,11 @@ class MergedTimelines(
             }
         }
     }
+
+    private fun TimelineEvent.correctBeforeMerging(correctedSenderInfo: SenderInfo?): TimelineEvent {
+        return copy(
+                senderInfo = correctedSenderInfo ?: senderInfo,
+                readReceipts = emptyList()
+        )
+    }
 }