From 10259e9345a73b482cb42786ca35cd1dbbdb50e1 Mon Sep 17 00:00:00 2001 From: Stefan Ceriu Date: Tue, 8 Aug 2023 09:41:10 +0300 Subject: [PATCH] Fixes #1455 - Use the stable timeline id to match timeline items in between local echo and remote echo states --- ElementX/Sources/Other/Extensions/Array.swift | 6 ++++++ .../Screens/RoomScreen/RoomScreenViewModel.swift | 10 +++++----- .../TimelineController/RoomTimelineController.swift | 6 +++--- 3 files changed, 14 insertions(+), 8 deletions(-) diff --git a/ElementX/Sources/Other/Extensions/Array.swift b/ElementX/Sources/Other/Extensions/Array.swift index a4a2e654e..26830cb57 100644 --- a/ElementX/Sources/Other/Extensions/Array.swift +++ b/ElementX/Sources/Other/Extensions/Array.swift @@ -67,3 +67,9 @@ extension Array { return newItems } } + +extension Array where Element == RoomTimelineItemProtocol { + func firstUsingStableID(_ id: TimelineItemIdentifier) -> Element? { + first { $0.id.timelineID == id.timelineID } + } +} diff --git a/ElementX/Sources/Screens/RoomScreen/RoomScreenViewModel.swift b/ElementX/Sources/Screens/RoomScreen/RoomScreenViewModel.swift index 86fc1317f..3e6e648b4 100644 --- a/ElementX/Sources/Screens/RoomScreen/RoomScreenViewModel.swift +++ b/ElementX/Sources/Screens/RoomScreen/RoomScreenViewModel.swift @@ -469,7 +469,7 @@ class RoomScreenViewModel: RoomScreenViewModelType, RoomScreenViewModelProtocol // MARK: TimelineItemActionMenu private func showTimelineItemActionMenu(for itemID: TimelineItemIdentifier) { - guard let timelineItem = timelineController.timelineItems.first(where: { $0.id == itemID }), + guard let timelineItem = timelineController.timelineItems.firstUsingStableID(itemID), let eventTimelineItem = timelineItem as? EventBasedTimelineItemProtocol else { // Don't show a menu for non-event based items. return @@ -479,7 +479,7 @@ class RoomScreenViewModel: RoomScreenViewModelType, RoomScreenViewModelProtocol } private func timelineItemMenuActionsForItemId(_ itemID: TimelineItemIdentifier) -> TimelineItemMenuActions? { - guard let timelineItem = timelineController.timelineItems.first(where: { $0.id == itemID }), + guard let timelineItem = timelineController.timelineItems.firstUsingStableID(itemID), let item = timelineItem as? EventBasedTimelineItemProtocol else { // Don't show a context menu for non-event based items. return nil @@ -541,7 +541,7 @@ class RoomScreenViewModel: RoomScreenViewModelType, RoomScreenViewModelProtocol // swiftlint:disable:next cyclomatic_complexity function_body_length private func processTimelineItemMenuAction(_ action: TimelineItemMenuAction, itemID: TimelineItemIdentifier) { - guard let timelineItem = timelineController.timelineItems.first(where: { $0.id == itemID }), + guard let timelineItem = timelineController.timelineItems.firstUsingStableID(itemID), let eventTimelineItem = timelineItem as? EventBasedTimelineItemProtocol else { return } @@ -766,7 +766,7 @@ class RoomScreenViewModel: RoomScreenViewModelType, RoomScreenViewModelProtocol // MARK: - Reactions private func showEmojiPicker(for itemID: TimelineItemIdentifier) { - guard let timelineItem = timelineController.timelineItems.first(where: { $0.id == itemID }), + guard let timelineItem = timelineController.timelineItems.firstUsingStableID(itemID), timelineItem.isReactable, let eventTimelineItem = timelineItem as? EventBasedTimelineItemProtocol else { return @@ -776,7 +776,7 @@ class RoomScreenViewModel: RoomScreenViewModelType, RoomScreenViewModelProtocol } private func showReactionSummary(for itemID: TimelineItemIdentifier, selectedKey: String) { - guard let timelineItem = timelineController.timelineItems.first(where: { $0.id == itemID }), + guard let timelineItem = timelineController.timelineItems.firstUsingStableID(itemID), let eventTimelineItem = timelineItem as? EventBasedTimelineItemProtocol else { return } diff --git a/ElementX/Sources/Services/Timeline/TimelineController/RoomTimelineController.swift b/ElementX/Sources/Services/Timeline/TimelineController/RoomTimelineController.swift index 880d3ca31..a0791ea0a 100644 --- a/ElementX/Sources/Services/Timeline/TimelineController/RoomTimelineController.swift +++ b/ElementX/Sources/Services/Timeline/TimelineController/RoomTimelineController.swift @@ -96,7 +96,7 @@ class RoomTimelineController: RoomTimelineControllerProtocol { } func processItemAppearance(_ itemID: TimelineItemIdentifier) async { - guard let timelineItem = timelineItems.first(where: { $0.id == itemID }) else { + guard let timelineItem = timelineItems.firstUsingStableID(itemID) else { return } @@ -108,7 +108,7 @@ class RoomTimelineController: RoomTimelineControllerProtocol { func processItemDisappearance(_ itemID: TimelineItemIdentifier) { } func processItemTap(_ itemID: TimelineItemIdentifier) async -> RoomTimelineControllerAction { - guard let timelineItem = timelineItems.first(where: { $0.id == itemID }) else { + guard let timelineItem = timelineItems.firstUsingStableID(itemID) else { return .none } @@ -158,7 +158,7 @@ class RoomTimelineController: RoomTimelineControllerProtocol { func editMessage(_ newMessage: String, original itemID: TimelineItemIdentifier) async { MXLog.info("Edit message in \(roomID)") - if let timelineItem = timelineItems.first(where: { $0.id == itemID }), + if let timelineItem = timelineItems.firstUsingStableID(itemID), let item = timelineItem as? EventBasedTimelineItemProtocol, item.hasFailedToSend { MXLog.info("Editing a failed echo, will cancel and resend it as a new message")