diff --git a/SBrowser.xcodeproj/project.pbxproj b/SBrowser.xcodeproj/project.pbxproj index d4fd467..c867b04 100644 --- a/SBrowser.xcodeproj/project.pbxproj +++ b/SBrowser.xcodeproj/project.pbxproj @@ -7,6 +7,7 @@ objects = { /* Begin PBXBuildFile section */ + 1A14FC2324D203D9009B3F83 /* TitlebarView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A14FC2224D203D9009B3F83 /* TitlebarView.swift */; }; 1ADFF46024C7DE53006DC7AE /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1ADFF45F24C7DE53006DC7AE /* AppDelegate.swift */; }; 1ADFF46224C7DE53006DC7AE /* SceneDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1ADFF46124C7DE53006DC7AE /* SceneDelegate.swift */; }; 1ADFF46924C7DE54006DC7AE /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 1ADFF46824C7DE54006DC7AE /* Assets.xcassets */; }; @@ -52,6 +53,7 @@ /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ + 1A14FC2224D203D9009B3F83 /* TitlebarView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TitlebarView.swift; sourceTree = ""; }; 1ADFF45C24C7DE53006DC7AE /* SBrowser.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = SBrowser.app; sourceTree = BUILT_PRODUCTS_DIR; }; 1ADFF45F24C7DE53006DC7AE /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 1ADFF46124C7DE53006DC7AE /* SceneDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SceneDelegate.swift; sourceTree = ""; }; @@ -151,6 +153,7 @@ children = ( 1ADFF47324C7DE9C006DC7AE /* BrowserViewController.swift */, 1ADFF47824C7DFF8006DC7AE /* BrowserView.swift */, + 1A14FC2224D203D9009B3F83 /* TitlebarView.swift */, 1ADFF4C824CA793E006DC7AE /* ToolbarViewController.swift */, 1ADFF4BF24CA6964006DC7AE /* URLBar.swift */, ); @@ -326,6 +329,7 @@ 1ADFF4C924CA793E006DC7AE /* ToolbarViewController.swift in Sources */, 1ADFF4CD24CBB0C8006DC7AE /* ScriptPolicyViewController.swift in Sources */, 1ADFF47924C7DFF8006DC7AE /* BrowserView.swift in Sources */, + 1A14FC2324D203D9009B3F83 /* TitlebarView.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/SBrowser/Browser View/BrowserView.swift b/SBrowser/Browser View/BrowserView.swift index cfa6db3..402bdcc 100644 --- a/SBrowser/Browser View/BrowserView.swift +++ b/SBrowser/Browser View/BrowserView.swift @@ -11,6 +11,8 @@ import WebKit class BrowserView: UIView { + let titlebarView = TitlebarView() + var toolbarView: ToolbarView? { didSet { addSubview(toolbarView!) } } @@ -32,6 +34,8 @@ class BrowserView: UIView convenience init() { self.init(frame: .zero) + addSubview(titlebarView) + keyboardWillShowObserver = NotificationCenter.default.publisher(for: UIWindow.keyboardWillShowNotification).sink { notification in if let keyboardFrame = notification.userInfo?[UIWindow.keyboardFrameEndUserInfoKey] as? CGRect { self.keyboardLayoutOffset = self.bounds.height - keyboardFrame.minY @@ -59,5 +63,21 @@ class BrowserView: UIView toolbarView.bounds = CGRect(origin: .zero, size: toolbarSize) toolbarView.center = CGPoint(x: bounds.center.x, y: bounds.maxY - (toolbarView.bounds.height / 2) - keyboardLayoutOffset) } + + bringSubviewToFront(titlebarView) + + var titlebarHeight: CGFloat = 24.0 + titlebarHeight += safeAreaInsets.top + + titlebarView.frame = CGRect(origin: .zero, size: CGSize(width: bounds.width, height: titlebarHeight)) + + // Fix web view content insets + webView?.scrollView.automaticallyAdjustsScrollIndicatorInsets = false + + var webViewContentInset = UIEdgeInsets() + webViewContentInset.top = titlebarView.frame.height + webViewContentInset.bottom = toolbarView?.frame.height ?? 0 + webView?.scrollView.contentInset = webViewContentInset + webView?.scrollView.scrollIndicatorInsets = webViewContentInset } } diff --git a/SBrowser/Browser View/BrowserViewController.swift b/SBrowser/Browser View/BrowserViewController.swift index f65fe0e..ecb5866 100644 --- a/SBrowser/Browser View/BrowserViewController.swift +++ b/SBrowser/Browser View/BrowserViewController.swift @@ -19,8 +19,11 @@ class BrowserViewController: UIViewController, private var blockedScriptOrigins = Set() override var canBecomeFirstResponder: Bool { true } + private var titleObservation: NSKeyValueObservation? private var loadingObservation: NSKeyValueObservation? + override var preferredStatusBarStyle: UIStatusBarStyle { .lightContent } + init() { super.init(nibName: nil, bundle: nil) } @@ -64,6 +67,11 @@ class BrowserViewController: UIViewController, self.toolbarController.urlBar.loadProgress = .loading(progress: webView.estimatedProgress) } + // Title observer + titleObservation = webView.observe(\.title, changeHandler: { (webView, observedChange) in + self.browserView.titlebarView.titleLabelView.text = webView.title + }) + self.view = browserView } diff --git a/SBrowser/Browser View/TitlebarView.swift b/SBrowser/Browser View/TitlebarView.swift new file mode 100644 index 0000000..50a5348 --- /dev/null +++ b/SBrowser/Browser View/TitlebarView.swift @@ -0,0 +1,60 @@ +// +// TitlebarView.swift +// SBrowser +// +// Created by James Magahern on 7/29/20. +// + +import UIKit + +class TitlebarView: UIView +{ + public let titleLabelView = UILabel(frame: .zero) + private let backgroundImageView = UIImageView(frame: .zero) + + convenience init() { + self.init(frame: .zero) + addSubview(backgroundImageView) + addSubview(titleLabelView) + + titleLabelView.textColor = .white + titleLabelView.layer.shadowColor = UIColor.black.cgColor + titleLabelView.layer.shadowRadius = 0.0 + titleLabelView.layer.shadowOffset = CGSize(width: 0.0, height: 2.0) + titleLabelView.font = UIFont.boldSystemFont(ofSize: 12.0) + } + + private func backgroundImageForSize(_ size: CGSize) -> UIImage? { + var image: UIImage? = nil + + UIGraphicsBeginImageContext(CGSize(width: size.width, height: 1.0)) + if let context = UIGraphicsGetCurrentContext() { + let gradientColorsArray = [ + UIColor(red: 0.101, green: 0.176, blue: 0.415, alpha: 1.0).cgColor, + UIColor(red: 0.153, green: 0.000, blue: 0.153, alpha: 1.0).cgColor + ] + + if let gradient = CGGradient(colorsSpace: nil, colors: gradientColorsArray as CFArray, locations: nil) { + context.drawLinearGradient(gradient, start: .zero, end: CGPoint(x: size.width, y: 0.0), options: CGGradientDrawingOptions()) + } + + image = UIGraphicsGetImageFromCurrentImageContext() + UIGraphicsEndImageContext(); + } + + return image + } + + override func layoutSubviews() { + super.layoutSubviews() + + backgroundImageView.frame = bounds + titleLabelView.frame = bounds.avoiding(verticalInsets: safeAreaInsets).insetBy(dx: 8.0, dy: 0.0) + + if let image = backgroundImageView.image, image.size == bounds.size { + // No op + } else { + backgroundImageView.image = backgroundImageForSize(bounds.size) + } + } +} diff --git a/SBrowser/Browser View/URLBar.swift b/SBrowser/Browser View/URLBar.swift index 2221403..cd912a0 100644 --- a/SBrowser/Browser View/URLBar.swift +++ b/SBrowser/Browser View/URLBar.swift @@ -46,7 +46,7 @@ class URLBar: UIView textField.keyboardType = .webSearch textField.autocorrectionType = .no textField.autocapitalizationType = .none - textField.font = .preferredFont(forTextStyle: .body) + textField.font = .systemFont(ofSize: 14.0) textField.clearingBehavior = .clearOnInsertionAndShowSelectionTint addSubview(textField) diff --git a/SBrowser/Utilities/CGPoint+Utils.swift b/SBrowser/Utilities/CGPoint+Utils.swift index 13bd96d..9d38d73 100644 --- a/SBrowser/Utilities/CGPoint+Utils.swift +++ b/SBrowser/Utilities/CGPoint+Utils.swift @@ -14,4 +14,12 @@ extension CGRect return CGPoint(x: size.width / 2.0, y: size.height / 2.0) } } + + public func avoiding(verticalInsets insets: UIEdgeInsets) -> CGRect { + var rect = self + rect.origin.y += insets.top + rect.size.height -= insets.top + + return rect + } }