Skip to content

Commit

Permalink
Add options parameter and animation option
Browse files Browse the repository at this point in the history
Backfillls turbo-ios PRs:

* hotwired/turbo-ios#207
* hotwired/turbo-ios#209
  • Loading branch information
joemasilotti committed May 15, 2024
1 parent 958fcd8 commit 981d697
Show file tree
Hide file tree
Showing 5 changed files with 55 additions and 34 deletions.
2 changes: 1 addition & 1 deletion Source/Router.swift
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,6 @@ public protocol Router: AnyObject {

extension Navigator: Router {
public func route(_ url: URL) {
route(url, parameters: nil)
route(url, options: VisitOptions(action: .advance), parameters: nil)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -59,4 +59,13 @@ public extension VisitProposal {

return VisitableViewController.pathConfigurationIdentifier
}

/// Allows the proposal to change the animation status when pushing, popping or presenting.
var animated: Bool {
if let animated = parameters?["animated"] as? Bool {
return animated
}

return true
}
}
58 changes: 29 additions & 29 deletions Source/Turbo/Navigator/NavigationHierarchyController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ class NavigationHierarchyController {

func route(controller: UIViewController, proposal: VisitProposal) {
if let alert = controller as? UIAlertController {
presentAlert(alert)
presentAlert(alert, via: proposal)
} else {
if let visitable = controller as? Visitable {
visitable.visitableView.allowsPullToRefresh = proposal.pullToRefreshEnabled
Expand All @@ -45,15 +45,15 @@ class NavigationHierarchyController {
case .default:
navigate(with: controller, via: proposal)
case .pop:
pop()
pop(via: proposal)
case .replace:
replace(with: controller, via: proposal)
case .refresh:
refresh()
refresh(via: proposal)
case .clearAll:
clearAll()
clearAll(via: proposal)
case .replaceRoot:
replaceRoot(with: controller)
replaceRoot(with: controller, via: proposal)
case .none:
break // Do nothing.
}
Expand All @@ -69,11 +69,11 @@ class NavigationHierarchyController {

private unowned let delegate: NavigationHierarchyControllerDelegate

private func presentAlert(_ alert: UIAlertController) {
private func presentAlert(_ alert: UIAlertController, via proposal: VisitProposal) {
if navigationController.presentedViewController != nil {
modalNavigationController.present(alert, animated: true)
modalNavigationController.present(alert, animated: proposal.animated)
} else {
navigationController.present(alert, animated: true)
navigationController.present(alert, animated: proposal.animated)
}
}

Expand All @@ -83,7 +83,7 @@ class NavigationHierarchyController {
if let visitable = controller as? Visitable {
delegate.visit(visitable, on: .main, with: proposal.options)
}
navigationController.dismiss(animated: true)
navigationController.dismiss(animated: proposal.animated)
pushOrReplace(on: navigationController, with: controller, via: proposal)
case .modal:
if let visitable = controller as? Visitable {
Expand All @@ -92,9 +92,9 @@ class NavigationHierarchyController {
if navigationController.presentedViewController != nil, !modalNavigationController.isBeingDismissed {
pushOrReplace(on: modalNavigationController, with: controller, via: proposal)
} else {
modalNavigationController.setViewControllers([controller], animated: true)
modalNavigationController.setViewControllers([controller], animated: proposal.animated)
modalNavigationController.setModalPresentationStyle(via: proposal)
navigationController.present(modalNavigationController, animated: true)
navigationController.present(modalNavigationController, animated: proposal.animated)
}
}
}
Expand All @@ -103,9 +103,9 @@ class NavigationHierarchyController {
if visitingSamePage(on: navigationController, with: controller, via: proposal.url) {
navigationController.replaceLastViewController(with: controller)
} else if visitingPreviousPage(on: navigationController, with: controller, via: proposal.url) {
navigationController.popViewController(animated: true)
navigationController.popViewController(animated: proposal.animated)
} else if proposal.options.action == .advance {
navigationController.pushViewController(controller, animated: true)
navigationController.pushViewController(controller, animated: proposal.animated)
} else {
navigationController.replaceLastViewController(with: controller)
}
Expand All @@ -130,15 +130,15 @@ class NavigationHierarchyController {
return type(of: previousController) == type(of: controller)
}

private func pop() {
private func pop(via proposal: VisitProposal) {
if navigationController.presentedViewController != nil {
if modalNavigationController.viewControllers.count == 1 {
navigationController.dismiss(animated: true)
navigationController.dismiss(animated: proposal.animated)
} else {
modalNavigationController.popViewController(animated: true)
modalNavigationController.popViewController(animated: proposal.animated)
}
} else {
navigationController.popViewController(animated: true)
navigationController.popViewController(animated: proposal.animated)
}
}

Expand All @@ -148,7 +148,7 @@ class NavigationHierarchyController {
if let visitable = controller as? Visitable {
delegate.visit(visitable, on: .main, with: proposal.options)
}
navigationController.dismiss(animated: true)
navigationController.dismiss(animated: proposal.animated)
navigationController.replaceLastViewController(with: controller)
case .modal:
if let visitable = controller as? Visitable {
Expand All @@ -159,38 +159,38 @@ class NavigationHierarchyController {
} else {
modalNavigationController.setViewControllers([controller], animated: false)
modalNavigationController.setModalPresentationStyle(via: proposal)
navigationController.present(modalNavigationController, animated: true)
navigationController.present(modalNavigationController, animated: proposal.animated)
}
}
}

private func refresh() {
private func refresh(via proposal: VisitProposal) {
if navigationController.presentedViewController != nil {
if modalNavigationController.viewControllers.count == 1 {
delegate.refresh(navigationStack: .main)
navigationController.dismiss(animated: true)
navigationController.dismiss(animated: proposal.animated)
} else {
delegate.refresh(navigationStack: .modal)
modalNavigationController.popViewController(animated: true)
modalNavigationController.popViewController(animated: proposal.animated)
}
} else {
delegate.refresh(navigationStack: .main)
navigationController.popViewController(animated: true)
navigationController.popViewController(animated: proposal.animated)
}
}

private func clearAll() {
private func clearAll(via proposal: VisitProposal) {
delegate.refresh(navigationStack: .main)
navigationController.dismiss(animated: true)
navigationController.popToRootViewController(animated: true)
navigationController.dismiss(animated: proposal.animated)
navigationController.popToRootViewController(animated: proposal.animated)
}

private func replaceRoot(with controller: UIViewController) {
private func replaceRoot(with controller: UIViewController, via proposal: VisitProposal) {
if let visitable = controller as? Visitable {
delegate.visit(visitable, on: .main, with: .init(action: .replace))
}

navigationController.dismiss(animated: true)
navigationController.setViewControllers([controller], animated: true)
navigationController.dismiss(animated: proposal.animated)
navigationController.setViewControllers([controller], animated: proposal.animated)
}
}
7 changes: 4 additions & 3 deletions Source/Turbo/Navigator/Navigator.swift
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ public class Navigator {
public unowned var delegate: NavigatorDelegate

public var rootViewController: UINavigationController { hierarchyController.navigationController }
public var modalRootViewController: UINavigationController { hierarchyController.modalNavigationController }
public var activeNavigationController: UINavigationController { hierarchyController.activeNavigationController }

/// Set to handle customize behavior of the `WKUIDelegate`.
Expand Down Expand Up @@ -42,11 +43,11 @@ public class Navigator {
/// Convenience function to routing a proposal directly.
///
/// - Parameter url: the URL to visit
/// - Parameter options: passed options will override default `advance` visit options
/// - Parameter parameters: provide context relevant to `url`
public func route(_ url: URL, parameters: [String: Any]? = nil) {
let options = VisitOptions(action: .advance, response: nil)
public func route(_ url: URL, options: VisitOptions? = VisitOptions(action: .advance), parameters: [String: Any]? = nil) {
let properties = session.pathConfiguration?.properties(for: url) ?? PathProperties()
route(VisitProposal(url: url, options: options, properties: properties, parameters: parameters))
route(VisitProposal(url: url, options: options ?? .init(action: .advance), properties: properties))
}

/// Transforms `VisitProposal` -> `UIViewController`
Expand Down
13 changes: 12 additions & 1 deletion Tests/Turbo/Navigator/NavigationHierarchyControllerTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ final class NavigationHierarchyControllerTests: XCTestCase {
loadNavigationControllerInWindow()
}

func test_default_default_default_pushesOnMainStack() {
func test_default_default_default_defaultOptionsParamater_pushesOnMainStack() {
navigator.route(oneURL)
XCTAssertEqual(navigationController.viewControllers.count, 1)
XCTAssert(navigator.rootViewController.viewControllers.last is VisitableViewController)
Expand All @@ -28,6 +28,17 @@ final class NavigationHierarchyControllerTests: XCTestCase {
assertVisited(url: twoURL, on: .main)
}

func test_default_default_default_nilOptionsParameter_pushesOnMainStack() {
navigator.route(oneURL)
XCTAssertEqual(navigationController.viewControllers.count, 1)
XCTAssert(navigator.rootViewController.viewControllers.last is VisitableViewController)

navigator.route(twoURL, options: nil)
XCTAssertEqual(navigationController.viewControllers.count, 2)
XCTAssert(navigator.rootViewController.viewControllers.last is VisitableViewController)
assertVisited(url: twoURL, on: .main)
}

func test_default_default_default_visitingSamePage_replacesOnMainStack() {
navigator.route(oneURL)
XCTAssertEqual(navigationController.viewControllers.count, 1)
Expand Down

0 comments on commit 981d697

Please sign in to comment.