Fix GIFs dragged from Finder posting as static images

Closes #239
This commit is contained in:
Shadowfacts 2022-11-13 13:46:19 -05:00
parent f848bbf7c4
commit b9bdd29986
4 changed files with 34 additions and 34 deletions

View File

@ -56,6 +56,7 @@ private let imageType = UTType.image.identifier
private let mp4Type = UTType.mpeg4Movie.identifier private let mp4Type = UTType.mpeg4Movie.identifier
private let quickTimeType = UTType.quickTimeMovie.identifier private let quickTimeType = UTType.quickTimeMovie.identifier
private let dataType = UTType.data.identifier private let dataType = UTType.data.identifier
private let gifType = UTType.gif.identifier
extension CompositionAttachment: NSItemProviderWriting { extension CompositionAttachment: NSItemProviderWriting {
static var writableTypeIdentifiersForItemProvider: [String] { static var writableTypeIdentifiersForItemProvider: [String] {
@ -95,20 +96,22 @@ extension CompositionAttachment: NSItemProviderReading {
[typeIdentifier] + UIImage.readableTypeIdentifiersForItemProvider + [mp4Type, quickTimeType] + NSURL.readableTypeIdentifiersForItemProvider [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 { 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) { } 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 { } else if let type = UTType(typeIdentifier), type == .mpeg4Movie || type == .quickTimeMovie {
let temporaryDirectoryURL = URL(fileURLWithPath: NSTemporaryDirectory(), isDirectory: true) let temporaryDirectoryURL = URL(fileURLWithPath: NSTemporaryDirectory(), isDirectory: true)
let temporaryFileName = ProcessInfo().globallyUniqueString let temporaryFileName = ProcessInfo().globallyUniqueString
let fileExt = type.preferredFilenameExtension! let fileExt = type.preferredFilenameExtension!
let temporaryFileURL = temporaryDirectoryURL.appendingPathComponent(temporaryFileName).appendingPathExtension(fileExt) let temporaryFileURL = temporaryDirectoryURL.appendingPathComponent(temporaryFileName).appendingPathExtension(fileExt)
try data.write(to: temporaryFileURL) 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 { } 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 { } else {
throw ItemProviderError.incompatibleTypeIdentifier throw ItemProviderError.incompatibleTypeIdentifier
} }

View File

@ -16,6 +16,7 @@ enum CompositionAttachmentData {
case image(UIImage) case image(UIImage)
case video(URL) case video(URL)
case drawing(PKDrawing) case drawing(PKDrawing)
case gif(Data)
var type: AttachmentType { var type: AttachmentType {
switch self { switch self {
@ -27,6 +28,8 @@ enum CompositionAttachmentData {
return .video return .video
case .drawing(_): case .drawing(_):
return .image return .image
case .gif(_):
return .image
} }
} }
@ -119,6 +122,8 @@ enum CompositionAttachmentData {
case let .drawing(drawing): case let .drawing(drawing):
let image = drawing.imageInLightMode(from: drawing.bounds, scale: 1) let image = drawing.imageInLightMode(from: drawing.bounds, scale: 1)
completion(.success((image.pngData()!, .png))) 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) try container.encode("drawing", forKey: .type)
let drawingData = drawing.dataRepresentation() let drawingData = drawing.dataRepresentation()
try container.encode(drawingData, forKey: .drawing) 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) let drawing = try PKDrawing(data: drawingData)
self = .drawing(drawing) self = .drawing(drawing)
default: 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")
} }
} }

View File

@ -13,18 +13,14 @@ import AVKit
class AssetPreviewViewController: UIViewController { class AssetPreviewViewController: UIViewController {
let attachment: CompositionAttachmentData let asset: PHAsset
init(attachment: CompositionAttachmentData) { init(asset: PHAsset) {
self.attachment = attachment self.asset = asset
super.init(nibName: nil, bundle: nil) super.init(nibName: nil, bundle: nil)
} }
convenience init(asset: PHAsset) {
self.init(attachment: .asset(asset))
}
required init?(coder: NSCoder) { required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented") fatalError("init(coder:) has not been implemented")
} }
@ -34,27 +30,17 @@ class AssetPreviewViewController: UIViewController {
view.backgroundColor = .black view.backgroundColor = .black
switch attachment { switch asset.mediaType {
case let .image(image): case .image:
showImage(image) if asset.mediaSubtypes.contains(.photoLive) {
case let .video(url): showLivePhoto(asset)
showVideo(asset: AVURLAsset(url: url)) } else {
case let .asset(asset): showAssetImage(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")
} }
case let .drawing(drawing): case .video:
let image = drawing.imageInLightMode(from: drawing.bounds) showAssetVideo(asset)
showImage(image) default:
fatalError("asset mediaType must be image or video")
} }
} }

View File

@ -69,6 +69,10 @@ struct ComposeAttachmentImage: View {
image = drawing.imageInLightMode(from: drawing.bounds) image = drawing.imageInLightMode(from: drawing.bounds)
imageContentMode = .fit imageContentMode = .fit
imageBackgroundColor = .white imageBackgroundColor = .white
case let .gif(data):
if let image = UIImage(data: data) {
self.image = image
}
} }
} }
} }