Skip to content

Commit

Permalink
Merge pull request #197 from hotwired/opt-into-retry
Browse files Browse the repository at this point in the history
Hide retry button in ErrorView if no handler is given
  • Loading branch information
olivaresf authored Mar 22, 2024
2 parents c4ea6f2 + 7e6893e commit 0b5d738
Show file tree
Hide file tree
Showing 3 changed files with 24 additions and 13 deletions.
4 changes: 2 additions & 2 deletions Demo/SceneController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -90,11 +90,11 @@ extension SceneController: TurboNavigatorDelegate {
}
}

func visitableDidFailRequest(_ visitable: Visitable, error: Error, retry: @escaping RetryBlock) {
func visitableDidFailRequest(_ visitable: Visitable, error: Error, retryHandler: RetryBlock?) {
if let turboError = error as? TurboError, case let .http(statusCode) = turboError, statusCode == 401 {
promptForAuthentication()
} else if let errorPresenter = visitable as? ErrorPresenter {
errorPresenter.presentError(error, handler: retry)
errorPresenter.presentError(error, retryHandler: retryHandler)
} else {
let alert = UIAlertController(title: "Visit failed!", message: error.localizedDescription, preferredStyle: .alert)
alert.addAction(UIAlertAction(title: "OK", style: .default, handler: nil))
Expand Down
27 changes: 19 additions & 8 deletions Source/Turbo Navigator/Helpers/ErrorPresenter.swift
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,21 @@ import SwiftUI
public protocol ErrorPresenter: UIViewController {
typealias Handler = () -> Void

func presentError(_ error: Error, handler: @escaping Handler)
func presentError(_ error: Error, retryHandler: Handler?)
}

public extension ErrorPresenter {
func presentError(_ error: Error, handler: @escaping () -> Void) {
let errorView = ErrorView(error: error) { [unowned self] in
handler()

/// Presents an error in a full screen view.
/// The error view will display a `Retry` button if `retryHandler != nil`.
/// Tapping `Retry` will call `retryHandler?()` then dismiss the error.
///
/// - Parameters:
/// - error: presents the data in this error
/// - retryHandler: a user-triggered action to perform in case the error is recoverable
func presentError(_ error: Error, retryHandler: Handler?) {
let errorView = ErrorView(error: error, shouldShowRetryButton: (retryHandler != nil)) {
retryHandler?()
self.removeErrorViewController()
}

Expand All @@ -34,6 +42,7 @@ extension UIViewController: ErrorPresenter {}

private struct ErrorView: View {
let error: Error
let shouldShowRetryButton: Bool
let handler: ErrorPresenter.Handler?

var body: some View {
Expand All @@ -49,10 +58,12 @@ private struct ErrorView: View {
.font(.body)
.multilineTextAlignment(.center)

Button("Retry") {
handler?()
if shouldShowRetryButton {
Button("Retry") {
handler?()
}
.font(.system(size: 17, weight: .bold))
}
.font(.system(size: 17, weight: .bold))
}
.padding(32)
}
Expand All @@ -64,7 +75,7 @@ private struct ErrorView_Previews: PreviewProvider {
domain: "com.example.error",
code: 1001,
userInfo: [NSLocalizedDescriptionKey: "Could not connect to the server."]
)) {}
), shouldShowRetryButton: true) {}
}
}

Expand Down
6 changes: 3 additions & 3 deletions Source/Turbo Navigator/TurboNavigatorDelegate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ public protocol TurboNavigatorDelegate: AnyObject {
/// An error occurred loading the request, present it to the user.
/// Retry the request by executing the closure.
/// - Important: If not implemented, will present the error's localized description and a Retry button.
func visitableDidFailRequest(_ visitable: Visitable, error: Error, retry: @escaping RetryBlock)
func visitableDidFailRequest(_ visitable: Visitable, error: Error, retryHandler: RetryBlock?)

/// Respond to authentication challenge presented by web servers behing basic auth.
/// If not implemented, default handling will be performed.
Expand All @@ -44,9 +44,9 @@ public extension TurboNavigatorDelegate {
.openViaSafariController
}

func visitableDidFailRequest(_ visitable: Visitable, error: Error, retry: @escaping RetryBlock) {
func visitableDidFailRequest(_ visitable: Visitable, error: Error, retryHandler: RetryBlock?) {
if let errorPresenter = visitable as? ErrorPresenter {
errorPresenter.presentError(error, handler: retry)
errorPresenter.presentError(error, retryHandler: retryHandler)
}
}

Expand Down

0 comments on commit 0b5d738

Please sign in to comment.