// // Onboarding.swift // OnboardingTCA // // Created by Adam Stener on 10/10/21. // import Foundation import SwiftUI import ComposableArchitecture import Generated import Models import ZcashLightClientKit import CoordFlows import MnemonicSwift import ZcashSDKEnvironment import WalletStorage @Reducer public struct OnboardingFlow { @ObservableState public struct State { public enum Destination: Equatable, CaseIterable { case createNewWallet case importExistingWallet } @Presents public var alert: AlertState? public var destination: Destination? public var walletConfig: WalletConfig // Path public var restoreWalletCoordFlowState = RestoreWalletCoordFlow.State.initial public init( destination: Destination? = nil, walletConfig: WalletConfig ) { self.destination = destination self.walletConfig = walletConfig } } public enum Action { case alert(PresentationAction) case createNewWalletRequested case createNewWalletTapped case importExistingWallet case newWalletSuccessfulyCreated case onAppear case restoreWalletCoordFlow(RestoreWalletCoordFlow.Action) case updateDestination(OnboardingFlow.State.Destination?) } @Dependency(\.mnemonic) var mnemonic @Dependency(\.walletStorage) var walletStorage @Dependency(\.zcashSDKEnvironment) var zcashSDKEnvironment public init() { } public var body: some Reducer { Scope(state: \.restoreWalletCoordFlowState, action: \.restoreWalletCoordFlow) { RestoreWalletCoordFlow() } Reduce { state, action in switch action { case .onAppear: return .none case .alert(.presented(let action)): return .send(action) case .alert(.dismiss): state.alert = nil return .none case .updateDestination(let destination): state.destination = destination return .none case .createNewWalletTapped: state.destination = .createNewWallet return .none case .createNewWalletRequested: do { // get the random english mnemonic let newRandomPhrase = try mnemonic.randomMnemonic() let birthday = zcashSDKEnvironment.latestCheckpoint // store the wallet to the keychain try walletStorage.importWallet(newRandomPhrase, birthday, .english, false) return .send(.newWalletSuccessfulyCreated) } catch { state.alert = AlertState.cantCreateNewWallet(error.toZcashError()) } return .none case .newWalletSuccessfulyCreated: return .none case .importExistingWallet: state.restoreWalletCoordFlowState = .initial state.destination = .importExistingWallet return .none case .restoreWalletCoordFlow: return .none } } } } // MARK: Alerts extension AlertState where Action == OnboardingFlow.Action { public static func cantCreateNewWallet(_ error: ZcashError) -> AlertState { AlertState { TextState(L10n.Root.Initialization.Alert.Failed.title) } message: { TextState(L10n.Root.Initialization.Alert.CantCreateNewWallet.message(error.detailedMessage)) } } }