feat: add post video supports for document picker
This commit is contained in:
parent
b9c262c84e
commit
6211663508
|
@ -95,7 +95,7 @@ final class ComposeViewController: UIViewController, NeedsDependency {
|
|||
}()
|
||||
|
||||
private(set) lazy var documentPickerController: UIDocumentPickerViewController = {
|
||||
let documentPickerController = UIDocumentPickerViewController(forOpeningContentTypes: [.image])
|
||||
let documentPickerController = UIDocumentPickerViewController(forOpeningContentTypes: [.image, .movie])
|
||||
documentPickerController.delegate = self
|
||||
return documentPickerController
|
||||
}()
|
||||
|
@ -1102,20 +1102,13 @@ extension ComposeViewController: UIImagePickerControllerDelegate & UINavigationC
|
|||
extension ComposeViewController: UIDocumentPickerDelegate {
|
||||
func documentPicker(_ controller: UIDocumentPickerViewController, didPickDocumentsAt urls: [URL]) {
|
||||
guard let url = urls.first else { return }
|
||||
|
||||
do {
|
||||
guard url.startAccessingSecurityScopedResource() else { return }
|
||||
defer { url.stopAccessingSecurityScopedResource() }
|
||||
let imageData = try Data(contentsOf: url)
|
||||
let attachmentService = MastodonAttachmentService(
|
||||
context: context,
|
||||
imageData: imageData,
|
||||
initalAuthenticationBox: viewModel.activeAuthenticationBox.value
|
||||
)
|
||||
viewModel.attachmentServices.value = viewModel.attachmentServices.value + [attachmentService]
|
||||
} catch {
|
||||
os_log("%{public}s[%{public}ld], %{public}s: %s", ((#file as NSString).lastPathComponent), #line, #function, error.localizedDescription)
|
||||
}
|
||||
|
||||
let attachmentService = MastodonAttachmentService(
|
||||
context: context,
|
||||
documentURL: url,
|
||||
initalAuthenticationBox: viewModel.activeAuthenticationBox.value
|
||||
)
|
||||
viewModel.attachmentServices.value = viewModel.attachmentServices.value + [attachmentService]
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -24,7 +24,7 @@ final class MastodonAttachmentService {
|
|||
weak var delegate: MastodonAttachmentServiceDelegate?
|
||||
|
||||
let identifier = UUID()
|
||||
|
||||
|
||||
// input
|
||||
let context: AppContext
|
||||
var authenticationBox: AuthenticationService.MastodonAuthenticationBox?
|
||||
|
@ -85,6 +85,65 @@ final class MastodonAttachmentService {
|
|||
self.uploadStateMachine.enter(UploadState.Initial.self)
|
||||
}
|
||||
.store(in: &disposeBag)
|
||||
}
|
||||
|
||||
init(
|
||||
context: AppContext,
|
||||
image: UIImage,
|
||||
initalAuthenticationBox: AuthenticationService.MastodonAuthenticationBox?
|
||||
) {
|
||||
self.context = context
|
||||
self.authenticationBox = initalAuthenticationBox
|
||||
// end init
|
||||
|
||||
setupServiceObserver()
|
||||
|
||||
file.value = .jpeg(image.jpegData(compressionQuality: 0.75))
|
||||
uploadStateMachine.enter(UploadState.Initial.self)
|
||||
}
|
||||
|
||||
init(
|
||||
context: AppContext,
|
||||
documentURL: URL,
|
||||
initalAuthenticationBox: AuthenticationService.MastodonAuthenticationBox?
|
||||
) {
|
||||
self.context = context
|
||||
self.authenticationBox = initalAuthenticationBox
|
||||
// end init
|
||||
|
||||
setupServiceObserver()
|
||||
|
||||
Just(documentURL)
|
||||
.flatMap { documentURL -> AnyPublisher<Mastodon.Query.MediaAttachment, Error> in
|
||||
return MastodonAttachmentService.loadAttachment(url: documentURL)
|
||||
}
|
||||
.sink { [weak self] completion in
|
||||
guard let self = self else { return }
|
||||
switch completion {
|
||||
case .failure(let error):
|
||||
self.error.value = error
|
||||
self.uploadStateMachine.enter(UploadState.Fail.self)
|
||||
case .finished:
|
||||
break
|
||||
}
|
||||
} receiveValue: { [weak self] file in
|
||||
guard let self = self else { return }
|
||||
self.file.value = file
|
||||
self.uploadStateMachine.enter(UploadState.Initial.self)
|
||||
}
|
||||
.store(in: &disposeBag)
|
||||
|
||||
uploadStateMachine.enter(UploadState.Initial.self)
|
||||
}
|
||||
|
||||
private func setupServiceObserver() {
|
||||
uploadStateMachineSubject
|
||||
.sink { [weak self] state in
|
||||
guard let self = self else { return }
|
||||
self.delegate?.mastodonAttachmentService(self, uploadStateDidChange: state)
|
||||
}
|
||||
.store(in: &disposeBag)
|
||||
|
||||
|
||||
file
|
||||
.map { file -> UIImage? in
|
||||
|
@ -117,45 +176,6 @@ final class MastodonAttachmentService {
|
|||
.store(in: &disposeBag)
|
||||
}
|
||||
|
||||
init(
|
||||
context: AppContext,
|
||||
image: UIImage,
|
||||
initalAuthenticationBox: AuthenticationService.MastodonAuthenticationBox?
|
||||
) {
|
||||
self.context = context
|
||||
self.authenticationBox = initalAuthenticationBox
|
||||
// end init
|
||||
|
||||
setupServiceObserver()
|
||||
|
||||
file.value = .jpeg(image.jpegData(compressionQuality: 0.75))
|
||||
uploadStateMachine.enter(UploadState.Initial.self)
|
||||
}
|
||||
|
||||
init(
|
||||
context: AppContext,
|
||||
imageData: Data,
|
||||
initalAuthenticationBox: AuthenticationService.MastodonAuthenticationBox?
|
||||
) {
|
||||
self.context = context
|
||||
self.authenticationBox = initalAuthenticationBox
|
||||
// end init
|
||||
|
||||
setupServiceObserver()
|
||||
|
||||
self.file.value = .jpeg(imageData)
|
||||
uploadStateMachine.enter(UploadState.Initial.self)
|
||||
}
|
||||
|
||||
private func setupServiceObserver() {
|
||||
uploadStateMachineSubject
|
||||
.sink { [weak self] state in
|
||||
guard let self = self else { return }
|
||||
self.delegate?.mastodonAttachmentService(self, uploadStateDidChange: state)
|
||||
}
|
||||
.store(in: &disposeBag)
|
||||
}
|
||||
|
||||
deinit {
|
||||
os_log(.info, log: .debug, "%{public}s[%{public}ld], %{public}s", ((#file as NSString).lastPathComponent), #line, #function)
|
||||
}
|
||||
|
@ -189,3 +209,64 @@ extension MastodonAttachmentService: Equatable, Hashable {
|
|||
}
|
||||
|
||||
}
|
||||
|
||||
extension MastodonAttachmentService {
|
||||
|
||||
private static func createWorkingQueue() -> DispatchQueue {
|
||||
return DispatchQueue(label: "org.joinmastodon.Mastodon.MastodonAttachmentService.\(UUID().uuidString)")
|
||||
}
|
||||
|
||||
static func loadAttachment(url: URL) -> AnyPublisher<Mastodon.Query.MediaAttachment, Error> {
|
||||
guard let uti = UTType(filenameExtension: url.pathExtension) else {
|
||||
return Fail(error: AttachmentError.invalidAttachmentType).eraseToAnyPublisher()
|
||||
}
|
||||
|
||||
if uti.conforms(to: .image) {
|
||||
return loadImageAttachment(url: url)
|
||||
} else if uti.conforms(to: .movie) {
|
||||
return loadVideoAttachment(url: url)
|
||||
} else {
|
||||
return Fail(error: AttachmentError.invalidAttachmentType).eraseToAnyPublisher()
|
||||
}
|
||||
}
|
||||
|
||||
static func loadImageAttachment(url: URL) -> AnyPublisher<Mastodon.Query.MediaAttachment, Error> {
|
||||
Future<Mastodon.Query.MediaAttachment, Error> { promise in
|
||||
createWorkingQueue().async {
|
||||
do {
|
||||
guard url.startAccessingSecurityScopedResource() else { return }
|
||||
defer { url.stopAccessingSecurityScopedResource() }
|
||||
let imageData = try Data(contentsOf: url)
|
||||
promise(.success(.jpeg(imageData)))
|
||||
} catch {
|
||||
os_log("%{public}s[%{public}ld], %{public}s: %s", ((#file as NSString).lastPathComponent), #line, #function, error.localizedDescription)
|
||||
promise(.failure(error))
|
||||
}
|
||||
}
|
||||
}
|
||||
.eraseToAnyPublisher()
|
||||
}
|
||||
|
||||
static func loadVideoAttachment(url: URL) -> AnyPublisher<Mastodon.Query.MediaAttachment, Error> {
|
||||
Future<Mastodon.Query.MediaAttachment, Error> { promise in
|
||||
createWorkingQueue().async {
|
||||
guard url.startAccessingSecurityScopedResource() else { return }
|
||||
defer { url.stopAccessingSecurityScopedResource() }
|
||||
|
||||
let fileName = UUID().uuidString
|
||||
let tempDirectoryURL = FileManager.default.temporaryDirectory
|
||||
let fileURL = tempDirectoryURL.appendingPathComponent(fileName).appendingPathExtension(url.pathExtension)
|
||||
do {
|
||||
try FileManager.default.createDirectory(at: tempDirectoryURL, withIntermediateDirectories: true, attributes: nil)
|
||||
try FileManager.default.copyItem(at: url, to: fileURL)
|
||||
let file = Mastodon.Query.MediaAttachment.other(fileURL, fileExtension: fileURL.pathExtension, mimeType: UTType.movie.preferredMIMEType ?? "video/mp4")
|
||||
promise(.success(file))
|
||||
} catch {
|
||||
promise(.failure(error))
|
||||
}
|
||||
}
|
||||
}
|
||||
.eraseToAnyPublisher()
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -95,7 +95,6 @@ enum PHPickerResultLoader {
|
|||
} catch {
|
||||
promise(.failure(error))
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue