Goofing around with Box
This commit is contained in:
@@ -287,6 +287,11 @@ class BrowserViewController: UIViewController
|
|||||||
showSettingsWindow()
|
showSettingsWindow()
|
||||||
}, for: .touchUpInside)
|
}, for: .touchUpInside)
|
||||||
|
|
||||||
|
// Share
|
||||||
|
documentControls.sharingView.addAction(UIAction { [unowned self] _ in
|
||||||
|
showShareSheetForCurrentURL(fromViewController: documentControls)
|
||||||
|
}, for: .touchUpInside)
|
||||||
|
|
||||||
present(documentControls, animated: true, completion: nil)
|
present(documentControls, animated: true, completion: nil)
|
||||||
}), for: .touchUpInside)
|
}), for: .touchUpInside)
|
||||||
|
|
||||||
|
|||||||
@@ -14,6 +14,13 @@ class DocumentControlItemView: UIControl
|
|||||||
let imageView = UIImageView(frame: .zero)
|
let imageView = UIImageView(frame: .zero)
|
||||||
let label = UILabel(frame: .zero)
|
let label = UILabel(frame: .zero)
|
||||||
|
|
||||||
|
enum ViewType: String {
|
||||||
|
case imageView
|
||||||
|
case label
|
||||||
|
case separator
|
||||||
|
case highlightView
|
||||||
|
}
|
||||||
|
|
||||||
var drawsBottomSeparator: Bool = false {
|
var drawsBottomSeparator: Bool = false {
|
||||||
didSet { setNeedsLayout() }
|
didSet { setNeedsLayout() }
|
||||||
}
|
}
|
||||||
@@ -50,38 +57,68 @@ class DocumentControlItemView: UIControl
|
|||||||
CGSize(width: size.width, height: Self.controlHeight)
|
CGSize(width: size.width, height: Self.controlHeight)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private func box(_ bounds: CGRect) -> Box<ViewType> {
|
||||||
|
Box {
|
||||||
|
let padding: CGFloat = 18.0
|
||||||
|
let imageSize: CGFloat = 24.0
|
||||||
|
let ibounds = bounds.inset(by: layoutMargins)
|
||||||
|
|
||||||
|
let imageRect = CGRect(
|
||||||
|
x: ibounds.minX + 6.0, y: 0.0,
|
||||||
|
width: imageSize, height: imageSize
|
||||||
|
).centeredY(inRect: bounds)
|
||||||
|
|
||||||
|
(ViewType.imageView, imageRect)
|
||||||
|
|
||||||
|
(ViewType.highlightView, bounds)
|
||||||
|
|
||||||
|
(ViewType.label, CGRect(
|
||||||
|
x: imageRect.maxX + padding, y: ibounds.minY,
|
||||||
|
width: ibounds.width - imageRect.maxX - padding, height: ibounds.height
|
||||||
|
))
|
||||||
|
|
||||||
|
let separatorHeight: CGFloat = 1.0
|
||||||
|
|
||||||
|
if drawsBottomSeparator {
|
||||||
|
(ViewType.separator, CGRect(
|
||||||
|
x: bounds.minX, y: bounds.height - separatorHeight,
|
||||||
|
width: bounds.width, height: separatorHeight
|
||||||
|
))
|
||||||
|
} else {
|
||||||
|
(ViewType.separator, CGRect.zero)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
override func layoutSubviews() {
|
override func layoutSubviews() {
|
||||||
super.layoutSubviews()
|
super.layoutSubviews()
|
||||||
|
|
||||||
highlightView.frame = bounds
|
box(bounds).fill([
|
||||||
|
.imageView : imageView,
|
||||||
|
.separator : separatorView,
|
||||||
|
.label : label,
|
||||||
|
.highlightView : highlightView
|
||||||
|
])
|
||||||
|
|
||||||
let padding: CGFloat = 18.0
|
separatorView.isHidden = !drawsBottomSeparator
|
||||||
let imageSize: CGFloat = 24.0
|
|
||||||
let bounds = self.bounds.inset(by: layoutMargins)
|
|
||||||
imageView.frame = CGRect(
|
|
||||||
x: bounds.minX + 6.0, y: 0.0,
|
|
||||||
width: imageSize, height: imageSize
|
|
||||||
).centeredY(inRect: self.bounds)
|
|
||||||
|
|
||||||
label.frame = CGRect(
|
|
||||||
x: imageView.frame.maxX + padding, y: bounds.minY,
|
|
||||||
width: bounds.width - imageView.frame.maxX - padding, height: bounds.height
|
|
||||||
)
|
|
||||||
|
|
||||||
let separatorHeight: CGFloat = 1.0
|
|
||||||
if drawsBottomSeparator {
|
|
||||||
separatorView.isHidden = false
|
|
||||||
separatorView.frame = CGRect(
|
|
||||||
x: self.bounds.minX, y: self.bounds.height - separatorHeight,
|
|
||||||
width: self.bounds.width, height: separatorHeight
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
separatorView.isHidden = true
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override func setTracking(_ tracking: Bool) {
|
override func setTracking(_ tracking: Bool) {
|
||||||
super.setTracking(tracking)
|
super.setTracking(tracking)
|
||||||
highlightView.isHidden = !tracking
|
highlightView.isHidden = !tracking
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public func title(_ title: String) -> Self {
|
||||||
|
self.label.text = title
|
||||||
|
return self
|
||||||
|
}
|
||||||
|
|
||||||
|
public func image(_ image: UIImage?) -> Self {
|
||||||
|
self.imageView.image = image
|
||||||
|
return self
|
||||||
|
}
|
||||||
|
|
||||||
|
public func symbol(_ name: String) -> Self {
|
||||||
|
return self.image(UIImage(systemName: name))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,37 +10,25 @@ import UIKit
|
|||||||
class DocumentControlViewController: UIViewController
|
class DocumentControlViewController: UIViewController
|
||||||
{
|
{
|
||||||
let documentControlsView = DocumentControlsView()
|
let documentControlsView = DocumentControlsView()
|
||||||
let fontSizeAdjustView = FontSizeAdjustView()
|
|
||||||
let findOnPageControlView = DocumentControlItemView()
|
let fontSizeAdjustView = FontSizeAdjustView()
|
||||||
let navigationControlView = NavigationControlsView()
|
let navigationControlView = NavigationControlsView()
|
||||||
let settingsView = DocumentControlItemView()
|
|
||||||
let readabilityView = DocumentControlItemView()
|
let findOnPageControlView = DocumentControlItemView().title("Find On Page") .symbol("magnifyingglass")
|
||||||
let darkModeView = DocumentControlItemView()
|
let settingsView = DocumentControlItemView().title("Settings") .symbol("gear")
|
||||||
let archiveView = DocumentControlItemView()
|
let readabilityView = DocumentControlItemView().title("Reader Mode") .symbol("doc.richtext")
|
||||||
let emailView = DocumentControlItemView()
|
let archiveView = DocumentControlItemView().title("Archive.today") .symbol("shippingbox")
|
||||||
|
let emailView = DocumentControlItemView().title("Email") .symbol("envelope")
|
||||||
|
let sharingView = DocumentControlItemView().title("Share") .symbol("square.and.arrow.up")
|
||||||
|
let darkModeView = DocumentControlItemView().title("Dark Mode")
|
||||||
|
|
||||||
var observations: [NSKeyValueObservation] = []
|
var observations: [NSKeyValueObservation] = []
|
||||||
|
|
||||||
static public let preferredWidth = CGFloat(200.0)
|
static public let preferredWidth = CGFloat(230.0)
|
||||||
|
|
||||||
init(darkModeEnabled: Bool) {
|
init(darkModeEnabled: Bool) {
|
||||||
super.init(nibName: nil, bundle: nil)
|
super.init(nibName: nil, bundle: nil)
|
||||||
|
|
||||||
findOnPageControlView.label.text = "Find On Page"
|
|
||||||
findOnPageControlView.imageView.image = UIImage(systemName: "magnifyingglass")
|
|
||||||
|
|
||||||
settingsView.label.text = "Settings"
|
|
||||||
settingsView.imageView.image = UIImage(systemName: "gear")
|
|
||||||
|
|
||||||
readabilityView.label.text = "Reader Mode"
|
|
||||||
readabilityView.imageView.image = UIImage(systemName: "doc.richtext")
|
|
||||||
|
|
||||||
archiveView.label.text = "Archive.today"
|
|
||||||
archiveView.imageView.image = UIImage(systemName: "shippingbox")
|
|
||||||
|
|
||||||
emailView.label.text = "Email"
|
|
||||||
emailView.imageView.image = UIImage(systemName: "envelope")
|
|
||||||
|
|
||||||
if darkModeEnabled {
|
if darkModeEnabled {
|
||||||
darkModeView.label.text = "Disable Dark Mode"
|
darkModeView.label.text = "Disable Dark Mode"
|
||||||
} else {
|
} else {
|
||||||
@@ -53,6 +41,7 @@ class DocumentControlViewController: UIViewController
|
|||||||
documentControlsView.stackView.addArrangedSubview(fontSizeAdjustView)
|
documentControlsView.stackView.addArrangedSubview(fontSizeAdjustView)
|
||||||
|
|
||||||
documentControlsView.stackView.addArrangedSubview(emailView)
|
documentControlsView.stackView.addArrangedSubview(emailView)
|
||||||
|
documentControlsView.stackView.addArrangedSubview(sharingView)
|
||||||
documentControlsView.stackView.addArrangedSubview(findOnPageControlView)
|
documentControlsView.stackView.addArrangedSubview(findOnPageControlView)
|
||||||
documentControlsView.stackView.addArrangedSubview(darkModeView)
|
documentControlsView.stackView.addArrangedSubview(darkModeView)
|
||||||
documentControlsView.stackView.addArrangedSubview(readabilityView)
|
documentControlsView.stackView.addArrangedSubview(readabilityView)
|
||||||
|
|||||||
50
App/Utilities/Box.swift
Normal file
50
App/Utilities/Box.swift
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
//
|
||||||
|
// Box.swift
|
||||||
|
// Box
|
||||||
|
//
|
||||||
|
// Created by James Magahern on 7/13/21.
|
||||||
|
//
|
||||||
|
|
||||||
|
import UIKit
|
||||||
|
|
||||||
|
struct Box<Identifier: Hashable> {
|
||||||
|
typealias Compartment = (Identifier, CGRect)
|
||||||
|
typealias Realized = (Identifier, UIView)
|
||||||
|
|
||||||
|
@resultBuilder
|
||||||
|
struct BoxBuilder {
|
||||||
|
static func buildEither(first component: [Compartment]) -> Compartment {
|
||||||
|
component[0]
|
||||||
|
}
|
||||||
|
|
||||||
|
static func buildEither(second component: [Compartment]) -> Compartment {
|
||||||
|
component[0]
|
||||||
|
}
|
||||||
|
|
||||||
|
static func buildBlock(_ compartments: Compartment...) -> [Compartment] {
|
||||||
|
return compartments
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public var boundingRect: CGRect {
|
||||||
|
get {
|
||||||
|
compartmentMap.reduce(into: CGRect.zero) { (result, compartment) in
|
||||||
|
result = result.union(compartment.value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private var compartmentMap: [Identifier: CGRect] = [:]
|
||||||
|
|
||||||
|
init(@BoxBuilder _ compartments: () -> [Compartment]) {
|
||||||
|
self.compartmentMap = compartments().reduce(into: [:]) { (result, compartment) in
|
||||||
|
result[compartment.0] = compartment.1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public func fill(_ realized: [Identifier: UIView]) {
|
||||||
|
realized.forEach { (key, value) in
|
||||||
|
value.frame = compartmentMap[key] ?? .zero
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -41,6 +41,7 @@
|
|||||||
1ADFF4CD24CBB0C8006DC7AE /* ScriptPolicyViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1ADFF4CC24CBB0C8006DC7AE /* ScriptPolicyViewController.swift */; };
|
1ADFF4CD24CBB0C8006DC7AE /* ScriptPolicyViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1ADFF4CC24CBB0C8006DC7AE /* ScriptPolicyViewController.swift */; };
|
||||||
CD01D5A5254A10BB00189CDC /* TabBarView.swift in Sources */ = {isa = PBXBuildFile; fileRef = CD01D5A4254A10BB00189CDC /* TabBarView.swift */; };
|
CD01D5A5254A10BB00189CDC /* TabBarView.swift in Sources */ = {isa = PBXBuildFile; fileRef = CD01D5A4254A10BB00189CDC /* TabBarView.swift */; };
|
||||||
CD01D5AB254A206D00189CDC /* TabBarViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = CD01D5AA254A206D00189CDC /* TabBarViewController.swift */; };
|
CD01D5AB254A206D00189CDC /* TabBarViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = CD01D5AA254A206D00189CDC /* TabBarViewController.swift */; };
|
||||||
|
CD16844D269E709400B8F8A5 /* Box.swift in Sources */ = {isa = PBXBuildFile; fileRef = CD16844C269E709400B8F8A5 /* Box.swift */; };
|
||||||
CD19576D268BE95900E8089B /* GenericContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = CD19576C268BE95900E8089B /* GenericContentView.swift */; };
|
CD19576D268BE95900E8089B /* GenericContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = CD19576C268BE95900E8089B /* GenericContentView.swift */; };
|
||||||
CD470C4225DE056600AFBE0E /* BrowserViewController+WebKitDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = CD470C4125DE056600AFBE0E /* BrowserViewController+WebKitDelegate.swift */; };
|
CD470C4225DE056600AFBE0E /* BrowserViewController+WebKitDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = CD470C4125DE056600AFBE0E /* BrowserViewController+WebKitDelegate.swift */; };
|
||||||
CD470C4425DE070400AFBE0E /* BrowserViewController+Keyboard.swift in Sources */ = {isa = PBXBuildFile; fileRef = CD470C4325DE070400AFBE0E /* BrowserViewController+Keyboard.swift */; };
|
CD470C4425DE070400AFBE0E /* BrowserViewController+Keyboard.swift in Sources */ = {isa = PBXBuildFile; fileRef = CD470C4325DE070400AFBE0E /* BrowserViewController+Keyboard.swift */; };
|
||||||
@@ -139,6 +140,7 @@
|
|||||||
1ADFF4CC24CBB0C8006DC7AE /* ScriptPolicyViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ScriptPolicyViewController.swift; sourceTree = "<group>"; };
|
1ADFF4CC24CBB0C8006DC7AE /* ScriptPolicyViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ScriptPolicyViewController.swift; sourceTree = "<group>"; };
|
||||||
CD01D5A4254A10BB00189CDC /* TabBarView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TabBarView.swift; sourceTree = "<group>"; };
|
CD01D5A4254A10BB00189CDC /* TabBarView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TabBarView.swift; sourceTree = "<group>"; };
|
||||||
CD01D5AA254A206D00189CDC /* TabBarViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TabBarViewController.swift; sourceTree = "<group>"; };
|
CD01D5AA254A206D00189CDC /* TabBarViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TabBarViewController.swift; sourceTree = "<group>"; };
|
||||||
|
CD16844C269E709400B8F8A5 /* Box.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Box.swift; sourceTree = "<group>"; };
|
||||||
CD19576C268BE95900E8089B /* GenericContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GenericContentView.swift; sourceTree = "<group>"; };
|
CD19576C268BE95900E8089B /* GenericContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GenericContentView.swift; sourceTree = "<group>"; };
|
||||||
CD470C4125DE056600AFBE0E /* BrowserViewController+WebKitDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "BrowserViewController+WebKitDelegate.swift"; sourceTree = "<group>"; };
|
CD470C4125DE056600AFBE0E /* BrowserViewController+WebKitDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "BrowserViewController+WebKitDelegate.swift"; sourceTree = "<group>"; };
|
||||||
CD470C4325DE070400AFBE0E /* BrowserViewController+Keyboard.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "BrowserViewController+Keyboard.swift"; sourceTree = "<group>"; };
|
CD470C4325DE070400AFBE0E /* BrowserViewController+Keyboard.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "BrowserViewController+Keyboard.swift"; sourceTree = "<group>"; };
|
||||||
@@ -355,6 +357,7 @@
|
|||||||
1ADFF4C124CA6AE4006DC7AE /* Utilities */ = {
|
1ADFF4C124CA6AE4006DC7AE /* Utilities */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
|
CD16844C269E709400B8F8A5 /* Box.swift */,
|
||||||
1ADFF4C224CA6AF6006DC7AE /* Geometry.swift */,
|
1ADFF4C224CA6AF6006DC7AE /* Geometry.swift */,
|
||||||
CD7A8918251989C90075991E /* UIKeyCommand+ConvInit.swift */,
|
CD7A8918251989C90075991E /* UIKeyCommand+ConvInit.swift */,
|
||||||
1ADFF4C624CA6DEB006DC7AE /* UIEdgeInsets+Layout.swift */,
|
1ADFF4C624CA6DEB006DC7AE /* UIEdgeInsets+Layout.swift */,
|
||||||
@@ -580,6 +583,7 @@
|
|||||||
1AD3103D252541E600A4A952 /* PersonalRedirectRules.swift in Sources */,
|
1AD3103D252541E600A4A952 /* PersonalRedirectRules.swift in Sources */,
|
||||||
1AB88F0624D4D3A90006F850 /* UIGestureRecognizer+Actions.swift in Sources */,
|
1AB88F0624D4D3A90006F850 /* UIGestureRecognizer+Actions.swift in Sources */,
|
||||||
1ADFF46224C7DE53006DC7AE /* SceneDelegate.swift in Sources */,
|
1ADFF46224C7DE53006DC7AE /* SceneDelegate.swift in Sources */,
|
||||||
|
CD16844D269E709400B8F8A5 /* Box.swift in Sources */,
|
||||||
CD853BCE24E7763900D2BDCC /* BrowserHistory.swift in Sources */,
|
CD853BCE24E7763900D2BDCC /* BrowserHistory.swift in Sources */,
|
||||||
1A03810B24E71C5600826501 /* ToolbarButtonContainerView.swift in Sources */,
|
1A03810B24E71C5600826501 /* ToolbarButtonContainerView.swift in Sources */,
|
||||||
CD7A7EA12686B2E600E20BA3 /* RedirectRulesSettingsViewController.swift in Sources */,
|
CD7A7EA12686B2E600E20BA3 /* RedirectRulesSettingsViewController.swift in Sources */,
|
||||||
|
|||||||
Reference in New Issue
Block a user