- all alerts refactored and connected - unit tests fixed
This commit is contained in:
parent
c61b406372
commit
36d2090654
|
@ -370,6 +370,13 @@
|
|||
9E2F1C842809B606004E65FE /* DebugMenu.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9E2F1C832809B606004E65FE /* DebugMenu.swift */; };
|
||||
9E2F1C8C280ED6A7004E65FE /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 9E2F1C8B280ED6A7004E65FE /* LaunchScreen.storyboard */; };
|
||||
9E2F1C8F280EDE09004E65FE /* Drawer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9E2F1C8E280EDE09004E65FE /* Drawer.swift */; };
|
||||
9E33ECD429D5D99000708DE4 /* AlertRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9E33ECD029D4CCB600708DE4 /* AlertRequest.swift */; };
|
||||
9E33ECD529D5D99700708DE4 /* AlertReducer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9E9CEA3229D32D5100599DF5 /* AlertReducer.swift */; };
|
||||
9E33ECD629D5D99A00708DE4 /* AlertStates.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9E33ECD229D4D1FB00708DE4 /* AlertStates.swift */; };
|
||||
9E33ECD729D5E30200708DE4 /* AlertReducer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9E9CEA3229D32D5100599DF5 /* AlertReducer.swift */; };
|
||||
9E33ECD829D5E30200708DE4 /* AlertStates.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9E33ECD229D4D1FB00708DE4 /* AlertStates.swift */; };
|
||||
9E33ECD929D5E30200708DE4 /* AlertRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9E33ECD029D4CCB600708DE4 /* AlertRequest.swift */; };
|
||||
9E33ECDA29D5E30700708DE4 /* OnChangeReducer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9E9CEA3D29D47BE000599DF5 /* OnChangeReducer.swift */; };
|
||||
9E34519529C4A4BF00177D16 /* AddressDetailsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9E207C382966EF87003E2C9B /* AddressDetailsTests.swift */; };
|
||||
9E34519629C4A4D800177D16 /* secantUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0D4E7A2526B364180058B01E /* secantUITests.swift */; };
|
||||
9E34519729C4A51100177D16 /* RecoveryPhraseBackupTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0DFE93DE272C6D4B000FCCA5 /* RecoveryPhraseBackupTests.swift */; };
|
||||
|
@ -466,6 +473,7 @@
|
|||
9E852D6229B098F400CF4AC1 /* RootDebug.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9E852D6029B098F400CF4AC1 /* RootDebug.swift */; };
|
||||
9E9ADA7D2938F4C00071767B /* RootInitialization.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9E9ADA7C2938F4C00071767B /* RootInitialization.swift */; };
|
||||
9E9ADA7F2938F5EC0071767B /* RootDestination.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9E9ADA7E2938F5EC0071767B /* RootDestination.swift */; };
|
||||
9E9CEA3E29D47BE000599DF5 /* OnChangeReducer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9E9CEA3D29D47BE000599DF5 /* OnChangeReducer.swift */; };
|
||||
9EAB466D285A0468002904A0 /* Parsing in Frameworks */ = {isa = PBXBuildFile; productRef = 9EAB466C285A0468002904A0 /* Parsing */; };
|
||||
9EAB4671285A1C77002904A0 /* Deeplink.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9EAB4670285A1C77002904A0 /* Deeplink.swift */; };
|
||||
9EAB46782860A1D2002904A0 /* WalletEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9EAB46772860A1D2002904A0 /* WalletEvent.swift */; };
|
||||
|
@ -711,6 +719,8 @@
|
|||
9E2F1C832809B606004E65FE /* DebugMenu.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DebugMenu.swift; sourceTree = "<group>"; };
|
||||
9E2F1C8B280ED6A7004E65FE /* LaunchScreen.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = LaunchScreen.storyboard; sourceTree = "<group>"; };
|
||||
9E2F1C8E280EDE09004E65FE /* Drawer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Drawer.swift; sourceTree = "<group>"; };
|
||||
9E33ECD029D4CCB600708DE4 /* AlertRequest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AlertRequest.swift; sourceTree = "<group>"; };
|
||||
9E33ECD229D4D1FB00708DE4 /* AlertStates.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AlertStates.swift; sourceTree = "<group>"; };
|
||||
9E37A2B727C8F59F00AE57B3 /* Localizable.strings */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; path = Localizable.strings; sourceTree = "<group>"; };
|
||||
9E391123283E4CAC0073DD9A /* ImportWalletTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ImportWalletTests.swift; sourceTree = "<group>"; };
|
||||
9E39112D283F91600073DD9A /* ZatoshiTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ZatoshiTests.swift; sourceTree = "<group>"; };
|
||||
|
@ -772,6 +782,8 @@
|
|||
9E94C62228AA7EE0008256E9 /* BalanceBreakdownSnapshotTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BalanceBreakdownSnapshotTests.swift; sourceTree = "<group>"; };
|
||||
9E9ADA7C2938F4C00071767B /* RootInitialization.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RootInitialization.swift; sourceTree = "<group>"; };
|
||||
9E9ADA7E2938F5EC0071767B /* RootDestination.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RootDestination.swift; sourceTree = "<group>"; };
|
||||
9E9CEA3229D32D5100599DF5 /* AlertReducer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AlertReducer.swift; sourceTree = "<group>"; };
|
||||
9E9CEA3D29D47BE000599DF5 /* OnChangeReducer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OnChangeReducer.swift; sourceTree = "<group>"; };
|
||||
9E9ECC8C28589E150099D5A2 /* HomeSnapshotTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HomeSnapshotTests.swift; sourceTree = "<group>"; };
|
||||
9E9ECC8E28589E150099D5A2 /* WelcomeSnapshotTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = WelcomeSnapshotTests.swift; sourceTree = "<group>"; };
|
||||
9E9ECC9028589E150099D5A2 /* RecoveryPhraseDisplaySnapshotTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RecoveryPhraseDisplaySnapshotTests.swift; sourceTree = "<group>"; };
|
||||
|
@ -1260,6 +1272,7 @@
|
|||
6654C73B2715A3F000901167 /* Features */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
9E33ECCF29D4CC9900708DE4 /* Alerts */,
|
||||
9E7CB61B2874140900A02233 /* AddressDetails */,
|
||||
9E6713F2289BC51200A6796F /* BalanceBreakdown */,
|
||||
34C5657F29B60BDF002F3A7C /* ExportLogs */,
|
||||
|
@ -1421,6 +1434,16 @@
|
|||
path = Drawer;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
9E33ECCF29D4CC9900708DE4 /* Alerts */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
9E33ECD029D4CCB600708DE4 /* AlertRequest.swift */,
|
||||
9E9CEA3229D32D5100599DF5 /* AlertReducer.swift */,
|
||||
9E33ECD229D4D1FB00708DE4 /* AlertStates.swift */,
|
||||
);
|
||||
path = Alerts;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
9E391122283E4C970073DD9A /* ImportWalletTests */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
|
@ -1648,6 +1671,7 @@
|
|||
9E7FE0BB282D1DC200C374E8 /* Utils */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
9E9CEA3C29D47BD100599DF5 /* Reducers */,
|
||||
9E7FE0D4282D281800C374E8 /* Array+Chunked.swift */,
|
||||
F9C165B3274031F600592F76 /* Bindings.swift */,
|
||||
0DACFA7E27208CE00039EEA5 /* Clamped.swift */,
|
||||
|
@ -1804,6 +1828,14 @@
|
|||
path = BalanceBreakdownSnapshotTests;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
9E9CEA3C29D47BD100599DF5 /* Reducers */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
9E9CEA3D29D47BE000599DF5 /* OnChangeReducer.swift */,
|
||||
);
|
||||
path = Reducers;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
9E9ECC8B28589E150099D5A2 /* HomeSnapshotTests */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
|
@ -2615,6 +2647,7 @@
|
|||
0D26AEC4299E8196005260EE /* TCALogging.swift in Sources */,
|
||||
0D26AEC5299E8196005260EE /* RecoveryPhraseValidationFlowStore.swift in Sources */,
|
||||
9E486DFA29BA09C2003E6945 /* UIKit+Extensions.swift in Sources */,
|
||||
9E33ECDA29D5E30700708DE4 /* OnChangeReducer.swift in Sources */,
|
||||
0D26AEC6299E8196005260EE /* ImportWalletView.swift in Sources */,
|
||||
0D26AEC7299E8196005260EE /* RootInitialization.swift in Sources */,
|
||||
0D26AEC8299E8196005260EE /* LogsHandlerLive.swift in Sources */,
|
||||
|
@ -2641,6 +2674,7 @@
|
|||
9E486DE629B637AF003E6945 /* ImportBirthdayView.swift in Sources */,
|
||||
3467319629AE265300974482 /* SupportDataGenerator.swift in Sources */,
|
||||
0D26AEDC299E8196005260EE /* CheckCircle.swift in Sources */,
|
||||
9E33ECD929D5E30200708DE4 /* AlertRequest.swift in Sources */,
|
||||
0D26AEDD299E8196005260EE /* LogStore.swift in Sources */,
|
||||
0D26AEDE299E8196005260EE /* RecoveryPhraseRandomizer.swift in Sources */,
|
||||
3467319D29AE374A00974482 /* SupportDataGeneratorLiveKey.swift in Sources */,
|
||||
|
@ -2742,6 +2776,7 @@
|
|||
0D26AF3F299E8196005260EE /* WordChipGrid.swift in Sources */,
|
||||
0D26AF40299E8196005260EE /* RootDestination.swift in Sources */,
|
||||
0D26AF41299E8196005260EE /* OnboardingProgressIndicator.swift in Sources */,
|
||||
9E33ECD829D5E30200708DE4 /* AlertStates.swift in Sources */,
|
||||
0D26AF42299E8196005260EE /* CaptureDeviceInterface.swift in Sources */,
|
||||
0D26AF43299E8196005260EE /* FeedbackGeneratorLiveKey.swift in Sources */,
|
||||
0D26AF44299E8196005260EE /* Memo+toString.swift in Sources */,
|
||||
|
@ -2776,6 +2811,7 @@
|
|||
0D26AF61299E8196005260EE /* WalletStorageTestKey.swift in Sources */,
|
||||
0D26AF62299E8196005260EE /* WelcomeView.swift in Sources */,
|
||||
0D26AF63299E8196005260EE /* DeeplinkLiveKey.swift in Sources */,
|
||||
9E33ECD729D5E30200708DE4 /* AlertReducer.swift in Sources */,
|
||||
0D26AF64299E8196005260EE /* SettingsStore.swift in Sources */,
|
||||
0D26AF65299E8196005260EE /* InitializationState.swift in Sources */,
|
||||
0D26AF66299E8196005260EE /* ZcashSymbol.swift in Sources */,
|
||||
|
@ -2795,6 +2831,7 @@
|
|||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
9E33ECD629D5D99A00708DE4 /* AlertStates.swift in Sources */,
|
||||
2EB660E02747EAB900A06A07 /* OnboardingFlowView.swift in Sources */,
|
||||
9E7FE0DF282D2DD600C374E8 /* ZcashBadge.swift in Sources */,
|
||||
34F682F229A764120022C079 /* WalletConfigProviderLiveKey.swift in Sources */,
|
||||
|
@ -2809,6 +2846,7 @@
|
|||
34DA414728E4385800F8CC61 /* TransactionSendingView.swift in Sources */,
|
||||
F96B41E9273B501F0021B49A /* WalletEventsFlowView.swift in Sources */,
|
||||
9E4AA4F829BF76BB00752BB3 /* About.swift in Sources */,
|
||||
9E33ECD429D5D99000708DE4 /* AlertRequest.swift in Sources */,
|
||||
9EBDF96E291ECED4000A1A05 /* CaptureDeviceLiveKey.swift in Sources */,
|
||||
3467319929AE374300974482 /* SupportDataGeneratorInterface.swift in Sources */,
|
||||
9EBDF968291ECDA2000A1A05 /* AudioServicesInterface.swift in Sources */,
|
||||
|
@ -2839,6 +2877,7 @@
|
|||
9EB8638C2922CD4A003D0F8B /* FeedbackGeneratorTestKey.swift in Sources */,
|
||||
9E0F5741297E7F1D005304FA /* TCALogging.swift in Sources */,
|
||||
0DFE93E3272CA1AA000FCCA5 /* RecoveryPhraseValidationFlowStore.swift in Sources */,
|
||||
9E9CEA3E29D47BE000599DF5 /* OnChangeReducer.swift in Sources */,
|
||||
9E486DF929BA09C2003E6945 /* UIKit+Extensions.swift in Sources */,
|
||||
9E2DF99E27CF704D00649636 /* ImportWalletView.swift in Sources */,
|
||||
9E9ADA7D2938F4C00071767B /* RootInitialization.swift in Sources */,
|
||||
|
@ -2851,6 +2890,7 @@
|
|||
9EB863A1292398A8003D0F8B /* URIParserInterface.swift in Sources */,
|
||||
2E6CF8DD27D78319004DCD7A /* CurrencySelectionStore.swift in Sources */,
|
||||
9E153A7729216EFB00112F41 /* UserDefaultsTestKey.swift in Sources */,
|
||||
9E33ECD529D5D99700708DE4 /* AlertReducer.swift in Sources */,
|
||||
9EBEF87A27CE369800B4F343 /* RecoveryPhraseValidationFlowView.swift in Sources */,
|
||||
9E6713F7289BC58C00A6796F /* BalanceBreakdownStore.swift in Sources */,
|
||||
9E66122C2877188700C75B70 /* SyncStatusSnapshot.swift in Sources */,
|
||||
|
|
|
@ -17,7 +17,7 @@ extension DependencyValues {
|
|||
struct CaptureDeviceClient {
|
||||
enum CaptureDeviceClientError: Error {
|
||||
case captureDeviceFailed
|
||||
case lockFailed
|
||||
case lockForConfigurationFailed
|
||||
case torchUnavailable
|
||||
}
|
||||
|
||||
|
|
|
@ -31,7 +31,7 @@ extension CaptureDeviceClient: DependencyKey {
|
|||
videoCaptureDevice.torchMode = isTorchOn ? .on : .off
|
||||
videoCaptureDevice.unlockForConfiguration()
|
||||
} catch {
|
||||
throw CaptureDeviceClientError.lockFailed
|
||||
throw CaptureDeviceClientError.lockForConfigurationFailed
|
||||
}
|
||||
}
|
||||
)
|
||||
|
|
|
@ -0,0 +1,118 @@
|
|||
//
|
||||
// AlertReducer.swift
|
||||
// secant
|
||||
//
|
||||
// Created by Lukáš Korba on 28.03.2023.
|
||||
//
|
||||
|
||||
import ComposableArchitecture
|
||||
|
||||
extension ReducerProtocol<RootReducer.State, RootReducer.Action> {
|
||||
func alerts() -> some ReducerProtocol<RootReducer.State, RootReducer.Action> {
|
||||
UniAlert(base: self)
|
||||
}
|
||||
}
|
||||
|
||||
private struct UniAlert<Base: ReducerProtocol<RootReducer.State, RootReducer.Action>>: ReducerProtocol {
|
||||
let base: Base
|
||||
|
||||
var body: some ReducerProtocol<RootReducer.State, RootReducer.Action> {
|
||||
base
|
||||
catchAlertRequests
|
||||
passAlertActions
|
||||
}
|
||||
|
||||
// Catching the alert side effects
|
||||
@ReducerBuilder<State, Action>
|
||||
var catchAlertRequests: some ReducerProtocol<State, Action> {
|
||||
Reduce { state, action in
|
||||
switch action {
|
||||
case .alert(let alert):
|
||||
state.uniAlert = alert.alertState()
|
||||
return .none
|
||||
|
||||
case .exportLogs(.alert(let alert)):
|
||||
state.uniAlert = alert.alertState()
|
||||
return .none
|
||||
case .home(.settings(.exportLogs(.alert(let alert)))):
|
||||
state.uniAlert = alert.alertState()
|
||||
return .none
|
||||
|
||||
case .home(.alert(let alert)):
|
||||
state.uniAlert = alert.alertState()
|
||||
return .none
|
||||
|
||||
case .home(.balanceBreakdown(.alert(let alert))):
|
||||
state.uniAlert = alert.alertState()
|
||||
return .none
|
||||
|
||||
case .home(.send(.scan(.alert(let alert)))):
|
||||
state.uniAlert = alert.alertState()
|
||||
return .none
|
||||
|
||||
case .onboarding(.importWallet(.alert(let alert))):
|
||||
state.uniAlert = alert.alertState()
|
||||
return .none
|
||||
|
||||
case .home(.settings(.alert(let alert))):
|
||||
state.uniAlert = alert.alertState()
|
||||
return .none
|
||||
|
||||
case .home(.walletEvents(.alert(let alert))):
|
||||
state.uniAlert = alert.alertState()
|
||||
return .none
|
||||
|
||||
default: return .none
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Passing alert actions back to the children
|
||||
@ReducerBuilder<State, Action>
|
||||
var passAlertActions: some ReducerProtocol<State, Action> {
|
||||
Reduce { state, action in
|
||||
switch action {
|
||||
case .dismissAlert:
|
||||
state.uniAlert = nil
|
||||
return .none
|
||||
|
||||
case .uniAlert(.balanceBreakdown(let action)):
|
||||
guard let action else { return .none }
|
||||
return EffectTask(value: .home(.balanceBreakdown(action)))
|
||||
|
||||
case .uniAlert(.exportLogs(let action)):
|
||||
guard let action else { return .none }
|
||||
return .concatenate(
|
||||
EffectTask(value: .exportLogs(action)),
|
||||
EffectTask(value: .home(.settings(.exportLogs(action))))
|
||||
)
|
||||
|
||||
case .uniAlert(.home(let action)):
|
||||
guard let action else { return .none }
|
||||
return EffectTask(value: .home(action))
|
||||
|
||||
case .uniAlert(.importWallet(let action)):
|
||||
guard let action else { return .none }
|
||||
return EffectTask(value: .onboarding(.importWallet(action)))
|
||||
|
||||
case .uniAlert(.root(let action)):
|
||||
guard let action else { return .none }
|
||||
return EffectTask(value: action)
|
||||
|
||||
case .uniAlert(.scan(let action)):
|
||||
guard let action else { return .none }
|
||||
return EffectTask(value: .home(.send(.scan(action))))
|
||||
|
||||
case .uniAlert(.settings(let action)):
|
||||
guard let action else { return .none }
|
||||
return EffectTask(value: .home(.settings(action)))
|
||||
|
||||
case .uniAlert(.walletEvents(let action)):
|
||||
guard let action else { return .none }
|
||||
return EffectTask(value: .home(.walletEvents(action)))
|
||||
|
||||
default: return .none
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,98 @@
|
|||
//
|
||||
// AlertRequest.swift
|
||||
// secant-testnet
|
||||
//
|
||||
// Created by Lukáš Korba on 29.03.2023.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import ComposableArchitecture
|
||||
|
||||
extension RootReducer {
|
||||
indirect enum AlertAction: Equatable {
|
||||
case balanceBreakdown(BalanceBreakdownReducer.Action?)
|
||||
case exportLogs(ExportLogsReducer.Action?)
|
||||
case home(HomeReducer.Action?)
|
||||
case importWallet(ImportWalletReducer.Action?)
|
||||
case root(RootReducer.Action?)
|
||||
case scan(ScanReducer.Action?)
|
||||
case settings(SettingsReducer.Action?)
|
||||
case walletEvents(WalletEventsFlowReducer.Action?)
|
||||
}
|
||||
}
|
||||
|
||||
enum AlertRequest: Equatable {
|
||||
enum BalanceBreakdown: Equatable {
|
||||
case shieldFundsSuccess
|
||||
case shieldFundsFailure(String)
|
||||
}
|
||||
|
||||
enum ExportLogs: Equatable {
|
||||
case failed(String)
|
||||
}
|
||||
|
||||
enum Home: Equatable {
|
||||
case syncFailed(String, String)
|
||||
}
|
||||
|
||||
enum ImportWallet: Equatable {
|
||||
case succeed
|
||||
case failed(String)
|
||||
}
|
||||
|
||||
enum Root: Equatable {
|
||||
case cantCreateNewWallet(String)
|
||||
case cantLoadSeedPhrase
|
||||
case cantStartSync(String)
|
||||
case cantStoreThatUserPassedPhraseBackupTest(String)
|
||||
case failedToProcessDeeplink(URL, String)
|
||||
case initializationFailed(String)
|
||||
case rewindFailed(String)
|
||||
case walletStateFailed(InitializationState)
|
||||
case wipeFailed
|
||||
case wipeRequest
|
||||
}
|
||||
|
||||
enum Scan: Equatable {
|
||||
case cantInitializeCamera(String)
|
||||
}
|
||||
|
||||
enum Settings: Equatable {
|
||||
case cantBackupWallet(String)
|
||||
case sendSupportMail
|
||||
}
|
||||
|
||||
enum WalletEvents: Equatable {
|
||||
case warnBeforeLeavingApp(URL?)
|
||||
}
|
||||
|
||||
case balanceBreakdown(BalanceBreakdown)
|
||||
case exportLogs(ExportLogs)
|
||||
case home(Home)
|
||||
case importWallet(ImportWallet)
|
||||
case root(Root)
|
||||
case scan(Scan)
|
||||
case settings(Settings)
|
||||
case walletEvents(WalletEvents)
|
||||
|
||||
func alertState() -> AlertState<RootReducer.Action> {
|
||||
switch self {
|
||||
case .balanceBreakdown(let balanceBreakdown):
|
||||
return balanceBreakdownAlertState(balanceBreakdown)
|
||||
case .exportLogs(let exportLogs):
|
||||
return exportLogsAlertState(exportLogs)
|
||||
case .home(let home):
|
||||
return homeAlertState(home)
|
||||
case .importWallet(let importWallet):
|
||||
return importWalletAlertState(importWallet)
|
||||
case .root(let root):
|
||||
return rootAlertState(root)
|
||||
case .scan(let scan):
|
||||
return scanAlertState(scan)
|
||||
case .settings(let settings):
|
||||
return settingsAlertState(settings)
|
||||
case .walletEvents(let walletEvents):
|
||||
return walletEventsAlertState(walletEvents)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,211 @@
|
|||
//
|
||||
// AlertStates.swift
|
||||
// secant-testnet
|
||||
//
|
||||
// Created by Lukáš Korba on 29.03.2023.
|
||||
//
|
||||
|
||||
import ComposableArchitecture
|
||||
|
||||
// MARK: - Balance Breakdown
|
||||
|
||||
extension AlertRequest {
|
||||
func balanceBreakdownAlertState(_ balanceBreakdown: BalanceBreakdown) -> AlertState<RootReducer.Action> {
|
||||
switch balanceBreakdown {
|
||||
case .shieldFundsFailure(let errorDescription):
|
||||
return AlertState(
|
||||
title: TextState(L10n.BalanceBreakdown.Alert.ShieldFunds.Failure.title),
|
||||
message: TextState(L10n.BalanceBreakdown.Alert.ShieldFunds.Failure.message(errorDescription)),
|
||||
dismissButton: .default(TextState(L10n.General.ok), action: .send(.dismissAlert))
|
||||
)
|
||||
case .shieldFundsSuccess:
|
||||
return AlertState(
|
||||
title: TextState(L10n.BalanceBreakdown.Alert.ShieldFunds.Success.title),
|
||||
message: TextState(L10n.BalanceBreakdown.Alert.ShieldFunds.Success.message),
|
||||
dismissButton: .default(TextState(L10n.General.ok), action: .send(.dismissAlert))
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Export Logs
|
||||
|
||||
extension AlertRequest {
|
||||
func exportLogsAlertState(_ exportLogs: ExportLogs) -> AlertState<RootReducer.Action> {
|
||||
switch exportLogs {
|
||||
case .failed(let errorDescription):
|
||||
return AlertState(
|
||||
title: TextState(L10n.ExportLogs.Alert.Failed.title),
|
||||
message: TextState(L10n.ExportLogs.Alert.Failed.message(errorDescription)),
|
||||
dismissButton: .default(TextState(L10n.General.ok), action: .send(.dismissAlert))
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Home
|
||||
|
||||
extension AlertRequest {
|
||||
func homeAlertState(_ home: Home) -> AlertState<RootReducer.Action> {
|
||||
switch home {
|
||||
case let .syncFailed(message, secondaryButtonTitle):
|
||||
return AlertState(
|
||||
title: TextState(L10n.Home.SyncFailed.title),
|
||||
message: TextState(message),
|
||||
primaryButton: .default(TextState(L10n.Home.SyncFailed.retry), action: .send(.uniAlert(.home(.retrySync)))),
|
||||
secondaryButton: .default(TextState(secondaryButtonTitle), action: .send(.dismissAlert))
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Import Wallet
|
||||
|
||||
extension AlertRequest {
|
||||
func importWalletAlertState(_ importWallet: ImportWallet) -> AlertState<RootReducer.Action> {
|
||||
switch importWallet {
|
||||
case .succeed:
|
||||
return AlertState(
|
||||
title: TextState(L10n.General.success),
|
||||
message: TextState(L10n.ImportWallet.Alert.Success.message),
|
||||
dismissButton: .default(TextState(L10n.General.ok), action: .send(.uniAlert(.importWallet(.successfullyRecovered))))
|
||||
)
|
||||
case .failed(let errorDescription):
|
||||
return AlertState(
|
||||
title: TextState(L10n.ImportWallet.Alert.Failed.title),
|
||||
message: TextState(L10n.ImportWallet.Alert.Failed.message(errorDescription)),
|
||||
dismissButton: .default(TextState(L10n.General.ok), action: .send(.dismissAlert))
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Root
|
||||
|
||||
extension AlertRequest {
|
||||
func rootAlertState(_ root: Root) -> AlertState<RootReducer.Action> {
|
||||
switch root {
|
||||
case .cantCreateNewWallet(let errorDescription):
|
||||
return AlertState(
|
||||
title: TextState(L10n.Root.Initialization.Alert.Failed.title),
|
||||
message: TextState(L10n.Root.Initialization.Alert.CantCreateNewWallet.message(errorDescription)),
|
||||
dismissButton: .default(TextState(L10n.General.ok), action: .send(.dismissAlert))
|
||||
)
|
||||
case .cantLoadSeedPhrase:
|
||||
return AlertState(
|
||||
title: TextState(L10n.Root.Initialization.Alert.Failed.title),
|
||||
message: TextState(L10n.Root.Initialization.Alert.CantLoadSeedPhrase.message),
|
||||
dismissButton: .default(TextState(L10n.General.ok), action: .send(.dismissAlert))
|
||||
)
|
||||
case .cantStartSync(let errorDescription):
|
||||
return AlertState(
|
||||
title: TextState(L10n.Root.Debug.Alert.Rewind.CantStartSync.title),
|
||||
message: TextState(L10n.Root.Debug.Alert.Rewind.CantStartSync.message(errorDescription)),
|
||||
dismissButton: .default(TextState(L10n.General.ok), action: .send(.dismissAlert))
|
||||
)
|
||||
case .cantStoreThatUserPassedPhraseBackupTest(let errorDescription):
|
||||
return AlertState(
|
||||
title: TextState(L10n.Root.Initialization.Alert.Failed.title),
|
||||
message: TextState(L10n.Root.Initialization.Alert.CantStoreThatUserPassedPhraseBackupTest.message(errorDescription)),
|
||||
dismissButton: .default(TextState(L10n.General.ok), action: .send(.dismissAlert))
|
||||
)
|
||||
case let .failedToProcessDeeplink(url, errorDescription):
|
||||
return AlertState(
|
||||
title: TextState(L10n.Root.Destination.Alert.FailedToProcessDeeplink.title),
|
||||
message: TextState(L10n.Root.Destination.Alert.FailedToProcessDeeplink.message(url, errorDescription)),
|
||||
dismissButton: .default(TextState(L10n.General.ok), action: .send(.dismissAlert))
|
||||
)
|
||||
case .initializationFailed(let errorDescription):
|
||||
return AlertState(
|
||||
title: TextState(L10n.Root.Initialization.Alert.SdkInitFailed.title),
|
||||
message: TextState(L10n.Root.Initialization.Alert.Error.message(errorDescription)),
|
||||
dismissButton: .default(TextState(L10n.General.ok), action: .send(.dismissAlert))
|
||||
)
|
||||
case .rewindFailed(let errorDescription):
|
||||
return AlertState(
|
||||
title: TextState(L10n.Root.Debug.Alert.Rewind.Failed.title),
|
||||
message: TextState(L10n.Root.Debug.Alert.Rewind.Failed.message(errorDescription)),
|
||||
dismissButton: .default(TextState(L10n.General.ok), action: .send(.dismissAlert))
|
||||
)
|
||||
case .walletStateFailed(let walletState):
|
||||
return AlertState(
|
||||
title: TextState(L10n.Root.Initialization.Alert.Failed.title),
|
||||
message: TextState(L10n.Root.Initialization.Alert.WalletStateFailed.message(walletState)),
|
||||
dismissButton: .default(TextState(L10n.General.ok), action: .send(.dismissAlert))
|
||||
)
|
||||
case .wipeFailed:
|
||||
return AlertState(
|
||||
title: TextState(L10n.Root.Initialization.Alert.WipeFailed.title),
|
||||
message: TextState(""),
|
||||
dismissButton: .default(TextState(L10n.General.ok), action: .send(.dismissAlert))
|
||||
)
|
||||
case .wipeRequest:
|
||||
return AlertState(
|
||||
title: TextState(L10n.Root.Initialization.Alert.Wipe.title),
|
||||
message: TextState(L10n.Root.Initialization.Alert.Wipe.message),
|
||||
buttons: [
|
||||
.destructive(TextState(L10n.General.yes), action: .send(.initialization(.nukeWallet))),
|
||||
.cancel(TextState(L10n.General.no), action: .send(.dismissAlert))
|
||||
]
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Scan
|
||||
|
||||
extension AlertRequest {
|
||||
func scanAlertState(_ scan: Scan) -> AlertState<RootReducer.Action> {
|
||||
switch scan {
|
||||
case .cantInitializeCamera(let errorDescription):
|
||||
return AlertState(
|
||||
title: TextState(L10n.Scan.Alert.CantInitializeCamera.title),
|
||||
message: TextState(L10n.Scan.Alert.CantInitializeCamera.message(errorDescription)),
|
||||
dismissButton: .default(TextState(L10n.General.ok), action: .send(.dismissAlert))
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Settings
|
||||
|
||||
extension AlertRequest {
|
||||
func settingsAlertState(_ settings: Settings) -> AlertState<RootReducer.Action> {
|
||||
switch settings {
|
||||
case .cantBackupWallet(let message):
|
||||
return AlertState<RootReducer.Action>(
|
||||
title: TextState(L10n.Settings.Alert.CantBackupWallet.title),
|
||||
message: TextState(L10n.Settings.Alert.CantBackupWallet.message(message)),
|
||||
dismissButton: .default(TextState(L10n.General.ok), action: .send(.dismissAlert))
|
||||
)
|
||||
case .sendSupportMail:
|
||||
return AlertState<RootReducer.Action>(
|
||||
title: TextState(L10n.Settings.Alert.CantSendEmail.title),
|
||||
message: TextState(L10n.Settings.Alert.CantSendEmail.message),
|
||||
dismissButton: .default(TextState(L10n.General.ok), action: .send(.uniAlert(.settings(.sendSupportMailFinished))))
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Wallet Events
|
||||
|
||||
extension AlertRequest {
|
||||
func walletEventsAlertState(_ walletEvents: WalletEvents) -> AlertState<RootReducer.Action> {
|
||||
switch walletEvents {
|
||||
case .warnBeforeLeavingApp(let blockExplorerURL):
|
||||
return AlertState(
|
||||
title: TextState(L10n.WalletEvent.Alert.LeavingApp.title),
|
||||
message: TextState(L10n.WalletEvent.Alert.LeavingApp.message),
|
||||
primaryButton: .cancel(
|
||||
TextState(L10n.WalletEvent.Alert.LeavingApp.Button.nevermind),
|
||||
action: .send(.dismissAlert)
|
||||
),
|
||||
secondaryButton: .default(
|
||||
TextState(L10n.WalletEvent.Alert.LeavingApp.Button.seeOnline),
|
||||
action: .send(.uniAlert(.walletEvents(.openBlockExplorer(blockExplorerURL))))
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -16,7 +16,6 @@ struct BalanceBreakdownReducer: ReducerProtocol {
|
|||
private enum CancelId {}
|
||||
|
||||
struct State: Equatable {
|
||||
@BindingState var alert: AlertState<BalanceBreakdownReducer.Action>?
|
||||
var autoShieldingThreshold: Zatoshi
|
||||
var latestBlock: String
|
||||
var shieldedBalance: Balance
|
||||
|
@ -36,9 +35,8 @@ struct BalanceBreakdownReducer: ReducerProtocol {
|
|||
}
|
||||
}
|
||||
|
||||
enum Action: Equatable, BindableAction {
|
||||
case binding(BindingAction<BalanceBreakdownReducer.State>)
|
||||
case dismissAlert
|
||||
enum Action: Equatable {
|
||||
case alert(AlertRequest)
|
||||
case onAppear
|
||||
case onDisappear
|
||||
case shieldFunds
|
||||
|
@ -56,15 +54,9 @@ struct BalanceBreakdownReducer: ReducerProtocol {
|
|||
@Dependency(\.walletStorage) var walletStorage
|
||||
|
||||
var body: some ReducerProtocol<State, Action> {
|
||||
BindingReducer()
|
||||
|
||||
Reduce { state, action in
|
||||
switch action {
|
||||
case .binding:
|
||||
return .none
|
||||
|
||||
case .dismissAlert:
|
||||
state.alert = nil
|
||||
case .alert:
|
||||
return .none
|
||||
|
||||
case .onAppear:
|
||||
|
@ -95,21 +87,11 @@ struct BalanceBreakdownReducer: ReducerProtocol {
|
|||
|
||||
case .shieldFundsSuccess:
|
||||
state.shieldingFunds = false
|
||||
state.alert = AlertState(
|
||||
title: TextState(L10n.BalanceBreakdown.Alert.ShieldFunds.Success.title),
|
||||
message: TextState(L10n.BalanceBreakdown.Alert.ShieldFunds.Success.message),
|
||||
dismissButton: .default(TextState(L10n.General.ok), action: .send(.dismissAlert))
|
||||
)
|
||||
return .none
|
||||
return EffectTask(value: .alert(.balanceBreakdown(.shieldFundsSuccess)))
|
||||
|
||||
case let .shieldFundsFailure(errorDescription):
|
||||
state.shieldingFunds = false
|
||||
state.alert = AlertState(
|
||||
title: TextState(L10n.BalanceBreakdown.Alert.ShieldFunds.Failure.title),
|
||||
message: TextState(L10n.BalanceBreakdown.Alert.ShieldFunds.Failure.message(errorDescription)),
|
||||
dismissButton: .default(TextState(L10n.General.ok), action: .send(.dismissAlert))
|
||||
)
|
||||
return .none
|
||||
return EffectTask(value: .alert(.balanceBreakdown(.shieldFundsFailure(errorDescription))))
|
||||
|
||||
case .synchronizerStateChanged(let latestState):
|
||||
state.shieldedBalance = latestState.shieldedBalance.redacted
|
||||
|
|
|
@ -47,7 +47,6 @@ struct BalanceBreakdownView: View {
|
|||
|
||||
Spacer()
|
||||
}
|
||||
.alert(self.store.scope(state: \.alert), dismiss: .dismissAlert)
|
||||
.onAppear { viewStore.send(.onAppear) }
|
||||
.onDisappear { viewStore.send(.onDisappear) }
|
||||
}
|
||||
|
|
|
@ -15,15 +15,13 @@ typealias ExportLogsViewStore = ViewStore<ExportLogsReducer.State, ExportLogsRed
|
|||
|
||||
struct ExportLogsReducer: ReducerProtocol {
|
||||
struct State: Equatable {
|
||||
@BindingState var alert: AlertState<ExportLogsReducer.Action>?
|
||||
var exportLogsDisabled = false
|
||||
var isSharingLogs = false
|
||||
var zippedLogsURLs: [URL] = []
|
||||
}
|
||||
|
||||
indirect enum Action: Equatable, BindableAction {
|
||||
case binding(BindingAction<ExportLogsReducer.State>)
|
||||
case dismissAlert
|
||||
indirect enum Action: Equatable {
|
||||
case alert(AlertRequest)
|
||||
case start
|
||||
case finished(URL?)
|
||||
case failed(String)
|
||||
|
@ -33,17 +31,9 @@ struct ExportLogsReducer: ReducerProtocol {
|
|||
@Dependency(\.logsHandler) var logsHandler
|
||||
|
||||
var body: some ReducerProtocol<State, Action> {
|
||||
BindingReducer()
|
||||
|
||||
Reduce { state, action in
|
||||
switch action {
|
||||
case .binding:
|
||||
return .none
|
||||
|
||||
case .dismissAlert:
|
||||
state.exportLogsDisabled = false
|
||||
state.isSharingLogs = false
|
||||
state.alert = nil
|
||||
case .alert:
|
||||
return .none
|
||||
|
||||
case .start:
|
||||
|
@ -66,13 +56,9 @@ struct ExportLogsReducer: ReducerProtocol {
|
|||
return .none
|
||||
|
||||
case let .failed(errorDescription):
|
||||
// TODO: [#527] address the error here https://github.com/zcash/secant-ios-wallet/issues/527
|
||||
state.alert = AlertState(
|
||||
title: TextState(L10n.ExportLogs.Alert.Failed.title),
|
||||
message: TextState(L10n.ExportLogs.Alert.Failed.message(errorDescription)),
|
||||
dismissButton: .default(TextState(L10n.General.ok), action: .send(.dismissAlert))
|
||||
)
|
||||
return .none
|
||||
state.exportLogsDisabled = false
|
||||
state.isSharingLogs = false
|
||||
return EffectTask(value: .alert(.exportLogs(.failed(errorDescription))))
|
||||
|
||||
case .shareFinished:
|
||||
state.isSharingLogs = false
|
||||
|
|
|
@ -21,7 +21,6 @@ struct HomeReducer: ReducerProtocol {
|
|||
case transactionHistory
|
||||
}
|
||||
|
||||
@BindingState var alert: AlertState<HomeReducer.Action>?
|
||||
var balanceBreakdownState: BalanceBreakdownReducer.State
|
||||
var destination: Destination?
|
||||
var profileState: ProfileReducer.State
|
||||
|
@ -62,9 +61,9 @@ struct HomeReducer: ReducerProtocol {
|
|||
}
|
||||
|
||||
enum Action: Equatable {
|
||||
case alert(AlertRequest)
|
||||
case balanceBreakdown(BalanceBreakdownReducer.Action)
|
||||
case debugMenuStartup
|
||||
case dismissAlert
|
||||
case onAppear
|
||||
case onDisappear
|
||||
case profile(ProfileReducer.Action)
|
||||
|
@ -183,8 +182,7 @@ struct HomeReducer: ReducerProtocol {
|
|||
}
|
||||
|
||||
case .showSynchronizerErrorAlert(let snapshot):
|
||||
state.alert = HomeStore.syncErrorAlert(with: snapshot)
|
||||
return .none
|
||||
return EffectTask(value: .alert(.home(.syncFailed(snapshot.message, L10n.Home.SyncFailed.dismiss))))
|
||||
|
||||
case .balanceBreakdown(.onDisappear):
|
||||
state.destination = nil
|
||||
|
@ -195,18 +193,11 @@ struct HomeReducer: ReducerProtocol {
|
|||
|
||||
case .debugMenuStartup:
|
||||
return .none
|
||||
|
||||
case .dismissAlert:
|
||||
state.alert = nil
|
||||
return .none
|
||||
|
||||
case .syncFailed(let errorMessage):
|
||||
state.alert = AlertState<HomeReducer.Action>(
|
||||
title: TextState(L10n.Home.SyncFailed.title),
|
||||
message: TextState(errorMessage),
|
||||
primaryButton: .default(TextState(L10n.Home.SyncFailed.retry), action: .send(.retrySync)),
|
||||
secondaryButton: .default(TextState(L10n.General.ok), action: .send(.dismissAlert))
|
||||
)
|
||||
return EffectTask(value: .alert(.home(.syncFailed(errorMessage, L10n.General.ok))))
|
||||
|
||||
case .alert:
|
||||
return .none
|
||||
}
|
||||
}
|
||||
|
@ -265,18 +256,6 @@ extension HomeViewStore {
|
|||
}
|
||||
}
|
||||
|
||||
// MARK: Alerts
|
||||
|
||||
extension HomeStore {
|
||||
static func syncErrorAlert(with snapshot: SyncStatusSnapshot) -> AlertState<HomeReducer.Action> {
|
||||
AlertState<HomeReducer.Action>(
|
||||
title: TextState(L10n.Home.SyncFailed.title),
|
||||
message: TextState(snapshot.message),
|
||||
primaryButton: .default(TextState(L10n.Home.SyncFailed.retry), action: .send(.retrySync)),
|
||||
secondaryButton: .default(TextState(L10n.Home.SyncFailed.dismiss), action: .send(.dismissAlert))
|
||||
)
|
||||
}
|
||||
}
|
||||
// MARK: Placeholders
|
||||
|
||||
extension HomeReducer.State {
|
||||
|
@ -306,11 +285,6 @@ extension HomeStore {
|
|||
static var error: HomeStore {
|
||||
HomeStore(
|
||||
initialState: .init(
|
||||
alert: HomeStore.syncErrorAlert(
|
||||
with: SyncStatusSnapshot.snapshotFor(
|
||||
state: .error(SynchronizerError.networkTimeout)
|
||||
)
|
||||
),
|
||||
balanceBreakdownState: .placeholder,
|
||||
profileState: .placeholder,
|
||||
scanState: .placeholder,
|
||||
|
|
|
@ -29,7 +29,6 @@ struct HomeView: View {
|
|||
.navigationBarTitleDisplayMode(.inline)
|
||||
.onAppear(perform: { viewStore.send(.onAppear) })
|
||||
.onDisappear(perform: { viewStore.send(.onDisappear) })
|
||||
.alert(self.store.scope(state: \.alert), dismiss: .dismissAlert)
|
||||
.navigationLinkEmpty(
|
||||
isActive: viewStore.bindingForDestination(.balanceBreakdown),
|
||||
destination: { BalanceBreakdownView(store: store.balanceBreakdownStore()) }
|
||||
|
|
|
@ -43,7 +43,6 @@ struct ImportBirthdayView: View {
|
|||
.applyScreenBackground()
|
||||
.scrollableWhenScaledUp()
|
||||
.onAppear(perform: { viewStore.send(.onAppear) })
|
||||
.alert(self.store.scope(state: \.alert), dismiss: .dismissAlert)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,7 +18,6 @@ struct ImportWalletReducer: ReducerProtocol {
|
|||
case birthday
|
||||
}
|
||||
|
||||
@BindingState var alert: AlertState<ImportWalletReducer.Action>?
|
||||
var birthdayHeight = "".redacted
|
||||
var birthdayHeightValue: RedactableBlockHeight?
|
||||
var destination: Destination?
|
||||
|
@ -43,10 +42,9 @@ struct ImportWalletReducer: ReducerProtocol {
|
|||
}
|
||||
}
|
||||
|
||||
enum Action: Equatable, BindableAction {
|
||||
case binding(BindingAction<ImportWalletReducer.State>)
|
||||
enum Action: Equatable {
|
||||
case alert(AlertRequest)
|
||||
case birthdayInputChanged(RedactableString)
|
||||
case dismissAlert
|
||||
case restoreWallet
|
||||
case importPrivateOrViewingKey
|
||||
case initializeSDK
|
||||
|
@ -61,8 +59,6 @@ struct ImportWalletReducer: ReducerProtocol {
|
|||
@Dependency(\.zcashSDKEnvironment) var zcashSDKEnvironment
|
||||
|
||||
var body: some ReducerProtocol<State, Action> {
|
||||
BindingReducer()
|
||||
|
||||
Reduce { state, action in
|
||||
switch action {
|
||||
case .onAppear:
|
||||
|
@ -95,11 +91,7 @@ struct ImportWalletReducer: ReducerProtocol {
|
|||
}
|
||||
return .none
|
||||
|
||||
case .binding:
|
||||
return .none
|
||||
|
||||
case .dismissAlert:
|
||||
state.alert = nil
|
||||
case .alert:
|
||||
return .none
|
||||
|
||||
case .restoreWallet:
|
||||
|
@ -116,31 +108,14 @@ struct ImportWalletReducer: ReducerProtocol {
|
|||
try walletStorage.markUserPassedPhraseBackupTest(true)
|
||||
|
||||
// notify user
|
||||
// TODO: [#221] Proper Error/Success handling (https://github.com/zcash/secant-ios-wallet/issues/221)
|
||||
state.alert = AlertState(
|
||||
title: TextState(L10n.General.success),
|
||||
message: TextState(L10n.ImportWallet.Alert.Success.message),
|
||||
dismissButton: .default(
|
||||
TextState(L10n.General.ok),
|
||||
action: .send(.successfullyRecovered)
|
||||
)
|
||||
return .concatenate(
|
||||
EffectTask(value: .alert(.importWallet(.succeed))),
|
||||
EffectTask(value: .initializeSDK)
|
||||
)
|
||||
|
||||
return EffectTask(value: .initializeSDK)
|
||||
} catch {
|
||||
// TODO: [#221] Proper Error/Success handling (https://github.com/zcash/secant-ios-wallet/issues/221)
|
||||
state.alert = AlertState(
|
||||
title: TextState(L10n.ImportWallet.Alert.Failed.title),
|
||||
message: TextState(L10n.ImportWallet.Alert.Failed.message(error.localizedDescription)),
|
||||
dismissButton: .default(
|
||||
TextState(L10n.General.ok),
|
||||
action: .send(.dismissAlert)
|
||||
)
|
||||
)
|
||||
return EffectTask(value: .alert(.importWallet(.failed(error.localizedDescription))))
|
||||
}
|
||||
|
||||
return .none
|
||||
|
||||
case .updateDestination(let destination):
|
||||
state.destination = destination
|
||||
return .none
|
||||
|
@ -149,7 +124,7 @@ struct ImportWalletReducer: ReducerProtocol {
|
|||
return .none
|
||||
|
||||
case .successfullyRecovered:
|
||||
return EffectTask(value: .dismissAlert)
|
||||
return .none
|
||||
|
||||
case .initializeSDK:
|
||||
return .none
|
||||
|
|
|
@ -39,7 +39,6 @@ struct ImportWalletView: View {
|
|||
.applyScreenBackground()
|
||||
.scrollableWhenScaledUp()
|
||||
.onAppear(perform: { viewStore.send(.onAppear) })
|
||||
.alert(self.store.scope(state: \.alert), dismiss: .dismissAlert)
|
||||
.navigationLinkEmpty(
|
||||
isActive: viewStore.bindingForDestination(.birthday),
|
||||
destination: { ImportBirthdayView(store: store) }
|
||||
|
|
|
@ -64,12 +64,7 @@ extension RootReducer {
|
|||
|
||||
case let .debug(.rewindDone(errorDescription, _)):
|
||||
if let errorDescription {
|
||||
// TODO: [#221] Handle error more properly (https://github.com/zcash/secant-ios-wallet/issues/221)
|
||||
state.alert = AlertState(
|
||||
title: TextState(L10n.Root.Debug.Alert.Rewind.Failed.title),
|
||||
message: TextState(L10n.Root.Debug.Alert.Rewind.Failed.message(errorDescription)),
|
||||
dismissButton: .default(TextState(L10n.General.ok), action: .send(.dismissAlert))
|
||||
)
|
||||
return EffectTask(value: .alert(.root(.rewindFailed(errorDescription))))
|
||||
} else {
|
||||
return .run { send in
|
||||
do {
|
||||
|
@ -79,8 +74,6 @@ extension RootReducer {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
return .none
|
||||
|
||||
case let .debug(.updateFlag(flag, isEnabled)):
|
||||
return walletConfigProvider.update(flag, !isEnabled)
|
||||
|
@ -100,13 +93,7 @@ extension RootReducer {
|
|||
return EffectTask(value: .updateStateAfterConfigUpdate(walletConfig))
|
||||
|
||||
case .debug(.cantStartSync(let errorMessage)):
|
||||
// TODO: [#221] Handle error more properly (https://github.com/zcash/secant-ios-wallet/issues/221)
|
||||
state.alert = AlertState(
|
||||
title: TextState(L10n.Root.Debug.Alert.Rewind.CantStartSync.title),
|
||||
message: TextState(L10n.Root.Debug.Alert.Rewind.CantStartSync.message(errorMessage)),
|
||||
dismissButton: .default(TextState(L10n.General.ok), action: .send(.dismissAlert))
|
||||
)
|
||||
return .none
|
||||
return EffectTask(value: .alert(.root(.cantStartSync(errorMessage))))
|
||||
|
||||
default: return .none
|
||||
}
|
||||
|
|
|
@ -23,7 +23,6 @@ extension RootReducer {
|
|||
case welcome
|
||||
}
|
||||
|
||||
@BindingState var alert: AlertState<RootReducer.Action>?
|
||||
var internalDestination: Destination = .welcome
|
||||
var previousDestination: Destination?
|
||||
|
||||
|
@ -41,7 +40,6 @@ extension RootReducer {
|
|||
case deeplinkHome
|
||||
case deeplinkSend(Zatoshi, String, String)
|
||||
case deeplinkFailed(URL, String)
|
||||
case dismissAlert
|
||||
case updateDestination(RootReducer.DestinationState.Destination)
|
||||
}
|
||||
|
||||
|
@ -113,16 +111,7 @@ extension RootReducer {
|
|||
return .none
|
||||
|
||||
case let .destination(.deeplinkFailed(url, errorDescription)):
|
||||
// TODO: [#221] Handle error more properly (https://github.com/zcash/secant-ios-wallet/issues/221)
|
||||
state.destinationState.alert = AlertState(
|
||||
title: TextState(L10n.Root.Destination.Alert.FailedToProcessDeeplink.title),
|
||||
message: TextState(L10n.Root.Destination.Alert.FailedToProcessDeeplink.message(url, errorDescription)),
|
||||
dismissButton: .default(
|
||||
TextState(L10n.General.ok),
|
||||
action: .send(.destination(.dismissAlert))
|
||||
)
|
||||
)
|
||||
return .none
|
||||
return EffectTask(value: .alert(.root(.failedToProcessDeeplink(url, errorDescription))))
|
||||
|
||||
case .home(.walletEvents(.replyTo(let address))):
|
||||
guard let url = URL(string: "zcash:\(address)") else {
|
||||
|
@ -130,12 +119,8 @@ extension RootReducer {
|
|||
}
|
||||
return EffectTask(value: .destination(.deeplink(url)))
|
||||
|
||||
case .destination(.dismissAlert):
|
||||
state.destinationState.alert = nil
|
||||
return .none
|
||||
|
||||
case .home, .initialization, .onboarding, .phraseDisplay, .phraseValidation, .sandbox, .updateStateAfterConfigUpdate,
|
||||
.welcome, .binding, .nukeWalletFailed, .nukeWalletSucceeded, .debug, .walletConfigLoaded, .dismissAlert, .exportLogs:
|
||||
case .home, .initialization, .onboarding, .phraseDisplay, .phraseValidation, .sandbox, .updateStateAfterConfigUpdate, .alert,
|
||||
.welcome, .binding, .nukeWalletFailed, .nukeWalletSucceeded, .debug, .walletConfigLoaded, .dismissAlert, .exportLogs, .uniAlert:
|
||||
return .none
|
||||
}
|
||||
|
||||
|
|
|
@ -80,22 +80,11 @@ extension RootReducer {
|
|||
case .initialization(.respondToWalletInitializationState(let walletState)):
|
||||
switch walletState {
|
||||
case .failed:
|
||||
// TODO: [#221] Handle error more properly (https://github.com/zcash/secant-ios-wallet/issues/221)
|
||||
state.appInitializationState = .failed
|
||||
state.alert = AlertState(
|
||||
title: TextState(L10n.Root.Initialization.Alert.Failed.title),
|
||||
message: TextState(L10n.Root.Initialization.Alert.WalletStateFailed.message(walletState)),
|
||||
dismissButton: .default(TextState(L10n.General.ok), action: .send(.dismissAlert))
|
||||
)
|
||||
return EffectTask(value: .alert(.root(.walletStateFailed(walletState))))
|
||||
case .keysMissing:
|
||||
// TODO: [#221] Handle error more properly (https://github.com/zcash/secant-ios-wallet/issues/221)
|
||||
state.appInitializationState = .keysMissing
|
||||
state.alert = AlertState(
|
||||
title: TextState(L10n.Root.Initialization.Alert.Failed.title),
|
||||
message: TextState(L10n.Root.Initialization.Alert.WalletStateFailed.message(walletState)),
|
||||
dismissButton: .default(TextState(L10n.General.ok), action: .send(.dismissAlert))
|
||||
)
|
||||
|
||||
return EffectTask(value: .alert(.root(.walletStateFailed(walletState))))
|
||||
case .initialized, .filesMissing:
|
||||
if walletState == .filesMissing {
|
||||
state.appInitializationState = .filesMissing
|
||||
|
@ -112,8 +101,6 @@ extension RootReducer {
|
|||
.cancellable(id: CancelId.self, cancelInFlight: true)
|
||||
}
|
||||
|
||||
return .none
|
||||
|
||||
/// Stored wallet is present, database files may or may not be present, trying to initialize app state variables and environments.
|
||||
/// When initialization succeeds user is taken to the home screen.
|
||||
case .initialization(.initializeSDK):
|
||||
|
@ -122,13 +109,7 @@ extension RootReducer {
|
|||
|
||||
guard let storedWallet = state.storedWallet else {
|
||||
state.appInitializationState = .failed
|
||||
// TODO: [#221] Handle fatal error more properly (https://github.com/zcash/secant-ios-wallet/issues/221)
|
||||
state.alert = AlertState(
|
||||
title: TextState(L10n.Root.Initialization.Alert.Failed.title),
|
||||
message: TextState(L10n.Root.Initialization.Alert.CantLoadSeedPhrase.message),
|
||||
dismissButton: .default(TextState(L10n.General.ok), action: .send(.dismissAlert))
|
||||
)
|
||||
return .none
|
||||
return EffectTask(value: .alert(.root(.cantLoadSeedPhrase)))
|
||||
}
|
||||
|
||||
let birthday = state.storedWallet?.birthday?.value() ?? zcashSDKEnvironment.latestCheckpoint
|
||||
|
@ -153,13 +134,7 @@ extension RootReducer {
|
|||
case .initialization(.checkBackupPhraseValidation):
|
||||
guard let storedWallet = state.storedWallet else {
|
||||
state.appInitializationState = .failed
|
||||
// TODO: [#221] Handle fatal error more properly (https://github.com/zcash/secant-ios-wallet/issues/221)
|
||||
state.alert = AlertState(
|
||||
title: TextState(L10n.Root.Initialization.Alert.Failed.title),
|
||||
message: TextState(L10n.Root.Initialization.Alert.CantLoadSeedPhrase.message),
|
||||
dismissButton: .default(TextState(L10n.General.ok), action: .send(.dismissAlert))
|
||||
)
|
||||
return .none
|
||||
return EffectTask(value: .alert(.root(.cantLoadSeedPhrase)))
|
||||
}
|
||||
|
||||
var landingDestination = RootReducer.DestinationState.Destination.home
|
||||
|
@ -200,47 +175,19 @@ extension RootReducer {
|
|||
EffectTask(value: .phraseValidation(.displayBackedUpPhrase))
|
||||
)
|
||||
} catch {
|
||||
// TODO: [#201] - merge with issue 221 (https://github.com/zcash/secant-ios-wallet/issues/221) and its Error States
|
||||
state.alert = AlertState(
|
||||
title: TextState(L10n.Root.Initialization.Alert.Failed.title),
|
||||
message: TextState(L10n.Root.Initialization.Alert.CantCreateNewWallet.message(error.localizedDescription)),
|
||||
dismissButton: .default(TextState(L10n.General.ok), action: .send(.dismissAlert))
|
||||
)
|
||||
return EffectTask(value: .alert(.root(.cantCreateNewWallet(error.localizedDescription))))
|
||||
}
|
||||
|
||||
return .none
|
||||
|
||||
case .phraseValidation(.succeed):
|
||||
do {
|
||||
try walletStorage.markUserPassedPhraseBackupTest(true)
|
||||
return .none
|
||||
} catch {
|
||||
// TODO: [#221] error we need to handle, issue #221 (https://github.com/zcash/secant-ios-wallet/issues/221)
|
||||
state.alert = AlertState(
|
||||
title: TextState(L10n.Root.Initialization.Alert.Failed.title),
|
||||
message: TextState(
|
||||
L10n.Root.Initialization.Alert.CantStoreThatUserPassedPhraseBackupTest.message(error.localizedDescription)
|
||||
),
|
||||
dismissButton: .default(TextState(L10n.General.ok), action: .send(.dismissAlert))
|
||||
)
|
||||
return EffectTask(value: .alert(.root(.cantStoreThatUserPassedPhraseBackupTest(error.localizedDescription))))
|
||||
}
|
||||
return .none
|
||||
|
||||
case .initialization(.nukeWalletRequest):
|
||||
state.destinationState.alert = AlertState(
|
||||
title: TextState(L10n.Root.Initialization.Alert.Wipe.title),
|
||||
message: TextState(L10n.Root.Initialization.Alert.Wipe.message),
|
||||
buttons: [
|
||||
.destructive(
|
||||
TextState(L10n.General.yes),
|
||||
action: .send(.initialization(.nukeWallet))
|
||||
),
|
||||
.cancel(
|
||||
TextState(L10n.General.no),
|
||||
action: .send(.destination(.dismissAlert))
|
||||
)
|
||||
]
|
||||
)
|
||||
return .none
|
||||
return EffectTask(value: .alert(.root(.wipeRequest)))
|
||||
|
||||
case .initialization(.nukeWallet):
|
||||
guard let wipePublisher = sdkSynchronizer.wipe() else {
|
||||
|
@ -264,13 +211,6 @@ extension RootReducer {
|
|||
)
|
||||
|
||||
case .nukeWalletFailed:
|
||||
// TODO: [#221] error we need to handle, issue #221 (https://github.com/zcash/secant-ios-wallet/issues/221)
|
||||
state.alert = AlertState(
|
||||
title: TextState(L10n.Root.Initialization.Alert.WipeFailed.title),
|
||||
message: TextState(""),
|
||||
dismissButton: .default(TextState(L10n.General.ok), action: .send(.dismissAlert))
|
||||
)
|
||||
|
||||
let backDestination: EffectTask<RootReducer.Action>
|
||||
if let previousDestination = state.destinationState.previousDestination {
|
||||
backDestination = EffectTask(value: .destination(.updateDestination(previousDestination)))
|
||||
|
@ -278,6 +218,7 @@ extension RootReducer {
|
|||
backDestination = EffectTask(value: .destination(.updateDestination(state.destinationState.destination)))
|
||||
}
|
||||
return .concatenate(
|
||||
EffectTask(value: .alert(.root(.wipeFailed))),
|
||||
.cancel(id: SynchronizerCancelId.self),
|
||||
backDestination
|
||||
)
|
||||
|
@ -311,20 +252,10 @@ extension RootReducer {
|
|||
|
||||
case .initialization(.initializationFailed(let errorMessage)):
|
||||
state.appInitializationState = .failed
|
||||
// TODO: [#221] Handle error more properly (https://github.com/zcash/secant-ios-wallet/issues/221)
|
||||
state.alert = AlertState(
|
||||
title: TextState(L10n.Root.Initialization.Alert.SdkInitFailed.title),
|
||||
message: TextState(L10n.Root.Initialization.Alert.Error.message(errorMessage)),
|
||||
dismissButton: .default(TextState(L10n.General.ok), action: .send(.dismissAlert))
|
||||
)
|
||||
return .none
|
||||
return EffectTask(value: .alert(.root(.initializationFailed(errorMessage))))
|
||||
|
||||
case .dismissAlert:
|
||||
state.alert = nil
|
||||
return .none
|
||||
|
||||
case .home, .destination, .onboarding, .phraseDisplay, .phraseValidation, .sandbox,
|
||||
.welcome, .binding, .debug, .exportLogs:
|
||||
.welcome, .binding, .debug, .exportLogs, .uniAlert, .dismissAlert, .alert:
|
||||
return .none
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,7 +10,6 @@ struct RootReducer: ReducerProtocol {
|
|||
enum WalletConfigCancelId {}
|
||||
|
||||
struct State: Equatable {
|
||||
@BindingState var alert: AlertState<RootReducer.Action>?
|
||||
var appInitializationState: InitializationState = .uninitialized
|
||||
var debugState: DebugState
|
||||
var destinationState: DestinationState
|
||||
|
@ -21,11 +20,13 @@ struct RootReducer: ReducerProtocol {
|
|||
var phraseDisplayState: RecoveryPhraseDisplayReducer.State
|
||||
var sandboxState: SandboxReducer.State
|
||||
var storedWallet: StoredWallet?
|
||||
@BindingState var uniAlert: AlertState<RootReducer.Action>?
|
||||
var walletConfig: WalletConfig
|
||||
var welcomeState: WelcomeReducer.State
|
||||
}
|
||||
|
||||
enum Action: Equatable, BindableAction {
|
||||
case alert(AlertRequest)
|
||||
case binding(BindingAction<RootReducer.State>)
|
||||
case debug(DebugAction)
|
||||
case dismissAlert
|
||||
|
@ -39,6 +40,7 @@ struct RootReducer: ReducerProtocol {
|
|||
case phraseDisplay(RecoveryPhraseDisplayReducer.Action)
|
||||
case phraseValidation(RecoveryPhraseValidationFlowReducer.Action)
|
||||
case sandbox(SandboxReducer.Action)
|
||||
case uniAlert(AlertAction)
|
||||
case updateStateAfterConfigUpdate(WalletConfig)
|
||||
case walletConfigLoaded(WalletConfig)
|
||||
case welcome(WelcomeReducer.Action)
|
||||
|
@ -57,7 +59,8 @@ struct RootReducer: ReducerProtocol {
|
|||
@Dependency(\.walletStorage) var walletStorage
|
||||
@Dependency(\.zcashSDKEnvironment) var zcashSDKEnvironment
|
||||
|
||||
var body: some ReducerProtocol<State, Action> {
|
||||
@ReducerBuilder<State, Action>
|
||||
var core: some ReducerProtocol<State, Action> {
|
||||
BindingReducer()
|
||||
|
||||
Scope(state: \.homeState, action: /Action.home) {
|
||||
|
@ -94,6 +97,11 @@ struct RootReducer: ReducerProtocol {
|
|||
|
||||
debugReduce()
|
||||
}
|
||||
|
||||
var body: some ReducerProtocol<State, Action> {
|
||||
self.core
|
||||
.alerts()
|
||||
}
|
||||
}
|
||||
|
||||
extension RootReducer {
|
||||
|
|
|
@ -89,7 +89,7 @@ struct RootView: View {
|
|||
}
|
||||
}
|
||||
.onOpenURL(perform: { viewStore.goToDeeplink($0) })
|
||||
.alert(self.store.scope(state: \.alert), dismiss: .dismissAlert)
|
||||
.alert(store.scope(state: \.uniAlert), dismiss: .dismissAlert)
|
||||
|
||||
shareLogsView(viewStore)
|
||||
}
|
||||
|
@ -197,14 +197,6 @@ private extension RootView {
|
|||
}
|
||||
}
|
||||
}
|
||||
.alert(self.store.scope(state: \.destinationState.alert), dismiss: .destination(.dismissAlert))
|
||||
.alert(
|
||||
self.store.scope(
|
||||
state: \.exportLogsState.alert,
|
||||
action: { (_: ExportLogsReducer.Action) in return .exportLogs(.dismissAlert) }
|
||||
),
|
||||
dismiss: .dismissAlert
|
||||
)
|
||||
.confirmationDialog(
|
||||
store.scope(state: \.debugState.rescanDialog),
|
||||
dismiss: .debug(.cancelRescan)
|
||||
|
|
|
@ -21,7 +21,6 @@ struct ScanReducer: ReducerProtocol {
|
|||
case unknown
|
||||
}
|
||||
|
||||
@BindingState var alert: AlertState<ScanReducer.Action>?
|
||||
var isTorchAvailable = false
|
||||
var isTorchOn = false
|
||||
var scanStatus: ScanStatus = .unknown
|
||||
|
@ -47,7 +46,7 @@ struct ScanReducer: ReducerProtocol {
|
|||
@Dependency(\.uriParser) var uriParser
|
||||
|
||||
enum Action: Equatable {
|
||||
case dismissAlert
|
||||
case alert(AlertRequest)
|
||||
case onAppear
|
||||
case onDisappear
|
||||
case found(RedactableString)
|
||||
|
@ -59,8 +58,7 @@ struct ScanReducer: ReducerProtocol {
|
|||
// swiftlint:disable:next cyclomatic_complexity
|
||||
func reduce(into state: inout State, action: Action) -> ComposableArchitecture.EffectTask<Action> {
|
||||
switch action {
|
||||
case .dismissAlert:
|
||||
state.alert = nil
|
||||
case .alert:
|
||||
return .none
|
||||
|
||||
case .onAppear:
|
||||
|
@ -70,15 +68,10 @@ struct ScanReducer: ReducerProtocol {
|
|||
// check the torch availability
|
||||
do {
|
||||
state.isTorchAvailable = try captureDevice.isTorchAvailable()
|
||||
return .none
|
||||
} catch {
|
||||
// TODO: [#322] Handle error more properly (https://github.com/zcash/secant-ios-wallet/issues/322)
|
||||
state.alert = AlertState(
|
||||
title: TextState(L10n.Scan.Alert.CantInitializeCamera.title),
|
||||
message: TextState(L10n.Scan.Alert.CantInitializeCamera.message(error.localizedDescription)),
|
||||
dismissButton: .default(TextState(L10n.General.ok), action: .send(.dismissAlert))
|
||||
)
|
||||
return EffectTask(value: .alert(.scan(.cantInitializeCamera(error.localizedDescription))))
|
||||
}
|
||||
return .none
|
||||
|
||||
case .onDisappear:
|
||||
return .cancel(id: CancelId.self)
|
||||
|
@ -115,15 +108,10 @@ struct ScanReducer: ReducerProtocol {
|
|||
do {
|
||||
try captureDevice.torch(!state.isTorchOn)
|
||||
state.isTorchOn.toggle()
|
||||
return .none
|
||||
} catch {
|
||||
// TODO: [#322] handle torch errors (https://github.com/zcash/secant-ios-wallet/issues/322)
|
||||
state.alert = AlertState(
|
||||
title: TextState(L10n.Scan.Alert.CantInitializeCamera.title),
|
||||
message: TextState(L10n.Scan.Alert.CantInitializeCamera.message(error.localizedDescription)),
|
||||
dismissButton: .default(TextState(L10n.General.ok), action: .send(.dismissAlert))
|
||||
)
|
||||
return EffectTask(value: .alert(.scan(.cantInitializeCamera(error.localizedDescription))))
|
||||
}
|
||||
return .none
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -50,7 +50,6 @@ struct ScanView: View {
|
|||
.applyScreenBackground()
|
||||
.onAppear { viewStore.send(.onAppear) }
|
||||
.onDisappear { viewStore.send(.onDisappear) }
|
||||
.alert(self.store.scope(state: \.alert), dismiss: .dismissAlert)
|
||||
}
|
||||
.ignoresSafeArea()
|
||||
}
|
||||
|
|
|
@ -12,7 +12,6 @@ struct SettingsReducer: ReducerProtocol {
|
|||
case backupPhrase
|
||||
}
|
||||
|
||||
@BindingState var alert: AlertState<SettingsReducer.Action>?
|
||||
var appVersion = ""
|
||||
var appBuild = ""
|
||||
var destination: Destination?
|
||||
|
@ -23,10 +22,10 @@ struct SettingsReducer: ReducerProtocol {
|
|||
}
|
||||
|
||||
enum Action: BindableAction, Equatable {
|
||||
case alert(AlertRequest)
|
||||
case backupWallet
|
||||
case backupWalletAccessRequest
|
||||
case binding(BindingAction<SettingsReducer.State>)
|
||||
case dismissAlert
|
||||
case exportLogs(ExportLogsReducer.Action)
|
||||
case onAppear
|
||||
case phraseDisplay(RecoveryPhraseDisplayReducer.Action)
|
||||
|
@ -67,13 +66,7 @@ struct SettingsReducer: ReducerProtocol {
|
|||
state.phraseDisplayState.phrase = recoveryPhrase
|
||||
return EffectTask(value: .updateDestination(.backupPhrase))
|
||||
} catch {
|
||||
// TODO: [#221] - merge with issue 221 (https://github.com/zcash/secant-ios-wallet/issues/221) and its Error States
|
||||
state.alert = AlertState(
|
||||
title: TextState(L10n.Settings.Alert.CantBackupWallet.title),
|
||||
message: TextState(L10n.Settings.Alert.CantBackupWallet.message(error.localizedDescription)),
|
||||
dismissButton: .default(TextState(L10n.General.ok), action: .send(.dismissAlert))
|
||||
)
|
||||
return .none
|
||||
return EffectTask(value: .alert(.settings(.cantBackupWallet(error.localizedDescription))))
|
||||
}
|
||||
|
||||
case .binding(\.$isCrashReportingOn):
|
||||
|
@ -86,10 +79,6 @@ struct SettingsReducer: ReducerProtocol {
|
|||
return .run { [state] _ in
|
||||
await userStoredPreferences.setIsUserOptedOutOfCrashReporting(state.isCrashReportingOn)
|
||||
}
|
||||
|
||||
case .dismissAlert:
|
||||
state.alert = nil
|
||||
return .none
|
||||
|
||||
case .exportLogs:
|
||||
return .none
|
||||
|
@ -108,19 +97,17 @@ struct SettingsReducer: ReducerProtocol {
|
|||
case .sendSupportMail:
|
||||
if MFMailComposeViewController.canSendMail() {
|
||||
state.supportData = SupportDataGenerator.generate()
|
||||
return .none
|
||||
} else {
|
||||
state.alert = AlertState(
|
||||
title: TextState(L10n.Settings.Alert.CantSendEmail.title),
|
||||
message: TextState(L10n.Settings.Alert.CantSendEmail.message),
|
||||
dismissButton: .default(TextState(L10n.General.ok), action: .send(.sendSupportMailFinished))
|
||||
)
|
||||
return EffectTask(value: .alert(.settings(.sendSupportMail)))
|
||||
}
|
||||
|
||||
return .none
|
||||
|
||||
case .sendSupportMailFinished:
|
||||
state.supportData = nil
|
||||
return .none
|
||||
|
||||
case .alert:
|
||||
return .none
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -71,14 +71,6 @@ struct SettingsView: View {
|
|||
}
|
||||
)
|
||||
.onAppear { viewStore.send(.onAppear) }
|
||||
.alert(self.store.scope(state: \.alert), dismiss: .dismissAlert)
|
||||
.alert(
|
||||
self.store.scope(
|
||||
state: \.exportLogsState.alert,
|
||||
action: { (_: ExportLogsReducer.Action) in return .exportLogs(.dismissAlert) }
|
||||
),
|
||||
dismiss: .dismissAlert
|
||||
)
|
||||
|
||||
shareLogsView(viewStore)
|
||||
|
||||
|
|
|
@ -17,7 +17,6 @@ struct WalletEventsFlowReducer: ReducerProtocol {
|
|||
|
||||
var destination: Destination?
|
||||
|
||||
@BindingState var alert: AlertState<WalletEventsFlowReducer.Action>?
|
||||
var latestMinedHeight: BlockHeight?
|
||||
var isScrollable = true
|
||||
var requiredTransactionConfirmations = 0
|
||||
|
@ -26,8 +25,8 @@ struct WalletEventsFlowReducer: ReducerProtocol {
|
|||
}
|
||||
|
||||
enum Action: Equatable {
|
||||
case alert(AlertRequest)
|
||||
case copyToPastboard(RedactableString)
|
||||
case dismissAlert
|
||||
case onAppear
|
||||
case onDisappear
|
||||
case openBlockExplorer(URL?)
|
||||
|
@ -97,27 +96,13 @@ struct WalletEventsFlowReducer: ReducerProtocol {
|
|||
case .replyTo:
|
||||
return .none
|
||||
|
||||
case .dismissAlert:
|
||||
state.alert = nil
|
||||
case .alert:
|
||||
return .none
|
||||
|
||||
case .warnBeforeLeavingApp(let blockExplorerURL):
|
||||
state.alert = AlertState(
|
||||
title: TextState(L10n.WalletEvent.Alert.LeavingApp.title),
|
||||
message: TextState(L10n.WalletEvent.Alert.LeavingApp.message),
|
||||
primaryButton: .cancel(
|
||||
TextState(L10n.WalletEvent.Alert.LeavingApp.Button.nevermind),
|
||||
action: .send(.dismissAlert)
|
||||
),
|
||||
secondaryButton: .default(
|
||||
TextState(L10n.WalletEvent.Alert.LeavingApp.Button.seeOnline),
|
||||
action: .send(.openBlockExplorer(blockExplorerURL))
|
||||
)
|
||||
)
|
||||
return .none
|
||||
return EffectTask(value: .alert(.walletEvents(.warnBeforeLeavingApp(blockExplorerURL))))
|
||||
|
||||
case .openBlockExplorer(let blockExplorerURL):
|
||||
state.alert = nil
|
||||
if let url = blockExplorerURL {
|
||||
UIApplication.shared.open(url, options: [:], completionHandler: nil)
|
||||
}
|
||||
|
|
|
@ -0,0 +1,57 @@
|
|||
//
|
||||
// OnChangeReducer.swift
|
||||
// secant-testnet
|
||||
//
|
||||
// Created by Lukáš Korba on 29.03.2023.
|
||||
//
|
||||
|
||||
import ComposableArchitecture
|
||||
|
||||
extension ReducerProtocol {
|
||||
@inlinable
|
||||
public func onChange<ChildState: Equatable>(
|
||||
of toLocalState: @escaping (State) -> ChildState,
|
||||
perform additionalEffects: @escaping (ChildState, inout State, Action) -> EffectPublisher<Action, Never>
|
||||
) -> some ReducerProtocol<State, Action> {
|
||||
self.onChange(of: toLocalState) { additionalEffects($1, &$2, $3) }
|
||||
}
|
||||
|
||||
@inlinable
|
||||
public func onChange<ChildState: Equatable>(
|
||||
of toLocalState: @escaping (State) -> ChildState,
|
||||
perform additionalEffects: @escaping (ChildState, ChildState, inout State, Action) -> EffectPublisher<Action, Never>
|
||||
) -> some ReducerProtocol<State, Action> {
|
||||
ChangeReducer(base: self, toLocalState: toLocalState, perform: additionalEffects)
|
||||
}
|
||||
}
|
||||
|
||||
@usableFromInline
|
||||
struct ChangeReducer<Base: ReducerProtocol, ChildState: Equatable>: ReducerProtocol {
|
||||
@usableFromInline let base: Base
|
||||
|
||||
@usableFromInline let toLocalState: (Base.State) -> ChildState
|
||||
|
||||
@usableFromInline let perform: (ChildState, ChildState, inout Base.State, Base.Action) -> EffectPublisher<Base.Action, Never>
|
||||
|
||||
@usableFromInline
|
||||
init(
|
||||
base: Base,
|
||||
toLocalState: @escaping (Base.State) -> ChildState,
|
||||
perform: @escaping (ChildState, ChildState, inout Base.State, Base.Action) -> EffectPublisher<Base.Action, Never>
|
||||
) {
|
||||
self.base = base
|
||||
self.toLocalState = toLocalState
|
||||
self.perform = perform
|
||||
}
|
||||
|
||||
@inlinable
|
||||
public func reduce(into state: inout Base.State, action: Base.Action) -> EffectPublisher<Base.Action, Never> {
|
||||
let previousLocalState = self.toLocalState(state)
|
||||
let effects = self.base.reduce(into: &state, action: action)
|
||||
let localState = self.toLocalState(state)
|
||||
|
||||
return previousLocalState != localState
|
||||
? .merge(effects, self.perform(previousLocalState, localState, &state, action))
|
||||
: effects
|
||||
}
|
||||
}
|
|
@ -52,13 +52,10 @@ class BalanceBreakdownTests: XCTestCase {
|
|||
}
|
||||
await store.receive(.shieldFundsSuccess) { state in
|
||||
state.shieldingFunds = false
|
||||
state.alert = AlertState(
|
||||
title: TextState(L10n.BalanceBreakdown.Alert.ShieldFunds.Success.title),
|
||||
message: TextState(L10n.BalanceBreakdown.Alert.ShieldFunds.Success.message),
|
||||
dismissButton: .default(TextState(L10n.General.ok), action: .send(.dismissAlert))
|
||||
)
|
||||
}
|
||||
|
||||
await store.receive(.alert(.balanceBreakdown(.shieldFundsSuccess)))
|
||||
|
||||
// long-living (cancelable) effects need to be properly canceled.
|
||||
// the .onDisappear action cancels the observer of the synchronizer status change.
|
||||
await store.send(.onDisappear)
|
||||
|
@ -81,13 +78,10 @@ class BalanceBreakdownTests: XCTestCase {
|
|||
}
|
||||
await store.receive(.shieldFundsFailure(SynchronizerError.criticalError.localizedDescription)) { state in
|
||||
state.shieldingFunds = false
|
||||
state.alert = AlertState(
|
||||
title: TextState(L10n.BalanceBreakdown.Alert.ShieldFunds.Failure.title),
|
||||
message: TextState(L10n.BalanceBreakdown.Alert.ShieldFunds.Failure.message(SynchronizerError.criticalError.localizedDescription)),
|
||||
dismissButton: .default(TextState(L10n.General.ok), action: .send(.dismissAlert))
|
||||
)
|
||||
}
|
||||
|
||||
await store.receive(.alert(.balanceBreakdown(.shieldFundsFailure("A critical Error Occurred"))))
|
||||
|
||||
// long-living (cancelable) effects need to be properly canceled.
|
||||
// the .onDisappear action cancels the observer of the synchronizer status change.
|
||||
await store.send(.onDisappear)
|
||||
|
|
|
@ -109,8 +109,8 @@ class HomeTests: XCTestCase {
|
|||
state.synchronizerStatusSnapshot = errorSnapshot
|
||||
}
|
||||
|
||||
store.receive(.showSynchronizerErrorAlert(errorSnapshot)) { state in
|
||||
state.alert = HomeStore.syncErrorAlert(with: errorSnapshot)
|
||||
}
|
||||
store.receive(.showSynchronizerErrorAlert(errorSnapshot))
|
||||
|
||||
store.receive(.alert(.home(.syncFailed("Error: Synchronizer failed", "Dismiss"))))
|
||||
}
|
||||
}
|
||||
|
|
|
@ -116,28 +116,7 @@ class ImportWalletTests: XCTestCase {
|
|||
state.birthdayHeightValue = RedactableBlockHeight(1_700_000)
|
||||
}
|
||||
}
|
||||
|
||||
func testDismissAlert() throws {
|
||||
let store = TestStore(
|
||||
initialState:
|
||||
ImportWalletReducer.State(
|
||||
alert: AlertState(
|
||||
title: TextState("Success"),
|
||||
message: TextState("The wallet has been successfully recovered."),
|
||||
dismissButton: .default(
|
||||
TextState("Ok"),
|
||||
action: .send(.successfullyRecovered)
|
||||
)
|
||||
)
|
||||
),
|
||||
reducer: ImportWalletReducer()
|
||||
)
|
||||
|
||||
store.send(.dismissAlert) { state in
|
||||
state.alert = nil
|
||||
}
|
||||
}
|
||||
|
||||
func testFormValidity_validBirthday_invalidMnemonic() throws {
|
||||
let store = TestStore(
|
||||
initialState: ImportWalletReducer.State(maxWordsCount: 24),
|
||||
|
@ -288,7 +267,6 @@ class ImportWalletTests: XCTestCase {
|
|||
func testRestoreWallet() throws {
|
||||
let store = TestStore(
|
||||
initialState: ImportWalletReducer.State(
|
||||
alert: nil,
|
||||
birthdayHeight: "1700000".redacted,
|
||||
birthdayHeightValue: RedactableBlockHeight(1_700_000),
|
||||
importedSeedPhrase: """
|
||||
|
@ -308,17 +286,10 @@ class ImportWalletTests: XCTestCase {
|
|||
store.dependencies.mnemonic = .noOp
|
||||
store.dependencies.walletStorage = .noOp
|
||||
|
||||
store.send(.restoreWallet) { state in
|
||||
state.alert = AlertState(
|
||||
title: TextState("Success"),
|
||||
message: TextState("The wallet has been successfully recovered."),
|
||||
dismissButton: .default(
|
||||
TextState("Ok"),
|
||||
action: .send(.successfullyRecovered)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
store.send(.restoreWallet)
|
||||
|
||||
store.receive(.alert(.importWallet(.succeed)))
|
||||
|
||||
store.receive(.initializeSDK)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -168,7 +168,10 @@ class AppInitializationTests: XCTestCase {
|
|||
|
||||
await store.receive(.initialization(.respondToWalletInitializationState(.keysMissing))) { state in
|
||||
state.appInitializationState = .keysMissing
|
||||
state.alert = AlertState(
|
||||
}
|
||||
|
||||
await store.receive(.alert(.root(.walletStateFailed(.keysMissing)))) { state in
|
||||
state.uniAlert = AlertState(
|
||||
title: TextState("Wallet initialisation failed."),
|
||||
message: TextState("App initialisation state: keysMissing."),
|
||||
dismissButton: .default(TextState("Ok"), action: .send(.dismissAlert))
|
||||
|
|
|
@ -118,7 +118,10 @@ class RootTests: XCTestCase {
|
|||
|
||||
store.send(.initialization(.respondToWalletInitializationState(.keysMissing))) { state in
|
||||
state.appInitializationState = .keysMissing
|
||||
state.alert = AlertState(
|
||||
}
|
||||
|
||||
store.receive(.alert(.root(.walletStateFailed(.keysMissing)))) { state in
|
||||
state.uniAlert = AlertState(
|
||||
title: TextState("Wallet initialisation failed."),
|
||||
message: TextState("App initialisation state: keysMissing."),
|
||||
dismissButton: .default(TextState("Ok"), action: .send(.dismissAlert))
|
||||
|
@ -140,21 +143,26 @@ class RootTests: XCTestCase {
|
|||
store.send(.initialization(.respondToWalletInitializationState(.filesMissing))) { state in
|
||||
state.appInitializationState = .filesMissing
|
||||
}
|
||||
|
||||
store.receive(.initialization(.initializeSDK))
|
||||
|
||||
store.receive(.initialization(.initializeSDK))
|
||||
|
||||
store.receive(.initialization(.checkBackupPhraseValidation)) { state in
|
||||
// failed is expected because environment is throwing errors
|
||||
state.appInitializationState = .failed
|
||||
state.alert = AlertState(
|
||||
}
|
||||
|
||||
store.receive(.initialization(.initializationFailed(walletStorageError.localizedDescription)))
|
||||
|
||||
store.receive(.alert(.root(.cantLoadSeedPhrase))) { state in
|
||||
state.uniAlert = AlertState(
|
||||
title: TextState("Wallet initialisation failed."),
|
||||
message: TextState("Can't load seed phrase from local storage."),
|
||||
dismissButton: .default(TextState("Ok"), action: .send(.dismissAlert))
|
||||
)
|
||||
}
|
||||
|
||||
store.receive(.initialization(.initializationFailed(walletStorageError.localizedDescription))) { state in
|
||||
state.alert = AlertState(
|
||||
store.receive(.alert(.root(.initializationFailed("The operation couldn’t be completed. (Swift.String error 1.)")))) { state in
|
||||
state.uniAlert = AlertState(
|
||||
title: TextState("Failed to initialize the SDK"),
|
||||
message: TextState("Error: \(walletStorageError.localizedDescription)"),
|
||||
dismissButton: .default(TextState("Ok"), action: .send(.dismissAlert))
|
||||
|
@ -179,15 +187,20 @@ class RootTests: XCTestCase {
|
|||
store.receive(.initialization(.checkBackupPhraseValidation)) { state in
|
||||
// failed is expected because environment is throwing errors
|
||||
state.appInitializationState = .failed
|
||||
state.alert = AlertState(
|
||||
}
|
||||
|
||||
store.receive(.initialization(.initializationFailed(walletStorageError.localizedDescription)))
|
||||
|
||||
store.receive(.alert(.root(.cantLoadSeedPhrase))) { state in
|
||||
state.uniAlert = AlertState(
|
||||
title: TextState("Wallet initialisation failed."),
|
||||
message: TextState("Can't load seed phrase from local storage."),
|
||||
dismissButton: .default(TextState("Ok"), action: .send(.dismissAlert))
|
||||
)
|
||||
}
|
||||
|
||||
store.receive(.initialization(.initializationFailed(walletStorageError.localizedDescription))) { state in
|
||||
state.alert = AlertState(
|
||||
store.receive(.alert(.root(.initializationFailed("The operation couldn’t be completed. (Swift.String error 1.)")))) { state in
|
||||
state.uniAlert = AlertState(
|
||||
title: TextState("Failed to initialize the SDK"),
|
||||
message: TextState("Error: \(walletStorageError.localizedDescription)"),
|
||||
dismissButton: .default(TextState("Ok"), action: .send(.dismissAlert))
|
||||
|
|
Loading…
Reference in New Issue