From b9bdd299862bfc26a288517b8c3873f05bc69fae Mon Sep 17 00:00:00 2001 From: Shadowfacts Date: Sun, 13 Nov 2022 13:46:19 -0500 Subject: [PATCH] Fix GIFs dragged from Finder posting as static images Closes #239 --- Tusker/Models/CompositionAttachment.swift | 13 +++--- Tusker/Models/CompositionAttachmentData.swift | 9 +++- .../AssetPreviewViewController.swift | 42 +++++++------------ .../Compose/ComposeAttachmentImage.swift | 4 ++ 4 files changed, 34 insertions(+), 34 deletions(-) diff --git a/Tusker/Models/CompositionAttachment.swift b/Tusker/Models/CompositionAttachment.swift index 30c41be326..9f7d621fc3 100644 --- a/Tusker/Models/CompositionAttachment.swift +++ b/Tusker/Models/CompositionAttachment.swift @@ -56,6 +56,7 @@ private let imageType = UTType.image.identifier private let mp4Type = UTType.mpeg4Movie.identifier private let quickTimeType = UTType.quickTimeMovie.identifier private let dataType = UTType.data.identifier +private let gifType = UTType.gif.identifier extension CompositionAttachment: NSItemProviderWriting { static var writableTypeIdentifiersForItemProvider: [String] { @@ -95,20 +96,22 @@ extension CompositionAttachment: NSItemProviderReading { [typeIdentifier] + UIImage.readableTypeIdentifiersForItemProvider + [mp4Type, quickTimeType] + NSURL.readableTypeIdentifiersForItemProvider } - static func object(withItemProviderData data: Data, typeIdentifier: String) throws -> Self { + static func object(withItemProviderData data: Data, typeIdentifier: String) throws -> CompositionAttachment { if typeIdentifier == CompositionAttachment.typeIdentifier { - return try PropertyListDecoder().decode(Self.self, from: data) + return try PropertyListDecoder().decode(CompositionAttachment.self, from: data) + } else if typeIdentifier == gifType { + return CompositionAttachment(data: .gif(data)) } else if UIImage.readableTypeIdentifiersForItemProvider.contains(typeIdentifier), let image = try? UIImage.object(withItemProviderData: data, typeIdentifier: typeIdentifier) { - return CompositionAttachment(data: .image(image)) as! Self + return CompositionAttachment(data: .image(image)) } else if let type = UTType(typeIdentifier), type == .mpeg4Movie || type == .quickTimeMovie { let temporaryDirectoryURL = URL(fileURLWithPath: NSTemporaryDirectory(), isDirectory: true) let temporaryFileName = ProcessInfo().globallyUniqueString let fileExt = type.preferredFilenameExtension! let temporaryFileURL = temporaryDirectoryURL.appendingPathComponent(temporaryFileName).appendingPathExtension(fileExt) try data.write(to: temporaryFileURL) - return CompositionAttachment(data: .video(temporaryFileURL)) as! Self + return CompositionAttachment(data: .video(temporaryFileURL)) } else if NSURL.readableTypeIdentifiersForItemProvider.contains(typeIdentifier), let url = try? NSURL.object(withItemProviderData: data, typeIdentifier: typeIdentifier) as URL { - return CompositionAttachment(data: .video(url)) as! Self + return CompositionAttachment(data: .video(url)) } else { throw ItemProviderError.incompatibleTypeIdentifier } diff --git a/Tusker/Models/CompositionAttachmentData.swift b/Tusker/Models/CompositionAttachmentData.swift index 0eb6e2e2b9..6b6c022243 100644 --- a/Tusker/Models/CompositionAttachmentData.swift +++ b/Tusker/Models/CompositionAttachmentData.swift @@ -16,6 +16,7 @@ enum CompositionAttachmentData { case image(UIImage) case video(URL) case drawing(PKDrawing) + case gif(Data) var type: AttachmentType { switch self { @@ -27,6 +28,8 @@ enum CompositionAttachmentData { return .video case .drawing(_): return .image + case .gif(_): + return .image } } @@ -119,6 +122,8 @@ enum CompositionAttachmentData { case let .drawing(drawing): let image = drawing.imageInLightMode(from: drawing.bounds, scale: 1) completion(.success((image.pngData()!, .png))) + case let .gif(data): + completion(.success((data, .gif))) } } @@ -191,6 +196,8 @@ extension CompositionAttachmentData: Codable { try container.encode("drawing", forKey: .type) let drawingData = drawing.dataRepresentation() try container.encode(drawingData, forKey: .drawing) + case .gif(_): + throw EncodingError.invalidValue(self, EncodingError.Context(codingPath: [], debugDescription: "gif CompositionAttachments cannot be encoded")) } } @@ -214,7 +221,7 @@ extension CompositionAttachmentData: Codable { let drawing = try PKDrawing(data: drawingData) self = .drawing(drawing) default: - throw DecodingError.dataCorruptedError(forKey: .type, in: container, debugDescription: "CompositionAttachment type must be one of 'image' or 'asset'") + throw DecodingError.dataCorruptedError(forKey: .type, in: container, debugDescription: "CompositionAttachment type must be one of image, asset, or drawing") } } diff --git a/Tusker/Screens/Asset Picker/AssetPreviewViewController.swift b/Tusker/Screens/Asset Picker/AssetPreviewViewController.swift index 8771d0d1b3..0583ecf04c 100644 --- a/Tusker/Screens/Asset Picker/AssetPreviewViewController.swift +++ b/Tusker/Screens/Asset Picker/AssetPreviewViewController.swift @@ -13,18 +13,14 @@ import AVKit class AssetPreviewViewController: UIViewController { - let attachment: CompositionAttachmentData + let asset: PHAsset - init(attachment: CompositionAttachmentData) { - self.attachment = attachment - + init(asset: PHAsset) { + self.asset = asset + super.init(nibName: nil, bundle: nil) } - convenience init(asset: PHAsset) { - self.init(attachment: .asset(asset)) - } - required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") } @@ -34,27 +30,17 @@ class AssetPreviewViewController: UIViewController { view.backgroundColor = .black - switch attachment { - case let .image(image): - showImage(image) - case let .video(url): - showVideo(asset: AVURLAsset(url: url)) - case let .asset(asset): - switch asset.mediaType { - case .image: - if asset.mediaSubtypes.contains(.photoLive) { - showLivePhoto(asset) - } else { - showAssetImage(asset) - } - case .video: - showAssetVideo(asset) - default: - fatalError("asset mediaType must be image or video") + switch asset.mediaType { + case .image: + if asset.mediaSubtypes.contains(.photoLive) { + showLivePhoto(asset) + } else { + showAssetImage(asset) } - case let .drawing(drawing): - let image = drawing.imageInLightMode(from: drawing.bounds) - showImage(image) + case .video: + showAssetVideo(asset) + default: + fatalError("asset mediaType must be image or video") } } diff --git a/Tusker/Screens/Compose/ComposeAttachmentImage.swift b/Tusker/Screens/Compose/ComposeAttachmentImage.swift index 5a7a04060f..c7dae3b4e3 100644 --- a/Tusker/Screens/Compose/ComposeAttachmentImage.swift +++ b/Tusker/Screens/Compose/ComposeAttachmentImage.swift @@ -69,6 +69,10 @@ struct ComposeAttachmentImage: View { image = drawing.imageInLightMode(from: drawing.bounds) imageContentMode = .fit imageBackgroundColor = .white + case let .gif(data): + if let image = UIImage(data: data) { + self.image = image + } } } }