Skip to content

Commit

Permalink
Merge pull request #165 from hotwired/turbo-navigator-handle-open-ext…
Browse files Browse the repository at this point in the history
…ernalURL
  • Loading branch information
olivaresf authored Nov 30, 2023
2 parents 1aae4fb + 931bb79 commit cd4f71e
Show file tree
Hide file tree
Showing 5 changed files with 43 additions and 20 deletions.
15 changes: 15 additions & 0 deletions Source/Turbo Navigator/Helpers/ExternalURLNavigationAction.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import Foundation

/// When TurboNavigator encounters an external URL, its delegate may handle it with any of these actions.
public enum ExternalURLNavigationAction {
/// Attempts to open via an embedded `SafariViewController` so the user stays in-app.
/// Silently fails if you pass a URL that's not `http` or `https`.
case openViaSafariController

/// Attempts to open via `openURL(_:options:completionHandler)`.
/// This is useful if the external URL is a deeplink.
case openViaSystem

/// Will do nothing with the external URL.
case reject
}
14 changes: 0 additions & 14 deletions Source/Turbo Navigator/TurboNavigationHierarchyController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -52,20 +52,6 @@ class TurboNavigationHierarchyController {
}
}

func openExternal(url: URL, navigationType: NavigationStackType) {
if ["http", "https"].contains(url.scheme) {
let safariViewController = SFSafariViewController(url: url)
safariViewController.modalPresentationStyle = .pageSheet
if #available(iOS 15.0, *) {
safariViewController.preferredControlTintColor = .tintColor
}
let navController = navController(for: navigationType)
navController.present(safariViewController, animated: true)
} else if UIApplication.shared.canOpenURL(url) {
UIApplication.shared.open(url)
}
}

// MARK: Private

@available(*, unavailable)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,5 @@ import WebKit
/// or to render a native controller instead of a Turbo web visit.
protocol TurboNavigationHierarchyControllerDelegate: AnyObject {
func visit(_ : Visitable, on: TurboNavigationHierarchyController.NavigationStackType, with: VisitOptions)

func refresh(navigationStack: TurboNavigationHierarchyController.NavigationStackType)
}
27 changes: 22 additions & 5 deletions Source/Turbo Navigator/TurboNavigator.swift
Original file line number Diff line number Diff line change
Expand Up @@ -111,9 +111,25 @@ extension TurboNavigator: SessionDelegate {
}
}

public func session(_ session: Session, openExternalURL url: URL) {
let navigationType: TurboNavigationHierarchyController.NavigationStackType = session === modalSession ? .modal : .main
hierarchyController.openExternal(url: url, navigationType: navigationType)
public func session(_ session: Session, openExternalURL externalURL: URL) {

switch delegate.handle(externalURL: externalURL) {

case .openViaSystem:
UIApplication.shared.open(externalURL)

case .openViaSafariController:
let safariViewController = SFSafariViewController(url: externalURL)
safariViewController.modalPresentationStyle = .pageSheet
if #available(iOS 15.0, *) {
safariViewController.preferredControlTintColor = .tintColor
}

activeNavigationController.present(safariViewController, animated: true)

case .reject:
return
}
}

public func session(_ session: Session, didFailRequestForVisitable visitable: Visitable, error: Error) {
Expand Down Expand Up @@ -146,10 +162,11 @@ extension TurboNavigator: SessionDelegate {
// MARK: - TurboNavigationHierarchyControllerDelegate

extension TurboNavigator: TurboNavigationHierarchyControllerDelegate {

func visit(_ controller: Visitable, on navigationStack: TurboNavigationHierarchyController.NavigationStackType, with: VisitOptions) {
switch navigationStack {
case .main: session.visit(controller, action: .advance)
case .modal: modalSession.visit(controller, action: .advance)
case .main: session.visit(controller, action: .advance)
case .modal: modalSession.visit(controller, action: .advance)
}
}

Expand Down
6 changes: 6 additions & 0 deletions Source/Turbo Navigator/TurboNavigatorDelegate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ public protocol TurboNavigatorDelegate: AnyObject {
/// - Returns: how to react to the visit proposal
func handle(proposal: VisitProposal) -> ProposalResult

func handle(externalURL: URL) -> ExternalURLNavigationAction

/// Optional. An error occurred loading the request, present it to the user.
/// Retry the request by executing the closure.
/// If not implemented, will present the error's localized description and a Retry button.
Expand All @@ -26,6 +28,10 @@ public extension TurboNavigatorDelegate {
func handle(proposal: VisitProposal) -> ProposalResult {
.accept
}

func handle(externalURL: URL) -> ExternalURLNavigationAction {
.openViaSafariController
}

func visitableDidFailRequest(_ visitable: Visitable, error: Error, retry: @escaping RetryBlock) {
if let errorPresenter = visitable as? ErrorPresenter {
Expand Down

0 comments on commit cd4f71e

Please sign in to comment.