- added alert view asking if nuke is triggered or canceled - wipe of the keychain - wipe publisher properly used - functional wipe accessible through debug menu
This commit is contained in:
parent
148ca941f1
commit
75150da3a4
|
@ -3517,8 +3517,8 @@
|
||||||
isa = XCRemoteSwiftPackageReference;
|
isa = XCRemoteSwiftPackageReference;
|
||||||
repositoryURL = "https://github.com/zcash/ZcashLightClientKit/";
|
repositoryURL = "https://github.com/zcash/ZcashLightClientKit/";
|
||||||
requirement = {
|
requirement = {
|
||||||
branch = main;
|
kind = revision;
|
||||||
kind = branch;
|
revision = 3b2d972b2dd0c51e36d76e49fcf58273bf585c1b;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
6654C7382715A38000901167 /* XCRemoteSwiftPackageReference "swift-composable-architecture" */ = {
|
6654C7382715A38000901167 /* XCRemoteSwiftPackageReference "swift-composable-architecture" */ = {
|
||||||
|
|
|
@ -338,8 +338,7 @@
|
||||||
"kind" : "remoteSourceControl",
|
"kind" : "remoteSourceControl",
|
||||||
"location" : "https://github.com/zcash/ZcashLightClientKit/",
|
"location" : "https://github.com/zcash/ZcashLightClientKit/",
|
||||||
"state" : {
|
"state" : {
|
||||||
"branch" : "main",
|
"revision" : "3b2d972b2dd0c51e36d76e49fcf58273bf585c1b"
|
||||||
"revision" : "27b99013f7dda11caee0a261361c155490966e7f"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
|
|
@ -18,24 +18,11 @@ extension DependencyValues {
|
||||||
}
|
}
|
||||||
|
|
||||||
enum SDKSynchronizerState: Equatable {
|
enum SDKSynchronizerState: Equatable {
|
||||||
case unknown
|
|
||||||
case transactionsUpdated
|
|
||||||
case started
|
|
||||||
case progressUpdated
|
case progressUpdated
|
||||||
case statusWillUpdate
|
case started
|
||||||
case synced
|
|
||||||
case stopped
|
case stopped
|
||||||
case disconnected
|
case synced
|
||||||
case syncing
|
case unknown
|
||||||
case downloading
|
|
||||||
case validating
|
|
||||||
case scanning
|
|
||||||
case enhancing
|
|
||||||
case fetching
|
|
||||||
case minedTransaction
|
|
||||||
case foundTransactions
|
|
||||||
case failed
|
|
||||||
case connectionStateChanged
|
|
||||||
}
|
}
|
||||||
|
|
||||||
enum SDKSynchronizerClientError: Error {
|
enum SDKSynchronizerClientError: Error {
|
||||||
|
@ -54,6 +41,8 @@ protocol SDKSynchronizerClient {
|
||||||
func stop()
|
func stop()
|
||||||
func synchronizerSynced(_ synchronizerState: SDKSynchronizer.SynchronizerState?)
|
func synchronizerSynced(_ synchronizerState: SDKSynchronizer.SynchronizerState?)
|
||||||
func statusSnapshot() -> SyncStatusSnapshot
|
func statusSnapshot() -> SyncStatusSnapshot
|
||||||
|
func isSyncing() -> Bool
|
||||||
|
func isInitialized() -> Bool
|
||||||
|
|
||||||
func rewind(_ policy: RewindPolicy) async throws
|
func rewind(_ policy: RewindPolicy) async throws
|
||||||
|
|
||||||
|
@ -75,6 +64,8 @@ protocol SDKSynchronizerClient {
|
||||||
to recipientAddress: Recipient,
|
to recipientAddress: Recipient,
|
||||||
memo: Memo?
|
memo: Memo?
|
||||||
) -> EffectTask<Result<TransactionState, NSError>>
|
) -> EffectTask<Result<TransactionState, NSError>>
|
||||||
|
|
||||||
|
func wipe() -> AnyPublisher<Void, Error>?
|
||||||
}
|
}
|
||||||
|
|
||||||
extension SDKSynchronizerClient {
|
extension SDKSynchronizerClient {
|
||||||
|
|
|
@ -75,6 +75,14 @@ class LiveSDKSynchronizerClient: SDKSynchronizerClient {
|
||||||
func stop() {
|
func stop() {
|
||||||
synchronizer?.stop()
|
synchronizer?.stop()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func isSyncing() -> Bool {
|
||||||
|
latestScannedSynchronizerState?.syncStatus.isSyncing ?? false
|
||||||
|
}
|
||||||
|
|
||||||
|
func isInitialized() -> Bool {
|
||||||
|
synchronizer != nil
|
||||||
|
}
|
||||||
|
|
||||||
func synchronizerStarted() {
|
func synchronizerStarted() {
|
||||||
stateChanged.send(.started)
|
stateChanged.send(.started)
|
||||||
|
@ -229,4 +237,8 @@ class LiveSDKSynchronizerClient: SDKSynchronizerClient {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func wipe() -> AnyPublisher<Void, Error>? {
|
||||||
|
synchronizer?.wipe()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,6 +33,10 @@ class MockSDKSynchronizerClient: SDKSynchronizerClient {
|
||||||
|
|
||||||
func stop() { }
|
func stop() { }
|
||||||
|
|
||||||
|
func isSyncing() -> Bool { false }
|
||||||
|
|
||||||
|
func isInitialized() -> Bool { false }
|
||||||
|
|
||||||
func synchronizerSynced(_ synchronizerState: SDKSynchronizer.SynchronizerState?) { }
|
func synchronizerSynced(_ synchronizerState: SDKSynchronizer.SynchronizerState?) { }
|
||||||
|
|
||||||
func statusSnapshot() -> SyncStatusSnapshot { .default }
|
func statusSnapshot() -> SyncStatusSnapshot { .default }
|
||||||
|
@ -200,4 +204,6 @@ class MockSDKSynchronizerClient: SDKSynchronizerClient {
|
||||||
|
|
||||||
return EffectTask(value: Result.success(transactionState))
|
return EffectTask(value: Result.success(transactionState))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func wipe() -> AnyPublisher<Void, Error>? { nil }
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,6 +32,10 @@ class NoopSDKSynchronizer: SDKSynchronizerClient {
|
||||||
|
|
||||||
func stop() { }
|
func stop() { }
|
||||||
|
|
||||||
|
func isSyncing() -> Bool { false }
|
||||||
|
|
||||||
|
func isInitialized() -> Bool { false }
|
||||||
|
|
||||||
func synchronizerSynced(_ synchronizerState: SDKSynchronizer.SynchronizerState?) { }
|
func synchronizerSynced(_ synchronizerState: SDKSynchronizer.SynchronizerState?) { }
|
||||||
|
|
||||||
func statusSnapshot() -> SyncStatusSnapshot { .default }
|
func statusSnapshot() -> SyncStatusSnapshot { .default }
|
||||||
|
@ -70,6 +74,8 @@ class NoopSDKSynchronizer: SDKSynchronizerClient {
|
||||||
func updateStateChanged(_ newState: SDKSynchronizerState) {
|
func updateStateChanged(_ newState: SDKSynchronizerState) {
|
||||||
stateChanged = CurrentValueSubject<SDKSynchronizerState, Never>(newState)
|
stateChanged = CurrentValueSubject<SDKSynchronizerState, Never>(newState)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func wipe() -> AnyPublisher<Void, Error>? { nil }
|
||||||
}
|
}
|
||||||
|
|
||||||
class TestSDKSynchronizerClient: SDKSynchronizerClient {
|
class TestSDKSynchronizerClient: SDKSynchronizerClient {
|
||||||
|
@ -90,6 +96,10 @@ class TestSDKSynchronizerClient: SDKSynchronizerClient {
|
||||||
|
|
||||||
func stop() { }
|
func stop() { }
|
||||||
|
|
||||||
|
func isSyncing() -> Bool { false }
|
||||||
|
|
||||||
|
func isInitialized() -> Bool { false }
|
||||||
|
|
||||||
func synchronizerSynced(_ synchronizerState: SDKSynchronizer.SynchronizerState?) { }
|
func synchronizerSynced(_ synchronizerState: SDKSynchronizer.SynchronizerState?) { }
|
||||||
|
|
||||||
func statusSnapshot() -> SyncStatusSnapshot { .default }
|
func statusSnapshot() -> SyncStatusSnapshot { .default }
|
||||||
|
@ -235,4 +245,6 @@ class TestSDKSynchronizerClient: SDKSynchronizerClient {
|
||||||
func updateStateChanged(_ newState: SDKSynchronizerState) {
|
func updateStateChanged(_ newState: SDKSynchronizerState) {
|
||||||
stateChanged = CurrentValueSubject<SDKSynchronizerState, Never>(newState)
|
stateChanged = CurrentValueSubject<SDKSynchronizerState, Never>(newState)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func wipe() -> AnyPublisher<Void, Error>? { nil }
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,9 +23,10 @@ extension RootReducer {
|
||||||
case welcome
|
case welcome
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@BindingState var alert: AlertState<RootReducer.Action>?
|
||||||
var internalDestination: Destination = .welcome
|
var internalDestination: Destination = .welcome
|
||||||
var previousDestination: Destination?
|
var previousDestination: Destination?
|
||||||
|
|
||||||
var destination: Destination {
|
var destination: Destination {
|
||||||
get { internalDestination }
|
get { internalDestination }
|
||||||
set {
|
set {
|
||||||
|
@ -39,6 +40,7 @@ extension RootReducer {
|
||||||
case deeplink(URL)
|
case deeplink(URL)
|
||||||
case deeplinkHome
|
case deeplinkHome
|
||||||
case deeplinkSend(Zatoshi, String, String)
|
case deeplinkSend(Zatoshi, String, String)
|
||||||
|
case dismissAlert
|
||||||
case updateDestination(RootReducer.DestinationState.Destination)
|
case updateDestination(RootReducer.DestinationState.Destination)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -112,7 +114,12 @@ extension RootReducer {
|
||||||
}
|
}
|
||||||
return EffectTask(value: .destination(.deeplink(url)))
|
return EffectTask(value: .destination(.deeplink(url)))
|
||||||
|
|
||||||
case .home, .initialization, .onboarding, .phraseDisplay, .phraseValidation, .sandbox, .welcome, .debug:
|
case .destination(.dismissAlert):
|
||||||
|
state.destinationState.alert = nil
|
||||||
|
return .none
|
||||||
|
|
||||||
|
case .home, .initialization, .onboarding, .phraseDisplay, .phraseValidation,
|
||||||
|
.sandbox, .welcome, .binding, .nukeWalletFailed, .nukeWalletSucceeded, .debug:
|
||||||
return .none
|
return .none
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -21,6 +21,7 @@ extension RootReducer {
|
||||||
case initializeSDK
|
case initializeSDK
|
||||||
case initialSetups
|
case initialSetups
|
||||||
case nukeWallet
|
case nukeWallet
|
||||||
|
case nukeWalletRequest
|
||||||
case respondToWalletInitializationState(InitializationState)
|
case respondToWalletInitializationState(InitializationState)
|
||||||
case walletConfigChanged(WalletConfig)
|
case walletConfigChanged(WalletConfig)
|
||||||
}
|
}
|
||||||
|
@ -125,10 +126,9 @@ extension RootReducer {
|
||||||
mnemonic: mnemonic,
|
mnemonic: mnemonic,
|
||||||
zcashSDKEnvironment: zcashSDKEnvironment
|
zcashSDKEnvironment: zcashSDKEnvironment
|
||||||
)
|
)
|
||||||
|
|
||||||
try sdkSynchronizer.prepareWith(initializer: initializer, seedBytes: seedBytes)
|
try sdkSynchronizer.prepareWith(initializer: initializer, seedBytes: seedBytes)
|
||||||
try sdkSynchronizer.start()
|
try sdkSynchronizer.start()
|
||||||
|
|
||||||
return .none
|
return .none
|
||||||
} catch {
|
} catch {
|
||||||
// TODO: [#221] error we need to handle (https://github.com/zcash/secant-ios-wallet/issues/221)
|
// TODO: [#221] error we need to handle (https://github.com/zcash/secant-ios-wallet/issues/221)
|
||||||
|
@ -199,14 +199,57 @@ extension RootReducer {
|
||||||
}
|
}
|
||||||
return .none
|
return .none
|
||||||
|
|
||||||
case .initialization(.nukeWallet):
|
case .initialization(.nukeWalletRequest):
|
||||||
walletStorage.nukeWallet()
|
state.destinationState.alert = AlertState(
|
||||||
do {
|
title: TextState("Wipe of the wallet"),
|
||||||
try databaseFiles.nukeDbFilesFor(zcashSDKEnvironment.network)
|
message: TextState("Are you sure?"),
|
||||||
} catch {
|
buttons: [
|
||||||
// TODO: [#221] error we need to handle, issue #221 (https://github.com/zcash/secant-ios-wallet/issues/221)
|
.destructive(
|
||||||
}
|
TextState("Yes"),
|
||||||
|
action: .send(.initialization(.nukeWallet))
|
||||||
|
),
|
||||||
|
.cancel(
|
||||||
|
TextState("No"),
|
||||||
|
action: .send(.destination(.dismissAlert))
|
||||||
|
)
|
||||||
|
]
|
||||||
|
)
|
||||||
return .none
|
return .none
|
||||||
|
|
||||||
|
case .initialization(.nukeWallet):
|
||||||
|
guard let wipePublisher = sdkSynchronizer.wipe() else {
|
||||||
|
return EffectTask(value: .nukeWalletFailed)
|
||||||
|
}
|
||||||
|
return wipePublisher
|
||||||
|
.catchToEffect()
|
||||||
|
.receive(on: mainQueue)
|
||||||
|
.replaceEmpty(with: .success(Void()))
|
||||||
|
.map { _ in return RootReducer.Action.nukeWalletSucceeded }
|
||||||
|
.replaceError(with: RootReducer.Action.nukeWalletFailed)
|
||||||
|
.eraseToEffect()
|
||||||
|
.cancellable(id: SynchronizerCancelId.self, cancelInFlight: true)
|
||||||
|
|
||||||
|
case .nukeWalletSucceeded:
|
||||||
|
walletStorage.nukeWallet()
|
||||||
|
state.onboardingState.destination = nil
|
||||||
|
state.onboardingState.index = 0
|
||||||
|
return .concatenate(
|
||||||
|
.cancel(id: SynchronizerCancelId.self),
|
||||||
|
EffectTask(value: .initialization(.checkWalletInitialization))
|
||||||
|
)
|
||||||
|
|
||||||
|
case .nukeWalletFailed:
|
||||||
|
// TODO: [#221] error we need to handle, issue #221 (https://github.com/zcash/secant-ios-wallet/issues/221)
|
||||||
|
let backDestination: EffectTask<RootReducer.Action>
|
||||||
|
if let previousDestination = state.destinationState.previousDestination {
|
||||||
|
backDestination = EffectTask(value: .destination(.updateDestination(previousDestination)))
|
||||||
|
} else {
|
||||||
|
backDestination = EffectTask(value: .destination(.updateDestination(state.destinationState.destination)))
|
||||||
|
}
|
||||||
|
return .concatenate(
|
||||||
|
.cancel(id: SynchronizerCancelId.self),
|
||||||
|
backDestination
|
||||||
|
)
|
||||||
|
|
||||||
case .welcome(.debugMenuStartup), .home(.debugMenuStartup):
|
case .welcome(.debugMenuStartup), .home(.debugMenuStartup):
|
||||||
return .concatenate(
|
return .concatenate(
|
||||||
|
@ -222,8 +265,8 @@ extension RootReducer {
|
||||||
|
|
||||||
case .onboarding(.createNewWallet):
|
case .onboarding(.createNewWallet):
|
||||||
return EffectTask(value: .initialization(.createNewWallet))
|
return EffectTask(value: .initialization(.createNewWallet))
|
||||||
|
|
||||||
case .home, .destination, .onboarding, .phraseDisplay, .phraseValidation, .sandbox, .welcome:
|
case .home, .destination, .onboarding, .phraseDisplay, .phraseValidation, .sandbox, .welcome, .binding:
|
||||||
return .none
|
return .none
|
||||||
|
|
||||||
case .initialization(.configureCrashReporter):
|
case .initialization(.configureCrashReporter):
|
||||||
|
|
|
@ -6,6 +6,7 @@ typealias RootViewStore = ViewStore<RootReducer.State, RootReducer.Action>
|
||||||
|
|
||||||
struct RootReducer: ReducerProtocol {
|
struct RootReducer: ReducerProtocol {
|
||||||
enum CancelId {}
|
enum CancelId {}
|
||||||
|
enum SynchronizerCancelId {}
|
||||||
|
|
||||||
struct State: Equatable {
|
struct State: Equatable {
|
||||||
var appInitializationState: InitializationState = .uninitialized
|
var appInitializationState: InitializationState = .uninitialized
|
||||||
|
@ -20,10 +21,13 @@ struct RootReducer: ReducerProtocol {
|
||||||
var welcomeState: WelcomeReducer.State
|
var welcomeState: WelcomeReducer.State
|
||||||
}
|
}
|
||||||
|
|
||||||
enum Action: Equatable {
|
enum Action: Equatable, BindableAction {
|
||||||
|
case binding(BindingAction<RootReducer.State>)
|
||||||
case destination(DestinationAction)
|
case destination(DestinationAction)
|
||||||
case home(HomeReducer.Action)
|
case home(HomeReducer.Action)
|
||||||
case initialization(InitializationAction)
|
case initialization(InitializationAction)
|
||||||
|
case nukeWalletFailed
|
||||||
|
case nukeWalletSucceeded
|
||||||
case onboarding(OnboardingFlowReducer.Action)
|
case onboarding(OnboardingFlowReducer.Action)
|
||||||
case phraseDisplay(RecoveryPhraseDisplayReducer.Action)
|
case phraseDisplay(RecoveryPhraseDisplayReducer.Action)
|
||||||
case phraseValidation(RecoveryPhraseValidationFlowReducer.Action)
|
case phraseValidation(RecoveryPhraseValidationFlowReducer.Action)
|
||||||
|
@ -46,6 +50,8 @@ struct RootReducer: ReducerProtocol {
|
||||||
@Dependency(\.zcashSDKEnvironment) var zcashSDKEnvironment
|
@Dependency(\.zcashSDKEnvironment) var zcashSDKEnvironment
|
||||||
|
|
||||||
var body: some ReducerProtocol<State, Action> {
|
var body: some ReducerProtocol<State, Action> {
|
||||||
|
BindingReducer()
|
||||||
|
|
||||||
Scope(state: \.homeState, action: /Action.home) {
|
Scope(state: \.homeState, action: /Action.home) {
|
||||||
HomeReducer()
|
HomeReducer()
|
||||||
}
|
}
|
||||||
|
@ -144,6 +150,7 @@ extension RootReducer {
|
||||||
network: zcashSDKEnvironment.network,
|
network: zcashSDKEnvironment.network,
|
||||||
spendParamsURL: try databaseFiles.spendParamsURLFor(network),
|
spendParamsURL: try databaseFiles.spendParamsURLFor(network),
|
||||||
outputParamsURL: try databaseFiles.outputParamsURLFor(network),
|
outputParamsURL: try databaseFiles.outputParamsURLFor(network),
|
||||||
|
saplingParamsSourceURL: SaplingParamsSourceURL.default,
|
||||||
viewingKeys: [viewingKey],
|
viewingKeys: [viewingKey],
|
||||||
walletBirthday: birthday,
|
walletBirthday: birthday,
|
||||||
loggerProxy: OSLogger_(logLevel: .debug, category: LoggerConstants.sdkLogs)
|
loggerProxy: OSLogger_(logLevel: .debug, category: LoggerConstants.sdkLogs)
|
||||||
|
|
|
@ -126,7 +126,7 @@ private extension RootView {
|
||||||
}
|
}
|
||||||
|
|
||||||
Button("[Be careful] Nuke Wallet") {
|
Button("[Be careful] Nuke Wallet") {
|
||||||
viewStore.send(.initialization(.nukeWallet))
|
viewStore.send(.initialization(.nukeWalletRequest))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -154,6 +154,7 @@ private extension RootView {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.alert(self.store.scope(state: \.destinationState.alert), dismiss: .destination(.dismissAlert))
|
||||||
}
|
}
|
||||||
.navigationBarTitle("Startup")
|
.navigationBarTitle("Startup")
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,7 +17,7 @@ class HomeTests: XCTestCase {
|
||||||
reducer: HomeReducer()
|
reducer: HomeReducer()
|
||||||
)
|
)
|
||||||
|
|
||||||
store.send(.synchronizerStateChanged(.downloading))
|
store.send(.synchronizerStateChanged(.progressUpdated))
|
||||||
|
|
||||||
store.receive(.updateSynchronizerStatus)
|
store.receive(.updateSynchronizerStatus)
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue