Skip to content

Commit 1df8ff9

Browse files
Generic alerts and action sheets (#201)
* alerts * wip * wip * wip * clean up * wip * wip * wip * wip * format * clean up * clean up * docs * wip * tests * API tweaks * Fix * More API changes * More API changes * More * Fix * Fix docs * Generic alerts optionality (#202) * Use Optional to model generic alerts * Xcode 12 * Refinement * update docs * Fix * Fix * doc fixes * rename * fixes * fixes Co-authored-by: Stephen Celis <[email protected]>
1 parent b01c81b commit 1df8ff9

File tree

68 files changed

+834
-339
lines changed

Some content is hidden

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

68 files changed

+834
-339
lines changed

.github/workflows/format.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,6 @@ jobs:
1818
- uses: stefanzweifel/git-auto-commit-action@v4
1919
with:
2020
commit_message: Run swift-format
21-
branch: 'master'
21+
branch: 'main'
2222
env:
2323
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

.swiftpm/xcode/xcshareddata/xcschemes/ComposableArchitecture.xcscheme

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
<?xml version="1.0" encoding="UTF-8"?>
22
<Scheme
3-
LastUpgradeVersion = "1140"
3+
LastUpgradeVersion = "1200"
44
version = "1.3">
55
<BuildAction
66
parallelizeBuildables = "YES"

.swiftpm/xcode/xcshareddata/xcschemes/ComposableCoreLocation.xcscheme

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
<?xml version="1.0" encoding="UTF-8"?>
22
<Scheme
3-
LastUpgradeVersion = "1140"
3+
LastUpgradeVersion = "1200"
44
version = "1.3">
55
<BuildAction
66
parallelizeBuildables = "YES"

.swiftpm/xcode/xcshareddata/xcschemes/ComposableCoreMotion.xcscheme

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
<?xml version="1.0" encoding="UTF-8"?>
22
<Scheme
3-
LastUpgradeVersion = "1150"
3+
LastUpgradeVersion = "1200"
44
version = "1.3">
55
<BuildAction
66
parallelizeBuildables = "YES"

Examples/CaseStudies/CaseStudies.xcodeproj/project.pbxproj

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,13 @@
77
objects = {
88

99
/* Begin PBXBuildFile section */
10-
CA0C51FB245389CC00A04EAB /* 04-HigherOrderReducers-ResuableOfflineDownloadsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = CA0C51FA245389CC00A04EAB /* 04-HigherOrderReducers-ResuableOfflineDownloadsTests.swift */; };
10+
CA0C51FB245389CC00A04EAB /* 04-HigherOrderReducers-ReusableOfflineDownloadsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = CA0C51FA245389CC00A04EAB /* 04-HigherOrderReducers-ReusableOfflineDownloadsTests.swift */; };
1111
CA25E5D224463AD700DA666A /* 01-GettingStarted-Bindings-Basics.swift in Sources */ = {isa = PBXBuildFile; fileRef = CA25E5D124463AD700DA666A /* 01-GettingStarted-Bindings-Basics.swift */; };
1212
CA27C0B7245780CE00CB1E59 /* 03-Effects-SystemEnvironment.swift in Sources */ = {isa = PBXBuildFile; fileRef = CA27C0B6245780CE00CB1E59 /* 03-Effects-SystemEnvironment.swift */; };
1313
CA34170824A4E89500FAF950 /* 01-GettingStarted-AnimationsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = CA34170724A4E89500FAF950 /* 01-GettingStarted-AnimationsTests.swift */; };
1414
CA410EE0247A15FE00E41798 /* 02-Effects-WebSocket.swift in Sources */ = {isa = PBXBuildFile; fileRef = CA410EDF247A15FE00E41798 /* 02-Effects-WebSocket.swift */; };
1515
CA410EE2247C73B400E41798 /* 02-Effects-WebSocketTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = CA410EE1247C73B400E41798 /* 02-Effects-WebSocketTests.swift */; };
16+
CA50BE6024A8F46500FE7DBA /* 01-GettingStarted-AlertsAndActionSheetsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = CA50BE5F24A8F46500FE7DBA /* 01-GettingStarted-AlertsAndActionSheetsTests.swift */; };
1617
CA6AC2642451135C00C71CB3 /* ReusableComponents-Download.swift in Sources */ = {isa = PBXBuildFile; fileRef = CA6AC2602451135C00C71CB3 /* ReusableComponents-Download.swift */; };
1718
CA6AC2652451135C00C71CB3 /* CircularProgressView.swift in Sources */ = {isa = PBXBuildFile; fileRef = CA6AC2612451135C00C71CB3 /* CircularProgressView.swift */; };
1819
CA6AC2662451135C00C71CB3 /* DownloadComponent.swift in Sources */ = {isa = PBXBuildFile; fileRef = CA6AC2622451135C00C71CB3 /* DownloadComponent.swift */; };
@@ -24,6 +25,7 @@
2425
CAA9ADC824465D950003A984 /* 02-Effects-CancellationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = CAA9ADC724465D950003A984 /* 02-Effects-CancellationTests.swift */; };
2526
CAA9ADCA2446605B0003A984 /* 02-Effects-LongLiving.swift in Sources */ = {isa = PBXBuildFile; fileRef = CAA9ADC92446605B0003A984 /* 02-Effects-LongLiving.swift */; };
2627
CAA9ADCC2446615B0003A984 /* 02-Effects-LongLivingTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = CAA9ADCB2446615B0003A984 /* 02-Effects-LongLivingTests.swift */; };
28+
CAE962FD24A7F7BE00EFC025 /* 01-GettingStarted-AlertsAndActionSheets.swift in Sources */ = {isa = PBXBuildFile; fileRef = CAE962FC24A7F7BE00EFC025 /* 01-GettingStarted-AlertsAndActionSheets.swift */; };
2729
DC07231724465D1E003A8B65 /* 02-Effects-TimersTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = DC07231624465D1E003A8B65 /* 02-Effects-TimersTests.swift */; };
2830
DC072322244663B1003A8B65 /* 03-Navigation-Sheet-LoadThenPresent.swift in Sources */ = {isa = PBXBuildFile; fileRef = DC072321244663B1003A8B65 /* 03-Navigation-Sheet-LoadThenPresent.swift */; };
2931
DC13940E2469E25C00EE1157 /* ComposableArchitecture in Frameworks */ = {isa = PBXBuildFile; productRef = DC13940D2469E25C00EE1157 /* ComposableArchitecture */; };
@@ -125,12 +127,13 @@
125127
/* End PBXCopyFilesBuildPhase section */
126128

127129
/* Begin PBXFileReference section */
128-
CA0C51FA245389CC00A04EAB /* 04-HigherOrderReducers-ResuableOfflineDownloadsTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "04-HigherOrderReducers-ResuableOfflineDownloadsTests.swift"; sourceTree = "<group>"; };
130+
CA0C51FA245389CC00A04EAB /* 04-HigherOrderReducers-ReusableOfflineDownloadsTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "04-HigherOrderReducers-ReusableOfflineDownloadsTests.swift"; sourceTree = "<group>"; };
129131
CA25E5D124463AD700DA666A /* 01-GettingStarted-Bindings-Basics.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "01-GettingStarted-Bindings-Basics.swift"; sourceTree = "<group>"; };
130132
CA27C0B6245780CE00CB1E59 /* 03-Effects-SystemEnvironment.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "03-Effects-SystemEnvironment.swift"; sourceTree = "<group>"; };
131133
CA34170724A4E89500FAF950 /* 01-GettingStarted-AnimationsTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "01-GettingStarted-AnimationsTests.swift"; sourceTree = "<group>"; };
132134
CA410EDF247A15FE00E41798 /* 02-Effects-WebSocket.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "02-Effects-WebSocket.swift"; sourceTree = "<group>"; };
133135
CA410EE1247C73B400E41798 /* 02-Effects-WebSocketTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "02-Effects-WebSocketTests.swift"; sourceTree = "<group>"; };
136+
CA50BE5F24A8F46500FE7DBA /* 01-GettingStarted-AlertsAndActionSheetsTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "01-GettingStarted-AlertsAndActionSheetsTests.swift"; sourceTree = "<group>"; };
134137
CA6AC2602451135C00C71CB3 /* ReusableComponents-Download.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "ReusableComponents-Download.swift"; sourceTree = "<group>"; };
135138
CA6AC2612451135C00C71CB3 /* CircularProgressView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CircularProgressView.swift; sourceTree = "<group>"; };
136139
CA6AC2622451135C00C71CB3 /* DownloadComponent.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DownloadComponent.swift; sourceTree = "<group>"; };
@@ -142,6 +145,7 @@
142145
CAA9ADC724465D950003A984 /* 02-Effects-CancellationTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "02-Effects-CancellationTests.swift"; sourceTree = "<group>"; };
143146
CAA9ADC92446605B0003A984 /* 02-Effects-LongLiving.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "02-Effects-LongLiving.swift"; sourceTree = "<group>"; };
144147
CAA9ADCB2446615B0003A984 /* 02-Effects-LongLivingTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "02-Effects-LongLivingTests.swift"; sourceTree = "<group>"; };
148+
CAE962FC24A7F7BE00EFC025 /* 01-GettingStarted-AlertsAndActionSheets.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "01-GettingStarted-AlertsAndActionSheets.swift"; sourceTree = "<group>"; };
145149
DC07231624465D1E003A8B65 /* 02-Effects-TimersTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "02-Effects-TimersTests.swift"; sourceTree = "<group>"; };
146150
DC072321244663B1003A8B65 /* 03-Navigation-Sheet-LoadThenPresent.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "03-Navigation-Sheet-LoadThenPresent.swift"; sourceTree = "<group>"; };
147151
DC25DC5E2450F13200082E81 /* IfLetStoreController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IfLetStoreController.swift; sourceTree = "<group>"; };
@@ -308,6 +312,7 @@
308312
children = (
309313
DC89C42424460F96006900B9 /* Info.plist */,
310314
DC89C41A24460F95006900B9 /* 00-RootView.swift */,
315+
CAE962FC24A7F7BE00EFC025 /* 01-GettingStarted-AlertsAndActionSheets.swift */,
311316
DC88D8A5245341EC0077F427 /* 01-GettingStarted-Animations.swift */,
312317
CA25E5D124463AD700DA666A /* 01-GettingStarted-Bindings-Basics.swift */,
313318
DCC68EE02447C4630037F998 /* 01-GettingStarted-Composition-TwoCounters.swift */,
@@ -341,14 +346,15 @@
341346
DC89C42C24460F96006900B9 /* SwiftUICaseStudiesTests */ = {
342347
isa = PBXGroup;
343348
children = (
349+
CA50BE5F24A8F46500FE7DBA /* 01-GettingStarted-AlertsAndActionSheetsTests.swift */,
344350
CA34170724A4E89500FAF950 /* 01-GettingStarted-AnimationsTests.swift */,
345351
CAA9ADC324465AB00003A984 /* 02-Effects-BasicsTests.swift */,
346352
CAA9ADC724465D950003A984 /* 02-Effects-CancellationTests.swift */,
347353
CAA9ADCB2446615B0003A984 /* 02-Effects-LongLivingTests.swift */,
348354
DC07231624465D1E003A8B65 /* 02-Effects-TimersTests.swift */,
349355
CA410EE1247C73B400E41798 /* 02-Effects-WebSocketTests.swift */,
350-
CA0C51FA245389CC00A04EAB /* 04-HigherOrderReducers-ResuableOfflineDownloadsTests.swift */,
351356
DC634B242448D15B00DAA016 /* 04-HigherOrderReducers-ReusableFavoritingTests.swift */,
357+
CA0C51FA245389CC00A04EAB /* 04-HigherOrderReducers-ReusableOfflineDownloadsTests.swift */,
352358
);
353359
path = SwiftUICaseStudiesTests;
354360
sourceTree = "<group>";
@@ -465,7 +471,7 @@
465471
isa = PBXProject;
466472
attributes = {
467473
LastSwiftUpdateCheck = 1140;
468-
LastUpgradeCheck = 1140;
474+
LastUpgradeCheck = 1200;
469475
ORGANIZATIONNAME = "Point-Free";
470476
TargetAttributes = {
471477
DC4C6EA62450DD380066A05D = {
@@ -589,6 +595,7 @@
589595
DC89C41B24460F95006900B9 /* 00-RootView.swift in Sources */,
590596
DCC68EDD2447A5B00037F998 /* 01-GettingStarted-OptionalState.swift in Sources */,
591597
DCC68EAB244666AF0037F998 /* 03-Navigation-Sheet-PresentAndLoad.swift in Sources */,
598+
CAE962FD24A7F7BE00EFC025 /* 01-GettingStarted-AlertsAndActionSheets.swift in Sources */,
592599
CA25E5D224463AD700DA666A /* 01-GettingStarted-Bindings-Basics.swift in Sources */,
593600
DC88D8A6245341EC0077F427 /* 01-GettingStarted-Animations.swift in Sources */,
594601
DC89C44D244621A5006900B9 /* 03-Navigation-NavigateAndLoad.swift in Sources */,
@@ -607,12 +614,13 @@
607614
isa = PBXSourcesBuildPhase;
608615
buildActionMask = 2147483647;
609616
files = (
610-
CA0C51FB245389CC00A04EAB /* 04-HigherOrderReducers-ResuableOfflineDownloadsTests.swift in Sources */,
617+
CA0C51FB245389CC00A04EAB /* 04-HigherOrderReducers-ReusableOfflineDownloadsTests.swift in Sources */,
611618
DC634B252448D15B00DAA016 /* 04-HigherOrderReducers-ReusableFavoritingTests.swift in Sources */,
612619
CAA9ADC824465D950003A984 /* 02-Effects-CancellationTests.swift in Sources */,
613620
CA410EE2247C73B400E41798 /* 02-Effects-WebSocketTests.swift in Sources */,
614621
CA34170824A4E89500FAF950 /* 01-GettingStarted-AnimationsTests.swift in Sources */,
615622
DC07231724465D1E003A8B65 /* 02-Effects-TimersTests.swift in Sources */,
623+
CA50BE6024A8F46500FE7DBA /* 01-GettingStarted-AlertsAndActionSheetsTests.swift in Sources */,
616624
CAA9ADC424465AB00003A984 /* 02-Effects-BasicsTests.swift in Sources */,
617625
CAA9ADCC2446615B0003A984 /* 02-Effects-LongLivingTests.swift in Sources */,
618626
);

Examples/CaseStudies/CaseStudies.xcodeproj/xcshareddata/xcschemes/CaseStudies (SwiftUI).xcscheme

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
<?xml version="1.0" encoding="UTF-8"?>
22
<Scheme
3-
LastUpgradeVersion = "1140"
3+
LastUpgradeVersion = "1200"
44
version = "1.3">
55
<BuildAction
66
parallelizeBuildables = "YES"

Examples/CaseStudies/CaseStudies.xcodeproj/xcshareddata/xcschemes/CaseStudies (UIKit).xcscheme

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
<?xml version="1.0" encoding="UTF-8"?>
22
<Scheme
3-
LastUpgradeVersion = "1140"
3+
LastUpgradeVersion = "1200"
44
version = "1.3">
55
<BuildAction
66
parallelizeBuildables = "YES"

Examples/CaseStudies/SwiftUICaseStudies/00-RootView.swift

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,17 @@ struct RootView: View {
6363
)
6464
)
6565

66+
NavigationLink(
67+
"Alerts and Action Sheets",
68+
destination: AlertAndSheetView(
69+
store: .init(
70+
initialState: .init(),
71+
reducer: alertAndSheetReducer,
72+
environment: .init()
73+
)
74+
)
75+
)
76+
6677
NavigationLink(
6778
"Animations",
6879
destination: AnimationsView(
Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
import ComposableArchitecture
2+
import SwiftUI
3+
4+
private let readMe = """
5+
This demonstrates how to best handle alerts and action sheets in the Composable Architecture.
6+
7+
Because the library demands that all data flow through the application in a single direction, we \
8+
cannot leverage SwiftUI's two-way bindings because they can make changes to state without going \
9+
through a reducer. This means we can't directly use the standard API to display alerts and sheets.
10+
11+
However, the library comes with two types, `AlertState` and `ActionSheetState`, which can be \
12+
constructed from reducers and control whether or not an alert or action sheet is displayed. \
13+
Further, it automatically handles sending actions when you tap their buttons, which allows you \
14+
to properly handle their functionality in the reducer rather than in two-way bindings and action \
15+
closures.
16+
17+
The benefit of doing this is that you can get full test coverage on how a user interacts with \
18+
with alerts and action sheets in your application
19+
"""
20+
21+
struct AlertAndSheetState: Equatable {
22+
var actionSheet: ActionSheetState<AlertAndSheetAction>?
23+
var alert: AlertState<AlertAndSheetAction>?
24+
var count = 0
25+
}
26+
27+
enum AlertAndSheetAction: Equatable {
28+
case actionSheetButtonTapped
29+
case actionSheetCancelTapped
30+
case alertButtonTapped
31+
case alertCancelTapped
32+
case decrementButtonTapped
33+
case incrementButtonTapped
34+
}
35+
36+
struct AlertAndSheetEnvironment {}
37+
38+
let alertAndSheetReducer = Reducer<
39+
AlertAndSheetState, AlertAndSheetAction, AlertAndSheetEnvironment
40+
> { state, action, _ in
41+
42+
switch action {
43+
case .actionSheetButtonTapped:
44+
state.actionSheet = .init(
45+
title: "Action sheet",
46+
message: "This is an action sheet.",
47+
buttons: [
48+
.cancel(),
49+
.default("Increment", send: .incrementButtonTapped),
50+
.default("Decrement", send: .decrementButtonTapped),
51+
]
52+
)
53+
return .none
54+
55+
case .actionSheetCancelTapped:
56+
state.actionSheet = nil
57+
return .none
58+
59+
case .alertButtonTapped:
60+
state.alert = .init(
61+
title: "Alert!",
62+
message: "This is an alert",
63+
primaryButton: .cancel(),
64+
secondaryButton: .default("Increment", send: .incrementButtonTapped)
65+
)
66+
return .none
67+
68+
case .alertCancelTapped:
69+
state.alert = nil
70+
return .none
71+
72+
case .decrementButtonTapped:
73+
state.actionSheet = nil
74+
state.count -= 1
75+
return .none
76+
77+
case .incrementButtonTapped:
78+
state.actionSheet = nil
79+
state.alert = nil
80+
state.count += 1
81+
return .none
82+
}
83+
}
84+
85+
struct AlertAndSheetView: View {
86+
let store: Store<AlertAndSheetState, AlertAndSheetAction>
87+
88+
var body: some View {
89+
WithViewStore(self.store) { viewStore in
90+
Form {
91+
Section(header: Text(template: readMe, .caption)) {
92+
Text("Count: \(viewStore.count)")
93+
94+
Button("Alert") { viewStore.send(.alertButtonTapped) }
95+
.alert(
96+
self.store.scope(state: { $0.alert }),
97+
dismiss: .alertCancelTapped
98+
)
99+
100+
Button("Action sheet") { viewStore.send(.actionSheetButtonTapped) }
101+
.actionSheet(
102+
self.store.scope(state: { $0.actionSheet }),
103+
dismiss: .actionSheetCancelTapped
104+
)
105+
}
106+
}
107+
}
108+
.navigationBarTitle("Alerts & Action Sheets")
109+
}
110+
}
111+
112+
struct AlertAndSheet_Previews: PreviewProvider {
113+
static var previews: some View {
114+
NavigationView {
115+
AlertAndSheetView(
116+
store: .init(
117+
initialState: .init(),
118+
reducer: alertAndSheetReducer,
119+
environment: .init()
120+
)
121+
)
122+
}
123+
}
124+
}

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

Lines changed: 7 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ struct SharedState: Equatable {
2121
enum Tab { case counter, profile }
2222

2323
struct CounterState: Equatable {
24-
var alert: String?
24+
var alert: AlertState<SharedStateAction.CounterAction>?
2525
var count = 0
2626
var maxCount = 0
2727
var minCount = 0
@@ -105,10 +105,11 @@ let sharedStateCounterReducer = Reducer<
105105
return .none
106106

107107
case .isPrimeButtonTapped:
108-
state.alert =
109-
isPrime(state.count)
110-
? "👍 The number \(state.count) is prime!"
111-
: "👎 The number \(state.count) is not prime :("
108+
state.alert = .init(
109+
title: isPrime(state.count)
110+
? "👍 The number \(state.count) is prime!"
111+
: "👎 The number \(state.count) is not prime :("
112+
)
112113
return .none
113114
}
114115
}
@@ -204,14 +205,7 @@ struct SharedStateCounterView: View {
204205
.padding(16)
205206
.frame(minWidth: 0, maxWidth: .infinity, minHeight: 0, maxHeight: .infinity, alignment: .top)
206207
.navigationBarTitle("Shared State Demo")
207-
.alert(
208-
item: viewStore.binding(
209-
get: { $0.alert.map(PrimeAlert.init(title:)) },
210-
send: .alertDismissed
211-
)
212-
) { alert in
213-
SwiftUI.Alert(title: Text(alert.title))
214-
}
208+
.alert(self.store.scope(state: { $0.alert }), dismiss: .alertDismissed)
215209
}
216210
}
217211
}
@@ -249,11 +243,6 @@ struct SharedStateProfileView: View {
249243
}
250244
}
251245

252-
private struct PrimeAlert: Equatable, Identifiable {
253-
let title: String
254-
var id: String { self.title }
255-
}
256-
257246
// MARK: - SwiftUI previews
258247

259248
struct SharedState_Previews: PreviewProvider {

0 commit comments

Comments
 (0)