├── .gitignore ├── LICENSE ├── README.md ├── WeatherBar.xcodeproj ├── project.pbxproj └── project.xcworkspace │ └── contents.xcworkspacedata ├── WeatherBar ├── AppDelegate.swift ├── Assets.xcassets │ ├── 01d.imageset │ │ ├── 01d.png │ │ └── Contents.json │ ├── 01n.imageset │ │ ├── 01n.png │ │ └── Contents.json │ ├── 02d.imageset │ │ ├── 02d.png │ │ └── Contents.json │ ├── 02n.imageset │ │ ├── 02n.png │ │ └── Contents.json │ ├── 03d.imageset │ │ ├── 03d.png │ │ └── Contents.json │ ├── 03n.imageset │ │ ├── 03n.png │ │ └── Contents.json │ ├── 04d.imageset │ │ ├── 04d.png │ │ └── Contents.json │ ├── 04n.imageset │ │ ├── 04n.png │ │ └── Contents.json │ ├── 09d.imageset │ │ ├── 09d.png │ │ └── Contents.json │ ├── 09n.imageset │ │ ├── 09n.png │ │ └── Contents.json │ ├── 10d.imageset │ │ ├── 10d.png │ │ └── Contents.json │ ├── 10n.imageset │ │ ├── 10n.png │ │ └── Contents.json │ ├── 11d.imageset │ │ ├── 11d.png │ │ └── Contents.json │ ├── 11n.imageset │ │ ├── 11n.png │ │ └── Contents.json │ ├── 13d.imageset │ │ ├── 13d.png │ │ └── Contents.json │ ├── 13n.imageset │ │ ├── 13n.png │ │ └── Contents.json │ ├── 50d.imageset │ │ ├── 50d.png │ │ └── Contents.json │ ├── 50n.imageset │ │ ├── 50n.png │ │ └── Contents.json │ ├── AppIcon.appiconset │ │ └── Contents.json │ ├── Contents.json │ └── statusIcon.imageset │ │ ├── Contents.json │ │ ├── statusIcon.png │ │ └── statusIcon@2x.png ├── Base.lproj │ └── MainMenu.xib ├── Info.plist ├── PreferencesWindow.swift ├── PreferencesWindow.xib ├── StatusMenuController.swift ├── WeatherAPI.swift └── WeatherView.swift ├── WeatherBarTests ├── Info.plist └── WeatherBarTests.swift ├── WeatherBarUITests ├── Info.plist └── WeatherBarUITests.swift └── weather-icons.zip /.gitignore: -------------------------------------------------------------------------------- 1 | # Mac 2 | .DS_Store 3 | 4 | # Xcode 5 | # 6 | build/ 7 | *.pbxuser 8 | !default.pbxuser 9 | *.mode1v3 10 | !default.mode1v3 11 | *.mode2v3 12 | !default.mode2v3 13 | *.perspectivev3 14 | !default.perspectivev3 15 | xcuserdata 16 | *.xccheckout 17 | *.moved-aside 18 | DerivedData 19 | *.hmap 20 | *.ipa 21 | *.xcuserstate 22 | 23 | # CocoaPods 24 | # 25 | # We recommend against adding the Pods directory to your .gitignore. However 26 | # you should judge for yourself, the pros and cons are mentioned at: 27 | # http://guides.cocoapods.org/using/using-cocoapods.html#should-i-ignore-the-pods-directory-in-source-control 28 | # 29 | # Pods/ 30 | 31 | # Carthage 32 | # 33 | # Add this line if you want to avoid checking in source code from Carthage dependencies. 34 | # Carthage/Checkouts 35 | 36 | Carthage/Build 37 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Brad Greenlee 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | WeatherBar 2 | ========== 3 | 4 | Demo weather app for Etsy School class on writing a Mac app in Swift 5 | 6 | See the tutorial at http://footle.org/WeatherBar/ 7 | 8 | -------------------------------------------------------------------------------- /WeatherBar.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | A21862A21BCDEA2E00770E87 /* PreferencesWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = A21862A01BCDEA2E00770E87 /* PreferencesWindow.swift */; settings = {ASSET_TAGS = (); }; }; 11 | A21862A31BCDEA2E00770E87 /* PreferencesWindow.xib in Resources */ = {isa = PBXBuildFile; fileRef = A21862A11BCDEA2E00770E87 /* PreferencesWindow.xib */; settings = {ASSET_TAGS = (); }; }; 12 | A2B4247D1BCDE3D300887CB2 /* WeatherView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A2B4247C1BCDE3D300887CB2 /* WeatherView.swift */; settings = {ASSET_TAGS = (); }; }; 13 | A2D582281BCAAF37006A464B /* StatusMenuController.swift in Sources */ = {isa = PBXBuildFile; fileRef = A2D582271BCAAF37006A464B /* StatusMenuController.swift */; settings = {ASSET_TAGS = (); }; }; 14 | A2D5822A1BCB6068006A464B /* WeatherAPI.swift in Sources */ = {isa = PBXBuildFile; fileRef = A2D582291BCB6068006A464B /* WeatherAPI.swift */; settings = {ASSET_TAGS = (); }; }; 15 | A2DEB14E1BC9980E004AAEB3 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = A2DEB14D1BC9980E004AAEB3 /* AppDelegate.swift */; }; 16 | A2DEB1501BC9980E004AAEB3 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = A2DEB14F1BC9980E004AAEB3 /* Assets.xcassets */; }; 17 | A2DEB1531BC9980E004AAEB3 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = A2DEB1511BC9980E004AAEB3 /* MainMenu.xib */; }; 18 | A2DEB15E1BC9980E004AAEB3 /* WeatherBarTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = A2DEB15D1BC9980E004AAEB3 /* WeatherBarTests.swift */; }; 19 | A2DEB1691BC9980E004AAEB3 /* WeatherBarUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = A2DEB1681BC9980E004AAEB3 /* WeatherBarUITests.swift */; }; 20 | /* End PBXBuildFile section */ 21 | 22 | /* Begin PBXContainerItemProxy section */ 23 | A2DEB15A1BC9980E004AAEB3 /* PBXContainerItemProxy */ = { 24 | isa = PBXContainerItemProxy; 25 | containerPortal = A2DEB1421BC9980E004AAEB3 /* Project object */; 26 | proxyType = 1; 27 | remoteGlobalIDString = A2DEB1491BC9980E004AAEB3; 28 | remoteInfo = WeatherBar; 29 | }; 30 | A2DEB1651BC9980E004AAEB3 /* PBXContainerItemProxy */ = { 31 | isa = PBXContainerItemProxy; 32 | containerPortal = A2DEB1421BC9980E004AAEB3 /* Project object */; 33 | proxyType = 1; 34 | remoteGlobalIDString = A2DEB1491BC9980E004AAEB3; 35 | remoteInfo = WeatherBar; 36 | }; 37 | /* End PBXContainerItemProxy section */ 38 | 39 | /* Begin PBXFileReference section */ 40 | A21862A01BCDEA2E00770E87 /* PreferencesWindow.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PreferencesWindow.swift; sourceTree = ""; }; 41 | A21862A11BCDEA2E00770E87 /* PreferencesWindow.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = PreferencesWindow.xib; sourceTree = ""; }; 42 | A2B4247C1BCDE3D300887CB2 /* WeatherView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = WeatherView.swift; sourceTree = ""; }; 43 | A2D582271BCAAF37006A464B /* StatusMenuController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StatusMenuController.swift; sourceTree = ""; }; 44 | A2D582291BCB6068006A464B /* WeatherAPI.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = WeatherAPI.swift; sourceTree = ""; }; 45 | A2DEB14A1BC9980E004AAEB3 /* WeatherBar.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = WeatherBar.app; sourceTree = BUILT_PRODUCTS_DIR; }; 46 | A2DEB14D1BC9980E004AAEB3 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 47 | A2DEB14F1BC9980E004AAEB3 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 48 | A2DEB1521BC9980E004AAEB3 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/MainMenu.xib; sourceTree = ""; }; 49 | A2DEB1541BC9980E004AAEB3 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 50 | A2DEB1591BC9980E004AAEB3 /* WeatherBarTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = WeatherBarTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 51 | A2DEB15D1BC9980E004AAEB3 /* WeatherBarTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WeatherBarTests.swift; sourceTree = ""; }; 52 | A2DEB15F1BC9980E004AAEB3 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 53 | A2DEB1641BC9980E004AAEB3 /* WeatherBarUITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = WeatherBarUITests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 54 | A2DEB1681BC9980E004AAEB3 /* WeatherBarUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WeatherBarUITests.swift; sourceTree = ""; }; 55 | A2DEB16A1BC9980E004AAEB3 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 56 | /* End PBXFileReference section */ 57 | 58 | /* Begin PBXFrameworksBuildPhase section */ 59 | A2DEB1471BC9980E004AAEB3 /* Frameworks */ = { 60 | isa = PBXFrameworksBuildPhase; 61 | buildActionMask = 2147483647; 62 | files = ( 63 | ); 64 | runOnlyForDeploymentPostprocessing = 0; 65 | }; 66 | A2DEB1561BC9980E004AAEB3 /* Frameworks */ = { 67 | isa = PBXFrameworksBuildPhase; 68 | buildActionMask = 2147483647; 69 | files = ( 70 | ); 71 | runOnlyForDeploymentPostprocessing = 0; 72 | }; 73 | A2DEB1611BC9980E004AAEB3 /* Frameworks */ = { 74 | isa = PBXFrameworksBuildPhase; 75 | buildActionMask = 2147483647; 76 | files = ( 77 | ); 78 | runOnlyForDeploymentPostprocessing = 0; 79 | }; 80 | /* End PBXFrameworksBuildPhase section */ 81 | 82 | /* Begin PBXGroup section */ 83 | A2DEB1411BC9980E004AAEB3 = { 84 | isa = PBXGroup; 85 | children = ( 86 | A2DEB14C1BC9980E004AAEB3 /* WeatherBar */, 87 | A2DEB15C1BC9980E004AAEB3 /* WeatherBarTests */, 88 | A2DEB1671BC9980E004AAEB3 /* WeatherBarUITests */, 89 | A2DEB14B1BC9980E004AAEB3 /* Products */, 90 | ); 91 | sourceTree = ""; 92 | }; 93 | A2DEB14B1BC9980E004AAEB3 /* Products */ = { 94 | isa = PBXGroup; 95 | children = ( 96 | A2DEB14A1BC9980E004AAEB3 /* WeatherBar.app */, 97 | A2DEB1591BC9980E004AAEB3 /* WeatherBarTests.xctest */, 98 | A2DEB1641BC9980E004AAEB3 /* WeatherBarUITests.xctest */, 99 | ); 100 | name = Products; 101 | sourceTree = ""; 102 | }; 103 | A2DEB14C1BC9980E004AAEB3 /* WeatherBar */ = { 104 | isa = PBXGroup; 105 | children = ( 106 | A2DEB14D1BC9980E004AAEB3 /* AppDelegate.swift */, 107 | A2D582271BCAAF37006A464B /* StatusMenuController.swift */, 108 | A2D582291BCB6068006A464B /* WeatherAPI.swift */, 109 | A2B4247C1BCDE3D300887CB2 /* WeatherView.swift */, 110 | A21862A01BCDEA2E00770E87 /* PreferencesWindow.swift */, 111 | A2DEB1511BC9980E004AAEB3 /* MainMenu.xib */, 112 | A21862A11BCDEA2E00770E87 /* PreferencesWindow.xib */, 113 | A2DEB14F1BC9980E004AAEB3 /* Assets.xcassets */, 114 | A2DEB1541BC9980E004AAEB3 /* Info.plist */, 115 | ); 116 | path = WeatherBar; 117 | sourceTree = ""; 118 | }; 119 | A2DEB15C1BC9980E004AAEB3 /* WeatherBarTests */ = { 120 | isa = PBXGroup; 121 | children = ( 122 | A2DEB15D1BC9980E004AAEB3 /* WeatherBarTests.swift */, 123 | A2DEB15F1BC9980E004AAEB3 /* Info.plist */, 124 | ); 125 | path = WeatherBarTests; 126 | sourceTree = ""; 127 | }; 128 | A2DEB1671BC9980E004AAEB3 /* WeatherBarUITests */ = { 129 | isa = PBXGroup; 130 | children = ( 131 | A2DEB1681BC9980E004AAEB3 /* WeatherBarUITests.swift */, 132 | A2DEB16A1BC9980E004AAEB3 /* Info.plist */, 133 | ); 134 | path = WeatherBarUITests; 135 | sourceTree = ""; 136 | }; 137 | /* End PBXGroup section */ 138 | 139 | /* Begin PBXNativeTarget section */ 140 | A2DEB1491BC9980E004AAEB3 /* WeatherBar */ = { 141 | isa = PBXNativeTarget; 142 | buildConfigurationList = A2DEB16D1BC9980E004AAEB3 /* Build configuration list for PBXNativeTarget "WeatherBar" */; 143 | buildPhases = ( 144 | A2DEB1461BC9980E004AAEB3 /* Sources */, 145 | A2DEB1471BC9980E004AAEB3 /* Frameworks */, 146 | A2DEB1481BC9980E004AAEB3 /* Resources */, 147 | ); 148 | buildRules = ( 149 | ); 150 | dependencies = ( 151 | ); 152 | name = WeatherBar; 153 | productName = WeatherBar; 154 | productReference = A2DEB14A1BC9980E004AAEB3 /* WeatherBar.app */; 155 | productType = "com.apple.product-type.application"; 156 | }; 157 | A2DEB1581BC9980E004AAEB3 /* WeatherBarTests */ = { 158 | isa = PBXNativeTarget; 159 | buildConfigurationList = A2DEB1701BC9980E004AAEB3 /* Build configuration list for PBXNativeTarget "WeatherBarTests" */; 160 | buildPhases = ( 161 | A2DEB1551BC9980E004AAEB3 /* Sources */, 162 | A2DEB1561BC9980E004AAEB3 /* Frameworks */, 163 | A2DEB1571BC9980E004AAEB3 /* Resources */, 164 | ); 165 | buildRules = ( 166 | ); 167 | dependencies = ( 168 | A2DEB15B1BC9980E004AAEB3 /* PBXTargetDependency */, 169 | ); 170 | name = WeatherBarTests; 171 | productName = WeatherBarTests; 172 | productReference = A2DEB1591BC9980E004AAEB3 /* WeatherBarTests.xctest */; 173 | productType = "com.apple.product-type.bundle.unit-test"; 174 | }; 175 | A2DEB1631BC9980E004AAEB3 /* WeatherBarUITests */ = { 176 | isa = PBXNativeTarget; 177 | buildConfigurationList = A2DEB1731BC9980E004AAEB3 /* Build configuration list for PBXNativeTarget "WeatherBarUITests" */; 178 | buildPhases = ( 179 | A2DEB1601BC9980E004AAEB3 /* Sources */, 180 | A2DEB1611BC9980E004AAEB3 /* Frameworks */, 181 | A2DEB1621BC9980E004AAEB3 /* Resources */, 182 | ); 183 | buildRules = ( 184 | ); 185 | dependencies = ( 186 | A2DEB1661BC9980E004AAEB3 /* PBXTargetDependency */, 187 | ); 188 | name = WeatherBarUITests; 189 | productName = WeatherBarUITests; 190 | productReference = A2DEB1641BC9980E004AAEB3 /* WeatherBarUITests.xctest */; 191 | productType = "com.apple.product-type.bundle.ui-testing"; 192 | }; 193 | /* End PBXNativeTarget section */ 194 | 195 | /* Begin PBXProject section */ 196 | A2DEB1421BC9980E004AAEB3 /* Project object */ = { 197 | isa = PBXProject; 198 | attributes = { 199 | LastUpgradeCheck = 0700; 200 | ORGANIZATIONNAME = Etsy; 201 | TargetAttributes = { 202 | A2DEB1491BC9980E004AAEB3 = { 203 | CreatedOnToolsVersion = 7.0.1; 204 | }; 205 | A2DEB1581BC9980E004AAEB3 = { 206 | CreatedOnToolsVersion = 7.0.1; 207 | TestTargetID = A2DEB1491BC9980E004AAEB3; 208 | }; 209 | A2DEB1631BC9980E004AAEB3 = { 210 | CreatedOnToolsVersion = 7.0.1; 211 | TestTargetID = A2DEB1491BC9980E004AAEB3; 212 | }; 213 | }; 214 | }; 215 | buildConfigurationList = A2DEB1451BC9980E004AAEB3 /* Build configuration list for PBXProject "WeatherBar" */; 216 | compatibilityVersion = "Xcode 3.2"; 217 | developmentRegion = English; 218 | hasScannedForEncodings = 0; 219 | knownRegions = ( 220 | en, 221 | Base, 222 | ); 223 | mainGroup = A2DEB1411BC9980E004AAEB3; 224 | productRefGroup = A2DEB14B1BC9980E004AAEB3 /* Products */; 225 | projectDirPath = ""; 226 | projectRoot = ""; 227 | targets = ( 228 | A2DEB1491BC9980E004AAEB3 /* WeatherBar */, 229 | A2DEB1581BC9980E004AAEB3 /* WeatherBarTests */, 230 | A2DEB1631BC9980E004AAEB3 /* WeatherBarUITests */, 231 | ); 232 | }; 233 | /* End PBXProject section */ 234 | 235 | /* Begin PBXResourcesBuildPhase section */ 236 | A2DEB1481BC9980E004AAEB3 /* Resources */ = { 237 | isa = PBXResourcesBuildPhase; 238 | buildActionMask = 2147483647; 239 | files = ( 240 | A2DEB1501BC9980E004AAEB3 /* Assets.xcassets in Resources */, 241 | A21862A31BCDEA2E00770E87 /* PreferencesWindow.xib in Resources */, 242 | A2DEB1531BC9980E004AAEB3 /* MainMenu.xib in Resources */, 243 | ); 244 | runOnlyForDeploymentPostprocessing = 0; 245 | }; 246 | A2DEB1571BC9980E004AAEB3 /* Resources */ = { 247 | isa = PBXResourcesBuildPhase; 248 | buildActionMask = 2147483647; 249 | files = ( 250 | ); 251 | runOnlyForDeploymentPostprocessing = 0; 252 | }; 253 | A2DEB1621BC9980E004AAEB3 /* Resources */ = { 254 | isa = PBXResourcesBuildPhase; 255 | buildActionMask = 2147483647; 256 | files = ( 257 | ); 258 | runOnlyForDeploymentPostprocessing = 0; 259 | }; 260 | /* End PBXResourcesBuildPhase section */ 261 | 262 | /* Begin PBXSourcesBuildPhase section */ 263 | A2DEB1461BC9980E004AAEB3 /* Sources */ = { 264 | isa = PBXSourcesBuildPhase; 265 | buildActionMask = 2147483647; 266 | files = ( 267 | A2D5822A1BCB6068006A464B /* WeatherAPI.swift in Sources */, 268 | A21862A21BCDEA2E00770E87 /* PreferencesWindow.swift in Sources */, 269 | A2D582281BCAAF37006A464B /* StatusMenuController.swift in Sources */, 270 | A2DEB14E1BC9980E004AAEB3 /* AppDelegate.swift in Sources */, 271 | A2B4247D1BCDE3D300887CB2 /* WeatherView.swift in Sources */, 272 | ); 273 | runOnlyForDeploymentPostprocessing = 0; 274 | }; 275 | A2DEB1551BC9980E004AAEB3 /* Sources */ = { 276 | isa = PBXSourcesBuildPhase; 277 | buildActionMask = 2147483647; 278 | files = ( 279 | A2DEB15E1BC9980E004AAEB3 /* WeatherBarTests.swift in Sources */, 280 | ); 281 | runOnlyForDeploymentPostprocessing = 0; 282 | }; 283 | A2DEB1601BC9980E004AAEB3 /* Sources */ = { 284 | isa = PBXSourcesBuildPhase; 285 | buildActionMask = 2147483647; 286 | files = ( 287 | A2DEB1691BC9980E004AAEB3 /* WeatherBarUITests.swift in Sources */, 288 | ); 289 | runOnlyForDeploymentPostprocessing = 0; 290 | }; 291 | /* End PBXSourcesBuildPhase section */ 292 | 293 | /* Begin PBXTargetDependency section */ 294 | A2DEB15B1BC9980E004AAEB3 /* PBXTargetDependency */ = { 295 | isa = PBXTargetDependency; 296 | target = A2DEB1491BC9980E004AAEB3 /* WeatherBar */; 297 | targetProxy = A2DEB15A1BC9980E004AAEB3 /* PBXContainerItemProxy */; 298 | }; 299 | A2DEB1661BC9980E004AAEB3 /* PBXTargetDependency */ = { 300 | isa = PBXTargetDependency; 301 | target = A2DEB1491BC9980E004AAEB3 /* WeatherBar */; 302 | targetProxy = A2DEB1651BC9980E004AAEB3 /* PBXContainerItemProxy */; 303 | }; 304 | /* End PBXTargetDependency section */ 305 | 306 | /* Begin PBXVariantGroup section */ 307 | A2DEB1511BC9980E004AAEB3 /* MainMenu.xib */ = { 308 | isa = PBXVariantGroup; 309 | children = ( 310 | A2DEB1521BC9980E004AAEB3 /* Base */, 311 | ); 312 | name = MainMenu.xib; 313 | sourceTree = ""; 314 | }; 315 | /* End PBXVariantGroup section */ 316 | 317 | /* Begin XCBuildConfiguration section */ 318 | A2DEB16B1BC9980E004AAEB3 /* Debug */ = { 319 | isa = XCBuildConfiguration; 320 | buildSettings = { 321 | ALWAYS_SEARCH_USER_PATHS = NO; 322 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 323 | CLANG_CXX_LIBRARY = "libc++"; 324 | CLANG_ENABLE_MODULES = YES; 325 | CLANG_ENABLE_OBJC_ARC = YES; 326 | CLANG_WARN_BOOL_CONVERSION = YES; 327 | CLANG_WARN_CONSTANT_CONVERSION = YES; 328 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 329 | CLANG_WARN_EMPTY_BODY = YES; 330 | CLANG_WARN_ENUM_CONVERSION = YES; 331 | CLANG_WARN_INT_CONVERSION = YES; 332 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 333 | CLANG_WARN_UNREACHABLE_CODE = YES; 334 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 335 | CODE_SIGN_IDENTITY = "-"; 336 | COPY_PHASE_STRIP = NO; 337 | DEBUG_INFORMATION_FORMAT = dwarf; 338 | ENABLE_STRICT_OBJC_MSGSEND = YES; 339 | ENABLE_TESTABILITY = YES; 340 | GCC_C_LANGUAGE_STANDARD = gnu99; 341 | GCC_DYNAMIC_NO_PIC = NO; 342 | GCC_NO_COMMON_BLOCKS = YES; 343 | GCC_OPTIMIZATION_LEVEL = 0; 344 | GCC_PREPROCESSOR_DEFINITIONS = ( 345 | "DEBUG=1", 346 | "$(inherited)", 347 | ); 348 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 349 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 350 | GCC_WARN_UNDECLARED_SELECTOR = YES; 351 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 352 | GCC_WARN_UNUSED_FUNCTION = YES; 353 | GCC_WARN_UNUSED_VARIABLE = YES; 354 | MACOSX_DEPLOYMENT_TARGET = 10.10; 355 | MTL_ENABLE_DEBUG_INFO = YES; 356 | ONLY_ACTIVE_ARCH = YES; 357 | SDKROOT = macosx; 358 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 359 | }; 360 | name = Debug; 361 | }; 362 | A2DEB16C1BC9980E004AAEB3 /* Release */ = { 363 | isa = XCBuildConfiguration; 364 | buildSettings = { 365 | ALWAYS_SEARCH_USER_PATHS = NO; 366 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 367 | CLANG_CXX_LIBRARY = "libc++"; 368 | CLANG_ENABLE_MODULES = YES; 369 | CLANG_ENABLE_OBJC_ARC = YES; 370 | CLANG_WARN_BOOL_CONVERSION = YES; 371 | CLANG_WARN_CONSTANT_CONVERSION = YES; 372 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 373 | CLANG_WARN_EMPTY_BODY = YES; 374 | CLANG_WARN_ENUM_CONVERSION = YES; 375 | CLANG_WARN_INT_CONVERSION = YES; 376 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 377 | CLANG_WARN_UNREACHABLE_CODE = YES; 378 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 379 | CODE_SIGN_IDENTITY = "-"; 380 | COPY_PHASE_STRIP = NO; 381 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 382 | ENABLE_NS_ASSERTIONS = NO; 383 | ENABLE_STRICT_OBJC_MSGSEND = YES; 384 | GCC_C_LANGUAGE_STANDARD = gnu99; 385 | GCC_NO_COMMON_BLOCKS = YES; 386 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 387 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 388 | GCC_WARN_UNDECLARED_SELECTOR = YES; 389 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 390 | GCC_WARN_UNUSED_FUNCTION = YES; 391 | GCC_WARN_UNUSED_VARIABLE = YES; 392 | MACOSX_DEPLOYMENT_TARGET = 10.10; 393 | MTL_ENABLE_DEBUG_INFO = NO; 394 | SDKROOT = macosx; 395 | }; 396 | name = Release; 397 | }; 398 | A2DEB16E1BC9980E004AAEB3 /* Debug */ = { 399 | isa = XCBuildConfiguration; 400 | buildSettings = { 401 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 402 | COMBINE_HIDPI_IMAGES = YES; 403 | INFOPLIST_FILE = WeatherBar/Info.plist; 404 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks"; 405 | PRODUCT_BUNDLE_IDENTIFIER = com.etsy.WeatherBar; 406 | PRODUCT_NAME = "$(TARGET_NAME)"; 407 | }; 408 | name = Debug; 409 | }; 410 | A2DEB16F1BC9980E004AAEB3 /* Release */ = { 411 | isa = XCBuildConfiguration; 412 | buildSettings = { 413 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 414 | COMBINE_HIDPI_IMAGES = YES; 415 | INFOPLIST_FILE = WeatherBar/Info.plist; 416 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks"; 417 | PRODUCT_BUNDLE_IDENTIFIER = com.etsy.WeatherBar; 418 | PRODUCT_NAME = "$(TARGET_NAME)"; 419 | }; 420 | name = Release; 421 | }; 422 | A2DEB1711BC9980E004AAEB3 /* Debug */ = { 423 | isa = XCBuildConfiguration; 424 | buildSettings = { 425 | BUNDLE_LOADER = "$(TEST_HOST)"; 426 | COMBINE_HIDPI_IMAGES = YES; 427 | INFOPLIST_FILE = WeatherBarTests/Info.plist; 428 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; 429 | PRODUCT_BUNDLE_IDENTIFIER = com.etsy.WeatherBarTests; 430 | PRODUCT_NAME = "$(TARGET_NAME)"; 431 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/WeatherBar.app/Contents/MacOS/WeatherBar"; 432 | }; 433 | name = Debug; 434 | }; 435 | A2DEB1721BC9980E004AAEB3 /* Release */ = { 436 | isa = XCBuildConfiguration; 437 | buildSettings = { 438 | BUNDLE_LOADER = "$(TEST_HOST)"; 439 | COMBINE_HIDPI_IMAGES = YES; 440 | INFOPLIST_FILE = WeatherBarTests/Info.plist; 441 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; 442 | PRODUCT_BUNDLE_IDENTIFIER = com.etsy.WeatherBarTests; 443 | PRODUCT_NAME = "$(TARGET_NAME)"; 444 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/WeatherBar.app/Contents/MacOS/WeatherBar"; 445 | }; 446 | name = Release; 447 | }; 448 | A2DEB1741BC9980E004AAEB3 /* Debug */ = { 449 | isa = XCBuildConfiguration; 450 | buildSettings = { 451 | COMBINE_HIDPI_IMAGES = YES; 452 | INFOPLIST_FILE = WeatherBarUITests/Info.plist; 453 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; 454 | PRODUCT_BUNDLE_IDENTIFIER = com.etsy.WeatherBarUITests; 455 | PRODUCT_NAME = "$(TARGET_NAME)"; 456 | TEST_TARGET_NAME = WeatherBar; 457 | USES_XCTRUNNER = YES; 458 | }; 459 | name = Debug; 460 | }; 461 | A2DEB1751BC9980E004AAEB3 /* Release */ = { 462 | isa = XCBuildConfiguration; 463 | buildSettings = { 464 | COMBINE_HIDPI_IMAGES = YES; 465 | INFOPLIST_FILE = WeatherBarUITests/Info.plist; 466 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; 467 | PRODUCT_BUNDLE_IDENTIFIER = com.etsy.WeatherBarUITests; 468 | PRODUCT_NAME = "$(TARGET_NAME)"; 469 | TEST_TARGET_NAME = WeatherBar; 470 | USES_XCTRUNNER = YES; 471 | }; 472 | name = Release; 473 | }; 474 | /* End XCBuildConfiguration section */ 475 | 476 | /* Begin XCConfigurationList section */ 477 | A2DEB1451BC9980E004AAEB3 /* Build configuration list for PBXProject "WeatherBar" */ = { 478 | isa = XCConfigurationList; 479 | buildConfigurations = ( 480 | A2DEB16B1BC9980E004AAEB3 /* Debug */, 481 | A2DEB16C1BC9980E004AAEB3 /* Release */, 482 | ); 483 | defaultConfigurationIsVisible = 0; 484 | defaultConfigurationName = Release; 485 | }; 486 | A2DEB16D1BC9980E004AAEB3 /* Build configuration list for PBXNativeTarget "WeatherBar" */ = { 487 | isa = XCConfigurationList; 488 | buildConfigurations = ( 489 | A2DEB16E1BC9980E004AAEB3 /* Debug */, 490 | A2DEB16F1BC9980E004AAEB3 /* Release */, 491 | ); 492 | defaultConfigurationIsVisible = 0; 493 | defaultConfigurationName = Release; 494 | }; 495 | A2DEB1701BC9980E004AAEB3 /* Build configuration list for PBXNativeTarget "WeatherBarTests" */ = { 496 | isa = XCConfigurationList; 497 | buildConfigurations = ( 498 | A2DEB1711BC9980E004AAEB3 /* Debug */, 499 | A2DEB1721BC9980E004AAEB3 /* Release */, 500 | ); 501 | defaultConfigurationIsVisible = 0; 502 | defaultConfigurationName = Release; 503 | }; 504 | A2DEB1731BC9980E004AAEB3 /* Build configuration list for PBXNativeTarget "WeatherBarUITests" */ = { 505 | isa = XCConfigurationList; 506 | buildConfigurations = ( 507 | A2DEB1741BC9980E004AAEB3 /* Debug */, 508 | A2DEB1751BC9980E004AAEB3 /* Release */, 509 | ); 510 | defaultConfigurationIsVisible = 0; 511 | defaultConfigurationName = Release; 512 | }; 513 | /* End XCConfigurationList section */ 514 | }; 515 | rootObject = A2DEB1421BC9980E004AAEB3 /* Project object */; 516 | } 517 | -------------------------------------------------------------------------------- /WeatherBar.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /WeatherBar/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.swift 3 | // WeatherBar 4 | // 5 | // Created by Brad Greenlee on 10/10/15. 6 | // Copyright © 2015 Etsy. All rights reserved. 7 | // 8 | 9 | import Cocoa 10 | 11 | @NSApplicationMain 12 | class AppDelegate: NSObject, NSApplicationDelegate { 13 | func applicationDidFinishLaunching(aNotification: NSNotification) { 14 | // Insert code here to initialize your application 15 | } 16 | 17 | func applicationWillTerminate(aNotification: NSNotification) { 18 | // Insert code here to tear down your application 19 | } 20 | } 21 | 22 | -------------------------------------------------------------------------------- /WeatherBar/Assets.xcassets/01d.imageset/01d.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PlayApple/WeatherBar/4ea8e524642edcfa0576e48881a38f940065adf1/WeatherBar/Assets.xcassets/01d.imageset/01d.png -------------------------------------------------------------------------------- /WeatherBar/Assets.xcassets/01d.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "01d.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /WeatherBar/Assets.xcassets/01n.imageset/01n.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PlayApple/WeatherBar/4ea8e524642edcfa0576e48881a38f940065adf1/WeatherBar/Assets.xcassets/01n.imageset/01n.png -------------------------------------------------------------------------------- /WeatherBar/Assets.xcassets/01n.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "01n.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /WeatherBar/Assets.xcassets/02d.imageset/02d.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PlayApple/WeatherBar/4ea8e524642edcfa0576e48881a38f940065adf1/WeatherBar/Assets.xcassets/02d.imageset/02d.png -------------------------------------------------------------------------------- /WeatherBar/Assets.xcassets/02d.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "02d.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /WeatherBar/Assets.xcassets/02n.imageset/02n.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PlayApple/WeatherBar/4ea8e524642edcfa0576e48881a38f940065adf1/WeatherBar/Assets.xcassets/02n.imageset/02n.png -------------------------------------------------------------------------------- /WeatherBar/Assets.xcassets/02n.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "02n.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /WeatherBar/Assets.xcassets/03d.imageset/03d.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PlayApple/WeatherBar/4ea8e524642edcfa0576e48881a38f940065adf1/WeatherBar/Assets.xcassets/03d.imageset/03d.png -------------------------------------------------------------------------------- /WeatherBar/Assets.xcassets/03d.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "03d.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /WeatherBar/Assets.xcassets/03n.imageset/03n.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PlayApple/WeatherBar/4ea8e524642edcfa0576e48881a38f940065adf1/WeatherBar/Assets.xcassets/03n.imageset/03n.png -------------------------------------------------------------------------------- /WeatherBar/Assets.xcassets/03n.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "03n.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /WeatherBar/Assets.xcassets/04d.imageset/04d.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PlayApple/WeatherBar/4ea8e524642edcfa0576e48881a38f940065adf1/WeatherBar/Assets.xcassets/04d.imageset/04d.png -------------------------------------------------------------------------------- /WeatherBar/Assets.xcassets/04d.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "04d.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /WeatherBar/Assets.xcassets/04n.imageset/04n.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PlayApple/WeatherBar/4ea8e524642edcfa0576e48881a38f940065adf1/WeatherBar/Assets.xcassets/04n.imageset/04n.png -------------------------------------------------------------------------------- /WeatherBar/Assets.xcassets/04n.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "04n.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /WeatherBar/Assets.xcassets/09d.imageset/09d.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PlayApple/WeatherBar/4ea8e524642edcfa0576e48881a38f940065adf1/WeatherBar/Assets.xcassets/09d.imageset/09d.png -------------------------------------------------------------------------------- /WeatherBar/Assets.xcassets/09d.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "09d.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /WeatherBar/Assets.xcassets/09n.imageset/09n.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PlayApple/WeatherBar/4ea8e524642edcfa0576e48881a38f940065adf1/WeatherBar/Assets.xcassets/09n.imageset/09n.png -------------------------------------------------------------------------------- /WeatherBar/Assets.xcassets/09n.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "09n.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /WeatherBar/Assets.xcassets/10d.imageset/10d.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PlayApple/WeatherBar/4ea8e524642edcfa0576e48881a38f940065adf1/WeatherBar/Assets.xcassets/10d.imageset/10d.png -------------------------------------------------------------------------------- /WeatherBar/Assets.xcassets/10d.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "10d.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /WeatherBar/Assets.xcassets/10n.imageset/10n.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PlayApple/WeatherBar/4ea8e524642edcfa0576e48881a38f940065adf1/WeatherBar/Assets.xcassets/10n.imageset/10n.png -------------------------------------------------------------------------------- /WeatherBar/Assets.xcassets/10n.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "10n.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /WeatherBar/Assets.xcassets/11d.imageset/11d.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PlayApple/WeatherBar/4ea8e524642edcfa0576e48881a38f940065adf1/WeatherBar/Assets.xcassets/11d.imageset/11d.png -------------------------------------------------------------------------------- /WeatherBar/Assets.xcassets/11d.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "11d.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /WeatherBar/Assets.xcassets/11n.imageset/11n.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PlayApple/WeatherBar/4ea8e524642edcfa0576e48881a38f940065adf1/WeatherBar/Assets.xcassets/11n.imageset/11n.png -------------------------------------------------------------------------------- /WeatherBar/Assets.xcassets/11n.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "11n.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /WeatherBar/Assets.xcassets/13d.imageset/13d.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PlayApple/WeatherBar/4ea8e524642edcfa0576e48881a38f940065adf1/WeatherBar/Assets.xcassets/13d.imageset/13d.png -------------------------------------------------------------------------------- /WeatherBar/Assets.xcassets/13d.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "13d.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /WeatherBar/Assets.xcassets/13n.imageset/13n.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PlayApple/WeatherBar/4ea8e524642edcfa0576e48881a38f940065adf1/WeatherBar/Assets.xcassets/13n.imageset/13n.png -------------------------------------------------------------------------------- /WeatherBar/Assets.xcassets/13n.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "13n.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /WeatherBar/Assets.xcassets/50d.imageset/50d.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PlayApple/WeatherBar/4ea8e524642edcfa0576e48881a38f940065adf1/WeatherBar/Assets.xcassets/50d.imageset/50d.png -------------------------------------------------------------------------------- /WeatherBar/Assets.xcassets/50d.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "50d.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /WeatherBar/Assets.xcassets/50n.imageset/50n.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PlayApple/WeatherBar/4ea8e524642edcfa0576e48881a38f940065adf1/WeatherBar/Assets.xcassets/50n.imageset/50n.png -------------------------------------------------------------------------------- /WeatherBar/Assets.xcassets/50n.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "50n.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /WeatherBar/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 | } -------------------------------------------------------------------------------- /WeatherBar/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } -------------------------------------------------------------------------------- /WeatherBar/Assets.xcassets/statusIcon.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "statusIcon.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "filename" : "statusIcon@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 | } -------------------------------------------------------------------------------- /WeatherBar/Assets.xcassets/statusIcon.imageset/statusIcon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PlayApple/WeatherBar/4ea8e524642edcfa0576e48881a38f940065adf1/WeatherBar/Assets.xcassets/statusIcon.imageset/statusIcon.png -------------------------------------------------------------------------------- /WeatherBar/Assets.xcassets/statusIcon.imageset/statusIcon@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PlayApple/WeatherBar/4ea8e524642edcfa0576e48881a38f940065adf1/WeatherBar/Assets.xcassets/statusIcon.imageset/statusIcon@2x.png -------------------------------------------------------------------------------- /WeatherBar/Base.lproj/MainMenu.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | -------------------------------------------------------------------------------- /WeatherBar/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIconFile 10 | 11 | CFBundleIdentifier 12 | $(PRODUCT_BUNDLE_IDENTIFIER) 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | $(PRODUCT_NAME) 17 | CFBundlePackageType 18 | APPL 19 | CFBundleShortVersionString 20 | 1.0 21 | CFBundleSignature 22 | ???? 23 | CFBundleVersion 24 | 1 25 | LSMinimumSystemVersion 26 | $(MACOSX_DEPLOYMENT_TARGET) 27 | LSUIElement 28 | 29 | NSHumanReadableCopyright 30 | Copyright © 2015 Etsy. All rights reserved. 31 | NSMainNibFile 32 | MainMenu 33 | NSPrincipalClass 34 | NSApplication 35 | NSAppTransportSecurity 36 | 37 | NSExceptionDomains 38 | 39 | api.openweathermap.org 40 | 41 | NSExceptionAllowsInsecureHTTPLoads 42 | 43 | 44 | 45 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /WeatherBar/PreferencesWindow.swift: -------------------------------------------------------------------------------- 1 | // 2 | // PreferencesWindow.swift 3 | // WeatherBar 4 | // 5 | // Created by Brad Greenlee on 10/13/15. 6 | // Copyright © 2015 Etsy. All rights reserved. 7 | // 8 | 9 | import Cocoa 10 | 11 | protocol PreferencesWindowDelegate { 12 | func preferencesDidUpdate() 13 | } 14 | 15 | class PreferencesWindow: NSWindowController, NSWindowDelegate { 16 | var delegate: PreferencesWindowDelegate? 17 | @IBOutlet weak var cityTextField: NSTextField! 18 | 19 | override var windowNibName : String! { 20 | return "PreferencesWindow" 21 | } 22 | 23 | override func windowDidLoad() { 24 | super.windowDidLoad() 25 | 26 | self.window?.center() 27 | self.window?.makeKeyAndOrderFront(nil) 28 | NSApp.activateIgnoringOtherApps(true) 29 | 30 | let defaults = NSUserDefaults.standardUserDefaults() 31 | let city = defaults.stringForKey("city") ?? DEFAULT_CITY 32 | cityTextField.stringValue = city 33 | } 34 | 35 | func windowWillClose(notification: NSNotification) { 36 | let defaults = NSUserDefaults.standardUserDefaults() 37 | defaults.setValue(cityTextField.stringValue, forKey: "city") 38 | delegate?.preferencesDidUpdate() 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /WeatherBar/PreferencesWindow.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | -------------------------------------------------------------------------------- /WeatherBar/StatusMenuController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // StatusMenuController.swift 3 | // WeatherBar 4 | // 5 | // Created by Brad Greenlee on 10/11/15. 6 | // Copyright © 2015 Etsy. All rights reserved. 7 | // 8 | 9 | import Cocoa 10 | 11 | let DEFAULT_CITY = "Seattle, WA" 12 | 13 | class StatusMenuController: NSObject, PreferencesWindowDelegate { 14 | @IBOutlet weak var statusMenu: NSMenu! 15 | @IBOutlet weak var weatherView: WeatherView! 16 | 17 | var weatherMenuItem: NSMenuItem! 18 | var preferencesWindow: PreferencesWindow! 19 | 20 | let statusItem = NSStatusBar.systemStatusBar().statusItemWithLength(NSVariableStatusItemLength) 21 | let weatherAPI = WeatherAPI() 22 | 23 | override func awakeFromNib() { 24 | statusItem.menu = statusMenu 25 | let icon = NSImage(named: "statusIcon") 26 | icon?.template = true // best for dark mode 27 | statusItem.image = icon 28 | statusItem.menu = statusMenu 29 | weatherMenuItem = statusMenu.itemWithTitle("Weather") 30 | weatherMenuItem.view = weatherView 31 | preferencesWindow = PreferencesWindow() 32 | preferencesWindow.delegate = self 33 | 34 | updateWeather() 35 | } 36 | 37 | func updateWeather() { 38 | let defaults = NSUserDefaults.standardUserDefaults() 39 | let city = defaults.stringForKey("city") ?? DEFAULT_CITY 40 | weatherAPI.fetchWeather(city) { weather in 41 | self.weatherView.update(weather) 42 | } 43 | } 44 | 45 | @IBAction func updateClicked(sender: NSMenuItem) { 46 | updateWeather() 47 | } 48 | 49 | @IBAction func preferencesClicked(sender: NSMenuItem) { 50 | preferencesWindow.showWindow(nil) 51 | } 52 | 53 | @IBAction func quitClicked(sender: NSMenuItem) { 54 | NSApplication.sharedApplication().terminate(self) 55 | } 56 | 57 | func preferencesDidUpdate() { 58 | updateWeather() 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /WeatherBar/WeatherAPI.swift: -------------------------------------------------------------------------------- 1 | // 2 | // WeatherAPI.swift 3 | // WeatherBar 4 | // 5 | // Created by Brad Greenlee on 10/11/15. 6 | // Copyright © 2015 Etsy. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | struct Weather: CustomStringConvertible { 12 | var city: String 13 | var currentTemp: Float 14 | var conditions: String 15 | var icon: String 16 | 17 | var description: String { 18 | return "\(city): \(currentTemp)F and \(conditions)" 19 | } 20 | } 21 | 22 | class WeatherAPI { 23 | let API_KEY = "your-api-key-here" 24 | let BASE_URL = "http://api.openweathermap.org/data/2.5/weather" 25 | 26 | func fetchWeather(query: String, success: (Weather) -> Void) { 27 | let session = NSURLSession.sharedSession() 28 | // url-escape the query string we're passed 29 | let escapedQuery = query.stringByAddingPercentEncodingWithAllowedCharacters(NSCharacterSet.URLQueryAllowedCharacterSet()) 30 | let url = NSURL(string: "\(BASE_URL)?APPID=\(API_KEY)&units=imperial&q=\(escapedQuery!)") 31 | let task = session.dataTaskWithURL(url!) { data, response, err in 32 | // first check for a hard error 33 | if let error = err { 34 | NSLog("weather api error: \(error)") 35 | } 36 | 37 | // then check the response code 38 | if let httpResponse = response as? NSHTTPURLResponse { 39 | switch httpResponse.statusCode { 40 | case 200: // all good! 41 | if let weather = self.weatherFromJSONData(data!) { 42 | success(weather) 43 | } 44 | case 401: // unauthorized 45 | NSLog("weather api returned an 'unauthorized' response. Did you set your API key?") 46 | default: 47 | NSLog("weather api returned response: %d %@", httpResponse.statusCode, NSHTTPURLResponse.localizedStringForStatusCode(httpResponse.statusCode)) 48 | } 49 | } 50 | } 51 | task.resume() 52 | } 53 | 54 | func weatherFromJSONData(data: NSData) -> Weather? { 55 | typealias JSONDict = [String:AnyObject] 56 | let json : JSONDict 57 | 58 | do { 59 | json = try NSJSONSerialization.JSONObjectWithData(data, options: []) as! JSONDict 60 | } catch { 61 | NSLog("JSON parsing failed: \(error)") 62 | return nil 63 | } 64 | 65 | var mainDict = json["main"] as! JSONDict 66 | var weatherList = json["weather"] as! [JSONDict] 67 | var weatherDict = weatherList[0] 68 | 69 | let weather = Weather( 70 | city: json["name"] as! String, 71 | currentTemp: mainDict["temp"] as! Float, 72 | conditions: weatherDict["main"] as! String, 73 | icon: weatherDict["icon"] as! String 74 | ) 75 | 76 | return weather 77 | } 78 | } -------------------------------------------------------------------------------- /WeatherBar/WeatherView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // WeatherView.swift 3 | // WeatherBar 4 | // 5 | // Created by Brad Greenlee on 10/13/15. 6 | // Copyright © 2015 Etsy. All rights reserved. 7 | // 8 | 9 | import Cocoa 10 | 11 | class WeatherView: NSView { 12 | @IBOutlet weak var imageView: NSImageView! 13 | @IBOutlet weak var cityTextField: NSTextField! 14 | @IBOutlet weak var currentConditionsTextField: NSTextField! 15 | 16 | func update(weather: Weather) { 17 | // do UI updates on the main thread 18 | dispatch_async(dispatch_get_main_queue()) { 19 | self.cityTextField.stringValue = weather.city 20 | self.currentConditionsTextField.stringValue = "\(Int(weather.currentTemp))°F and \(weather.conditions)" 21 | self.imageView.image = NSImage(named: weather.icon) 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /WeatherBarTests/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 | -------------------------------------------------------------------------------- /WeatherBarTests/WeatherBarTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // WeatherBarTests.swift 3 | // WeatherBarTests 4 | // 5 | // Created by Brad Greenlee on 10/10/15. 6 | // Copyright © 2015 Etsy. All rights reserved. 7 | // 8 | 9 | import XCTest 10 | @testable import WeatherBar 11 | 12 | class WeatherBarTests: XCTestCase { 13 | 14 | override func setUp() { 15 | super.setUp() 16 | // Put setup code here. This method is called before the invocation of each test method in the class. 17 | } 18 | 19 | override func tearDown() { 20 | // Put teardown code here. This method is called after the invocation of each test method in the class. 21 | super.tearDown() 22 | } 23 | 24 | func testExample() { 25 | // This is an example of a functional test case. 26 | // Use XCTAssert and related functions to verify your tests produce the correct results. 27 | } 28 | 29 | func testPerformanceExample() { 30 | // This is an example of a performance test case. 31 | self.measureBlock { 32 | // Put the code you want to measure the time of here. 33 | } 34 | } 35 | 36 | } 37 | -------------------------------------------------------------------------------- /WeatherBarUITests/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 | -------------------------------------------------------------------------------- /WeatherBarUITests/WeatherBarUITests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // WeatherBarUITests.swift 3 | // WeatherBarUITests 4 | // 5 | // Created by Brad Greenlee on 10/10/15. 6 | // Copyright © 2015 Etsy. All rights reserved. 7 | // 8 | 9 | import XCTest 10 | 11 | class WeatherBarUITests: XCTestCase { 12 | 13 | override func setUp() { 14 | super.setUp() 15 | 16 | // Put setup code here. This method is called before the invocation of each test method in the class. 17 | 18 | // In UI tests it is usually best to stop immediately when a failure occurs. 19 | continueAfterFailure = false 20 | // UI tests must launch the application that they test. Doing this in setup will make sure it happens for each test method. 21 | XCUIApplication().launch() 22 | 23 | // In UI tests it’s important to set the initial state - such as interface orientation - required for your tests before they run. The setUp method is a good place to do this. 24 | } 25 | 26 | override func tearDown() { 27 | // Put teardown code here. This method is called after the invocation of each test method in the class. 28 | super.tearDown() 29 | } 30 | 31 | func testExample() { 32 | // Use recording to get started writing UI tests. 33 | // Use XCTAssert and related functions to verify your tests produce the correct results. 34 | } 35 | 36 | } 37 | -------------------------------------------------------------------------------- /weather-icons.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PlayApple/WeatherBar/4ea8e524642edcfa0576e48881a38f940065adf1/weather-icons.zip --------------------------------------------------------------------------------