From 22b5d62ba12aaf53b4cd0707ea1fd699d9f3f1ac Mon Sep 17 00:00:00 2001 From: Shadowfacts Date: Sun, 13 Nov 2022 14:01:54 -0500 Subject: [PATCH] Make GIF attachments animate in the Compose screen --- .../Compose/ComposeAttachmentImage.swift | 52 ++++++++++++++++--- 1 file changed, 45 insertions(+), 7 deletions(-) diff --git a/Tusker/Screens/Compose/ComposeAttachmentImage.swift b/Tusker/Screens/Compose/ComposeAttachmentImage.swift index c7dae3b4e3..a0ffd2c61c 100644 --- a/Tusker/Screens/Compose/ComposeAttachmentImage.swift +++ b/Tusker/Screens/Compose/ComposeAttachmentImage.swift @@ -13,6 +13,7 @@ struct ComposeAttachmentImage: View { let attachment: CompositionAttachment let fullSize: Bool + @State private var gifData: Data? = nil @State private var image: UIImage? = nil @State private var imageContentMode: ContentMode = .fill @State private var imageBackgroundColor: Color = .black @@ -20,7 +21,9 @@ struct ComposeAttachmentImage: View { @Environment(\.colorScheme) private var colorScheme: ColorScheme var body: some View { - if let image = image { + if let gifData { + GIFViewWrapper(gifData: gifData) + } else if let image { Image(uiImage: image) .resizable() .aspectRatio(contentMode: imageContentMode) @@ -54,9 +57,23 @@ struct ComposeAttachmentImage: View { // currently only used as thumbnail in ComposeAttachmentRow size = CGSize(width: 80, height: 80) } - PHImageManager.default().requestImage(for: asset, targetSize: size, contentMode: .aspectFill, options: nil) { (image, _) in - DispatchQueue.main.async { - self.image = image + let isGIF = PHAssetResource.assetResources(for: asset).contains(where: { $0.uniformTypeIdentifier == UTType.gif.identifier }) + if isGIF { + PHImageManager.default().requestImageDataAndOrientation(for: asset, options: nil) { data, typeIdentifier, orientation, info in + if typeIdentifier == UTType.gif.identifier { + self.gifData = data + } else if let data { + let image = UIImage(data: data) + DispatchQueue.main.async { + self.image = image + } + } + } + } else { + PHImageManager.default().requestImage(for: asset, targetSize: size, contentMode: .aspectFill, options: nil) { (image, _) in + DispatchQueue.main.async { + self.image = image + } } } case let .video(url): @@ -70,13 +87,34 @@ struct ComposeAttachmentImage: View { imageContentMode = .fit imageBackgroundColor = .white case let .gif(data): - if let image = UIImage(data: data) { - self.image = image - } + self.gifData = data } } } +private struct GIFViewWrapper: UIViewRepresentable { + typealias UIViewType = GIFImageView + + @State private var controller: GIFController + + init(gifData: Data) { + self._controller = State(wrappedValue: GIFController(gifData: gifData)) + } + + func makeUIView(context: Context) -> GIFImageView { + let view = GIFImageView() + controller.attach(to: view) + controller.startAnimating() + view.contentMode = .scaleAspectFit + view.setContentCompressionResistancePriority(.defaultLow, for: .horizontal) + view.setContentCompressionResistancePriority(.defaultLow, for: .vertical) + return view + } + + func updateUIView(_ uiView: GIFImageView, context: Context) { + } +} + struct ComposeAttachmentImage_Previews: PreviewProvider { static var previews: some View { ComposeAttachmentImage(attachment: CompositionAttachment(data: .image(UIImage())), fullSize: false)