From d3ca5d0db07f452496cd9fe04bf27490fe8b7372 Mon Sep 17 00:00:00 2001 From: SpiritCroc Date: Thu, 20 May 2021 13:22:37 +0200 Subject: [PATCH] Invalidate the timeline when the DM state changes for a room We need to redraw messages when this changes, since we use different layouts for DMs and non-direct chats. Change-Id: Icf2df3a14655f7c9b6e5f7cdb29b590f393de4fd --- .../sdk/api/session/room/timeline/Timeline.kt | 10 ++++++++ .../session/room/timeline/DefaultTimeline.kt | 6 +++++ .../home/room/detail/RoomDetailViewModel.kt | 8 ++++++ .../timeline/TimelineEventController.kt | 13 ++++++++++ ...InvalidateTimelineEventDiffUtilCallback.kt | 25 +++++++++++++++++++ 5 files changed, 62 insertions(+) create mode 100644 vector/src/main/java/im/vector/app/features/home/room/detail/timeline/helper/InvalidateTimelineEventDiffUtilCallback.kt diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/timeline/Timeline.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/timeline/Timeline.kt index 06c88db831..11efaafd2c 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/timeline/Timeline.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/timeline/Timeline.kt @@ -95,6 +95,11 @@ interface Timeline { */ fun getTimelineEventWithId(eventId: String?): TimelineEvent? + /** + * Called when the DM flag of the room is changed + */ + fun onDmStateChanged() + interface Listener { /** * Call when the timeline has been updated through pagination or sync. @@ -112,6 +117,11 @@ interface Timeline { * Called when new events come through the sync */ fun onNewTimelineEvents(eventIds: List) + + /** + * Called when the DM flag of the room is changed + */ + fun onDmStateChanged() } /** diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/DefaultTimeline.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/DefaultTimeline.kt index e230599f8f..c9c2f58718 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/DefaultTimeline.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/timeline/DefaultTimeline.kt @@ -285,6 +285,12 @@ internal class DefaultTimeline( } } + override fun onDmStateChanged() { + listeners.forEach { + it.onDmStateChanged() + } + } + override fun rebuildEvent(eventId: String, builder: (TimelineEvent) -> TimelineEvent?): Boolean { return tryOrNull { builtEventsIdMap[eventId]?.let { builtIndex -> diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailViewModel.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailViewModel.kt index aeb8d010d7..c816a27762 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailViewModel.kt @@ -1498,6 +1498,7 @@ class RoomDetailViewModel @AssistedInject constructor( private fun observeSummaryState() { asyncSubscribe(RoomDetailViewState::asyncRoomSummary) { summary -> + val previousSummary = roomSummariesHolder.get(summary.roomId) roomSummariesHolder.set(summary) setState { val typingMessage = typingHelper.getTypingMessage(summary.typingUsers) @@ -1516,6 +1517,9 @@ class RoomDetailViewModel @AssistedInject constructor( room.getStateEvent(EventType.STATE_ROOM_TOMBSTONE)?.also { setState { copy(tombstoneEvent = it) } } + if (previousSummary == null || previousSummary.isDirect != summary.isDirect) { + timeline.onDmStateChanged() + } } } @@ -1567,4 +1571,8 @@ class RoomDetailViewModel @AssistedInject constructor( callManager.removePstnSupportListener(this) super.onCleared() } + + override fun onDmStateChanged() { + // No-op + } } diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/TimelineEventController.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/TimelineEventController.kt index b67527c24c..29d5976686 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/TimelineEventController.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/TimelineEventController.kt @@ -46,6 +46,7 @@ import im.vector.app.features.home.room.detail.timeline.helper.TimelineEventDiff import im.vector.app.features.home.room.detail.timeline.helper.TimelineEventVisibilityHelper import im.vector.app.features.home.room.detail.timeline.helper.TimelineEventVisibilityStateChangedListener import im.vector.app.features.home.room.detail.timeline.factory.TimelineItemFactoryParams +import im.vector.app.features.home.room.detail.timeline.helper.InvalidateTimelineEventDiffUtilCallback import im.vector.app.features.home.room.detail.timeline.helper.TimelineMediaSizeProvider import im.vector.app.features.home.room.detail.timeline.item.AbsMessageItem import im.vector.app.features.home.room.detail.timeline.item.BasedMergedItem @@ -292,6 +293,18 @@ class TimelineEventController @Inject constructor(private val dateFormatter: Vec // no-op, already handled } + override fun onDmStateChanged() { + backgroundHandler.post { + inSubmitList = true + // Invalidate all timeline events to rebuild the whole Room/DM layout + val diffCallback = InvalidateTimelineEventDiffUtilCallback(currentSnapshot) + val diffResult = DiffUtil.calculateDiff(diffCallback) + diffResult.dispatchUpdatesTo(listUpdateCallback) + requestModelBuild() + inSubmitList = false + } + } + private fun submitSnapshot(newSnapshot: List) { backgroundHandler.post { inSubmitList = true diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/helper/InvalidateTimelineEventDiffUtilCallback.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/helper/InvalidateTimelineEventDiffUtilCallback.kt new file mode 100644 index 0000000000..85430afb00 --- /dev/null +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/helper/InvalidateTimelineEventDiffUtilCallback.kt @@ -0,0 +1,25 @@ +package im.vector.app.features.home.room.detail.timeline.helper + +import androidx.recyclerview.widget.DiffUtil +import org.matrix.android.sdk.api.session.room.timeline.TimelineEvent + +class InvalidateTimelineEventDiffUtilCallback(private val oldAndNewList: List): DiffUtil.Callback() { + + override fun getOldListSize(): Int { + return oldAndNewList.size + } + + override fun getNewListSize(): Int { + return oldAndNewList.size + } + + override fun areItemsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean { + // We want to 'fake' updated items with this class - updated means in this case, not completely invalidated. + return oldItemPosition == newItemPosition + } + + override fun areContentsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean { + // We want to 'fake' updated items with this class. + return false + } +}