Last active
March 11, 2024 17:49
-
-
Save lukeredpath/f895504cc16fd11f9c0f541f6bf4573e to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// TCAStoreCachingApp.swift | |
// TCAStoreCaching | |
// | |
// Created by Luke Redpath on 11/03/2024. | |
// | |
import ComposableArchitecture | |
import SwiftUI | |
@Reducer | |
struct RootFeature: Reducer { | |
@ObservableState | |
struct State: Equatable { | |
@Presents | |
var legacyFeature: LegacyFeature.State? | |
} | |
enum Action { | |
case legacyFeature(PresentationAction<LegacyFeature.Action>) | |
case openLegacyFeatureButtonTapped | |
} | |
var body: some ReducerOf<Self> { | |
Reduce { state, action in | |
switch action { | |
case .openLegacyFeatureButtonTapped: | |
state.legacyFeature = .init() | |
return .none | |
case .legacyFeature(.presented(.doneButtonTapped)): | |
state.legacyFeature = nil | |
return .none | |
case .legacyFeature: | |
return .none | |
} | |
} | |
.ifLet(\.$legacyFeature, action: \.legacyFeature) { | |
LegacyFeature() | |
} | |
} | |
} | |
@Reducer | |
struct LegacyFeature: Reducer { | |
struct State: Equatable { | |
@PresentationState | |
var destination: Destination.State? | |
} | |
enum Action { | |
case destination(PresentationAction<Destination.Action>) | |
case openNewFeatureButtonTapped | |
case doneButtonTapped | |
} | |
var body: some ReducerOf<Self> { | |
Reduce { state, action in | |
switch action { | |
case .openNewFeatureButtonTapped: | |
state.destination = .newFeature(NewFeature.State()) | |
return .none | |
case .destination(.presented(.newFeature(.doneButtonTapped))): | |
state.destination = nil | |
return .none | |
case .doneButtonTapped: | |
return .none | |
case .destination: | |
return .none | |
} | |
} | |
.ifLet(\.$destination, action: \.destination) | |
} | |
@Reducer(state: .equatable) | |
enum Destination { | |
case newFeature(NewFeature) | |
} | |
} | |
@Reducer | |
struct NewFeature: Reducer { | |
@ObservableState | |
struct State: Equatable { | |
var child: Child.State? | |
} | |
enum Action { | |
case toggleChild | |
case doneButtonTapped | |
case child(Child.Action) | |
} | |
var body: some ReducerOf<Self> { | |
Reduce<State, Action> { state, action in | |
switch action { | |
case .toggleChild: | |
if state.child == nil { | |
state.child = .init() | |
} else { | |
state.child = nil | |
} | |
return .none | |
case .doneButtonTapped: | |
return .none | |
case .child: | |
return .none | |
} | |
} | |
} | |
@Reducer | |
struct Child {} | |
} | |
struct RootView: View { | |
@Bindable | |
var store: StoreOf<RootFeature> | |
var body: some View { | |
List { | |
Button("Open Legacy Feature") { | |
store.send(.openLegacyFeatureButtonTapped) | |
} | |
} | |
.navigationTitle("Root View") | |
.sheet(item: $store.scope(state: \.legacyFeature, action: \.legacyFeature)) { store in | |
NavigationStack { | |
LegacyFeatureView(store: store) | |
} | |
} | |
} | |
} | |
struct LegacyFeatureView: View { | |
let store: StoreOf<LegacyFeature> | |
var body: some View { | |
WithViewStore(store, observe: { $0 }) { _ in | |
List { | |
Button("Open New Feature") { | |
store.send(.openNewFeatureButtonTapped) | |
} | |
} | |
} | |
.toolbar { | |
ToolbarItem(placement: .primaryAction) { | |
Button("Done") { | |
store.send(.doneButtonTapped) | |
} | |
} | |
} | |
.sheet(store: store.scope(state: \.$destination.newFeature, action: \.destination.newFeature)) { store in | |
NavigationStack { | |
NewFeatureView(store: store) | |
} | |
} | |
.navigationTitle("Legacy Feature") | |
} | |
} | |
struct NewFeatureView: View { | |
let store: StoreOf<NewFeature> | |
@Environment(\.dismiss) | |
private var dismiss | |
var body: some View { | |
List { | |
Section { | |
Text("New Feature") | |
Button("Toggle Child") { | |
store.send(.toggleChild) | |
} | |
} | |
if let childStore = store.scope(state: \.child, action: \.child) { | |
ChildView(store: childStore) | |
} | |
} | |
.toolbar { | |
ToolbarItem(placement: .cancellationAction) { | |
Button("Close") { | |
dismiss() | |
} | |
} | |
ToolbarItem(placement: .primaryAction) { | |
Button("Done") { | |
store.send(.doneButtonTapped) | |
} | |
} | |
} | |
} | |
struct ChildView: View { | |
let store: StoreOf<NewFeature.Child> | |
var body: some View { | |
Section("Child") { | |
Text("Child Section") | |
} | |
} | |
} | |
} | |
@main | |
struct TCAStoreCachingApp: App { | |
@State | |
var store = Store(initialState: RootFeature.State()) { | |
RootFeature() | |
} | |
var body: some Scene { | |
WindowGroup { | |
NavigationStack { | |
RootView(store: store) | |
} | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment