forked from shadowfacts/Tusker
Support dragging and dropping attachments in the compose view controller
Allos dragging in attachments from other apps and drag/dropping with the compose VC to reorder attachments
This commit is contained in:
parent
7117ce6320
commit
1ccb450477
|
@ -2,6 +2,17 @@
|
||||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||||
<plist version="1.0">
|
<plist version="1.0">
|
||||||
<dict>
|
<dict>
|
||||||
|
<key>UTExportedTypeDeclarations</key>
|
||||||
|
<array>
|
||||||
|
<dict>
|
||||||
|
<key>UTTypeConformsTo</key>
|
||||||
|
<array/>
|
||||||
|
<key>UTTypeIdentifier</key>
|
||||||
|
<string>space.vaccor.Tusker.composition-attachment</string>
|
||||||
|
<key>UTTypeTagSpecification</key>
|
||||||
|
<dict/>
|
||||||
|
</dict>
|
||||||
|
</array>
|
||||||
<key>CFBundleDevelopmentRegion</key>
|
<key>CFBundleDevelopmentRegion</key>
|
||||||
<string>$(DEVELOPMENT_LANGUAGE)</string>
|
<string>$(DEVELOPMENT_LANGUAGE)</string>
|
||||||
<key>CFBundleExecutable</key>
|
<key>CFBundleExecutable</key>
|
||||||
|
@ -49,7 +60,7 @@
|
||||||
<key>NSMicrophoneUsageDescription</key>
|
<key>NSMicrophoneUsageDescription</key>
|
||||||
<string>Post videos from the camera.</string>
|
<string>Post videos from the camera.</string>
|
||||||
<key>NSPhotoLibraryAddUsageDescription</key>
|
<key>NSPhotoLibraryAddUsageDescription</key>
|
||||||
<string>Save photos directly from other people's posts.</string>
|
<string>Save photos directly from other people's posts.</string>
|
||||||
<key>NSPhotoLibraryUsageDescription</key>
|
<key>NSPhotoLibraryUsageDescription</key>
|
||||||
<string>Post photos from the photo library.</string>
|
<string>Post photos from the photo library.</string>
|
||||||
<key>NSUserActivityTypes</key>
|
<key>NSUserActivityTypes</key>
|
||||||
|
|
|
@ -23,6 +23,7 @@ class ComposeAttachmentTableViewCell: UITableViewCell {
|
||||||
@IBOutlet weak var assetImageView: UIImageView!
|
@IBOutlet weak var assetImageView: UIImageView!
|
||||||
@IBOutlet weak var descriptionTextView: UITextView!
|
@IBOutlet weak var descriptionTextView: UITextView!
|
||||||
@IBOutlet weak var descriptionPlaceholderLabel: UILabel!
|
@IBOutlet weak var descriptionPlaceholderLabel: UILabel!
|
||||||
|
@IBOutlet weak var removeButton: UIButton!
|
||||||
|
|
||||||
var attachment: CompositionAttachment!
|
var attachment: CompositionAttachment!
|
||||||
|
|
||||||
|
@ -38,7 +39,7 @@ class ComposeAttachmentTableViewCell: UITableViewCell {
|
||||||
func updateUI(for attachment: CompositionAttachment) {
|
func updateUI(for attachment: CompositionAttachment) {
|
||||||
self.attachment = attachment
|
self.attachment = attachment
|
||||||
|
|
||||||
descriptionTextView.text = attachment.description
|
descriptionTextView.text = attachment.attachmentDescription
|
||||||
updateDescriptionPlaceholderLabel()
|
updateDescriptionPlaceholderLabel()
|
||||||
|
|
||||||
switch attachment.data {
|
switch attachment.data {
|
||||||
|
@ -63,6 +64,16 @@ class ComposeAttachmentTableViewCell: UITableViewCell {
|
||||||
descriptionPlaceholderLabel.isHidden = !descriptionTextView.text.isEmpty
|
descriptionPlaceholderLabel.isHidden = !descriptionTextView.text.isEmpty
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func setEnabled(_ enabled: Bool) {
|
||||||
|
descriptionTextView.isEditable = enabled
|
||||||
|
removeButton.isEnabled = enabled
|
||||||
|
}
|
||||||
|
|
||||||
|
override func prepareForReuse() {
|
||||||
|
super.prepareForReuse()
|
||||||
|
assetImageView.image = nil
|
||||||
|
}
|
||||||
|
|
||||||
@IBAction func removeButtonPressed(_ sender: Any) {
|
@IBAction func removeButtonPressed(_ sender: Any) {
|
||||||
delegate?.removeAttachment(self)
|
delegate?.removeAttachment(self)
|
||||||
}
|
}
|
||||||
|
@ -72,7 +83,7 @@ class ComposeAttachmentTableViewCell: UITableViewCell {
|
||||||
extension ComposeAttachmentTableViewCell: UITextViewDelegate {
|
extension ComposeAttachmentTableViewCell: UITextViewDelegate {
|
||||||
func textViewDidChange(_ textView: UITextView) {
|
func textViewDidChange(_ textView: UITextView) {
|
||||||
delegate?.attachmentDescriptionChanged(self)
|
delegate?.attachmentDescriptionChanged(self)
|
||||||
attachment.description = textView.text
|
attachment.attachmentDescription = textView.text
|
||||||
updateDescriptionPlaceholderLabel()
|
updateDescriptionPlaceholderLabel()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,6 +27,7 @@
|
||||||
<subviews>
|
<subviews>
|
||||||
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="GLY-o8-47z">
|
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="GLY-o8-47z">
|
||||||
<rect key="frame" x="0.0" y="0.0" width="80" height="80"/>
|
<rect key="frame" x="0.0" y="0.0" width="80" height="80"/>
|
||||||
|
<color key="backgroundColor" systemColor="secondarySystemBackgroundColor" red="0.94901960780000005" green="0.94901960780000005" blue="0.96862745100000003" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||||
<constraints>
|
<constraints>
|
||||||
<constraint firstAttribute="width" constant="80" id="X6q-g9-dPN"/>
|
<constraint firstAttribute="width" constant="80" id="X6q-g9-dPN"/>
|
||||||
<constraint firstAttribute="height" constant="80" id="xgQ-E3-0QI"/>
|
<constraint firstAttribute="height" constant="80" id="xgQ-E3-0QI"/>
|
||||||
|
@ -72,6 +73,7 @@
|
||||||
<outlet property="assetImageView" destination="GLY-o8-47z" id="hZH-ur-m4z"/>
|
<outlet property="assetImageView" destination="GLY-o8-47z" id="hZH-ur-m4z"/>
|
||||||
<outlet property="descriptionPlaceholderLabel" destination="h6T-x4-yzl" id="jBe-R0-Sfn"/>
|
<outlet property="descriptionPlaceholderLabel" destination="h6T-x4-yzl" id="jBe-R0-Sfn"/>
|
||||||
<outlet property="descriptionTextView" destination="cwP-Eh-5dJ" id="pxJ-zF-GKC"/>
|
<outlet property="descriptionTextView" destination="cwP-Eh-5dJ" id="pxJ-zF-GKC"/>
|
||||||
|
<outlet property="removeButton" destination="Lvf-I9-aV3" id="3qk-Zr-je1"/>
|
||||||
</connections>
|
</connections>
|
||||||
<point key="canvasLocation" x="107" y="181"/>
|
<point key="canvasLocation" x="107" y="181"/>
|
||||||
</tableViewCell>
|
</tableViewCell>
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
|
|
||||||
import UIKit
|
import UIKit
|
||||||
import Pachyderm
|
import Pachyderm
|
||||||
|
import MobileCoreServices
|
||||||
|
|
||||||
protocol ComposeAttachmentsViewControllerDelegate: class {
|
protocol ComposeAttachmentsViewControllerDelegate: class {
|
||||||
func composeSelectedAttachmentsDidChange()
|
func composeSelectedAttachmentsDidChange()
|
||||||
|
@ -55,10 +56,20 @@ class ComposeAttachmentsViewController: UITableViewController {
|
||||||
tableView.register(UINib(nibName: "AddAttachmentTableViewCell", bundle: .main), forCellReuseIdentifier: "addAttachment")
|
tableView.register(UINib(nibName: "AddAttachmentTableViewCell", bundle: .main), forCellReuseIdentifier: "addAttachment")
|
||||||
tableView.register(UINib(nibName: "ComposeAttachmentTableViewCell", bundle: .main), forCellReuseIdentifier: "composeAttachment")
|
tableView.register(UINib(nibName: "ComposeAttachmentTableViewCell", bundle: .main), forCellReuseIdentifier: "composeAttachment")
|
||||||
|
|
||||||
heightConstraint = tableView.heightAnchor.constraint(equalToConstant: tableView.contentSize.height)
|
// you would think the table view could handle this itself, but no, using a constraint on the table view's contentLayoutGuide doesn't work
|
||||||
|
// add extra space, so when dropping items, the add attachment cell doesn't disappear
|
||||||
|
heightConstraint = tableView.heightAnchor.constraint(equalToConstant: tableView.contentSize.height + 80)
|
||||||
heightConstraint.isActive = true
|
heightConstraint.isActive = true
|
||||||
|
|
||||||
pasteConfiguration = UIPasteConfiguration(forAccepting: UIImage.self)
|
// prevents extra separator lines from appearing when the height of the table view is greater than the height of the content
|
||||||
|
tableView.tableFooterView = UIView()
|
||||||
|
|
||||||
|
pasteConfiguration = UIPasteConfiguration(forAccepting: CompositionAttachment.self)
|
||||||
|
|
||||||
|
// enable dragging on iPhone to allow reordering
|
||||||
|
tableView.dragInteractionEnabled = true
|
||||||
|
tableView.dragDelegate = self
|
||||||
|
tableView.dropDelegate = self
|
||||||
}
|
}
|
||||||
|
|
||||||
override func viewWillAppear(_ animated: Bool) {
|
override func viewWillAppear(_ animated: Bool) {
|
||||||
|
@ -77,7 +88,8 @@ class ComposeAttachmentsViewController: UITableViewController {
|
||||||
}
|
}
|
||||||
|
|
||||||
private func updateHeightConstraint() {
|
private func updateHeightConstraint() {
|
||||||
heightConstraint.constant = tableView.contentSize.height
|
// add extra space, so when dropping items, the add attachment cell doesn't disappear
|
||||||
|
heightConstraint.constant = tableView.contentSize.height + 80
|
||||||
}
|
}
|
||||||
|
|
||||||
private func isAddAttachmentsButtonEnabled() -> Bool {
|
private func isAddAttachmentsButtonEnabled() -> Bool {
|
||||||
|
@ -90,7 +102,7 @@ class ComposeAttachmentsViewController: UITableViewController {
|
||||||
}
|
}
|
||||||
|
|
||||||
private func updateAddAttachmentsButtonEnabled() {
|
private func updateAddAttachmentsButtonEnabled() {
|
||||||
let cell = tableView.cellForRow(at: IndexPath(row: 0, section: 1)) as! AddAttachmentTableViewCell
|
guard let cell = tableView.cellForRow(at: IndexPath(row: 0, section: 1)) as? AddAttachmentTableViewCell else { return }
|
||||||
cell.setEnabled(isAddAttachmentsButtonEnabled())
|
cell.setEnabled(isAddAttachmentsButtonEnabled())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -105,16 +117,15 @@ class ComposeAttachmentsViewController: UITableViewController {
|
||||||
|
|
||||||
override func paste(itemProviders: [NSItemProvider]) {
|
override func paste(itemProviders: [NSItemProvider]) {
|
||||||
for provider in itemProviders {
|
for provider in itemProviders {
|
||||||
provider.loadObject(ofClass: UIImage.self) { (object, error) in
|
provider.loadObject(ofClass: CompositionAttachment.self) { (object, error) in
|
||||||
if let error = error {
|
if let error = error {
|
||||||
fatalError("Couldn't load image from NSItemProvider: \(error)")
|
fatalError("Couldn't load image from NSItemProvider: \(error)")
|
||||||
}
|
}
|
||||||
guard let image = object as? UIImage else {
|
guard let attachment = object as? CompositionAttachment else {
|
||||||
fatalError("Couldn't convert object from NSItemProvider to UIImage")
|
fatalError("Couldn't convert object from NSItemProvider to CompositionAttachment")
|
||||||
}
|
}
|
||||||
|
|
||||||
DispatchQueue.main.async {
|
DispatchQueue.main.async {
|
||||||
let attachment = CompositionAttachment(data: .image(image))
|
|
||||||
self.attachments.append(attachment)
|
self.attachments.append(attachment)
|
||||||
self.tableView.insertRows(at: [IndexPath(row: self.attachments.count - 1, section: 0)], with: .automatic)
|
self.tableView.insertRows(at: [IndexPath(row: self.attachments.count - 1, section: 0)], with: .automatic)
|
||||||
self.updateHeightConstraint()
|
self.updateHeightConstraint()
|
||||||
|
@ -219,6 +230,7 @@ class ComposeAttachmentsViewController: UITableViewController {
|
||||||
let cell = tableView.dequeueReusableCell(withIdentifier: "composeAttachment", for: indexPath) as! ComposeAttachmentTableViewCell
|
let cell = tableView.dequeueReusableCell(withIdentifier: "composeAttachment", for: indexPath) as! ComposeAttachmentTableViewCell
|
||||||
cell.delegate = self
|
cell.delegate = self
|
||||||
cell.updateUI(for: attachment)
|
cell.updateUI(for: attachment)
|
||||||
|
cell.setEnabled(true)
|
||||||
return cell
|
return cell
|
||||||
case 1:
|
case 1:
|
||||||
let cell = tableView.dequeueReusableCell(withIdentifier: "addAttachment", for: indexPath) as! AddAttachmentTableViewCell
|
let cell = tableView.dequeueReusableCell(withIdentifier: "addAttachment", for: indexPath) as! AddAttachmentTableViewCell
|
||||||
|
@ -229,6 +241,12 @@ class ComposeAttachmentsViewController: UITableViewController {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override func tableView(_ tableView: UITableView, moveRowAt sourceIndexPath: IndexPath, to destinationIndexPath: IndexPath) {
|
||||||
|
guard sourceIndexPath != destinationIndexPath, sourceIndexPath.section == 0, destinationIndexPath.section == 0 else { return }
|
||||||
|
|
||||||
|
attachments.insert(attachments.remove(at: sourceIndexPath.row), at: destinationIndexPath.row)
|
||||||
|
}
|
||||||
|
|
||||||
// MARK: Table view delegate
|
// MARK: Table view delegate
|
||||||
|
|
||||||
override func tableView(_ tableView: UITableView, willSelectRowAt indexPath: IndexPath) -> IndexPath? {
|
override func tableView(_ tableView: UITableView, willSelectRowAt indexPath: IndexPath) -> IndexPath? {
|
||||||
|
@ -254,6 +272,88 @@ class ComposeAttachmentsViewController: UITableViewController {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extension ComposeAttachmentsViewController: UITableViewDragDelegate {
|
||||||
|
func tableView(_ tableView: UITableView, itemsForBeginning session: UIDragSession, at indexPath: IndexPath) -> [UIDragItem] {
|
||||||
|
let attachment = attachments[indexPath.row]
|
||||||
|
let provider = NSItemProvider(object: attachment)
|
||||||
|
let dragItem = UIDragItem(itemProvider: provider)
|
||||||
|
dragItem.localObject = attachment
|
||||||
|
return [dragItem]
|
||||||
|
}
|
||||||
|
|
||||||
|
func tableView(_ tableView: UITableView, itemsForAddingTo session: UIDragSession, at indexPath: IndexPath, point: CGPoint) -> [UIDragItem] {
|
||||||
|
let attachment = attachments[indexPath.row]
|
||||||
|
let provider = NSItemProvider(object: attachment)
|
||||||
|
let dragItem = UIDragItem(itemProvider: provider)
|
||||||
|
dragItem.localObject = attachment
|
||||||
|
return [dragItem]
|
||||||
|
}
|
||||||
|
|
||||||
|
func tableView(_ tableView: UITableView, dragPreviewParametersForRowAt indexPath: IndexPath) -> UIDragPreviewParameters? {
|
||||||
|
let cell = tableView.cellForRow(at: indexPath) as! ComposeAttachmentTableViewCell
|
||||||
|
let rect = cell.convert(cell.assetImageView.bounds, from: cell.assetImageView)
|
||||||
|
let path = UIBezierPath(roundedRect: rect, cornerRadius: cell.assetImageView.layer.cornerRadius)
|
||||||
|
let params = UIDragPreviewParameters()
|
||||||
|
params.visiblePath = path
|
||||||
|
return params
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extension ComposeAttachmentsViewController: UITableViewDropDelegate {
|
||||||
|
func tableView(_ tableView: UITableView, canHandle session: UIDropSession) -> Bool {
|
||||||
|
return session.canLoadObjects(ofClass: CompositionAttachment.self)
|
||||||
|
}
|
||||||
|
|
||||||
|
func tableView(_ tableView: UITableView, dropSessionDidUpdate session: UIDropSession, withDestinationIndexPath destinationIndexPath: IndexPath?) -> UITableViewDropProposal {
|
||||||
|
// if items were dragged out of ourself, then the items are only being moved
|
||||||
|
if tableView.hasActiveDrag {
|
||||||
|
// todo: should moving multiple items actually be prohibited?
|
||||||
|
if session.items.count > 1 {
|
||||||
|
return UITableViewDropProposal(operation: .cancel)
|
||||||
|
} else {
|
||||||
|
return UITableViewDropProposal(operation: .move, intent: .insertAtDestinationIndexPath)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return UITableViewDropProposal(operation: .copy, intent: .insertAtDestinationIndexPath)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func tableView(_ tableView: UITableView, performDropWith coordinator: UITableViewDropCoordinator) {
|
||||||
|
let destinationIndexPath = coordinator.destinationIndexPath ?? IndexPath(row: attachments.count, section: 0)
|
||||||
|
|
||||||
|
// we don't need to handle local items here, when the .move operation is used returned from the tableView(_:dropSessionDidUpdate:withDestinationIndexPath:) method,
|
||||||
|
// the table view will handle animating and call the normal data source tableView(_:moveRowAt:to:)
|
||||||
|
|
||||||
|
for (index, item) in coordinator.items.enumerated() {
|
||||||
|
let provider = item.dragItem.itemProvider
|
||||||
|
|
||||||
|
if provider.canLoadObject(ofClass: CompositionAttachment.self) {
|
||||||
|
let indexPath = IndexPath(row: destinationIndexPath.row + index, section: 0)
|
||||||
|
let placeholder = UITableViewDropPlaceholder(insertionIndexPath: indexPath, reuseIdentifier: "composeAttachment", rowHeight: 96)
|
||||||
|
placeholder.cellUpdateHandler = { (cell) in
|
||||||
|
let cell = cell as! ComposeAttachmentTableViewCell
|
||||||
|
cell.setEnabled(false)
|
||||||
|
}
|
||||||
|
let placeholderContext = coordinator.drop(item.dragItem, to: placeholder)
|
||||||
|
|
||||||
|
provider.loadObject(ofClass: CompositionAttachment.self) { (object, error) in
|
||||||
|
DispatchQueue.main.async {
|
||||||
|
if let attachment = object as? CompositionAttachment {
|
||||||
|
placeholderContext.commitInsertion { (insertionIndexPath) in
|
||||||
|
self.attachments.insert(attachment, at: insertionIndexPath.row)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
placeholderContext.deletePlaceholder()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
updateHeightConstraint()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
extension ComposeAttachmentsViewController: AssetPickerViewControllerDelegate {
|
extension ComposeAttachmentsViewController: AssetPickerViewControllerDelegate {
|
||||||
func assetPicker(_ assetPicker: AssetPickerViewController, shouldAllowAssetOfType type: CompositionAttachmentData.AttachmentType) -> Bool {
|
func assetPicker(_ assetPicker: AssetPickerViewController, shouldAllowAssetOfType type: CompositionAttachmentData.AttachmentType) -> Bool {
|
||||||
switch mastodonController.instance.instanceType {
|
switch mastodonController.instance.instanceType {
|
||||||
|
|
|
@ -7,19 +7,72 @@
|
||||||
//
|
//
|
||||||
|
|
||||||
import Foundation
|
import Foundation
|
||||||
|
import UIKit
|
||||||
|
import MobileCoreServices
|
||||||
|
|
||||||
|
final class CompositionAttachment: NSObject, Codable {
|
||||||
|
static let typeIdentifier = "space.vaccor.Tusker.composition-attachment"
|
||||||
|
|
||||||
class CompositionAttachment: Codable {
|
|
||||||
let data: CompositionAttachmentData
|
let data: CompositionAttachmentData
|
||||||
var description: String
|
var attachmentDescription: String
|
||||||
|
|
||||||
init(data: CompositionAttachmentData, description: String = "") {
|
init(data: CompositionAttachmentData, description: String = "") {
|
||||||
self.data = data
|
self.data = data
|
||||||
self.description = description
|
self.attachmentDescription = description
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
extension CompositionAttachment: Equatable {
|
|
||||||
static func ==(lhs: CompositionAttachment, rhs: CompositionAttachment) -> Bool {
|
static func ==(lhs: CompositionAttachment, rhs: CompositionAttachment) -> Bool {
|
||||||
return lhs.data == rhs.data
|
return lhs.data == rhs.data
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private let imageType = kUTTypeImage 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] {
|
||||||
|
[typeIdentifier] + UIImage.readableTypeIdentifiersForItemProvider + 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 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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue