added iOS source code
[wl-app.git] / iOS / Pods / JSQWebViewController / Source / WebViewController.swift
1 //
2 //  Created by Jesse Squires
3 //  http://www.jessesquires.com
4 //
5 //
6 //  Documentation
7 //  http://jessesquires.github.io/JSQWebViewController
8 //
9 //
10 //  GitHub
11 //  https://github.com/jessesquires/JSQWebViewController
12 //
13 //
14 //  License
15 //  Copyright (c) 2015 Jesse Squires
16 //  Released under an MIT license: http://opensource.org/licenses/MIT
17 //
18
19 import UIKit
20 import WebKit
21
22
23 private let titleKeyPath = "title"
24 private let estimatedProgressKeyPath = "estimatedProgress"
25
26
27 /// An instance of `WebViewController` displays interactive web content.
28 open class WebViewController: UIViewController {
29
30     // MARK: Properties
31
32     /// Returns the web view for the controller.
33     public final var webView: WKWebView {
34         get {
35             return _webView
36         }
37     }
38
39     /// Returns the progress view for the controller.
40     public final var progressBar: UIProgressView {
41         get {
42             return _progressBar
43         }
44     }
45
46     /// The URL request for the web view. Upon setting this property, the web view immediately begins loading the request.
47     public final var urlRequest: URLRequest {
48         didSet {
49             webView.load(urlRequest)
50         }
51     }
52
53     /**
54      Specifies whether or not to display the web view title as the navigation bar title.
55      The default is `false`, which sets the navigation bar title to the URL host name of the URL request.
56      */
57     public final var displaysWebViewTitle: Bool = false
58
59     // MARK: Private properties
60
61     private final let configuration: WKWebViewConfiguration
62     private final let activities: [UIActivity]?
63
64     private lazy final var _webView: WKWebView = {
65         let webView = WKWebView(frame: CGRect.zero, configuration: configuration)
66         webView.addObserver(self, forKeyPath: titleKeyPath, options: .new, context: nil)
67         webView.addObserver(self, forKeyPath: estimatedProgressKeyPath, options: .new, context: nil)
68         webView.allowsBackForwardNavigationGestures = true
69         if #available(iOS 9.0, *) {
70             webView.allowsLinkPreview = true
71         }
72         return webView
73     }()
74
75     private lazy final var _progressBar: UIProgressView = {
76         let progressBar = UIProgressView(progressViewStyle: .bar)
77         progressBar.backgroundColor = .clear
78         progressBar.trackTintColor = .clear
79         return progressBar
80     }()
81
82     // MARK: Initialization
83
84     /**
85      Constructs a new `WebViewController`.
86
87      - parameter urlRequest:    The URL request for the web view to load.
88      - parameter configuration: The configuration for the web view.
89      - parameter activities:    The custom activities to display in the `UIActivityViewController` that is presented when the action button is tapped.
90
91      - returns: A new `WebViewController` instance.
92      */
93     public init(urlRequest: URLRequest, configuration: WKWebViewConfiguration = WKWebViewConfiguration(), activities: [UIActivity]? = nil) {
94         self.configuration = configuration
95         self.urlRequest = urlRequest
96         self.activities = activities
97         super.init(nibName: nil, bundle: nil)
98     }
99
100     /**
101      Constructs a new `WebViewController`.
102
103      - parameter url: The URL to display in the web view.
104
105      - returns: A new `WebViewController` instance.
106      */
107     public convenience init(url: URL) {
108         self.init(urlRequest: URLRequest(url: url))
109     }
110
111     /// :nodoc:
112     public required init?(coder aDecoder: NSCoder) {
113         self.configuration = WKWebViewConfiguration()
114         self.urlRequest = URLRequest(url: URL(string: "http://")!)
115         self.activities = nil
116         super.init(coder: aDecoder)
117     }
118
119     deinit {
120         webView.removeObserver(self, forKeyPath: titleKeyPath, context: nil)
121         webView.removeObserver(self, forKeyPath: estimatedProgressKeyPath, context: nil)
122     }
123
124
125     // MARK: View lifecycle
126
127     /// :nodoc:
128     open override func viewDidLoad() {
129         super.viewDidLoad()
130         title = urlRequest.url?.host
131         view.addSubview(_webView)
132         view.addSubview(_progressBar)
133
134         if presentingViewController?.presentedViewController != nil {
135             navigationItem.leftBarButtonItem = UIBarButtonItem(barButtonSystemItem: .done,
136                                                                target: self,
137                                                                action: #selector(didTapDoneButton(_:)))
138         }
139
140         navigationItem.rightBarButtonItem = UIBarButtonItem(barButtonSystemItem: .action,
141                                                             target: self,
142                                                             action: #selector(didTapActionButton(_:)))
143
144         webView.load(urlRequest)
145     }
146
147     /// :nodoc:
148     open override func viewWillAppear(_ animated: Bool) {
149         assert(navigationController != nil, "\(WebViewController.self) must be presented in a \(UINavigationController.self)")
150         super.viewWillAppear(animated)
151     }
152
153     /// :nodoc:
154     open override func viewDidDisappear(_ animated: Bool) {
155         super.viewDidDisappear(animated)
156         webView.stopLoading()
157     }
158
159     /// :nodoc:
160     open override func viewDidLayoutSubviews() {
161         super.viewDidLayoutSubviews()
162         webView.frame = view.bounds
163
164         let isIOS11 = ProcessInfo.processInfo.isOperatingSystemAtLeast(
165             OperatingSystemVersion(majorVersion: 11, minorVersion: 0, patchVersion: 0))
166         let top = isIOS11 ? CGFloat(0.0) : topLayoutGuide.length
167         let insets = UIEdgeInsets(top: top, left: 0, bottom: 0, right: 0)
168         webView.scrollView.contentInset = insets
169         webView.scrollView.scrollIndicatorInsets = insets
170
171         view.bringSubview(toFront: progressBar)
172         progressBar.frame = CGRect(x: view.frame.minX,
173                                    y: topLayoutGuide.length,
174                                    width: view.frame.size.width,
175                                    height: 2)
176     }
177
178
179     // MARK: Actions
180
181     @objc private func didTapDoneButton(_ sender: UIBarButtonItem) {
182         dismiss(animated: true, completion: nil)
183     }
184
185     @objc private func didTapActionButton(_ sender: UIBarButtonItem) {
186         if let url = urlRequest.url {
187             let activityVC = UIActivityViewController(activityItems: [url], applicationActivities: activities)
188             activityVC.popoverPresentationController?.barButtonItem = sender
189             present(activityVC, animated: true, completion: nil)
190         }
191     }
192
193
194     // MARK: KVO
195
196     /// :nodoc:
197     open override func observeValue(forKeyPath keyPath: String?,
198                                     of object: Any?,
199                                     change: [NSKeyValueChangeKey : Any]?,
200                                     context: UnsafeMutableRawPointer?) {
201         guard let theKeyPath = keyPath , object as? WKWebView == webView else {
202             super.observeValue(forKeyPath: keyPath, of: object, change: change, context: context)
203             return
204         }
205
206         if displaysWebViewTitle && theKeyPath == titleKeyPath {
207             title = webView.title
208         }
209         
210         if theKeyPath == estimatedProgressKeyPath {
211             updateProgress()
212         }
213     }
214     
215     // MARK: Private
216     
217     private final func updateProgress() {
218         let completed = webView.estimatedProgress == 1.0
219         progressBar.setProgress(completed ? 0.0 : Float(webView.estimatedProgress), animated: !completed)
220         UIApplication.shared.isNetworkActivityIndicatorVisible = !completed
221     }
222 }