From a07305314f4258feec3ee1eb2c889257679ee8b9 Mon Sep 17 00:00:00 2001 From: ganfra Date: Thu, 13 Jul 2023 17:21:56 +0200 Subject: [PATCH] Timeline: make group id really stable --- .../timeline/groups/TimelineItemGrouper.kt | 39 ++++++++++++++++--- .../impl/timeline/model/TimelineItem.kt | 7 ++-- 2 files changed, 36 insertions(+), 10 deletions(-) diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/groups/TimelineItemGrouper.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/groups/TimelineItemGrouper.kt index b04509ba22..bee2b055f3 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/groups/TimelineItemGrouper.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/groups/TimelineItemGrouper.kt @@ -17,10 +17,20 @@ package io.element.android.features.messages.impl.timeline.groups import io.element.android.features.messages.impl.timeline.model.TimelineItem +import io.element.android.libraries.di.RoomScope +import io.element.android.libraries.di.SingleIn import kotlinx.collections.immutable.toImmutableList import javax.inject.Inject +@SingleIn(RoomScope::class) class TimelineItemGrouper @Inject constructor() { + + /** + * Keys are identifier of items in a group, only one by group will be kept. + * Values are the actual groupIds. + */ + private val groupIds = HashMap() + /** * Create a new list of [TimelineItem] by grouping some of them into [TimelineItem.GroupedEvents]. */ @@ -34,14 +44,14 @@ class TimelineItemGrouper @Inject constructor() { // timelineItem cannot be grouped if (currentGroup.isNotEmpty()) { // There is a pending group, create a TimelineItem.GroupedEvents if there is more than 1 Event in the pending group. - result.addGroup(currentGroup) + result.addGroup(groupIds, currentGroup) currentGroup.clear() } result.add(timelineItem) } } if (currentGroup.isNotEmpty()) { - result.addGroup(currentGroup) + result.addGroup(groupIds, currentGroup) } return result } @@ -51,16 +61,33 @@ class TimelineItemGrouper @Inject constructor() { * Will add a group if there is more than 1 item, else add the item to the list. */ private fun MutableList.addGroup( - group: MutableList + groupIds: MutableMap, + groupOfItems: MutableList ) { - if (group.size == 1) { + if (groupOfItems.size == 1) { // Do not create a group with just 1 item, just add the item to the result - add(group.first()) + add(groupOfItems.first()) } else { + val groupId = groupIds.getOrPutGroupId(groupOfItems) add( TimelineItem.GroupedEvents( - events = group.toImmutableList() + id = groupId, + events = groupOfItems.toImmutableList() ) ) } } + +private fun MutableMap.getOrPutGroupId(timelineItems: List): String { + assert(timelineItems.isNotEmpty()) + for (item in timelineItems) { + val itemIdentifier = item.identifier() + if (this.contains(itemIdentifier)) { + return this[itemIdentifier]!! + } + } + val itemIdentifier = timelineItems.first().identifier() + return "${itemIdentifier}_group".also { groupId -> + this[itemIdentifier] = groupId + } +} 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 7f95b30409..b415d128a2 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 @@ -82,9 +82,8 @@ sealed interface TimelineItem { @Immutable data class GroupedEvents( + val id: String, 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" - } + ) : TimelineItem + }