From 43a5c6ebc7f2d6faf0be8f1fb9a36e0634c635e7 Mon Sep 17 00:00:00 2001 From: StephenHeaps <5314553+StephenHeaps@users.noreply.github.com> Date: Thu, 7 Dec 2023 09:15:45 -0500 Subject: [PATCH] Fix brave/brave-ios#8345, brave/brave-ios#8425: Add 'Creating Wallet...' step to onboarding (brave/brave-ios#8509) * Check for wallet existing before creating Wallet to prevent possible race condition with multi-window. * Add 'Creating Wallet...' step to onboarding for when asynchronous create wallet / restore wallet functions are setting up the wallet and fetching wallet data files. * Fix Wallet re-opened before create/restore wallet callback returns. * Use old api for `ToolbarItemPlacement` as CI is using older Xcode version. * Address PR comments; Fix backup banner showing until network call to fetch wallet data returns after wallet restore. Banner would only be visible if wallet is dismissed and re-opened prior to callback. Fix wallet dismiss on wallet lock. * Address PR comment; Fix `CreatingWalletView` not covering fullscreen by overlaying on ScrollView instead of only on contents. --- Sources/BraveWallet/Crypto/CryptoView.swift | 4 +- .../Crypto/Onboarding/CreateWalletView.swift | 226 ++++++++++-------- .../Crypto/Onboarding/LegalView.swift | 26 +- .../Crypto/Onboarding/RestoreWalletView.swift | 92 ++++--- .../Crypto/Onboarding/SetupCryptoView.swift | 20 +- .../Crypto/Stores/KeyringStore.swift | 44 +++- .../BraveWallet/Crypto/UnlockWalletView.swift | 10 +- .../WalletHostingViewController.swift | 2 +- Sources/BraveWallet/WalletStrings.swift | 7 + 9 files changed, 278 insertions(+), 153 deletions(-) diff --git a/Sources/BraveWallet/Crypto/CryptoView.swift b/Sources/BraveWallet/Crypto/CryptoView.swift index 0b3bef368ffc..d62dcbb8eb28 100644 --- a/Sources/BraveWallet/Crypto/CryptoView.swift +++ b/Sources/BraveWallet/Crypto/CryptoView.swift @@ -236,7 +236,7 @@ public struct CryptoView: View { } case .unlock: UIKitNavigationView { - UnlockWalletView(keyringStore: keyringStore) + UnlockWalletView(keyringStore: keyringStore, dismissAction: dismissAction) .toolbar { dismissButtonToolbarContents } @@ -252,7 +252,7 @@ public struct CryptoView: View { .zIndex(2) // Needed or the dismiss animation messes up } else { UIKitNavigationView { - SetupCryptoView(keyringStore: keyringStore) + SetupCryptoView(keyringStore: keyringStore, dismissAction: dismissAction) .toolbar { ToolbarItemGroup(placement: .destructiveAction) { Button(action: { diff --git a/Sources/BraveWallet/Crypto/Onboarding/CreateWalletView.swift b/Sources/BraveWallet/Crypto/Onboarding/CreateWalletView.swift index 88c4fc48f16e..83997973870e 100644 --- a/Sources/BraveWallet/Crypto/Onboarding/CreateWalletView.swift +++ b/Sources/BraveWallet/Crypto/Onboarding/CreateWalletView.swift @@ -5,40 +5,11 @@ import Foundation import SwiftUI +import BraveUI import DesignSystem import Strings import struct Shared.AppConstants -struct RestorePackage { - let recoveryWords: [String] - let onRestoreCompleted: (_ status: Bool, _ validPassword: String) -> Void - var isLegacyWallet: Bool { - recoveryWords.count == .legacyWalletRecoveryPhraseNumber - } -} - -struct CreateWalletContainerView: View { - @ObservedObject var keyringStore: KeyringStore - var restorePackage: RestorePackage? - - init(keyringStore: KeyringStore, restorePackage: RestorePackage? = nil) { - self.keyringStore = keyringStore - self.restorePackage = restorePackage - } - - var body: some View { - ScrollView(.vertical) { - CreateWalletView( - keyringStore: keyringStore, - restorePackage: restorePackage - ) - .background(Color(.braveBackground)) - } - .background(Color(.braveBackground).edgesIgnoringSafeArea(.all)) - .transparentNavigationBar(backButtonTitle: Strings.Wallet.createWalletBackButtonTitle, backButtonDisplayMode: .generic) - } -} - private enum ValidationError: LocalizedError, Equatable { case requirementsNotMet case inputsDontMatch @@ -53,9 +24,12 @@ private enum ValidationError: LocalizedError, Equatable { } } -private struct CreateWalletView: View { +struct CreateWalletView: View { @ObservedObject var keyringStore: KeyringStore - var restorePackage: RestorePackage? + let setupOption: OnboardingSetupOption + let onValidPasswordEntered: ((_ validPassword: String) -> Void)? + // Used to dismiss all of Wallet + let dismissAction: () -> Void @State private var password: String = "" @State private var repeatedPassword: String = "" @@ -63,25 +37,39 @@ private struct CreateWalletView: View { @State private var isNewWalletCreated: Bool = false @State private var passwordStatus: PasswordStatus = .none @State private var isInputsMatch: Bool = false + /// If this view is showing `Creating Wallet...` overlay, blocking input fields. + /// Using a local flag for the view instead of `keyringStore.isCreatingWallet` so we + /// only show `CreatingWalletView` on the `RestoreWalletView` when restoring. + @State private var isShowingCreatingWallet: Bool = false @FocusState private var isFieldFocused: Bool + + init( + keyringStore: KeyringStore, + setupOption: OnboardingSetupOption, + onValidPasswordEntered: ((_ validPassword: String) -> Void)? = nil, + dismissAction: @escaping () -> Void + ) { + self.keyringStore = keyringStore + self.setupOption = setupOption + self.onValidPasswordEntered = onValidPasswordEntered + self.dismissAction = dismissAction + } private func createWallet() { - if let restorePackage { - // restore wallet with recovery phrases and a new password - keyringStore.restoreWallet( - words: restorePackage.recoveryWords, - password: password, - isLegacyBraveWallet: restorePackage.isLegacyWallet - ) { success in - restorePackage.onRestoreCompleted(success, password) - } - } else { + switch setupOption { + case .new: + isShowingCreatingWallet = true keyringStore.createWallet(password: password) { mnemonic in + defer { self.isShowingCreatingWallet = false } if let mnemonic, !mnemonic.isEmpty { isNewWalletCreated = true } } + case .restore: + if isInputsMatch { + onValidPasswordEntered?(password) + } } } @@ -127,7 +115,7 @@ private struct CreateWalletView: View { } } - func errorLabel(_ error: ValidationError?) -> some View { + private func errorLabel(_ error: ValidationError?) -> some View { HStack(spacing: 12) { Image(braveSystemName: "leo.warning.circle-filled") .renderingMode(.template) @@ -151,65 +139,67 @@ private struct CreateWalletView: View { } var body: some View { - VStack(spacing: 16) { - VStack { - Text(Strings.Wallet.createWalletTitle) - .font(.title) - .padding(.bottom) - .multilineTextAlignment(.center) - .foregroundColor(Color(uiColor: WalletV2Design.textPrimary)) - Text(Strings.Wallet.createWalletSubTitle) - .font(.subheadline) - .padding(.bottom) - .multilineTextAlignment(.center) - .foregroundColor(Color(uiColor: WalletV2Design.textSecondary)) - } - VStack(alignment: .leading, spacing: 20) { - VStack(spacing: 30) { - VStack(alignment: .leading, spacing: 10) { - Text(Strings.Wallet.newPasswordPlaceholder) - .foregroundColor(Color(uiColor: WalletV2Design.textPrimary)) - HStack(spacing: 8) { - SecureField(Strings.Wallet.newPasswordPlaceholder, text: $password) - .textContentType(.newPassword) - .focused($isFieldFocused) - Spacer() - if passwordStatus != .none { - passwordStatusView(passwordStatus) + ScrollView(.vertical) { + VStack(spacing: 16) { + VStack { + Text(Strings.Wallet.createWalletTitle) + .font(.title) + .padding(.bottom) + .multilineTextAlignment(.center) + .foregroundColor(Color(uiColor: WalletV2Design.textPrimary)) + Text(Strings.Wallet.createWalletSubTitle) + .font(.subheadline) + .padding(.bottom) + .multilineTextAlignment(.center) + .foregroundColor(Color(uiColor: WalletV2Design.textSecondary)) + } + VStack(alignment: .leading, spacing: 20) { + VStack(spacing: 30) { + VStack(alignment: .leading, spacing: 10) { + Text(Strings.Wallet.newPasswordPlaceholder) + .foregroundColor(Color(uiColor: WalletV2Design.textPrimary)) + HStack(spacing: 8) { + SecureField(Strings.Wallet.newPasswordPlaceholder, text: $password) + .textContentType(.newPassword) + .focused($isFieldFocused) + Spacer() + if passwordStatus != .none { + passwordStatusView(passwordStatus) + } } + Divider() } - Divider() - } - VStack(alignment: .leading, spacing: 12) { - Text(Strings.Wallet.repeatedPasswordPlaceholder) - .foregroundColor(.primary) - HStack(spacing: 8) { - SecureField(Strings.Wallet.repeatedPasswordPlaceholder, text: $repeatedPassword, onCommit: createWallet) - .textContentType(.newPassword) - Spacer() - if isInputsMatch { - Text("\(Image(braveSystemName: "leo.check.normal")) \(Strings.Wallet.repeatedPasswordMatch)") - .multilineTextAlignment(.trailing) - .font(.footnote) - .foregroundColor(.secondary) + VStack(alignment: .leading, spacing: 12) { + Text(Strings.Wallet.repeatedPasswordPlaceholder) + .foregroundColor(.primary) + HStack(spacing: 8) { + SecureField(Strings.Wallet.repeatedPasswordPlaceholder, text: $repeatedPassword, onCommit: createWallet) + .textContentType(.newPassword) + Spacer() + if isInputsMatch { + Text("\(Image(braveSystemName: "leo.check.normal")) \(Strings.Wallet.repeatedPasswordMatch)") + .multilineTextAlignment(.trailing) + .font(.footnote) + .foregroundColor(.secondary) + } } + Divider() } - Divider() } + .font(.subheadline) + errorLabel(validationError) } - .font(.subheadline) - errorLabel(validationError) - } - Button(action: createWallet) { - Text(Strings.Wallet.continueButtonTitle) - .frame(maxWidth: .infinity) + Button(action: createWallet) { + Text(Strings.Wallet.continueButtonTitle) + .frame(maxWidth: .infinity) + } + .buttonStyle(BraveFilledButtonStyle(size: .large)) + .disabled(isContinueDisabled) + .padding(.top, 60) } - .buttonStyle(BraveFilledButtonStyle(size: .large)) - .disabled(isContinueDisabled) - .padding(.top, 60) + .padding(.horizontal, 20) + .padding(.bottom, 20) } - .padding(.horizontal, 20) - .padding(.bottom, 20) .background(Color(.braveBackground).edgesIgnoringSafeArea(.all)) .background( NavigationLink( @@ -224,9 +214,33 @@ private struct CreateWalletView: View { ) .onChange(of: password, perform: handleInputChange) .onChange(of: repeatedPassword, perform: handleInputChange) + .navigationBarBackButtonHidden(isShowingCreatingWallet) + .frame(maxWidth: .infinity, maxHeight: .infinity) + .overlay { + if isShowingCreatingWallet { + CreatingWalletView() + .ignoresSafeArea() + .frame(maxWidth: .infinity, maxHeight: .infinity) + } + } + .toolbar(content: { + ToolbarItem(placement: .navigationBarLeading) { + if isShowingCreatingWallet { + Button(action: dismissAction) { // dismiss all of wallet + Image("wallet-dismiss", bundle: .module) + .renderingMode(.template) + .foregroundColor(Color(.braveBlurpleTint)) + } + } + } + }) .onAppear { isFieldFocused = true } + .transparentNavigationBar( + backButtonTitle: Strings.Wallet.createWalletBackButtonTitle, + backButtonDisplayMode: .generic + ) } } @@ -234,10 +248,32 @@ private struct CreateWalletView: View { struct CreateWalletView_Previews: PreviewProvider { static var previews: some View { NavigationView { - CreateWalletContainerView(keyringStore: .previewStore) + CreateWalletView( + keyringStore: .previewStore, + setupOption: .new, + dismissAction: {} + ) } .previewLayout(.sizeThatFits) .previewColorSchemes() } } #endif + +/// View shown as an overlay over `CreateWalletView` or `RestoreWalletView` +/// when waiting for Wallet to be created & wallet data files downloaded. +struct CreatingWalletView: View { + + var body: some View { + VStack(spacing: 24) { + Spacer() + ProgressView() + .progressViewStyle(.braveCircular(size: .normal, tint: .braveBlurpleTint)) + Text(Strings.Wallet.creatingWallet) + .font(.title) + Spacer() + } + .frame(maxWidth: .infinity, maxHeight: .infinity) + .background(Color(braveSystemName: .containerBackground)) + } +} diff --git a/Sources/BraveWallet/Crypto/Onboarding/LegalView.swift b/Sources/BraveWallet/Crypto/Onboarding/LegalView.swift index 8b3daffc8a3a..a7c22ce4b7a3 100644 --- a/Sources/BraveWallet/Crypto/Onboarding/LegalView.swift +++ b/Sources/BraveWallet/Crypto/Onboarding/LegalView.swift @@ -8,18 +8,15 @@ import DesignSystem struct LegalView: View { @ObservedObject var keyringStore: KeyringStore - var setupOption: SetupOption + let setupOption: OnboardingSetupOption + // Used to dismiss all of Wallet + let dismissAction: () -> Void @State private var isResponsibilityCheckboxChecked: Bool = false @State private var isTermsCheckboxChecked: Bool = false @State private var isShowingCreateNewWallet: Bool = false @State private var isShowingRestoreExistedWallet: Bool = false - enum SetupOption { - case new - case restore - } - private var isContinueDisabled: Bool { !isResponsibilityCheckboxChecked || !isTermsCheckboxChecked } @@ -79,7 +76,11 @@ struct LegalView: View { .padding() .background( NavigationLink( - destination: CreateWalletContainerView(keyringStore: keyringStore), + destination: CreateWalletView( + keyringStore: keyringStore, + setupOption: setupOption, + dismissAction: dismissAction + ), isActive: $isShowingCreateNewWallet, label: { EmptyView() @@ -88,7 +89,10 @@ struct LegalView: View { ) .background( NavigationLink( - destination: RestoreWalletContainerView(keyringStore: keyringStore), + destination: RestoreWalletView( + keyringStore: keyringStore, + dismissAction: dismissAction + ), isActive: $isShowingRestoreExistedWallet, label: { EmptyView() @@ -118,7 +122,11 @@ struct LegalCheckbox: View { #if DEBUG struct LegalView_Previews: PreviewProvider { static var previews: some View { - LegalView(keyringStore: .previewStore, setupOption: .new) + LegalView( + keyringStore: .previewStore, + setupOption: .new, + dismissAction: {} + ) } } #endif diff --git a/Sources/BraveWallet/Crypto/Onboarding/RestoreWalletView.swift b/Sources/BraveWallet/Crypto/Onboarding/RestoreWalletView.swift index 23450f99f785..c23461e1bd04 100644 --- a/Sources/BraveWallet/Crypto/Onboarding/RestoreWalletView.swift +++ b/Sources/BraveWallet/Crypto/Onboarding/RestoreWalletView.swift @@ -10,24 +10,12 @@ import Strings import struct Shared.AppConstants import Preferences -struct RestoreWalletContainerView: View { - @ObservedObject var keyringStore: KeyringStore - - var body: some View { - ScrollView(.vertical) { - RestoreWalletView(keyringStore: keyringStore) - .background(Color(.braveBackground)) - } - .background(Color(.braveBackground).edgesIgnoringSafeArea(.all)) - .transparentUnlessScrolledNavigationAppearance() - } -} - -private struct RestoreWalletView: View { +struct RestoreWalletView: View { @ObservedObject var keyringStore: KeyringStore + // Used to dismiss all of Wallet + let dismissAction: () -> Void @Environment(\.sizeCategory) private var sizeCategory - @Environment(\.dismiss) private var dismiss @State private var isBraveLegacyWallet: Bool = false @State private var isRevealRecoveryWords: Bool = true @@ -49,6 +37,10 @@ private struct RestoreWalletView: View { !recoveryWords.allSatisfy({ !$0.isEmpty }) || keyringStore.isRestoringWallet } + private var isShowingCreatingWallet: Bool { + keyringStore.isCreatingWallet || keyringStore.isRestoringWallet + } + private var errorLabel: some View { HStack(spacing: 12) { Image(braveSystemName: "leo.warning.circle-filled") @@ -96,7 +88,6 @@ private struct RestoreWalletView: View { resignFirstResponder() } } - } var body: some View { @@ -188,26 +179,34 @@ private struct RestoreWalletView: View { .onChange(of: recoveryWords) { [recoveryWords] newValue in handleRecoveryWordsChanged(oldValue: recoveryWords, newValue: newValue) } + .navigationBarBackButtonHidden(isShowingCreatingWallet) + .frame(maxWidth: .infinity, maxHeight: .infinity) + .background(Color(.braveBackground).edgesIgnoringSafeArea(.all)) + .overlay { + if isShowingCreatingWallet { + CreatingWalletView() + .ignoresSafeArea() + .frame(maxWidth: .infinity, maxHeight: .infinity) + } + } + .toolbar(content: { + ToolbarItem(placement: .navigationBarLeading) { + if isShowingCreatingWallet { + Button(action: dismissAction) { // dismiss all of wallet + Image("wallet-dismiss", bundle: .module) + .renderingMode(.template) + .foregroundColor(Color(.braveBlurpleTint)) + } + } + } + }) .sheet(isPresented: $isShowingCreateNewPassword) { NavigationView { - CreateWalletContainerView( + CreateWalletView( keyringStore: keyringStore, - restorePackage: RestorePackage( - recoveryWords: recoveryWords, - onRestoreCompleted: { success, password in - if success { - isShowingPhraseError = false - keyringStore.resetKeychainStoredPassword() - if keyringStore.isOnboardingVisible { - Preferences.Wallet.isOnboardingCompleted.value = true - } - } else { - newPassword = password - isShowingPhraseError = true - } - isShowingCreateNewPassword = false - } - ) + setupOption: .restore, + onValidPasswordEntered: restoreWallet, + dismissAction: dismissAction ) .toolbar { ToolbarItemGroup(placement: .destructiveAction) { @@ -218,18 +217,43 @@ private struct RestoreWalletView: View { } } } + .transparentUnlessScrolledNavigationAppearance() } private func resignFirstResponder() { UIApplication.shared.sendAction(#selector(UIResponder.resignFirstResponder), to: nil, from: nil, for: nil) } + + private func restoreWallet(_ password: String) { + newPassword = password + isShowingCreateNewPassword = false + keyringStore.restoreWallet( + words: recoveryWords, + password: password, + isLegacyBraveWallet: recoveryWords.count == .legacyWalletRecoveryPhraseNumber + ) { success in + if success { + isShowingPhraseError = false + keyringStore.resetKeychainStoredPassword() + if keyringStore.isOnboardingVisible { + Preferences.Wallet.isOnboardingCompleted.value = true + } + } else { + newPassword = password + isShowingPhraseError = true + } + } + } } #if DEBUG struct RestoreWalletView_Previews: PreviewProvider { static var previews: some View { NavigationView { - RestoreWalletContainerView(keyringStore: .previewStore) + RestoreWalletView( + keyringStore: .previewStore, + dismissAction: {} + ) } .previewLayout(.sizeThatFits) .previewColorSchemes() diff --git a/Sources/BraveWallet/Crypto/Onboarding/SetupCryptoView.swift b/Sources/BraveWallet/Crypto/Onboarding/SetupCryptoView.swift index b3857690919b..9bd947726204 100644 --- a/Sources/BraveWallet/Crypto/Onboarding/SetupCryptoView.swift +++ b/Sources/BraveWallet/Crypto/Onboarding/SetupCryptoView.swift @@ -9,10 +9,17 @@ import Introspect import DesignSystem import Strings +enum OnboardingSetupOption { + case new + case restore +} + struct SetupCryptoView: View { @ObservedObject var keyringStore: KeyringStore + // Used to dismiss all of Wallet + let dismissAction: () -> Void - @State private var setupOption: LegalView.SetupOption? + @State private var setupOption: OnboardingSetupOption? var body: some View { ScrollView { @@ -117,7 +124,11 @@ struct SetupCryptoView: View { ), destination: { if let option = setupOption { - LegalView(keyringStore: keyringStore, setupOption: option) + LegalView( + keyringStore: keyringStore, + setupOption: option, + dismissAction: dismissAction + ) } }, label: { @@ -134,7 +145,10 @@ struct SetupCryptoView: View { struct SetupCryptoView_Previews: PreviewProvider { static var previews: some View { NavigationView { - SetupCryptoView(keyringStore: .previewStore) + SetupCryptoView( + keyringStore: .previewStore, + dismissAction: {} + ) } .previewLayout(.sizeThatFits) .previewColorSchemes() diff --git a/Sources/BraveWallet/Crypto/Stores/KeyringStore.swift b/Sources/BraveWallet/Crypto/Stores/KeyringStore.swift index e903ff454386..20c8296f529a 100644 --- a/Sources/BraveWallet/Crypto/Stores/KeyringStore.swift +++ b/Sources/BraveWallet/Crypto/Stores/KeyringStore.swift @@ -213,6 +213,14 @@ public class KeyringStore: ObservableObject, WalletObserverStore { public func setupObservers() { guard !isObserving else { return } + Task { @MainActor in + // For case where Wallet is dismissed while wallet is being created. + // Ex. User creates wallet, dismisses & re-opens Wallet before + // create wallet completion callback. Callback is held with + // strong ref which keeps `KeyringStore` alive. + let isWalletCreated = await keyringService.isWalletCreated() + self.isOnboardingVisible = !isWalletCreated + } self.keyringServiceObserver = KeyringServiceObserver( keyringService: keyringService, _walletReset: { [weak self] in @@ -270,6 +278,19 @@ public class KeyringStore: ObservableObject, WalletObserverStore { } public func tearDown() { + Task { @MainActor in + // For case where Wallet is dismissed while wallet is being created. + // Ex. User creates wallet, dismisses & re-opens Wallet before + // create wallet completion callback. Callback is held with + // strong ref which keeps `KeyringStore` alive. + let isWalletCreated = await keyringService.isWalletCreated() + self.isOnboardingVisible = !isWalletCreated + if isRestoringWallet && isWalletCreated { + // user dismissed wallet while restoring, but after wallet was created in core. + keyringService.notifyWalletBackupComplete() + self.isWalletBackedUp = await keyringService.isWalletBackedUp() + } + } keyringServiceObserver = nil rpcServiceObserver = nil } @@ -383,13 +404,24 @@ public class KeyringStore: ObservableObject, WalletObserverStore { } isOnboarding = true isCreatingWallet = true - keyringService.createWallet(password) { [weak self] mnemonic in - self?.isCreatingWallet = false - self?.updateInfo() - if !mnemonic.isEmpty { - self?.passwordToSaveInBiometric = password + keyringService.isWalletCreated { [weak self] isWalletCreated in + guard let self else { return } + guard !isWalletCreated else { + // Wallet was created already (possible with multi-window) #8425 + self.isOnboarding = false + self.isCreatingWallet = false + // Dismiss onboarding if wallet is already setup + self.isOnboardingVisible = false + return + } + keyringService.createWallet(password) { mnemonic in + self.isCreatingWallet = false + self.updateInfo() + if !mnemonic.isEmpty { + self.passwordToSaveInBiometric = password + } + completion?(mnemonic) } - completion?(mnemonic) } } diff --git a/Sources/BraveWallet/Crypto/UnlockWalletView.swift b/Sources/BraveWallet/Crypto/UnlockWalletView.swift index 80cc2ad6bf8d..f2826052a0de 100644 --- a/Sources/BraveWallet/Crypto/UnlockWalletView.swift +++ b/Sources/BraveWallet/Crypto/UnlockWalletView.swift @@ -10,6 +10,8 @@ import LocalAuthentication struct UnlockWalletView: View { @ObservedObject var keyringStore: KeyringStore + // Used to dismiss all of Wallet + let dismissAction: () -> Void @State private var password: String = "" @FocusState private var isPasswordFieldFocused: Bool @@ -80,8 +82,9 @@ struct UnlockWalletView: View { .disabled(!isPasswordValid) NavigationLink( - destination: RestoreWalletContainerView( - keyringStore: keyringStore + destination: RestoreWalletView( + keyringStore: keyringStore, + dismissAction: dismissAction ) ) { Text(Strings.Wallet.restoreWalletButtonTitle) @@ -161,7 +164,8 @@ struct UnlockWalletView_Previews: PreviewProvider { static var previews: some View { NavigationView { UnlockWalletView( - keyringStore: .previewStoreWithWalletCreated + keyringStore: .previewStoreWithWalletCreated, + dismissAction: {} ) } .previewColorSchemes() diff --git a/Sources/BraveWallet/WalletHostingViewController.swift b/Sources/BraveWallet/WalletHostingViewController.swift index f6c03d4dc470..557d88fcf8db 100644 --- a/Sources/BraveWallet/WalletHostingViewController.swift +++ b/Sources/BraveWallet/WalletHostingViewController.swift @@ -95,7 +95,7 @@ public class WalletHostingViewController: UIHostingController { // As a workaround to this issue, we can just watch keyring's `isLocked` value from here // and dismiss the first sheet ourselves to ensure we dont get stuck with a child view visible // while the wallet is locked. - if /*#unavailable(iOS 16.4),*/ + if #unavailable(iOS 16.4), let self = self, isLocked, let presentedViewController = self.presentedViewController, diff --git a/Sources/BraveWallet/WalletStrings.swift b/Sources/BraveWallet/WalletStrings.swift index 0443f161c28a..9f970965ee9d 100644 --- a/Sources/BraveWallet/WalletStrings.swift +++ b/Sources/BraveWallet/WalletStrings.swift @@ -856,6 +856,13 @@ extension Strings { value: "Strong", comment: "A label will be displayed beside input password when it is considered as a strong password" ) + public static let creatingWallet = NSLocalizedString( + "wallet.creatingWallet", + tableName: "BraveWallet", + bundle: .module, + value: "Creating Wallet...", + comment: "The title of the creating wallet screen, shown after user enters their password while the wallet is being set up." + ) public static let biometricsSetupErrorTitle = NSLocalizedString( "wallet.biometricsSetupErrorTitle", tableName: "BraveWallet",