pr suggestions

This commit is contained in:
Mauro Romito
2026-07-30 23:19:28 +02:00
committed by Mauro
parent b044764310
commit e32c534b89
6 changed files with 19 additions and 26 deletions
@@ -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)
}
}
@@ -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)
@@ -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)
@@ -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):
@@ -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)))
}
}
@@ -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 {