[#462] Migrate Profile to ReducerProtocol (#484)

- Profile migrated to ReducerProtocol
- unit and snapshot tests fixed
- sandbox feature still works with all the TCA pullback/scope navigation
This commit is contained in:
Lukas Korba 2022-11-08 09:36:23 +01:00 committed by GitHub
parent 046681efff
commit 7f6c104d28
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 93 additions and 155 deletions

View File

@ -6,6 +6,7 @@
//
import Foundation
import ComposableArchitecture
struct AppVersionHandler {
let appVersion: () -> String
@ -23,3 +24,15 @@ extension AppVersionHandler {
appBuild: { "31" }
)
}
private enum AppVersionHandlerKey: DependencyKey {
static let liveValue = AppVersionHandler.live
static let testValue = AppVersionHandler.test
}
extension DependencyValues {
var appVersionHandler: AppVersionHandler {
get { self[AppVersionHandlerKey.self] }
set { self[AppVersionHandlerKey.self] = newValue }
}
}

View File

@ -12,6 +12,7 @@ typealias HomeViewStore = ViewStore<HomeState, HomeAction>
typealias AnyBalanceBreakdownReducer = AnyReducer<BalanceBreakdownReducer.State, BalanceBreakdownReducer.Action, HomeEnvironment>
typealias AnyScanReducer = AnyReducer<ScanReducer.State, ScanReducer.Action, HomeEnvironment>
typealias AnyWalletEventsFlowReducer = AnyReducer<WalletEventsFlowReducer.State, WalletEventsFlowReducer.Action, HomeEnvironment>
typealias AnyProfileReducer = AnyReducer<ProfileReducer.State, ProfileReducer.Action, HomeEnvironment>
// MARK: State
@ -29,7 +30,7 @@ struct HomeState: Equatable {
var balanceBreakdown: BalanceBreakdownReducer.State
var drawerOverlay: DrawerOverlay
var profileState: ProfileState
var profileState: ProfileReducer.State
var requestState: RequestReducer.State
var requiredTransactionConfirmations = 0
var scanState: ScanReducer.State
@ -66,7 +67,7 @@ enum HomeAction: Equatable {
case debugMenuStartup
case onAppear
case onDisappear
case profile(ProfileAction)
case profile(ProfileReducer.Action)
case request(RequestReducer.Action)
case send(SendFlowAction)
case scan(ScanReducer.Action)
@ -269,18 +270,13 @@ extension HomeReducer {
environment: { $0 }
)
private static let profileReducer: HomeReducer = ProfileReducer.default.pullback(
private static let profileReducer: HomeReducer = AnyProfileReducer { _ in
ProfileReducer()
}
.pullback(
state: \HomeState.profileState,
action: /HomeAction.profile,
environment: { environment in
ProfileEnvironment(
appVersionHandler: .live,
mnemonic: environment.mnemonic,
SDKSynchronizer: environment.SDKSynchronizer,
walletStorage: environment.walletStorage,
zcashSDKEnvironment: environment.zcashSDKEnvironment
)
}
environment: { $0 }
)
private static let balanceBreakdownReducer: HomeReducer = AnyBalanceBreakdownReducer { _ in

View File

@ -1,120 +1,70 @@
import ComposableArchitecture
import SwiftUI
typealias ProfileReducer = Reducer<ProfileState, ProfileAction, ProfileEnvironment>
typealias ProfileStore = Store<ProfileState, ProfileAction>
typealias ProfileViewStore = ViewStore<ProfileState, ProfileAction>
typealias ProfileStore = Store<ProfileReducer.State, ProfileReducer.Action>
typealias ProfileViewStore = ViewStore<ProfileReducer.State, ProfileReducer.Action>
typealias AnySettingsReducer = AnyReducer<SettingsReducer.State, SettingsReducer.Action, ProfileEnvironment>
typealias AnyAddressDetailsReducer = AnyReducer<AddressDetailsReducer.State, AddressDetailsReducer.Action, ProfileEnvironment>
struct ProfileReducer: ReducerProtocol {
struct State: Equatable {
enum Route {
case addressDetails
case settings
}
// MARK: - State
struct ProfileState: Equatable {
enum Route {
case addressDetails
case settings
var address = ""
var addressDetailsState: AddressDetailsReducer.State
var appBuild = ""
var appVersion = ""
var route: Route?
var sdkVersion = ""
var settingsState: SettingsReducer.State
}
var address = ""
var addressDetailsState: AddressDetailsReducer.State
var appBuild = ""
var appVersion = ""
var route: Route?
var sdkVersion = ""
var settingsState: SettingsReducer.State
}
// MARK: - Action
enum ProfileAction: Equatable {
case addressDetails(AddressDetailsReducer.Action)
case back
case onAppear
case settings(SettingsReducer.Action)
case updateRoute(ProfileState.Route?)
}
// MARK: - Environment
struct ProfileEnvironment {
let appVersionHandler: AppVersionHandler
let mnemonic: WrappedMnemonic
let SDKSynchronizer: WrappedSDKSynchronizer
let walletStorage: WrappedWalletStorage
let zcashSDKEnvironment: ZCashSDKEnvironment
}
extension ProfileEnvironment {
static let live = ProfileEnvironment(
appVersionHandler: .live,
mnemonic: .live,
SDKSynchronizer: LiveWrappedSDKSynchronizer(),
walletStorage: .live(),
zcashSDKEnvironment: .mainnet
)
static let mock = ProfileEnvironment(
appVersionHandler: .test,
mnemonic: .mock,
SDKSynchronizer: MockWrappedSDKSynchronizer(),
walletStorage: .live(),
zcashSDKEnvironment: .testnet
)
}
// MARK: - Reducer
extension ProfileReducer {
static let `default` = ProfileReducer.combine(
[
profileReducer,
addressDetailsReducer,
settingsReducer
]
)
private static let profileReducer = ProfileReducer { state, action, environment in
switch action {
case .onAppear:
state.address = environment.SDKSynchronizer.getShieldedAddress() ?? ""
state.appBuild = environment.appVersionHandler.appBuild()
state.appVersion = environment.appVersionHandler.appVersion()
state.sdkVersion = environment.zcashSDKEnvironment.sdkVersion
return .none
case .back:
return .none
case let .updateRoute(route):
state.route = route
return .none
case .addressDetails:
return .none
case .settings:
return .none
}
enum Action: Equatable {
case addressDetails(AddressDetailsReducer.Action)
case back
case onAppear
case settings(SettingsReducer.Action)
case updateRoute(ProfileReducer.State.Route?)
}
private static let addressDetailsReducer: ProfileReducer = AnyAddressDetailsReducer { _ in
AddressDetailsReducer()
}
.pullback(
state: \ProfileState.addressDetailsState,
action: /ProfileAction.addressDetails,
environment: { $0 }
)
@Dependency(\.sdkSynchronizer) var sdkSynchronizer
@Dependency(\.zcashSDKEnvironment) var zcashSDKEnvironment
@Dependency(\.appVersionHandler) var appVersionHandler
private static let settingsReducer: ProfileReducer = AnySettingsReducer { _ in
SettingsReducer()
var body: some ReducerProtocol<State, Action> {
Scope(state: \.addressDetailsState, action: /Action.addressDetails) {
AddressDetailsReducer()
}
Scope(state: \.settingsState, action: /Action.settings) {
SettingsReducer()
}
Reduce { state, action in
switch action {
case .onAppear:
state.address = sdkSynchronizer.getShieldedAddress() ?? ""
state.appBuild = appVersionHandler.appBuild()
state.appVersion = appVersionHandler.appVersion()
state.sdkVersion = zcashSDKEnvironment.sdkVersion
return .none
case .back:
return .none
case let .updateRoute(route):
state.route = route
return .none
case .addressDetails:
return .none
case .settings:
return .none
}
}
}
.pullback(
state: \ProfileState.settingsState,
action: /ProfileAction.settings,
environment: { $0 }
)
}
// MARK: - Store
@ -123,7 +73,7 @@ extension ProfileStore {
func settingsStore() -> SettingsStore {
self.scope(
state: \.settingsState,
action: ProfileAction.settings
action: ProfileReducer.Action.settings
)
}
}
@ -131,10 +81,10 @@ extension ProfileStore {
// MARK: - ViewStore
extension ProfileViewStore {
var routeBinding: Binding<ProfileState.Route?> {
var routeBinding: Binding<ProfileReducer.State.Route?> {
self.binding(
get: \.route,
send: ProfileAction.updateRoute
send: ProfileReducer.Action.updateRoute
)
}
@ -153,9 +103,9 @@ extension ProfileViewStore {
}
}
// MARK: Placeholders
// MARK: - Placeholders
extension ProfileState {
extension ProfileReducer.State {
static var placeholder: Self {
.init(
addressDetailsState: .placeholder,

View File

@ -116,8 +116,7 @@ struct ProfileView_Previews: PreviewProvider {
addressDetailsState: .placeholder,
settingsState: .placeholder
),
reducer: .default,
environment: .live
reducer: ProfileReducer()
)
)
}

View File

@ -15,14 +15,14 @@ struct SandboxReducer: ReducerProtocol {
case request
}
var walletEventsState: WalletEventsFlowReducer.State
var profileState: ProfileState
var profileState: ProfileReducer.State
var route: Route?
}
enum Action: Equatable {
case updateRoute(SandboxReducer.State.Route?)
case walletEvents(WalletEventsFlowReducer.Action)
case profile(ProfileAction)
case profile(ProfileReducer.Action)
case reset
}
@ -38,14 +38,10 @@ struct SandboxReducer: ReducerProtocol {
.map(SandboxReducer.Action.walletEvents)
case .profile:
return ProfileReducer
.default
.pullback(
state: \.profileState,
action: /SandboxReducer.Action.profile,
environment: { _ in ProfileEnvironment.live }
)
.run(&state, action, ())
return Scope(state: \SandboxReducer.State.profileState, action: /SandboxReducer.Action.profile) {
ProfileReducer()
}
.reduce(into: &state, action: action)
case .reset:
return .none

View File

@ -11,18 +11,10 @@ import ComposableArchitecture
class ProfileTests: XCTestCase {
func testSynchronizerStateChanged_AnyButSynced() throws {
let testEnvironment = ProfileEnvironment(
appVersionHandler: .test,
mnemonic: .mock,
SDKSynchronizer: TestWrappedSDKSynchronizer(),
walletStorage: .throwing,
zcashSDKEnvironment: .testnet
)
let store = TestStore(
initialState: .placeholder,
reducer: ProfileReducer.default,
environment: testEnvironment
reducer: ProfileReducer()
.dependency(\.sdkSynchronizer, TestWrappedSDKSynchronizer())
)
store.send(.onAppear) { state in

View File

@ -12,18 +12,10 @@ import SwiftUI
class ProfileSnapshotTests: XCTestCase {
func testProfileSnapshot_sent() throws {
let testEnvironment = ProfileEnvironment(
appVersionHandler: .test,
mnemonic: .mock,
SDKSynchronizer: TestWrappedSDKSynchronizer(),
walletStorage: .throwing,
zcashSDKEnvironment: .testnet
)
let store = Store(
initialState: .placeholder,
reducer: ProfileReducer.default,
environment: testEnvironment
reducer: ProfileReducer()
.dependency(\.sdkSynchronizer, TestWrappedSDKSynchronizer())
)
ViewStore(store).send(.onAppear)