diff --git a/Package.swift b/Package.swift index eb11779..c4aabf8 100644 --- a/Package.swift +++ b/Package.swift @@ -16,7 +16,7 @@ let package = Package( dependencies: [ // Dependencies declare other packages that this package depends on. // .package(url: /* package url */, from: "1.0.0"), - .package(name: "GiniBankAPILibrary", url: "https://github.com/gini/bank-api-library-ios.git", .exact("3.1.2")), + .package(name: "GiniBankAPILibrary", url: "https://github.com/gini/bank-api-library-ios.git", .exact("3.1.3")), ], targets: [ // Targets are the basic building blocks of a package. A target can define a module or a test suite. diff --git a/Sources/GiniCaptureSDK/Core/Screens/Camera/Camera.swift b/Sources/GiniCaptureSDK/Core/Screens/Camera/Camera.swift index 4f581d1..d4c45dd 100644 --- a/Sources/GiniCaptureSDK/Core/Screens/Camera/Camera.swift +++ b/Sources/GiniCaptureSDK/Core/Screens/Camera/Camera.swift @@ -245,8 +245,7 @@ final class Camera: NSObject, CameraProtocol { } // Set the orientation according to the current orientation of the interface - DispatchQueue.main.sync { [weak self] in - guard let self = self else { return } + DispatchQueue.main.sync { connection.videoOrientation = AVCaptureVideoOrientation(Device.orientation) } diff --git a/Sources/GiniCaptureSDK/Core/Screens/Error/ErrorType.swift b/Sources/GiniCaptureSDK/Core/Screens/Error/ErrorType.swift index 22ad99c..25844d5 100644 --- a/Sources/GiniCaptureSDK/Core/Screens/Error/ErrorType.swift +++ b/Sources/GiniCaptureSDK/Core/Screens/Error/ErrorType.swift @@ -16,7 +16,7 @@ import GiniBankAPILibrary - serverError: Error returned by the server. - authentication: Error related to authentication. - unexpected: Unexpected error that is not covered by the other cases. - - importError: Error related to importing documents. + - maintenance: Error returned when the system is under maintenance. */ @objc public enum ErrorType: Int { @@ -25,7 +25,8 @@ import GiniBankAPILibrary case serverError case authentication case unexpected - case importError + case maintenance + case outage /** Initializes a new instance of the `ErrorType` enum based on the given `GiniError`. @@ -35,26 +36,22 @@ import GiniBankAPILibrary */ public init(error: GiniError) { switch error { - case .unauthorized(_, _): + case .unauthorized: self = .authentication - case .noResponse: + case .noInternetConnection: self = .connection - case .notAcceptable(let response, _), .tooManyRequests(let response, _), - .parseError(_, let response, _), .badRequest(let response, _), .notFound(let response, _): - if let status = response?.statusCode { - switch status { - case 400, 402 ... 499: - self = .request - case 401: - self = .authentication - case let code where code >= 500: - self = .serverError - default: - self = .unexpected - } - } else { - self = .serverError - } + case .noResponse: + self = .unexpected + case .notAcceptable, .tooManyRequests, + .parseError, .badRequest, + .notFound: + self = .request + case .server: + self = .serverError + case .maintenance: + self = .maintenance + case .outage: + self = .outage default: self = .unexpected } @@ -68,12 +65,12 @@ import GiniBankAPILibrary return "errorUpload" case .authentication: return "errorAuth" - case .serverError: + case .serverError, .outage: return "errorCloud" case .unexpected: return "alertTriangle" - case .importError: - return "alertTriangle" + case .maintenance: + return "errorMaintenance" } } @@ -99,10 +96,14 @@ import GiniBankAPILibrary return NSLocalizedStringPreferredFormat( "ginicapture.error.unexpected.content", comment: "Unexpected error") - case .importError: + case .maintenance: + return NSLocalizedStringPreferredFormat( + "ginicapture.error.maintenance.content", + comment: "Maintenance error") + case .outage: return NSLocalizedStringPreferredFormat( - "ginicapture.error.importError.content", - comment: "Import error") + "ginicapture.error.outage.content", + comment: "Outage error") } } @@ -128,10 +129,14 @@ import GiniBankAPILibrary return NSLocalizedStringPreferredFormat( "ginicapture.error.request.title", comment: "Upload error") - case .importError: + case .maintenance: return NSLocalizedStringPreferredFormat( - "ginicapture.error.importError.title", - comment: "Upload error") + "ginicapture.error.maintenance.title", + comment: "Maintenance error") + case .outage: + return NSLocalizedStringPreferredFormat( + "ginicapture.error.outage.title", + comment: "Outage error") } } } diff --git a/Sources/GiniCaptureSDK/GiniCaptureSDKVersion.swift b/Sources/GiniCaptureSDK/GiniCaptureSDKVersion.swift index 0b361cb..166818d 100644 --- a/Sources/GiniCaptureSDK/GiniCaptureSDKVersion.swift +++ b/Sources/GiniCaptureSDK/GiniCaptureSDKVersion.swift @@ -5,4 +5,4 @@ // Created by Nadya Karaban on 29.10.21. // -public let GiniCaptureSDKVersion = "3.7.1" +public let GiniCaptureSDKVersion = "3.7.2" diff --git a/Sources/GiniCaptureSDK/Resources/GiniImages.xcassets/errorMaintenance.imageset/Contents.json b/Sources/GiniCaptureSDK/Resources/GiniImages.xcassets/errorMaintenance.imageset/Contents.json new file mode 100644 index 0000000..8af754f --- /dev/null +++ b/Sources/GiniCaptureSDK/Resources/GiniImages.xcassets/errorMaintenance.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "filename" : "errorMaintenance.pdf", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Sources/GiniCaptureSDK/Resources/GiniImages.xcassets/errorMaintenance.imageset/errorMaintenance.pdf b/Sources/GiniCaptureSDK/Resources/GiniImages.xcassets/errorMaintenance.imageset/errorMaintenance.pdf new file mode 100644 index 0000000..fa342b8 Binary files /dev/null and b/Sources/GiniCaptureSDK/Resources/GiniImages.xcassets/errorMaintenance.imageset/errorMaintenance.pdf differ diff --git a/Sources/GiniCaptureSDK/Resources/de.lproj/Localizable.strings b/Sources/GiniCaptureSDK/Resources/de.lproj/Localizable.strings index 659a2bc..3970ded 100644 --- a/Sources/GiniCaptureSDK/Resources/de.lproj/Localizable.strings +++ b/Sources/GiniCaptureSDK/Resources/de.lproj/Localizable.strings @@ -136,16 +136,27 @@ "ginicapture.error.enterManually" = "Manuell ausfüllen"; "ginicapture.error.backToCamera" = "Neues Foto"; "ginicapture.error.title" = "Error"; + +"ginicapture.error.connection.title" = "Überprüfen Sie Ihre Internetverbindung."; "ginicapture.error.connection.content" = "Es konnte keine Verbindung zum Internet hergestellt werden. Bitte überprüfen Sie Ihre Netzwerkverbindung und wiederholen Sie den Vorgang."; + +"ginicapture.error.authentication.title" = "Authentifizierung fehlgeschlagen."; "ginicapture.error.authentication.content" = "Der Upload des Dokuments ist fehlgeschlagen aufgrund eines Fehlers bei der Authentifizierung. Bitte versuchen Sie es später noch einmal."; -"ginicapture.error.serverError.content" = "Der Upload des Dokuments ist fehlgeschlagen aufgrund eines Serverfehlers. Bitte versuchen Sie es später noch einmal."; -"ginicapture.error.unexpected.content" = "Es scheint, hier ist etwas schiefgelaufen. Bitte versuchen Sie es später noch einmal."; -"ginicapture.error.connection.title" = "Überprüfen Sie Ihre Internetverbindung"; -"ginicapture.error.authentication.title" = "Authentifizierung fehlgeschlagen"; -"ginicapture.error.serverError.title" = "Dienst nicht verfügbar"; -"ginicapture.error.unexpected.title" = "Ein unbekannter Fehler ist aufgetreten."; + +"ginicapture.error.serverError.title" = "Ein unerwarteter Fehler ist aufgetreten."; +"ginicapture.error.serverError.content" = "Etwas ist schiefgelaufen. Es gab eine unerwartete Antwort vom Service. Bitte versuchen Sie es in Kürze erneut. Wir danken Ihnen für Ihr Verständnis."; + +"ginicapture.error.unexpected.title" = "Ein unerwarteter Fehler ist aufgetreten."; +"ginicapture.error.unexpected.content" = "Etwas ist schiefgelaufen. Bitte versuchen Sie es in Kürze erneut. Wir danken Ihnen für Ihr Verständnis."; + +"ginicapture.error.request.title" = "Der Upload des Dokuments ist fehlgeschlagen."; "ginicapture.error.request.content" = "Das Dokument konnte nicht verarbeitet werden. Bitte überprüfen Sie, ob das Bild scharf ist, das Dokument Zahlungsinformationen enthält und im richtigen Dateiformat hochgeladen wurde."; -"ginicapture.error.request.title" = "Der Upload des Dokuments ist fehlgeschlagen!"; + +"ginicapture.error.maintenance.title" = "Wartungsarbeiten sind im Gange."; +"ginicapture.error.maintenance.content" = "Wir führen Wartungsarbeiten an unserem System durch. Bitte versuchen Sie es in Kürze erneut. Wir danken Ihnen für Ihr Verständnis."; + +"ginicapture.error.outage.title" = "Der Dienst ist nicht verfügbar."; +"ginicapture.error.outage.content" = "Der Dienst ist nicht verfügbar. Bitte versuchen Sie es später erneut. Wir danken Ihnen für Ihr Verständnis."; "ginicapture.help.import.title" = "Importieren"; "ginicapture.help.import.selectInvoice.title" = "Rechnung auswählen"; diff --git a/Sources/GiniCaptureSDK/Resources/en.lproj/Localizable.strings b/Sources/GiniCaptureSDK/Resources/en.lproj/Localizable.strings index f80353b..944d2ed 100644 --- a/Sources/GiniCaptureSDK/Resources/en.lproj/Localizable.strings +++ b/Sources/GiniCaptureSDK/Resources/en.lproj/Localizable.strings @@ -177,16 +177,27 @@ conveniently drag-and-drop PDFs from the iOS Files app to your Banking App to st "ginicapture.error.enterManually" = "Enter manually"; "ginicapture.error.backToCamera" = "Back to camera"; "ginicapture.error.title" = "Error"; + +"ginicapture.error.connection.title" = "There was a problem connecting to the internet."; "ginicapture.error.connection.content" = "Please check your internet connection and try again later on."; + +"ginicapture.error.authentication.title" = "There has been an authentication error."; "ginicapture.error.authentication.content" = "Upload failed due to authentication error. Please try again later."; -"ginicapture.error.serverError.content" = "Upload failed due to a server error. Please try again later."; -"ginicapture.error.unexpected.content" = "It seems something went wrong. Please try again later."; -"ginicapture.error.connection.title" = "There was a problem connecting to the internet"; -"ginicapture.error.authentication.title" = "There has been an authentication error"; -"ginicapture.error.serverError.title" = "Service unavailable"; -"ginicapture.error.unexpected.title" = "An unknown error occurred."; + +"ginicapture.error.serverError.title" = "An unexpected error occurred."; +"ginicapture.error.serverError.content" = "Something went wrong. There was an unexpected response from the service. Please retry shortly. We appreciate your understanding."; + +"ginicapture.error.unexpected.title" = "An unexpected error occurred."; +"ginicapture.error.unexpected.content" = "Something went wrong. Please retry shortly. We appreciate your understanding."; + +"ginicapture.error.request.title" = "There was a problem with the upload."; "ginicapture.error.request.content" = "The document couldn’t be accepted. Please check if the image is sharp, the document contains payment information and has the right file type."; -"ginicapture.error.request.title" = "There was a problem with the upload"; + +"ginicapture.error.maintenance.title" = "Maintenance is in progress."; +"ginicapture.error.maintenance.content" = "We are maintaining our system. Please retry shortly. We appreciate your understanding."; + +"ginicapture.error.outage.title" = "Service is unavailable."; +"ginicapture.error.outage.content" = "The service is unavailable. Please try again later. We appreciate your understanding."; "ginicapture.images.backToAlbums" = "Albums"; "ginicapture.images.openWithTutorialStep1" = "openWithTutorialStep1_en"; diff --git a/Tests/GiniCaptureSDKTests/GiniScreenAPICoordinatorTests.swift b/Tests/GiniCaptureSDKTests/GiniScreenAPICoordinatorTests.swift index 7f881fb..29c3b8c 100644 --- a/Tests/GiniCaptureSDKTests/GiniScreenAPICoordinatorTests.swift +++ b/Tests/GiniCaptureSDKTests/GiniScreenAPICoordinatorTests.swift @@ -125,8 +125,8 @@ final class GiniScreenAPICoordinatorTests: XCTestCase { XCTAssertNotNil( errorScreen, "first view controller is not a ErrorScreenViewController") - XCTAssertTrue(errorScreen?.errorHeader.headerLabel.text == ErrorType.connection.title(), "Error title should match no response error type") - XCTAssertTrue(errorScreen?.errorContent.text == ErrorType.connection.content(), "Error content should match no response error type") + XCTAssertTrue(errorScreen?.errorHeader.headerLabel.text == ErrorType.unexpected.title(), "Error title should match no response error type") + XCTAssertTrue(errorScreen?.errorContent.text == ErrorType.unexpected.content(), "Error content should match no response error type") } @@ -147,17 +147,34 @@ final class GiniScreenAPICoordinatorTests: XCTestCase { "first view controller is not a ErrorScreenViewController") XCTAssertTrue(errorScreen?.errorHeader.headerLabel.text == ErrorType.request.title(), "Error title should match no response error type") XCTAssertTrue(errorScreen?.errorContent.text == ErrorType.request.content(), "Error content should match no response error type") - } + func testUnauthorizedError() { + giniConfiguration.multipageEnabled = false + let capturedImages = [GiniCaptureTestsHelper.loadImageDocument(named: "invoice")] + + let rootViewController = coordinator.start(withDocuments: capturedImages) + _ = rootViewController.view + let response = HTTPURLResponse(url: URL(string: "example")!, statusCode: 401, httpVersion: "", headerFields: [:]) + let errorType = ErrorType(error: .unauthorized(response: response, data: Data())) + coordinator.displayError(errorType: errorType, animated: false) + let screenNavigator = rootViewController.children.first as? UINavigationController + let errorScreen = screenNavigator?.viewControllers.last as? ErrorScreenViewController + errorScreen?.setupView() + XCTAssertNotNil( + errorScreen, + "first view controller is not a ErrorScreenViewController") + XCTAssertTrue(errorScreen?.errorHeader.headerLabel.text == ErrorType.authentication.title(), "Error title should match unauthorized error type") + XCTAssertTrue(errorScreen?.errorContent.text == ErrorType.authentication.content(), "Error content should match unauthorized error type") + } + func testErrorServerError() { giniConfiguration.multipageEnabled = false let capturedImages = [GiniCaptureTestsHelper.loadImageDocument(named: "invoice")] let rootViewController = coordinator.start(withDocuments: capturedImages) _ = rootViewController.view - let response = HTTPURLResponse(url: URL(string: "example")!, statusCode: 501, httpVersion: "", headerFields: [:]) - let errorType = ErrorType(error: .notAcceptable(response: response, data: Data())) + let errorType = ErrorType(error: .server) coordinator.displayError(errorType: errorType, animated: false) let screenNavigator = rootViewController.children.first as? UINavigationController let errorScreen = screenNavigator?.viewControllers.last as? ErrorScreenViewController @@ -169,4 +186,42 @@ final class GiniScreenAPICoordinatorTests: XCTestCase { XCTAssertTrue(errorScreen?.errorContent.text == ErrorType.serverError.content(), "Error content should match server error type") } + + func testMaintenanceError() { + giniConfiguration.multipageEnabled = false + let capturedImages = [GiniCaptureTestsHelper.loadImageDocument(named: "invoice")] + + let rootViewController = coordinator.start(withDocuments: capturedImages) + _ = rootViewController.view + let errorType = ErrorType(error: .maintenance) + coordinator.displayError(errorType: errorType, animated: false) + let screenNavigator = rootViewController.children.first as? UINavigationController + let errorScreen = screenNavigator?.viewControllers.last as? ErrorScreenViewController + errorScreen?.setupView() + XCTAssertNotNil( + errorScreen, + "first view controller is not a ErrorScreenViewController") + XCTAssertTrue(errorScreen?.errorHeader.headerLabel.text == ErrorType.maintenance.title(), "Error title should match server error type") + XCTAssertTrue(errorScreen?.errorContent.text == ErrorType.maintenance.content(), "Error content should match server error type") + + } + + func testOutageError() { + giniConfiguration.multipageEnabled = false + let capturedImages = [GiniCaptureTestsHelper.loadImageDocument(named: "invoice")] + + let rootViewController = coordinator.start(withDocuments: capturedImages) + _ = rootViewController.view + let errorType = ErrorType(error: .outage) + coordinator.displayError(errorType: errorType, animated: false) + let screenNavigator = rootViewController.children.first as? UINavigationController + let errorScreen = screenNavigator?.viewControllers.last as? ErrorScreenViewController + errorScreen?.setupView() + XCTAssertNotNil( + errorScreen, + "first view controller is not a ErrorScreenViewController") + XCTAssertTrue(errorScreen?.errorHeader.headerLabel.text == ErrorType.outage.title(), "Error title should match server error type") + XCTAssertTrue(errorScreen?.errorContent.text == ErrorType.outage.content(), "Error content should match server error type") + + } }