2020-07-24 19:26:35 -07:00
|
|
|
//
|
|
|
|
|
// ToolbarViewController.swift
|
|
|
|
|
// SBrowser
|
|
|
|
|
//
|
|
|
|
|
// Created by James Magahern on 7/23/20.
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
import UIKit
|
|
|
|
|
|
|
|
|
|
class ToolbarButtonView: UIView
|
|
|
|
|
{
|
2020-07-29 17:46:53 -07:00
|
|
|
private var buttonPadding = CGFloat(24.0)
|
2020-07-24 19:26:35 -07:00
|
|
|
private var buttonViews: [UIView] = []
|
|
|
|
|
|
2020-07-31 14:08:10 -07:00
|
|
|
public var numberOfButtonViews: Int { buttonViews.count }
|
|
|
|
|
|
2020-07-24 19:26:35 -07:00
|
|
|
func addButtonView(_ button: UIView) {
|
|
|
|
|
buttonViews.append(button)
|
|
|
|
|
addSubview(button)
|
|
|
|
|
setNeedsLayout()
|
|
|
|
|
}
|
|
|
|
|
|
2020-07-29 19:24:05 -07:00
|
|
|
func removeAllButtonViews() {
|
|
|
|
|
buttonViews.forEach { $0.removeFromSuperview() }
|
|
|
|
|
buttonViews.removeAll()
|
|
|
|
|
setNeedsLayout()
|
|
|
|
|
}
|
|
|
|
|
|
2020-07-24 19:26:35 -07:00
|
|
|
override func sizeThatFits(_ size: CGSize) -> CGSize {
|
|
|
|
|
let width: CGFloat = buttonViews.reduce(0.0) { (result, button) -> CGFloat in
|
|
|
|
|
return result + button.sizeThatFits(size).width + buttonPadding
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return CGSize(width: width, height: size.height)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
override func layoutSubviews() {
|
|
|
|
|
var buttonRect = CGRect(origin: .zero, size: CGSize(width: 0, height: bounds.height))
|
2020-07-29 17:46:53 -07:00
|
|
|
buttonRect.origin.x = layoutMargins.left
|
2020-07-24 19:26:35 -07:00
|
|
|
|
|
|
|
|
for button in buttonViews {
|
|
|
|
|
let buttonSize = button.sizeThatFits(bounds.size)
|
|
|
|
|
buttonRect.size = CGSize(width: buttonSize.width, height: bounds.height)
|
|
|
|
|
button.frame = buttonRect
|
|
|
|
|
|
|
|
|
|
buttonRect.origin.x += buttonRect.width + buttonPadding
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
class ToolbarView: UIView
|
|
|
|
|
{
|
|
|
|
|
var urlBar: URLBar? { didSet { containerView.addSubview(urlBar!) } }
|
|
|
|
|
|
2020-07-29 17:46:53 -07:00
|
|
|
var cancelButtonVisible: Bool = false { didSet { layoutSubviews() } }
|
|
|
|
|
|
2020-07-24 19:26:35 -07:00
|
|
|
let containerView = UIView(frame: .zero)
|
|
|
|
|
let backgroundView = UIVisualEffectView(effect: UIBlurEffect(style: .systemThickMaterial))
|
2020-07-29 17:46:53 -07:00
|
|
|
let cancelButton = UIButton(type: .system)
|
2020-07-24 19:26:35 -07:00
|
|
|
|
2020-07-31 14:08:10 -07:00
|
|
|
let leadingButtonsView = ToolbarButtonView(frame: .zero)
|
|
|
|
|
let trailingButtonsView = ToolbarButtonView(frame: .zero)
|
|
|
|
|
|
2020-07-24 19:26:35 -07:00
|
|
|
convenience init()
|
|
|
|
|
{
|
|
|
|
|
self.init(frame: .zero)
|
|
|
|
|
addSubview(backgroundView)
|
|
|
|
|
addSubview(containerView)
|
|
|
|
|
|
2020-07-31 14:08:10 -07:00
|
|
|
containerView.addSubview(leadingButtonsView)
|
|
|
|
|
containerView.addSubview(trailingButtonsView)
|
2020-07-29 17:46:53 -07:00
|
|
|
|
|
|
|
|
cancelButton.setTitle("Cancel", for: .normal)
|
|
|
|
|
containerView.addSubview(cancelButton)
|
2020-07-29 19:24:05 -07:00
|
|
|
|
|
|
|
|
layer.masksToBounds = false
|
|
|
|
|
layer.shadowColor = UIColor.black.cgColor
|
|
|
|
|
layer.shadowOpacity = 0.2
|
|
|
|
|
layer.shadowOffset = CGSize(width: 0.0, height: 1.0)
|
|
|
|
|
layer.shadowRadius = 1.5
|
2020-07-24 19:26:35 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
override func sizeThatFits(_ size: CGSize) -> CGSize
|
|
|
|
|
{
|
|
|
|
|
return CGSize(width: size.width, height: 44.0)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
override func layoutSubviews()
|
|
|
|
|
{
|
|
|
|
|
super.layoutSubviews()
|
|
|
|
|
|
|
|
|
|
backgroundView.frame = bounds
|
|
|
|
|
|
|
|
|
|
var containerBounds = bounds
|
|
|
|
|
containerBounds.size.height -= safeAreaInsets.bottom
|
|
|
|
|
containerView.frame = containerBounds
|
|
|
|
|
containerView.frame = containerView.frame.insetBy(dx: 8.0, dy: 4.0)
|
|
|
|
|
|
2020-07-29 17:46:53 -07:00
|
|
|
// Cancel button
|
|
|
|
|
let urlBarPadding: CGFloat = 8.0
|
2020-07-31 14:23:00 -07:00
|
|
|
var cancelButtonSize = cancelButton.sizeThatFits(containerView.bounds.size)
|
|
|
|
|
cancelButtonSize.width += (urlBarPadding * 2)
|
2020-07-29 18:34:46 -07:00
|
|
|
cancelButton.frame = CGRect(origin: CGPoint(x: (containerView.bounds.maxX - cancelButtonSize.width), y: 0),
|
2020-07-31 14:23:00 -07:00
|
|
|
size: CGSize(width: cancelButtonSize.width + urlBarPadding, height: containerView.bounds.height))
|
2020-07-29 17:46:53 -07:00
|
|
|
|
2020-07-31 14:08:10 -07:00
|
|
|
// Leading toolbar buttons
|
|
|
|
|
if leadingButtonsView.numberOfButtonViews > 0 {
|
|
|
|
|
let leadingContainerSize = leadingButtonsView.sizeThatFits(containerView.bounds.size)
|
|
|
|
|
leadingButtonsView.frame = CGRect(origin: .zero, size: leadingContainerSize)
|
|
|
|
|
} else {
|
|
|
|
|
leadingButtonsView.frame = .zero
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Trailing toolbar buttons
|
|
|
|
|
let trailingContainerSize = trailingButtonsView.sizeThatFits(containerView.bounds.size)
|
|
|
|
|
trailingButtonsView.frame = CGRect(origin: CGPoint(x: (containerView.bounds.maxX - trailingContainerSize.width) + urlBarPadding, y: 0), size: trailingContainerSize)
|
2020-07-29 17:46:53 -07:00
|
|
|
|
|
|
|
|
var avoidingSize: CGSize = .zero
|
|
|
|
|
if cancelButtonVisible {
|
|
|
|
|
cancelButton.alpha = 1.0
|
2020-07-31 14:08:10 -07:00
|
|
|
trailingButtonsView.alpha = 0.0
|
2020-07-29 17:46:53 -07:00
|
|
|
|
|
|
|
|
avoidingSize = cancelButtonSize
|
|
|
|
|
} else {
|
|
|
|
|
cancelButton.alpha = 0.0
|
2020-07-31 14:08:10 -07:00
|
|
|
trailingButtonsView.alpha = 1.0
|
2020-07-29 17:46:53 -07:00
|
|
|
|
2020-07-31 14:08:10 -07:00
|
|
|
avoidingSize = trailingContainerSize
|
2020-07-24 19:26:35 -07:00
|
|
|
}
|
|
|
|
|
|
2020-07-29 17:46:53 -07:00
|
|
|
if let urlBar = urlBar {
|
2020-07-31 14:08:10 -07:00
|
|
|
let origin = CGPoint(
|
|
|
|
|
x: leadingButtonsView.frame.maxX,
|
|
|
|
|
y: 0.0
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
urlBar.frame = CGRect(
|
|
|
|
|
origin: origin,
|
|
|
|
|
size: CGSize(
|
|
|
|
|
width: containerView.bounds.width - avoidingSize.width - origin.x,
|
|
|
|
|
height: containerView.bounds.height
|
|
|
|
|
)
|
|
|
|
|
)
|
2020-07-29 17:46:53 -07:00
|
|
|
}
|
2020-07-24 19:26:35 -07:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
class ToolbarViewController: UIViewController
|
|
|
|
|
{
|
|
|
|
|
let urlBar = URLBar()
|
|
|
|
|
let toolbarView = ToolbarView()
|
|
|
|
|
let scriptControllerIconView = ScriptControllerIconView()
|
|
|
|
|
let shareButton = UIButton(frame: .zero)
|
2020-07-29 17:46:53 -07:00
|
|
|
let darkModeButton = UIButton(frame: .zero)
|
2020-07-29 19:24:05 -07:00
|
|
|
let windowButton = UIButton(frame: .zero)
|
2020-07-31 14:08:10 -07:00
|
|
|
let backButton = UIButton(frame: .zero)
|
|
|
|
|
let forwardButton = UIButton(frame: .zero)
|
2020-07-31 16:36:10 -07:00
|
|
|
let newTabButton = UIButton(frame: .zero)
|
2020-07-24 19:26:35 -07:00
|
|
|
|
2020-07-29 18:17:22 -07:00
|
|
|
var darkModeEnabled: Bool = false {
|
|
|
|
|
didSet {
|
|
|
|
|
if darkModeEnabled {
|
|
|
|
|
darkModeButton.setImage(darkModeEnabledImage, for: .normal)
|
|
|
|
|
} else {
|
|
|
|
|
darkModeButton.setImage(darkModeDisabledImage, for: .normal)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private let darkModeDisabledImage = UIImage(systemName: "moon.circle")
|
|
|
|
|
private let darkModeEnabledImage = UIImage(systemName: "moon.circle.fill")
|
|
|
|
|
|
2020-07-24 19:26:35 -07:00
|
|
|
init() {
|
|
|
|
|
super.init(nibName: nil, bundle: nil)
|
|
|
|
|
|
|
|
|
|
toolbarView.urlBar = urlBar
|
|
|
|
|
|
2020-07-29 19:24:05 -07:00
|
|
|
// Dark mode button
|
2020-07-29 18:17:22 -07:00
|
|
|
darkModeButton.setImage(darkModeDisabledImage, for: .normal)
|
2020-07-29 17:46:53 -07:00
|
|
|
|
2020-07-29 19:24:05 -07:00
|
|
|
// Share button
|
2020-07-24 19:26:35 -07:00
|
|
|
shareButton.setImage(UIImage(systemName: "square.and.arrow.up"), for: .normal)
|
2020-07-29 19:24:05 -07:00
|
|
|
|
|
|
|
|
// Window button
|
|
|
|
|
windowButton.setImage(UIImage(systemName: "rectangle.on.rectangle"), for: .normal)
|
2020-07-29 17:46:53 -07:00
|
|
|
|
2020-07-31 14:08:10 -07:00
|
|
|
// Back button
|
|
|
|
|
backButton.setImage(UIImage(systemName: "chevron.left"), for: .normal)
|
|
|
|
|
|
|
|
|
|
// Forward button
|
|
|
|
|
forwardButton.setImage(UIImage(systemName: "chevron.right"), for: .normal)
|
|
|
|
|
|
2020-07-31 16:36:10 -07:00
|
|
|
// New tab button
|
|
|
|
|
newTabButton.setImage(UIImage(systemName: "plus"), for: .normal)
|
|
|
|
|
|
2020-07-29 17:46:53 -07:00
|
|
|
let toolbarAnimationDuration: TimeInterval = 0.3
|
2020-07-31 14:23:00 -07:00
|
|
|
urlBar.textField.addAction(.init(handler: { [traitCollection, toolbarView, urlBar] _ in
|
|
|
|
|
if traitCollection.horizontalSizeClass == .compact {
|
|
|
|
|
UIView.animate(withDuration: toolbarAnimationDuration) {
|
|
|
|
|
toolbarView.cancelButtonVisible = urlBar.textField.isFirstResponder
|
|
|
|
|
}
|
2020-07-29 17:46:53 -07:00
|
|
|
}
|
|
|
|
|
}), for: [ .editingDidBegin, .editingDidEnd ])
|
|
|
|
|
|
2020-07-31 14:08:10 -07:00
|
|
|
toolbarView.cancelButton.addAction(.init(handler: { [urlBar] action in
|
|
|
|
|
urlBar.textField.resignFirstResponder()
|
2020-07-29 17:46:53 -07:00
|
|
|
}), for: .touchUpInside)
|
2020-07-29 19:24:05 -07:00
|
|
|
|
|
|
|
|
traitCollectionDidChange(nil)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) {
|
|
|
|
|
super.traitCollectionDidChange(previousTraitCollection)
|
|
|
|
|
|
2020-07-31 14:08:10 -07:00
|
|
|
toolbarView.leadingButtonsView.removeAllButtonViews()
|
|
|
|
|
toolbarView.trailingButtonsView.removeAllButtonViews()
|
2020-07-29 19:24:05 -07:00
|
|
|
|
|
|
|
|
// Setup toolbar based on trait collection
|
|
|
|
|
if traitCollection.horizontalSizeClass == .compact {
|
2020-07-31 14:08:10 -07:00
|
|
|
toolbarView.trailingButtonsView.addButtonView(darkModeButton)
|
|
|
|
|
toolbarView.trailingButtonsView.addButtonView(scriptControllerIconView)
|
|
|
|
|
toolbarView.trailingButtonsView.addButtonView(windowButton)
|
2020-07-29 19:24:05 -07:00
|
|
|
} else {
|
2020-07-31 14:08:10 -07:00
|
|
|
toolbarView.leadingButtonsView.addButtonView(backButton)
|
|
|
|
|
toolbarView.leadingButtonsView.addButtonView(forwardButton)
|
|
|
|
|
|
|
|
|
|
toolbarView.trailingButtonsView.addButtonView(darkModeButton)
|
|
|
|
|
toolbarView.trailingButtonsView.addButtonView(shareButton)
|
|
|
|
|
toolbarView.trailingButtonsView.addButtonView(scriptControllerIconView)
|
2020-07-31 16:36:10 -07:00
|
|
|
toolbarView.trailingButtonsView.addButtonView(newTabButton)
|
2020-07-31 14:08:10 -07:00
|
|
|
toolbarView.trailingButtonsView.addButtonView(windowButton)
|
2020-07-29 19:24:05 -07:00
|
|
|
}
|
2020-07-24 19:26:35 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
override func loadView() {
|
|
|
|
|
self.view = toolbarView
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
required init?(coder: NSCoder) {
|
|
|
|
|
fatalError("init(coder:) has not been implemented")
|
|
|
|
|
}
|
|
|
|
|
}
|