mastodon-ios/MastodonSDK/Sources/MastodonUI/Scene/ComposeContent/Attachment/AttachmentViewModel+DragAnd...

145 lines
5.0 KiB
Swift
Raw Normal View History

//
// AttachmentViewModel+DragAndDrop.swift
//
//
// Created by MainasuK on 2022/11/8.
//
import os.log
import UIKit
import Combine
import UniformTypeIdentifiers
// MARK: - TypeIdentifiedItemProvider
extension AttachmentViewModel: TypeIdentifiedItemProvider {
public static var typeIdentifier: String {
// must in UTI format
// https://developer.apple.com/library/archive/qa/qa1796/_index.html
return "org.joinmastodon.app.AttachmentViewModel"
}
}
// MARK: - NSItemProviderWriting
extension AttachmentViewModel: NSItemProviderWriting {
/// Attachment uniform type idendifiers
///
/// The latest one for in-app drag and drop.
/// And use generic `image` and `movie` type to
/// allows transformable media in different formats
public static var writableTypeIdentifiersForItemProvider: [String] {
return [
UTType.image.identifier,
UTType.movie.identifier,
AttachmentViewModel.typeIdentifier,
]
}
public var writableTypeIdentifiersForItemProvider: [String] {
// should append elements in priority order from high to low
var typeIdentifiers: [String] = []
// FIXME: check jpg or png
switch input {
case .image:
typeIdentifiers.append(UTType.png.identifier)
case .url(let url):
let _uti = UTType(filenameExtension: url.pathExtension)
if let uti = _uti {
if uti.conforms(to: .image) {
typeIdentifiers.append(UTType.png.identifier)
} else if uti.conforms(to: .movie) {
typeIdentifiers.append(UTType.mpeg4Movie.identifier)
}
}
case .pickerResult(let item):
if item.itemProvider.isImage() {
typeIdentifiers.append(UTType.png.identifier)
} else if item.itemProvider.isMovie() {
typeIdentifiers.append(UTType.mpeg4Movie.identifier)
}
case .itemProvider(let itemProvider):
if itemProvider.isImage() {
typeIdentifiers.append(UTType.png.identifier)
} else if itemProvider.isMovie() {
typeIdentifiers.append(UTType.mpeg4Movie.identifier)
}
}
typeIdentifiers.append(AttachmentViewModel.typeIdentifier)
return typeIdentifiers
}
public func loadData(
withTypeIdentifier typeIdentifier: String,
forItemProviderCompletionHandler completionHandler: @escaping (Data?, Error?) -> Void
) -> Progress? {
switch typeIdentifier {
case AttachmentViewModel.typeIdentifier:
do {
let archiver = NSKeyedArchiver(requiringSecureCoding: false)
try archiver.encodeEncodable(id, forKey: NSKeyedArchiveRootObjectKey)
archiver.finishEncoding()
let data = archiver.encodedData
completionHandler(data, nil)
} catch {
assertionFailure()
completionHandler(nil, nil)
}
default:
break
}
let loadingProgress = Progress(totalUnitCount: 100)
Publishers.CombineLatest(
$output,
$error
)
.sink { [weak self] output, error in
guard let self = self else { return }
// continue when load completed
guard output != nil || error != nil else { return }
switch output {
case .image(let data, _):
switch typeIdentifier {
case UTType.png.identifier:
loadingProgress.completedUnitCount = 100
completionHandler(data, nil)
default:
completionHandler(nil, nil)
}
case .video(let url, _):
switch typeIdentifier {
case UTType.png.identifier:
let _image = AttachmentViewModel.createThumbnailForVideo(url: url)
let _data = _image?.pngData()
loadingProgress.completedUnitCount = 100
completionHandler(_data, nil)
case UTType.mpeg4Movie.identifier:
let task = URLSession.shared.dataTask(with: url) { data, response, error in
completionHandler(data, error)
}
task.progress.observe(\.fractionCompleted) { progress, change in
loadingProgress.completedUnitCount = Int64(100 * progress.fractionCompleted)
}
.store(in: &self.observations)
task.resume()
default:
completionHandler(nil, nil)
}
case nil:
completionHandler(nil, error)
}
}
.store(in: &disposeBag)
return loadingProgress
}
}