parent
1d86157198
commit
bb5af14f4a
|
@ -74,6 +74,8 @@ struct HomeReducer: ReducerProtocol {
|
|||
case walletEvents(WalletEventsFlowReducer.Action)
|
||||
case updateDestination(HomeReducer.State.Destination?)
|
||||
case updateSynchronizerStatus
|
||||
case showSynchronizerErrorAlert(SyncStatusSnapshot)
|
||||
case retrySync
|
||||
case updateWalletEvents([WalletEvent])
|
||||
}
|
||||
|
||||
|
@ -129,12 +131,24 @@ struct HomeReducer: ReducerProtocol {
|
|||
return .none
|
||||
|
||||
case .updateSynchronizerStatus:
|
||||
state.synchronizerStatusSnapshot = sdkSynchronizer.statusSnapshot()
|
||||
let snapshot = sdkSynchronizer.statusSnapshot()
|
||||
|
||||
guard snapshot != state.synchronizerStatusSnapshot else {
|
||||
return .none
|
||||
}
|
||||
|
||||
state.synchronizerStatusSnapshot = snapshot
|
||||
if let shieldedBalance = sdkSynchronizer.latestScannedSynchronizerState?.shieldedBalance {
|
||||
state.shieldedBalance = shieldedBalance.redacted
|
||||
}
|
||||
return .none
|
||||
|
||||
|
||||
switch snapshot.syncStatus {
|
||||
case .error:
|
||||
return EffectTask(value: .showSynchronizerErrorAlert(snapshot))
|
||||
default:
|
||||
return .none
|
||||
}
|
||||
|
||||
case .updateDestination(.profile):
|
||||
state.profileState.destination = nil
|
||||
state.destination = .profile
|
||||
|
@ -162,6 +176,23 @@ struct HomeReducer: ReducerProtocol {
|
|||
|
||||
case .send:
|
||||
return .none
|
||||
|
||||
case .retrySync:
|
||||
do {
|
||||
try sdkSynchronizer.start(retry: true)
|
||||
} catch {
|
||||
state.alert = AlertState<HomeReducer.Action>(
|
||||
title: TextState(L10n.Home.SyncFailed.title),
|
||||
message: TextState(error.localizedDescription),
|
||||
primaryButton: .default(TextState(L10n.Home.SyncFailed.retry), action: .send(.retrySync)),
|
||||
secondaryButton: .default(TextState(L10n.General.ok), action: .send(.dismissAlert))
|
||||
)
|
||||
}
|
||||
return .none
|
||||
|
||||
case .showSynchronizerErrorAlert(let snapshot):
|
||||
state.alert = HomeStore.syncErrorAlert(with: snapshot)
|
||||
return .none
|
||||
|
||||
case .balanceBreakdown(.onDisappear):
|
||||
state.destination = nil
|
||||
|
@ -233,6 +264,18 @@ 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 {
|
||||
|
@ -258,4 +301,28 @@ extension HomeStore {
|
|||
reducer: HomeReducer()
|
||||
)
|
||||
}
|
||||
|
||||
static var error: HomeStore {
|
||||
HomeStore(
|
||||
initialState: .init(
|
||||
alert: HomeStore.syncErrorAlert(
|
||||
with: SyncStatusSnapshot.snapshotFor(
|
||||
state: .error(SynchronizerError.networkTimeout)
|
||||
)
|
||||
),
|
||||
balanceBreakdownState: .placeholder,
|
||||
profileState: .placeholder,
|
||||
scanState: .placeholder,
|
||||
sendState: .placeholder,
|
||||
settingsState: .placeholder,
|
||||
shieldedBalance: Balance.zero,
|
||||
synchronizerStatusSnapshot: .snapshotFor(
|
||||
state: .error(SDKInitializationError.failed)
|
||||
),
|
||||
walletConfig: .default,
|
||||
walletEventsState: .emptyPlaceHolder
|
||||
),
|
||||
reducer: HomeReducer()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -125,7 +125,7 @@ extension HomeView {
|
|||
struct HomeView_Previews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
NavigationView {
|
||||
HomeView(store: .placeholder)
|
||||
HomeView(store: .error)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -108,8 +108,16 @@ extension RootReducer {
|
|||
|
||||
private func rewind(policy: RewindPolicy, sourceAction: DebugAction) -> EffectPublisher<RootReducer.Action, Never> {
|
||||
guard let rewindPublisher = sdkSynchronizer.rewind(policy) else {
|
||||
return EffectTask(value: .debug(.rewindDone(L10n.Root.Debug.Error.Rewind.sdkSynchronizerNotInitialized, .debug(sourceAction))))
|
||||
return EffectTask(
|
||||
value: .debug(
|
||||
.rewindDone(
|
||||
L10n.Root.Debug.Error.Rewind.sdkSynchronizerNotInitialized,
|
||||
.debug(sourceAction)
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
return rewindPublisher
|
||||
.replaceEmpty(with: Void())
|
||||
.map { _ in return RootReducer.Action.debug(.rewindDone(nil, .debug(sourceAction))) }
|
||||
|
|
|
@ -159,6 +159,14 @@ internal enum L10n {
|
|||
internal static let title = L10n.tr("Localizable", "home.title", fallback: "Secant Wallet")
|
||||
/// See transaction history
|
||||
internal static let transactionHistory = L10n.tr("Localizable", "home.transactionHistory", fallback: "See transaction history")
|
||||
internal enum SyncFailed {
|
||||
/// Dismiss
|
||||
internal static let dismiss = L10n.tr("Localizable", "home.syncFailed.dismiss", fallback: "Dismiss")
|
||||
/// Retry
|
||||
internal static let retry = L10n.tr("Localizable", "home.syncFailed.retry", fallback: "Retry")
|
||||
/// Sync failed!
|
||||
internal static let title = L10n.tr("Localizable", "home.syncFailed.title", fallback: "Sync failed!")
|
||||
}
|
||||
}
|
||||
internal enum ImportWallet {
|
||||
/// Enter your secret backup seed phrase.
|
||||
|
|
|
@ -66,7 +66,9 @@
|
|||
"home.receiveZec" = "Receive %@";
|
||||
"home.transactionHistory" = "See transaction history";
|
||||
"home.title" = "Secant Wallet";
|
||||
|
||||
"home.syncFailed.title" = "Sync failed!";
|
||||
"home.syncFailed.dismiss" = "Dismiss";
|
||||
"home.syncFailed.retry" = "Retry";
|
||||
// MARK: - Receive ZEC (Formerly Profile Screen)
|
||||
"receiveZec.yourAddress" = "Your Address";
|
||||
"receiveZec.error.cantExtractUnifiedAddress" = "could not extract UA";
|
||||
|
|
|
@ -174,4 +174,30 @@ class HomeTests: XCTestCase {
|
|||
// the .onDisappear action cancels the observer of the synchronizer status change.
|
||||
store.send(.onDisappear)
|
||||
}
|
||||
|
||||
func testSynchronizerErrorBringsUpAlert() {
|
||||
let testError = SDKInitializationError.failed
|
||||
let errorSnapshot = SyncStatusSnapshot.snapshotFor(
|
||||
state: .error(testError)
|
||||
)
|
||||
|
||||
let mockSynchronizer = MockSDKSynchronizerClient(
|
||||
snapshot: errorSnapshot
|
||||
)
|
||||
|
||||
let store = TestStore(
|
||||
initialState: .placeholder,
|
||||
reducer: HomeReducer()
|
||||
) {
|
||||
$0.sdkSynchronizer = mockSynchronizer
|
||||
}
|
||||
|
||||
store.send(.updateSynchronizerStatus) {
|
||||
$0.synchronizerStatusSnapshot = errorSnapshot
|
||||
}
|
||||
|
||||
store.receive(.showSynchronizerErrorAlert(errorSnapshot)) {
|
||||
$0.alert = HomeStore.syncErrorAlert(with: errorSnapshot)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue