Show edited attachments in gallery

This commit is contained in:
Shadowfacts 2025-02-06 10:33:24 -05:00
parent f102ebbfc8
commit abbe0f82e6
6 changed files with 69 additions and 12 deletions

View File

@ -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() {
}

View File

@ -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)
}

View File

@ -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
}

View File

@ -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):

View File

@ -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

View File

@ -104,6 +104,18 @@ class ComposeHostingController: UIHostingController<ComposeHostingController.Vie
config.fetchAvatar = { @MainActor in await ImageCache.avatars.get($0).1 }
config.displayNameLabel = { AnyView(AccountDisplayNameView(account: $0, textStyle: $1, emojiSize: $2)) }
config.replyContentView = { [mastodonController] in AnyView(ComposeReplyContentView(status: $0, mastodonController: mastodonController, heightChanged: $1)) }
config.fetchImageAndGIFData = {
if case let (.some(data), .some(image)) = await ImageCache.attachments.get($0) {
return (image, data)
} else {
return nil
}
}
config.makeGifvGalleryContentVC = {
let asset = AVAsset(url: $0)
let controller = GifvController(asset: asset)
return GifvGalleryContentViewController(controller: controller, url: $0, caption: nil)
}
self.config = config
}