diff --git a/Sample App/Podfile b/Sample App/Podfile index 7080bdb..6c45639 100644 --- a/Sample App/Podfile +++ b/Sample App/Podfile @@ -14,6 +14,7 @@ source 'https://cdn.cocoapods.org/' source 'https://github.com/circlefin/w3s-ios-sdk.git' +platform :ios, '13.0' target 'w3s-ios-sample-app-wallets' do # Comment the next line if you don't want to use dynamic frameworks diff --git a/Sample App/w3s-ios-sample-app-wallets.xcodeproj/project.pbxproj b/Sample App/w3s-ios-sample-app-wallets.xcodeproj/project.pbxproj index 8fd8dfa..43ac279 100644 --- a/Sample App/w3s-ios-sample-app-wallets.xcodeproj/project.pbxproj +++ b/Sample App/w3s-ios-sample-app-wallets.xcodeproj/project.pbxproj @@ -17,6 +17,7 @@ B3BEDEDF2A5064E800861533 /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B3BEDEDD2A5064E800861533 /* ContentView.swift */; }; B3BEDEE62A50651700861533 /* UserDefault.swift in Sources */ = {isa = PBXBuildFile; fileRef = B3BEDEE32A50651700861533 /* UserDefault.swift */; }; B3BEDEE82A50651700861533 /* Toast.swift in Sources */ = {isa = PBXBuildFile; fileRef = B3BEDEE52A50651700861533 /* Toast.swift */; }; + BAE182562AF36AD3004D6494 /* ChallengeResultView.swift in Sources */ = {isa = PBXBuildFile; fileRef = BAE182552AF36AD3004D6494 /* ChallengeResultView.swift */; }; /* End PBXBuildFile section */ /* Begin PBXFileReference section */ @@ -31,6 +32,7 @@ B3BEDEDD2A5064E800861533 /* ContentView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = ""; }; B3BEDEE32A50651700861533 /* UserDefault.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UserDefault.swift; sourceTree = ""; }; B3BEDEE52A50651700861533 /* Toast.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Toast.swift; sourceTree = ""; }; + BAE182552AF36AD3004D6494 /* ChallengeResultView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ChallengeResultView.swift; sourceTree = ""; }; ED19DFB9C55BB7A8A6609DD9 /* Pods-w3s-ios-sample-app-wallets.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-w3s-ios-sample-app-wallets.release.xcconfig"; path = "Target Support Files/Pods-w3s-ios-sample-app-wallets/Pods-w3s-ios-sample-app-wallets.release.xcconfig"; sourceTree = ""; }; F095FAC15E5990E5728EEDA8 /* Pods_w3s_ios_sample_app_wallets.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_w3s_ios_sample_app_wallets.framework; sourceTree = BUILT_PRODUCTS_DIR; }; /* End PBXFileReference section */ @@ -88,6 +90,7 @@ B3CD172C2A5DA09D000664EA /* Resources */, B3BEDECE2A50648300861533 /* w3s_ios_sample_app_walletsApp.swift */, B3BEDEDD2A5064E800861533 /* ContentView.swift */, + BAE182552AF36AD3004D6494 /* ChallengeResultView.swift */, B3BEDEDC2A5064E800861533 /* WalletSdkAdapter.swift */, B3BEDEE22A50651700861533 /* Helpers */, B3BEDED42A50648400861533 /* Preview Content */, @@ -243,6 +246,7 @@ B3BEDECF2A50648300861533 /* w3s_ios_sample_app_walletsApp.swift in Sources */, B3BEDEDE2A5064E800861533 /* WalletSdkAdapter.swift in Sources */, B3BEDEDF2A5064E800861533 /* ContentView.swift in Sources */, + BAE182562AF36AD3004D6494 /* ChallengeResultView.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -376,6 +380,7 @@ ENABLE_PREVIEWS = YES; GENERATE_INFOPLIST_FILE = YES; INFOPLIST_KEY_CFBundleDisplayName = "w3s-ios-sample"; + INFOPLIST_KEY_NSFaceIDUsageDescription = "Enable Biometrics PIN"; INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES; INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES; INFOPLIST_KEY_UILaunchScreen_Generation = YES; @@ -408,6 +413,7 @@ ENABLE_PREVIEWS = YES; GENERATE_INFOPLIST_FILE = YES; INFOPLIST_KEY_CFBundleDisplayName = "w3s-ios-sample"; + INFOPLIST_KEY_NSFaceIDUsageDescription = "Enable Biometrics PIN"; INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES; INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES; INFOPLIST_KEY_UILaunchScreen_Generation = YES; diff --git a/Sample App/w3s-ios-sample-app-wallets/ChallengeResultView.swift b/Sample App/w3s-ios-sample-app-wallets/ChallengeResultView.swift new file mode 100644 index 0000000..4f4af96 --- /dev/null +++ b/Sample App/w3s-ios-sample-app-wallets/ChallengeResultView.swift @@ -0,0 +1,111 @@ +// +// ChallengeResultView.swift +// w3s-ios-sample-app-wallets +// +// Created by CIRCLE on 2023/11/1. +// + +import SwiftUI +import CircleProgrammableWalletSDK + +struct ChallengeResultView: View { + var executeResult: CircleProgrammableWalletSDK.ExecuteCompletionStruct + + @Binding var path: NavigationPath + + @State var challengeId: String = "" + + @State var showToast = false + @State var toastMessage: String? + @State var toastConfig: Toast.Config = .init() + + var body: some View { + VStack { + List { + /// Section I + if let challengeId = executeResult.challenges.first { + sectionInputField("Challenge ID", text: challengeId) + } + + /// Section II + switch executeResult.result { + case .success(let result): + let challeangeType = result.resultType.rawValue + sectionInputField("Challeange Type", text: challeangeType) + + let challengeStatus = result.status.rawValue + sectionInputField("Challenge Status", text: challengeStatus) + + /// Support from version 1.0.11 (622) + if let signature = result.data?.signature { + sectionInputField("Signature", text: signature) + } + + case .failure(let error): + let errorCode = error.errorCode + sectionInputField("Error Code", text: String(describing: errorCode)) + + let errorDisplayString = error.displayString + sectionInputField("Error Message", text: errorDisplayString) + } + + /// Section III + if let executeWarning = executeResult.onWarning { + let warningType = executeWarning.warningType + sectionInputField("Warning Type", text: String(describing: warningType)) + + let warningString = executeWarning.warningString + sectionInputField("Warning Message", text: warningString) + } + } + .listStyle(InsetGroupedListStyle()) + versionText + } + .navigationBarBackButtonHidden() + .toolbar { + ToolbarItem(placement: ToolbarItemPlacement.navigationBarLeading) { + Button { + path.removeLast() + } label: { + Image(uiImage: UIImage(named: "ic_navi_back")!) + } + } + } + .toast(message: toastMessage ?? "", + isShowing: $showToast, + config: toastConfig) + } + + var versionText: some View { + Text("CircleProgrammableWalletSDK - \(WalletSdk.shared.sdkVersion() ?? "")").font(.footnote) + } + + func sectionInputField(_ title: String, text: String) -> Section { + Section { + Button(action: { + UIPasteboard.general.string = text + showToast(message: "Copied: \(text)") + }) { + Text(text) + .foregroundColor(.black) + .frame(maxWidth: .infinity, alignment: .leading) + .multilineTextAlignment(.leading) + } + .buttonStyle(.bordered) + .buttonBorderShape(.roundedRectangle) + } header: { + Text(title + " :") + } + } +} + +extension ChallengeResultView { + + func showToast(message: String) { + toastMessage = message + showToast = true + + toastConfig = Toast.Config() + } + +} diff --git a/Sample App/w3s-ios-sample-app-wallets/ContentView.swift b/Sample App/w3s-ios-sample-app-wallets/ContentView.swift index 8e0ad6a..c4e8728 100644 --- a/Sample App/w3s-ios-sample-app-wallets/ContentView.swift +++ b/Sample App/w3s-ios-sample-app-wallets/ContentView.swift @@ -25,26 +25,35 @@ struct ContentView: View { @State var userToken = "" @State var encryptionKey = "" @State var challengeId = "" + @State var enableBiometrics = false @State var showToast = false @State var toastMessage: String? @State var toastConfig: Toast.Config = .init() + @State var path = NavigationPath() + var body: some View { - VStack { - List { - titleText - sectionEndPoint - sectionInputField("App ID", binding: $appId) - sectionInputField("User Token", binding: $userToken) - sectionInputField("Encryption Key", binding: $encryptionKey) - sectionInputField("Challenge ID", binding: $challengeId) - sectionExecuteButton - - Spacer() -// TestButtons + NavigationStack(path: $path) { + VStack { + List { + titleText + sectionEndPoint + sectionInputField("App ID", binding: $appId) + sectionInputField("User Token", binding: $userToken) + sectionInputField("Encryption Key", binding: $encryptionKey) + sectionInputField("Challenge ID", binding: $challengeId) + sectionToggle("Biometrics", binding: $enableBiometrics) + sectionButtons + +// TestButtons + } + .listStyle(InsetGroupedListStyle()) + versionText + } + .navigationDestination(for: CircleProgrammableWalletSDK.ExecuteCompletionStruct.self) { executeResult in + ChallengeResultView(executeResult: executeResult, path: $path) } - versionText } .scrollContentBackground(.hidden) .onAppear { @@ -55,9 +64,16 @@ struct ContentView: View { } } .onChange(of: appId) { newValue in - self.adapter.updateEndPoint(endPoint, appId: newValue) + if let errStr = self.adapter.updateEndPoint(endPoint, appId: newValue, biometrics: enableBiometrics) { + showToast(.failure, message: "Error: " + errStr) + } self.adapter.storedAppId = newValue } + .onChange(of: enableBiometrics) { newValue in + if let errStr = self.adapter.updateEndPoint(endPoint, appId: appId, biometrics: newValue) { + showToast(.failure, message: "Error: " + errStr) + } + } .toast(message: toastMessage ?? "", isShowing: $showToast, config: toastConfig) @@ -88,7 +104,26 @@ struct ContentView: View { } } - var sectionExecuteButton: some View { + func sectionToggle(_ title: String, binding: Binding) -> some View { + Section { + Toggle(isOn: binding) { + HStack { + Text(title) + Image(systemName: "faceid") + } + } + } + } + + var sectionButtons: some View { + Section { + executeButton + setBiometricsButton + Spacer() + } + } + + var executeButton: some View { Button { guard !userToken.isEmpty else { showToast(.general, message: "User Token is Empty"); return } guard !encryptionKey.isEmpty else { showToast(.general, message: "Encryption Key is Empty"); return } @@ -102,6 +137,28 @@ struct ContentView: View { .buttonStyle(.borderedProminent) .listRowSeparator(.hidden) } + + var setBiometricsButton: some View { + Button { + biometricsPIN(userToken: userToken, encryptionKey: encryptionKey) + } label: { + Text("Set Biometrics") + .frame(maxWidth: .infinity) + } + .buttonStyle(.borderedProminent) + .listRowSeparator(.hidden) + .padding([.top], 8) + } +} + +extension CircleProgrammableWalletSDK.ExecuteCompletionStruct: Hashable { + public func hash(into hasher: inout Hasher) { + hasher.combine(challenges) + } + + public static func == (lhs: CircleProgrammableWalletSDK.ExecuteCompletionStruct, rhs: CircleProgrammableWalletSDK.ExecuteCompletionStruct) -> Bool { + return lhs.challenges.first == rhs.challenges.first + } } extension ContentView { @@ -127,10 +184,48 @@ extension ContentView { } func executeChallenge(userToken: String, encryptionKey: String, challengeId: String) { + var showChallengeResult = true + WalletSdk.shared.execute(userToken: userToken, encryptionKey: encryptionKey, challengeIds: [challengeId]) { response in switch response.result { + case .success(let result): + let challengeStatus = result.status.rawValue + let challeangeType = result.resultType.rawValue + let warningType = response.onWarning?.warningType + let warningString = warningType != nil ? + " (\(warningType!))" : "" + showToast(.success, message: "\(challeangeType) - \(challengeStatus)\(warningString)") + + response.onErrorController?.dismiss(animated: true) + + case .failure(let error): + showToast(.failure, message: "Error: " + error.displayString) + errorHandler(apiError: error, onErrorController: response.onErrorController) + + if error.errorCode == .userCanceled { + showChallengeResult = false + } + } + + if let onWarning = response.onWarning { + print(onWarning) + } + + if showChallengeResult { + path.append(response) + } + } + } + + func biometricsPIN(userToken: String, encryptionKey: String) { + guard !userToken.isEmpty else { showToast(.general, message: "User Token is Empty"); return } + guard !encryptionKey.isEmpty else { showToast(.general, message: "Encryption Key is Empty"); return } + + WalletSdk.shared.setBiometricsPin(userToken: userToken, encryptionKey: encryptionKey) { + response in + switch response.result { case .success(let result): let challengeStatus = result.status.rawValue let challeangeType = result.resultType.rawValue @@ -145,7 +240,16 @@ extension ContentView { func errorHandler(apiError: ApiError, onErrorController: UINavigationController?) { switch apiError.errorCode { - case .userHasSetPin: + case .userHasSetPin, + .biometricsSettingNotEnabled, + .deviceNotSupportBiometrics, + .biometricsKeyPermanentlyInvalidated, + .biometricsUserSkip, + .biometricsUserDisableForPin, + .biometricsUserLockout, + .biometricsUserLockoutPermanent, + .biometricsUserNotAllowPermission, + .biometricsInternalError: onErrorController?.dismiss(animated: true) default: break @@ -158,6 +262,9 @@ extension ContentView { Button("Change PIN", action: changePIN) Button("Restore PIN", action: restorePIN) Button("Enter PIN", action: enterPIN) + Button("Set Biometrics PIN") { + biometricsPIN(userToken: userToken, encryptionKey: encryptionKey) + } } header: { Text("UI Customization Entry") diff --git a/Sample App/w3s-ios-sample-app-wallets/Resources/Assets.xcassets/eye_closed.imageset/Contents.json b/Sample App/w3s-ios-sample-app-wallets/Resources/Assets.xcassets/eye_closed.imageset/Contents.json new file mode 100644 index 0000000..9152deb --- /dev/null +++ b/Sample App/w3s-ios-sample-app-wallets/Resources/Assets.xcassets/eye_closed.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "eye_closed.pdf", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Sample App/w3s-ios-sample-app-wallets/Resources/Assets.xcassets/eye_closed.imageset/eye_closed.pdf b/Sample App/w3s-ios-sample-app-wallets/Resources/Assets.xcassets/eye_closed.imageset/eye_closed.pdf new file mode 100644 index 0000000..4f239ba Binary files /dev/null and b/Sample App/w3s-ios-sample-app-wallets/Resources/Assets.xcassets/eye_closed.imageset/eye_closed.pdf differ diff --git a/Sample App/w3s-ios-sample-app-wallets/Resources/Assets.xcassets/eye_open.imageset/Contents.json b/Sample App/w3s-ios-sample-app-wallets/Resources/Assets.xcassets/eye_open.imageset/Contents.json new file mode 100644 index 0000000..53a1edb --- /dev/null +++ b/Sample App/w3s-ios-sample-app-wallets/Resources/Assets.xcassets/eye_open.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "eye_open.pdf", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Sample App/w3s-ios-sample-app-wallets/Resources/Assets.xcassets/eye_open.imageset/eye_open.pdf b/Sample App/w3s-ios-sample-app-wallets/Resources/Assets.xcassets/eye_open.imageset/eye_open.pdf new file mode 100644 index 0000000..72d7560 Binary files /dev/null and b/Sample App/w3s-ios-sample-app-wallets/Resources/Assets.xcassets/eye_open.imageset/eye_open.pdf differ diff --git a/Sample App/w3s-ios-sample-app-wallets/Resources/Assets.xcassets/ic_biometrics.imageset/Contents.json b/Sample App/w3s-ios-sample-app-wallets/Resources/Assets.xcassets/ic_biometrics.imageset/Contents.json new file mode 100644 index 0000000..b53e1f5 --- /dev/null +++ b/Sample App/w3s-ios-sample-app-wallets/Resources/Assets.xcassets/ic_biometrics.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "ic_biometrics.pdf", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Sample App/w3s-ios-sample-app-wallets/Resources/Assets.xcassets/ic_biometrics.imageset/ic_biometrics.pdf b/Sample App/w3s-ios-sample-app-wallets/Resources/Assets.xcassets/ic_biometrics.imageset/ic_biometrics.pdf new file mode 100644 index 0000000..d2740fb Binary files /dev/null and b/Sample App/w3s-ios-sample-app-wallets/Resources/Assets.xcassets/ic_biometrics.imageset/ic_biometrics.pdf differ diff --git a/Sample App/w3s-ios-sample-app-wallets/Resources/CirclePWLocalizable.strings b/Sample App/w3s-ios-sample-app-wallets/Resources/CirclePWLocalizable.strings index 80f5c28..12222e3 100644 --- a/Sample App/w3s-ios-sample-app-wallets/Resources/CirclePWLocalizable.strings +++ b/Sample App/w3s-ios-sample-app-wallets/Resources/CirclePWLocalizable.strings @@ -8,11 +8,10 @@ */ // [General] -"circlepw_show_pin" = "Show PIN"; -"circlepw_hide_pin" = "Hide PIN"; "circlepw_continue" = "Continue"; "circlepw_next" = "Next"; "circlepw_confirm" = "Confirm"; +"circlepw_skip" = "Skip"; "circlepw_question" = "Question"; "circlepw_answer" = "Answer"; @@ -24,6 +23,7 @@ "circlepw_enter_pincode_headline_2" = "PIN"; "circlepw_enter_pincode_subhead" = "Let us know if it’s really you."; "circlepw_enter_pincode_forgot_pin" = "Forgot PIN?"; +"circlepw_enter_pincode_use_biometrics" = "Use Biometrics"; // [Page] NewPINCode "circlepw_new_pincode_headline" = "Enter your"; @@ -36,13 +36,14 @@ "circlepw_confirm_pincode_subhead" = ""; // [Page] SecurityIntros +"circlepw_security_intros_title" = "Recovery Method"; "circlepw_security_intros_headline" = "Set up your"; "circlepw_security_intros_headline_2" = "Recovery Method"; "circlepw_security_intros_description" = "This is the only way to recover wallet access if you forget your PIN. Pick 2 security questions and provide answers for access recovery."; "circlepw_security_intros_link" = "Learn more"; // [Page] SecurityQuestions -"circlepw_security_questions_title" = "Recovery method"; +"circlepw_security_questions_title" = "Recovery Method"; "circlepw_security_questions_question_header" = "Choose your %@ question"; "circlepw_security_questions_question_placeholder" = "Select one question"; "circlepw_security_questions_required_mark" = "*"; @@ -70,3 +71,12 @@ "circlepw_recover_pincode_subhead" = "Please enter the answer of the security questions provided below."; "circlepw_recover_pincode_answer_input_header" = "Enter your answer here"; "circlepw_recover_pincode_answer_input_placeholder" = "Type your answer here"; + +// [Page] BiometricsPrompt +"circlepw_pin_biometrics_allow_title" = "Allow Biometrics for Web3 Access"; +"circlepw_pin_biometrics_allow_subtitle" = "Elevate Your Experience with Effortless Biometrics"; +"circlepw_pin_biometrics_failed_title" = "Failed Biometrics for Web3 Access"; +"circlepw_pin_biometrics_update_title" = "Update Biometrics for Web3 Access"; +"circlepw_pin_biometrics_update_subtitle" = "Please update your biometrics"; +"circlepw_pin_biometrics_disable" = "Don't ask me again"; +"circlepw_pin_touch_id_dialog_subtitle" = "Using Touch ID protect PIN"; diff --git a/Sample App/w3s-ios-sample-app-wallets/Resources/CirclePWTheme.json b/Sample App/w3s-ios-sample-app-wallets/Resources/CirclePWTheme.json index f188a63..f78b2b8 100644 --- a/Sample App/w3s-ios-sample-app-wallets/Resources/CirclePWTheme.json +++ b/Sample App/w3s-ios-sample-app-wallets/Resources/CirclePWTheme.json @@ -14,7 +14,7 @@ "color": { "background": "#FFFFFF", "divider": "#F0EFEF", - "success": "#0073C3", + "success": "#0B9C4A", "error": "#F55538", "error_background": "#FDF2F2", @@ -27,10 +27,13 @@ "text_placeholder": "#A3A3A3", "text_action": "#136FD8", "text_action_pressed": "#B3136FD8", + "text_prompt": "#29233B", + "text_prompt2": "#6B6580", "pin_dot_base": "#FFFFFF", "pin_dot_base_border": "#707070", - "pin_dot_activated": "#3D3D3D", + "pin_dot_activated": "#0073C3", + "pin_dot_focused": "#0073C3", "input_border": "#E8E8E8", "input_border_focused": "#46B5FF", @@ -43,6 +46,15 @@ "main_bt_background_pressed": "#1AA3FF", "main_bt_background_disabled": "#F5F5F5", + "second_bt_text": "#0073C3", + "second_bt_border": "#0073C3", + "second_bt_background": "#FFFFFF", + "second_bt_background_pressed": "#F1F9FE", + + "plain_bt_text": "#0073C3", + "plain_bt_background": "#FFFFFF", + "plain_bt_background_pressed": "#F1F9FE", + "recover_pin_hint_title": "#3D3652", "recover_pin_hint_title_bg": "#E1F2FF", "recover_pin_hint": "#0073C3", diff --git a/Sample App/w3s-ios-sample-app-wallets/WalletSdkAdapter.swift b/Sample App/w3s-ios-sample-app-wallets/WalletSdkAdapter.swift index 43bed29..f963d36 100644 --- a/Sample App/w3s-ios-sample-app-wallets/WalletSdkAdapter.swift +++ b/Sample App/w3s-ios-sample-app-wallets/WalletSdkAdapter.swift @@ -28,15 +28,28 @@ class WalletSdkAdapter { WalletSdk.shared.setDelegate(self) } - func updateEndPoint(_ endPoint: String, appId: String) { + @discardableResult + func updateEndPoint(_ endPoint: String, appId: String, biometrics: Bool = false) -> String? { let _appId = appId.trimmingCharacters(in: .whitespacesAndNewlines) - let configuration = WalletSdk.Configuration(endPoint: endPoint, appId: _appId) + let settings: WalletSdk.SettingsManagement = .init(enableBiometricsPin: biometrics) + let configuration = WalletSdk.Configuration(endPoint: endPoint, appId: _appId, settingsManagement: settings) do { try WalletSdk.shared.setConfiguration(configuration) print("Configuration Success") + return nil } catch { + let configurationErrorString: String + if let apiError = error as? ApiError { + print(apiError) + configurationErrorString = apiError.displayString + } else { + print(error.localizedDescription) + configurationErrorString = error.localizedDescription + } + + return configurationErrorString } } } @@ -78,7 +91,10 @@ extension WalletSdkAdapter: WalletSdkLayoutProvider { .dropdownArrow: UIImage(named: "ic_trailing_down")!, .errorInfo: UIImage(named: "ic_warning_alt")!, .securityIntroMain: UIImage(named: "img_security_intro")!, - .securityConfirmMain: UIImage(named: "img_confirmation")! + .securityConfirmMain: UIImage(named: "img_confirmation")!, + .biometricsAllowMain: UIImage(named: "ic_biometrics")!, + .hidePin: UIImage(named: "eye_closed")!, + .showPin: UIImage(named: "eye_open")! ] let remote: [ImageStore.Img: URL] = [:] @@ -150,7 +166,7 @@ extension WalletSdkAdapter: ErrorMessenger { return nil - // MARK: Sample - Error message customization + // MARK: Sample - Error message customization // switch code { // case .hintsMatchAnswers: // return "Your custom error message."