Skip to content

Commit 56196ac

Browse files
authored
Merge pull request #98 from hotwired/switching-context-behavior
Improved `default` context visit behavior when dismissing the `modal` context
2 parents ae8c066 + 4613575 commit 56196ac

File tree

2 files changed

+47
-4
lines changed

2 files changed

+47
-4
lines changed

Source/Turbo/Navigator/NavigationHierarchyController.swift

+17-4
Original file line numberDiff line numberDiff line change
@@ -94,22 +94,31 @@ class NavigationHierarchyController {
9494
navigationController.present(alert, animated: proposal.animated)
9595
}
9696
}
97+
98+
private var isInModalContext: Bool {
99+
navigationController.presentedViewController != nil
100+
&& !modalNavigationController.isBeingDismissed
101+
}
97102

98103
private func navigate(with controller: UIViewController, via proposal: VisitProposal) {
99104
switch proposal.context {
100105
case .default:
101106
if let visitable = controller as? Visitable {
102107
delegate.visit(visitable, on: .main, with: proposal.options)
103108
}
109+
let willReplaceModalContext = isInModalContext
104110
navigationController.dismiss(animated: proposal.animated)
105-
pushOrReplace(on: navigationController, with: controller, via: proposal)
111+
pushOrReplace(on: navigationController,
112+
with: controller,
113+
via: proposal,
114+
didReplaceModalContext: willReplaceModalContext)
106115
case .modal:
107116
if let visitable = controller as? Visitable {
108117
delegate.visit(visitable, on: .modal, with: proposal.options)
109118
}
110119
controller.configureModalBehaviour(with: proposal)
111120

112-
if navigationController.presentedViewController != nil, !modalNavigationController.isBeingDismissed {
121+
if isInModalContext {
113122
pushOrReplace(on: modalNavigationController, with: controller, via: proposal)
114123
} else {
115124
modalNavigationController.setViewControllers([controller], animated: proposal.animated)
@@ -119,12 +128,16 @@ class NavigationHierarchyController {
119128
}
120129
}
121130

122-
private func pushOrReplace(on navigationController: UINavigationController, with controller: UIViewController, via proposal: VisitProposal) {
131+
private func pushOrReplace(on navigationController: UINavigationController,
132+
with controller: UIViewController,
133+
via proposal: VisitProposal,
134+
didReplaceModalContext: Bool = false) {
135+
123136
if visitingSamePage(on: navigationController, with: controller, via: proposal.url) {
124137
navigationController.replaceLastViewController(with: controller)
125138
} else if visitingPreviousPage(on: navigationController, with: controller, via: proposal.url) {
126139
navigationController.popViewController(animated: proposal.animated)
127-
} else if proposal.options.action == .advance {
140+
} else if proposal.options.action == .advance || didReplaceModalContext {
128141
navigationController.pushViewController(controller, animated: proposal.animated)
129142
} else {
130143
navigationController.replaceLastViewController(with: controller)

Tests/Turbo/Navigator/NavigationHierarchyControllerTests.swift

+30
Original file line numberDiff line numberDiff line change
@@ -214,6 +214,36 @@ final class NavigationHierarchyControllerTests: XCTestCase {
214214
XCTAssert(modalNavigationController.viewControllers.last is VisitableViewController)
215215
assertVisited(url: proposal.url, on: .modal)
216216
}
217+
218+
func test_modal_default_default_replaceAction_pushesOnMainStack_ifDifferentDestination() {
219+
navigator.route(VisitProposal(path: "/one", context: .default))
220+
XCTAssertEqual(navigationController.viewControllers.count, 1)
221+
222+
navigator.route(VisitProposal(path: "/two", context: .modal))
223+
XCTAssertEqual(modalNavigationController.viewControllers.count, 1)
224+
225+
let proposal = VisitProposal(path: "/three", action: .replace, context: .default)
226+
navigator.route(proposal)
227+
228+
XCTAssertNil(navigationController.presentedViewController)
229+
XCTAssertEqual(navigationController.viewControllers.count, 2)
230+
assertVisited(url: proposal.url, on: .main)
231+
}
232+
233+
func test_modal_default_default_replaceAction_replacesOnMainStack_ifSameDestination() {
234+
navigator.route(VisitProposal(path: "/one", context: .default))
235+
XCTAssertEqual(navigationController.viewControllers.count, 1)
236+
237+
navigator.route(VisitProposal(path: "/two", context: .modal))
238+
XCTAssertEqual(modalNavigationController.viewControllers.count, 1)
239+
240+
let proposal = VisitProposal(path: "/one", action: .replace, context: .default)
241+
navigator.route(proposal)
242+
243+
XCTAssertNil(navigationController.presentedViewController)
244+
XCTAssertEqual(navigationController.viewControllers.count, 1)
245+
assertVisited(url: proposal.url, on: .main)
246+
}
217247

218248
func test_modal_modal_replace_pushesOnModalStack() {
219249
navigator.route(VisitProposal(path: "/one", context: .modal))

0 commit comments

Comments
 (0)