├── weather-icons.zip
├── WeatherBar
├── Assets.xcassets
│ ├── Contents.json
│ ├── 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
│ ├── statusIcon.imageset
│ │ ├── statusIcon.png
│ │ ├── statusIcon@2x.png
│ │ └── Contents.json
│ └── AppIcon.appiconset
│ │ └── Contents.json
├── AppDelegate.swift
├── WeatherView.swift
├── PreferencesWindow.swift
├── Info.plist
├── StatusMenuController.swift
├── WeatherAPI.swift
├── PreferencesWindow.xib
└── Base.lproj
│ └── MainMenu.xib
├── README.md
├── WeatherBar.xcodeproj
├── project.xcworkspace
│ └── contents.xcworkspacedata
└── project.pbxproj
├── .gitignore
├── WeatherBarTests
├── Info.plist
└── WeatherBarTests.swift
├── WeatherBarUITests
├── Info.plist
└── WeatherBarUITests.swift
└── LICENSE
/weather-icons.zip:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PlayApple/WeatherBar/HEAD/weather-icons.zip
--------------------------------------------------------------------------------
/WeatherBar/Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "version" : 1,
4 | "author" : "xcode"
5 | }
6 | }
--------------------------------------------------------------------------------
/WeatherBar/Assets.xcassets/01d.imageset/01d.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PlayApple/WeatherBar/HEAD/WeatherBar/Assets.xcassets/01d.imageset/01d.png
--------------------------------------------------------------------------------
/WeatherBar/Assets.xcassets/01n.imageset/01n.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PlayApple/WeatherBar/HEAD/WeatherBar/Assets.xcassets/01n.imageset/01n.png
--------------------------------------------------------------------------------
/WeatherBar/Assets.xcassets/02d.imageset/02d.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PlayApple/WeatherBar/HEAD/WeatherBar/Assets.xcassets/02d.imageset/02d.png
--------------------------------------------------------------------------------
/WeatherBar/Assets.xcassets/02n.imageset/02n.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PlayApple/WeatherBar/HEAD/WeatherBar/Assets.xcassets/02n.imageset/02n.png
--------------------------------------------------------------------------------
/WeatherBar/Assets.xcassets/03d.imageset/03d.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PlayApple/WeatherBar/HEAD/WeatherBar/Assets.xcassets/03d.imageset/03d.png
--------------------------------------------------------------------------------
/WeatherBar/Assets.xcassets/03n.imageset/03n.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PlayApple/WeatherBar/HEAD/WeatherBar/Assets.xcassets/03n.imageset/03n.png
--------------------------------------------------------------------------------
/WeatherBar/Assets.xcassets/04d.imageset/04d.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PlayApple/WeatherBar/HEAD/WeatherBar/Assets.xcassets/04d.imageset/04d.png
--------------------------------------------------------------------------------
/WeatherBar/Assets.xcassets/04n.imageset/04n.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PlayApple/WeatherBar/HEAD/WeatherBar/Assets.xcassets/04n.imageset/04n.png
--------------------------------------------------------------------------------
/WeatherBar/Assets.xcassets/09d.imageset/09d.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PlayApple/WeatherBar/HEAD/WeatherBar/Assets.xcassets/09d.imageset/09d.png
--------------------------------------------------------------------------------
/WeatherBar/Assets.xcassets/09n.imageset/09n.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PlayApple/WeatherBar/HEAD/WeatherBar/Assets.xcassets/09n.imageset/09n.png
--------------------------------------------------------------------------------
/WeatherBar/Assets.xcassets/10d.imageset/10d.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PlayApple/WeatherBar/HEAD/WeatherBar/Assets.xcassets/10d.imageset/10d.png
--------------------------------------------------------------------------------
/WeatherBar/Assets.xcassets/10n.imageset/10n.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PlayApple/WeatherBar/HEAD/WeatherBar/Assets.xcassets/10n.imageset/10n.png
--------------------------------------------------------------------------------
/WeatherBar/Assets.xcassets/11d.imageset/11d.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PlayApple/WeatherBar/HEAD/WeatherBar/Assets.xcassets/11d.imageset/11d.png
--------------------------------------------------------------------------------
/WeatherBar/Assets.xcassets/11n.imageset/11n.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PlayApple/WeatherBar/HEAD/WeatherBar/Assets.xcassets/11n.imageset/11n.png
--------------------------------------------------------------------------------
/WeatherBar/Assets.xcassets/13d.imageset/13d.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PlayApple/WeatherBar/HEAD/WeatherBar/Assets.xcassets/13d.imageset/13d.png
--------------------------------------------------------------------------------
/WeatherBar/Assets.xcassets/13n.imageset/13n.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PlayApple/WeatherBar/HEAD/WeatherBar/Assets.xcassets/13n.imageset/13n.png
--------------------------------------------------------------------------------
/WeatherBar/Assets.xcassets/50d.imageset/50d.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PlayApple/WeatherBar/HEAD/WeatherBar/Assets.xcassets/50d.imageset/50d.png
--------------------------------------------------------------------------------
/WeatherBar/Assets.xcassets/50n.imageset/50n.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PlayApple/WeatherBar/HEAD/WeatherBar/Assets.xcassets/50n.imageset/50n.png
--------------------------------------------------------------------------------
/WeatherBar/Assets.xcassets/statusIcon.imageset/statusIcon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PlayApple/WeatherBar/HEAD/WeatherBar/Assets.xcassets/statusIcon.imageset/statusIcon.png
--------------------------------------------------------------------------------
/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/Assets.xcassets/statusIcon.imageset/statusIcon@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PlayApple/WeatherBar/HEAD/WeatherBar/Assets.xcassets/statusIcon.imageset/statusIcon@2x.png
--------------------------------------------------------------------------------
/WeatherBar.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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/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 |
--------------------------------------------------------------------------------
/.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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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/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/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/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 |
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.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 |
--------------------------------------------------------------------------------