Skip to content

Commit b84f736

Browse files
committed
Checkpoint action handlers
1 parent 41eabed commit b84f736

File tree

3 files changed

+51
-5
lines changed

3 files changed

+51
-5
lines changed

CHANGELOG

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,10 @@
22

33
### 0.9.22
44

5+
* Added support for optional action handlers to checkpoints
56
* Updated documentation on Navigation Trees
67
* Update app dependencies protocol
8+
* Merge initial unit tests PR #29
79
* Merge minor fixes from PR #28
810
* Fixes some warnings in code
911

NavigatorDemo/NavigatorDemo/NavigatorDemo/Features/Home/HomeView.swift

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -134,7 +134,10 @@ struct HomePage2View: View {
134134
ContentPopSection()
135135
}
136136
.navigationCheckpoint(.page2)
137-
.navigationCheckpoint(.duplicate)
137+
// shows a checkpoint with an action handler triggered on return
138+
.navigationCheckpoint(.duplicate) {
139+
print("DUPLICATE ACTION")
140+
}
138141
// .navigationCheckpoint(.page2, position: 1)
139142
.navigationTitle(viewModel.title)
140143
}

Sources/Navigator/Navigator/Core/NavigationCheckpoint.swift

Lines changed: 45 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -177,6 +177,11 @@ extension NavigationState {
177177
log("Navigator returning to checkpoint: \(checkpoint.name)")
178178
_ = navigator.dismissAll()
179179
_ = navigator.pop(to: found.index)
180+
// send trigger to specific action handler
181+
if let identifier = found.identifier {
182+
let values = NavigationSendValues(navigator: Navigator(state: self), identifier: identifier, value: CheckpointAction())
183+
publisher.send(values)
184+
}
180185
}
181186

182187
internal func returnToCheckpoint<T: Hashable>(_ checkpoint: NavigationCheckpoint, value: T) {
@@ -186,14 +191,14 @@ extension NavigationState {
186191
return
187192
}
188193
log("Navigator returning to checkpoint: \(checkpoint.name) value: \(value)")
194+
// return to sender
195+
_ = navigator.dismissAll()
196+
_ = navigator.pop(to: found.index)
189197
// send value to specific receive handler
190198
if let identifier = found.identifier {
191199
let values = NavigationSendValues(navigator: Navigator(state: self), identifier: identifier, value: value)
192200
publisher.send(values)
193201
}
194-
// return to sender
195-
_ = navigator.dismissAll()
196-
_ = navigator.pop(to: found.index)
197202
}
198203

199204
internal nonisolated func canReturnToCheckpoint(_ checkpoint: NavigationCheckpoint) -> Bool {
@@ -245,7 +250,16 @@ extension View {
245250
self.modifier(NavigationCheckpointModifier(checkpoint: checkpoint.setting(index: position)))
246251
}
247252

248-
/// Establishes a navigation checkpoint with a completion handler.
253+
/// Establishes a navigation checkpoint with an action handler fired on return.
254+
public func navigationCheckpoint(
255+
_ checkpoint: NavigationCheckpoint,
256+
position: Int = 0,
257+
action: @escaping () -> Void
258+
) -> some View {
259+
self.modifier(NavigationCheckpointActionModifier(checkpoint: checkpoint.setting(index: position), action: action))
260+
}
261+
262+
/// Establishes a navigation checkpoint with a completion handler that accepts a return value.
249263
public func navigationCheckpoint<T: Hashable>(
250264
_ checkpoint: NavigationCheckpoint,
251265
position: Int = 0,
@@ -293,6 +307,33 @@ private struct NavigationCheckpointModifier: ViewModifier {
293307
}
294308
}
295309

310+
private struct CheckpointAction: Hashable {}
311+
312+
private struct NavigationCheckpointActionModifier: ViewModifier {
313+
@State internal var checkpoint: NavigationCheckpoint
314+
internal let action: () -> Void
315+
@Environment(\.navigator) private var navigator: Navigator
316+
init(
317+
checkpoint: NavigationCheckpoint,
318+
action: @escaping () -> Void
319+
) {
320+
self.checkpoint = checkpoint
321+
.setting(identifier: checkpoint.identifier ?? UUID().uuidString)
322+
self.action = action
323+
}
324+
func body(content: Content) -> some View {
325+
content
326+
.onReceive(navigator.state.publisher) { values in
327+
if let _: CheckpointAction = values.consume(checkpoint.identifier) {
328+
navigator.log("Navigator processing checkpoint action: \(checkpoint.name)")
329+
action()
330+
values.resume(.auto)
331+
}
332+
}
333+
.navigationCheckpoint(checkpoint)
334+
}
335+
}
336+
296337
private struct NavigationCheckpointValueModifier<T: Hashable>: ViewModifier {
297338
@State internal var checkpoint: NavigationCheckpoint
298339
internal let completion: (T) -> Void

0 commit comments

Comments
 (0)