Files
swift-composable-architectu…/Examples/CaseStudies/SwiftUICaseStudies/03-Navigation-LoadThenNavigate.swift
Brandon Williams a38e04da7d Modernize some things (#713)
* Modernize some things.

* clean up

* wip

* wip

* clean up

* wip

* wip
2021-08-12 18:13:40 -04:00

114 lines
3.1 KiB
Swift

import ComposableArchitecture
import SwiftUI
private let readMe = """
This screen demonstrates navigation that depends on loading optional state.
Tapping "Load optional counter" fires off an effect that will load the counter state a second \
later. When the counter state is present, you will be programmatically navigated to the screen \
that depends on this data.
"""
struct LoadThenNavigateState: Equatable {
var optionalCounter: CounterState?
var isActivityIndicatorVisible = false
var isNavigationActive: Bool { self.optionalCounter != nil }
}
enum LoadThenNavigateAction: Equatable {
case optionalCounter(CounterAction)
case setNavigation(isActive: Bool)
case setNavigationIsActiveDelayCompleted
}
struct LoadThenNavigateEnvironment {
var mainQueue: AnySchedulerOf<DispatchQueue>
}
let loadThenNavigateReducer =
counterReducer
.optional()
.pullback(
state: \.optionalCounter,
action: /LoadThenNavigateAction.optionalCounter,
environment: { _ in CounterEnvironment() }
)
.combined(
with: Reducer<
LoadThenNavigateState, LoadThenNavigateAction, LoadThenNavigateEnvironment
> { state, action, environment in
switch action {
case .setNavigation(isActive: true):
state.isActivityIndicatorVisible = true
return Effect(value: .setNavigationIsActiveDelayCompleted)
.delay(for: 1, scheduler: environment.mainQueue)
.eraseToEffect()
case .setNavigation(isActive: false):
state.optionalCounter = nil
return .none
case .setNavigationIsActiveDelayCompleted:
state.isActivityIndicatorVisible = false
state.optionalCounter = CounterState()
return .none
case .optionalCounter:
return .none
}
}
)
struct LoadThenNavigateView: View {
let store: Store<LoadThenNavigateState, LoadThenNavigateAction>
var body: some View {
WithViewStore(self.store) { viewStore in
Form {
Section(header: Text(readMe)) {
NavigationLink(
destination: IfLetStore(
self.store.scope(
state: \.optionalCounter,
action: LoadThenNavigateAction.optionalCounter
),
then: CounterView.init(store:)
),
isActive: viewStore.binding(
get: \.isNavigationActive,
send: LoadThenNavigateAction.setNavigation(isActive:)
)
) {
HStack {
Text("Load optional counter")
if viewStore.isActivityIndicatorVisible {
Spacer()
ProgressView()
}
}
}
}
}
}
.navigationBarTitle("Load then navigate")
}
}
struct LoadThenNavigateView_Previews: PreviewProvider {
static var previews: some View {
NavigationView {
LoadThenNavigateView(
store: Store(
initialState: LoadThenNavigateState(),
reducer: loadThenNavigateReducer,
environment: LoadThenNavigateEnvironment(
mainQueue: .main
)
)
)
}
.navigationViewStyle(StackNavigationViewStyle())
}
}