123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227 |
- import Foundation
- import MobileCoreServices
- import DcCore
- import UIKit
- import QuickLookThumbnailing
- import SDWebImage
- protocol ShareAttachmentDelegate: class {
- func onAttachmentChanged()
- func onThumbnailChanged()
- func onUrlShared(url: URL)
- }
- class ShareAttachment {
- weak var delegate: ShareAttachmentDelegate?
- let dcContext: DcContext
- let thumbnailSize = CGFloat(96)
- var inputItems: [Any]?
- var messages: [DcMsg] = []
- private var imageThumbnail: UIImage?
- private var attachmentThumbnail: UIImage?
- var thumbnail: UIImage? {
- return self.imageThumbnail ?? self.attachmentThumbnail
- }
- var isEmpty: Bool {
- return messages.isEmpty
- }
- init(dcContext: DcContext, inputItems: [Any]?, delegate: ShareAttachmentDelegate) {
- self.dcContext = dcContext
- self.inputItems = inputItems
- self.delegate = delegate
- createMessages()
- }
- private func createMessages() {
- guard let items = inputItems as? [NSExtensionItem] else { return }
- for item in items {
- if let attachments = item.attachments {
- createMessageFromDataRepresentaion(attachments)
- }
- }
- }
- private func createMessageFromDataRepresentaion(_ attachments: [NSItemProvider]) {
- for attachment in attachments {
- if attachment.hasItemConformingToTypeIdentifier(kUTTypeGIF as String) {
- createAnimatedImageMsg(attachment)
- } else if attachment.hasItemConformingToTypeIdentifier(kUTTypeImage as String) {
- createImageMsg(attachment)
- } else if attachment.hasItemConformingToTypeIdentifier(kUTTypeMovie as String) {
- createMovieMsg(attachment)
- } else if attachment.hasItemConformingToTypeIdentifier(kUTTypeAudio as String) {
- createAudioMsg(attachment)
- } else if attachment.hasItemConformingToTypeIdentifier(kUTTypeFileURL as String) {
- createFileMsg(attachment)
- } else if attachment.hasItemConformingToTypeIdentifier(kUTTypeURL as String) {
- addSharedUrl(attachment)
- }
- }
- }
- // for now we only support GIF
- private func createAnimatedImageMsg(_ item: NSItemProvider) {
- item.loadItem(forTypeIdentifier: kUTTypeGIF as String, options: nil) { data, error in
- var result: SDAnimatedImage?
- switch data {
- case let animatedImageData as Data:
- result = SDAnimatedImage(data: animatedImageData)
- case let url as URL:
- result = SDAnimatedImage(contentsOfFile: url.path)
- default:
- self.dcContext.logger?.debug("Unexpected data: \(type(of: data))")
- }
- if let result = result, let animatedImageData = result.animatedImageData {
- let path = DcUtils.saveImage(data: animatedImageData, suffix: "gif")
- let msg = DcMsg(viewType: DC_MSG_GIF)
- msg.setFile(filepath: path)
- self.messages.append(msg)
- self.delegate?.onAttachmentChanged()
- if self.imageThumbnail == nil {
- self.imageThumbnail = result.scaleDownImage(toMax: self.thumbnailSize)
- self.delegate?.onThumbnailChanged()
- }
- if let error = error {
- self.dcContext.logger?.error("Could not load share item as image: \(error.localizedDescription)")
- }
- }
- }
- }
- private func createImageMsg(_ item: NSItemProvider) {
- item.loadItem(forTypeIdentifier: kUTTypeImage as String, options: nil) { data, error in
- let result: UIImage?
- switch data {
- case let image as UIImage:
- result = image
- case let data as Data:
- result = UIImage(data: data)
- case let url as URL:
- result = UIImage(contentsOfFile: url.path)
- default:
- self.dcContext.logger?.debug("Unexpected data: \(type(of: data))")
- result = nil
- }
- if let result = result {
- let path = DcUtils.saveImage(image: result)
- let msg = DcMsg(viewType: DC_MSG_IMAGE)
- msg.setFile(filepath: path)
- self.messages.append(msg)
- self.delegate?.onAttachmentChanged()
- if self.imageThumbnail == nil {
- self.imageThumbnail = result.scaleDownImage(toMax: self.thumbnailSize)
- self.delegate?.onThumbnailChanged()
- }
- }
- if let error = error {
- self.dcContext.logger?.error("Could not load share item as image: \(error.localizedDescription)")
- }
- }
- }
- private func createMovieMsg(_ item: NSItemProvider) {
- item.loadItem(forTypeIdentifier: kUTTypeMovie as String, options: nil) { data, error in
- switch data {
- case let url as URL:
- self.addDcMsg(url: url, viewType: DC_MSG_VIDEO)
- self.delegate?.onAttachmentChanged()
- if self.imageThumbnail == nil {
- DispatchQueue.global(qos: .background).async {
- self.imageThumbnail = DcUtils.generateThumbnailFromVideo(url: url)?.scaleDownImage(toMax: self.thumbnailSize)
- DispatchQueue.main.async {
- self.delegate?.onThumbnailChanged()
- }
- }
- }
- default:
- self.dcContext.logger?.debug("Unexpected data: \(type(of: data))")
- }
- if let error = error {
- self.dcContext.logger?.error("Could not load share item as video: \(error.localizedDescription)")
- }
- }
- }
- private func createAudioMsg(_ item: NSItemProvider) {
- createMessageFromItemURL(item: item, typeIdentifier: kUTTypeAudio, viewType: DC_MSG_AUDIO)
- }
- private func createFileMsg(_ item: NSItemProvider) {
- createMessageFromItemURL(item: item, typeIdentifier: kUTTypeFileURL, viewType: DC_MSG_FILE)
- }
- private func createMessageFromItemURL(item: NSItemProvider, typeIdentifier: CFString, viewType: Int32) {
- item.loadItem(forTypeIdentifier: typeIdentifier as String, options: nil) { data, error in
- switch data {
- case let url as URL:
- self.addDcMsg(url: url, viewType: viewType)
- self.delegate?.onAttachmentChanged()
- if self.imageThumbnail == nil {
- self.generateThumbnailRepresentations(url: url)
- }
- default:
- self.dcContext.logger?.debug("Unexpected data: \(type(of: data))")
- }
- if let error = error {
- self.dcContext.logger?.error("Could not load share item: \(error.localizedDescription)")
- }
- }
- }
- private func addDcMsg(url: URL, viewType: Int32) {
- let msg = DcMsg(viewType: viewType)
- msg.setFile(filepath: url.relativePath)
- self.messages.append(msg)
- }
- private func generateThumbnailRepresentations(url: URL) {
- let size: CGSize = CGSize(width: self.thumbnailSize * 2 / 3, height: self.thumbnailSize)
- let scale = UIScreen.main.scale
- if #available(iOSApplicationExtension 13.0, *) {
- let request = QLThumbnailGenerator.Request(fileAt: url,
- size: size,
- scale: scale,
- representationTypes: .all)
- let generator = QLThumbnailGenerator.shared
- generator.generateRepresentations(for: request) { (thumbnail, _, error) in
- DispatchQueue.main.async {
- if thumbnail == nil || error != nil {
- self.dcContext.logger?.warning(error?.localizedDescription ?? "Could not create thumbnail.")
- } else {
- self.attachmentThumbnail = thumbnail?.uiImage
- self.delegate?.onThumbnailChanged()
- }
- }
- }
- } else {
- let controller = UIDocumentInteractionController(url: url)
- self.attachmentThumbnail = controller.icons.first
- self.delegate?.onThumbnailChanged()
- }
- }
- private func addSharedUrl(_ item: NSItemProvider) {
- if let delegate = self.delegate {
- item.loadItem(forTypeIdentifier: kUTTypeURL as String, options: nil) { data, error in
- switch data {
- case let url as URL:
- delegate.onUrlShared(url: url)
- default:
- self.dcContext.logger?.debug("Unexpected data: \(type(of: data))")
- }
- if let error = error {
- self.dcContext.logger?.error("Could not share URL: \(error.localizedDescription)")
- }
- }
- }
- }
- }
|