// // ScriptPolicyViewController.swift // SBrowser // // Created by James Magahern on 7/24/20. // import UIKit class ScriptPolicyViewController: UIViewController, UICollectionViewDelegate { var collectionView: UICollectionView? var allowScriptsForTab = false weak var delegate: ScriptPolicyViewControllerDelegate? = nil private enum Section: Int { case tabOptions case policies } private enum Item: Hashable { case allowScriptsForTab case policy(ScriptPolicy.PolicyType) } private var dataSource: UICollectionViewDiffableDataSource? private var didChangeScriptPolicy = false private var policyManager: ResourcePolicyManager! private var hostOrigin: String! convenience init(policyManager: ResourcePolicyManager, hostOrigin: String, loadedScripts: Set, scriptsAllowedForTab: Bool) { self.init(nibName: nil, bundle: nil) self.allowScriptsForTab = scriptsAllowedForTab self.policyManager = policyManager self.hostOrigin = hostOrigin let listConfig = UICollectionLayoutListConfiguration(appearance: .insetGrouped) let listLayout = UICollectionViewCompositionalLayout.list(using: listConfig) let collectionView = UICollectionView(frame: .zero, collectionViewLayout: listLayout) let scriptPolicyRegistry = UICollectionView.CellRegistration { (listCell, indexPath, item) in guard case let Item.policy(policyType) = item else { return } var config = listCell.defaultContentConfiguration() config.text = ScriptPolicy.title(forPolicyType: policyType) config.secondaryText = ScriptPolicy.localizedDescription(forPolicyType: policyType) config.image = ScriptPolicy.iconRepresentation(forPolicyType: policyType, size: CGSize(width: 24.0, height: 24.0)) config.textProperties.font = UIFont.boldSystemFont(ofSize: 14.0) if policyManager.scriptPolicy(forOrigin: hostOrigin).policyType == policyType { listCell.accessories = [ .checkmark() ] } listCell.contentConfiguration = config } let enableButtonRegistry = UICollectionView.CellRegistration { [unowned self] (listCell, indexPath, item) in var config = listCell.defaultContentConfiguration() if indexPath.section == Section.tabOptions.rawValue { 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 dataSource = UICollectionViewDiffableDataSource(collectionView: collectionView) { (collectionView, indexPath, item) -> UICollectionViewCell? in if indexPath.section == Section.tabOptions.rawValue { return collectionView.dequeueConfiguredReusableCell(using: enableButtonRegistry, for: indexPath, item: item) } return collectionView.dequeueConfiguredReusableCell(using: scriptPolicyRegistry, for: indexPath, item: item) } collectionView.dataSource = dataSource collectionView.delegate = self var snapshot = dataSource.snapshot() snapshot.appendSections([ .tabOptions ]) snapshot.appendItems([ .allowScriptsForTab ], toSection: .tabOptions) if !allowScriptsForTab { snapshot.appendSections([ .policies ]) snapshot.appendItems(ScriptPolicy.PolicyType.allCases.map { .policy($0) }, toSection: .policies) } dataSource.apply(snapshot) self.dataSource = dataSource self.collectionView = collectionView title = "Script Security Policy" navigationItem.rightBarButtonItem = UIBarButtonItem(systemItem: .done, primaryAction: UIAction(handler: { [unowned self] action in if self.didChangeScriptPolicy { self.delegate?.didChangeScriptPolicy() self.delegate?.setScriptsEnabledForTab(self.allowScriptsForTab) } self.dismiss(animated: true, completion: nil) }), menu: nil) } override func loadView() { self.view = collectionView self.view.backgroundColor = .systemGroupedBackground } // MARK: UICollectionViewDelegate 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 == .allowScriptsForTab { self.allowScriptsForTab = !self.allowScriptsForTab // Immediately notify and dismiss self.delegate?.didChangeScriptPolicy() self.delegate?.setScriptsEnabledForTab(self.allowScriptsForTab) self.dismiss(animated: true, completion: nil) } } else if indexPath.section == Section.policies.rawValue { guard let identifier = dataSource.itemIdentifier(for: indexPath) else { return } guard case let Item.policy(policyType) = identifier else { return } var snapshot = dataSource.snapshot() snapshot.reloadItems([ identifier ]) let selectedItem = Item.policy(policyManager.scriptPolicy(forOrigin: hostOrigin).policyType) snapshot.reloadItems([ selectedItem ]) policyManager.setScriptPolicyType(policyType, forOrigin: hostOrigin) dataSource.apply(snapshot) delegate?.didChangeScriptPolicy() collectionView.deselectItem(at: indexPath, animated: true) dismiss(animated: true, completion: nil) } } }