From 1eb5e46207b3f0a2e9653d34c719bf2ed4f548ba Mon Sep 17 00:00:00 2001 From: OS-ricardomoreirasilva Date: Thu, 9 May 2024 10:02:13 +0100 Subject: [PATCH] fix: Picking ProRAW pictures from Gallery If object can't be loaded, load its data representation. Considering that the code was duplicated for multiple and single selections, refactor the code to remove redundancy. For multiple selection, since it's not possible to cancel image loading when one fails, the refactor also changes concurrent loading to serial. References: https://outsystemsrd.atlassian.net/browse/RMET-3243 --- .../Sources/CameraPlugin/CameraPlugin.swift | 90 ++++++++++--------- 1 file changed, 46 insertions(+), 44 deletions(-) diff --git a/camera/ios/Sources/CameraPlugin/CameraPlugin.swift b/camera/ios/Sources/CameraPlugin/CameraPlugin.swift index 8909d0f95..b90fd77c0 100644 --- a/camera/ios/Sources/CameraPlugin/CameraPlugin.swift +++ b/camera/ios/Sources/CameraPlugin/CameraPlugin.swift @@ -256,59 +256,61 @@ extension CameraPlugin: UIImagePickerControllerDelegate, UINavigationControllerD extension CameraPlugin: PHPickerViewControllerDelegate { public func picker(_ picker: PHPickerViewController, didFinishPicking results: [PHPickerResult]) { picker.dismiss(animated: true, completion: nil) - guard let result = results.first else { + + guard !results.isEmpty else { self.call?.reject("User cancelled photos app") return } - if multiple { - var images: [ProcessedImage] = [] - var processedCount = 0 - for img in results { - guard img.itemProvider.canLoadObject(ofClass: UIImage.self) else { - self.call?.reject("Error loading image") - return - } - // extract the image - img.itemProvider.loadObject(ofClass: UIImage.self) { [weak self] (reading, _) in - if let image = reading as? UIImage { - var asset: PHAsset? - if let assetId = img.assetIdentifier { - asset = PHAsset.fetchAssets(withLocalIdentifiers: [assetId], options: nil).firstObject - } - if let processedImage = self?.processedImage(from: image, with: asset?.imageData) { - images.append(processedImage) - } - processedCount += 1 - if processedCount == results.count { - self?.returnImages(images) - } - } else { - self?.call?.reject("Error loading image") - } - } - } - - } else { - guard result.itemProvider.canLoadObject(ofClass: UIImage.self) else { - self.call?.reject("Error loading image") + + self.fetchProcessedImages(from: results) { [weak self] processedImageArray in + guard let processedImageArray else { + self?.call?.reject("Error loading image") return } - // extract the image - result.itemProvider.loadObject(ofClass: UIImage.self) { [weak self] (reading, _) in - if let image = reading as? UIImage { - var asset: PHAsset? - if let assetId = result.assetIdentifier { - asset = PHAsset.fetchAssets(withLocalIdentifiers: [assetId], options: nil).firstObject - } - if var processedImage = self?.processedImage(from: image, with: asset?.imageData) { - processedImage.flags = .gallery - self?.returnProcessedImage(processedImage) - return + + if self?.multiple == true { + self?.returnImages(processedImageArray) + } else if var processedImage = processedImageArray.first { + processedImage.flags = .gallery + self?.returnProcessedImage(processedImage) + } + } + } + + private func fetchProcessedImages(from pickerResultArray: [PHPickerResult], accumulating: [ProcessedImage] = [], _ completionHandler: @escaping ([ProcessedImage]?) -> Void) { + func loadImage(from pickerResult: PHPickerResult,_ completionHandler: @escaping (UIImage?) -> Void) { + let itemProvider = pickerResult.itemProvider + if itemProvider.canLoadObject(ofClass: UIImage.self) { + // extract the image + itemProvider.loadObject(ofClass: UIImage.self) { itemProviderReading, _ in + completionHandler(itemProviderReading as? UIImage) + } + } else { + // extract the image's data representation + itemProvider.loadDataRepresentation(forTypeIdentifier: UTType.image.identifier) { data, _ in + guard let data else { + return completionHandler(nil) } + completionHandler(UIImage(data: data)) } - self?.call?.reject("Error loading image") } } + + guard let currentPickerResult = pickerResultArray.first else { return completionHandler(accumulating) } + + loadImage(from: currentPickerResult) { [weak self] loadedImage in + guard let self, let loadedImage else { return completionHandler(nil) } + var asset: PHAsset? + if let assetId = currentPickerResult.assetIdentifier { + asset = PHAsset.fetchAssets(withLocalIdentifiers: [assetId], options: nil).firstObject + } + let newElement = self.processedImage(from: loadedImage, with: asset?.imageData) + self.fetchProcessedImages( + from: Array(pickerResultArray.dropFirst()), + accumulating: accumulating + [newElement], + completionHandler + ) + } } }