diff --git a/ElementX/Sources/Screens/FilePreviewScreen/TimelineMediaPreviewDataSource.swift b/ElementX/Sources/Screens/FilePreviewScreen/TimelineMediaPreviewDataSource.swift index 6d67a0c9f..a96c04d48 100644 --- a/ElementX/Sources/Screens/FilePreviewScreen/TimelineMediaPreviewDataSource.swift +++ b/ElementX/Sources/Screens/FilePreviewScreen/TimelineMediaPreviewDataSource.swift @@ -449,7 +449,7 @@ private extension RoomTimelineItemViewState { return [TimelineMediaPreviewItem.Media(roomTimelineItemViewState: self)].compactMap { $0 } } - return galleryItem.content.attachments(allowedTypes: allowedGalleryItemTypes).map { + return galleryItem.content.items(matching: allowedGalleryItemTypes).map { TimelineMediaPreviewItem.Media(galleryParent: galleryItem, item: $0.item) } } diff --git a/ElementX/Sources/Screens/MediaEventsTimelineScreen/MediaEventsTimelineScreenViewModel.swift b/ElementX/Sources/Screens/MediaEventsTimelineScreen/MediaEventsTimelineScreenViewModel.swift index 966b6e412..3abbef626 100644 --- a/ElementX/Sources/Screens/MediaEventsTimelineScreen/MediaEventsTimelineScreenViewModel.swift +++ b/ElementX/Sources/Screens/MediaEventsTimelineScreen/MediaEventsTimelineScreenViewModel.swift @@ -20,14 +20,9 @@ class MediaEventsTimelineScreenViewModel: MediaEventsTimelineScreenViewModelType private var isOldestItemVisible = false - /// The gallery attachment that a listed item was built from, keyed by that item's unique ID. - /// Interactions are forwarded using the gallery's own identifier, which is the one the timeline knows. - private struct GalleryItemLocation { - let parentID: TimelineItemIdentifier - let mediaIndex: Int - } - - private var galleryItemLookup = [TimelineItemIdentifier.UniqueID: GalleryItemLocation]() + /// The gallery item that a listed item was built from, so that interactions can be forwarded + /// using the gallery's identifier rather than the listed item's. + private var galleryItemIDs = [TimelineItemIdentifier.UniqueID: GalleryItemID]() private var activeTimelineViewModel: TimelineViewModelProtocol { switch state.screenMode { @@ -132,14 +127,14 @@ class MediaEventsTimelineScreenViewModel: MediaEventsTimelineScreenViewModelType case .oldestItemDidDisappear: isOldestItemVisible = false case .tappedItem(let item): - if let location = galleryItemLookup[item.id] { - activeTimelineViewModel.context.send(viewAction: .galleryItemTapped(itemID: location.parentID, index: location.mediaIndex)) + if let galleryItemID = galleryItemIDs[item.id] { + activeTimelineViewModel.context.send(viewAction: .galleryItemTapped(galleryItemID)) } else { activeTimelineViewModel.context.send(viewAction: .mediaTapped(itemID: item.identifier)) } case .longPressedItem(let item): - // The menu acts on the gallery as a whole, as its actions can't apply to a single attachment. - let itemID = galleryItemLookup[item.id]?.parentID ?? item.identifier + // The menu acts on the gallery as a whole, as its actions can't apply to a single item. + let itemID = galleryItemIDs[item.id]?.timelineItemID ?? item.identifier activeTimelineViewModel.context.send(viewAction: .displayTimelineItemMenu(itemID: itemID)) } } @@ -192,7 +187,7 @@ class MediaEventsTimelineScreenViewModel: MediaEventsTimelineScreenViewModelType private func updateWithTimelineViewState(_ timelineViewState: TimelineViewState) { var newGroups = [MediaEventsTimelineGroup]() var currentItems = [RoomTimelineItemViewState]() - var newGalleryItemLookup = [TimelineItemIdentifier.UniqueID: GalleryItemLocation]() + var newGalleryItemIDs = [TimelineItemIdentifier.UniqueID: GalleryItemID]() timelineViewState.timelineState.itemViewStates.flatMap { itemViewState -> [RoomTimelineItemViewState] in switch itemViewState.type { @@ -203,10 +198,9 @@ class MediaEventsTimelineScreenViewModel: MediaEventsTimelineScreenViewModelType case .separator: return [itemViewState] case .gallery(let galleryItem): - // A gallery's attachments are displayed flattened, listed individually. let flattenedItems = galleryItem.itemsAsIndividualMessages(allowedTypes: timelineViewState.allowedGalleryItemTypes) for (mediaIndex, item) in flattenedItems { - newGalleryItemLookup[item.id.uniqueID] = .init(parentID: galleryItem.id, mediaIndex: mediaIndex) + newGalleryItemIDs[item.id.uniqueID] = .init(timelineItemID: galleryItem.id, mediaIndex: mediaIndex) } return flattenedItems.map { .init(item: $0.item, groupStyle: .single) } default: @@ -235,7 +229,7 @@ class MediaEventsTimelineScreenViewModel: MediaEventsTimelineScreenViewModelType } state.groups = newGroups - galleryItemLookup = newGalleryItemLookup + galleryItemIDs = newGalleryItemIDs state.isBackPaginating = timelineViewState.timelineState.paginationState.backward == .paginating state.shouldShowEmptyState = newGroups.isEmpty && timelineViewState.timelineState.paginationState.backward == .endReached @@ -291,7 +285,7 @@ private extension GalleryRoomTimelineItem { func itemsAsIndividualMessages(allowedTypes: [TimelineAllowedGalleryItemType]?) -> [(mediaIndex: Int, item: EventBasedMessageTimelineItemProtocol)] { guard let eventOrTransactionID = id.eventOrTransactionID else { return [] } - return content.attachments(allowedTypes: allowedTypes).compactMap { mediaIndex, galleryItem in + return content.items(matching: allowedTypes).compactMap { mediaIndex, galleryItem in let itemID = TimelineItemIdentifier.event(uniqueID: .init("\(id.uniqueID.value)-\(mediaIndex)"), eventOrTransactionID: eventOrTransactionID) diff --git a/ElementX/Sources/Screens/Timeline/TimelineModels.swift b/ElementX/Sources/Screens/Timeline/TimelineModels.swift index bfa2fdd30..3e923d339 100644 --- a/ElementX/Sources/Screens/Timeline/TimelineModels.swift +++ b/ElementX/Sources/Screens/Timeline/TimelineModels.swift @@ -53,7 +53,7 @@ enum TimelineViewAction { case itemDisappeared(itemID: TimelineItemIdentifier) case mediaTapped(itemID: TimelineItemIdentifier) - case galleryItemTapped(itemID: TimelineItemIdentifier, index: Int) + case galleryItemTapped(GalleryItemID) case itemSendInfoTapped(itemID: TimelineItemIdentifier) case toggleReaction(key: String, itemID: TimelineItemIdentifier) case sendReadReceiptIfNeeded(TimelineItemIdentifier) diff --git a/ElementX/Sources/Screens/Timeline/TimelineViewModel.swift b/ElementX/Sources/Screens/Timeline/TimelineViewModel.swift index 12d61cc5c..2c4b0ce77 100644 --- a/ElementX/Sources/Screens/Timeline/TimelineViewModel.swift +++ b/ElementX/Sources/Screens/Timeline/TimelineViewModel.swift @@ -160,8 +160,8 @@ class TimelineViewModel: TimelineViewModelType, TimelineViewModelProtocol { Task { await timelineController.processItemDisappearance(id) } case .mediaTapped(let id): Task { await handleMediaTapped(with: id) } - case .galleryItemTapped(let id, let index): - Task { await handleMediaTapped(with: id, galleryIndex: index) } + case .galleryItemTapped(let galleryItemID): + Task { await handleMediaTapped(with: galleryItemID.timelineItemID, galleryIndex: galleryItemID.mediaIndex) } case .itemSendInfoTapped(let itemID): handleItemSendInfoTapped(itemID: itemID) case .toggleReaction(let emoji, let itemID): diff --git a/ElementX/Sources/Screens/Timeline/View/TimelineItemViews/GalleryRoomTimelineView.swift b/ElementX/Sources/Screens/Timeline/View/TimelineItemViews/GalleryRoomTimelineView.swift index b39dabe70..e455d7f74 100644 --- a/ElementX/Sources/Screens/Timeline/View/TimelineItemViews/GalleryRoomTimelineView.swift +++ b/ElementX/Sources/Screens/Timeline/View/TimelineItemViews/GalleryRoomTimelineView.swift @@ -61,7 +61,7 @@ struct GalleryRoomTimelineView: View { } private func tap(index: Int) { - context?.send(viewAction: .galleryItemTapped(itemID: timelineItem.id, index: index)) + context?.send(viewAction: .galleryItemTapped(.init(timelineItemID: timelineItem.id, mediaIndex: index))) } } diff --git a/ElementX/Sources/Services/Timeline/TimelineItems/Items/Messages/GalleryRoomTimelineItemContent.swift b/ElementX/Sources/Services/Timeline/TimelineItems/Items/Messages/GalleryRoomTimelineItemContent.swift index 385e281fa..1e8369b6d 100644 --- a/ElementX/Sources/Services/Timeline/TimelineItems/Items/Messages/GalleryRoomTimelineItemContent.swift +++ b/ElementX/Sources/Services/Timeline/TimelineItems/Items/Messages/GalleryRoomTimelineItemContent.swift @@ -16,11 +16,10 @@ nonisolated struct GalleryRoomTimelineItemContent: Hashable { var formattedCaptionHTMLString: String? let items: [GalleryItem] - /// The attachments of the given types, paired with their position in the gallery so that they remain - /// identifiable once separated from it. Attachments of an unknown type are never included as there's - /// nothing to show for them. + /// The items of the given types, paired with their position in the gallery so that they remain + /// identifiable once separated from it. Items of an unknown type are never included. /// - Parameter allowedTypes: The types to include, or `nil` to include them all. - func attachments(allowedTypes: [TimelineAllowedGalleryItemType]?) -> [(mediaIndex: Int, item: GalleryItem)] { + func items(matching allowedTypes: [TimelineAllowedGalleryItemType]?) -> [(mediaIndex: Int, item: GalleryItem)] { items.enumerated().compactMap { mediaIndex, item in guard let allowedItemType = item.allowedItemType, allowedTypes?.contains(allowedItemType) ?? true else {