├── .gitignore ├── .travis.yml ├── Example ├── OAStatusItemKit Example.xcodeproj │ ├── project.pbxproj │ ├── project.xcworkspace │ │ └── contents.xcworkspacedata │ └── xcshareddata │ │ └── xcschemes │ │ └── OAStatusItemKit-Example.xcscheme └── OAStatusItemKit_Example │ ├── AppDelegate.swift │ ├── Assets.xcassets │ ├── AppIcon.appiconset │ │ └── Contents.json │ ├── Contents.json │ ├── Icon-bright.imageset │ │ ├── Contents.json │ │ ├── Icon.png │ │ └── Icon@2x.png │ └── Icon-dark.imageset │ │ ├── Contents.json │ │ ├── IconHighlighted.png │ │ └── IconHighlighted@2x.png │ ├── Base.lproj │ └── Main.storyboard │ ├── Info.plist │ ├── Panel.xib │ └── ViewController.swift ├── LICENSE ├── Makefile ├── OAStatusItemKit.podspec ├── OAStatusItemKit ├── OAStatusItemKit.xcodeproj │ ├── project.pbxproj │ ├── project.xcworkspace │ │ └── contents.xcworkspacedata │ └── xcshareddata │ │ └── xcschemes │ │ └── OAStatusItemKit.xcscheme ├── OAStatusItemKit.xcworkspace │ └── contents.xcworkspacedata ├── OAStatusItemKit │ ├── Info.plist │ └── OAStatusItemKit.h ├── OAStatusItemKitTests │ ├── ImageDrawerSpec.swift │ ├── Info.plist │ ├── StatusBarImagesSpec.swift │ ├── StatusBarItemViewSpec.swift │ ├── TestHelper.swift │ └── WindowPlacerSpec.swift ├── Podfile └── Podfile.lock ├── Pod └── Classes │ ├── .gitkeep │ ├── BundleLoading.swift │ ├── EventMonitor.swift │ ├── ImageDrawer.swift │ ├── NSImage+Tint.swift │ ├── ScreenWindowPlacer.swift │ ├── StatusBarImages.swift │ ├── StatusBarInterface.swift │ ├── StatusBarItemCenterPlacer.swift │ ├── StatusBarItemView.swift │ ├── StatusBarPopupPresenter.swift │ ├── StatusBarViewPresenter.swift │ ├── StatusBarWindowController.swift │ ├── StatusBarWindowStyle.swift │ ├── StatusPanel.swift │ ├── StatusWindowPlacement.swift │ └── WindowPlacer.swift └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | # OS X 2 | .DS_Store 3 | 4 | # Xcode 5 | build/ 6 | *.pbxuser 7 | !default.pbxuser 8 | *.mode1v3 9 | !default.mode1v3 10 | *.mode2v3 11 | !default.mode2v3 12 | *.perspectivev3 13 | !default.perspectivev3 14 | xcuserdata 15 | *.xccheckout 16 | profile 17 | *.moved-aside 18 | DerivedData 19 | *.hmap 20 | *.ipa 21 | 22 | # Bundler 23 | .bundle 24 | 25 | Carthage 26 | # We recommend against adding the Pods directory to your .gitignore. However 27 | # you should judge for yourself, the pros and cons are mentioned at: 28 | # http://guides.cocoapods.org/using/using-cocoapods.html#should-i-ignore-the-pods-directory-in-source-control 29 | # 30 | # Note: if you ignore the Pods directory, make sure to uncomment 31 | # `pod install` in .travis.yml 32 | # 33 | OAStatusItemKit/Pods/ 34 | 35 | 36 | # Created by https://www.gitignore.io/api/objective-c,swift,xcode 37 | 38 | ### Objective-C ### 39 | # Xcode 40 | # 41 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore 42 | 43 | ## Build generated 44 | build/ 45 | DerivedData 46 | 47 | ## Various settings 48 | *.pbxuser 49 | !default.pbxuser 50 | *.mode1v3 51 | !default.mode1v3 52 | *.mode2v3 53 | !default.mode2v3 54 | *.perspectivev3 55 | !default.perspectivev3 56 | xcuserdata 57 | 58 | ## Other 59 | *.xccheckout 60 | *.moved-aside 61 | *.xcuserstate 62 | *.xcscmblueprint 63 | 64 | ## Obj-C/Swift specific 65 | *.hmap 66 | *.ipa 67 | 68 | # CocoaPods 69 | # 70 | # We recommend against adding the Pods directory to your .gitignore. However 71 | # you should judge for yourself, the pros and cons are mentioned at: 72 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control 73 | # 74 | # Pods/ 75 | 76 | # Carthage 77 | # 78 | # Add this line if you want to avoid checking in source code from Carthage dependencies. 79 | # Carthage/Checkouts 80 | 81 | Carthage/Build 82 | 83 | # fastlane 84 | # 85 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the 86 | # screenshots whenever they are needed. 87 | # For more information about the recommended setup visit: 88 | # https://github.com/fastlane/fastlane/blob/master/docs/Gitignore.md 89 | 90 | fastlane/report.xml 91 | fastlane/screenshots 92 | 93 | ### Objective-C Patch ### 94 | *.xcscmblueprint 95 | 96 | 97 | ### Swift ### 98 | # Xcode 99 | # 100 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore 101 | 102 | ## Build generated 103 | build/ 104 | DerivedData 105 | 106 | ## Various settings 107 | *.pbxuser 108 | !default.pbxuser 109 | *.mode1v3 110 | !default.mode1v3 111 | *.mode2v3 112 | !default.mode2v3 113 | *.perspectivev3 114 | !default.perspectivev3 115 | xcuserdata 116 | 117 | ## Other 118 | *.xccheckout 119 | *.moved-aside 120 | *.xcuserstate 121 | *.xcscmblueprint 122 | 123 | ## Obj-C/Swift specific 124 | *.hmap 125 | *.ipa 126 | 127 | # Swift Package Manager 128 | # 129 | # Add this line if you want to avoid checking in source code from Swift Package Manager dependencies. 130 | # Packages/ 131 | .build/ 132 | 133 | # CocoaPods 134 | # 135 | # We recommend against adding the Pods directory to your .gitignore. However 136 | # you should judge for yourself, the pros and cons are mentioned at: 137 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control 138 | # 139 | # Pods/ 140 | 141 | # Carthage 142 | # 143 | # Add this line if you want to avoid checking in source code from Carthage dependencies. 144 | # Carthage/Checkouts 145 | 146 | Carthage/Build 147 | 148 | # fastlane 149 | # 150 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the 151 | # screenshots whenever they are needed. 152 | # For more information about the recommended setup visit: 153 | # https://github.com/fastlane/fastlane/blob/master/docs/Gitignore.md 154 | 155 | fastlane/report.xml 156 | fastlane/screenshots 157 | 158 | 159 | ### Xcode ### 160 | # Xcode 161 | # 162 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore 163 | 164 | ## Build generated 165 | build/ 166 | DerivedData 167 | 168 | ## Various settings 169 | *.pbxuser 170 | !default.pbxuser 171 | *.mode1v3 172 | !default.mode1v3 173 | *.mode2v3 174 | !default.mode2v3 175 | *.perspectivev3 176 | !default.perspectivev3 177 | xcuserdata 178 | 179 | ## Other 180 | *.xccheckout 181 | *.moved-aside 182 | *.xcuserstate 183 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | sudo: false 2 | language: objective-c 3 | osx_image: xcode8.2 4 | cache: cocoapods 5 | podfile: OAStatusItemKit/Podfile 6 | 7 | install: 8 | - gem install xcpretty --no-rdoc --no-ri --no-document --quiet 9 | 10 | script: 11 | - (cd OAStatusItemKit; pod update) 12 | - make test 13 | - pod lib lint --quick 14 | 15 | after_success: 16 | - bash <(curl -s https://codecov.io/bash) 17 | -------------------------------------------------------------------------------- /Example/OAStatusItemKit Example.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | D76538801C4F23B00073C059 /* OAStatusItemKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D765387B1C4F23A40073C059 /* OAStatusItemKit.framework */; }; 11 | D7D859DB1C517FDD00F2A447 /* Panel.xib in Resources */ = {isa = PBXBuildFile; fileRef = D7D859DA1C517FDD00F2A447 /* Panel.xib */; }; 12 | D7F9F4731C4F1393000ACE5E /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = D7F9F4721C4F1393000ACE5E /* AppDelegate.swift */; }; 13 | D7F9F4751C4F1393000ACE5E /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D7F9F4741C4F1393000ACE5E /* ViewController.swift */; }; 14 | D7F9F4771C4F1393000ACE5E /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = D7F9F4761C4F1393000ACE5E /* Assets.xcassets */; }; 15 | D7F9F47A1C4F1393000ACE5E /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = D7F9F4781C4F1393000ACE5E /* Main.storyboard */; }; 16 | /* End PBXBuildFile section */ 17 | 18 | /* Begin PBXContainerItemProxy section */ 19 | D765387A1C4F23A40073C059 /* PBXContainerItemProxy */ = { 20 | isa = PBXContainerItemProxy; 21 | containerPortal = D76538751C4F23A40073C059 /* OAStatusItemKit.xcodeproj */; 22 | proxyType = 2; 23 | remoteGlobalIDString = D765384F1C4F21010073C059; 24 | remoteInfo = OAStatusItemKit; 25 | }; 26 | D765387C1C4F23A40073C059 /* PBXContainerItemProxy */ = { 27 | isa = PBXContainerItemProxy; 28 | containerPortal = D76538751C4F23A40073C059 /* OAStatusItemKit.xcodeproj */; 29 | proxyType = 2; 30 | remoteGlobalIDString = D76538591C4F21010073C059; 31 | remoteInfo = OAStatusItemKitTests; 32 | }; 33 | D765387E1C4F23AB0073C059 /* PBXContainerItemProxy */ = { 34 | isa = PBXContainerItemProxy; 35 | containerPortal = D76538751C4F23A40073C059 /* OAStatusItemKit.xcodeproj */; 36 | proxyType = 1; 37 | remoteGlobalIDString = D765384E1C4F21010073C059; 38 | remoteInfo = OAStatusItemKit; 39 | }; 40 | /* End PBXContainerItemProxy section */ 41 | 42 | /* Begin PBXFileReference section */ 43 | D76538751C4F23A40073C059 /* OAStatusItemKit.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = OAStatusItemKit.xcodeproj; path = ../OAStatusItemKit/OAStatusItemKit.xcodeproj; sourceTree = ""; }; 44 | D7D859DA1C517FDD00F2A447 /* Panel.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = Panel.xib; sourceTree = ""; }; 45 | D7F9F4701C4F1393000ACE5E /* OAStatusItemKit_Example.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = OAStatusItemKit_Example.app; sourceTree = BUILT_PRODUCTS_DIR; }; 46 | D7F9F4721C4F1393000ACE5E /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 47 | D7F9F4741C4F1393000ACE5E /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = ""; }; 48 | D7F9F4761C4F1393000ACE5E /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 49 | D7F9F4791C4F1393000ACE5E /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 50 | D7F9F47B1C4F1393000ACE5E /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 51 | /* End PBXFileReference section */ 52 | 53 | /* Begin PBXFrameworksBuildPhase section */ 54 | D7F9F46D1C4F1393000ACE5E /* Frameworks */ = { 55 | isa = PBXFrameworksBuildPhase; 56 | buildActionMask = 2147483647; 57 | files = ( 58 | D76538801C4F23B00073C059 /* OAStatusItemKit.framework in Frameworks */, 59 | ); 60 | runOnlyForDeploymentPostprocessing = 0; 61 | }; 62 | /* End PBXFrameworksBuildPhase section */ 63 | 64 | /* Begin PBXGroup section */ 65 | 607FACC71AFB9204008FA782 = { 66 | isa = PBXGroup; 67 | children = ( 68 | D76538751C4F23A40073C059 /* OAStatusItemKit.xcodeproj */, 69 | D7F9F4711C4F1393000ACE5E /* Example for OAStatusItemKit */, 70 | 607FACD11AFB9204008FA782 /* Products */, 71 | ); 72 | sourceTree = ""; 73 | }; 74 | 607FACD11AFB9204008FA782 /* Products */ = { 75 | isa = PBXGroup; 76 | children = ( 77 | D7F9F4701C4F1393000ACE5E /* OAStatusItemKit_Example.app */, 78 | ); 79 | name = Products; 80 | sourceTree = ""; 81 | }; 82 | D76538761C4F23A40073C059 /* Products */ = { 83 | isa = PBXGroup; 84 | children = ( 85 | D765387B1C4F23A40073C059 /* OAStatusItemKit.framework */, 86 | D765387D1C4F23A40073C059 /* OAStatusItemKitTests.xctest */, 87 | ); 88 | name = Products; 89 | sourceTree = ""; 90 | }; 91 | D7F9F4711C4F1393000ACE5E /* Example for OAStatusItemKit */ = { 92 | isa = PBXGroup; 93 | children = ( 94 | D7F9F4721C4F1393000ACE5E /* AppDelegate.swift */, 95 | D7F9F4741C4F1393000ACE5E /* ViewController.swift */, 96 | D7F9F4761C4F1393000ACE5E /* Assets.xcassets */, 97 | D7F9F4781C4F1393000ACE5E /* Main.storyboard */, 98 | D7F9F47B1C4F1393000ACE5E /* Info.plist */, 99 | D7D859DA1C517FDD00F2A447 /* Panel.xib */, 100 | ); 101 | name = "Example for OAStatusItemKit"; 102 | path = OAStatusItemKit_Example; 103 | sourceTree = ""; 104 | }; 105 | /* End PBXGroup section */ 106 | 107 | /* Begin PBXNativeTarget section */ 108 | D7F9F46F1C4F1393000ACE5E /* OAStatusItemKit_Example */ = { 109 | isa = PBXNativeTarget; 110 | buildConfigurationList = D7F9F47C1C4F1393000ACE5E /* Build configuration list for PBXNativeTarget "OAStatusItemKit_Example" */; 111 | buildPhases = ( 112 | D7F9F46C1C4F1393000ACE5E /* Sources */, 113 | D7F9F46D1C4F1393000ACE5E /* Frameworks */, 114 | D7F9F46E1C4F1393000ACE5E /* Resources */, 115 | ); 116 | buildRules = ( 117 | ); 118 | dependencies = ( 119 | D765387F1C4F23AB0073C059 /* PBXTargetDependency */, 120 | ); 121 | name = OAStatusItemKit_Example; 122 | productName = OAStatusItemKit_Example; 123 | productReference = D7F9F4701C4F1393000ACE5E /* OAStatusItemKit_Example.app */; 124 | productType = "com.apple.product-type.application"; 125 | }; 126 | /* End PBXNativeTarget section */ 127 | 128 | /* Begin PBXProject section */ 129 | 607FACC81AFB9204008FA782 /* Project object */ = { 130 | isa = PBXProject; 131 | attributes = { 132 | LastSwiftUpdateCheck = 0720; 133 | LastUpgradeCheck = 0720; 134 | ORGANIZATIONNAME = CocoaPods; 135 | TargetAttributes = { 136 | D7F9F46F1C4F1393000ACE5E = { 137 | CreatedOnToolsVersion = 7.2; 138 | LastSwiftMigration = 0820; 139 | }; 140 | }; 141 | }; 142 | buildConfigurationList = 607FACCB1AFB9204008FA782 /* Build configuration list for PBXProject "OAStatusItemKit Example" */; 143 | compatibilityVersion = "Xcode 3.2"; 144 | developmentRegion = English; 145 | hasScannedForEncodings = 0; 146 | knownRegions = ( 147 | en, 148 | Base, 149 | ); 150 | mainGroup = 607FACC71AFB9204008FA782; 151 | productRefGroup = 607FACD11AFB9204008FA782 /* Products */; 152 | projectDirPath = ""; 153 | projectReferences = ( 154 | { 155 | ProductGroup = D76538761C4F23A40073C059 /* Products */; 156 | ProjectRef = D76538751C4F23A40073C059 /* OAStatusItemKit.xcodeproj */; 157 | }, 158 | ); 159 | projectRoot = ""; 160 | targets = ( 161 | D7F9F46F1C4F1393000ACE5E /* OAStatusItemKit_Example */, 162 | ); 163 | }; 164 | /* End PBXProject section */ 165 | 166 | /* Begin PBXReferenceProxy section */ 167 | D765387B1C4F23A40073C059 /* OAStatusItemKit.framework */ = { 168 | isa = PBXReferenceProxy; 169 | fileType = wrapper.framework; 170 | path = OAStatusItemKit.framework; 171 | remoteRef = D765387A1C4F23A40073C059 /* PBXContainerItemProxy */; 172 | sourceTree = BUILT_PRODUCTS_DIR; 173 | }; 174 | D765387D1C4F23A40073C059 /* OAStatusItemKitTests.xctest */ = { 175 | isa = PBXReferenceProxy; 176 | fileType = wrapper.cfbundle; 177 | path = OAStatusItemKitTests.xctest; 178 | remoteRef = D765387C1C4F23A40073C059 /* PBXContainerItemProxy */; 179 | sourceTree = BUILT_PRODUCTS_DIR; 180 | }; 181 | /* End PBXReferenceProxy section */ 182 | 183 | /* Begin PBXResourcesBuildPhase section */ 184 | D7F9F46E1C4F1393000ACE5E /* Resources */ = { 185 | isa = PBXResourcesBuildPhase; 186 | buildActionMask = 2147483647; 187 | files = ( 188 | D7F9F4771C4F1393000ACE5E /* Assets.xcassets in Resources */, 189 | D7D859DB1C517FDD00F2A447 /* Panel.xib in Resources */, 190 | D7F9F47A1C4F1393000ACE5E /* Main.storyboard in Resources */, 191 | ); 192 | runOnlyForDeploymentPostprocessing = 0; 193 | }; 194 | /* End PBXResourcesBuildPhase section */ 195 | 196 | /* Begin PBXSourcesBuildPhase section */ 197 | D7F9F46C1C4F1393000ACE5E /* Sources */ = { 198 | isa = PBXSourcesBuildPhase; 199 | buildActionMask = 2147483647; 200 | files = ( 201 | D7F9F4751C4F1393000ACE5E /* ViewController.swift in Sources */, 202 | D7F9F4731C4F1393000ACE5E /* AppDelegate.swift in Sources */, 203 | ); 204 | runOnlyForDeploymentPostprocessing = 0; 205 | }; 206 | /* End PBXSourcesBuildPhase section */ 207 | 208 | /* Begin PBXTargetDependency section */ 209 | D765387F1C4F23AB0073C059 /* PBXTargetDependency */ = { 210 | isa = PBXTargetDependency; 211 | name = OAStatusItemKit; 212 | targetProxy = D765387E1C4F23AB0073C059 /* PBXContainerItemProxy */; 213 | }; 214 | /* End PBXTargetDependency section */ 215 | 216 | /* Begin PBXVariantGroup section */ 217 | D7F9F4781C4F1393000ACE5E /* Main.storyboard */ = { 218 | isa = PBXVariantGroup; 219 | children = ( 220 | D7F9F4791C4F1393000ACE5E /* Base */, 221 | ); 222 | name = Main.storyboard; 223 | sourceTree = ""; 224 | }; 225 | /* End PBXVariantGroup section */ 226 | 227 | /* Begin XCBuildConfiguration section */ 228 | 607FACED1AFB9204008FA782 /* Debug */ = { 229 | isa = XCBuildConfiguration; 230 | buildSettings = { 231 | ALWAYS_SEARCH_USER_PATHS = NO; 232 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 233 | CLANG_CXX_LIBRARY = "libc++"; 234 | CLANG_ENABLE_MODULES = YES; 235 | CLANG_ENABLE_OBJC_ARC = YES; 236 | CLANG_WARN_BOOL_CONVERSION = YES; 237 | CLANG_WARN_CONSTANT_CONVERSION = YES; 238 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 239 | CLANG_WARN_EMPTY_BODY = YES; 240 | CLANG_WARN_ENUM_CONVERSION = YES; 241 | CLANG_WARN_INT_CONVERSION = YES; 242 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 243 | CLANG_WARN_UNREACHABLE_CODE = YES; 244 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 245 | COPY_PHASE_STRIP = NO; 246 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 247 | ENABLE_STRICT_OBJC_MSGSEND = YES; 248 | ENABLE_TESTABILITY = YES; 249 | GCC_C_LANGUAGE_STANDARD = gnu99; 250 | GCC_DYNAMIC_NO_PIC = NO; 251 | GCC_NO_COMMON_BLOCKS = YES; 252 | GCC_OPTIMIZATION_LEVEL = 0; 253 | GCC_PREPROCESSOR_DEFINITIONS = ( 254 | "DEBUG=1", 255 | "$(inherited)", 256 | ); 257 | GCC_SYMBOLS_PRIVATE_EXTERN = NO; 258 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 259 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 260 | GCC_WARN_UNDECLARED_SELECTOR = YES; 261 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 262 | GCC_WARN_UNUSED_FUNCTION = YES; 263 | GCC_WARN_UNUSED_VARIABLE = YES; 264 | IPHONEOS_DEPLOYMENT_TARGET = 9.2; 265 | MACOSX_DEPLOYMENT_TARGET = 10.11; 266 | MTL_ENABLE_DEBUG_INFO = YES; 267 | ONLY_ACTIVE_ARCH = YES; 268 | SDKROOT = macosx; 269 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 270 | }; 271 | name = Debug; 272 | }; 273 | 607FACEE1AFB9204008FA782 /* Release */ = { 274 | isa = XCBuildConfiguration; 275 | buildSettings = { 276 | ALWAYS_SEARCH_USER_PATHS = NO; 277 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 278 | CLANG_CXX_LIBRARY = "libc++"; 279 | CLANG_ENABLE_MODULES = YES; 280 | CLANG_ENABLE_OBJC_ARC = YES; 281 | CLANG_WARN_BOOL_CONVERSION = YES; 282 | CLANG_WARN_CONSTANT_CONVERSION = YES; 283 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 284 | CLANG_WARN_EMPTY_BODY = YES; 285 | CLANG_WARN_ENUM_CONVERSION = YES; 286 | CLANG_WARN_INT_CONVERSION = YES; 287 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 288 | CLANG_WARN_UNREACHABLE_CODE = YES; 289 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 290 | COPY_PHASE_STRIP = NO; 291 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 292 | ENABLE_NS_ASSERTIONS = NO; 293 | ENABLE_STRICT_OBJC_MSGSEND = YES; 294 | GCC_C_LANGUAGE_STANDARD = gnu99; 295 | GCC_NO_COMMON_BLOCKS = YES; 296 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 297 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 298 | GCC_WARN_UNDECLARED_SELECTOR = YES; 299 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 300 | GCC_WARN_UNUSED_FUNCTION = YES; 301 | GCC_WARN_UNUSED_VARIABLE = YES; 302 | IPHONEOS_DEPLOYMENT_TARGET = 9.2; 303 | MACOSX_DEPLOYMENT_TARGET = 10.11; 304 | MTL_ENABLE_DEBUG_INFO = NO; 305 | SDKROOT = macosx; 306 | VALIDATE_PRODUCT = YES; 307 | }; 308 | name = Release; 309 | }; 310 | D7F9F47D1C4F1393000ACE5E /* Debug */ = { 311 | isa = XCBuildConfiguration; 312 | buildSettings = { 313 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 314 | CODE_SIGN_IDENTITY = "-"; 315 | COMBINE_HIDPI_IMAGES = YES; 316 | DEBUG_INFORMATION_FORMAT = dwarf; 317 | INFOPLIST_FILE = OAStatusItemKit_Example/Info.plist; 318 | LD_RUNPATH_SEARCH_PATHS = "@executable_path/../Frameworks"; 319 | MACOSX_DEPLOYMENT_TARGET = 10.10; 320 | PRODUCT_BUNDLE_IDENTIFIER = "nsomar.OAStatusItemKit-Example"; 321 | PRODUCT_NAME = "$(TARGET_NAME)"; 322 | SWIFT_VERSION = 3.0; 323 | }; 324 | name = Debug; 325 | }; 326 | D7F9F47E1C4F1393000ACE5E /* Release */ = { 327 | isa = XCBuildConfiguration; 328 | buildSettings = { 329 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 330 | CODE_SIGN_IDENTITY = "-"; 331 | COMBINE_HIDPI_IMAGES = YES; 332 | INFOPLIST_FILE = OAStatusItemKit_Example/Info.plist; 333 | LD_RUNPATH_SEARCH_PATHS = "@executable_path/../Frameworks"; 334 | MACOSX_DEPLOYMENT_TARGET = 10.10; 335 | PRODUCT_BUNDLE_IDENTIFIER = "nsomar.OAStatusItemKit-Example"; 336 | PRODUCT_NAME = "$(TARGET_NAME)"; 337 | SWIFT_VERSION = 3.0; 338 | }; 339 | name = Release; 340 | }; 341 | /* End XCBuildConfiguration section */ 342 | 343 | /* Begin XCConfigurationList section */ 344 | 607FACCB1AFB9204008FA782 /* Build configuration list for PBXProject "OAStatusItemKit Example" */ = { 345 | isa = XCConfigurationList; 346 | buildConfigurations = ( 347 | 607FACED1AFB9204008FA782 /* Debug */, 348 | 607FACEE1AFB9204008FA782 /* Release */, 349 | ); 350 | defaultConfigurationIsVisible = 0; 351 | defaultConfigurationName = Release; 352 | }; 353 | D7F9F47C1C4F1393000ACE5E /* Build configuration list for PBXNativeTarget "OAStatusItemKit_Example" */ = { 354 | isa = XCConfigurationList; 355 | buildConfigurations = ( 356 | D7F9F47D1C4F1393000ACE5E /* Debug */, 357 | D7F9F47E1C4F1393000ACE5E /* Release */, 358 | ); 359 | defaultConfigurationIsVisible = 0; 360 | defaultConfigurationName = Release; 361 | }; 362 | /* End XCConfigurationList section */ 363 | }; 364 | rootObject = 607FACC81AFB9204008FA782 /* Project object */; 365 | } 366 | -------------------------------------------------------------------------------- /Example/OAStatusItemKit Example.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Example/OAStatusItemKit Example.xcodeproj/xcshareddata/xcschemes/OAStatusItemKit-Example.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 39 | 40 | 41 | 42 | 43 | 44 | 54 | 56 | 62 | 63 | 64 | 65 | 66 | 67 | 73 | 75 | 81 | 82 | 83 | 84 | 86 | 87 | 90 | 91 | 92 | -------------------------------------------------------------------------------- /Example/OAStatusItemKit_Example/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.swift 3 | // OAStatusItemKit_Example 4 | // 5 | // Created by Omar Abdelhafith on 20/01/2016. 6 | // Copyright © 2016 CocoaPods. All rights reserved. 7 | // 8 | 9 | import Cocoa 10 | 11 | import OAStatusItemKit 12 | 13 | @NSApplicationMain 14 | class AppDelegate: NSObject, NSApplicationDelegate { 15 | 16 | func applicationDidFinishLaunching(_ aNotification: Notification) { 17 | NSApplication.shared().hide(nil) 18 | 19 | let statusBarItem = StatusBarItemView(brightStatusImage: NSImage(named: "Icon-bright")!, darkStatusImage: NSImage(named: "Icon-dark")!) 20 | 21 | 22 | // Uncomment this to display the view in a window 23 | // StatusBarWindowStyle.Window(.StatusBarItemCenter) 24 | // .createPresenter(withXibName: "Panel", statusItem: statusBarItem) 25 | 26 | 27 | // Uncomment this to display the window with a specific size 28 | // StatusBarWindowStyle.WindowWithSize(.StatusBarItemCenter, NSSize(width: 400, height: 400)) 29 | // .createPresenter(withXibName: "Panel", statusItem: statusBarItem) 30 | 31 | 32 | StatusBarWindowStyle.popup.createPresenter(withXibName: "Panel", statusItem: statusBarItem) 33 | } 34 | 35 | func applicationWillTerminate(_ aNotification: Notification) { 36 | // Insert code here to tear down your application 37 | } 38 | 39 | 40 | } 41 | 42 | -------------------------------------------------------------------------------- /Example/OAStatusItemKit_Example/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "mac", 5 | "size" : "16x16", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "mac", 10 | "size" : "16x16", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "idiom" : "mac", 15 | "size" : "32x32", 16 | "scale" : "1x" 17 | }, 18 | { 19 | "idiom" : "mac", 20 | "size" : "32x32", 21 | "scale" : "2x" 22 | }, 23 | { 24 | "idiom" : "mac", 25 | "size" : "128x128", 26 | "scale" : "1x" 27 | }, 28 | { 29 | "idiom" : "mac", 30 | "size" : "128x128", 31 | "scale" : "2x" 32 | }, 33 | { 34 | "idiom" : "mac", 35 | "size" : "256x256", 36 | "scale" : "1x" 37 | }, 38 | { 39 | "idiom" : "mac", 40 | "size" : "256x256", 41 | "scale" : "2x" 42 | }, 43 | { 44 | "idiom" : "mac", 45 | "size" : "512x512", 46 | "scale" : "1x" 47 | }, 48 | { 49 | "idiom" : "mac", 50 | "size" : "512x512", 51 | "scale" : "2x" 52 | } 53 | ], 54 | "info" : { 55 | "version" : 1, 56 | "author" : "xcode" 57 | } 58 | } -------------------------------------------------------------------------------- /Example/OAStatusItemKit_Example/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } -------------------------------------------------------------------------------- /Example/OAStatusItemKit_Example/Assets.xcassets/Icon-bright.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "Icon.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "filename" : "Icon@2x.png", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "idiom" : "universal", 15 | "scale" : "3x" 16 | } 17 | ], 18 | "info" : { 19 | "version" : 1, 20 | "author" : "xcode" 21 | } 22 | } -------------------------------------------------------------------------------- /Example/OAStatusItemKit_Example/Assets.xcassets/Icon-bright.imageset/Icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nsomar/OAStatusItemKit/13118b5eb5a5da534c0a8188db615252f7456610/Example/OAStatusItemKit_Example/Assets.xcassets/Icon-bright.imageset/Icon.png -------------------------------------------------------------------------------- /Example/OAStatusItemKit_Example/Assets.xcassets/Icon-bright.imageset/Icon@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nsomar/OAStatusItemKit/13118b5eb5a5da534c0a8188db615252f7456610/Example/OAStatusItemKit_Example/Assets.xcassets/Icon-bright.imageset/Icon@2x.png -------------------------------------------------------------------------------- /Example/OAStatusItemKit_Example/Assets.xcassets/Icon-dark.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "IconHighlighted.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "filename" : "IconHighlighted@2x.png", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "idiom" : "universal", 15 | "scale" : "3x" 16 | } 17 | ], 18 | "info" : { 19 | "version" : 1, 20 | "author" : "xcode" 21 | } 22 | } -------------------------------------------------------------------------------- /Example/OAStatusItemKit_Example/Assets.xcassets/Icon-dark.imageset/IconHighlighted.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nsomar/OAStatusItemKit/13118b5eb5a5da534c0a8188db615252f7456610/Example/OAStatusItemKit_Example/Assets.xcassets/Icon-dark.imageset/IconHighlighted.png -------------------------------------------------------------------------------- /Example/OAStatusItemKit_Example/Assets.xcassets/Icon-dark.imageset/IconHighlighted@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nsomar/OAStatusItemKit/13118b5eb5a5da534c0a8188db615252f7456610/Example/OAStatusItemKit_Example/Assets.xcassets/Icon-dark.imageset/IconHighlighted@2x.png -------------------------------------------------------------------------------- /Example/OAStatusItemKit_Example/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 | 260 | 261 | 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 | 270 | 271 | 272 | 273 | 274 | 275 | 276 | 277 | 278 | 279 | 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 | 289 | 290 | 291 | 292 | 293 | 294 | 295 | 296 | 297 | 298 | 299 | 300 | 301 | 302 | 303 | 304 | 305 | 306 | 307 | 308 | 309 | 310 | 311 | 312 | 313 | 314 | 315 | 316 | 317 | 318 | 319 | 320 | 321 | 322 | 323 | 324 | 325 | 326 | 327 | 328 | 329 | 330 | 331 | 332 | 333 | 334 | 335 | 336 | 337 | 338 | 339 | 340 | 341 | 342 | 343 | 344 | 345 | 346 | 347 | 348 | 349 | 350 | 351 | 352 | 353 | 354 | 355 | 356 | 357 | 358 | 359 | 360 | 361 | 362 | 363 | 364 | 365 | 366 | 367 | 368 | 369 | 370 | 371 | 372 | 373 | 374 | 375 | 376 | 377 | 378 | 379 | 380 | 381 | 382 | 383 | 384 | 385 | 386 | 387 | 388 | 389 | 390 | 391 | 392 | 393 | 394 | 395 | 396 | 397 | 398 | 399 | 400 | 401 | 402 | 403 | 404 | 405 | 406 | 407 | 408 | 409 | 410 | 411 | 412 | 413 | 414 | 415 | 416 | 417 | 418 | 419 | 420 | 421 | 422 | 423 | 424 | 425 | 426 | 427 | 428 | 429 | 430 | 431 | 432 | 433 | 434 | 435 | 436 | 437 | 438 | 439 | 440 | 441 | 442 | 443 | 444 | 445 | 446 | 447 | 448 | 449 | 450 | 451 | 452 | 453 | 454 | 455 | 456 | 457 | 458 | 459 | 460 | 461 | 462 | 463 | 464 | 465 | 466 | 467 | 468 | 469 | 470 | 471 | 472 | 473 | 474 | 475 | 476 | 477 | 478 | 479 | 480 | 481 | 482 | 483 | 484 | 485 | 486 | 487 | 488 | 489 | 490 | 491 | 492 | 493 | 494 | 495 | 496 | 497 | 498 | 499 | 500 | 501 | 502 | 503 | 504 | 505 | 506 | 507 | 508 | 509 | Default 510 | 511 | 512 | 513 | 514 | 515 | 516 | Left to Right 517 | 518 | 519 | 520 | 521 | 522 | 523 | Right to Left 524 | 525 | 526 | 527 | 528 | 529 | 530 | 531 | 532 | 533 | 534 | Default 535 | 536 | 537 | 538 | 539 | 540 | 541 | Left to Right 542 | 543 | 544 | 545 | 546 | 547 | 548 | Right to Left 549 | 550 | 551 | 552 | 553 | 554 | 555 | 556 | 557 | 558 | 559 | 560 | 561 | 562 | 563 | 564 | 565 | 566 | 567 | 568 | 569 | 570 | 571 | 572 | 573 | 574 | 575 | 576 | 577 | 578 | 579 | 580 | 581 | 582 | 583 | 584 | 585 | 586 | 587 | 588 | 589 | 590 | 591 | 592 | 593 | 594 | 595 | 596 | 597 | 598 | 599 | 600 | 601 | 602 | 603 | 604 | 605 | 606 | 607 | 608 | 609 | 610 | 611 | 612 | 613 | 614 | 615 | 616 | 617 | 618 | 619 | 620 | 621 | 622 | 623 | 624 | 625 | 626 | 627 | 628 | 629 | 630 | 631 | 632 | 633 | 634 | 635 | 636 | 637 | 638 | 639 | 640 | 641 | 642 | 643 | 644 | 645 | 646 | 647 | 648 | 649 | 650 | 651 | 652 | 653 | 654 | 655 | 656 | 657 | 658 | 659 | 660 | 661 | 662 | 663 | 664 | 665 | 666 | 667 | 668 | 669 | 670 | 671 | 672 | 673 | 674 | 675 | 676 | 677 | 678 | 679 | 680 | 681 | 682 | -------------------------------------------------------------------------------- /Example/OAStatusItemKit_Example/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | LSUIElement 6 | 7 | CFBundleDevelopmentRegion 8 | en 9 | CFBundleExecutable 10 | $(EXECUTABLE_NAME) 11 | CFBundleIconFile 12 | 13 | CFBundleIdentifier 14 | $(PRODUCT_BUNDLE_IDENTIFIER) 15 | CFBundleInfoDictionaryVersion 16 | 6.0 17 | CFBundleName 18 | $(PRODUCT_NAME) 19 | CFBundlePackageType 20 | APPL 21 | CFBundleShortVersionString 22 | 1.0 23 | CFBundleSignature 24 | ???? 25 | CFBundleVersion 26 | 1 27 | LSMinimumSystemVersion 28 | $(MACOSX_DEPLOYMENT_TARGET) 29 | NSHumanReadableCopyright 30 | Copyright © 2016 CocoaPods. All rights reserved. 31 | NSMainStoryboardFile 32 | Main 33 | NSPrincipalClass 34 | NSApplication 35 | 36 | 37 | -------------------------------------------------------------------------------- /Example/OAStatusItemKit_Example/Panel.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | -------------------------------------------------------------------------------- /Example/OAStatusItemKit_Example/ViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.swift 3 | // OAStatusItemKit_Example 4 | // 5 | // Created by Omar Abdelhafith on 20/01/2016. 6 | // Copyright © 2016 CocoaPods. All rights reserved. 7 | // 8 | 9 | import Cocoa 10 | 11 | class ViewController: NSViewController { 12 | 13 | override func viewDidLoad() { 14 | super.viewDidLoad() 15 | 16 | // Do any additional setup after loading the view. 17 | } 18 | 19 | override var representedObject: Any? { 20 | didSet { 21 | // Update the view, if already loaded. 22 | } 23 | } 24 | 25 | 26 | } 27 | 28 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2016 Omar Abdelhafith 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in 11 | all copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | THE SOFTWARE. 20 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | build_help: 2 | cd OAStatusItemKit && jazzy \ 3 | --clean \ 4 | --author NSOmar \ 5 | --author_url https://nsomar.com \ 6 | --github_url https://github.com/oarrabi/OAStatusItemKit \ 7 | --github-file-prefix https://github.com/oarrabi/OAStatusItemKit \ 8 | --module-version 0.1.0 \ 9 | --xcodebuild-arguments -scheme,OAStatusItemKit \ 10 | --module OAStatusItemKit \ 11 | --output ../../Docs/swift_output 12 | git stash 13 | git checkout gh-pages 14 | git fetch origin 15 | \git reset --hard origin/gh-pages 16 | git clean -fd 17 | \cp -rf ../Docs/swift_output/* . 18 | git aa 19 | git commit -m "Updating documentation" 20 | \git push origin gh-pages --force 21 | git co - 22 | - git stash pop 23 | 24 | test: 25 | (cd OAStatusItemKit; xcodebuild -workspace OAStatusItemKit.xcworkspace -scheme "OAStatusItemKit" build test | xcpretty) 26 | -------------------------------------------------------------------------------- /OAStatusItemKit.podspec: -------------------------------------------------------------------------------- 1 | # 2 | # Be sure to run `pod lib lint OAStatusItemKit.podspec' to ensure this is a 3 | # valid spec before submitting. 4 | # 5 | # Any lines starting with a # are optional, but their use is encouraged 6 | # To learn more about a Podspec see http://guides.cocoapods.org/syntax/podspec.html 7 | # 8 | 9 | Pod::Spec.new do |s| 10 | s.name = "OAStatusItemKit" 11 | s.version = "0.4.0" 12 | s.summary = "Provides an easy way to create Status bar apps." 13 | 14 | # This description is used to generate tags and improve search results. 15 | # * Think: What does it do? Why did you write it? What is the focus? 16 | # * Try to keep it short, snappy and to the point. 17 | # * Write the description between the DESC delimiters below. 18 | # * Finally, don't worry about the indent, CocoaPods strips it! 19 | s.description = <<-DESC 20 | OAStatusItemKit allows you to easily create mac status bar apps with swifty flavour. 21 | DESC 22 | 23 | s.homepage = "https://github.com/oarrabi/OAStatusItemKit" 24 | # s.screenshots = "www.example.com/screenshots_1", "www.example.com/screenshots_2" 25 | s.license = 'MIT' 26 | s.author = { "Omar Abdelhafith" => "o.arrabi@me.com" } 27 | s.source = { :git => "https://github.com/oarrabi/OAStatusItemKit.git", :tag => s.version.to_s } 28 | # s.social_media_url = 'https://twitter.com/ifnottrue' 29 | 30 | s.platform = :osx, '10.9' 31 | s.requires_arc = true 32 | 33 | s.source_files = 'Pod/Classes/**/*' 34 | # s.resource_bundles = { 35 | # 'OAStatusItemKit' => ['Pod/Assets/*.png'] 36 | # } 37 | 38 | # s.public_header_files = 'Pod/Classes/**/*.h' 39 | # s.frameworks = 'UIKit', 'MapKit' 40 | # s.dependency 'AFNetworking', '~> 2.3' 41 | end 42 | -------------------------------------------------------------------------------- /OAStatusItemKit/OAStatusItemKit.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 9B16FCDB9EA779EC2589454E /* Pods_OAStatusItemKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9F0093F2631F1A54698AE8BB /* Pods_OAStatusItemKit.framework */; }; 11 | A9419C4E5898E58256146887 /* Pods_OAStatusItemKitTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 54058F4238A8B7300B28C942 /* Pods_OAStatusItemKitTests.framework */; }; 12 | D76538531C4F21010073C059 /* OAStatusItemKit.h in Headers */ = {isa = PBXBuildFile; fileRef = D76538521C4F21010073C059 /* OAStatusItemKit.h */; settings = {ATTRIBUTES = (Public, ); }; }; 13 | D765385A1C4F21010073C059 /* OAStatusItemKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D765384F1C4F21010073C059 /* OAStatusItemKit.framework */; }; 14 | D76538821C4F24770073C059 /* StatusBarImagesSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = D76538811C4F24770073C059 /* StatusBarImagesSpec.swift */; }; 15 | D765388A1C4F24F30073C059 /* NSImage+Tint.swift in Sources */ = {isa = PBXBuildFile; fileRef = D76538851C4F24F30073C059 /* NSImage+Tint.swift */; }; 16 | D765388B1C4F24F30073C059 /* StatusBarImages.swift in Sources */ = {isa = PBXBuildFile; fileRef = D76538861C4F24F30073C059 /* StatusBarImages.swift */; }; 17 | D765388C1C4F24F30073C059 /* StatusBarItemView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D76538871C4F24F30073C059 /* StatusBarItemView.swift */; }; 18 | D765388D1C4F24F30073C059 /* StatusBarWindowController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D76538881C4F24F30073C059 /* StatusBarWindowController.swift */; }; 19 | D765388F1C4F25B60073C059 /* StatusBarInterface.swift in Sources */ = {isa = PBXBuildFile; fileRef = D765388E1C4F25B60073C059 /* StatusBarInterface.swift */; }; 20 | D76538941C4FF8B60073C059 /* ImageDrawer.swift in Sources */ = {isa = PBXBuildFile; fileRef = D76538931C4FF8B60073C059 /* ImageDrawer.swift */; }; 21 | D76538961C5025940073C059 /* ImageDrawerSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = D76538951C5025930073C059 /* ImageDrawerSpec.swift */; }; 22 | D76538981C502C580073C059 /* TestHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = D76538971C502C580073C059 /* TestHelper.swift */; }; 23 | D765389A1C5030FD0073C059 /* StatusBarItemViewSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = D76538991C5030FD0073C059 /* StatusBarItemViewSpec.swift */; }; 24 | D765389C1C5043830073C059 /* WindowPlacer.swift in Sources */ = {isa = PBXBuildFile; fileRef = D765389B1C5043830073C059 /* WindowPlacer.swift */; }; 25 | D765389E1C504A510073C059 /* StatusWindowPlacement.swift in Sources */ = {isa = PBXBuildFile; fileRef = D765389D1C504A510073C059 /* StatusWindowPlacement.swift */; }; 26 | D76538A01C504B7F0073C059 /* WindowPlacerSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = D765389F1C504B7F0073C059 /* WindowPlacerSpec.swift */; }; 27 | D76538A21C5120150073C059 /* StatusBarItemCenterPlacer.swift in Sources */ = {isa = PBXBuildFile; fileRef = D76538A11C5120150073C059 /* StatusBarItemCenterPlacer.swift */; }; 28 | D76538A41C5120320073C059 /* ScreenWindowPlacer.swift in Sources */ = {isa = PBXBuildFile; fileRef = D76538A31C5120320073C059 /* ScreenWindowPlacer.swift */; }; 29 | D76538A61C513CD90073C059 /* BundleLoading.swift in Sources */ = {isa = PBXBuildFile; fileRef = D76538A51C513CD90073C059 /* BundleLoading.swift */; }; 30 | D77649C91C548A7900923F9C /* StatusBarPopupPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = D77649C81C548A7900923F9C /* StatusBarPopupPresenter.swift */; }; 31 | D77649D01C54929F00923F9C /* EventMonitor.swift in Sources */ = {isa = PBXBuildFile; fileRef = D77649CF1C54929F00923F9C /* EventMonitor.swift */; }; 32 | D77649D21C549A5100923F9C /* StatusBarWindowStyle.swift in Sources */ = {isa = PBXBuildFile; fileRef = D77649D11C549A5100923F9C /* StatusBarWindowStyle.swift */; }; 33 | D77649D41C549B5400923F9C /* StatusBarViewPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = D77649D31C549B5400923F9C /* StatusBarViewPresenter.swift */; }; 34 | D7D859D91C5179EC00F2A447 /* StatusPanel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D7D859D81C5179EC00F2A447 /* StatusPanel.swift */; }; 35 | /* End PBXBuildFile section */ 36 | 37 | /* Begin PBXContainerItemProxy section */ 38 | D765385B1C4F21010073C059 /* PBXContainerItemProxy */ = { 39 | isa = PBXContainerItemProxy; 40 | containerPortal = D76538461C4F21000073C059 /* Project object */; 41 | proxyType = 1; 42 | remoteGlobalIDString = D765384E1C4F21010073C059; 43 | remoteInfo = OAStatusItemKit; 44 | }; 45 | /* End PBXContainerItemProxy section */ 46 | 47 | /* Begin PBXFileReference section */ 48 | 3E7EA329915BDB4188160025 /* Pods-OAStatusItemKit.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-OAStatusItemKit.debug.xcconfig"; path = "Pods/Target Support Files/Pods-OAStatusItemKit/Pods-OAStatusItemKit.debug.xcconfig"; sourceTree = ""; }; 49 | 54058F4238A8B7300B28C942 /* Pods_OAStatusItemKitTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_OAStatusItemKitTests.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 50 | 9F0093F2631F1A54698AE8BB /* Pods_OAStatusItemKit.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_OAStatusItemKit.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 51 | A8C2877BBEF8DD99180BE6C3 /* Pods-OAStatusItemKitTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-OAStatusItemKitTests.release.xcconfig"; path = "Pods/Target Support Files/Pods-OAStatusItemKitTests/Pods-OAStatusItemKitTests.release.xcconfig"; sourceTree = ""; }; 52 | B89204C89E477875464B16DE /* Pods-OAStatusItemKit.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-OAStatusItemKit.release.xcconfig"; path = "Pods/Target Support Files/Pods-OAStatusItemKit/Pods-OAStatusItemKit.release.xcconfig"; sourceTree = ""; }; 53 | BEBBCEF0D972CAF3A86BEB16 /* Pods-OAStatusItemKitTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-OAStatusItemKitTests.debug.xcconfig"; path = "Pods/Target Support Files/Pods-OAStatusItemKitTests/Pods-OAStatusItemKitTests.debug.xcconfig"; sourceTree = ""; }; 54 | D765384F1C4F21010073C059 /* OAStatusItemKit.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = OAStatusItemKit.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 55 | D76538521C4F21010073C059 /* OAStatusItemKit.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = OAStatusItemKit.h; sourceTree = ""; }; 56 | D76538541C4F21010073C059 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 57 | D76538591C4F21010073C059 /* OAStatusItemKitTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = OAStatusItemKitTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 58 | D76538601C4F21010073C059 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 59 | D76538811C4F24770073C059 /* StatusBarImagesSpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StatusBarImagesSpec.swift; sourceTree = ""; }; 60 | D76538851C4F24F30073C059 /* NSImage+Tint.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "NSImage+Tint.swift"; sourceTree = ""; }; 61 | D76538861C4F24F30073C059 /* StatusBarImages.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StatusBarImages.swift; sourceTree = ""; }; 62 | D76538871C4F24F30073C059 /* StatusBarItemView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StatusBarItemView.swift; sourceTree = ""; }; 63 | D76538881C4F24F30073C059 /* StatusBarWindowController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StatusBarWindowController.swift; sourceTree = ""; }; 64 | D765388E1C4F25B60073C059 /* StatusBarInterface.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StatusBarInterface.swift; sourceTree = ""; }; 65 | D76538931C4FF8B60073C059 /* ImageDrawer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ImageDrawer.swift; sourceTree = ""; }; 66 | D76538951C5025930073C059 /* ImageDrawerSpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ImageDrawerSpec.swift; sourceTree = ""; }; 67 | D76538971C502C580073C059 /* TestHelper.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TestHelper.swift; sourceTree = ""; }; 68 | D76538991C5030FD0073C059 /* StatusBarItemViewSpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StatusBarItemViewSpec.swift; sourceTree = ""; }; 69 | D765389B1C5043830073C059 /* WindowPlacer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = WindowPlacer.swift; sourceTree = ""; }; 70 | D765389D1C504A510073C059 /* StatusWindowPlacement.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StatusWindowPlacement.swift; sourceTree = ""; }; 71 | D765389F1C504B7F0073C059 /* WindowPlacerSpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = WindowPlacerSpec.swift; sourceTree = ""; }; 72 | D76538A11C5120150073C059 /* StatusBarItemCenterPlacer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StatusBarItemCenterPlacer.swift; sourceTree = ""; }; 73 | D76538A31C5120320073C059 /* ScreenWindowPlacer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ScreenWindowPlacer.swift; sourceTree = ""; }; 74 | D76538A51C513CD90073C059 /* BundleLoading.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BundleLoading.swift; sourceTree = ""; }; 75 | D77649C81C548A7900923F9C /* StatusBarPopupPresenter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StatusBarPopupPresenter.swift; sourceTree = ""; }; 76 | D77649CF1C54929F00923F9C /* EventMonitor.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EventMonitor.swift; sourceTree = ""; }; 77 | D77649D11C549A5100923F9C /* StatusBarWindowStyle.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StatusBarWindowStyle.swift; sourceTree = ""; }; 78 | D77649D31C549B5400923F9C /* StatusBarViewPresenter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StatusBarViewPresenter.swift; sourceTree = ""; }; 79 | D7D859D81C5179EC00F2A447 /* StatusPanel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StatusPanel.swift; sourceTree = ""; }; 80 | /* End PBXFileReference section */ 81 | 82 | /* Begin PBXFrameworksBuildPhase section */ 83 | D765384B1C4F21010073C059 /* Frameworks */ = { 84 | isa = PBXFrameworksBuildPhase; 85 | buildActionMask = 2147483647; 86 | files = ( 87 | 9B16FCDB9EA779EC2589454E /* Pods_OAStatusItemKit.framework in Frameworks */, 88 | ); 89 | runOnlyForDeploymentPostprocessing = 0; 90 | }; 91 | D76538561C4F21010073C059 /* Frameworks */ = { 92 | isa = PBXFrameworksBuildPhase; 93 | buildActionMask = 2147483647; 94 | files = ( 95 | D765385A1C4F21010073C059 /* OAStatusItemKit.framework in Frameworks */, 96 | A9419C4E5898E58256146887 /* Pods_OAStatusItemKitTests.framework in Frameworks */, 97 | ); 98 | runOnlyForDeploymentPostprocessing = 0; 99 | }; 100 | /* End PBXFrameworksBuildPhase section */ 101 | 102 | /* Begin PBXGroup section */ 103 | 7D00103CF900238074D6199A /* Pods */ = { 104 | isa = PBXGroup; 105 | children = ( 106 | 3E7EA329915BDB4188160025 /* Pods-OAStatusItemKit.debug.xcconfig */, 107 | B89204C89E477875464B16DE /* Pods-OAStatusItemKit.release.xcconfig */, 108 | BEBBCEF0D972CAF3A86BEB16 /* Pods-OAStatusItemKitTests.debug.xcconfig */, 109 | A8C2877BBEF8DD99180BE6C3 /* Pods-OAStatusItemKitTests.release.xcconfig */, 110 | ); 111 | name = Pods; 112 | sourceTree = ""; 113 | }; 114 | AF078CE192E4F9E417EFA003 /* Frameworks */ = { 115 | isa = PBXGroup; 116 | children = ( 117 | 9F0093F2631F1A54698AE8BB /* Pods_OAStatusItemKit.framework */, 118 | 54058F4238A8B7300B28C942 /* Pods_OAStatusItemKitTests.framework */, 119 | ); 120 | name = Frameworks; 121 | sourceTree = ""; 122 | }; 123 | D76538451C4F21000073C059 = { 124 | isa = PBXGroup; 125 | children = ( 126 | D76538511C4F21010073C059 /* OAStatusItemKit */, 127 | D765385D1C4F21010073C059 /* OAStatusItemKitTests */, 128 | D76538501C4F21010073C059 /* Products */, 129 | 7D00103CF900238074D6199A /* Pods */, 130 | AF078CE192E4F9E417EFA003 /* Frameworks */, 131 | ); 132 | sourceTree = ""; 133 | }; 134 | D76538501C4F21010073C059 /* Products */ = { 135 | isa = PBXGroup; 136 | children = ( 137 | D765384F1C4F21010073C059 /* OAStatusItemKit.framework */, 138 | D76538591C4F21010073C059 /* OAStatusItemKitTests.xctest */, 139 | ); 140 | name = Products; 141 | sourceTree = ""; 142 | }; 143 | D76538511C4F21010073C059 /* OAStatusItemKit */ = { 144 | isa = PBXGroup; 145 | children = ( 146 | D76538831C4F24F30073C059 /* Classes */, 147 | D76538521C4F21010073C059 /* OAStatusItemKit.h */, 148 | D76538541C4F21010073C059 /* Info.plist */, 149 | ); 150 | path = OAStatusItemKit; 151 | sourceTree = ""; 152 | }; 153 | D765385D1C4F21010073C059 /* OAStatusItemKitTests */ = { 154 | isa = PBXGroup; 155 | children = ( 156 | D76538601C4F21010073C059 /* Info.plist */, 157 | D76538811C4F24770073C059 /* StatusBarImagesSpec.swift */, 158 | D76538951C5025930073C059 /* ImageDrawerSpec.swift */, 159 | D76538971C502C580073C059 /* TestHelper.swift */, 160 | D76538991C5030FD0073C059 /* StatusBarItemViewSpec.swift */, 161 | D765389F1C504B7F0073C059 /* WindowPlacerSpec.swift */, 162 | ); 163 | path = OAStatusItemKitTests; 164 | sourceTree = ""; 165 | }; 166 | D76538831C4F24F30073C059 /* Classes */ = { 167 | isa = PBXGroup; 168 | children = ( 169 | D77649D81C54A46B00923F9C /* WindowPlacer */, 170 | D77649D71C54A43900923F9C /* Views */, 171 | D77649D51C54A28800923F9C /* StatusBarViewPresenter */, 172 | D77649D61C54A42700923F9C /* Utilities */, 173 | ); 174 | name = Classes; 175 | path = ../../Pod/Classes; 176 | sourceTree = ""; 177 | }; 178 | D77649D51C54A28800923F9C /* StatusBarViewPresenter */ = { 179 | isa = PBXGroup; 180 | children = ( 181 | D77649D31C549B5400923F9C /* StatusBarViewPresenter.swift */, 182 | D77649C81C548A7900923F9C /* StatusBarPopupPresenter.swift */, 183 | D76538881C4F24F30073C059 /* StatusBarWindowController.swift */, 184 | ); 185 | name = StatusBarViewPresenter; 186 | sourceTree = ""; 187 | }; 188 | D77649D61C54A42700923F9C /* Utilities */ = { 189 | isa = PBXGroup; 190 | children = ( 191 | D77649D11C549A5100923F9C /* StatusBarWindowStyle.swift */, 192 | D76538A51C513CD90073C059 /* BundleLoading.swift */, 193 | D765389B1C5043830073C059 /* WindowPlacer.swift */, 194 | D765388E1C4F25B60073C059 /* StatusBarInterface.swift */, 195 | D76538851C4F24F30073C059 /* NSImage+Tint.swift */, 196 | D77649CF1C54929F00923F9C /* EventMonitor.swift */, 197 | ); 198 | name = Utilities; 199 | sourceTree = ""; 200 | }; 201 | D77649D71C54A43900923F9C /* Views */ = { 202 | isa = PBXGroup; 203 | children = ( 204 | D7D859D81C5179EC00F2A447 /* StatusPanel.swift */, 205 | D76538931C4FF8B60073C059 /* ImageDrawer.swift */, 206 | D76538871C4F24F30073C059 /* StatusBarItemView.swift */, 207 | D76538861C4F24F30073C059 /* StatusBarImages.swift */, 208 | ); 209 | name = Views; 210 | sourceTree = ""; 211 | }; 212 | D77649D81C54A46B00923F9C /* WindowPlacer */ = { 213 | isa = PBXGroup; 214 | children = ( 215 | D765389D1C504A510073C059 /* StatusWindowPlacement.swift */, 216 | D76538A31C5120320073C059 /* ScreenWindowPlacer.swift */, 217 | D76538A11C5120150073C059 /* StatusBarItemCenterPlacer.swift */, 218 | ); 219 | name = WindowPlacer; 220 | sourceTree = ""; 221 | }; 222 | /* End PBXGroup section */ 223 | 224 | /* Begin PBXHeadersBuildPhase section */ 225 | D765384C1C4F21010073C059 /* Headers */ = { 226 | isa = PBXHeadersBuildPhase; 227 | buildActionMask = 2147483647; 228 | files = ( 229 | D76538531C4F21010073C059 /* OAStatusItemKit.h in Headers */, 230 | ); 231 | runOnlyForDeploymentPostprocessing = 0; 232 | }; 233 | /* End PBXHeadersBuildPhase section */ 234 | 235 | /* Begin PBXNativeTarget section */ 236 | D765384E1C4F21010073C059 /* OAStatusItemKit */ = { 237 | isa = PBXNativeTarget; 238 | buildConfigurationList = D76538631C4F21010073C059 /* Build configuration list for PBXNativeTarget "OAStatusItemKit" */; 239 | buildPhases = ( 240 | 0566B5D585BB3421D564E591 /* [CP] Check Pods Manifest.lock */, 241 | D765384A1C4F21010073C059 /* Sources */, 242 | D765384B1C4F21010073C059 /* Frameworks */, 243 | D765384C1C4F21010073C059 /* Headers */, 244 | D765384D1C4F21010073C059 /* Resources */, 245 | C1D6BEE94C6A9D027A90855E /* [CP] Copy Pods Resources */, 246 | ); 247 | buildRules = ( 248 | ); 249 | dependencies = ( 250 | ); 251 | name = OAStatusItemKit; 252 | productName = OAStatusItemKit; 253 | productReference = D765384F1C4F21010073C059 /* OAStatusItemKit.framework */; 254 | productType = "com.apple.product-type.framework"; 255 | }; 256 | D76538581C4F21010073C059 /* OAStatusItemKitTests */ = { 257 | isa = PBXNativeTarget; 258 | buildConfigurationList = D76538661C4F21010073C059 /* Build configuration list for PBXNativeTarget "OAStatusItemKitTests" */; 259 | buildPhases = ( 260 | FD7FCDB7273DBFDA486F076C /* [CP] Check Pods Manifest.lock */, 261 | D76538551C4F21010073C059 /* Sources */, 262 | D76538561C4F21010073C059 /* Frameworks */, 263 | D76538571C4F21010073C059 /* Resources */, 264 | 1D042DBF9C05C9AF5D15BAF6 /* [CP] Embed Pods Frameworks */, 265 | 2D3BA988287A56CFCD93125F /* [CP] Copy Pods Resources */, 266 | ); 267 | buildRules = ( 268 | ); 269 | dependencies = ( 270 | D765385C1C4F21010073C059 /* PBXTargetDependency */, 271 | ); 272 | name = OAStatusItemKitTests; 273 | productName = OAStatusItemKitTests; 274 | productReference = D76538591C4F21010073C059 /* OAStatusItemKitTests.xctest */; 275 | productType = "com.apple.product-type.bundle.unit-test"; 276 | }; 277 | /* End PBXNativeTarget section */ 278 | 279 | /* Begin PBXProject section */ 280 | D76538461C4F21000073C059 /* Project object */ = { 281 | isa = PBXProject; 282 | attributes = { 283 | LastSwiftUpdateCheck = 0720; 284 | LastUpgradeCheck = 0820; 285 | ORGANIZATIONNAME = "Omar Abdelhafith"; 286 | TargetAttributes = { 287 | D765384E1C4F21010073C059 = { 288 | CreatedOnToolsVersion = 7.2; 289 | LastSwiftMigration = 0820; 290 | }; 291 | D76538581C4F21010073C059 = { 292 | CreatedOnToolsVersion = 7.2; 293 | LastSwiftMigration = 0820; 294 | }; 295 | }; 296 | }; 297 | buildConfigurationList = D76538491C4F21000073C059 /* Build configuration list for PBXProject "OAStatusItemKit" */; 298 | compatibilityVersion = "Xcode 3.2"; 299 | developmentRegion = English; 300 | hasScannedForEncodings = 0; 301 | knownRegions = ( 302 | en, 303 | ); 304 | mainGroup = D76538451C4F21000073C059; 305 | productRefGroup = D76538501C4F21010073C059 /* Products */; 306 | projectDirPath = ""; 307 | projectRoot = ""; 308 | targets = ( 309 | D765384E1C4F21010073C059 /* OAStatusItemKit */, 310 | D76538581C4F21010073C059 /* OAStatusItemKitTests */, 311 | ); 312 | }; 313 | /* End PBXProject section */ 314 | 315 | /* Begin PBXResourcesBuildPhase section */ 316 | D765384D1C4F21010073C059 /* Resources */ = { 317 | isa = PBXResourcesBuildPhase; 318 | buildActionMask = 2147483647; 319 | files = ( 320 | ); 321 | runOnlyForDeploymentPostprocessing = 0; 322 | }; 323 | D76538571C4F21010073C059 /* Resources */ = { 324 | isa = PBXResourcesBuildPhase; 325 | buildActionMask = 2147483647; 326 | files = ( 327 | ); 328 | runOnlyForDeploymentPostprocessing = 0; 329 | }; 330 | /* End PBXResourcesBuildPhase section */ 331 | 332 | /* Begin PBXShellScriptBuildPhase section */ 333 | 0566B5D585BB3421D564E591 /* [CP] Check Pods Manifest.lock */ = { 334 | isa = PBXShellScriptBuildPhase; 335 | buildActionMask = 2147483647; 336 | files = ( 337 | ); 338 | inputPaths = ( 339 | ); 340 | name = "[CP] Check Pods Manifest.lock"; 341 | outputPaths = ( 342 | ); 343 | runOnlyForDeploymentPostprocessing = 0; 344 | shellPath = /bin/sh; 345 | shellScript = "diff \"${PODS_ROOT}/../Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n"; 346 | showEnvVarsInLog = 0; 347 | }; 348 | 1D042DBF9C05C9AF5D15BAF6 /* [CP] Embed Pods Frameworks */ = { 349 | isa = PBXShellScriptBuildPhase; 350 | buildActionMask = 2147483647; 351 | files = ( 352 | ); 353 | inputPaths = ( 354 | ); 355 | name = "[CP] Embed Pods Frameworks"; 356 | outputPaths = ( 357 | ); 358 | runOnlyForDeploymentPostprocessing = 0; 359 | shellPath = /bin/sh; 360 | shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-OAStatusItemKitTests/Pods-OAStatusItemKitTests-frameworks.sh\"\n"; 361 | showEnvVarsInLog = 0; 362 | }; 363 | 2D3BA988287A56CFCD93125F /* [CP] Copy Pods Resources */ = { 364 | isa = PBXShellScriptBuildPhase; 365 | buildActionMask = 2147483647; 366 | files = ( 367 | ); 368 | inputPaths = ( 369 | ); 370 | name = "[CP] Copy Pods Resources"; 371 | outputPaths = ( 372 | ); 373 | runOnlyForDeploymentPostprocessing = 0; 374 | shellPath = /bin/sh; 375 | shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-OAStatusItemKitTests/Pods-OAStatusItemKitTests-resources.sh\"\n"; 376 | showEnvVarsInLog = 0; 377 | }; 378 | C1D6BEE94C6A9D027A90855E /* [CP] Copy Pods Resources */ = { 379 | isa = PBXShellScriptBuildPhase; 380 | buildActionMask = 2147483647; 381 | files = ( 382 | ); 383 | inputPaths = ( 384 | ); 385 | name = "[CP] Copy Pods Resources"; 386 | outputPaths = ( 387 | ); 388 | runOnlyForDeploymentPostprocessing = 0; 389 | shellPath = /bin/sh; 390 | shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-OAStatusItemKit/Pods-OAStatusItemKit-resources.sh\"\n"; 391 | showEnvVarsInLog = 0; 392 | }; 393 | FD7FCDB7273DBFDA486F076C /* [CP] Check Pods Manifest.lock */ = { 394 | isa = PBXShellScriptBuildPhase; 395 | buildActionMask = 2147483647; 396 | files = ( 397 | ); 398 | inputPaths = ( 399 | ); 400 | name = "[CP] Check Pods Manifest.lock"; 401 | outputPaths = ( 402 | ); 403 | runOnlyForDeploymentPostprocessing = 0; 404 | shellPath = /bin/sh; 405 | shellScript = "diff \"${PODS_ROOT}/../Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n"; 406 | showEnvVarsInLog = 0; 407 | }; 408 | /* End PBXShellScriptBuildPhase section */ 409 | 410 | /* Begin PBXSourcesBuildPhase section */ 411 | D765384A1C4F21010073C059 /* Sources */ = { 412 | isa = PBXSourcesBuildPhase; 413 | buildActionMask = 2147483647; 414 | files = ( 415 | D76538A21C5120150073C059 /* StatusBarItemCenterPlacer.swift in Sources */, 416 | D76538941C4FF8B60073C059 /* ImageDrawer.swift in Sources */, 417 | D765388C1C4F24F30073C059 /* StatusBarItemView.swift in Sources */, 418 | D77649D41C549B5400923F9C /* StatusBarViewPresenter.swift in Sources */, 419 | D765388A1C4F24F30073C059 /* NSImage+Tint.swift in Sources */, 420 | D7D859D91C5179EC00F2A447 /* StatusPanel.swift in Sources */, 421 | D77649D01C54929F00923F9C /* EventMonitor.swift in Sources */, 422 | D77649D21C549A5100923F9C /* StatusBarWindowStyle.swift in Sources */, 423 | D76538A41C5120320073C059 /* ScreenWindowPlacer.swift in Sources */, 424 | D77649C91C548A7900923F9C /* StatusBarPopupPresenter.swift in Sources */, 425 | D765389E1C504A510073C059 /* StatusWindowPlacement.swift in Sources */, 426 | D765389C1C5043830073C059 /* WindowPlacer.swift in Sources */, 427 | D765388B1C4F24F30073C059 /* StatusBarImages.swift in Sources */, 428 | D765388F1C4F25B60073C059 /* StatusBarInterface.swift in Sources */, 429 | D765388D1C4F24F30073C059 /* StatusBarWindowController.swift in Sources */, 430 | D76538A61C513CD90073C059 /* BundleLoading.swift in Sources */, 431 | ); 432 | runOnlyForDeploymentPostprocessing = 0; 433 | }; 434 | D76538551C4F21010073C059 /* Sources */ = { 435 | isa = PBXSourcesBuildPhase; 436 | buildActionMask = 2147483647; 437 | files = ( 438 | D765389A1C5030FD0073C059 /* StatusBarItemViewSpec.swift in Sources */, 439 | D76538981C502C580073C059 /* TestHelper.swift in Sources */, 440 | D76538961C5025940073C059 /* ImageDrawerSpec.swift in Sources */, 441 | D76538821C4F24770073C059 /* StatusBarImagesSpec.swift in Sources */, 442 | D76538A01C504B7F0073C059 /* WindowPlacerSpec.swift in Sources */, 443 | ); 444 | runOnlyForDeploymentPostprocessing = 0; 445 | }; 446 | /* End PBXSourcesBuildPhase section */ 447 | 448 | /* Begin PBXTargetDependency section */ 449 | D765385C1C4F21010073C059 /* PBXTargetDependency */ = { 450 | isa = PBXTargetDependency; 451 | target = D765384E1C4F21010073C059 /* OAStatusItemKit */; 452 | targetProxy = D765385B1C4F21010073C059 /* PBXContainerItemProxy */; 453 | }; 454 | /* End PBXTargetDependency section */ 455 | 456 | /* Begin XCBuildConfiguration section */ 457 | D76538611C4F21010073C059 /* Debug */ = { 458 | isa = XCBuildConfiguration; 459 | buildSettings = { 460 | ALWAYS_SEARCH_USER_PATHS = NO; 461 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 462 | CLANG_CXX_LIBRARY = "libc++"; 463 | CLANG_ENABLE_MODULES = YES; 464 | CLANG_ENABLE_OBJC_ARC = YES; 465 | CLANG_WARN_BOOL_CONVERSION = YES; 466 | CLANG_WARN_CONSTANT_CONVERSION = YES; 467 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 468 | CLANG_WARN_EMPTY_BODY = YES; 469 | CLANG_WARN_ENUM_CONVERSION = YES; 470 | CLANG_WARN_INFINITE_RECURSION = YES; 471 | CLANG_WARN_INT_CONVERSION = YES; 472 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 473 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 474 | CLANG_WARN_UNREACHABLE_CODE = YES; 475 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 476 | CODE_SIGN_IDENTITY = "-"; 477 | COPY_PHASE_STRIP = NO; 478 | CURRENT_PROJECT_VERSION = 1; 479 | DEBUG_INFORMATION_FORMAT = dwarf; 480 | ENABLE_STRICT_OBJC_MSGSEND = YES; 481 | ENABLE_TESTABILITY = YES; 482 | GCC_C_LANGUAGE_STANDARD = gnu99; 483 | GCC_DYNAMIC_NO_PIC = NO; 484 | GCC_NO_COMMON_BLOCKS = YES; 485 | GCC_OPTIMIZATION_LEVEL = 0; 486 | GCC_PREPROCESSOR_DEFINITIONS = ( 487 | "DEBUG=1", 488 | "$(inherited)", 489 | ); 490 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 491 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 492 | GCC_WARN_UNDECLARED_SELECTOR = YES; 493 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 494 | GCC_WARN_UNUSED_FUNCTION = YES; 495 | GCC_WARN_UNUSED_VARIABLE = YES; 496 | MACOSX_DEPLOYMENT_TARGET = 10.9; 497 | MTL_ENABLE_DEBUG_INFO = YES; 498 | ONLY_ACTIVE_ARCH = YES; 499 | SDKROOT = macosx; 500 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 501 | VERSIONING_SYSTEM = "apple-generic"; 502 | VERSION_INFO_PREFIX = ""; 503 | }; 504 | name = Debug; 505 | }; 506 | D76538621C4F21010073C059 /* Release */ = { 507 | isa = XCBuildConfiguration; 508 | buildSettings = { 509 | ALWAYS_SEARCH_USER_PATHS = NO; 510 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 511 | CLANG_CXX_LIBRARY = "libc++"; 512 | CLANG_ENABLE_MODULES = YES; 513 | CLANG_ENABLE_OBJC_ARC = YES; 514 | CLANG_WARN_BOOL_CONVERSION = YES; 515 | CLANG_WARN_CONSTANT_CONVERSION = YES; 516 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 517 | CLANG_WARN_EMPTY_BODY = YES; 518 | CLANG_WARN_ENUM_CONVERSION = YES; 519 | CLANG_WARN_INFINITE_RECURSION = YES; 520 | CLANG_WARN_INT_CONVERSION = YES; 521 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 522 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 523 | CLANG_WARN_UNREACHABLE_CODE = YES; 524 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 525 | CODE_SIGN_IDENTITY = "-"; 526 | COPY_PHASE_STRIP = NO; 527 | CURRENT_PROJECT_VERSION = 1; 528 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 529 | ENABLE_NS_ASSERTIONS = NO; 530 | ENABLE_STRICT_OBJC_MSGSEND = YES; 531 | GCC_C_LANGUAGE_STANDARD = gnu99; 532 | GCC_NO_COMMON_BLOCKS = YES; 533 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 534 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 535 | GCC_WARN_UNDECLARED_SELECTOR = YES; 536 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 537 | GCC_WARN_UNUSED_FUNCTION = YES; 538 | GCC_WARN_UNUSED_VARIABLE = YES; 539 | MACOSX_DEPLOYMENT_TARGET = 10.9; 540 | MTL_ENABLE_DEBUG_INFO = NO; 541 | SDKROOT = macosx; 542 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; 543 | VERSIONING_SYSTEM = "apple-generic"; 544 | VERSION_INFO_PREFIX = ""; 545 | }; 546 | name = Release; 547 | }; 548 | D76538641C4F21010073C059 /* Debug */ = { 549 | isa = XCBuildConfiguration; 550 | baseConfigurationReference = 3E7EA329915BDB4188160025 /* Pods-OAStatusItemKit.debug.xcconfig */; 551 | buildSettings = { 552 | COMBINE_HIDPI_IMAGES = YES; 553 | DEFINES_MODULE = YES; 554 | DYLIB_COMPATIBILITY_VERSION = 1; 555 | DYLIB_CURRENT_VERSION = 1; 556 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 557 | FRAMEWORK_VERSION = A; 558 | INFOPLIST_FILE = OAStatusItemKit/Info.plist; 559 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 560 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/Frameworks"; 561 | MACOSX_DEPLOYMENT_TARGET = 10.11; 562 | PRODUCT_BUNDLE_IDENTIFIER = nsomar.OAStatusItemKit; 563 | PRODUCT_NAME = "$(TARGET_NAME)"; 564 | SKIP_INSTALL = YES; 565 | SWIFT_VERSION = 3.0; 566 | }; 567 | name = Debug; 568 | }; 569 | D76538651C4F21010073C059 /* Release */ = { 570 | isa = XCBuildConfiguration; 571 | baseConfigurationReference = B89204C89E477875464B16DE /* Pods-OAStatusItemKit.release.xcconfig */; 572 | buildSettings = { 573 | COMBINE_HIDPI_IMAGES = YES; 574 | DEFINES_MODULE = YES; 575 | DYLIB_COMPATIBILITY_VERSION = 1; 576 | DYLIB_CURRENT_VERSION = 1; 577 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 578 | FRAMEWORK_VERSION = A; 579 | INFOPLIST_FILE = OAStatusItemKit/Info.plist; 580 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 581 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/Frameworks"; 582 | MACOSX_DEPLOYMENT_TARGET = 10.11; 583 | PRODUCT_BUNDLE_IDENTIFIER = nsomar.OAStatusItemKit; 584 | PRODUCT_NAME = "$(TARGET_NAME)"; 585 | SKIP_INSTALL = YES; 586 | SWIFT_VERSION = 3.0; 587 | }; 588 | name = Release; 589 | }; 590 | D76538671C4F21010073C059 /* Debug */ = { 591 | isa = XCBuildConfiguration; 592 | baseConfigurationReference = BEBBCEF0D972CAF3A86BEB16 /* Pods-OAStatusItemKitTests.debug.xcconfig */; 593 | buildSettings = { 594 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; 595 | CLANG_ENABLE_MODULES = YES; 596 | COMBINE_HIDPI_IMAGES = YES; 597 | INFOPLIST_FILE = OAStatusItemKitTests/Info.plist; 598 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; 599 | MACOSX_DEPLOYMENT_TARGET = 10.11; 600 | PRODUCT_BUNDLE_IDENTIFIER = nsomar.OAStatusItemKitTests; 601 | PRODUCT_NAME = "$(TARGET_NAME)"; 602 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 603 | SWIFT_VERSION = 3.0; 604 | }; 605 | name = Debug; 606 | }; 607 | D76538681C4F21010073C059 /* Release */ = { 608 | isa = XCBuildConfiguration; 609 | baseConfigurationReference = A8C2877BBEF8DD99180BE6C3 /* Pods-OAStatusItemKitTests.release.xcconfig */; 610 | buildSettings = { 611 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; 612 | CLANG_ENABLE_MODULES = YES; 613 | COMBINE_HIDPI_IMAGES = YES; 614 | INFOPLIST_FILE = OAStatusItemKitTests/Info.plist; 615 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; 616 | MACOSX_DEPLOYMENT_TARGET = 10.11; 617 | PRODUCT_BUNDLE_IDENTIFIER = nsomar.OAStatusItemKitTests; 618 | PRODUCT_NAME = "$(TARGET_NAME)"; 619 | SWIFT_VERSION = 3.0; 620 | }; 621 | name = Release; 622 | }; 623 | /* End XCBuildConfiguration section */ 624 | 625 | /* Begin XCConfigurationList section */ 626 | D76538491C4F21000073C059 /* Build configuration list for PBXProject "OAStatusItemKit" */ = { 627 | isa = XCConfigurationList; 628 | buildConfigurations = ( 629 | D76538611C4F21010073C059 /* Debug */, 630 | D76538621C4F21010073C059 /* Release */, 631 | ); 632 | defaultConfigurationIsVisible = 0; 633 | defaultConfigurationName = Release; 634 | }; 635 | D76538631C4F21010073C059 /* Build configuration list for PBXNativeTarget "OAStatusItemKit" */ = { 636 | isa = XCConfigurationList; 637 | buildConfigurations = ( 638 | D76538641C4F21010073C059 /* Debug */, 639 | D76538651C4F21010073C059 /* Release */, 640 | ); 641 | defaultConfigurationIsVisible = 0; 642 | defaultConfigurationName = Release; 643 | }; 644 | D76538661C4F21010073C059 /* Build configuration list for PBXNativeTarget "OAStatusItemKitTests" */ = { 645 | isa = XCConfigurationList; 646 | buildConfigurations = ( 647 | D76538671C4F21010073C059 /* Debug */, 648 | D76538681C4F21010073C059 /* Release */, 649 | ); 650 | defaultConfigurationIsVisible = 0; 651 | defaultConfigurationName = Release; 652 | }; 653 | /* End XCConfigurationList section */ 654 | }; 655 | rootObject = D76538461C4F21000073C059 /* Project object */; 656 | } 657 | -------------------------------------------------------------------------------- /OAStatusItemKit/OAStatusItemKit.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /OAStatusItemKit/OAStatusItemKit.xcodeproj/xcshareddata/xcschemes/OAStatusItemKit.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 33 | 39 | 40 | 41 | 42 | 43 | 49 | 50 | 51 | 52 | 53 | 54 | 64 | 65 | 71 | 72 | 73 | 74 | 75 | 76 | 82 | 83 | 89 | 90 | 91 | 92 | 94 | 95 | 98 | 99 | 100 | -------------------------------------------------------------------------------- /OAStatusItemKit/OAStatusItemKit.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /OAStatusItemKit/OAStatusItemKit/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | $(CURRENT_PROJECT_VERSION) 23 | NSHumanReadableCopyright 24 | Copyright © 2016 Omar Abdelhafith. All rights reserved. 25 | NSPrincipalClass 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /OAStatusItemKit/OAStatusItemKit/OAStatusItemKit.h: -------------------------------------------------------------------------------- 1 | // 2 | // OAStatusItemKit.h 3 | // OAStatusItemKit 4 | // 5 | // Created by Omar Abdelhafith on 20/01/2016. 6 | // Copyright © 2016 Omar Abdelhafith. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | //! Project version number for OAStatusItemKit. 12 | FOUNDATION_EXPORT double OAStatusItemKitVersionNumber; 13 | 14 | //! Project version string for OAStatusItemKit. 15 | FOUNDATION_EXPORT const unsigned char OAStatusItemKitVersionString[]; 16 | 17 | // In this header, you should import all the public headers of your framework using statements like #import 18 | 19 | 20 | -------------------------------------------------------------------------------- /OAStatusItemKit/OAStatusItemKitTests/ImageDrawerSpec.swift: -------------------------------------------------------------------------------- 1 | import Quick 2 | import Nimble 3 | 4 | @testable import OAStatusItemKit 5 | 6 | class ImageDrawerSpec: QuickSpec { 7 | override func spec() { 8 | 9 | it("Draws the image in the rect") { 10 | let dummy = DummyImage(size: NSMakeSize(2.0, 2.0)) 11 | 12 | ImageDrawer.draw(image: dummy, inRect: NSMakeRect(0.0, 0.0, 10.0, 10.0)) 13 | 14 | expect(dummy.drawPoint) == NSMakePoint(4.0, 4.0) 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /OAStatusItemKit/OAStatusItemKitTests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | 24 | 25 | -------------------------------------------------------------------------------- /OAStatusItemKit/OAStatusItemKitTests/StatusBarImagesSpec.swift: -------------------------------------------------------------------------------- 1 | import Quick 2 | import Nimble 3 | @testable import OAStatusItemKit 4 | 5 | 6 | class StatusBarImagesSpec: QuickSpec { 7 | override func spec() { 8 | 9 | describe("StatusBarImages") { 10 | var statusBarImages: StatusBarImages! 11 | 12 | describe("Initializing with 1 image") { 13 | let tintedImage = DummyImage(size: NSMakeSize(2, 2)) 14 | let image = DummyImage(size: NSMakeSize(1, 1), tintedImage: tintedImage) 15 | tintedImage.tintedImage = image 16 | 17 | context("Bright Interface") { 18 | 19 | beforeEach { 20 | statusBarImages = StatusBarImages(image: image, 21 | statusBarInterface: MockStatusBarInterface(isDarkInterface: false, statusBarHeight: 100)) 22 | } 23 | 24 | it("returns the passed image") { 25 | expect(statusBarImages.image) == image 26 | } 27 | 28 | it("returns a tinted image when highlighted") { 29 | statusBarImages.isHighlighted = true 30 | expect(statusBarImages.image) == tintedImage 31 | } 32 | 33 | it("returns size of the image") { 34 | expect(statusBarImages.imagesSize) == NSMakeSize(1, 1) 35 | } 36 | 37 | } 38 | 39 | context("Dark Interface") { 40 | 41 | beforeEach { 42 | statusBarImages = StatusBarImages(image: image, 43 | statusBarInterface: MockStatusBarInterface(isDarkInterface: true, statusBarHeight: 100)) 44 | } 45 | 46 | it("returns a tinted image") { 47 | expect(statusBarImages.image) == tintedImage 48 | } 49 | 50 | it("returns the same tinted image") { 51 | statusBarImages.isHighlighted = true 52 | expect(statusBarImages.image) == tintedImage 53 | } 54 | 55 | it("returns size of the tinted image") { 56 | expect(statusBarImages.imagesSize) == NSMakeSize(2, 2) 57 | } 58 | 59 | } 60 | 61 | } 62 | 63 | 64 | describe("Initializing with 2 image") { 65 | 66 | let tintedDarkImage = DummyImage(size: NSMakeSize(2, 2)) 67 | let darkImage = DummyImage(size: NSMakeSize(1, 1), tintedImage: tintedDarkImage) 68 | tintedDarkImage.tintedImage = darkImage 69 | 70 | let tintedBrightImage = DummyImage(size: NSMakeSize(20, 20)) 71 | let brightImage = DummyImage(size: NSMakeSize(10, 10), tintedImage: tintedBrightImage) 72 | tintedBrightImage.tintedImage = brightImage 73 | 74 | context("Bright Interface") { 75 | 76 | beforeEach { 77 | statusBarImages = StatusBarImages(brightImage: brightImage, darkImage: darkImage, 78 | statusBarInterface: MockStatusBarInterface(isDarkInterface: false, statusBarHeight: 100)) 79 | } 80 | 81 | it("returns the bright image") { 82 | expect(statusBarImages.image) == brightImage 83 | } 84 | 85 | it("returns the dark image instead of a tinted image") { 86 | statusBarImages.isHighlighted = true 87 | expect(statusBarImages.image) == darkImage 88 | } 89 | 90 | it("returns size of the image") { 91 | expect(statusBarImages.imagesSize) == NSMakeSize(10, 10) 92 | } 93 | } 94 | 95 | context("Dark Interface") { 96 | beforeEach { 97 | statusBarImages = StatusBarImages(brightImage: brightImage, darkImage: darkImage, 98 | statusBarInterface: MockStatusBarInterface(isDarkInterface: true, statusBarHeight: 100)) 99 | } 100 | 101 | it("returns the dark image") { 102 | expect(statusBarImages.image) == darkImage 103 | } 104 | 105 | it("returns the same dark image") { 106 | statusBarImages.isHighlighted = true 107 | expect(statusBarImages.image) == darkImage 108 | } 109 | 110 | it("returns size of the tinted image") { 111 | expect(statusBarImages.imagesSize) == NSMakeSize(1, 1) 112 | } 113 | 114 | } 115 | 116 | } 117 | 118 | } 119 | } 120 | } -------------------------------------------------------------------------------- /OAStatusItemKit/OAStatusItemKitTests/StatusBarItemViewSpec.swift: -------------------------------------------------------------------------------- 1 | import Quick 2 | import Nimble 3 | 4 | @testable import OAStatusItemKit 5 | 6 | 7 | class StatusBarItemViewSpec: QuickSpec { 8 | override func spec() { 9 | 10 | it("gets initialized with two images") { 11 | 12 | let brightImage = NSImage() 13 | let darkImage = NSImage() 14 | let statusView = StatusBarItemView(brightStatusImage: brightImage, darkStatusImage: darkImage) 15 | 16 | expect(statusView.statusBarImages.brightImage) == brightImage 17 | expect(statusView.statusBarImages.darkImage) == darkImage 18 | } 19 | 20 | it("gets initialized with single image") { 21 | 22 | let image = NSImage() 23 | let statusView = StatusBarItemView(statusImage: image) 24 | 25 | expect(statusView.statusBarImages.brightImage) == image 26 | expect(statusView.statusBarImages.darkImage).to(beNil()) 27 | } 28 | 29 | it("creates a view with correct height and width") { 30 | let interface = MockStatusBarInterface(isDarkInterface: true, statusBarHeight: 22.0) 31 | let image = NSImage(size: NSMakeSize(10.0, 10.0)) 32 | 33 | let statusView = 34 | StatusBarItemView(statusBarImages: StatusBarImages(image: image), statusBarInterface: interface) 35 | 36 | expect(statusView.frame) == NSMakeRect(0.0, 0.0, 18.0, 22.0) 37 | } 38 | 39 | it("updates the frame width") { 40 | let statusView = StatusBarItemView(statusBarImages: StatusBarImages(image: NSImage())) 41 | 42 | statusView.itemWidth = 200.0 43 | expect(statusView.frame) == NSMakeRect(0.0, 0.0, 200.0, 22.0) 44 | } 45 | 46 | it("handles clicks") { 47 | let statusView = StatusBarItemView(statusBarImages: StatusBarImages(image: NSImage())) 48 | 49 | var clicked = false 50 | statusView.clickHandler = { highlighted in 51 | clicked = true 52 | } 53 | 54 | expect(clicked) == false 55 | 56 | statusView.mouseDown(with: NSEvent()) 57 | expect(clicked) == true 58 | } 59 | 60 | it("becomes highlighted when clicked") { 61 | let statusView = StatusBarItemView(statusBarImages: StatusBarImages(image: NSImage())) 62 | 63 | expect(statusView.isHighlighted) == false 64 | expect(statusView.statusBarImages.isHighlighted) == false 65 | 66 | statusView.mouseDown(with: NSEvent()) 67 | 68 | expect(statusView.isHighlighted) == true 69 | expect(statusView.statusBarImages.isHighlighted) == true 70 | } 71 | 72 | it("returns the rect in a window") { 73 | let statusView = StatusBarItemView(statusBarImages: StatusBarImages(image: NSImage())) 74 | let window = 75 | NSWindow(contentRect: NSMakeRect(0.0, 0.0, 500.0, 500.0), 76 | styleMask: NSWindowStyleMask(rawValue: 1), backing: NSBackingStoreType.buffered, defer: false) 77 | 78 | window.contentView?.addSubview(statusView) 79 | statusView.frame = NSMakeRect(10.0, 10.0, 100, 100) 80 | 81 | expect(statusView.statusBarRect.size) == NSMakeSize(100, 22.0) 82 | expect(statusView.statusBarRect.origin.x) == 0 83 | } 84 | 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /OAStatusItemKit/OAStatusItemKitTests/TestHelper.swift: -------------------------------------------------------------------------------- 1 | // 2 | // TestHelper.swift 3 | // OAStatusItemKit 4 | // 5 | // Created by Omar Abdelhafith on 20/01/2016. 6 | // Copyright © 2016 Omar Abdelhafith. All rights reserved. 7 | // 8 | 9 | import Cocoa 10 | 11 | @testable import OAStatusItemKit 12 | 13 | 14 | struct MockStatusBarInterface: StatusBarInterface { 15 | var isDarkInterface: Bool 16 | var statusBarHeight: CGFloat 17 | } 18 | 19 | class DummyImage: NSImage { 20 | 21 | var tintedImage: NSImage? 22 | var drawPoint: NSPoint? 23 | 24 | convenience init(size: NSSize, tintedImage: NSImage) { 25 | self.init(size: size) 26 | self.tintedImage = tintedImage 27 | } 28 | 29 | override func imageTinted(withColor color: NSColor) -> NSImage { 30 | return tintedImage! 31 | } 32 | 33 | override func draw(at point: NSPoint, from fromRect: NSRect, operation op: NSCompositingOperation, fraction delta: CGFloat) { 34 | drawPoint = point 35 | } 36 | } 37 | 38 | class DummyWindow: NSWindow { 39 | convenience init(frame: CGRect) { 40 | self.init() 41 | self.contentView = DummyView(fittingSize: frame.size) 42 | } 43 | } 44 | 45 | class DummyView: NSView { 46 | var __fittingSize: NSSize? = NSZeroSize 47 | 48 | convenience init(fittingSize: NSSize) { 49 | self.init() 50 | self.__fittingSize = fittingSize 51 | } 52 | 53 | override var fittingSize: NSSize { 54 | get { 55 | return __fittingSize! 56 | } 57 | } 58 | } 59 | 60 | class DummyScreen: NSScreen { 61 | var __frame: NSRect? = CGRect.zero 62 | 63 | convenience init(frame: CGRect) { 64 | self.init() 65 | self.__frame = frame 66 | } 67 | 68 | override var frame: NSRect { 69 | get { 70 | return __frame! 71 | } 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /OAStatusItemKit/OAStatusItemKitTests/WindowPlacerSpec.swift: -------------------------------------------------------------------------------- 1 | import Quick 2 | import Nimble 3 | 4 | @testable import OAStatusItemKit 5 | 6 | class WindowPlacerSpec: QuickSpec { 7 | override func spec() { 8 | 9 | let window = DummyWindow(frame: NSRect(x: 0.0, y: 0.0, width: 200.0, height: 200.0)) 10 | let screen = DummyScreen(frame: NSRect(x: 0.0, y: 0.0, width: 500.0, height: 500.0)) 11 | 12 | 13 | describe("Screen bottom") { 14 | 15 | it("returns the left bottom coordinates") { 16 | 17 | let statusItemRect = NSRect(x: 260.0, y: 478.0, width: 22.0, height: 22.0) 18 | let rect = ScreenWindowPlacer() 19 | .rect(forWindow: window, withSize: nil, 20 | statusBarItemRect: statusItemRect, 21 | inScreen: screen, 22 | placement: .screenBottomLeft) 23 | 24 | expect(rect) == NSRect(x: 12, y: 12, width: 200.0, height: 200.0) 25 | 26 | expect(StatusWindowPlacement 27 | .screenBottomLeft 28 | .rect(forWindow: window, 29 | withSize: nil, 30 | statusBarItemRect: statusItemRect, 31 | inScreen: screen)) == NSRect(x: 12, y: 12, width: 200.0, height: 200.0) 32 | } 33 | 34 | it("returns the center bottom coordinates") { 35 | 36 | let statusItemRect = NSRect(x: 260.0, y: 478.0, width: 22.0, height: 22.0) 37 | let rect = ScreenWindowPlacer() 38 | .rect(forWindow: window, withSize: nil, 39 | statusBarItemRect: statusItemRect, 40 | inScreen: screen, 41 | placement: .screenBottomCenter) 42 | 43 | expect(rect) == NSRect(x: 150, y: 12, width: 200.0, height: 200.0) 44 | 45 | expect(StatusWindowPlacement 46 | .screenBottomCenter 47 | .rect(forWindow: window, 48 | withSize: nil, 49 | statusBarItemRect: statusItemRect, 50 | inScreen: screen)) == NSRect(x: 150, y: 12, width: 200.0, height: 200.0) 51 | } 52 | 53 | it("returns the right bottom coordinates") { 54 | 55 | let statusItemRect = NSRect(x: 260.0, y: 478.0, width: 22.0, height: 22.0) 56 | let rect = ScreenWindowPlacer() 57 | .rect(forWindow: window, withSize: nil, 58 | statusBarItemRect: statusItemRect, 59 | inScreen: screen, 60 | placement: .screenBottomRight) 61 | 62 | expect(rect) == NSRect(x: 288, y: 12, width: 200.0, height: 200.0) 63 | 64 | expect(StatusWindowPlacement 65 | .screenBottomRight 66 | .rect(forWindow: window, 67 | withSize: nil, 68 | statusBarItemRect: statusItemRect, 69 | inScreen: screen)) == NSRect(x: 288, y: 12, width: 200.0, height: 200.0) 70 | } 71 | 72 | } 73 | 74 | describe("Screen top") { 75 | 76 | it("returns the left top coordinates") { 77 | 78 | let statusItemRect = NSRect(x: 260.0, y: 478.0, width: 22.0, height: 22.0) 79 | let rect = ScreenWindowPlacer() 80 | .rect(forWindow: window, withSize: nil, 81 | statusBarItemRect: statusItemRect, 82 | inScreen: screen, 83 | placement: .screenTopLeft) 84 | 85 | expect(rect) == NSRect(x: 12, y: 278, width: 200.0, height: 200.0) 86 | 87 | expect(StatusWindowPlacement 88 | .screenTopLeft 89 | .rect(forWindow: window, 90 | withSize: nil, 91 | statusBarItemRect: statusItemRect, 92 | inScreen: screen)) == NSRect(x: 12, y: 278, width: 200.0, height: 200.0) 93 | } 94 | 95 | it("returns the center top coordinates") { 96 | 97 | let statusItemRect = NSRect(x: 260.0, y: 478.0, width: 22.0, height: 22.0) 98 | let rect = ScreenWindowPlacer() 99 | .rect(forWindow: window, withSize: nil, 100 | statusBarItemRect: statusItemRect, 101 | inScreen: screen, 102 | placement: .screenTopCenter) 103 | 104 | expect(rect) == NSRect(x: 150, y: 278, width: 200.0, height: 200.0) 105 | 106 | expect(StatusWindowPlacement 107 | .screenTopCenter 108 | .rect(forWindow: window, 109 | withSize: nil, 110 | statusBarItemRect: statusItemRect, 111 | inScreen: screen)) == NSRect(x: 150, y: 278, width: 200.0, height: 200.0) 112 | } 113 | 114 | it("returns the right top coordinates") { 115 | 116 | let statusItemRect = NSRect(x: 260.0, y: 478.0, width: 22.0, height: 22.0) 117 | let rect = ScreenWindowPlacer() 118 | .rect(forWindow: window, withSize: nil, 119 | statusBarItemRect: statusItemRect, 120 | inScreen: screen, 121 | placement: .screenTopRight) 122 | 123 | expect(rect) == NSRect(x: 288, y: 278, width: 200.0, height: 200.0) 124 | 125 | expect(StatusWindowPlacement 126 | .screenTopRight 127 | .rect(forWindow: window, 128 | withSize: nil, 129 | statusBarItemRect: statusItemRect, 130 | inScreen: screen)) == NSRect(x: 288, y: 278, width: 200.0, height: 200.0) 131 | } 132 | 133 | } 134 | 135 | 136 | describe("Screen middle") { 137 | 138 | it("returns the left middle coordinates") { 139 | 140 | let statusItemRect = NSRect(x: 260.0, y: 478.0, width: 22.0, height: 22.0) 141 | let rect = ScreenWindowPlacer() 142 | .rect(forWindow: window, withSize: nil, 143 | statusBarItemRect: statusItemRect, 144 | inScreen: screen, 145 | placement: .screenMiddleLeft) 146 | 147 | expect(rect) == NSRect(x: 12, y: 139, width: 200.0, height: 200.0) 148 | 149 | expect(StatusWindowPlacement 150 | .screenMiddleLeft 151 | .rect(forWindow: window, 152 | withSize: nil, 153 | statusBarItemRect: statusItemRect, 154 | inScreen: screen)) == NSRect(x: 12, y: 139, width: 200.0, height: 200.0) 155 | } 156 | 157 | it("returns the center middle coordinates") { 158 | 159 | let statusItemRect = NSRect(x: 260.0, y: 478.0, width: 22.0, height: 22.0) 160 | let rect = ScreenWindowPlacer() 161 | .rect(forWindow: window, withSize: nil, 162 | statusBarItemRect: statusItemRect, 163 | inScreen: screen, 164 | placement: .screenMiddleCenter) 165 | 166 | expect(rect) == NSRect(x: 150, y: 139, width: 200.0, height: 200.0) 167 | 168 | expect(StatusWindowPlacement 169 | .screenMiddleCenter 170 | .rect(forWindow: window, 171 | withSize: nil, 172 | statusBarItemRect: statusItemRect, 173 | inScreen: screen)) == NSRect(x: 150, y: 139, width: 200.0, height: 200.0) 174 | 175 | } 176 | 177 | it("returns the right middle coordinates") { 178 | 179 | let statusItemRect = NSRect(x: 260.0, y: 478.0, width: 22.0, height: 22.0) 180 | let rect = ScreenWindowPlacer() 181 | .rect(forWindow: window, withSize: nil, 182 | statusBarItemRect: statusItemRect, 183 | inScreen: screen, 184 | placement: .screenMiddleRight) 185 | 186 | expect(rect) == NSRect(x: 288, y: 139, width: 200.0, height: 200.0) 187 | 188 | expect(StatusWindowPlacement 189 | .screenMiddleRight 190 | .rect(forWindow: window, 191 | withSize: nil, 192 | statusBarItemRect: statusItemRect, 193 | inScreen: screen)) == NSRect(x: 288, y: 139, width: 200.0, height: 200.0) 194 | } 195 | 196 | } 197 | 198 | 199 | describe("Status bar item relative") { 200 | 201 | it("places the window on the center of the status bar item view") { 202 | 203 | let statusItemRect = NSRect(x: 260.0, y: 478.0, width: 22.0, height: 22.0) 204 | let rect = StatusBarItemCenterPlacer() 205 | .rect(forWindow: window, withSize: nil, 206 | statusBarItemRect: statusItemRect, 207 | placement: .statusBarItemCenter) 208 | 209 | expect(rect) == NSRect(x: 171, y: 278, width: 200.0, height: 200.0) 210 | 211 | expect(StatusWindowPlacement 212 | .statusBarItemCenter 213 | .rect(forWindow: window, 214 | withSize: nil, 215 | statusBarItemRect: statusItemRect, 216 | inScreen: screen)) == NSRect(x: 171, y: 278, width: 200.0, height: 200.0) 217 | } 218 | 219 | 220 | it("places the window on the right of the status bar item view") { 221 | 222 | let statusItemRect = NSRect(x: 260.0, y: 478.0, width: 22.0, height: 22.0) 223 | let rect = StatusBarItemCenterPlacer() 224 | .rect(forWindow: window, withSize: nil, 225 | statusBarItemRect: statusItemRect, 226 | placement: .statusBarItemRight) 227 | 228 | expect(rect) == NSRect(x: 248, y: 278, width: 200.0, height: 200.0) 229 | 230 | expect(StatusWindowPlacement 231 | .statusBarItemRight 232 | .rect(forWindow: window, 233 | withSize: nil, 234 | statusBarItemRect: statusItemRect, 235 | inScreen: screen)) == NSRect(x: 248, y: 278, width: 200.0, height: 200.0) 236 | } 237 | 238 | 239 | it("places the window on the left of the status bar item view") { 240 | 241 | let statusItemRect = NSRect(x: 260.0, y: 478.0, width: 22.0, height: 22.0) 242 | let rect = StatusBarItemCenterPlacer() 243 | .rect(forWindow: window, withSize: nil, 244 | statusBarItemRect: statusItemRect, 245 | placement: .statusBarItemLeft) 246 | 247 | expect(rect) == NSRect(x: 94.0, y: 278, width: 200.0, height: 200.0) 248 | 249 | expect(StatusWindowPlacement 250 | .statusBarItemLeft 251 | .rect(forWindow: window, 252 | withSize: nil, 253 | statusBarItemRect: statusItemRect, 254 | inScreen: screen)) == NSRect(x: 94.0, y: 278, width: 200.0, height: 200.0) 255 | } 256 | 257 | } 258 | 259 | it("places the window inside the screen") { 260 | 261 | let statusItemRect = NSRect(x: 450.0, y: 478.0, width: 22.0, height: 22.0) 262 | 263 | expect(StatusWindowPlacement 264 | .statusBarItemRight 265 | .rect(forWindow: window, 266 | withSize: nil, 267 | statusBarItemRect: statusItemRect, 268 | inScreen: screen)) == NSRect(x: 288.0, y: 278.0, width: 200.0, height: 200.0) 269 | } 270 | 271 | } 272 | 273 | } 274 | -------------------------------------------------------------------------------- /OAStatusItemKit/Podfile: -------------------------------------------------------------------------------- 1 | platform :osx, '10.10' 2 | use_frameworks! 3 | 4 | target 'OAStatusItemKit' do 5 | 6 | end 7 | 8 | target 'OAStatusItemKitTests' do 9 | pod 'Quick' 10 | pod 'Nimble' 11 | end 12 | -------------------------------------------------------------------------------- /OAStatusItemKit/Podfile.lock: -------------------------------------------------------------------------------- 1 | PODS: 2 | - Nimble (6.0.1) 3 | - Quick (1.1.0) 4 | 5 | DEPENDENCIES: 6 | - Nimble 7 | - Quick 8 | 9 | SPEC CHECKSUMS: 10 | Nimble: 1527fd1bd2b4cf0636251a36bc8ab37e81da8347 11 | Quick: dafc587e21eed9f4cab3249b9f9015b0b7a7f71d 12 | 13 | PODFILE CHECKSUM: 38cd81d6f14c011a0af23f58719eb49c71083c47 14 | 15 | COCOAPODS: 1.1.1 16 | -------------------------------------------------------------------------------- /Pod/Classes/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nsomar/OAStatusItemKit/13118b5eb5a5da534c0a8188db615252f7456610/Pod/Classes/.gitkeep -------------------------------------------------------------------------------- /Pod/Classes/BundleLoading.swift: -------------------------------------------------------------------------------- 1 | // 2 | // BundleLoadable.swift 3 | // OAStatusItemKit 4 | // 5 | // Created by Omar Abdelhafith on 21/01/2016. 6 | // Copyright © 2016 Omar Abdelhafith. All rights reserved. 7 | // 8 | 9 | import Cocoa 10 | 11 | 12 | /** 13 | Class that helps loading an object from a nib 14 | */ 15 | class BundleLoading { 16 | 17 | /** 18 | Load a view from a nib 19 | 20 | - parameter xibName: the nib name 21 | */ 22 | static func load(_ xibName: String) -> T { 23 | return self.loadFromBundle(Bundle.main, nibName: xibName)! 24 | } 25 | 26 | fileprivate static func loadFromBundle(_ bundle: Bundle, nibName: String) -> T? { 27 | var objects: NSArray = [] 28 | Bundle.main.loadNibNamed(nibName, owner: nil, topLevelObjects: &objects) 29 | return objects.flatMap { $0 as? T }.first 30 | } 31 | 32 | } 33 | -------------------------------------------------------------------------------- /Pod/Classes/EventMonitor.swift: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2015 Razeware LLC 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | * THE SOFTWARE. 21 | */ 22 | 23 | import Cocoa 24 | 25 | class EventMonitor { 26 | fileprivate var monitor: AnyObject? 27 | fileprivate let mask: NSEventMask 28 | fileprivate let handler: (NSEvent?) -> () 29 | 30 | init(mask: NSEventMask, handler: @escaping (NSEvent?) -> ()) { 31 | self.mask = mask 32 | self.handler = handler 33 | } 34 | 35 | deinit { 36 | stop() 37 | } 38 | 39 | func start() { 40 | monitor = NSEvent.addGlobalMonitorForEvents(matching: mask, handler: handler) as AnyObject? 41 | } 42 | 43 | func stop() { 44 | if monitor != nil { 45 | NSEvent.removeMonitor(monitor!) 46 | monitor = nil 47 | } 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /Pod/Classes/ImageDrawer.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ImageDrawer.swift 3 | // OAStatusItemKit 4 | // 5 | // Created by Omar Abdelhafith on 20/01/2016. 6 | // Copyright © 2016 Omar Abdelhafith. All rights reserved. 7 | // 8 | 9 | import Cocoa 10 | 11 | struct ImageDrawer { 12 | 13 | /** 14 | Draws an image in the current graphical context 15 | 16 | - parameter image: image to draw 17 | - parameter rect: rect to draw the image in 18 | */ 19 | static func draw(image: NSImage, inRect rect: NSRect) { 20 | image.draw( 21 | at: imageDrawingPoint(forImageSize: image.size, inRect: rect), 22 | from: .zero, 23 | operation: .sourceOver, 24 | fraction: 1.0) 25 | } 26 | 27 | /** 28 | The point at where to draw the image 29 | */ 30 | static func imageDrawingPoint(forImageSize imageSize: NSSize, inRect rect: NSRect) -> NSPoint { 31 | let iconX = roundf(Float(NSWidth(rect) - imageSize.width) / 2.0) 32 | let iconY = roundf(Float(NSHeight(rect) - imageSize.height) / 2.0) 33 | return NSMakePoint(CGFloat(iconX), CGFloat(iconY)) 34 | } 35 | 36 | } 37 | -------------------------------------------------------------------------------- /Pod/Classes/NSImage+Tint.swift: -------------------------------------------------------------------------------- 1 | // 2 | // NSImage+Tint.swift 3 | // MarkdownSharer 4 | // 5 | // Created by Omar Abdelhafith on 14/12/2015. 6 | // Copyright © 2015 Omar Abdelhafith. All rights reserved. 7 | // 8 | 9 | import Cocoa 10 | 11 | 12 | extension NSImage { 13 | 14 | /** 15 | Return a copy of the image tinted with a color 16 | 17 | - parameter color: The color to tint the image 18 | 19 | - returns: a tinted copy of the image 20 | */ 21 | func imageTinted(withColor color: NSColor) -> NSImage { 22 | let newImage = self.copy() 23 | (newImage as AnyObject).lockFocus() 24 | color.set() 25 | 26 | let imageRect = NSRect(x: 0, y: 0, width: (newImage as! NSImage).size.width, height: (newImage as! NSImage).size.height) 27 | NSRectFillUsingOperation(imageRect, .sourceAtop) 28 | (newImage as AnyObject).unlockFocus() 29 | 30 | return newImage as! NSImage 31 | } 32 | 33 | } 34 | -------------------------------------------------------------------------------- /Pod/Classes/ScreenWindowPlacer.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ScreenWindowPlacer.swift 3 | // OAStatusItemKit 4 | // 5 | // Created by Omar Abdelhafith on 21/01/2016. 6 | // Copyright © 2016 Omar Abdelhafith. All rights reserved. 7 | // 8 | 9 | import Cocoa 10 | 11 | 12 | /** 13 | Class thats responsible for placing a window relative to the screen passed 14 | */ 15 | class ScreenWindowPlacer { 16 | 17 | /** 18 | return the rect for the passed arguments 19 | 20 | - parameter window: the window to place 21 | - parameter windowSize: the window size 22 | - parameter statusBarItemRect: the status menu item rect 23 | - parameter screen: the screen 24 | - parameter placement: placement type 25 | */ 26 | func rect(forWindow window: NSWindow, withSize windowSize: CGSize?, 27 | statusBarItemRect: NSRect, inScreen screen: NSScreen, 28 | placement: StatusWindowPlacement) -> NSRect { 29 | 30 | let windowSize = windowSize ?? window.contentView!.fittingSize 31 | 32 | let point = 33 | NSPoint( 34 | x: xPos(windowSize.width, inScreen: screen, placement: placement), 35 | y: yPos(windowSize.height, inScreen: screen, statusBarItemRect: statusBarItemRect, placement: placement)) 36 | 37 | return NSRect(origin: point, size: windowSize) 38 | } 39 | 40 | fileprivate func xPos(_ windowWidth: CGFloat, inScreen screen: NSScreen, 41 | placement: StatusWindowPlacement) -> CGFloat { 42 | 43 | let screenWidth = screen.frame.size.width 44 | switch placement { 45 | case .screenTopLeft: 46 | fallthrough 47 | case .screenMiddleLeft: 48 | fallthrough 49 | case .screenBottomLeft: 50 | return defaultXMargin 51 | 52 | case .screenTopCenter: 53 | fallthrough 54 | case .screenMiddleCenter: 55 | fallthrough 56 | case .screenBottomCenter: 57 | return (screenWidth - windowWidth) / 2.0 58 | 59 | case .screenTopRight: 60 | fallthrough 61 | case .screenMiddleRight: 62 | fallthrough 63 | case .screenBottomRight: 64 | return screenWidth - windowWidth - defaultXMargin 65 | 66 | default: 67 | return 0 68 | } 69 | } 70 | 71 | fileprivate func yPos(_ windowHeight: CGFloat, inScreen screen: NSScreen, 72 | statusBarItemRect: NSRect, 73 | placement: StatusWindowPlacement) -> CGFloat { 74 | 75 | let maxYPossible = NSMinY(statusBarItemRect) 76 | 77 | switch placement { 78 | case .screenBottomLeft: 79 | fallthrough 80 | case .screenBottomCenter: 81 | fallthrough 82 | case .screenBottomRight: 83 | return defaultXMargin 84 | 85 | case .screenTopLeft: 86 | fallthrough 87 | case .screenTopCenter: 88 | fallthrough 89 | case .screenTopRight: 90 | return maxYPossible - windowHeight 91 | 92 | case .screenMiddleLeft: 93 | fallthrough 94 | case .screenMiddleCenter: 95 | fallthrough 96 | case .screenMiddleRight: 97 | return (maxYPossible - windowHeight) / 2.0 98 | 99 | default: 100 | return 0 101 | } 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /Pod/Classes/StatusBarImages.swift: -------------------------------------------------------------------------------- 1 | // 2 | // StatusBarImages.swift 3 | // MarkdownSharer 4 | // 5 | // Created by Omar Abdelhafith on 19/01/2016. 6 | // Copyright © 2016 Omar Abdelhafith. All rights reserved. 7 | // 8 | 9 | import Cocoa 10 | 11 | 12 | struct StatusBarImages { 13 | 14 | /// Images used 15 | let brightImage: NSImage 16 | let darkImage: NSImage? 17 | 18 | /// Get/Set the image highligh status 19 | var isHighlighted = false 20 | 21 | /// The current image size 22 | var imagesSize: NSSize { 23 | get { return image.size } 24 | } 25 | 26 | /// Get the current image used 27 | var image: NSImage { 28 | get { 29 | if statusBarInterface.isDarkInterface { 30 | return tintedDarkImage() 31 | } else { 32 | return tintedBrightImage() 33 | } 34 | } 35 | } 36 | 37 | fileprivate let statusBarInterface: StatusBarInterface 38 | 39 | // MARK:- Initializers 40 | 41 | /** 42 | Initialize with a single image 43 | 44 | - parameter image: Image to use 45 | - parameter statusBarInterface Status bar interface helper to use 46 | */ 47 | init(image: NSImage, 48 | statusBarInterface: StatusBarInterface = StatusBarUtilities()) { 49 | 50 | self.statusBarInterface = statusBarInterface 51 | self.brightImage = image 52 | self.darkImage = nil 53 | } 54 | 55 | /** 56 | Initialize with 2 images 57 | 58 | - parameter brightImage: Image to use in bright status bar theme 59 | - parameter darkImage: Image to use in dark status bar theme 60 | - parameter statusBarInterface Status bar interface helper to use 61 | */ 62 | init(brightImage: NSImage, darkImage: NSImage, 63 | statusBarInterface: StatusBarInterface = StatusBarUtilities()) { 64 | 65 | self.statusBarInterface = statusBarInterface 66 | self.brightImage = brightImage 67 | self.darkImage = darkImage 68 | } 69 | 70 | /** 71 | Draw the current image in the current drawing context 72 | 73 | - parameter rect: the rect representing the size of the status bar item view 74 | */ 75 | func drawImage(inRect rect: NSRect) { 76 | ImageDrawer.draw(image: image, inRect: rect) 77 | } 78 | 79 | // MARK:- Private 80 | 81 | /** 82 | Returns the bright image if not highlighted. 83 | If highlighted, return the darkImage or a tinted bright image 84 | */ 85 | func tintedBrightImage() -> NSImage { 86 | if isHighlighted { 87 | return darkImage ?? brightImage.imageTinted(withColor: NSColor.white) 88 | } else { 89 | return brightImage 90 | } 91 | } 92 | 93 | /** 94 | Returns the dark image or a tinted bright image 95 | */ 96 | func tintedDarkImage() -> NSImage { 97 | return darkImage ?? brightImage.imageTinted(withColor: NSColor.white) 98 | } 99 | 100 | } 101 | -------------------------------------------------------------------------------- /Pod/Classes/StatusBarInterface.swift: -------------------------------------------------------------------------------- 1 | // 2 | // StatusBarInterface.swift 3 | // OAStatusItemKit 4 | // 5 | // Created by Omar Abdelhafith on 20/01/2016. 6 | // Copyright © 2016 Omar Abdelhafith. All rights reserved. 7 | // 8 | 9 | import Cocoa 10 | 11 | 12 | /** 13 | * Status bar interface utility 14 | */ 15 | protocol StatusBarInterface { 16 | 17 | /** 18 | * return true if the status bar is in dark theme 19 | */ 20 | var isDarkInterface: Bool { get } 21 | 22 | /** 23 | * return the height of the status bar 24 | */ 25 | var statusBarHeight: CGFloat { get } 26 | } 27 | 28 | 29 | class StatusBarUtilities: StatusBarInterface { 30 | 31 | /// Return true if the status ber is in dark theme 32 | var isDarkInterface: Bool { 33 | get { 34 | return UserDefaults.standard.string(forKey: "AppleInterfaceStyle") == "Dark" 35 | } 36 | } 37 | 38 | /// Return the height of the status bar 39 | var statusBarHeight: CGFloat { 40 | get { 41 | return NSStatusBar.system().thickness 42 | } 43 | } 44 | 45 | } 46 | -------------------------------------------------------------------------------- /Pod/Classes/StatusBarItemCenterPlacer.swift: -------------------------------------------------------------------------------- 1 | // 2 | // StatusBarItemCenterPlacer.swift 3 | // OAStatusItemKit 4 | // 5 | // Created by Omar Abdelhafith on 21/01/2016. 6 | // Copyright © 2016 Omar Abdelhafith. All rights reserved. 7 | // 8 | 9 | import Cocoa 10 | 11 | 12 | /** 13 | Class thats responsible for placing a window relative to the status bar item view 14 | */ 15 | class StatusBarItemCenterPlacer { 16 | 17 | /** 18 | return the rect for the passed arguments 19 | 20 | - parameter window: the window to place 21 | - parameter windowSize: the window size 22 | - parameter statusBarItemRect: the status menu item rect 23 | - parameter placement: placement type 24 | */ 25 | func rect(forWindow window: NSWindow, withSize windowSize: CGSize?, 26 | statusBarItemRect: NSRect, placement: StatusWindowPlacement) -> NSRect { 27 | 28 | let windowSize = windowSize ?? window.contentView!.fittingSize 29 | let statusRect = self.rectForStatusItem(statusBarItemRect) 30 | 31 | let point = 32 | NSPoint( 33 | x: xPos(statusRect: statusRect, windowWidth: windowSize.width, placement: placement), 34 | y: NSMaxY(statusRect) - windowSize.height) 35 | 36 | return NSRect(origin: point, size: windowSize) 37 | } 38 | 39 | fileprivate func xPos(statusRect: NSRect, windowWidth: CGFloat, placement: StatusWindowPlacement) -> CGFloat { 40 | 41 | switch placement { 42 | case .statusBarItemCenter: 43 | return NSMidX(statusRect) - windowWidth / 2.0 44 | 45 | case .statusBarItemLeft: 46 | return NSMaxX(statusRect) - windowWidth + defaultXMargin 47 | 48 | case .statusBarItemRight: 49 | return NSMinX(statusRect) - defaultXMargin 50 | 51 | default: 52 | return 0 53 | } 54 | } 55 | 56 | fileprivate func rectForStatusItem(_ statusBarItemRect: NSRect) -> NSRect { 57 | var statusRect = NSZeroRect 58 | 59 | statusRect = statusBarItemRect 60 | statusRect.origin.y = NSMinY(statusRect) - NSHeight(statusRect) 61 | 62 | return statusRect 63 | } 64 | 65 | } 66 | -------------------------------------------------------------------------------- /Pod/Classes/StatusBarItemView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // StatusBarItemView.swift 3 | // MarkdownSharer 4 | // 5 | // Created by Omar Abdelhafith on 07/12/2015. 6 | // Copyright © 2015 Omar Abdelhafith. All rights reserved. 7 | // 8 | 9 | import Cocoa 10 | 11 | 12 | /** 13 | Class representing a status bar item view 14 | */ 15 | open class StatusBarItemView: NSView { 16 | 17 | /** 18 | The status bar images 19 | */ 20 | var statusBarImages: StatusBarImages 21 | 22 | /** 23 | Status Item to use in mac status bar 24 | */ 25 | var statusItem: NSStatusItem 26 | 27 | /** 28 | Click handler called when the status bar item is clicked 29 | */ 30 | open var clickHandler: ((_ isHighlighted: Bool) -> ())? 31 | 32 | /** 33 | Sets/Gets the highlighted status of the status bar item 34 | */ 35 | open var isHighlighted: Bool = false { 36 | didSet { 37 | statusBarImages.isHighlighted = isHighlighted 38 | needsDisplay = true 39 | } 40 | } 41 | 42 | /** 43 | Gets/Sets the status bar item view 44 | The status bar item height is always the height of the mac status bar 45 | */ 46 | open var itemWidth: CGFloat { 47 | didSet { 48 | let itemHeight = NSStatusBar.system().thickness 49 | self.frame = NSRect(x: 0.0, y: 0.0, width: itemWidth, height: itemHeight) 50 | } 51 | } 52 | 53 | /** 54 | The status bar absolute rect 55 | */ 56 | var statusBarRect: NSRect { 57 | return window?.convertToScreen(frame) ?? NSZeroRect 58 | } 59 | 60 | // MARK: - Initializers 61 | 62 | /** 63 | Initializes a status bar item view with 2 images 64 | 65 | - parameter brightStatusImage: Image to use when the status bar is in bright mode 66 | - parameter darkStatusImage: Image to use when the status bar is in dark mode 67 | */ 68 | public convenience init(brightStatusImage: NSImage, darkStatusImage: NSImage) { 69 | self.init(statusBarImages: StatusBarImages(brightImage: brightStatusImage, darkImage: darkStatusImage)) 70 | } 71 | 72 | /** 73 | Initializes a status bar item view with a single image 74 | 75 | - parameter statusImage: Image to use when the status bar is in bright mode 76 | */ 77 | public convenience init(statusImage: NSImage) { 78 | self.init(statusBarImages: StatusBarImages(image: statusImage)) 79 | } 80 | 81 | /** 82 | Initializes a status bar item view with a status bar object 83 | 84 | - parameter statusBarImages: status bar images to use 85 | - parameter statusBarInterface: status bar interface wrapper to use 86 | */ 87 | init(statusBarImages: StatusBarImages, 88 | statusBarInterface: StatusBarInterface = StatusBarUtilities()) { 89 | 90 | self.statusBarImages = statusBarImages 91 | self.statusItem = StatusBarItemView.createStatusItem(NSVariableStatusItemLength) 92 | 93 | self.itemWidth = statusBarImages.imagesSize.width + 8 94 | 95 | let rect = StatusBarItemView.rect(withWidth: itemWidth, statusBarInterface: statusBarInterface) 96 | super.init(frame: rect) 97 | 98 | statusItem.view = self 99 | } 100 | 101 | /** 102 | Method not avaialble 103 | */ 104 | public required init?(coder: NSCoder) { 105 | fatalError("init(coder:) has not been implemented") 106 | } 107 | 108 | // MARK: - Events 109 | 110 | override open func draw(_ dirtyRect: NSRect) { 111 | statusItem.drawStatusBarBackground(in: dirtyRect, withHighlight: isHighlighted) 112 | statusBarImages.drawImage(inRect: bounds) 113 | } 114 | 115 | override open func mouseDown(with theEvent: NSEvent) { 116 | isHighlighted = !isHighlighted 117 | clickHandler?(isHighlighted) 118 | } 119 | 120 | // MARK: - Static helpers 121 | 122 | fileprivate static func createStatusItem(_ length: CGFloat) -> NSStatusItem { 123 | return NSStatusBar.system().statusItem(withLength: length) 124 | } 125 | 126 | fileprivate static func rect(withWidth width: CGFloat, statusBarInterface: StatusBarInterface) -> NSRect { 127 | return NSRect(x: 0.0, y: 0.0, width: width, 128 | height: statusBarInterface.statusBarHeight) 129 | } 130 | } 131 | -------------------------------------------------------------------------------- /Pod/Classes/StatusBarPopupPresenter.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Bla.swift 3 | // OAStatusItemKit 4 | // 5 | // Created by Omar Abdelhafith on 24/01/2016. 6 | // Copyright © 2016 Omar Abdelhafith. All rights reserved. 7 | // 8 | 9 | import Cocoa 10 | 11 | 12 | /** 13 | Class responsible for displaying the view in a popover 14 | */ 15 | class StatusBarPopupPresenter: StatusBarViewPresenter { 16 | 17 | /** 18 | The view to present 19 | */ 20 | let view: NSView 21 | 22 | /** 23 | The popover that presents the view 24 | */ 25 | fileprivate let popover = NSPopover() 26 | 27 | /** 28 | The status bar item view 29 | */ 30 | let statusItem: StatusBarItemView 31 | 32 | /** 33 | The event monitor to help the popover when clicking outside of it 34 | */ 35 | fileprivate var eventMonitor: EventMonitor? 36 | 37 | /** 38 | Initializes a status bar window controller 39 | 40 | - parameter xibName: The xib name to load 41 | - parameter statusItem: The status bar item view to add to mac status bar 42 | 43 | - returns: a status bar controller 44 | */ 45 | convenience required init(xibName: String, statusItem: StatusBarItemView) { 46 | let view: NSView = BundleLoading.load(xibName) 47 | self.init(view: view, statusItem: statusItem) 48 | } 49 | 50 | /** 51 | Initializes a status bar window controller 52 | 53 | - parameter view: The view to display when the status bar item is clicked 54 | - parameter statusItem: The status bar item view to add to mac status bar 55 | 56 | - returns: a status bar controller 57 | */ 58 | required init(view: NSView, statusItem: StatusBarItemView) { 59 | self.view = view 60 | self.statusItem = statusItem 61 | 62 | self.popover.contentViewController = StatusPanelViewController(view: view) 63 | setEvents() 64 | } 65 | 66 | internal var visible: Bool { 67 | 68 | get { 69 | return statusItem.isHighlighted 70 | } 71 | 72 | set { 73 | if newValue == visible { return } 74 | statusItem.isHighlighted = newValue 75 | 76 | if newValue { 77 | showPopup() 78 | } else { 79 | hidePopup() 80 | } 81 | } 82 | } 83 | 84 | // MARK: - Private 85 | 86 | fileprivate func setEvents() { 87 | 88 | self.statusItem.clickHandler = { isHighlighted in 89 | isHighlighted ? self.showPopup() : self.hidePopup() 90 | } 91 | 92 | eventMonitor = EventMonitor(mask: [.leftMouseDown, .rightMouseDown]) { [unowned self] event in 93 | if self.popover.isShown { 94 | self.statusItem.isHighlighted = false 95 | self.hidePopup() 96 | } 97 | } 98 | 99 | eventMonitor?.start() 100 | } 101 | 102 | fileprivate func showPopup () { 103 | popover.show(relativeTo: statusItem.bounds, of: statusItem, preferredEdge: NSRectEdge.minY) 104 | eventMonitor?.start() 105 | } 106 | 107 | fileprivate func hidePopup () { 108 | self.popover.performClose(nil) 109 | eventMonitor?.stop() 110 | } 111 | 112 | } 113 | 114 | 115 | /** 116 | View controller to be placed in the popover 117 | */ 118 | class StatusPanelViewController: NSViewController { 119 | init?(view: NSView) { 120 | super.init(nibName: nil, bundle: nil) 121 | self.view = view 122 | } 123 | 124 | required init?(coder: NSCoder) { 125 | fatalError("init(coder:) has not been implemented") 126 | } 127 | } 128 | -------------------------------------------------------------------------------- /Pod/Classes/StatusBarViewPresenter.swift: -------------------------------------------------------------------------------- 1 | // 2 | // StatusBarViewPresenter.swift 3 | // OAStatusItemKit 4 | // 5 | // Created by Omar Abdelhafith on 24/01/2016. 6 | // Copyright © 2016 Omar Abdelhafith. All rights reserved. 7 | // 8 | 9 | import Cocoa 10 | 11 | public protocol StatusBarViewPresenter { 12 | 13 | /** 14 | Initializes a status bar window controller 15 | 16 | - parameter xibName: The xib name to load 17 | - parameter statusItem: The status bar item view to add to mac status bar 18 | 19 | - returns: a status bar controller 20 | */ 21 | init(xibName: String, statusItem: StatusBarItemView) 22 | 23 | /** 24 | Initializes a status bar window controller 25 | 26 | - parameter view: The view to display when the status bar item is clicked 27 | - parameter statusItem: The status bar item view to add to mac status bar 28 | 29 | - returns: a status bar controller 30 | */ 31 | init(view: NSView, statusItem: StatusBarItemView) 32 | 33 | /// Sets and gets the visibility of the tool bar window 34 | var visible: Bool { get set } 35 | 36 | } 37 | 38 | 39 | /** 40 | StatusBarViewControllerType a type that can hold a status view presenter 41 | */ 42 | public protocol StatusBarViewControllerType: AnyObject { 43 | 44 | /// The status bar item used 45 | var statusViewPresenter: StatusBarViewPresenter! { get set } 46 | 47 | } 48 | -------------------------------------------------------------------------------- /Pod/Classes/StatusBarWindowController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // StatusBarWindowController.swift 3 | // MarkdownSharer 4 | // 5 | // Created by Omar Abdelhafith on 07/12/2015. 6 | // Copyright © 2015 Omar Abdelhafith. All rights reserved. 7 | // 8 | 9 | import Cocoa 10 | 11 | 12 | /** 13 | Class responsible for displaying and placing the main status bar panel view 14 | */ 15 | class StatusBarWindowController: NSWindowController, StatusBarViewPresenter { 16 | 17 | // MARK: - Properties 18 | 19 | /** 20 | Sets/Gets the window size for the displayed panel 21 | */ 22 | var windowSize: NSSize? 23 | 24 | /** 25 | Sets/Gets the window placement, defaults to status bar item center 26 | */ 27 | var windowPlacement = StatusWindowPlacement.statusBarItemCenter 28 | 29 | /** 30 | Sets/Gets the visibility of the panel 31 | */ 32 | var visible: Bool = false { 33 | didSet { 34 | if visible { 35 | openWindow() 36 | } else { 37 | closeWindow() 38 | } 39 | } 40 | } 41 | 42 | /** 43 | The status bar item view 44 | */ 45 | fileprivate let statusBarItemView: StatusBarItemView 46 | 47 | // MARK: - Initializers 48 | 49 | /** 50 | Initializes a status bar window controller 51 | 52 | - parameter xibName: The xib name to load 53 | - parameter statusItem: The status bar item view to add to mac status bar 54 | 55 | - returns: a status bar controller 56 | */ 57 | convenience required init(xibName: String, statusItem: StatusBarItemView) { 58 | let view: NSView = BundleLoading.load(xibName) 59 | self.init(view: view, statusItem: statusItem) 60 | } 61 | 62 | /** 63 | Initializes a status bar window controller 64 | 65 | - parameter view: The view to display when the status bar item is clicked 66 | - parameter statusItem: The status bar item view to add to mac status bar 67 | 68 | - returns: a status bar controller 69 | */ 70 | required init(view: NSView, statusItem: StatusBarItemView) { 71 | statusBarItemView = statusItem 72 | 73 | let window = type(of: self).createWindow() 74 | 75 | window.contentView?.addSubview(view) 76 | view.translatesAutoresizingMaskIntoConstraints = false 77 | 78 | type(of: self).pin(view, inWindow: window); 79 | 80 | super.init(window: window) 81 | window.delegate = self 82 | 83 | statusItem.clickHandler = { isHighlighted in 84 | self.visible = isHighlighted 85 | } 86 | 87 | } 88 | 89 | /** 90 | Method not available 91 | */ 92 | required init?(coder: NSCoder) { 93 | fatalError("init(coder:) has not been implemented") 94 | } 95 | 96 | /** 97 | Opens the window and displays it inplace 98 | */ 99 | fileprivate func openWindow() { 100 | 101 | guard 102 | let screen = NSScreen.screens()?.first , 103 | let window = window 104 | else { return } 105 | 106 | NSApp.activate(ignoringOtherApps: false) 107 | window.makeKeyAndOrderFront(nil) 108 | 109 | let frame = 110 | windowPlacement.rect(forWindow: window, 111 | withSize: actualWindowSize(), 112 | statusBarItemRect: statusBarItemView.statusBarRect, 113 | inScreen: screen) 114 | 115 | window.alphaValue = 0 116 | window.setFrame(frame, display: true) 117 | 118 | performWithAnimation { 119 | window.animator().alphaValue = 1 120 | window.setFrame(frame, display: true) 121 | } 122 | } 123 | 124 | /** 125 | Hides and closes the window 126 | */ 127 | fileprivate func closeWindow() { 128 | statusBarItemView.isHighlighted = false 129 | 130 | guard let window = self.window else { return } 131 | 132 | performWithAnimation { window.animator().alphaValue = 0 } 133 | 134 | performAfter(0.2) { window.orderOut(nil) } 135 | } 136 | 137 | // MARK: - Events 138 | 139 | fileprivate func actualWindowSize() -> NSSize { 140 | guard let size = windowSize ?? window?.frame.size else { 141 | fatalError("The windowSize is not set and cannot infer the size from the window passed (have you set any constraint)") 142 | } 143 | 144 | return size 145 | } 146 | 147 | // MARK: - Private 148 | 149 | fileprivate func performAfter(_ delay: Double, closure: @escaping () -> ()) { 150 | DispatchQueue.main.asyncAfter(deadline: .now() + delay) { 151 | closure() 152 | } 153 | } 154 | 155 | fileprivate func performWithAnimation(_ closure: () -> ()) { 156 | NSAnimationContext.beginGrouping() 157 | NSAnimationContext.current().duration = 0.1 158 | closure() 159 | NSAnimationContext.endGrouping() 160 | } 161 | 162 | fileprivate class func createWindow() -> NSWindow { 163 | let window = StatusPanel.create() 164 | window.acceptsMouseMovedEvents = true 165 | window.level = Int(CGWindowLevelForKey(CGWindowLevelKey.popUpMenuWindow)) 166 | window.orderOut(nil) 167 | 168 | return window 169 | } 170 | 171 | fileprivate class func pin(_ view: NSView, inWindow window: NSWindow?) { 172 | 173 | window?.contentView?.addConstraints( 174 | NSLayoutConstraint.constraints(withVisualFormat: "V:|-0-[v]-0-|", 175 | options: NSLayoutFormatOptions(rawValue: 0), 176 | metrics: nil, 177 | views: ["v": view])) 178 | 179 | window?.contentView?.addConstraints( 180 | NSLayoutConstraint.constraints(withVisualFormat: "H:|-0-[v]-0-|", 181 | options: NSLayoutFormatOptions(rawValue: 0), 182 | metrics: nil, 183 | views: ["v": view])) 184 | } 185 | 186 | } 187 | 188 | extension StatusBarWindowController: NSWindowDelegate { 189 | 190 | func windowDidResignKey(_ notification: Notification) { 191 | self.closeWindow() 192 | } 193 | 194 | func windowWillClose(_ notification: Notification) { 195 | self.closeWindow() 196 | } 197 | 198 | func windowDidResignMain(_ notification: Notification) { 199 | self.closeWindow() 200 | } 201 | } 202 | -------------------------------------------------------------------------------- /Pod/Classes/StatusBarWindowStyle.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ShowIt.swift 3 | // OAStatusItemKit 4 | // 5 | // Created by Omar Abdelhafith on 24/01/2016. 6 | // Copyright © 2016 Omar Abdelhafith. All rights reserved. 7 | // 8 | 9 | import Cocoa 10 | 11 | /** 12 | Enum that controls the style of presenting the view 13 | */ 14 | public enum StatusBarWindowStyle { 15 | /** 16 | Present the view in a a popover 17 | */ 18 | case popup 19 | 20 | /** 21 | Present the view in a custom window 22 | 23 | - parameter StatusWindowPlacement: Window placement type 24 | */ 25 | case window(StatusWindowPlacement) 26 | 27 | /** 28 | Present the view in a custom window 29 | 30 | - parameter StatusWindowPlacement: Window placement type 31 | - parameter NSSize: The size to display the window 32 | */ 33 | case windowWithSize(StatusWindowPlacement, NSSize) 34 | } 35 | 36 | 37 | public extension StatusBarWindowStyle { 38 | 39 | /** 40 | Initializes a status bar window controller 41 | 42 | - parameter xibName: The xib name to load 43 | - parameter statusItem: The status bar item view to add to mac status bar 44 | 45 | - returns: a status bar controller 46 | */ 47 | @discardableResult public func createPresenter(withXibName xibName: String, statusItem: StatusBarItemView) -> StatusBarViewPresenter { 48 | return self.createPresenter(withView: BundleLoading.load(xibName), statusItem: statusItem) 49 | } 50 | 51 | /** 52 | Initializes a status bar window controller 53 | 54 | - parameter viewController: The view controller to display when the status bar item is clicked 55 | 56 | If the view controller adhere to StatusBarViewControllerType then the status view presenter will be set 57 | - parameter statusItem: The status bar item view to add to mac status bar 58 | 59 | - returns: a status bar controller 60 | 61 | 62 | */ 63 | @discardableResult public func createPresenter(withViewController viewController: NSViewController, statusItem: StatusBarItemView) -> StatusBarViewPresenter { 64 | let presenter = createPresenter(withView: viewController.view, statusItem: statusItem) 65 | 66 | if let viewController = viewController as? StatusBarViewControllerType { 67 | viewController.statusViewPresenter = presenter 68 | } 69 | 70 | return presenter 71 | } 72 | 73 | /** 74 | Initializes a status bar window controller 75 | 76 | - parameter view: The view to display when the status bar item is clicked 77 | - parameter statusItem: The status bar item view to add to mac status bar 78 | 79 | - returns: a status bar controller 80 | */ 81 | @discardableResult public func createPresenter(withView view: NSView, statusItem: StatusBarItemView) -> StatusBarViewPresenter { 82 | switch self { 83 | 84 | case .popup: 85 | return StatusBarPopupPresenter(view: view, statusItem: statusItem) 86 | 87 | case let .window(windowPlacement): 88 | let windowController = StatusBarWindowController(view: view, statusItem: statusItem) 89 | windowController.windowPlacement = windowPlacement 90 | return windowController 91 | 92 | case let .windowWithSize(windowPlacement, size): 93 | let windowController = StatusBarWindowController(view: view, statusItem: statusItem) 94 | windowController.windowPlacement = windowPlacement 95 | windowController.windowSize = size 96 | return windowController 97 | } 98 | } 99 | 100 | } 101 | -------------------------------------------------------------------------------- /Pod/Classes/StatusPanel.swift: -------------------------------------------------------------------------------- 1 | // 2 | // StatusPanel.swift 3 | // OAStatusItemKit 4 | // 5 | // Created by Omar Abdelhafith on 21/01/2016. 6 | // Copyright © 2016 Omar Abdelhafith. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | /** 12 | the main panel class 13 | */ 14 | class StatusPanel: NSPanel { 15 | 16 | /** 17 | Create a new status panel 18 | */ 19 | class func create() -> StatusPanel { 20 | let panel = StatusPanel(contentRect: NSRect(x: 0, y: 0, width: 200, height: 200), styleMask: NSNonactivatingPanelMask, 21 | backing: .buffered, defer: true) 22 | return panel 23 | } 24 | 25 | override var canBecomeKey: Bool { 26 | return true 27 | } 28 | 29 | } 30 | -------------------------------------------------------------------------------- /Pod/Classes/StatusWindowPlacement.swift: -------------------------------------------------------------------------------- 1 | // 2 | // StatusWindowPlacement.swift 3 | // OAStatusItemKit 4 | // 5 | // Created by Omar Abdelhafith on 20/01/2016. 6 | // Copyright © 2016 Omar Abdelhafith. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | 12 | /** 13 | Status window placement type 14 | */ 15 | public enum StatusWindowPlacement { 16 | 17 | /** 18 | * Place the window in the middle left of the screen 19 | */ 20 | case screenMiddleLeft 21 | 22 | /** 23 | * Place the window in the middle center of the screen 24 | */ 25 | case screenMiddleCenter 26 | 27 | /** 28 | * Place the window in the middle right of the screen 29 | */ 30 | case screenMiddleRight 31 | 32 | 33 | /** 34 | * Place the window in the top left of the screen 35 | */ 36 | case screenTopLeft 37 | 38 | /** 39 | * Place the window in the top right of the screen 40 | */ 41 | case screenTopRight 42 | 43 | /** 44 | * Place the window in the top center of the screen 45 | */ 46 | case screenTopCenter 47 | 48 | /** 49 | * Place the window in the bottom left of the screen 50 | */ 51 | case screenBottomLeft 52 | 53 | /** 54 | * Place the window in the bottom right of the screen 55 | */ 56 | case screenBottomRight 57 | 58 | /** 59 | * Place the window in the bottom center of the screen 60 | */ 61 | case screenBottomCenter 62 | 63 | 64 | /** 65 | * Place the window in the bellow the status bar item, horizontally centered to the item 66 | */ 67 | case statusBarItemCenter 68 | 69 | /** 70 | * Place the window in the bellow the status bar item, left alligned to the item 71 | */ 72 | case statusBarItemLeft 73 | 74 | /** 75 | * Place the window in the bellow the status bar item, right alligned to the item 76 | */ 77 | case statusBarItemRight 78 | 79 | } 80 | -------------------------------------------------------------------------------- /Pod/Classes/WindowPlacer.swift: -------------------------------------------------------------------------------- 1 | // 2 | // WindowPlacer.swift 3 | // OAStatusItemKit 4 | // 5 | // Created by Omar Abdelhafith on 20/01/2016. 6 | // Copyright © 2016 Omar Abdelhafith. All rights reserved. 7 | // 8 | 9 | import Cocoa 10 | 11 | 12 | /** 13 | * Window placer protocol 14 | */ 15 | protocol WindowPlacer { 16 | /** 17 | Place a window 18 | 19 | - parameter window: window to place 20 | - parameter windowSize: window size 21 | - parameter statusBarItemRect: status bar item rect 22 | - parameter screen: screen 23 | */ 24 | func rect(forWindow window: NSWindow, withSize windowSize: CGSize?, 25 | statusBarItemRect: NSRect, inScreen screen: NSScreen) -> NSRect 26 | } 27 | 28 | 29 | let minimumXMargin: CGFloat = 8.0 30 | let defaultXMargin: CGFloat = 12.0 31 | 32 | extension StatusWindowPlacement: WindowPlacer { 33 | 34 | func rect(forWindow window: NSWindow, withSize windowSize: CGSize?, 35 | statusBarItemRect: NSRect, inScreen screen: NSScreen) -> NSRect { 36 | 37 | var rect = NSZeroRect 38 | 39 | switch self { 40 | 41 | case .statusBarItemCenter: 42 | fallthrough 43 | case .statusBarItemLeft: 44 | fallthrough 45 | case .statusBarItemRight: 46 | rect = StatusBarItemCenterPlacer() 47 | .rect(forWindow: window, 48 | withSize: windowSize, 49 | statusBarItemRect: statusBarItemRect, 50 | placement: self) 51 | break 52 | 53 | case .screenMiddleLeft: 54 | fallthrough 55 | case .screenMiddleCenter: 56 | fallthrough 57 | case .screenMiddleRight: 58 | fallthrough 59 | case .screenTopLeft: 60 | fallthrough 61 | case .screenTopRight: 62 | fallthrough 63 | case .screenTopCenter: 64 | fallthrough 65 | case .screenBottomLeft: 66 | fallthrough 67 | case .screenBottomRight: 68 | fallthrough 69 | case .screenBottomCenter: 70 | rect = ScreenWindowPlacer() 71 | .rect(forWindow: window, 72 | withSize: windowSize, 73 | statusBarItemRect: statusBarItemRect, 74 | inScreen: screen, 75 | placement: self) 76 | break 77 | } 78 | 79 | return adjustedRectForBorders(rect, screen: screen) 80 | } 81 | 82 | func adjustedRectForBorders(_ windowRect: NSRect, screen: NSScreen) -> NSRect { 83 | let screenRect = screen.frame 84 | 85 | if (NSMaxX(windowRect) > (NSMaxX(screenRect) - minimumXMargin)) { 86 | var fixedRect = windowRect 87 | fixedRect.origin.x -= NSMaxX(windowRect) - (NSMaxX(screenRect) - defaultXMargin) 88 | return fixedRect 89 | } else { 90 | return windowRect 91 | } 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # OAStatusItemKit 2 | 3 |

4 | 5 |
6 |

7 | 8 | [![CI Status](http://img.shields.io/travis/oarrabi/OAStatusItemKit.svg?style=flat)](https://travis-ci.org/oarrabi/OAStatusItemKit) 9 | [![codecov.io](https://codecov.io/github/oarrabi/OAStatusItemKit/coverage.svg?branch=master)](https://codecov.io/github/oarrabi/OAStatusItemKit?branch=master) 10 | [![Version](https://img.shields.io/cocoapods/v/OAStatusItemKit.svg?style=flat)](http://cocoapods.org/pods/OAStatusItemKit) 11 | [![License](https://img.shields.io/cocoapods/l/OAStatusItemKit.svg?style=flat)](http://cocoapods.org/pods/OAStatusItemKit) 12 | [![Platform](https://img.shields.io/cocoapods/p/OAStatusItemKit.svg?style=flat)](http://cocoapods.org/pods/OAStatusItemKit) 13 | 14 |
15 | OAStatusItemKit allows you to easily create mac status bar apps with a swifty flavour. 16 | 17 | ## Usage 18 | 19 | To run the example project, clone the repo, and run `pod install` from the Example directory first. 20 | 21 | 22 | ## Installation 23 | 24 | OAStatusItemKit is available through [CocoaPods](http://cocoapods.org). To install 25 | it, simply add the following line to your Podfile: 26 | 27 | ```ruby 28 | pod "OAStatusItemKit" 29 | ``` 30 | 31 | ## Usage 32 | First, `import OAStatusItemKit` 33 | 34 | Then create a `StatusBarItemView` 35 | 36 | ```swift 37 | let statusBarItem = 38 | StatusBarItemView(brightStatusImage: NSImage(named: "Icon-bright")!, 39 | darkStatusImage: NSImage(named: "Icon-dark")!) 40 | ``` 41 | 42 | Pass the created status bar item to a value of `StatusBarWindowStyle` enum. 43 | 44 | ``` 45 | StatusBarWindowStyle.Popup 46 | .createPresenter(withXibName: "Panel", statusItem: statusBarItem) 47 | ``` 48 | 49 | Finally, you need to make your app a mac agent app. to do so open Info.plist. Add a new key "Application is agent (UIElement)" and set it's value to YES. 50 | 51 | ![image](http://i.imgur.com/DwY0Ffj.png) 52 | 53 | Thats it, enjoy. 54 | 55 | ## Documentation 56 | Bellow is a quick and dirty introduction, check the full documentation [here](http://oarrabi.github.io/OAStatusItemKit/) 57 | 58 | #### StatusBarItemView 59 | [StatusBarItemView](http://oarrabi.github.io/OAStatusItemKit/Classes/StatusBarItemView.html) is the class responsible for representing a status bar view. 60 | 61 | Example usage: 62 | 63 | ```swift 64 | let statusItem = StatusBarItemView(brightStatusImage: BrightImage, 65 | darkStatusImage: DarkImage) 66 | 67 | let statusItem = StatusBarItemView(statusImage: AnyImage) 68 | ``` 69 | 70 | To change the width of the view, use `itemWidth` 71 | 72 | ```swift 73 | statusItem.itemWidth = 200 74 | ``` 75 | 76 | #### StatusBarWindowStyle 77 | [StatusBarWindowStyle](http://oarrabi.github.io/OAStatusItemKit/Classes/StatusBarWindowStyle.html) is a class responsible for displaying the status bar view. 78 | 79 | The status ber view can be displayed in a popup, or in a window. 80 | 81 | To display in a popup, use the following: 82 | 83 | ```swift 84 | StatusBarWindowStyle.Popup.createPresenter(withXibName:statusItem:) 85 | ``` 86 | 87 | If however you want to display it in a window, you have two choices: 88 | 89 | ```swift 90 | StatusBarWindowStyle.Window(StatusWindowPlacement) 91 | StatusBarWindowStyle.WindowWithSize(StatusWindowPlacement, NSSize) 92 | ``` 93 | 94 | For example, you can do the following: 95 | 96 | ```swift 97 | StatusBarWindowStyle.Window(.StatusBarItemCenter) 98 | .createPresenter(withXibName: "NAME", statusItem: statusBarItem) 99 | 100 | //or 101 | 102 | StatusBarWindowStyle.WindowWithSize(.StatusBarItemCenter, NSSize(width: 400, height: 400)) 103 | .createPresenter(withXibName: "NAME", statusItem: statusBarItem) 104 | ``` 105 | 106 | 107 | `StatusWindowPlacement` is used to determine the placement of the window in the screen, the values are described [here](http://oarrabi.github.io/OAStatusItemKit/Enums/StatusWindowPlacement.html) 108 | 109 | #### StatusBarViewControllerType 110 | If your view controller implements the `StatusBarViewControllerType` protocol, then `StatusBarViewPresenter` will set its `statusViewPresenter` field. 111 | 112 | This is useful if you want to show/hide the status bar window from inside your view controller. 113 | 114 | ## Tests 115 | To run tests execute `make test` 116 | 117 | ## Author 118 | 119 | Omar Abdelhafith, o.arrabi@me.com 120 | 121 | ## License 122 | 123 | OAStatusItemKit is available under the MIT license. See the LICENSE file for more info. 124 | --------------------------------------------------------------------------------