Skip to content

Commit 4569fcc

Browse files
committed
Merge remote-tracking branch 'origin/navigation-beta' into prerelease/1.0
2 parents 6ab036a + 4274c83 commit 4569fcc

File tree

5 files changed

+97
-85
lines changed

5 files changed

+97
-85
lines changed

ComposableArchitecture.xcworkspace/xcshareddata/swiftpm/Package.resolved

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

Package.swift

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ let package = Package(
2525
.package(url: "https://github.com/pointfreeco/swift-custom-dump", from: "0.9.1"),
2626
.package(url: "https://github.com/pointfreeco/swift-dependencies", from: "0.2.0"),
2727
.package(url: "https://github.com/pointfreeco/swift-identified-collections", from: "0.7.0"),
28-
.package(url: "https://github.com/pointfreeco/swiftui-navigation", from: "0.7.0"),
28+
.package(url: "https://github.com/pointfreeco/swiftui-navigation", from: "0.7.1"),
2929
.package(url: "https://github.com/pointfreeco/xctest-dynamic-overlay", from: "0.8.4"),
3030
],
3131
targets: [
@@ -39,6 +39,7 @@ let package = Package(
3939
.product(name: "IdentifiedCollections", package: "swift-identified-collections"),
4040
.product(name: "OrderedCollections", package: "swift-collections"),
4141
.product(name: "_SwiftUINavigationState", package: "swiftui-navigation"),
42+
.product(name: "SwiftUINavigation", package: "swiftui-navigation"),
4243
.product(name: "XCTestDynamicOverlay", package: "xctest-dynamic-overlay"),
4344
]
4445
),

Sources/ComposableArchitecture/SwiftUI/ConfirmationDialog.swift

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -90,21 +90,25 @@ private struct NewConfirmationDialogModifier<Action>: ViewModifier {
9090
}
9191

9292
@available(iOS 13, *)
93-
@available(macOS, unavailable)
93+
@available(macOS 12, *)
9494
@available(tvOS 13, *)
9595
@available(watchOS 6, *)
9696
private struct OldConfirmationDialogModifier<Action>: ViewModifier {
9797
@ObservedObject var viewStore: ViewStore<ConfirmationDialogState<Action>?, Action>
9898
let dismiss: Action
9999

100100
func body(content: Content) -> some View {
101-
content.actionSheet(item: viewStore.binding(send: dismiss)) {
102-
ActionSheet($0) { action in
103-
if let action = action {
104-
viewStore.send(action)
101+
#if !os(macOS)
102+
content.actionSheet(item: viewStore.binding(send: dismiss)) {
103+
ActionSheet($0) { action in
104+
if let action = action {
105+
viewStore.send(action)
106+
}
105107
}
106108
}
107-
}
109+
#else
110+
EmptyView()
111+
#endif
108112
}
109113
}
110114

Lines changed: 82 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -1,86 +1,93 @@
11
import SwiftUI
2+
import SwiftUINavigation
23

3-
#if swift(>=5.7)
4-
extension View {
5-
@available(iOS 16, macOS 13, tvOS 16, watchOS 9, *)
6-
public func navigationDestination<State, Action, Destination: View>(
7-
store: Store<PresentationState<State>, PresentationAction<Action>>,
8-
@ViewBuilder destination: @escaping (Store<State, Action>) -> Destination
9-
) -> some View {
10-
self.navigationDestination(
11-
store: store, state: { $0 }, action: { $0 }, destination: destination
12-
)
13-
}
4+
extension View {
5+
@available(iOS 16, macOS 13, tvOS 16, watchOS 9, *)
6+
public func navigationDestination<State, Action, Destination: View>(
7+
store: Store<PresentationState<State>, PresentationAction<Action>>,
8+
@ViewBuilder destination: @escaping (Store<State, Action>) -> Destination
9+
) -> some View {
10+
self.navigationDestination(
11+
store: store, state: { $0 }, action: { $0 }, destination: destination
12+
)
13+
}
1414

15-
@available(iOS 16, macOS 13, tvOS 16, watchOS 9, *)
16-
public func navigationDestination<
17-
State, Action, DestinationState, DestinationAction, Destination: View
18-
>(
19-
store: Store<PresentationState<State>, PresentationAction<Action>>,
20-
state toDestinationState: @escaping (State) -> DestinationState?,
21-
action fromDestinationAction: @escaping (DestinationAction) -> Action,
22-
@ViewBuilder destination: @escaping (Store<DestinationState, DestinationAction>) ->
23-
Destination
24-
) -> some View {
25-
self.modifier(
26-
PresentationNavigationDestinationModifier(
27-
store: store,
28-
state: toDestinationState,
29-
action: fromDestinationAction,
30-
content: destination
31-
)
15+
@available(iOS 16, macOS 13, tvOS 16, watchOS 9, *)
16+
public func navigationDestination<
17+
State, Action, DestinationState, DestinationAction, Destination: View
18+
>(
19+
store: Store<PresentationState<State>, PresentationAction<Action>>,
20+
state toDestinationState: @escaping (State) -> DestinationState?,
21+
action fromDestinationAction: @escaping (DestinationAction) -> Action,
22+
@ViewBuilder destination: @escaping (Store<DestinationState, DestinationAction>) ->
23+
Destination
24+
) -> some View {
25+
self.modifier(
26+
PresentationNavigationDestinationModifier(
27+
store: store,
28+
state: toDestinationState,
29+
action: fromDestinationAction,
30+
content: destination
3231
)
33-
}
32+
)
3433
}
34+
}
3535

36-
@available(iOS 16, macOS 13, tvOS 16, watchOS 9, *)
37-
private struct PresentationNavigationDestinationModifier<
38-
State,
39-
Action,
40-
DestinationState,
41-
DestinationAction,
42-
DestinationContent: View
43-
>: ViewModifier {
44-
let store: Store<PresentationState<State>, PresentationAction<Action>>
45-
@StateObject var viewStore: ViewStore<Bool, PresentationAction<Action>>
46-
let toDestinationState: (State) -> DestinationState?
47-
let fromDestinationAction: (DestinationAction) -> Action
48-
let destinationContent: (Store<DestinationState, DestinationAction>) -> DestinationContent
36+
@available(iOS 16, macOS 13, tvOS 16, watchOS 9, *)
37+
private struct PresentationNavigationDestinationModifier<
38+
State,
39+
Action,
40+
DestinationState,
41+
DestinationAction,
42+
DestinationContent: View
43+
>: ViewModifier {
44+
let store: Store<PresentationState<State>, PresentationAction<Action>>
45+
@StateObject var viewStore: ViewStore<Bool, PresentationAction<Action>>
46+
let toDestinationState: (State) -> DestinationState?
47+
let fromDestinationAction: (DestinationAction) -> Action
48+
let destinationContent: (Store<DestinationState, DestinationAction>) -> DestinationContent
4949

50-
init(
51-
store: Store<PresentationState<State>, PresentationAction<Action>>,
52-
state toDestinationState: @escaping (State) -> DestinationState?,
53-
action fromDestinationAction: @escaping (DestinationAction) -> Action,
54-
content destinationContent:
55-
@escaping (Store<DestinationState, DestinationAction>) -> DestinationContent
56-
) {
57-
self.store = store
58-
self._viewStore = StateObject(
59-
wrappedValue: ViewStore(
60-
store
61-
.filterSend { state, _ in state.wrappedValue != nil }
62-
.scope(state: { $0.wrappedValue.flatMap(toDestinationState) != nil }),
63-
observe: { $0 }
64-
)
50+
init(
51+
store: Store<PresentationState<State>, PresentationAction<Action>>,
52+
state toDestinationState: @escaping (State) -> DestinationState?,
53+
action fromDestinationAction: @escaping (DestinationAction) -> Action,
54+
content destinationContent:
55+
@escaping (Store<DestinationState, DestinationAction>) -> DestinationContent
56+
) {
57+
self.store = store
58+
self._viewStore = StateObject(
59+
wrappedValue: ViewStore(
60+
store
61+
.filterSend { state, _ in state.wrappedValue != nil }
62+
.scope(state: { $0.wrappedValue.flatMap(toDestinationState) != nil })
6563
)
66-
self.toDestinationState = toDestinationState
67-
self.fromDestinationAction = fromDestinationAction
68-
self.destinationContent = destinationContent
69-
}
64+
)
65+
self.toDestinationState = toDestinationState
66+
self.fromDestinationAction = fromDestinationAction
67+
self.destinationContent = destinationContent
68+
}
7069

71-
func body(content: Content) -> some View {
72-
content.navigationDestination(
73-
// TODO: do binding with ID check
74-
isPresented: self.viewStore.binding(send: .dismiss)
75-
) {
76-
IfLetStore(
77-
self.store.scope(
78-
state: returningLastNonNilValue { $0.wrappedValue.flatMap(self.toDestinationState) },
79-
action: { .presented(self.fromDestinationAction($0)) }
80-
),
81-
then: self.destinationContent
82-
)
83-
}
70+
func body(content: Content) -> some View {
71+
content.navigationDestination(
72+
// TODO: do binding with ID check
73+
unwrapping: self.viewStore.binding(send: .dismiss).presence
74+
) { _ in
75+
IfLetStore(
76+
self.store.scope(
77+
state: returningLastNonNilValue { $0.wrappedValue.flatMap(self.toDestinationState) },
78+
action: { .presented(self.fromDestinationAction($0)) }
79+
),
80+
then: self.destinationContent
81+
)
8482
}
8583
}
86-
#endif
84+
}
85+
86+
fileprivate extension Binding where Value == Bool {
87+
var presence: Binding<Void?> {
88+
.init(
89+
get: { self.wrappedValue ? () : nil },
90+
set: { self.transaction($1).wrappedValue = $0 != nil }
91+
)
92+
}
93+
}

Sources/ComposableArchitecture/SwiftUI/NavigationLinkStore.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ public struct NavigationLinkStore<
4242
public init(
4343
_ store: Store<PresentationState<State>, PresentationAction<Action>>,
4444
state toDestinationState: @escaping (State) -> DestinationState?,
45-
onTap fromDestinationAction: @escaping (DestinationAction) -> Action,
45+
action fromDestinationAction: @escaping (DestinationAction) -> Action,
4646
onTap: @escaping () -> Void,
4747
@ViewBuilder destination: @escaping (Store<DestinationState, DestinationAction>) -> Destination,
4848
@ViewBuilder label: () -> Label

0 commit comments

Comments
 (0)