Skip to content

Commit 7d33b2d

Browse files
mbrandonwp4checo
authored andcommitted
Use @StateObject for iOS 15+ alert modifier. (#1860)
(cherry picked from commit 6f33e07a7a3adba7a0f87c1361b19c4f96ef26f7) # Conflicts: # Sources/ComposableArchitecture/SwiftUI/Alert.swift # Sources/ComposableArchitecture/SwiftUI/ConfirmationDialog.swift
1 parent b6bc66e commit 7d33b2d

File tree

2 files changed

+117
-117
lines changed

2 files changed

+117
-117
lines changed
Lines changed: 52 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -1,66 +1,66 @@
11
#if canImport(SwiftUI)
2-
import SwiftUI
2+
import SwiftUI
33

4-
extension View {
5-
/// Displays an alert when then store's state becomes non-`nil`, and dismisses it when it becomes
6-
/// `nil`.
7-
///
8-
/// - Parameters:
9-
/// - store: A store that describes if the alert is shown or dismissed.
10-
/// - dismissal: An action to send when the alert is dismissed through non-user actions, such
11-
/// as when an alert is automatically dismissed by the system. Use this action to `nil` out
12-
/// the associated alert state.
13-
@ViewBuilder public func alert<Action>(
14-
_ store: Store<AlertState<Action>?, Action>,
15-
dismiss: Action
16-
) -> some View {
17-
if #available(iOS 15, macOS 12, tvOS 15, watchOS 8, *) {
18-
self.modifier(
19-
NewAlertModifier(
20-
viewStore: ViewStore(store, removeDuplicates: { $0?.id == $1?.id }),
21-
dismiss: dismiss
22-
)
4+
extension View {
5+
/// Displays an alert when then store's state becomes non-`nil`, and dismisses it when it becomes
6+
/// `nil`.
7+
///
8+
/// - Parameters:
9+
/// - store: A store that describes if the alert is shown or dismissed.
10+
/// - dismissal: An action to send when the alert is dismissed through non-user actions, such
11+
/// as when an alert is automatically dismissed by the system. Use this action to `nil` out
12+
/// the associated alert state.
13+
@ViewBuilder public func alert<Action>(
14+
_ store: Store<AlertState<Action>?, Action>,
15+
dismiss: Action
16+
) -> some View {
17+
if #available(iOS 15, macOS 12, tvOS 15, watchOS 8, *) {
18+
self.modifier(
19+
NewAlertModifier(
20+
viewStore: ViewStore(store, removeDuplicates: { $0?.id == $1?.id }),
21+
dismiss: dismiss
2322
)
24-
} else {
25-
self.modifier(
26-
OldAlertModifier(
27-
viewStore: ViewStore(store, removeDuplicates: { $0?.id == $1?.id }),
28-
dismiss: dismiss
29-
)
23+
)
24+
} else {
25+
self.modifier(
26+
OldAlertModifier(
27+
viewStore: ViewStore(store, removeDuplicates: { $0?.id == $1?.id }),
28+
dismiss: dismiss
3029
)
31-
}
30+
)
3231
}
3332
}
33+
}
3434

35-
// NB: Workaround for iOS 14 runtime crashes during iOS 15 availability checks.
36-
@available(iOS 15, macOS 12, tvOS 15, watchOS 8, *)
37-
private struct NewAlertModifier<Action>: ViewModifier {
38-
@ObservedObject var viewStore: ViewStore<AlertState<Action>?, Action>
39-
let dismiss: Action
35+
// NB: Workaround for iOS 14 runtime crashes during iOS 15 availability checks.
36+
@available(iOS 15, macOS 12, tvOS 15, watchOS 8, *)
37+
private struct NewAlertModifier<Action>: ViewModifier {
38+
@StateObject var viewStore: ViewStore<AlertState<Action>?, Action>
39+
let dismiss: Action
4040

41-
func body(content: Content) -> some View {
42-
content.alert(
43-
(viewStore.state?.title).map { Text($0) } ?? Text(""),
44-
isPresented: viewStore.binding(send: dismiss).isPresent(),
45-
presenting: viewStore.state,
46-
actions: {
47-
ForEach($0.buttons) {
48-
Button($0) { viewStore.send($0) }
49-
}
50-
},
51-
message: { $0.message.map { Text($0) } }
52-
)
53-
}
41+
func body(content: Content) -> some View {
42+
content.alert(
43+
(viewStore.state?.title).map { Text($0) } ?? Text(""),
44+
isPresented: viewStore.binding(send: dismiss).isPresent(),
45+
presenting: viewStore.state,
46+
actions: {
47+
ForEach($0.buttons) {
48+
Button($0) { viewStore.send($0) }
49+
}
50+
},
51+
message: { $0.message.map { Text($0) } }
52+
)
5453
}
54+
}
5555

56-
private struct OldAlertModifier<Action>: ViewModifier {
57-
@ObservedObject var viewStore: ViewStore<AlertState<Action>?, Action>
58-
let dismiss: Action
56+
private struct OldAlertModifier<Action>: ViewModifier {
57+
@ObservedObject var viewStore: ViewStore<AlertState<Action>?, Action>
58+
let dismiss: Action
5959

60-
func body(content: Content) -> some View {
61-
content.alert(item: viewStore.binding(send: dismiss)) { state in
62-
Alert(state) { viewStore.send($0) }
63-
}
60+
func body(content: Content) -> some View {
61+
content.alert(item: viewStore.binding(send: dismiss)) { state in
62+
Alert(state) { viewStore.send($0) }
6463
}
6564
}
65+
}
6666
#endif
Lines changed: 65 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -1,82 +1,82 @@
11
#if canImport(SwiftUI)
2-
import SwiftUI
2+
import SwiftUI
33

44
@available(iOS 13, macOS 10.15, macCatalyst 13, tvOS 13, watchOS 6, *)
5-
extension View {
6-
/// Displays a dialog when the store's state becomes non-`nil`, and dismisses it when it becomes
7-
/// `nil`.
8-
///
9-
/// - Parameters:
10-
/// - store: A store that describes if the dialog is shown or dismissed.
11-
/// - dismissal: An action to send when the dialog is dismissed through non-user actions, such
12-
/// as when a dialog is automatically dismissed by the system. Use this action to `nil` out
13-
/// the associated dialog state.
14-
@available(iOS 13, *)
15-
@available(macOS 12, *)
16-
@available(tvOS 13, *)
17-
@available(watchOS 6, *)
18-
@ViewBuilder public func confirmationDialog<Action>(
19-
_ store: Store<ConfirmationDialogState<Action>?, Action>,
20-
dismiss: Action
21-
) -> some View {
22-
if #available(iOS 15, tvOS 15, watchOS 8, *) {
5+
extension View {
6+
/// Displays a dialog when the store's state becomes non-`nil`, and dismisses it when it becomes
7+
/// `nil`.
8+
///
9+
/// - Parameters:
10+
/// - store: A store that describes if the dialog is shown or dismissed.
11+
/// - dismissal: An action to send when the dialog is dismissed through non-user actions, such
12+
/// as when a dialog is automatically dismissed by the system. Use this action to `nil` out
13+
/// the associated dialog state.
14+
@available(iOS 13, *)
15+
@available(macOS 12, *)
16+
@available(tvOS 13, *)
17+
@available(watchOS 6, *)
18+
@ViewBuilder public func confirmationDialog<Action>(
19+
_ store: Store<ConfirmationDialogState<Action>?, Action>,
20+
dismiss: Action
21+
) -> some View {
22+
if #available(iOS 15, tvOS 15, watchOS 8, *) {
23+
self.modifier(
24+
NewConfirmationDialogModifier(
25+
viewStore: ViewStore(store, removeDuplicates: { $0?.id == $1?.id }),
26+
dismiss: dismiss
27+
)
28+
)
29+
} else {
30+
#if !os(macOS)
2331
self.modifier(
24-
NewConfirmationDialogModifier(
32+
OldConfirmationDialogModifier(
2533
viewStore: ViewStore(store, removeDuplicates: { $0?.id == $1?.id }),
2634
dismiss: dismiss
2735
)
2836
)
29-
} else {
30-
#if !os(macOS)
31-
self.modifier(
32-
OldConfirmationDialogModifier(
33-
viewStore: ViewStore(store, removeDuplicates: { $0?.id == $1?.id }),
34-
dismiss: dismiss
35-
)
36-
)
37-
#endif
38-
}
37+
#endif
3938
}
4039
}
40+
}
4141

42-
// NB: Workaround for iOS 14 runtime crashes during iOS 15 availability checks.
43-
@available(iOS 15, macOS 12, tvOS 15, watchOS 8, *)
44-
private struct NewConfirmationDialogModifier<Action>: ViewModifier {
45-
@ObservedObject var viewStore: ViewStore<ConfirmationDialogState<Action>?, Action>
46-
let dismiss: Action
42+
// NB: Workaround for iOS 14 runtime crashes during iOS 15 availability checks.
43+
@available(iOS 15, macOS 12, tvOS 15, watchOS 8, *)
44+
private struct NewConfirmationDialogModifier<Action>: ViewModifier {
45+
@StateObject var viewStore: ViewStore<ConfirmationDialogState<Action>?, Action>
46+
let dismiss: Action
4747

48-
func body(content: Content) -> some View {
49-
content.confirmationDialog(
50-
(viewStore.state?.title).map { Text($0) } ?? Text(""),
51-
isPresented: viewStore.binding(send: dismiss).isPresent(),
52-
titleVisibility: viewStore.state.map { .init($0.titleVisibility) } ?? .automatic,
53-
presenting: viewStore.state,
54-
actions: {
55-
ForEach($0.buttons) {
56-
Button($0, action: { viewStore.send($0) })
57-
}
58-
},
59-
message: { $0.message.map { Text($0) } }
60-
)
61-
}
48+
func body(content: Content) -> some View {
49+
content.confirmationDialog(
50+
(viewStore.state?.title).map { Text($0) } ?? Text(""),
51+
isPresented: viewStore.binding(send: dismiss).isPresent(),
52+
titleVisibility: viewStore.state.map { .init($0.titleVisibility) } ?? .automatic,
53+
presenting: viewStore.state,
54+
actions: {
55+
ForEach($0.buttons) {
56+
Button($0, action: { viewStore.send($0) })
57+
}
58+
},
59+
message: { $0.message.map { Text($0) } }
60+
)
6261
}
62+
}
6363

64-
@available(iOS 13, *)
65-
@available(macOS 12, *)
66-
@available(tvOS 13, *)
67-
@available(watchOS 6, *)
68-
private struct OldConfirmationDialogModifier<Action>: ViewModifier {
69-
@ObservedObject var viewStore: ViewStore<ConfirmationDialogState<Action>?, Action>
70-
let dismiss: Action
64+
@available(iOS 13, *)
65+
@available(macOS 12, *)
66+
@available(tvOS 13, *)
67+
@available(watchOS 6, *)
68+
private struct OldConfirmationDialogModifier<Action>: ViewModifier {
69+
@ObservedObject var viewStore: ViewStore<ConfirmationDialogState<Action>?, Action>
70+
let dismiss: Action
7171

72-
func body(content: Content) -> some View {
73-
#if !os(macOS)
74-
return content.actionSheet(item: viewStore.binding(send: dismiss)) {
75-
ActionSheet($0) { viewStore.send($0) }
76-
}
77-
#else
78-
return EmptyView()
79-
#endif
80-
}
72+
func body(content: Content) -> some View {
73+
#if !os(macOS)
74+
return content.actionSheet(item: viewStore.binding(send: dismiss)) {
75+
ActionSheet($0) { viewStore.send($0) }
76+
}
77+
#else
78+
return EmptyView()
79+
#endif
8180
}
81+
}
8282
#endif

0 commit comments

Comments
 (0)