diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/TimelineStateProvider.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/TimelineStateProvider.kt index e96d7ac0f3..d8f823e0c8 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/TimelineStateProvider.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/TimelineStateProvider.kt @@ -36,6 +36,7 @@ import kotlinx.collections.immutable.ImmutableList import kotlinx.collections.immutable.persistentListOf import kotlinx.collections.immutable.toImmutableList import kotlinx.collections.immutable.toPersistentList +import java.util.UUID import kotlin.random.Random fun aTimelineState(timelineItems: ImmutableList = persistentListOf()) = TimelineState( @@ -96,7 +97,7 @@ internal fun aTimelineItemList(content: TimelineItemEventContent): ImmutableList } fun aTimelineItemDaySeparator(): TimelineItem.Virtual { - return TimelineItem.Virtual("virtual_day", aTimelineItemDaySeparatorModel("Today")) + return TimelineItem.Virtual(UUID.randomUUID().mostSignificantBits, aTimelineItemDaySeparatorModel("Today")) } internal fun aTimelineItemEvent( @@ -111,7 +112,7 @@ internal fun aTimelineItemEvent( timelineItemReactions: TimelineItemReactions = aTimelineItemReactions(), ): TimelineItem.Event { return TimelineItem.Event( - id = eventId.value, + id = UUID.randomUUID().mostSignificantBits, eventId = eventId, transactionId = transactionId, senderId = UserId("@senderId:domain"), diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/factories/TimelineItemsFactory.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/factories/TimelineItemsFactory.kt index 87a91f7ec2..f607a0e034 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/factories/TimelineItemsFactory.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/factories/TimelineItemsFactory.kt @@ -106,7 +106,7 @@ class TimelineItemsFactory @Inject constructor( val timelineItemState = when (val currentTimelineItem = timelineItems[index]) { is MatrixTimelineItem.Event -> eventItemFactory.create(currentTimelineItem, index, timelineItems) - is MatrixTimelineItem.Virtual -> virtualItemFactory.create(currentTimelineItem, index) + is MatrixTimelineItem.Virtual -> virtualItemFactory.create(currentTimelineItem) MatrixTimelineItem.Other -> null } timelineItemsCache[index] = timelineItemState diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/factories/virtual/TimelineItemVirtualFactory.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/factories/virtual/TimelineItemVirtualFactory.kt index 8aae552880..8d705b6bdb 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/factories/virtual/TimelineItemVirtualFactory.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/factories/virtual/TimelineItemVirtualFactory.kt @@ -29,10 +29,9 @@ class TimelineItemVirtualFactory @Inject constructor( fun create( virtualTimelineItem: MatrixTimelineItem.Virtual, - index: Int, ): TimelineItem.Virtual { return TimelineItem.Virtual( - id = "virtual_item_$index", + id = virtualTimelineItem.uniqueId, model = virtualTimelineItem.computeModel() ) } diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/model/TimelineItem.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/model/TimelineItem.kt index 6743651e76..b9bed4f5c9 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/model/TimelineItem.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/model/TimelineItem.kt @@ -24,16 +24,16 @@ import io.element.android.libraries.designsystem.components.avatar.AvatarData import io.element.android.libraries.matrix.api.core.EventId import io.element.android.libraries.matrix.api.core.UserId import io.element.android.libraries.matrix.api.timeline.item.TimelineItemDebugInfo -import io.element.android.libraries.matrix.api.timeline.item.event.LocalEventSendState import io.element.android.libraries.matrix.api.timeline.item.event.InReplyTo +import io.element.android.libraries.matrix.api.timeline.item.event.LocalEventSendState import kotlinx.collections.immutable.ImmutableList @Immutable sealed interface TimelineItem { fun identifier(): String = when (this) { - is Event -> id - is Virtual -> id + is Event -> id.toString() + is Virtual -> id.toString() is GroupedEvents -> id } @@ -45,13 +45,13 @@ sealed interface TimelineItem { @Immutable data class Virtual( - val id: String, + val id: Long, val model: TimelineItemVirtualModel ) : TimelineItem @Immutable data class Event( - val id: String, + val id: Long, val eventId: EventId? = null, val transactionId: String? = null, val senderId: UserId, @@ -83,6 +83,6 @@ sealed interface TimelineItem { val events: ImmutableList, ) : TimelineItem { // use last id with a suffix. Last will not change in cas of new event from backpagination. - val id = events.last().id + "_group" + val id = "${events.last().id}_group" } } diff --git a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/timeline/MatrixTimelineItem.kt b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/timeline/MatrixTimelineItem.kt index f84f1875e4..e64d803aba 100644 --- a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/timeline/MatrixTimelineItem.kt +++ b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/timeline/MatrixTimelineItem.kt @@ -21,13 +21,12 @@ import io.element.android.libraries.matrix.api.timeline.item.event.EventTimeline import io.element.android.libraries.matrix.api.timeline.item.virtual.VirtualTimelineItem sealed interface MatrixTimelineItem { - data class Event(val event: EventTimelineItem) : MatrixTimelineItem { - val uniqueId: String = event.uniqueIdentifier + data class Event(val uniqueId: Long, val event: EventTimelineItem) : MatrixTimelineItem { val eventId: EventId? = event.eventId val transactionId: String? = event.transactionId } - data class Virtual(val virtual: VirtualTimelineItem) : MatrixTimelineItem + data class Virtual(val uniqueId: Long, val virtual: VirtualTimelineItem) : MatrixTimelineItem object Other : MatrixTimelineItem } diff --git a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/timeline/item/event/EventTimelineItem.kt b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/timeline/item/event/EventTimelineItem.kt index e2a86fbb3c..854d38b7dd 100644 --- a/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/timeline/item/event/EventTimelineItem.kt +++ b/libraries/matrix/api/src/main/kotlin/io/element/android/libraries/matrix/api/timeline/item/event/EventTimelineItem.kt @@ -21,7 +21,6 @@ import io.element.android.libraries.matrix.api.core.UserId import io.element.android.libraries.matrix.api.timeline.item.TimelineItemDebugInfo data class EventTimelineItem( - val uniqueIdentifier: String, val eventId: EventId?, val transactionId: String?, val isEditable: Boolean, diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/room/RoomSummaryDetailsFactory.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/room/RoomSummaryDetailsFactory.kt index 43d96f8e8a..7dd7bf4581 100644 --- a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/room/RoomSummaryDetailsFactory.kt +++ b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/room/RoomSummaryDetailsFactory.kt @@ -24,7 +24,7 @@ import org.matrix.rustcomponents.sdk.RoomListItem class RoomSummaryDetailsFactory(private val roomMessageFactory: RoomMessageFactory = RoomMessageFactory()) { - fun create(roomListItem: RoomListItem, room: Room?): RoomSummaryDetails { + suspend fun create(roomListItem: RoomListItem, room: Room?): RoomSummaryDetails { val latestRoomMessage = roomListItem.latestEvent()?.use { roomMessageFactory.create(it) } diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/room/RoomSummaryListProcessor.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/room/RoomSummaryListProcessor.kt index f489bbc5e0..a8ab4cb807 100644 --- a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/room/RoomSummaryListProcessor.kt +++ b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/room/RoomSummaryListProcessor.kt @@ -16,6 +16,7 @@ package io.element.android.libraries.matrix.impl.room +import io.element.android.libraries.core.coroutine.parallelMap import io.element.android.libraries.matrix.api.room.RoomSummary import kotlinx.coroutines.CompletableDeferred import kotlinx.coroutines.flow.MutableStateFlow @@ -43,7 +44,8 @@ class RoomSummaryListProcessor( suspend fun postEntries(entries: List) { updateRoomSummaries { Timber.v("Update rooms from postEntries (with ${entries.size} items) on ${Thread.currentThread()}") - addAll(entries.map(::buildSummaryForRoomListEntry)) + val roomSummaries = entries.parallelMap(::buildSummaryForRoomListEntry) + addAll(roomSummaries) } initLatch.complete(Unit) } @@ -57,7 +59,7 @@ class RoomSummaryListProcessor( } } - private fun MutableList.applyUpdate(update: RoomListEntriesUpdate) { + private suspend fun MutableList.applyUpdate(update: RoomListEntriesUpdate) { when (update) { is RoomListEntriesUpdate.Append -> { val roomSummaries = update.values.map { @@ -100,7 +102,7 @@ class RoomSummaryListProcessor( } } - private fun buildSummaryForRoomListEntry(entry: RoomListEntry): RoomSummary { + private suspend fun buildSummaryForRoomListEntry(entry: RoomListEntry): RoomSummary { return when (entry) { RoomListEntry.Empty -> buildEmptyRoomSummary() is RoomListEntry.Filled -> buildAndCacheRoomSummaryForIdentifier(entry.roomId) @@ -114,7 +116,7 @@ class RoomSummaryListProcessor( return RoomSummary.Empty(UUID.randomUUID().toString()) } - private fun buildAndCacheRoomSummaryForIdentifier(identifier: String): RoomSummary { + private suspend fun buildAndCacheRoomSummaryForIdentifier(identifier: String): RoomSummary { val builtRoomSummary = roomListService.roomOrNull(identifier)?.use { roomListItem -> roomListItem.fullRoomOrNull().use { fullRoom -> RoomSummary.Filled( @@ -134,7 +136,7 @@ class RoomSummaryListProcessor( } } - private suspend fun updateRoomSummaries(block: MutableList.() -> Unit) = + private suspend fun updateRoomSummaries(block: suspend MutableList.() -> Unit) = mutex.withLock { val mutableRoomSummaries = roomSummaries.value.toMutableList() block(mutableRoomSummaries) diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/timeline/MatrixTimelineItemMapper.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/timeline/MatrixTimelineItemMapper.kt index f448873ab7..2e86aa0706 100644 --- a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/timeline/MatrixTimelineItemMapper.kt +++ b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/timeline/MatrixTimelineItemMapper.kt @@ -32,21 +32,20 @@ class MatrixTimelineItemMapper( ) { fun map(timelineItem: TimelineItem): MatrixTimelineItem = timelineItem.use { + val uniqueId = timelineItem.uniqueId().toLong() val asEvent = it.asEvent() if (asEvent != null) { val eventTimelineItem = eventTimelineItemMapper.map(asEvent) - - if (eventTimelineItem.hasNotLoadedInReplyTo() && eventTimelineItem.eventId != null) { fetchEventDetails(eventTimelineItem.eventId!!) } - return MatrixTimelineItem.Event(eventTimelineItem) + return MatrixTimelineItem.Event(uniqueId, eventTimelineItem) } val asVirtual = it.asVirtual() if (asVirtual != null) { val virtualTimelineItem = virtualTimelineItemMapper.map(asVirtual) - return MatrixTimelineItem.Virtual(virtualTimelineItem) + return MatrixTimelineItem.Virtual(uniqueId, virtualTimelineItem) } return MatrixTimelineItem.Other } diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/timeline/item/event/EventTimelineItemMapper.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/timeline/item/event/EventTimelineItemMapper.kt index d250072267..b4887faf68 100644 --- a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/timeline/item/event/EventTimelineItemMapper.kt +++ b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/timeline/item/event/EventTimelineItemMapper.kt @@ -20,8 +20,8 @@ import io.element.android.libraries.matrix.api.core.EventId import io.element.android.libraries.matrix.api.core.UserId import io.element.android.libraries.matrix.api.timeline.item.TimelineItemDebugInfo import io.element.android.libraries.matrix.api.timeline.item.event.EventReaction -import io.element.android.libraries.matrix.api.timeline.item.event.LocalEventSendState import io.element.android.libraries.matrix.api.timeline.item.event.EventTimelineItem +import io.element.android.libraries.matrix.api.timeline.item.event.LocalEventSendState import io.element.android.libraries.matrix.api.timeline.item.event.ProfileTimelineDetails import org.matrix.rustcomponents.sdk.Reaction import org.matrix.rustcomponents.sdk.EventSendState as RustEventSendState @@ -33,7 +33,6 @@ class EventTimelineItemMapper(private val contentMapper: TimelineEventContentMap fun map(eventTimelineItem: RustEventTimelineItem): EventTimelineItem = eventTimelineItem.use { EventTimelineItem( - uniqueIdentifier = it.uniqueIdentifier(), eventId = it.eventId()?.let(::EventId), transactionId = it.transactionId(), isEditable = it.isEditable(), @@ -79,7 +78,7 @@ private fun List?.map(): List { EventReaction( key = it.key, count = it.count.toLong(), - senderIds = it.senders.map { sender -> UserId(sender) } + senderIds = it.senders.map { sender -> UserId(sender.senderId) } ) } ?: emptyList() }