Skip to content

Instantly share code, notes, and snippets.

@gkaimakas
Created December 11, 2022 21:46
Show Gist options
  • Save gkaimakas/7c12a596826a6d4c277e067a11ed88fb to your computer and use it in GitHub Desktop.
Save gkaimakas/7c12a596826a6d4c277e067a11ed88fb to your computer and use it in GitHub Desktop.
NavigationStack + ComposableArchitecture
import Foundation
public enum NavigationStackAction<View> where View: Equatable & Hashable & Codable {
case stackChanged([View])
case destinationRemoved(View)
}
import ComposableArchitecture
public func NavigationStackScope<
ParentState,
ParentAction,
View: Equatable & Hashable & Codable
>(
state toNavigationState: WritableKeyPath<ParentState, NavigationStackState<View>>,
action toChildAction: CasePath<ParentAction, NavigationStackAction<View>>
) -> Scope<ParentState, ParentAction, NavigationStackReducer<View>> {
Scope(
state: toNavigationState,
action: toChildAction,
NavigationStackReducer.init
)
}
import Foundation
public struct NavigationStackState<View> where View: Equatable & Hashable & Codable {
public var stack: [View]
public init() {
stack = []
}
public init(stack: [View]) {
self.stack = stack
}
}
extension NavigationStackState:
Equatable,
Hashable,
Codable {
}
import ComposableArchitecture
import Foundation
public struct NavigationStackReducer<View: Equatable & Hashable & Codable>: ReducerProtocol {
public typealias State = NavigationStackState<View>
public typealias Action = NavigationStackAction<View>
public var body: some ReducerProtocol<State, Action> {
Reduce(_reduce(into:action:))
}
public init() {}
func _reduce(
into state: inout State,
action: Action
) -> EffectTask<Action> {
switch action {
case let .stackChanged(newStack):
let oldStack = state.stack
state.stack = newStack
let effects = newStack
.difference(from: oldStack)
.removals
.compactMap(toRemovedElementEffect)
return .concatenate(effects)
case .destinationRemoved:
break
}
return .none
}
func toRemovedElementEffect(
_ change: CollectionDifference<View>.Change
) -> EffectTask<Action>? {
switch change {
case let .remove(_, element, _):
return .task(operation: { .destinationRemoved(element) })
case _:
return nil
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment