diff --git a/Yattee/Services/Navigation/NavigationRouter.swift b/Yattee/Services/Navigation/NavigationRouter.swift index 6f97a337..299b0bb1 100644 --- a/Yattee/Services/Navigation/NavigationRouter.swift +++ b/Yattee/Services/Navigation/NavigationRouter.swift @@ -44,7 +44,15 @@ final class NavigationRouter { let key = item.id return Binding( get: { self.stacks[key] ?? [] }, - set: { self.stacks[key] = $0 } + set: { + // Only the selected section's stack is on screen, so only it + // edits its path (Back, swipe back). A NavigationSplitView + // detail stack that is being replaced on a selection change + // writes an empty path on its way out, which would throw + // away what the section had pushed. + guard key == self.selection.id else { return } + self.stacks[key] = $0 + } ) } diff --git a/YatteeTests/NavigationTests.swift b/YatteeTests/NavigationTests.swift index 054ae909..5b125655 100644 --- a/YatteeTests/NavigationTests.swift +++ b/YatteeTests/NavigationTests.swift @@ -677,6 +677,28 @@ struct NavigationCoordinatorTests { #expect(router.selection == .bookmarks) } + @Test("A stack that is no longer selected can't clear itself") + func offscreenStackWriteIgnored() { + let router = NavigationRouter() + router.push(.history) + let homePath = router.path(for: .home) + + router.select(.bookmarks) + homePath.wrappedValue = [] + + #expect(router.stack(for: .home) == [.history]) + } + + @Test("The selected stack still pops") + func selectedStackPops() { + let router = NavigationRouter() + router.push(.history) + + router.path(for: .home).wrappedValue = [] + + #expect(router.stack(for: .home).isEmpty) + } + @Test("A destination pushed before startup keeps its section") func deepLinkBeforeStartup() { let coordinator = NavigationCoordinator()