diff --git a/Packages/ComposeUI/Sources/ComposeUI/Views/Attachments/AttachmentsGalleryDataSource.swift b/Packages/ComposeUI/Sources/ComposeUI/Views/Attachments/AttachmentsGalleryDataSource.swift index 49e7fa93..30b84475 100644 --- a/Packages/ComposeUI/Sources/ComposeUI/Views/Attachments/AttachmentsGalleryDataSource.swift +++ b/Packages/ComposeUI/Sources/ComposeUI/Views/Attachments/AttachmentsGalleryDataSource.swift @@ -7,6 +7,8 @@ import UIKit import GalleryVC +import TuskerComponents +import Photos struct AttachmentsGalleryDataSource: GalleryDataSource { let collectionView: UICollectionView @@ -24,15 +26,33 @@ struct AttachmentsGalleryDataSource: GalleryDataSource { case .editing(_, _, _): fatalError("TODO") - case .asset(_): - fatalError("TODO") + case .asset(let id): + content = LoadingGalleryContentViewController(caption: nil) { + if let (image, gifData) = await fetchImageAndGIFData(assetID: id) { + let gifController = gifData.map(GIFController.init) + return ImageGalleryContentViewController(image: image, caption: nil, gifController: gifController) + } else { + return nil + } + } case .drawing(let drawing): let image = drawing.imageInLightMode(from: drawing.bounds) content = ImageGalleryContentViewController(image: image, caption: nil, gifController: nil) - case .file(_, _): - fatalError("TODO") + case .file(let url, let type): + if type.conforms(to: .movie) { + content = VideoGalleryContentViewController(url: url, caption: nil) + } else if type.conforms(to: .image), + let data = try? Data(contentsOf: url), + let image = UIImage(data: data) { + let gifController = type == .gif ? GIFController(gifData: data) : nil + content = ImageGalleryContentViewController(image: image, caption: nil, gifController: gifController) + } else { + return LoadingGalleryContentViewController(caption: nil) { + nil + } + } case .none: return LoadingGalleryContentViewController(caption: nil) { @@ -47,4 +67,24 @@ struct AttachmentsGalleryDataSource: GalleryDataSource { collectionView.cellForItem(at: IndexPath(item: index, section: 0)) } + private func fetchImageAndGIFData(assetID id: String) async -> (UIImage, Data?)? { + guard let asset = PHAsset.fetchAssets(withLocalIdentifiers: [id], options: nil).firstObject else { + return nil + } + let (type, data) = await withCheckedContinuation { continuation in + PHImageManager.default().requestImageDataAndOrientation(for: asset, options: nil) { data, typeIdentifier, orientation, info in + continuation.resume(returning: (typeIdentifier, data)) + } + } + guard let data, + let image = UIImage(data: data) else { + return nil + } + if type == UTType.gif.identifier { + return (image, data) + } else { + return (image, nil) + } + } + } diff --git a/Packages/ComposeUI/Sources/ComposeUI/Views/Attachments/AttachmentsSection.swift b/Packages/ComposeUI/Sources/ComposeUI/Views/Attachments/AttachmentsSection.swift index 15d2ab32..8f8995e7 100644 --- a/Packages/ComposeUI/Sources/ComposeUI/Views/Attachments/AttachmentsSection.swift +++ b/Packages/ComposeUI/Sources/ComposeUI/Views/Attachments/AttachmentsSection.swift @@ -21,7 +21,8 @@ struct AttachmentsSection: View { ) // Impose a minimum height, because otherwise it defaults to zero which prevents the collection // view from laying out, and leaving the intrinsic content size at zero too. - .frame(minHeight: 100) + // Add 4 to the minItemSize because otherwise drag-and-drop while reordering can alter the contentOffset by that much. + .frame(minHeight: 104) } } diff --git a/Packages/ComposeUI/Sources/ComposeUI/Views/Attachments/EditAttachmentWrapperGalleryContentViewController.swift b/Packages/ComposeUI/Sources/ComposeUI/Views/Attachments/EditAttachmentWrapperGalleryContentViewController.swift index 86fe600b..cd107fe9 100644 --- a/Packages/ComposeUI/Sources/ComposeUI/Views/Attachments/EditAttachmentWrapperGalleryContentViewController.swift +++ b/Packages/ComposeUI/Sources/ComposeUI/Views/Attachments/EditAttachmentWrapperGalleryContentViewController.swift @@ -36,8 +36,8 @@ class EditAttachmentWrapperGalleryContentViewController: UIViewController, Galle false } - var canAnimateFromSourceView: Bool { - wrapped.canAnimateFromSourceView + var presentationAnimation: GalleryContentPresentationAnimation { + wrapped.presentationAnimation } var hideControlsOnZoom: Bool { diff --git a/Packages/GalleryVC/Sources/GalleryVC/UIView+Utilities.swift b/Packages/GalleryVC/Sources/GalleryVC/UIView+Utilities.swift index 411122be..7b03388c 100644 --- a/Packages/GalleryVC/Sources/GalleryVC/UIView+Utilities.swift +++ b/Packages/GalleryVC/Sources/GalleryVC/UIView+Utilities.swift @@ -14,7 +14,8 @@ extension UIView { while let superview = view.superview { if superview.layer.masksToBounds { return superview - } else if superview is UIScrollView { + } else if let scrollView = superview as? UIScrollView, + scrollView.isScrollEnabled { return self } else { view = superview