From ecee3bd9bbfe1fc8cf8fe3c6a665ef75ae109f85 Mon Sep 17 00:00:00 2001 From: James Magahern Date: Mon, 14 Jun 2021 15:46:01 -0700 Subject: [PATCH] Script policy UI adjustments --- App/Browser View/BrowserViewController.swift | 2 + .../ScriptPolicyControl.swift | 73 -------- .../ScriptPolicyViewController.swift | 172 +++++++----------- SBrowser.xcodeproj/project.pbxproj | 4 - 4 files changed, 64 insertions(+), 187 deletions(-) delete mode 100644 App/Script Policy UI/ScriptPolicyControl.swift diff --git a/App/Browser View/BrowserViewController.swift b/App/Browser View/BrowserViewController.swift index ac74c67..a9756c0 100644 --- a/App/Browser View/BrowserViewController.swift +++ b/App/Browser View/BrowserViewController.swift @@ -505,6 +505,8 @@ class BrowserViewController: UIViewController iconView.shieldsDown = tab.javaScriptEnabled iconView.someScriptsAllowed = scriptsAllowedForHost iconView.setBlockedScriptsNumber(numBlockedScripts) + + iconView.isEnabled = (webView.url != nil) } public func createNewTab(withURL url: URL?) { diff --git a/App/Script Policy UI/ScriptPolicyControl.swift b/App/Script Policy UI/ScriptPolicyControl.swift deleted file mode 100644 index 670e72d..0000000 --- a/App/Script Policy UI/ScriptPolicyControl.swift +++ /dev/null @@ -1,73 +0,0 @@ -// -// ScriptPolicyControl.swift -// SBrowser -// -// Created by James Magahern on 7/24/20. -// - -import UIKit - -class ScriptPolicyControl: UIControl -{ - enum PolicyStatus { - case allowed - case blocked - } - - var policyStatus: PolicyStatus = .blocked { - didSet { setNeedsLayout() } - } - - private let allowButton = ReliefButton() - private let denyButton = ReliefButton() - private let segmentContainer = SegmentedReliefButton(children: []) - - convenience init() { - self.init(frame: .zero) - - segmentContainer.children = [ allowButton, denyButton ] - addSubview(segmentContainer) - - allowButton.showsTouchWhenHighlighted = false - allowButton.addAction(UIAction(handler: { [unowned self] _ in - self.policyStatus = .allowed - self.sendActions(for: .valueChanged) - }), for: .touchUpInside) - allowButton.imageView?.contentMode = .scaleAspectFit - - denyButton.showsTouchWhenHighlighted = false - denyButton.addAction(UIAction(handler: { [unowned self] _ in - self.policyStatus = .blocked - self.sendActions(for: .valueChanged) - }), for: .touchUpInside) - denyButton.imageView?.contentMode = .scaleAspectFit - } - - override func sizeThatFits(_ size: CGSize) -> CGSize { - return segmentContainer.sizeThatFits(size) - } - - override func layoutSubviews() { - super.layoutSubviews() - - segmentContainer.frame = bounds - - if policyStatus == .allowed { - allowButton.tintColor = .blue - allowButton.remainsPressed = true - allowButton.setImage(UIImage(systemName: "play.circle.fill"), for: .normal) - - denyButton.tintColor = nil - denyButton.remainsPressed = false - denyButton.setImage(UIImage(systemName: "stop.circle"), for: .normal) - } else { - allowButton.tintColor = nil - allowButton.remainsPressed = false - allowButton.setImage(UIImage(systemName: "play.circle"), for: .normal) - - denyButton.tintColor = .red - denyButton.remainsPressed = true - denyButton.setImage(UIImage(systemName: "stop.circle.fill"), for: .normal) - } - } -} diff --git a/App/Script Policy UI/ScriptPolicyViewController.swift b/App/Script Policy UI/ScriptPolicyViewController.swift index e822734..21d25d2 100644 --- a/App/Script Policy UI/ScriptPolicyViewController.swift +++ b/App/Script Policy UI/ScriptPolicyViewController.swift @@ -12,75 +12,6 @@ protocol ScriptPolicyViewControllerDelegate: AnyObject { func setScriptsEnabledForTab(_ enabled: Bool) } -class ScriptPolicyControlListCell: UICollectionViewListCell -{ - var enabled: Bool = true { - didSet { - if enabled != oldValue { - setNeedsLayout() - } - } - } - let policyControl = ScriptPolicyControl() - override init(frame: CGRect) { - super.init(frame: frame) - addSubview(policyControl) - } - - required init?(coder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } - - - override func layoutSubviews() { - let policyControlWidth = policyControl.sizeThatFits(bounds.size).width - policyControl.frame = CGRect( - x: bounds.maxX - policyControlWidth - layoutMargins.right, - y: 0, - width: policyControlWidth, - height: bounds.height * 0.75 - ) - policyControl.frame = policyControl.frame.centeredY(inRect: bounds) - bringSubviewToFront(policyControl) - - super.layoutSubviews() - - if enabled { - contentView.alpha = 1.0 - policyControl.alpha = 1.0 - policyControl.isUserInteractionEnabled = true - } else { - contentView.alpha = 0.5 - policyControl.alpha = 0.5 - policyControl.isUserInteractionEnabled = false - } - } -} - -class SwitchListCell: UICollectionViewListCell -{ - let switchView = UISwitch(frame: .zero) - - override init(frame: CGRect) { - super.init(frame: frame) - addSubview(switchView) - } - - required init?(coder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } - - override func layoutSubviews() { - super.layoutSubviews() - - let switchWidth: CGFloat = switchView.sizeThatFits(bounds.size).width - switchView.frame = CGRect(x: bounds.maxX - switchWidth - layoutMargins.right, y: 0, - width: switchWidth, height: bounds.height * 0.85) - switchView.frame = switchView.frame.centeredY(inRect: bounds) - contentView.frame = CGRect(origin: contentView.frame.origin, size: CGSize(width: switchView.frame.minX, height: contentView.frame.height)) - } -} - class ScriptPolicyViewController: UIViewController, UICollectionViewDelegate { var collectionView: UICollectionView? @@ -95,17 +26,13 @@ class ScriptPolicyViewController: UIViewController, UICollectionViewDelegate case origins } - override var traitCollection: UITraitCollection { - get { return super.traitCollection.alwaysPadLike() } - } - private static let enableScriptsForTabItem: String = "enableScriptsForTab" convenience init(policyManager: ResourcePolicyManager, hostOrigin: String, loadedScripts: Set, scriptsAllowedForTab: Bool) { self.init(nibName: nil, bundle: nil) allowScriptsForTab = scriptsAllowedForTab - let listConfig = UICollectionLayoutListConfiguration(appearance: .grouped) + let listConfig = UICollectionLayoutListConfiguration(appearance: .insetGrouped) let listLayout = UICollectionViewCompositionalLayout.list(using: listConfig) let collectionView = UICollectionView(frame: .zero, collectionViewLayout: listLayout) @@ -115,51 +42,44 @@ class ScriptPolicyViewController: UIViewController, UICollectionViewDelegate let originItems = [ hostOrigin ] + allowedScripts + otherOriginScripts.subtracting(allowedScripts) - let switchCellRegistry = UICollectionView.CellRegistration { [unowned self] (listCell, indexPath, item) in + let switchCellRegistry = UICollectionView.CellRegistration { [unowned self] (listCell, indexPath, item) in var config = listCell.defaultContentConfiguration() if item == Self.enableScriptsForTabItem { - config.text = "Allow for Tab" - listCell.switchView.isOn = self.allowScriptsForTab - listCell.switchView.addAction(.init(handler: { _ in - let enabled = listCell.switchView.isOn - - self.allowScriptsForTab = enabled - self.didChangeScriptPolicy = true - - if var snapshot = self.dataSource?.snapshot() { - if enabled { - // Hide script origins - snapshot.deleteSections([ .origins ]) - } else { - if !snapshot.sectionIdentifiers.contains(.origins) { - snapshot.appendSections([ .origins ]) - } - snapshot.appendItems(originItems, toSection: .origins) - } - - self.dataSource?.apply(snapshot, animatingDifferences: true) - } - }), for: .valueChanged) + if allowScriptsForTab { + config.text = "Shields Up" + config.image = UIImage(systemName: "shield.fill") + } else { + config.text = "Allow for Tab" + config.image = UIImage(systemName: "shield.slash") + } + + config.textProperties.color = UIColor.systemBlue } listCell.contentConfiguration = config } - let scriptPolicyRegistry = UICollectionView.CellRegistration { [unowned self] (listCell, indexPath, item) in + let scriptPolicyRegistry = UICollectionView.CellRegistration { [unowned self] (listCell, indexPath, item) in var config = listCell.defaultContentConfiguration() config.text = item listCell.contentConfiguration = config - if policyManager.allowedOriginsForScriptResources().contains(item) { - listCell.policyControl.policyStatus = .allowed - } else { - listCell.policyControl.policyStatus = .blocked - } + let segmentedControl = UISegmentedControl(items: [ + UIImage(systemName: "xmark.seal")!, // Disabled + UIImage(systemName: "checkmark.seal.fill")! // Enabled + ]) - listCell.policyControl.removeTarget(nil, action: nil, for: .valueChanged) - listCell.policyControl.addAction(UIAction(handler: { _ in - let allowed: Bool = listCell.policyControl.policyStatus == .allowed + segmentedControl.setTitleTextAttributes([ .foregroundColor: UIColor.init(dynamicProvider: { traits in + if traits.userInterfaceStyle == .dark { + return UIColor.systemTeal + } else { + return UIColor.systemBlue + } + }) ], for: .selected) + + segmentedControl.addAction(UIAction(handler: { [unowned segmentedControl] _ in + let allowed: Bool = (segmentedControl.selectedSegmentIndex == 1) if allowed { policyManager.allowOriginToLoadScriptResources(item) @@ -175,11 +95,27 @@ class ScriptPolicyViewController: UIViewController, UICollectionViewDelegate } self.didChangeScriptPolicy = true + }), for: .valueChanged) - if item != hostOrigin { - listCell.enabled = policyManager.allowedOriginsForScriptResources().contains(hostOrigin) + if policyManager.allowedOriginsForScriptResources().contains(item) { + segmentedControl.selectedSegmentIndex = 1 + } else { + segmentedControl.selectedSegmentIndex = 0 } + + let customViewConfiguration = UICellAccessory.CustomViewConfiguration( + customView: segmentedControl, + placement: .trailing(displayed: .always, at: { _ in return 0 }), + isHidden: false, + reservedLayoutWidth: .actual, + tintColor: nil, + maintainsFixedSize: true + ) + + listCell.accessories = [ + .customView(configuration: customViewConfiguration) + ] } let dataSource = UICollectionViewDiffableDataSource(collectionView: collectionView) { (collectionView, indexPath, item) -> UICollectionViewCell? in @@ -226,10 +162,26 @@ class ScriptPolicyViewController: UIViewController, UICollectionViewDelegate // MARK: UICollectionViewDelegate func collectionView(_ collectionView: UICollectionView, shouldHighlightItemAt indexPath: IndexPath) -> Bool { - false + indexPath.section != Section.origins.rawValue } func collectionView(_ collectionView: UICollectionView, shouldSelectItemAt indexPath: IndexPath) -> Bool { - false + indexPath.section != Section.origins.rawValue + } + + func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) { + guard let dataSource = dataSource else { return } + + if indexPath.section == Section.tabOptions.rawValue { + let identifier = dataSource.itemIdentifier(for: indexPath) + if identifier == Self.enableScriptsForTabItem { + self.allowScriptsForTab = !self.allowScriptsForTab + + // Immediately notify and dismiss + self.delegate?.didChangeScriptPolicy() + self.delegate?.setScriptsEnabledForTab(self.allowScriptsForTab) + self.dismiss(animated: true, completion: nil) + } + } } } diff --git a/SBrowser.xcodeproj/project.pbxproj b/SBrowser.xcodeproj/project.pbxproj index 5e85118..5e70655 100644 --- a/SBrowser.xcodeproj/project.pbxproj +++ b/SBrowser.xcodeproj/project.pbxproj @@ -39,7 +39,6 @@ 1ADFF4C924CA793E006DC7AE /* ToolbarViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1ADFF4C824CA793E006DC7AE /* ToolbarViewController.swift */; }; 1ADFF4CB24CB8278006DC7AE /* ScriptControllerIconView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1ADFF4CA24CB8278006DC7AE /* ScriptControllerIconView.swift */; }; 1ADFF4CD24CBB0C8006DC7AE /* ScriptPolicyViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1ADFF4CC24CBB0C8006DC7AE /* ScriptPolicyViewController.swift */; }; - 1ADFF4D024CBBCD1006DC7AE /* ScriptPolicyControl.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1ADFF4CF24CBBCD1006DC7AE /* ScriptPolicyControl.swift */; }; CD01D5A5254A10BB00189CDC /* TabBarView.swift in Sources */ = {isa = PBXBuildFile; fileRef = CD01D5A4254A10BB00189CDC /* TabBarView.swift */; }; CD01D5AB254A206D00189CDC /* TabBarViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = CD01D5AA254A206D00189CDC /* TabBarViewController.swift */; }; CD470C4225DE056600AFBE0E /* BrowserViewController+WebKitDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = CD470C4125DE056600AFBE0E /* BrowserViewController+WebKitDelegate.swift */; }; @@ -134,7 +133,6 @@ 1ADFF4C824CA793E006DC7AE /* ToolbarViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ToolbarViewController.swift; sourceTree = ""; }; 1ADFF4CA24CB8278006DC7AE /* ScriptControllerIconView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ScriptControllerIconView.swift; sourceTree = ""; }; 1ADFF4CC24CBB0C8006DC7AE /* ScriptPolicyViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ScriptPolicyViewController.swift; sourceTree = ""; }; - 1ADFF4CF24CBBCD1006DC7AE /* ScriptPolicyControl.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ScriptPolicyControl.swift; sourceTree = ""; }; CD01D5A4254A10BB00189CDC /* TabBarView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TabBarView.swift; sourceTree = ""; }; CD01D5AA254A206D00189CDC /* TabBarViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TabBarViewController.swift; sourceTree = ""; }; CD470C4125DE056600AFBE0E /* BrowserViewController+WebKitDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "BrowserViewController+WebKitDelegate.swift"; sourceTree = ""; }; @@ -361,7 +359,6 @@ isa = PBXGroup; children = ( 1ADFF4CA24CB8278006DC7AE /* ScriptControllerIconView.swift */, - 1ADFF4CF24CBBCD1006DC7AE /* ScriptPolicyControl.swift */, 1ADFF4CC24CBB0C8006DC7AE /* ScriptPolicyViewController.swift */, ); path = "Script Policy UI"; @@ -555,7 +552,6 @@ 1ADFF47424C7DE9C006DC7AE /* BrowserViewController.swift in Sources */, CDCE2668251AAA9A007FE92A /* FontSizeAdjustView.swift in Sources */, CD01D5A5254A10BB00189CDC /* TabBarView.swift in Sources */, - 1ADFF4D024CBBCD1006DC7AE /* ScriptPolicyControl.swift in Sources */, 1A03810D24E71CA700826501 /* ToolbarView.swift in Sources */, CD470C4425DE070400AFBE0E /* BrowserViewController+Keyboard.swift in Sources */, CDD0522425F8055700DD1771 /* SearchProvider.swift in Sources */,