Skip to content

Commit 195284b

Browse files
stephencelismbrandonwJager-yoobarabashd
authored
The Composable Architecture 1.0 (#2318)
* docs * wip * wip * wip * wip * wip * wip * wip * Fix invalid states count for 3 optionals and typos (#2094) * wip * wip * more dismisseffect docs * fixed some references * navigation doc corrections * more nav docs * fix cancellation tests in release mode * wrap some tests in #if DEBUG since they are testing expected failures * update UUIDs in tests to use shorter initializer * fixed a todo * wip * fix merge errors * wip * fix * wip * wip * fixing a bunch of todos * get rid of rawvalue in StackElementID * more todos * NavLinkStore docs * fix swift 5.6 stuff * fix some standups tests * fix * clean up * docs fix * fixes * wip * 5.6 fix * wip * wip * dont parallelize tests * updated demo readmes * wip * Use ObservedObject instead of StateObject for alert/dialog modifiers. * integration tests for bad dismissal behavior * check for runtime warnings in every integration test * wip * wip * wip * fix * wip * wip * wip * wip * wip * wip * Drop a bunch of Hashables. * some nav bug fixes * wip * wip * wip * fix * fix * wip * wip * Simplify recording test. * add concurrent async test * fix * wip * Refact how detail dismisses itself. * fix * 5.6 fix * wip * wip * wip * wip * Add TestStore.assert. * Revert "Add TestStore.assert." This reverts commit a892ccc. * add Ukrainian Readme.md (#2121) * Add TestStore.assert. (#2123) * Add TestStore.assert. * wip * Update Sources/ComposableArchitecture/TestStore.swift Co-authored-by: Stephen Celis <[email protected]> * Update Sources/ComposableArchitecture/Documentation.docc/Extensions/TestStore.md Co-authored-by: Stephen Celis <[email protected]> * fix tests --------- Co-authored-by: Stephen Celis <[email protected]> * Run swift-format * push for store.finish and presentation * wip * move docs around * wip * wip * wip * wip * wip * wip * wip * wip * wip * wip * wip * wip * wip * wip * Add case subscripts * wip * wip * wip * 5.7-only * wip * wip * wip * wip * fix * revert store.finish task cancellation * wip * wip * wip * wip * wip * wip * wip * wip * wip * wip * wip * wip * wip * wip * wip * wip * wip * wip * wip * wip * add test for presentation scope * wip * wip * wip * wip * wip * cleanup * wip * wip * wip * wip * wip * wip * wip * wip * wip * wip * wip * wip * Rename ReducerProtocol.swift to Reducer.swift (#2206) * Hard-deprecate old SwitchStore initializers/overloads * wip * wip * Resolve CaseStudies crash (#2258) * wip * wip * wip * wip * wip * wip * wip * wip * Bump timeout for CI * wip * Remove old deprecations * Simplify test store * wip * wip * wip * wip * wip * wip * wip * wip * wip * wip * wip * wip * wip * wip * wip * wip * wip * images for tutorials * wip * wip * Remove deprecated alert APIs * Bump dependencies * wip --------- Co-authored-by: Brandon Williams <[email protected]> Co-authored-by: 유재호 <[email protected]> Co-authored-by: Dmytro <[email protected]> Co-authored-by: Brandon Williams <[email protected]> Co-authored-by: mbrandonw <[email protected]>
1 parent 4cf2104 commit 195284b

File tree

130 files changed

+859
-8474
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

130 files changed

+859
-8474
lines changed

ComposableArchitecture.xcworkspace/xcshareddata/swiftpm/Package.resolved

Lines changed: 18 additions & 18 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Examples/CaseStudies/CaseStudies.xcodeproj/project.pbxproj

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,10 @@
99
/* Begin PBXBuildFile section */
1010
433B8B762A49C9AF0035DEE4 /* 03-Navigation-Multiple-Destinations.swift in Sources */ = {isa = PBXBuildFile; fileRef = 433B8B752A49C9AF0035DEE4 /* 03-Navigation-Multiple-Destinations.swift */; };
1111
4F5AC11F24ECC7E4009DC50B /* 01-GettingStarted-SharedStateTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4F5AC11E24ECC7E4009DC50B /* 01-GettingStarted-SharedStateTests.swift */; };
12-
CA0C0C4724B89BEC00CBDD8A /* 04-HigherOrderReducers-LifecycleTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = CA0C0C4624B89BEC00CBDD8A /* 04-HigherOrderReducers-LifecycleTests.swift */; };
1312
CA0C51FB245389CC00A04EAB /* 04-HigherOrderReducers-ReusableOfflineDownloadsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = CA0C51FA245389CC00A04EAB /* 04-HigherOrderReducers-ReusableOfflineDownloadsTests.swift */; };
1413
CA25E5D224463AD700DA666A /* 01-GettingStarted-Bindings-Basics.swift in Sources */ = {isa = PBXBuildFile; fileRef = CA25E5D124463AD700DA666A /* 01-GettingStarted-Bindings-Basics.swift */; };
1514
CA34170824A4E89500FAF950 /* 01-GettingStarted-AnimationsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = CA34170724A4E89500FAF950 /* 01-GettingStarted-AnimationsTests.swift */; };
1615
CA3E421F26B8337500581ABC /* 01-GettingStarted-FocusState.swift in Sources */ = {isa = PBXBuildFile; fileRef = CA3E421E26B8337500581ABC /* 01-GettingStarted-FocusState.swift */; };
17-
CA3E4C5B24B4FA0E00447C0B /* 04-HigherOrderReducers-Lifecycle.swift in Sources */ = {isa = PBXBuildFile; fileRef = CA3E4C5A24B4FA0E00447C0B /* 04-HigherOrderReducers-Lifecycle.swift */; };
1816
CA410EE0247A15FE00E41798 /* 02-Effects-WebSocket.swift in Sources */ = {isa = PBXBuildFile; fileRef = CA410EDF247A15FE00E41798 /* 02-Effects-WebSocket.swift */; };
1917
CA410EE2247C73B400E41798 /* 02-Effects-WebSocketTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = CA410EE1247C73B400E41798 /* 02-Effects-WebSocketTests.swift */; };
2018
CA50BE6024A8F46500FE7DBA /* 01-GettingStarted-AlertsAndConfirmationDialogsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = CA50BE5F24A8F46500FE7DBA /* 01-GettingStarted-AlertsAndConfirmationDialogsTests.swift */; };
@@ -72,7 +70,6 @@
7270
DC89C45324465452006900B9 /* 03-Navigation-Lists-NavigateAndLoad.swift in Sources */ = {isa = PBXBuildFile; fileRef = DC89C45224465451006900B9 /* 03-Navigation-Lists-NavigateAndLoad.swift */; };
7371
DC89C45524465C44006900B9 /* 02-Effects-Timers.swift in Sources */ = {isa = PBXBuildFile; fileRef = DC89C45424465C44006900B9 /* 02-Effects-Timers.swift */; };
7472
DC9EB4172450CBD2005F413B /* UIViewRepresented.swift in Sources */ = {isa = PBXBuildFile; fileRef = DC9EB4162450CBD2005F413B /* UIViewRepresented.swift */; };
75-
DCAC2A4F2452352E0094DEF5 /* 04-HigherOrderReducers-ElmLikeSubscriptions.swift in Sources */ = {isa = PBXBuildFile; fileRef = DCAC2A4E2452352E0094DEF5 /* 04-HigherOrderReducers-ElmLikeSubscriptions.swift */; };
7673
DCC68EAB244666AF0037F998 /* 03-Navigation-Sheet-PresentAndLoad.swift in Sources */ = {isa = PBXBuildFile; fileRef = DCC68EAA244666AF0037F998 /* 03-Navigation-Sheet-PresentAndLoad.swift */; };
7774
DCC68EDD2447A5B00037F998 /* 01-GettingStarted-OptionalState.swift in Sources */ = {isa = PBXBuildFile; fileRef = DCC68EDC2447A5B00037F998 /* 01-GettingStarted-OptionalState.swift */; };
7875
DCC68EDF2447BC810037F998 /* TemplateText.swift in Sources */ = {isa = PBXBuildFile; fileRef = DCC68EDE2447BC810037F998 /* TemplateText.swift */; };
@@ -153,12 +150,10 @@
153150
/* Begin PBXFileReference section */
154151
433B8B752A49C9AF0035DEE4 /* 03-Navigation-Multiple-Destinations.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "03-Navigation-Multiple-Destinations.swift"; sourceTree = "<group>"; };
155152
4F5AC11E24ECC7E4009DC50B /* 01-GettingStarted-SharedStateTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "01-GettingStarted-SharedStateTests.swift"; sourceTree = "<group>"; };
156-
CA0C0C4624B89BEC00CBDD8A /* 04-HigherOrderReducers-LifecycleTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "04-HigherOrderReducers-LifecycleTests.swift"; sourceTree = "<group>"; };
157153
CA0C51FA245389CC00A04EAB /* 04-HigherOrderReducers-ReusableOfflineDownloadsTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "04-HigherOrderReducers-ReusableOfflineDownloadsTests.swift"; sourceTree = "<group>"; };
158154
CA25E5D124463AD700DA666A /* 01-GettingStarted-Bindings-Basics.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "01-GettingStarted-Bindings-Basics.swift"; sourceTree = "<group>"; };
159155
CA34170724A4E89500FAF950 /* 01-GettingStarted-AnimationsTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "01-GettingStarted-AnimationsTests.swift"; sourceTree = "<group>"; };
160156
CA3E421E26B8337500581ABC /* 01-GettingStarted-FocusState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "01-GettingStarted-FocusState.swift"; sourceTree = "<group>"; };
161-
CA3E4C5A24B4FA0E00447C0B /* 04-HigherOrderReducers-Lifecycle.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "04-HigherOrderReducers-Lifecycle.swift"; sourceTree = "<group>"; };
162157
CA410EDF247A15FE00E41798 /* 02-Effects-WebSocket.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "02-Effects-WebSocket.swift"; sourceTree = "<group>"; };
163158
CA410EE1247C73B400E41798 /* 02-Effects-WebSocketTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "02-Effects-WebSocketTests.swift"; sourceTree = "<group>"; };
164159
CA50BE5F24A8F46500FE7DBA /* 01-GettingStarted-AlertsAndConfirmationDialogsTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "01-GettingStarted-AlertsAndConfirmationDialogsTests.swift"; sourceTree = "<group>"; };
@@ -225,7 +220,6 @@
225220
DC89C45224465451006900B9 /* 03-Navigation-Lists-NavigateAndLoad.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "03-Navigation-Lists-NavigateAndLoad.swift"; sourceTree = "<group>"; };
226221
DC89C45424465C44006900B9 /* 02-Effects-Timers.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "02-Effects-Timers.swift"; sourceTree = "<group>"; };
227222
DC9EB4162450CBD2005F413B /* UIViewRepresented.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UIViewRepresented.swift; sourceTree = "<group>"; };
228-
DCAC2A4E2452352E0094DEF5 /* 04-HigherOrderReducers-ElmLikeSubscriptions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "04-HigherOrderReducers-ElmLikeSubscriptions.swift"; sourceTree = "<group>"; };
229223
DCC68EAA244666AF0037F998 /* 03-Navigation-Sheet-PresentAndLoad.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "03-Navigation-Sheet-PresentAndLoad.swift"; sourceTree = "<group>"; };
230224
DCC68EDC2447A5B00037F998 /* 01-GettingStarted-OptionalState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "01-GettingStarted-OptionalState.swift"; sourceTree = "<group>"; };
231225
DCC68EDE2447BC810037F998 /* TemplateText.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TemplateText.swift; sourceTree = "<group>"; };
@@ -416,8 +410,6 @@
416410
DCC68EAA244666AF0037F998 /* 03-Navigation-Sheet-PresentAndLoad.swift */,
417411
433B8B752A49C9AF0035DEE4 /* 03-Navigation-Multiple-Destinations.swift */,
418412
DC3C87AF29A48C4D004D9104 /* 03-NavigationStack.swift */,
419-
DCAC2A4E2452352E0094DEF5 /* 04-HigherOrderReducers-ElmLikeSubscriptions.swift */,
420-
CA3E4C5A24B4FA0E00447C0B /* 04-HigherOrderReducers-Lifecycle.swift */,
421413
DCE63B70245CC0B90080A23D /* 04-HigherOrderReducers-Recursion.swift */,
422414
DCC68EE22447C8540037F998 /* 04-HigherOrderReducers-ReusableFavoriting.swift */,
423415
DCFE195F278DBF0600C14CCF /* CaseStudiesApp.swift */,
@@ -442,7 +434,6 @@
442434
CABC4F3A26AEE20200D5FA2C /* 02-Effects-RefreshableTests.swift */,
443435
DC07231624465D1E003A8B65 /* 02-Effects-TimersTests.swift */,
444436
CA410EE1247C73B400E41798 /* 02-Effects-WebSocketTests.swift */,
445-
CA0C0C4624B89BEC00CBDD8A /* 04-HigherOrderReducers-LifecycleTests.swift */,
446437
CA78F0CC28DA47D70026C4AD /* 04-HigherOrderReducers-RecursionTests.swift */,
447438
DC634B242448D15B00DAA016 /* 04-HigherOrderReducers-ReusableFavoritingTests.swift */,
448439
CA0C51FA245389CC00A04EAB /* 04-HigherOrderReducers-ReusableOfflineDownloadsTests.swift */,
@@ -750,7 +741,6 @@
750741
DCC68EE32447C8540037F998 /* 04-HigherOrderReducers-ReusableFavoriting.swift in Sources */,
751742
CA3E421F26B8337500581ABC /* 01-GettingStarted-FocusState.swift in Sources */,
752743
DCC68EDF2447BC810037F998 /* TemplateText.swift in Sources */,
753-
DCAC2A4F2452352E0094DEF5 /* 04-HigherOrderReducers-ElmLikeSubscriptions.swift in Sources */,
754744
CA6AC2672451135C00C71CB3 /* DownloadClient.swift in Sources */,
755745
CAA9ADC624465C810003A984 /* 02-Effects-Cancellation.swift in Sources */,
756746
CA5ECF92267A79F0002067FF /* FactClient.swift in Sources */,
@@ -760,7 +750,6 @@
760750
DCFE1960278DBF0600C14CCF /* CaseStudiesApp.swift in Sources */,
761751
DCD442C6286CA91F008B4EA7 /* AboutView.swift in Sources */,
762752
CA6AC2662451135C00C71CB3 /* DownloadComponent.swift in Sources */,
763-
CA3E4C5B24B4FA0E00447C0B /* 04-HigherOrderReducers-Lifecycle.swift in Sources */,
764753
DC5B505125C86EBC000D8DFD /* 01-GettingStarted-Bindings-Forms.swift in Sources */,
765754
CAA9ADC22446587C0003A984 /* 02-Effects-Basics.swift in Sources */,
766755
DC89C41B24460F95006900B9 /* 00-RootView.swift in Sources */,
@@ -793,7 +782,6 @@
793782
CA410EE2247C73B400E41798 /* 02-Effects-WebSocketTests.swift in Sources */,
794783
CABC4F3B26AEE20200D5FA2C /* 02-Effects-RefreshableTests.swift in Sources */,
795784
CA34170824A4E89500FAF950 /* 01-GettingStarted-AnimationsTests.swift in Sources */,
796-
CA0C0C4724B89BEC00CBDD8A /* 04-HigherOrderReducers-LifecycleTests.swift in Sources */,
797785
DC07231724465D1E003A8B65 /* 02-Effects-TimersTests.swift in Sources */,
798786
CA50BE6024A8F46500FE7DBA /* 01-GettingStarted-AlertsAndConfirmationDialogsTests.swift in Sources */,
799787
CAA9ADC424465AB00003A984 /* 02-Effects-BasicsTests.swift in Sources */,

Examples/CaseStudies/SwiftUICaseStudies/00-Core.swift

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,11 @@ struct Root: Reducer {
66
var animation = Animations.State()
77
var bindingBasics = BindingBasics.State()
88
var bindingForm = BindingForm.State()
9-
var clock = ClockState()
109
var counter = Counter.State()
1110
var effectsBasics = EffectsBasics.State()
1211
var effectsCancellation = EffectsCancellation.State()
1312
var episodes = Episodes.State(episodes: .mocks)
1413
var focusDemo = FocusDemo.State()
15-
var lifecycle = LifecycleDemo.State()
1614
var loadThenPresent = LoadThenPresent.State()
1715
var longLivingEffects = LongLivingEffects.State()
1816
var map = MapApp.State(cityMaps: .mocks)
@@ -35,13 +33,11 @@ struct Root: Reducer {
3533
case animation(Animations.Action)
3634
case bindingBasics(BindingBasics.Action)
3735
case bindingForm(BindingForm.Action)
38-
case clock(ClockAction)
3936
case counter(Counter.Action)
4037
case effectsBasics(EffectsBasics.Action)
4138
case effectsCancellation(EffectsCancellation.Action)
4239
case episodes(Episodes.Action)
4340
case focusDemo(FocusDemo.Action)
44-
case lifecycle(LifecycleDemo.Action)
4541
case loadThenPresent(LoadThenPresent.Action)
4642
case longLivingEffects(LongLivingEffects.Action)
4743
case map(MapApp.Action)
@@ -86,9 +82,6 @@ struct Root: Reducer {
8682
Scope(state: \.bindingForm, action: /Action.bindingForm) {
8783
BindingForm()
8884
}
89-
Scope(state: \.clock, action: /Action.clock) {
90-
Reduce(clockReducer, environment: ClockEnvironment(clock: self.clock))
91-
}
9285
Scope(state: \.counter, action: /Action.counter) {
9386
Counter()
9487
}
@@ -104,9 +97,6 @@ struct Root: Reducer {
10497
Scope(state: \.focusDemo, action: /Action.focusDemo) {
10598
FocusDemo()
10699
}
107-
Scope(state: \.lifecycle, action: /Action.lifecycle) {
108-
LifecycleDemo()
109-
}
110100
Scope(state: \.loadThenPresent, action: /Action.loadThenPresent) {
111101
LoadThenPresent()
112102
}

Examples/CaseStudies/SwiftUICaseStudies/00-RootView.swift

Lines changed: 0 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -243,26 +243,6 @@ struct RootView: View {
243243
)
244244
)
245245

246-
NavigationLink(
247-
"Lifecycle",
248-
destination: LifecycleDemoView(
249-
store: self.store.scope(
250-
state: \.lifecycle,
251-
action: Root.Action.lifecycle
252-
)
253-
)
254-
)
255-
256-
NavigationLink(
257-
"Elm-like subscriptions",
258-
destination: ClockView(
259-
store: self.store.scope(
260-
state: \.clock,
261-
action: Root.Action.clock
262-
)
263-
)
264-
)
265-
266246
NavigationLink(
267247
"Recursive state and actions",
268248
destination: NestedView(

Examples/CaseStudies/SwiftUICaseStudies/01-GettingStarted-Animations.swift

Lines changed: 50 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -22,73 +22,78 @@ private let readMe = """
2222

2323
struct Animations: Reducer {
2424
struct State: Equatable {
25-
var alert: AlertState<Action>?
25+
@PresentationState var alert: AlertState<Action.Alert>?
2626
var circleCenter: CGPoint?
2727
var circleColor = Color.black
2828
var isCircleScaled = false
2929
}
3030

3131
enum Action: Equatable, Sendable {
32-
case alertDismissed
32+
case alert(PresentationAction<Alert>)
3333
case circleScaleToggleChanged(Bool)
3434
case rainbowButtonTapped
3535
case resetButtonTapped
36-
case resetConfirmationButtonTapped
3736
case setColor(Color)
3837
case tapped(CGPoint)
38+
39+
enum Alert: Equatable, Sendable {
40+
case resetConfirmationButtonTapped
41+
}
3942
}
4043

4144
@Dependency(\.continuousClock) var clock
4245

43-
func reduce(into state: inout State, action: Action) -> Effect<Action> {
44-
enum CancelID { case rainbow }
46+
private enum CancelID { case rainbow }
4547

46-
switch action {
47-
case .alertDismissed:
48-
state.alert = nil
49-
return .none
48+
var body: some Reducer<State, Action> {
49+
Reduce { state, action in
50+
switch action {
51+
case .alert(.presented(.resetConfirmationButtonTapped)):
52+
state = State()
53+
return .cancel(id: CancelID.rainbow)
5054

51-
case let .circleScaleToggleChanged(isScaled):
52-
state.isCircleScaled = isScaled
53-
return .none
55+
case .alert:
56+
return .none
5457

55-
case .rainbowButtonTapped:
56-
return .run { send in
57-
for color in [Color.red, .blue, .green, .orange, .pink, .purple, .yellow, .black] {
58-
await send(.setColor(color), animation: .linear)
59-
try await self.clock.sleep(for: .seconds(1))
60-
}
61-
}
62-
.cancellable(id: CancelID.rainbow)
63-
64-
case .resetButtonTapped:
65-
state.alert = AlertState {
66-
TextState("Reset state?")
67-
} actions: {
68-
ButtonState(
69-
role: .destructive,
70-
action: .send(.resetConfirmationButtonTapped, animation: .default)
71-
) {
72-
TextState("Reset")
58+
case let .circleScaleToggleChanged(isScaled):
59+
state.isCircleScaled = isScaled
60+
return .none
61+
62+
case .rainbowButtonTapped:
63+
return .run { send in
64+
for color in [Color.red, .blue, .green, .orange, .pink, .purple, .yellow, .black] {
65+
await send(.setColor(color), animation: .linear)
66+
try await self.clock.sleep(for: .seconds(1))
67+
}
7368
}
74-
ButtonState(role: .cancel) {
75-
TextState("Cancel")
69+
.cancellable(id: CancelID.rainbow)
70+
71+
case .resetButtonTapped:
72+
state.alert = AlertState {
73+
TextState("Reset state?")
74+
} actions: {
75+
ButtonState(
76+
role: .destructive,
77+
action: .send(.resetConfirmationButtonTapped, animation: .default)
78+
) {
79+
TextState("Reset")
80+
}
81+
ButtonState(role: .cancel) {
82+
TextState("Cancel")
83+
}
7684
}
77-
}
78-
return .none
85+
return .none
7986

80-
case .resetConfirmationButtonTapped:
81-
state = State()
82-
return .cancel(id: CancelID.rainbow)
87+
case let .setColor(color):
88+
state.circleColor = color
89+
return .none
8390

84-
case let .setColor(color):
85-
state.circleColor = color
86-
return .none
87-
88-
case let .tapped(point):
89-
state.circleCenter = point
90-
return .none
91+
case let .tapped(point):
92+
state.circleCenter = point
93+
return .none
94+
}
9195
}
96+
.ifLet(\.$alert, action: /Action.alert)
9297
}
9398
}
9499

@@ -139,7 +144,7 @@ struct AnimationsView: View {
139144
Button("Reset") { viewStore.send(.resetButtonTapped) }
140145
.padding([.horizontal, .bottom])
141146
}
142-
.alert(self.store.scope(state: \.alert, action: { $0 }), dismiss: .alertDismissed)
147+
.alert(store: self.store.scope(state: \.$alert, action: { .alert($0) }))
143148
.navigationBarTitleDisplayMode(.inline)
144149
}
145150
}

0 commit comments

Comments
 (0)