@@ -4,8 +4,7 @@ import Combine
44public class UIPilot < T: Equatable > : ObservableObject {
55
66 private let logger : Logger
7- private let viewGenerator = PathViewGenerator < T > ( )
8-
7+
98 @Published var paths : [ UIPilotPath < T > ] = [ ]
109
1110 public var stack : [ T ] {
@@ -16,13 +15,6 @@ public class UIPilot<T: Equatable>: ObservableObject {
1615 logger = debug ? DebugLog ( ) : EmptyLog ( )
1716 logger. log ( " UIPilot - Pilot Initialized. " )
1817
19- viewGenerator. onPop = { [ weak self] path in
20- if let self = self , self . paths. count > 1
21- && path. id == self . paths [ self . paths. count - 2 ] . id {
22- self . pop ( )
23- }
24- }
25-
2618 push ( initial)
2719 }
2820
@@ -59,10 +51,14 @@ public class UIPilot<T: Equatable>: ObservableObject {
5951 logger. log ( " UIPilot - Popping \( numToPop) routes " )
6052 paths. removeLast ( numToPop)
6153 }
62-
63- func getView< Screen: View > ( _ paths: [ UIPilotPath < T > ] , _ routeMap: RouteMap < T , Screen > , _ pathViews: [ UIPilotPath < T > : Screen ] ) -> ( PathView < Screen > ? , [ UIPilotPath < T > : Screen ] ) {
64- return viewGenerator. generate ( paths, routeMap, pathViews)
54+
55+ func systemPop( path: UIPilotPath < T > ) {
56+ if paths. count > 1
57+ && path. id == self . paths [ self . paths. count - 2 ] . id {
58+ self . pop ( )
59+ }
6560 }
61+
6662}
6763
6864struct UIPilotPath < T: Equatable > : Equatable , Hashable {
@@ -125,22 +121,51 @@ class PathViewState<Screen: View>: ObservableObject {
125121 }
126122}
127123
128- class PathViewGenerator < T: Equatable > {
124+ public struct UIPilotHost < T: Equatable , Screen: View > : View {
125+
126+ @ObservedObject
127+ private var pilot : UIPilot < T >
128+ @ViewBuilder
129+ private let routeMap : ( T ) -> Screen
130+
131+ @State
132+ private var viewGenerator = ViewGenerator < T , Screen > ( )
133+
134+ public init ( _ pilot: UIPilot < T > , @ViewBuilder _ routeMap: @escaping ( T ) -> Screen ) {
135+ self . pilot = pilot
136+ self . routeMap = routeMap
137+ self . viewGenerator. onPop = { path in
138+ pilot. systemPop ( path: path)
139+ }
140+ }
141+
142+ public var body : some View {
143+ NavigationView {
144+ viewGenerator. build ( pilot. paths, routeMap)
145+ }
146+ #if !os(macOS)
147+ . navigationViewStyle( . stack)
148+ #endif
149+ . environmentObject( pilot)
150+ }
151+ }
129152
130- var onPop : ( ( UIPilotPath < T > ) -> Void ) ?
153+ class ViewGenerator < T: Equatable , Screen: View > : ObservableObject {
154+ var onPop : ( ( UIPilotPath < T > ) -> Void ) ? = nil
155+
156+ private var pathViews = [ UIPilotPath < T > : Screen ] ( )
131157
132- func generate < Screen : View > (
158+ func build (
133159 _ paths: [ UIPilotPath < T > ] ,
134- @ViewBuilder _ routeMap: RouteMap < T , Screen > ,
135- _ pathViews: [ UIPilotPath < T > : Screen ] ) -> ( PathView < Screen > ? ,
136- [ UIPilotPath < T > : Screen ] ) {
137- var pathViews = recycleViews ( paths, pathViews: pathViews)
160+ @ViewBuilder _ routeMap: ( T ) -> Screen ) -> PathView < Screen > ? {
161+
162+ recycleViews ( paths)
138163
139164 var current : PathView < Screen > ?
140165 for path in paths. reversed ( ) {
141166 let view = pathViews [ path] ?? routeMap ( path. route)
142167 pathViews [ path] = view
143-
168+
144169 let content = PathView ( view, state: PathViewState ( ) )
145170
146171 content. state. next = current
@@ -151,53 +176,17 @@ class PathViewGenerator<T: Equatable> {
151176 }
152177 current = content
153178 }
154- return ( current, pathViews )
179+ return current
155180 }
156181
157- private func recycleViews< Screen : View > ( _ paths: [ UIPilotPath < T > ] , pathViews : [ UIPilotPath < T > : Screen ] ) -> [ UIPilotPath < T > : Screen ] {
158- var pathViews = pathViews
182+ private func recycleViews( _ paths: [ UIPilotPath < T > ] ) {
183+ var pathViews = self . pathViews
159184 for key in pathViews. keys {
160185 if !paths. contains ( key) {
161186 pathViews. removeValue ( forKey: key)
162187 }
163188 }
164- return pathViews
165- }
166- }
167-
168- public typealias RouteMap < T, Screen> = ( T ) -> Screen
169-
170- public struct UIPilotHost < T: Equatable , Screen: View > : View {
171-
172- @ObservedObject
173- private var pilot : UIPilot < T >
174-
175- @ViewBuilder
176- let routeMap : RouteMap < T , Screen >
177-
178- @State
179- var pathViews = [ UIPilotPath < T > : Screen ] ( )
180- @State
181- var content : PathView < Screen > ?
182-
183- public init ( _ pilot: UIPilot < T > , @ViewBuilder _ routeMap: @escaping RouteMap < T , Screen > ) {
184- self . pilot = pilot
185- self . routeMap = routeMap
186- }
187-
188- public var body : some View {
189- NavigationView {
190- content
191- }
192- #if !os(macOS)
193- . navigationViewStyle( . stack)
194- #endif
195- . environmentObject( pilot)
196- . onReceive ( pilot. $paths) { paths in
197- let ( newContent, newPathViews) = pilot. getView ( paths, routeMap, pathViews)
198- self . content = newContent
199- self . pathViews = newPathViews
200- }
189+ self . pathViews = pathViews
201190 }
202191}
203192
0 commit comments