spiegel-keyman/ios/keyman/Keyman/Keyman/KMWebBrowser/WebBrowserViewController.swift
2017-11-16 16:31:45 +07:00

291 lines
11 KiB
Swift

//
// WebBrowserViewController.swift
// Keyman
//
// Created by Gabriel Wong on 2017-09-05.
// Copyright © 2017 SIL International. All rights reserved.
//
import KeymanEngine
import UIKit
class WebBrowserViewController: UIViewController, UIWebViewDelegate, UIAlertViewDelegate {
@IBOutlet var webView: UIWebView!
@IBOutlet var navBar: UINavigationBar!
@IBOutlet var toolBar: UIToolbar!
@IBOutlet var navBarTopConstraint: NSLayoutConstraint!
private var addressField: UITextField!
private var rightView: UIView!
private var refreshButton: UIButton!
private var stopButton: UIButton!
@IBOutlet var backButton: UIBarButtonItem!
@IBOutlet var forwardButton: UIBarButtonItem!
@IBOutlet var bookmarksButton: UIBarButtonItem!
@IBOutlet var globeButton: UIBarButtonItem!
@IBOutlet var closeButton: UIBarButtonItem!
var fontFamily = UIFont.systemFont(ofSize: UIFont.systemFontSize).fontName
private var newFontFamily = ""
private let webBrowserLastURLKey = "KMWebBrowserLastURL"
private var keyboardChangedObserver: NotificationObserver?
private var keyboardPickerDismissedObserver: NotificationObserver?
convenience init() {
self.init(nibName: "WebBrowserViewController", bundle: nil)
}
override func viewDidLoad() {
super.viewDidLoad()
keyboardChangedObserver = NotificationCenter.default.addObserver(
forName: Notifications.keyboardChanged,
observer: self,
function: WebBrowserViewController.keyboardChanged)
keyboardPickerDismissedObserver = NotificationCenter.default.addObserver(
forName: Notifications.keyboardPickerDismissed,
observer: self,
function: WebBrowserViewController.keyboardPickerDismissed)
webView.delegate = self
webView.scalesPageToFit = true
// Setup NavigationBar
let screenRect = UIScreen.main.bounds
let orientation = UIApplication.shared.statusBarOrientation
if UIDevice.current.userInterfaceIdiom == .phone {
let size = CGFloat.maximum(screenRect.size.height, screenRect.size.width)
if size > 568.0 {
// Navbar for iPhone 6 & 6 Plus
let image: UIImage
if UIInterfaceOrientationIsPortrait(orientation) {
image = #imageLiteral(resourceName: "kmwb-navbar-Portrait.png")
} else {
image = #imageLiteral(resourceName: "kmwb-navbar-Landscape-568h.png")
}
let bgImg = image.resizableImage(
withCapInsets: UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0), resizingMode: .stretch)
navBar.setBackgroundImage(bgImg, for: UIBarMetrics.default)
} else if size == 568 {
// Navbar for iPhone and iPod Touch with 4" Display
navBar.setBackgroundImage(#imageLiteral(resourceName: "kmwb-navbar-Portrait.png"),
for: UIBarMetrics.default)
navBar.setBackgroundImage(#imageLiteral(resourceName: "kmwb-navbar-Landscape-568h.png"),
for: UIBarMetrics.compact)
} else if size < 568.0 {
// Navbar for iPhone and iPod Touch with 3.5" Display
navBar.setBackgroundImage(#imageLiteral(resourceName: "kmwb-navbar-Portrait.png"),
for: UIBarMetrics.default)
navBar.setBackgroundImage(#imageLiteral(resourceName: "kmwb-navbar-Landscape.png"),
for: UIBarMetrics.compact)
}
} else {
// Navbar for iPad
if UIInterfaceOrientationIsPortrait(orientation) {
navBar.setBackgroundImage(#imageLiteral(resourceName: "kmwb-navbar-Portrait.png"), for: UIBarMetrics.default)
} else {
navBar.setBackgroundImage(#imageLiteral(resourceName: "kmwb-navbar-Landscape.png"), for: UIBarMetrics.default)
}
}
// Setup address field
let addressFrame = CGRect(x: 10, y: 4.0, width: navBar.frame.size.width - 20, height: 28)
addressField = UITextField(frame: addressFrame)
addressField.clearButtonMode = .whileEditing
addressField.rightViewMode = .unlessEditing
addressField.autoresizingMask = .flexibleWidth
addressField.borderStyle = .roundedRect
addressField.autocapitalizationType = .none
addressField.autocorrectionType = .no
addressField.font = UIFont.systemFont(ofSize: 17)
addressField.placeholder = "http://"
addressField.text = ""
addressField.keyboardType = UIKeyboardType.URL
addressField.addTarget(self, action: #selector(self.loadAddress), for: .editingDidEndOnExit)
navBar.addSubview(addressField)
rightView = UIView(frame: CGRect(x: 0, y: 0, width: 40, height: 28))
addressField.rightView = rightView
let refreshSize = CGSize(width: 18, height: 22)
let refreshIcon = #imageLiteral(resourceName: "UIButtonBarRefresh.png").resize(to: refreshSize)
.withRenderingMode(.alwaysOriginal)
refreshButton = UIButton(type: UIButtonType.system)
refreshButton.setImage(refreshIcon, for: .normal)
refreshButton.frame = rightView.frame
refreshButton.addTarget(self, action: #selector(self.refresh), for: .touchUpInside)
refreshButton.isHidden = true
rightView.addSubview(refreshButton)
let stopSize = CGSize(width: 17, height: 17)
let stopIcon = #imageLiteral(resourceName: "UIButtonBarStop.png").resize(to: stopSize)
.withRenderingMode(.alwaysOriginal)
stopButton = UIButton(type: UIButtonType.system)
stopButton.setImage(stopIcon, for: .normal)
stopButton.frame = rightView.frame
stopButton.addTarget(self, action: #selector(self.stop), for: .touchUpInside)
stopButton.isHidden = true
rightView.addSubview(stopButton)
updateButtons()
let userData = UserDefaults.standard
let lastUrlStr = userData.object(forKey: webBrowserLastURLKey) as? String ?? "https://www.google.com/"
if let url = URL(string: lastUrlStr) {
let request = URLRequest(url: url)
webView.loadRequest(request)
}
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
navBarTopConstraint.constant = AppDelegate.statusBarHeight()
}
override func willRotate(to toInterfaceOrientation: UIInterfaceOrientation, duration: TimeInterval) {
let orientation: UIInterfaceOrientation = toInterfaceOrientation
if UIDevice.current.userInterfaceIdiom == .phone {
let screenRect = UIScreen.main.bounds
let size = CGFloat.maximum(screenRect.size.width, screenRect.size.height)
if size > 568.0 {
// TODO: Refactor since duplicated in viewDidLoad()
// Navbar for iPhone 6 & 6 Plus
let image: UIImage
if UIInterfaceOrientationIsPortrait(orientation) {
image = #imageLiteral(resourceName: "kmwb-navbar-Portrait.png")
} else {
image = #imageLiteral(resourceName: "kmwb-navbar-Landscape-568h.png")
}
let bgImg = image.resizableImage(
withCapInsets: UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0), resizingMode: .stretch)
navigationController?.navigationBar.setBackgroundImage(bgImg, for: UIBarMetrics.default)
}
} else {
let image: UIImage
if UIInterfaceOrientationIsPortrait(orientation) {
image = #imageLiteral(resourceName: "kmwb-navbar-Portrait.png")
} else {
image = #imageLiteral(resourceName: "kmwb-navbar-Landscape.png")
}
navigationController?.navigationBar.setBackgroundImage(image, for: UIBarMetrics.default)
}
}
override func didRotate(from fromInterfaceOrientation: UIInterfaceOrientation) {
navBarTopConstraint.constant = AppDelegate.statusBarHeight()
}
@objc func loadAddress(_ sender: Any, event: UIEvent) {
guard let urlString = addressField?.text, var url = URL(string: urlString) else {
#if DEBUG
NSLog("Attempting to load invalid URL: %@", addressField?.text ?? "nil")
#endif
return
}
if url.scheme == nil {
url = URL(string: "http://\(urlString)") ?? url
}
let request = URLRequest(url: url)
webView.loadRequest(request)
}
func updateAddress(_ request: URLRequest) {
let url: URL? = request.mainDocumentURL
addressField.text = url?.absoluteString
let userData = UserDefaults.standard
userData.set(url?.absoluteString, forKey: "KMWebBrowserLastURL")
userData.synchronize()
}
@objc func refresh(_ sender: Any) {
webView.reload()
}
@objc func stop(_ sender: Any?) {
webView.stopLoading()
}
@IBAction func back(_ sender: Any) {
webView.goBack()
}
@IBAction func forward(_ sender: Any) {
webView.goForward()
}
@IBAction func bookmarks(_ sender: Any) {
let bookmarksVC = BookmarksViewController()
bookmarksVC.webBrowser = self
present(bookmarksVC, animated: true, completion: nil)
}
@IBAction func globe(_ sender: Any) {
Manager.shared.showKeyboardPicker(in: self, shouldAddKeyboard: false)
}
@objc func close(_ sender: Any?) {
dismiss(animated: true, completion: nil)
}
func webView(_ webView: UIWebView,
shouldStartLoadWith request: URLRequest,
navigationType: UIWebViewNavigationType) -> Bool {
updateAddress(request)
return true
}
func webViewDidStartLoad(_ webView: UIWebView) {
UIApplication.shared.isNetworkActivityIndicatorVisible = true
updateButtons()
}
func webViewDidFinishLoad(_ webView: UIWebView) {
UIApplication.shared.isNetworkActivityIndicatorVisible = false
appendCSSFontFamily()
updateButtons()
}
func webView(_ webView: UIWebView, didFailLoadWithError error: Error) {
UIApplication.shared.isNetworkActivityIndicatorVisible = false
updateButtons()
let alert = UIAlertView(title: "Cannot Open Page",
message: error.localizedDescription,
delegate: self,
cancelButtonTitle: "OK",
otherButtonTitles: "")
alert.show()
}
private func updateButtons() {
refreshButton.isHidden = webView.isLoading
stopButton.isHidden = !webView.isLoading
backButton.isEnabled = webView.canGoBack
forwardButton.isEnabled = webView.canGoForward
}
private func appendCSSFontFamily() {
let jsStr: String = "var style = document.createElement('style');" +
"style.type = 'text/css';" +
"style.innerHTML = '*{font-family:\"\(fontFamily)\" !important;}';" +
"document.getElementsByTagName('head')[0].appendChild(style);"
webView?.stringByEvaluatingJavaScript(from: jsStr)
}
private func keyboardChanged(_ kb: InstallableKeyboard) {
if let fontName = Manager.shared.fontNameForKeyboard(withID: kb.id, languageID: kb.languageID) {
newFontFamily = fontName
} else {
newFontFamily = UIFont.systemFont(ofSize: UIFont.systemFontSize).fontName
}
}
private func keyboardPickerDismissed() {
if newFontFamily != fontFamily {
fontFamily = newFontFamily
webView?.reload()
}
}
}