mirror of
https://github.com/Novaloop-AG/element-x-ios.git
synced 2026-11-02 12:07:55 +00:00
pr suggestions
This commit is contained in:
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
+11
-17
@@ -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):
|
||||
|
||||
+1
-1
@@ -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)))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+3
-4
@@ -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 {
|
||||
|
||||
Reference in New Issue
Block a user