[#1191] Refactor AdvancedSettingsReducer to latest TCA

- The reducer has been refactored
- The Bindings have been refactored to not use deprecated API
- View has been refactored to not rely on ViewStore
- Dependency version have been bumped up in order to use latest TCA
This commit is contained in:
Lukas Korba 2024-04-15 16:08:59 +02:00
parent ecad037103
commit d46d0a4f94
6 changed files with 147 additions and 157 deletions

View File

@ -67,12 +67,12 @@ let package = Package(
.library(name: "ZcashSDKEnvironment", targets: ["ZcashSDKEnvironment"])
],
dependencies: [
.package(url: "https://github.com/pointfreeco/swift-composable-architecture", from: "1.7.0"),
.package(url: "https://github.com/pointfreeco/swift-case-paths", from: "1.1.0"),
.package(url: "https://github.com/pointfreeco/swift-composable-architecture", from: "1.9.2"),
.package(url: "https://github.com/pointfreeco/swift-case-paths", from: "1.3.2"),
.package(url: "https://github.com/pointfreeco/swift-url-routing", from: "0.6.0"),
.package(url: "https://github.com/zcash-hackworks/MnemonicSwift", from: "2.2.4"),
.package(url: "https://github.com/Electric-Coin-Company/zcash-swift-wallet-sdk", from: "2.1.3"),
.package(url: "https://github.com/firebase/firebase-ios-sdk", from: "10.17.0")
.package(url: "https://github.com/firebase/firebase-ios-sdk", from: "10.24.0")
],
targets: [
.target(

View File

@ -12,10 +12,9 @@ import RestoreWalletStorage
import ServerSetup
import ZcashLightClientKit
public typealias AdvancedSettingsStore = Store<AdvancedSettingsReducer.State, AdvancedSettingsReducer.Action>
public typealias AdvancedSettingsViewStore = ViewStore<AdvancedSettingsReducer.State, AdvancedSettingsReducer.Action>
public struct AdvancedSettingsReducer: Reducer {
@Reducer
public struct AdvancedSettings {
@ObservableState
public struct State: Equatable {
public enum Destination {
case backupPhrase
@ -56,7 +55,7 @@ public struct AdvancedSettingsReducer: Reducer {
case restoreWalletTask
case restoreWalletValue(Bool)
case serverSetup(ServerSetup.Action)
case updateDestination(AdvancedSettingsReducer.State.Destination?)
case updateDestination(AdvancedSettings.State.Destination?)
}
@Dependency(\.localAuthentication) var localAuthentication
@ -73,7 +72,7 @@ public struct AdvancedSettingsReducer: Reducer {
await send(.updateDestination(.backupPhrase))
}
}
case .deleteWallet:
return .none
@ -138,110 +137,3 @@ public struct AdvancedSettingsReducer: Reducer {
}
}
// MARK: - ViewStore
extension AdvancedSettingsViewStore {
var destinationBinding: Binding<AdvancedSettingsReducer.State.Destination?> {
self.binding(
get: \.destination,
send: AdvancedSettingsReducer.Action.updateDestination
)
}
var bindingForBackupPhrase: Binding<Bool> {
self.destinationBinding.map(
extract: { $0 == .backupPhrase },
embed: { $0 ? .backupPhrase : nil }
)
}
var bindingForPrivateDataConsent: Binding<Bool> {
self.destinationBinding.map(
extract: { $0 == .privateDataConsent },
embed: { $0 ? .privateDataConsent : nil }
)
}
var bindingForServerSetup: Binding<Bool> {
self.destinationBinding.map(
extract: { $0 == .serverSetup },
embed: { $0 ? .serverSetup : nil }
)
}
var bindingDeleteWallet: Binding<Bool> {
self.destinationBinding.map(
extract: { $0 == .deleteWallet },
embed: { $0 ? .deleteWallet : nil }
)
}
}
// MARK: - Store
extension AdvancedSettingsStore {
func backupPhraseStore() -> StoreOf<RecoveryPhraseDisplay> {
self.scope(
state: \.phraseDisplayState,
action: AdvancedSettingsReducer.Action.phraseDisplay
)
}
func privateDataConsentStore() -> PrivateDataConsentStore {
self.scope(
state: \.privateDataConsentState,
action: AdvancedSettingsReducer.Action.privateDataConsent
)
}
func serverSetupStore() -> StoreOf<ServerSetup> {
self.scope(
state: \.serverSetupState,
action: AdvancedSettingsReducer.Action.serverSetup
)
}
func deleteWalletStore() -> StoreOf<DeleteWallet> {
self.scope(
state: \.deleteWallet,
action: AdvancedSettingsReducer.Action.deleteWallet
)
}
}
// MARK: Placeholders
extension AdvancedSettingsReducer.State {
public static let initial = AdvancedSettingsReducer.State(
deleteWallet: .initial,
phraseDisplayState: RecoveryPhraseDisplay.State(
phrase: nil,
showBackButton: false,
birthday: nil
),
privateDataConsentState: .initial,
serverSetupState: ServerSetup.State()
)
}
extension AdvancedSettingsStore {
public static let placeholder = AdvancedSettingsStore(
initialState: .initial
) {
AdvancedSettingsReducer()
}
public static let demo = AdvancedSettingsStore(
initialState: .init(
deleteWallet: .initial,
phraseDisplayState: RecoveryPhraseDisplay.State(
phrase: nil,
birthday: nil
),
privateDataConsentState: .initial,
serverSetupState: ServerSetup.State()
)
) {
AdvancedSettingsReducer()
}
}

View File

@ -16,62 +16,56 @@ import PrivateDataConsent
import ServerSetup
public struct AdvancedSettingsView: View {
@State private var isRestoringWalletBadgeOn = false
let store: AdvancedSettingsStore
@Perception.Bindable var store: StoreOf<AdvancedSettings>
public init(store: AdvancedSettingsStore) {
public init(store: StoreOf<AdvancedSettings>) {
self.store = store
}
public var body: some View {
VStack {
WithViewStore(store, observe: { $0 }) { viewStore in
WithPerceptionTracking {
VStack {
Button(L10n.Settings.recoveryPhrase.uppercased()) {
viewStore.send(.backupWalletAccessRequest)
store.send(.backupWalletAccessRequest)
}
.zcashStyle()
.padding(.vertical, 25)
.padding(.top, 40)
.padding(.horizontal, 70)
.navigationLinkEmpty(
isActive: viewStore.bindingForBackupPhrase,
isActive: store.bindingForBackupPhrase,
destination: {
RecoveryPhraseDisplayView(store: store.backupPhraseStore())
}
)
.navigationLinkEmpty(
isActive: viewStore.bindingForPrivateDataConsent,
isActive: store.bindingForPrivateDataConsent,
destination: {
PrivateDataConsentView(store: store.privateDataConsentStore())
}
)
.navigationLinkEmpty(
isActive: viewStore.bindingForServerSetup,
isActive: store.bindingForServerSetup,
destination: {
ServerSetupView(store: store.serverSetupStore())
}
)
.navigationLinkEmpty(
isActive: viewStore.bindingDeleteWallet,
isActive: store.bindingDeleteWallet,
destination: {
DeleteWalletView(store: store.deleteWalletStore())
}
)
.onAppear {
isRestoringWalletBadgeOn = viewStore.isRestoringWallet
}
.onChange(of: viewStore.isRestoringWallet) { isRestoringWalletBadgeOn = $0 }
.padding(.horizontal, 70)
Button(L10n.Settings.exportPrivateData.uppercased()) {
viewStore.send(.updateDestination(.privateDataConsent))
store.send(.updateDestination(.privateDataConsent))
}
.zcashStyle()
.padding(.bottom, 25)
.padding(.horizontal, 70)
Button(L10n.Settings.chooseServer.uppercased()) {
viewStore.send(.updateDestination(.serverSetup))
store.send(.updateDestination(.serverSetup))
}
.zcashStyle()
.padding(.horizontal, 70)
@ -79,7 +73,7 @@ public struct AdvancedSettingsView: View {
Spacer()
Button(L10n.Settings.deleteZashi.uppercased()) {
viewStore.send(.updateDestination(.deleteWallet))
store.send(.updateDestination(.deleteWallet))
}
.zcashStyle()
.padding(.bottom, 20)
@ -99,7 +93,7 @@ public struct AdvancedSettingsView: View {
.resizable()
.frame(width: 62, height: 17)
}
.restoringWalletBadge(isOn: isRestoringWalletBadgeOn)
.restoringWalletBadge(isOn: store.isRestoringWallet)
.task { await store.send(.restoreWalletTask).finish() }
}
}
@ -108,6 +102,110 @@ public struct AdvancedSettingsView: View {
#Preview {
NavigationView {
AdvancedSettingsView(store: .placeholder)
AdvancedSettingsView(store: .initial)
}
}
// MARK: - ViewStore
extension StoreOf<AdvancedSettings> {
var destinationBinding: Binding<AdvancedSettings.State.Destination?> {
Binding {
self.state.destination
} set: {
self.send(.updateDestination($0))
}
}
var bindingForBackupPhrase: Binding<Bool> {
self.destinationBinding.map(
extract: { $0 == .backupPhrase },
embed: { $0 ? .backupPhrase : nil }
)
}
var bindingForPrivateDataConsent: Binding<Bool> {
self.destinationBinding.map(
extract: { $0 == .privateDataConsent },
embed: { $0 ? .privateDataConsent : nil }
)
}
var bindingForServerSetup: Binding<Bool> {
self.destinationBinding.map(
extract: { $0 == .serverSetup },
embed: { $0 ? .serverSetup : nil }
)
}
var bindingDeleteWallet: Binding<Bool> {
self.destinationBinding.map(
extract: { $0 == .deleteWallet },
embed: { $0 ? .deleteWallet : nil }
)
}
func backupPhraseStore() -> StoreOf<RecoveryPhraseDisplay> {
self.scope(
state: \.phraseDisplayState,
action: \.phraseDisplay
)
}
func privateDataConsentStore() -> PrivateDataConsentStore {
self.scope(
state: \.privateDataConsentState,
action: \.privateDataConsent
)
}
func serverSetupStore() -> StoreOf<ServerSetup> {
self.scope(
state: \.serverSetupState,
action: \.serverSetup
)
}
func deleteWalletStore() -> StoreOf<DeleteWallet> {
self.scope(
state: \.deleteWallet,
action: \.deleteWallet
)
}
}
// MARK: Placeholders
extension AdvancedSettings.State {
public static let initial = AdvancedSettings.State(
deleteWallet: .initial,
phraseDisplayState: RecoveryPhraseDisplay.State(
phrase: nil,
showBackButton: false,
birthday: nil
),
privateDataConsentState: .initial,
serverSetupState: ServerSetup.State()
)
}
extension StoreOf<AdvancedSettings> {
public static let initial = StoreOf<AdvancedSettings>(
initialState: .initial
) {
AdvancedSettings()
}
public static let demo = StoreOf<AdvancedSettings>(
initialState: .init(
deleteWallet: .initial,
phraseDisplayState: RecoveryPhraseDisplay.State(
phrase: nil,
birthday: nil
),
privateDataConsentState: .initial,
serverSetupState: ServerSetup.State()
)
) {
AdvancedSettings()
}
}

View File

@ -20,7 +20,7 @@ public struct SettingsReducer: Reducer {
case advanced
}
public var advancedSettingsState: AdvancedSettingsReducer.State
public var advancedSettingsState: AdvancedSettings.State
@PresentationState public var alert: AlertState<Action>?
public var appVersion = ""
public var appBuild = ""
@ -29,7 +29,7 @@ public struct SettingsReducer: Reducer {
public var supportData: SupportData?
public init(
advancedSettingsState: AdvancedSettingsReducer.State,
advancedSettingsState: AdvancedSettings.State,
appVersion: String = "",
appBuild: String = "",
destination: Destination? = nil,
@ -46,7 +46,7 @@ public struct SettingsReducer: Reducer {
}
public enum Action: Equatable {
case advancedSettings(AdvancedSettingsReducer.Action)
case advancedSettings(AdvancedSettings.Action)
case alert(PresentationAction<Action>)
case copyEmail
case onAppear
@ -119,7 +119,7 @@ public struct SettingsReducer: Reducer {
.ifLet(\.$alert, action: /Action.alert)
Scope(state: \.advancedSettingsState, action: /Action.advancedSettings) {
AdvancedSettingsReducer()
AdvancedSettings()
}
}
}
@ -152,7 +152,7 @@ extension SettingsViewStore {
// MARK: - Store
extension SettingsStore {
func advancedSettingsStore() -> StoreOf<AdvancedSettingsReducer> {
func advancedSettingsStore() -> StoreOf<AdvancedSettings> {
self.scope(
state: \.advancedSettingsState,
action: SettingsReducer.Action.advancedSettings

View File

@ -5,8 +5,8 @@
"kind" : "remoteSourceControl",
"location" : "https://github.com/google/abseil-cpp-binary.git",
"state" : {
"revision" : "bfc0b6f81adc06ce5121eb23f628473638d67c5c",
"version" : "1.2022062300.0"
"revision" : "748c7837511d0e6a507737353af268484e1745e2",
"version" : "1.2024011601.1"
}
},
{
@ -32,8 +32,8 @@
"kind" : "remoteSourceControl",
"location" : "https://github.com/firebase/firebase-ios-sdk",
"state" : {
"revision" : "b880ec8ec927a838c51c12862c6222c30d7097d7",
"version" : "10.20.0"
"revision" : "42eae77a0af79e9c3f41df04a23c76f05cfdda77",
"version" : "10.24.0"
}
},
{
@ -41,8 +41,8 @@
"kind" : "remoteSourceControl",
"location" : "https://github.com/google/GoogleAppMeasurement.git",
"state" : {
"revision" : "ceec9f28dea12b7cf3dabf18b5ed7621c88fd4aa",
"version" : "10.20.0"
"revision" : "51ba746a9d51a4bd0774b68499b0c73ef6e8570d",
"version" : "10.24.0"
}
},
{
@ -68,8 +68,8 @@
"kind" : "remoteSourceControl",
"location" : "https://github.com/google/grpc-binary.git",
"state" : {
"revision" : "a673bc2937fbe886dd1f99c401b01b6d977a9c98",
"version" : "1.49.1"
"revision" : "e9fad491d0673bdda7063a0341fb6b47a30c5359",
"version" : "1.62.2"
}
},
{
@ -158,8 +158,8 @@
"kind" : "remoteSourceControl",
"location" : "https://github.com/pointfreeco/swift-case-paths",
"state" : {
"revision" : "8cc3bc05d0cc956f7374c6c208a11f66a7cac3db",
"version" : "1.2.2"
"revision" : "79623dbe2c7672f5e450d8325613d231454390b3",
"version" : "1.3.2"
}
},
{
@ -185,8 +185,8 @@
"kind" : "remoteSourceControl",
"location" : "https://github.com/pointfreeco/swift-composable-architecture",
"state" : {
"revision" : "776bc5c28f3beb0ab9897678b5ec63596360f786",
"version" : "1.7.1"
"revision" : "115fe5af41d333b6156d4924d7c7058bc77fd580",
"version" : "1.9.2"
}
},
{

View File

@ -54,14 +54,14 @@ class SettingsTests: XCTestCase {
)
let store = TestStore(
initialState: AdvancedSettingsReducer.State(
initialState: AdvancedSettings.State(
deleteWallet: .initial,
phraseDisplayState: RecoveryPhraseDisplay.State(phrase: nil),
privateDataConsentState: .initial,
serverSetupState: .initial
)
) {
AdvancedSettingsReducer()
AdvancedSettings()
}
store.dependencies.localAuthentication = .mockAuthenticationSucceeded
@ -81,7 +81,7 @@ class SettingsTests: XCTestCase {
let store = TestStore(
initialState: .initial
) {
AdvancedSettingsReducer()
AdvancedSettings()
}
store.dependencies.localAuthentication = .mockAuthenticationFailed