[#597] Sync cannot be retried after a failure (#646)

This commit is contained in:
Francisco Gindre 2023-03-12 10:12:24 -03:00 committed by GitHub
parent 1d86157198
commit bb5af14f4a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 117 additions and 6 deletions

View File

@ -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()
)
}
}

View File

@ -125,7 +125,7 @@ extension HomeView {
struct HomeView_Previews: PreviewProvider {
static var previews: some View {
NavigationView {
HomeView(store: .placeholder)
HomeView(store: .error)
}
}
}

View File

@ -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))) }

View File

@ -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.

View File

@ -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";

View File

@ -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)
}
}
}