@@ -100,7 +100,7 @@ public class LiveSessionCoordinator<R: RootRegistry>: ObservableObject {
100100 try ? LiveViewNativeCore . storeSessionCookie ( " \( cookie. name) = \( cookie. value) " , self . url. absoluteString)
101101 }
102102
103- self . navigationPath = [ . init( url: url, coordinator: . init( session: self , url: self . url) , navigationTransition: nil , pendingView: nil ) ]
103+ self . navigationPath = [ . init( url: url, coordinator: . init( session: self , url: self . url) , mode : . replaceTop , navigationTransition: nil , pendingView: nil ) ]
104104
105105 self . mergedEventSubjects = self . navigationPath. first!. coordinator. eventSubject. compactMap ( { [ weak self] value in
106106 self . map ( { ( $0. navigationPath. first!. coordinator, value) } )
@@ -112,28 +112,64 @@ public class LiveSessionCoordinator<R: RootRegistry>: ObservableObject {
112112 $navigationPath. scan ( ( [ LiveNavigationEntry < R > ] ( ) , [ LiveNavigationEntry < R > ] ( ) ) , { ( $0. 1 , $1) } ) . sink { [ weak self] prev, next in
113113 guard let self else { return }
114114 Task {
115- try await prev. last? . coordinator. disconnect ( )
116115 if prev. count > next. count {
117- let targetEntry = self . liveSocket!. getEntries ( ) [ next. count - 1 ]
118- next. last? . coordinator. join (
119- try await self . liveSocket!. traverseTo ( targetEntry. id,
120- . some( [
121- " _format " : . str( string: LiveSessionParameters . platform) ,
122- " _interface " : . object( object: LiveSessionParameters . platformParams)
123- ] ) ,
124- nil )
125- )
116+ // backward navigation
117+
118+ // if the coordinator is connected, the mode was a `patch`, and the new entry has the same coordinator
119+ // send a `live_patch` event and keep the same coordinator.
120+ switch prev. last!. mode {
121+ case . patch:
122+ if case . connected = prev. last? . coordinator. state,
123+ next. last? . coordinator === prev. last? . coordinator
124+ {
125+ _ = try await prev. last? . coordinator. doPushEvent (
126+ " live_patch " ,
127+ payload: . jsonPayload( json: . object( object: [
128+ " url " : . str( string: next. last!. url. absoluteString)
129+ ] ) )
130+ )
131+ next. last!. coordinator. url = next. last!. url
132+ next. last!. coordinator. objectWillChange. send ( )
133+ if next. count <= 1 { // if we navigated back to the root page, trigger an update on the session too
134+ self . objectWillChange. send ( )
135+ }
136+ return
137+ }
138+ case . replaceTop:
139+ try await prev. last? . coordinator. disconnect ( )
140+ let targetEntry = self . liveSocket!. getEntries ( ) [ next. count - 1 ]
141+ next. last? . coordinator. join (
142+ try await self . liveSocket!. traverseTo (
143+ targetEntry. id,
144+ . some( [
145+ " _format " : . str( string: LiveSessionParameters . platform) ,
146+ " _interface " : . object( object: LiveSessionParameters . platformParams)
147+ ] ) ,
148+ nil
149+ )
150+ )
151+ }
126152 } else if next. count > prev. count && prev. count > 0 {
127153 // forward navigation (from `redirect` or `<NavigationLink>`)
128- next. last? . coordinator. join (
129- try await self . liveSocket!. navigate ( next. last!. url. absoluteString,
130- . some( [
131- " _format " : . str( string: LiveSessionParameters . platform) ,
132- " _interface " : . object( object: LiveSessionParameters . platformParams)
133- ] ) ,
134- NavOptions ( action: . push) )
135- )
154+
155+ // if the coordinator instance is the same and its connected, we don't need to handle a connection.
156+ switch next. last!. mode {
157+ case . patch:
158+ next. last? . coordinator. url = next. last!. url
159+ return
160+ case . replaceTop:
161+ try await prev. last? . coordinator. disconnect ( )
162+ next. last? . coordinator. join (
163+ try await self . liveSocket!. navigate ( next. last!. url. absoluteString,
164+ . some( [
165+ " _format " : . str( string: LiveSessionParameters . platform) ,
166+ " _interface " : . object( object: LiveSessionParameters . platformParams)
167+ ] ) ,
168+ NavOptions ( action: . push) )
169+ )
170+ }
136171 } else if next. count == prev. count {
172+ try await prev. last? . coordinator. disconnect ( )
137173 guard let liveChannel =
138174 try await self . liveSocket? . navigate ( next. last!. url. absoluteString,
139175 . some( [
@@ -318,7 +354,7 @@ public class LiveSessionCoordinator<R: RootRegistry>: ObservableObject {
318354 if case . user( user: " assets_change " ) = event. event {
319355 Task { @MainActor in
320356 await self . disconnect ( )
321- self . navigationPath = [ . init( url: self . url, coordinator: . init( session: self , url: self . url) , navigationTransition: nil , pendingView: nil ) ]
357+ self . navigationPath = [ . init( url: self . url, coordinator: . init( session: self , url: self . url) , mode : . replaceTop , navigationTransition: nil , pendingView: nil ) ]
322358 await self . connect ( )
323359 self . lastReloadTime = Date ( )
324360 }
@@ -374,7 +410,7 @@ public class LiveSessionCoordinator<R: RootRegistry>: ObservableObject {
374410 await self . disconnect ( )
375411 if let url {
376412 self . url = url
377- self . navigationPath = [ . init( url: self . url, coordinator: self . navigationPath. first!. coordinator, navigationTransition: nil , pendingView: nil ) ]
413+ self . navigationPath = [ . init( url: self . url, coordinator: self . navigationPath. first!. coordinator, mode : . replaceTop , navigationTransition: nil , pendingView: nil ) ]
378414 }
379415 await self . connect ( httpMethod: httpMethod, httpBody: httpBody, additionalHeaders: headers)
380416// do {
@@ -440,7 +476,7 @@ public class LiveSessionCoordinator<R: RootRegistry>: ObservableObject {
440476 switch redirect. mode {
441477 case . replaceTop:
442478 let coordinator = LiveViewCoordinator ( session: self , url: redirect. to)
443- let entry = LiveNavigationEntry ( url: redirect. to, coordinator: coordinator, navigationTransition: navigationTransition, pendingView: pendingView)
479+ let entry = LiveNavigationEntry ( url: redirect. to, coordinator: coordinator, mode : redirect . mode , navigationTransition: navigationTransition, pendingView: pendingView)
444480 switch redirect. kind {
445481 case . push:
446482 navigationPath. append ( entry)
@@ -458,7 +494,7 @@ public class LiveSessionCoordinator<R: RootRegistry>: ObservableObject {
458494 // patch is like `replaceTop`, but it does not disconnect.
459495 let coordinator = navigationPath. last!. coordinator
460496 coordinator. url = redirect. to
461- let entry = LiveNavigationEntry ( url: redirect. to, coordinator: coordinator, navigationTransition: navigationTransition, pendingView: pendingView)
497+ let entry = LiveNavigationEntry ( url: redirect. to, coordinator: coordinator, mode : redirect . mode , navigationTransition: navigationTransition, pendingView: pendingView)
462498 switch redirect. kind {
463499 case . push:
464500 navigationPath. append ( entry)
0 commit comments