Allow previews in the timeline to include filtered galleries (#5943)

* remove the usage of the timeline kind override in favour of getting it properly from the timeline view model

* allow the previews to include gallery items filtered by the allowed types when started outside the gallery

sss

asa

* fix for actions not being forwarded to the timeline right

* pr suggestions
This commit is contained in:
Mauro
2026-07-30 13:49:22 +02:00
committed by GitHub
parent 33f8ce2759
commit ae795df530
17 changed files with 243 additions and 110 deletions
@@ -35,13 +35,19 @@ class TimelineMediaPreviewDataSource: NSObject, QLPreviewControllerDataSource {
var paginationState: TimelinePaginationState
/// The gallery attachments to include, so that a gallery only contributes the media being browsed.
private let allowedGalleryItemTypes: [TimelineAllowedGalleryItemType]?
/// Builds a data source spanning every previewable attachment in the timeline, paginating
/// as the user swipes past the loaded range. Used when tapping a standalone media message.
init(itemViewStates: [RoomTimelineItemViewState],
initialItem: EventBasedMessageTimelineItemProtocol,
initialPadding: Int = 100,
paginationState: TimelinePaginationState) {
previewItems = itemViewStates.compactMap(TimelineMediaPreviewItem.Media.init)
paginationState: TimelinePaginationState,
allowedGalleryItemTypes: [TimelineAllowedGalleryItemType]? = nil) {
self.allowedGalleryItemTypes = allowedGalleryItemTypes
previewItems = itemViewStates.flatMap { $0.previewableMedia(allowedGalleryItemTypes: allowedGalleryItemTypes) }
let initialPreviewID = TimelineMediaPreviewItem.Media(timelineItem: initialItem).id
if let initialItemArrayIndex = previewItems.firstIndex(where: { $0.id == initialPreviewID }) {
@@ -66,6 +72,8 @@ class TimelineMediaPreviewDataSource: NSObject, QLPreviewControllerDataSource {
/// gallery and there's no timeline pagination to drive.
init(galleryItem: GalleryRoomTimelineItem,
initialIndex: Int) {
allowedGalleryItemTypes = nil // All of the gallery's attachments are shown.
let media = galleryItem.content.items.map { item in
TimelineMediaPreviewItem.Media(galleryParent: galleryItem, item: item)
}
@@ -93,17 +101,17 @@ class TimelineMediaPreviewDataSource: NSObject, QLPreviewControllerDataSource {
}
func updatePreviewItems(itemViewStates: [RoomTimelineItemViewState]) {
let newItems: [TimelineMediaPreviewItem.Media] = itemViewStates.compactMap { itemViewState in
guard let newItem = TimelineMediaPreviewItem.Media(roomTimelineItemViewState: itemViewState) else { return nil }
// If an item already exists use that instead to preserve the file handle, download error etc.
if let oldItem = previewItems.first(where: { $0.id == newItem.id }) {
oldItem.content = newItem.content
return oldItem
let newItems: [TimelineMediaPreviewItem.Media] = itemViewStates
.flatMap { $0.previewableMedia(allowedGalleryItemTypes: allowedGalleryItemTypes) }
.map { newItem in
// If an item already exists use that instead to preserve the file handle, download error etc.
if let oldItem = previewItems.first(where: { $0.id == newItem.id }) {
oldItem.content = newItem.content
return oldItem
}
return newItem
}
return newItem
}
var hasPaginated = false
if let range = newItems.map(\.id).firstRange(of: previewItems.map(\.id)) {
@@ -430,3 +438,23 @@ enum TimelineMediaPreviewItem: Equatable {
}
}
}
private extension RoomTimelineItemViewState {
/// The media of this item that can be previewed, flattening a gallery message into its individual
/// attachments so that they can be browsed alongside the timeline's other media.
/// - Parameter allowedGalleryItemTypes: Restricts a gallery's attachments to the media being
/// browsed, as the SDK can only filter the gallery event as a whole.
func previewableMedia(allowedGalleryItemTypes: [TimelineAllowedGalleryItemType]?) -> [TimelineMediaPreviewItem.Media] {
guard case .gallery(let galleryItem) = type else {
return [TimelineMediaPreviewItem.Media(roomTimelineItemViewState: self)].compactMap { $0 }
}
return galleryItem.content.items.filter { item in
guard let allowedItemType = item.allowedItemType else {
return false // Nothing to preview, and unlike a tile there's no index to line up with.
}
return allowedGalleryItemTypes?.contains(allowedItemType) ?? true
}.map { TimelineMediaPreviewItem.Media(galleryParent: galleryItem, item: $0) }
}
}