zashi-ios-wallet-private/secant/Features/Root/RootDestination.swift

158 lines
5.5 KiB
Swift

//
// RootDestination.swift
// secant-testnet
//
// Created by Lukáš Korba on 01.12.2022.
//
import Foundation
import ComposableArchitecture
import ZcashLightClientKit
/// In this file is a collection of helpers that control all state and action related operations
/// for the `RootReducer` with a connection to the UI navigation.
extension RootReducer {
struct DestinationState: Equatable {
enum Destination: Equatable {
case welcome
case startup
case onboarding
case sandbox
case home
case phraseValidation
case phraseDisplay
}
var internalDestination: Destination = .welcome
var previousDestination: Destination?
var destination: Destination {
get { internalDestination }
set {
previousDestination = internalDestination
internalDestination = newValue
}
}
}
enum DestinationAction: Equatable {
case deeplink(URL)
case deeplinkHome
case deeplinkSend(Zatoshi, String, String)
case updateDestination(RootReducer.DestinationState.Destination)
}
// swiftlint:disable:next cyclomatic_complexity
func destinationReduce() -> Reduce<RootReducer.State, RootReducer.Action> {
Reduce { state, action in
switch action {
case let .destination(.updateDestination(destination)):
state.destinationState.destination = destination
case .sandbox(.reset):
state.destinationState.destination = .startup
case .phraseValidation(.proceedToHome):
state.destinationState.destination = .home
case .phraseValidation(.displayBackedUpPhrase):
state.destinationState.destination = .phraseDisplay
case .phraseDisplay(.finishedPressed):
// user is still supposed to do the backup phrase validation test
if state.destinationState.previousDestination == .welcome
|| state.destinationState.previousDestination == .onboarding {
state.destinationState.destination = .phraseValidation
}
// user wanted to see the backup phrase once again (at validation finished screen)
if state.destinationState.previousDestination == .phraseValidation {
state.destinationState.destination = .home
}
case .destination(.deeplink(let url)):
// get the latest synchronizer state
let synchronizerStatus = sdkSynchronizer.stateChanged.value
// process the deeplink only if app is initialized and synchronizer synced
guard state.appInitializationState == .initialized && synchronizerStatus == .synced else {
// TODO [#370]: There are many different states and edge cases we need to handle here
// (https://github.com/zcash/secant-ios-wallet/issues/370)
return .none
}
return .run { send in
do {
await send(
try await process(
url: url,
deeplink: deeplink,
derivationTool: derivationTool
)
)
} catch {
// TODO [#221]: error we need to handle (https://github.com/zcash/secant-ios-wallet/issues/221)
}
}
case .destination(.deeplinkHome):
state.destinationState.destination = .home
state.homeState.destination = nil
return .none
case let .destination(.deeplinkSend(amount, address, memo)):
state.destinationState.destination = .home
state.homeState.destination = .send
state.homeState.sendState.amount = amount
state.homeState.sendState.address = address
state.homeState.sendState.memoState.text = memo
return .none
case .home(.walletEvents(.replyTo(let address))):
guard let url = URL(string: "zcash:\(address)") else {
return .none
}
return Effect(value: .destination(.deeplink(url)))
case .home, .initialization, .onboarding, .phraseDisplay, .phraseValidation, .sandbox, .welcome:
return .none
}
return .none
}
}
}
private extension RootReducer {
func process(
url: URL,
deeplink: DeeplinkClient,
derivationTool: DerivationToolClient
) async throws -> RootReducer.Action {
let deeplink = try deeplink.resolveDeeplinkURL(url, derivationTool)
switch deeplink {
case .home:
return .destination(.deeplinkHome)
case let .send(amount, address, memo):
return .destination(.deeplinkSend(Zatoshi(amount), address, memo))
}
}
}
extension RootViewStore {
func goToDestination(_ destination: RootReducer.DestinationState.Destination) {
send(.destination(.updateDestination(destination)))
}
func goToDeeplink(_ deeplink: URL) {
send(.destination(.deeplink(deeplink)))
}
}
// MARK: Placeholders
extension RootReducer.DestinationState {
static var placeholder: Self {
.init()
}
}