-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathSceneController.swift
143 lines (116 loc) · 5.47 KB
/
SceneController.swift
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
import UIKit
import WebKit
import SafariServices
import Turbo
import Strada
final class SceneController: UIResponder {
private static var sharedProcessPool = WKProcessPool()
var window: UIWindow?
private let rootURL = Demo.current
private var navigationController: TurboNavigationController!
// MARK: - Setup
private func configureRootViewController() {
guard let window = window else {
fatalError()
}
window.tintColor = UIColor(named: "Tint")
let turboNavController: TurboNavigationController
if let navController = window.rootViewController as? TurboNavigationController {
turboNavController = navController
navigationController = navController
} else {
turboNavController = TurboNavigationController()
window.rootViewController = turboNavController
}
turboNavController.session = session
turboNavController.modalSession = modalSession
}
// MARK: - Authentication
private func promptForAuthentication() {
let authURL = rootURL.appendingPathComponent("/signin")
let properties = pathConfiguration.properties(for: authURL)
navigationController.route(url: authURL, options: VisitOptions(), properties: properties)
}
// MARK: - Sessions
private lazy var session = makeSession()
private lazy var modalSession = makeSession()
private func makeSession() -> Session {
let webView = WKWebView(frame: .zero,
configuration: .appConfiguration)
if #available(iOS 16.4, *) {
webView.isInspectable = true
}
// Initialize Strada bridge.
Bridge.initialize(webView)
let session = Session(webView: webView)
session.delegate = self
session.pathConfiguration = pathConfiguration
return session
}
// MARK: - Path Configuration
private lazy var pathConfiguration = PathConfiguration(sources: [
.file(Bundle.main.url(forResource: "path-configuration", withExtension: "json")!),
])
}
extension SceneController: UIWindowSceneDelegate {
func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
guard let _ = scene as? UIWindowScene else { return }
configureRootViewController()
navigationController.route(url: rootURL, options: VisitOptions(action: .replace), properties: [:])
}
}
extension SceneController: SessionDelegate {
func session(_ session: Session, didProposeVisit proposal: VisitProposal) {
navigationController.route(url: proposal.url, options: proposal.options, properties: proposal.properties)
}
func session(_ session: Session, didFailRequestForVisitable visitable: Visitable, error: Error) {
if let turboError = error as? TurboError, case let .http(statusCode) = turboError, statusCode == 401 {
promptForAuthentication()
} else if let errorPresenter = visitable as? ErrorPresenter {
errorPresenter.presentError(error) { [weak self] in
self?.session.reload()
}
} else {
let alert = UIAlertController(title: "Visit failed!", message: error.localizedDescription, preferredStyle: .alert)
alert.addAction(UIAlertAction(title: "OK", style: .default, handler: nil))
navigationController.present(alert, animated: true)
}
}
// When a form submission completes in the modal session, we need to
// manually clear the snapshot cache in the default session, since we
// don't want potentially stale cached snapshots to be used
func sessionDidFinishFormSubmission(_ session: Session) {
if (session == modalSession) {
self.session.clearSnapshotCache()
}
}
func sessionDidLoadWebView(_ session: Session) {
session.webView.navigationDelegate = self
}
func sessionWebViewProcessDidTerminate(_ session: Session) {
session.reload()
}
}
extension SceneController: WKNavigationDelegate {
func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping (WKNavigationActionPolicy) -> Void) {
if navigationAction.navigationType == .linkActivated {
// Any link that's not on the same domain as the Turbo root url will go through here
// Other links on the domain, but that have an extension that is non-html will also go here
// You can decide how to handle those, by default if you're not the navigationDelegate
// the Session will open them in the default browser
let url = navigationAction.request.url!
// For this demo, we'll load files from our domain in a SafariViewController so you
// don't need to leave the app. You might expand this in your app
// to open all audio/video/images in a native media viewer
if url.host == rootURL.host, !url.pathExtension.isEmpty {
let safariViewController = SFSafariViewController(url: url)
navigationController.present(safariViewController, animated: true)
} else {
UIApplication.shared.open(url)
}
decisionHandler(.cancel)
} else {
decisionHandler(.allow)
}
}
}