316 lines
11 KiB
Swift
316 lines
11 KiB
Swift
import ComposableArchitecture
|
|
import ZcashLightClientKit
|
|
import DatabaseFiles
|
|
import Deeplink
|
|
import RecoveryPhraseValidationFlow
|
|
import ZcashSDKEnvironment
|
|
import WalletStorage
|
|
import WalletConfigProvider
|
|
import UserPreferencesStorage
|
|
import Models
|
|
import RecoveryPhraseDisplay
|
|
import Welcome
|
|
import Generated
|
|
import Foundation
|
|
import ExportLogs
|
|
import OnboardingFlow
|
|
import Sandbox
|
|
import Home
|
|
|
|
public typealias RootStore = Store<RootReducer.State, RootReducer.Action>
|
|
public typealias RootViewStore = ViewStore<RootReducer.State, RootReducer.Action>
|
|
|
|
public struct RootReducer: ReducerProtocol {
|
|
enum CancelId { case timer }
|
|
enum SynchronizerCancelId { case timer }
|
|
enum WalletConfigCancelId { case timer }
|
|
let tokenName: String
|
|
let zcashNetwork: ZcashNetwork
|
|
|
|
public struct State: Equatable {
|
|
@PresentationState public var alert: AlertState<Action>?
|
|
public var appInitializationState: InitializationState = .uninitialized
|
|
public var debugState: DebugState
|
|
public var destinationState: DestinationState
|
|
public var exportLogsState: ExportLogsReducer.State
|
|
public var homeState: HomeReducer.State
|
|
public var onboardingState: OnboardingFlowReducer.State
|
|
public var phraseValidationState: RecoveryPhraseValidationFlowReducer.State
|
|
public var phraseDisplayState: RecoveryPhraseDisplayReducer.State
|
|
public var sandboxState: SandboxReducer.State
|
|
public var storedWallet: StoredWallet?
|
|
public var walletConfig: WalletConfig
|
|
public var welcomeState: WelcomeReducer.State
|
|
|
|
public init(
|
|
appInitializationState: InitializationState = .uninitialized,
|
|
debugState: DebugState,
|
|
destinationState: DestinationState,
|
|
exportLogsState: ExportLogsReducer.State,
|
|
homeState: HomeReducer.State,
|
|
onboardingState: OnboardingFlowReducer.State,
|
|
phraseValidationState: RecoveryPhraseValidationFlowReducer.State,
|
|
phraseDisplayState: RecoveryPhraseDisplayReducer.State,
|
|
sandboxState: SandboxReducer.State,
|
|
storedWallet: StoredWallet? = nil,
|
|
walletConfig: WalletConfig,
|
|
welcomeState: WelcomeReducer.State
|
|
) {
|
|
self.appInitializationState = appInitializationState
|
|
self.debugState = debugState
|
|
self.destinationState = destinationState
|
|
self.exportLogsState = exportLogsState
|
|
self.homeState = homeState
|
|
self.onboardingState = onboardingState
|
|
self.phraseValidationState = phraseValidationState
|
|
self.phraseDisplayState = phraseDisplayState
|
|
self.sandboxState = sandboxState
|
|
self.storedWallet = storedWallet
|
|
self.walletConfig = walletConfig
|
|
self.welcomeState = welcomeState
|
|
}
|
|
}
|
|
|
|
public enum Action: Equatable {
|
|
case alert(PresentationAction<Action>)
|
|
case binding(BindingAction<RootReducer.State>)
|
|
case debug(DebugAction)
|
|
case dismissAlert
|
|
case destination(DestinationAction)
|
|
case exportLogs(ExportLogsReducer.Action)
|
|
case home(HomeReducer.Action)
|
|
case initialization(InitializationAction)
|
|
case nukeWalletFailed
|
|
case nukeWalletSucceeded
|
|
case onboarding(OnboardingFlowReducer.Action)
|
|
case phraseDisplay(RecoveryPhraseDisplayReducer.Action)
|
|
case phraseValidation(RecoveryPhraseValidationFlowReducer.Action)
|
|
case sandbox(SandboxReducer.Action)
|
|
case updateStateAfterConfigUpdate(WalletConfig)
|
|
case walletConfigLoaded(WalletConfig)
|
|
case welcome(WelcomeReducer.Action)
|
|
}
|
|
|
|
// TODO: [#747] crashReporter needs a bit of extra work, see https://github.com/zcash/secant-ios-wallet/issues/747
|
|
//@Dependency(\.crashReporter) var crashReporter
|
|
@Dependency(\.databaseFiles) var databaseFiles
|
|
@Dependency(\.deeplink) var deeplink
|
|
@Dependency(\.derivationTool) var derivationTool
|
|
@Dependency(\.mainQueue) var mainQueue
|
|
@Dependency(\.mnemonic) var mnemonic
|
|
@Dependency(\.randomRecoveryPhrase) var randomRecoveryPhrase
|
|
@Dependency(\.sdkSynchronizer) var sdkSynchronizer
|
|
@Dependency(\.userStoredPreferences) var userStoredPreferences
|
|
@Dependency(\.walletConfigProvider) var walletConfigProvider
|
|
@Dependency(\.walletStorage) var walletStorage
|
|
@Dependency(\.zcashSDKEnvironment) var zcashSDKEnvironment
|
|
|
|
public init(tokenName: String, zcashNetwork: ZcashNetwork) {
|
|
self.tokenName = tokenName
|
|
self.zcashNetwork = zcashNetwork
|
|
}
|
|
|
|
@ReducerBuilder<State, Action>
|
|
var core: some ReducerProtocol<State, Action> {
|
|
Scope(state: \.homeState, action: /Action.home) {
|
|
HomeReducer(networkType: zcashNetwork.networkType)
|
|
}
|
|
|
|
Scope(state: \.exportLogsState, action: /Action.exportLogs) {
|
|
ExportLogsReducer()
|
|
}
|
|
|
|
Scope(state: \.onboardingState, action: /Action.onboarding) {
|
|
OnboardingFlowReducer(saplingActivationHeight: zcashNetwork.constants.saplingActivationHeight)
|
|
}
|
|
|
|
Scope(state: \.phraseValidationState, action: /Action.phraseValidation) {
|
|
RecoveryPhraseValidationFlowReducer()
|
|
}
|
|
|
|
Scope(state: \.phraseDisplayState, action: /Action.phraseDisplay) {
|
|
RecoveryPhraseDisplayReducer()
|
|
}
|
|
|
|
Scope(state: \.sandboxState, action: /Action.sandbox) {
|
|
SandboxReducer()
|
|
}
|
|
|
|
Scope(state: \.welcomeState, action: /Action.welcome) {
|
|
WelcomeReducer()
|
|
}
|
|
|
|
initializationReduce()
|
|
|
|
destinationReduce()
|
|
|
|
debugReduce()
|
|
}
|
|
|
|
public var body: some ReducerProtocol<State, Action> {
|
|
self.core
|
|
}
|
|
}
|
|
|
|
extension RootReducer {
|
|
public static func walletInitializationState(
|
|
databaseFiles: DatabaseFilesClient,
|
|
walletStorage: WalletStorageClient,
|
|
zcashNetwork: ZcashNetwork
|
|
) -> InitializationState {
|
|
var keysPresent = false
|
|
do {
|
|
keysPresent = try walletStorage.areKeysPresent()
|
|
let databaseFilesPresent = databaseFiles.areDbFilesPresentFor(
|
|
zcashNetwork
|
|
)
|
|
|
|
switch (keysPresent, databaseFilesPresent) {
|
|
case (false, false):
|
|
return .uninitialized
|
|
case (false, true):
|
|
return .keysMissing
|
|
case (true, false):
|
|
return .filesMissing
|
|
case (true, true):
|
|
return .initialized
|
|
}
|
|
} catch WalletStorage.WalletStorageError.uninitializedWallet {
|
|
if databaseFiles.areDbFilesPresentFor(zcashNetwork) {
|
|
return .keysMissing
|
|
}
|
|
} catch {
|
|
return .failed
|
|
}
|
|
|
|
return .uninitialized
|
|
}
|
|
}
|
|
|
|
// MARK: Alerts
|
|
|
|
extension AlertState where Action == RootReducer.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.message, error.code.rawValue))
|
|
}
|
|
}
|
|
|
|
public static func cantLoadSeedPhrase() -> AlertState {
|
|
AlertState {
|
|
TextState(L10n.Root.Initialization.Alert.Failed.title)
|
|
} message: {
|
|
TextState(L10n.Root.Initialization.Alert.CantLoadSeedPhrase.message)
|
|
}
|
|
}
|
|
|
|
public static func cantStartSync(_ error: ZcashError) -> AlertState {
|
|
AlertState {
|
|
TextState(L10n.Root.Debug.Alert.Rewind.CantStartSync.title)
|
|
} message: {
|
|
TextState(L10n.Root.Debug.Alert.Rewind.CantStartSync.message(error.message, error.code.rawValue))
|
|
}
|
|
}
|
|
|
|
public static func cantStoreThatUserPassedPhraseBackupTest(_ error: ZcashError) -> AlertState {
|
|
AlertState {
|
|
TextState(L10n.Root.Initialization.Alert.Failed.title)
|
|
} message: {
|
|
TextState(
|
|
L10n.Root.Initialization.Alert.CantStoreThatUserPassedPhraseBackupTest.message(error.message, error.code.rawValue)
|
|
)
|
|
}
|
|
}
|
|
|
|
public static func failedToProcessDeeplink(_ url: URL, _ error: ZcashError) -> AlertState {
|
|
AlertState {
|
|
TextState(L10n.Root.Destination.Alert.FailedToProcessDeeplink.title)
|
|
} message: {
|
|
TextState(L10n.Root.Destination.Alert.FailedToProcessDeeplink.message(url, error.message, error.code.rawValue))
|
|
}
|
|
}
|
|
|
|
public static func initializationFailed(_ error: ZcashError) -> AlertState {
|
|
AlertState {
|
|
TextState(L10n.Root.Initialization.Alert.SdkInitFailed.title)
|
|
} message: {
|
|
TextState(L10n.Root.Initialization.Alert.Error.message(error.message, error.code.rawValue))
|
|
}
|
|
}
|
|
|
|
public static func rewindFailed(_ error: ZcashError) -> AlertState {
|
|
AlertState {
|
|
TextState(L10n.Root.Debug.Alert.Rewind.Failed.title)
|
|
} message: {
|
|
TextState(L10n.Root.Debug.Alert.Rewind.Failed.message(error.message, error.code.rawValue))
|
|
}
|
|
}
|
|
|
|
public static func walletStateFailed(_ walletState: InitializationState) -> AlertState {
|
|
AlertState {
|
|
TextState(L10n.Root.Initialization.Alert.Failed.title)
|
|
} message: {
|
|
TextState(L10n.Root.Initialization.Alert.WalletStateFailed.message(walletState))
|
|
}
|
|
}
|
|
|
|
public static func wipeFailed() -> AlertState {
|
|
AlertState {
|
|
TextState(L10n.Root.Initialization.Alert.WipeFailed.title)
|
|
}
|
|
}
|
|
|
|
public static func wipeRequest() -> AlertState {
|
|
AlertState {
|
|
TextState(L10n.Root.Initialization.Alert.Wipe.title)
|
|
} actions: {
|
|
ButtonState(role: .destructive, action: .initialization(.nukeWallet)) {
|
|
TextState(L10n.General.yes)
|
|
}
|
|
ButtonState(role: .cancel, action: .dismissAlert) {
|
|
TextState(L10n.General.no)
|
|
}
|
|
} message: {
|
|
TextState(L10n.Root.Initialization.Alert.Wipe.message)
|
|
}
|
|
}
|
|
}
|
|
|
|
// MARK: Placeholders
|
|
|
|
extension RootReducer.State {
|
|
public static var placeholder: Self {
|
|
.init(
|
|
debugState: .placeholder,
|
|
destinationState: .placeholder,
|
|
exportLogsState: .placeholder,
|
|
homeState: .placeholder,
|
|
onboardingState: .init(
|
|
walletConfig: .default,
|
|
importWalletState: .placeholder
|
|
),
|
|
phraseValidationState: .placeholder,
|
|
phraseDisplayState: RecoveryPhraseDisplayReducer.State(
|
|
phrase: .placeholder
|
|
),
|
|
sandboxState: .placeholder,
|
|
walletConfig: .default,
|
|
welcomeState: .placeholder
|
|
)
|
|
}
|
|
}
|
|
|
|
extension RootStore {
|
|
public static var placeholder: RootStore {
|
|
RootStore(
|
|
initialState: .placeholder,
|
|
reducer: RootReducer(
|
|
tokenName: "ZEC",
|
|
zcashNetwork: ZcashNetworkBuilder.network(for: .testnet)
|
|
).logging()
|
|
)
|
|
}
|
|
}
|