2020-08-14 15:55:08 -07:00
|
|
|
//
|
|
|
|
|
// ToolbarView.swift
|
|
|
|
|
// App
|
|
|
|
|
//
|
|
|
|
|
// Created by James Magahern on 8/14/20.
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
import UIKit
|
|
|
|
|
|
|
|
|
|
class ToolbarView: UIView
|
|
|
|
|
{
|
2023-08-10 19:52:59 -07:00
|
|
|
var urlBar: URLBar? {
|
|
|
|
|
didSet {
|
|
|
|
|
guard let urlBar else { return }
|
|
|
|
|
containerView.addSubview(urlBar)
|
|
|
|
|
|
|
|
|
|
urlBar.textField.addAction(.init(handler: { [unowned self] _ in
|
|
|
|
|
layoutLatch.activate()
|
|
|
|
|
}), for: [ .editingDidBegin, .editingDidEnd ])
|
|
|
|
|
}
|
|
|
|
|
}
|
2020-08-14 15:55:08 -07:00
|
|
|
|
2023-08-10 19:52:59 -07:00
|
|
|
var cancelButtonVisible: Bool = false { didSet { setNeedsLayout() } }
|
2020-08-14 15:55:08 -07:00
|
|
|
|
|
|
|
|
let containerView = UIView(frame: .zero)
|
2021-06-14 16:32:51 -07:00
|
|
|
let backgroundView = GradientView(direction: .vertical, colors: [
|
2022-02-21 15:52:18 -08:00
|
|
|
.secondarySystemGroupedBackground,
|
2021-06-14 16:32:51 -07:00
|
|
|
.secondarySystemGroupedBackground
|
|
|
|
|
])
|
2020-08-14 15:55:08 -07:00
|
|
|
let cancelButton = UIButton(type: .system)
|
|
|
|
|
|
|
|
|
|
let leadingButtonsView = ToolbarButtonContainerView(frame: .zero)
|
|
|
|
|
let trailingButtonsView = ToolbarButtonContainerView(frame: .zero)
|
|
|
|
|
|
2023-08-10 19:52:59 -07:00
|
|
|
// Something I'm sure I'll regret: to ensure animation with the keyboard, latch layout until we get the right signal.
|
|
|
|
|
lazy var layoutLatch = LayoutLatch(self)
|
|
|
|
|
|
2020-08-14 15:55:08 -07:00
|
|
|
convenience init()
|
|
|
|
|
{
|
|
|
|
|
self.init(frame: .zero)
|
|
|
|
|
addSubview(backgroundView)
|
|
|
|
|
addSubview(containerView)
|
|
|
|
|
|
|
|
|
|
containerView.addSubview(leadingButtonsView)
|
|
|
|
|
containerView.addSubview(trailingButtonsView)
|
|
|
|
|
|
|
|
|
|
cancelButton.setTitle("Cancel", for: .normal)
|
|
|
|
|
containerView.addSubview(cancelButton)
|
|
|
|
|
|
|
|
|
|
layer.masksToBounds = false
|
|
|
|
|
layer.shadowColor = UIColor.black.cgColor
|
2021-06-14 16:32:51 -07:00
|
|
|
layer.shadowOpacity = 0.3
|
2020-08-14 15:55:08 -07:00
|
|
|
layer.shadowOffset = CGSize(width: 0.0, height: 1.0)
|
2021-06-14 16:32:51 -07:00
|
|
|
layer.shadowRadius = 1.8
|
2020-08-14 15:55:08 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
override func sizeThatFits(_ size: CGSize) -> CGSize
|
|
|
|
|
{
|
2022-02-21 15:52:18 -08:00
|
|
|
var height: CGFloat = 42.0
|
|
|
|
|
if traitCollection.userInterfaceIdiom == .mac {
|
|
|
|
|
height = 40.0
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return CGSize(width: size.width, height: height)
|
2020-08-14 15:55:08 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
override func layoutSubviews()
|
|
|
|
|
{
|
2023-08-10 19:52:59 -07:00
|
|
|
guard !layoutLatch.latched else { return }
|
2020-08-14 15:55:08 -07:00
|
|
|
super.layoutSubviews()
|
2020-09-30 18:26:45 -07:00
|
|
|
|
|
|
|
|
let shadowPath = UIBezierPath(rect: bounds)
|
|
|
|
|
layer.shadowPath = shadowPath.cgPath
|
2020-08-14 15:55:08 -07:00
|
|
|
|
|
|
|
|
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)
|
|
|
|
|
|
|
|
|
|
let buttonContainerInset = UIEdgeInsets(top: 1.0, left: 0.0, bottom: 1.0, right: 0.0)
|
|
|
|
|
|
2020-08-14 17:44:49 -07:00
|
|
|
let urlBarPadding = CGFloat(8.0)
|
2020-08-14 15:55:08 -07:00
|
|
|
var urlBarInsets = UIEdgeInsets(top: 0.0, left: 0.0, bottom: 0.0, right: 0.0)
|
|
|
|
|
|
|
|
|
|
// Cancel button
|
|
|
|
|
var cancelButtonSize = cancelButton.sizeThatFits(containerView.bounds.size)
|
|
|
|
|
cancelButtonSize.width += (urlBarPadding * 2)
|
|
|
|
|
cancelButton.frame = CGRect(origin: CGPoint(x: (containerView.bounds.maxX - cancelButtonSize.width), y: 0),
|
|
|
|
|
size: CGSize(width: cancelButtonSize.width + urlBarPadding, height: containerView.bounds.height))
|
|
|
|
|
|
|
|
|
|
// Leading toolbar buttons
|
|
|
|
|
if leadingButtonsView.numberOfButtonViews > 0 {
|
|
|
|
|
let leadingContainerSize = leadingButtonsView.sizeThatFits(containerView.bounds.size)
|
|
|
|
|
leadingButtonsView.frame = CGRect(origin: .zero, size: leadingContainerSize).inset(by: buttonContainerInset)
|
|
|
|
|
urlBarInsets.left = urlBarPadding
|
|
|
|
|
} 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), y: 0), size: trailingContainerSize)
|
|
|
|
|
trailingButtonsView.frame = trailingButtonsView.frame.inset(by: buttonContainerInset)
|
|
|
|
|
urlBarInsets.right = urlBarPadding
|
|
|
|
|
|
|
|
|
|
var avoidingSize: CGSize = .zero
|
|
|
|
|
if cancelButtonVisible {
|
|
|
|
|
cancelButton.alpha = 1.0
|
|
|
|
|
trailingButtonsView.alpha = 0.0
|
|
|
|
|
|
|
|
|
|
avoidingSize = cancelButtonSize
|
|
|
|
|
} else {
|
|
|
|
|
cancelButton.alpha = 0.0
|
|
|
|
|
trailingButtonsView.alpha = 1.0
|
|
|
|
|
|
|
|
|
|
avoidingSize = trailingContainerSize
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if let urlBar = urlBar {
|
2020-09-22 14:33:00 -07:00
|
|
|
var origin = CGPoint(
|
2020-08-14 15:55:08 -07:00
|
|
|
x: leadingButtonsView.frame.maxX,
|
|
|
|
|
y: 0.0
|
|
|
|
|
)
|
|
|
|
|
|
2020-09-22 14:33:00 -07:00
|
|
|
if origin.x == 0 {
|
|
|
|
|
// Add some padding if url bar is flush with side
|
|
|
|
|
origin.x = layoutMargins.left
|
|
|
|
|
}
|
|
|
|
|
|
2020-08-14 15:55:08 -07:00
|
|
|
urlBar.frame = CGRect(
|
|
|
|
|
origin: origin,
|
|
|
|
|
size: CGSize(
|
|
|
|
|
width: containerView.bounds.width - avoidingSize.width - origin.x,
|
|
|
|
|
height: trailingContainerSize.height
|
|
|
|
|
)
|
|
|
|
|
)
|
|
|
|
|
|
2020-09-22 14:33:00 -07:00
|
|
|
urlBar.frame = urlBar.frame.inset(by: urlBarInsets).inset(by: buttonContainerInset)
|
2020-08-14 15:55:08 -07:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|