diff --git a/.DS_Store b/.DS_Store
new file mode 100644
index 0000000..38e0ca9
Binary files /dev/null and b/.DS_Store differ
diff --git a/.gitignore b/.gitignore
index 4e1972b..129fea3 100644
--- a/.gitignore
+++ b/.gitignore
@@ -18,6 +18,54 @@ DerivedData
*.ipa
*.xcuserstate
+### AppCode ###
+# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio
+
+*.iml
+
+## Directory-based project format:
+.idea/
+# if you remove the above rule, at least ignore the following:
+
+# User-specific stuff:
+# .idea/workspace.xml
+# .idea/tasks.xml
+# .idea/dictionaries
+
+# Sensitive or high-churn files:
+# .idea/dataSources.ids
+# .idea/dataSources.xml
+# .idea/sqlDataSources.xml
+# .idea/dynamic.xml
+# .idea/uiDesigner.xml
+
+# Gradle:
+# .idea/gradle.xml
+# .idea/libraries
+
+# Mongo Explorer plugin:
+# .idea/mongoSettings.xml
+
+## File-based project format:
+*.ipr
+*.iws
+
+## Plugin-specific files:
+
+# IntelliJ
+/out/
+
+# mpeltonen/sbt-idea plugin
+.idea_modules/
+
+# JIRA plugin
+atlassian-ide-plugin.xml
+
+# Crashlytics plugin (for Android Studio and IntelliJ)
+com_crashlytics_export_strings.xml
+crashlytics.properties
+crashlytics-build.properties
+
# CocoaPods
#
# We recommend against adding the Pods directory to your .gitignore. However
@@ -25,3 +73,14 @@ DerivedData
# http://guides.cocoapods.org/using/using-cocoapods.html#should-i-ignore-the-pods-directory-in-source-control?
#
Pods/
+
+# Carthage
+Carthage.pkg
+Carthage.build
+Carthage.checkout
+
+# Access keys
+.access_tokens
+
+# rbenv
+.ruby-version
diff --git a/.gitmodules b/.gitmodules
new file mode 100644
index 0000000..bf80a7b
--- /dev/null
+++ b/.gitmodules
@@ -0,0 +1,6 @@
+[submodule "Alamofire"]
+ path = Alamofire
+ url = https://github.com/Alamofire/Alamofire.git
+[submodule "SwiftyJSON"]
+ path = SwiftyJSON
+ url = https://github.com/SwiftyJSON/SwiftyJSON.git
diff --git a/.swiftlint.yml b/.swiftlint.yml
new file mode 100644
index 0000000..8d6f864
--- /dev/null
+++ b/.swiftlint.yml
@@ -0,0 +1,2 @@
+excluded:
+ - Pods
diff --git a/Design/SwiftWeather.sketch b/Design/SwiftWeather.sketch
new file mode 100644
index 0000000..3ac39f1
Binary files /dev/null and b/Design/SwiftWeather.sketch differ
diff --git a/Design/background.png b/Design/background.png
new file mode 100644
index 0000000..05e01f8
Binary files /dev/null and b/Design/background.png differ
diff --git a/Podfile b/Podfile
index b081fae..5d0e718 100644
--- a/Podfile
+++ b/Podfile
@@ -1,2 +1,17 @@
-platform :ios, :deployment_target => '7.0'
-pod 'AFNetworking'
+platform :ios, '10.0'
+use_frameworks!
+
+target 'SwiftWeather' do
+ pod 'SwiftyJSON'
+ pod 'FacebookShare'
+end
+
+abstract_target 'Tests' do
+ pod 'Quick'
+ pod 'Nimble'
+
+ target 'SwiftWeatherTests'
+ target 'SwiftWeatherUITests'
+end
+
+
diff --git a/Podfile.lock b/Podfile.lock
index 6a4c801..299b94e 100644
--- a/Podfile.lock
+++ b/Podfile.lock
@@ -1,30 +1,53 @@
PODS:
- - AFNetworking (2.3.1):
- - AFNetworking/NSURLConnection
- - AFNetworking/NSURLSession
- - AFNetworking/Reachability
- - AFNetworking/Security
- - AFNetworking/Serialization
- - AFNetworking/UIKit
- - AFNetworking/NSURLConnection (2.3.1):
- - AFNetworking/Reachability
- - AFNetworking/Security
- - AFNetworking/Serialization
- - AFNetworking/NSURLSession (2.3.1):
- - AFNetworking/Reachability
- - AFNetworking/Security
- - AFNetworking/Serialization
- - AFNetworking/Reachability (2.3.1)
- - AFNetworking/Security (2.3.1)
- - AFNetworking/Serialization (2.3.1)
- - AFNetworking/UIKit (2.3.1):
- - AFNetworking/NSURLConnection
- - AFNetworking/NSURLSession
+ - Bolts (1.9.0):
+ - Bolts/AppLinks (= 1.9.0)
+ - Bolts/Tasks (= 1.9.0)
+ - Bolts/AppLinks (1.9.0):
+ - Bolts/Tasks
+ - Bolts/Tasks (1.9.0)
+ - FacebookCore (0.3.0):
+ - Bolts (~> 1.8)
+ - FBSDKCoreKit (~> 4.27)
+ - FacebookShare (0.3.0):
+ - Bolts (~> 1.8)
+ - FacebookCore (~> 0.3)
+ - FBSDKCoreKit (~> 4.27)
+ - FBSDKShareKit (~> 4.27)
+ - FBSDKCoreKit (4.33.0):
+ - Bolts (~> 1.7)
+ - FBSDKShareKit (4.33.0):
+ - FBSDKCoreKit (~> 4.33.0)
+ - Nimble (7.0.3)
+ - Quick (1.2.0)
+ - SwiftyJSON (4.0.0)
DEPENDENCIES:
- - AFNetworking
+ - FacebookShare
+ - Nimble
+ - Quick
+ - SwiftyJSON
+
+SPEC REPOS:
+ https://github.com/CocoaPods/Specs.git:
+ - Bolts
+ - FacebookCore
+ - FacebookShare
+ - FBSDKCoreKit
+ - FBSDKShareKit
+ - Nimble
+ - Quick
+ - SwiftyJSON
SPEC CHECKSUMS:
- AFNetworking: 6d7b76aa5d04c8c37daad3eef4b7e3f2a7620da3
+ Bolts: ac6567323eac61e203f6a9763667d0f711be34c8
+ FacebookCore: 3ffa190a3f1f96cec0e44d3fc221bc322c595ffa
+ FacebookShare: 0469964297ebd75f052be2c5083389a4208e82b7
+ FBSDKCoreKit: 572b047a7e029bc44542bcf8a59414e7ff2b543e
+ FBSDKShareKit: 1869cb24db2cea90666a50cb9d568deb38e2d16e
+ Nimble: 7f5a9c447a33002645a071bddafbfb24ea70e0ac
+ Quick: 58d203b1c5e27fff7229c4c1ae445ad7069a7a08
+ SwiftyJSON: 070dabdcb1beb81b247c65ffa3a79dbbfb3b48aa
+
+PODFILE CHECKSUM: 28f6397e3ce4b1c0258bb51e941d6155f9477e75
-COCOAPODS: 0.34.0.rc2
+COCOAPODS: 1.5.0
diff --git a/README.md b/README.md
index 4a780c8..c47c7de 100644
--- a/README.md
+++ b/README.md
@@ -1,50 +1,100 @@
-Swift Weather
+Swift Language Weather
============
+[](https://dashboard.buddybuild.com/apps/562a9aac2492560100211378/build/latest)
+
+
-SwiftWeather is an iOS weather app developed in Swift language. The app can support iPhone 4(s), iPhone 5(s), iPhone 6 and iPhone 6 Plus.
+**SwiftWeather** has renamed to **Swift Language Weather**. Because this repo is ranked number one in Google when we search "Swift Weather", I got an email from Swift Weather Company's lawyer to ask me to change the name because they said they are the owner of U.S. Trademark SWIFT WEATHER. After discussed with them, they were not happy with the name Swift**y**Weather. Now the new project name is **Swift Language Weather**. More details can be found on [Issue: Open source project using a registered trademark](https://github.com/JakeLin/SwiftWeather/issues/65).
-## Screenshots
-
+**Swift Language Weather** is an iOS weather app developed in Swift 4. The app has been actively upgrading to adopt the latest features of iOS and Swift language.
-
+## Notices
+The current version is working with Xcode Version Xcode 9.1 (9B55). If you are using different Xcode version, please check out the previous releases.
+## Version 4
+This version has been upgraded to support iOS 10+ only using Swift 4.
-#### iPhone 4s
-
+There is three major version of the app released before.
-#### iPhone 5s
-
+* V1.0 - Support iOS 7+ using CocoaPods and AFNetworking. [README.v1.md](https://github.com/JakeLin/SwiftWeather/blob/master/README.v1.md) and [Release V1 - Using CocoaPods and AFNetworking](https://github.com/JakeLin/SwiftWeather/releases/tag/V1)
+* V2.0 - Support iOS 8+ using Carthage, Alamofire, and SwiftyJSON. [README.v2.md](https://github.com/JakeLin/SwiftWeather/blob/master/README.v2.md) and [Release V2.0](https://github.com/JakeLin/SwiftWeather/releases/tag/v2.0)
+* V2.1 - Support iOS 8+ using Alamofire and SwiftyJSON. This version has removed Carthage because some developers don't have a paid Apple iOS developer account, and they have issues to build Carthage packages.
+* V3.0 - Support iOS 9+ and Swift 3.
-#### iPhone 6
-
+## Screenshots
-#### iPhone 6 Plus
-
+## Features
+* Swift Programming Language
+* Design-driven development - [Sketch design file ](https://raw.githubusercontent.com/JakeLin/SwiftWeather/master/Design/SwiftWeather.sketch)
-## Notices
-Because Apple keeps changing the Swift compiler, the current version can be compiled in Xcode 6.1.
+
-## Used features
-* Swift Programming Language
-* CocoaPods
-* AFNetworking
-* Core Location
+* Custom UIView
+
+
+* `@IBDesignable` and `@IBInspectable` - Reusable UI components
+
+
+
+* `UIStackView`
+
+
+
+* Size Classes - Support different devices with adaptive layout
+
+
+
+* MVVM - Reactively update `ViewController` UI from `ViewModel`
+* Protocol-Oriented Programming - We use Protocol-Oriented Programming in [IBAnimatable open source project](https://github.com/IBAnimatable/IBAnimatable).
+* Value-based programming - Use immutable value anywhere.
+* Icon fonts - Use [Weather Icons](https://erikflowers.github.io/weather-icons/)
+* [SwiftyJSON](https://github.com/SwiftyJSON/SwiftyJSON)
+* Core Location
+* App indexing like CoreSpotlight and `NSUserActivity`
+* Unit Tests
+* UI Tests
+* Animations
## How to build
-Because the app uses CocoaPods, we need to run `pod install` to install all the pods.
-
-1. Open Terminal app.
-2. Change directory to the project folder. `cd $project_dir`
-3. Use `ls` to list all the file to check whether *Podfile* file is in the folder?
-4. If the *Podfile* has been found, then execute `pod install`
-5. If the Mac OS doesn't have CocoaPods installed. Please follow [CocoaPods Getting Started](http://guides.cocoapods.org/using/getting-started.html) to install.
-6. Once complete installation, open *Swift Weather.xcworkspace* file with Xcode 6.
-7. Press *Cmd + B* to build the app.
-8. Press *Cmd + R* to run the app on Simulator.
-
-## Credits
-* Thanks to [johnsonjake](https://github.com/johnsonjake) for adding iOS 8 support and improving the UI/UX.
-* Thanks to [Marc](https://github.com/gizmou) for adding forcast feature, widget and app icon.
+
+1) Clone the repository
+
+```bash
+$ git clone https://github.com/JakeLin/SwiftLanguageWeather.git
+```
+
+2) Install pods
+
+```bash
+$ cd SwiftLanguageWeather
+$ pod install
+```
+
+3) Open the workspace in Xcode
+
+```bash
+$ open "SwiftWeather.xcworkspace"
+```
+
+4) Sign up on [openweathermap.org/appid](http://openweathermap.org/appid) to get an appid
+
+```bash
+$ mkdir .access_tokens
+$ echo "your-openweathermap-appid" > .access_tokens/openweathermap
+```
+*Please replace "your-openweathermap-appid" with your actual appid key.*
+
+5) Compile and run the app in your simulator
+
+6) If you don't see any data, please check "Simulator" -> "Debug" -> "Location" to change the location.
+
+# Requirements
+
+* Xcode 9
+* iOS 10+
+* Swift 4
+
+
diff --git a/README.v1.md b/README.v1.md
new file mode 100644
index 0000000..4a780c8
--- /dev/null
+++ b/README.v1.md
@@ -0,0 +1,50 @@
+Swift Weather
+============
+
+SwiftWeather is an iOS weather app developed in Swift language. The app can support iPhone 4(s), iPhone 5(s), iPhone 6 and iPhone 6 Plus.
+
+## Screenshots
+
+
+
+
+
+#### iPhone 4s
+
+
+#### iPhone 5s
+
+
+
+#### iPhone 6
+
+
+
+#### iPhone 6 Plus
+
+
+## Notices
+Because Apple keeps changing the Swift compiler, the current version can be compiled in Xcode 6.1.
+
+## Used features
+* Swift Programming Language
+* CocoaPods
+* AFNetworking
+* Core Location
+
+
+## How to build
+Because the app uses CocoaPods, we need to run `pod install` to install all the pods.
+
+1. Open Terminal app.
+2. Change directory to the project folder. `cd $project_dir`
+3. Use `ls` to list all the file to check whether *Podfile* file is in the folder?
+4. If the *Podfile* has been found, then execute `pod install`
+5. If the Mac OS doesn't have CocoaPods installed. Please follow [CocoaPods Getting Started](http://guides.cocoapods.org/using/getting-started.html) to install.
+6. Once complete installation, open *Swift Weather.xcworkspace* file with Xcode 6.
+7. Press *Cmd + B* to build the app.
+8. Press *Cmd + R* to run the app on Simulator.
+
+## Credits
+* Thanks to [johnsonjake](https://github.com/johnsonjake) for adding iOS 8 support and improving the UI/UX.
+* Thanks to [Marc](https://github.com/gizmou) for adding forcast feature, widget and app icon.
diff --git a/README.v2.1.md b/README.v2.1.md
new file mode 100644
index 0000000..7dd49a2
--- /dev/null
+++ b/README.v2.1.md
@@ -0,0 +1,65 @@
+Swift Weather
+============
+
+SwiftWeather is an iOS weather app developed in the Swift language. The app can support iPhone 4(s), iPhone 5(s), iPhone 6, and iPhone 6 Plus. The app also supports Today Widgets.
+
+## Notices
+The current version is working with Xcode Version 6.4 (6E35b). If you have any issues, please check the Xcode version. If there is still a problem with the supported versions, please raise an issue, thanks.
+
+## Version 2.1
+This is version 2.1. I have removed Carthage because some developers don't have a paid Apple iOS developer account and they have issues to build Carthage packages.
+
+There are two major versions of the app released before.
+
+* V1.0 - Support iOS 7+ using CocoaPods and AFNetworking. [README.v1.md](https://github.com/JakeLin/SwiftWeather/blob/master/README.v1.md) and [Release V1 - Using Cocoapods and AFNetworking](https://github.com/JakeLin/SwiftWeather/releases/tag/V1)
+* V2.0 - Support iOS 8+ using Carthage, Alamofire and SwiftyJSON. [README.v2.md](https://github.com/JakeLin/SwiftWeather/blob/master/README.v2.md) and [Release V2.0](https://github.com/JakeLin/SwiftWeather/releases/tag/v2.0)*
+
+V2.1 will be the last version to support iOS 8. I am working on Xcode 7 to support iOS 9 only features like `UIStackView`. Happy coding.
+
+## Screenshots
+
+
+
+
+
+
+
+## Used features
+* Swift Programming Language
+* [Alamofire](https://github.com/Alamofire/Alamofire)
+* [SwiftyJSON](https://github.com/SwiftyJSON/SwiftyJSON)
+* Core Location
+* Using Framework to share code between targets(app and widget).
+
+
+## How to build
+
+1) Download the repository
+
+```
+$ git clone https://github.com/JakeLin/SwiftWeather.git
+$ cd SwiftWeather
+```
+
+2) Initialize submodule dependencies
+
+```
+$ git submodule update --init --recursive
+```
+
+3) Open the project in Xcode
+
+```
+$ open "Swift Weather.xcodeproj"
+```
+
+4) Compile and run the app in your simulator
+
+# Requirements
+
+- Xcode 6.4
+- iOS 8
+
+## Credits
+* Thanks to [johnsonjake](https://github.com/johnsonjake) for adding iOS 8 support and improving the UI/UX.
+* Thanks to [Marc](https://github.com/gizmou) for adding forecast feature, widget, and app icon.
diff --git a/README.v2.md b/README.v2.md
new file mode 100644
index 0000000..1f1d7ee
--- /dev/null
+++ b/README.v2.md
@@ -0,0 +1,45 @@
+Swift Weather
+============
+
+SwiftWeather is an iOS weather app developed in Swift language. The app can support iPhone 4(s), iPhone 5(s), iPhone 6 and iPhone 6 Plus. The app also supports Today Widgets.
+
+## Notices
+The current version is working with Xcode Version 6.3 (6D570) and Version 6.3.1 (6D1002), I have been updating the app to support the lastest version of Xcode, if you have any issue, please check the Xcode version. If there is still a problem with the supported versions, please raise an issue, thanks.
+
+## Version 2
+This is version 2. I have ugraded the entire project to use [Carthage](https://github.com/Carthage/Carthage), [Alamofire](https://github.com/Alamofire/Alamofire) and [SwiftyJSON](https://github.com/SwiftyJSON/SwiftyJSON). And the app can only support iOS8+, if you want to support iOS7 or use CocoaPods and AFNetworking. Please have a look at [README.v1.md](https://github.com/JakeLin/SwiftWeather/blob/master/README.v1.md) and Release [Using Cocoapods and AFNetworking](https://github.com/JakeLin/SwiftWeather/releases/tag/V1). Happy coding.
+
+## Screenshots
+
+
+
+
+
+
+
+## Used features
+* Swift Programming Language
+* [Carthage](https://github.com/Carthage/Carthage)
+* [Alamofire](https://github.com/Alamofire/Alamofire)
+* [SwiftyJSON](https://github.com/SwiftyJSON/SwiftyJSON)
+* Core Location
+* Using Framework to share code between targets(app and widget).
+
+
+## Known issues
+Because we are using [Carthage](https://github.com/Carthage/Carthage) to build the third party packages. There are some build warings like `ld: warning: linking against dylib not safe for use in application extensions: /Build/Products/Debug-iphoneos/Alamofire.framework/Alamofire`
+
+## How to build
+Because the app uses carthage, we need to install carthage. To install the carthage tool on your system, please download and run the Carthage.pkg file for the latest [release](https://github.com/Carthage/Carthage/releases), then follow the on-screen instructions..
+
+1. Open Terminal app.
+2. Change directory to the project folder. `cd $project_dir`
+3. Use `ls` to list all the file to check whether *Cartfile* file is in the folder?
+4. If the *Cartfile* has been found, then execute `carthage update`.This will fetch dependencies into a Carthage/Checkouts folder, then build each one.
+5. On your application targets’ “General” settings tab, in the “Linked Frameworks and Libraries” section, drag and drop each framework you want to use from the Carthage/Build folder on disk. In our project, which are `Alamofire` and `SwiftyJSON`
+7. Press *Cmd + B* to build the app.
+8. Press *Cmd + R* to run the app on Simulator.
+
+## Credits
+* Thanks to [johnsonjake](https://github.com/johnsonjake) for adding iOS 8 support and improving the UI/UX.
+* Thanks to [Marc](https://github.com/gizmou) for adding forcast feature, widget and app icon.
diff --git a/Swift Weather Instant/MainInterface.storyboard b/Swift Weather Instant/MainInterface.storyboard
deleted file mode 100644
index 871694a..0000000
--- a/Swift Weather Instant/MainInterface.storyboard
+++ /dev/null
@@ -1,206 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/Swift Weather Instant/Swift Weather Instant-Bridging-Header.h b/Swift Weather Instant/Swift Weather Instant-Bridging-Header.h
deleted file mode 100644
index 6de8b15..0000000
--- a/Swift Weather Instant/Swift Weather Instant-Bridging-Header.h
+++ /dev/null
@@ -1,5 +0,0 @@
-//
-// Use this file to import your target's public headers that you would like to expose to Swift.
-//
-
-#import
\ No newline at end of file
diff --git a/Swift Weather Instant/TodayViewController.swift b/Swift Weather Instant/TodayViewController.swift
deleted file mode 100644
index 78201f5..0000000
--- a/Swift Weather Instant/TodayViewController.swift
+++ /dev/null
@@ -1,274 +0,0 @@
-//
-// TodayViewController.swift
-// Swift Weather Instant
-//
-// Created by Marc Tarnutzer on 12.12.14.
-// Copyright (c) 2014 rushjet. All rights reserved.
-//
-
-import UIKit
-import NotificationCenter
-import CoreLocation
-
-class TodayViewController: UIViewController, NCWidgetProviding, CLLocationManagerDelegate {
-
- let locationManager:CLLocationManager = CLLocationManager()
-
- @IBOutlet weak var time1: UILabel!
- @IBOutlet weak var time2: UILabel!
- @IBOutlet weak var time3: UILabel!
- @IBOutlet weak var time4: UILabel!
- @IBOutlet weak var image1: UIImageView!
- @IBOutlet weak var image2: UIImageView!
- @IBOutlet weak var image3: UIImageView!
- @IBOutlet weak var image4: UIImageView!
- @IBOutlet weak var temp1: UILabel!
- @IBOutlet weak var temp2: UILabel!
- @IBOutlet weak var temp3: UILabel!
- @IBOutlet weak var temp4: UILabel!
-
- override func viewDidLoad() {
- super.viewDidLoad()
-
- locationManager.delegate = self
- locationManager.desiredAccuracy = kCLLocationAccuracyBest
-
- if ( ios8() ) {
- locationManager.requestAlwaysAuthorization()
- }
- locationManager.startUpdatingLocation()
- }
-
- func updateWeatherInfo(latitude: CLLocationDegrees, longitude: CLLocationDegrees) {
- let manager = AFHTTPRequestOperationManager()
-
- let url = "http://api.openweathermap.org/data/2.5/forecast"
- println(url)
-
- let params = ["lat":latitude, "lon":longitude]
- println(params)
-
- manager.GET(url,
- parameters: params,
- success: { (operation: AFHTTPRequestOperation!,
- responseObject: AnyObject!) in
- //println("JSON: " + responseObject.description!)
-
- self.updateUISuccess(responseObject as NSDictionary!)
- },
- failure: { (operation: AFHTTPRequestOperation!,
- error: NSError!) in
- println("Error: " + error.localizedDescription)
-
- })
- }
-
- func updateUISuccess(jsonResult: NSDictionary) {
-
- if let tempResult = ((jsonResult["list"]? as NSArray)[0]["main"] as NSDictionary)["temp"] as? Double {
- // If we can get the temperature from JSON correctly, we assume the rest of JSON is correct.
- var temperature: Double
- var cntry: String
- cntry = ""
-
- if let weatherArray = (jsonResult["list"]? as? NSArray) {
- for index in 1...4 {
- if let perTime = (weatherArray[index] as? NSDictionary) {
- if let main = (perTime["main"]? as? NSDictionary) {
- var temp = (main["temp"] as Double)
- if (cntry == "US") {
- // Convert temperature to Fahrenheit if user is within the US
- temperature = round(((temp - 273.15) * 1.8) + 32)
- }
- else {
- // Otherwise, convert temperature to Celsius
- temperature = round(temp - 273.15)
- }
-
- if (index==1) {
- self.temp1.text = "\(temperature)°"
- }
- if (index==2) {
- self.temp2.text = "\(temperature)°"
- }
- if (index==3) {
- self.temp3.text = "\(temperature)°"
- }
- if (index==4) {
- self.temp4.text = "\(temperature)°"
- }
- }
- var dateFormatter = NSDateFormatter()
- dateFormatter.dateFormat = "HH:mm"
- if let date = (perTime["dt"]? as? Double) {
- let thisDate = NSDate(timeIntervalSince1970: date)
- let forecastTime = dateFormatter.stringFromDate(thisDate)
- if (index==1) {
- self.time1.text = forecastTime
- }
- if (index==2) {
- self.time2.text = forecastTime
- }
- if (index==3) {
- self.time3.text = forecastTime
- }
- if (index==4) {
- self.time4.text = forecastTime
- }
- }
- if let weather = (perTime["weather"]? as? NSArray) {
- var condition = (weather[0] as NSDictionary)["id"] as Int
- var icon = (weather[0] as NSDictionary)["icon"] as String
- var nightTime = false
- if icon.rangeOfString("n") != nil{
- nightTime = true
- }
- self.updateWeatherIcon(condition, nightTime: nightTime, index: index)
- if (index==4) {
- return
- }
-
- }
- }
- }
- }
- }
- }
-
- func updatePictures(index: Int, name: String) {
-
- if (index==1) {
- self.image1.image = UIImage(named: name)
- }
- if (index==2) {
- self.image2.image = UIImage(named: name)
- }
- if (index==3) {
- self.image3.image = UIImage(named: name)
- }
- if (index==4) {
- self.image4.image = UIImage(named: name)
- }
- }
-
- func updateWeatherIcon(condition: Int, nightTime: Bool, index: Int) {
- // Thunderstorm
-
- var images = [self.image1.image, self.image2.image, self.image3.image, self.image4.image]
-
- if (condition < 300) {
- if nightTime {
- self.updatePictures(index, name: "tstorm1_night")
- } else {
- self.updatePictures(index, name: "tstorm1")
- }
- }
- // Drizzle
- else if (condition < 500) {
- self.updatePictures(index, name: "light_rain")
-
- }
- // Rain / Freezing rain / Shower rain
- else if (condition < 600) {
- self.updatePictures(index, name: "shower3")
- }
- // Snow
- else if (condition < 700) {
- self.updatePictures(index, name: "snow4")
- }
- // Fog / Mist / Haze / etc.
- else if (condition < 771) {
- if nightTime {
- self.updatePictures(index, name: "fog_night")
- } else {
- self.updatePictures(index, name: "fog")
- }
- }
- // Tornado / Squalls
- else if (condition < 800) {
- self.updatePictures(index, name: "tstorm3")
- }
- // Sky is clear
- else if (condition == 800) {
- if (nightTime){
- self.updatePictures(index, name: "sunny_night")
- }
- else {
- self.updatePictures(index, name: "sunny")
- }
- }
- // few / scattered / broken clouds
- else if (condition < 804) {
- if (nightTime){
- self.updatePictures(index, name: "cloudy2_night")
- }
- else{
- self.updatePictures(index, name: "cloudy2")
- }
- }
- // overcast clouds
- else if (condition == 804) {
- self.updatePictures(index, name: "overcast")
- }
- // Extreme
- else if ((condition >= 900 && condition < 903) || (condition > 904 && condition < 1000)) {
- self.updatePictures(index, name: "tstorm3")
- }
- // Cold
- else if (condition == 903) {
- self.updatePictures(index, name: "snow5")
- }
- // Hot
- else if (condition == 904) {
- self.updatePictures(index, name: "sunny")
- }
- // Weather condition is not available
- else {
- self.updatePictures(index, name: "dunno")
- }
- }
-
- /*
- iOS 8 Utility
- */
- func ios8() -> Bool {
- if ( NSFoundationVersionNumber <= NSFoundationVersionNumber_iOS_7_1 ) {
- return false
- } else {
- return true
- }
- }
-
- //CLLocationManagerDelegate
- func locationManager(manager: CLLocationManager!, didUpdateLocations locations: [AnyObject]!) {
- var location:CLLocation = locations[locations.count-1] as CLLocation
-
- if (location.horizontalAccuracy > 0) {
- self.locationManager.stopUpdatingLocation()
- println(location.coordinate)
- updateWeatherInfo(location.coordinate.latitude, longitude: location.coordinate.longitude)
- }
- }
-
- func locationManager(manager: CLLocationManager!, didFailWithError error: NSError!) {
- println(error)
- }
-
-
- override func didReceiveMemoryWarning() {
- super.didReceiveMemoryWarning()
- // Dispose of any resources that can be recreated.
- }
-
- func widgetPerformUpdateWithCompletionHandler(completionHandler: ((NCUpdateResult) -> Void)!) {
- // Perform any setup necessary in order to update the view.
-
- // If an error is encountered, use NCUpdateResult.Failed
- // If there's no update required, use NCUpdateResult.NoData
- // If there's an update, use NCUpdateResult.NewData
-
- locationManager.startUpdatingLocation()
- completionHandler(NCUpdateResult.NewData)
- }
-
-}
diff --git a/Swift Weather.xcodeproj/project.pbxproj b/Swift Weather.xcodeproj/project.pbxproj
deleted file mode 100644
index 2879a8a..0000000
--- a/Swift Weather.xcodeproj/project.pbxproj
+++ /dev/null
@@ -1,735 +0,0 @@
-// !$*UTF8*$!
-{
- archiveVersion = 1;
- classes = {
- };
- objectVersion = 46;
- objects = {
-
-/* Begin PBXBuildFile section */
- 2310F50D8A3E4C249F761AE7 /* libPods.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 398F769C3A054C82877812B1 /* libPods.a */; };
- 232FF1B4193F320D007015C4 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 232FF1B3193F320D007015C4 /* AppDelegate.swift */; };
- 232FF1B6193F320D007015C4 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 232FF1B5193F320D007015C4 /* ViewController.swift */; };
- 232FF1B9193F320D007015C4 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 232FF1B7193F320D007015C4 /* Main.storyboard */; };
- 232FF1BB193F320D007015C4 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 232FF1BA193F320D007015C4 /* Images.xcassets */; };
- 232FF1C7193F320D007015C4 /* Swift_WeatherTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 232FF1C6193F320D007015C4 /* Swift_WeatherTests.swift */; };
- 3442BAAF1A3BE73400139CDC /* libPods.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 3442BAAE1A3BE73400139CDC /* libPods.a */; };
- 3442BAB31A3BF5D300139CDC /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 232FF1BA193F320D007015C4 /* Images.xcassets */; };
- 344C735C1A3B92A4002CB13B /* NotificationCenter.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 344C735B1A3B92A4002CB13B /* NotificationCenter.framework */; };
- 344C73611A3B92A4002CB13B /* TodayViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 344C73601A3B92A4002CB13B /* TodayViewController.swift */; };
- 344C73631A3B92A4002CB13B /* MainInterface.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 344C73621A3B92A4002CB13B /* MainInterface.storyboard */; };
- 344C73661A3B92A4002CB13B /* Swift Weather Instant.appex in Embed App Extensions */ = {isa = PBXBuildFile; fileRef = 344C735A1A3B92A4002CB13B /* Swift Weather Instant.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
- E10D3FA5194A170F00769A84 /* Cloud-Refresh.png in Resources */ = {isa = PBXBuildFile; fileRef = E10D3FA4194A170F00769A84 /* Cloud-Refresh.png */; };
- E12DE1EB194A0CFF00056102 /* background_summer.png in Resources */ = {isa = PBXBuildFile; fileRef = E12DE1EA194A0CFF00056102 /* background_summer.png */; };
- E1A5708D194A11F700708955 /* tstorm1_night.png in Resources */ = {isa = PBXBuildFile; fileRef = E1A5708B194A11F700708955 /* tstorm1_night.png */; };
- E1A5708E194A11F700708955 /* tstorm1.png in Resources */ = {isa = PBXBuildFile; fileRef = E1A5708C194A11F700708955 /* tstorm1.png */; };
- E1A57090194A128C00708955 /* light_rain.png in Resources */ = {isa = PBXBuildFile; fileRef = E1A5708F194A128C00708955 /* light_rain.png */; };
- E1A57093194A131100708955 /* fog_night.png in Resources */ = {isa = PBXBuildFile; fileRef = E1A57091194A131100708955 /* fog_night.png */; };
- E1A57094194A131100708955 /* fog.png in Resources */ = {isa = PBXBuildFile; fileRef = E1A57092194A131100708955 /* fog.png */; };
- E1A57096194A135400708955 /* shower3.png in Resources */ = {isa = PBXBuildFile; fileRef = E1A57095194A135400708955 /* shower3.png */; };
- E1A57098194A137600708955 /* snow5.png in Resources */ = {isa = PBXBuildFile; fileRef = E1A57097194A137600708955 /* snow5.png */; };
- E1A5709A194A139700708955 /* tstorm3.png in Resources */ = {isa = PBXBuildFile; fileRef = E1A57099194A139700708955 /* tstorm3.png */; };
- E1A5709C194A13AC00708955 /* sunny.png in Resources */ = {isa = PBXBuildFile; fileRef = E1A5709B194A13AC00708955 /* sunny.png */; };
- E1A5709E194A13B800708955 /* sunny_night.png in Resources */ = {isa = PBXBuildFile; fileRef = E1A5709D194A13B800708955 /* sunny_night.png */; };
- E1A570A1194A140100708955 /* cloudy2_night.png in Resources */ = {isa = PBXBuildFile; fileRef = E1A5709F194A140100708955 /* cloudy2_night.png */; };
- E1A570A2194A140100708955 /* cloudy2.png in Resources */ = {isa = PBXBuildFile; fileRef = E1A570A0194A140100708955 /* cloudy2.png */; };
- E1A570A4194A142B00708955 /* overcast.png in Resources */ = {isa = PBXBuildFile; fileRef = E1A570A3194A142B00708955 /* overcast.png */; };
- E1A570A6194A146200708955 /* snow4.png in Resources */ = {isa = PBXBuildFile; fileRef = E1A570A5194A146200708955 /* snow4.png */; };
- E1A570A8194A148D00708955 /* dunno.png in Resources */ = {isa = PBXBuildFile; fileRef = E1A570A7194A148D00708955 /* dunno.png */; };
- E1C9689E194A07510045500E /* background.png in Resources */ = {isa = PBXBuildFile; fileRef = E1C9689D194A07510045500E /* background.png */; };
-/* End PBXBuildFile section */
-
-/* Begin PBXContainerItemProxy section */
- 232FF1C1193F320D007015C4 /* PBXContainerItemProxy */ = {
- isa = PBXContainerItemProxy;
- containerPortal = 232FF1A6193F320C007015C4 /* Project object */;
- proxyType = 1;
- remoteGlobalIDString = 232FF1AD193F320D007015C4;
- remoteInfo = "Swift Weather";
- };
- 344C73641A3B92A4002CB13B /* PBXContainerItemProxy */ = {
- isa = PBXContainerItemProxy;
- containerPortal = 232FF1A6193F320C007015C4 /* Project object */;
- proxyType = 1;
- remoteGlobalIDString = 344C73591A3B92A4002CB13B;
- remoteInfo = "Swift Weather Instant";
- };
-/* End PBXContainerItemProxy section */
-
-/* Begin PBXCopyFilesBuildPhase section */
- 344C736A1A3B92A4002CB13B /* Embed App Extensions */ = {
- isa = PBXCopyFilesBuildPhase;
- buildActionMask = 2147483647;
- dstPath = "";
- dstSubfolderSpec = 13;
- files = (
- 344C73661A3B92A4002CB13B /* Swift Weather Instant.appex in Embed App Extensions */,
- );
- name = "Embed App Extensions";
- runOnlyForDeploymentPostprocessing = 0;
- };
-/* End PBXCopyFilesBuildPhase section */
-
-/* Begin PBXFileReference section */
- 06E8C19B175E2E99642E6B61 /* Pods.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = Pods.release.xcconfig; path = "Pods/Target Support Files/Pods/Pods.release.xcconfig"; sourceTree = ""; };
- 232FF1AE193F320D007015C4 /* Swift Weather.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "Swift Weather.app"; sourceTree = BUILT_PRODUCTS_DIR; };
- 232FF1B2193F320D007015C4 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
- 232FF1B3193F320D007015C4 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; };
- 232FF1B5193F320D007015C4 /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = ""; };
- 232FF1B8193F320D007015C4 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; };
- 232FF1BA193F320D007015C4 /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = ""; };
- 232FF1C0193F320D007015C4 /* Swift WeatherTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "Swift WeatherTests.xctest"; sourceTree = BUILT_PRODUCTS_DIR; };
- 232FF1C5193F320D007015C4 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
- 232FF1C6193F320D007015C4 /* Swift_WeatherTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Swift_WeatherTests.swift; sourceTree = ""; };
- 232FF1D0193F3346007015C4 /* SwiftWeather-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "SwiftWeather-Bridging-Header.h"; sourceTree = ""; };
- 3442BAAE1A3BE73400139CDC /* libPods.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libPods.a; path = "Pods/build/Debug-iphoneos/libPods.a"; sourceTree = ""; };
- 3442BAB01A3BE88A00139CDC /* Swift Weather Instant-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Swift Weather Instant-Bridging-Header.h"; sourceTree = ""; };
- 344C735A1A3B92A4002CB13B /* Swift Weather Instant.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = "Swift Weather Instant.appex"; sourceTree = BUILT_PRODUCTS_DIR; };
- 344C735B1A3B92A4002CB13B /* NotificationCenter.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = NotificationCenter.framework; path = System/Library/Frameworks/NotificationCenter.framework; sourceTree = SDKROOT; };
- 344C735F1A3B92A4002CB13B /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
- 344C73601A3B92A4002CB13B /* TodayViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TodayViewController.swift; sourceTree = ""; };
- 344C73621A3B92A4002CB13B /* MainInterface.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = MainInterface.storyboard; sourceTree = ""; };
- 398F769C3A054C82877812B1 /* libPods.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libPods.a; sourceTree = BUILT_PRODUCTS_DIR; };
- 741F0930ADAB139D5441794C /* Pods.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = Pods.debug.xcconfig; path = "Pods/Target Support Files/Pods/Pods.debug.xcconfig"; sourceTree = ""; };
- E10D3FA4194A170F00769A84 /* Cloud-Refresh.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Cloud-Refresh.png"; sourceTree = ""; };
- E12DE1EA194A0CFF00056102 /* background_summer.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = background_summer.png; sourceTree = ""; };
- E1A5708B194A11F700708955 /* tstorm1_night.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = tstorm1_night.png; sourceTree = ""; };
- E1A5708C194A11F700708955 /* tstorm1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = tstorm1.png; sourceTree = ""; };
- E1A5708F194A128C00708955 /* light_rain.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = light_rain.png; sourceTree = ""; };
- E1A57091194A131100708955 /* fog_night.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = fog_night.png; sourceTree = ""; };
- E1A57092194A131100708955 /* fog.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = fog.png; sourceTree = ""; };
- E1A57095194A135400708955 /* shower3.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = shower3.png; sourceTree = ""; };
- E1A57097194A137600708955 /* snow5.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = snow5.png; sourceTree = ""; };
- E1A57099194A139700708955 /* tstorm3.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = tstorm3.png; sourceTree = ""; };
- E1A5709B194A13AC00708955 /* sunny.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = sunny.png; sourceTree = ""; };
- E1A5709D194A13B800708955 /* sunny_night.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = sunny_night.png; sourceTree = ""; };
- E1A5709F194A140100708955 /* cloudy2_night.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = cloudy2_night.png; sourceTree = ""; };
- E1A570A0194A140100708955 /* cloudy2.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = cloudy2.png; sourceTree = ""; };
- E1A570A3194A142B00708955 /* overcast.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = overcast.png; sourceTree = ""; };
- E1A570A5194A146200708955 /* snow4.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = snow4.png; sourceTree = ""; };
- E1A570A7194A148D00708955 /* dunno.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = dunno.png; sourceTree = ""; };
- E1C9689D194A07510045500E /* background.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = background.png; sourceTree = ""; };
-/* End PBXFileReference section */
-
-/* Begin PBXFrameworksBuildPhase section */
- 232FF1AB193F320D007015C4 /* Frameworks */ = {
- isa = PBXFrameworksBuildPhase;
- buildActionMask = 2147483647;
- files = (
- 2310F50D8A3E4C249F761AE7 /* libPods.a in Frameworks */,
- );
- runOnlyForDeploymentPostprocessing = 0;
- };
- 232FF1BD193F320D007015C4 /* Frameworks */ = {
- isa = PBXFrameworksBuildPhase;
- buildActionMask = 2147483647;
- files = (
- );
- runOnlyForDeploymentPostprocessing = 0;
- };
- 344C73571A3B92A4002CB13B /* Frameworks */ = {
- isa = PBXFrameworksBuildPhase;
- buildActionMask = 2147483647;
- files = (
- 3442BAAF1A3BE73400139CDC /* libPods.a in Frameworks */,
- 344C735C1A3B92A4002CB13B /* NotificationCenter.framework in Frameworks */,
- );
- runOnlyForDeploymentPostprocessing = 0;
- };
-/* End PBXFrameworksBuildPhase section */
-
-/* Begin PBXGroup section */
- 128ACBBD2E004856867FDAD7 /* Frameworks */ = {
- isa = PBXGroup;
- children = (
- 3442BAAE1A3BE73400139CDC /* libPods.a */,
- 398F769C3A054C82877812B1 /* libPods.a */,
- 344C735B1A3B92A4002CB13B /* NotificationCenter.framework */,
- );
- name = Frameworks;
- sourceTree = "";
- };
- 230CFCDE193FDCBF001D6F21 /* images */ = {
- isa = PBXGroup;
- children = (
- E10D3FA4194A170F00769A84 /* Cloud-Refresh.png */,
- E1A570A7194A148D00708955 /* dunno.png */,
- E1A570A5194A146200708955 /* snow4.png */,
- E1A570A3194A142B00708955 /* overcast.png */,
- E1A5709F194A140100708955 /* cloudy2_night.png */,
- E1A570A0194A140100708955 /* cloudy2.png */,
- E1A5709D194A13B800708955 /* sunny_night.png */,
- E1A5709B194A13AC00708955 /* sunny.png */,
- E1A57099194A139700708955 /* tstorm3.png */,
- E1A57097194A137600708955 /* snow5.png */,
- E1A57095194A135400708955 /* shower3.png */,
- E1A57091194A131100708955 /* fog_night.png */,
- E1A57092194A131100708955 /* fog.png */,
- E1A5708F194A128C00708955 /* light_rain.png */,
- E1A5708B194A11F700708955 /* tstorm1_night.png */,
- E1A5708C194A11F700708955 /* tstorm1.png */,
- );
- path = images;
- sourceTree = "";
- };
- 232FF1A5193F320C007015C4 = {
- isa = PBXGroup;
- children = (
- 232FF1B0193F320D007015C4 /* Swift Weather */,
- 232FF1C3193F320D007015C4 /* Swift WeatherTests */,
- 344C735D1A3B92A4002CB13B /* Swift Weather Instant */,
- 232FF1AF193F320D007015C4 /* Products */,
- 128ACBBD2E004856867FDAD7 /* Frameworks */,
- FDE706C161C9E8FA9C9264A3 /* Pods */,
- );
- sourceTree = "";
- };
- 232FF1AF193F320D007015C4 /* Products */ = {
- isa = PBXGroup;
- children = (
- 232FF1AE193F320D007015C4 /* Swift Weather.app */,
- 232FF1C0193F320D007015C4 /* Swift WeatherTests.xctest */,
- 344C735A1A3B92A4002CB13B /* Swift Weather Instant.appex */,
- );
- name = Products;
- sourceTree = "";
- };
- 232FF1B0193F320D007015C4 /* Swift Weather */ = {
- isa = PBXGroup;
- children = (
- 232FF1B3193F320D007015C4 /* AppDelegate.swift */,
- 232FF1B5193F320D007015C4 /* ViewController.swift */,
- 232FF1B7193F320D007015C4 /* Main.storyboard */,
- 232FF1D0193F3346007015C4 /* SwiftWeather-Bridging-Header.h */,
- 232FF1BA193F320D007015C4 /* Images.xcassets */,
- 230CFCDE193FDCBF001D6F21 /* images */,
- 232FF1B1193F320D007015C4 /* Supporting Files */,
- );
- path = "Swift Weather";
- sourceTree = "";
- };
- 232FF1B1193F320D007015C4 /* Supporting Files */ = {
- isa = PBXGroup;
- children = (
- E12DE1EA194A0CFF00056102 /* background_summer.png */,
- E1C9689D194A07510045500E /* background.png */,
- 232FF1B2193F320D007015C4 /* Info.plist */,
- );
- name = "Supporting Files";
- sourceTree = "";
- };
- 232FF1C3193F320D007015C4 /* Swift WeatherTests */ = {
- isa = PBXGroup;
- children = (
- 232FF1C6193F320D007015C4 /* Swift_WeatherTests.swift */,
- 232FF1C4193F320D007015C4 /* Supporting Files */,
- );
- path = "Swift WeatherTests";
- sourceTree = "";
- };
- 232FF1C4193F320D007015C4 /* Supporting Files */ = {
- isa = PBXGroup;
- children = (
- 232FF1C5193F320D007015C4 /* Info.plist */,
- );
- name = "Supporting Files";
- sourceTree = "";
- };
- 344C735D1A3B92A4002CB13B /* Swift Weather Instant */ = {
- isa = PBXGroup;
- children = (
- 344C73601A3B92A4002CB13B /* TodayViewController.swift */,
- 344C73621A3B92A4002CB13B /* MainInterface.storyboard */,
- 344C735E1A3B92A4002CB13B /* Supporting Files */,
- 3442BAB01A3BE88A00139CDC /* Swift Weather Instant-Bridging-Header.h */,
- );
- path = "Swift Weather Instant";
- sourceTree = "";
- };
- 344C735E1A3B92A4002CB13B /* Supporting Files */ = {
- isa = PBXGroup;
- children = (
- 344C735F1A3B92A4002CB13B /* Info.plist */,
- );
- name = "Supporting Files";
- sourceTree = "";
- };
- FDE706C161C9E8FA9C9264A3 /* Pods */ = {
- isa = PBXGroup;
- children = (
- 741F0930ADAB139D5441794C /* Pods.debug.xcconfig */,
- 06E8C19B175E2E99642E6B61 /* Pods.release.xcconfig */,
- );
- name = Pods;
- sourceTree = "";
- };
-/* End PBXGroup section */
-
-/* Begin PBXNativeTarget section */
- 232FF1AD193F320D007015C4 /* Swift Weather */ = {
- isa = PBXNativeTarget;
- buildConfigurationList = 232FF1CA193F320D007015C4 /* Build configuration list for PBXNativeTarget "Swift Weather" */;
- buildPhases = (
- 6C16E3CD13AF4DDE8CD9CBD5 /* Check Pods Manifest.lock */,
- 232FF1AA193F320D007015C4 /* Sources */,
- 232FF1AB193F320D007015C4 /* Frameworks */,
- 232FF1AC193F320D007015C4 /* Resources */,
- D599F504738F419D978D2F6C /* Copy Pods Resources */,
- 344C736A1A3B92A4002CB13B /* Embed App Extensions */,
- );
- buildRules = (
- );
- dependencies = (
- 344C73651A3B92A4002CB13B /* PBXTargetDependency */,
- );
- name = "Swift Weather";
- productName = "Swift Weather";
- productReference = 232FF1AE193F320D007015C4 /* Swift Weather.app */;
- productType = "com.apple.product-type.application";
- };
- 232FF1BF193F320D007015C4 /* Swift WeatherTests */ = {
- isa = PBXNativeTarget;
- buildConfigurationList = 232FF1CD193F320D007015C4 /* Build configuration list for PBXNativeTarget "Swift WeatherTests" */;
- buildPhases = (
- 232FF1BC193F320D007015C4 /* Sources */,
- 232FF1BD193F320D007015C4 /* Frameworks */,
- 232FF1BE193F320D007015C4 /* Resources */,
- );
- buildRules = (
- );
- dependencies = (
- 232FF1C2193F320D007015C4 /* PBXTargetDependency */,
- );
- name = "Swift WeatherTests";
- productName = "Swift WeatherTests";
- productReference = 232FF1C0193F320D007015C4 /* Swift WeatherTests.xctest */;
- productType = "com.apple.product-type.bundle.unit-test";
- };
- 344C73591A3B92A4002CB13B /* Swift Weather Instant */ = {
- isa = PBXNativeTarget;
- buildConfigurationList = 344C73691A3B92A4002CB13B /* Build configuration list for PBXNativeTarget "Swift Weather Instant" */;
- buildPhases = (
- 344C73561A3B92A4002CB13B /* Sources */,
- 344C73571A3B92A4002CB13B /* Frameworks */,
- 344C73581A3B92A4002CB13B /* Resources */,
- );
- buildRules = (
- );
- dependencies = (
- );
- name = "Swift Weather Instant";
- productName = "Swift Weather Instant";
- productReference = 344C735A1A3B92A4002CB13B /* Swift Weather Instant.appex */;
- productType = "com.apple.product-type.app-extension";
- };
-/* End PBXNativeTarget section */
-
-/* Begin PBXProject section */
- 232FF1A6193F320C007015C4 /* Project object */ = {
- isa = PBXProject;
- attributes = {
- LastUpgradeCheck = 0600;
- ORGANIZATIONNAME = rushjet;
- TargetAttributes = {
- 232FF1AD193F320D007015C4 = {
- CreatedOnToolsVersion = 6.0;
- DevelopmentTeam = 964HJ5SV2F;
- };
- 232FF1BF193F320D007015C4 = {
- CreatedOnToolsVersion = 6.0;
- DevelopmentTeam = 964HJ5SV2F;
- TestTargetID = 232FF1AD193F320D007015C4;
- };
- 344C73591A3B92A4002CB13B = {
- CreatedOnToolsVersion = 6.1.1;
- DevelopmentTeam = 964HJ5SV2F;
- };
- };
- };
- buildConfigurationList = 232FF1A9193F320D007015C4 /* Build configuration list for PBXProject "Swift Weather" */;
- compatibilityVersion = "Xcode 3.2";
- developmentRegion = English;
- hasScannedForEncodings = 0;
- knownRegions = (
- en,
- Base,
- );
- mainGroup = 232FF1A5193F320C007015C4;
- productRefGroup = 232FF1AF193F320D007015C4 /* Products */;
- projectDirPath = "";
- projectRoot = "";
- targets = (
- 232FF1AD193F320D007015C4 /* Swift Weather */,
- 232FF1BF193F320D007015C4 /* Swift WeatherTests */,
- 344C73591A3B92A4002CB13B /* Swift Weather Instant */,
- );
- };
-/* End PBXProject section */
-
-/* Begin PBXResourcesBuildPhase section */
- 232FF1AC193F320D007015C4 /* Resources */ = {
- isa = PBXResourcesBuildPhase;
- buildActionMask = 2147483647;
- files = (
- E1A570A2194A140100708955 /* cloudy2.png in Resources */,
- E12DE1EB194A0CFF00056102 /* background_summer.png in Resources */,
- E1A57093194A131100708955 /* fog_night.png in Resources */,
- E1A57096194A135400708955 /* shower3.png in Resources */,
- E1A570A4194A142B00708955 /* overcast.png in Resources */,
- E1A5709E194A13B800708955 /* sunny_night.png in Resources */,
- E1A570A1194A140100708955 /* cloudy2_night.png in Resources */,
- E1A570A6194A146200708955 /* snow4.png in Resources */,
- E1A57094194A131100708955 /* fog.png in Resources */,
- E1A5708E194A11F700708955 /* tstorm1.png in Resources */,
- E1A57090194A128C00708955 /* light_rain.png in Resources */,
- E1A5709C194A13AC00708955 /* sunny.png in Resources */,
- E1C9689E194A07510045500E /* background.png in Resources */,
- E1A570A8194A148D00708955 /* dunno.png in Resources */,
- E1A57098194A137600708955 /* snow5.png in Resources */,
- E10D3FA5194A170F00769A84 /* Cloud-Refresh.png in Resources */,
- 232FF1B9193F320D007015C4 /* Main.storyboard in Resources */,
- 232FF1BB193F320D007015C4 /* Images.xcassets in Resources */,
- E1A5709A194A139700708955 /* tstorm3.png in Resources */,
- E1A5708D194A11F700708955 /* tstorm1_night.png in Resources */,
- );
- runOnlyForDeploymentPostprocessing = 0;
- };
- 232FF1BE193F320D007015C4 /* Resources */ = {
- isa = PBXResourcesBuildPhase;
- buildActionMask = 2147483647;
- files = (
- );
- runOnlyForDeploymentPostprocessing = 0;
- };
- 344C73581A3B92A4002CB13B /* Resources */ = {
- isa = PBXResourcesBuildPhase;
- buildActionMask = 2147483647;
- files = (
- 344C73631A3B92A4002CB13B /* MainInterface.storyboard in Resources */,
- 3442BAB31A3BF5D300139CDC /* Images.xcassets in Resources */,
- );
- runOnlyForDeploymentPostprocessing = 0;
- };
-/* End PBXResourcesBuildPhase section */
-
-/* Begin PBXShellScriptBuildPhase section */
- 6C16E3CD13AF4DDE8CD9CBD5 /* Check Pods Manifest.lock */ = {
- isa = PBXShellScriptBuildPhase;
- buildActionMask = 2147483647;
- files = (
- );
- inputPaths = (
- );
- name = "Check Pods Manifest.lock";
- outputPaths = (
- );
- runOnlyForDeploymentPostprocessing = 0;
- shellPath = /bin/sh;
- shellScript = "diff \"${PODS_ROOT}/../Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [[ $? != 0 ]] ; then\n cat << EOM\nerror: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\nEOM\n exit 1\nfi\n";
- showEnvVarsInLog = 0;
- };
- D599F504738F419D978D2F6C /* Copy Pods Resources */ = {
- isa = PBXShellScriptBuildPhase;
- buildActionMask = 2147483647;
- files = (
- );
- inputPaths = (
- );
- name = "Copy Pods Resources";
- outputPaths = (
- );
- runOnlyForDeploymentPostprocessing = 0;
- shellPath = /bin/sh;
- shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods/Pods-resources.sh\"\n";
- showEnvVarsInLog = 0;
- };
-/* End PBXShellScriptBuildPhase section */
-
-/* Begin PBXSourcesBuildPhase section */
- 232FF1AA193F320D007015C4 /* Sources */ = {
- isa = PBXSourcesBuildPhase;
- buildActionMask = 2147483647;
- files = (
- 232FF1B6193F320D007015C4 /* ViewController.swift in Sources */,
- 232FF1B4193F320D007015C4 /* AppDelegate.swift in Sources */,
- );
- runOnlyForDeploymentPostprocessing = 0;
- };
- 232FF1BC193F320D007015C4 /* Sources */ = {
- isa = PBXSourcesBuildPhase;
- buildActionMask = 2147483647;
- files = (
- 232FF1C7193F320D007015C4 /* Swift_WeatherTests.swift in Sources */,
- );
- runOnlyForDeploymentPostprocessing = 0;
- };
- 344C73561A3B92A4002CB13B /* Sources */ = {
- isa = PBXSourcesBuildPhase;
- buildActionMask = 2147483647;
- files = (
- 344C73611A3B92A4002CB13B /* TodayViewController.swift in Sources */,
- );
- runOnlyForDeploymentPostprocessing = 0;
- };
-/* End PBXSourcesBuildPhase section */
-
-/* Begin PBXTargetDependency section */
- 232FF1C2193F320D007015C4 /* PBXTargetDependency */ = {
- isa = PBXTargetDependency;
- target = 232FF1AD193F320D007015C4 /* Swift Weather */;
- targetProxy = 232FF1C1193F320D007015C4 /* PBXContainerItemProxy */;
- };
- 344C73651A3B92A4002CB13B /* PBXTargetDependency */ = {
- isa = PBXTargetDependency;
- target = 344C73591A3B92A4002CB13B /* Swift Weather Instant */;
- targetProxy = 344C73641A3B92A4002CB13B /* PBXContainerItemProxy */;
- };
-/* End PBXTargetDependency section */
-
-/* Begin PBXVariantGroup section */
- 232FF1B7193F320D007015C4 /* Main.storyboard */ = {
- isa = PBXVariantGroup;
- children = (
- 232FF1B8193F320D007015C4 /* Base */,
- );
- name = Main.storyboard;
- sourceTree = "";
- };
-/* End PBXVariantGroup section */
-
-/* Begin XCBuildConfiguration section */
- 232FF1C8193F320D007015C4 /* Debug */ = {
- isa = XCBuildConfiguration;
- buildSettings = {
- ALWAYS_SEARCH_USER_PATHS = NO;
- CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
- CLANG_CXX_LIBRARY = "libc++";
- CLANG_ENABLE_MODULES = YES;
- CLANG_ENABLE_OBJC_ARC = YES;
- CLANG_WARN_BOOL_CONVERSION = YES;
- CLANG_WARN_CONSTANT_CONVERSION = YES;
- CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
- CLANG_WARN_EMPTY_BODY = YES;
- CLANG_WARN_ENUM_CONVERSION = YES;
- CLANG_WARN_INT_CONVERSION = YES;
- CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
- CLANG_WARN_UNREACHABLE_CODE = YES;
- CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
- "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
- COPY_PHASE_STRIP = NO;
- ENABLE_STRICT_OBJC_MSGSEND = YES;
- GCC_C_LANGUAGE_STANDARD = gnu99;
- GCC_DYNAMIC_NO_PIC = NO;
- GCC_OPTIMIZATION_LEVEL = 0;
- GCC_PREPROCESSOR_DEFINITIONS = (
- "DEBUG=1",
- "$(inherited)",
- );
- GCC_SYMBOLS_PRIVATE_EXTERN = NO;
- GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
- GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
- GCC_WARN_UNDECLARED_SELECTOR = YES;
- GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
- GCC_WARN_UNUSED_FUNCTION = YES;
- GCC_WARN_UNUSED_VARIABLE = YES;
- IPHONEOS_DEPLOYMENT_TARGET = 7.1;
- METAL_ENABLE_DEBUG_INFO = YES;
- ONLY_ACTIVE_ARCH = YES;
- SDKROOT = iphoneos;
- SWIFT_OPTIMIZATION_LEVEL = "-Onone";
- };
- name = Debug;
- };
- 232FF1C9193F320D007015C4 /* Release */ = {
- isa = XCBuildConfiguration;
- buildSettings = {
- ALWAYS_SEARCH_USER_PATHS = NO;
- CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
- CLANG_CXX_LIBRARY = "libc++";
- CLANG_ENABLE_MODULES = YES;
- CLANG_ENABLE_OBJC_ARC = YES;
- CLANG_WARN_BOOL_CONVERSION = YES;
- CLANG_WARN_CONSTANT_CONVERSION = YES;
- CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
- CLANG_WARN_EMPTY_BODY = YES;
- CLANG_WARN_ENUM_CONVERSION = YES;
- CLANG_WARN_INT_CONVERSION = YES;
- CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
- CLANG_WARN_UNREACHABLE_CODE = YES;
- CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
- "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
- COPY_PHASE_STRIP = YES;
- ENABLE_NS_ASSERTIONS = NO;
- ENABLE_STRICT_OBJC_MSGSEND = YES;
- GCC_C_LANGUAGE_STANDARD = gnu99;
- GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
- GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
- GCC_WARN_UNDECLARED_SELECTOR = YES;
- GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
- GCC_WARN_UNUSED_FUNCTION = YES;
- GCC_WARN_UNUSED_VARIABLE = YES;
- IPHONEOS_DEPLOYMENT_TARGET = 7.1;
- METAL_ENABLE_DEBUG_INFO = NO;
- SDKROOT = iphoneos;
- VALIDATE_PRODUCT = YES;
- };
- name = Release;
- };
- 232FF1CB193F320D007015C4 /* Debug */ = {
- isa = XCBuildConfiguration;
- baseConfigurationReference = 741F0930ADAB139D5441794C /* Pods.debug.xcconfig */;
- buildSettings = {
- ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
- ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage;
- EMBEDDED_CONTENT_CONTAINS_SWIFT = YES;
- INFOPLIST_FILE = "Swift Weather/Info.plist";
- IPHONEOS_DEPLOYMENT_TARGET = 7.0;
- LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
- PRODUCT_NAME = "$(TARGET_NAME)";
- SWIFT_OBJC_BRIDGING_HEADER = "Swift Weather/SwiftWeather-Bridging-Header.h";
- };
- name = Debug;
- };
- 232FF1CC193F320D007015C4 /* Release */ = {
- isa = XCBuildConfiguration;
- baseConfigurationReference = 06E8C19B175E2E99642E6B61 /* Pods.release.xcconfig */;
- buildSettings = {
- ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
- ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage;
- EMBEDDED_CONTENT_CONTAINS_SWIFT = YES;
- INFOPLIST_FILE = "Swift Weather/Info.plist";
- IPHONEOS_DEPLOYMENT_TARGET = 7.0;
- LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
- PRODUCT_NAME = "$(TARGET_NAME)";
- SWIFT_OBJC_BRIDGING_HEADER = "Swift Weather/SwiftWeather-Bridging-Header.h";
- };
- name = Release;
- };
- 232FF1CE193F320D007015C4 /* Debug */ = {
- isa = XCBuildConfiguration;
- buildSettings = {
- BUNDLE_LOADER = "$(BUILT_PRODUCTS_DIR)/Swift Weather.app/Swift Weather";
- CODE_SIGN_IDENTITY = "iPhone Developer";
- "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
- FRAMEWORK_SEARCH_PATHS = (
- "$(SDKROOT)/Developer/Library/Frameworks",
- "$(inherited)",
- );
- GCC_PREPROCESSOR_DEFINITIONS = (
- "DEBUG=1",
- "$(inherited)",
- );
- INFOPLIST_FILE = "Swift WeatherTests/Info.plist";
- LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
- METAL_ENABLE_DEBUG_INFO = YES;
- PRODUCT_NAME = "$(TARGET_NAME)";
- PROVISIONING_PROFILE = "";
- TEST_HOST = "$(BUNDLE_LOADER)";
- };
- name = Debug;
- };
- 232FF1CF193F320D007015C4 /* Release */ = {
- isa = XCBuildConfiguration;
- buildSettings = {
- BUNDLE_LOADER = "$(BUILT_PRODUCTS_DIR)/Swift Weather.app/Swift Weather";
- CODE_SIGN_IDENTITY = "iPhone Developer";
- "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
- FRAMEWORK_SEARCH_PATHS = (
- "$(SDKROOT)/Developer/Library/Frameworks",
- "$(inherited)",
- );
- INFOPLIST_FILE = "Swift WeatherTests/Info.plist";
- LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
- METAL_ENABLE_DEBUG_INFO = NO;
- PRODUCT_NAME = "$(TARGET_NAME)";
- PROVISIONING_PROFILE = "";
- TEST_HOST = "$(BUNDLE_LOADER)";
- };
- name = Release;
- };
- 344C73671A3B92A4002CB13B /* Debug */ = {
- isa = XCBuildConfiguration;
- baseConfigurationReference = 741F0930ADAB139D5441794C /* Pods.debug.xcconfig */;
- buildSettings = {
- CLANG_ENABLE_MODULES = YES;
- GCC_PREPROCESSOR_DEFINITIONS = (
- "DEBUG=1",
- "$(inherited)",
- );
- INFOPLIST_FILE = "Swift Weather Instant/Info.plist";
- IPHONEOS_DEPLOYMENT_TARGET = 8.1;
- LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @executable_path/../../Frameworks";
- LIBRARY_SEARCH_PATHS = (
- "$(inherited)",
- "$(PROJECT_DIR)/Pods/build/Debug-iphoneos",
- );
- MTL_ENABLE_DEBUG_INFO = YES;
- PRODUCT_NAME = "$(TARGET_NAME)";
- SKIP_INSTALL = YES;
- SWIFT_OBJC_BRIDGING_HEADER = "Swift Weather/SwiftWeather-Bridging-Header.h";
- SWIFT_OPTIMIZATION_LEVEL = "-Onone";
- };
- name = Debug;
- };
- 344C73681A3B92A4002CB13B /* Release */ = {
- isa = XCBuildConfiguration;
- baseConfigurationReference = 06E8C19B175E2E99642E6B61 /* Pods.release.xcconfig */;
- buildSettings = {
- CLANG_ENABLE_MODULES = YES;
- INFOPLIST_FILE = "Swift Weather Instant/Info.plist";
- IPHONEOS_DEPLOYMENT_TARGET = 8.1;
- LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @executable_path/../../Frameworks";
- LIBRARY_SEARCH_PATHS = (
- "$(inherited)",
- "$(PROJECT_DIR)/Pods/build/Debug-iphoneos",
- );
- MTL_ENABLE_DEBUG_INFO = NO;
- PRODUCT_NAME = "$(TARGET_NAME)";
- SKIP_INSTALL = YES;
- SWIFT_OBJC_BRIDGING_HEADER = "Swift Weather/SwiftWeather-Bridging-Header.h";
- };
- name = Release;
- };
-/* End XCBuildConfiguration section */
-
-/* Begin XCConfigurationList section */
- 232FF1A9193F320D007015C4 /* Build configuration list for PBXProject "Swift Weather" */ = {
- isa = XCConfigurationList;
- buildConfigurations = (
- 232FF1C8193F320D007015C4 /* Debug */,
- 232FF1C9193F320D007015C4 /* Release */,
- );
- defaultConfigurationIsVisible = 0;
- defaultConfigurationName = Release;
- };
- 232FF1CA193F320D007015C4 /* Build configuration list for PBXNativeTarget "Swift Weather" */ = {
- isa = XCConfigurationList;
- buildConfigurations = (
- 232FF1CB193F320D007015C4 /* Debug */,
- 232FF1CC193F320D007015C4 /* Release */,
- );
- defaultConfigurationIsVisible = 0;
- defaultConfigurationName = Release;
- };
- 232FF1CD193F320D007015C4 /* Build configuration list for PBXNativeTarget "Swift WeatherTests" */ = {
- isa = XCConfigurationList;
- buildConfigurations = (
- 232FF1CE193F320D007015C4 /* Debug */,
- 232FF1CF193F320D007015C4 /* Release */,
- );
- defaultConfigurationIsVisible = 0;
- defaultConfigurationName = Release;
- };
- 344C73691A3B92A4002CB13B /* Build configuration list for PBXNativeTarget "Swift Weather Instant" */ = {
- isa = XCConfigurationList;
- buildConfigurations = (
- 344C73671A3B92A4002CB13B /* Debug */,
- 344C73681A3B92A4002CB13B /* Release */,
- );
- defaultConfigurationIsVisible = 0;
- defaultConfigurationName = Release;
- };
-/* End XCConfigurationList section */
- };
- rootObject = 232FF1A6193F320C007015C4 /* Project object */;
-}
diff --git a/Swift Weather.xcworkspace/contents.xcworkspacedata b/Swift Weather.xcworkspace/contents.xcworkspacedata
deleted file mode 100644
index 4f62278..0000000
--- a/Swift Weather.xcworkspace/contents.xcworkspacedata
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/Swift Weather/AppDelegate.swift b/Swift Weather/AppDelegate.swift
deleted file mode 100644
index 85d9a03..0000000
--- a/Swift Weather/AppDelegate.swift
+++ /dev/null
@@ -1,46 +0,0 @@
-//
-// AppDelegate.swift
-// Swift Weather
-//
-// Created by Jake Lin on 4/06/2014.
-// Copyright (c) 2014 rushjet. All rights reserved.
-//
-
-import UIKit
-
-@UIApplicationMain
-class AppDelegate: UIResponder, UIApplicationDelegate {
-
- var window: UIWindow?
-
-
-
- func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: NSDictionary?) -> Bool {
- // Override point for customization after application launch.
-
- return true
- }
-
- func applicationWillResignActive(application: UIApplication) {
- // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
- // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game.
- }
-
- func applicationDidEnterBackground(application: UIApplication) {
- // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
- // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
- }
-
- func applicationWillEnterForeground(application: UIApplication) {
- // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background.
- }
-
- func applicationDidBecomeActive(application: UIApplication) {
- // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
- }
-
- func applicationWillTerminate(application: UIApplication) {
- // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
- }
-}
-
diff --git a/Swift Weather/Base.lproj/Main.storyboard b/Swift Weather/Base.lproj/Main.storyboard
deleted file mode 100644
index 75cdc8a..0000000
--- a/Swift Weather/Base.lproj/Main.storyboard
+++ /dev/null
@@ -1,165 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/Swift Weather/Images.xcassets/AppIcon.appiconset/Icon-29.png b/Swift Weather/Images.xcassets/AppIcon.appiconset/Icon-29.png
deleted file mode 100644
index 5aff191..0000000
Binary files a/Swift Weather/Images.xcassets/AppIcon.appiconset/Icon-29.png and /dev/null differ
diff --git a/Swift Weather/Images.xcassets/AppIcon.appiconset/Icon-29@2x.png b/Swift Weather/Images.xcassets/AppIcon.appiconset/Icon-29@2x.png
deleted file mode 100644
index 07b81d7..0000000
Binary files a/Swift Weather/Images.xcassets/AppIcon.appiconset/Icon-29@2x.png and /dev/null differ
diff --git a/Swift Weather/Images.xcassets/AppIcon.appiconset/Icon-29@3x.png b/Swift Weather/Images.xcassets/AppIcon.appiconset/Icon-29@3x.png
deleted file mode 100644
index 526f606..0000000
Binary files a/Swift Weather/Images.xcassets/AppIcon.appiconset/Icon-29@3x.png and /dev/null differ
diff --git a/Swift Weather/Images.xcassets/AppIcon.appiconset/Icon-40.png b/Swift Weather/Images.xcassets/AppIcon.appiconset/Icon-40.png
deleted file mode 100644
index f4fc2f7..0000000
Binary files a/Swift Weather/Images.xcassets/AppIcon.appiconset/Icon-40.png and /dev/null differ
diff --git a/Swift Weather/Images.xcassets/AppIcon.appiconset/Icon-40@2x.png b/Swift Weather/Images.xcassets/AppIcon.appiconset/Icon-40@2x.png
deleted file mode 100644
index d4824cc..0000000
Binary files a/Swift Weather/Images.xcassets/AppIcon.appiconset/Icon-40@2x.png and /dev/null differ
diff --git a/Swift Weather/Images.xcassets/AppIcon.appiconset/Icon-40@3x.png b/Swift Weather/Images.xcassets/AppIcon.appiconset/Icon-40@3x.png
deleted file mode 100644
index 790bdab..0000000
Binary files a/Swift Weather/Images.xcassets/AppIcon.appiconset/Icon-40@3x.png and /dev/null differ
diff --git a/Swift Weather/Images.xcassets/AppIcon.appiconset/Icon-60@2x.png b/Swift Weather/Images.xcassets/AppIcon.appiconset/Icon-60@2x.png
deleted file mode 100644
index 790bdab..0000000
Binary files a/Swift Weather/Images.xcassets/AppIcon.appiconset/Icon-60@2x.png and /dev/null differ
diff --git a/Swift Weather/Images.xcassets/AppIcon.appiconset/Icon-60@3x.png b/Swift Weather/Images.xcassets/AppIcon.appiconset/Icon-60@3x.png
deleted file mode 100644
index fa1fd20..0000000
Binary files a/Swift Weather/Images.xcassets/AppIcon.appiconset/Icon-60@3x.png and /dev/null differ
diff --git a/Swift Weather/Images.xcassets/AppIcon.appiconset/Icon-76@2x.png b/Swift Weather/Images.xcassets/AppIcon.appiconset/Icon-76@2x.png
deleted file mode 100644
index a53afc9..0000000
Binary files a/Swift Weather/Images.xcassets/AppIcon.appiconset/Icon-76@2x.png and /dev/null differ
diff --git a/Swift Weather/Images.xcassets/AppIcon.appiconset/iTunesArtwork@2x.png b/Swift Weather/Images.xcassets/AppIcon.appiconset/iTunesArtwork@2x.png
deleted file mode 100644
index 91481c2..0000000
Binary files a/Swift Weather/Images.xcassets/AppIcon.appiconset/iTunesArtwork@2x.png and /dev/null differ
diff --git a/Swift Weather/Images.xcassets/LaunchImage.launchimage/Contents.json b/Swift Weather/Images.xcassets/LaunchImage.launchimage/Contents.json
deleted file mode 100644
index fadb823..0000000
--- a/Swift Weather/Images.xcassets/LaunchImage.launchimage/Contents.json
+++ /dev/null
@@ -1,23 +0,0 @@
-{
- "images" : [
- {
- "orientation" : "portrait",
- "idiom" : "iphone",
- "extent" : "full-screen",
- "minimum-system-version" : "7.0",
- "scale" : "2x"
- },
- {
- "orientation" : "portrait",
- "idiom" : "iphone",
- "extent" : "full-screen",
- "minimum-system-version" : "7.0",
- "subtype" : "retina4",
- "scale" : "2x"
- }
- ],
- "info" : {
- "version" : 1,
- "author" : "xcode"
- }
-}
\ No newline at end of file
diff --git a/Swift Weather/Images.xcassets/cloudy2.imageset/Contents.json b/Swift Weather/Images.xcassets/cloudy2.imageset/Contents.json
deleted file mode 100644
index 939179a..0000000
--- a/Swift Weather/Images.xcassets/cloudy2.imageset/Contents.json
+++ /dev/null
@@ -1,21 +0,0 @@
-{
- "images" : [
- {
- "idiom" : "universal",
- "scale" : "1x",
- "filename" : "cloudy2.png"
- },
- {
- "idiom" : "universal",
- "scale" : "2x"
- },
- {
- "idiom" : "universal",
- "scale" : "3x"
- }
- ],
- "info" : {
- "version" : 1,
- "author" : "xcode"
- }
-}
\ No newline at end of file
diff --git a/Swift Weather/Images.xcassets/cloudy2.imageset/cloudy2.png b/Swift Weather/Images.xcassets/cloudy2.imageset/cloudy2.png
deleted file mode 100644
index 737fb19..0000000
Binary files a/Swift Weather/Images.xcassets/cloudy2.imageset/cloudy2.png and /dev/null differ
diff --git a/Swift Weather/Images.xcassets/cloudy2_night.imageset/Contents.json b/Swift Weather/Images.xcassets/cloudy2_night.imageset/Contents.json
deleted file mode 100644
index 0c5a58e..0000000
--- a/Swift Weather/Images.xcassets/cloudy2_night.imageset/Contents.json
+++ /dev/null
@@ -1,21 +0,0 @@
-{
- "images" : [
- {
- "idiom" : "universal",
- "scale" : "1x",
- "filename" : "cloudy2_night.png"
- },
- {
- "idiom" : "universal",
- "scale" : "2x"
- },
- {
- "idiom" : "universal",
- "scale" : "3x"
- }
- ],
- "info" : {
- "version" : 1,
- "author" : "xcode"
- }
-}
\ No newline at end of file
diff --git a/Swift Weather/Images.xcassets/cloudy2_night.imageset/cloudy2_night.png b/Swift Weather/Images.xcassets/cloudy2_night.imageset/cloudy2_night.png
deleted file mode 100644
index 130c4e5..0000000
Binary files a/Swift Weather/Images.xcassets/cloudy2_night.imageset/cloudy2_night.png and /dev/null differ
diff --git a/Swift Weather/Images.xcassets/dunno.imageset/dunno.png b/Swift Weather/Images.xcassets/dunno.imageset/dunno.png
deleted file mode 100644
index fca43b8..0000000
Binary files a/Swift Weather/Images.xcassets/dunno.imageset/dunno.png and /dev/null differ
diff --git a/Swift Weather/Images.xcassets/fog.imageset/fog.png b/Swift Weather/Images.xcassets/fog.imageset/fog.png
deleted file mode 100644
index 6c3ba81..0000000
Binary files a/Swift Weather/Images.xcassets/fog.imageset/fog.png and /dev/null differ
diff --git a/Swift Weather/Images.xcassets/fog_night.imageset/Contents.json b/Swift Weather/Images.xcassets/fog_night.imageset/Contents.json
deleted file mode 100644
index 4e9d7a0..0000000
--- a/Swift Weather/Images.xcassets/fog_night.imageset/Contents.json
+++ /dev/null
@@ -1,21 +0,0 @@
-{
- "images" : [
- {
- "idiom" : "universal",
- "scale" : "1x",
- "filename" : "fog_night.png"
- },
- {
- "idiom" : "universal",
- "scale" : "2x"
- },
- {
- "idiom" : "universal",
- "scale" : "3x"
- }
- ],
- "info" : {
- "version" : 1,
- "author" : "xcode"
- }
-}
\ No newline at end of file
diff --git a/Swift Weather/Images.xcassets/fog_night.imageset/fog_night.png b/Swift Weather/Images.xcassets/fog_night.imageset/fog_night.png
deleted file mode 100644
index 47128a9..0000000
Binary files a/Swift Weather/Images.xcassets/fog_night.imageset/fog_night.png and /dev/null differ
diff --git a/Swift Weather/Images.xcassets/light_rain.imageset/Contents.json b/Swift Weather/Images.xcassets/light_rain.imageset/Contents.json
deleted file mode 100644
index e34a65a..0000000
--- a/Swift Weather/Images.xcassets/light_rain.imageset/Contents.json
+++ /dev/null
@@ -1,21 +0,0 @@
-{
- "images" : [
- {
- "idiom" : "universal",
- "scale" : "1x",
- "filename" : "light_rain.png"
- },
- {
- "idiom" : "universal",
- "scale" : "2x"
- },
- {
- "idiom" : "universal",
- "scale" : "3x"
- }
- ],
- "info" : {
- "version" : 1,
- "author" : "xcode"
- }
-}
\ No newline at end of file
diff --git a/Swift Weather/Images.xcassets/light_rain.imageset/light_rain.png b/Swift Weather/Images.xcassets/light_rain.imageset/light_rain.png
deleted file mode 100644
index b3be5b8..0000000
Binary files a/Swift Weather/Images.xcassets/light_rain.imageset/light_rain.png and /dev/null differ
diff --git a/Swift Weather/Images.xcassets/overcast.imageset/Contents.json b/Swift Weather/Images.xcassets/overcast.imageset/Contents.json
deleted file mode 100644
index c115ab0..0000000
--- a/Swift Weather/Images.xcassets/overcast.imageset/Contents.json
+++ /dev/null
@@ -1,21 +0,0 @@
-{
- "images" : [
- {
- "idiom" : "universal",
- "scale" : "1x",
- "filename" : "overcast.png"
- },
- {
- "idiom" : "universal",
- "scale" : "2x"
- },
- {
- "idiom" : "universal",
- "scale" : "3x"
- }
- ],
- "info" : {
- "version" : 1,
- "author" : "xcode"
- }
-}
\ No newline at end of file
diff --git a/Swift Weather/Images.xcassets/overcast.imageset/overcast.png b/Swift Weather/Images.xcassets/overcast.imageset/overcast.png
deleted file mode 100644
index 18c18ee..0000000
Binary files a/Swift Weather/Images.xcassets/overcast.imageset/overcast.png and /dev/null differ
diff --git a/Swift Weather/Images.xcassets/shower3.imageset/Contents.json b/Swift Weather/Images.xcassets/shower3.imageset/Contents.json
deleted file mode 100644
index e3e90ea..0000000
--- a/Swift Weather/Images.xcassets/shower3.imageset/Contents.json
+++ /dev/null
@@ -1,21 +0,0 @@
-{
- "images" : [
- {
- "idiom" : "universal",
- "scale" : "1x",
- "filename" : "shower3.png"
- },
- {
- "idiom" : "universal",
- "scale" : "2x"
- },
- {
- "idiom" : "universal",
- "scale" : "3x"
- }
- ],
- "info" : {
- "version" : 1,
- "author" : "xcode"
- }
-}
\ No newline at end of file
diff --git a/Swift Weather/Images.xcassets/shower3.imageset/shower3.png b/Swift Weather/Images.xcassets/shower3.imageset/shower3.png
deleted file mode 100644
index 67f992d..0000000
Binary files a/Swift Weather/Images.xcassets/shower3.imageset/shower3.png and /dev/null differ
diff --git a/Swift Weather/Images.xcassets/snow4.imageset/Contents.json b/Swift Weather/Images.xcassets/snow4.imageset/Contents.json
deleted file mode 100644
index 1ccae15..0000000
--- a/Swift Weather/Images.xcassets/snow4.imageset/Contents.json
+++ /dev/null
@@ -1,21 +0,0 @@
-{
- "images" : [
- {
- "idiom" : "universal",
- "scale" : "1x",
- "filename" : "snow4.png"
- },
- {
- "idiom" : "universal",
- "scale" : "2x"
- },
- {
- "idiom" : "universal",
- "scale" : "3x"
- }
- ],
- "info" : {
- "version" : 1,
- "author" : "xcode"
- }
-}
\ No newline at end of file
diff --git a/Swift Weather/Images.xcassets/snow4.imageset/snow4.png b/Swift Weather/Images.xcassets/snow4.imageset/snow4.png
deleted file mode 100644
index 3000a3c..0000000
Binary files a/Swift Weather/Images.xcassets/snow4.imageset/snow4.png and /dev/null differ
diff --git a/Swift Weather/Images.xcassets/snow5.imageset/Contents.json b/Swift Weather/Images.xcassets/snow5.imageset/Contents.json
deleted file mode 100644
index a570d45..0000000
--- a/Swift Weather/Images.xcassets/snow5.imageset/Contents.json
+++ /dev/null
@@ -1,21 +0,0 @@
-{
- "images" : [
- {
- "idiom" : "universal",
- "scale" : "1x",
- "filename" : "snow5.png"
- },
- {
- "idiom" : "universal",
- "scale" : "2x"
- },
- {
- "idiom" : "universal",
- "scale" : "3x"
- }
- ],
- "info" : {
- "version" : 1,
- "author" : "xcode"
- }
-}
\ No newline at end of file
diff --git a/Swift Weather/Images.xcassets/snow5.imageset/snow5.png b/Swift Weather/Images.xcassets/snow5.imageset/snow5.png
deleted file mode 100644
index 0f5b793..0000000
Binary files a/Swift Weather/Images.xcassets/snow5.imageset/snow5.png and /dev/null differ
diff --git a/Swift Weather/Images.xcassets/sunny.imageset/Contents.json b/Swift Weather/Images.xcassets/sunny.imageset/Contents.json
deleted file mode 100644
index 0959dcb..0000000
--- a/Swift Weather/Images.xcassets/sunny.imageset/Contents.json
+++ /dev/null
@@ -1,21 +0,0 @@
-{
- "images" : [
- {
- "idiom" : "universal",
- "scale" : "1x",
- "filename" : "sunny.png"
- },
- {
- "idiom" : "universal",
- "scale" : "2x"
- },
- {
- "idiom" : "universal",
- "scale" : "3x"
- }
- ],
- "info" : {
- "version" : 1,
- "author" : "xcode"
- }
-}
\ No newline at end of file
diff --git a/Swift Weather/Images.xcassets/sunny.imageset/sunny.png b/Swift Weather/Images.xcassets/sunny.imageset/sunny.png
deleted file mode 100644
index 7304f86..0000000
Binary files a/Swift Weather/Images.xcassets/sunny.imageset/sunny.png and /dev/null differ
diff --git a/Swift Weather/Images.xcassets/sunny_night.imageset/Contents.json b/Swift Weather/Images.xcassets/sunny_night.imageset/Contents.json
deleted file mode 100644
index 2898ecd..0000000
--- a/Swift Weather/Images.xcassets/sunny_night.imageset/Contents.json
+++ /dev/null
@@ -1,21 +0,0 @@
-{
- "images" : [
- {
- "idiom" : "universal",
- "scale" : "1x",
- "filename" : "sunny_night.png"
- },
- {
- "idiom" : "universal",
- "scale" : "2x"
- },
- {
- "idiom" : "universal",
- "scale" : "3x"
- }
- ],
- "info" : {
- "version" : 1,
- "author" : "xcode"
- }
-}
\ No newline at end of file
diff --git a/Swift Weather/Images.xcassets/sunny_night.imageset/sunny_night.png b/Swift Weather/Images.xcassets/sunny_night.imageset/sunny_night.png
deleted file mode 100644
index fcec655..0000000
Binary files a/Swift Weather/Images.xcassets/sunny_night.imageset/sunny_night.png and /dev/null differ
diff --git a/Swift Weather/Images.xcassets/tstorm1.imageset/Contents.json b/Swift Weather/Images.xcassets/tstorm1.imageset/Contents.json
deleted file mode 100644
index 5aaedd6..0000000
--- a/Swift Weather/Images.xcassets/tstorm1.imageset/Contents.json
+++ /dev/null
@@ -1,21 +0,0 @@
-{
- "images" : [
- {
- "idiom" : "universal",
- "scale" : "1x",
- "filename" : "tstorm1.png"
- },
- {
- "idiom" : "universal",
- "scale" : "2x"
- },
- {
- "idiom" : "universal",
- "scale" : "3x"
- }
- ],
- "info" : {
- "version" : 1,
- "author" : "xcode"
- }
-}
\ No newline at end of file
diff --git a/Swift Weather/Images.xcassets/tstorm1.imageset/tstorm1.png b/Swift Weather/Images.xcassets/tstorm1.imageset/tstorm1.png
deleted file mode 100644
index 407c894..0000000
Binary files a/Swift Weather/Images.xcassets/tstorm1.imageset/tstorm1.png and /dev/null differ
diff --git a/Swift Weather/Images.xcassets/tstorm1_night.imageset/Contents.json b/Swift Weather/Images.xcassets/tstorm1_night.imageset/Contents.json
deleted file mode 100644
index 5a39b2e..0000000
--- a/Swift Weather/Images.xcassets/tstorm1_night.imageset/Contents.json
+++ /dev/null
@@ -1,21 +0,0 @@
-{
- "images" : [
- {
- "idiom" : "universal",
- "scale" : "1x",
- "filename" : "tstorm1_night.png"
- },
- {
- "idiom" : "universal",
- "scale" : "2x"
- },
- {
- "idiom" : "universal",
- "scale" : "3x"
- }
- ],
- "info" : {
- "version" : 1,
- "author" : "xcode"
- }
-}
\ No newline at end of file
diff --git a/Swift Weather/Images.xcassets/tstorm1_night.imageset/tstorm1_night.png b/Swift Weather/Images.xcassets/tstorm1_night.imageset/tstorm1_night.png
deleted file mode 100644
index 41749e6..0000000
Binary files a/Swift Weather/Images.xcassets/tstorm1_night.imageset/tstorm1_night.png and /dev/null differ
diff --git a/Swift Weather/Images.xcassets/tstorm3.imageset/Contents.json b/Swift Weather/Images.xcassets/tstorm3.imageset/Contents.json
deleted file mode 100644
index 153cd26..0000000
--- a/Swift Weather/Images.xcassets/tstorm3.imageset/Contents.json
+++ /dev/null
@@ -1,21 +0,0 @@
-{
- "images" : [
- {
- "idiom" : "universal",
- "scale" : "1x",
- "filename" : "tstorm3.png"
- },
- {
- "idiom" : "universal",
- "scale" : "2x"
- },
- {
- "idiom" : "universal",
- "scale" : "3x"
- }
- ],
- "info" : {
- "version" : 1,
- "author" : "xcode"
- }
-}
\ No newline at end of file
diff --git a/Swift Weather/Images.xcassets/tstorm3.imageset/tstorm3.png b/Swift Weather/Images.xcassets/tstorm3.imageset/tstorm3.png
deleted file mode 100644
index ebfe876..0000000
Binary files a/Swift Weather/Images.xcassets/tstorm3.imageset/tstorm3.png and /dev/null differ
diff --git a/Swift Weather/Info.plist b/Swift Weather/Info.plist
deleted file mode 100644
index d0c723b..0000000
--- a/Swift Weather/Info.plist
+++ /dev/null
@@ -1,40 +0,0 @@
-
-
-
-
- CFBundleDevelopmentRegion
- en
- CFBundleExecutable
- ${EXECUTABLE_NAME}
- CFBundleIdentifier
- com.rushjet.${PRODUCT_NAME:rfc1034identifier}
- CFBundleInfoDictionaryVersion
- 6.0
- CFBundleName
- ${PRODUCT_NAME}
- CFBundlePackageType
- APPL
- CFBundleShortVersionString
- 1.0
- CFBundleSignature
- ????
- CFBundleVersion
- 1
- LSRequiresIPhoneOS
-
- UIMainStoryboardFile
- Main
- UIRequiredDeviceCapabilities
-
- armv7
-
- NSLocationUsageDescription
- Your location is used to tell where you are.
- NSLocationAlwaysUsageDescription
- Your location is used to tell where you are.
- UISupportedInterfaceOrientations
-
- UIInterfaceOrientationPortrait
-
-
-
diff --git a/Swift Weather/SwiftWeather-Bridging-Header.h b/Swift Weather/SwiftWeather-Bridging-Header.h
deleted file mode 100644
index a1d2720..0000000
--- a/Swift Weather/SwiftWeather-Bridging-Header.h
+++ /dev/null
@@ -1,9 +0,0 @@
-//
-// SwiftWeather-Bridging-Header.h
-// SwiftWeather
-//
-// Created by Jake Lin on 4/06/2014.
-// Copyright (c) 2014 Jake Lin. All rights reserved.
-//
-
-#import
\ No newline at end of file
diff --git a/Swift Weather/ViewController.swift b/Swift Weather/ViewController.swift
deleted file mode 100644
index 7eb2048..0000000
--- a/Swift Weather/ViewController.swift
+++ /dev/null
@@ -1,316 +0,0 @@
-//
-// ViewController.swift
-// Swift Weather
-//
-// Created by Jake Lin on 4/06/2014.
-// Copyright (c) 2014 rushjet. All rights reserved.
-//
-
-import UIKit
-import CoreLocation
-
-class ViewController: UIViewController, CLLocationManagerDelegate {
-
- let locationManager:CLLocationManager = CLLocationManager()
-
- @IBOutlet var loadingIndicator : UIActivityIndicatorView! = nil
- @IBOutlet var icon : UIImageView!
- @IBOutlet var temperature : UILabel!
- @IBOutlet var loading : UILabel!
- @IBOutlet var location : UILabel!
- @IBOutlet weak var time1: UILabel!
- @IBOutlet weak var time2: UILabel!
- @IBOutlet weak var time3: UILabel!
- @IBOutlet weak var time4: UILabel!
- @IBOutlet weak var image1: UIImageView!
- @IBOutlet weak var image2: UIImageView!
- @IBOutlet weak var image3: UIImageView!
- @IBOutlet weak var image4: UIImageView!
- @IBOutlet weak var temp1: UILabel!
- @IBOutlet weak var temp2: UILabel!
- @IBOutlet weak var temp3: UILabel!
- @IBOutlet weak var temp4: UILabel!
-
- override func viewDidLoad() {
- super.viewDidLoad()
- locationManager.delegate = self
- locationManager.desiredAccuracy = kCLLocationAccuracyBest
-
- self.loadingIndicator.startAnimating()
-
- let background = UIImage(named: "background.png")
- self.view.backgroundColor = UIColor(patternImage: background!)
-
- let singleFingerTap = UITapGestureRecognizer(target: self, action: "handleSingleTap:")
- self.view.addGestureRecognizer(singleFingerTap)
-
- if ( ios8() ) {
- locationManager.requestAlwaysAuthorization()
- }
- locationManager.startUpdatingLocation()
- }
-
- func handleSingleTap(recognizer: UITapGestureRecognizer) {
- locationManager.startUpdatingLocation()
- }
-
- override func didReceiveMemoryWarning() {
- super.didReceiveMemoryWarning()
- // Dispose of any resources that can be recreated.
- }
-
- func updateWeatherInfo(latitude: CLLocationDegrees, longitude: CLLocationDegrees) {
- let manager = AFHTTPRequestOperationManager()
-
- let url = "http://api.openweathermap.org/data/2.5/forecast"
- println(url)
-
- let params = ["lat":latitude, "lon":longitude]
- println(params)
-
- manager.GET(url,
- parameters: params,
- success: { (operation: AFHTTPRequestOperation!,
- responseObject: AnyObject!) in
- println("JSON: " + responseObject.description!)
-
- self.updateUISuccess(responseObject as NSDictionary!)
- },
- failure: { (operation: AFHTTPRequestOperation!,
- error: NSError!) in
- println("Error: " + error.localizedDescription)
-
- self.loading.text = "Internet appears down!"
- })
- }
-
- func updateUISuccess(jsonResult: NSDictionary) {
- self.loading.text = nil
- self.loadingIndicator.hidden = true
- self.loadingIndicator.stopAnimating()
-
- if let tempResult = ((jsonResult["list"]? as NSArray)[0]["main"] as NSDictionary)["temp"] as? Double {
- println("TempResult:", tempResult)
- // If we can get the temperature from JSON correctly, we assume the rest of JSON is correct.
- var temperature: Double
- var cntry: String
- cntry = ""
- if let city = (jsonResult["city"]? as? NSDictionary) {
- if let country = (city["country"] as? String) {
- cntry = country
- if (country == "US") {
- // Convert temperature to Fahrenheit if user is within the US
- temperature = round(((tempResult - 273.15) * 1.8) + 32)
- }
- else {
- // Otherwise, convert temperature to Celsius
- temperature = round(tempResult - 273.15)
- }
-
- // FIXED: Is it a bug of Xcode 6? can not set the font size in IB.
- //self.temperature.font = UIFont.boldSystemFontOfSize(60)
- self.temperature.text = "\(temperature)°"
- }
-
- if let name = (city["name"] as? String) {
- self.location.font = UIFont.boldSystemFontOfSize(25)
- self.location.text = name
- }
- }
-
-
- if let weatherArray = (jsonResult["list"]? as? NSArray) {
- for index in 0...4 {
- println(index)
- if let perTime = (weatherArray[index] as? NSDictionary) {
- if let main = (perTime["main"]? as? NSDictionary) {
- var temp = (main["temp"] as Double)
- if (cntry == "US") {
- // Convert temperature to Fahrenheit if user is within the US
- temperature = round(((temp - 273.15) * 1.8) + 32)
- }
- else {
- // Otherwise, convert temperature to Celsius
- temperature = round(temp - 273.15)
- }
-
- // FIXED: Is it a bug of Xcode 6? can not set the font size in IB.
- //self.temperature.font = UIFont.boldSystemFontOfSize(60)
- if (index==1) {
- self.temp1.text = "\(temperature)°"
- }
- if (index==2) {
- self.temp2.text = "\(temperature)°"
- }
- if (index==3) {
- self.temp3.text = "\(temperature)°"
- }
- if (index==4) {
- self.temp4.text = "\(temperature)°"
- }
- }
- var dateFormatter = NSDateFormatter()
- dateFormatter.dateFormat = "HH:mm"
- if let date = (perTime["dt"]? as? Double) {
- let thisDate = NSDate(timeIntervalSince1970: date)
- let forecastTime = dateFormatter.stringFromDate(thisDate)
- if (index==1) {
- self.time1.text = forecastTime
- }
- if (index==2) {
- self.time2.text = forecastTime
- }
- if (index==3) {
- self.time3.text = forecastTime
- }
- if (index==4) {
- self.time4.text = forecastTime
- }
- }
- if let weather = (perTime["weather"]? as? NSArray) {
- var condition = (weather[0] as NSDictionary)["id"] as Int
- var icon = (weather[0] as NSDictionary)["icon"] as String
- var nightTime = false
- if icon.rangeOfString("n") != nil{
- nightTime = true
- }
- self.updateWeatherIcon(condition, nightTime: nightTime, index: index)
- if (index==4) {
- return
- }
-
- }
- }
- }
- }
- }
- self.loading.text = "Weather info is not available!"
-
- }
-
- func updatePictures(index: Int, name: String) {
- if (index==0) {
- self.icon.image = UIImage(named: name)
- }
- if (index==1) {
- self.image1.image = UIImage(named: name)
- }
- if (index==2) {
- self.image2.image = UIImage(named: name)
- }
- if (index==3) {
- self.image3.image = UIImage(named: name)
- }
- if (index==4) {
- self.image4.image = UIImage(named: name)
- }
- }
-
- func updateWeatherIcon(condition: Int, nightTime: Bool, index: Int) {
- // Thunderstorm
-
- var images = [self.icon.image, self.image1.image, self.image2.image, self.image3.image, self.image4.image]
-
- if (condition < 300) {
- if nightTime {
- self.updatePictures(index, name: "tstorm1_night")
- } else {
- self.updatePictures(index, name: "tstorm1")
- }
- }
- // Drizzle
- else if (condition < 500) {
- self.updatePictures(index, name: "light_rain")
-
- }
- // Rain / Freezing rain / Shower rain
- else if (condition < 600) {
- self.updatePictures(index, name: "shower3")
- }
- // Snow
- else if (condition < 700) {
- self.updatePictures(index, name: "snow4")
- }
- // Fog / Mist / Haze / etc.
- else if (condition < 771) {
- if nightTime {
- self.updatePictures(index, name: "fog_night")
- } else {
- self.updatePictures(index, name: "fog")
- }
- }
- // Tornado / Squalls
- else if (condition < 800) {
- self.updatePictures(index, name: "tstorm3")
- }
- // Sky is clear
- else if (condition == 800) {
- if (nightTime){
- self.updatePictures(index, name: "sunny_night")
- }
- else {
- self.updatePictures(index, name: "sunny")
- }
- }
- // few / scattered / broken clouds
- else if (condition < 804) {
- if (nightTime){
- self.updatePictures(index, name: "cloudy2_night")
- }
- else{
- self.updatePictures(index, name: "cloudy2")
- }
- }
- // overcast clouds
- else if (condition == 804) {
- self.updatePictures(index, name: "overcast")
- }
- // Extreme
- else if ((condition >= 900 && condition < 903) || (condition > 904 && condition < 1000)) {
- self.updatePictures(index, name: "tstorm3")
- }
- // Cold
- else if (condition == 903) {
- self.updatePictures(index, name: "snow5")
- }
- // Hot
- else if (condition == 904) {
- self.updatePictures(index, name: "sunny")
- }
- // Weather condition is not available
- else {
- self.updatePictures(index, name: "dunno")
- }
- }
-
- /*
- iOS 8 Utility
- */
- func ios8() -> Bool {
- if ( NSFoundationVersionNumber <= NSFoundationVersionNumber_iOS_7_1 ) {
- return false
- } else {
- return true
- }
- }
-
- //CLLocationManagerDelegate
- func locationManager(manager: CLLocationManager!, didUpdateLocations locations: [AnyObject]!) {
- var location:CLLocation = locations[locations.count-1] as CLLocation
-
- if (location.horizontalAccuracy > 0) {
- self.locationManager.stopUpdatingLocation()
- println(location.coordinate)
- updateWeatherInfo(location.coordinate.latitude, longitude: location.coordinate.longitude)
- }
- }
-
- func locationManager(manager: CLLocationManager!, didFailWithError error: NSError!) {
- println(error)
- self.loading.text = "Can't get your location!"
- }
-
- override func preferredStatusBarStyle() -> UIStatusBarStyle {
- return .LightContent
- }
-}
diff --git a/Swift Weather/background.png b/Swift Weather/background.png
deleted file mode 100644
index 9b7f02f..0000000
Binary files a/Swift Weather/background.png and /dev/null differ
diff --git a/Swift Weather/background_summer.png b/Swift Weather/background_summer.png
deleted file mode 100644
index db69b9f..0000000
Binary files a/Swift Weather/background_summer.png and /dev/null differ
diff --git a/Swift Weather/images/Cloud-Refresh.png b/Swift Weather/images/Cloud-Refresh.png
deleted file mode 100755
index 783e8f7..0000000
Binary files a/Swift Weather/images/Cloud-Refresh.png and /dev/null differ
diff --git a/Swift Weather/images/cloudy2.png b/Swift Weather/images/cloudy2.png
deleted file mode 100755
index 737fb19..0000000
Binary files a/Swift Weather/images/cloudy2.png and /dev/null differ
diff --git a/Swift Weather/images/cloudy2_night.png b/Swift Weather/images/cloudy2_night.png
deleted file mode 100755
index 130c4e5..0000000
Binary files a/Swift Weather/images/cloudy2_night.png and /dev/null differ
diff --git a/Swift Weather/images/dunno.png b/Swift Weather/images/dunno.png
deleted file mode 100755
index fca43b8..0000000
Binary files a/Swift Weather/images/dunno.png and /dev/null differ
diff --git a/Swift Weather/images/fog.png b/Swift Weather/images/fog.png
deleted file mode 100755
index 6c3ba81..0000000
Binary files a/Swift Weather/images/fog.png and /dev/null differ
diff --git a/Swift Weather/images/fog_night.png b/Swift Weather/images/fog_night.png
deleted file mode 100755
index 47128a9..0000000
Binary files a/Swift Weather/images/fog_night.png and /dev/null differ
diff --git a/Swift Weather/images/light_rain.png b/Swift Weather/images/light_rain.png
deleted file mode 100755
index b3be5b8..0000000
Binary files a/Swift Weather/images/light_rain.png and /dev/null differ
diff --git a/Swift Weather/images/overcast.png b/Swift Weather/images/overcast.png
deleted file mode 100755
index 18c18ee..0000000
Binary files a/Swift Weather/images/overcast.png and /dev/null differ
diff --git a/Swift Weather/images/shower3.png b/Swift Weather/images/shower3.png
deleted file mode 100755
index 67f992d..0000000
Binary files a/Swift Weather/images/shower3.png and /dev/null differ
diff --git a/Swift Weather/images/snow4.png b/Swift Weather/images/snow4.png
deleted file mode 100755
index 3000a3c..0000000
Binary files a/Swift Weather/images/snow4.png and /dev/null differ
diff --git a/Swift Weather/images/snow5.png b/Swift Weather/images/snow5.png
deleted file mode 100755
index 0f5b793..0000000
Binary files a/Swift Weather/images/snow5.png and /dev/null differ
diff --git a/Swift Weather/images/sunny.png b/Swift Weather/images/sunny.png
deleted file mode 100755
index 7304f86..0000000
Binary files a/Swift Weather/images/sunny.png and /dev/null differ
diff --git a/Swift Weather/images/sunny_night.png b/Swift Weather/images/sunny_night.png
deleted file mode 100755
index fcec655..0000000
Binary files a/Swift Weather/images/sunny_night.png and /dev/null differ
diff --git a/Swift Weather/images/tstorm1.png b/Swift Weather/images/tstorm1.png
deleted file mode 100755
index 407c894..0000000
Binary files a/Swift Weather/images/tstorm1.png and /dev/null differ
diff --git a/Swift Weather/images/tstorm1_night.png b/Swift Weather/images/tstorm1_night.png
deleted file mode 100755
index 41749e6..0000000
Binary files a/Swift Weather/images/tstorm1_night.png and /dev/null differ
diff --git a/Swift Weather/images/tstorm3.png b/Swift Weather/images/tstorm3.png
deleted file mode 100755
index ebfe876..0000000
Binary files a/Swift Weather/images/tstorm3.png and /dev/null differ
diff --git a/Swift WeatherTests/Swift_WeatherTests.swift b/Swift WeatherTests/Swift_WeatherTests.swift
deleted file mode 100644
index 0ae7df4..0000000
--- a/Swift WeatherTests/Swift_WeatherTests.swift
+++ /dev/null
@@ -1,35 +0,0 @@
-//
-// Swift_WeatherTests.swift
-// Swift WeatherTests
-//
-// Created by Jake Lin on 4/06/2014.
-// Copyright (c) 2014 rushjet. All rights reserved.
-//
-
-import XCTest
-
-class Swift_WeatherTests: XCTestCase {
-
- override func setUp() {
- super.setUp()
- // Put setup code here. This method is called before the invocation of each test method in the class.
- }
-
- override func tearDown() {
- // Put teardown code here. This method is called after the invocation of each test method in the class.
- super.tearDown()
- }
-
- func testExample() {
- // This is an example of a functional test case.
- XCTAssert(true, "Pass")
- }
-
- func testPerformanceExample() {
- // This is an example of a performance test case.
- self.measureBlock() {
- // Put the code you want to measure the time of here.
- }
- }
-
-}
diff --git a/SwiftWeather.xcodeproj/project.pbxproj b/SwiftWeather.xcodeproj/project.pbxproj
new file mode 100644
index 0000000..1913c14
--- /dev/null
+++ b/SwiftWeather.xcodeproj/project.pbxproj
@@ -0,0 +1,905 @@
+// !$*UTF8*$!
+{
+ archiveVersion = 1;
+ classes = {
+ };
+ objectVersion = 46;
+ objects = {
+
+/* Begin PBXBuildFile section */
+ 1E8FF8444E2C29BD30B867EF /* Pods_Tests_SwiftWeatherUITests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 418594A8DD8093A647A30E12 /* Pods_Tests_SwiftWeatherUITests.framework */; };
+ 5120F2EFC3DE077315306794 /* Pods_SwiftWeather.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = BF971A1BA4A6D64984CB0A75 /* Pods_SwiftWeather.framework */; };
+ 655E8966C3E09626A8221261 /* Pods_Tests_SwiftWeatherTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 342A91306F3CF92DD999C97D /* Pods_Tests_SwiftWeatherTests.framework */; };
+ AE09C4301B9723DE00C7CCED /* LocationService.swift in Sources */ = {isa = PBXBuildFile; fileRef = AE09C42F1B9723DE00C7CCED /* LocationService.swift */; };
+ AE0DC2CD1B8E7B3900E67147 /* Observable.swift in Sources */ = {isa = PBXBuildFile; fileRef = AE0DC2CC1B8E7B3900E67147 /* Observable.swift */; };
+ AE26CCAB1B875C2400D518CB /* ForecastView.xib in Resources */ = {isa = PBXBuildFile; fileRef = AE26CCAA1B875C2400D518CB /* ForecastView.xib */; };
+ AE2C7D6C1BA028C000A7A714 /* WeatherIcon.swift in Sources */ = {isa = PBXBuildFile; fileRef = AE2C7D6B1BA028C000A7A714 /* WeatherIcon.swift */; };
+ AE6C34E91B84742900F726C2 /* weathericons-regular-webfont.ttf in Resources */ = {isa = PBXBuildFile; fileRef = AE6C34E81B84742900F726C2 /* weathericons-regular-webfont.ttf */; };
+ AEBE643B1B8D1F90004A0814 /* ForecastViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = AEBE643A1B8D1F90004A0814 /* ForecastViewModel.swift */; };
+ AEBE643E1B8D2108004A0814 /* Forecast.swift in Sources */ = {isa = PBXBuildFile; fileRef = AEBE643D1B8D2108004A0814 /* Forecast.swift */; };
+ AEBE64431B8D2370004A0814 /* Weather.swift in Sources */ = {isa = PBXBuildFile; fileRef = AEBE64421B8D2370004A0814 /* Weather.swift */; };
+ AEBE64451B8D23B8004A0814 /* WeatherViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = AEBE64441B8D23B8004A0814 /* WeatherViewModel.swift */; };
+ AECBA5E61B836BF20004A536 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = AECBA5E51B836BF20004A536 /* AppDelegate.swift */; };
+ AECBA5E81B836BF20004A536 /* WeatherViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = AECBA5E71B836BF20004A536 /* WeatherViewController.swift */; };
+ AECBA5EB1B836BF20004A536 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = AECBA5E91B836BF20004A536 /* Main.storyboard */; };
+ AECBA5ED1B836BF20004A536 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = AECBA5EC1B836BF20004A536 /* Assets.xcassets */; };
+ AECBA5F01B836BF20004A536 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = AECBA5EE1B836BF20004A536 /* LaunchScreen.storyboard */; };
+ AECBA6061B836BF20004A536 /* SwiftWeatherUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = AECBA6051B836BF20004A536 /* SwiftWeatherUITests.swift */; };
+ AED4B2C21B876E8B0003D765 /* ForecastView.swift in Sources */ = {isa = PBXBuildFile; fileRef = AED4B2C01B876DF50003D765 /* ForecastView.swift */; };
+ AEEDF6891B9F09E300C6067B /* Error.swift in Sources */ = {isa = PBXBuildFile; fileRef = AEEDF6881B9F09E300C6067B /* Error.swift */; };
+ AEEDF68B1B9F99F800C6067B /* WeatherBuilder.swift in Sources */ = {isa = PBXBuildFile; fileRef = AEEDF68A1B9F99F800C6067B /* WeatherBuilder.swift */; };
+ AEEDF68D1B9F9B2900C6067B /* Temperature.swift in Sources */ = {isa = PBXBuildFile; fileRef = AEEDF68C1B9F9B2900C6067B /* Temperature.swift */; };
+ AEF61B281BA23B1200E8F259 /* ForecastDateTime.swift in Sources */ = {isa = PBXBuildFile; fileRef = AEF61B271BA23B1200E8F259 /* ForecastDateTime.swift */; };
+ CAB565DDADB61DF9053BD50F /* WeatherServiceProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = CAB56A3D23F4A93BB599E4BA /* WeatherServiceProtocol.swift */; };
+ CAB56F4267B3BC487990A92D /* OpenWeatherMapService.swift in Sources */ = {isa = PBXBuildFile; fileRef = CAB56D46471CA243B1FD646F /* OpenWeatherMapService.swift */; };
+ EADFFD301CAEA22F008357FF /* TemperatureConverter.swift in Sources */ = {isa = PBXBuildFile; fileRef = EADFFD2F1CAEA22F008357FF /* TemperatureConverter.swift */; };
+ F3897F7C1C118C4F001609E2 /* ForecastDateTimeSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = F3897F7B1C118C4F001609E2 /* ForecastDateTimeSpec.swift */; };
+ F3897F7E1C118C6E001609E2 /* WeatherSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = F3897F7D1C118C6E001609E2 /* WeatherSpec.swift */; };
+ F3897F801C118D7D001609E2 /* ForecastSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = F3897F7F1C118D7D001609E2 /* ForecastSpec.swift */; };
+ F3897F821C118F0A001609E2 /* TemperatureSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = F3897F811C118F0A001609E2 /* TemperatureSpec.swift */; };
+ F3897F841C11911B001609E2 /* WeatherIconSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = F3897F831C11911B001609E2 /* WeatherIconSpec.swift */; };
+ F3FADA1B1C1327CB006D8551 /* WeatherBuilderSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = F3FADA1A1C1327CB006D8551 /* WeatherBuilderSpec.swift */; };
+/* End PBXBuildFile section */
+
+/* Begin PBXContainerItemProxy section */
+ AECBA5F71B836BF20004A536 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = AECBA5DA1B836BF20004A536 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = AECBA5E11B836BF20004A536;
+ remoteInfo = SwiftWeather;
+ };
+ AECBA6021B836BF20004A536 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = AECBA5DA1B836BF20004A536 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = AECBA5E11B836BF20004A536;
+ remoteInfo = SwiftWeather;
+ };
+/* End PBXContainerItemProxy section */
+
+/* Begin PBXFileReference section */
+ 342A91306F3CF92DD999C97D /* Pods_Tests_SwiftWeatherTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Tests_SwiftWeatherTests.framework; sourceTree = BUILT_PRODUCTS_DIR; };
+ 418594A8DD8093A647A30E12 /* Pods_Tests_SwiftWeatherUITests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Tests_SwiftWeatherUITests.framework; sourceTree = BUILT_PRODUCTS_DIR; };
+ 53EEE101C82E858E57980710 /* Pods-Tests-SwiftWeatherUITests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Tests-SwiftWeatherUITests.release.xcconfig"; path = "Pods/Target Support Files/Pods-Tests-SwiftWeatherUITests/Pods-Tests-SwiftWeatherUITests.release.xcconfig"; sourceTree = ""; };
+ 900AFFBB41C69FC277CB0A33 /* Pods-SwiftWeather.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-SwiftWeather.debug.xcconfig"; path = "Pods/Target Support Files/Pods-SwiftWeather/Pods-SwiftWeather.debug.xcconfig"; sourceTree = ""; };
+ 919B9EF9E5898277AD9C772A /* Pods-Tests-SwiftWeatherUITests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Tests-SwiftWeatherUITests.debug.xcconfig"; path = "Pods/Target Support Files/Pods-Tests-SwiftWeatherUITests/Pods-Tests-SwiftWeatherUITests.debug.xcconfig"; sourceTree = ""; };
+ AE09C42F1B9723DE00C7CCED /* LocationService.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LocationService.swift; sourceTree = ""; };
+ AE0DC2CC1B8E7B3900E67147 /* Observable.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Observable.swift; sourceTree = ""; };
+ AE26CCAA1B875C2400D518CB /* ForecastView.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = ForecastView.xib; sourceTree = ""; };
+ AE2C7D6B1BA028C000A7A714 /* WeatherIcon.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = WeatherIcon.swift; sourceTree = ""; };
+ AE6C34E81B84742900F726C2 /* weathericons-regular-webfont.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "weathericons-regular-webfont.ttf"; sourceTree = ""; };
+ AEBE643A1B8D1F90004A0814 /* ForecastViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ForecastViewModel.swift; sourceTree = ""; };
+ AEBE643D1B8D2108004A0814 /* Forecast.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Forecast.swift; sourceTree = ""; };
+ AEBE64421B8D2370004A0814 /* Weather.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Weather.swift; sourceTree = ""; };
+ AEBE64441B8D23B8004A0814 /* WeatherViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.swift; path = WeatherViewModel.swift; sourceTree = ""; tabWidth = 2; };
+ AECBA5E21B836BF20004A536 /* SwiftWeather.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = SwiftWeather.app; sourceTree = BUILT_PRODUCTS_DIR; };
+ AECBA5E51B836BF20004A536 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; };
+ AECBA5E71B836BF20004A536 /* WeatherViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WeatherViewController.swift; sourceTree = ""; };
+ AECBA5EA1B836BF20004A536 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; };
+ AECBA5EC1B836BF20004A536 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; };
+ AECBA5EF1B836BF20004A536 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; };
+ AECBA5F11B836BF20004A536 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
+ AECBA5F61B836BF20004A536 /* SwiftWeatherTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = SwiftWeatherTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
+ AECBA5FC1B836BF20004A536 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
+ AECBA6011B836BF20004A536 /* SwiftWeatherUITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = SwiftWeatherUITests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
+ AECBA6051B836BF20004A536 /* SwiftWeatherUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SwiftWeatherUITests.swift; sourceTree = ""; };
+ AECBA6071B836BF20004A536 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
+ AED4B2C01B876DF50003D765 /* ForecastView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ForecastView.swift; sourceTree = ""; };
+ AEEDF6881B9F09E300C6067B /* Error.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Error.swift; sourceTree = ""; };
+ AEEDF68A1B9F99F800C6067B /* WeatherBuilder.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = WeatherBuilder.swift; sourceTree = ""; };
+ AEEDF68C1B9F9B2900C6067B /* Temperature.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Temperature.swift; sourceTree = ""; };
+ AEF61B271BA23B1200E8F259 /* ForecastDateTime.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ForecastDateTime.swift; sourceTree = ""; };
+ BF971A1BA4A6D64984CB0A75 /* Pods_SwiftWeather.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_SwiftWeather.framework; sourceTree = BUILT_PRODUCTS_DIR; };
+ BFCBC7111E6F5822A73508A5 /* Pods-Tests-SwiftWeatherTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Tests-SwiftWeatherTests.debug.xcconfig"; path = "Pods/Target Support Files/Pods-Tests-SwiftWeatherTests/Pods-Tests-SwiftWeatherTests.debug.xcconfig"; sourceTree = ""; };
+ CAB56A3D23F4A93BB599E4BA /* WeatherServiceProtocol.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = WeatherServiceProtocol.swift; sourceTree = ""; };
+ CAB56D46471CA243B1FD646F /* OpenWeatherMapService.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OpenWeatherMapService.swift; sourceTree = ""; };
+ E835C39D4B929F35B6A57B12 /* Pods-SwiftWeather.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-SwiftWeather.release.xcconfig"; path = "Pods/Target Support Files/Pods-SwiftWeather/Pods-SwiftWeather.release.xcconfig"; sourceTree = ""; };
+ EADFFD2F1CAEA22F008357FF /* TemperatureConverter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TemperatureConverter.swift; sourceTree = ""; };
+ F3897F7B1C118C4F001609E2 /* ForecastDateTimeSpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ForecastDateTimeSpec.swift; sourceTree = ""; };
+ F3897F7D1C118C6E001609E2 /* WeatherSpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = WeatherSpec.swift; sourceTree = ""; };
+ F3897F7F1C118D7D001609E2 /* ForecastSpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ForecastSpec.swift; sourceTree = ""; };
+ F3897F811C118F0A001609E2 /* TemperatureSpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TemperatureSpec.swift; sourceTree = ""; };
+ F3897F831C11911B001609E2 /* WeatherIconSpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = WeatherIconSpec.swift; sourceTree = ""; };
+ F3FADA1A1C1327CB006D8551 /* WeatherBuilderSpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = WeatherBuilderSpec.swift; sourceTree = ""; };
+ F4007F80070D3AAE1C564D8D /* Pods-Tests-SwiftWeatherTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Tests-SwiftWeatherTests.release.xcconfig"; path = "Pods/Target Support Files/Pods-Tests-SwiftWeatherTests/Pods-Tests-SwiftWeatherTests.release.xcconfig"; sourceTree = ""; };
+/* End PBXFileReference section */
+
+/* Begin PBXFrameworksBuildPhase section */
+ AECBA5DF1B836BF20004A536 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 5120F2EFC3DE077315306794 /* Pods_SwiftWeather.framework in Frameworks */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ AECBA5F31B836BF20004A536 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 655E8966C3E09626A8221261 /* Pods_Tests_SwiftWeatherTests.framework in Frameworks */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ AECBA5FE1B836BF20004A536 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 1E8FF8444E2C29BD30B867EF /* Pods_Tests_SwiftWeatherUITests.framework in Frameworks */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXFrameworksBuildPhase section */
+
+/* Begin PBXGroup section */
+ 0D4BA09867F4A2B5754C4C42 /* Frameworks */ = {
+ isa = PBXGroup;
+ children = (
+ BF971A1BA4A6D64984CB0A75 /* Pods_SwiftWeather.framework */,
+ 342A91306F3CF92DD999C97D /* Pods_Tests_SwiftWeatherTests.framework */,
+ 418594A8DD8093A647A30E12 /* Pods_Tests_SwiftWeatherUITests.framework */,
+ );
+ name = Frameworks;
+ sourceTree = "";
+ };
+ AE0DC2CB1B8E7ACE00E67147 /* Common */ = {
+ isa = PBXGroup;
+ children = (
+ AE0DC2CC1B8E7B3900E67147 /* Observable.swift */,
+ AE09C42F1B9723DE00C7CCED /* LocationService.swift */,
+ AEEDF6881B9F09E300C6067B /* Error.swift */,
+ AEF61B271BA23B1200E8F259 /* ForecastDateTime.swift */,
+ );
+ name = Common;
+ sourceTree = "";
+ };
+ AE6C34E71B84742900F726C2 /* fonts */ = {
+ isa = PBXGroup;
+ children = (
+ AE6C34E81B84742900F726C2 /* weathericons-regular-webfont.ttf */,
+ );
+ path = fonts;
+ sourceTree = "";
+ };
+ AEBE643C1B8D203C004A0814 /* Forecast */ = {
+ isa = PBXGroup;
+ children = (
+ AE26CCAA1B875C2400D518CB /* ForecastView.xib */,
+ AED4B2C01B876DF50003D765 /* ForecastView.swift */,
+ AEBE643A1B8D1F90004A0814 /* ForecastViewModel.swift */,
+ AEBE643D1B8D2108004A0814 /* Forecast.swift */,
+ );
+ name = Forecast;
+ sourceTree = "";
+ };
+ AEBE643F1B8D22ED004A0814 /* Storyboards */ = {
+ isa = PBXGroup;
+ children = (
+ AECBA5E91B836BF20004A536 /* Main.storyboard */,
+ AECBA5EE1B836BF20004A536 /* LaunchScreen.storyboard */,
+ );
+ name = Storyboards;
+ sourceTree = "";
+ };
+ AEBE64401B8D2306004A0814 /* Weather */ = {
+ isa = PBXGroup;
+ children = (
+ AEF61B2B1BA23C2A00E8F259 /* Models */,
+ AEBE64441B8D23B8004A0814 /* WeatherViewModel.swift */,
+ AECBA5E71B836BF20004A536 /* WeatherViewController.swift */,
+ AEF61B291BA23C0500E8F259 /* Services */,
+ );
+ name = Weather;
+ sourceTree = "";
+ };
+ AEBE64411B8D231E004A0814 /* Features */ = {
+ isa = PBXGroup;
+ children = (
+ AEBE64401B8D2306004A0814 /* Weather */,
+ AEBE643C1B8D203C004A0814 /* Forecast */,
+ );
+ name = Features;
+ sourceTree = "";
+ };
+ AECBA5D91B836BF20004A536 = {
+ isa = PBXGroup;
+ children = (
+ AECBA5E41B836BF20004A536 /* SwiftWeather */,
+ AECBA5F91B836BF20004A536 /* SwiftWeatherTests */,
+ AECBA6041B836BF20004A536 /* SwiftWeatherUITests */,
+ AECBA5E31B836BF20004A536 /* Products */,
+ E117EDC87D7E5DC450870FDD /* Pods */,
+ 0D4BA09867F4A2B5754C4C42 /* Frameworks */,
+ );
+ sourceTree = "";
+ };
+ AECBA5E31B836BF20004A536 /* Products */ = {
+ isa = PBXGroup;
+ children = (
+ AECBA5E21B836BF20004A536 /* SwiftWeather.app */,
+ AECBA5F61B836BF20004A536 /* SwiftWeatherTests.xctest */,
+ AECBA6011B836BF20004A536 /* SwiftWeatherUITests.xctest */,
+ );
+ name = Products;
+ sourceTree = "";
+ };
+ AECBA5E41B836BF20004A536 /* SwiftWeather */ = {
+ isa = PBXGroup;
+ children = (
+ AE0DC2CB1B8E7ACE00E67147 /* Common */,
+ AEBE64411B8D231E004A0814 /* Features */,
+ AEBE643F1B8D22ED004A0814 /* Storyboards */,
+ AE6C34E71B84742900F726C2 /* fonts */,
+ AECBA5EC1B836BF20004A536 /* Assets.xcassets */,
+ AECBA5E51B836BF20004A536 /* AppDelegate.swift */,
+ AECBA5F11B836BF20004A536 /* Info.plist */,
+ );
+ path = SwiftWeather;
+ sourceTree = "";
+ };
+ AECBA5F91B836BF20004A536 /* SwiftWeatherTests */ = {
+ isa = PBXGroup;
+ children = (
+ F3897F7A1C118C4F001609E2 /* UnitTests */,
+ AECBA5FC1B836BF20004A536 /* Info.plist */,
+ );
+ path = SwiftWeatherTests;
+ sourceTree = "";
+ };
+ AECBA6041B836BF20004A536 /* SwiftWeatherUITests */ = {
+ isa = PBXGroup;
+ children = (
+ AECBA6051B836BF20004A536 /* SwiftWeatherUITests.swift */,
+ AECBA6071B836BF20004A536 /* Info.plist */,
+ );
+ path = SwiftWeatherUITests;
+ sourceTree = "";
+ };
+ AEF61B291BA23C0500E8F259 /* Services */ = {
+ isa = PBXGroup;
+ children = (
+ CAB56A3D23F4A93BB599E4BA /* WeatherServiceProtocol.swift */,
+ CAB56D46471CA243B1FD646F /* OpenWeatherMapService.swift */,
+ );
+ name = Services;
+ sourceTree = "";
+ };
+ AEF61B2B1BA23C2A00E8F259 /* Models */ = {
+ isa = PBXGroup;
+ children = (
+ AEBE64421B8D2370004A0814 /* Weather.swift */,
+ AEEDF68C1B9F9B2900C6067B /* Temperature.swift */,
+ EADFFD2F1CAEA22F008357FF /* TemperatureConverter.swift */,
+ AE2C7D6B1BA028C000A7A714 /* WeatherIcon.swift */,
+ AEEDF68A1B9F99F800C6067B /* WeatherBuilder.swift */,
+ );
+ name = Models;
+ sourceTree = "";
+ };
+ E117EDC87D7E5DC450870FDD /* Pods */ = {
+ isa = PBXGroup;
+ children = (
+ 900AFFBB41C69FC277CB0A33 /* Pods-SwiftWeather.debug.xcconfig */,
+ E835C39D4B929F35B6A57B12 /* Pods-SwiftWeather.release.xcconfig */,
+ BFCBC7111E6F5822A73508A5 /* Pods-Tests-SwiftWeatherTests.debug.xcconfig */,
+ F4007F80070D3AAE1C564D8D /* Pods-Tests-SwiftWeatherTests.release.xcconfig */,
+ 919B9EF9E5898277AD9C772A /* Pods-Tests-SwiftWeatherUITests.debug.xcconfig */,
+ 53EEE101C82E858E57980710 /* Pods-Tests-SwiftWeatherUITests.release.xcconfig */,
+ );
+ name = Pods;
+ sourceTree = "";
+ };
+ F3897F7A1C118C4F001609E2 /* UnitTests */ = {
+ isa = PBXGroup;
+ children = (
+ F3897F7B1C118C4F001609E2 /* ForecastDateTimeSpec.swift */,
+ F3897F7D1C118C6E001609E2 /* WeatherSpec.swift */,
+ F3897F7F1C118D7D001609E2 /* ForecastSpec.swift */,
+ F3897F811C118F0A001609E2 /* TemperatureSpec.swift */,
+ F3897F831C11911B001609E2 /* WeatherIconSpec.swift */,
+ F3FADA1A1C1327CB006D8551 /* WeatherBuilderSpec.swift */,
+ );
+ path = UnitTests;
+ sourceTree = "";
+ };
+/* End PBXGroup section */
+
+/* Begin PBXNativeTarget section */
+ AECBA5E11B836BF20004A536 /* SwiftWeather */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = AECBA60A1B836BF20004A536 /* Build configuration list for PBXNativeTarget "SwiftWeather" */;
+ buildPhases = (
+ 875372B40EF6130AA88D65AB /* [CP] Check Pods Manifest.lock */,
+ AECBA5DE1B836BF20004A536 /* Sources */,
+ AECBA5DF1B836BF20004A536 /* Frameworks */,
+ AECBA5E01B836BF20004A536 /* Resources */,
+ ADD0EBFC1C562E52002D8392 /* ShellScript */,
+ 6691608BB84CB91D5EDADE36 /* [CP] Embed Pods Frameworks */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = SwiftWeather;
+ productName = SwiftWeather;
+ productReference = AECBA5E21B836BF20004A536 /* SwiftWeather.app */;
+ productType = "com.apple.product-type.application";
+ };
+ AECBA5F51B836BF20004A536 /* SwiftWeatherTests */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = AECBA60D1B836BF20004A536 /* Build configuration list for PBXNativeTarget "SwiftWeatherTests" */;
+ buildPhases = (
+ 2A25B97139655BE3B502C748 /* [CP] Check Pods Manifest.lock */,
+ AECBA5F21B836BF20004A536 /* Sources */,
+ AECBA5F31B836BF20004A536 /* Frameworks */,
+ AECBA5F41B836BF20004A536 /* Resources */,
+ 3211EE071253F1D6513A17BA /* [CP] Embed Pods Frameworks */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ AECBA5F81B836BF20004A536 /* PBXTargetDependency */,
+ );
+ name = SwiftWeatherTests;
+ productName = SwiftWeatherTests;
+ productReference = AECBA5F61B836BF20004A536 /* SwiftWeatherTests.xctest */;
+ productType = "com.apple.product-type.bundle.unit-test";
+ };
+ AECBA6001B836BF20004A536 /* SwiftWeatherUITests */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = AECBA6101B836BF20004A536 /* Build configuration list for PBXNativeTarget "SwiftWeatherUITests" */;
+ buildPhases = (
+ 7E7F83383B6114FE2CC03BD6 /* [CP] Check Pods Manifest.lock */,
+ AECBA5FD1B836BF20004A536 /* Sources */,
+ AECBA5FE1B836BF20004A536 /* Frameworks */,
+ AECBA5FF1B836BF20004A536 /* Resources */,
+ EC9ED72913B1DE182823A53C /* [CP] Embed Pods Frameworks */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ AECBA6031B836BF20004A536 /* PBXTargetDependency */,
+ );
+ name = SwiftWeatherUITests;
+ productName = SwiftWeatherUITests;
+ productReference = AECBA6011B836BF20004A536 /* SwiftWeatherUITests.xctest */;
+ productType = "com.apple.product-type.bundle.ui-testing";
+ };
+/* End PBXNativeTarget section */
+
+/* Begin PBXProject section */
+ AECBA5DA1B836BF20004A536 /* Project object */ = {
+ isa = PBXProject;
+ attributes = {
+ LastSwiftUpdateCheck = 0710;
+ LastUpgradeCheck = 0900;
+ ORGANIZATIONNAME = "Jake Lin";
+ TargetAttributes = {
+ AECBA5E11B836BF20004A536 = {
+ CreatedOnToolsVersion = 7.0;
+ DevelopmentTeam = 32GB2HU6K5;
+ LastSwiftMigration = 0900;
+ };
+ AECBA5F51B836BF20004A536 = {
+ CreatedOnToolsVersion = 7.0;
+ LastSwiftMigration = 0900;
+ TestTargetID = AECBA5E11B836BF20004A536;
+ };
+ AECBA6001B836BF20004A536 = {
+ CreatedOnToolsVersion = 7.0;
+ LastSwiftMigration = 0900;
+ TestTargetID = AECBA5E11B836BF20004A536;
+ };
+ };
+ };
+ buildConfigurationList = AECBA5DD1B836BF20004A536 /* Build configuration list for PBXProject "SwiftWeather" */;
+ compatibilityVersion = "Xcode 3.2";
+ developmentRegion = English;
+ hasScannedForEncodings = 0;
+ knownRegions = (
+ en,
+ Base,
+ );
+ mainGroup = AECBA5D91B836BF20004A536;
+ productRefGroup = AECBA5E31B836BF20004A536 /* Products */;
+ projectDirPath = "";
+ projectRoot = "";
+ targets = (
+ AECBA5E11B836BF20004A536 /* SwiftWeather */,
+ AECBA5F51B836BF20004A536 /* SwiftWeatherTests */,
+ AECBA6001B836BF20004A536 /* SwiftWeatherUITests */,
+ );
+ };
+/* End PBXProject section */
+
+/* Begin PBXResourcesBuildPhase section */
+ AECBA5E01B836BF20004A536 /* Resources */ = {
+ isa = PBXResourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ AECBA5F01B836BF20004A536 /* LaunchScreen.storyboard in Resources */,
+ AECBA5ED1B836BF20004A536 /* Assets.xcassets in Resources */,
+ AE6C34E91B84742900F726C2 /* weathericons-regular-webfont.ttf in Resources */,
+ AECBA5EB1B836BF20004A536 /* Main.storyboard in Resources */,
+ AE26CCAB1B875C2400D518CB /* ForecastView.xib in Resources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ AECBA5F41B836BF20004A536 /* Resources */ = {
+ isa = PBXResourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ AECBA5FF1B836BF20004A536 /* Resources */ = {
+ isa = PBXResourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXResourcesBuildPhase section */
+
+/* Begin PBXShellScriptBuildPhase section */
+ 2A25B97139655BE3B502C748 /* [CP] Check Pods Manifest.lock */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ inputPaths = (
+ "${PODS_PODFILE_DIR_PATH}/Podfile.lock",
+ "${PODS_ROOT}/Manifest.lock",
+ );
+ name = "[CP] Check Pods Manifest.lock";
+ outputPaths = (
+ "$(DERIVED_FILE_DIR)/Pods-Tests-SwiftWeatherTests-checkManifestLockResult.txt",
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ shellPath = /bin/sh;
+ shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
+ showEnvVarsInLog = 0;
+ };
+ 3211EE071253F1D6513A17BA /* [CP] Embed Pods Frameworks */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ inputPaths = (
+ "${SRCROOT}/Pods/Target Support Files/Pods-Tests-SwiftWeatherTests/Pods-Tests-SwiftWeatherTests-frameworks.sh",
+ "${BUILT_PRODUCTS_DIR}/Nimble/Nimble.framework",
+ "${BUILT_PRODUCTS_DIR}/Quick/Quick.framework",
+ );
+ name = "[CP] Embed Pods Frameworks";
+ outputPaths = (
+ "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Nimble.framework",
+ "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Quick.framework",
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ shellPath = /bin/sh;
+ shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Tests-SwiftWeatherTests/Pods-Tests-SwiftWeatherTests-frameworks.sh\"\n";
+ showEnvVarsInLog = 0;
+ };
+ 6691608BB84CB91D5EDADE36 /* [CP] Embed Pods Frameworks */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ inputPaths = (
+ "${SRCROOT}/Pods/Target Support Files/Pods-SwiftWeather/Pods-SwiftWeather-frameworks.sh",
+ "${BUILT_PRODUCTS_DIR}/Bolts/Bolts.framework",
+ "${BUILT_PRODUCTS_DIR}/FBSDKCoreKit/FBSDKCoreKit.framework",
+ "${BUILT_PRODUCTS_DIR}/FBSDKShareKit/FBSDKShareKit.framework",
+ "${BUILT_PRODUCTS_DIR}/FacebookCore/FacebookCore.framework",
+ "${BUILT_PRODUCTS_DIR}/FacebookShare/FacebookShare.framework",
+ "${BUILT_PRODUCTS_DIR}/SwiftyJSON/SwiftyJSON.framework",
+ );
+ name = "[CP] Embed Pods Frameworks";
+ outputPaths = (
+ "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Bolts.framework",
+ "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/FBSDKCoreKit.framework",
+ "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/FBSDKShareKit.framework",
+ "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/FacebookCore.framework",
+ "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/FacebookShare.framework",
+ "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/SwiftyJSON.framework",
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ shellPath = /bin/sh;
+ shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-SwiftWeather/Pods-SwiftWeather-frameworks.sh\"\n";
+ showEnvVarsInLog = 0;
+ };
+ 7E7F83383B6114FE2CC03BD6 /* [CP] Check Pods Manifest.lock */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ inputPaths = (
+ "${PODS_PODFILE_DIR_PATH}/Podfile.lock",
+ "${PODS_ROOT}/Manifest.lock",
+ );
+ name = "[CP] Check Pods Manifest.lock";
+ outputPaths = (
+ "$(DERIVED_FILE_DIR)/Pods-Tests-SwiftWeatherUITests-checkManifestLockResult.txt",
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ shellPath = /bin/sh;
+ shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
+ showEnvVarsInLog = 0;
+ };
+ 875372B40EF6130AA88D65AB /* [CP] Check Pods Manifest.lock */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ inputPaths = (
+ "${PODS_PODFILE_DIR_PATH}/Podfile.lock",
+ "${PODS_ROOT}/Manifest.lock",
+ );
+ name = "[CP] Check Pods Manifest.lock";
+ outputPaths = (
+ "$(DERIVED_FILE_DIR)/Pods-SwiftWeather-checkManifestLockResult.txt",
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ shellPath = /bin/sh;
+ shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
+ showEnvVarsInLog = 0;
+ };
+ ADD0EBFC1C562E52002D8392 /* ShellScript */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ inputPaths = (
+ );
+ outputPaths = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ shellPath = /bin/sh;
+ shellScript = "token_file=.access_tokens/openweathermap\ntoken=\"$(cat $token_file)\"\nif [ \"$token\" ]; then\nplutil -replace OWMAccessToken -string $token $TARGET_BUILD_DIR/$INFOPLIST_PATH\nelse\necho 'error: Missing OpenWeatherMap access token'\nopen 'http://openweathermap.org/appid'\necho \"error: Get an access token from , then create a new file at $token_file that contains the access token.\"\nexit 1\nfi";
+ };
+ EC9ED72913B1DE182823A53C /* [CP] Embed Pods Frameworks */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ inputPaths = (
+ "${SRCROOT}/Pods/Target Support Files/Pods-Tests-SwiftWeatherUITests/Pods-Tests-SwiftWeatherUITests-frameworks.sh",
+ "${BUILT_PRODUCTS_DIR}/Nimble/Nimble.framework",
+ "${BUILT_PRODUCTS_DIR}/Quick/Quick.framework",
+ );
+ name = "[CP] Embed Pods Frameworks";
+ outputPaths = (
+ "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Nimble.framework",
+ "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Quick.framework",
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ shellPath = /bin/sh;
+ shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Tests-SwiftWeatherUITests/Pods-Tests-SwiftWeatherUITests-frameworks.sh\"\n";
+ showEnvVarsInLog = 0;
+ };
+/* End PBXShellScriptBuildPhase section */
+
+/* Begin PBXSourcesBuildPhase section */
+ AECBA5DE1B836BF20004A536 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ AE0DC2CD1B8E7B3900E67147 /* Observable.swift in Sources */,
+ AE2C7D6C1BA028C000A7A714 /* WeatherIcon.swift in Sources */,
+ AECBA5E81B836BF20004A536 /* WeatherViewController.swift in Sources */,
+ AEBE643B1B8D1F90004A0814 /* ForecastViewModel.swift in Sources */,
+ AECBA5E61B836BF20004A536 /* AppDelegate.swift in Sources */,
+ AEF61B281BA23B1200E8F259 /* ForecastDateTime.swift in Sources */,
+ AEEDF6891B9F09E300C6067B /* Error.swift in Sources */,
+ AEEDF68B1B9F99F800C6067B /* WeatherBuilder.swift in Sources */,
+ AEBE64451B8D23B8004A0814 /* WeatherViewModel.swift in Sources */,
+ AED4B2C21B876E8B0003D765 /* ForecastView.swift in Sources */,
+ EADFFD301CAEA22F008357FF /* TemperatureConverter.swift in Sources */,
+ AE09C4301B9723DE00C7CCED /* LocationService.swift in Sources */,
+ AEBE64431B8D2370004A0814 /* Weather.swift in Sources */,
+ AEBE643E1B8D2108004A0814 /* Forecast.swift in Sources */,
+ CAB56F4267B3BC487990A92D /* OpenWeatherMapService.swift in Sources */,
+ AEEDF68D1B9F9B2900C6067B /* Temperature.swift in Sources */,
+ CAB565DDADB61DF9053BD50F /* WeatherServiceProtocol.swift in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ AECBA5F21B836BF20004A536 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ F3897F7C1C118C4F001609E2 /* ForecastDateTimeSpec.swift in Sources */,
+ F3897F821C118F0A001609E2 /* TemperatureSpec.swift in Sources */,
+ F3897F7E1C118C6E001609E2 /* WeatherSpec.swift in Sources */,
+ F3FADA1B1C1327CB006D8551 /* WeatherBuilderSpec.swift in Sources */,
+ F3897F841C11911B001609E2 /* WeatherIconSpec.swift in Sources */,
+ F3897F801C118D7D001609E2 /* ForecastSpec.swift in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ AECBA5FD1B836BF20004A536 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ AECBA6061B836BF20004A536 /* SwiftWeatherUITests.swift in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXSourcesBuildPhase section */
+
+/* Begin PBXTargetDependency section */
+ AECBA5F81B836BF20004A536 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = AECBA5E11B836BF20004A536 /* SwiftWeather */;
+ targetProxy = AECBA5F71B836BF20004A536 /* PBXContainerItemProxy */;
+ };
+ AECBA6031B836BF20004A536 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = AECBA5E11B836BF20004A536 /* SwiftWeather */;
+ targetProxy = AECBA6021B836BF20004A536 /* PBXContainerItemProxy */;
+ };
+/* End PBXTargetDependency section */
+
+/* Begin PBXVariantGroup section */
+ AECBA5E91B836BF20004A536 /* Main.storyboard */ = {
+ isa = PBXVariantGroup;
+ children = (
+ AECBA5EA1B836BF20004A536 /* Base */,
+ );
+ name = Main.storyboard;
+ sourceTree = "";
+ };
+ AECBA5EE1B836BF20004A536 /* LaunchScreen.storyboard */ = {
+ isa = PBXVariantGroup;
+ children = (
+ AECBA5EF1B836BF20004A536 /* Base */,
+ );
+ name = LaunchScreen.storyboard;
+ sourceTree = "";
+ };
+/* End PBXVariantGroup section */
+
+/* Begin XCBuildConfiguration section */
+ AECBA6081B836BF20004A536 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ALWAYS_SEARCH_USER_PATHS = NO;
+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
+ CLANG_CXX_LIBRARY = "libc++";
+ CLANG_ENABLE_MODULES = YES;
+ CLANG_ENABLE_OBJC_ARC = YES;
+ CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
+ CLANG_WARN_BOOL_CONVERSION = YES;
+ CLANG_WARN_COMMA = YES;
+ CLANG_WARN_CONSTANT_CONVERSION = YES;
+ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+ CLANG_WARN_EMPTY_BODY = YES;
+ CLANG_WARN_ENUM_CONVERSION = YES;
+ CLANG_WARN_INFINITE_RECURSION = YES;
+ CLANG_WARN_INT_CONVERSION = YES;
+ CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
+ CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
+ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+ CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
+ CLANG_WARN_STRICT_PROTOTYPES = YES;
+ CLANG_WARN_SUSPICIOUS_MOVE = YES;
+ CLANG_WARN_UNREACHABLE_CODE = YES;
+ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
+ COPY_PHASE_STRIP = NO;
+ DEBUG_INFORMATION_FORMAT = dwarf;
+ ENABLE_STRICT_OBJC_MSGSEND = YES;
+ ENABLE_TESTABILITY = YES;
+ GCC_C_LANGUAGE_STANDARD = gnu99;
+ GCC_DYNAMIC_NO_PIC = NO;
+ GCC_NO_COMMON_BLOCKS = YES;
+ GCC_OPTIMIZATION_LEVEL = 0;
+ GCC_PREPROCESSOR_DEFINITIONS = (
+ "DEBUG=1",
+ "$(inherited)",
+ );
+ GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+ GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
+ GCC_WARN_UNDECLARED_SELECTOR = YES;
+ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
+ GCC_WARN_UNUSED_FUNCTION = YES;
+ GCC_WARN_UNUSED_VARIABLE = YES;
+ IPHONEOS_DEPLOYMENT_TARGET = 10.0;
+ MTL_ENABLE_DEBUG_INFO = YES;
+ ONLY_ACTIVE_ARCH = YES;
+ SDKROOT = iphoneos;
+ SWIFT_OPTIMIZATION_LEVEL = "-Onone";
+ SWIFT_VERSION = 3.0;
+ TARGETED_DEVICE_FAMILY = "1,2";
+ };
+ name = Debug;
+ };
+ AECBA6091B836BF20004A536 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ALWAYS_SEARCH_USER_PATHS = NO;
+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
+ CLANG_CXX_LIBRARY = "libc++";
+ CLANG_ENABLE_MODULES = YES;
+ CLANG_ENABLE_OBJC_ARC = YES;
+ CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
+ CLANG_WARN_BOOL_CONVERSION = YES;
+ CLANG_WARN_COMMA = YES;
+ CLANG_WARN_CONSTANT_CONVERSION = YES;
+ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+ CLANG_WARN_EMPTY_BODY = YES;
+ CLANG_WARN_ENUM_CONVERSION = YES;
+ CLANG_WARN_INFINITE_RECURSION = YES;
+ CLANG_WARN_INT_CONVERSION = YES;
+ CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
+ CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
+ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+ CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
+ CLANG_WARN_STRICT_PROTOTYPES = YES;
+ CLANG_WARN_SUSPICIOUS_MOVE = YES;
+ CLANG_WARN_UNREACHABLE_CODE = YES;
+ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
+ COPY_PHASE_STRIP = NO;
+ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+ ENABLE_NS_ASSERTIONS = NO;
+ ENABLE_STRICT_OBJC_MSGSEND = YES;
+ GCC_C_LANGUAGE_STANDARD = gnu99;
+ GCC_NO_COMMON_BLOCKS = YES;
+ GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+ GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
+ GCC_WARN_UNDECLARED_SELECTOR = YES;
+ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
+ GCC_WARN_UNUSED_FUNCTION = YES;
+ GCC_WARN_UNUSED_VARIABLE = YES;
+ IPHONEOS_DEPLOYMENT_TARGET = 10.0;
+ MTL_ENABLE_DEBUG_INFO = NO;
+ SDKROOT = iphoneos;
+ SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
+ SWIFT_VERSION = 3.0;
+ TARGETED_DEVICE_FAMILY = "1,2";
+ VALIDATE_PRODUCT = YES;
+ };
+ name = Release;
+ };
+ AECBA60B1B836BF20004A536 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ baseConfigurationReference = 900AFFBB41C69FC277CB0A33 /* Pods-SwiftWeather.debug.xcconfig */;
+ buildSettings = {
+ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
+ DEVELOPMENT_TEAM = 32GB2HU6K5;
+ INFOPLIST_FILE = SwiftWeather/Info.plist;
+ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
+ PRODUCT_BUNDLE_IDENTIFIER = com.rushjet.SwiftWeather;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ SWIFT_SWIFT3_OBJC_INFERENCE = Default;
+ SWIFT_VERSION = 4.0;
+ };
+ name = Debug;
+ };
+ AECBA60C1B836BF20004A536 /* Release */ = {
+ isa = XCBuildConfiguration;
+ baseConfigurationReference = E835C39D4B929F35B6A57B12 /* Pods-SwiftWeather.release.xcconfig */;
+ buildSettings = {
+ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
+ DEVELOPMENT_TEAM = 32GB2HU6K5;
+ INFOPLIST_FILE = SwiftWeather/Info.plist;
+ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
+ PRODUCT_BUNDLE_IDENTIFIER = com.rushjet.SwiftWeather;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ SWIFT_SWIFT3_OBJC_INFERENCE = Default;
+ SWIFT_VERSION = 4.0;
+ };
+ name = Release;
+ };
+ AECBA60E1B836BF20004A536 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ baseConfigurationReference = BFCBC7111E6F5822A73508A5 /* Pods-Tests-SwiftWeatherTests.debug.xcconfig */;
+ buildSettings = {
+ BUNDLE_LOADER = "$(TEST_HOST)";
+ CLANG_ENABLE_MODULES = YES;
+ DEVELOPMENT_TEAM = "";
+ INFOPLIST_FILE = SwiftWeatherTests/Info.plist;
+ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
+ PRODUCT_BUNDLE_IDENTIFIER = com.rushjet.SwiftWeatherTests;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ SWIFT_OPTIMIZATION_LEVEL = "-Onone";
+ SWIFT_SWIFT3_OBJC_INFERENCE = Default;
+ SWIFT_VERSION = 4.0;
+ TEST_HOST = "$(BUILT_PRODUCTS_DIR)/SwiftWeather.app/SwiftWeather";
+ };
+ name = Debug;
+ };
+ AECBA60F1B836BF20004A536 /* Release */ = {
+ isa = XCBuildConfiguration;
+ baseConfigurationReference = F4007F80070D3AAE1C564D8D /* Pods-Tests-SwiftWeatherTests.release.xcconfig */;
+ buildSettings = {
+ BUNDLE_LOADER = "$(TEST_HOST)";
+ CLANG_ENABLE_MODULES = YES;
+ DEVELOPMENT_TEAM = "";
+ INFOPLIST_FILE = SwiftWeatherTests/Info.plist;
+ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
+ PRODUCT_BUNDLE_IDENTIFIER = com.rushjet.SwiftWeatherTests;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ SWIFT_SWIFT3_OBJC_INFERENCE = Default;
+ SWIFT_VERSION = 4.0;
+ TEST_HOST = "$(BUILT_PRODUCTS_DIR)/SwiftWeather.app/SwiftWeather";
+ };
+ name = Release;
+ };
+ AECBA6111B836BF20004A536 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ baseConfigurationReference = 919B9EF9E5898277AD9C772A /* Pods-Tests-SwiftWeatherUITests.debug.xcconfig */;
+ buildSettings = {
+ DEVELOPMENT_TEAM = "";
+ INFOPLIST_FILE = SwiftWeatherUITests/Info.plist;
+ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
+ PRODUCT_BUNDLE_IDENTIFIER = com.rushjet.SwiftWeatherUITests;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ SWIFT_SWIFT3_OBJC_INFERENCE = Default;
+ SWIFT_VERSION = 4.0;
+ TEST_TARGET_NAME = SwiftWeather;
+ USES_XCTRUNNER = YES;
+ };
+ name = Debug;
+ };
+ AECBA6121B836BF20004A536 /* Release */ = {
+ isa = XCBuildConfiguration;
+ baseConfigurationReference = 53EEE101C82E858E57980710 /* Pods-Tests-SwiftWeatherUITests.release.xcconfig */;
+ buildSettings = {
+ DEVELOPMENT_TEAM = "";
+ INFOPLIST_FILE = SwiftWeatherUITests/Info.plist;
+ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
+ PRODUCT_BUNDLE_IDENTIFIER = com.rushjet.SwiftWeatherUITests;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ SWIFT_SWIFT3_OBJC_INFERENCE = Default;
+ SWIFT_VERSION = 4.0;
+ TEST_TARGET_NAME = SwiftWeather;
+ USES_XCTRUNNER = YES;
+ };
+ name = Release;
+ };
+/* End XCBuildConfiguration section */
+
+/* Begin XCConfigurationList section */
+ AECBA5DD1B836BF20004A536 /* Build configuration list for PBXProject "SwiftWeather" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ AECBA6081B836BF20004A536 /* Debug */,
+ AECBA6091B836BF20004A536 /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ AECBA60A1B836BF20004A536 /* Build configuration list for PBXNativeTarget "SwiftWeather" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ AECBA60B1B836BF20004A536 /* Debug */,
+ AECBA60C1B836BF20004A536 /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ AECBA60D1B836BF20004A536 /* Build configuration list for PBXNativeTarget "SwiftWeatherTests" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ AECBA60E1B836BF20004A536 /* Debug */,
+ AECBA60F1B836BF20004A536 /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ AECBA6101B836BF20004A536 /* Build configuration list for PBXNativeTarget "SwiftWeatherUITests" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ AECBA6111B836BF20004A536 /* Debug */,
+ AECBA6121B836BF20004A536 /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+/* End XCConfigurationList section */
+ };
+ rootObject = AECBA5DA1B836BF20004A536 /* Project object */;
+}
diff --git a/Swift Weather.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/SwiftWeather.xcodeproj/project.xcworkspace/contents.xcworkspacedata
similarity index 68%
rename from Swift Weather.xcodeproj/project.xcworkspace/contents.xcworkspacedata
rename to SwiftWeather.xcodeproj/project.xcworkspace/contents.xcworkspacedata
index 918049c..ea6a61a 100644
--- a/Swift Weather.xcodeproj/project.xcworkspace/contents.xcworkspacedata
+++ b/SwiftWeather.xcodeproj/project.xcworkspace/contents.xcworkspacedata
@@ -2,6 +2,6 @@
+ location = "self:SwiftWeather.xcodeproj">
diff --git a/SwiftWeather.xcworkspace/contents.xcworkspacedata b/SwiftWeather.xcworkspace/contents.xcworkspacedata
new file mode 100644
index 0000000..3ae5647
--- /dev/null
+++ b/SwiftWeather.xcworkspace/contents.xcworkspacedata
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
diff --git a/SwiftWeather/AppDelegate.swift b/SwiftWeather/AppDelegate.swift
new file mode 100644
index 0000000..ef6d9eb
--- /dev/null
+++ b/SwiftWeather/AppDelegate.swift
@@ -0,0 +1,53 @@
+//
+// AppDelegate.swift
+// SwiftWeather
+//
+// Created by Jake Lin on 8/18/15.
+// Copyright © 2015 Jake Lin. All rights reserved.
+//
+
+import UIKit
+
+@UIApplicationMain
+class AppDelegate: UIResponder, UIApplicationDelegate {
+
+ var window: UIWindow?
+
+ func application(_ application: UIApplication,
+ didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
+ // Override point for customization after application launch.
+ return true
+ }
+
+ func applicationWillResignActive(_ application: UIApplication) {
+ // Sent when the application is about to move from active to inactive state. This can occur for
+ // certain types of temporary interruptions (such as an incoming phone call or SMS message) or
+ // when the user quits the application and it begins the transition to the background state.
+ // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame
+ // rates. Games should use this method to pause the game.
+ }
+
+ func applicationDidEnterBackground(_ application: UIApplication) {
+ // Use this method to release shared resources, save user data, invalidate timers, and store
+ // enough application state information to restore your application to its current state in case
+ // it is terminated later.
+ // If your application supports background execution, this method is called instead of
+ // applicationWillTerminate: when the user quits.
+ }
+
+ func applicationWillEnterForeground(_ application: UIApplication) {
+ // Called as part of the transition from the background to the inactive state; here you can undo
+ // many of the changes made on entering the background.
+ }
+
+ func applicationDidBecomeActive(_ application: UIApplication) {
+ // Restart any tasks that were paused (or not yet started) while the application was inactive.
+ // If the application was previously in the background, optionally refresh the user interface.
+ }
+
+ func applicationWillTerminate(_ application: UIApplication) {
+ // Called when the application is about to terminate. Save data if appropriate. See also
+ // applicationDidEnterBackground:.
+ }
+
+}
diff --git a/Swift Weather/Images.xcassets/AppIcon.appiconset/Contents.json b/SwiftWeather/Assets.xcassets/AppIcon.appiconset/Contents.json
similarity index 71%
rename from Swift Weather/Images.xcassets/AppIcon.appiconset/Contents.json
rename to SwiftWeather/Assets.xcassets/AppIcon.appiconset/Contents.json
index 79c8882..d8db8d6 100644
--- a/Swift Weather/Images.xcassets/AppIcon.appiconset/Contents.json
+++ b/SwiftWeather/Assets.xcassets/AppIcon.appiconset/Contents.json
@@ -1,47 +1,55 @@
{
"images" : [
{
- "size" : "29x29",
"idiom" : "iphone",
- "filename" : "Icon-29.png",
- "scale" : "1x"
+ "size" : "20x20",
+ "scale" : "2x"
},
{
- "size" : "29x29",
"idiom" : "iphone",
- "filename" : "Icon-29@2x.png",
- "scale" : "2x"
+ "size" : "20x20",
+ "scale" : "3x"
},
{
+ "idiom" : "iphone",
"size" : "29x29",
+ "scale" : "2x"
+ },
+ {
"idiom" : "iphone",
- "filename" : "Icon-29@3x.png",
+ "size" : "29x29",
"scale" : "3x"
},
{
- "size" : "40x40",
"idiom" : "iphone",
- "filename" : "Icon-40@2x.png",
+ "size" : "40x40",
"scale" : "2x"
},
{
- "size" : "40x40",
"idiom" : "iphone",
- "filename" : "Icon-40@3x.png",
+ "size" : "40x40",
"scale" : "3x"
},
{
- "size" : "60x60",
"idiom" : "iphone",
- "filename" : "Icon-60@2x.png",
+ "size" : "60x60",
"scale" : "2x"
},
{
- "size" : "60x60",
"idiom" : "iphone",
- "filename" : "Icon-60@3x.png",
+ "size" : "60x60",
"scale" : "3x"
},
+ {
+ "idiom" : "ipad",
+ "size" : "20x20",
+ "scale" : "1x"
+ },
+ {
+ "idiom" : "ipad",
+ "size" : "20x20",
+ "scale" : "2x"
+ },
{
"idiom" : "ipad",
"size" : "29x29",
@@ -53,9 +61,8 @@
"scale" : "2x"
},
{
- "size" : "40x40",
"idiom" : "ipad",
- "filename" : "Icon-40.png",
+ "size" : "40x40",
"scale" : "1x"
},
{
@@ -69,21 +76,19 @@
"scale" : "1x"
},
{
- "size" : "76x76",
"idiom" : "ipad",
- "filename" : "Icon-76@2x.png",
+ "size" : "76x76",
"scale" : "2x"
},
{
- "idiom" : "mac",
- "size" : "512x512",
- "scale" : "1x"
+ "idiom" : "ipad",
+ "size" : "83.5x83.5",
+ "scale" : "2x"
},
{
- "size" : "512x512",
- "idiom" : "mac",
- "filename" : "iTunesArtwork@2x.png",
- "scale" : "2x"
+ "idiom" : "ios-marketing",
+ "size" : "1024x1024",
+ "scale" : "1x"
}
],
"info" : {
diff --git a/SwiftWeather/Assets.xcassets/Contents.json b/SwiftWeather/Assets.xcassets/Contents.json
new file mode 100644
index 0000000..da4a164
--- /dev/null
+++ b/SwiftWeather/Assets.xcassets/Contents.json
@@ -0,0 +1,6 @@
+{
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+}
\ No newline at end of file
diff --git a/Swift Weather/Images.xcassets/fog.imageset/Contents.json b/SwiftWeather/Assets.xcassets/background.imageset/Contents.json
similarity index 81%
rename from Swift Weather/Images.xcassets/fog.imageset/Contents.json
rename to SwiftWeather/Assets.xcassets/background.imageset/Contents.json
index 5623282..790c09f 100644
--- a/Swift Weather/Images.xcassets/fog.imageset/Contents.json
+++ b/SwiftWeather/Assets.xcassets/background.imageset/Contents.json
@@ -2,8 +2,8 @@
"images" : [
{
"idiom" : "universal",
- "scale" : "1x",
- "filename" : "fog.png"
+ "filename" : "background.png",
+ "scale" : "1x"
},
{
"idiom" : "universal",
diff --git a/SwiftWeather/Assets.xcassets/background.imageset/background.png b/SwiftWeather/Assets.xcassets/background.imageset/background.png
new file mode 100644
index 0000000..05e01f8
Binary files /dev/null and b/SwiftWeather/Assets.xcassets/background.imageset/background.png differ
diff --git a/Swift Weather/Images.xcassets/dunno.imageset/Contents.json b/SwiftWeather/Assets.xcassets/share.imageset/Contents.json
similarity index 82%
rename from Swift Weather/Images.xcassets/dunno.imageset/Contents.json
rename to SwiftWeather/Assets.xcassets/share.imageset/Contents.json
index c62fe51..bfbe1c1 100644
--- a/Swift Weather/Images.xcassets/dunno.imageset/Contents.json
+++ b/SwiftWeather/Assets.xcassets/share.imageset/Contents.json
@@ -2,8 +2,8 @@
"images" : [
{
"idiom" : "universal",
- "scale" : "1x",
- "filename" : "dunno.png"
+ "filename" : "share.png",
+ "scale" : "1x"
},
{
"idiom" : "universal",
diff --git a/SwiftWeather/Assets.xcassets/share.imageset/share.png b/SwiftWeather/Assets.xcassets/share.imageset/share.png
new file mode 100644
index 0000000..089f04a
Binary files /dev/null and b/SwiftWeather/Assets.xcassets/share.imageset/share.png differ
diff --git a/SwiftWeather/Base.lproj/LaunchScreen.storyboard b/SwiftWeather/Base.lproj/LaunchScreen.storyboard
new file mode 100644
index 0000000..5a9c4a6
--- /dev/null
+++ b/SwiftWeather/Base.lproj/LaunchScreen.storyboard
@@ -0,0 +1,27 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/SwiftWeather/Base.lproj/Main.storyboard b/SwiftWeather/Base.lproj/Main.storyboard
new file mode 100644
index 0000000..c3d1b9b
--- /dev/null
+++ b/SwiftWeather/Base.lproj/Main.storyboard
@@ -0,0 +1,271 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ WeatherIcons-Regular
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/SwiftWeather/Error.swift b/SwiftWeather/Error.swift
new file mode 100644
index 0000000..93b8272
--- /dev/null
+++ b/SwiftWeather/Error.swift
@@ -0,0 +1,18 @@
+//
+// Created by Jake Lin on 9/8/15.
+// Copyright © 2015 Jake Lin. All rights reserved.
+//
+
+import Foundation
+
+struct SWError {
+ enum Code: Int {
+ case urlError = -6000
+ case networkRequestFailed = -6001
+ case jsonSerializationFailed = -6002
+ case jsonParsingFailed = -6003
+ case unableToFindLocation = -6004
+ }
+
+ let errorCode: Code
+}
diff --git a/SwiftWeather/Forecast.swift b/SwiftWeather/Forecast.swift
new file mode 100644
index 0000000..9fac80c
--- /dev/null
+++ b/SwiftWeather/Forecast.swift
@@ -0,0 +1,12 @@
+//
+// Created by Jake Lin on 8/26/15.
+// Copyright © 2015 Jake Lin. All rights reserved.
+//
+
+import Foundation
+
+struct Forecast {
+ let time: String
+ let iconText: String
+ let temperature: String
+}
diff --git a/SwiftWeather/ForecastDateTime.swift b/SwiftWeather/ForecastDateTime.swift
new file mode 100644
index 0000000..23e5f1d
--- /dev/null
+++ b/SwiftWeather/ForecastDateTime.swift
@@ -0,0 +1,24 @@
+//
+// Created by Jake Lin on 9/11/15.
+// Copyright © 2015 Jake Lin. All rights reserved.
+//
+
+import Foundation
+
+struct ForecastDateTime {
+ let rawDate: Double
+ let timeZone: TimeZone
+
+ init(date: Double, timeZone: TimeZone) {
+ self.timeZone = timeZone
+ self.rawDate = date
+ }
+
+ var shortTime: String {
+ let dateFormatter = DateFormatter()
+ dateFormatter.timeZone = timeZone
+ dateFormatter.dateFormat = "HH:mm"
+ let date = Date(timeIntervalSince1970: rawDate)
+ return dateFormatter.string(from: date)
+ }
+}
diff --git a/SwiftWeather/ForecastView.swift b/SwiftWeather/ForecastView.swift
new file mode 100644
index 0000000..e17b780
--- /dev/null
+++ b/SwiftWeather/ForecastView.swift
@@ -0,0 +1,139 @@
+//
+// Created by Jake Lin on 8/22/15.
+// Copyright © 2015 Jake Lin. All rights reserved.
+//
+
+import UIKit
+
+@IBDesignable class ForecastView: UIView {
+ // Our custom view from the XIB file
+ var view: UIView!
+
+ @IBOutlet weak var timeLabel: UILabel!
+ @IBOutlet weak var iconLabel: UILabel!
+ @IBOutlet weak var temperatureLabel: UILabel!
+
+ // MARK: - init
+ override init(frame: CGRect) {
+ super.init(frame: frame)
+ view = loadViewFromNib()
+ }
+
+ required init?(coder aDecoder: NSCoder) {
+ super.init(coder: aDecoder)
+ view = loadViewFromNib()
+ }
+
+ func loadViewFromNib() -> UIView {
+ let bundle = Bundle(for: type(of: self))
+ let nib = UINib(nibName: nibName(), bundle: bundle)
+ // swiftlint:disable force_cast
+ let view = nib.instantiate(withOwner: self, options: nil)[0] as! UIView
+ // swiftlint:enable force_cast
+
+ view.frame = bounds
+ view.autoresizingMask = [.flexibleWidth, .flexibleHeight]
+ addSubview(view)
+ return view
+ }
+
+ // MARK: - ViewModel
+ var viewModel: ForecastViewModel? {
+ didSet {
+ viewModel?.time.observe {
+ [unowned self] in
+ self.timeLabel.text = $0
+ }
+
+ viewModel?.iconText.observe {
+ [unowned self] in
+ self.iconLabel.text = $0
+ }
+
+ viewModel?.temperature.observe {
+ [unowned self] in
+ self.temperatureLabel.text = $0
+ }
+ }
+ }
+
+ func loadViewModel(_ viewModel: ForecastViewModel) {
+ self.viewModel = viewModel
+ }
+
+ // MARK: - IBInspectable
+ @IBInspectable var time: String? {
+ get {
+ return timeLabel.text
+ }
+
+ set {
+ timeLabel.text = newValue
+ }
+ }
+
+ @IBInspectable var icon: String? {
+ get {
+ return iconLabel.text
+ }
+
+ set {
+ iconLabel.text = newValue
+ }
+ }
+
+ @IBInspectable var temperature: String? {
+ get {
+ return temperatureLabel.text
+ }
+
+ set {
+ temperatureLabel.text = newValue
+ }
+ }
+
+ @IBInspectable var timeColor: UIColor {
+ get {
+ return timeLabel.textColor
+ }
+
+ set {
+ timeLabel.textColor = newValue
+ }
+ }
+
+ @IBInspectable var iconColor: UIColor {
+ get {
+ return iconLabel.textColor
+ }
+
+ set {
+ iconLabel.textColor = newValue
+ }
+ }
+
+ @IBInspectable var temperatureColor: UIColor {
+ get {
+ return temperatureLabel.textColor
+ }
+
+ set {
+ temperatureLabel.textColor = newValue
+ }
+ }
+
+ @IBInspectable var bgColor: UIColor {
+ get {
+ return view.backgroundColor!
+ }
+
+ set {
+ view.backgroundColor = newValue
+ }
+ }
+
+ // MARK: - Private
+ fileprivate func nibName() -> String {
+ return String(describing: type(of: self))
+ }
+}
diff --git a/SwiftWeather/ForecastView.xib b/SwiftWeather/ForecastView.xib
new file mode 100644
index 0000000..6c7fca9
--- /dev/null
+++ b/SwiftWeather/ForecastView.xib
@@ -0,0 +1,62 @@
+
+
+
+
+
+
+
+ WeatherIcons-Regular
+ WeatherIcons-Regular
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/SwiftWeather/ForecastViewModel.swift b/SwiftWeather/ForecastViewModel.swift
new file mode 100644
index 0000000..df5ed19
--- /dev/null
+++ b/SwiftWeather/ForecastViewModel.swift
@@ -0,0 +1,18 @@
+//
+// Created by Jake Lin on 8/26/15.
+// Copyright © 2015 Jake Lin. All rights reserved.
+//
+
+import Foundation
+
+struct ForecastViewModel {
+ let time: Observable
+ let iconText: Observable
+ let temperature: Observable
+
+ init(_ forecast: Forecast) {
+ time = Observable(forecast.time)
+ iconText = Observable(forecast.iconText)
+ temperature = Observable(forecast.temperature)
+ }
+}
diff --git a/SwiftWeather/Info.plist b/SwiftWeather/Info.plist
new file mode 100644
index 0000000..5b2d434
--- /dev/null
+++ b/SwiftWeather/Info.plist
@@ -0,0 +1,78 @@
+
+
+
+
+ NSAppTransportSecurity
+
+ NSAllowsArbitraryLoads
+
+
+ NSLocationWhenInUseUsageDescription
+ Location is required to retrieve the weather info for your current place.
+ UIAppFonts
+
+ weathericons-regular-webfont.ttf
+
+ CFBundleDevelopmentRegion
+ en
+ CFBundleExecutable
+ $(EXECUTABLE_NAME)
+ CFBundleIdentifier
+ $(PRODUCT_BUNDLE_IDENTIFIER)
+ CFBundleInfoDictionaryVersion
+ 6.0
+ CFBundleName
+ $(PRODUCT_NAME)
+ CFBundlePackageType
+ APPL
+ CFBundleShortVersionString
+ 3.0
+ CFBundleSignature
+ ????
+ CFBundleVersion
+ 1
+ LSRequiresIPhoneOS
+
+ UILaunchStoryboardName
+ LaunchScreen
+ UIMainStoryboardFile
+ Main
+ UIRequiredDeviceCapabilities
+
+ armv7
+
+ UISupportedInterfaceOrientations
+
+ UIInterfaceOrientationPortrait
+ UIInterfaceOrientationLandscapeLeft
+ UIInterfaceOrientationLandscapeRight
+
+ UISupportedInterfaceOrientations~ipad
+
+ UIInterfaceOrientationPortrait
+ UIInterfaceOrientationPortraitUpsideDown
+ UIInterfaceOrientationLandscapeLeft
+ UIInterfaceOrientationLandscapeRight
+
+ CFBundleURLTypes
+
+
+ CFBundleURLSchemes
+
+ fb1725220270856995
+
+
+
+ FacebookAppID
+ 1725220270856995
+ FacebookDisplayName
+ Swift Weather
+ LSApplicationQueriesSchemes
+
+ fbapi
+ fb-messenger-share-api
+ fbauth2
+ fbshareextension
+
+
+
diff --git a/SwiftWeather/LocationService.swift b/SwiftWeather/LocationService.swift
new file mode 100644
index 0000000..ae50b2b
--- /dev/null
+++ b/SwiftWeather/LocationService.swift
@@ -0,0 +1,60 @@
+//
+// Created by Jake Lin on 9/2/15.
+// Copyright © 2015 Jake Lin. All rights reserved.
+//
+
+import Foundation
+import CoreLocation
+
+protocol LocationServiceDelegate {
+ func locationDidUpdate(_ service: LocationService, location: CLLocation)
+ func locationDidFail(withError error: SWError)
+}
+
+class LocationService: NSObject {
+ var delegate: LocationServiceDelegate?
+
+ fileprivate let locationManager = CLLocationManager()
+
+ override init() {
+ super.init()
+ locationManager.delegate = self
+ locationManager.desiredAccuracy = kCLLocationAccuracyHundredMeters
+ }
+
+ func requestLocation() {
+ locationManager.requestWhenInUseAuthorization()
+ locationManager.requestLocation()
+ }
+}
+
+// MARK: - CLLocationManager Delegate
+extension LocationService : CLLocationManagerDelegate {
+ func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
+ if let location = locations.first {
+ print("Current location: \(location)")
+ delegate?.locationDidUpdate(self, location: location)
+ }
+ }
+
+ func locationManager(_ manager: CLLocationManager, didFailWithError error: Error) {
+ let swError = SWError(errorCode: .unableToFindLocation)
+ delegate?.locationDidFail(withError: swError)
+ print("Error finding location: \(error.localizedDescription)")
+ }
+
+ // requestWhenInUseAuthorization issue #70
+ // Handle Authorization Status Changes
+ func locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) {
+ if status == .authorizedWhenInUse {
+ locationManager.requestLocation()
+ }
+ }
+
+ @available(iOS 14.0, *)
+ func locationManagerDidChangeAuthorization(_ manager: CLLocationManager) {
+ if manager.authorizationStatus == .authorizedWhenInUse{
+ locationManager.requestLocation()
+ }
+ }
+}
diff --git a/SwiftWeather/Observable.swift b/SwiftWeather/Observable.swift
new file mode 100644
index 0000000..996ef60
--- /dev/null
+++ b/SwiftWeather/Observable.swift
@@ -0,0 +1,26 @@
+//
+// Created by Jake Lin on 8/27/15.
+// Copyright © 2015 Jake Lin. All rights reserved.
+//
+
+import Foundation
+
+class Observable {
+ typealias Observer = (T) -> Void
+ var observer: Observer?
+
+ func observe(_ observer: Observer?) {
+ self.observer = observer
+ observer?(value)
+ }
+
+ var value: T {
+ didSet {
+ observer?(value)
+ }
+ }
+
+ init(_ value: T) {
+ self.value = value
+ }
+}
diff --git a/SwiftWeather/OpenWeatherMapService.swift b/SwiftWeather/OpenWeatherMapService.swift
new file mode 100644
index 0000000..b8de361
--- /dev/null
+++ b/SwiftWeather/OpenWeatherMapService.swift
@@ -0,0 +1,118 @@
+//
+// Created by Jake Lin on 9/2/15.
+// Copyright (c) 2015 Jake Lin. All rights reserved.
+//
+
+import Foundation
+import CoreLocation
+import SwiftyJSON
+
+struct OpenWeatherMapService: WeatherServiceProtocol {
+ fileprivate let urlPath = "http://api.openweathermap.org/data/2.5/forecast"
+
+ fileprivate func getFirstFourForecasts(_ json: JSON) -> [Forecast] {
+ var forecasts: [Forecast] = []
+
+ for index in 0...3 {
+ guard let forecastTempDegrees = json["list"][index]["main"]["temp"].double,
+ let rawDateTime = json["list"][index]["dt"].double,
+ let forecastCondition = json["list"][index]["weather"][0]["id"].int,
+ let forecastIcon = json["list"][index]["weather"][0]["icon"].string else {
+ break
+ }
+
+ let country = json["city"]["country"].string
+ let forecastTemperature = Temperature(country: country!,
+ openWeatherMapDegrees: forecastTempDegrees)
+ let forecastTimeString = ForecastDateTime(date: rawDateTime, timeZone: TimeZone.current).shortTime
+ let weatherIcon = WeatherIcon(condition: forecastCondition, iconString: forecastIcon)
+ let forcastIconText = weatherIcon.iconText
+
+ let forecast = Forecast(time: forecastTimeString,
+ iconText: forcastIconText,
+ temperature: forecastTemperature.degrees)
+
+ forecasts.append(forecast)
+ }
+
+ return forecasts
+ }
+
+ func retrieveWeatherInfo(_ location: CLLocation, completionHandler: @escaping WeatherCompletionHandler) {
+ let sessionConfig = URLSessionConfiguration.default
+ let session = URLSession(configuration: sessionConfig)
+
+ guard let url = generateRequestURL(location) else {
+ let error = SWError(errorCode: .urlError)
+ completionHandler(nil, error)
+ return
+ }
+
+ let task = session.dataTask(with: url) { (data, response, error) in
+ // Check network error
+ guard error == nil else {
+ let error = SWError(errorCode: .networkRequestFailed)
+ completionHandler(nil, error)
+ return
+ }
+
+ // Check JSON serialization error
+ guard let data = data else {
+ let error = SWError(errorCode: .jsonSerializationFailed)
+ completionHandler(nil, error)
+ return
+ }
+
+ guard let json = try? JSON(data: data) else {
+ let error = SWError(errorCode: .jsonParsingFailed)
+ completionHandler(nil, error)
+ return
+ }
+
+ // Get temperature, location and icon and check parsing error
+ guard let tempDegrees = json["list"][0]["main"]["temp"].double,
+ let country = json["city"]["country"].string,
+ let city = json["city"]["name"].string,
+ let weatherCondition = json["list"][0]["weather"][0]["id"].int,
+ let iconString = json["list"][0]["weather"][0]["icon"].string else {
+ let error = SWError(errorCode: .jsonParsingFailed)
+ completionHandler(nil, error)
+ return
+ }
+
+ var weatherBuilder = WeatherBuilder()
+ let temperature = Temperature(country: country, openWeatherMapDegrees:tempDegrees)
+ weatherBuilder.temperature = temperature.degrees
+ weatherBuilder.location = city
+
+ let weatherIcon = WeatherIcon(condition: weatherCondition, iconString: iconString)
+ weatherBuilder.iconText = weatherIcon.iconText
+
+ weatherBuilder.forecasts = self.getFirstFourForecasts(json)
+
+ completionHandler(weatherBuilder.build(), nil)
+ }
+
+ task.resume()
+ }
+
+ fileprivate func generateRequestURL(_ location: CLLocation) -> URL? {
+ guard var components = URLComponents(string:urlPath) else {
+ return nil
+ }
+
+ // get appId from Info.plist
+ let filePath = Bundle.main.path(forResource: "Info", ofType: "plist")!
+ let parameters = NSDictionary(contentsOfFile:filePath)
+ let appId = parameters!["OWMAccessToken"]! as! String
+
+ let latitude = String(location.coordinate.latitude)
+ let longitude = String(location.coordinate.longitude)
+
+ components.queryItems = [URLQueryItem(name:"lat", value:latitude),
+ URLQueryItem(name:"lon", value:longitude),
+ URLQueryItem(name:"appid", value:appId)]
+
+ return components.url
+ }
+}
diff --git a/SwiftWeather/Temperature.swift b/SwiftWeather/Temperature.swift
new file mode 100644
index 0000000..743e80d
--- /dev/null
+++ b/SwiftWeather/Temperature.swift
@@ -0,0 +1,18 @@
+//
+// Created by Jake Lin on 9/9/15.
+// Copyright © 2015 Jake Lin. All rights reserved.
+//
+
+import Foundation
+
+struct Temperature {
+ let degrees: String
+
+ init(country: String, openWeatherMapDegrees: Double) {
+ if country == "US" {
+ degrees = String(TemperatureConverter.kelvinToFahrenheit(openWeatherMapDegrees)) + "\u{f045}"
+ } else {
+ degrees = String(TemperatureConverter.kelvinToCelsius(openWeatherMapDegrees)) + "\u{f03c}"
+ }
+ }
+}
diff --git a/SwiftWeather/TemperatureConverter.swift b/SwiftWeather/TemperatureConverter.swift
new file mode 100644
index 0000000..bb360e7
--- /dev/null
+++ b/SwiftWeather/TemperatureConverter.swift
@@ -0,0 +1,16 @@
+//
+// Created by Tiago Martinho on 4/1/16.
+// Copyright © 2015 Jake Lin. All rights reserved.
+//
+
+import Foundation
+
+struct TemperatureConverter {
+ static func kelvinToCelsius(_ degrees: Double) -> Double {
+ return round(degrees - 273.15)
+ }
+
+ static func kelvinToFahrenheit(_ degrees: Double) -> Double {
+ return round(degrees * 9 / 5 - 459.67)
+ }
+}
diff --git a/SwiftWeather/Weather.swift b/SwiftWeather/Weather.swift
new file mode 100644
index 0000000..e047d5b
--- /dev/null
+++ b/SwiftWeather/Weather.swift
@@ -0,0 +1,14 @@
+//
+// Created by Jake Lin on 8/26/15.
+// Copyright © 2015 Jake Lin. All rights reserved.
+//
+
+import Foundation
+
+struct Weather {
+ let location: String
+ let iconText: String
+ let temperature: String
+
+ let forecasts: [Forecast]
+}
diff --git a/SwiftWeather/WeatherBuilder.swift b/SwiftWeather/WeatherBuilder.swift
new file mode 100644
index 0000000..5bdafcf
--- /dev/null
+++ b/SwiftWeather/WeatherBuilder.swift
@@ -0,0 +1,21 @@
+//
+// Created by Jake Lin on 9/9/15.
+// Copyright © 2015 Jake Lin. All rights reserved.
+//
+
+import Foundation
+
+struct WeatherBuilder {
+ var location: String?
+ var iconText: String?
+ var temperature: String?
+
+ var forecasts: [Forecast]?
+
+ func build() -> Weather {
+ return Weather(location: location!,
+ iconText: iconText!,
+ temperature: temperature!,
+ forecasts: forecasts!)
+ }
+}
diff --git a/SwiftWeather/WeatherIcon.swift b/SwiftWeather/WeatherIcon.swift
new file mode 100644
index 0000000..7569227
--- /dev/null
+++ b/SwiftWeather/WeatherIcon.swift
@@ -0,0 +1,289 @@
+//
+// Created by Jake Lin on 9/9/15.
+// Copyright © 2015 Jake Lin. All rights reserved.
+//
+
+import Foundation
+
+/*
+ `WeatherIcon` is used to map Open Weather Map icon string to Weather Icons unicode string.
+ It is generated by
+ ```
+ var caseString = '';
+ var caseAndReturnString = '';
+ Array.prototype.forEach.call(document.styleSheets[1].cssRules,function(element){
+ if (element.selectorText && element.selectorText.startsWith('.wi-owm')) {
+ var caseName = element.selectorText.substring(8,
+ element.selectorText.indexOf('::before')).replace('-', '')
+ caseString += 'case ' + caseName + ' = "' + caseName + '"\n';
+ caseAndReturnString += 'case .' + caseName + ': return "\\u{'
+ + element.style['content'].charCodeAt(1).toString(16) + '}"\n'
+ }
+ });
+ console.log(caseString);
+ console.log(caseAndReturnString);
+ ```
+*/
+// swiftlint:disable type_body_length
+struct WeatherIcon {
+ let iconText: String
+
+ enum IconType: String, CustomStringConvertible {
+ case day200 = "day200"
+ case day201 = "day201"
+ case day202 = "day202"
+ case day210 = "day210"
+ case day211 = "day211"
+ case day212 = "day212"
+ case day221 = "day221"
+ case day230 = "day230"
+ case day231 = "day231"
+ case day232 = "day232"
+ case day300 = "day300"
+ case day301 = "day301"
+ case day302 = "day302"
+ case day310 = "day310"
+ case day311 = "day311"
+ case day312 = "day312"
+ case day313 = "day313"
+ case day314 = "day314"
+ case day321 = "day321"
+ case day500 = "day500"
+ case day501 = "day501"
+ case day502 = "day502"
+ case day503 = "day503"
+ case day504 = "day504"
+ case day511 = "day511"
+ case day520 = "day520"
+ case day521 = "day521"
+ case day522 = "day522"
+ case day531 = "day531"
+ case day600 = "day600"
+ case day601 = "day601"
+ case day602 = "day602"
+ case day611 = "day611"
+ case day612 = "day612"
+ case day615 = "day615"
+ case day616 = "day616"
+ case day620 = "day620"
+ case day621 = "day621"
+ case day622 = "day622"
+ case day701 = "day701"
+ case day711 = "day711"
+ case day721 = "day721"
+ case day731 = "day731"
+ case day741 = "day741"
+ case day761 = "day761"
+ case day762 = "day762"
+ case day781 = "day781"
+ case day800 = "day800"
+ case day801 = "day801"
+ case day802 = "day802"
+ case day803 = "day803"
+ case day804 = "day804"
+ case day900 = "day900"
+ case day902 = "day902"
+ case day903 = "day903"
+ case day904 = "day904"
+ case day906 = "day906"
+ case day957 = "day957"
+ case night200 = "night200"
+ case night201 = "night201"
+ case night202 = "night202"
+ case night210 = "night210"
+ case night211 = "night211"
+ case night212 = "night212"
+ case night221 = "night221"
+ case night230 = "night230"
+ case night231 = "night231"
+ case night232 = "night232"
+ case night300 = "night300"
+ case night301 = "night301"
+ case night302 = "night302"
+ case night310 = "night310"
+ case night311 = "night311"
+ case night312 = "night312"
+ case night313 = "night313"
+ case night314 = "night314"
+ case night321 = "night321"
+ case night500 = "night500"
+ case night501 = "night501"
+ case night502 = "night502"
+ case night503 = "night503"
+ case night504 = "night504"
+ case night511 = "night511"
+ case night520 = "night520"
+ case night521 = "night521"
+ case night522 = "night522"
+ case night531 = "night531"
+ case night600 = "night600"
+ case night601 = "night601"
+ case night602 = "night602"
+ case night611 = "night611"
+ case night612 = "night612"
+ case night615 = "night615"
+ case night616 = "night616"
+ case night620 = "night620"
+ case night621 = "night621"
+ case night622 = "night622"
+ case night701 = "night701"
+ case night711 = "night711"
+ case night721 = "night721"
+ case night731 = "night731"
+ case night741 = "night741"
+ case night761 = "night761"
+ case night762 = "night762"
+ case night781 = "night781"
+ case night800 = "night800"
+ case night801 = "night801"
+ case night802 = "night802"
+ case night803 = "night803"
+ case night804 = "night804"
+ case night900 = "night900"
+ case night902 = "night902"
+ case night903 = "night903"
+ case night904 = "night904"
+ case night906 = "night906"
+ case night957 = "night957"
+
+ var description: String {
+ switch self {
+ case .day200: return "\u{f010}"
+ case .day201: return "\u{f010}"
+ case .day202: return "\u{f010}"
+ case .day210: return "\u{f005}"
+ case .day211: return "\u{f005}"
+ case .day212: return "\u{f005}"
+ case .day221: return "\u{f005}"
+ case .day230: return "\u{f010}"
+ case .day231: return "\u{f010}"
+ case .day232: return "\u{f010}"
+ case .day300: return "\u{f00b}"
+ case .day301: return "\u{f00b}"
+ case .day302: return "\u{f008}"
+ case .day310: return "\u{f008}"
+ case .day311: return "\u{f008}"
+ case .day312: return "\u{f008}"
+ case .day313: return "\u{f008}"
+ case .day314: return "\u{f008}"
+ case .day321: return "\u{f00b}"
+ case .day500: return "\u{f00b}"
+ case .day501: return "\u{f008}"
+ case .day502: return "\u{f008}"
+ case .day503: return "\u{f008}"
+ case .day504: return "\u{f008}"
+ case .day511: return "\u{f006}"
+ case .day520: return "\u{f009}"
+ case .day521: return "\u{f009}"
+ case .day522: return "\u{f009}"
+ case .day531: return "\u{f00e}"
+ case .day600: return "\u{f00a}"
+ case .day601: return "\u{f0b2}"
+ case .day602: return "\u{f00a}"
+ case .day611: return "\u{f006}"
+ case .day612: return "\u{f006}"
+ case .day615: return "\u{f006}"
+ case .day616: return "\u{f006}"
+ case .day620: return "\u{f006}"
+ case .day621: return "\u{f00a}"
+ case .day622: return "\u{f00a}"
+ case .day701: return "\u{f009}"
+ case .day711: return "\u{f062}"
+ case .day721: return "\u{f0b6}"
+ case .day731: return "\u{f063}"
+ case .day741: return "\u{f003}"
+ case .day761: return "\u{f063}"
+ case .day762: return "\u{f063}"
+ case .day781: return "\u{f056}"
+ case .day800: return "\u{f00d}"
+ case .day801: return "\u{f000}"
+ case .day802: return "\u{f000}"
+ case .day803: return "\u{f000}"
+ case .day804: return "\u{f00c}"
+ case .day900: return "\u{f056}"
+ case .day902: return "\u{f073}"
+ case .day903: return "\u{f076}"
+ case .day904: return "\u{f072}"
+ case .day906: return "\u{f004}"
+ case .day957: return "\u{f050}"
+ case .night200: return "\u{f02d}"
+ case .night201: return "\u{f02d}"
+ case .night202: return "\u{f02d}"
+ case .night210: return "\u{f025}"
+ case .night211: return "\u{f025}"
+ case .night212: return "\u{f025}"
+ case .night221: return "\u{f025}"
+ case .night230: return "\u{f02d}"
+ case .night231: return "\u{f02d}"
+ case .night232: return "\u{f02d}"
+ case .night300: return "\u{f02b}"
+ case .night301: return "\u{f02b}"
+ case .night302: return "\u{f028}"
+ case .night310: return "\u{f028}"
+ case .night311: return "\u{f028}"
+ case .night312: return "\u{f028}"
+ case .night313: return "\u{f028}"
+ case .night314: return "\u{f028}"
+ case .night321: return "\u{f02b}"
+ case .night500: return "\u{f02b}"
+ case .night501: return "\u{f028}"
+ case .night502: return "\u{f028}"
+ case .night503: return "\u{f028}"
+ case .night504: return "\u{f028}"
+ case .night511: return "\u{f026}"
+ case .night520: return "\u{f029}"
+ case .night521: return "\u{f029}"
+ case .night522: return "\u{f029}"
+ case .night531: return "\u{f02c}"
+ case .night600: return "\u{f02a}"
+ case .night601: return "\u{f0b4}"
+ case .night602: return "\u{f02a}"
+ case .night611: return "\u{f026}"
+ case .night612: return "\u{f026}"
+ case .night615: return "\u{f026}"
+ case .night616: return "\u{f026}"
+ case .night620: return "\u{f026}"
+ case .night621: return "\u{f02a}"
+ case .night622: return "\u{f02a}"
+ case .night701: return "\u{f029}"
+ case .night711: return "\u{f062}"
+ case .night721: return "\u{f0b6}"
+ case .night731: return "\u{f063}"
+ case .night741: return "\u{f04a}"
+ case .night761: return "\u{f063}"
+ case .night762: return "\u{f063}"
+ case .night781: return "\u{f056}"
+ case .night800: return "\u{f02e}"
+ case .night801: return "\u{f022}"
+ case .night802: return "\u{f022}"
+ case .night803: return "\u{f022}"
+ case .night804: return "\u{f086}"
+ case .night900: return "\u{f056}"
+ case .night902: return "\u{f073}"
+ case .night903: return "\u{f076}"
+ case .night904: return "\u{f072}"
+ case .night906: return "\u{f024}"
+ case .night957: return "\u{f050}"
+ }
+ }
+ }
+
+ init(condition: Int, iconString: String) {
+ var rawValue: String
+
+ // if iconString has 'n', it means night time.
+ if iconString.range(of: "n") != nil {
+ rawValue = "night" + String(condition)
+ } else {
+ // day time
+ rawValue = "day" + String(condition)
+ }
+
+ guard let iconType = IconType(rawValue: rawValue) else {
+ iconText = ""
+ return
+ }
+ iconText = iconType.description
+ }
+}
+// swiftlint:enable type_body_length
diff --git a/SwiftWeather/WeatherServiceProtocol.swift b/SwiftWeather/WeatherServiceProtocol.swift
new file mode 100644
index 0000000..8a009ed
--- /dev/null
+++ b/SwiftWeather/WeatherServiceProtocol.swift
@@ -0,0 +1,13 @@
+//
+// Created by Jake Lin on 9/2/15.
+// Copyright (c) 2015 Jake Lin. All rights reserved.
+//
+
+import Foundation
+import CoreLocation
+
+typealias WeatherCompletionHandler = (Weather?, SWError?) -> Void
+
+protocol WeatherServiceProtocol {
+ func retrieveWeatherInfo(_ location: CLLocation, completionHandler: @escaping WeatherCompletionHandler)
+}
diff --git a/SwiftWeather/WeatherViewController.swift b/SwiftWeather/WeatherViewController.swift
new file mode 100644
index 0000000..8fa0ba1
--- /dev/null
+++ b/SwiftWeather/WeatherViewController.swift
@@ -0,0 +1,145 @@
+//
+// Created by Jake Lin on 8/18/15.
+// Copyright © 2015 Jake Lin. All rights reserved.
+//
+
+import UIKit
+import FacebookShare
+import CoreSpotlight
+import MobileCoreServices
+
+//MARK: - UIViewController Properties
+class WeatherViewController: UIViewController {
+
+ //MARK: - IBOutlets
+ @IBOutlet weak var locationLabel: UILabel!
+ @IBOutlet weak var iconLabel: UILabel!
+ @IBOutlet weak var temperatureLabel: UILabel!
+ @IBOutlet var forecastViews: [ForecastView]!
+
+ let identifier = "WeatherIdentifier"
+
+ //MARK: - Super Methods
+ override func viewDidLoad() {
+ super.viewDidLoad()
+ viewModel = WeatherViewModel()
+ viewModel?.startLocationService()
+ setAccessibilityIdentifiers()
+ }
+
+ override func viewWillAppear(_ animated: Bool) {
+ super.viewWillAppear(animated)
+ configureLabels()
+ }
+
+ override func viewDidAppear(_ animated: Bool) {
+ super.viewDidAppear(animated)
+ configureLabelsWithAnimation()
+ }
+
+ //MARK: ViewModel
+ var viewModel: WeatherViewModel? {
+ didSet {
+ setLocationLabel()
+ viewModel?.iconText.observe {
+ [unowned self] in
+ self.iconLabel.text = $0
+ }
+
+ viewModel?.temperature.observe {
+ [unowned self] in
+ self.temperatureLabel.text = $0
+ }
+ setForcastView()
+ }
+ }
+
+ //MARK: Accessibility
+ func setAccessibilityIdentifiers() {
+ locationLabel.accessibilityIdentifier = "a11y_current_city"
+ iconLabel.accessibilityIdentifier = "a11y_wheather_icon"
+ temperatureLabel.accessibilityIdentifier = "a11y_wheather_temperature"
+ }
+
+ //MARK: Functions
+ func configureLabels(){
+ locationLabel.center.x -= view.bounds.width
+ iconLabel.center.x -= view.bounds.width
+ temperatureLabel.center.x -= view.bounds.width
+ iconLabel.alpha = 0.0
+ locationLabel.alpha = 0.0
+ temperatureLabel.alpha = 0.0
+ }
+
+ func configureLabelsWithAnimation(){
+ UIView.animate(withDuration: 0.5, animations: {
+ self.locationLabel.center.x += self.view.bounds.width
+ })
+
+ UIView.animate(withDuration: 0.5, delay: 0.3, usingSpringWithDamping: 0.2, initialSpringVelocity: 0.0, options: [], animations: {
+ self.iconLabel.center.x += self.view.bounds.width
+ }, completion: nil)
+
+ UIView.animate(withDuration: 0.5, delay: 0.4, usingSpringWithDamping: 0.2, initialSpringVelocity: 0.0, options: [], animations: {
+ self.temperatureLabel.center.x += self.view.bounds.width
+ }, completion: nil)
+
+ UIView.animate(withDuration: 0.5, delay: 0.3, options: [], animations: {
+ self.iconLabel.alpha = 1.0
+ }, completion: nil)
+
+ UIView.animate(withDuration: 0.5, delay: 0.4, options: [], animations: {
+ self.locationLabel.alpha = 1.0
+ }, completion: nil)
+
+ UIView.animate(withDuration: 0.5, delay: 0.5, options: [], animations: {
+ self.temperatureLabel.alpha = 1.0
+ }, completion: nil)
+ }
+
+ //MARK: Actions
+ @IBAction func shareButtonPressed(_ sender: Any) {
+ shareOnFacebook()
+ }
+
+ func shareOnFacebook(){
+ let photo = Photo(image: #imageLiteral(resourceName: "background"), userGenerated: false)
+ let myContent = PhotoShareContent(photos: [photo])
+ let shareDialog = ShareDialog(content: myContent)
+ shareDialog.mode = .native
+ shareDialog.failsOnInvalidData = true
+
+ try? shareDialog.show()
+ }
+
+ //MARK: Private Functions
+ private func setLocationLabel() {
+ viewModel?.location.observe {
+ [unowned self] in
+ self.locationLabel.text = $0
+
+ let attributeSet = CSSearchableItemAttributeSet(itemContentType: kUTTypeText as String)
+ attributeSet.title = self.locationLabel.text
+
+ let item = CSSearchableItem(uniqueIdentifier: self.identifier, domainIdentifier: "com.rushjet.SwiftWeather", attributeSet: attributeSet)
+ CSSearchableIndex.default().indexSearchableItems([item]){error in
+ if let error = error {
+ print("Indexing error: \(error.localizedDescription)")
+ } else {
+ print("Location item successfully indexed")
+ }
+ }
+ }
+ }
+
+ private func setForcastView() {
+ viewModel?.forecasts.observe {
+ [unowned self] (forecastViewModels) in
+ if forecastViewModels.count >= 4 {
+ for (index, forecastView) in self.forecastViews.enumerated() {
+ forecastView.loadViewModel(forecastViewModels[index])
+ }
+ }
+ }
+ }
+}
diff --git a/SwiftWeather/WeatherViewModel.swift b/SwiftWeather/WeatherViewModel.swift
new file mode 100644
index 0000000..e826951
--- /dev/null
+++ b/SwiftWeather/WeatherViewModel.swift
@@ -0,0 +1,107 @@
+//
+// Created by Jake Lin on 8/26/15.
+// Copyright © 2015 Jake Lin. All rights reserved.
+//
+
+import Foundation
+import CoreLocation
+
+class WeatherViewModel {
+ // MARK: - Constants
+ fileprivate let emptyString = ""
+
+ // MARK: - Properties
+ let hasError: Observable
+ let errorMessage: Observable
+
+ let location: Observable
+ let iconText: Observable
+ let temperature: Observable
+ let forecasts: Observable<[ForecastViewModel]>
+
+ // MARK: - Services
+ fileprivate var locationService: LocationService
+ fileprivate var weatherService: WeatherServiceProtocol
+
+ // MARK: - init
+ init() {
+ hasError = Observable(false)
+ errorMessage = Observable(nil)
+
+ location = Observable(emptyString)
+ iconText = Observable(emptyString)
+ temperature = Observable(emptyString)
+ forecasts = Observable([])
+
+ // Can put Dependency Injection here
+ locationService = LocationService()
+ weatherService = OpenWeatherMapService()
+ }
+
+ // MARK: - public
+ func startLocationService() {
+ locationService.delegate = self
+ locationService.requestLocation()
+ }
+
+ // MARK: - private
+ fileprivate func update(_ weather: Weather) {
+ hasError.value = false
+ errorMessage.value = nil
+
+ location.value = weather.location
+ iconText.value = weather.iconText
+ temperature.value = weather.temperature
+
+ let tempForecasts = weather.forecasts.map { forecast in
+ return ForecastViewModel(forecast)
+ }
+ forecasts.value = tempForecasts
+ }
+
+ fileprivate func update(_ error: SWError) {
+ hasError.value = true
+
+ switch error.errorCode {
+ case .urlError:
+ errorMessage.value = "The weather service is not working."
+ case .networkRequestFailed:
+ errorMessage.value = "The network appears to be down."
+ case .jsonSerializationFailed:
+ errorMessage.value = "We're having trouble processing weather data."
+ case .jsonParsingFailed:
+ errorMessage.value = "We're having trouble parsing weather data."
+ case .unableToFindLocation:
+ errorMessage.value = "We're having trouble getting user location."
+ }
+
+ location.value = emptyString
+ iconText.value = emptyString
+ temperature.value = emptyString
+ self.forecasts.value = []
+ }
+}
+
+// MARK: LocationServiceDelegate
+extension WeatherViewModel: LocationServiceDelegate {
+ func locationDidUpdate(_ service: LocationService, location: CLLocation) {
+ weatherService.retrieveWeatherInfo(location) { (weather, error) -> Void in
+ DispatchQueue.main.async(execute: {
+ if let unwrappedError = error {
+ print(unwrappedError)
+ self.update(unwrappedError)
+ return
+ }
+
+ guard let unwrappedWeather = weather else {
+ return
+ }
+ self.update(unwrappedWeather)
+ })
+ }
+ }
+
+ func locationDidFail(withError error: SWError) {
+ self.update(error)
+ }
+}
diff --git a/SwiftWeather/fonts/weathericons-regular-webfont.ttf b/SwiftWeather/fonts/weathericons-regular-webfont.ttf
new file mode 100755
index 0000000..f971fba
Binary files /dev/null and b/SwiftWeather/fonts/weathericons-regular-webfont.ttf differ
diff --git a/Swift WeatherTests/Info.plist b/SwiftWeatherTests/Info.plist
similarity index 64%
rename from Swift WeatherTests/Info.plist
rename to SwiftWeatherTests/Info.plist
index af7eb87..ba72822 100644
--- a/Swift WeatherTests/Info.plist
+++ b/SwiftWeatherTests/Info.plist
@@ -2,20 +2,16 @@
- NSLocationAlwaysUsageDescription
- would like to use your current location
- NSLocationWhenInUsageDescription
- would like to use your current location
CFBundleDevelopmentRegion
en
CFBundleExecutable
- ${EXECUTABLE_NAME}
+ $(EXECUTABLE_NAME)
CFBundleIdentifier
- com.rushjet.${PRODUCT_NAME:rfc1034identifier}
+ $(PRODUCT_BUNDLE_IDENTIFIER)
CFBundleInfoDictionaryVersion
6.0
CFBundleName
- ${PRODUCT_NAME}
+ $(PRODUCT_NAME)
CFBundlePackageType
BNDL
CFBundleShortVersionString
diff --git a/SwiftWeatherTests/UnitTests/ForecastDateTimeSpec.swift b/SwiftWeatherTests/UnitTests/ForecastDateTimeSpec.swift
new file mode 100644
index 0000000..d9c89e7
--- /dev/null
+++ b/SwiftWeatherTests/UnitTests/ForecastDateTimeSpec.swift
@@ -0,0 +1,33 @@
+//
+// Created by Tran Xuan Hoang on 12/4/15.
+// Copyright © 2015 Jake Lin. All rights reserved.
+//
+
+import Quick
+import Nimble
+@testable import SwiftWeather
+
+class ForecastDateTimeSpec: QuickSpec {
+
+ private let testTimeZone = TimeZone(abbreviation: "UTC+11:00")!
+
+ override func spec() {
+ describe("#init") {
+ it("should init with the rawDate correctly assigned") {
+ var forecastDateTime = ForecastDateTime(date: 1488096060, timeZone: self.testTimeZone)
+ expect(forecastDateTime.rawDate).to(beCloseTo(1488096060))
+ forecastDateTime = ForecastDateTime(date: 0, timeZone: self.testTimeZone)
+ expect(forecastDateTime.rawDate).to(beCloseTo(0))
+ }
+ }
+
+ describe("#shortTime") {
+ it("should return the correct shortTime string with format HH:mm") {
+ var forecastDateTime = ForecastDateTime(date: 1488096060, timeZone: self.testTimeZone)
+ expect(forecastDateTime.shortTime).to(equal("7:01 PM"))
+ forecastDateTime = ForecastDateTime(date: 1488103200, timeZone: self.testTimeZone)
+ expect(forecastDateTime.shortTime).to(equal("9:00 PM"))
+ }
+ }
+ }
+}
diff --git a/SwiftWeatherTests/UnitTests/ForecastSpec.swift b/SwiftWeatherTests/UnitTests/ForecastSpec.swift
new file mode 100644
index 0000000..49db22e
--- /dev/null
+++ b/SwiftWeatherTests/UnitTests/ForecastSpec.swift
@@ -0,0 +1,25 @@
+//
+// Created by Tran Xuan Hoang on 12/4/15.
+// Copyright © 2015 Jake Lin. All rights reserved.
+//
+
+import Quick
+import Nimble
+@testable import SwiftWeather
+
+class ForecastSpec: QuickSpec {
+
+ override func spec() {
+
+ describe("#init") {
+ it("should have time, iconText, temperature") {
+ let forecast = Forecast(time: "time", iconText: "iconText", temperature: "temperature")
+ expect(forecast.time).to(equal("time"))
+ expect(forecast.iconText).to(equal("iconText"))
+ expect(forecast.temperature).to(equal("temperature"))
+ }
+ }
+
+ }
+
+}
diff --git a/SwiftWeatherTests/UnitTests/TemperatureSpec.swift b/SwiftWeatherTests/UnitTests/TemperatureSpec.swift
new file mode 100644
index 0000000..ad8c7d6
--- /dev/null
+++ b/SwiftWeatherTests/UnitTests/TemperatureSpec.swift
@@ -0,0 +1,31 @@
+//
+// Created by Tran Xuan Hoang on 12/4/15.
+// Copyright © 2015 Jake Lin. All rights reserved.
+//
+
+import Quick
+import Nimble
+@testable import SwiftWeather
+
+class TemperatureSpec: QuickSpec {
+
+ override func spec() {
+
+ describe("#init(country:openWeatherMapDegrees:)") {
+ context("country is US") {
+ it("should convert temperature to Fahrenheit") {
+ let temperature = Temperature(country: "US", openWeatherMapDegrees: 20)
+ expect(temperature.degrees).to(equal("-424.0" + "\u{f045}"))
+ }
+ }
+ context("country is not US") {
+ it("should convert to Celsius") {
+ let temperature = Temperature(country: "ABC", openWeatherMapDegrees: 20)
+ expect(temperature.degrees).to(equal("-253.0" + "\u{f03c}"))
+ }
+ }
+ }
+
+ }
+
+}
diff --git a/SwiftWeatherTests/UnitTests/WeatherBuilderSpec.swift b/SwiftWeatherTests/UnitTests/WeatherBuilderSpec.swift
new file mode 100644
index 0000000..e5bbdf3
--- /dev/null
+++ b/SwiftWeatherTests/UnitTests/WeatherBuilderSpec.swift
@@ -0,0 +1,28 @@
+//
+// Created by Tran Xuan Hoang on 12/5/15.
+// Copyright © 2015 Jake Lin. All rights reserved.
+//
+
+import Quick
+import Nimble
+@testable import SwiftWeather
+
+class WeatherBuilderSpec: QuickSpec {
+
+ override func spec() {
+
+ describe("#build") {
+ it("should create a Weather model with all the properties correctly") {
+ let builder = WeatherBuilder(location: "location", iconText: "iconText",
+ temperature: "temperature", forecasts: [])
+ let weather = builder.build()
+ expect(weather.location).to(equal("location"))
+ expect(weather.iconText).to(equal("iconText"))
+ expect(weather.temperature).to(equal("temperature"))
+ expect(weather.forecasts.count).to(equal(0))
+ }
+ }
+
+ }
+
+}
diff --git a/SwiftWeatherTests/UnitTests/WeatherIconSpec.swift b/SwiftWeatherTests/UnitTests/WeatherIconSpec.swift
new file mode 100644
index 0000000..9670f72
--- /dev/null
+++ b/SwiftWeatherTests/UnitTests/WeatherIconSpec.swift
@@ -0,0 +1,172 @@
+//
+// Created by Tran Xuan Hoang on 12/4/15.
+// Copyright © 2015 Jake Lin. All rights reserved.
+//
+
+import Quick
+import Nimble
+@testable import SwiftWeather
+
+class WeatherIconSpec: QuickSpec {
+
+ let dayDictionary = [
+ 200: "\u{f010}",
+ 201: "\u{f010}",
+ 202: "\u{f010}",
+ 210: "\u{f005}",
+ 211: "\u{f005}",
+ 212: "\u{f005}",
+ 221: "\u{f005}",
+ 230: "\u{f010}",
+ 231: "\u{f010}",
+ 232: "\u{f010}",
+ 300: "\u{f00b}",
+ 301: "\u{f00b}",
+ 302: "\u{f008}",
+ 310: "\u{f008}",
+ 311: "\u{f008}",
+ 312: "\u{f008}",
+ 313: "\u{f008}",
+ 314: "\u{f008}",
+ 321: "\u{f00b}",
+ 500: "\u{f00b}",
+ 501: "\u{f008}",
+ 502: "\u{f008}",
+ 503: "\u{f008}",
+ 504: "\u{f008}",
+ 511: "\u{f006}",
+ 520: "\u{f009}",
+ 521: "\u{f009}",
+ 522: "\u{f009}",
+ 531: "\u{f00e}",
+ 600: "\u{f00a}",
+ 601: "\u{f0b2}",
+ 602: "\u{f00a}",
+ 611: "\u{f006}",
+ 612: "\u{f006}",
+ 615: "\u{f006}",
+ 616: "\u{f006}",
+ 620: "\u{f006}",
+ 621: "\u{f00a}",
+ 622: "\u{f00a}",
+ 701: "\u{f009}",
+ 711: "\u{f062}",
+ 721: "\u{f0b6}",
+ 731: "\u{f063}",
+ 741: "\u{f003}",
+ 761: "\u{f063}",
+ 762: "\u{f063}",
+ 781: "\u{f056}",
+ 800: "\u{f00d}",
+ 801: "\u{f000}",
+ 802: "\u{f000}",
+ 803: "\u{f000}",
+ 804: "\u{f00c}",
+ 900: "\u{f056}",
+ 902: "\u{f073}",
+ 903: "\u{f076}",
+ 904: "\u{f072}",
+ 906: "\u{f004}",
+ 957: "\u{f050}"
+ ]
+ let nightDictionary = [
+ 200: "\u{f02d}",
+ 201: "\u{f02d}",
+ 202: "\u{f02d}",
+ 210: "\u{f025}",
+ 211: "\u{f025}",
+ 212: "\u{f025}",
+ 221: "\u{f025}",
+ 230: "\u{f02d}",
+ 231: "\u{f02d}",
+ 232: "\u{f02d}",
+ 300: "\u{f02b}",
+ 301: "\u{f02b}",
+ 302: "\u{f028}",
+ 310: "\u{f028}",
+ 311: "\u{f028}",
+ 312: "\u{f028}",
+ 313: "\u{f028}",
+ 314: "\u{f028}",
+ 321: "\u{f02b}",
+ 500: "\u{f02b}",
+ 501: "\u{f028}",
+ 502: "\u{f028}",
+ 503: "\u{f028}",
+ 504: "\u{f028}",
+ 511: "\u{f026}",
+ 520: "\u{f029}",
+ 521: "\u{f029}",
+ 522: "\u{f029}",
+ 531: "\u{f02c}",
+ 600: "\u{f02a}",
+ 601: "\u{f0b4}",
+ 602: "\u{f02a}",
+ 611: "\u{f026}",
+ 612: "\u{f026}",
+ 615: "\u{f026}",
+ 616: "\u{f026}",
+ 620: "\u{f026}",
+ 621: "\u{f02a}",
+ 622: "\u{f02a}",
+ 701: "\u{f029}",
+ 711: "\u{f062}",
+ 721: "\u{f0b6}",
+ 731: "\u{f063}",
+ 741: "\u{f04a}",
+ 761: "\u{f063}",
+ 762: "\u{f063}",
+ 781: "\u{f056}",
+ 800: "\u{f02e}",
+ 801: "\u{f022}",
+ 802: "\u{f022}",
+ 803: "\u{f022}",
+ 804: "\u{f086}",
+ 900: "\u{f056}",
+ 902: "\u{f073}",
+ 903: "\u{f076}",
+ 904: "\u{f072}",
+ 906: "\u{f024}",
+ 957: "\u{f050}"
+ ]
+
+ override func spec() {
+
+ describe("#init(condition:,iconString:)") {
+ context("day") {
+ context("invalid condition Int") {
+ self.expectWeatherIconWithCondition(999, isDay: true, toHaveIconTextEqualToString: "")
+ }
+ context("valid condition Int") {
+ for (condition, description) in self.dayDictionary {
+ self.expectWeatherIconWithCondition(condition, isDay: true,
+ toHaveIconTextEqualToString: description)
+ }
+ }
+ }
+ context("night") {
+ context("invalid condition Int") {
+ self.expectWeatherIconWithCondition(999, isDay: false, toHaveIconTextEqualToString: "")
+ }
+ context("valid condition Int") {
+ for (condition, description) in self.nightDictionary {
+ self.expectWeatherIconWithCondition(condition, isDay: false,
+ toHaveIconTextEqualToString: description)
+ }
+ }
+ }
+ }
+
+ }
+
+}
+
+extension WeatherIconSpec {
+
+ func expectWeatherIconWithCondition(_ condition: Int, isDay: Bool,
+ toHaveIconTextEqualToString description: String) {
+ let weatherIcon = WeatherIcon(condition: condition, iconString: isDay ? "day" : "night")
+ expect(weatherIcon.iconText).to(equal(description))
+ }
+
+}
diff --git a/SwiftWeatherTests/UnitTests/WeatherSpec.swift b/SwiftWeatherTests/UnitTests/WeatherSpec.swift
new file mode 100644
index 0000000..1f370c6
--- /dev/null
+++ b/SwiftWeatherTests/UnitTests/WeatherSpec.swift
@@ -0,0 +1,27 @@
+//
+// Created by Tran Xuan Hoang on 12/4/15.
+// Copyright © 2015 Jake Lin. All rights reserved.
+//
+
+import Quick
+import Nimble
+@testable import SwiftWeather
+
+class WeatherSpec: QuickSpec {
+
+ override func spec() {
+
+ describe("#init") {
+ it("should have location, iconText, temperature and forecasts") {
+ let weather = Weather(location: "location", iconText: "iconText",
+ temperature: "temperature", forecasts: [])
+ expect(weather.location).to(equal("location"))
+ expect(weather.iconText).to(equal("iconText"))
+ expect(weather.temperature).to(equal("temperature"))
+ expect(weather.forecasts.count).to(equal(0))
+ }
+ }
+
+ }
+
+}
diff --git a/Swift Weather Instant/Info.plist b/SwiftWeatherUITests/Info.plist
similarity index 64%
rename from Swift Weather Instant/Info.plist
rename to SwiftWeatherUITests/Info.plist
index a0d9ab7..ba72822 100644
--- a/Swift Weather Instant/Info.plist
+++ b/SwiftWeatherUITests/Info.plist
@@ -4,30 +4,21 @@
CFBundleDevelopmentRegion
en
- CFBundleDisplayName
- Swift Weather Instant
CFBundleExecutable
$(EXECUTABLE_NAME)
CFBundleIdentifier
- com.rushjet.Swift-Weather.$(PRODUCT_NAME:rfc1034identifier)
+ $(PRODUCT_BUNDLE_IDENTIFIER)
CFBundleInfoDictionaryVersion
6.0
CFBundleName
$(PRODUCT_NAME)
CFBundlePackageType
- XPC!
+ BNDL
CFBundleShortVersionString
1.0
CFBundleSignature
????
CFBundleVersion
1
- NSExtension
-
- NSExtensionMainStoryboard
- MainInterface
- NSExtensionPointIdentifier
- com.apple.widget-extension
-
diff --git a/SwiftWeatherUITests/SwiftWeatherUITests.swift b/SwiftWeatherUITests/SwiftWeatherUITests.swift
new file mode 100644
index 0000000..6d18bed
--- /dev/null
+++ b/SwiftWeatherUITests/SwiftWeatherUITests.swift
@@ -0,0 +1,70 @@
+//
+// Created by Jake Lin on 8/18/15.
+// Copyright © 2015 Jake Lin. All rights reserved.
+//
+
+import XCTest
+import Quick
+import Nimble
+
+class SwiftWeatherUITests: QuickSpec {
+
+ override func spec() {
+ let app = XCUIApplication()
+
+ beforeSuite {
+ self.continueAfterFailure = false
+
+ app.launch()
+ }
+
+ describe("a wheather viewcontroller") {
+ context("location service is enabled") {
+ context("when in portrait") {
+ beforeEach {
+ XCUIDevice.shared.orientation = .portrait
+ }
+ itBehavesLike("a properly laidout wheather viewcontroller")
+ }
+
+ context("when in landscape") {
+ beforeEach {
+ XCUIDevice.shared.orientation = .landscapeLeft
+ }
+ itBehavesLike("a properly laidout wheather viewcontroller")
+ }
+ }
+ }
+ }
+}
+
+class RegularWheatherViewControllerConfiguration: QuickConfiguration {
+ override class func configure(_ configuration: Configuration) {
+ let app = XCUIApplication()
+ let window = app.windows.element(boundBy: 0)
+
+ sharedExamples("a properly laidout wheather viewcontroller") { (context: SharedExampleContext) in
+ it("shows city") {
+ let cityLabel = app.staticTexts["a11y_current_city"]
+
+ expect(cityLabel.exists).to(beTruthy())
+ expect(window.frame.contains(cityLabel.frame)).to(beTruthy())
+ }
+
+ it("shows wheather icon") {
+ let wheatherIconLabel = app.staticTexts["a11y_wheather_icon"]
+
+ expect(wheatherIconLabel.exists).to(beTruthy())
+ expect(window.frame.contains(wheatherIconLabel.frame)).to(beTruthy())
+ }
+
+ it("shows wheather temperature") {
+ let wheatherTemperatureLabel = app.staticTexts["a11y_wheather_temperature"]
+
+ expect(wheatherTemperatureLabel.exists).to(beTruthy())
+ expect(window.frame.contains(wheatherTemperatureLabel.frame)).to(beTruthy())
+ }
+ }
+ }
+}
+
diff --git a/buddybuild_postclone.sh b/buddybuild_postclone.sh
new file mode 100644
index 0000000..7b33dcd
--- /dev/null
+++ b/buddybuild_postclone.sh
@@ -0,0 +1,5 @@
+#!/usr/bin/env bash
+cd /Users/buddybuild/workspace
+
+mkdir .access_tokens
+echo $OPENWEATHERMAP > .access_tokens/openweathermap
diff --git a/screenshots/Custom-UIView.png b/screenshots/Custom-UIView.png
new file mode 100644
index 0000000..8ac66c8
Binary files /dev/null and b/screenshots/Custom-UIView.png differ
diff --git a/screenshots/IBDesignable-IBInspectable.png b/screenshots/IBDesignable-IBInspectable.png
new file mode 100644
index 0000000..16f8caf
Binary files /dev/null and b/screenshots/IBDesignable-IBInspectable.png differ
diff --git a/screenshots/SketchDesign.png b/screenshots/SketchDesign.png
new file mode 100644
index 0000000..9872a23
Binary files /dev/null and b/screenshots/SketchDesign.png differ
diff --git a/screenshots/UIStackView-with-Size-Classes.png b/screenshots/UIStackView-with-Size-Classes.png
new file mode 100644
index 0000000..5a4b3c4
Binary files /dev/null and b/screenshots/UIStackView-with-Size-Classes.png differ
diff --git a/screenshots/UIStackView.png b/screenshots/UIStackView.png
new file mode 100644
index 0000000..5f376c8
Binary files /dev/null and b/screenshots/UIStackView.png differ