Skip to content

Commit

Permalink
Several improvements (#209)
Browse files Browse the repository at this point in the history
* Add options parameter

* Add animation key to visit proposal

* Add modal root view controller access

* Change var -> constant

* Add default parameter for visit options

* Clarify default visit options
  • Loading branch information
olivaresf authored May 15, 2024
1 parent 2f81df9 commit 93af6fd
Show file tree
Hide file tree
Showing 4 changed files with 60 additions and 32 deletions.
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
}
}
56 changes: 28 additions & 28 deletions Source/Turbo Navigator/TurboNavigationHierarchyController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ class TurboNavigationHierarchyController {

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 TurboNavigationHierarchyController {
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,18 +69,18 @@ class TurboNavigationHierarchyController {

private unowned let delegate: TurboNavigationHierarchyControllerDelegate

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)
}
}

private func navigate(with controller: UIViewController, via proposal: VisitProposal) {
switch proposal.context {
case .default:
navigationController.dismiss(animated: true)
navigationController.dismiss(animated: proposal.animated)
pushOrReplace(on: navigationController, with: controller, via: proposal)
if let visitable = controller as? Visitable {
delegate.visit(visitable, on: .main, with: proposal.options)
Expand All @@ -89,9 +89,9 @@ class TurboNavigationHierarchyController {
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)
}
if let visitable = controller as? Visitable {
delegate.visit(visitable, on: .modal, with: proposal.options)
Expand All @@ -103,9 +103,9 @@ class TurboNavigationHierarchyController {
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,22 +130,22 @@ class TurboNavigationHierarchyController {
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)
}
}

private func replace(with controller: UIViewController, via proposal: VisitProposal) {
switch proposal.context {
case .default:
navigationController.dismiss(animated: true)
navigationController.dismiss(animated: proposal.animated)
navigationController.replaceLastViewController(with: controller)
if let visitable = controller as? Visitable {
delegate.visit(visitable, on: .main, with: proposal.options)
Expand All @@ -156,38 +156,38 @@ class TurboNavigationHierarchyController {
} else {
modalNavigationController.setViewControllers([controller], animated: false)
modalNavigationController.setModalPresentationStyle(via: proposal)
navigationController.present(modalNavigationController, animated: true)
navigationController.present(modalNavigationController, animated: proposal.animated)
}
if let visitable = controller as? Visitable {
delegate.visit(visitable, on: .modal, with: proposal.options)
}
}
}

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

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

private func replaceRoot(with controller: UIViewController) {
private func replaceRoot(with controller: UIViewController, via proposal: VisitProposal) {
navigationController.dismiss(animated: true)
navigationController.setViewControllers([controller], animated: true)
navigationController.setViewControllers([controller], animated: proposal.animated)

if let visitable = controller as? Visitable {
delegate.visit(visitable, on: .main, with: .init(action: .replace))
Expand Down
14 changes: 11 additions & 3 deletions Source/Turbo Navigator/TurboNavigator.swift
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@ public class TurboNavigator {
public unowned var delegate: TurboNavigatorDelegate

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 +45,16 @@ public class TurboNavigator {
/// 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,
parameters: parameters))
}

/// Transforms `VisitProposal` -> `UIViewController`
Expand Down
13 changes: 12 additions & 1 deletion Tests/Turbo Navigator/TurboNavigatorTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ final class TurboNavigationHierarchyControllerTests: 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 @@ -27,6 +27,17 @@ final class TurboNavigationHierarchyControllerTests: XCTestCase {
XCTAssert(navigator.rootViewController.viewControllers.last is VisitableViewController)
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)
Expand Down

0 comments on commit 93af6fd

Please sign in to comment.