From 97de4ee898ed65a0350cf5c71537d90725528854 Mon Sep 17 00:00:00 2001 From: Vansh Gandhi Date: Wed, 4 Oct 2023 16:54:10 -0700 Subject: [PATCH] Fix delegate (#77) * Fix delegate * Bump versions * Update Sources/SmileID/Resources/Localization/en.lproj/Localizable.strings Co-authored-by: Michael * renamed instructions and re-ordered products * Update Swift Docs --------- Co-authored-by: Michael Co-authored-by: Juma Allan --- CHANGELOG.md | 9 ++- Example/SmileID/HomeViewModel.swift | 2 + SmileID.podspec | 8 +-- .../Model/DocumentCaptureModel.swift | 11 ++-- .../View/DocumentCaptureInstructionView.swift | 25 ++++--- .../View/DocumentCaptureView.swift | 14 +++- .../Classes/Navigation/NavigationBar.swift | 12 ++-- .../Navigation/NavigationDestination.swift | 9 +-- .../Classes/Navigation/ViewFactory.swift | 15 ++--- Sources/SmileID/Classes/SmileID.swift | 65 +++++++++---------- .../Localization/en.lproj/Localizable.strings | 2 +- 11 files changed, 98 insertions(+), 74 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index be84cca54..3151ca3f0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,11 +1,18 @@ -## 10.0.0-beta09 (unreleased) +## 10.0.0-beta10 (unreleased) ### Added ### Changed +### Fixed + ### Removed +## 10.0.0-beta09 + +### Fixed +- Fixed a bug where Document Verification results were not being delivered to the delegate + ## 10.0.0-beta08 ### Added diff --git a/Example/SmileID/HomeViewModel.swift b/Example/SmileID/HomeViewModel.swift index 5b36622b8..5017b470d 100644 --- a/Example/SmileID/HomeViewModel.swift +++ b/Example/SmileID/HomeViewModel.swift @@ -91,6 +91,8 @@ class HomeViewModel: ObservableObject, SmartSelfieResultDelegate, DocumentCaptur documentBackImage: URL?, jobStatusResponse: JobStatusResponse ) { + showToast = true + toastMessage = "Document Verification submitted successfully, results processing" } @objc func handleAuthCompletion(_ notification: NSNotification) { diff --git a/SmileID.podspec b/SmileID.podspec index 29fbc9b59..2b9e8537c 100644 --- a/SmileID.podspec +++ b/SmileID.podspec @@ -1,11 +1,11 @@ Pod::Spec.new do |s| s.name = 'SmileID' - s.version = '10.0.0-beta08' + s.version = '10.0.0-beta09' s.summary = 'The Official Smile Identity iOS SDK.' - s.homepage = "https://docs.smileidentity.com/mobile/ios" - s.license = { :type => 'MIT', :file => 'LICENSE' } + s.homepage = 'https://docs.usesmileid.com/integration-options/mobile/ios-v10-beta' + s.license = { :type => 'MIT', :file => 'LICENSE' } s.author = { 'Jubril O' => 'jubril@smileidentity.com', 'Japhet' => 'japhet@smileidentity.com', 'Juma Allan' => 'juma@smileidentity.com', 'Vansh Gandhi' => 'vansh@smileidentity.com'} - s.source = { :git => "https://github.com/smileidentity/ios.git", :tag => "v10.0.0-beta08" } + s.source = { :git => "https://github.com/smileidentity/ios.git", :tag => "v10.0.0-beta09" } s.ios.deployment_target = '13.0' s.dependency 'Zip', '~> 2.1.0' s.swift_version = '5.5' diff --git a/Sources/SmileID/Classes/DocumentVerification/Model/DocumentCaptureModel.swift b/Sources/SmileID/Classes/DocumentVerification/Model/DocumentCaptureModel.swift index 03c87cc51..5e6b1f105 100644 --- a/Sources/SmileID/Classes/DocumentVerification/Model/DocumentCaptureModel.swift +++ b/Sources/SmileID/Classes/DocumentVerification/Model/DocumentCaptureModel.swift @@ -32,7 +32,7 @@ class DocumentCaptureViewModel: ObservableObject, } weak var rectangleDetectionDelegate: RectangleDetectionDelegate? - weak var captureResultDelegate: DocumentCaptureResultDelegate? + var captureResultDelegate: DocumentCaptureResultDelegate? var router: Router? private var cameraCapture: Bool = false private let textDetector = TextDetector() @@ -111,7 +111,8 @@ class DocumentCaptureViewModel: ObservableObject, selfie: Data? = nil, captureBothSides: Bool, showAttribution: Bool, - allowGalleryUpload: Bool + allowGalleryUpload: Bool, + delegate: DocumentCaptureResultDelegate ) { self.userId = userId self.jobId = jobId @@ -122,6 +123,7 @@ class DocumentCaptureViewModel: ObservableObject, self.captureBothSides = captureBothSides self.showAttribution = showAttribution self.allowGalleryUpload = allowGalleryUpload + captureResultDelegate = delegate autoCaptureTimer = RestartableTimer( timeInterval: autoCaptureDelayInSecs, @@ -274,6 +276,8 @@ class DocumentCaptureViewModel: ObservableObject, documentBackImage: savedFiles.documentBack, jobStatusResponse: response ) + } else { + captureResultDelegate?.didError(error: SmileIDError.unknown("Unknown Error")) } default: break @@ -297,8 +301,7 @@ class DocumentCaptureViewModel: ObservableObject, router?.push( .documentBackCaptureInstructionScreen( documentCaptureViewModel: self, - skipDestination: selfieCaptureScreen, - delegate: captureResultDelegate + skipDestination: selfieCaptureScreen ) ) } else { diff --git a/Sources/SmileID/Classes/DocumentVerification/View/DocumentCaptureInstructionView.swift b/Sources/SmileID/Classes/DocumentVerification/View/DocumentCaptureInstructionView.swift index 8757e204a..abf2d5974 100644 --- a/Sources/SmileID/Classes/DocumentVerification/View/DocumentCaptureInstructionView.swift +++ b/Sources/SmileID/Classes/DocumentVerification/View/DocumentCaptureInstructionView.swift @@ -10,18 +10,15 @@ public struct DocumentCaptureInstructionsView: View { @ObservedObject private var viewModel: DocumentCaptureViewModel private var side: Side private var skipDestination: NavigationDestination? - private weak var documentCaptureDelegate: DocumentCaptureResultDelegate? init( viewModel: DocumentCaptureViewModel, side: Side, - skipDestination: NavigationDestination? = nil, - delegate: DocumentCaptureResultDelegate + skipDestination: NavigationDestination? = nil ) { self.viewModel = viewModel self.side = side self.skipDestination = skipDestination - documentCaptureDelegate = delegate } fileprivate init(viewModel: DocumentCaptureViewModel) { @@ -81,8 +78,7 @@ public struct DocumentCaptureInstructionsView: View { ], captureType: .document(.back), destination: .documentCaptureScreen( - documentCaptureViewModel: viewModel, - delegate: documentCaptureDelegate + documentCaptureViewModel: viewModel ), secondaryDestination: .imagePicker(viewModel: viewModel), skipDestination: skipDestination, @@ -115,8 +111,7 @@ public struct DocumentCaptureInstructionsView: View { ], captureType: .document(.front), destination: .documentCaptureScreen( - documentCaptureViewModel: viewModel, - delegate: documentCaptureDelegate + documentCaptureViewModel: viewModel ), secondaryDestination: .imagePicker(viewModel: viewModel), showAttribution: viewModel.showAttribution, @@ -135,8 +130,20 @@ struct DocumentCaptureInstructionsView_Previews: PreviewProvider { documentType: "", captureBothSides: true, showAttribution: true, - allowGalleryUpload: true + allowGalleryUpload: true, + delegate: DocPlaceHolderDelegate() ) ).environment(\.locale, Locale(identifier: "en")) } + + private class DocPlaceHolderDelegate: DocumentCaptureResultDelegate { + func didSucceed( + selfie: URL, + documentFrontImage: URL, + documentBackImage: URL?, + jobStatusResponse: JobStatusResponse + ) {} + + func didError(error _: Error) {} + } } diff --git a/Sources/SmileID/Classes/DocumentVerification/View/DocumentCaptureView.swift b/Sources/SmileID/Classes/DocumentVerification/View/DocumentCaptureView.swift index c7945ed1e..2b1c1d7a2 100644 --- a/Sources/SmileID/Classes/DocumentVerification/View/DocumentCaptureView.swift +++ b/Sources/SmileID/Classes/DocumentVerification/View/DocumentCaptureView.swift @@ -79,8 +79,20 @@ struct DocumentCaptureView_Previews: PreviewProvider { documentType: "", captureBothSides: true, showAttribution: true, - allowGalleryUpload: true + allowGalleryUpload: true, + delegate: DocPlaceHolderDelegate() ) ) } + + private class DocPlaceHolderDelegate: DocumentCaptureResultDelegate { + func didSucceed( + selfie: URL, + documentFrontImage: URL, + documentBackImage: URL?, + jobStatusResponse: JobStatusResponse + ) {} + + func didError(error _: Error) {} + } } diff --git a/Sources/SmileID/Classes/Navigation/NavigationBar.swift b/Sources/SmileID/Classes/Navigation/NavigationBar.swift index 337965a69..d42ffb105 100644 --- a/Sources/SmileID/Classes/Navigation/NavigationBar.swift +++ b/Sources/SmileID/Classes/Navigation/NavigationBar.swift @@ -4,13 +4,13 @@ struct NavigationBar: View { let backButtonHandler: () -> Void var body: some View { HStack { - Button { - backButtonHandler() - } label: { - Image(uiImage: SmileIDResourcesHelper.ArrowLeft) - }.padding(.leading) + Button( + action: backButtonHandler, + label: { Image(uiImage: SmileIDResourcesHelper.ArrowLeft) } + ).padding(.leading) Spacer() - }.frame(height: 50) + } + .frame(height: 50) .frame(maxHeight: .infinity, alignment: .top) } } diff --git a/Sources/SmileID/Classes/Navigation/NavigationDestination.swift b/Sources/SmileID/Classes/Navigation/NavigationDestination.swift index 753dd8a16..c9de109f7 100644 --- a/Sources/SmileID/Classes/Navigation/NavigationDestination.swift +++ b/Sources/SmileID/Classes/Navigation/NavigationDestination.swift @@ -10,17 +10,14 @@ indirect enum NavigationDestination: ReflectiveEquatable { delegate: SmartSelfieResultDelegate? ) case documentFrontCaptureInstructionScreen( - documentCaptureViewModel: DocumentCaptureViewModel, - delegate: DocumentCaptureResultDelegate? + documentCaptureViewModel: DocumentCaptureViewModel ) case documentBackCaptureInstructionScreen( documentCaptureViewModel: DocumentCaptureViewModel, - skipDestination: NavigationDestination, - delegate: DocumentCaptureResultDelegate? + skipDestination: NavigationDestination ) case documentCaptureScreen( - documentCaptureViewModel: DocumentCaptureViewModel, - delegate: DocumentCaptureResultDelegate? + documentCaptureViewModel: DocumentCaptureViewModel ) case documentCaptureProcessing case documentCaptureError(viewModel: DocumentCaptureViewModel) diff --git a/Sources/SmileID/Classes/Navigation/ViewFactory.swift b/Sources/SmileID/Classes/Navigation/ViewFactory.swift index b38a4552f..817b5b141 100644 --- a/Sources/SmileID/Classes/Navigation/ViewFactory.swift +++ b/Sources/SmileID/Classes/Navigation/ViewFactory.swift @@ -35,24 +35,21 @@ class ViewFactory { viewModel: selfieCaptureViewModel, delegate: delegate ?? SelfiePlaceHolderDelegate() ) - case let .documentFrontCaptureInstructionScreen(documentCaptureViewModel, delegate): + case let .documentFrontCaptureInstructionScreen(documentCaptureViewModel): DocumentCaptureInstructionsView( viewModel: documentCaptureViewModel, - side: .front, - delegate: delegate ?? DocPlaceHolderDelegate() + side: .front ) - case let .documentCaptureScreen(documentCaptureViewModel, _): + case let .documentCaptureScreen(documentCaptureViewModel): DocumentCaptureView(viewModel: documentCaptureViewModel) case .documentBackCaptureInstructionScreen( documentCaptureViewModel: let viewModel, - let skipDestination, - delegate: let delegate + let skipDestination ): DocumentCaptureInstructionsView( viewModel: viewModel, side: .back, - skipDestination: skipDestination, - delegate: delegate ?? DocPlaceHolderDelegate() + skipDestination: skipDestination ) case .documentCaptureProcessing: ModalPresenter(centered: true) { @@ -67,7 +64,7 @@ class ViewFactory { SuccessView( titleKey: "Document.Complete.Header", bodyKey: "Document.Complete.Callout", - clicked: { viewModel.handleCompletion() } + clicked: viewModel.handleCompletion ) } case .documentCaptureError(viewModel: let viewModel): diff --git a/Sources/SmileID/Classes/SmileID.swift b/Sources/SmileID/Classes/SmileID.swift index ca1411f4d..d82f5095d 100644 --- a/Sources/SmileID/Classes/SmileID.swift +++ b/Sources/SmileID/Classes/SmileID.swift @@ -3,7 +3,7 @@ import SwiftUI import UIKit public class SmileID { - public static let version = "10.0.0-beta08" + public static let version = "10.0.0-beta09" @Injected var injectedApi: SmileIDServiceable public static var configuration: Config { config } @@ -85,7 +85,7 @@ public class SmileID { jobId: String = generateJobId(), allowAgentMode: Bool = false, showAttribution: Bool = true, - showInstruction: Bool = true, + showInstructions: Bool = true, delegate: SmartSelfieResultDelegate ) -> some View { @@ -96,7 +96,28 @@ public class SmileID { allowsAgentMode: allowAgentMode, showAttribution: showAttribution ) - let destination: NavigationDestination = showInstruction ? + let destination: NavigationDestination = showInstructions ? + .selfieInstructionScreen(selfieCaptureViewModel: viewModel, delegate: delegate) : + .selfieCaptureScreen(selfieCaptureViewModel: viewModel, delegate: delegate) + return SmileView(initialDestination: destination).environmentObject(router) + } + + public class func smartSelfieAuthenticationScreen( + userId: String, + jobId: String = generateJobId(), + allowAgentMode: Bool = false, + showAttribution: Bool = true, + showInstructions: Bool = true, + delegate: SmartSelfieResultDelegate + ) -> some View { + let viewModel = SelfieCaptureViewModel( + userId: userId, + jobId: jobId, + isEnroll: false, + allowsAgentMode: allowAgentMode, + showAttribution: showAttribution + ) + let destination: NavigationDestination = showInstructions ? .selfieInstructionScreen(selfieCaptureViewModel: viewModel, delegate: delegate) : .selfieCaptureScreen(selfieCaptureViewModel: viewModel, delegate: delegate) return SmileView(initialDestination: destination).environmentObject(router) @@ -114,8 +135,8 @@ public class SmileID { /// - documentType: An optional string for the type of document to be captured /// - idAspectRatio: An optional value for the aspect ratio of the document. If no value is, /// supplied, image analysis is done to calculate the documents aspect ratio - /// - selfie: A jpg selfie where if provided, the user will not be prompted to capture a - /// selfie and this file will be used as the selfie image. + /// - bypassSelfieCaptureWithFile: If provided, selfie capture will be bypassed using this + /// image /// - captureBothSides: Whether to capture both sides of the ID or not. Otherwise, only the /// front side will be captured. If this is true, an option to skip back side will still be /// shown @@ -130,7 +151,7 @@ public class SmileID { countryCode: String, documentType: String? = nil, idAspectRatio: Double? = nil, - selfie: Data? = nil, + bypassSelfieCaptureWithFile: URL? = nil, captureBothSides: Bool = true, allowGalleryUpload: Bool = false, showInstructions: Bool = true, @@ -143,45 +164,23 @@ public class SmileID { countryCode: countryCode, documentType: documentType, idAspectRatio: idAspectRatio, - selfie: selfie, + selfie: bypassSelfieCaptureWithFile.flatMap { try? Data(contentsOf: $0) }, captureBothSides: captureBothSides, showAttribution: showAttribution, - allowGalleryUpload: allowGalleryUpload + allowGalleryUpload: allowGalleryUpload, + delegate: delegate ) let destination = showInstructions ? NavigationDestination.documentFrontCaptureInstructionScreen( - documentCaptureViewModel: viewModel, - delegate: delegate + documentCaptureViewModel: viewModel ) : NavigationDestination.documentCaptureScreen( - documentCaptureViewModel: viewModel, - delegate: delegate + documentCaptureViewModel: viewModel ) return SmileView(initialDestination: destination).environmentObject(router) } - public class func smartSelfieAuthenticationScreen( - userId: String, - jobId: String = generateJobId(), - allowAgentMode: Bool = false, - showAttribution: Bool = true, - showInstruction: Bool = true, - delegate: SmartSelfieResultDelegate - ) -> some View { - let viewModel = SelfieCaptureViewModel( - userId: userId, - jobId: jobId, - isEnroll: false, - allowsAgentMode: allowAgentMode, - showAttribution: showAttribution - ) - let destination: NavigationDestination = showInstruction ? - .selfieInstructionScreen(selfieCaptureViewModel: viewModel, delegate: delegate) : - .selfieCaptureScreen(selfieCaptureViewModel: viewModel, delegate: delegate) - return SmileView(initialDestination: destination).environmentObject(router) - } - public class func setEnvironment(useSandbox: Bool) { SmileID.useSandbox = useSandbox } diff --git a/Sources/SmileID/Resources/Localization/en.lproj/Localizable.strings b/Sources/SmileID/Resources/Localization/en.lproj/Localizable.strings index 4e4af4e1a..a50087daf 100644 --- a/Sources/SmileID/Resources/Localization/en.lproj/Localizable.strings +++ b/Sources/SmileID/Resources/Localization/en.lproj/Localizable.strings @@ -5,7 +5,7 @@ "Instructions.ClearImage" = "Clear Image"; "Instructions.GoodLightBody" = "Make sure you are in a well-lit environment where your face is clear and visible."; -"Instructions.ClearImageBody" = "Hold your phone steady so the selfie is clear and sharp. Don’t take blurry images."; +"Instructions.ClearImageBody" = "Hold your phone steady so the image is clear and sharp. Don’t take blurry photos."; "Instructions.GoodLight" = "Good Light"; "Instructions.RemoveObstructions" = "Remove Obstructions"; "Instructions.RemoveObstructionsBody" = "Remove anything that covers your face, such glasses, masks, hats and scarves";