├── .gitignore ├── Assets ├── AppIcon.png └── Screenshot.png ├── Browsing ├── Base.lproj │ └── SafariExtensionViewController.xib ├── Browsing.entitlements ├── BrowsingIcon.swift ├── Compass.pdf ├── IconFactory.swift ├── Info.plist ├── Mask.pdf ├── SafariExtensionHandler.swift ├── SafariExtensionViewController.swift └── Unavailable.pdf ├── Gemfile ├── Gemfile.lock ├── IsItPrivate.xcodeproj ├── project.pbxproj └── project.xcworkspace │ ├── contents.xcworkspacedata │ └── xcshareddata │ └── IDEWorkspaceChecks.plist ├── IsItPrivate ├── AboutWindow │ ├── AboutWindowController.swift │ ├── AboutWindowController.xib │ └── ActionLabel.swift ├── AppDelegate.swift ├── DefaultWindow │ ├── Base.lproj │ │ └── Main.storyboard │ ├── ExtensionStateManager.swift │ ├── PreferencesViewController.swift │ ├── TutorialViewController.swift │ └── ViewController.swift ├── Extensions │ └── NSViewController+Extension.swift └── Resources │ ├── Assets.xcassets │ ├── AppIcon.appiconset │ │ ├── Contents.json │ │ ├── Icon-128x128-@1x.png │ │ ├── Icon-128x128-@2x.png │ │ ├── Icon-16x16-@1x.png │ │ ├── Icon-16x16-@2x.png │ │ ├── Icon-256x256-@1x.png │ │ ├── Icon-256x256-@2x.png │ │ ├── Icon-32x32-@1x.png │ │ ├── Icon-32x32-@2x.png │ │ ├── Icon-512x512-@1x.png │ │ └── Icon-512x512-@2x.png │ ├── Contents.json │ ├── Safari_Preferences.imageset │ │ ├── Contents.json │ │ ├── Safari_Preferences_Dark.png │ │ ├── Safari_Preferences_Light-1.png │ │ └── Safari_Preferences_Light.png │ ├── Tutorial_Normal.imageset │ │ ├── Contents.json │ │ ├── Tutorial_Normal_Dark.png │ │ ├── Tutorial_Normal_Light-1.png │ │ └── Tutorial_Normal_Light.png │ └── Tutorial_Private.imageset │ │ ├── Contents.json │ │ ├── Tutorial_Private_Dark.png │ │ ├── Tutorial_Private_Light-1.png │ │ └── Tutorial_Private_Light.png │ ├── Info.plist │ └── IsItPrivate.entitlements ├── LICENSE ├── PRIVACY.md ├── README.md └── fastlane ├── Appfile ├── Fastfile ├── README.md └── actions └── appicon.rb /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | # Created by https://www.gitignore.io/api/swift 3 | 4 | ### Swift ### 5 | # Xcode 6 | # 7 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore 8 | 9 | ## Build generated 10 | build/ 11 | DerivedData/ 12 | 13 | ## Various settings 14 | *.pbxuser 15 | !default.pbxuser 16 | *.mode1v3 17 | !default.mode1v3 18 | *.mode2v3 19 | !default.mode2v3 20 | *.perspectivev3 21 | !default.perspectivev3 22 | xcuserdata/ 23 | 24 | ## Other 25 | *.moved-aside 26 | *.xccheckout 27 | *.xcscmblueprint 28 | 29 | ## Obj-C/Swift specific 30 | *.hmap 31 | *.ipa 32 | *.dSYM.zip 33 | *.dSYM 34 | 35 | ## Playgrounds 36 | timeline.xctimeline 37 | playground.xcworkspace 38 | 39 | # Swift Package Manager 40 | # 41 | # Add this line if you want to avoid checking in source code from Swift Package Manager dependencies. 42 | # Packages/ 43 | # Package.pins 44 | # Package.resolved 45 | .build/ 46 | 47 | # CocoaPods 48 | # 49 | # We recommend against adding the Pods directory to your .gitignore. However 50 | # you should judge for yourself, the pros and cons are mentioned at: 51 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control 52 | # 53 | # Pods/ 54 | # 55 | # Add this line if you want to avoid checking in source code from the Xcode workspace 56 | # *.xcworkspace 57 | 58 | # Carthage 59 | # 60 | # Add this line if you want to avoid checking in source code from Carthage dependencies. 61 | # Carthage/Checkouts 62 | 63 | Carthage/Build 64 | 65 | # fastlane 66 | # 67 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the 68 | # screenshots whenever they are needed. 69 | # For more information about the recommended setup visit: 70 | # https://docs.fastlane.tools/best-practices/source-control/#source-control 71 | 72 | fastlane/report.xml 73 | fastlane/Preview.html 74 | fastlane/screenshots/**/*.png 75 | fastlane/test_output 76 | 77 | # Code Injection 78 | # 79 | # After new code Injection tools there's a generated folder /iOSInjectionProject 80 | # https://github.com/johnno1962/injectionforxcode 81 | 82 | iOSInjectionProject/ 83 | 84 | 85 | # End of https://www.gitignore.io/api/swift -------------------------------------------------------------------------------- /Assets/AppIcon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ffittschen/IsItPrivate/d61e9a5c765642dc5dd8b3aa8f1e73a4f0aea79f/Assets/AppIcon.png -------------------------------------------------------------------------------- /Assets/Screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ffittschen/IsItPrivate/d61e9a5c765642dc5dd8b3aa8f1e73a4f0aea79f/Assets/Screenshot.png -------------------------------------------------------------------------------- /Browsing/Base.lproj/SafariExtensionViewController.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /Browsing/Browsing.entitlements: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | com.apple.security.app-sandbox 6 | 7 | com.apple.security.files.user-selected.read-only 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /Browsing/BrowsingIcon.swift: -------------------------------------------------------------------------------- 1 | // 2 | // BrowsingIcon.swift 3 | // Browsing 4 | // 5 | // Created by Florian Fittschen on 22.10.18. 6 | // Copyright © 2018 Florian Fittschen. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import AppKit.NSImage 11 | 12 | enum BrowsingIcon: String { 13 | case Mask 14 | case Compass 15 | case Unavailable 16 | } 17 | 18 | extension BrowsingIcon { 19 | var url: URL { 20 | return URL(fileURLWithPath: Bundle.main.path(forResource: rawValue, ofType: "pdf")!) 21 | } 22 | 23 | var label: String { 24 | switch self { 25 | case .Compass: 26 | return "Private Browsing: Off" 27 | case .Mask: 28 | return "Private Browsing: On" 29 | case .Unavailable: 30 | return "Private Browsing: ?" 31 | } 32 | } 33 | 34 | var image: NSImage { 35 | return NSImage(contentsOf: url)! 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /Browsing/Compass.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ffittschen/IsItPrivate/d61e9a5c765642dc5dd8b3aa8f1e73a4f0aea79f/Browsing/Compass.pdf -------------------------------------------------------------------------------- /Browsing/IconFactory.swift: -------------------------------------------------------------------------------- 1 | // 2 | // IconFactory.swift 3 | // Browsing 4 | // 5 | // Created by Florian Fittschen on 22.10.18. 6 | // Copyright © 2018 Florian Fittschen. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import SafariServices 11 | 12 | struct IconFactory { 13 | static func icon(for window: SFSafariWindow, _ completionHandler: @escaping (BrowsingIcon?) -> Void) { 14 | window.getActiveTab { tab in 15 | IconFactory.icon(for: tab, completionHandler) 16 | } 17 | } 18 | 19 | static func icon(for tab: SFSafariTab?, _ completionHandler: @escaping (BrowsingIcon?) -> Void) { 20 | guard let tab = tab else { 21 | completionHandler(nil) 22 | return 23 | } 24 | tab.getActivePage { page in 25 | IconFactory.icon(for: page, completionHandler) 26 | } 27 | } 28 | 29 | static func icon(for page: SFSafariPage?, _ completionHandler: @escaping (BrowsingIcon?) -> Void) { 30 | guard let page = page else { 31 | completionHandler(nil) 32 | return 33 | } 34 | page.getPropertiesWithCompletionHandler { properties in 35 | IconFactory.icon(for: properties, completionHandler) 36 | } 37 | } 38 | 39 | static func icon(for properties: SFSafariPageProperties?, _ completionHandler: @escaping (BrowsingIcon?) -> Void) { 40 | guard let properties = properties else { 41 | completionHandler(nil) 42 | return 43 | } 44 | let icon: BrowsingIcon = properties.usesPrivateBrowsing ? .Mask : .Compass 45 | completionHandler(icon) 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /Browsing/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleDisplayName 8 | Private Browsing Detector 9 | CFBundleExecutable 10 | $(EXECUTABLE_NAME) 11 | CFBundleIdentifier 12 | $(PRODUCT_BUNDLE_IDENTIFIER) 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | $(PRODUCT_NAME) 17 | CFBundlePackageType 18 | XPC! 19 | CFBundleShortVersionString 20 | 1.0 21 | CFBundleVersion 22 | 2 23 | ITSAppUsesNonExemptEncryption 24 | 25 | LSMinimumSystemVersion 26 | $(MACOSX_DEPLOYMENT_TARGET) 27 | NSExtension 28 | 29 | NSExtensionPointIdentifier 30 | com.apple.Safari.extension 31 | NSExtensionPrincipalClass 32 | $(PRODUCT_MODULE_NAME).SafariExtensionHandler 33 | SFSafariToolbarItem 34 | 35 | Action 36 | Popover 37 | Identifier 38 | Button 39 | Image 40 | Compass.pdf 41 | Label 42 | Private Browsing: ? 43 | 44 | SFSafariWebsiteAccess 45 | 46 | Level 47 | All 48 | 49 | 50 | NSHumanReadableCopyright 51 | Copyright © 2018 Florian Fittschen. All rights reserved. 52 | NSHumanReadableDescription 53 | Adds a toolbar item that changes its icon to quickly identify if Private Browsing is enabled in the current Safari window. 54 | 55 | 56 | -------------------------------------------------------------------------------- /Browsing/Mask.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ffittschen/IsItPrivate/d61e9a5c765642dc5dd8b3aa8f1e73a4f0aea79f/Browsing/Mask.pdf -------------------------------------------------------------------------------- /Browsing/SafariExtensionHandler.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SafariExtensionHandler.swift 3 | // Browsing 4 | // 5 | // Created by Florian Fittschen on 19.10.18. 6 | // Copyright © 2018 Florian Fittschen. All rights reserved. 7 | // 8 | 9 | import SafariServices 10 | 11 | class SafariExtensionHandler: SFSafariExtensionHandler { 12 | 13 | override func messageReceived(withName messageName: String, from page: SFSafariPage, userInfo: [String : Any]?) { 14 | // This method will be called when a content script provided by your extension calls safari.extension.dispatchMessage("message"). 15 | 16 | page.getPropertiesWithCompletionHandler { properties in 17 | NSLog("The extension received a message (\(messageName)) from a script injected into (\(String(describing: properties?.url))) with userInfo (\(userInfo ?? [:]))") 18 | } 19 | } 20 | 21 | override func toolbarItemClicked(in window: SFSafariWindow) { 22 | // This method will be called when your toolbar item is clicked. 23 | NSLog("The extension's toolbar item was clicked") 24 | } 25 | 26 | override func validateToolbarItem(in window: SFSafariWindow, validationHandler: @escaping ((Bool, String) -> Void)) { 27 | // This is called when Safari's state changed in some way that would require the extension's toolbar item to be validated again. 28 | NSLog("The extension's toolbar item was validated") 29 | 30 | IconFactory.icon(for: window) { icon in 31 | guard let icon = icon else { return } 32 | NSLog("Icon for window: \(icon)") 33 | window.getToolbarItem { toolbarItem in 34 | toolbarItem?.setImage(icon.image) 35 | toolbarItem?.setLabel(icon.label) 36 | } 37 | } 38 | 39 | validationHandler(true, "") 40 | } 41 | 42 | override func popoverViewController() -> SFSafariExtensionViewController { 43 | return SafariExtensionViewController.shared 44 | } 45 | 46 | override func popoverWillShow(in window: SFSafariWindow) { 47 | IconFactory.icon(for: window) { icon in 48 | guard let icon = icon else { return } 49 | SafariExtensionViewController.shared.configureLabel(with: icon) 50 | } 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /Browsing/SafariExtensionViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SafariExtensionViewController.swift 3 | // Browsing 4 | // 5 | // Created by Florian Fittschen on 19.10.18. 6 | // Copyright © 2018 Florian Fittschen. All rights reserved. 7 | // 8 | 9 | import SafariServices 10 | 11 | class SafariExtensionViewController: SFSafariExtensionViewController { 12 | 13 | @IBOutlet private weak var textField: NSTextField! 14 | 15 | static let shared: SafariExtensionViewController = { 16 | let shared = SafariExtensionViewController() 17 | shared.preferredContentSize = NSSize(width: 160, height: 42) 18 | return shared 19 | }() 20 | 21 | func configureLabel(with icon: BrowsingIcon) { 22 | NSLog("Label for Popover: \(icon.label)") 23 | textField.stringValue = icon.label 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /Browsing/Unavailable.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ffittschen/IsItPrivate/d61e9a5c765642dc5dd8b3aa8f1e73a4f0aea79f/Browsing/Unavailable.pdf -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source 'https://rubygems.org' 2 | 3 | gem 'fastlane' 4 | -------------------------------------------------------------------------------- /Gemfile.lock: -------------------------------------------------------------------------------- 1 | GEM 2 | remote: https://rubygems.org/ 3 | specs: 4 | CFPropertyList (3.0.1) 5 | addressable (2.8.0) 6 | public_suffix (>= 2.0.2, < 5.0) 7 | atomos (0.1.3) 8 | babosa (1.0.2) 9 | claide (1.0.3) 10 | colored (1.2) 11 | colored2 (3.1.2) 12 | commander-fastlane (4.4.6) 13 | highline (~> 1.7.2) 14 | declarative (0.0.10) 15 | declarative-option (0.1.0) 16 | digest-crc (0.4.1) 17 | domain_name (0.5.20190701) 18 | unf (>= 0.0.5, < 1.0.0) 19 | dotenv (2.7.5) 20 | emoji_regex (1.0.1) 21 | excon (0.71.0) 22 | faraday (0.15.4) 23 | multipart-post (>= 1.2, < 3) 24 | faraday-cookie_jar (0.0.6) 25 | faraday (>= 0.7.4) 26 | http-cookie (~> 1.0.0) 27 | faraday_middleware (0.13.1) 28 | faraday (>= 0.7.4, < 1.0) 29 | fastimage (2.1.7) 30 | fastlane (2.131.0) 31 | CFPropertyList (>= 2.3, < 4.0.0) 32 | addressable (>= 2.3, < 3.0.0) 33 | babosa (>= 1.0.2, < 2.0.0) 34 | bundler (>= 1.12.0, < 3.0.0) 35 | colored 36 | commander-fastlane (>= 4.4.6, < 5.0.0) 37 | dotenv (>= 2.1.1, < 3.0.0) 38 | emoji_regex (>= 0.1, < 2.0) 39 | excon (>= 0.45.0, < 1.0.0) 40 | faraday (~> 0.9) 41 | faraday-cookie_jar (~> 0.0.6) 42 | faraday_middleware (~> 0.9) 43 | fastimage (>= 2.1.0, < 3.0.0) 44 | gh_inspector (>= 1.1.2, < 2.0.0) 45 | google-api-client (>= 0.21.2, < 0.24.0) 46 | google-cloud-storage (>= 1.15.0, < 2.0.0) 47 | highline (>= 1.7.2, < 2.0.0) 48 | json (< 3.0.0) 49 | jwt (~> 2.1.0) 50 | mini_magick (>= 4.9.4, < 5.0.0) 51 | multi_xml (~> 0.5) 52 | multipart-post (~> 2.0.0) 53 | plist (>= 3.1.0, < 4.0.0) 54 | public_suffix (~> 2.0.0) 55 | rubyzip (>= 1.2.2, < 2.0.0) 56 | security (= 0.1.3) 57 | simctl (~> 1.6.3) 58 | slack-notifier (>= 2.0.0, < 3.0.0) 59 | terminal-notifier (>= 2.0.0, < 3.0.0) 60 | terminal-table (>= 1.4.5, < 2.0.0) 61 | tty-screen (>= 0.6.3, < 1.0.0) 62 | tty-spinner (>= 0.8.0, < 1.0.0) 63 | word_wrap (~> 1.0.0) 64 | xcodeproj (>= 1.8.1, < 2.0.0) 65 | xcpretty (~> 0.3.0) 66 | xcpretty-travis-formatter (>= 0.0.3) 67 | gh_inspector (1.1.3) 68 | google-api-client (0.23.9) 69 | addressable (~> 2.5, >= 2.5.1) 70 | googleauth (>= 0.5, < 0.7.0) 71 | httpclient (>= 2.8.1, < 3.0) 72 | mime-types (~> 3.0) 73 | representable (~> 3.0) 74 | retriable (>= 2.0, < 4.0) 75 | signet (~> 0.9) 76 | google-cloud-core (1.3.1) 77 | google-cloud-env (~> 1.0) 78 | google-cloud-env (1.2.1) 79 | faraday (~> 0.11) 80 | google-cloud-storage (1.16.0) 81 | digest-crc (~> 0.4) 82 | google-api-client (~> 0.23) 83 | google-cloud-core (~> 1.2) 84 | googleauth (>= 0.6.2, < 0.10.0) 85 | googleauth (0.6.7) 86 | faraday (~> 0.12) 87 | jwt (>= 1.4, < 3.0) 88 | memoist (~> 0.16) 89 | multi_json (~> 1.11) 90 | os (>= 0.9, < 2.0) 91 | signet (~> 0.7) 92 | highline (1.7.10) 93 | http-cookie (1.0.3) 94 | domain_name (~> 0.5) 95 | httpclient (2.8.3) 96 | json (2.3.1) 97 | jwt (2.1.0) 98 | memoist (0.16.0) 99 | mime-types (3.3) 100 | mime-types-data (~> 3.2015) 101 | mime-types-data (3.2019.0904) 102 | mini_magick (4.9.5) 103 | multi_json (1.13.1) 104 | multi_xml (0.6.0) 105 | multipart-post (2.0.0) 106 | nanaimo (0.2.6) 107 | naturally (2.2.0) 108 | os (1.0.1) 109 | plist (3.5.0) 110 | public_suffix (2.0.5) 111 | representable (3.0.4) 112 | declarative (< 0.1.0) 113 | declarative-option (< 0.2.0) 114 | uber (< 0.2.0) 115 | retriable (3.1.2) 116 | rouge (2.0.7) 117 | rubyzip (1.3.0) 118 | security (0.1.3) 119 | signet (0.11.0) 120 | addressable (~> 2.3) 121 | faraday (~> 0.9) 122 | jwt (>= 1.5, < 3.0) 123 | multi_json (~> 1.10) 124 | simctl (1.6.6) 125 | CFPropertyList 126 | naturally 127 | slack-notifier (2.3.2) 128 | terminal-notifier (2.0.0) 129 | terminal-table (1.8.0) 130 | unicode-display_width (~> 1.1, >= 1.1.1) 131 | tty-cursor (0.7.0) 132 | tty-screen (0.7.0) 133 | tty-spinner (0.9.1) 134 | tty-cursor (~> 0.7) 135 | uber (0.1.0) 136 | unf (0.1.4) 137 | unf_ext 138 | unf_ext (0.0.7.6) 139 | unicode-display_width (1.6.0) 140 | word_wrap (1.0.0) 141 | xcodeproj (1.12.0) 142 | CFPropertyList (>= 2.3.3, < 4.0) 143 | atomos (~> 0.1.3) 144 | claide (>= 1.0.2, < 2.0) 145 | colored2 (~> 3.1) 146 | nanaimo (~> 0.2.6) 147 | xcpretty (0.3.0) 148 | rouge (~> 2.0.7) 149 | xcpretty-travis-formatter (1.0.0) 150 | xcpretty (~> 0.2, >= 0.0.7) 151 | 152 | PLATFORMS 153 | ruby 154 | 155 | DEPENDENCIES 156 | fastlane 157 | 158 | BUNDLED WITH 159 | 2.0.2 160 | -------------------------------------------------------------------------------- /IsItPrivate.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 50; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 041DE6AC217DC0C5006AF8AD /* Mask.pdf in Resources */ = {isa = PBXBuildFile; fileRef = 041DE6AB217DC0C5006AF8AD /* Mask.pdf */; }; 11 | 041DE6B0217DC0F0006AF8AD /* Compass.pdf in Resources */ = {isa = PBXBuildFile; fileRef = 041DE6AF217DC0F0006AF8AD /* Compass.pdf */; }; 12 | 041DE6B4217DD3A2006AF8AD /* IconFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 041DE6B3217DD3A2006AF8AD /* IconFactory.swift */; }; 13 | 041DE6B6217DD7C0006AF8AD /* BrowsingIcon.swift in Sources */ = {isa = PBXBuildFile; fileRef = 041DE6B5217DD7C0006AF8AD /* BrowsingIcon.swift */; }; 14 | 041DE6BA217DE480006AF8AD /* Unavailable.pdf in Resources */ = {isa = PBXBuildFile; fileRef = 041DE6B9217DE480006AF8AD /* Unavailable.pdf */; }; 15 | 049AFCEA2179E00300AC25DC /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 049AFCE92179E00300AC25DC /* AppDelegate.swift */; }; 16 | 049AFCEC2179E00300AC25DC /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 049AFCEB2179E00300AC25DC /* ViewController.swift */; }; 17 | 049AFCEE2179E00400AC25DC /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 049AFCED2179E00400AC25DC /* Assets.xcassets */; }; 18 | 049AFCF12179E00400AC25DC /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 049AFCEF2179E00400AC25DC /* Main.storyboard */; }; 19 | 049AFD0E2179E03500AC25DC /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 049AFD0D2179E03500AC25DC /* Cocoa.framework */; }; 20 | 049AFD112179E03500AC25DC /* SafariExtensionHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 049AFD102179E03500AC25DC /* SafariExtensionHandler.swift */; }; 21 | 049AFD132179E03500AC25DC /* SafariExtensionViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 049AFD122179E03500AC25DC /* SafariExtensionViewController.swift */; }; 22 | 049AFD162179E03500AC25DC /* SafariExtensionViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 049AFD142179E03500AC25DC /* SafariExtensionViewController.xib */; }; 23 | 049AFD1F2179E03500AC25DC /* Browsing.appex in Embed App Extensions */ = {isa = PBXBuildFile; fileRef = 049AFD0B2179E03500AC25DC /* Browsing.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; }; 24 | 04A9DD5C2181F97600655766 /* PreferencesViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 04A9DD5B2181F97600655766 /* PreferencesViewController.swift */; }; 25 | 04A9DD5F2181F98700655766 /* TutorialViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 04A9DD5D2181F98700655766 /* TutorialViewController.swift */; }; 26 | 04A9DD622182FBB900655766 /* ExtensionStateManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 04A9DD612182FBB900655766 /* ExtensionStateManager.swift */; }; 27 | 04A9DD64218301C700655766 /* NSViewController+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 04A9DD63218301C700655766 /* NSViewController+Extension.swift */; }; 28 | 04A9DD672183284D00655766 /* AboutWindowController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 04A9DD652183284D00655766 /* AboutWindowController.swift */; }; 29 | 04A9DD682183284D00655766 /* AboutWindowController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 04A9DD662183284D00655766 /* AboutWindowController.xib */; }; 30 | 04A9DD6A21832EC200655766 /* ActionLabel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 04A9DD6921832EC200655766 /* ActionLabel.swift */; }; 31 | /* End PBXBuildFile section */ 32 | 33 | /* Begin PBXContainerItemProxy section */ 34 | 049AFD1D2179E03500AC25DC /* PBXContainerItemProxy */ = { 35 | isa = PBXContainerItemProxy; 36 | containerPortal = 049AFCDE2179E00300AC25DC /* Project object */; 37 | proxyType = 1; 38 | remoteGlobalIDString = 049AFD0A2179E03500AC25DC; 39 | remoteInfo = Browsing; 40 | }; 41 | /* End PBXContainerItemProxy section */ 42 | 43 | /* Begin PBXCopyFilesBuildPhase section */ 44 | 049AFD232179E03500AC25DC /* Embed App Extensions */ = { 45 | isa = PBXCopyFilesBuildPhase; 46 | buildActionMask = 2147483647; 47 | dstPath = ""; 48 | dstSubfolderSpec = 13; 49 | files = ( 50 | 049AFD1F2179E03500AC25DC /* Browsing.appex in Embed App Extensions */, 51 | ); 52 | name = "Embed App Extensions"; 53 | runOnlyForDeploymentPostprocessing = 0; 54 | }; 55 | /* End PBXCopyFilesBuildPhase section */ 56 | 57 | /* Begin PBXFileReference section */ 58 | 041DE6AB217DC0C5006AF8AD /* Mask.pdf */ = {isa = PBXFileReference; lastKnownFileType = image.pdf; path = Mask.pdf; sourceTree = ""; }; 59 | 041DE6AF217DC0F0006AF8AD /* Compass.pdf */ = {isa = PBXFileReference; lastKnownFileType = image.pdf; path = Compass.pdf; sourceTree = ""; }; 60 | 041DE6B3217DD3A2006AF8AD /* IconFactory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IconFactory.swift; sourceTree = ""; }; 61 | 041DE6B5217DD7C0006AF8AD /* BrowsingIcon.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BrowsingIcon.swift; sourceTree = ""; }; 62 | 041DE6B9217DE480006AF8AD /* Unavailable.pdf */ = {isa = PBXFileReference; lastKnownFileType = image.pdf; path = Unavailable.pdf; sourceTree = ""; }; 63 | 049AFCE62179E00300AC25DC /* IsItPrivate.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = IsItPrivate.app; sourceTree = BUILT_PRODUCTS_DIR; }; 64 | 049AFCE92179E00300AC25DC /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 65 | 049AFCEB2179E00300AC25DC /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = ""; }; 66 | 049AFCED2179E00400AC25DC /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 67 | 049AFCF02179E00400AC25DC /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 68 | 049AFCF22179E00400AC25DC /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 69 | 049AFCF32179E00400AC25DC /* IsItPrivate.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = IsItPrivate.entitlements; sourceTree = ""; }; 70 | 049AFD0B2179E03500AC25DC /* Browsing.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = Browsing.appex; sourceTree = BUILT_PRODUCTS_DIR; }; 71 | 049AFD0D2179E03500AC25DC /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = System/Library/Frameworks/Cocoa.framework; sourceTree = SDKROOT; }; 72 | 049AFD102179E03500AC25DC /* SafariExtensionHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SafariExtensionHandler.swift; sourceTree = ""; }; 73 | 049AFD122179E03500AC25DC /* SafariExtensionViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SafariExtensionViewController.swift; sourceTree = ""; }; 74 | 049AFD152179E03500AC25DC /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/SafariExtensionViewController.xib; sourceTree = ""; }; 75 | 049AFD172179E03500AC25DC /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 76 | 049AFD1C2179E03500AC25DC /* Browsing.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = Browsing.entitlements; sourceTree = ""; }; 77 | 04A9DD5B2181F97600655766 /* PreferencesViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PreferencesViewController.swift; sourceTree = ""; }; 78 | 04A9DD5D2181F98700655766 /* TutorialViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TutorialViewController.swift; sourceTree = ""; }; 79 | 04A9DD612182FBB900655766 /* ExtensionStateManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ExtensionStateManager.swift; sourceTree = ""; }; 80 | 04A9DD63218301C700655766 /* NSViewController+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NSViewController+Extension.swift"; sourceTree = ""; }; 81 | 04A9DD652183284D00655766 /* AboutWindowController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AboutWindowController.swift; sourceTree = ""; }; 82 | 04A9DD662183284D00655766 /* AboutWindowController.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = AboutWindowController.xib; sourceTree = ""; }; 83 | 04A9DD6921832EC200655766 /* ActionLabel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ActionLabel.swift; sourceTree = ""; }; 84 | /* End PBXFileReference section */ 85 | 86 | /* Begin PBXFrameworksBuildPhase section */ 87 | 049AFCE32179E00300AC25DC /* Frameworks */ = { 88 | isa = PBXFrameworksBuildPhase; 89 | buildActionMask = 2147483647; 90 | files = ( 91 | ); 92 | runOnlyForDeploymentPostprocessing = 0; 93 | }; 94 | 049AFD082179E03500AC25DC /* Frameworks */ = { 95 | isa = PBXFrameworksBuildPhase; 96 | buildActionMask = 2147483647; 97 | files = ( 98 | 049AFD0E2179E03500AC25DC /* Cocoa.framework in Frameworks */, 99 | ); 100 | runOnlyForDeploymentPostprocessing = 0; 101 | }; 102 | /* End PBXFrameworksBuildPhase section */ 103 | 104 | /* Begin PBXGroup section */ 105 | 049AFCDD2179E00300AC25DC = { 106 | isa = PBXGroup; 107 | children = ( 108 | 049AFCE82179E00300AC25DC /* IsItPrivate */, 109 | 049AFD0F2179E03500AC25DC /* Browsing */, 110 | 049AFD0C2179E03500AC25DC /* Frameworks */, 111 | 049AFCE72179E00300AC25DC /* Products */, 112 | ); 113 | sourceTree = ""; 114 | }; 115 | 049AFCE72179E00300AC25DC /* Products */ = { 116 | isa = PBXGroup; 117 | children = ( 118 | 049AFCE62179E00300AC25DC /* IsItPrivate.app */, 119 | 049AFD0B2179E03500AC25DC /* Browsing.appex */, 120 | ); 121 | name = Products; 122 | sourceTree = ""; 123 | }; 124 | 049AFCE82179E00300AC25DC /* IsItPrivate */ = { 125 | isa = PBXGroup; 126 | children = ( 127 | 049AFCE92179E00300AC25DC /* AppDelegate.swift */, 128 | 04A9DD6D21833A2F00655766 /* DefaultWindow */, 129 | 04A9DD6C21833A1C00655766 /* AboutWindow */, 130 | 04A9DD6B21833A1100655766 /* Extensions */, 131 | 04A9DD6E21833A4900655766 /* Resources */, 132 | ); 133 | path = IsItPrivate; 134 | sourceTree = ""; 135 | }; 136 | 049AFD0C2179E03500AC25DC /* Frameworks */ = { 137 | isa = PBXGroup; 138 | children = ( 139 | 049AFD0D2179E03500AC25DC /* Cocoa.framework */, 140 | ); 141 | name = Frameworks; 142 | sourceTree = ""; 143 | }; 144 | 049AFD0F2179E03500AC25DC /* Browsing */ = { 145 | isa = PBXGroup; 146 | children = ( 147 | 049AFD102179E03500AC25DC /* SafariExtensionHandler.swift */, 148 | 049AFD122179E03500AC25DC /* SafariExtensionViewController.swift */, 149 | 049AFD142179E03500AC25DC /* SafariExtensionViewController.xib */, 150 | 041DE6B3217DD3A2006AF8AD /* IconFactory.swift */, 151 | 041DE6B5217DD7C0006AF8AD /* BrowsingIcon.swift */, 152 | 041DE6B9217DE480006AF8AD /* Unavailable.pdf */, 153 | 041DE6AF217DC0F0006AF8AD /* Compass.pdf */, 154 | 041DE6AB217DC0C5006AF8AD /* Mask.pdf */, 155 | 049AFD172179E03500AC25DC /* Info.plist */, 156 | 049AFD1C2179E03500AC25DC /* Browsing.entitlements */, 157 | ); 158 | path = Browsing; 159 | sourceTree = ""; 160 | }; 161 | 04A9DD6B21833A1100655766 /* Extensions */ = { 162 | isa = PBXGroup; 163 | children = ( 164 | 04A9DD63218301C700655766 /* NSViewController+Extension.swift */, 165 | ); 166 | path = Extensions; 167 | sourceTree = ""; 168 | }; 169 | 04A9DD6C21833A1C00655766 /* AboutWindow */ = { 170 | isa = PBXGroup; 171 | children = ( 172 | 04A9DD652183284D00655766 /* AboutWindowController.swift */, 173 | 04A9DD662183284D00655766 /* AboutWindowController.xib */, 174 | 04A9DD6921832EC200655766 /* ActionLabel.swift */, 175 | ); 176 | path = AboutWindow; 177 | sourceTree = ""; 178 | }; 179 | 04A9DD6D21833A2F00655766 /* DefaultWindow */ = { 180 | isa = PBXGroup; 181 | children = ( 182 | 049AFCEF2179E00400AC25DC /* Main.storyboard */, 183 | 049AFCEB2179E00300AC25DC /* ViewController.swift */, 184 | 04A9DD612182FBB900655766 /* ExtensionStateManager.swift */, 185 | 04A9DD5B2181F97600655766 /* PreferencesViewController.swift */, 186 | 04A9DD5D2181F98700655766 /* TutorialViewController.swift */, 187 | ); 188 | path = DefaultWindow; 189 | sourceTree = ""; 190 | }; 191 | 04A9DD6E21833A4900655766 /* Resources */ = { 192 | isa = PBXGroup; 193 | children = ( 194 | 049AFCED2179E00400AC25DC /* Assets.xcassets */, 195 | 049AFCF22179E00400AC25DC /* Info.plist */, 196 | 049AFCF32179E00400AC25DC /* IsItPrivate.entitlements */, 197 | ); 198 | path = Resources; 199 | sourceTree = ""; 200 | }; 201 | /* End PBXGroup section */ 202 | 203 | /* Begin PBXNativeTarget section */ 204 | 049AFCE52179E00300AC25DC /* IsItPrivate */ = { 205 | isa = PBXNativeTarget; 206 | buildConfigurationList = 049AFD012179E00400AC25DC /* Build configuration list for PBXNativeTarget "IsItPrivate" */; 207 | buildPhases = ( 208 | 049AFCE22179E00300AC25DC /* Sources */, 209 | 049AFCE32179E00300AC25DC /* Frameworks */, 210 | 049AFCE42179E00300AC25DC /* Resources */, 211 | 049AFD232179E03500AC25DC /* Embed App Extensions */, 212 | ); 213 | buildRules = ( 214 | ); 215 | dependencies = ( 216 | 049AFD1E2179E03500AC25DC /* PBXTargetDependency */, 217 | ); 218 | name = IsItPrivate; 219 | productName = IsItPrivate; 220 | productReference = 049AFCE62179E00300AC25DC /* IsItPrivate.app */; 221 | productType = "com.apple.product-type.application"; 222 | }; 223 | 049AFD0A2179E03500AC25DC /* Browsing */ = { 224 | isa = PBXNativeTarget; 225 | buildConfigurationList = 049AFD202179E03500AC25DC /* Build configuration list for PBXNativeTarget "Browsing" */; 226 | buildPhases = ( 227 | 049AFD072179E03500AC25DC /* Sources */, 228 | 049AFD082179E03500AC25DC /* Frameworks */, 229 | 049AFD092179E03500AC25DC /* Resources */, 230 | ); 231 | buildRules = ( 232 | ); 233 | dependencies = ( 234 | ); 235 | name = Browsing; 236 | productName = Browsing; 237 | productReference = 049AFD0B2179E03500AC25DC /* Browsing.appex */; 238 | productType = "com.apple.product-type.app-extension"; 239 | }; 240 | /* End PBXNativeTarget section */ 241 | 242 | /* Begin PBXProject section */ 243 | 049AFCDE2179E00300AC25DC /* Project object */ = { 244 | isa = PBXProject; 245 | attributes = { 246 | LastSwiftUpdateCheck = 1000; 247 | LastUpgradeCheck = 1000; 248 | ORGANIZATIONNAME = "Florian Fittschen"; 249 | TargetAttributes = { 250 | 049AFCE52179E00300AC25DC = { 251 | CreatedOnToolsVersion = 10.0; 252 | }; 253 | 049AFD0A2179E03500AC25DC = { 254 | CreatedOnToolsVersion = 10.0; 255 | }; 256 | }; 257 | }; 258 | buildConfigurationList = 049AFCE12179E00300AC25DC /* Build configuration list for PBXProject "IsItPrivate" */; 259 | compatibilityVersion = "Xcode 9.3"; 260 | developmentRegion = en; 261 | hasScannedForEncodings = 0; 262 | knownRegions = ( 263 | en, 264 | Base, 265 | ); 266 | mainGroup = 049AFCDD2179E00300AC25DC; 267 | productRefGroup = 049AFCE72179E00300AC25DC /* Products */; 268 | projectDirPath = ""; 269 | projectRoot = ""; 270 | targets = ( 271 | 049AFCE52179E00300AC25DC /* IsItPrivate */, 272 | 049AFD0A2179E03500AC25DC /* Browsing */, 273 | ); 274 | }; 275 | /* End PBXProject section */ 276 | 277 | /* Begin PBXResourcesBuildPhase section */ 278 | 049AFCE42179E00300AC25DC /* Resources */ = { 279 | isa = PBXResourcesBuildPhase; 280 | buildActionMask = 2147483647; 281 | files = ( 282 | 04A9DD682183284D00655766 /* AboutWindowController.xib in Resources */, 283 | 049AFCEE2179E00400AC25DC /* Assets.xcassets in Resources */, 284 | 049AFCF12179E00400AC25DC /* Main.storyboard in Resources */, 285 | ); 286 | runOnlyForDeploymentPostprocessing = 0; 287 | }; 288 | 049AFD092179E03500AC25DC /* Resources */ = { 289 | isa = PBXResourcesBuildPhase; 290 | buildActionMask = 2147483647; 291 | files = ( 292 | 041DE6B0217DC0F0006AF8AD /* Compass.pdf in Resources */, 293 | 041DE6AC217DC0C5006AF8AD /* Mask.pdf in Resources */, 294 | 049AFD162179E03500AC25DC /* SafariExtensionViewController.xib in Resources */, 295 | 041DE6BA217DE480006AF8AD /* Unavailable.pdf in Resources */, 296 | ); 297 | runOnlyForDeploymentPostprocessing = 0; 298 | }; 299 | /* End PBXResourcesBuildPhase section */ 300 | 301 | /* Begin PBXSourcesBuildPhase section */ 302 | 049AFCE22179E00300AC25DC /* Sources */ = { 303 | isa = PBXSourcesBuildPhase; 304 | buildActionMask = 2147483647; 305 | files = ( 306 | 049AFCEC2179E00300AC25DC /* ViewController.swift in Sources */, 307 | 049AFCEA2179E00300AC25DC /* AppDelegate.swift in Sources */, 308 | 04A9DD6A21832EC200655766 /* ActionLabel.swift in Sources */, 309 | 04A9DD622182FBB900655766 /* ExtensionStateManager.swift in Sources */, 310 | 04A9DD5F2181F98700655766 /* TutorialViewController.swift in Sources */, 311 | 04A9DD64218301C700655766 /* NSViewController+Extension.swift in Sources */, 312 | 04A9DD5C2181F97600655766 /* PreferencesViewController.swift in Sources */, 313 | 04A9DD672183284D00655766 /* AboutWindowController.swift in Sources */, 314 | ); 315 | runOnlyForDeploymentPostprocessing = 0; 316 | }; 317 | 049AFD072179E03500AC25DC /* Sources */ = { 318 | isa = PBXSourcesBuildPhase; 319 | buildActionMask = 2147483647; 320 | files = ( 321 | 041DE6B4217DD3A2006AF8AD /* IconFactory.swift in Sources */, 322 | 041DE6B6217DD7C0006AF8AD /* BrowsingIcon.swift in Sources */, 323 | 049AFD132179E03500AC25DC /* SafariExtensionViewController.swift in Sources */, 324 | 049AFD112179E03500AC25DC /* SafariExtensionHandler.swift in Sources */, 325 | ); 326 | runOnlyForDeploymentPostprocessing = 0; 327 | }; 328 | /* End PBXSourcesBuildPhase section */ 329 | 330 | /* Begin PBXTargetDependency section */ 331 | 049AFD1E2179E03500AC25DC /* PBXTargetDependency */ = { 332 | isa = PBXTargetDependency; 333 | target = 049AFD0A2179E03500AC25DC /* Browsing */; 334 | targetProxy = 049AFD1D2179E03500AC25DC /* PBXContainerItemProxy */; 335 | }; 336 | /* End PBXTargetDependency section */ 337 | 338 | /* Begin PBXVariantGroup section */ 339 | 049AFCEF2179E00400AC25DC /* Main.storyboard */ = { 340 | isa = PBXVariantGroup; 341 | children = ( 342 | 049AFCF02179E00400AC25DC /* Base */, 343 | ); 344 | name = Main.storyboard; 345 | sourceTree = ""; 346 | }; 347 | 049AFD142179E03500AC25DC /* SafariExtensionViewController.xib */ = { 348 | isa = PBXVariantGroup; 349 | children = ( 350 | 049AFD152179E03500AC25DC /* Base */, 351 | ); 352 | name = SafariExtensionViewController.xib; 353 | sourceTree = ""; 354 | }; 355 | /* End PBXVariantGroup section */ 356 | 357 | /* Begin XCBuildConfiguration section */ 358 | 049AFCFF2179E00400AC25DC /* Debug */ = { 359 | isa = XCBuildConfiguration; 360 | buildSettings = { 361 | ALWAYS_SEARCH_USER_PATHS = NO; 362 | CLANG_ANALYZER_NONNULL = YES; 363 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 364 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 365 | CLANG_CXX_LIBRARY = "libc++"; 366 | CLANG_ENABLE_MODULES = YES; 367 | CLANG_ENABLE_OBJC_ARC = YES; 368 | CLANG_ENABLE_OBJC_WEAK = YES; 369 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 370 | CLANG_WARN_BOOL_CONVERSION = YES; 371 | CLANG_WARN_COMMA = YES; 372 | CLANG_WARN_CONSTANT_CONVERSION = YES; 373 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 374 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 375 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 376 | CLANG_WARN_EMPTY_BODY = YES; 377 | CLANG_WARN_ENUM_CONVERSION = YES; 378 | CLANG_WARN_INFINITE_RECURSION = YES; 379 | CLANG_WARN_INT_CONVERSION = YES; 380 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 381 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 382 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 383 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 384 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 385 | CLANG_WARN_STRICT_PROTOTYPES = YES; 386 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 387 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 388 | CLANG_WARN_UNREACHABLE_CODE = YES; 389 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 390 | CODE_SIGN_ENTITLEMENTS = ""; 391 | CODE_SIGN_IDENTITY = "Mac Developer"; 392 | COPY_PHASE_STRIP = NO; 393 | DEBUG_INFORMATION_FORMAT = dwarf; 394 | ENABLE_STRICT_OBJC_MSGSEND = YES; 395 | ENABLE_TESTABILITY = YES; 396 | GCC_C_LANGUAGE_STANDARD = gnu11; 397 | GCC_DYNAMIC_NO_PIC = NO; 398 | GCC_NO_COMMON_BLOCKS = YES; 399 | GCC_OPTIMIZATION_LEVEL = 0; 400 | GCC_PREPROCESSOR_DEFINITIONS = ( 401 | "DEBUG=1", 402 | "$(inherited)", 403 | ); 404 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 405 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 406 | GCC_WARN_UNDECLARED_SELECTOR = YES; 407 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 408 | GCC_WARN_UNUSED_FUNCTION = YES; 409 | GCC_WARN_UNUSED_VARIABLE = YES; 410 | MACOSX_DEPLOYMENT_TARGET = 10.14; 411 | MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; 412 | MTL_FAST_MATH = YES; 413 | ONLY_ACTIVE_ARCH = YES; 414 | SDKROOT = macosx; 415 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; 416 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 417 | }; 418 | name = Debug; 419 | }; 420 | 049AFD002179E00400AC25DC /* Release */ = { 421 | isa = XCBuildConfiguration; 422 | buildSettings = { 423 | ALWAYS_SEARCH_USER_PATHS = NO; 424 | CLANG_ANALYZER_NONNULL = YES; 425 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 426 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 427 | CLANG_CXX_LIBRARY = "libc++"; 428 | CLANG_ENABLE_MODULES = YES; 429 | CLANG_ENABLE_OBJC_ARC = YES; 430 | CLANG_ENABLE_OBJC_WEAK = YES; 431 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 432 | CLANG_WARN_BOOL_CONVERSION = YES; 433 | CLANG_WARN_COMMA = YES; 434 | CLANG_WARN_CONSTANT_CONVERSION = YES; 435 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 436 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 437 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 438 | CLANG_WARN_EMPTY_BODY = YES; 439 | CLANG_WARN_ENUM_CONVERSION = YES; 440 | CLANG_WARN_INFINITE_RECURSION = YES; 441 | CLANG_WARN_INT_CONVERSION = YES; 442 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 443 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 444 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 445 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 446 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 447 | CLANG_WARN_STRICT_PROTOTYPES = YES; 448 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 449 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 450 | CLANG_WARN_UNREACHABLE_CODE = YES; 451 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 452 | CODE_SIGN_ENTITLEMENTS = ""; 453 | CODE_SIGN_IDENTITY = "Mac Developer"; 454 | COPY_PHASE_STRIP = NO; 455 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 456 | ENABLE_NS_ASSERTIONS = NO; 457 | ENABLE_STRICT_OBJC_MSGSEND = YES; 458 | GCC_C_LANGUAGE_STANDARD = gnu11; 459 | GCC_NO_COMMON_BLOCKS = YES; 460 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 461 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 462 | GCC_WARN_UNDECLARED_SELECTOR = YES; 463 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 464 | GCC_WARN_UNUSED_FUNCTION = YES; 465 | GCC_WARN_UNUSED_VARIABLE = YES; 466 | MACOSX_DEPLOYMENT_TARGET = 10.14; 467 | MTL_ENABLE_DEBUG_INFO = NO; 468 | MTL_FAST_MATH = YES; 469 | SDKROOT = macosx; 470 | SWIFT_COMPILATION_MODE = wholemodule; 471 | SWIFT_OPTIMIZATION_LEVEL = "-O"; 472 | }; 473 | name = Release; 474 | }; 475 | 049AFD022179E00400AC25DC /* Debug */ = { 476 | isa = XCBuildConfiguration; 477 | buildSettings = { 478 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; 479 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 480 | CODE_SIGN_ENTITLEMENTS = "$(SRCROOT)/IsItPrivate/Resources/IsItPrivate.entitlements"; 481 | CODE_SIGN_STYLE = Automatic; 482 | COMBINE_HIDPI_IMAGES = YES; 483 | DEVELOPMENT_TEAM = F9Y6K72HCR; 484 | INFOPLIST_FILE = "$(SRCROOT)/IsItPrivate/Resources/Info.plist"; 485 | LD_RUNPATH_SEARCH_PATHS = ( 486 | "$(inherited)", 487 | "@executable_path/../Frameworks", 488 | ); 489 | PRODUCT_BUNDLE_IDENTIFIER = com.fittschen.IsItPrivate; 490 | PRODUCT_NAME = "$(TARGET_NAME)"; 491 | SWIFT_VERSION = 4.2; 492 | }; 493 | name = Debug; 494 | }; 495 | 049AFD032179E00400AC25DC /* Release */ = { 496 | isa = XCBuildConfiguration; 497 | buildSettings = { 498 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; 499 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 500 | CODE_SIGN_ENTITLEMENTS = "$(SRCROOT)/IsItPrivate/Resources/IsItPrivate.entitlements"; 501 | CODE_SIGN_STYLE = Automatic; 502 | COMBINE_HIDPI_IMAGES = YES; 503 | DEVELOPMENT_TEAM = F9Y6K72HCR; 504 | INFOPLIST_FILE = "$(SRCROOT)/IsItPrivate/Resources/Info.plist"; 505 | LD_RUNPATH_SEARCH_PATHS = ( 506 | "$(inherited)", 507 | "@executable_path/../Frameworks", 508 | ); 509 | PRODUCT_BUNDLE_IDENTIFIER = com.fittschen.IsItPrivate; 510 | PRODUCT_NAME = "$(TARGET_NAME)"; 511 | SWIFT_VERSION = 4.2; 512 | }; 513 | name = Release; 514 | }; 515 | 049AFD212179E03500AC25DC /* Debug */ = { 516 | isa = XCBuildConfiguration; 517 | buildSettings = { 518 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 519 | CODE_SIGN_ENTITLEMENTS = Browsing/Browsing.entitlements; 520 | CODE_SIGN_STYLE = Automatic; 521 | DEVELOPMENT_TEAM = F9Y6K72HCR; 522 | INFOPLIST_FILE = Browsing/Info.plist; 523 | LD_RUNPATH_SEARCH_PATHS = ( 524 | "$(inherited)", 525 | "@executable_path/../Frameworks", 526 | "@executable_path/../../../../Frameworks", 527 | ); 528 | PRODUCT_BUNDLE_IDENTIFIER = com.fittschen.IsItPrivate.Browsing; 529 | PRODUCT_NAME = "$(TARGET_NAME)"; 530 | SKIP_INSTALL = YES; 531 | SWIFT_VERSION = 4.2; 532 | }; 533 | name = Debug; 534 | }; 535 | 049AFD222179E03500AC25DC /* Release */ = { 536 | isa = XCBuildConfiguration; 537 | buildSettings = { 538 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 539 | CODE_SIGN_ENTITLEMENTS = Browsing/Browsing.entitlements; 540 | CODE_SIGN_STYLE = Automatic; 541 | DEVELOPMENT_TEAM = F9Y6K72HCR; 542 | INFOPLIST_FILE = Browsing/Info.plist; 543 | LD_RUNPATH_SEARCH_PATHS = ( 544 | "$(inherited)", 545 | "@executable_path/../Frameworks", 546 | "@executable_path/../../../../Frameworks", 547 | ); 548 | PRODUCT_BUNDLE_IDENTIFIER = com.fittschen.IsItPrivate.Browsing; 549 | PRODUCT_NAME = "$(TARGET_NAME)"; 550 | SKIP_INSTALL = YES; 551 | SWIFT_VERSION = 4.2; 552 | }; 553 | name = Release; 554 | }; 555 | /* End XCBuildConfiguration section */ 556 | 557 | /* Begin XCConfigurationList section */ 558 | 049AFCE12179E00300AC25DC /* Build configuration list for PBXProject "IsItPrivate" */ = { 559 | isa = XCConfigurationList; 560 | buildConfigurations = ( 561 | 049AFCFF2179E00400AC25DC /* Debug */, 562 | 049AFD002179E00400AC25DC /* Release */, 563 | ); 564 | defaultConfigurationIsVisible = 0; 565 | defaultConfigurationName = Release; 566 | }; 567 | 049AFD012179E00400AC25DC /* Build configuration list for PBXNativeTarget "IsItPrivate" */ = { 568 | isa = XCConfigurationList; 569 | buildConfigurations = ( 570 | 049AFD022179E00400AC25DC /* Debug */, 571 | 049AFD032179E00400AC25DC /* Release */, 572 | ); 573 | defaultConfigurationIsVisible = 0; 574 | defaultConfigurationName = Release; 575 | }; 576 | 049AFD202179E03500AC25DC /* Build configuration list for PBXNativeTarget "Browsing" */ = { 577 | isa = XCConfigurationList; 578 | buildConfigurations = ( 579 | 049AFD212179E03500AC25DC /* Debug */, 580 | 049AFD222179E03500AC25DC /* Release */, 581 | ); 582 | defaultConfigurationIsVisible = 0; 583 | defaultConfigurationName = Release; 584 | }; 585 | /* End XCConfigurationList section */ 586 | }; 587 | rootObject = 049AFCDE2179E00300AC25DC /* Project object */; 588 | } 589 | -------------------------------------------------------------------------------- /IsItPrivate.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /IsItPrivate.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /IsItPrivate/AboutWindow/AboutWindowController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AboutWindowController.swift 3 | // IsItPrivate 4 | // 5 | // Created by Florian Fittschen on 26.10.18. 6 | // Copyright © 2018 Florian Fittschen. All rights reserved. 7 | // 8 | 9 | import Cocoa 10 | 11 | class AboutWindowController: NSWindowController { 12 | 13 | @IBOutlet weak var applicationNameLabel: NSTextField! 14 | @IBOutlet weak var versionLabel: NSTextField! 15 | @IBOutlet weak var buildLabel: NSTextField! 16 | @IBOutlet weak var creatorLabel: ActionLabel! 17 | @IBOutlet weak var repositoryLabel: ActionLabel! 18 | @IBOutlet weak var maskCreatorLabel: ActionLabel! 19 | @IBOutlet weak var compassCreatorLabel: ActionLabel! 20 | @IBOutlet weak var licenseLabel: NSTextField! 21 | 22 | convenience init() { 23 | self.init(windowNibName: "AboutWindowController") 24 | } 25 | 26 | override func windowDidLoad() { 27 | super.windowDidLoad() 28 | 29 | // close the window when the escape key is pressed 30 | NSEvent.addLocalMonitorForEvents(matching: .keyDown) { event in 31 | guard event.keyCode == 53 else { return event } 32 | 33 | self.closeAnimated() 34 | 35 | return nil 36 | } 37 | 38 | window?.collectionBehavior = [.transient, .ignoresCycle] 39 | window?.isMovableByWindowBackground = true 40 | 41 | guard let info = Bundle.main.infoDictionary else { return } 42 | 43 | configureUIFor(infoDictionary: info) 44 | } 45 | 46 | private func configureUIFor(infoDictionary info: [String: Any]) { 47 | applicationNameLabel.stringValue = info.stringOrEmpty(for: "CFBundleName") 48 | versionLabel.stringValue = info.stringOrEmpty(for: "CFBundleShortVersionString") 49 | buildLabel.stringValue = info.stringOrEmpty(for: "CFBundleVersionString") 50 | licenseLabel.stringValue = info.stringOrEmpty(for: "FFBundleLicenseName") 51 | creatorLabel.stringValue = info.stringOrEmpty(for: "FFBundleMainDeveloperName") 52 | repositoryLabel.stringValue = info.stringOrEmpty(for: "FFBundleRepositoryName") 53 | 54 | mainDeveloperWebsite = URL(string: info.stringOrEmpty(for: "FFBundleMainDeveloperWebsite")) 55 | repositoryWebsite = URL(string: info.stringOrEmpty(for: "FFBundleRepositoryWebsite")) 56 | maskCreatorWebsite = URL(string: info.stringOrEmpty(for: "FFBundleMaskIconCreatorWebsite")) 57 | compassCreatorWebsite = URL(string: info.stringOrEmpty(for: "FFBundleCompassIconCreatorWebsite")) 58 | 59 | configureActionLabel(creatorLabel, selector: #selector(openMainDeveloperWebsite)) 60 | configureActionLabel(repositoryLabel, selector: #selector(openRepositoryWebsite)) 61 | configureActionLabel(maskCreatorLabel, selector: #selector(openMaskIconCreatorWebsite)) 62 | configureActionLabel(compassCreatorLabel, selector: #selector(openCompassIconCreatorWebsite)) 63 | 64 | } 65 | 66 | private func configureActionLabel(_ label: ActionLabel, selector: Selector) { 67 | label.alphaValue = 0.8 68 | label.textColor = NSColor(red:0.023, green:0.752, blue:0.905, alpha:1) 69 | label.target = self 70 | label.action = selector 71 | } 72 | 73 | private var mainDeveloperWebsite: URL? 74 | private var repositoryWebsite: URL? 75 | private var maskCreatorWebsite: URL? 76 | private var compassCreatorWebsite: URL? 77 | 78 | @IBAction private func openMainDeveloperWebsite(_ sender: Any) { 79 | guard let mainDeveloperWebsite = mainDeveloperWebsite else { return } 80 | 81 | NSWorkspace.shared.open(mainDeveloperWebsite) 82 | } 83 | 84 | @IBAction private func openRepositoryWebsite(_ sender: Any) { 85 | guard let repositoryWebsite = repositoryWebsite else { return } 86 | 87 | NSWorkspace.shared.open(repositoryWebsite) 88 | } 89 | 90 | @IBAction private func openMaskIconCreatorWebsite(_ sender: Any) { 91 | guard let maskCreatorWebsite = maskCreatorWebsite else { return } 92 | 93 | NSWorkspace.shared.open(maskCreatorWebsite) 94 | } 95 | 96 | @IBAction private func openCompassIconCreatorWebsite(_ sender: Any) { 97 | guard let compassCreatorWebsite = compassCreatorWebsite else { return } 98 | 99 | NSWorkspace.shared.open(compassCreatorWebsite) 100 | } 101 | 102 | override func showWindow(_ sender: Any?) { 103 | window?.center() 104 | window?.alphaValue = 0.0 105 | 106 | super.showWindow(sender) 107 | 108 | window?.animator().alphaValue = 1.0 109 | } 110 | 111 | private func closeAnimated() { 112 | NSAnimationContext.beginGrouping() 113 | NSAnimationContext.current.duration = 0.4 114 | NSAnimationContext.current.completionHandler = { 115 | self.close() 116 | } 117 | window?.animator().alphaValue = 0.0 118 | NSAnimationContext.endGrouping() 119 | } 120 | 121 | } 122 | 123 | fileprivate extension Dictionary where Key == String, Value == Any { 124 | fileprivate func stringOrEmpty(for key: String) -> String { 125 | return (self[key] as? String) ?? "" 126 | } 127 | } 128 | -------------------------------------------------------------------------------- /IsItPrivate/AboutWindow/AboutWindowController.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 | 260 | 261 | 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 | 270 | 271 | 272 | 273 | 274 | 275 | 276 | 277 | 278 | 279 | 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 | 289 | 290 | -------------------------------------------------------------------------------- /IsItPrivate/AboutWindow/ActionLabel.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ActionLabel.swift 3 | // IsItPrivate 4 | // 5 | // Created by Florian Fittschen on 26.10.18. 6 | // Copyright © 2018 Florian Fittschen. All rights reserved. 7 | // 8 | 9 | import Cocoa 10 | 11 | final class ActionLabel: NSTextField { 12 | 13 | private var cursorTrackingArea: NSTrackingArea! 14 | 15 | override func updateTrackingAreas() { 16 | super.updateTrackingAreas() 17 | 18 | if cursorTrackingArea != nil { 19 | removeTrackingArea(cursorTrackingArea) 20 | } 21 | 22 | cursorTrackingArea = NSTrackingArea(rect: bounds, 23 | options: [.cursorUpdate, .inVisibleRect, .activeInActiveApp], 24 | owner: self, 25 | userInfo: nil) 26 | addTrackingArea(cursorTrackingArea) 27 | } 28 | 29 | override func cursorUpdate(with event: NSEvent) { 30 | if event.trackingArea == cursorTrackingArea { 31 | NSCursor.pointingHand.push() 32 | } else { 33 | super.cursorUpdate(with: event) 34 | } 35 | } 36 | 37 | override func mouseDown(with event: NSEvent) { 38 | if let action = action { 39 | NSApp.sendAction(action, to: target, from: self) 40 | } 41 | } 42 | 43 | } 44 | -------------------------------------------------------------------------------- /IsItPrivate/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.swift 3 | // IsItPrivate 4 | // 5 | // Created by Florian Fittschen on 19.10.18. 6 | // Copyright © 2018 Florian Fittschen. All rights reserved. 7 | // 8 | 9 | import Cocoa 10 | 11 | @NSApplicationMain 12 | class AppDelegate: NSObject, NSApplicationDelegate { 13 | 14 | private lazy var aboutWindowController: AboutWindowController = { 15 | return AboutWindowController() 16 | }() 17 | 18 | func applicationShouldTerminateAfterLastWindowClosed(_ sender: NSApplication) -> Bool { 19 | return true 20 | } 21 | 22 | func applicationWillBecomeActive(_ notification: Notification) { 23 | ExtensionStateManager.shared.fetchExtensionState() 24 | 25 | } 26 | 27 | @IBAction func showAboutWindow(_ sender: NSMenuItem) { 28 | aboutWindowController.showWindow(nil) 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /IsItPrivate/DefaultWindow/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 | 260 | 261 | 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 | 270 | 271 | 272 | 273 | 274 | 275 | 276 | 277 | 278 | -------------------------------------------------------------------------------- /IsItPrivate/DefaultWindow/ExtensionStateManager.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ExtensionStateManager.swift 3 | // IsItPrivate 4 | // 5 | // Created by Florian Fittschen on 26.10.18. 6 | // Copyright © 2018 Florian Fittschen. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import SafariServices 11 | 12 | protocol ExtensionStateManagerDelegate: class { 13 | func extensionStateChanged(from oldExtensionState: SFSafariExtensionState?, to newExtensionState: SFSafariExtensionState) 14 | } 15 | 16 | final class ExtensionStateManager { 17 | 18 | static let shared = ExtensionStateManager() 19 | 20 | weak var delegate: ExtensionStateManagerDelegate? 21 | 22 | let extensionIdentifier = "com.fittschen.IsItPrivate.Browsing" 23 | 24 | private var extensionState: SFSafariExtensionState? { 25 | didSet { 26 | guard let newValue = extensionState else { return } 27 | delegate?.extensionStateChanged(from: oldValue, to: newValue) 28 | } 29 | } 30 | 31 | private init() { 32 | fetchExtensionState() 33 | } 34 | 35 | func fetchExtensionState() { 36 | SFSafariExtensionManager.getStateOfSafariExtension(withIdentifier: extensionIdentifier) { [weak self] (state, error) in 37 | if let error = error { 38 | NSLog("Error fetching Safari Extension State: \(error.localizedDescription)") 39 | } else if let state = state { 40 | DispatchQueue.main.async { 41 | self?.extensionState = state 42 | } 43 | } 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /IsItPrivate/DefaultWindow/PreferencesViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // PreferencesViewController.swift 3 | // IsItPrivate 4 | // 5 | // Created by Florian Fittschen on 25.10.18. 6 | // Copyright © 2018 Florian Fittschen. All rights reserved. 7 | // 8 | 9 | import Cocoa 10 | 11 | class PreferencesViewController: NSViewController { 12 | 13 | override func viewDidLoad() { 14 | super.viewDidLoad() 15 | // Do view setup here. 16 | } 17 | 18 | override func viewWillAppear() { 19 | super.viewWillAppear() 20 | preferredContentSize = view.fittingSize 21 | } 22 | 23 | } 24 | -------------------------------------------------------------------------------- /IsItPrivate/DefaultWindow/TutorialViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // TutorialViewController.swift 3 | // IsItPrivate 4 | // 5 | // Created by Florian Fittschen on 25.10.18. 6 | // Copyright © 2018 Florian Fittschen. All rights reserved. 7 | // 8 | 9 | import Cocoa 10 | 11 | class TutorialViewController: NSViewController { 12 | 13 | @IBOutlet weak var imageView: NSImageView! 14 | 15 | override func viewDidLoad() { 16 | super.viewDidLoad() 17 | // Do view setup here. 18 | } 19 | 20 | override func viewWillAppear() { 21 | super.viewWillAppear() 22 | preferredContentSize = view.fittingSize 23 | } 24 | 25 | @IBAction func changeBrowsingMode(_ sender: NSSegmentedControl) { 26 | if sender.selectedSegment == 0 { 27 | imageView.image = #imageLiteral(resourceName: "Tutorial_Normal") 28 | } else if sender.selectedSegment == 1 { 29 | imageView.image = #imageLiteral(resourceName: "Tutorial_Private") 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /IsItPrivate/DefaultWindow/ViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.swift 3 | // IsItPrivate 4 | // 5 | // Created by Florian Fittschen on 19.10.18. 6 | // Copyright © 2018 Florian Fittschen. All rights reserved. 7 | // 8 | 9 | import Cocoa 10 | import SafariServices 11 | 12 | enum ContainerContent: String { 13 | case preferences 14 | case tutorial 15 | } 16 | 17 | extension ContainerContent { 18 | init(extensionState: SFSafariExtensionState) { 19 | if extensionState.isEnabled { 20 | self = .tutorial 21 | } else { 22 | self = .preferences 23 | } 24 | } 25 | } 26 | 27 | class ViewController: NSViewController { 28 | 29 | @IBOutlet weak var extensionStateLabel: NSTextField! 30 | @IBOutlet weak var openSafariPreferencesButton: NSButton! 31 | @IBOutlet weak var containerView: NSView! 32 | @IBOutlet weak var containerWidthConstraint: NSLayoutConstraint! 33 | @IBOutlet weak var containerHeightConstraint: NSLayoutConstraint! 34 | 35 | private var content: ContainerContent? 36 | private var shownViewController: NSViewController? 37 | 38 | override func viewDidLoad() { 39 | super.viewDidLoad() 40 | 41 | ExtensionStateManager.shared.delegate = self 42 | ExtensionStateManager.shared.fetchExtensionState() 43 | } 44 | 45 | @IBAction func openSafariPreferences(_ sender: NSButton) { 46 | SFSafariApplication.showPreferencesForExtension(withIdentifier: ExtensionStateManager.shared.extensionIdentifier) { error in 47 | if let error = error { 48 | NSLog("Error opening Safari Preferences: \(error.localizedDescription)") 49 | } 50 | } 51 | } 52 | 53 | private func transition(to content: ContainerContent) { 54 | shownViewController?.remove() 55 | let vc = createViewController(for: content) 56 | add(vc, view: containerView) 57 | 58 | shownViewController = vc 59 | self.content = content 60 | 61 | containerWidthConstraint.constant = vc.view.frame.width 62 | containerHeightConstraint.constant = vc.view.frame.height 63 | } 64 | 65 | private func createViewController(for content: ContainerContent) -> NSViewController { 66 | guard let storyboard = storyboard else { 67 | preconditionFailure("Can't transition to other ViewControllers without storyboard.") 68 | } 69 | 70 | switch content { 71 | case .preferences: 72 | return storyboard.instantiateController(withIdentifier: "PreferencesViewController") as! PreferencesViewController 73 | case .tutorial: 74 | return storyboard.instantiateController(withIdentifier: "TutorialViewController") as! TutorialViewController 75 | } 76 | } 77 | 78 | private func updateUI(for state: SFSafariExtensionState) { 79 | if state.isEnabled { 80 | extensionStateLabel.stringValue = "enabled ✅" 81 | openSafariPreferencesButton.title = "Open Safari Preferences" 82 | } else { 83 | extensionStateLabel.stringValue = "disabled ❌" 84 | openSafariPreferencesButton.title = "Enable Private Browsing Detector" 85 | } 86 | } 87 | } 88 | 89 | extension ViewController: ExtensionStateManagerDelegate { 90 | func extensionStateChanged(from oldExtensionState: SFSafariExtensionState?, to newExtensionState: SFSafariExtensionState) { 91 | let firstStateChange = oldExtensionState == nil 92 | let statesDiffer = oldExtensionState != nil && oldExtensionState!.isEnabled != newExtensionState.isEnabled 93 | 94 | guard firstStateChange || statesDiffer else { 95 | // We don't want to react to the same state 96 | return 97 | } 98 | 99 | updateUI(for: newExtensionState) 100 | transition(to: ContainerContent(extensionState: newExtensionState)) 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /IsItPrivate/Extensions/NSViewController+Extension.swift: -------------------------------------------------------------------------------- 1 | // 2 | // NSViewController+Extension.swift 3 | // IsItPrivate 4 | // 5 | // Created by Florian Fittschen on 26.10.18. 6 | // Copyright © 2018 Florian Fittschen. All rights reserved. 7 | // 8 | 9 | import Cocoa 10 | 11 | @nonobjc extension NSViewController { 12 | func add(_ child: NSViewController, frame: CGRect? = nil) { 13 | addChild(child) 14 | 15 | if let frame = frame { 16 | child.view.frame = frame 17 | } 18 | 19 | view.addSubview(child.view) 20 | } 21 | 22 | func add(_ child: NSViewController, view: NSView) { 23 | addChild(child) 24 | view.addSubview(child.view) 25 | } 26 | 27 | func remove() { 28 | view.removeFromSuperview() 29 | removeFromParent() 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /IsItPrivate/Resources/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images": [ 3 | { 4 | "idiom": "mac", 5 | "size": "16x16", 6 | "scale": "1x", 7 | "filename": "Icon-16x16-@1x.png" 8 | }, 9 | { 10 | "idiom": "mac", 11 | "size": "16x16", 12 | "scale": "2x", 13 | "filename": "Icon-16x16-@2x.png" 14 | }, 15 | { 16 | "idiom": "mac", 17 | "size": "32x32", 18 | "scale": "1x", 19 | "filename": "Icon-32x32-@1x.png" 20 | }, 21 | { 22 | "idiom": "mac", 23 | "size": "32x32", 24 | "scale": "2x", 25 | "filename": "Icon-32x32-@2x.png" 26 | }, 27 | { 28 | "idiom": "mac", 29 | "size": "128x128", 30 | "scale": "1x", 31 | "filename": "Icon-128x128-@1x.png" 32 | }, 33 | { 34 | "idiom": "mac", 35 | "size": "128x128", 36 | "scale": "2x", 37 | "filename": "Icon-128x128-@2x.png" 38 | }, 39 | { 40 | "idiom": "mac", 41 | "size": "256x256", 42 | "scale": "1x", 43 | "filename": "Icon-256x256-@1x.png" 44 | }, 45 | { 46 | "idiom": "mac", 47 | "size": "256x256", 48 | "scale": "2x", 49 | "filename": "Icon-256x256-@2x.png" 50 | }, 51 | { 52 | "idiom": "mac", 53 | "size": "512x512", 54 | "scale": "1x", 55 | "filename": "Icon-512x512-@1x.png" 56 | }, 57 | { 58 | "idiom": "mac", 59 | "size": "512x512", 60 | "scale": "2x", 61 | "filename": "Icon-512x512-@2x.png" 62 | } 63 | ], 64 | "info": { 65 | "version": 1, 66 | "author": "xcode" 67 | } 68 | } -------------------------------------------------------------------------------- /IsItPrivate/Resources/Assets.xcassets/AppIcon.appiconset/Icon-128x128-@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ffittschen/IsItPrivate/d61e9a5c765642dc5dd8b3aa8f1e73a4f0aea79f/IsItPrivate/Resources/Assets.xcassets/AppIcon.appiconset/Icon-128x128-@1x.png -------------------------------------------------------------------------------- /IsItPrivate/Resources/Assets.xcassets/AppIcon.appiconset/Icon-128x128-@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ffittschen/IsItPrivate/d61e9a5c765642dc5dd8b3aa8f1e73a4f0aea79f/IsItPrivate/Resources/Assets.xcassets/AppIcon.appiconset/Icon-128x128-@2x.png -------------------------------------------------------------------------------- /IsItPrivate/Resources/Assets.xcassets/AppIcon.appiconset/Icon-16x16-@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ffittschen/IsItPrivate/d61e9a5c765642dc5dd8b3aa8f1e73a4f0aea79f/IsItPrivate/Resources/Assets.xcassets/AppIcon.appiconset/Icon-16x16-@1x.png -------------------------------------------------------------------------------- /IsItPrivate/Resources/Assets.xcassets/AppIcon.appiconset/Icon-16x16-@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ffittschen/IsItPrivate/d61e9a5c765642dc5dd8b3aa8f1e73a4f0aea79f/IsItPrivate/Resources/Assets.xcassets/AppIcon.appiconset/Icon-16x16-@2x.png -------------------------------------------------------------------------------- /IsItPrivate/Resources/Assets.xcassets/AppIcon.appiconset/Icon-256x256-@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ffittschen/IsItPrivate/d61e9a5c765642dc5dd8b3aa8f1e73a4f0aea79f/IsItPrivate/Resources/Assets.xcassets/AppIcon.appiconset/Icon-256x256-@1x.png -------------------------------------------------------------------------------- /IsItPrivate/Resources/Assets.xcassets/AppIcon.appiconset/Icon-256x256-@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ffittschen/IsItPrivate/d61e9a5c765642dc5dd8b3aa8f1e73a4f0aea79f/IsItPrivate/Resources/Assets.xcassets/AppIcon.appiconset/Icon-256x256-@2x.png -------------------------------------------------------------------------------- /IsItPrivate/Resources/Assets.xcassets/AppIcon.appiconset/Icon-32x32-@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ffittschen/IsItPrivate/d61e9a5c765642dc5dd8b3aa8f1e73a4f0aea79f/IsItPrivate/Resources/Assets.xcassets/AppIcon.appiconset/Icon-32x32-@1x.png -------------------------------------------------------------------------------- /IsItPrivate/Resources/Assets.xcassets/AppIcon.appiconset/Icon-32x32-@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ffittschen/IsItPrivate/d61e9a5c765642dc5dd8b3aa8f1e73a4f0aea79f/IsItPrivate/Resources/Assets.xcassets/AppIcon.appiconset/Icon-32x32-@2x.png -------------------------------------------------------------------------------- /IsItPrivate/Resources/Assets.xcassets/AppIcon.appiconset/Icon-512x512-@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ffittschen/IsItPrivate/d61e9a5c765642dc5dd8b3aa8f1e73a4f0aea79f/IsItPrivate/Resources/Assets.xcassets/AppIcon.appiconset/Icon-512x512-@1x.png -------------------------------------------------------------------------------- /IsItPrivate/Resources/Assets.xcassets/AppIcon.appiconset/Icon-512x512-@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ffittschen/IsItPrivate/d61e9a5c765642dc5dd8b3aa8f1e73a4f0aea79f/IsItPrivate/Resources/Assets.xcassets/AppIcon.appiconset/Icon-512x512-@2x.png -------------------------------------------------------------------------------- /IsItPrivate/Resources/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } -------------------------------------------------------------------------------- /IsItPrivate/Resources/Assets.xcassets/Safari_Preferences.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "mac", 5 | "filename" : "Safari_Preferences_Light-1.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "mac", 10 | "filename" : "Safari_Preferences_Light.png", 11 | "appearances" : [ 12 | { 13 | "appearance" : "luminosity", 14 | "value" : "light" 15 | } 16 | ], 17 | "scale" : "1x" 18 | }, 19 | { 20 | "idiom" : "mac", 21 | "filename" : "Safari_Preferences_Dark.png", 22 | "appearances" : [ 23 | { 24 | "appearance" : "luminosity", 25 | "value" : "dark" 26 | } 27 | ], 28 | "scale" : "1x" 29 | }, 30 | { 31 | "idiom" : "mac", 32 | "scale" : "2x" 33 | }, 34 | { 35 | "idiom" : "mac", 36 | "scale" : "2x", 37 | "appearances" : [ 38 | { 39 | "appearance" : "luminosity", 40 | "value" : "light" 41 | } 42 | ] 43 | }, 44 | { 45 | "idiom" : "mac", 46 | "scale" : "2x", 47 | "appearances" : [ 48 | { 49 | "appearance" : "luminosity", 50 | "value" : "dark" 51 | } 52 | ] 53 | } 54 | ], 55 | "info" : { 56 | "version" : 1, 57 | "author" : "xcode" 58 | } 59 | } -------------------------------------------------------------------------------- /IsItPrivate/Resources/Assets.xcassets/Safari_Preferences.imageset/Safari_Preferences_Dark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ffittschen/IsItPrivate/d61e9a5c765642dc5dd8b3aa8f1e73a4f0aea79f/IsItPrivate/Resources/Assets.xcassets/Safari_Preferences.imageset/Safari_Preferences_Dark.png -------------------------------------------------------------------------------- /IsItPrivate/Resources/Assets.xcassets/Safari_Preferences.imageset/Safari_Preferences_Light-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ffittschen/IsItPrivate/d61e9a5c765642dc5dd8b3aa8f1e73a4f0aea79f/IsItPrivate/Resources/Assets.xcassets/Safari_Preferences.imageset/Safari_Preferences_Light-1.png -------------------------------------------------------------------------------- /IsItPrivate/Resources/Assets.xcassets/Safari_Preferences.imageset/Safari_Preferences_Light.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ffittschen/IsItPrivate/d61e9a5c765642dc5dd8b3aa8f1e73a4f0aea79f/IsItPrivate/Resources/Assets.xcassets/Safari_Preferences.imageset/Safari_Preferences_Light.png -------------------------------------------------------------------------------- /IsItPrivate/Resources/Assets.xcassets/Tutorial_Normal.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "mac", 5 | "filename" : "Tutorial_Normal_Light.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "mac", 10 | "filename" : "Tutorial_Normal_Light-1.png", 11 | "appearances" : [ 12 | { 13 | "appearance" : "luminosity", 14 | "value" : "light" 15 | } 16 | ], 17 | "scale" : "1x" 18 | }, 19 | { 20 | "idiom" : "mac", 21 | "filename" : "Tutorial_Normal_Dark.png", 22 | "appearances" : [ 23 | { 24 | "appearance" : "luminosity", 25 | "value" : "dark" 26 | } 27 | ], 28 | "scale" : "1x" 29 | }, 30 | { 31 | "idiom" : "mac", 32 | "scale" : "2x" 33 | }, 34 | { 35 | "idiom" : "mac", 36 | "scale" : "2x", 37 | "appearances" : [ 38 | { 39 | "appearance" : "luminosity", 40 | "value" : "light" 41 | } 42 | ] 43 | }, 44 | { 45 | "idiom" : "mac", 46 | "scale" : "2x", 47 | "appearances" : [ 48 | { 49 | "appearance" : "luminosity", 50 | "value" : "dark" 51 | } 52 | ] 53 | } 54 | ], 55 | "info" : { 56 | "version" : 1, 57 | "author" : "xcode" 58 | } 59 | } -------------------------------------------------------------------------------- /IsItPrivate/Resources/Assets.xcassets/Tutorial_Normal.imageset/Tutorial_Normal_Dark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ffittschen/IsItPrivate/d61e9a5c765642dc5dd8b3aa8f1e73a4f0aea79f/IsItPrivate/Resources/Assets.xcassets/Tutorial_Normal.imageset/Tutorial_Normal_Dark.png -------------------------------------------------------------------------------- /IsItPrivate/Resources/Assets.xcassets/Tutorial_Normal.imageset/Tutorial_Normal_Light-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ffittschen/IsItPrivate/d61e9a5c765642dc5dd8b3aa8f1e73a4f0aea79f/IsItPrivate/Resources/Assets.xcassets/Tutorial_Normal.imageset/Tutorial_Normal_Light-1.png -------------------------------------------------------------------------------- /IsItPrivate/Resources/Assets.xcassets/Tutorial_Normal.imageset/Tutorial_Normal_Light.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ffittschen/IsItPrivate/d61e9a5c765642dc5dd8b3aa8f1e73a4f0aea79f/IsItPrivate/Resources/Assets.xcassets/Tutorial_Normal.imageset/Tutorial_Normal_Light.png -------------------------------------------------------------------------------- /IsItPrivate/Resources/Assets.xcassets/Tutorial_Private.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "mac", 5 | "filename" : "Tutorial_Private_Light.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "mac", 10 | "filename" : "Tutorial_Private_Light-1.png", 11 | "appearances" : [ 12 | { 13 | "appearance" : "luminosity", 14 | "value" : "light" 15 | } 16 | ], 17 | "scale" : "1x" 18 | }, 19 | { 20 | "idiom" : "mac", 21 | "filename" : "Tutorial_Private_Dark.png", 22 | "appearances" : [ 23 | { 24 | "appearance" : "luminosity", 25 | "value" : "dark" 26 | } 27 | ], 28 | "scale" : "1x" 29 | }, 30 | { 31 | "idiom" : "mac", 32 | "scale" : "2x" 33 | }, 34 | { 35 | "idiom" : "mac", 36 | "scale" : "2x", 37 | "appearances" : [ 38 | { 39 | "appearance" : "luminosity", 40 | "value" : "light" 41 | } 42 | ] 43 | }, 44 | { 45 | "idiom" : "mac", 46 | "scale" : "2x", 47 | "appearances" : [ 48 | { 49 | "appearance" : "luminosity", 50 | "value" : "dark" 51 | } 52 | ] 53 | } 54 | ], 55 | "info" : { 56 | "version" : 1, 57 | "author" : "xcode" 58 | } 59 | } -------------------------------------------------------------------------------- /IsItPrivate/Resources/Assets.xcassets/Tutorial_Private.imageset/Tutorial_Private_Dark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ffittschen/IsItPrivate/d61e9a5c765642dc5dd8b3aa8f1e73a4f0aea79f/IsItPrivate/Resources/Assets.xcassets/Tutorial_Private.imageset/Tutorial_Private_Dark.png -------------------------------------------------------------------------------- /IsItPrivate/Resources/Assets.xcassets/Tutorial_Private.imageset/Tutorial_Private_Light-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ffittschen/IsItPrivate/d61e9a5c765642dc5dd8b3aa8f1e73a4f0aea79f/IsItPrivate/Resources/Assets.xcassets/Tutorial_Private.imageset/Tutorial_Private_Light-1.png -------------------------------------------------------------------------------- /IsItPrivate/Resources/Assets.xcassets/Tutorial_Private.imageset/Tutorial_Private_Light.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ffittschen/IsItPrivate/d61e9a5c765642dc5dd8b3aa8f1e73a4f0aea79f/IsItPrivate/Resources/Assets.xcassets/Tutorial_Private.imageset/Tutorial_Private_Light.png -------------------------------------------------------------------------------- /IsItPrivate/Resources/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | Is It Private? 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 2 21 | FFBundleCompassIconCreatorWebsite 22 | https://thenounproject.com/xinhstudio 23 | FFBundleLicenseName 24 | BSD 25 | FFBundleMainDeveloperName 26 | Florian Fittschen 27 | FFBundleMainDeveloperWebsite 28 | https://twitter.com/flofi 29 | FFBundleMaskIconCreatorWebsite 30 | https://thenounproject.com/bfarias 31 | FFBundleRepositoryName 32 | ffittschen/isitprivate 33 | FFBundleRepositoryWebsite 34 | https://github.com/ffittschen/isitprivate 35 | ITSAppUsesNonExemptEncryption 36 | 37 | LSApplicationCategoryType 38 | public.app-category.productivity 39 | LSMinimumSystemVersion 40 | $(MACOSX_DEPLOYMENT_TARGET) 41 | NSHumanReadableCopyright 42 | Copyright © 2018 Florian Fittschen. All rights reserved. 43 | NSMainStoryboardFile 44 | Main 45 | NSPrincipalClass 46 | NSApplication 47 | 48 | 49 | -------------------------------------------------------------------------------- /IsItPrivate/Resources/IsItPrivate.entitlements: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | com.apple.security.app-sandbox 6 | 7 | com.apple.security.files.user-selected.read-only 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Florian Fittschen 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /PRIVACY.md: -------------------------------------------------------------------------------- 1 | # Is It Private — Privacy Policy 2 | 3 | This privacy policy governs your use of the software application Is It Private ("Application"). The Application is a Safari App Extension providing a toolbar icon that changes its visual appearance if Private Browsing is enabled. 4 | 5 | The Application does not store or transmit any personal details, nor does it include advertising, tracking software or analytics software that talks to third parties. 6 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

2 | 3 | Is It Private App Icon
4 |
5 |

6 | 7 | # Is It Private? 8 | 9 | ![macOS](https://img.shields.io/badge/platform-macOS-lightgrey.svg) 10 | [![GitHub release](https://img.shields.io/github/release/ffittschen/isitprivate.svg)](https://github.com/ffittschen/IsItPrivate/releases/latest) 11 | [![GitHub](https://img.shields.io/github/license/ffittschen/isitprivate.svg)](https://github.com/ffittschen/IsItPrivate/blob/master/LICENSE) 12 | 13 | _Is It Private_ is a Safari Extension providing a toolbar icon that changes its visual appearance if Private Browsing is enabled. This is especially helpful when the Dark appearance of macOS is activated. 14 | 15 | 16 | ## Installation 17 | 18 | ### App Store 19 | 20 | _Is It Private_ is available on the [App Store](https://itunes.apple.com/de/app/is-it-private/id1440322906?l=en&mt=12) 🎉. 21 | 22 | ### GitHub Releases 23 | 24 | 1. Open the [releases](/releases) page and download the `IsItPrivate.app.zip` from the latest release. 25 | 1. Unzip the file and move `IsItPrivate.app` into your Applications folder. 26 | 27 | 28 | ### Build from Source 29 | 30 | 1. Clone this repository or download the source code of the [latest release](/releases/latest). 31 | 1. Open `IsItPrivate.xcodeproj` with Xcode and build the `IsItPrivate` scheme. 32 | 33 | 34 | ## Support 35 | 36 | If you encounter any problems, feel free to [open an issue](/issues) or contact me [on Twitter](https://twitter.com/flofi). 37 | 38 | 39 | ## Privacy Policy 40 | 41 | This privacy policy governs your use of the software application Is It Private ("Application"). The Application is a Safari App Extension providing a toolbar icon that changes its visual appearance if Private Browsing is enabled. 42 | 43 | The Application does not store or transmit any personal details, nor does it include advertising, tracking software or analytics software that talks to third parties. 44 | 45 | 46 | ## Attributions 47 | 48 | mask by b farias from the Noun Project -- [Link](https://thenounproject.com/browse/?i=795831) 49 | 50 | Compass by Xinh Studio from the Noun Project -- [Link](https://thenounproject.com/browse/?i=51854) 51 | 52 | ## License 53 | 54 | [MIT](LICENSE) 55 | -------------------------------------------------------------------------------- /fastlane/Appfile: -------------------------------------------------------------------------------- 1 | # app_identifier("[[APP_IDENTIFIER]]") # The bundle identifier of your app 2 | # apple_id("[[APPLE_ID]]") # Your Apple email address 3 | 4 | 5 | # For more information about the Appfile, see: 6 | # https://docs.fastlane.tools/advanced/#appfile 7 | -------------------------------------------------------------------------------- /fastlane/Fastfile: -------------------------------------------------------------------------------- 1 | # This file contains the fastlane.tools configuration 2 | # You can find the documentation at https://docs.fastlane.tools 3 | # 4 | # For a list of all available actions, check out 5 | # 6 | # https://docs.fastlane.tools/actions 7 | # 8 | # For a list of all available plugins, check out 9 | # 10 | # https://docs.fastlane.tools/plugins/available-plugins 11 | # 12 | 13 | # Uncomment the line if you want fastlane to automatically update itself 14 | # update_fastlane 15 | 16 | default_platform(:mac) 17 | 18 | platform :mac do 19 | desc "Description of what the lane does" 20 | lane :generate_icons do 21 | appicon( 22 | icon_path: "./Assets/AppIcon.png", 23 | asset_catalog_path: "./IsItPrivate/Assets.xcassets" 24 | ) 25 | end 26 | end 27 | -------------------------------------------------------------------------------- /fastlane/README.md: -------------------------------------------------------------------------------- 1 | fastlane documentation 2 | ================ 3 | # Installation 4 | 5 | Make sure you have the latest version of the Xcode command line tools installed: 6 | 7 | ``` 8 | xcode-select --install 9 | ``` 10 | 11 | Install _fastlane_ using 12 | ``` 13 | [sudo] gem install fastlane -NV 14 | ``` 15 | or alternatively using `brew cask install fastlane` 16 | 17 | # Available Actions 18 | ## Mac 19 | ### mac generate_icons 20 | ``` 21 | fastlane mac generate_icons 22 | ``` 23 | Description of what the lane does 24 | 25 | ---- 26 | 27 | This README.md is auto-generated and will be re-generated every time [fastlane](https://fastlane.tools) is run. 28 | More information about fastlane can be found on [fastlane.tools](https://fastlane.tools). 29 | The documentation of fastlane can be found on [docs.fastlane.tools](https://docs.fastlane.tools). 30 | -------------------------------------------------------------------------------- /fastlane/actions/appicon.rb: -------------------------------------------------------------------------------- 1 | module Fastlane 2 | module Actions 3 | 4 | class AppiconAction < Action 5 | def self.run(params) 6 | 7 | icon_sets = Dir.glob(File.join(params[:asset_catalog_path], '*.appiconset')) 8 | UI.user_error!("Could not find any app icon sets in the specified asset catalog. Please create one first!") unless icon_sets.size > 0 9 | 10 | if icon_sets.size > 1 11 | UI.message "Select Icon Set: " 12 | icon_set = choose(*(icon_sets)) 13 | else 14 | icon_set = icon_sets.first 15 | end 16 | 17 | contents_file = File.join(icon_set, 'Contents.json') 18 | contentsJSON = JSON.parse(File.read(contents_file)) 19 | 20 | contentsJSON['images'].each do |image| 21 | image_size = image['size'] 22 | image_scale = image['scale'] 23 | 24 | scaled_image_width = Integer(image_size.split('x').first.to_f * image_scale.sub('x', '').to_f) 25 | scaled_image_name = "Icon-#{image_size}-@#{image_scale}#{File.extname(params[:icon_path])}" 26 | scaled_image_output = File.join(icon_set, scaled_image_name) 27 | 28 | UI.message "Generating #{image_size} @ #{image_scale} 🎨" 29 | if system("convert #{params[:icon_path].shellescape} -resize #{scaled_image_width}x#{scaled_image_width} #{scaled_image_output.shellescape}") 30 | 31 | current_icon_name = image['filename'] 32 | if current_icon_name 33 | current_icon_file = File.join(icon_set, current_icon_name) 34 | if File.exist?(current_icon_file) and !scaled_image_name.eql?(current_icon_name) 35 | FileUtils.rm(current_icon_file) 36 | end 37 | end 38 | 39 | image['filename'] = scaled_image_name 40 | else 41 | UI.crash!("Failed to run: 'convert #{params[:icon_path].shellescape} -resize #{scaled_image_width}x#{scaled_image_width} #{scaled_image_output.shellescape}'") 42 | end 43 | 44 | end 45 | 46 | # Save the new Contents.json 47 | File.open(contents_file, "w") do |file| 48 | file.write(JSON.pretty_generate(contentsJSON)) 49 | end 50 | 51 | UI.success "Successfully generated and installed the app icons 🎉" 52 | end 53 | 54 | ##################################################### 55 | # @!group Documentation 56 | ##################################################### 57 | 58 | def self.description 59 | "Generate and install icons into an Xcode Asset Catalog" 60 | end 61 | 62 | def self.available_options 63 | [ 64 | FastlaneCore::ConfigItem.new(key: :icon_path, 65 | env_name: "FL_APPICON_PATH", 66 | description: "Path to the 1024x1024 iTunes icon png", 67 | is_string: true, 68 | verify_block: proc do |value| 69 | UI.user_error!("Couldn't find the specified icon at path '#{value}'") unless File.exist?(value) 70 | end 71 | ), 72 | FastlaneCore::ConfigItem.new(key: :asset_catalog_path, 73 | env_name: "FL_ASSET_CATALOG_PATH", 74 | description: "Path to the asset catalog, which holds your *.appiconset", 75 | is_string: true, 76 | verify_block: proc do |value| 77 | UI.user_error!("Couldn't find the specified asset catalog at path '#{value}'") unless File.exist?(value) 78 | UI.user_error!("It seems that you did not specify a valid asset catalog. It needs to be a .xcassets directory.") unless File.directory?(value) and File.extname(value).eql?('.xcassets') 79 | end 80 | ) 81 | ] 82 | end 83 | 84 | def self.authors 85 | ["ffittschen"] 86 | end 87 | 88 | def self.is_supported?(platform) 89 | true 90 | end 91 | end 92 | end 93 | end 94 | --------------------------------------------------------------------------------