Fix crash when fetching attachment data fails

This commit is contained in:
Shadowfacts 2022-01-21 11:10:03 -05:00
parent e65ed3e773
commit fa1482a152
3 changed files with 45 additions and 15 deletions

View File

@ -48,13 +48,13 @@ enum CompositionAttachmentData {
}
}
func getData(completion: @escaping (_ data: Data, _ mimeType: String) -> Void) {
func getData(completion: @escaping (Result<(Data, String), Error>) -> Void) {
switch self {
case let .image(image):
// Export as JPEG instead of PNG, otherweise photos straight from the camera are too large
// for Mastodon in its default configuration (max of 10MB).
// The quality of 0.8 was chosen completely arbitrarily, it may need to be tuned in the future.
completion(image.jpegData(compressionQuality: 0.8)!, "image/jpeg")
completion(.success((image.jpegData(compressionQuality: 0.8)!, "image/jpeg")))
case let .asset(asset):
if asset.mediaType == .image {
let options = PHImageRequestOptions()
@ -63,7 +63,10 @@ enum CompositionAttachmentData {
options.resizeMode = .none
options.isNetworkAccessAllowed = true
PHImageManager.default().requestImageDataAndOrientation(for: asset, options: options) { (data, dataUTI, orientation, info) in
guard var data = data, let dataUTI = dataUTI else { fatalError() }
guard var data = data, let dataUTI = dataUTI else {
completion(.failure(.missingData))
return
}
let mimeType: String
if dataUTI == "public.heic" {
@ -77,7 +80,7 @@ enum CompositionAttachmentData {
mimeType = UTType(dataUTI)!.preferredMIMEType!
}
completion(data, mimeType)
completion(.success((data, mimeType)))
}
} else if asset.mediaType == .video {
let options = PHVideoRequestOptions()
@ -100,20 +103,23 @@ enum CompositionAttachmentData {
case let .drawing(drawing):
let image = drawing.imageInLightMode(from: drawing.bounds, scale: 1)
completion(image.pngData()!, "image/png")
completion(.success((image.pngData()!, "image/png")))
}
}
private static func exportVideoData(session: AVAssetExportSession, completion: @escaping (Data, String) -> Void) {
private static func exportVideoData(session: AVAssetExportSession, completion: @escaping (Result<(Data, String), Error>) -> Void) {
session.outputFileType = .mp4
session.outputURL = FileManager.default.temporaryDirectory.appendingPathComponent("exported_video_\(UUID())").appendingPathExtension("mp4")
session.exportAsynchronously {
guard session.status == .completed else { fatalError("video export failed: \(String(describing: session.error))") }
guard session.status == .completed else {
completion(.failure(.export(session.error!)))
return
}
do {
let data = try Data(contentsOf: session.outputURL!)
completion(data, "video/mp4")
completion(.success((data, "video/mp4")))
} catch {
fatalError("Unable to load video: \(error)")
completion(.failure(.export(error)))
}
}
}
@ -121,6 +127,11 @@ enum CompositionAttachmentData {
enum AttachmentType {
case image, video
}
enum Error: Swift.Error {
case missingData
case export(Swift.Error)
}
}
extension PHAsset {

View File

@ -97,7 +97,18 @@ struct ComposeAttachmentRow: View {
mode = .recognizingText
DispatchQueue.global(qos: .userInitiated).async {
self.attachment.data.getData { (data, mimeType) in
self.attachment.data.getData { (result) in
let data: Data
do {
try data = result.get().0
} catch {
DispatchQueue.main.async {
self.mode = .allowEntry
self.isShowingTextRecognitionFailedAlert = true
self.textRecognitionErrorMessage = error.localizedDescription
}
return
}
let handler = VNImageRequestHandler(data: data, options: [:])
let request = VNRecognizeTextRequest { (request, error) in
DispatchQueue.main.async {

View File

@ -244,17 +244,17 @@ struct ComposeView: View {
private func uploadAttachments(_ completion: @escaping (Result<[Attachment], AttachmentUploadError>) -> Void) {
let group = DispatchGroup()
var attachmentDatas = [(Data, String)?]()
var attachmentDataResults = [Result<(Data, String), CompositionAttachmentData.Error>?]()
for (index, compAttachment) in draft.attachments.enumerated() {
group.enter()
attachmentDatas.append(nil)
attachmentDataResults.append(nil)
compAttachment.data.getData { (data, mimeType) in
compAttachment.data.getData { (result) in
postProgress += 1
attachmentDatas[index] = (data, mimeType)
attachmentDataResults[index] = result
group.leave()
}
}
@ -271,7 +271,15 @@ struct ComposeView: View {
// posted status reflects order the user set.
// Pleroma does respect the order of the `media_ids` parameter.
for (index, (data, mimeType)) in attachmentDatas.map(\.unsafelyUnwrapped).enumerated() {
let datas: [(Data, String)]
do {
datas = try attachmentDataResults.map { try $0!.get() }
} catch {
completion(.failure(AttachmentUploadError(errors: [error])))
return
}
for (index, (data, mimeType)) in datas.enumerated() {
group.enter()
let compAttachment = draft.attachments[index]