diff --git a/Packages/ComposeUI/Sources/ComposeUI/ComposeUIConfig.swift b/Packages/ComposeUI/Sources/ComposeUI/ComposeUIConfig.swift index eb1d9e46..cfba97fb 100644 --- a/Packages/ComposeUI/Sources/ComposeUI/ComposeUIConfig.swift +++ b/Packages/ComposeUI/Sources/ComposeUI/ComposeUIConfig.swift @@ -10,6 +10,7 @@ import Pachyderm import PhotosUI import PencilKit import TuskerComponents +import GalleryVC // Configuration/data injected from outside the compose UI. public struct ComposeUIConfig { @@ -38,6 +39,8 @@ public struct ComposeUIConfig { public var fetchAvatar: AvatarImageView.FetchAvatar = { _ in nil } public var displayNameLabel: (any AccountProtocol, Font.TextStyle, CGFloat) -> AnyView = { _, _, _ in AnyView(EmptyView()) } public var replyContentView: (any StatusProtocol, @escaping (CGFloat) -> Void) -> AnyView = { _, _ in AnyView(EmptyView()) } + public var fetchImageAndGIFData: (URL) async -> (UIImage, Data)? = { _ in nil } + public var makeGifvGalleryContentVC: (URL) -> (any GalleryContentViewController)? = { _ in nil } public init() { } diff --git a/Packages/ComposeUI/Sources/ComposeUI/Views/AttachmentThumbnailView.swift b/Packages/ComposeUI/Sources/ComposeUI/Views/AttachmentThumbnailView.swift index 226fb9c2..e5a87d64 100644 --- a/Packages/ComposeUI/Sources/ComposeUI/Views/AttachmentThumbnailView.swift +++ b/Packages/ComposeUI/Sources/ComposeUI/Views/AttachmentThumbnailView.swift @@ -31,7 +31,7 @@ private struct AttachmentThumbnailViewContent: View { var contentMode: ContentMode = .fit var thumbnailSize: CGSize? @State private var mode: Mode = .empty - @EnvironmentObject private var composeController: ComposeController + @Environment(\.composeUIConfig.fetchImageAndGIFData) private var fetchImageAndGIFData var body: some View { switch mode { @@ -56,7 +56,7 @@ private struct AttachmentThumbnailViewContent: View { case .editing(_, let kind, let url): switch kind { case .image: - if let image = await composeController.fetchAttachment(url) { + if let (image, _) = await fetchImageAndGIFData(url) { self.mode = .image(image) } diff --git a/Packages/ComposeUI/Sources/ComposeUI/Views/Attachments/AttachmentsGalleryDataSource.swift b/Packages/ComposeUI/Sources/ComposeUI/Views/Attachments/AttachmentsGalleryDataSource.swift index b5779757..9147cecd 100644 --- a/Packages/ComposeUI/Sources/ComposeUI/Views/Attachments/AttachmentsGalleryDataSource.swift +++ b/Packages/ComposeUI/Sources/ComposeUI/Views/Attachments/AttachmentsGalleryDataSource.swift @@ -1,5 +1,5 @@ // -// AttachmentGalleryDataSource.swift +// AttachmentsGalleryDataSource.swift // ComposeUI // // Created by Shadowfacts on 11/21/24. @@ -12,6 +12,8 @@ import Photos struct AttachmentsGalleryDataSource: GalleryDataSource { let collectionView: UICollectionView + let fetchImageAndGIFData: (URL) async -> (UIImage, Data)? + let makeGifvGalleryContentVC: (URL) -> (any GalleryContentViewController)? let attachmentAtIndex: (Int) -> DraftAttachment? func galleryItemsCount() -> Int { @@ -23,12 +25,32 @@ struct AttachmentsGalleryDataSource: GalleryDataSource { let content: any GalleryContentViewController switch attachment.data { - case .editing(_, _, _): - fatalError("TODO") + case .editing(_, let kind, let url): + switch kind { + case .image: + content = LoadingGalleryContentViewController(caption: nil) { + if let (image, data) = await fetchImageAndGIFData(url) { + let gifController: GIFController? = if url.pathExtension == "gif" { + GIFController(gifData: data) + } else { + nil + } + return ImageGalleryContentViewController(image: image, caption: nil, gifController: gifController) + } else { + return nil + } + } + case .video, .audio: + content = VideoGalleryContentViewController(url: url, caption: nil) + case .gifv: + content = LoadingGalleryContentViewController(caption: nil) { makeGifvGalleryContentVC(url) } + case .unknown: + content = LoadingGalleryContentViewController(caption: nil) { nil } + } case .asset(let id): content = LoadingGalleryContentViewController(caption: nil) { - if let (image, gifData) = await fetchImageAndGIFData(assetID: id) { + if let (image, gifData) = await fetchAssetImageAndGIFData(assetID: id) { let gifController = gifData.map(GIFController.init) return ImageGalleryContentViewController(image: image, caption: nil, gifController: gifController) } else { @@ -72,7 +94,7 @@ struct AttachmentsGalleryDataSource: GalleryDataSource { } } - private func fetchImageAndGIFData(assetID id: String) async -> (UIImage, Data?)? { + private func fetchAssetImageAndGIFData(assetID id: String) async -> (UIImage, Data?)? { guard let asset = PHAsset.fetchAssets(withLocalIdentifiers: [id], options: nil).firstObject else { return nil } diff --git a/Packages/ComposeUI/Sources/ComposeUI/Views/Attachments/AttachmentsSection.swift b/Packages/ComposeUI/Sources/ComposeUI/Views/Attachments/AttachmentsSection.swift index bef0a6d0..b991647e 100644 --- a/Packages/ComposeUI/Sources/ComposeUI/Views/Attachments/AttachmentsSection.swift +++ b/Packages/ComposeUI/Sources/ComposeUI/Views/Attachments/AttachmentsSection.swift @@ -98,9 +98,16 @@ private struct WrappedCollectionView: UIViewControllerRepresentable { @ObservedObject var draft: Draft let spacing: CGFloat let minItemSize: CGFloat - + @Environment(\.composeUIConfig.fetchImageAndGIFData) private var fetchImageAndGIFData + @Environment(\.composeUIConfig.makeGifvGalleryContentVC) private var makeGifvGalleryContentVC + func makeUIViewController(context: Context) -> WrappedCollectionViewController { - WrappedCollectionViewController(spacing: spacing, minItemSize: minItemSize) + WrappedCollectionViewController( + spacing: spacing, + minItemSize: minItemSize, + fetchImageAndGIFData: fetchImageAndGIFData, + makeGifvGalleryContentVC: makeGifvGalleryContentVC + ) } func updateUIViewController(_ uiViewController: UIViewControllerType, context: Context) { @@ -167,14 +174,23 @@ private class WrappedCollectionViewController: UIViewController { fileprivate var currentInteractiveMoveStartOffsetInCell: CGPoint? fileprivate var currentInteractiveMoveCell: HostingCollectionViewCell? fileprivate var addAttachment: ((DraftAttachment) -> Void)? = nil + fileprivate var fetchImageAndGIFData: (URL) async -> (UIImage, Data)? + fileprivate var makeGifvGalleryContentVC: (URL) -> (any GalleryContentViewController)? var collectionView: UICollectionView { view as! UICollectionView } - init(spacing: CGFloat, minItemSize: CGFloat) { + init( + spacing: CGFloat, + minItemSize: CGFloat, + fetchImageAndGIFData: @escaping (URL) async -> (UIImage, Data)?, + makeGifvGalleryContentVC: @escaping (URL) -> (any GalleryContentViewController)? + ) { self.spacing = spacing self.minItemSize = minItemSize + self.fetchImageAndGIFData = fetchImageAndGIFData + self.makeGifvGalleryContentVC = makeGifvGalleryContentVC super.init(nibName: nil, bundle: nil) } @@ -330,7 +346,11 @@ extension WrappedCollectionViewController: UICollectionViewDelegate { guard case .attachment(_) = dataSource.itemIdentifier(for: indexPath) else { return } - let dataSource = AttachmentsGalleryDataSource(collectionView: collectionView) { [dataSource] in + let dataSource = AttachmentsGalleryDataSource( + collectionView: collectionView, + fetchImageAndGIFData: self.fetchImageAndGIFData, + makeGifvGalleryContentVC: self.makeGifvGalleryContentVC + ) { [dataSource] in let item = dataSource?.itemIdentifier(for: IndexPath(item: $0, section: 0)) switch item { case .attachment(let attachment): diff --git a/Packages/GalleryVC/Sources/GalleryVC/Content/LoadingGalleryContentViewController.swift b/Packages/GalleryVC/Sources/GalleryVC/Content/LoadingGalleryContentViewController.swift index f2b039bc..f4805421 100644 --- a/Packages/GalleryVC/Sources/GalleryVC/Content/LoadingGalleryContentViewController.swift +++ b/Packages/GalleryVC/Sources/GalleryVC/Content/LoadingGalleryContentViewController.swift @@ -55,7 +55,7 @@ public class LoadingGalleryContentViewController: UIViewController, GalleryConte container?.setGalleryContentLoading(true) - Task { + Task { @MainActor in if let wrapped = await provider() { self.wrapped = wrapped wrapped.container = container diff --git a/Tusker/Screens/Compose/ComposeHostingController.swift b/Tusker/Screens/Compose/ComposeHostingController.swift index ee3a08bc..9177c774 100644 --- a/Tusker/Screens/Compose/ComposeHostingController.swift +++ b/Tusker/Screens/Compose/ComposeHostingController.swift @@ -104,6 +104,18 @@ class ComposeHostingController: UIHostingController