From 291abfcd6a9e24b4f1fa56946ed01ae43b67e96b Mon Sep 17 00:00:00 2001 From: James Magahern Date: Thu, 21 Oct 2021 15:08:04 -0700 Subject: [PATCH] ScriptControllerIconView: Update to reflect policy type --- App/Browser View/BrowserViewController.swift | 15 ++++---- App/Common UI/ReliefButton.swift | 6 ++-- .../ScriptControllerIconView.swift | 36 +++++++++++++++---- .../ScriptPolicyViewController.swift | 8 ++++- .../SBRScriptPolicy.h | 16 +++++++-- .../SBRScriptPolicy.m | 35 +++++++++++++++--- SBrowser.xcodeproj/project.pbxproj | 8 ++--- .../xcshareddata/xcschemes/App.xcscheme | 4 +-- 8 files changed, 96 insertions(+), 32 deletions(-) diff --git a/App/Browser View/BrowserViewController.swift b/App/Browser View/BrowserViewController.swift index c67d674..01d43fe 100644 --- a/App/Browser View/BrowserViewController.swift +++ b/App/Browser View/BrowserViewController.swift @@ -513,17 +513,20 @@ class BrowserViewController: UIViewController numBlockedScripts += 1 } - var scriptsAllowedForHost = false - if let url = webView.url, let host = url.host, policyManager.allowedOriginsForScriptResources().contains(host) { - scriptsAllowedForHost = true + var policy: ScriptPolicy? = nil + if let url = webView.url, let host = url.host { + policy = policyManager.scriptPolicy(forOrigin: host) } let iconView = toolbarController.scriptControllerIconView iconView.shieldsDown = tab.javaScriptEnabled - iconView.someScriptsAllowed = scriptsAllowedForHost - iconView.setBlockedScriptsNumber(numBlockedScripts) + // iconView.setBlockedScriptsNumber(numBlockedScripts) - // iconView.isEnabled = (webView.url != nil) + if let policy = policy { + iconView.currentPolicy = policy + } + + iconView.isEnabled = (webView.url != nil) } public func createNewTab(withURL url: URL?) { diff --git a/App/Common UI/ReliefButton.swift b/App/Common UI/ReliefButton.swift index dba570b..a5d680a 100644 --- a/App/Common UI/ReliefButton.swift +++ b/App/Common UI/ReliefButton.swift @@ -125,11 +125,13 @@ class ReliefButton: UIButton override func imageRect(forContentRect contentRect: CGRect) -> CGRect { let ratio = CGFloat(0.45) + let constantSize = round(ratio * contentRect.width) return CGRect( origin: .zero, size: CGSize( - width: ratio * contentRect.width, - height: ratio * contentRect.width + // Ensure multiple of two for proper centering. + width: constantSize + constantSize.truncatingRemainder(dividingBy: 2), + height: constantSize + constantSize.truncatingRemainder(dividingBy: 2) ) ).centered(inRect: contentRect) } diff --git a/App/Script Policy UI/ScriptControllerIconView.swift b/App/Script Policy UI/ScriptControllerIconView.swift index 5b482b7..8c267d5 100644 --- a/App/Script Policy UI/ScriptControllerIconView.swift +++ b/App/Script Policy UI/ScriptControllerIconView.swift @@ -13,17 +13,16 @@ class ScriptControllerIconView: ReliefButton didSet { setNeedsLayout() } } - public var someScriptsAllowed: Bool = false { - didSet { setNeedsLayout() } - } + @Invalidating(.layout) + public var currentPolicy: ScriptPolicy = ScriptPolicy(securityOrigin: "", policyType: .alpha) private let labelView = UILabel(frame: .zero) + private let policyImageView = UIImageView(frame: .zero) private let shieldsDownImage = UIImage(systemName: "shield.slash") private let shieldsUpImage = UIImage(systemName: "shield") private let shieldsPartiallyUpImage = UIImage(systemName: "shield.lefthalf.fill") - override init() { super.init() @@ -37,6 +36,8 @@ class ScriptControllerIconView: ReliefButton labelView.font = .boldSystemFont(ofSize: 8) labelView.textColor = .white + policyImageView.contentMode = .scaleAspectFit + setBlockedScriptsNumber(0) } @@ -62,13 +63,34 @@ class ScriptControllerIconView: ReliefButton labelView.center = CGPoint(x: bounds.center.x + 10, y: bounds.center.y + 10) labelView.bounds = labelView.bounds.insetBy(dx: -3.0, dy: -2.0) + let policyImageWidth = round(bounds.width / 3) + let policyImageSize = CGSize( + // Make multiple of 2 to ensure proper centering + width: policyImageWidth - policyImageWidth.truncatingRemainder(dividingBy: 2), + height: policyImageWidth - policyImageWidth.truncatingRemainder(dividingBy: 2) + ) + + if let imageView = imageView { + imageView.addSubview(policyImageView) + policyImageView.frame = CGRect(origin: .zero, size: policyImageSize) + .centered(inRect: imageView.bounds) + .offsetBy(dx: 0.0, dy: -1.0) + } + if shieldsDown { setImage(shieldsDownImage, for: .normal) } else { - if someScriptsAllowed { - setImage(shieldsPartiallyUpImage, for: .normal) + setImage(shieldsUpImage, for: .normal) + + if isEnabled { + policyImageView.isHidden = false + policyImageView.image = ScriptPolicy.iconRepresentation(forPolicyType: currentPolicy.policyType, configuration: ScriptPolicy.IconConfiguration( + size: policyImageSize, + foregroundColor: .label, + backgroundColor: .clear + )) } else { - setImage(shieldsUpImage, for: .normal) + policyImageView.isHidden = true } } } diff --git a/App/Script Policy UI/ScriptPolicyViewController.swift b/App/Script Policy UI/ScriptPolicyViewController.swift index 186f79e..e88f027 100644 --- a/App/Script Policy UI/ScriptPolicyViewController.swift +++ b/App/Script Policy UI/ScriptPolicyViewController.swift @@ -51,10 +51,16 @@ class ScriptPolicyViewController: UIViewController, UICollectionViewDelegate let scriptPolicyRegistry = UICollectionView.CellRegistration { (listCell, indexPath, item) in guard case let Item.policy(policyType) = item else { return } + let iconSize = CGSize(width: 24.0, height: 24.0) + 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.image = ScriptPolicy.iconRepresentation(forPolicyType: policyType, configuration: ScriptPolicy.IconConfiguration( + size: iconSize, + foregroundColor: .white, + backgroundColor: .black + )) config.textProperties.font = UIFont.boldSystemFont(ofSize: 14.0) diff --git a/App/Web Process Bundle Bridge/SBRScriptPolicy.h b/App/Web Process Bundle Bridge/SBRScriptPolicy.h index 673f647..d27c7b6 100644 --- a/App/Web Process Bundle Bridge/SBRScriptPolicy.h +++ b/App/Web Process Bundle Bridge/SBRScriptPolicy.h @@ -6,10 +6,11 @@ // #import +#import NS_ASSUME_NONNULL_BEGIN -@class UIImage; +@class UIImage, UIColor; typedef NS_ENUM(NSInteger, SBRScriptOriginPolicyType) { SBRScriptOriginPolicyTypeAlpha, @@ -19,6 +20,15 @@ typedef NS_ENUM(NSInteger, SBRScriptOriginPolicyType) { SBRScriptOriginPolicyTypeEcho, } NS_SWIFT_NAME(ScriptPolicy.PolicyType); +NS_SWIFT_NAME(ScriptPolicy.IconConfiguration) +@interface SBRScriptPolicyIconConfiguration : NSObject +@property (nonatomic, readwrite) CGSize size; +@property (nonatomic, strong, nullable) UIColor *foregroundColor; +@property (nonatomic, strong, nullable) UIColor *backgroundColor; + +- (instancetype)initWithSize:(CGSize)size foregroundColor:(nullable UIColor *)foregroundColor backgroundColor:(nullable UIColor *)backgroundColor; +@end + NS_SWIFT_NAME(ScriptPolicy) @interface SBRScriptPolicy : NSObject @property (nonatomic, copy) NSString *origin; @@ -30,8 +40,8 @@ NS_SWIFT_NAME(ScriptPolicy) + (NSString *)localizedDescriptionForPolicyType:(SBRScriptOriginPolicyType)policyType NS_SWIFT_NAME(localizedDescription(forPolicyType:)); -+ (UIImage *)iconRepresentationForPolicyType:(SBRScriptOriginPolicyType)policyType withSize:(CGSize)size - NS_SWIFT_NAME(iconRepresentation(forPolicyType:size:)); ++ (UIImage *)iconRepresentationForPolicyType:(SBRScriptOriginPolicyType)policyType withConfiguration:(SBRScriptPolicyIconConfiguration *)configuration + NS_SWIFT_NAME(iconRepresentation(forPolicyType:configuration:)); - (instancetype)initWithSecurityOrigin:(NSString *)origin policyType:(SBRScriptOriginPolicyType)policyType; diff --git a/App/Web Process Bundle Bridge/SBRScriptPolicy.m b/App/Web Process Bundle Bridge/SBRScriptPolicy.m index fbbe2ac..c45e857 100644 --- a/App/Web Process Bundle Bridge/SBRScriptPolicy.m +++ b/App/Web Process Bundle Bridge/SBRScriptPolicy.m @@ -10,6 +10,10 @@ // For icon drawing #import +static CGFloat RoundToScale(CGFloat v, CGFloat s) { + return round(v * s) / s; +} + @implementation SBRScriptPolicy + (NSSet *)_commonCDNOrigins { @@ -70,17 +74,20 @@ } } -+ (UIImage *)iconRepresentationForPolicyType:(SBRScriptOriginPolicyType)policyType withSize:(CGSize)size ++ (UIImage *)iconRepresentationForPolicyType:(SBRScriptOriginPolicyType)policyType withConfiguration:(nonnull SBRScriptPolicyIconConfiguration *)configuration { + const CGSize size = [configuration size]; UIFont *font = [UIFont boldSystemFontOfSize:size.height - 2]; NSDictionary *attrs = @{ NSFontAttributeName : font, - NSForegroundColorAttributeName : [UIColor whiteColor] + NSForegroundColorAttributeName : [configuration foregroundColor] ?: [UIColor whiteColor], }; + const CGFloat scale = UIScreen.mainScreen.scale; const CGRect rect = (CGRect) { .origin = CGPointZero, .size = size }; - UIGraphicsBeginImageContextWithOptions(size, NO, UIScreen.mainScreen.scale); + UIGraphicsBeginImageContextWithOptions(size, NO, scale); + [([configuration backgroundColor] ?: [UIColor blackColor]) setFill]; UIBezierPath *backgroundPath = [UIBezierPath bezierPathWithRoundedRect:rect cornerRadius:4.0]; [backgroundPath fill]; @@ -98,11 +105,14 @@ character = @"𝝴"; break; } - const CGSize charSize = [character sizeWithAttributes:attrs]; + CGSize charSize = [character sizeWithAttributes:attrs]; + charSize.width = RoundToScale(charSize.width, scale); + charSize.height = RoundToScale(charSize.height, scale); + const CGRect charRect = (CGRect) { .origin = (CGPoint) { .x = (size.width - charSize.width) / 2, - .y = -(charSize.height - size.height) / 2, + .y = -(charSize.height - size.height) / 2, }, .size = charSize @@ -203,3 +213,18 @@ } @end + +@implementation SBRScriptPolicyIconConfiguration + +- (instancetype)initWithSize:(CGSize)size foregroundColor:(nullable UIColor *)foregroundColor backgroundColor:(nullable UIColor *)backgroundColor +{ + if (self = [super init]) { + _size = size; + _foregroundColor = foregroundColor; + _backgroundColor = backgroundColor; + } + + return self; +} + +@end diff --git a/SBrowser.xcodeproj/project.pbxproj b/SBrowser.xcodeproj/project.pbxproj index 6070cac..6ded038 100644 --- a/SBrowser.xcodeproj/project.pbxproj +++ b/SBrowser.xcodeproj/project.pbxproj @@ -711,7 +711,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 14.0; + IPHONEOS_DEPLOYMENT_TARGET = 15.0; MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; MTL_FAST_MATH = YES; ONLY_ACTIVE_ARCH = YES; @@ -767,7 +767,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 14.0; + IPHONEOS_DEPLOYMENT_TARGET = 15.0; MTL_ENABLE_DEBUG_INFO = NO; MTL_FAST_MATH = YES; SDKROOT = iphoneos.internal; @@ -789,12 +789,10 @@ CURRENT_PROJECT_VERSION = 2; DEVELOPMENT_TEAM = DQQH5H6GBD; INFOPLIST_FILE = "App/Supporting Files/Info.plist"; - IPHONEOS_DEPLOYMENT_TARGET = 14.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", ); - MACOSX_DEPLOYMENT_TARGET = 10.15; MARKETING_VERSION = 2.0; PRODUCT_BUNDLE_IDENTIFIER = net.buzzert.rosslerattix; PRODUCT_NAME = "rossler attix"; @@ -819,12 +817,10 @@ CURRENT_PROJECT_VERSION = 2; DEVELOPMENT_TEAM = DQQH5H6GBD; INFOPLIST_FILE = "App/Supporting Files/Info.plist"; - IPHONEOS_DEPLOYMENT_TARGET = 14.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", ); - MACOSX_DEPLOYMENT_TARGET = 10.15; MARKETING_VERSION = 2.0; PRODUCT_BUNDLE_IDENTIFIER = net.buzzert.rosslerattix; PRODUCT_NAME = "rossler attix"; diff --git a/SBrowser.xcodeproj/xcshareddata/xcschemes/App.xcscheme b/SBrowser.xcodeproj/xcshareddata/xcschemes/App.xcscheme index 9c37fa1..c358d78 100644 --- a/SBrowser.xcodeproj/xcshareddata/xcschemes/App.xcscheme +++ b/SBrowser.xcodeproj/xcshareddata/xcschemes/App.xcscheme @@ -32,8 +32,8 @@