Skip to content

Commit

Permalink
setup the SmileID enhanced views
Browse files Browse the repository at this point in the history
  • Loading branch information
jumaallan committed Dec 13, 2024
1 parent a1c259a commit 495e850
Show file tree
Hide file tree
Showing 5 changed files with 119 additions and 89 deletions.
30 changes: 22 additions & 8 deletions Example/SmileID/Home/HomeView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -59,11 +59,8 @@ struct HomeView: View {
viewModel.onProductClicked()
},
content: {
SmileID.smartSelfieEnrollmentScreen(
SmileID.smartSelfieEnrollmentScreenEnhanced(
userId: viewModel.newUserId,
jobId: viewModel.newJobId,
allowAgentMode: true,
useStrictMode: true,
delegate: SmartSelfieEnrollmentDelegate(
userId: viewModel.newUserId,
onEnrollmentSuccess: viewModel.onSmartSelfieEnrollment,
Expand All @@ -79,9 +76,8 @@ struct HomeView: View {
viewModel.onProductClicked()
},
content: {
SmartSelfieAuthWithUserIdEntry(
SmartSelfieAuthEnhancedWithUserIdEntry(
initialUserId: viewModel.lastSelfieEnrollmentUserId ?? "",
useStrictMode: true,
delegate: viewModel
)
}
Expand Down Expand Up @@ -196,7 +192,6 @@ struct SmartSelfieEnrollmentDelegate: SmartSelfieResultDelegate {

private struct SmartSelfieAuthWithUserIdEntry: View {
let initialUserId: String
var useStrictMode: Bool = false
let delegate: SmartSelfieResultDelegate

@State private var userId: String?
Expand All @@ -206,7 +201,26 @@ private struct SmartSelfieAuthWithUserIdEntry: View {
SmileID.smartSelfieAuthenticationScreen(
userId: userId,
allowAgentMode: true,
useStrictMode: useStrictMode,
delegate: delegate
)
} else {
EnterUserIDView(initialUserId: initialUserId) { userId in
self.userId = userId
}
}
}
}

private struct SmartSelfieAuthEnhancedWithUserIdEntry: View {
let initialUserId: String
let delegate: SmartSelfieResultDelegate

@State private var userId: String?

var body: some View {
if let userId {
SmileID.smartSelfieAuthenticationScreenEnhanced(
userId: userId,
delegate: delegate
)
} else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,11 +67,8 @@ public class EnhancedSmartSelfieViewModel: ObservableObject {
// MARK: Injected Properties
private let isEnroll: Bool
private let userId: String
private let jobId: String
private let allowNewEnroll: Bool
private let skipApiSubmission: Bool
private let extraPartnerParams: [String: String]
private let useStrictMode: Bool
private let onResult: SmartSelfieResultDelegate
private var localMetadata: LocalMetadata

Expand All @@ -92,21 +89,15 @@ public class EnhancedSmartSelfieViewModel: ObservableObject {
public init(
isEnroll: Bool,
userId: String,
jobId: String,
allowNewEnroll: Bool,
skipApiSubmission: Bool,
extraPartnerParams: [String: String],
useStrictMode: Bool,
onResult: SmartSelfieResultDelegate,
localMetadata: LocalMetadata
) {
self.isEnroll = isEnroll
self.userId = userId
self.jobId = jobId
self.allowNewEnroll = allowNewEnroll
self.skipApiSubmission = skipApiSubmission
self.extraPartnerParams = extraPartnerParams
self.useStrictMode = useStrictMode
self.onResult = onResult
self.localMetadata = localMetadata
self.initialSetup()
Expand Down Expand Up @@ -294,8 +285,9 @@ extension EnhancedSmartSelfieViewModel {
throw SmileIDError.unknown("Error resizing selfie image")
}
self.selfieImage = flipImageForPreview(uiImage)
// we use a userId and not a jobId here
self.selfieImageURL = try LocalStorage.createSelfieFile(
jobId: jobId, selfieFile: imageData)
jobId: userId, selfieFile: imageData)
} catch {
handleError(error)
}
Expand Down Expand Up @@ -345,8 +337,9 @@ extension EnhancedSmartSelfieViewModel {
else {
throw SmileIDError.unknown("Error resizing liveness image")
}
// we use a userId and not a jobId here
let imageUrl = try LocalStorage.createLivenessFile(
jobId: jobId, livenessFile: imageData)
jobId: userId, livenessFile: imageData)
livenessImages.append(imageUrl)
} catch {
handleError(error)
Expand Down Expand Up @@ -485,15 +478,9 @@ extension EnhancedSmartSelfieViewModel: SelfieSubmissionDelegate {
// Add metadata before submission
addSelfieCaptureMetaData()

if skipApiSubmission {
// Skip API submission and update processing state to success
self.selfieCaptureState = .processing(.success)
return
}
// Create an instance of SelfieSubmissionManager to manage the submission process
let submissionManager = SelfieSubmissionManager(
userId: self.userId,
jobId: self.jobId,
isEnroll: self.isEnroll,
numLivenessImages: self.numLivenessImages,
allowNewEnroll: self.allowNewEnroll,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ protocol SelfieSubmissionDelegate: AnyObject {
final class SelfieSubmissionManager {
// MARK: - Properties
private let userId: String
private let jobId: String
private let isEnroll: Bool
private let numLivenessImages: Int
private let allowNewEnroll: Bool
Expand All @@ -28,7 +27,6 @@ final class SelfieSubmissionManager {
// MARK: - Initializer
init(
userId: String,
jobId: String,
isEnroll: Bool,
numLivenessImages: Int,
allowNewEnroll: Bool,
Expand All @@ -38,7 +36,6 @@ final class SelfieSubmissionManager {
localMetadata: LocalMetadata
) {
self.userId = userId
self.jobId = jobId
self.isEnroll = isEnroll
self.numLivenessImages = numLivenessImages
self.allowNewEnroll = allowNewEnroll
Expand Down Expand Up @@ -102,14 +99,14 @@ final class SelfieSubmissionManager {
return AuthenticationRequest(
jobType: jobType,
enrollment: isEnroll,
jobId: jobId,
userId: userId
)
}

// we need to discuss this
private func saveOfflineMode(jobType: JobType) throws {
try LocalStorage.saveOfflineJob(
jobId: jobId,
jobId: userId,
userId: userId,
jobType: jobType,
enrollment: isEnroll,
Expand Down Expand Up @@ -187,29 +184,29 @@ final class SelfieSubmissionManager {

private func updateLocalStorageAfterSuccess() throws {
// Move the job to the submitted jobs directory for record-keeping
try LocalStorage.moveToSubmittedJobs(jobId: self.jobId)
try LocalStorage.moveToSubmittedJobs(jobId: self.userId)

// Update the references to the submitted selfie and liveness images
self.selfieImageUrl = try LocalStorage.getFileByType(
jobId: jobId,
jobId: userId,
fileType: FileType.selfie,
submitted: true
)
self.livenessImages =
try LocalStorage.getFilesByType(
jobId: jobId,
jobId: userId,
fileType: FileType.liveness,
submitted: true
) ?? []
}

private func handleJobSubmissionFailure(_ smileIDError: SmileIDError) {
do {
let didMove = try LocalStorage.handleOfflineJobFailure(jobId: self.jobId, error: smileIDError)
let didMove = try LocalStorage.handleOfflineJobFailure(jobId: self.userId, error: smileIDError)
if didMove {
self.selfieImageUrl = try LocalStorage.getFileByType(jobId: jobId, fileType: .selfie, submitted: true)
self.selfieImageUrl = try LocalStorage.getFileByType(jobId: userId, fileType: .selfie, submitted: true)
self.livenessImages =
try LocalStorage.getFilesByType(jobId: jobId, fileType: .liveness, submitted: true) ?? []
try LocalStorage.getFilesByType(jobId: userId, fileType: .liveness, submitted: true) ?? []
}
} catch {
let (errorMessageRes, errorMessage) = toErrorMessage(error: smileIDError)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,37 +4,28 @@ import SwiftUI
/// Orchestrates the selfie capture flow - navigates between instructions, requesting permissions,
/// showing camera view, and displaying processing screen
public struct OrchestratedEnhancedSelfieCaptureScreen: View {
public let allowAgentMode: Bool
public let showAttribution: Bool
public let showInstructions: Bool
public let onResult: SmartSelfieResultDelegate
private let viewModel: EnhancedSmartSelfieViewModel

public init(
userId: String,
jobId: String,
isEnroll: Bool,
allowNewEnroll: Bool,
allowAgentMode: Bool,
showAttribution: Bool,
showInstructions: Bool,
useStrictMode: Bool,
extraPartnerParams: [String: String],
skipApiSubmission: Bool,
onResult: SmartSelfieResultDelegate
) {
self.allowAgentMode = allowAgentMode
self.showAttribution = showAttribution
self.showInstructions = showInstructions
self.onResult = onResult
self.viewModel = EnhancedSmartSelfieViewModel(
isEnroll: isEnroll,
userId: userId,
jobId: jobId,
allowNewEnroll: allowNewEnroll,
skipApiSubmission: skipApiSubmission,
extraPartnerParams: extraPartnerParams,
useStrictMode: useStrictMode,
onResult: onResult,
localMetadata: LocalMetadata()
)
Expand Down
129 changes: 85 additions & 44 deletions Sources/SmileID/Classes/SmileID.swift
Original file line number Diff line number Diff line change
Expand Up @@ -308,21 +308,6 @@ public class SmileID {
extraPartnerParams: [String: String] = [:],
delegate: SmartSelfieResultDelegate
) -> some View {
if useStrictMode {
OrchestratedEnhancedSelfieCaptureScreen(
userId: userId,
jobId: jobId,
isEnroll: true,
allowNewEnroll: allowNewEnroll,
allowAgentMode: allowAgentMode,
showAttribution: showAttribution,
showInstructions: showInstructions,
useStrictMode: useStrictMode,
extraPartnerParams: extraPartnerParams,
skipApiSubmission: skipApiSubmission,
onResult: delegate
)
} else {
OrchestratedSelfieCaptureScreen(
userId: userId,
jobId: jobId,
Expand All @@ -335,7 +320,39 @@ public class SmileID {
skipApiSubmission: skipApiSubmission,
onResult: delegate
)
}
}

/// Perform a SmartSelfie™ Enrollment
///
/// Docs: https://docs.usesmileid.com/products/for-individuals-kyc/biometric-authentication
///
/// - Parameters:
/// - userId: The user ID to associate with the SmartSelfie™ Enrollment. Most often, this will
/// correspond to a unique User ID within your own system. If not provided, a random user ID
/// will be generated.
/// - allowNewEnroll: Allows a partner to enroll the same user id again
/// - showAttribution: Whether to show the Smile ID attribution or not on the Instructions
/// screen
/// - showInstructions: Whether to deactivate capture screen's instructions for SmartSelfie.
/// - extraPartnerParams: Custom values specific to partners
/// - delegate: Callback to be invoked when the SmartSelfie™ Enrollment is complete.
@ViewBuilder public class func smartSelfieEnrollmentScreenEnhanced(
userId: String = generateUserId(),
allowNewEnroll: Bool = false,
showAttribution: Bool = true,
showInstructions: Bool = true,
extraPartnerParams: [String: String] = [:],
delegate: SmartSelfieResultDelegate
) -> some View {
OrchestratedEnhancedSelfieCaptureScreen(
userId: userId,
isEnroll: true,
allowNewEnroll: allowNewEnroll,
showAttribution: showAttribution,
showInstructions: showInstructions,
extraPartnerParams: extraPartnerParams,
onResult: delegate
)
}

/// Perform a SmartSelfie™ Authentication
Expand Down Expand Up @@ -370,34 +387,58 @@ public class SmileID {
extraPartnerParams: [String: String] = [:],
delegate: SmartSelfieResultDelegate
) -> some View {
if useStrictMode {
OrchestratedEnhancedSelfieCaptureScreen(
userId: userId,
jobId: jobId,
isEnroll: false,
allowNewEnroll: allowNewEnroll,
allowAgentMode: allowAgentMode,
showAttribution: showAttribution,
showInstructions: showInstructions,
useStrictMode: useStrictMode,
extraPartnerParams: extraPartnerParams,
skipApiSubmission: false,
onResult: delegate
)
} else {
OrchestratedSelfieCaptureScreen(
userId: userId,
jobId: jobId,
isEnroll: false,
allowNewEnroll: allowNewEnroll,
allowAgentMode: allowAgentMode,
showAttribution: showAttribution,
showInstructions: showInstructions,
extraPartnerParams: extraPartnerParams,
skipApiSubmission: false,
onResult: delegate
)
}
OrchestratedSelfieCaptureScreen(
userId: userId,
jobId: jobId,
isEnroll: false,
allowNewEnroll: allowNewEnroll,
allowAgentMode: allowAgentMode,
showAttribution: showAttribution,
showInstructions: showInstructions,
extraPartnerParams: extraPartnerParams,
skipApiSubmission: false,
onResult: delegate
)
}

/// Perform a SmartSelfie™ Authentication
///
/// Docs: https://docs.usesmileid.com/products/for-individuals-kyc/biometric-authentication
///
/// - Parameters:
/// - userId: The user ID to associate with the SmartSelfie™ Enrollment. Most often, this will
/// correspond to a unique User ID within your own system. If not provided, a random user ID
/// will be generated.
/// - jobId: The job ID to associate with the SmartSelfie™ Enrollment. Most often, this will
/// correspond to a unique Job ID within your own system. If not provided, a random job ID
/// will be generated.
/// - allowNewEnroll: Allows a partner to enroll the same user id again
/// - allowAgentMode: Whether to allow Agent Mode or not. If allowed, a switch will be
/// displayed allowing toggling between the back camera and front camera. If not allowed,
/// only the front camera will be used.
/// - showAttribution: Whether to show the Smile ID attribution or not on the Instructions
/// screen
/// - showInstructions: Whether to deactivate capture screen's instructions for SmartSelfie.
/// - skipApiSubmission: Whether to skip api submission to SmileID and return only captured images
/// - extraPartnerParams: Custom values specific to partners
/// - delegate: Callback to be invoked when the SmartSelfie™ Authentication is complete.
@ViewBuilder public class func smartSelfieAuthenticationScreenEnhanced(
userId: String,
allowNewEnroll: Bool = false,
showAttribution: Bool = true,
showInstructions: Bool = true,
extraPartnerParams: [String: String] = [:],
delegate: SmartSelfieResultDelegate
) -> some View {
OrchestratedEnhancedSelfieCaptureScreen(
userId: userId,
isEnroll: false,
allowNewEnroll: allowNewEnroll,
showAttribution: showAttribution,
showInstructions: showInstructions,
extraPartnerParams: extraPartnerParams,
onResult: delegate
)
}

/// Perform a Document Verification
Expand Down

0 comments on commit 495e850

Please sign in to comment.