Files
GitHawk/Classes/Repository/RepositoryWebViewController.swift
Ivan Magda 6c3c451677 Add PDF support (#1596)
* Add string extension for searching pdf files (#1552)

* Create RepositoryWebViewController (#1552)

* Initial presenting of the pdf files (#1552)

* refactor: Rename String+Resource -> String+BinaryFile (#1552)

* Build destination URL (#1552)

* Configure title (#1552)

* Encode file path

* Use EmptyView for errors

* Replace UIWebView with WKWebView

* Review fixes

* refactor: Make binarySuffix computed property

* Unify if-else path

* Group guard statements
2018-03-11 15:59:51 -04:00

204 lines
5.4 KiB
Swift

//
// RepositoryWebViewController.swift
// Freetime
//
// Created by Ivan Magda on 01/03/2018.
// Copyright © 2018 Ryan Nystrom. All rights reserved.
//
import UIKit
import WebKit
// MARK: RepositoryWebViewController: UIViewController
final class RepositoryWebViewController: UIViewController {
// MARK: Types
private enum State {
case idle
case fetching
case error(String?)
}
// MARK: Instance Variables
private let branch: String
private let path: FilePath
private let repo: RepositoryDetails
private var state = State.idle {
didSet {
switch state {
case .idle:
activityIndicator.stopAnimating()
emptyView.isHidden = true
webView.isHidden = false
case .fetching:
activityIndicator.startAnimating()
emptyView.isHidden = true
webView.isHidden = false
case .error(let message):
activityIndicator.stopAnimating()
webView.isHidden = true
emptyView.isHidden = false
emptyView.label.text = message
}
}
}
private var resourceURL: URL? {
guard let encodedPath = path.path.addingPercentEncoding(withAllowedCharacters: .urlHostAllowed) else {
return nil
}
return URL(string: "https://github.com/\(repo.owner)/\(repo.name)/raw/\(branch)/\(encodedPath)")
}
private lazy var webView: WKWebView = {
let webView = WKWebView()
webView.translatesAutoresizingMaskIntoConstraints = false
webView.navigationDelegate = self
webView.backgroundColor = .white
return webView
}()
private let emptyView = EmptyView()
private lazy var activityIndicator: UIActivityIndicatorView = {
let activityIndicator = UIActivityIndicatorView(activityIndicatorStyle: .gray)
activityIndicator.hidesWhenStopped = true
return activityIndicator
}()
// MARK: Init
init(
repo: RepositoryDetails,
branch: String,
path: FilePath
) {
self.repo = repo
self.branch = branch
self.path = path
super.init(nibName: nil, bundle: nil)
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
// MARK: UIViewController Lifecycle
override func viewDidLoad() {
super.viewDidLoad()
setup()
fetch()
}
override func viewWillLayoutSubviews() {
super.viewWillLayoutSubviews()
emptyView.frame = view.bounds
activityIndicator.center = view.center
if let tabBarController = tabBarController {
webView.scrollView.contentInset.bottom = tabBarController.tabBar.bounds.height
}
}
}
// MARK: - RepositoryWebViewController (UIWebViewDelegate) -
extension RepositoryWebViewController: WKNavigationDelegate {
func webView(_ webView: WKWebView, didStartProvisionalNavigation navigation: WKNavigation!) {
state = .fetching
}
func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
state = .idle
}
func webView(_ webView: WKWebView, didFail navigation: WKNavigation!, withError error: Error) {
showError(cannotLoad: true)
}
}
// MARK: - RepositoryWebViewController (Fetch Data) -
extension RepositoryWebViewController {
private func fetch() {
guard let url = resourceURL else { return showError(cannotLoad: false) }
state = .fetching
URLSession.shared.dataTask(with: url) { [weak self] (data, _, error) in
DispatchQueue.main.async {
guard let strongSelf = self else { return }
guard error == nil,
let data = data else { return strongSelf.showError(cannotLoad: true) }
strongSelf.webView.load(
data,
mimeType: strongSelf.path.mimeType ?? "text/plain",
characterEncodingName: "UTF-8",
baseURL: url
)
}
}.resume()
}
}
// MARK: - RepositoryWebViewController (Actions) -
extension RepositoryWebViewController {
@objc private func onFileNavigationTitle(sender: UIView) {
showAlert(filePath: path, sender: sender)
}
}
// MARK: - RepositoryWebViewController (Private Helpers) -
extension RepositoryWebViewController {
private func setup() {
makeBackBarItemEmpty()
configureTitle(
filePath: path,
target: self,
action: #selector(onFileNavigationTitle(sender:))
)
state = .idle
emptyView.isHidden = true
view.backgroundColor = .white
view.addSubview(emptyView)
view.addSubview(webView)
view.addSubview(activityIndicator)
NSLayoutConstraint.activate([
webView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
webView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
webView.topAnchor.constraint(equalTo: view.topAnchor),
webView.bottomAnchor.constraint(equalTo: view.bottomAnchor)
])
}
private func showError(cannotLoad: Bool) {
state = .error(cannotLoad
? NSLocalizedString("Cannot display file", comment: "")
: NSLocalizedString("Error loading file", comment: "")
)
}
}