├── .gitignore ├── Fluor.xcodeproj ├── project.pbxproj ├── project.xcworkspace │ ├── contents.xcworkspacedata │ └── xcshareddata │ │ ├── IDEWorkspaceChecks.plist │ │ └── swiftpm │ │ └── Package.resolved └── xcshareddata │ └── xcschemes │ └── Fluor.xcscheme ├── Fluor ├── Assets.xcassets │ ├── About.imageset │ │ ├── AboutDark.png │ │ ├── AboutDark@2x.png │ │ ├── AboutLight.png │ │ ├── AboutLight@2x.png │ │ └── Contents.json │ ├── App.imageset │ │ ├── Contents.json │ │ ├── RealAppDark.png │ │ ├── RealAppDark@2x.png │ │ ├── RealAppLight.png │ │ └── RealAppLight@2x.png │ ├── AppIcon.appiconset │ │ ├── 128.png │ │ ├── 128@2x.png │ │ ├── 16.png │ │ ├── 16@2x.png │ │ ├── 256.png │ │ ├── 256@2x.png │ │ ├── 32.png │ │ ├── 32@2x.png │ │ ├── 512.png │ │ ├── 512@2x.png │ │ └── Contents.json │ ├── AppSwitch.imageset │ │ ├── AppSwitchDark.png │ │ ├── AppSwitchDark@2x.png │ │ ├── AppSwitchLight.png │ │ ├── AppSwitchLight@2x.png │ │ └── Contents.json │ ├── AppleMode.imageset │ │ ├── AppleMode.png │ │ ├── AppleMode@2x.png │ │ └── Contents.json │ ├── ArrowBackward.imageset │ │ ├── ArrowBackwardDark.png │ │ ├── ArrowBackwardDark@2x.png │ │ ├── ArrowBackwardLight.png │ │ ├── ArrowBackwardLight@2x.png │ │ └── Contents.json │ ├── ArrowForward.imageset │ │ ├── ArrowButtonDark.png │ │ ├── ArrowButtonDark@2x.png │ │ ├── ArrowButtonLight.png │ │ ├── ArrowButtonLight@2x.png │ │ └── Contents.json │ ├── ButtonGithub.imageset │ │ ├── ButtonGithubDark.png │ │ ├── ButtonGithubDark@2x.png │ │ ├── ButtonGithubLight.png │ │ ├── ButtonGithubLight@2x.png │ │ └── Contents.json │ ├── ButtonTwitter.imageset │ │ ├── ButtonTwitterDark.png │ │ ├── ButtonTwitterDark@2x.png │ │ ├── ButtonTwitterLight.png │ │ ├── ButtonTwitterLight@2x.png │ │ └── Contents.json │ ├── ButtonWeb.imageset │ │ ├── ButtonWebDark.png │ │ ├── ButtonWebDark@2x.png │ │ ├── ButtonWebLight.png │ │ ├── ButtonWebLight@2x.png │ │ └── Contents.json │ ├── CheckDisabled.imageset │ │ ├── CheckDisabledDark.png │ │ ├── CheckDisabledDark@2x.png │ │ ├── CheckDisabledLight.png │ │ ├── CheckDisabledLight@2x.png │ │ └── Contents.json │ ├── CheckEnabled.imageset │ │ ├── CheckEnabledDark.png │ │ ├── CheckEnabledDark@2x.png │ │ ├── CheckEnabledLight.png │ │ ├── CheckEnabledLight@2x.png │ │ └── Contents.json │ ├── CheckMixed.imageset │ │ ├── CheckMixedDark.png │ │ ├── CheckMixedDark@2x.png │ │ ├── CheckMixedLight.png │ │ ├── CheckMixedLight@2x.png │ │ └── Contents.json │ ├── Contents.json │ ├── Cross.imageset │ │ ├── Contents.json │ │ ├── CrossDark.png │ │ ├── CrossDark@2x.png │ │ ├── CrossLight.png │ │ └── CrossLight@2x.png │ ├── DefaultMode.imageset │ │ ├── Contents.json │ │ ├── DefaultModeDark.png │ │ ├── DefaultModeDark@2x.png │ │ ├── DefaultModeLight.png │ │ └── DefaultModeLight@2x.png │ ├── DoubleArrowForward.imageset │ │ ├── Contents.json │ │ ├── DoubleArrowButtonDark.png │ │ ├── DoubleArrowButtonDark@2x.png │ │ ├── DoubleArrowButtonLight.png │ │ └── DoubleArrowButtonLight@2x.png │ ├── FluorBlue.colorset │ │ └── Contents.json │ ├── FluorRed.colorset │ │ └── Contents.json │ ├── FnKey.imageset │ │ ├── Contents.json │ │ ├── FnKeyDark.png │ │ ├── FnKeyDark@2x.png │ │ ├── FnKeyLight.png │ │ └── FnKeyLight@2x.png │ ├── IconAppleMode.imageset │ │ ├── Contents.json │ │ ├── IconAppleMode.png │ │ └── IconAppleMode@2x.png │ ├── IconDisabled.imageset │ │ ├── Contents.json │ │ ├── IconDisabled.png │ │ └── IconDisabled@2x.png │ ├── IconOtherMode.imageset │ │ ├── Contents.json │ │ ├── IconOtherMode.png │ │ └── IconOtherMode@2x.png │ ├── LighIconDisabled.imageset │ │ ├── Contents.json │ │ ├── LighIconDisabled.png │ │ └── LighIconDisabled@2x.png │ ├── MixedSwitch.imageset │ │ ├── Contents.json │ │ ├── MixedSwitchDark.png │ │ ├── MixedSwitchDark@2x.png │ │ ├── MixedSwitchLight.png │ │ └── MixedSwitchLight@2x.png │ ├── OtherMode.imageset │ │ ├── Contents.json │ │ ├── OtherMode.png │ │ └── OtherMode@2x.png │ ├── Preferences.imageset │ │ ├── Contents.json │ │ ├── PreferencesDark.png │ │ ├── PreferencesDark@2x.png │ │ ├── PreferencesLight.png │ │ └── PreferencesLight@2x.png │ ├── QuestionMark.imageset │ │ ├── Contents.json │ │ ├── QuestionMark.png │ │ └── QuestionMark@2x.png │ ├── Quit.imageset │ │ ├── Contents.json │ │ ├── Quit.png │ │ └── Quit@2x.png │ ├── Rules.imageset │ │ ├── Contents.json │ │ ├── RulesDark.png │ │ ├── RulesDark@2x.png │ │ ├── RulesLight.png │ │ └── RulesLight@2x.png │ ├── RunningApps.imageset │ │ ├── Contents.json │ │ ├── RunningAppsDark.png │ │ ├── RunningAppsDark@2x.png │ │ ├── RunningAppsLight.png │ │ └── RunningAppsLight@2x.png │ └── Service.imageset │ │ ├── Contents.json │ │ ├── ServiceDark.png │ │ ├── ServiceDark@2x.png │ │ ├── ServiceLight.png │ │ └── ServiceLight@2x.png ├── Base.lproj │ ├── About.storyboard │ ├── Main.xib │ ├── MainMenu.xib │ ├── Preferences.storyboard │ ├── RulesEditor.storyboard │ ├── RunningApps.storyboard │ └── Welcome.storyboard ├── Controllers │ ├── BehaviorController.swift │ ├── LaunchAtLoginController.h │ ├── LaunchAtLoginController.m │ ├── MenuItemsController.swift │ ├── StatusMenuController.swift │ ├── ViewControllers │ │ ├── AboutViewController.swift │ │ ├── CurrentAppViewController.swift │ │ ├── DefaultModeViewController.swift │ │ ├── PreferencesTabViewController.swift │ │ ├── ReleaseNotesViewController.swift │ │ ├── RulesEditorViewController.swift │ │ ├── RunningAppsViewController.swift │ │ ├── SwitchMethodSelectionViewController.swift │ │ ├── SwitchMethodViewController.swift │ │ └── UserNotificationEnablementViewController.swift │ └── WindowControllers │ │ ├── AboutWindowController.swift │ │ ├── PreferencesWindowController.swift │ │ ├── ReleaseNotesWindowController.swift │ │ ├── RulesEditorWindowController.swift │ │ └── RunningAppWindowController.swift ├── Extensions │ ├── NSStoryboardNamesExtension.swift │ ├── NSViewExtension.swift │ ├── ResultExtension.swift │ └── SetExtension.swift ├── Fluor-Bridging-Header.h ├── Fluor.entitlements ├── Info.plist ├── Misc │ ├── AppDelegate.swift │ ├── AppErrorManager.swift │ ├── FKeyManager.swift │ ├── PFMoveApplication.h │ ├── PFMoveApplication.m │ ├── TableViewContentAnimator.swift │ └── UserNotificationHelper.swift ├── Models │ ├── AppManager.swift │ ├── Enums.swift │ ├── Items.swift │ ├── Release.swift │ └── RuleValueTransformer.swift ├── Protocols │ ├── NotificationHelpers.swift │ └── StoryboardInstantiableProtocol.swift ├── ReleaseNotes.rtf ├── Views │ ├── CheckableMenuItem.swift │ ├── LinkButton.swift │ ├── MenuItemView.swift │ ├── MoverEffectView.swift │ ├── MoverImageView.swift │ ├── MultilinesCheckBoxLabel.swift │ ├── PoppingLinkButton.swift │ ├── RuleCellView.swift │ └── SelectableBox.swift ├── dsa_pub.pem ├── en.lproj │ └── Localizable.strings ├── fr.lproj │ ├── About.strings │ ├── Localizable.strings │ ├── MainMenu.strings │ ├── Preferences.strings │ ├── RulesEditor.strings │ └── RunningApps.strings └── zh-Hans.lproj │ ├── About.strings │ ├── Localizable.strings │ ├── MainMenu.strings │ ├── Preferences.strings │ ├── RulesEditor.strings │ └── RunningApps.strings ├── LICENSE ├── README.md └── ressources ├── banner.png ├── mainmenu.png ├── preferences.png ├── ruleseditor.png ├── runningapps.png └── statusbar.png /.gitignore: -------------------------------------------------------------------------------- 1 | # Xcode 2 | 3 | ## Build generated 4 | build/ 5 | DerivedData/ 6 | 7 | ## Various settings 8 | *.pbxuser 9 | !default.pbxuser 10 | *.mode1v3 11 | !default.mode1v3 12 | *.mode2v3 13 | !default.mode2v3 14 | *.perspectivev3 15 | !default.perspectivev3 16 | xcuserdata/ 17 | 18 | ## Other 19 | *.moved-aside 20 | *.xccheckout 21 | *.xcscmblueprint 22 | 23 | ## Obj-C/Swift specific 24 | *.hmap 25 | *.ipa 26 | 27 | ## Playgrounds 28 | timeline.xctimeline 29 | playground.xcworkspace 30 | 31 | # Swift Package Manager 32 | # 33 | # Add this line if you want to avoid checking in source code from Swift Package Manager dependencies. 34 | # Packages/ 35 | .build/ 36 | 37 | # CocoaPods 38 | # 39 | # We recommend against adding the Pods directory to your .gitignore. However 40 | # you should judge for yourself, the pros and cons are mentioned at: 41 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control 42 | # 43 | # Pods/ 44 | 45 | # Carthage 46 | # 47 | # Add this line if you want to avoid checking in source code from Carthage dependencies. 48 | # Carthage/Checkouts 49 | 50 | Carthage/Build 51 | 52 | # fastlane 53 | # 54 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the 55 | # screenshots whenever they are needed. 56 | # For more information about the recommended setup visit: 57 | # https://github.com/fastlane/fastlane/blob/master/docs/Gitignore.md 58 | 59 | fastlane/report.xml 60 | fastlane/screenshots 61 | 62 | # Documentation 63 | Documentation/docs 64 | /Fluor/Sparkle.framework 65 | /Fluor/Sparkle.framework.dSYM 66 | -------------------------------------------------------------------------------- /Fluor.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Fluor.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /Fluor.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved: -------------------------------------------------------------------------------- 1 | { 2 | "object": { 3 | "pins": [ 4 | { 5 | "package": "CoreGeometry", 6 | "repositoryURL": "https://gitlab.com/Pyroh/CoreGeometry.git", 7 | "state": { 8 | "branch": null, 9 | "revision": "a59affa331972263980f8a2af4cfd5f37ad42d3d", 10 | "version": "3.0.0" 11 | } 12 | }, 13 | { 14 | "package": "DefaultsWrapper", 15 | "repositoryURL": "https://github.com/Pyroh/DefaultsWrapper.git", 16 | "state": { 17 | "branch": null, 18 | "revision": "649794e5c7af45f69d1e128a3c9fd0fe1cde282e", 19 | "version": "1.2.0" 20 | } 21 | }, 22 | { 23 | "package": "SmoothOperators", 24 | "repositoryURL": "https://github.com/Pyroh/SmoothOperators.git", 25 | "state": { 26 | "branch": null, 27 | "revision": "12f0d7cc9ade6bc826a822f9d2021b4dd394c4a0", 28 | "version": "0.4.0" 29 | } 30 | } 31 | ] 32 | }, 33 | "version": 1 34 | } 35 | -------------------------------------------------------------------------------- /Fluor.xcodeproj/xcshareddata/xcschemes/Fluor.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 11 | 14 | 15 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 33 | 39 | 40 | 41 | 42 | 43 | 48 | 49 | 55 | 56 | 57 | 58 | 59 | 60 | 71 | 73 | 79 | 80 | 81 | 82 | 86 | 87 | 88 | 89 | 95 | 97 | 103 | 104 | 105 | 106 | 108 | 109 | 112 | 113 | 115 | 118 | 119 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | -------------------------------------------------------------------------------- /Fluor/Assets.xcassets/About.imageset/AboutDark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Pyroh/Fluor/6b5fcd11324dfe99ef0fb20d4015625a0e96f283/Fluor/Assets.xcassets/About.imageset/AboutDark.png -------------------------------------------------------------------------------- /Fluor/Assets.xcassets/About.imageset/AboutDark@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Pyroh/Fluor/6b5fcd11324dfe99ef0fb20d4015625a0e96f283/Fluor/Assets.xcassets/About.imageset/AboutDark@2x.png -------------------------------------------------------------------------------- /Fluor/Assets.xcassets/About.imageset/AboutLight.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Pyroh/Fluor/6b5fcd11324dfe99ef0fb20d4015625a0e96f283/Fluor/Assets.xcassets/About.imageset/AboutLight.png -------------------------------------------------------------------------------- /Fluor/Assets.xcassets/About.imageset/AboutLight@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Pyroh/Fluor/6b5fcd11324dfe99ef0fb20d4015625a0e96f283/Fluor/Assets.xcassets/About.imageset/AboutLight@2x.png -------------------------------------------------------------------------------- /Fluor/Assets.xcassets/About.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "mac", 5 | "filename" : "AboutLight.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "mac", 10 | "filename" : "AboutDark.png", 11 | "appearances" : [ 12 | { 13 | "appearance" : "luminosity", 14 | "value" : "dark" 15 | } 16 | ], 17 | "scale" : "1x" 18 | }, 19 | { 20 | "idiom" : "mac", 21 | "filename" : "AboutLight@2x.png", 22 | "scale" : "2x" 23 | }, 24 | { 25 | "idiom" : "mac", 26 | "filename" : "AboutDark@2x.png", 27 | "appearances" : [ 28 | { 29 | "appearance" : "luminosity", 30 | "value" : "dark" 31 | } 32 | ], 33 | "scale" : "2x" 34 | } 35 | ], 36 | "info" : { 37 | "version" : 1, 38 | "author" : "xcode" 39 | }, 40 | "properties" : { 41 | "template-rendering-intent" : "template" 42 | } 43 | } -------------------------------------------------------------------------------- /Fluor/Assets.xcassets/App.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "RealAppLight.png", 5 | "idiom" : "mac", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "appearances" : [ 10 | { 11 | "appearance" : "luminosity", 12 | "value" : "dark" 13 | } 14 | ], 15 | "filename" : "RealAppDark.png", 16 | "idiom" : "mac", 17 | "scale" : "1x" 18 | }, 19 | { 20 | "filename" : "RealAppLight@2x.png", 21 | "idiom" : "mac", 22 | "scale" : "2x" 23 | }, 24 | { 25 | "appearances" : [ 26 | { 27 | "appearance" : "luminosity", 28 | "value" : "dark" 29 | } 30 | ], 31 | "filename" : "RealAppDark@2x.png", 32 | "idiom" : "mac", 33 | "scale" : "2x" 34 | } 35 | ], 36 | "info" : { 37 | "author" : "xcode", 38 | "version" : 1 39 | }, 40 | "properties" : { 41 | "template-rendering-intent" : "template" 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /Fluor/Assets.xcassets/App.imageset/RealAppDark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Pyroh/Fluor/6b5fcd11324dfe99ef0fb20d4015625a0e96f283/Fluor/Assets.xcassets/App.imageset/RealAppDark.png -------------------------------------------------------------------------------- /Fluor/Assets.xcassets/App.imageset/RealAppDark@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Pyroh/Fluor/6b5fcd11324dfe99ef0fb20d4015625a0e96f283/Fluor/Assets.xcassets/App.imageset/RealAppDark@2x.png -------------------------------------------------------------------------------- /Fluor/Assets.xcassets/App.imageset/RealAppLight.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Pyroh/Fluor/6b5fcd11324dfe99ef0fb20d4015625a0e96f283/Fluor/Assets.xcassets/App.imageset/RealAppLight.png -------------------------------------------------------------------------------- /Fluor/Assets.xcassets/App.imageset/RealAppLight@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Pyroh/Fluor/6b5fcd11324dfe99ef0fb20d4015625a0e96f283/Fluor/Assets.xcassets/App.imageset/RealAppLight@2x.png -------------------------------------------------------------------------------- /Fluor/Assets.xcassets/AppIcon.appiconset/128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Pyroh/Fluor/6b5fcd11324dfe99ef0fb20d4015625a0e96f283/Fluor/Assets.xcassets/AppIcon.appiconset/128.png -------------------------------------------------------------------------------- /Fluor/Assets.xcassets/AppIcon.appiconset/128@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Pyroh/Fluor/6b5fcd11324dfe99ef0fb20d4015625a0e96f283/Fluor/Assets.xcassets/AppIcon.appiconset/128@2x.png -------------------------------------------------------------------------------- /Fluor/Assets.xcassets/AppIcon.appiconset/16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Pyroh/Fluor/6b5fcd11324dfe99ef0fb20d4015625a0e96f283/Fluor/Assets.xcassets/AppIcon.appiconset/16.png -------------------------------------------------------------------------------- /Fluor/Assets.xcassets/AppIcon.appiconset/16@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Pyroh/Fluor/6b5fcd11324dfe99ef0fb20d4015625a0e96f283/Fluor/Assets.xcassets/AppIcon.appiconset/16@2x.png -------------------------------------------------------------------------------- /Fluor/Assets.xcassets/AppIcon.appiconset/256.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Pyroh/Fluor/6b5fcd11324dfe99ef0fb20d4015625a0e96f283/Fluor/Assets.xcassets/AppIcon.appiconset/256.png -------------------------------------------------------------------------------- /Fluor/Assets.xcassets/AppIcon.appiconset/256@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Pyroh/Fluor/6b5fcd11324dfe99ef0fb20d4015625a0e96f283/Fluor/Assets.xcassets/AppIcon.appiconset/256@2x.png -------------------------------------------------------------------------------- /Fluor/Assets.xcassets/AppIcon.appiconset/32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Pyroh/Fluor/6b5fcd11324dfe99ef0fb20d4015625a0e96f283/Fluor/Assets.xcassets/AppIcon.appiconset/32.png -------------------------------------------------------------------------------- /Fluor/Assets.xcassets/AppIcon.appiconset/32@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Pyroh/Fluor/6b5fcd11324dfe99ef0fb20d4015625a0e96f283/Fluor/Assets.xcassets/AppIcon.appiconset/32@2x.png -------------------------------------------------------------------------------- /Fluor/Assets.xcassets/AppIcon.appiconset/512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Pyroh/Fluor/6b5fcd11324dfe99ef0fb20d4015625a0e96f283/Fluor/Assets.xcassets/AppIcon.appiconset/512.png -------------------------------------------------------------------------------- /Fluor/Assets.xcassets/AppIcon.appiconset/512@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Pyroh/Fluor/6b5fcd11324dfe99ef0fb20d4015625a0e96f283/Fluor/Assets.xcassets/AppIcon.appiconset/512@2x.png -------------------------------------------------------------------------------- /Fluor/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "size" : "16x16", 5 | "idiom" : "mac", 6 | "filename" : "16.png", 7 | "scale" : "1x" 8 | }, 9 | { 10 | "size" : "16x16", 11 | "idiom" : "mac", 12 | "filename" : "16@2x.png", 13 | "scale" : "2x" 14 | }, 15 | { 16 | "size" : "32x32", 17 | "idiom" : "mac", 18 | "filename" : "32.png", 19 | "scale" : "1x" 20 | }, 21 | { 22 | "size" : "32x32", 23 | "idiom" : "mac", 24 | "filename" : "32@2x.png", 25 | "scale" : "2x" 26 | }, 27 | { 28 | "size" : "128x128", 29 | "idiom" : "mac", 30 | "filename" : "128.png", 31 | "scale" : "1x" 32 | }, 33 | { 34 | "size" : "128x128", 35 | "idiom" : "mac", 36 | "filename" : "128@2x.png", 37 | "scale" : "2x" 38 | }, 39 | { 40 | "size" : "256x256", 41 | "idiom" : "mac", 42 | "filename" : "256.png", 43 | "scale" : "1x" 44 | }, 45 | { 46 | "size" : "256x256", 47 | "idiom" : "mac", 48 | "filename" : "256@2x.png", 49 | "scale" : "2x" 50 | }, 51 | { 52 | "size" : "512x512", 53 | "idiom" : "mac", 54 | "filename" : "512.png", 55 | "scale" : "1x" 56 | }, 57 | { 58 | "size" : "512x512", 59 | "idiom" : "mac", 60 | "filename" : "512@2x.png", 61 | "scale" : "2x" 62 | } 63 | ], 64 | "info" : { 65 | "version" : 1, 66 | "author" : "xcode" 67 | } 68 | } -------------------------------------------------------------------------------- /Fluor/Assets.xcassets/AppSwitch.imageset/AppSwitchDark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Pyroh/Fluor/6b5fcd11324dfe99ef0fb20d4015625a0e96f283/Fluor/Assets.xcassets/AppSwitch.imageset/AppSwitchDark.png -------------------------------------------------------------------------------- /Fluor/Assets.xcassets/AppSwitch.imageset/AppSwitchDark@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Pyroh/Fluor/6b5fcd11324dfe99ef0fb20d4015625a0e96f283/Fluor/Assets.xcassets/AppSwitch.imageset/AppSwitchDark@2x.png -------------------------------------------------------------------------------- /Fluor/Assets.xcassets/AppSwitch.imageset/AppSwitchLight.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Pyroh/Fluor/6b5fcd11324dfe99ef0fb20d4015625a0e96f283/Fluor/Assets.xcassets/AppSwitch.imageset/AppSwitchLight.png -------------------------------------------------------------------------------- /Fluor/Assets.xcassets/AppSwitch.imageset/AppSwitchLight@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Pyroh/Fluor/6b5fcd11324dfe99ef0fb20d4015625a0e96f283/Fluor/Assets.xcassets/AppSwitch.imageset/AppSwitchLight@2x.png -------------------------------------------------------------------------------- /Fluor/Assets.xcassets/AppSwitch.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "mac", 5 | "filename" : "AppSwitchLight.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "mac", 10 | "filename" : "AppSwitchDark.png", 11 | "appearances" : [ 12 | { 13 | "appearance" : "luminosity", 14 | "value" : "dark" 15 | } 16 | ], 17 | "scale" : "1x" 18 | }, 19 | { 20 | "idiom" : "mac", 21 | "filename" : "AppSwitchLight@2x.png", 22 | "scale" : "2x" 23 | }, 24 | { 25 | "idiom" : "mac", 26 | "filename" : "AppSwitchDark@2x.png", 27 | "appearances" : [ 28 | { 29 | "appearance" : "luminosity", 30 | "value" : "dark" 31 | } 32 | ], 33 | "scale" : "2x" 34 | } 35 | ], 36 | "info" : { 37 | "version" : 1, 38 | "author" : "xcode" 39 | }, 40 | "properties" : { 41 | "template-rendering-intent" : "template" 42 | } 43 | } -------------------------------------------------------------------------------- /Fluor/Assets.xcassets/AppleMode.imageset/AppleMode.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Pyroh/Fluor/6b5fcd11324dfe99ef0fb20d4015625a0e96f283/Fluor/Assets.xcassets/AppleMode.imageset/AppleMode.png -------------------------------------------------------------------------------- /Fluor/Assets.xcassets/AppleMode.imageset/AppleMode@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Pyroh/Fluor/6b5fcd11324dfe99ef0fb20d4015625a0e96f283/Fluor/Assets.xcassets/AppleMode.imageset/AppleMode@2x.png -------------------------------------------------------------------------------- /Fluor/Assets.xcassets/AppleMode.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "mac", 5 | "filename" : "AppleMode.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "mac", 10 | "filename" : "AppleMode@2x.png", 11 | "scale" : "2x" 12 | } 13 | ], 14 | "info" : { 15 | "version" : 1, 16 | "author" : "xcode" 17 | }, 18 | "properties" : { 19 | "template-rendering-intent" : "template" 20 | } 21 | } -------------------------------------------------------------------------------- /Fluor/Assets.xcassets/ArrowBackward.imageset/ArrowBackwardDark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Pyroh/Fluor/6b5fcd11324dfe99ef0fb20d4015625a0e96f283/Fluor/Assets.xcassets/ArrowBackward.imageset/ArrowBackwardDark.png -------------------------------------------------------------------------------- /Fluor/Assets.xcassets/ArrowBackward.imageset/ArrowBackwardDark@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Pyroh/Fluor/6b5fcd11324dfe99ef0fb20d4015625a0e96f283/Fluor/Assets.xcassets/ArrowBackward.imageset/ArrowBackwardDark@2x.png -------------------------------------------------------------------------------- /Fluor/Assets.xcassets/ArrowBackward.imageset/ArrowBackwardLight.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Pyroh/Fluor/6b5fcd11324dfe99ef0fb20d4015625a0e96f283/Fluor/Assets.xcassets/ArrowBackward.imageset/ArrowBackwardLight.png -------------------------------------------------------------------------------- /Fluor/Assets.xcassets/ArrowBackward.imageset/ArrowBackwardLight@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Pyroh/Fluor/6b5fcd11324dfe99ef0fb20d4015625a0e96f283/Fluor/Assets.xcassets/ArrowBackward.imageset/ArrowBackwardLight@2x.png -------------------------------------------------------------------------------- /Fluor/Assets.xcassets/ArrowBackward.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "ArrowBackwardLight.png", 5 | "idiom" : "universal", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "appearances" : [ 10 | { 11 | "appearance" : "luminosity", 12 | "value" : "dark" 13 | } 14 | ], 15 | "filename" : "ArrowBackwardDark.png", 16 | "idiom" : "universal", 17 | "scale" : "1x" 18 | }, 19 | { 20 | "filename" : "ArrowBackwardLight@2x.png", 21 | "idiom" : "universal", 22 | "scale" : "2x" 23 | }, 24 | { 25 | "appearances" : [ 26 | { 27 | "appearance" : "luminosity", 28 | "value" : "dark" 29 | } 30 | ], 31 | "filename" : "ArrowBackwardDark@2x.png", 32 | "idiom" : "universal", 33 | "scale" : "2x" 34 | }, 35 | { 36 | "idiom" : "universal", 37 | "scale" : "3x" 38 | }, 39 | { 40 | "appearances" : [ 41 | { 42 | "appearance" : "luminosity", 43 | "value" : "dark" 44 | } 45 | ], 46 | "idiom" : "universal", 47 | "scale" : "3x" 48 | } 49 | ], 50 | "info" : { 51 | "author" : "xcode", 52 | "version" : 1 53 | }, 54 | "properties" : { 55 | "template-rendering-intent" : "template" 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /Fluor/Assets.xcassets/ArrowForward.imageset/ArrowButtonDark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Pyroh/Fluor/6b5fcd11324dfe99ef0fb20d4015625a0e96f283/Fluor/Assets.xcassets/ArrowForward.imageset/ArrowButtonDark.png -------------------------------------------------------------------------------- /Fluor/Assets.xcassets/ArrowForward.imageset/ArrowButtonDark@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Pyroh/Fluor/6b5fcd11324dfe99ef0fb20d4015625a0e96f283/Fluor/Assets.xcassets/ArrowForward.imageset/ArrowButtonDark@2x.png -------------------------------------------------------------------------------- /Fluor/Assets.xcassets/ArrowForward.imageset/ArrowButtonLight.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Pyroh/Fluor/6b5fcd11324dfe99ef0fb20d4015625a0e96f283/Fluor/Assets.xcassets/ArrowForward.imageset/ArrowButtonLight.png -------------------------------------------------------------------------------- /Fluor/Assets.xcassets/ArrowForward.imageset/ArrowButtonLight@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Pyroh/Fluor/6b5fcd11324dfe99ef0fb20d4015625a0e96f283/Fluor/Assets.xcassets/ArrowForward.imageset/ArrowButtonLight@2x.png -------------------------------------------------------------------------------- /Fluor/Assets.xcassets/ArrowForward.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "ArrowButtonLight.png", 5 | "idiom" : "universal", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "appearances" : [ 10 | { 11 | "appearance" : "luminosity", 12 | "value" : "dark" 13 | } 14 | ], 15 | "filename" : "ArrowButtonDark.png", 16 | "idiom" : "universal", 17 | "scale" : "1x" 18 | }, 19 | { 20 | "filename" : "ArrowButtonLight@2x.png", 21 | "idiom" : "universal", 22 | "scale" : "2x" 23 | }, 24 | { 25 | "appearances" : [ 26 | { 27 | "appearance" : "luminosity", 28 | "value" : "dark" 29 | } 30 | ], 31 | "filename" : "ArrowButtonDark@2x.png", 32 | "idiom" : "universal", 33 | "scale" : "2x" 34 | }, 35 | { 36 | "idiom" : "universal", 37 | "scale" : "3x" 38 | }, 39 | { 40 | "appearances" : [ 41 | { 42 | "appearance" : "luminosity", 43 | "value" : "dark" 44 | } 45 | ], 46 | "idiom" : "universal", 47 | "scale" : "3x" 48 | } 49 | ], 50 | "info" : { 51 | "author" : "xcode", 52 | "version" : 1 53 | }, 54 | "properties" : { 55 | "template-rendering-intent" : "template" 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /Fluor/Assets.xcassets/ButtonGithub.imageset/ButtonGithubDark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Pyroh/Fluor/6b5fcd11324dfe99ef0fb20d4015625a0e96f283/Fluor/Assets.xcassets/ButtonGithub.imageset/ButtonGithubDark.png -------------------------------------------------------------------------------- /Fluor/Assets.xcassets/ButtonGithub.imageset/ButtonGithubDark@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Pyroh/Fluor/6b5fcd11324dfe99ef0fb20d4015625a0e96f283/Fluor/Assets.xcassets/ButtonGithub.imageset/ButtonGithubDark@2x.png -------------------------------------------------------------------------------- /Fluor/Assets.xcassets/ButtonGithub.imageset/ButtonGithubLight.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Pyroh/Fluor/6b5fcd11324dfe99ef0fb20d4015625a0e96f283/Fluor/Assets.xcassets/ButtonGithub.imageset/ButtonGithubLight.png -------------------------------------------------------------------------------- /Fluor/Assets.xcassets/ButtonGithub.imageset/ButtonGithubLight@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Pyroh/Fluor/6b5fcd11324dfe99ef0fb20d4015625a0e96f283/Fluor/Assets.xcassets/ButtonGithub.imageset/ButtonGithubLight@2x.png -------------------------------------------------------------------------------- /Fluor/Assets.xcassets/ButtonGithub.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "mac", 5 | "filename" : "ButtonGithubLight.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "mac", 10 | "filename" : "ButtonGithubDark.png", 11 | "appearances" : [ 12 | { 13 | "appearance" : "luminosity", 14 | "value" : "dark" 15 | } 16 | ], 17 | "scale" : "1x" 18 | }, 19 | { 20 | "idiom" : "mac", 21 | "filename" : "ButtonGithubLight@2x.png", 22 | "scale" : "2x" 23 | }, 24 | { 25 | "idiom" : "mac", 26 | "filename" : "ButtonGithubDark@2x.png", 27 | "appearances" : [ 28 | { 29 | "appearance" : "luminosity", 30 | "value" : "dark" 31 | } 32 | ], 33 | "scale" : "2x" 34 | } 35 | ], 36 | "info" : { 37 | "version" : 1, 38 | "author" : "xcode" 39 | } 40 | } -------------------------------------------------------------------------------- /Fluor/Assets.xcassets/ButtonTwitter.imageset/ButtonTwitterDark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Pyroh/Fluor/6b5fcd11324dfe99ef0fb20d4015625a0e96f283/Fluor/Assets.xcassets/ButtonTwitter.imageset/ButtonTwitterDark.png -------------------------------------------------------------------------------- /Fluor/Assets.xcassets/ButtonTwitter.imageset/ButtonTwitterDark@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Pyroh/Fluor/6b5fcd11324dfe99ef0fb20d4015625a0e96f283/Fluor/Assets.xcassets/ButtonTwitter.imageset/ButtonTwitterDark@2x.png -------------------------------------------------------------------------------- /Fluor/Assets.xcassets/ButtonTwitter.imageset/ButtonTwitterLight.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Pyroh/Fluor/6b5fcd11324dfe99ef0fb20d4015625a0e96f283/Fluor/Assets.xcassets/ButtonTwitter.imageset/ButtonTwitterLight.png -------------------------------------------------------------------------------- /Fluor/Assets.xcassets/ButtonTwitter.imageset/ButtonTwitterLight@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Pyroh/Fluor/6b5fcd11324dfe99ef0fb20d4015625a0e96f283/Fluor/Assets.xcassets/ButtonTwitter.imageset/ButtonTwitterLight@2x.png -------------------------------------------------------------------------------- /Fluor/Assets.xcassets/ButtonTwitter.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "mac", 5 | "filename" : "ButtonTwitterLight.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "mac", 10 | "filename" : "ButtonTwitterDark.png", 11 | "appearances" : [ 12 | { 13 | "appearance" : "luminosity", 14 | "value" : "dark" 15 | } 16 | ], 17 | "scale" : "1x" 18 | }, 19 | { 20 | "idiom" : "mac", 21 | "filename" : "ButtonTwitterLight@2x.png", 22 | "scale" : "2x" 23 | }, 24 | { 25 | "idiom" : "mac", 26 | "filename" : "ButtonTwitterDark@2x.png", 27 | "appearances" : [ 28 | { 29 | "appearance" : "luminosity", 30 | "value" : "dark" 31 | } 32 | ], 33 | "scale" : "2x" 34 | } 35 | ], 36 | "info" : { 37 | "version" : 1, 38 | "author" : "xcode" 39 | } 40 | } -------------------------------------------------------------------------------- /Fluor/Assets.xcassets/ButtonWeb.imageset/ButtonWebDark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Pyroh/Fluor/6b5fcd11324dfe99ef0fb20d4015625a0e96f283/Fluor/Assets.xcassets/ButtonWeb.imageset/ButtonWebDark.png -------------------------------------------------------------------------------- /Fluor/Assets.xcassets/ButtonWeb.imageset/ButtonWebDark@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Pyroh/Fluor/6b5fcd11324dfe99ef0fb20d4015625a0e96f283/Fluor/Assets.xcassets/ButtonWeb.imageset/ButtonWebDark@2x.png -------------------------------------------------------------------------------- /Fluor/Assets.xcassets/ButtonWeb.imageset/ButtonWebLight.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Pyroh/Fluor/6b5fcd11324dfe99ef0fb20d4015625a0e96f283/Fluor/Assets.xcassets/ButtonWeb.imageset/ButtonWebLight.png -------------------------------------------------------------------------------- /Fluor/Assets.xcassets/ButtonWeb.imageset/ButtonWebLight@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Pyroh/Fluor/6b5fcd11324dfe99ef0fb20d4015625a0e96f283/Fluor/Assets.xcassets/ButtonWeb.imageset/ButtonWebLight@2x.png -------------------------------------------------------------------------------- /Fluor/Assets.xcassets/ButtonWeb.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "mac", 5 | "filename" : "ButtonWebLight.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "mac", 10 | "filename" : "ButtonWebDark.png", 11 | "appearances" : [ 12 | { 13 | "appearance" : "luminosity", 14 | "value" : "dark" 15 | } 16 | ], 17 | "scale" : "1x" 18 | }, 19 | { 20 | "idiom" : "mac", 21 | "filename" : "ButtonWebLight@2x.png", 22 | "scale" : "2x" 23 | }, 24 | { 25 | "idiom" : "mac", 26 | "filename" : "ButtonWebDark@2x.png", 27 | "appearances" : [ 28 | { 29 | "appearance" : "luminosity", 30 | "value" : "dark" 31 | } 32 | ], 33 | "scale" : "2x" 34 | } 35 | ], 36 | "info" : { 37 | "version" : 1, 38 | "author" : "xcode" 39 | } 40 | } -------------------------------------------------------------------------------- /Fluor/Assets.xcassets/CheckDisabled.imageset/CheckDisabledDark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Pyroh/Fluor/6b5fcd11324dfe99ef0fb20d4015625a0e96f283/Fluor/Assets.xcassets/CheckDisabled.imageset/CheckDisabledDark.png -------------------------------------------------------------------------------- /Fluor/Assets.xcassets/CheckDisabled.imageset/CheckDisabledDark@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Pyroh/Fluor/6b5fcd11324dfe99ef0fb20d4015625a0e96f283/Fluor/Assets.xcassets/CheckDisabled.imageset/CheckDisabledDark@2x.png -------------------------------------------------------------------------------- /Fluor/Assets.xcassets/CheckDisabled.imageset/CheckDisabledLight.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Pyroh/Fluor/6b5fcd11324dfe99ef0fb20d4015625a0e96f283/Fluor/Assets.xcassets/CheckDisabled.imageset/CheckDisabledLight.png -------------------------------------------------------------------------------- /Fluor/Assets.xcassets/CheckDisabled.imageset/CheckDisabledLight@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Pyroh/Fluor/6b5fcd11324dfe99ef0fb20d4015625a0e96f283/Fluor/Assets.xcassets/CheckDisabled.imageset/CheckDisabledLight@2x.png -------------------------------------------------------------------------------- /Fluor/Assets.xcassets/CheckDisabled.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "mac", 5 | "filename" : "CheckDisabledLight.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "mac", 10 | "filename" : "CheckDisabledDark.png", 11 | "appearances" : [ 12 | { 13 | "appearance" : "luminosity", 14 | "value" : "dark" 15 | } 16 | ], 17 | "scale" : "1x" 18 | }, 19 | { 20 | "idiom" : "mac", 21 | "filename" : "CheckDisabledLight@2x.png", 22 | "scale" : "2x" 23 | }, 24 | { 25 | "idiom" : "mac", 26 | "filename" : "CheckDisabledDark@2x.png", 27 | "appearances" : [ 28 | { 29 | "appearance" : "luminosity", 30 | "value" : "dark" 31 | } 32 | ], 33 | "scale" : "2x" 34 | } 35 | ], 36 | "info" : { 37 | "version" : 1, 38 | "author" : "xcode" 39 | }, 40 | "properties" : { 41 | "template-rendering-intent" : "template" 42 | } 43 | } -------------------------------------------------------------------------------- /Fluor/Assets.xcassets/CheckEnabled.imageset/CheckEnabledDark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Pyroh/Fluor/6b5fcd11324dfe99ef0fb20d4015625a0e96f283/Fluor/Assets.xcassets/CheckEnabled.imageset/CheckEnabledDark.png -------------------------------------------------------------------------------- /Fluor/Assets.xcassets/CheckEnabled.imageset/CheckEnabledDark@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Pyroh/Fluor/6b5fcd11324dfe99ef0fb20d4015625a0e96f283/Fluor/Assets.xcassets/CheckEnabled.imageset/CheckEnabledDark@2x.png -------------------------------------------------------------------------------- /Fluor/Assets.xcassets/CheckEnabled.imageset/CheckEnabledLight.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Pyroh/Fluor/6b5fcd11324dfe99ef0fb20d4015625a0e96f283/Fluor/Assets.xcassets/CheckEnabled.imageset/CheckEnabledLight.png -------------------------------------------------------------------------------- /Fluor/Assets.xcassets/CheckEnabled.imageset/CheckEnabledLight@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Pyroh/Fluor/6b5fcd11324dfe99ef0fb20d4015625a0e96f283/Fluor/Assets.xcassets/CheckEnabled.imageset/CheckEnabledLight@2x.png -------------------------------------------------------------------------------- /Fluor/Assets.xcassets/CheckEnabled.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "mac", 5 | "filename" : "CheckEnabledLight.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "mac", 10 | "filename" : "CheckEnabledDark.png", 11 | "appearances" : [ 12 | { 13 | "appearance" : "luminosity", 14 | "value" : "dark" 15 | } 16 | ], 17 | "scale" : "1x" 18 | }, 19 | { 20 | "idiom" : "mac", 21 | "filename" : "CheckEnabledLight@2x.png", 22 | "scale" : "2x" 23 | }, 24 | { 25 | "idiom" : "mac", 26 | "filename" : "CheckEnabledDark@2x.png", 27 | "appearances" : [ 28 | { 29 | "appearance" : "luminosity", 30 | "value" : "dark" 31 | } 32 | ], 33 | "scale" : "2x" 34 | } 35 | ], 36 | "info" : { 37 | "version" : 1, 38 | "author" : "xcode" 39 | }, 40 | "properties" : { 41 | "template-rendering-intent" : "template" 42 | } 43 | } -------------------------------------------------------------------------------- /Fluor/Assets.xcassets/CheckMixed.imageset/CheckMixedDark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Pyroh/Fluor/6b5fcd11324dfe99ef0fb20d4015625a0e96f283/Fluor/Assets.xcassets/CheckMixed.imageset/CheckMixedDark.png -------------------------------------------------------------------------------- /Fluor/Assets.xcassets/CheckMixed.imageset/CheckMixedDark@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Pyroh/Fluor/6b5fcd11324dfe99ef0fb20d4015625a0e96f283/Fluor/Assets.xcassets/CheckMixed.imageset/CheckMixedDark@2x.png -------------------------------------------------------------------------------- /Fluor/Assets.xcassets/CheckMixed.imageset/CheckMixedLight.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Pyroh/Fluor/6b5fcd11324dfe99ef0fb20d4015625a0e96f283/Fluor/Assets.xcassets/CheckMixed.imageset/CheckMixedLight.png -------------------------------------------------------------------------------- /Fluor/Assets.xcassets/CheckMixed.imageset/CheckMixedLight@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Pyroh/Fluor/6b5fcd11324dfe99ef0fb20d4015625a0e96f283/Fluor/Assets.xcassets/CheckMixed.imageset/CheckMixedLight@2x.png -------------------------------------------------------------------------------- /Fluor/Assets.xcassets/CheckMixed.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "mac", 5 | "filename" : "CheckMixedLight.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "mac", 10 | "filename" : "CheckMixedDark.png", 11 | "appearances" : [ 12 | { 13 | "appearance" : "luminosity", 14 | "value" : "dark" 15 | } 16 | ], 17 | "scale" : "1x" 18 | }, 19 | { 20 | "idiom" : "mac", 21 | "filename" : "CheckMixedLight@2x.png", 22 | "scale" : "2x" 23 | }, 24 | { 25 | "idiom" : "mac", 26 | "filename" : "CheckMixedDark@2x.png", 27 | "appearances" : [ 28 | { 29 | "appearance" : "luminosity", 30 | "value" : "dark" 31 | } 32 | ], 33 | "scale" : "2x" 34 | } 35 | ], 36 | "info" : { 37 | "version" : 1, 38 | "author" : "xcode" 39 | }, 40 | "properties" : { 41 | "template-rendering-intent" : "template" 42 | } 43 | } -------------------------------------------------------------------------------- /Fluor/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } -------------------------------------------------------------------------------- /Fluor/Assets.xcassets/Cross.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "CrossLight.png", 5 | "idiom" : "universal", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "appearances" : [ 10 | { 11 | "appearance" : "luminosity", 12 | "value" : "dark" 13 | } 14 | ], 15 | "filename" : "CrossDark.png", 16 | "idiom" : "universal", 17 | "scale" : "1x" 18 | }, 19 | { 20 | "filename" : "CrossLight@2x.png", 21 | "idiom" : "universal", 22 | "scale" : "2x" 23 | }, 24 | { 25 | "appearances" : [ 26 | { 27 | "appearance" : "luminosity", 28 | "value" : "dark" 29 | } 30 | ], 31 | "filename" : "CrossDark@2x.png", 32 | "idiom" : "universal", 33 | "scale" : "2x" 34 | }, 35 | { 36 | "idiom" : "universal", 37 | "scale" : "3x" 38 | }, 39 | { 40 | "appearances" : [ 41 | { 42 | "appearance" : "luminosity", 43 | "value" : "dark" 44 | } 45 | ], 46 | "idiom" : "universal", 47 | "scale" : "3x" 48 | } 49 | ], 50 | "info" : { 51 | "author" : "xcode", 52 | "version" : 1 53 | }, 54 | "properties" : { 55 | "template-rendering-intent" : "template" 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /Fluor/Assets.xcassets/Cross.imageset/CrossDark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Pyroh/Fluor/6b5fcd11324dfe99ef0fb20d4015625a0e96f283/Fluor/Assets.xcassets/Cross.imageset/CrossDark.png -------------------------------------------------------------------------------- /Fluor/Assets.xcassets/Cross.imageset/CrossDark@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Pyroh/Fluor/6b5fcd11324dfe99ef0fb20d4015625a0e96f283/Fluor/Assets.xcassets/Cross.imageset/CrossDark@2x.png -------------------------------------------------------------------------------- /Fluor/Assets.xcassets/Cross.imageset/CrossLight.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Pyroh/Fluor/6b5fcd11324dfe99ef0fb20d4015625a0e96f283/Fluor/Assets.xcassets/Cross.imageset/CrossLight.png -------------------------------------------------------------------------------- /Fluor/Assets.xcassets/Cross.imageset/CrossLight@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Pyroh/Fluor/6b5fcd11324dfe99ef0fb20d4015625a0e96f283/Fluor/Assets.xcassets/Cross.imageset/CrossLight@2x.png -------------------------------------------------------------------------------- /Fluor/Assets.xcassets/DefaultMode.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "mac", 5 | "filename" : "DefaultModeLight.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "mac", 10 | "filename" : "DefaultModeDark.png", 11 | "appearances" : [ 12 | { 13 | "appearance" : "luminosity", 14 | "value" : "dark" 15 | } 16 | ], 17 | "scale" : "1x" 18 | }, 19 | { 20 | "idiom" : "mac", 21 | "filename" : "DefaultModeLight@2x.png", 22 | "scale" : "2x" 23 | }, 24 | { 25 | "idiom" : "mac", 26 | "filename" : "DefaultModeDark@2x.png", 27 | "appearances" : [ 28 | { 29 | "appearance" : "luminosity", 30 | "value" : "dark" 31 | } 32 | ], 33 | "scale" : "2x" 34 | } 35 | ], 36 | "info" : { 37 | "version" : 1, 38 | "author" : "xcode" 39 | }, 40 | "properties" : { 41 | "template-rendering-intent" : "template" 42 | } 43 | } -------------------------------------------------------------------------------- /Fluor/Assets.xcassets/DefaultMode.imageset/DefaultModeDark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Pyroh/Fluor/6b5fcd11324dfe99ef0fb20d4015625a0e96f283/Fluor/Assets.xcassets/DefaultMode.imageset/DefaultModeDark.png -------------------------------------------------------------------------------- /Fluor/Assets.xcassets/DefaultMode.imageset/DefaultModeDark@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Pyroh/Fluor/6b5fcd11324dfe99ef0fb20d4015625a0e96f283/Fluor/Assets.xcassets/DefaultMode.imageset/DefaultModeDark@2x.png -------------------------------------------------------------------------------- /Fluor/Assets.xcassets/DefaultMode.imageset/DefaultModeLight.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Pyroh/Fluor/6b5fcd11324dfe99ef0fb20d4015625a0e96f283/Fluor/Assets.xcassets/DefaultMode.imageset/DefaultModeLight.png -------------------------------------------------------------------------------- /Fluor/Assets.xcassets/DefaultMode.imageset/DefaultModeLight@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Pyroh/Fluor/6b5fcd11324dfe99ef0fb20d4015625a0e96f283/Fluor/Assets.xcassets/DefaultMode.imageset/DefaultModeLight@2x.png -------------------------------------------------------------------------------- /Fluor/Assets.xcassets/DoubleArrowForward.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "DoubleArrowButtonLight.png", 5 | "idiom" : "universal", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "appearances" : [ 10 | { 11 | "appearance" : "luminosity", 12 | "value" : "dark" 13 | } 14 | ], 15 | "filename" : "DoubleArrowButtonDark.png", 16 | "idiom" : "universal", 17 | "scale" : "1x" 18 | }, 19 | { 20 | "filename" : "DoubleArrowButtonLight@2x.png", 21 | "idiom" : "universal", 22 | "scale" : "2x" 23 | }, 24 | { 25 | "appearances" : [ 26 | { 27 | "appearance" : "luminosity", 28 | "value" : "dark" 29 | } 30 | ], 31 | "filename" : "DoubleArrowButtonDark@2x.png", 32 | "idiom" : "universal", 33 | "scale" : "2x" 34 | }, 35 | { 36 | "idiom" : "universal", 37 | "scale" : "3x" 38 | }, 39 | { 40 | "appearances" : [ 41 | { 42 | "appearance" : "luminosity", 43 | "value" : "dark" 44 | } 45 | ], 46 | "idiom" : "universal", 47 | "scale" : "3x" 48 | } 49 | ], 50 | "info" : { 51 | "author" : "xcode", 52 | "version" : 1 53 | }, 54 | "properties" : { 55 | "template-rendering-intent" : "template" 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /Fluor/Assets.xcassets/DoubleArrowForward.imageset/DoubleArrowButtonDark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Pyroh/Fluor/6b5fcd11324dfe99ef0fb20d4015625a0e96f283/Fluor/Assets.xcassets/DoubleArrowForward.imageset/DoubleArrowButtonDark.png -------------------------------------------------------------------------------- /Fluor/Assets.xcassets/DoubleArrowForward.imageset/DoubleArrowButtonDark@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Pyroh/Fluor/6b5fcd11324dfe99ef0fb20d4015625a0e96f283/Fluor/Assets.xcassets/DoubleArrowForward.imageset/DoubleArrowButtonDark@2x.png -------------------------------------------------------------------------------- /Fluor/Assets.xcassets/DoubleArrowForward.imageset/DoubleArrowButtonLight.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Pyroh/Fluor/6b5fcd11324dfe99ef0fb20d4015625a0e96f283/Fluor/Assets.xcassets/DoubleArrowForward.imageset/DoubleArrowButtonLight.png -------------------------------------------------------------------------------- /Fluor/Assets.xcassets/DoubleArrowForward.imageset/DoubleArrowButtonLight@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Pyroh/Fluor/6b5fcd11324dfe99ef0fb20d4015625a0e96f283/Fluor/Assets.xcassets/DoubleArrowForward.imageset/DoubleArrowButtonLight@2x.png -------------------------------------------------------------------------------- /Fluor/Assets.xcassets/FluorBlue.colorset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "colors" : [ 3 | { 4 | "color" : { 5 | "color-space" : "srgb", 6 | "components" : { 7 | "alpha" : "1.000", 8 | "blue" : "0.635", 9 | "green" : "0.447", 10 | "red" : "0.282" 11 | } 12 | }, 13 | "idiom" : "universal" 14 | } 15 | ], 16 | "info" : { 17 | "author" : "xcode", 18 | "version" : 1 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /Fluor/Assets.xcassets/FluorRed.colorset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "colors" : [ 3 | { 4 | "color" : { 5 | "color-space" : "srgb", 6 | "components" : { 7 | "alpha" : "1.000", 8 | "blue" : "0.374", 9 | "green" : "0.317", 10 | "red" : "0.961" 11 | } 12 | }, 13 | "idiom" : "universal" 14 | } 15 | ], 16 | "info" : { 17 | "author" : "xcode", 18 | "version" : 1 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /Fluor/Assets.xcassets/FnKey.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "mac", 5 | "filename" : "FnKeyLight.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "mac", 10 | "filename" : "FnKeyDark.png", 11 | "appearances" : [ 12 | { 13 | "appearance" : "luminosity", 14 | "value" : "dark" 15 | } 16 | ], 17 | "scale" : "1x" 18 | }, 19 | { 20 | "idiom" : "mac", 21 | "filename" : "FnKeyLight@2x.png", 22 | "scale" : "2x" 23 | }, 24 | { 25 | "idiom" : "mac", 26 | "filename" : "FnKeyDark@2x.png", 27 | "appearances" : [ 28 | { 29 | "appearance" : "luminosity", 30 | "value" : "dark" 31 | } 32 | ], 33 | "scale" : "2x" 34 | } 35 | ], 36 | "info" : { 37 | "version" : 1, 38 | "author" : "xcode" 39 | }, 40 | "properties" : { 41 | "template-rendering-intent" : "template" 42 | } 43 | } -------------------------------------------------------------------------------- /Fluor/Assets.xcassets/FnKey.imageset/FnKeyDark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Pyroh/Fluor/6b5fcd11324dfe99ef0fb20d4015625a0e96f283/Fluor/Assets.xcassets/FnKey.imageset/FnKeyDark.png -------------------------------------------------------------------------------- /Fluor/Assets.xcassets/FnKey.imageset/FnKeyDark@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Pyroh/Fluor/6b5fcd11324dfe99ef0fb20d4015625a0e96f283/Fluor/Assets.xcassets/FnKey.imageset/FnKeyDark@2x.png -------------------------------------------------------------------------------- /Fluor/Assets.xcassets/FnKey.imageset/FnKeyLight.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Pyroh/Fluor/6b5fcd11324dfe99ef0fb20d4015625a0e96f283/Fluor/Assets.xcassets/FnKey.imageset/FnKeyLight.png -------------------------------------------------------------------------------- /Fluor/Assets.xcassets/FnKey.imageset/FnKeyLight@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Pyroh/Fluor/6b5fcd11324dfe99ef0fb20d4015625a0e96f283/Fluor/Assets.xcassets/FnKey.imageset/FnKeyLight@2x.png -------------------------------------------------------------------------------- /Fluor/Assets.xcassets/IconAppleMode.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "mac", 5 | "filename" : "IconAppleMode.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "mac", 10 | "filename" : "IconAppleMode@2x.png", 11 | "scale" : "2x" 12 | } 13 | ], 14 | "info" : { 15 | "version" : 1, 16 | "author" : "xcode" 17 | }, 18 | "properties" : { 19 | "template-rendering-intent" : "template" 20 | } 21 | } -------------------------------------------------------------------------------- /Fluor/Assets.xcassets/IconAppleMode.imageset/IconAppleMode.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Pyroh/Fluor/6b5fcd11324dfe99ef0fb20d4015625a0e96f283/Fluor/Assets.xcassets/IconAppleMode.imageset/IconAppleMode.png -------------------------------------------------------------------------------- /Fluor/Assets.xcassets/IconAppleMode.imageset/IconAppleMode@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Pyroh/Fluor/6b5fcd11324dfe99ef0fb20d4015625a0e96f283/Fluor/Assets.xcassets/IconAppleMode.imageset/IconAppleMode@2x.png -------------------------------------------------------------------------------- /Fluor/Assets.xcassets/IconDisabled.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "mac", 5 | "filename" : "IconDisabled.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "mac", 10 | "filename" : "IconDisabled@2x.png", 11 | "scale" : "2x" 12 | } 13 | ], 14 | "info" : { 15 | "version" : 1, 16 | "author" : "xcode" 17 | }, 18 | "properties" : { 19 | "template-rendering-intent" : "template" 20 | } 21 | } -------------------------------------------------------------------------------- /Fluor/Assets.xcassets/IconDisabled.imageset/IconDisabled.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Pyroh/Fluor/6b5fcd11324dfe99ef0fb20d4015625a0e96f283/Fluor/Assets.xcassets/IconDisabled.imageset/IconDisabled.png -------------------------------------------------------------------------------- /Fluor/Assets.xcassets/IconDisabled.imageset/IconDisabled@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Pyroh/Fluor/6b5fcd11324dfe99ef0fb20d4015625a0e96f283/Fluor/Assets.xcassets/IconDisabled.imageset/IconDisabled@2x.png -------------------------------------------------------------------------------- /Fluor/Assets.xcassets/IconOtherMode.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "mac", 5 | "filename" : "IconOtherMode.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "mac", 10 | "filename" : "IconOtherMode@2x.png", 11 | "scale" : "2x" 12 | } 13 | ], 14 | "info" : { 15 | "version" : 1, 16 | "author" : "xcode" 17 | }, 18 | "properties" : { 19 | "template-rendering-intent" : "template" 20 | } 21 | } -------------------------------------------------------------------------------- /Fluor/Assets.xcassets/IconOtherMode.imageset/IconOtherMode.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Pyroh/Fluor/6b5fcd11324dfe99ef0fb20d4015625a0e96f283/Fluor/Assets.xcassets/IconOtherMode.imageset/IconOtherMode.png -------------------------------------------------------------------------------- /Fluor/Assets.xcassets/IconOtherMode.imageset/IconOtherMode@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Pyroh/Fluor/6b5fcd11324dfe99ef0fb20d4015625a0e96f283/Fluor/Assets.xcassets/IconOtherMode.imageset/IconOtherMode@2x.png -------------------------------------------------------------------------------- /Fluor/Assets.xcassets/LighIconDisabled.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "mac", 5 | "filename" : "LighIconDisabled.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "mac", 10 | "filename" : "LighIconDisabled@2x.png", 11 | "scale" : "2x" 12 | } 13 | ], 14 | "info" : { 15 | "version" : 1, 16 | "author" : "xcode" 17 | }, 18 | "properties" : { 19 | "template-rendering-intent" : "template" 20 | } 21 | } -------------------------------------------------------------------------------- /Fluor/Assets.xcassets/LighIconDisabled.imageset/LighIconDisabled.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Pyroh/Fluor/6b5fcd11324dfe99ef0fb20d4015625a0e96f283/Fluor/Assets.xcassets/LighIconDisabled.imageset/LighIconDisabled.png -------------------------------------------------------------------------------- /Fluor/Assets.xcassets/LighIconDisabled.imageset/LighIconDisabled@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Pyroh/Fluor/6b5fcd11324dfe99ef0fb20d4015625a0e96f283/Fluor/Assets.xcassets/LighIconDisabled.imageset/LighIconDisabled@2x.png -------------------------------------------------------------------------------- /Fluor/Assets.xcassets/MixedSwitch.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "mac", 5 | "filename" : "MixedSwitchLight.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "mac", 10 | "filename" : "MixedSwitchDark.png", 11 | "appearances" : [ 12 | { 13 | "appearance" : "luminosity", 14 | "value" : "dark" 15 | } 16 | ], 17 | "scale" : "1x" 18 | }, 19 | { 20 | "idiom" : "mac", 21 | "filename" : "MixedSwitchLight@2x.png", 22 | "scale" : "2x" 23 | }, 24 | { 25 | "idiom" : "mac", 26 | "filename" : "MixedSwitchDark@2x.png", 27 | "appearances" : [ 28 | { 29 | "appearance" : "luminosity", 30 | "value" : "dark" 31 | } 32 | ], 33 | "scale" : "2x" 34 | } 35 | ], 36 | "info" : { 37 | "version" : 1, 38 | "author" : "xcode" 39 | } 40 | } -------------------------------------------------------------------------------- /Fluor/Assets.xcassets/MixedSwitch.imageset/MixedSwitchDark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Pyroh/Fluor/6b5fcd11324dfe99ef0fb20d4015625a0e96f283/Fluor/Assets.xcassets/MixedSwitch.imageset/MixedSwitchDark.png -------------------------------------------------------------------------------- /Fluor/Assets.xcassets/MixedSwitch.imageset/MixedSwitchDark@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Pyroh/Fluor/6b5fcd11324dfe99ef0fb20d4015625a0e96f283/Fluor/Assets.xcassets/MixedSwitch.imageset/MixedSwitchDark@2x.png -------------------------------------------------------------------------------- /Fluor/Assets.xcassets/MixedSwitch.imageset/MixedSwitchLight.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Pyroh/Fluor/6b5fcd11324dfe99ef0fb20d4015625a0e96f283/Fluor/Assets.xcassets/MixedSwitch.imageset/MixedSwitchLight.png -------------------------------------------------------------------------------- /Fluor/Assets.xcassets/MixedSwitch.imageset/MixedSwitchLight@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Pyroh/Fluor/6b5fcd11324dfe99ef0fb20d4015625a0e96f283/Fluor/Assets.xcassets/MixedSwitch.imageset/MixedSwitchLight@2x.png -------------------------------------------------------------------------------- /Fluor/Assets.xcassets/OtherMode.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "mac", 5 | "filename" : "OtherMode.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "mac", 10 | "filename" : "OtherMode@2x.png", 11 | "scale" : "2x" 12 | } 13 | ], 14 | "info" : { 15 | "version" : 1, 16 | "author" : "xcode" 17 | }, 18 | "properties" : { 19 | "template-rendering-intent" : "template" 20 | } 21 | } -------------------------------------------------------------------------------- /Fluor/Assets.xcassets/OtherMode.imageset/OtherMode.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Pyroh/Fluor/6b5fcd11324dfe99ef0fb20d4015625a0e96f283/Fluor/Assets.xcassets/OtherMode.imageset/OtherMode.png -------------------------------------------------------------------------------- /Fluor/Assets.xcassets/OtherMode.imageset/OtherMode@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Pyroh/Fluor/6b5fcd11324dfe99ef0fb20d4015625a0e96f283/Fluor/Assets.xcassets/OtherMode.imageset/OtherMode@2x.png -------------------------------------------------------------------------------- /Fluor/Assets.xcassets/Preferences.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "mac", 5 | "filename" : "PreferencesLight.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "mac", 10 | "filename" : "PreferencesDark.png", 11 | "appearances" : [ 12 | { 13 | "appearance" : "luminosity", 14 | "value" : "dark" 15 | } 16 | ], 17 | "scale" : "1x" 18 | }, 19 | { 20 | "idiom" : "mac", 21 | "filename" : "PreferencesLight@2x.png", 22 | "scale" : "2x" 23 | }, 24 | { 25 | "idiom" : "mac", 26 | "filename" : "PreferencesDark@2x.png", 27 | "appearances" : [ 28 | { 29 | "appearance" : "luminosity", 30 | "value" : "dark" 31 | } 32 | ], 33 | "scale" : "2x" 34 | } 35 | ], 36 | "info" : { 37 | "version" : 1, 38 | "author" : "xcode" 39 | }, 40 | "properties" : { 41 | "template-rendering-intent" : "template" 42 | } 43 | } -------------------------------------------------------------------------------- /Fluor/Assets.xcassets/Preferences.imageset/PreferencesDark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Pyroh/Fluor/6b5fcd11324dfe99ef0fb20d4015625a0e96f283/Fluor/Assets.xcassets/Preferences.imageset/PreferencesDark.png -------------------------------------------------------------------------------- /Fluor/Assets.xcassets/Preferences.imageset/PreferencesDark@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Pyroh/Fluor/6b5fcd11324dfe99ef0fb20d4015625a0e96f283/Fluor/Assets.xcassets/Preferences.imageset/PreferencesDark@2x.png -------------------------------------------------------------------------------- /Fluor/Assets.xcassets/Preferences.imageset/PreferencesLight.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Pyroh/Fluor/6b5fcd11324dfe99ef0fb20d4015625a0e96f283/Fluor/Assets.xcassets/Preferences.imageset/PreferencesLight.png -------------------------------------------------------------------------------- /Fluor/Assets.xcassets/Preferences.imageset/PreferencesLight@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Pyroh/Fluor/6b5fcd11324dfe99ef0fb20d4015625a0e96f283/Fluor/Assets.xcassets/Preferences.imageset/PreferencesLight@2x.png -------------------------------------------------------------------------------- /Fluor/Assets.xcassets/QuestionMark.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "QuestionMark.png", 5 | "idiom" : "mac", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "filename" : "QuestionMark@2x.png", 10 | "idiom" : "mac", 11 | "scale" : "2x" 12 | } 13 | ], 14 | "info" : { 15 | "author" : "xcode", 16 | "version" : 1 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /Fluor/Assets.xcassets/QuestionMark.imageset/QuestionMark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Pyroh/Fluor/6b5fcd11324dfe99ef0fb20d4015625a0e96f283/Fluor/Assets.xcassets/QuestionMark.imageset/QuestionMark.png -------------------------------------------------------------------------------- /Fluor/Assets.xcassets/QuestionMark.imageset/QuestionMark@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Pyroh/Fluor/6b5fcd11324dfe99ef0fb20d4015625a0e96f283/Fluor/Assets.xcassets/QuestionMark.imageset/QuestionMark@2x.png -------------------------------------------------------------------------------- /Fluor/Assets.xcassets/Quit.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "mac", 5 | "filename" : "Quit.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "mac", 10 | "filename" : "Quit@2x.png", 11 | "scale" : "2x" 12 | } 13 | ], 14 | "info" : { 15 | "version" : 1, 16 | "author" : "xcode" 17 | }, 18 | "properties" : { 19 | "template-rendering-intent" : "template" 20 | } 21 | } -------------------------------------------------------------------------------- /Fluor/Assets.xcassets/Quit.imageset/Quit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Pyroh/Fluor/6b5fcd11324dfe99ef0fb20d4015625a0e96f283/Fluor/Assets.xcassets/Quit.imageset/Quit.png -------------------------------------------------------------------------------- /Fluor/Assets.xcassets/Quit.imageset/Quit@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Pyroh/Fluor/6b5fcd11324dfe99ef0fb20d4015625a0e96f283/Fluor/Assets.xcassets/Quit.imageset/Quit@2x.png -------------------------------------------------------------------------------- /Fluor/Assets.xcassets/Rules.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "mac", 5 | "filename" : "RulesLight.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "mac", 10 | "filename" : "RulesDark.png", 11 | "appearances" : [ 12 | { 13 | "appearance" : "luminosity", 14 | "value" : "dark" 15 | } 16 | ], 17 | "scale" : "1x" 18 | }, 19 | { 20 | "idiom" : "mac", 21 | "filename" : "RulesLight@2x.png", 22 | "scale" : "2x" 23 | }, 24 | { 25 | "idiom" : "mac", 26 | "filename" : "RulesDark@2x.png", 27 | "appearances" : [ 28 | { 29 | "appearance" : "luminosity", 30 | "value" : "dark" 31 | } 32 | ], 33 | "scale" : "2x" 34 | } 35 | ], 36 | "info" : { 37 | "version" : 1, 38 | "author" : "xcode" 39 | }, 40 | "properties" : { 41 | "template-rendering-intent" : "template" 42 | } 43 | } -------------------------------------------------------------------------------- /Fluor/Assets.xcassets/Rules.imageset/RulesDark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Pyroh/Fluor/6b5fcd11324dfe99ef0fb20d4015625a0e96f283/Fluor/Assets.xcassets/Rules.imageset/RulesDark.png -------------------------------------------------------------------------------- /Fluor/Assets.xcassets/Rules.imageset/RulesDark@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Pyroh/Fluor/6b5fcd11324dfe99ef0fb20d4015625a0e96f283/Fluor/Assets.xcassets/Rules.imageset/RulesDark@2x.png -------------------------------------------------------------------------------- /Fluor/Assets.xcassets/Rules.imageset/RulesLight.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Pyroh/Fluor/6b5fcd11324dfe99ef0fb20d4015625a0e96f283/Fluor/Assets.xcassets/Rules.imageset/RulesLight.png -------------------------------------------------------------------------------- /Fluor/Assets.xcassets/Rules.imageset/RulesLight@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Pyroh/Fluor/6b5fcd11324dfe99ef0fb20d4015625a0e96f283/Fluor/Assets.xcassets/Rules.imageset/RulesLight@2x.png -------------------------------------------------------------------------------- /Fluor/Assets.xcassets/RunningApps.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "mac", 5 | "filename" : "RunningAppsLight.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "mac", 10 | "filename" : "RunningAppsDark.png", 11 | "appearances" : [ 12 | { 13 | "appearance" : "luminosity", 14 | "value" : "dark" 15 | } 16 | ], 17 | "scale" : "1x" 18 | }, 19 | { 20 | "idiom" : "mac", 21 | "filename" : "RunningAppsLight@2x.png", 22 | "scale" : "2x" 23 | }, 24 | { 25 | "idiom" : "mac", 26 | "filename" : "RunningAppsDark@2x.png", 27 | "appearances" : [ 28 | { 29 | "appearance" : "luminosity", 30 | "value" : "dark" 31 | } 32 | ], 33 | "scale" : "2x" 34 | } 35 | ], 36 | "info" : { 37 | "version" : 1, 38 | "author" : "xcode" 39 | }, 40 | "properties" : { 41 | "template-rendering-intent" : "template" 42 | } 43 | } -------------------------------------------------------------------------------- /Fluor/Assets.xcassets/RunningApps.imageset/RunningAppsDark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Pyroh/Fluor/6b5fcd11324dfe99ef0fb20d4015625a0e96f283/Fluor/Assets.xcassets/RunningApps.imageset/RunningAppsDark.png -------------------------------------------------------------------------------- /Fluor/Assets.xcassets/RunningApps.imageset/RunningAppsDark@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Pyroh/Fluor/6b5fcd11324dfe99ef0fb20d4015625a0e96f283/Fluor/Assets.xcassets/RunningApps.imageset/RunningAppsDark@2x.png -------------------------------------------------------------------------------- /Fluor/Assets.xcassets/RunningApps.imageset/RunningAppsLight.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Pyroh/Fluor/6b5fcd11324dfe99ef0fb20d4015625a0e96f283/Fluor/Assets.xcassets/RunningApps.imageset/RunningAppsLight.png -------------------------------------------------------------------------------- /Fluor/Assets.xcassets/RunningApps.imageset/RunningAppsLight@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Pyroh/Fluor/6b5fcd11324dfe99ef0fb20d4015625a0e96f283/Fluor/Assets.xcassets/RunningApps.imageset/RunningAppsLight@2x.png -------------------------------------------------------------------------------- /Fluor/Assets.xcassets/Service.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "ServiceLight.png", 5 | "idiom" : "mac", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "appearances" : [ 10 | { 11 | "appearance" : "luminosity", 12 | "value" : "dark" 13 | } 14 | ], 15 | "filename" : "ServiceDark.png", 16 | "idiom" : "mac", 17 | "scale" : "1x" 18 | }, 19 | { 20 | "filename" : "ServiceLight@2x.png", 21 | "idiom" : "mac", 22 | "scale" : "2x" 23 | }, 24 | { 25 | "appearances" : [ 26 | { 27 | "appearance" : "luminosity", 28 | "value" : "dark" 29 | } 30 | ], 31 | "filename" : "ServiceDark@2x.png", 32 | "idiom" : "mac", 33 | "scale" : "2x" 34 | } 35 | ], 36 | "info" : { 37 | "author" : "xcode", 38 | "version" : 1 39 | }, 40 | "properties" : { 41 | "template-rendering-intent" : "template" 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /Fluor/Assets.xcassets/Service.imageset/ServiceDark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Pyroh/Fluor/6b5fcd11324dfe99ef0fb20d4015625a0e96f283/Fluor/Assets.xcassets/Service.imageset/ServiceDark.png -------------------------------------------------------------------------------- /Fluor/Assets.xcassets/Service.imageset/ServiceDark@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Pyroh/Fluor/6b5fcd11324dfe99ef0fb20d4015625a0e96f283/Fluor/Assets.xcassets/Service.imageset/ServiceDark@2x.png -------------------------------------------------------------------------------- /Fluor/Assets.xcassets/Service.imageset/ServiceLight.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Pyroh/Fluor/6b5fcd11324dfe99ef0fb20d4015625a0e96f283/Fluor/Assets.xcassets/Service.imageset/ServiceLight.png -------------------------------------------------------------------------------- /Fluor/Assets.xcassets/Service.imageset/ServiceLight@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Pyroh/Fluor/6b5fcd11324dfe99ef0fb20d4015625a0e96f283/Fluor/Assets.xcassets/Service.imageset/ServiceLight@2x.png -------------------------------------------------------------------------------- /Fluor/Base.lproj/Main.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /Fluor/Controllers/LaunchAtLoginController.h: -------------------------------------------------------------------------------- 1 | // 2 | // LaunchAtLoginController.h 3 | // 4 | // Copyright 2011 Tomáš Znamenáček 5 | // Copyright 2010 Ben Clark-Robinson 6 | // 7 | // Permission is hereby granted, free of charge, to any person obtaining 8 | // a copy of this software and associated documentation files (the ‘Software’), 9 | // to deal in the Software without restriction, including without limitation 10 | // the rights to use, copy, modify, merge, publish, distribute, sublicense, 11 | // and/or sell copies of the Software, and to permit persons to whom the 12 | // Software is furnished to do so, subject to the following conditions: 13 | // 14 | // The above copyright notice and this permission notice shall be 15 | // included in all copies or substantial portions of the Software. 16 | // 17 | // THE SOFTWARE IS PROVIDED ‘AS IS’, WITHOUT WARRANTY OF ANY KIND, 18 | // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 19 | // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 20 | // IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 21 | // CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 22 | // TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 23 | // SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 24 | 25 | @import Foundation; 26 | @import CoreServices; 27 | 28 | @interface LaunchAtLoginController : NSObject {} 29 | 30 | @property(assign) BOOL launchAtLogin; 31 | 32 | - (BOOL) willLaunchAtLogin: (NSURL*) itemURL; 33 | - (void) setLaunchAtLogin: (BOOL) enabled forURL: (NSURL*) itemURL; 34 | 35 | @end 36 | -------------------------------------------------------------------------------- /Fluor/Controllers/LaunchAtLoginController.m: -------------------------------------------------------------------------------- 1 | // 2 | // LaunchAtLoginController.m 3 | // 4 | // Copyright 2011 Tomáš Znamenáček 5 | // Copyright 2010 Ben Clark-Robinson 6 | // 7 | // Permission is hereby granted, free of charge, to any person obtaining 8 | // a copy of this software and associated documentation files (the ‘Software’), 9 | // to deal in the Software without restriction, including without limitation 10 | // the rights to use, copy, modify, merge, publish, distribute, sublicense, 11 | // and/or sell copies of the Software, and to permit persons to whom the 12 | // Software is furnished to do so, subject to the following conditions: 13 | // 14 | // The above copyright notice and this permission notice shall be 15 | // included in all copies or substantial portions of the Software. 16 | // 17 | // THE SOFTWARE IS PROVIDED ‘AS IS’, WITHOUT WARRANTY OF ANY KIND, 18 | // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 19 | // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 20 | // IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 21 | // CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 22 | // TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 23 | // SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 24 | 25 | #import "LaunchAtLoginController.h" 26 | 27 | #pragma clang diagnostic push 28 | #pragma clang diagnostic ignored "-Wdeprecated-declarations" 29 | 30 | static NSString *const StartAtLoginKey = @"launchAtLogin"; 31 | 32 | @interface LaunchAtLoginController () 33 | @property(assign) LSSharedFileListRef loginItems; 34 | @end 35 | 36 | @implementation LaunchAtLoginController 37 | @synthesize loginItems; 38 | 39 | #pragma mark Change Observing 40 | 41 | void sharedFileListDidChange(LSSharedFileListRef inList, void *context) 42 | { 43 | LaunchAtLoginController *self = (__bridge id) context; 44 | [self willChangeValueForKey:StartAtLoginKey]; 45 | [self didChangeValueForKey:StartAtLoginKey]; 46 | } 47 | 48 | #pragma mark Initialization 49 | 50 | - (id) init 51 | { 52 | self = [super init]; 53 | loginItems = LSSharedFileListCreate(NULL, kLSSharedFileListSessionLoginItems, NULL); 54 | LSSharedFileListAddObserver(loginItems, CFRunLoopGetMain(), 55 | (CFStringRef)NSDefaultRunLoopMode, sharedFileListDidChange, (voidPtr)CFBridgingRetain(self)); 56 | return self; 57 | } 58 | 59 | - (void) dealloc 60 | { 61 | LSSharedFileListRemoveObserver(loginItems, CFRunLoopGetMain(), 62 | (CFStringRef)NSDefaultRunLoopMode, sharedFileListDidChange, (__bridge void *)(self)); 63 | CFRelease(loginItems); 64 | } 65 | 66 | #pragma mark Launch List Control 67 | #pragma clang diagnostic push 68 | #pragma clang diagnostic ignored "-Wdeprecated-declarations" 69 | LSSharedFileListItemRef copyItemWithURLinFileList(NSURL* wantedURL, LSSharedFileListRef fileList) { 70 | if (wantedURL == NULL || fileList == NULL) 71 | return NULL; 72 | 73 | NSArray *listSnapshot = (__bridge_transfer NSArray *)LSSharedFileListCopySnapshot(fileList, NULL); 74 | for(NSUInteger i = 0; i< [listSnapshot count]; i++) { 75 | LSSharedFileListItemRef item = (__bridge LSSharedFileListItemRef)[listSnapshot objectAtIndex:i]; 76 | UInt32 resolutionFlags = kLSSharedFileListNoUserInteraction | kLSSharedFileListDoNotMountVolumes; 77 | CFURLRef currentItemURL = NULL; 78 | LSSharedFileListItemResolve(item, resolutionFlags, ¤tItemURL, NULL); 79 | if (currentItemURL && [(__bridge_transfer NSURL*)currentItemURL isEqual:wantedURL]) { 80 | CFRetain(item); 81 | return item; 82 | } 83 | } 84 | 85 | return NULL; 86 | } 87 | #pragma clang diagnostic pop 88 | 89 | - (BOOL) willLaunchAtLogin: (NSURL*) itemURL 90 | { 91 | return !!copyItemWithURLinFileList(itemURL, loginItems); 92 | } 93 | 94 | - (void) setLaunchAtLogin: (BOOL) enabled forURL: (NSURL*) itemURL 95 | { 96 | LSSharedFileListItemRef appItem = copyItemWithURLinFileList(itemURL, loginItems); 97 | if (enabled && !appItem) { 98 | LSSharedFileListInsertItemURL(loginItems, kLSSharedFileListItemBeforeFirst, 99 | NULL, NULL, (__bridge CFURLRef)itemURL, NULL, NULL); 100 | } else if (!enabled && appItem) { 101 | LSSharedFileListItemRemove(loginItems, appItem); 102 | } 103 | if (appItem) { 104 | CFRelease(appItem); 105 | } 106 | } 107 | 108 | #pragma mark Basic Interface 109 | 110 | - (NSURL*) appURL 111 | { 112 | return [NSURL fileURLWithPath:[[NSBundle mainBundle] bundlePath]]; 113 | } 114 | 115 | - (void) setLaunchAtLogin: (BOOL) enabled 116 | { 117 | [self willChangeValueForKey:StartAtLoginKey]; 118 | [self setLaunchAtLogin:enabled forURL:[self appURL]]; 119 | [self didChangeValueForKey:StartAtLoginKey]; 120 | } 121 | 122 | - (BOOL) launchAtLogin 123 | { 124 | return [self willLaunchAtLogin:[self appURL]]; 125 | } 126 | 127 | @end 128 | #pragma clang diagnostic pop 129 | -------------------------------------------------------------------------------- /Fluor/Controllers/MenuItemsController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // MenuItemsController.swift 3 | // 4 | // Fluor 5 | // 6 | // MIT License 7 | // 8 | // Copyright (c) 2020 Pierre Tacchi 9 | // 10 | // Permission is hereby granted, free of charge, to any person obtaining a copy 11 | // of this software and associated documentation files (the "Software"), to deal 12 | // in the Software without restriction, including without limitation the rights 13 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 14 | // copies of the Software, and to permit persons to whom the Software is 15 | // furnished to do so, subject to the following conditions: 16 | // 17 | // The above copyright notice and this permission notice shall be included in all 18 | // copies or substantial portions of the Software. 19 | // 20 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 21 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 22 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 23 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 24 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 25 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 26 | // SOFTWARE. 27 | // 28 | 29 | 30 | import Cocoa 31 | 32 | class MenuItemsController: NSObject, SwitchMethodDidChangeObserver, TriggerSectionVisibilityDidChangeObserver { 33 | @IBOutlet weak var menu: NSMenu! 34 | @IBOutlet var switchMethodViewController: SwitchMethodViewController! 35 | @IBOutlet var currentAppViewController: CurrentAppViewController! 36 | @IBOutlet weak var defaultModeViewController: DefaultModeViewController! 37 | 38 | override init() { 39 | super.init() 40 | self.startObservingSwitchMethodDidChange() 41 | self.startObservingTriggerSectionVisibilityDidChange() 42 | } 43 | 44 | deinit { 45 | self.stopObservingSwitchMethodDidChange() 46 | self.stopObservingTriggerSectionVisibilityDidChange() 47 | } 48 | 49 | func setupController() { 50 | let switchingPlaceHolder = menu.item(withTag: 1) 51 | let statePlaceHolder = menu.item(withTag: 3) 52 | let currentPlaceHolder = menu.item(withTag: 5) 53 | switchingPlaceHolder?.view = switchMethodViewController.view 54 | statePlaceHolder?.view = defaultModeViewController.view 55 | currentPlaceHolder?.view = currentAppViewController.view 56 | if case SwitchMethod.key = AppManager.default.switchMethod { 57 | currentAppViewController.shrinkView() 58 | } 59 | } 60 | 61 | // MARK: - SwitchMethodDidChangeObserver 62 | 63 | func switchMethodDidChange(notification: Notification) { 64 | guard let method = notification.userInfo?["method"] as? SwitchMethod, 65 | method != currentAppViewController.currentSwitchMethod else { return } 66 | switch method { 67 | case .key: 68 | currentAppViewController.shrinkView() 69 | case .window, .hybrid: 70 | currentAppViewController.expandView() 71 | } 72 | } 73 | 74 | // MARK: - TriggerSectionVisibilityDidChangeObserver 75 | 76 | @objc func triggerSectionVisibilityDidChange(notification: Notification) { 77 | guard let visible = notification.userInfo?["visible"] as? Bool else { return } 78 | if visible { 79 | self.showTriggerSection() 80 | } else { 81 | self.hideTriggerSection() 82 | } 83 | } 84 | 85 | // MARK: - Private functions 86 | 87 | private func showTriggerSection() { 88 | guard let switchMethodItem = self.menu.item(at: 0), let separatorItem = self.menu.item(at: 1) else { return } 89 | switchMethodItem.view = self.switchMethodViewController.view 90 | switchMethodItem.isHidden = false 91 | separatorItem.isHidden = false 92 | } 93 | 94 | private func hideTriggerSection() { 95 | guard let switchMethodItem = self.menu.item(at: 0), let separatorItem = self.menu.item(at: 1) else { return } 96 | switchMethodItem.view = nil 97 | switchMethodItem.isHidden = true 98 | separatorItem.isHidden = true 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /Fluor/Controllers/ViewControllers/AboutViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AboutViewController.swift 3 | // 4 | // Fluor 5 | // 6 | // MIT License 7 | // 8 | // Copyright (c) 2020 Pierre Tacchi 9 | // 10 | // Permission is hereby granted, free of charge, to any person obtaining a copy 11 | // of this software and associated documentation files (the "Software"), to deal 12 | // in the Software without restriction, including without limitation the rights 13 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 14 | // copies of the Software, and to permit persons to whom the Software is 15 | // furnished to do so, subject to the following conditions: 16 | // 17 | // The above copyright notice and this permission notice shall be included in all 18 | // copies or substantial portions of the Software. 19 | // 20 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 21 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 22 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 23 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 24 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 25 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 26 | // SOFTWARE. 27 | // 28 | 29 | 30 | import Cocoa 31 | 32 | class AboutViewController: NSViewController { 33 | @IBOutlet weak var versionLabel: NSTextField! 34 | @IBOutlet weak var webpageButton: NSButton! 35 | @IBOutlet weak var twitterButton: NSButton! 36 | @IBOutlet weak var githubButton: NSButton! 37 | @IBOutlet weak var supportButton: NSButton! 38 | @IBOutlet weak var iconView: NSImageView! 39 | 40 | override func viewDidLoad() { 41 | super.viewDidLoad() 42 | 43 | let bundleVersion = getBundleVersion() 44 | versionLabel.stringValue = "Version \(bundleVersion.version) build \(bundleVersion.build)" 45 | } 46 | 47 | private func getBundleVersion() -> (version: String, build: String) { 48 | let version = Bundle.main.infoDictionary?["CFBundleShortVersionString"] as! String 49 | let build = Bundle.main.infoDictionary?[kCFBundleVersionKey as String] as! String 50 | 51 | return (version, build) 52 | } 53 | 54 | private func openUrlForInfo(key: String) { 55 | guard let url = self.urlForInfo(key: key) else { return } 56 | NSWorkspace.shared.open(url) 57 | } 58 | 59 | private func urlForInfo(key: String) -> URL? { 60 | guard let str = Bundle.main.infoDictionary?[key] as? String, 61 | let url = URL(string: str) else { return nil } 62 | 63 | return url 64 | } 65 | 66 | @IBAction func closeWindow(_ sender: Any) { 67 | view.window?.close() 68 | } 69 | 70 | @IBAction func goToWebpage(_ sender: Any) { 71 | self.openUrlForInfo(key: "FLPyrolyseURL") 72 | } 73 | 74 | @IBAction func goToTwitter(_ sender: Any) { 75 | self.openUrlForInfo(key: "FLTwitterURL") 76 | } 77 | 78 | @IBAction func goToGithub(_ sender: Any) { 79 | self.openUrlForInfo(key: "FLGithubURL") 80 | } 81 | 82 | @IBAction func goToSupport(_ sender: Any) { 83 | self.openUrlForInfo(key: "FLSupportEmail") 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /Fluor/Controllers/ViewControllers/CurrentAppViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CurrentAppViewController.swift 3 | // 4 | // Fluor 5 | // 6 | // MIT License 7 | // 8 | // Copyright (c) 2020 Pierre Tacchi 9 | // 10 | // Permission is hereby granted, free of charge, to any person obtaining a copy 11 | // of this software and associated documentation files (the "Software"), to deal 12 | // in the Software without restriction, including without limitation the rights 13 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 14 | // copies of the Software, and to permit persons to whom the Software is 15 | // furnished to do so, subject to the following conditions: 16 | // 17 | // The above copyright notice and this permission notice shall be included in all 18 | // copies or substantial portions of the Software. 19 | // 20 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 21 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 22 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 23 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 24 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 25 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 26 | // SOFTWARE. 27 | // 28 | 29 | 30 | import Cocoa 31 | 32 | class CurrentAppViewController: NSViewController, BehaviorDidChangeObserver, ActiveApplicationDidChangeObserver { 33 | 34 | @IBOutlet weak var appIconView: NSImageView! 35 | @IBOutlet weak var appNameLabel: NSTextField! 36 | @IBOutlet weak var behaviorSegment: NSSegmentedControl! 37 | @IBOutlet weak var imageConstraint: NSLayoutConstraint! 38 | 39 | internal var currentSwitchMethod = SwitchMethod.window 40 | 41 | private var currentAppID: String = "" 42 | private var currentAppURL: URL? 43 | 44 | deinit { 45 | self.stopObservingBehaviorDidChange() 46 | self.stopObservingActiveApplicationDidChange() 47 | } 48 | 49 | override func viewDidLoad() { 50 | self.startObservingBehaviorDidChange() 51 | self.startObservingActiveApplicationDidChange() 52 | 53 | if let currentApp = NSWorkspace.shared.frontmostApplication { 54 | self.setCurrent(app: currentApp) 55 | } 56 | } 57 | 58 | func shrinkView() { 59 | self.currentSwitchMethod = .key 60 | var newFrame = self.view.frame 61 | newFrame.size.height = 32 62 | self.imageConstraint.constant = 24 63 | self.behaviorSegment.isHidden = true 64 | self.view.setFrameSize(newFrame.size) 65 | } 66 | 67 | func expandView() { 68 | self.currentSwitchMethod = .window 69 | var newFrame = self.view.frame 70 | newFrame.size.height = 72 71 | self.imageConstraint.constant = 64 72 | self.behaviorSegment.isHidden = false 73 | self.view.setFrameSize(newFrame.size) 74 | } 75 | 76 | /// Change the behavior for the current running application. 77 | /// It makes sure the behavior manager gets notfified of this change. 78 | /// 79 | /// - parameter sender: The object that sent the action. 80 | @IBAction func behaviorChanged(_ sender: NSSegmentedControl) { 81 | guard let behavior = AppBehavior(rawValue: sender.selectedSegment), let url = self.currentAppURL else { return } 82 | AppManager.default.propagate(behavior: behavior, forApp: self.currentAppID, at: url, from: .mainMenu) 83 | } 84 | 85 | // MARK: - Private functions 86 | 87 | /// Change the current running application presented by the view. 88 | /// 89 | /// - parameter app: The running application. 90 | /// - parameter behavior: The behavior for the application. Either from the rules collection or infered if none. 91 | private func setCurrent(app: NSRunningApplication) { 92 | guard let id = app.bundleIdentifier ?? app.executableURL?.lastPathComponent, 93 | let url = app.bundleURL ?? app.executableURL else { return } 94 | 95 | self.currentAppID = id 96 | self.currentAppURL = url 97 | let behavior = AppManager.default.behaviorForApp(id: id) 98 | 99 | behaviorSegment.setSelected(true, forSegment: behavior.rawValue) 100 | appIconView.image = app.icon 101 | if let name = app.localizedName { 102 | appNameLabel.stringValue = name 103 | } else { 104 | appNameLabel.stringValue = "An app" 105 | } 106 | } 107 | 108 | // MARK: - ActiveApplicationDidChangeObserver 109 | 110 | func activeApplicationDidChangw(notification: Notification) { 111 | guard let app = notification.userInfo?[NSWorkspace.applicationUserInfoKey] as? NSRunningApplication else { return } 112 | self.setCurrent(app: app) 113 | } 114 | 115 | // MARK: - BehaviorDidChangeObserver 116 | 117 | func behaviorDidChangeForApp(notification: Notification) { 118 | guard let userInfo = notification.userInfo as? [String: Any], userInfo["source"] as? NotificationSource != .mainMenu else { return } 119 | guard let id = userInfo["id"] as? String, self.currentAppID == id, let behavior = userInfo["behavior"] as? AppBehavior else { return } 120 | 121 | behaviorSegment.setSelected(true, forSegment: behavior.rawValue) 122 | } 123 | } 124 | -------------------------------------------------------------------------------- /Fluor/Controllers/ViewControllers/DefaultModeViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DefaultModeViewController.swift 3 | // 4 | // Fluor 5 | // 6 | // MIT License 7 | // 8 | // Copyright (c) 2020 Pierre Tacchi 9 | // 10 | // Permission is hereby granted, free of charge, to any person obtaining a copy 11 | // of this software and associated documentation files (the "Software"), to deal 12 | // in the Software without restriction, including without limitation the rights 13 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 14 | // copies of the Software, and to permit persons to whom the Software is 15 | // furnished to do so, subject to the following conditions: 16 | // 17 | // The above copyright notice and this permission notice shall be included in all 18 | // copies or substantial portions of the Software. 19 | // 20 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 21 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 22 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 23 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 24 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 25 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 26 | // SOFTWARE. 27 | // 28 | 29 | 30 | import Cocoa 31 | 32 | @objc protocol DefaultModeViewControllerDelegate: class { 33 | @objc optional func defaultModeController(_ controller: DefaultModeViewController, willChangeModeTo mode: FKeyMode) 34 | func defaultModeController(_ controller: DefaultModeViewController, didChangeModeTo mode: FKeyMode) 35 | } 36 | 37 | class DefaultModeViewController: NSViewController { 38 | @IBOutlet weak var delegate: (AnyObject & DefaultModeViewControllerDelegate)? 39 | 40 | /// Change the current keyboard state. 41 | /// 42 | /// - parameter sender: The object that sent the action. 43 | @IBAction func changeMode(_ sender: NSSegmentedControl) { 44 | guard let state = FKeyMode(rawValue: sender.selectedSegment) else { return } 45 | delegate?.defaultModeController?(self, willChangeModeTo: state) 46 | delegate?.defaultModeController(self, didChangeModeTo: state) 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /Fluor/Controllers/ViewControllers/PreferencesTabViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // PreferencesTabViewController.swift 3 | // 4 | // Fluor 5 | // 6 | // MIT License 7 | // 8 | // Copyright (c) 2020 Pierre Tacchi 9 | // 10 | // Permission is hereby granted, free of charge, to any person obtaining a copy 11 | // of this software and associated documentation files (the "Software"), to deal 12 | // in the Software without restriction, including without limitation the rights 13 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 14 | // copies of the Software, and to permit persons to whom the Software is 15 | // furnished to do so, subject to the following conditions: 16 | // 17 | // The above copyright notice and this permission notice shall be included in all 18 | // copies or substantial portions of the Software. 19 | // 20 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 21 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 22 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 23 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 24 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 25 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 26 | // SOFTWARE. 27 | // 28 | 29 | 30 | import Cocoa 31 | 32 | class PreferencesTabViewController: NSTabViewController, TriggerSectionVisibilityDidChangePoster, SwitchMethodDidChangePoster { 33 | @IBAction func changeTriggerSectionVisibility(_ sender: NSButton) { 34 | let visible = sender.state == .off 35 | if !visible { 36 | self.postSwitchMethodDidChangeNotification(method: .window) 37 | AppManager.default.switchMethod = .window 38 | } 39 | self.postTriggerSectionVisibilityDidChange(visible: visible) 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /Fluor/Controllers/ViewControllers/ReleaseNotesViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ReleaseNotesViewController.swift 3 | // 4 | // Fluor 5 | // 6 | // MIT License 7 | // 8 | // Copyright (c) 2020 Pierre Tacchi 9 | // 10 | // Permission is hereby granted, free of charge, to any person obtaining a copy 11 | // of this software and associated documentation files (the "Software"), to deal 12 | // in the Software without restriction, including without limitation the rights 13 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 14 | // copies of the Software, and to permit persons to whom the Software is 15 | // furnished to do so, subject to the following conditions: 16 | // 17 | // The above copyright notice and this permission notice shall be included in all 18 | // copies or substantial portions of the Software. 19 | // 20 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 21 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 22 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 23 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 24 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 25 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 26 | // SOFTWARE. 27 | // 28 | 29 | 30 | import Cocoa 31 | import WebKit 32 | 33 | class ReleaseNotesViewController: NSViewController, WKNavigationDelegate { 34 | @IBOutlet weak var webView: WKWebView! 35 | 36 | func show(url: URL) { 37 | let request = URLRequest(url: url, cachePolicy: .reloadIgnoringLocalCacheData) 38 | self.webView.load(request) 39 | } 40 | 41 | // MARK: - WKNavigationDelegate 42 | 43 | func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping (WKNavigationActionPolicy) -> Void) { 44 | if navigationAction.navigationType == .linkActivated{ 45 | if let url = navigationAction.request.url { 46 | NSWorkspace.shared.open(url) 47 | } 48 | 49 | decisionHandler(.cancel) 50 | } 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /Fluor/Controllers/ViewControllers/RunningAppsViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // RunningAppsViewController.swift 3 | // 4 | // Fluor 5 | // 6 | // MIT License 7 | // 8 | // Copyright (c) 2020 Pierre Tacchi 9 | // 10 | // Permission is hereby granted, free of charge, to any person obtaining a copy 11 | // of this software and associated documentation files (the "Software"), to deal 12 | // in the Software without restriction, including without limitation the rights 13 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 14 | // copies of the Software, and to permit persons to whom the Software is 15 | // furnished to do so, subject to the following conditions: 16 | // 17 | // The above copyright notice and this permission notice shall be included in all 18 | // copies or substantial portions of the Software. 19 | // 20 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 21 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 22 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 23 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 24 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 25 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 26 | // SOFTWARE. 27 | // 28 | 29 | 30 | import Cocoa 31 | 32 | class RunningAppsViewController: NSViewController, NSTableViewDelegate { 33 | @IBOutlet weak var tableView: NSTableView! 34 | @IBOutlet var itemsArrayController: NSArrayController! 35 | 36 | @objc dynamic var runningAppsArray = [RunningApp]() 37 | @objc dynamic var showAll: Bool = AppManager.default.showAllRunningProcesses { 38 | didSet { self.reloadData() } 39 | } 40 | @objc dynamic var searchPredicate: NSPredicate? 41 | @objc dynamic var sortDescriptors: [NSSortDescriptor] = [.init(key: "name", ascending: true, selector: #selector(NSString.caseInsensitiveCompare(_:)))] 42 | 43 | private var tableContentAnimator: TableViewContentAnimator! 44 | 45 | override func viewDidLoad() { 46 | super.viewDidLoad() 47 | 48 | self.tableContentAnimator = TableViewContentAnimator(tableView: tableView, arrayController: itemsArrayController) 49 | self.tableContentAnimator.performUnanimated { 50 | self.reloadData() 51 | } 52 | 53 | self.applyAsObserver() 54 | } 55 | 56 | deinit { 57 | NSWorkspace.shared.notificationCenter.removeObserver(self) 58 | } 59 | 60 | /// Called whenever an application is launched by the system or the user. 61 | /// 62 | /// - parameter notification: The notification. 63 | @objc private func appDidLaunch(notification: Notification) { 64 | guard let app = notification.userInfo?[NSWorkspace.applicationUserInfoKey] as? NSRunningApplication, 65 | let id = app.bundleIdentifier ?? app.executableURL?.lastPathComponent, 66 | let url = app.bundleURL ?? app.executableURL else { return } 67 | let isApp = app.activationPolicy == .regular 68 | guard self.showAll || isApp else { return } 69 | let behavior = AppManager.default.behaviorForApp(id: id) 70 | let item = RunningApp(id: id, url: url, behavior: behavior, pid: app.processIdentifier, isApp: isApp) 71 | 72 | self.runningAppsArray.append(item) 73 | } 74 | 75 | /// Called whenever an application is terminated by the system or the user. 76 | /// 77 | /// - parameter notification: The notification. 78 | @objc private func appDidTerminate(notification: Notification) { 79 | guard let app = notification.userInfo?[NSWorkspace.applicationUserInfoKey] as? NSRunningApplication, 80 | let item = runningAppsArray.first(where: { $0.pid == app.processIdentifier }), let index = runningAppsArray.firstIndex(of: item) else { return } 81 | self.runningAppsArray.remove(at: index) 82 | } 83 | 84 | /// Set `self` as an observer for *launch* and *terminate* notfications. 85 | private func applyAsObserver() { 86 | NSWorkspace.shared.notificationCenter.addObserver(self, selector: #selector(appDidLaunch(notification:)), name: NSWorkspace.didLaunchApplicationNotification, object: nil) 87 | NSWorkspace.shared.notificationCenter.addObserver(self, selector: #selector(appDidTerminate(notification:)), name: NSWorkspace.didTerminateApplicationNotification, object: nil) 88 | } 89 | 90 | /// Load all running applications and populate the table view with corresponding data. 91 | private func reloadData() { 92 | self.runningAppsArray = self.getRunningApps() 93 | } 94 | 95 | private func getRunningApps() -> [RunningApp] { 96 | return NSWorkspace.shared.runningApplications.compactMap { (app) -> RunningApp? in 97 | guard let id = app.bundleIdentifier ?? app.executableURL?.lastPathComponent, let url = app.bundleURL ?? app.executableURL else { return nil } 98 | let isApp = app.activationPolicy == .regular 99 | guard showAll || isApp else { return nil } 100 | 101 | let behavior = AppManager.default.behaviorForApp(id: id) 102 | let pid = app.processIdentifier 103 | 104 | return RunningApp(id: id, url: url, behavior: behavior, pid: pid, isApp: isApp) 105 | } 106 | } 107 | 108 | // MARK: - Table View Delegate 109 | 110 | func tableView(_ tableView: NSTableView, shouldSelectRow row: Int) -> Bool { false } 111 | } 112 | -------------------------------------------------------------------------------- /Fluor/Controllers/ViewControllers/SwitchMethodSelectionViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SwitchMethodSelectionViewController.swift 3 | // Fluor 4 | // 5 | // Created by Pierre TACCHI on 26/02/2020. 6 | // Copyright © 2020 Pyrolyse. All rights reserved. 7 | // 8 | 9 | import Cocoa 10 | 11 | protocol WelcomeTabViewChildren: NSViewController { 12 | var welcomeTabViewController: WelcomeTabViewController? { get } 13 | } 14 | 15 | extension WelcomeTabViewChildren { 16 | var welcomeTabViewController: WelcomeTabViewController? { 17 | self.presentingViewController as? WelcomeTabViewController 18 | } 19 | } 20 | 21 | class SwitchMethodSelectionViewController: NSViewController, WelcomeTabViewChildren { 22 | @IBOutlet weak var activeAppSelectableView: SelectableView! 23 | @IBOutlet weak var fnKeySelectableView: SelectableView! 24 | 25 | deinit { 26 | self.resignAsObserver() 27 | } 28 | 29 | override func viewDidLoad() { 30 | super.viewDidLoad() 31 | self.applyAsObserver() 32 | } 33 | 34 | private func applyAsObserver() { 35 | self.activeAppSelectableView.addObserver(self, forKeyPath: "isSelected", options: [.new], context: nil) 36 | self.fnKeySelectableView.addObserver(self, forKeyPath: "isSelected", options: [.new], context: nil) 37 | } 38 | 39 | private func resignAsObserver() { 40 | self.activeAppSelectableView.removeObserver(self, forKeyPath: "isSelected") 41 | self.fnKeySelectableView.removeObserver(self, forKeyPath: "isSelected") 42 | } 43 | 44 | override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) { 45 | switch keyPath { 46 | case "isSelected": 47 | if object as AnyObject === self.activeAppSelectableView, change?[.newKey] as? Bool == true { 48 | self.activeAppHasBeenSelected() 49 | } 50 | if object as AnyObject === self.fnKeySelectableView, change?[.newKey] as? Bool == true { 51 | self.fnKeyHasBeenSelected() 52 | } 53 | default: 54 | super.observeValue(forKeyPath: keyPath, of: object, change: change, context: context) 55 | } 56 | } 57 | 58 | private func activeAppHasBeenSelected() { 59 | self.fnKeySelectableView.isSelected = false 60 | } 61 | 62 | private func fnKeyHasBeenSelected() { 63 | self.activeAppSelectableView.isSelected = false 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /Fluor/Controllers/ViewControllers/SwitchMethodViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SwitchModeViewController.swift 3 | // 4 | // Fluor 5 | // 6 | // MIT License 7 | // 8 | // Copyright (c) 2020 Pierre Tacchi 9 | // 10 | // Permission is hereby granted, free of charge, to any person obtaining a copy 11 | // of this software and associated documentation files (the "Software"), to deal 12 | // in the Software without restriction, including without limitation the rights 13 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 14 | // copies of the Software, and to permit persons to whom the Software is 15 | // furnished to do so, subject to the following conditions: 16 | // 17 | // The above copyright notice and this permission notice shall be included in all 18 | // copies or substantial portions of the Software. 19 | // 20 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 21 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 22 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 23 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 24 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 25 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 26 | // SOFTWARE. 27 | // 28 | 29 | 30 | import Cocoa 31 | 32 | class SwitchMethodViewController: NSViewController, MenuControlPoster, SwitchMethodDidChangePoster { 33 | @IBOutlet weak var methodSegmentedControl: NSSegmentedControl! 34 | @objc private dynamic var switchCapable: Bool = true 35 | 36 | @IBAction func changeSwitchMethod(_ sender: NSSegmentedControl) { 37 | guard let method = SwitchMethod(rawValue: sender.selectedSegment) else { return } 38 | self.postSwitchMethodDidChangeNotification(method: method) 39 | } 40 | 41 | @IBAction func askAccessibilityPersmission(_ sender: Any) { 42 | self.postMenuNeedsToCloseNotification() 43 | let options : NSDictionary = [kAXTrustedCheckOptionPrompt.takeRetainedValue(): true] 44 | AXIsProcessTrustedWithOptions(options) 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /Fluor/Controllers/ViewControllers/UserNotificationEnablementViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // UserNotificationEnablementViewController.swift 3 | // 4 | // Fluor 5 | // 6 | // MIT License 7 | // 8 | // Copyright (c) 2020 Pierre Tacchi 9 | // 10 | // Permission is hereby granted, free of charge, to any person obtaining a copy 11 | // of this software and associated documentation files (the "Software"), to deal 12 | // in the Software without restriction, including without limitation the rights 13 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 14 | // copies of the Software, and to permit persons to whom the Software is 15 | // furnished to do so, subject to the following conditions: 16 | // 17 | // The above copyright notice and this permission notice shall be included in all 18 | // copies or substantial portions of the Software. 19 | // 20 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 21 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 22 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 23 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 24 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 25 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 26 | // SOFTWARE. 27 | // 28 | 29 | 30 | import Cocoa 31 | import UserNotifications 32 | 33 | final class UserNotificationEnablementViewController: NSViewController, StoryboardInstantiable { 34 | static var storyboardName: NSStoryboard.Name { .preferences } 35 | static var sceneIdentifier: NSStoryboard.SceneIdentifier? { "NotificationsEnablement" } 36 | 37 | @IBOutlet weak var trailiingConstraint: NSLayoutConstraint! 38 | @IBOutlet weak var topConstraint: NSLayoutConstraint! 39 | @IBOutlet weak var bottomConstraint: NSLayoutConstraint! 40 | @IBOutlet weak var leadingConstraint: NSLayoutConstraint! 41 | private var stackViewConstraints: [NSLayoutConstraint] { 42 | [trailiingConstraint, topConstraint, bottomConstraint, leadingConstraint] 43 | } 44 | 45 | @objc dynamic var activeAppSwitch: Bool = true 46 | @objc dynamic var activeAppFnKey: Bool = true 47 | @objc dynamic var globalFnKey: Bool = true 48 | @objc dynamic var everytime: Bool = true 49 | 50 | @objc dynamic var isShownInAlert: Bool = false 51 | 52 | @objc dynamic var canEnableNotifications: Bool { 53 | everytime || activeAppSwitch || activeAppFnKey || globalFnKey 54 | } 55 | 56 | override func viewWillAppear() { 57 | self.adaptStackConstraints() 58 | guard !isShownInAlert, AppManager.default.userNotificationEnablement != .none else { 59 | if !isShownInAlert { UserNotificationEnablement.none.apply(to: self) } 60 | return 61 | } 62 | UserNotificationHelper.ifAuthorized(perform: { 63 | AppManager.default.userNotificationEnablement.apply(to: self) 64 | }) { 65 | UserNotificationEnablement.none.apply(to: self) 66 | } 67 | } 68 | 69 | @IBAction func checkBoxDidChange(_ sender: NSButton?) { 70 | if let tag = sender?.tag, tag == 1 { 71 | activeAppSwitch = everytime 72 | activeAppFnKey = everytime 73 | globalFnKey = everytime 74 | } else { 75 | everytime = activeAppSwitch && activeAppFnKey && globalFnKey 76 | } 77 | guard !isShownInAlert else { return } 78 | self.checkAuthorizations() 79 | } 80 | 81 | private func adaptStackConstraints() { 82 | stackViewConstraints.forEach { $0.constant = isShownInAlert ? 2 : 0 } 83 | } 84 | 85 | private func checkAuthorizations() { 86 | UserNotificationHelper.askUser { (isAuthorized) in 87 | if isAuthorized { 88 | AppManager.default.userNotificationEnablement = .from(self) 89 | } else { 90 | UserNotificationEnablement.none.apply(to: self) 91 | } 92 | } 93 | } 94 | 95 | override class func keyPathsForValuesAffectingValue(forKey key: String) -> Set { 96 | guard key == "canEnableNotifications" else { 97 | return super.keyPathsForValuesAffectingValue(forKey: key) 98 | } 99 | 100 | return .init(["activeAppSwitch", "activeAppFnKey", "globalFnKey", "everytime"]) 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /Fluor/Controllers/WindowControllers/AboutWindowController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AboutWindowController.swift 3 | // 4 | // Fluor 5 | // 6 | // MIT License 7 | // 8 | // Copyright (c) 2020 Pierre Tacchi 9 | // 10 | // Permission is hereby granted, free of charge, to any person obtaining a copy 11 | // of this software and associated documentation files (the "Software"), to deal 12 | // in the Software without restriction, including without limitation the rights 13 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 14 | // copies of the Software, and to permit persons to whom the Software is 15 | // furnished to do so, subject to the following conditions: 16 | // 17 | // The above copyright notice and this permission notice shall be included in all 18 | // copies or substantial portions of the Software. 19 | // 20 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 21 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 22 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 23 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 24 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 25 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 26 | // SOFTWARE. 27 | // 28 | 29 | 30 | import Cocoa 31 | 32 | final class AboutWindowController: NSWindowController, StoryboardInstantiable { 33 | static var storyboardName: NSStoryboard.Name = .about 34 | } 35 | -------------------------------------------------------------------------------- /Fluor/Controllers/WindowControllers/PreferencesWindowController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // PreferencesWindowController.swift 3 | // 4 | // Fluor 5 | // 6 | // MIT License 7 | // 8 | // Copyright (c) 2020 Pierre Tacchi 9 | // 10 | // Permission is hereby granted, free of charge, to any person obtaining a copy 11 | // of this software and associated documentation files (the "Software"), to deal 12 | // in the Software without restriction, including without limitation the rights 13 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 14 | // copies of the Software, and to permit persons to whom the Software is 15 | // furnished to do so, subject to the following conditions: 16 | // 17 | // The above copyright notice and this permission notice shall be included in all 18 | // copies or substantial portions of the Software. 19 | // 20 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 21 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 22 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 23 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 24 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 25 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 26 | // SOFTWARE. 27 | // 28 | 29 | 30 | import Cocoa 31 | 32 | final class PreferencesWindowController: NSWindowController, StoryboardInstantiable { 33 | static var storyboardName: NSStoryboard.Name = .preferences 34 | 35 | override func windowDidLoad() { 36 | super.windowDidLoad() 37 | 38 | let toolbar = window?.toolbar 39 | toolbar?.insertItem(withItemIdentifier: .flexibleSpace, at: (toolbar?.items.count ?? 0) - 1) 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /Fluor/Controllers/WindowControllers/ReleaseNotesWindowController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ReleaseNotesWindowController.swift 3 | // 4 | // Fluor 5 | // 6 | // MIT License 7 | // 8 | // Copyright (c) 2020 Pierre Tacchi 9 | // 10 | // Permission is hereby granted, free of charge, to any person obtaining a copy 11 | // of this software and associated documentation files (the "Software"), to deal 12 | // in the Software without restriction, including without limitation the rights 13 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 14 | // copies of the Software, and to permit persons to whom the Software is 15 | // furnished to do so, subject to the following conditions: 16 | // 17 | // The above copyright notice and this permission notice shall be included in all 18 | // copies or substantial portions of the Software. 19 | // 20 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 21 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 22 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 23 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 24 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 25 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 26 | // SOFTWARE. 27 | // 28 | 29 | 30 | import Cocoa 31 | 32 | class ReleaseNotesWindowController: NSWindowController, NSWindowDelegate, StoryboardInstantiable { 33 | static var storyboardName: NSStoryboard.Name { .about } 34 | static var sceneIdentifier: NSStoryboard.SceneIdentifier? { "RNWC" } 35 | 36 | @objc dynamic var releases: [Release] = [] 37 | private var session: URLSession? 38 | 39 | override func windowDidLoad() { 40 | super.windowDidLoad() 41 | self.populateList() 42 | } 43 | 44 | override func cancelOperation(_ sender: Any?) { 45 | window?.close() 46 | } 47 | 48 | // MARK: - NSWindowDelegate 49 | 50 | func windowWillClose(_ notification: Notification) { 51 | self.session?.invalidateAndCancel() 52 | } 53 | 54 | // MARK: - Actions 55 | 56 | @IBAction func changeVersion(_ sender: NSPopUpButton) { 57 | guard let release = sender.selectedItem?.representedObject as? Release else { fatalError() } 58 | self.show(url: release.url) 59 | } 60 | 61 | // MARK: - Private functions 62 | 63 | private func populateList() { 64 | guard let str = Bundle.main.infoDictionary?["FLRNListURL"] as? String, 65 | let url = URL(string: str) else { 66 | fatalError("No RN String !") 67 | } 68 | 69 | self.session = URLSession(configuration: .ephemeral) 70 | 71 | self.session?.dataTask(with: url, completionHandler: { (data, response, error) in 72 | if let error = error { 73 | DispatchQueue.main.async { [unowned self] in 74 | self.presentError(error, modalFor: self.window!, delegate: nil, didPresent: nil, contextInfo: nil) 75 | } 76 | } else if let data = data { 77 | do { 78 | let entries = try JSONDecoder().decode([Release].self, from: data) 79 | DispatchQueue.main.async { 80 | [unowned self] in self.releases = entries 81 | if let last = entries.first { 82 | self.show(url: last.url) 83 | } 84 | } 85 | } catch { 86 | DispatchQueue.main.async { [unowned self] in 87 | self.presentError(error, modalFor: self.window!, delegate: nil, didPresent: nil, contextInfo: nil) 88 | } 89 | } 90 | } 91 | }).resume() 92 | } 93 | 94 | private func show(url: URL) { 95 | guard let ctrl = self.contentViewController as? ReleaseNotesViewController else { fatalError() } 96 | ctrl.show(url: url) 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /Fluor/Controllers/WindowControllers/RulesEditorWindowController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // RulesEditorWindowController.swift 3 | // 4 | // Fluor 5 | // 6 | // MIT License 7 | // 8 | // Copyright (c) 2020 Pierre Tacchi 9 | // 10 | // Permission is hereby granted, free of charge, to any person obtaining a copy 11 | // of this software and associated documentation files (the "Software"), to deal 12 | // in the Software without restriction, including without limitation the rights 13 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 14 | // copies of the Software, and to permit persons to whom the Software is 15 | // furnished to do so, subject to the following conditions: 16 | // 17 | // The above copyright notice and this permission notice shall be included in all 18 | // copies or substantial portions of the Software. 19 | // 20 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 21 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 22 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 23 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 24 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 25 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 26 | // SOFTWARE. 27 | // 28 | 29 | 30 | import Cocoa 31 | 32 | final class RulesEditorWindowController: NSWindowController, StoryboardInstantiable { 33 | static let storyboardName: NSStoryboard.Name = .rulesEditor 34 | 35 | @IBAction func filterRuleList(_ sender: NSSearchField) { 36 | let searchString = sender.stringValue 37 | if searchString != "" { 38 | let predicate = NSPredicate(format: "name CONTAINS[cd] %@", searchString) 39 | (self.contentViewController as? RulesEditorViewController)?.searchPredicate = predicate 40 | } else { 41 | (self.contentViewController as? RulesEditorViewController)?.searchPredicate = nil 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /Fluor/Controllers/WindowControllers/RunningAppWindowController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // RunningAppWindowController.swift 3 | // 4 | // Fluor 5 | // 6 | // MIT License 7 | // 8 | // Copyright (c) 2020 Pierre Tacchi 9 | // 10 | // Permission is hereby granted, free of charge, to any person obtaining a copy 11 | // of this software and associated documentation files (the "Software"), to deal 12 | // in the Software without restriction, including without limitation the rights 13 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 14 | // copies of the Software, and to permit persons to whom the Software is 15 | // furnished to do so, subject to the following conditions: 16 | // 17 | // The above copyright notice and this permission notice shall be included in all 18 | // copies or substantial portions of the Software. 19 | // 20 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 21 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 22 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 23 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 24 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 25 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 26 | // SOFTWARE. 27 | // 28 | 29 | 30 | import Cocoa 31 | 32 | final class RunningAppWindowController: NSWindowController, StoryboardInstantiable { 33 | static let storyboardName: NSStoryboard.Name = .runningApps 34 | 35 | @IBAction func filterAppList(_ sender: NSSearchField) { 36 | let searchString = sender.stringValue 37 | if searchString != "" { 38 | let predicate = NSPredicate(format: "name CONTAINS[cd] %@", searchString) 39 | (self.contentViewController as? RunningAppsViewController)?.searchPredicate = predicate 40 | } else { 41 | (self.contentViewController as? RunningAppsViewController)?.searchPredicate = nil 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /Fluor/Extensions/NSStoryboardNamesExtension.swift: -------------------------------------------------------------------------------- 1 | // 2 | // NSStoryboardNamesExtension.swift 3 | // 4 | // Fluor 5 | // 6 | // MIT License 7 | // 8 | // Copyright (c) 2020 Pierre Tacchi 9 | // 10 | // Permission is hereby granted, free of charge, to any person obtaining a copy 11 | // of this software and associated documentation files (the "Software"), to deal 12 | // in the Software without restriction, including without limitation the rights 13 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 14 | // copies of the Software, and to permit persons to whom the Software is 15 | // furnished to do so, subject to the following conditions: 16 | // 17 | // The above copyright notice and this permission notice shall be included in all 18 | // copies or substantial portions of the Software. 19 | // 20 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 21 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 22 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 23 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 24 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 25 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 26 | // SOFTWARE. 27 | // 28 | 29 | 30 | import Cocoa 31 | 32 | extension NSStoryboard.Name { 33 | static let preferences = "Preferences" 34 | static let runningApps = "RunningApps" 35 | static let rulesEditor = "RulesEditor" 36 | static let about = "About" 37 | static let welcome = "Welcome" 38 | } 39 | -------------------------------------------------------------------------------- /Fluor/Extensions/NSViewExtension.swift: -------------------------------------------------------------------------------- 1 | // 2 | // NSViewExtension.swift 3 | // 4 | // Fluor 5 | // 6 | // MIT License 7 | // 8 | // Copyright (c) 2020 Pierre Tacchi 9 | // 10 | // Permission is hereby granted, free of charge, to any person obtaining a copy 11 | // of this software and associated documentation files (the "Software"), to deal 12 | // in the Software without restriction, including without limitation the rights 13 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 14 | // copies of the Software, and to permit persons to whom the Software is 15 | // furnished to do so, subject to the following conditions: 16 | // 17 | // The above copyright notice and this permission notice shall be included in all 18 | // copies or substantial portions of the Software. 19 | // 20 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 21 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 22 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 23 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 24 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 25 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 26 | // SOFTWARE. 27 | // 28 | 29 | 30 | import Cocoa 31 | 32 | extension NSView { 33 | var isDark: Bool { 34 | if #available(OSX 10.14, *) { 35 | return effectiveAppearance.bestMatch(from: [.darkAqua, 36 | .accessibilityHighContrastDarkAqua, 37 | .vibrantDark, 38 | .accessibilityHighContrastVibrantDark]) != nil 39 | } else { 40 | return false 41 | } 42 | } 43 | 44 | var isAccessible: Bool { 45 | if #available(OSX 10.14, *) { 46 | return effectiveAppearance.bestMatch(from: [.accessibilityHighContrastAqua, 47 | .accessibilityHighContrastVibrantLight, 48 | .accessibilityHighContrastDarkAqua, 49 | .accessibilityHighContrastVibrantDark]) != nil 50 | } else { 51 | return false 52 | } 53 | } 54 | 55 | func centerLayerAnchor() { 56 | let x = self.frame.midX 57 | let y = self.frame.midY 58 | 59 | self.layer?.anchorPoint = CGPoint(x: 0.5, y: 0.5) 60 | self.layer?.position = CGPoint(x: x, y: y) 61 | self.layer?.contentsGravity = CALayerContentsGravity.center 62 | } 63 | } 64 | 65 | -------------------------------------------------------------------------------- /Fluor/Extensions/ResultExtension.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ResultExtension.swift 3 | // 4 | // Fluor 5 | // 6 | // MIT License 7 | // 8 | // Copyright (c) 2020 Pierre Tacchi 9 | // 10 | // Permission is hereby granted, free of charge, to any person obtaining a copy 11 | // of this software and associated documentation files (the "Software"), to deal 12 | // in the Software without restriction, including without limitation the rights 13 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 14 | // copies of the Software, and to permit persons to whom the Software is 15 | // furnished to do so, subject to the following conditions: 16 | // 17 | // The above copyright notice and this permission notice shall be included in all 18 | // copies or substantial portions of the Software. 19 | // 20 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 21 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 22 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 23 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 24 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 25 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 26 | // SOFTWARE. 27 | // 28 | 29 | 30 | extension Result { 31 | func getOrFailWith(_ block: (Failure) -> Never) -> Success { 32 | switch self { 33 | case .success(let success): 34 | return success 35 | case .failure(let failure): 36 | block(failure) 37 | } 38 | } 39 | } 40 | 41 | -------------------------------------------------------------------------------- /Fluor/Extensions/SetExtension.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SetExtension.swift 3 | // 4 | // Fluor 5 | // 6 | // MIT License 7 | // 8 | // Copyright (c) 2020 Pierre Tacchi 9 | // 10 | // Permission is hereby granted, free of charge, to any person obtaining a copy 11 | // of this software and associated documentation files (the "Software"), to deal 12 | // in the Software without restriction, including without limitation the rights 13 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 14 | // copies of the Software, and to permit persons to whom the Software is 15 | // furnished to do so, subject to the following conditions: 16 | // 17 | // The above copyright notice and this permission notice shall be included in all 18 | // copies or substantial portions of the Software. 19 | // 20 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 21 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 22 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 23 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 24 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 25 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 26 | // SOFTWARE. 27 | // 28 | 29 | 30 | import DefaultsWrapper 31 | 32 | extension Set: UserDefaultsConvertible where Element: UserDefaultsConvertible { 33 | public func convertedObject() -> [Element.PropertyListSerializableType] { 34 | self.map { $0.convertedObject() } 35 | } 36 | 37 | public static func instanciate(from object: [Element.PropertyListSerializableType]) -> Self? { 38 | Set(object.compactMap(Element.instanciate(from:))) 39 | } 40 | } 41 | 42 | -------------------------------------------------------------------------------- /Fluor/Fluor-Bridging-Header.h: -------------------------------------------------------------------------------- 1 | // 2 | // Fluor-Bridging-Header.h 3 | // 4 | // Fluor 5 | // 6 | // Use this file to import your target's public headers that you would like to expose to Swift. 7 | // 8 | 9 | #include "LaunchAtLoginController.h" 10 | #include "PFMoveApplication.h" 11 | -------------------------------------------------------------------------------- /Fluor/Fluor.entitlements: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | com.apple.security.cs.disable-library-validation 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /Fluor/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIconFile 10 | 11 | CFBundleIdentifier 12 | $(PRODUCT_BUNDLE_IDENTIFIER) 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | $(PRODUCT_NAME) 17 | CFBundlePackageType 18 | APPL 19 | CFBundleShortVersionString 20 | $(MARKETING_VERSION) 21 | CFBundleVersion 22 | 2345 23 | FLGithubURL 24 | https://github.com/Pyroh/Fluor 25 | FLPyrolyseURL 26 | https://pyrolyse.it 27 | FLRNListURL 28 | https://resources.pyrolyse.it/releasenotes/Fluor/versions.json 29 | FLSupportEmail 30 | mailto:fluor.support@pyrolyse.it?subject=Fluor%20Issue 31 | FLSupportURL 32 | https://pyrolyse.it 33 | FLTwitterURL 34 | https://twitter.com/__pyroh 35 | LSApplicationCategoryType 36 | public.app-category.productivity 37 | LSMinimumSystemVersion 38 | $(MACOSX_DEPLOYMENT_TARGET) 39 | LSUIElement 40 | 41 | NSHumanReadableCopyright 42 | Copyright © 2016 - 2020 Pierre TACCHI. All rights reserved. 43 | NSMainNibFile 44 | Main 45 | NSPrincipalClass 46 | NSApplication 47 | NSServices 48 | 49 | 50 | NSMenuItem 51 | 52 | 53 | 54 | NSSupportsAutomaticGraphicsSwitching 55 | 56 | SUFeedURL 57 | https://updates.pyrolyse.co/Fluor/2.0/appcast.xml 58 | SUPublicDSAKeyFile 59 | dsa_pub.pem 60 | SUPublicEDKey 61 | 2SzTTYB9kulc+kJ8i0YdyKel2RoNIRKrJ8xp/wXWVyk= 62 | 63 | 64 | -------------------------------------------------------------------------------- /Fluor/Misc/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.swift 3 | // 4 | // Fluor 5 | // 6 | // MIT License 7 | // 8 | // Copyright (c) 2020 Pierre Tacchi 9 | // 10 | // Permission is hereby granted, free of charge, to any person obtaining a copy 11 | // of this software and associated documentation files (the "Software"), to deal 12 | // in the Software without restriction, including without limitation the rights 13 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 14 | // copies of the Software, and to permit persons to whom the Software is 15 | // furnished to do so, subject to the following conditions: 16 | // 17 | // The above copyright notice and this permission notice shall be included in all 18 | // copies or substantial portions of the Software. 19 | // 20 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 21 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 22 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 23 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 24 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 25 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 26 | // SOFTWARE. 27 | // 28 | 29 | 30 | import Cocoa 31 | 32 | @NSApplicationMain 33 | class AppDelegate: NSObject, NSApplicationDelegate, NSWindowDelegate { 34 | let statusMenuController: StatusMenuController = .init() 35 | 36 | func applicationDidFinishLaunching(_ notification: Notification) { 37 | #if RELEASE 38 | PFMoveToApplicationsFolderIfNecessary() 39 | #endif 40 | 41 | ValueTransformer.setValueTransformer(RuleValueTransformer(), forName: NSValueTransformerName("RuleValueTransformer")) 42 | 43 | // Check accessibility 44 | if !AXIsProcessTrusted() && !AppManager.default.hasAlreadyAnsweredAccessibility { 45 | let options : NSDictionary = [kAXTrustedCheckOptionPrompt.takeRetainedValue(): true] 46 | AXIsProcessTrustedWithOptions(options) 47 | AppManager.default.hasAlreadyAnsweredAccessibility = true 48 | } 49 | 50 | if AppManager.default.lastRunVersion != self.getBundleVersion() { 51 | AppManager.default.lastRunVersion = self.getBundleVersion() 52 | let rnctrl = ReleaseNotesWindowController.instantiate() 53 | rnctrl.window?.orderFrontRegardless() 54 | } 55 | 56 | UserNotificationHelper.askUserAtLaunch() 57 | 58 | self.loadMainMenu() 59 | } 60 | 61 | private func loadMainMenu() { 62 | let nib = NSNib(nibNamed: "MainMenu", bundle: nil) 63 | nib?.instantiate(withOwner: self.statusMenuController, topLevelObjects: nil) 64 | 65 | NSApp.hide(self) 66 | } 67 | 68 | private func getBundleVersion() -> String { 69 | Bundle.main.infoDictionary?["CFBundleShortVersionString"] as! String 70 | } 71 | 72 | func windowWillClose(_ notification: Notification) { 73 | self.loadMainMenu() 74 | } 75 | } 76 | 77 | 78 | -------------------------------------------------------------------------------- /Fluor/Misc/AppErrorManager.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AppExterminator.swift 3 | // 4 | // Fluor 5 | // 6 | // MIT License 7 | // 8 | // Copyright (c) 2020 Pierre Tacchi 9 | // 10 | // Permission is hereby granted, free of charge, to any person obtaining a copy 11 | // of this software and associated documentation files (the "Software"), to deal 12 | // in the Software without restriction, including without limitation the rights 13 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 14 | // copies of the Software, and to permit persons to whom the Software is 15 | // furnished to do so, subject to the following conditions: 16 | // 17 | // The above copyright notice and this permission notice shall be included in all 18 | // copies or substantial portions of the Software. 19 | // 20 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 21 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 22 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 23 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 24 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 25 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 26 | // SOFTWARE. 27 | // 28 | 29 | 30 | import Cocoa 31 | 32 | enum AppErrorManager { 33 | static func showError(withReason reason: @autoclosure () -> String, andMessage msg: String? = nil) { 34 | let info = reason() 35 | let message = msg ?? NSLocalizedString("Sorry, an unexpected error occured.", comment: "") 36 | let alert = NSAlert() 37 | 38 | alert.alertStyle = .warning 39 | alert.informativeText = info 40 | alert.messageText = message 41 | alert.runModal() 42 | } 43 | 44 | static func terminateApp(withReason reason: @autoclosure () -> String, andMessage msg: String? = nil) -> Never { 45 | let info = reason() 46 | let message = msg ?? NSLocalizedString("Sorry, an unexpected error occured.", comment: "") 47 | let alert = NSAlert() 48 | 49 | alert.alertStyle = .critical 50 | alert.informativeText = info 51 | alert.messageText = message 52 | alert.runModal() 53 | 54 | NSApp.terminate(self) 55 | fatalError(info) 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /Fluor/Misc/FKeyManager.swift: -------------------------------------------------------------------------------- 1 | // 2 | // FKeyManager.swift 3 | // 4 | // Fluor 5 | // 6 | // MIT License 7 | // 8 | // Copyright (c) 2020 Pierre Tacchi 9 | // 10 | // Permission is hereby granted, free of charge, to any person obtaining a copy 11 | // of this software and associated documentation files (the "Software"), to deal 12 | // in the Software without restriction, including without limitation the rights 13 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 14 | // copies of the Software, and to permit persons to whom the Software is 15 | // furnished to do so, subject to the following conditions: 16 | // 17 | // The above copyright notice and this permission notice shall be included in all 18 | // copies or substantial portions of the Software. 19 | // 20 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 21 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 22 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 23 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 24 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 25 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 26 | // SOFTWARE. 27 | // 28 | 29 | 30 | enum FKeyManager { 31 | typealias FKeyManagerResult = Result 32 | 33 | enum FKeyManagerError: Error { 34 | case cannotCreateMasterPort 35 | case cannotOpenService 36 | case cannotSetParameter 37 | case cannotGetParameter 38 | 39 | case otherError 40 | 41 | var localizedDescription: String { 42 | switch self { 43 | case .cannotCreateMasterPort: 44 | return "Master port creation failed (E1)" 45 | case .cannotOpenService: 46 | return "Service opening failed (E2)" 47 | case .cannotSetParameter: 48 | return "Parameter set not possible (E3)" 49 | case .cannotGetParameter: 50 | return "Parameter read not possible (E4)" 51 | default: 52 | return "Unknown error (E99)" 53 | } 54 | } 55 | } 56 | 57 | static func setCurrentFKeyMode(_ mode: FKeyMode) throws { 58 | let connect = try FKeyManager.getServiceConnect() 59 | let value = mode.rawValue as CFNumber 60 | 61 | guard IOHIDSetCFTypeParameter(connect, kIOHIDFKeyModeKey as CFString, value) == KERN_SUCCESS else { 62 | throw FKeyManagerError.cannotSetParameter 63 | } 64 | 65 | IOServiceClose(connect) 66 | } 67 | 68 | static func getCurrentFKeyMode() -> FKeyManagerResult { 69 | FKeyManagerResult { 70 | let ri = try self.getIORegistry() 71 | defer { IOObjectRelease(ri) } 72 | 73 | let entry = IORegistryEntryCreateCFProperty(ri, "HIDParameters" as CFString, kCFAllocatorDefault, 0).autorelease() 74 | 75 | guard let dict = entry.takeUnretainedValue() as? NSDictionary, 76 | let mode = dict.value(forKey: "HIDFKeyMode") as? Int, 77 | let currentMode = FKeyMode(rawValue: mode) else { 78 | throw FKeyManagerError.cannotGetParameter 79 | } 80 | 81 | return currentMode 82 | } 83 | } 84 | 85 | private static func getIORegistry() throws -> io_registry_entry_t { 86 | var masterPort: mach_port_t = .zero 87 | guard IOMasterPort(bootstrap_port, &masterPort) == KERN_SUCCESS else { throw FKeyManagerError.cannotCreateMasterPort } 88 | 89 | return IORegistryEntryFromPath(masterPort, "IOService:/IOResources/IOHIDSystem") 90 | } 91 | 92 | private static func getIOHandle() throws -> io_service_t { 93 | try self.getIORegistry() as io_service_t 94 | } 95 | 96 | private static func getServiceConnect() throws -> io_connect_t { 97 | var service: io_connect_t = .zero 98 | let handle = try self.getIOHandle() 99 | defer { IOObjectRelease(handle) } 100 | 101 | guard IOServiceOpen(handle, mach_task_self_, UInt32(kIOHIDParamConnectType), &service) == KERN_SUCCESS else { 102 | throw FKeyManagerError.cannotOpenService 103 | } 104 | 105 | return service 106 | } 107 | } 108 | -------------------------------------------------------------------------------- /Fluor/Misc/PFMoveApplication.h: -------------------------------------------------------------------------------- 1 | // 2 | // PFMoveApplication.h, version 1.24 3 | // LetsMove 4 | // 5 | // Created by Andy Kim at Potion Factory LLC on 9/17/09 6 | // 7 | // The contents of this file are dedicated to the public domain. 8 | 9 | #ifdef __cplusplus 10 | extern "C" { 11 | #endif 12 | 13 | #import 14 | 15 | /** 16 | Moves the running application to ~/Applications or /Applications if the former does not exist. 17 | After the move, it relaunches app from the new location. 18 | DOES NOT work for sandboxed applications. 19 | 20 | Call from \c NSApplication's delegate method \c -applicationWillFinishLaunching: method. */ 21 | void PFMoveToApplicationsFolderIfNecessary(void); 22 | 23 | /** 24 | Check whether an app move is currently in progress. 25 | Returns YES if LetsMove is currently in-progress trying to move the app to the Applications folder, or NO otherwise. 26 | This can be used to work around a crash with apps that terminate after last window is closed. 27 | See https://github.com/potionfactory/LetsMove/issues/64 for details. */ 28 | BOOL PFMoveIsInProgress(void); 29 | 30 | #ifdef __cplusplus 31 | } 32 | #endif 33 | -------------------------------------------------------------------------------- /Fluor/Models/Enums.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Enums.swift 3 | // 4 | // Fluor 5 | // 6 | // MIT License 7 | // 8 | // Copyright (c) 2020 Pierre Tacchi 9 | // 10 | // Permission is hereby granted, free of charge, to any person obtaining a copy 11 | // of this software and associated documentation files (the "Software"), to deal 12 | // in the Software without restriction, including without limitation the rights 13 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 14 | // copies of the Software, and to permit persons to whom the Software is 15 | // furnished to do so, subject to the following conditions: 16 | // 17 | // The above copyright notice and this permission notice shall be included in all 18 | // copies or substantial portions of the Software. 19 | // 20 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 21 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 22 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 23 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 24 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 25 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 26 | // SOFTWARE. 27 | // 28 | 29 | import DefaultsWrapper 30 | 31 | @objc enum FKeyMode: Int { 32 | case media = 0 33 | case function 34 | 35 | var behavior: AppBehavior { 36 | switch self { 37 | case .media: 38 | return .media 39 | case .function: 40 | return .function 41 | } 42 | } 43 | 44 | var counterPart: FKeyMode { 45 | switch self { 46 | case .media: return .function 47 | case .function: return .media 48 | } 49 | } 50 | 51 | var label: String { 52 | switch self { 53 | case .media: 54 | return NSLocalizedString("Media keys", comment: "") 55 | case .function: 56 | return NSLocalizedString("Function keys", comment: "") 57 | } 58 | } 59 | } 60 | 61 | @objc enum AppBehavior: Int { 62 | case inferred = 0 63 | case media 64 | case function 65 | 66 | var counterPart: AppBehavior { 67 | switch self { 68 | case .media: 69 | return .function 70 | case .function: 71 | return .media 72 | default: 73 | return .inferred 74 | } 75 | } 76 | 77 | var label: String { 78 | switch self { 79 | case .inferred: 80 | return NSLocalizedString("Same as default", comment: "") 81 | case .media: 82 | return NSLocalizedString("Media keys", comment: "") 83 | case .function: 84 | return NSLocalizedString("Function keys", comment: "") 85 | } 86 | } 87 | } 88 | 89 | @objc enum SwitchMethod: Int { 90 | case window = 0 91 | case hybrid 92 | case key 93 | } 94 | 95 | enum ItemKind { 96 | case rule 97 | case runningApp 98 | 99 | var source: NotificationSource { 100 | switch self { 101 | case .rule: 102 | return .rule 103 | case .runningApp: 104 | return .runningApp 105 | } 106 | } 107 | } 108 | 109 | enum NotificationSource { 110 | case rule 111 | case runningApp 112 | case mainMenu 113 | case fnKey 114 | case behaviorManager 115 | case undefined 116 | } 117 | 118 | struct UserNotificationEnablement: OptionSet { 119 | let rawValue: Int 120 | 121 | static let appSwitch: Self = .init(rawValue: 1 << 0) 122 | static let appKey: Self = .init(rawValue: 1 << 1) 123 | static let globalKey: Self = .init(rawValue: 1 << 2) 124 | 125 | static let all: Self = [.appSwitch, .appKey, .globalKey] 126 | static let none: Self = [] 127 | 128 | static func from(_ vc: UserNotificationEnablementViewController) -> Self { 129 | guard !vc.everytime else { return .all } 130 | return Self.none 131 | .union(vc.activeAppSwitch ? .appSwitch : .none) 132 | .union(vc.activeAppFnKey ? .appKey : .none) 133 | .union(vc.globalFnKey ? .globalKey : .none) 134 | } 135 | 136 | func apply(to vc: UserNotificationEnablementViewController) { 137 | if self == .all { 138 | vc.everytime = true 139 | vc.activeAppSwitch = true 140 | vc.activeAppFnKey = true 141 | vc.globalFnKey = true 142 | } else if self == .none { 143 | vc.everytime = false 144 | vc.activeAppSwitch = false 145 | vc.activeAppFnKey = false 146 | vc.globalFnKey = false 147 | } else { 148 | vc.everytime = false 149 | vc.activeAppSwitch = self.contains(.appSwitch) 150 | vc.activeAppFnKey = self.contains(.appKey) 151 | vc.globalFnKey = self.contains(.globalKey) 152 | } 153 | } 154 | } 155 | -------------------------------------------------------------------------------- /Fluor/Models/Items.swift: -------------------------------------------------------------------------------- 1 | // 2 | // RulesTableItem.swift 3 | // 4 | // Fluor 5 | // 6 | // MIT License 7 | // 8 | // Copyright (c) 2020 Pierre Tacchi 9 | // 10 | // Permission is hereby granted, free of charge, to any person obtaining a copy 11 | // of this software and associated documentation files (the "Software"), to deal 12 | // in the Software without restriction, including without limitation the rights 13 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 14 | // copies of the Software, and to permit persons to whom the Software is 15 | // furnished to do so, subject to the following conditions: 16 | // 17 | // The above copyright notice and this permission notice shall be included in all 18 | // copies or substantial portions of the Software. 19 | // 20 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 21 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 22 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 23 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 24 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 25 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 26 | // SOFTWARE. 27 | // 28 | 29 | import Cocoa 30 | import DefaultsWrapper 31 | 32 | class Item: NSObject, Identifiable { 33 | var notificationSource: NotificationSource { .undefined } 34 | 35 | let id: String 36 | @objc let url: URL 37 | @objc dynamic var behavior: AppBehavior 38 | 39 | @objc var icon: NSImage { NSWorkspace.shared.icon(forFile: self.url.path) } 40 | @objc var name: String { Bundle(path: self.url.path)?.localizedInfoDictionary?["CFBundleName"] as? String ?? self.url.deletingPathExtension().lastPathComponent } 41 | 42 | override var hash: Int { 43 | self.url.hashValue 44 | } 45 | 46 | init(id: String, url: URL, behavior: AppBehavior) { 47 | self.id = id 48 | self.url = url 49 | self.behavior = behavior 50 | } 51 | } 52 | 53 | final class RunningApp: Item, BehaviorDidChangeObserver { 54 | override var notificationSource: NotificationSource { .runningApp } 55 | 56 | let pid: pid_t 57 | @objc let isApp: Bool 58 | 59 | override var hash: Int { 60 | Int(self.pid) 61 | } 62 | 63 | init(id: String, url: URL, behavior: AppBehavior, pid: pid_t, isApp: Bool) { 64 | self.pid = pid 65 | self.isApp = isApp 66 | 67 | super.init(id: id, url: url, behavior: behavior) 68 | 69 | self.startObservingBehaviorDidChange() 70 | } 71 | 72 | deinit { 73 | self.stopObservingBehaviorDidChange() 74 | } 75 | 76 | // MARK: BehaviorDidChangeObserver 77 | func behaviorDidChangeForApp(notification: Notification) { 78 | guard let id = notification.userInfo?["id"] as? String, self.id == id, 79 | let appBehavior = notification.userInfo?["behavior"] as? AppBehavior else { return } 80 | self.behavior = appBehavior 81 | } 82 | } 83 | 84 | 85 | final class Rule: Item, UserDefaultsConvertible { 86 | override var notificationSource: NotificationSource { .rule } 87 | 88 | override var hash: Int { 89 | self.url.hashValue 90 | } 91 | 92 | // MARK: UserDefaultsConvertible 93 | 94 | func convertedObject() -> [String: Any] { 95 | ["id": self.id, "path": self.url.path, "behavior": self.behavior.rawValue] 96 | } 97 | 98 | static func instanciate(from object: [String: Any]) -> Rule? { 99 | guard let id = object["id"] as? String, let path = object["path"] as? String, let rawBehavior = object["behavior"] as? Int, let behavior = AppBehavior(rawValue: rawBehavior) else { return nil } 100 | let url = URL(fileURLWithPath: path) 101 | return Rule(id: id, url: url, behavior: behavior) 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /Fluor/Models/Release.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Release.swift 3 | // 4 | // Fluor 5 | // 6 | // MIT License 7 | // 8 | // Copyright (c) 2020 Pierre Tacchi 9 | // 10 | // Permission is hereby granted, free of charge, to any person obtaining a copy 11 | // of this software and associated documentation files (the "Software"), to deal 12 | // in the Software without restriction, including without limitation the rights 13 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 14 | // copies of the Software, and to permit persons to whom the Software is 15 | // furnished to do so, subject to the following conditions: 16 | // 17 | // The above copyright notice and this permission notice shall be included in all 18 | // copies or substantial portions of the Software. 19 | // 20 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 21 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 22 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 23 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 24 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 25 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 26 | // SOFTWARE. 27 | // 28 | 29 | 30 | import Foundation 31 | 32 | @objcMembers 33 | class Release: NSObject, Decodable { 34 | dynamic let tag: String 35 | dynamic let url: URL 36 | dynamic var displayName: String { 37 | return String(format: NSLocalizedString("version %@", comment: ""), tag) 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /Fluor/Models/RuleValueTransformer.swift: -------------------------------------------------------------------------------- 1 | // 2 | // RuleValueTransformer.swift 3 | // 4 | // Fluor 5 | // 6 | // MIT License 7 | // 8 | // Copyright (c) 2020 Pierre Tacchi 9 | // 10 | // Permission is hereby granted, free of charge, to any person obtaining a copy 11 | // of this software and associated documentation files (the "Software"), to deal 12 | // in the Software without restriction, including without limitation the rights 13 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 14 | // copies of the Software, and to permit persons to whom the Software is 15 | // furnished to do so, subject to the following conditions: 16 | // 17 | // The above copyright notice and this permission notice shall be included in all 18 | // copies or substantial portions of the Software. 19 | // 20 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 21 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 22 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 23 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 24 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 25 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 26 | // SOFTWARE. 27 | // 28 | 29 | import Cocoa 30 | 31 | class RuleValueTransformer: ValueTransformer { 32 | override class func allowsReverseTransformation() -> Bool { 33 | true 34 | } 35 | 36 | override class func transformedValueClass() -> AnyClass { 37 | NSNumber.self 38 | } 39 | 40 | override func transformedValue(_ value: Any?) -> Any? { 41 | (value as? Int).map { NSNumber(value: $0 - 1) } 42 | } 43 | 44 | override func reverseTransformedValue(_ value: Any?) -> Any? { 45 | (value as? Int).map { NSNumber(value: $0 + 1) } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /Fluor/Protocols/StoryboardInstantiableProtocol.swift: -------------------------------------------------------------------------------- 1 | // 2 | // StoryboardInstantiableProtocol.swift 3 | // 4 | // Fluor 5 | // 6 | // MIT License 7 | // 8 | // Copyright (c) 2020 Pierre Tacchi 9 | // 10 | // Permission is hereby granted, free of charge, to any person obtaining a copy 11 | // of this software and associated documentation files (the "Software"), to deal 12 | // in the Software without restriction, including without limitation the rights 13 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 14 | // copies of the Software, and to permit persons to whom the Software is 15 | // furnished to do so, subject to the following conditions: 16 | // 17 | // The above copyright notice and this permission notice shall be included in all 18 | // copies or substantial portions of the Software. 19 | // 20 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 21 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 22 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 23 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 24 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 25 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 26 | // SOFTWARE. 27 | // 28 | 29 | 30 | import Cocoa 31 | 32 | protocol StoryboardInstantiable: NSObjectProtocol { 33 | static var storyboardName: NSStoryboard.Name { get } 34 | static var sceneIdentifier: NSStoryboard.SceneIdentifier? { get } 35 | static var bundle: Bundle? { get } 36 | 37 | static func instantiate() -> Self 38 | } 39 | 40 | extension StoryboardInstantiable { 41 | static var sceneIdentifier: NSStoryboard.SceneIdentifier? { nil } 42 | static var bundle: Bundle? { nil } 43 | 44 | static func instantiate() -> Self { 45 | if let id = sceneIdentifier { 46 | return NSStoryboard(name: storyboardName, bundle: bundle).instantiateController(withIdentifier: id) as! Self 47 | } else { 48 | return NSStoryboard(name: storyboardName, bundle: bundle).instantiateInitialController() as! Self 49 | } 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /Fluor/Views/CheckableMenuItem.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CheckableMenuItem.swift 3 | // 4 | // Fluor 5 | // 6 | // MIT License 7 | // 8 | // Copyright (c) 2020 Pierre Tacchi 9 | // 10 | // Permission is hereby granted, free of charge, to any person obtaining a copy 11 | // of this software and associated documentation files (the "Software"), to deal 12 | // in the Software without restriction, including without limitation the rights 13 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 14 | // copies of the Software, and to permit persons to whom the Software is 15 | // furnished to do so, subject to the following conditions: 16 | // 17 | // The above copyright notice and this permission notice shall be included in all 18 | // copies or substantial portions of the Software. 19 | // 20 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 21 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 22 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 23 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 24 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 25 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 26 | // SOFTWARE. 27 | // 28 | 29 | 30 | import Cocoa 31 | 32 | class CheckableMenuItem: NSMenuItem { 33 | private static let eraserImage = NSImage(size: NSSize(width: 16.0, height: 16.0)) 34 | 35 | private var onStateImageShadow: NSImage? 36 | private var offStateImageShadow: NSImage? 37 | private var mixedStateImageShadow: NSImage? 38 | 39 | override var onStateImage: NSImage! { 40 | didSet { 41 | guard self.onStateImage != Self.eraserImage else { return } 42 | self.onStateImageShadow = self.onStateImage 43 | self.onStateImage = Self.eraserImage 44 | } 45 | } 46 | 47 | override var state: NSControl.StateValue { 48 | didSet { 49 | self.adaptImageToState() 50 | } 51 | } 52 | 53 | override init(title string: String, action selector: Selector?, keyEquivalent charCode: String) { 54 | super.init(title: string, action: selector, keyEquivalent: charCode) 55 | self.setup() 56 | self.adaptImageToState() 57 | } 58 | 59 | required init(coder decoder: NSCoder) { 60 | super.init(coder: decoder) 61 | self.setup() 62 | self.adaptImageToState() 63 | } 64 | 65 | private func setup() { 66 | self.onStateImageShadow = self.onStateImage 67 | self.offStateImageShadow = self.offStateImage 68 | self.mixedStateImageShadow = self.mixedStateImage 69 | self.onStateImage = Self.eraserImage 70 | self.offStateImage = Self.eraserImage 71 | self.mixedStateImage = Self.eraserImage 72 | } 73 | 74 | private func adaptImageToState() { 75 | switch self.state { 76 | case .on: 77 | self.image = self.onStateImageShadow 78 | case .off: 79 | self.image = self.offStateImageShadow 80 | default: 81 | self.image = self.mixedStateImageShadow 82 | } 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /Fluor/Views/LinkButton.swift: -------------------------------------------------------------------------------- 1 | // 2 | // LinkButton.swift 3 | // 4 | // Fluor 5 | // 6 | // MIT License 7 | // 8 | // Copyright (c) 2020 Pierre Tacchi 9 | // 10 | // Permission is hereby granted, free of charge, to any person obtaining a copy 11 | // of this software and associated documentation files (the "Software"), to deal 12 | // in the Software without restriction, including without limitation the rights 13 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 14 | // copies of the Software, and to permit persons to whom the Software is 15 | // furnished to do so, subject to the following conditions: 16 | // 17 | // The above copyright notice and this permission notice shall be included in all 18 | // copies or substantial portions of the Software. 19 | // 20 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 21 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 22 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 23 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 24 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 25 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 26 | // SOFTWARE. 27 | // 28 | 29 | 30 | import Cocoa 31 | import SmoothOperators 32 | 33 | final class LinkButton: NSButton { 34 | @IBInspectable var url: String? 35 | private var actualURL: URL? { 36 | guard let url = url else { return nil } 37 | return URL(string: url) 38 | } 39 | 40 | override init(frame frameRect: NSRect) { 41 | super.init(frame: frameRect) 42 | setupAppearance() 43 | createAction() 44 | } 45 | 46 | required init?(coder: NSCoder) { 47 | super.init(coder: coder) 48 | setupAppearance() 49 | createAction() 50 | } 51 | 52 | private func setupAppearance() { 53 | isBordered = false 54 | imagePosition = .noImage 55 | alternateTitle = title 56 | 57 | var attributes = attributedTitle.fontAttributes(in: .init(location: 0, length: attributedTitle.length)) 58 | attributes[.foregroundColor] = NSColor.linkColor 59 | attributes[.underlineStyle] = NSUnderlineStyle.single.rawValue 60 | 61 | let newAttributedTitle = NSAttributedString(string: title, attributes: attributes) 62 | 63 | attributedTitle = newAttributedTitle 64 | attributedAlternateTitle = newAttributedTitle 65 | } 66 | 67 | private func createAction() { 68 | target = self 69 | action = #selector(openURL(_:)) 70 | } 71 | 72 | override func resetCursorRects() { 73 | super.resetCursorRects() 74 | self.addCursorRect(self.bounds, cursor: .pointingHand) 75 | } 76 | 77 | @IBAction func openURL(_ sender: Any?){ 78 | guard !!url else { return } 79 | guard let destinationURL = actualURL else { return assertionFailure("\(self.url!) is not a valid URL.") } 80 | NSWorkspace.shared.open(destinationURL) 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /Fluor/Views/MenuItemView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // OpaqueView.swift 3 | // 4 | // Fluor 5 | // 6 | // MIT License 7 | // 8 | // Copyright (c) 2020 Pierre Tacchi 9 | // 10 | // Permission is hereby granted, free of charge, to any person obtaining a copy 11 | // of this software and associated documentation files (the "Software"), to deal 12 | // in the Software without restriction, including without limitation the rights 13 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 14 | // copies of the Software, and to permit persons to whom the Software is 15 | // furnished to do so, subject to the following conditions: 16 | // 17 | // The above copyright notice and this permission notice shall be included in all 18 | // copies or substantial portions of the Software. 19 | // 20 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 21 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 22 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 23 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 24 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 25 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 26 | // SOFTWARE. 27 | // 28 | 29 | 30 | import AppKit 31 | 32 | class MenuItemView: NSView { 33 | override func draw(_ dirtyRect: NSRect) { 34 | if #available(OSX 10.14, *), isAccessible { 35 | let darkComponent: CGFloat = 42.0/255 36 | let lightComponent: CGFloat = 244.0/255 37 | let component = isDark ? darkComponent : lightComponent 38 | 39 | NSColor(calibratedRed: component, green: component, blue: component, alpha: 1).setFill() 40 | dirtyRect.fill() 41 | } else { 42 | super.draw(dirtyRect) 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /Fluor/Views/MoverEffectView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // MoverEffectView.swift 3 | // 4 | // Fluor 5 | // 6 | // MIT License 7 | // 8 | // Copyright (c) 2020 Pierre Tacchi 9 | // 10 | // Permission is hereby granted, free of charge, to any person obtaining a copy 11 | // of this software and associated documentation files (the "Software"), to deal 12 | // in the Software without restriction, including without limitation the rights 13 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 14 | // copies of the Software, and to permit persons to whom the Software is 15 | // furnished to do so, subject to the following conditions: 16 | // 17 | // The above copyright notice and this permission notice shall be included in all 18 | // copies or substantial portions of the Software. 19 | // 20 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 21 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 22 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 23 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 24 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 25 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 26 | // SOFTWARE. 27 | // 28 | 29 | 30 | import Cocoa 31 | 32 | class MoverEffectView: NSVisualEffectView { 33 | override func mouseDown(with event: NSEvent) { 34 | guard let window = self.window else { return } 35 | window.performDrag(with: event) 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /Fluor/Views/MoverImageView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // PassthroughImageView.swift 3 | // 4 | // Fluor 5 | // 6 | // MIT License 7 | // 8 | // Copyright (c) 2020 Pierre Tacchi 9 | // 10 | // Permission is hereby granted, free of charge, to any person obtaining a copy 11 | // of this software and associated documentation files (the "Software"), to deal 12 | // in the Software without restriction, including without limitation the rights 13 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 14 | // copies of the Software, and to permit persons to whom the Software is 15 | // furnished to do so, subject to the following conditions: 16 | // 17 | // The above copyright notice and this permission notice shall be included in all 18 | // copies or substantial portions of the Software. 19 | // 20 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 21 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 22 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 23 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 24 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 25 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 26 | // SOFTWARE. 27 | // 28 | 29 | 30 | import Cocoa 31 | 32 | class MoverImageView: NSImageView { 33 | override var mouseDownCanMoveWindow: Bool { true } 34 | } 35 | -------------------------------------------------------------------------------- /Fluor/Views/MultilinesCheckBoxLabel.swift: -------------------------------------------------------------------------------- 1 | // 2 | // MultilinesCheckBoxLabel.swift 3 | // 4 | // Fluor 5 | // 6 | // MIT License 7 | // 8 | // Copyright (c) 2020 Pierre Tacchi 9 | // 10 | // Permission is hereby granted, free of charge, to any person obtaining a copy 11 | // of this software and associated documentation files (the "Software"), to deal 12 | // in the Software without restriction, including without limitation the rights 13 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 14 | // copies of the Software, and to permit persons to whom the Software is 15 | // furnished to do so, subject to the following conditions: 16 | // 17 | // The above copyright notice and this permission notice shall be included in all 18 | // copies or substantial portions of the Software. 19 | // 20 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 21 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 22 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 23 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 24 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 25 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 26 | // SOFTWARE. 27 | // 28 | 29 | 30 | import Cocoa 31 | 32 | class MultilinesCheckBoxLabel: NSTextField { 33 | @IBOutlet weak var checkBox: NSButton! 34 | 35 | override var isHighlighted: Bool { 36 | didSet { 37 | checkBox.isHighlighted = isHighlighted 38 | } 39 | } 40 | private var isClicked = false 41 | 42 | override func updateTrackingAreas() { 43 | super.updateTrackingAreas() 44 | 45 | self.trackingAreas.forEach(self.removeTrackingArea(_:)) 46 | let trackingArea = NSTrackingArea(rect: self.bounds, options: [.activeAlways, .mouseEnteredAndExited, .enabledDuringMouseDrag], owner: self, userInfo: nil) 47 | self.addTrackingArea(trackingArea) 48 | } 49 | 50 | override func mouseDown(with event: NSEvent) { 51 | isClicked = true 52 | isHighlighted = true 53 | } 54 | 55 | override func mouseUp(with event: NSEvent) { 56 | if isHighlighted { checkBox.performClick(self) } 57 | isClicked = false 58 | } 59 | 60 | override func mouseEntered(with event: NSEvent) { 61 | if isClicked { isHighlighted = true } 62 | } 63 | 64 | override func mouseExited(with event: NSEvent) { 65 | if isClicked { isHighlighted = false } 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /Fluor/Views/PoppingLinkButton.swift: -------------------------------------------------------------------------------- 1 | // 2 | // PoppingLinkButton.swift 3 | // 4 | // Fluor 5 | // 6 | // MIT License 7 | // 8 | // Copyright (c) 2020 Pierre Tacchi 9 | // 10 | // Permission is hereby granted, free of charge, to any person obtaining a copy 11 | // of this software and associated documentation files (the "Software"), to deal 12 | // in the Software without restriction, including without limitation the rights 13 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 14 | // copies of the Software, and to permit persons to whom the Software is 15 | // furnished to do so, subject to the following conditions: 16 | // 17 | // The above copyright notice and this permission notice shall be included in all 18 | // copies or substantial portions of the Software. 19 | // 20 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 21 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 22 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 23 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 24 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 25 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 26 | // SOFTWARE. 27 | // 28 | 29 | 30 | import Cocoa 31 | 32 | @IBDesignable 33 | class PoppingLinkButton: NSButton { 34 | @IBInspectable var growsOnHover: Bool = true 35 | @IBInspectable var growFactor: CGFloat = 1.15 36 | 37 | override func layout() { 38 | super.layout() 39 | self.centerLayerAnchor() 40 | } 41 | 42 | override func updateTrackingAreas() { 43 | super.updateTrackingAreas() 44 | 45 | self.trackingAreas.forEach(self.removeTrackingArea(_:)) 46 | let trackingArea = NSTrackingArea(rect: self.bounds, options: [.activeAlways, .mouseEnteredAndExited], owner: self, userInfo: nil) 47 | self.addTrackingArea(trackingArea) 48 | } 49 | 50 | override func resetCursorRects() { 51 | super.resetCursorRects() 52 | self.addCursorRect(self.bounds, cursor: .pointingHand) 53 | } 54 | 55 | // Thanks to Kite Compositor (kiteapp.co) 56 | override func mouseEntered(with event: NSEvent) { 57 | guard self.growsOnHover, let layer = self.layer else { return } 58 | 59 | let transformScaleAnimation = CASpringAnimation() 60 | 61 | transformScaleAnimation.fillMode = CAMediaTimingFillMode.forwards 62 | transformScaleAnimation.duration = 0.99321 63 | transformScaleAnimation.isRemovedOnCompletion = false 64 | transformScaleAnimation.keyPath = "transform.scale" 65 | transformScaleAnimation.toValue = self.growFactor 66 | transformScaleAnimation.stiffness = 200 67 | transformScaleAnimation.damping = 10 68 | transformScaleAnimation.mass = 0.7 69 | transformScaleAnimation.initialVelocity = 4 70 | 71 | layer.add(transformScaleAnimation, forKey: "growAnimation") 72 | } 73 | 74 | // Thanks to Kite Compositor (kiteapp.co) 75 | override func mouseExited(with event: NSEvent) { 76 | guard self.growsOnHover, let layer = self.layer else { return } 77 | 78 | let transformScaleAnimation1 = CASpringAnimation() 79 | 80 | transformScaleAnimation1.duration = 0.99321 81 | transformScaleAnimation1.fillMode = CAMediaTimingFillMode.forwards 82 | transformScaleAnimation1.isRemovedOnCompletion = false 83 | transformScaleAnimation1.keyPath = "transform.scale" 84 | transformScaleAnimation1.toValue = 1 85 | transformScaleAnimation1.stiffness = 200 86 | transformScaleAnimation1.damping = 10 87 | transformScaleAnimation1.mass = 0.7 88 | transformScaleAnimation1.initialVelocity = 4 89 | 90 | layer.add(transformScaleAnimation1, forKey: "shrinkAnimation") 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /Fluor/Views/RuleCellView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // RuleCellView.swift 3 | // 4 | // Fluor 5 | // 6 | // MIT License 7 | // 8 | // Copyright (c) 2020 Pierre Tacchi 9 | // 10 | // Permission is hereby granted, free of charge, to any person obtaining a copy 11 | // of this software and associated documentation files (the "Software"), to deal 12 | // in the Software without restriction, including without limitation the rights 13 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 14 | // copies of the Software, and to permit persons to whom the Software is 15 | // furnished to do so, subject to the following conditions: 16 | // 17 | // The above copyright notice and this permission notice shall be included in all 18 | // copies or substantial portions of the Software. 19 | // 20 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 21 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 22 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 23 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 24 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 25 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 26 | // SOFTWARE. 27 | // 28 | 29 | 30 | import Cocoa 31 | 32 | class RuleCellView: NSTableCellView { 33 | override var backgroundStyle: NSView.BackgroundStyle { 34 | didSet { 35 | switch self.backgroundStyle { 36 | case .light: 37 | self.textField?.textColor = .textColor 38 | default: 39 | self.textField?.textColor = .selectedMenuItemTextColor 40 | } 41 | } 42 | } 43 | 44 | @IBAction func action(_ sender: Any?) { 45 | guard let item = objectValue as? Item else { 46 | return AppErrorManager.showError(withReason: "Can't set behavior") 47 | } 48 | 49 | AppManager.default.propagate(behavior: item.behavior, forApp: item.id, at: item.url, from: item.notificationSource) 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /Fluor/Views/SelectableBox.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SelectableBox.swift 3 | // Fluor 4 | // 5 | // Created by Pierre TACCHI on 24/02/2020. 6 | // Copyright © 2020 Pyrolyse. All rights reserved 7 | // 8 | 9 | import Cocoa 10 | 11 | class SelectableView: NSBox { 12 | private var isClicked: Bool = false { 13 | didSet { self.updateState() } 14 | } 15 | 16 | private var isHighlighted: Bool = false { 17 | didSet { self.updateState() } 18 | } 19 | 20 | private var highlightedColor: NSColor { 21 | .controlColor 22 | } 23 | 24 | private var clickedColor: NSColor { 25 | .selectedControlColor 26 | } 27 | 28 | override var mouseDownCanMoveWindow: Bool { false } 29 | 30 | override func updateTrackingAreas() { 31 | self.trackingAreas.forEach(self.removeTrackingArea(_:)) 32 | self.addTrackingArea(.init(rect: self.bounds, options: [.activeAlways, .mouseEnteredAndExited, .enabledDuringMouseDrag], owner: self, userInfo: nil)) 33 | } 34 | 35 | override func mouseEntered(with event: NSEvent) { 36 | super.mouseEntered(with: event) 37 | guard NSEvent.pressedMouseButtons == 0 || self.isClicked else { return } 38 | self.isHighlighted = true 39 | } 40 | 41 | override func mouseExited(with event: NSEvent) { 42 | super.mouseExited(with: event) 43 | self.isHighlighted = false 44 | } 45 | 46 | override func mouseDown(with event: NSEvent) { 47 | self.isClicked = true 48 | } 49 | 50 | override func mouseUp(with event: NSEvent) { 51 | self.isClicked = false 52 | if self.isHighlighted { 53 | 54 | } 55 | } 56 | 57 | private func updateState() { 58 | switch (self.isHighlighted, self.isClicked) { 59 | case (false, true): 60 | self.fillColor = .clear 61 | case (_, true): 62 | self.fillColor = self.clickedColor 63 | case (true, _): 64 | if self.fillColor == self.clickedColor { 65 | self.fillColor = self.highlightedColor 66 | } else { 67 | self.animator().fillColor = self.highlightedColor 68 | } 69 | default: 70 | if self.fillColor == self.highlightedColor { 71 | self.animator().fillColor = .clear 72 | } else { 73 | self.fillColor = .clear 74 | } 75 | } 76 | } 77 | 78 | private func handleClick() { 79 | 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /Fluor/dsa_pub.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN PUBLIC KEY----- 2 | MIIGRzCCBDkGByqGSM44BAEwggQsAoICAQCQx6TQEbKejJRlvpUbTXKHCZEHifHm 3 | dfJmi/abYBJcKNYpFWFvZdi94xswYt0RX9xzIrvseDPdcSJNGr4cvHCfBEdgRbk0 4 | PHmo80lGCtMi9EvVxlYvZqcN/k/O8YtgRv5YMLJzoVQqmIDRZYR+zgstUX+5dqZF 5 | OVoRBMnmg7P4tVTcFaCs6QXbyABAOQrM45EbEzDEgaC5CvGmw7uavKdt9FB5+CNx 6 | bud64mPcButwr127g4oZHx/x5E2N1xzd2myCEksVm6e2MNEOmzU6UcMcnv6kq/ib 7 | e8Xd4sI21YSBQQo0J0i0tBevCtoXo0vMQhxhauRZD53x8zFeZyXmMcO48qej3dfF 8 | /4LDqKekHy0rcZuBGOkFbIR5AojGZXIjxdYYLiFz86y1MIpEt4Agr3HslP9TdzJX 9 | Qg5tdIA+1Qi5kBA4581KaIt/xtEi6fV8UAtoRO16ILnp0yYyqKxw/XodqhPO3m1M 10 | NgAXNbKFncnZUDwVYjAx/Bb8HkfhaSfFb2ihS3MMQmZuRY7r4H1Utp4ZjWrGIimN 11 | xZbEDqAwYlcmEP82/ALC+R1Y92N9BxR1T5BjQP5OwyfgHO7kpKuFraxhBK57UFE/ 12 | l1fHQhmQAbu6bPCLwP4Jr8TZYcLwNPg9VvZDt6ThxCkxhk2DGGPPzIc0Vknvfe3L 13 | epUWKV3qUbH5qQIhAJ7yDbYPljsZQ9Nfr8HTXTH+p+2j0eHF19p31rJJFmIZAoIC 14 | ABk3RNEz7+ttAMlkUNCQt9t6cORrNS1zUpkPOCFfVrctYn4U/eGDEzrxmvrTZeaU 15 | 9/X+DDd/7f2eMPnwGgailyXoU68g0yyuUyK9afIXmj6QfA0Tm6E+1hzUywmhNPMO 16 | A+hT3TVRES98tyDfLg2gRvmWQh7GAnW3edMpk9Q2gCl8Nn4AjRjs77hsM+d1OHUS 17 | N9ZFZoTT3MQJpjaSr0ei0ZOdf0LqTsEc54gofWSv85JUrWnEcJzVmc06ex5W/MTd 18 | ZxAjHtbhz/YVlG5fFP2JlifxaBlkRA6sqZbTykdQVso9T5uCiW1Dc8euWfz1QLdE 19 | rwldrOyMjr8/RVVobMlgTOcjWPKXrsrb8M1PgJ5Dxm292qFId63mIuLm9oRf1UX6 20 | aJVbcgm6qr9W7JMTEdEJxM2EnTDKafPNy1wng2d3qPyglaw0Nw3H2K7kckMXS7tq 21 | aRNMwQdS+apy0F+hHctklJDbYnAB+YIYQuQbaRjgS8/ih+KPPlW1JdmKyNbaejR+ 22 | pOAOsPxIP6jzaWTlL/Q36OA3CpM3VSFzktCxyP1vlIZva4U0VRX1pFexPKf+VXBz 23 | c1V7Ap+BzmgHU2qkLwdtj9lq3hMUGBdceFjlQjb5a7eniUN5pFFDAXdE2B57ti0k 24 | QHBelNfpKlZFf1erzm6LjXjmcy5G9i7Tc7au1lSl0HbdA4ICBgACggIBAI993Nil 25 | aqchhltIobZz+KTaRuIT6lmVg0geIlpdFTIexVofveGMz6Ms+bFBTWIPyDtWNGXb 26 | i/fNBnPtjdwbAoXrdSAqL2Bq/+p3hfvqtlqaEVRTPLXUlr9mSto8efoExJGNoAAi 27 | D0J/0Je3bt9womWdlCejYAK0ilwCjAimOLiNZStDHkafuiC7g3avHz20GW8F3SNx 28 | mGIG9G8dS+aL0Tm32/SHSfaMjuTaE69Wl5RyzrDGe95g06eadEJseCQWYf5+sp4Q 29 | vzt0xTRxOQ92p0nhjmP56Y+3gWXdJFBHWFtapzeTkwCL7Ldzzf8eZW192v6a8ukd 30 | FXk5wwBmNYDoblYl6/0tA8siqBaCXI9WM4pPC4a7g1o/LzOM7Az/dRJVRtlN7nn4 31 | 9Yi83zhdKxz55L4VCCxubd3y85/pdsQNm9aSTuVT4y/6yzmm2z/h0PUFmPXUWoU1 32 | SweG+wDiAVG1Fzlv39hKvI+4E6VPhZujuwno6GQBHzwDHyzcn4W6TJeK8jC2FuJK 33 | fI7C5SSjPPprx1Px3ovfA5SDRannYsipFheVm3AFu4geswxr9p20S6rdDkjDln16 34 | t3B8j8wKNgk+E54XCp2yBpoSE4uuKWJ/ya/WHGwW0VW1eK/Po9RnBl/DYiYt5wBS 35 | lzW4UcgE8CEJr9dV2P5WUve3FHRz7Zf7qmiQ 36 | -----END PUBLIC KEY----- 37 | -------------------------------------------------------------------------------- /Fluor/en.lproj/Localizable.strings: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Pyroh/Fluor/6b5fcd11324dfe99ef0fb20d4015625a0e96f283/Fluor/en.lproj/Localizable.strings -------------------------------------------------------------------------------- /Fluor/fr.lproj/About.strings: -------------------------------------------------------------------------------- 1 | /* Class = "NSButtonCell"; title = "Release notes"; ObjectID = "3LZ-kH-mRF"; */ 2 | "3LZ-kH-mRF.title" = "Notes de version"; 3 | 4 | /* Class = "NSTextFieldCell"; title = "Copyright (c) Pyrolyse 2016-2019"; ObjectID = "D9M-Xx-uVv"; */ 5 | "D9M-Xx-uVv.title" = "Copyright (c) Pyrolyse 2016-2019"; 6 | 7 | /* Class = "NSWindow"; title = "Window"; ObjectID = "Iyh-kg-rFF"; */ 8 | "Iyh-kg-rFF.title" = "Window"; 9 | 10 | /* Class = "NSButtonCell"; title = "Technical support"; ObjectID = "k51-I5-gTD"; */ 11 | "k51-I5-gTD.title" = "Support technique"; 12 | 13 | /* Class = "NSButton"; ibShadowedToolTip = "Pyrolyse Website"; ObjectID = "LAF-Vr-LJH"; */ 14 | "LAF-Vr-LJH.ibShadowedToolTip" = "Site web Pyrolyse"; 15 | 16 | /* Class = "NSTextFieldCell"; title = "Version"; ObjectID = "nBp-xh-w5r"; */ 17 | "nBp-xh-w5r.title" = "Version"; 18 | 19 | /* Class = "NSTextFieldCell"; title = "Fluor"; ObjectID = "Rb1-qw-yPI"; */ 20 | "Rb1-qw-yPI.title" = "Fluor"; 21 | 22 | /* Class = "NSButton"; ibShadowedToolTip = "Twitter Account"; ObjectID = "tcP-8l-Eun"; */ 23 | "tcP-8l-Eun.ibShadowedToolTip" = "Compte Twitter"; 24 | 25 | /* Class = "NSButton"; ibShadowedToolTip = "Fork me on GitHub"; ObjectID = "z33-BR-yuW"; */ 26 | "z33-BR-yuW.ibShadowedToolTip" = "Fork me on GitHub"; 27 | 28 | -------------------------------------------------------------------------------- /Fluor/fr.lproj/Localizable.strings: -------------------------------------------------------------------------------- 1 | /* No comment provided by engineer. */ 2 | "Default mode changed" = "Modification du mode par défaut"; 3 | 4 | /* No comment provided by engineer. */ 5 | "Don't ask me on startup again" = "Ne pas me demander au démarrage de l'application"; 6 | 7 | /* No comment provided by engineer. */ 8 | "Don't enable notifications" = "Ne pas activer les notifications"; 9 | 10 | /* No comment provided by engineer. */ 11 | "Enable notfications" = "Activer les notifications"; 12 | 13 | /* No comment provided by engineer. */ 14 | "Enable notifications ?" = "Voulez-vous recevoir des notifications ?"; 15 | 16 | /* No comment provided by engineer. */ 17 | "F-Keys mode changed" = "Le mode des touches F a changé"; 18 | 19 | /* No comment provided by engineer. */ 20 | "F-Keys mode changed for %@" = "Le mode des touches F a changé pour %@"; 21 | 22 | /* No comment provided by engineer. */ 23 | "Fluor can send notifications when the F-Keys mode change." = "Fluor peut envoyer des notifications quand le mode des touches F est modifié"; 24 | 25 | /* No comment provided by engineer. */ 26 | "Function keys" = "Touches de fonction"; 27 | 28 | /* No comment provided by engineer. */ 29 | "I allowed it" = "Je l'ai autorisé"; 30 | 31 | /* No comment provided by engineer. */ 32 | "I won't allow it" = "Je ne l'autoriserai pas"; 33 | 34 | /* No comment provided by engineer. */ 35 | "Media keys" = "Touches média"; 36 | 37 | /* No comment provided by engineer. */ 38 | "Notifications are not allowed from Fluor" = "Fluor n'est pas autorisé à envoyer des notifications"; 39 | 40 | /* No comment provided by engineer. */ 41 | "Same as default" = "Identique au mode par défaut"; 42 | 43 | /* No comment provided by engineer. */ 44 | "Sorry, an unexpected error occured." = "Désolé une erreur inattendue est survenue"; 45 | 46 | /* No comment provided by engineer. */ 47 | "version %@" = "version %@"; 48 | 49 | -------------------------------------------------------------------------------- /Fluor/fr.lproj/MainMenu.strings: -------------------------------------------------------------------------------- 1 | /* Class = "NSSegmentedCell"; 1I5-bW-HGh.ibShadowedToolTips[0] = "Same as default mode"; ObjectID = "1I5-bW-HGh"; */ 2 | "1I5-bW-HGh.ibShadowedToolTips[0]" = "Identique au mode par défaut"; 3 | 4 | /* Class = "NSSegmentedCell"; 1I5-bW-HGh.ibShadowedToolTips[1] = "Media keys mode"; ObjectID = "1I5-bW-HGh"; */ 5 | "1I5-bW-HGh.ibShadowedToolTips[1]" = "Choisir sur les touches Apple"; 6 | 7 | /* Class = "NSSegmentedCell"; 1I5-bW-HGh.ibShadowedToolTips[2] = "Function keys mode"; ObjectID = "1I5-bW-HGh"; */ 8 | "1I5-bW-HGh.ibShadowedToolTips[2]" = "Choisir sur les touches de function"; 9 | 10 | /* Class = "NSTextFieldCell"; title = "Trigger"; ObjectID = "AiN-Qo-Ikx"; */ 11 | "AiN-Qo-Ikx.title" = "Déclencheur"; 12 | 13 | /* Class = "NSMenuItem"; title = "Running applications..."; ObjectID = "Ark-Du-XrQ"; */ 14 | "Ark-Du-XrQ.title" = "Applications en cours..."; 15 | 16 | /* Class = "NSMenuItem"; title = "Disabled"; ObjectID = "DqN-qz-yQz"; */ 17 | "DqN-qz-yQz.title" = "Désactivé"; 18 | 19 | /* Class = "NSMenuItem"; title = "Start Fluor at login"; ObjectID = "eWy-d7-62P"; */ 20 | "eWy-d7-62P.title" = "Lancer Fluor au démarrage"; 21 | 22 | /* Class = "NSButtonCell"; title = "Ask permission"; ObjectID = "gP8-wU-Xyk"; */ 23 | "gP8-wU-Xyk.title" = "Gérer permission"; 24 | 25 | /* Class = "NSMenuItem"; title = "Switch method"; ObjectID = "hM4-Z2-ndk"; */ 26 | "hM4-Z2-ndk.title" = "Switch method"; 27 | 28 | /* Class = "NSMenuItem"; title = "About Fluor"; ObjectID = "Ib7-Rw-HnK"; */ 29 | "Ib7-Rw-HnK.title" = "À propos de Fluor"; 30 | 31 | /* Class = "NSMenuItem"; title = "Manage rules..."; ObjectID = "MHf-OK-jHk"; */ 32 | "MHf-OK-jHk.title" = "Gérer les règles..."; 33 | 34 | /* Class = "NSTextFieldCell"; title = "Label"; ObjectID = "nND-dO-QEg"; */ 35 | "nND-dO-QEg.title" = "Label"; 36 | 37 | /* Class = "NSMenuItem"; title = "Default mode"; ObjectID = "PtY-YF-jEr"; */ 38 | "PtY-YF-jEr.title" = "Mode par défaut"; 39 | 40 | /* Class = "NSMenuItem"; title = "Quit"; ObjectID = "QjA-WT-wFW"; */ 41 | "QjA-WT-wFW.title" = "Quitter"; 42 | 43 | /* Class = "NSSegmentedCell"; qZf-Wa-JJt.ibShadowedToolTips[0] = "Change mode with the active application"; ObjectID = "qZf-Wa-JJt"; */ 44 | "qZf-Wa-JJt.ibShadowedToolTips[0]" = "Bascule le mode en fonction de l'application active"; 45 | 46 | /* Class = "NSSegmentedCell"; qZf-Wa-JJt.ibShadowedToolTips[1] = "Set mode for the active application when the fn key is pressed"; ObjectID = "qZf-Wa-JJt"; */ 47 | "qZf-Wa-JJt.ibShadowedToolTips[1]" = "Bascule le mode quand la touche Fn est pressée"; 48 | 49 | /* Class = "NSSegmentedCell"; qZf-Wa-JJt.ibShadowedToolTips[2] = "Set the default mode when the fn key is pressed"; ObjectID = "qZf-Wa-JJt"; */ 50 | "qZf-Wa-JJt.ibShadowedToolTips[2]" = "Modifie le mode par défaut lors d'un appui sur le touche fn"; 51 | 52 | /* Class = "NSTextFieldCell"; title = "Default mode"; ObjectID = "S28-Jt-nN1"; */ 53 | "S28-Jt-nN1.title" = "Mode par défaut"; 54 | 55 | /* Class = "NSMenuItem"; title = "Preferences..."; ObjectID = "sjb-Ql-h6c"; */ 56 | "sjb-Ql-h6c.title" = "Préférences..."; 57 | 58 | /* Class = "NSMenuItem"; title = "Current application"; ObjectID = "ulH-vE-QEF"; */ 59 | "ulH-vE-QEF.title" = "Application active"; 60 | 61 | /* Class = "NSSegmentedCell"; Vfh-zJ-Axi.ibShadowedToolTips[0] = "Media keys mode"; ObjectID = "Vfh-zJ-Axi"; */ 62 | "Vfh-zJ-Axi.ibShadowedToolTips[0]" = "Switch to Apple mode"; 63 | 64 | /* Class = "NSSegmentedCell"; Vfh-zJ-Axi.ibShadowedToolTips[1] = "Function keys mode"; ObjectID = "Vfh-zJ-Axi"; */ 65 | "Vfh-zJ-Axi.ibShadowedToolTips[1]" = "Switch to function key mode"; 66 | 67 | -------------------------------------------------------------------------------- /Fluor/fr.lproj/RulesEditor.strings: -------------------------------------------------------------------------------- 1 | /* Class = "NSTextFieldCell"; title = "Text Cell"; ObjectID = "3Tm-fC-RsQ"; */ 2 | "3Tm-fC-RsQ.title" = "Text Cell"; 3 | 4 | /* Class = "NSTextFieldCell"; title = "Label"; ObjectID = "Bp2-iW-iXC"; */ 5 | "Bp2-iW-iXC.title" = "Label"; 6 | 7 | /* Class = "CocoaBindingsConnection"; ibShadowedDisplayPattern = "%{value1}@ rules"; ObjectID = "Ddg-CJ-Ktm"; */ 8 | "Ddg-CJ-Ktm.ibShadowedDisplayPattern" = "%{value1}@ règles"; 9 | 10 | /* Class = "NSWindow"; title = "Rules"; ObjectID = "eXk-yp-Np1"; */ 11 | "eXk-yp-Np1.title" = "Règles"; 12 | 13 | /* Class = "NSToolbarItem"; paletteLabel = "Search"; ObjectID = "Fxg-EK-kQD"; */ 14 | "Fxg-EK-kQD.paletteLabel" = "Rechercher"; 15 | 16 | /* Class = "NSSegmentedCell"; qsY-JB-wQQ.ibShadowedToolTips[0] = "Add rule"; ObjectID = "qsY-JB-wQQ"; */ 17 | "qsY-JB-wQQ.ibShadowedToolTips[0]" = "Ajouter une règle"; 18 | 19 | /* Class = "NSSegmentedCell"; qsY-JB-wQQ.ibShadowedToolTips[1] = "Delete selected rule"; ObjectID = "qsY-JB-wQQ"; */ 20 | "qsY-JB-wQQ.ibShadowedToolTips[1]" = "Supprimer la règle selectionnée"; 21 | 22 | /* Class = "NSSegmentedCell"; Xfv-1b-Hu4.ibShadowedToolTips[0] = "Media keys mode"; ObjectID = "Xfv-1b-Hu4"; */ 23 | "Xfv-1b-Hu4.ibShadowedToolTips[0]" = "Touches Apple"; 24 | 25 | /* Class = "NSSegmentedCell"; Xfv-1b-Hu4.ibShadowedToolTips[1] = "Function keys mode"; ObjectID = "Xfv-1b-Hu4"; */ 26 | "Xfv-1b-Hu4.ibShadowedToolTips[1]" = "Touches de fonction"; 27 | 28 | /* Class = "NSTextFieldCell"; title = "Label"; ObjectID = "Y1u-Fa-sgm"; */ 29 | "Y1u-Fa-sgm.title" = "Label"; 30 | 31 | -------------------------------------------------------------------------------- /Fluor/fr.lproj/RunningApps.strings: -------------------------------------------------------------------------------- 1 | /* Class = "CocoaBindingsConnection"; ibShadowedDisplayPattern = "%{value1}@ running"; ObjectID = "8nZ-Ag-ymF"; */ 2 | "8nZ-Ag-ymF.ibShadowedDisplayPattern" = "%{value1}@ en cours d'exécution"; 3 | 4 | /* Class = "NSTextFieldCell"; title = "Label"; ObjectID = "b56-33-3LM"; */ 5 | "b56-33-3LM.title" = "Label"; 6 | 7 | /* Class = "NSTextFieldCell"; title = "Text Cell"; ObjectID = "bZs-z5-c1g"; */ 8 | "bZs-z5-c1g.title" = "Text Cell"; 9 | 10 | /* Class = "NSSegmentedCell"; q73-3D-poM.ibShadowedToolTips[0] = "Same as default"; ObjectID = "q73-3D-poM"; */ 11 | "q73-3D-poM.ibShadowedToolTips[0]" = "Par défaut"; 12 | 13 | /* Class = "NSSegmentedCell"; q73-3D-poM.ibShadowedToolTips[1] = "Media keys mode"; ObjectID = "q73-3D-poM"; */ 14 | "q73-3D-poM.ibShadowedToolTips[1]" = "Touches Apple"; 15 | 16 | /* Class = "NSSegmentedCell"; q73-3D-poM.ibShadowedToolTips[2] = "Function keys mode"; ObjectID = "q73-3D-poM"; */ 17 | "q73-3D-poM.ibShadowedToolTips[2]" = "Touches de fonction"; 18 | 19 | /* Class = "NSTextFieldCell"; title = "Label"; ObjectID = "Twm-uj-Z9c"; */ 20 | "Twm-uj-Z9c.title" = "Label"; 21 | 22 | /* Class = "NSToolbarItem"; label = "Search"; ObjectID = "u25-IX-3ln"; */ 23 | "u25-IX-3ln.label" = "Rechercher"; 24 | 25 | /* Class = "NSToolbarItem"; paletteLabel = "Search"; ObjectID = "u25-IX-3ln"; */ 26 | "u25-IX-3ln.paletteLabel" = "Rechercher"; 27 | 28 | /* Class = "NSWindow"; title = "Running Applications"; ObjectID = "Vdh-R9-Luc"; */ 29 | "Vdh-R9-Luc.title" = "Applications en cours"; 30 | 31 | /* Class = "NSButtonCell"; alternateTitle = "Hide services"; ObjectID = "Yb5-hU-zbp"; */ 32 | "Yb5-hU-zbp.alternateTitle" = "Cacher les services"; 33 | 34 | /* Class = "NSButtonCell"; title = "Show all"; ObjectID = "Yb5-hU-zbp"; */ 35 | "Yb5-hU-zbp.title" = "Montrer tout"; 36 | 37 | -------------------------------------------------------------------------------- /Fluor/zh-Hans.lproj/About.strings: -------------------------------------------------------------------------------- 1 | 2 | /* Class = "NSButtonCell"; title = "Release notes"; ObjectID = "3LZ-kH-mRF"; */ 3 | "3LZ-kH-mRF.title" = "发行说明"; 4 | 5 | /* Class = "NSTextFieldCell"; title = "Copyright (c) Pyrolyse 2016-2019"; ObjectID = "D9M-Xx-uVv"; */ 6 | "D9M-Xx-uVv.title" = "版权所有 (c) Pyrolyse 2016-2019"; 7 | 8 | /* Class = "NSButtonCell"; title = "Update"; ObjectID = "DN8-JH-bOp"; */ 9 | "DN8-JH-bOp.title" = "更新"; 10 | 11 | /* Class = "NSToolbarItem"; label = "Custom View"; ObjectID = "F1c-dv-XMN"; */ 12 | "F1c-dv-XMN.label" = "Custom View"; 13 | 14 | /* Class = "NSToolbarItem"; paletteLabel = "Custom View"; ObjectID = "F1c-dv-XMN"; */ 15 | "F1c-dv-XMN.paletteLabel" = "Custom View"; 16 | 17 | /* Class = "NSWindow"; title = "Window"; ObjectID = "Iyh-kg-rFF"; */ 18 | "Iyh-kg-rFF.title" = "Window"; 19 | 20 | /* Class = "NSButton"; ibShadowedToolTip = "Pyrolyse Website"; ObjectID = "LAF-Vr-LJH"; */ 21 | "LAF-Vr-LJH.ibShadowedToolTip" = "Pyrolyse 网站"; 22 | 23 | /* Class = "NSTextFieldCell"; title = "Fluor"; ObjectID = "Rb1-qw-yPI"; */ 24 | "Rb1-qw-yPI.title" = "Fluor"; 25 | 26 | /* Class = "NSWindow"; title = "Window"; ObjectID = "Xar-Fu-9dh"; */ 27 | "Xar-Fu-9dh.title" = "Window"; 28 | 29 | /* Class = "NSToolbarItem"; label = "Custom View"; ObjectID = "c5J-iu-x6L"; */ 30 | "c5J-iu-x6L.label" = "Custom View"; 31 | 32 | /* Class = "NSToolbarItem"; paletteLabel = "Custom View"; ObjectID = "c5J-iu-x6L"; */ 33 | "c5J-iu-x6L.paletteLabel" = "Custom View"; 34 | 35 | /* Class = "NSButtonCell"; title = "Technical support"; ObjectID = "k51-I5-gTD"; */ 36 | "k51-I5-gTD.title" = "技术支持"; 37 | 38 | /* Class = "NSTextFieldCell"; title = "Version"; ObjectID = "nBp-xh-w5r"; */ 39 | "nBp-xh-w5r.title" = "版本"; 40 | 41 | /* Class = "NSButton"; ibShadowedToolTip = "Twitter Account"; ObjectID = "tcP-8l-Eun"; */ 42 | "tcP-8l-Eun.ibShadowedToolTip" = "Twitter 帐号"; 43 | 44 | /* Class = "NSButton"; ibShadowedToolTip = "Fork me on GitHub"; ObjectID = "z33-BR-yuW"; */ 45 | "z33-BR-yuW.ibShadowedToolTip" = "Fork me on GitHub"; 46 | -------------------------------------------------------------------------------- /Fluor/zh-Hans.lproj/Localizable.strings: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Pyroh/Fluor/6b5fcd11324dfe99ef0fb20d4015625a0e96f283/Fluor/zh-Hans.lproj/Localizable.strings -------------------------------------------------------------------------------- /Fluor/zh-Hans.lproj/MainMenu.strings: -------------------------------------------------------------------------------- 1 | 2 | /* Class = "NSSegmentedCell"; 1I5-bW-HGh.ibShadowedToolTips[0] = "Same as default mode"; ObjectID = "1I5-bW-HGh"; */ 3 | "1I5-bW-HGh.ibShadowedToolTips[0]" = "与默认模式相同"; 4 | 5 | /* Class = "NSSegmentedCell"; 1I5-bW-HGh.ibShadowedToolTips[1] = "Media keys mode"; ObjectID = "1I5-bW-HGh"; */ 6 | "1I5-bW-HGh.ibShadowedToolTips[1]" = "媒体键模式"; 7 | 8 | /* Class = "NSSegmentedCell"; 1I5-bW-HGh.ibShadowedToolTips[2] = "Function keys mode"; ObjectID = "1I5-bW-HGh"; */ 9 | "1I5-bW-HGh.ibShadowedToolTips[2]" = "功能键模式"; 10 | 11 | /* Class = "NSTextFieldCell"; title = "Trigger"; ObjectID = "AiN-Qo-Ikx"; */ 12 | "AiN-Qo-Ikx.title" = "切换方式"; 13 | 14 | /* Class = "NSMenuItem"; title = "Running applications..."; ObjectID = "Ark-Du-XrQ"; */ 15 | "Ark-Du-XrQ.title" = "运行中的应用..."; 16 | 17 | /* Class = "NSMenuItem"; title = "Disabled"; ObjectID = "DqN-qz-yQz"; */ 18 | "DqN-qz-yQz.title" = "禁用"; 19 | 20 | /* Class = "NSMenuItem"; title = "About Fluor"; ObjectID = "Ib7-Rw-HnK"; */ 21 | "Ib7-Rw-HnK.title" = "关于 Fluor"; 22 | 23 | /* Class = "NSMenuItem"; title = "Manage rules..."; ObjectID = "MHf-OK-jHk"; */ 24 | "MHf-OK-jHk.title" = "规则..."; 25 | 26 | /* Class = "NSMenuItem"; title = "Default mode"; ObjectID = "PtY-YF-jEr"; */ 27 | "PtY-YF-jEr.title" = "默认模式"; 28 | 29 | /* Class = "NSMenuItem"; title = "sep2"; ObjectID = "QCJ-IJ-MMQ"; */ 30 | "QCJ-IJ-MMQ.title" = "sep2"; 31 | 32 | /* Class = "NSMenuItem"; title = "Quit"; ObjectID = "QjA-WT-wFW"; */ 33 | "QjA-WT-wFW.title" = "退出"; 34 | 35 | /* Class = "NSTextFieldCell"; title = "Default mode"; ObjectID = "S28-Jt-nN1"; */ 36 | "S28-Jt-nN1.title" = "默认模式"; 37 | 38 | /* Class = "NSSegmentedCell"; Vfh-zJ-Axi.ibShadowedToolTips[0] = "Media keys mode"; ObjectID = "Vfh-zJ-Axi"; */ 39 | "Vfh-zJ-Axi.ibShadowedToolTips[0]" = "媒体键模式"; 40 | 41 | /* Class = "NSSegmentedCell"; Vfh-zJ-Axi.ibShadowedToolTips[1] = "Function keys mode"; ObjectID = "Vfh-zJ-Axi"; */ 42 | "Vfh-zJ-Axi.ibShadowedToolTips[1]" = "功能键模式"; 43 | 44 | /* Class = "NSMenuItem"; title = "Start Fluor at login"; ObjectID = "eWy-d7-62P"; */ 45 | "eWy-d7-62P.title" = "自动启动"; 46 | 47 | /* Class = "NSButtonCell"; title = "Ask permission"; ObjectID = "gP8-wU-Xyk"; */ 48 | "gP8-wU-Xyk.title" = "请求权限"; 49 | 50 | /* Class = "NSMenuItem"; title = "Switch method"; ObjectID = "hM4-Z2-ndk"; */ 51 | "hM4-Z2-ndk.title" = "Switch method"; 52 | 53 | /* Class = "NSTextFieldCell"; title = "Label"; ObjectID = "nND-dO-QEg"; */ 54 | "nND-dO-QEg.title" = "Label"; 55 | 56 | /* Class = "NSSegmentedCell"; qZf-Wa-JJt.ibShadowedToolTips[0] = "Change mode with the active application"; ObjectID = "qZf-Wa-JJt"; */ 57 | "qZf-Wa-JJt.ibShadowedToolTips[0]" = "随活动的应用自动切换模式"; 58 | 59 | /* Class = "NSSegmentedCell"; qZf-Wa-JJt.ibShadowedToolTips[1] = "Set mode for the active application when the fn key is pressed"; ObjectID = "qZf-Wa-JJt"; */ 60 | "qZf-Wa-JJt.ibShadowedToolTips[1]" = "通过按 fn 键为活动的应用切换模式"; 61 | 62 | /* Class = "NSSegmentedCell"; qZf-Wa-JJt.ibShadowedToolTips[2] = "Set the default mode when the fn key is pressed"; ObjectID = "qZf-Wa-JJt"; */ 63 | "qZf-Wa-JJt.ibShadowedToolTips[2]" = "通过按 fn 键切换默认模式"; 64 | 65 | /* Class = "NSMenuItem"; title = "sep1"; ObjectID = "qvx-bn-WPk"; */ 66 | "qvx-bn-WPk.title" = "sep1"; 67 | 68 | /* Class = "NSMenuItem"; title = "Preferences..."; ObjectID = "sjb-Ql-h6c"; */ 69 | "sjb-Ql-h6c.title" = "偏好设置..."; 70 | 71 | /* Class = "NSMenuItem"; title = "Current application"; ObjectID = "ulH-vE-QEF"; */ 72 | "ulH-vE-QEF.title" = "当前应用"; 73 | -------------------------------------------------------------------------------- /Fluor/zh-Hans.lproj/Preferences.strings: -------------------------------------------------------------------------------- 1 | 2 | /* Class = "NSTextFieldCell"; title = "When do you want notifications to be sent ?"; ObjectID = "0PF-9f-i6n"; */ 3 | "0PF-9f-i6n.title" = "您希望何时收到通知?"; 4 | 5 | /* Class = "NSTabViewItem"; label = "Advanced"; ObjectID = "18q-Zg-Tl1"; */ 6 | "18q-Zg-Tl1.label" = "高级"; 7 | 8 | /* Class = "NSTextFieldCell"; title = "3."; ObjectID = "Cvg-Yl-ZC5"; */ 9 | "Cvg-Yl-ZC5.title" = "3."; 10 | 11 | /* Class = "NSTextFieldCell"; title = "Default mode on launch"; ObjectID = "F4H-9X-Gkc"; */ 12 | "F4H-9X-Gkc.title" = "启动时的默认模式"; 13 | 14 | /* Class = "NSTabViewItem"; label = "General"; ObjectID = "Hob-Dv-Dm7"; */ 15 | "Hob-Dv-Dm7.label" = "一般"; 16 | 17 | /* Class = "NSTextFieldCell"; title = "Find and select Fluor in the list"; ObjectID = "IKU-zN-gyv"; */ 18 | "IKU-zN-gyv.title" = "Find and select Fluor in the list"; 19 | 20 | /* Class = "NSSegmentedCell"; J3t-x7-5C6.ibShadowedToolTips[0] = "Media keys mode"; ObjectID = "J3t-x7-5C6"; */ 21 | "J3t-x7-5C6.ibShadowedToolTips[0]" = "媒体键模式"; 22 | 23 | /* Class = "NSSegmentedCell"; J3t-x7-5C6.ibShadowedToolTips[1] = "Function keys mode"; ObjectID = "J3t-x7-5C6"; */ 24 | "J3t-x7-5C6.ibShadowedToolTips[1]" = "功能键模式"; 25 | 26 | /* Class = "NSTextFieldCell"; title = "Send notification "; ObjectID = "Jmi-kR-PLT"; */ 27 | "Jmi-kR-PLT.title" = "发送通知 "; 28 | 29 | /* Class = "NSWindow"; title = "Preferences"; ObjectID = "N9r-FQ-Oq3"; */ 30 | "N9r-FQ-Oq3.title" = "偏好设置"; 31 | 32 | /* Class = "NSButtonCell"; title = "Automaticaly download updates"; ObjectID = "RZl-MW-RaS"; */ 33 | "RZl-MW-RaS.title" = "自动下载更新"; 34 | 35 | /* Class = "NSTextFieldCell"; title = "Last Checked:"; ObjectID = "TZA-yl-nGe"; */ 36 | "TZA-yl-nGe.title" = "最后检查时间:"; 37 | 38 | /* Class = "NSViewController"; title = "Advanced"; ObjectID = "UoT-kw-xfb"; */ 39 | "UoT-kw-xfb.title" = "高级"; 40 | 41 | /* Class = "NSButtonCell"; title = "Check now"; ObjectID = "Vtq-y9-sm5"; */ 42 | "Vtq-y9-sm5.title" = "立即检查"; 43 | 44 | /* Class = "NSSegmentedCell"; aHs-kY-jFz.ibShadowedToolTips[0] = "Media keys mode"; ObjectID = "aHs-kY-jFz"; */ 45 | "aHs-kY-jFz.ibShadowedToolTips[0]" = "媒体键模式"; 46 | 47 | /* Class = "NSSegmentedCell"; aHs-kY-jFz.ibShadowedToolTips[1] = "Function keys mode"; ObjectID = "aHs-kY-jFz"; */ 48 | "aHs-kY-jFz.ibShadowedToolTips[1]" = "功能键模式"; 49 | 50 | /* Class = "NSViewController"; title = "General"; ObjectID = "bdY-l4-Nw7"; */ 51 | "bdY-l4-Nw7.title" = "一般"; 52 | 53 | /* Class = "NSButtonCell"; title = "Restore startup mode"; ObjectID = "cXi-qe-jsD"; */ 54 | "cXi-qe-jsD.title" = "恢复启动时的模式"; 55 | 56 | /* Class = "NSButtonCell"; title = "Open Notifications preference pane"; ObjectID = "caw-E4-tuY"; */ 57 | "caw-E4-tuY.title" = "打开通知偏好设置"; 58 | 59 | /* Class = "NSTabViewItem"; label = "Updates"; ObjectID = "dHq-vD-kde"; */ 60 | "dHq-vD-kde.label" = "更新"; 61 | 62 | /* Class = "NSViewController"; title = "Updates"; ObjectID = "dlC-Ac-YKV"; */ 63 | "dlC-Ac-YKV.title" = "更新"; 64 | 65 | /* Class = "NSTextFieldCell"; title = "When the current application mode is set by pressing the fn key"; ObjectID = "ezd-7Z-VvY"; */ 66 | "ezd-7Z-VvY.title" = "当按 fn 键切换当前应用模式时"; 67 | 68 | /* Class = "NSTextFieldCell"; title = "When the global mode is set by pressing the fn key"; ObjectID = "fT0-a8-Fn0"; */ 69 | "fT0-a8-Fn0.title" = "当按 fn 键切换全局模式时"; 70 | 71 | /* Class = "NSTabViewController"; title = "Preferences"; ObjectID = "glG-bk-x2Q"; */ 72 | "glG-bk-x2Q.title" = "偏好设置"; 73 | 74 | /* Class = "NSTabViewItem"; label = "Notifications"; ObjectID = "hM9-Ia-nxv"; */ 75 | "hM9-Ia-nxv.label" = "通知"; 76 | 77 | /* Class = "NSButtonCell"; title = "Everytime"; ObjectID = "hgm-4a-jDl"; */ 78 | "hgm-4a-jDl.title" = "全部通知"; 79 | 80 | /* Class = "NSTextFieldCell"; title = "Activate the Allow Notification from Fluor switch"; ObjectID = "hv4-f4-B7v"; */ 81 | "hv4-f4-B7v.title" = "Activate the Allow Notification from Fluor switch"; 82 | 83 | /* Class = "NSButtonCell"; title = "Use light menu icon"; ObjectID = "j3E-2l-1wC"; */ 84 | "j3E-2l-1wC.title" = "使用浅色菜单栏图标"; 85 | 86 | /* Class = "CocoaBindingsConnection"; ibShadowedIsNilPlaceholder = "280ms"; ObjectID = "kjd-tC-eHL"; */ 87 | "kjd-tC-eHL.ibShadowedIsNilPlaceholder" = "280ms"; 88 | 89 | /* Class = "NSButtonCell"; title = "Start Fluor at login"; ObjectID = "kkr-ac-7zW"; */ 90 | "kkr-ac-7zW.title" = "登陆时启动 Fluor"; 91 | 92 | /* Class = "NSTextFieldCell"; title = "2."; ObjectID = "lXR-Ye-zzj"; */ 93 | "lXR-Ye-zzj.title" = "2."; 94 | 95 | /* Class = "NSTextFieldCell"; title = "1."; ObjectID = "mjv-jW-mRK"; */ 96 | "mjv-jW-mRK.title" = "1."; 97 | 98 | /* Class = "NSButtonCell"; title = "Reset mode on quit"; ObjectID = "o0g-Zi-PDV"; */ 99 | "o0g-Zi-PDV.title" = "退出时将模式重置为"; 100 | 101 | /* Class = "NSButtonCell"; title = "Always show all running processes"; ObjectID = "oGT-JF-Yp4"; */ 102 | "oGT-JF-Yp4.title" = "总是显示所有正在运行的进程"; 103 | 104 | /* Class = "NSButtonCell"; title = "Hide the trigger method selection section"; ObjectID = "qxq-5O-b7c"; */ 105 | "qxq-5O-b7c.title" = "隐藏菜单中的切换方式"; 106 | 107 | /* Class = "NSTextFieldCell"; title = "Fn key release maximum delay:"; ObjectID = "sJJ-c6-Cuv"; */ 108 | "sJJ-c6-Cuv.title" = "Fn 键释放最大延迟:"; 109 | 110 | /* Class = "NSTextFieldCell"; title = "Yesterday at 16:28"; ObjectID = "tQx-sm-17A"; */ 111 | "tQx-sm-17A.title" = "昨天 16:28"; 112 | 113 | /* Class = "NSTextFieldCell"; title = "When the mode changes with the active application"; ObjectID = "tcj-WZ-834"; */ 114 | "tcj-WZ-834.title" = "当模式随活动应用程序而改变时"; 115 | 116 | /* Class = "NSButtonCell"; title = "Automaticaly check for updates"; ObjectID = "xgt-53-WGT"; */ 117 | "xgt-53-WGT.title" = "自动检查更新"; 118 | -------------------------------------------------------------------------------- /Fluor/zh-Hans.lproj/RulesEditor.strings: -------------------------------------------------------------------------------- 1 | 2 | /* Class = "NSTextFieldCell"; title = "Text Cell"; ObjectID = "3Tm-fC-RsQ"; */ 3 | "3Tm-fC-RsQ.title" = "Text Cell"; 4 | 5 | /* Class = "NSTextFieldCell"; title = "Label"; ObjectID = "Bp2-iW-iXC"; */ 6 | "Bp2-iW-iXC.title" = "Label"; 7 | 8 | /* Class = "CocoaBindingsConnection"; ibShadowedDisplayPattern = "%{value1}@ rules"; ObjectID = "Ddg-CJ-Ktm"; */ 9 | "Ddg-CJ-Ktm.ibShadowedDisplayPattern" = "规则数量: %{value1}@"; 10 | 11 | /* Class = "NSToolbarItem"; paletteLabel = "Search"; ObjectID = "Fxg-EK-kQD"; */ 12 | "Fxg-EK-kQD.paletteLabel" = "搜索"; 13 | 14 | /* Class = "NSSegmentedCell"; Xfv-1b-Hu4.ibShadowedToolTips[0] = "Media keys mode"; ObjectID = "Xfv-1b-Hu4"; */ 15 | "Xfv-1b-Hu4.ibShadowedToolTips[0]" = "媒体键模式"; 16 | 17 | /* Class = "NSSegmentedCell"; Xfv-1b-Hu4.ibShadowedToolTips[1] = "Function keys mode"; ObjectID = "Xfv-1b-Hu4"; */ 18 | "Xfv-1b-Hu4.ibShadowedToolTips[1]" = "功能键模式"; 19 | 20 | /* Class = "NSTextFieldCell"; title = "Label"; ObjectID = "Y1u-Fa-sgm"; */ 21 | "Y1u-Fa-sgm.title" = "Label"; 22 | 23 | /* Class = "NSWindow"; title = "Rules"; ObjectID = "eXk-yp-Np1"; */ 24 | "eXk-yp-Np1.title" = "规则"; 25 | 26 | /* Class = "NSSegmentedCell"; qsY-JB-wQQ.ibShadowedToolTips[0] = "Add rule"; ObjectID = "qsY-JB-wQQ"; */ 27 | "qsY-JB-wQQ.ibShadowedToolTips[0]" = "添加规则"; 28 | 29 | /* Class = "NSSegmentedCell"; qsY-JB-wQQ.ibShadowedToolTips[1] = "Delete selected rule"; ObjectID = "qsY-JB-wQQ"; */ 30 | "qsY-JB-wQQ.ibShadowedToolTips[1]" = "删除选中规则"; 31 | -------------------------------------------------------------------------------- /Fluor/zh-Hans.lproj/RunningApps.strings: -------------------------------------------------------------------------------- 1 | 2 | /* Class = "CocoaBindingsConnection"; ibShadowedDisplayPattern = "%{value1}@ running"; ObjectID = "8nZ-Ag-ymF"; */ 3 | "8nZ-Ag-ymF.ibShadowedDisplayPattern" = "运行中数量: %{value1}@"; 4 | 5 | /* Class = "NSTextFieldCell"; title = "Label"; ObjectID = "Twm-uj-Z9c"; */ 6 | "Twm-uj-Z9c.title" = "Label"; 7 | 8 | /* Class = "NSWindow"; title = "Running Applications"; ObjectID = "Vdh-R9-Luc"; */ 9 | "Vdh-R9-Luc.title" = "运行中的应用"; 10 | 11 | /* Class = "NSButtonCell"; alternateTitle = "Hide services"; ObjectID = "Yb5-hU-zbp"; */ 12 | "Yb5-hU-zbp.alternateTitle" = "隐藏服务"; 13 | 14 | /* Class = "NSButtonCell"; title = "Show all"; ObjectID = "Yb5-hU-zbp"; */ 15 | "Yb5-hU-zbp.title" = "显示全部"; 16 | 17 | /* Class = "NSTextFieldCell"; title = "Label"; ObjectID = "b56-33-3LM"; */ 18 | "b56-33-3LM.title" = "Label"; 19 | 20 | /* Class = "NSTextFieldCell"; title = "Text Cell"; ObjectID = "bZs-z5-c1g"; */ 21 | "bZs-z5-c1g.title" = "Text Cell"; 22 | 23 | /* Class = "NSSegmentedCell"; q73-3D-poM.ibShadowedToolTips[0] = "Same as default"; ObjectID = "q73-3D-poM"; */ 24 | "q73-3D-poM.ibShadowedToolTips[0]" = "默认模式"; 25 | 26 | /* Class = "NSSegmentedCell"; q73-3D-poM.ibShadowedToolTips[1] = "Media keys mode"; ObjectID = "q73-3D-poM"; */ 27 | "q73-3D-poM.ibShadowedToolTips[1]" = "媒体键模式"; 28 | 29 | /* Class = "NSSegmentedCell"; q73-3D-poM.ibShadowedToolTips[2] = "Function keys mode"; ObjectID = "q73-3D-poM"; */ 30 | "q73-3D-poM.ibShadowedToolTips[2]" = "功能键模式"; 31 | 32 | /* Class = "NSToolbarItem"; label = "Search"; ObjectID = "u25-IX-3ln"; */ 33 | "u25-IX-3ln.label" = "搜索"; 34 | 35 | /* Class = "NSToolbarItem"; paletteLabel = "Search"; ObjectID = "u25-IX-3ln"; */ 36 | "u25-IX-3ln.paletteLabel" = "搜索"; 37 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2016 Pierre Tacchi 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 4 | 5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 6 | 7 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | # This README is out-of-date 3 | 4 | [![Swift](https://img.shields.io/badge/Swift-4.0-orange.svg?style=flat)](https://developer.apple.com/swift/) 5 | ![version](https://img.shields.io/badge/macOS-10.11+-green.svg?style=flat) 6 | [![License](https://img.shields.io/badge/license-MIT-71787A.svg)](https://tldrlegal.com/license/mit-license) 7 | 8 | 9 | ![](https://github.com/Pyroh/Fluor/blob/master/ressources/banner.png?raw=true) 10 | 11 | > Want to know how **Fluor** development is going ? [**Follow me on Twitter**](https://twitter.com/__pyroh). 12 | 13 | # What is Fluor ? 14 | **Fluor** is a tool that allows you to automatically change the behavior of the keyboard's fn keys depending on the active application. It's that simple. 15 | 16 | # Instaling Fluor 17 | There's two main ways to install **Fluor**: 18 | 19 | 1. Download the [latest release](https://github.com/Pyroh/Fluor/releases), open the DMG and drag the application to your `/Applications` folder. 20 | 2. Install via [Homebrew Cask](https://caskroom.github.io): 21 | `$ brew cask install fluor` 22 | 23 | You can also build it from source, but this is not recommended if your are only going to use **Fluor** in the regular way, and not hack it. 24 | 25 | # How does it work? 26 | 27 | 28 | **Fluor** lies in your status bar and makes you see instantaneously which mode your keyboard is on: 29 | 30 | - means that the keyboard's fn keys act like the default Apple function keys. 31 | - means that the keyboard's fn keys act like these good old function keys (F1, F2, F3, you got it...). 32 | 33 | ## Fluor's menu 34 | This is what you get when you click on **Fluor** in the status bar: 35 | 36 | 37 | 38 | You can choose the default mode. Whenever **Fluor** runs it will activate the default mode for your keyboard's fn keys. 39 | 40 | **Fluor** also displays the active application and its associated rule that you can change on the go. 41 | is the default rule and means that the application will adopt default Fluor's keyboard behaviour. 42 | 43 | You can also disable **Fluor** if you need to. It will set the keyboard's behaviour as it was prior to the application's launch. 44 | 45 | ## Rules Editor 46 | 47 | 48 | This panel allows you to see all the rules you set at once. You can modify or delete any rule. Adding a rule will prompt a file selector in which you'll be able to select the application you want to set a rule for. 49 | 50 | ## Running Applications 51 | 52 | 53 | Sometimes it is not possible to select an application in the *Rules Editor*, especially for Steam games. This panel lets you set a rule for any running application. Of course the rules you set in this panel will be available directly in the *Rules Editor*. You can also remove a rule by setting the application behaviour to , it will also disappear from the *Rules Editor* panel. 54 | 55 | # Why is it open source ? 56 | I made **Fluor** because I needed such an application. I wanted it simple, nicely designed and free and I didn't find such a thing on the internet. Once it was done I used it for a little while, cleaned up the code and decided to give it to others for free. What was a requirement for me can well be a requirement for others too. 57 | You'd argue that such a non-sandboxed app had no chance to hit the AppStore and you'd be right. But if I had the chance it would have remained free and open-source. I don't think there's many people needing such an app and I prefer seeing it used by a wider range of people. 58 | 59 | This app is also built using open-source code, that's why I think it belongs to this world. And if someone learns something looking at the code I'll be happy 😃. 60 | 61 | # Contributing 62 | All contributions are welcome. Fork it, hack it and make a pull request. 63 | 64 | # License 65 | **Fluor** is released under the MIT license. See LICENSE for details. 66 | 67 | Some of [**fntoggle**](https://github.com/nelsonjchen/fntoggle)'s code was used. As its author [wrote](https://github.com/nelsonjchen/fntoggle#license) it could be released under the GPL2 license. 68 | 69 | The code also uses [**LaunchAtLoginController**](https://github.com/Mozketo/LaunchAtLoginController) which is Copyright (c) 2010 Ben Clark-Robinson, ben.clarkrobinson@gmail.com and is released under the MIT LICENSE. 70 | -------------------------------------------------------------------------------- /ressources/banner.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Pyroh/Fluor/6b5fcd11324dfe99ef0fb20d4015625a0e96f283/ressources/banner.png -------------------------------------------------------------------------------- /ressources/mainmenu.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Pyroh/Fluor/6b5fcd11324dfe99ef0fb20d4015625a0e96f283/ressources/mainmenu.png -------------------------------------------------------------------------------- /ressources/preferences.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Pyroh/Fluor/6b5fcd11324dfe99ef0fb20d4015625a0e96f283/ressources/preferences.png -------------------------------------------------------------------------------- /ressources/ruleseditor.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Pyroh/Fluor/6b5fcd11324dfe99ef0fb20d4015625a0e96f283/ressources/ruleseditor.png -------------------------------------------------------------------------------- /ressources/runningapps.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Pyroh/Fluor/6b5fcd11324dfe99ef0fb20d4015625a0e96f283/ressources/runningapps.png -------------------------------------------------------------------------------- /ressources/statusbar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Pyroh/Fluor/6b5fcd11324dfe99ef0fb20d4015625a0e96f283/ressources/statusbar.png --------------------------------------------------------------------------------