// // CompositionAttachment.swift // Tusker // // Created by Shadowfacts on 3/14/20. // Copyright © 2020 Shadowfacts. All rights reserved. // import Foundation import UIKit import MobileCoreServices final class CompositionAttachment: NSObject, Codable { static let typeIdentifier = "space.vaccor.Tusker.composition-attachment" let data: CompositionAttachmentData var attachmentDescription: String init(data: CompositionAttachmentData, description: String = "") { self.data = data self.attachmentDescription = description } static func ==(lhs: CompositionAttachment, rhs: CompositionAttachment) -> Bool { return lhs.data == rhs.data } } private let imageType = kUTTypeImage as String private let mp4Type = kUTTypeMPEG4 as String private let quickTimeType = kUTTypeQuickTimeMovie as String private let dataType = kUTTypeData as String extension CompositionAttachment: NSItemProviderWriting { static var writableTypeIdentifiersForItemProvider: [String] { [typeIdentifier] } func loadData(withTypeIdentifier typeIdentifier: String, forItemProviderCompletionHandler completionHandler: @escaping (Data?, Error?) -> Void) -> Progress? { if typeIdentifier == CompositionAttachment.typeIdentifier { do { completionHandler(try PropertyListEncoder().encode(self), nil) } catch { completionHandler(nil, error) } } completionHandler(nil, ItemProviderError.incompatibleTypeIdentifier) return nil } enum ItemProviderError: Error { case incompatibleTypeIdentifier var localizedDescription: String { switch self { case .incompatibleTypeIdentifier: return "Cannot provide data for given type" } } } } extension CompositionAttachment: NSItemProviderReading { static var readableTypeIdentifiersForItemProvider: [String] { // todo: is there a better way of handling movies than manually adding all possible UTI types? // just using kUTTypeMovie doesn't work, because we need the actually type in order to get the file extension // without the file extension, getting the thumbnail and exporting the video for attachment upload fails [typeIdentifier] + UIImage.readableTypeIdentifiersForItemProvider + [mp4Type, quickTimeType] + NSURL.readableTypeIdentifiersForItemProvider } static func object(withItemProviderData data: Data, typeIdentifier: String) throws -> Self { if typeIdentifier == CompositionAttachment.typeIdentifier { return try PropertyListDecoder().decode(Self.self, from: data) } else if UIImage.readableTypeIdentifiersForItemProvider.contains(typeIdentifier), let image = try? UIImage.object(withItemProviderData: data, typeIdentifier: typeIdentifier) { return CompositionAttachment(data: .image(image)) as! Self } else if typeIdentifier == mp4Type || typeIdentifier == quickTimeType { let temporaryDirectoryURL = URL(fileURLWithPath: NSTemporaryDirectory(), isDirectory: true) let temporaryFileName = ProcessInfo().globallyUniqueString let fileExt = UTTypeCopyPreferredTagWithClass(typeIdentifier as CFString, kUTTagClassFilenameExtension)! let temporaryFileURL = temporaryDirectoryURL.appendingPathComponent(temporaryFileName).appendingPathExtension(fileExt.takeUnretainedValue() as String) try data.write(to: temporaryFileURL) return CompositionAttachment(data: .video(temporaryFileURL)) as! Self } else if NSURL.readableTypeIdentifiersForItemProvider.contains(typeIdentifier), let url = try? NSURL.object(withItemProviderData: data, typeIdentifier: typeIdentifier) as URL { return CompositionAttachment(data: .video(url)) as! Self } else { throw ItemProviderError.incompatibleTypeIdentifier } } }