Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion Sources/IONCameraLib/IONCAMRCoordinator.swift
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,9 @@ class IONCAMRCoordinator {

/// Dismisses the currently presented view controllers. In case of a multiple step screen, all are dismissed.
func dismiss() {
rootViewController.dismiss(animated: true)
currentlyPresentedViewControllerArray.removeAll()
Task { @MainActor in
self.rootViewController.dismiss(animated: true)
}
}
}
51 changes: 27 additions & 24 deletions Sources/IONCameraLib/IONCAMRFlowBehaviour.swift
Original file line number Diff line number Diff line change
Expand Up @@ -168,11 +168,11 @@ extension IONCAMRFlowBehaviour: IONCAMRCancelResultsDelegate {
}

extension IONCAMRFlowBehaviour: IONCAMRResultsDelegate {
func didReturn(_ object: AnyObject, with result: Result<IONCAMRResultItem, IONCAMRError>) {
func didReturn(_ object: AnyObject, with result: Result<IONCAMRResultItem, IONCAMRError>) async {
if object === picker {
pickerDidReturn(result)
await pickerDidReturn(result)
} else if object === editorBehaviour {
editorDidReturn(result)
await editorDidReturn(result)
} else if object === galleryBehaviour {
galleryDidReturnSingle(result)
}
Expand Down Expand Up @@ -305,29 +305,32 @@ extension IONCAMRFlowBehaviour {

/// Method triggered when the user could finish, with or without success, the picker behaviour.
/// - Parameter result: Returned object to who implements this object. It returns a base64 encoding text if successful or an error otherwise.
private func pickerDidReturn(_ result: Result<IONCAMRResultItem, IONCAMRError>) {
func pickerDidReturn(_ result: Result<IONCAMRResultItem, IONCAMRError>) async {
func didFailed(withError error: IONCAMRError) {
delegate?.didFailed(type: IONCAMRMediaResult.self, with: error)
}

defer { self.coordinator.dismiss() }
var canDismiss = true
defer {
if canDismiss {
self.coordinator.dismiss()
self.options = nil
}
}

switch result {
case .success(let item):
switch item {
case .picture(let image):
Task {
do {
guard let mediaResult = try await self.imagePickerDidReturn(image) else {
self.editPhoto(image)
return
}
self.options = nil
self.delegate?.didSucceed(with: mediaResult)
} catch {
self.options = nil
didFailed(withError: .takePictureIssue)
do {
guard let mediaResult = try await imagePickerDidReturn(image) else {
canDismiss = false
editPhoto(image)
return
}
delegate?.didSucceed(with: mediaResult)
} catch {
didFailed(withError: .takePictureIssue)
}
case .video(let url):
videoPickerDidReturn(url) { [weak self] mediaResult in
Expand Down Expand Up @@ -375,7 +378,7 @@ extension IONCAMRFlowBehaviour {

/// Method triggered when the user could finish, with or without success, the editor behaviour.
/// - Parameter result: Returned object to who implements this object. It returns a base64 encoding text if successful or an error otherwise.
private func editorDidReturn(_ result: Result<IONCAMRResultItem, IONCAMRError>) {
func editorDidReturn(_ result: Result<IONCAMRResultItem, IONCAMRError>) async {
func didFailed(with error: IONCAMRError = .editPictureIssue) {
delegate?.didFailed(type: IONCAMRMediaResult.self, with: error)
}
Expand All @@ -385,13 +388,13 @@ extension IONCAMRFlowBehaviour {
switch result {
case .success(let item):
if case .picture(let image) = item {
Task {
do {
let result = try await imageEditorDidReturn(image)
self.options = nil
self.delegate?.didSucceed(with: result)
} catch {
self.options = nil
do {
let result = try await imageEditorDidReturn(image)
delegate?.didSucceed(with: result)
} catch {
if let ionError = error as? IONCAMRError {
didFailed(with: ionError)
} else {
didFailed()
}
}
Expand Down
38 changes: 20 additions & 18 deletions Sources/IONCameraLib/Interfaces/Editor/IONCAMRImageEditorView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -108,24 +108,26 @@ struct IONCAMRImageEditorView: View {
Spacer()

Button {
guard let cgImage = image.cgImage else {
delegate?.finishEditing(with: .editPictureIssue) // it wasn't possible to retrieve the image, so an error is returned.
return
}
let scaler = CGSize(width: CGFloat(cgImage.width) / imageWidth, height: CGFloat(cgImage.height) / imageHeight)
let dim = CGSize(width: cgImage.width, height: cgImage.height)
let cropRect = CGRect(
x: croppingOffset.width * scaler.width,
y: croppingOffset.height * scaler.height,
width: dim.width * croppingWidthMagnification,
height: dim.height * croppingHeightMagnification
)

if let cImage = cgImage.cropping(to: cropRect) {
let croppedImage = UIImage(cgImage: cImage)
delegate?.finishEditing(with: croppedImage) // the resulting cropped image is returned.
} else {
delegate?.finishEditing(with: .editPictureIssue) // it wasn't possible to retrieve the image, so an error is returned.
Task {
guard let cgImage = image.cgImage else {
await delegate?.finishEditing(with: .editPictureIssue) // it wasn't possible to retrieve the image, so an error is returned.
return
}
let scaler = CGSize(width: CGFloat(cgImage.width) / imageWidth, height: CGFloat(cgImage.height) / imageHeight)
let dim = CGSize(width: cgImage.width, height: cgImage.height)
let cropRect = CGRect(
x: croppingOffset.width * scaler.width,
y: croppingOffset.height * scaler.height,
width: dim.width * croppingWidthMagnification,
height: dim.height * croppingHeightMagnification
)

if let cImage = cgImage.cropping(to: cropRect) {
let croppedImage = UIImage(cgImage: cImage)
await delegate?.finishEditing(with: croppedImage) // the resulting cropped image is returned.
} else {
await delegate?.finishEditing(with: .editPictureIssue) // it wasn't possible to retrieve the image, so an error is returned.
}
}
} label: {
Text("Done")
Expand Down
16 changes: 8 additions & 8 deletions Sources/IONCameraLib/Interfaces/IONCAMREditorBehaviour.swift
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,11 @@ extension IONCAMREditorBehaviour: IONCAMRImageEditorResultsDelegate {
/// - Parameters:
/// - result: Resulting image.
/// - error: Error occurred during the edit.
func finishEditing(_ result: UIImage?, error: IONCAMRError?) {
func finishEditing(_ result: UIImage?, error: IONCAMRError?) async {
if let image = result {
delegate?.didReturn(self, with: .success(.picture(image)))
await delegate?.didReturn(self, with: .success(.picture(image)))
} else {
delegate?.didReturn(self, with: .failure(.editPictureIssue))
await delegate?.didReturn(self, with: .failure(.editPictureIssue))
}
}

Expand All @@ -35,16 +35,16 @@ extension IONCAMREditorBehaviour: IONCAMRImageEditorResultsDelegate {
}

protocol IONCAMRImageEditorResultsDelegate: AnyObject {
func finishEditing(_ result: UIImage?, error: IONCAMRError?)
func finishEditing(_ result: UIImage?, error: IONCAMRError?) async
func didCancelEdit()
}

extension IONCAMRImageEditorResultsDelegate {
func finishEditing(with result: UIImage) {
finishEditing(result, error: nil)
func finishEditing(with result: UIImage) async {
await finishEditing(result, error: nil)
}

func finishEditing(with error: IONCAMRError) {
finishEditing(nil, error: error)
func finishEditing(with error: IONCAMRError) async {
await finishEditing(nil, error: error)
}
}
6 changes: 3 additions & 3 deletions Sources/IONCameraLib/Interfaces/IONCAMRGalleryBehaviour.swift
Original file line number Diff line number Diff line change
Expand Up @@ -85,11 +85,11 @@ extension IONCAMRGalleryBehaviour: IONCAMRPhotoLibraryViewDelegate {
}
}

func didPickPicture(_ item: IONCAMRResultItem?) {
func didPickPicture(_ item: IONCAMRResultItem?) async {
if let item {
delegate?.didReturn(self, with: .success(item))
await delegate?.didReturn(self, with: .success(item))
} else {
delegate?.didReturn(self, with: .failure(.choosePictureIssue))
await delegate?.didReturn(self, with: .failure(.choosePictureIssue))
}
}

Expand Down
40 changes: 21 additions & 19 deletions Sources/IONCameraLib/Interfaces/IONCAMRPickerBehaviour.swift
Original file line number Diff line number Diff line change
Expand Up @@ -30,26 +30,28 @@ final class IONCAMRPickerBehaviour: NSObject, IONCAMRPickerDelegate {
/// Extension that handles the responses obtained through the Image Picker user interaction.
extension IONCAMRPickerBehaviour: UIImagePickerControllerDelegate, UINavigationControllerDelegate {
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey: Any]) {
guard let mediaType = mediaOptions?.mediaType else {
delegate?.didReturn(self, with: .failure(.generalIssue))
return
}
Task {
guard let mediaType = self.mediaOptions?.mediaType else {
await self.delegate?.didReturn(self, with: .failure(.generalIssue))
return
}

let result: Result<IONCAMRResultItem, IONCAMRError>
switch mediaType {
case .picture:
let image = info[.originalImage] as? UIImage
result = fetchToReturn(image)
.flatMap { .success(.picture($0)) }
.flatMapError { .failure($0) }
delegate?.didReturn(self, with: result)
case .video:
let videoURL = info[.mediaURL] as? URL
result = fetchToReturn(videoURL)
.flatMap { .success(.video($0)) }
.flatMapError { .failure($0) }
delegate?.didReturn(self, with: result)
default: break // not supposed to get here
let result: Result<IONCAMRResultItem, IONCAMRError>
switch mediaType {
case .picture:
let image = info[.originalImage] as? UIImage
result = self.fetchToReturn(image)
.flatMap { .success(.picture($0)) }
.flatMapError { .failure($0) }
await self.delegate?.didReturn(self, with: result)
case .video:
let videoURL = info[.mediaURL] as? URL
result = self.fetchToReturn(videoURL)
.flatMap { .success(.video($0)) }
.flatMapError { .failure($0) }
await self.delegate?.didReturn(self, with: result)
default: break // not supposed to get here
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -213,7 +213,7 @@ extension IONCAMRPhotoLibraryService {
} else {
let item = await self.fetchSingleResult(assetArray.first)
Task { @MainActor in
self.delegate?.didPickPicture(item)
await self.delegate?.didPickPicture(item)
}
}
}
Expand Down
30 changes: 15 additions & 15 deletions Sources/IONCameraLib/Models/IONCAMRError.swift
Original file line number Diff line number Diff line change
Expand Up @@ -3,47 +3,47 @@ import Foundation
/// All plugin errors that can be thrown
public enum IONCAMRError: Int, CustomNSError, LocalizedError {
// MARK: - Permissions Errors

case cameraAccess = 3
case cameraAvailability = 7

// MARK: - Take Pictures Errors

case takePictureCancel = 6
case takePictureIssue = 10
case takePictureArguments = 14

// MARK: - Edit Picture Errors

case invalidImageData = 8
case editPictureIssue = 9
case editPictureCancel = 13

// MARK: - Choose Picture Errors

case photoLibraryAccess = 5
case imageNotFound = 11
case choosePictureIssue = 12
case choosePictureCancel = 18

// MARK: - Capture Video Errors

case captureVideoIssue = 16
case captureVideoCancel = 17

// MARK: - Choose Multimedia Errors

case videoNotFound = 26
case chooseMultimediaIssue = 19
case chooseMultimediaCancel = 21
case fetchImageFromURLFailed = 29

// MARK: - Play Video Errors

case playVideoIssue = 24

// MARK: - General Errors

case invalidEncodeResultMedia = 20
case generalIssue = 27

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,6 @@ import UIKit

protocol IONCAMRPhotoLibraryViewDelegate: AnyObject {
func didPickMultimedia(_ mediaResultArray: [IONCAMRMediaResult]?)
func didPickPicture(_ item: IONCAMRResultItem?)
func didPickPicture(_ item: IONCAMRResultItem?) async
func didCancel()
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ protocol IONCAMRMultipleResultsDelegate: AnyObject {
}

protocol IONCAMRResultsDelegate: AnyObject {
func didReturn(_ object: AnyObject, with result: Result<IONCAMRResultItem, IONCAMRError>)
func didReturn(_ object: AnyObject, with result: Result<IONCAMRResultItem, IONCAMRError>) async
}

enum IONCAMRResultItem {
Expand Down
16 changes: 8 additions & 8 deletions Tests/IONCameraLibTests/Configurations/MockConfigurations.swift
Original file line number Diff line number Diff line change
Expand Up @@ -409,9 +409,9 @@ class IONCAMRPickerBehaviourMock: IONCAMRPickerDelegate {
func takePictureHandler(with success: Bool = true, and error: IONCAMRError? = nil) {
if success {
if let error {
delegate?.didReturn(self, with: .failure(error))
Task { await delegate?.didReturn(self, with: .failure(error)) }
} else {
delegate?.didReturn(self, with: .success(.picture(IONCAMRPictureMock.osLogo.image)))
Task { await self.delegate?.didReturn(self, with: .success(.picture(IONCAMRPictureMock.osLogo.image))) }
}
} else {
delegate?.didCancel(self)
Expand All @@ -435,9 +435,9 @@ class IONCAMRPickerBehaviourMock: IONCAMRPickerDelegate {
func captureVideoHandler(with success: Bool = true, and error: IONCAMRError? = nil) {
if success {
if let error {
delegate?.didReturn(self, with: .failure(error))
Task { await delegate?.didReturn(self, with: .failure(error)) }
} else {
delegate?.didReturn(self, with: .success(.video(IONCAMRVideoMock.first.url)))
Task { await self.delegate?.didReturn(self, with: .success(.video(IONCAMRVideoMock.first.url))) }
}
} else {
delegate?.didCancel(self)
Expand Down Expand Up @@ -490,9 +490,9 @@ class IONCAMRGalleryBehaviourMock: IONCAMRGalleryDelegate {
private func choosePictureHandler(with success: Bool, and error: IONCAMRError?) {
if success {
if let error {
delegate?.didReturn(self, with: .failure(error))
Task { await delegate?.didReturn(self, with: .failure(error)) }
} else {
delegate?.didReturn(self, with: .success(.picture(IONCAMRPictureMock.osLogo.image)))
Task { await self.delegate?.didReturn(self, with: .success(.picture(IONCAMRPictureMock.osLogo.image))) }
}
} else {
delegate?.didCancel(self)
Expand Down Expand Up @@ -593,9 +593,9 @@ class IONCAMREditorBehaviourMock: IONCAMREditorDelegate {
func editPictureHandler(with success: Bool, and error: IONCAMRError?) {
if success {
if let error {
delegate?.didReturn(self, with: .failure(error))
Task { await delegate?.didReturn(self, with: .failure(error)) }
} else {
delegate?.didReturn(self, with: .success(.picture(IONCAMRPictureMock.osLogoBlue.image)))
Task { await self.delegate?.didReturn(self, with: .success(.picture(IONCAMRPictureMock.osLogoBlue.image))) }
}
} else {
delegate?.didCancel(self)
Expand Down
Loading
Loading