Show SSL status in titlebar
This commit is contained in:
@@ -32,6 +32,7 @@ class BrowserViewController: UIViewController
|
|||||||
private var loadingObservation: NSKeyValueObservation?
|
private var loadingObservation: NSKeyValueObservation?
|
||||||
private var backButtonObservation: NSKeyValueObservation?
|
private var backButtonObservation: NSKeyValueObservation?
|
||||||
private var forwardButtonObservation: NSKeyValueObservation?
|
private var forwardButtonObservation: NSKeyValueObservation?
|
||||||
|
private var hasSecureContentObservation: NSKeyValueObservation?
|
||||||
private var activeTabObservation: AnyCancellable?
|
private var activeTabObservation: AnyCancellable?
|
||||||
private var faviconObservation: AnyCancellable?
|
private var faviconObservation: AnyCancellable?
|
||||||
|
|
||||||
@@ -454,15 +455,21 @@ class BrowserViewController: UIViewController
|
|||||||
|
|
||||||
// Back/forward observer
|
// Back/forward observer
|
||||||
toolbarController.backButton.isEnabled = webView.canGoBack
|
toolbarController.backButton.isEnabled = webView.canGoBack
|
||||||
backButtonObservation = webView.observe(\.canGoBack, changeHandler: { [toolbarController] (webView, observedChange) in
|
backButtonObservation = webView.observe(\.canGoBack, changeHandler: { [unowned self] (webView, observedChange) in
|
||||||
toolbarController.backButton.isEnabled = webView.canGoBack
|
toolbarController.backButton.isEnabled = webView.canGoBack
|
||||||
})
|
})
|
||||||
|
|
||||||
toolbarController.forwardButton.isEnabled = webView.canGoForward
|
toolbarController.forwardButton.isEnabled = webView.canGoForward
|
||||||
forwardButtonObservation = webView.observe(\.canGoForward, changeHandler: { [toolbarController] (webView, observedChange) in
|
forwardButtonObservation = webView.observe(\.canGoForward, changeHandler: { [unowned self] (webView, observedChange) in
|
||||||
toolbarController.forwardButton.isEnabled = webView.canGoForward
|
toolbarController.forwardButton.isEnabled = webView.canGoForward
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// Secure content
|
||||||
|
browserView.titlebarView.showsSecurityIndicator = webView.hasOnlySecureContent
|
||||||
|
hasSecureContentObservation = webView.observe(\.hasOnlySecureContent, changeHandler: { [unowned self] (webView, observedChange) in
|
||||||
|
browserView.titlebarView.showsSecurityIndicator = webView.hasOnlySecureContent
|
||||||
|
})
|
||||||
|
|
||||||
// Favicon observation
|
// Favicon observation
|
||||||
faviconObservation = tab.$favicon.receive(on: DispatchQueue.main)
|
faviconObservation = tab.$favicon.receive(on: DispatchQueue.main)
|
||||||
.sink { [unowned self] _ in
|
.sink { [unowned self] _ in
|
||||||
|
|||||||
@@ -8,8 +8,51 @@
|
|||||||
import UIKit
|
import UIKit
|
||||||
import QuartzCore_Private
|
import QuartzCore_Private
|
||||||
|
|
||||||
|
class SecurityIndicatorView: UIView
|
||||||
|
{
|
||||||
|
let imageView = UIImageView(image: UIImage(systemName: "lock.fill"))
|
||||||
|
let label = UILabel(frame: .zero)
|
||||||
|
|
||||||
|
var labelVisible: Bool = true { didSet { setNeedsLayout() } }
|
||||||
|
|
||||||
|
private let imageViewPadding = CGFloat(3.0)
|
||||||
|
|
||||||
|
convenience init() {
|
||||||
|
self.init(frame: .zero)
|
||||||
|
|
||||||
|
addSubview(imageView)
|
||||||
|
addSubview(label)
|
||||||
|
|
||||||
|
label.text = "Secure Connection"
|
||||||
|
imageView.contentMode = .scaleAspectFit
|
||||||
|
}
|
||||||
|
|
||||||
|
override func sizeThatFits(_ size: CGSize) -> CGSize {
|
||||||
|
var size = CGSize(width: imageView.intrinsicContentSize.width, height: size.height)
|
||||||
|
if labelVisible {
|
||||||
|
size.width += label.sizeThatFits(size).width + imageViewPadding
|
||||||
|
}
|
||||||
|
|
||||||
|
return size
|
||||||
|
}
|
||||||
|
|
||||||
|
override func layoutSubviews() {
|
||||||
|
super.layoutSubviews()
|
||||||
|
|
||||||
|
imageView.frame = CGRect(x: 0, y: 0, width: bounds.height, height: bounds.height)
|
||||||
|
if labelVisible {
|
||||||
|
label.isHidden = false
|
||||||
|
label.frame = CGRect(x: imageView.frame.maxX + imageViewPadding, y: 1.0, width: bounds.width - (imageView.frame.maxX + imageViewPadding), height: bounds.height)
|
||||||
|
} else {
|
||||||
|
label.isHidden = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
class TitlebarView: UIView
|
class TitlebarView: UIView
|
||||||
{
|
{
|
||||||
|
public var showsSecurityIndicator: Bool = false { didSet { setNeedsLayout() } }
|
||||||
|
|
||||||
private let titleLabelView = UILabel(frame: .zero)
|
private let titleLabelView = UILabel(frame: .zero)
|
||||||
private let backgroundView = GradientView(direction: .horizontal, colors: [
|
private let backgroundView = GradientView(direction: .horizontal, colors: [
|
||||||
UIColor(red: 0.101, green: 0.176, blue: 0.415, alpha: 1.0),
|
UIColor(red: 0.101, green: 0.176, blue: 0.415, alpha: 1.0),
|
||||||
@@ -17,11 +60,13 @@ class TitlebarView: UIView
|
|||||||
])
|
])
|
||||||
|
|
||||||
private let separatorView = UIView(frame: .zero)
|
private let separatorView = UIView(frame: .zero)
|
||||||
|
private let securityIndicatorView = SecurityIndicatorView()
|
||||||
|
|
||||||
convenience init() {
|
convenience init() {
|
||||||
self.init(frame: .zero)
|
self.init(frame: .zero)
|
||||||
addSubview(backgroundView)
|
addSubview(backgroundView)
|
||||||
addSubview(titleLabelView)
|
addSubview(titleLabelView)
|
||||||
|
addSubview(securityIndicatorView)
|
||||||
addSubview(separatorView)
|
addSubview(separatorView)
|
||||||
|
|
||||||
separatorView.backgroundColor = UIColor(white: 1.0, alpha: 0.20)
|
separatorView.backgroundColor = UIColor(white: 1.0, alpha: 0.20)
|
||||||
@@ -33,6 +78,11 @@ class TitlebarView: UIView
|
|||||||
titleLabelView.layer.shadowOffset = CGSize(width: 0.0, height: 2.0)
|
titleLabelView.layer.shadowOffset = CGSize(width: 0.0, height: 2.0)
|
||||||
titleLabelView.font = UIFont.boldSystemFont(ofSize: 12.0)
|
titleLabelView.font = UIFont.boldSystemFont(ofSize: 12.0)
|
||||||
|
|
||||||
|
let securityIndicatorLabelColor = UIColor(white: 1.0, alpha: 0.7)
|
||||||
|
securityIndicatorView.imageView.tintColor = securityIndicatorLabelColor
|
||||||
|
securityIndicatorView.label.textColor = securityIndicatorLabelColor
|
||||||
|
securityIndicatorView.label.font = UIFont.systemFont(ofSize: 10.0)
|
||||||
|
|
||||||
backgroundView.alpha = 0.98
|
backgroundView.alpha = 0.98
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -66,8 +116,44 @@ class TitlebarView: UIView
|
|||||||
override func layoutSubviews() {
|
override func layoutSubviews() {
|
||||||
super.layoutSubviews()
|
super.layoutSubviews()
|
||||||
|
|
||||||
|
let edgePadding: CGFloat = 8.0
|
||||||
|
|
||||||
|
// Thought it would be cool to have a different style for regular, but eh.
|
||||||
|
let securityLabelOnTrailingSide = false // (traitCollection.horizontalSizeClass == .regular)
|
||||||
|
securityIndicatorView.labelVisible = securityLabelOnTrailingSide
|
||||||
|
|
||||||
|
var securityIndicatorSize = showsSecurityIndicator ? securityIndicatorView.sizeThatFits(bounds.size) : .zero
|
||||||
|
securityIndicatorSize.height = 10.0
|
||||||
|
|
||||||
backgroundView.frame = bounds
|
backgroundView.frame = bounds
|
||||||
titleLabelView.frame = bounds.avoiding(verticalInsets: safeAreaInsets).insetBy(dx: 8.0 + layoutMargins.left, dy: 0.0)
|
titleLabelView.frame = bounds
|
||||||
|
.avoiding(verticalInsets: safeAreaInsets)
|
||||||
|
.insetBy(dx: edgePadding + layoutMargins.left, dy: 0.0)
|
||||||
|
.subtracting(width: securityIndicatorSize.width, height: 0)
|
||||||
|
|
||||||
|
if showsSecurityIndicator {
|
||||||
|
securityIndicatorView.isHidden = false
|
||||||
|
|
||||||
|
if !securityLabelOnTrailingSide {
|
||||||
|
securityIndicatorView.frame = CGRect(
|
||||||
|
origin: CGPoint(x: edgePadding + layoutMargins.left, y: 0.0),
|
||||||
|
size: CGSize(width: securityIndicatorSize.height, height: securityIndicatorSize.height)
|
||||||
|
)
|
||||||
|
|
||||||
|
// Scooch the title over a bit
|
||||||
|
titleLabelView.frame.origin.x = securityIndicatorView.frame.maxX + 4.0
|
||||||
|
} else {
|
||||||
|
securityIndicatorView.frame = CGRect(
|
||||||
|
x: bounds.width - layoutMargins.right - securityIndicatorSize.width, y: 0.0,
|
||||||
|
width: securityIndicatorSize.width,
|
||||||
|
height: securityIndicatorSize.height
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
securityIndicatorView.frame = securityIndicatorView.frame.centeredY(inRect: titleLabelView.frame)
|
||||||
|
} else {
|
||||||
|
securityIndicatorView.isHidden = true
|
||||||
|
}
|
||||||
|
|
||||||
let separatorHeight = 1.0 / UIScreen.main.scale
|
let separatorHeight = 1.0 / UIScreen.main.scale
|
||||||
separatorView.frame = CGRect(x: 0, y: bounds.height - separatorHeight, width: bounds.width, height: separatorHeight)
|
separatorView.frame = CGRect(x: 0, y: bounds.height - separatorHeight, width: bounds.width, height: separatorHeight)
|
||||||
|
|||||||
@@ -23,16 +23,24 @@ extension CGRect
|
|||||||
return rect
|
return rect
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public func subtracting(width: CGFloat, height: CGFloat) -> CGRect {
|
||||||
|
var rect = self
|
||||||
|
rect.size.width -= width
|
||||||
|
rect.size.height -= height
|
||||||
|
|
||||||
|
return rect
|
||||||
|
}
|
||||||
|
|
||||||
public func centeredY(inRect: CGRect) -> CGRect {
|
public func centeredY(inRect: CGRect) -> CGRect {
|
||||||
var rect = self
|
var rect = self
|
||||||
rect.origin.y = CGRound((inRect.height - rect.height) / 2.0)
|
rect.origin.y = CGRound(inRect.origin.y + (inRect.height - rect.height) / 2.0)
|
||||||
|
|
||||||
return rect
|
return rect
|
||||||
}
|
}
|
||||||
|
|
||||||
public func centeredX(inRect: CGRect) -> CGRect {
|
public func centeredX(inRect: CGRect) -> CGRect {
|
||||||
var rect = self
|
var rect = self
|
||||||
rect.origin.x = CGRound((inRect.width - rect.width) / 2.0)
|
rect.origin.x = CGRound(inRect.origin.x + (inRect.width - rect.width) / 2.0)
|
||||||
|
|
||||||
return rect
|
return rect
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user