Skip to content

Instantly share code, notes, and snippets.

@lukeredpath
Last active March 11, 2024 17:49
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save lukeredpath/f895504cc16fd11f9c0f541f6bf4573e to your computer and use it in GitHub Desktop.
Save lukeredpath/f895504cc16fd11f9c0f541f6bf4573e to your computer and use it in GitHub Desktop.
//
// 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