diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..11c5ea08 --- /dev/null +++ b/.gitignore @@ -0,0 +1,94 @@ +# Xcode +# +# gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore + +## User settings +xcuserdata/ + +## API keys +/Clima/Keys.plist + + +## compatibility with Xcode 8 and earlier (ignoring not required starting Xcode 9) +*.xcscmblueprint +*.xccheckout + +## compatibility with Xcode 3 and earlier (ignoring not required starting Xcode 4) +build/ +DerivedData/ +*.moved-aside +*.pbxuser +!default.pbxuser +*.mode1v3 +!default.mode1v3 +*.mode2v3 +!default.mode2v3 +*.perspectivev3 +!default.perspectivev3 + +## Obj-C/Swift specific +*.hmap + +## App packaging +*.ipa +*.dSYM.zip +*.dSYM + +## Playgrounds +timeline.xctimeline +playground.xcworkspace + +# Swift Package Manager +# +# Add this line if you want to avoid checking in source code from Swift Package Manager dependencies. +# Packages/ +# Package.pins +# Package.resolved +# *.xcodeproj +# +# Xcode automatically generates this directory with a .xcworkspacedata file and xcuserdata +# hence it is not needed unless you have added a package configuration file to your project +# .swiftpm + +.build/ + +# CocoaPods +# +# We recommend against adding the Pods directory to your .gitignore. However +# you should judge for yourself, the pros and cons are mentioned at: +# https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control +# +# Pods/ +# +# Add this line if you want to avoid checking in source code from the Xcode workspace +# *.xcworkspace + +# Carthage +# +# Add this line if you want to avoid checking in source code from Carthage dependencies. +# Carthage/Checkouts + +Carthage/Build/ + +# Accio dependency management +Dependencies/ +.accio/ + +# fastlane +# +# It is recommended to not store the screenshots in the git repo. +# Instead, use fastlane to re-generate the screenshots whenever they are needed. +# For more information about the recommended setup visit: +# https://docs.fastlane.tools/best-practices/source-control/#source-control + +fastlane/report.xml +fastlane/Preview.html +fastlane/screenshots/**/*.png +fastlane/test_output + +# Code Injection +# +# After new code Injection tools there's a generated folder /iOSInjectionProject +# https://github.com/johnno1962/injectionforxcode + +iOSInjectionProject/ diff --git a/Clima.xcodeproj/project.pbxproj b/Clima.xcodeproj/project.pbxproj index 076632ce..2b20dc61 100644 --- a/Clima.xcodeproj/project.pbxproj +++ b/Clima.xcodeproj/project.pbxproj @@ -3,22 +3,29 @@ archiveVersion = 1; classes = { }; - objectVersion = 50; + objectVersion = 53; objects = { /* Begin PBXBuildFile section */ + 1260ECE829E18F9F002569CF /* WeatherManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1260ECE729E18F9F002569CF /* WeatherManager.swift */; }; + 126AAEC929E889E900173620 /* WeatherData.swift in Sources */ = {isa = PBXBuildFile; fileRef = 126AAEC829E889E900173620 /* WeatherData.swift */; }; + 126AAECB29E9D38400173620 /* WeatherModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 126AAECA29E9D38400173620 /* WeatherModel.swift */; }; + 12BE3F1C2A4F3D7D0078E526 /* Keys.plist in Resources */ = {isa = PBXBuildFile; fileRef = 12BE3F1B2A4F3D7D0078E526 /* Keys.plist */; }; ADAA27B1231BBFAF00365194 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = ADAA27B0231BBFAF00365194 /* AppDelegate.swift */; }; ADAA27B3231BBFAF00365194 /* SceneDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = ADAA27B2231BBFAF00365194 /* SceneDelegate.swift */; }; ADAA27B5231BBFAF00365194 /* WeatherViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = ADAA27B4231BBFAF00365194 /* WeatherViewController.swift */; }; ADAA27B8231BBFAF00365194 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = ADAA27B6231BBFAF00365194 /* Main.storyboard */; }; ADAA27BA231BBFB300365194 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = ADAA27B9231BBFB300365194 /* Assets.xcassets */; }; ADAA27BD231BBFB300365194 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = ADAA27BB231BBFB300365194 /* LaunchScreen.storyboard */; }; - ADAA27C6231BC02C00365194 /* light_background.pdf in Resources */ = {isa = PBXBuildFile; fileRef = ADAA27C4231BC02B00365194 /* light_background.pdf */; }; - ADAA27C7231BC02C00365194 /* dark_background.pdf in Resources */ = {isa = PBXBuildFile; fileRef = ADAA27C5231BC02B00365194 /* dark_background.pdf */; }; ADAA27CE231BC87F00365194 /* README.md in Resources */ = {isa = PBXBuildFile; fileRef = ADAA27CD231BC87F00365194 /* README.md */; }; /* End PBXBuildFile section */ /* Begin PBXFileReference section */ + 1260ECE729E18F9F002569CF /* WeatherManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = WeatherManager.swift; path = Clima/Model/WeatherManager.swift; sourceTree = SOURCE_ROOT; }; + 126AAEC829E889E900173620 /* WeatherData.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WeatherData.swift; sourceTree = ""; }; + 126AAECA29E9D38400173620 /* WeatherModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WeatherModel.swift; sourceTree = ""; }; + 12BB5E152A213A810093C6C1 /* Clima.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = Clima.entitlements; sourceTree = ""; }; + 12BE3F1B2A4F3D7D0078E526 /* Keys.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Keys.plist; sourceTree = ""; }; ADAA27AD231BBFAF00365194 /* Clima.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Clima.app; sourceTree = BUILT_PRODUCTS_DIR; }; ADAA27B0231BBFAF00365194 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; ADAA27B2231BBFAF00365194 /* SceneDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SceneDelegate.swift; sourceTree = ""; }; @@ -27,8 +34,6 @@ ADAA27B9231BBFB300365194 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; ADAA27BC231BBFB300365194 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; ADAA27BE231BBFB300365194 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - ADAA27C4231BC02B00365194 /* light_background.pdf */ = {isa = PBXFileReference; lastKnownFileType = image.pdf; path = light_background.pdf; sourceTree = ""; }; - ADAA27C5231BC02B00365194 /* dark_background.pdf */ = {isa = PBXFileReference; lastKnownFileType = image.pdf; path = dark_background.pdf; sourceTree = ""; }; ADAA27CD231BC87F00365194 /* README.md */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = ""; }; /* End PBXFileReference section */ @@ -43,6 +48,16 @@ /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ + 126AAEC729E18FF900173620 /* Model */ = { + isa = PBXGroup; + children = ( + 1260ECE729E18F9F002569CF /* WeatherManager.swift */, + 126AAEC829E889E900173620 /* WeatherData.swift */, + 126AAECA29E9D38400173620 /* WeatherModel.swift */, + ); + path = Model; + sourceTree = ""; + }; ADAA27A4231BBFAF00365194 = { isa = PBXGroup; children = ( @@ -63,16 +78,16 @@ ADAA27AF231BBFAF00365194 /* Clima */ = { isa = PBXGroup; children = ( + 12BB5E152A213A810093C6C1 /* Clima.entitlements */, ADAA27B0231BBFAF00365194 /* AppDelegate.swift */, ADAA27B2231BBFAF00365194 /* SceneDelegate.swift */, - ADAA27CA231BC3FA00365194 /* Model */, + 126AAEC729E18FF900173620 /* Model */, ADAA27C9231BC3F200365194 /* View */, ADAA27C8231BC3E500365194 /* Controller */, ADAA27B9231BBFB300365194 /* Assets.xcassets */, ADAA27BB231BBFB300365194 /* LaunchScreen.storyboard */, ADAA27BE231BBFB300365194 /* Info.plist */, - ADAA27C5231BC02B00365194 /* dark_background.pdf */, - ADAA27C4231BC02B00365194 /* light_background.pdf */, + 12BE3F1B2A4F3D7D0078E526 /* Keys.plist */, ); path = Clima; sourceTree = ""; @@ -93,13 +108,6 @@ path = View; sourceTree = ""; }; - ADAA27CA231BC3FA00365194 /* Model */ = { - isa = PBXGroup; - children = ( - ); - path = Model; - sourceTree = ""; - }; /* End PBXGroup section */ /* Begin PBXNativeTarget section */ @@ -126,8 +134,9 @@ ADAA27A5231BBFAF00365194 /* Project object */ = { isa = PBXProject; attributes = { + BuildIndependentTargetsInParallel = YES; LastSwiftUpdateCheck = 1100; - LastUpgradeCheck = 1100; + LastUpgradeCheck = 1430; ORGANIZATIONNAME = "App Brewery"; TargetAttributes = { ADAA27AC231BBFAF00365194 = { @@ -159,11 +168,10 @@ buildActionMask = 2147483647; files = ( ADAA27CE231BC87F00365194 /* README.md in Resources */, - ADAA27C7231BC02C00365194 /* dark_background.pdf in Resources */, ADAA27BD231BBFB300365194 /* LaunchScreen.storyboard in Resources */, ADAA27BA231BBFB300365194 /* Assets.xcassets in Resources */, ADAA27B8231BBFAF00365194 /* Main.storyboard in Resources */, - ADAA27C6231BC02C00365194 /* light_background.pdf in Resources */, + 12BE3F1C2A4F3D7D0078E526 /* Keys.plist in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -175,7 +183,10 @@ buildActionMask = 2147483647; files = ( ADAA27B5231BBFAF00365194 /* WeatherViewController.swift in Sources */, + 126AAEC929E889E900173620 /* WeatherData.swift in Sources */, ADAA27B1231BBFAF00365194 /* AppDelegate.swift in Sources */, + 1260ECE829E18F9F002569CF /* WeatherManager.swift in Sources */, + 126AAECB29E9D38400173620 /* WeatherModel.swift in Sources */, ADAA27B3231BBFAF00365194 /* SceneDelegate.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -228,6 +239,7 @@ CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; @@ -288,6 +300,7 @@ CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; @@ -320,14 +333,22 @@ isa = XCBuildConfiguration; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CODE_SIGN_ENTITLEMENTS = Clima/Clima.entitlements; CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + DEVELOPMENT_TEAM = 5422CL2MVH; INFOPLIST_FILE = Clima/Info.plist; + INFOPLIST_KEY_CFBundleDisplayName = Clima; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", ); - PRODUCT_BUNDLE_IDENTIFIER = co.appbrewery.Clima; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = seoanemartin.ramon.Clima; PRODUCT_NAME = "$(TARGET_NAME)"; + SUPPORTED_PLATFORMS = "iphoneos iphonesimulator"; + SUPPORTS_MACCATALYST = YES; + SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = YES; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; }; @@ -337,14 +358,22 @@ isa = XCBuildConfiguration; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CODE_SIGN_ENTITLEMENTS = Clima/Clima.entitlements; CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + DEVELOPMENT_TEAM = 5422CL2MVH; INFOPLIST_FILE = Clima/Info.plist; + INFOPLIST_KEY_CFBundleDisplayName = Clima; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", ); - PRODUCT_BUNDLE_IDENTIFIER = co.appbrewery.Clima; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = seoanemartin.ramon.Clima; PRODUCT_NAME = "$(TARGET_NAME)"; + SUPPORTED_PLATFORMS = "iphoneos iphonesimulator"; + SUPPORTS_MACCATALYST = YES; + SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = YES; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; }; diff --git a/Clima/AppDelegate.swift b/Clima/AppDelegate.swift index b618e6ac..0436002b 100644 --- a/Clima/AppDelegate.swift +++ b/Clima/AppDelegate.swift @@ -11,11 +11,15 @@ import UIKit @UIApplicationMain class AppDelegate: UIResponder, UIApplicationDelegate { - + var keys: NSDictionary? func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { - // Override point for customization after application launch. - return true + // Override point for customization after application launch. + if let path = Bundle.main.path(forResource: "Keys", ofType: "plist") { + keys = NSDictionary(contentsOfFile: path) + } + + return true } // MARK: UISceneSession Lifecycle diff --git a/Clima/Assets.xcassets/Contents.json b/Clima/Assets.xcassets/Contents.json index da4a164c..73c00596 100644 --- a/Clima/Assets.xcassets/Contents.json +++ b/Clima/Assets.xcassets/Contents.json @@ -1,6 +1,6 @@ { "info" : { - "version" : 1, - "author" : "xcode" + "author" : "xcode", + "version" : 1 } -} \ No newline at end of file +} diff --git a/Clima/Assets.xcassets/background.imageset/Contents.json b/Clima/Assets.xcassets/background.imageset/Contents.json index 790c09f1..d89173a8 100644 --- a/Clima/Assets.xcassets/background.imageset/Contents.json +++ b/Clima/Assets.xcassets/background.imageset/Contents.json @@ -1,21 +1,35 @@ { "images" : [ { - "idiom" : "universal", - "filename" : "background.png", - "scale" : "1x" + "filename" : "light_background.pdf", + "idiom" : "universal" }, { - "idiom" : "universal", - "scale" : "2x" + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "light" + } + ], + "filename" : "light_background 1.pdf", + "idiom" : "universal" }, { - "idiom" : "universal", - "scale" : "3x" + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "filename" : "dark_background.pdf", + "idiom" : "universal" } ], "info" : { - "version" : 1, - "author" : "xcode" + "author" : "xcode", + "version" : 1 + }, + "properties" : { + "preserves-vector-representation" : true } -} \ No newline at end of file +} diff --git a/Clima/Assets.xcassets/background.imageset/background.png b/Clima/Assets.xcassets/background.imageset/background.png deleted file mode 100644 index 22e31fdb..00000000 Binary files a/Clima/Assets.xcassets/background.imageset/background.png and /dev/null differ diff --git a/Clima/dark_background.pdf b/Clima/Assets.xcassets/background.imageset/dark_background.pdf similarity index 100% rename from Clima/dark_background.pdf rename to Clima/Assets.xcassets/background.imageset/dark_background.pdf diff --git a/Clima/light_background.pdf b/Clima/Assets.xcassets/background.imageset/light_background 1.pdf similarity index 100% rename from Clima/light_background.pdf rename to Clima/Assets.xcassets/background.imageset/light_background 1.pdf diff --git a/Clima/Assets.xcassets/background.imageset/light_background.pdf b/Clima/Assets.xcassets/background.imageset/light_background.pdf new file mode 100644 index 00000000..1f3a3e7e Binary files /dev/null and b/Clima/Assets.xcassets/background.imageset/light_background.pdf differ diff --git a/Clima/Assets.xcassets/weatherColor.colorset/Contents.json b/Clima/Assets.xcassets/weatherColor.colorset/Contents.json new file mode 100644 index 00000000..30a9c934 --- /dev/null +++ b/Clima/Assets.xcassets/weatherColor.colorset/Contents.json @@ -0,0 +1,56 @@ +{ + "colors" : [ + { + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0.281", + "green" : "0.262", + "red" : "0.105" + } + }, + "idiom" : "universal" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "light" + } + ], + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0.281", + "green" : "0.262", + "red" : "0.105" + } + }, + "idiom" : "universal" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "1.000", + "green" : "1.000", + "red" : "1.000" + } + }, + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Clima.xcodeproj/xcuserdata/angelayu.xcuserdatad/xcschemes/xcschememanagement.plist b/Clima/Clima.entitlements similarity index 51% rename from Clima.xcodeproj/xcuserdata/angelayu.xcuserdatad/xcschemes/xcschememanagement.plist rename to Clima/Clima.entitlements index ab521101..fc07546c 100644 --- a/Clima.xcodeproj/xcuserdata/angelayu.xcuserdatad/xcschemes/xcschememanagement.plist +++ b/Clima/Clima.entitlements @@ -2,13 +2,11 @@ - SchemeUserState - - Clima.xcscheme_^#shared#^_ - - orderHint - 0 - - + com.apple.security.app-sandbox + + com.apple.security.network.client + + com.apple.security.personal-information.location + diff --git a/Clima/Controller/WeatherViewController.swift b/Clima/Controller/WeatherViewController.swift index 038c2bba..07c30c5c 100644 --- a/Clima/Controller/WeatherViewController.swift +++ b/Clima/Controller/WeatherViewController.swift @@ -7,18 +7,132 @@ // import UIKit +import CoreLocation class WeatherViewController: UIViewController { + + //MARK: - Outlets + @IBOutlet weak var conditionImageView: UIImageView! @IBOutlet weak var temperatureLabel: UILabel! @IBOutlet weak var cityLabel: UILabel! - - override func viewDidLoad() { + @IBOutlet weak var searchTextField: UITextField! + + //MARK: - Vars + + var weatherManager = WeatherManager() + let locationManager = CLLocationManager() + let appDelegate = UIApplication.shared.delegate as! AppDelegate + + override func viewDidLoad() { super.viewDidLoad() - // Do any additional setup after loading the view. + + // Set the VC as delegate of the WeatherManager !!! + weatherManager.delegate = self + searchTextField.delegate = self + locationManager.delegate = self + + // Set the API Key to the WeatherManager + let keys = appDelegate.keys! + weatherManager.apiKey = keys["apiKey"] as! String + + locationManager.requestWhenInUseAuthorization() + locationManager.requestLocation() + + setupUI() } + + //MARK: - Private functions + + private func setupUI() { + // set up the user inteface + } + + @IBAction func locationButtonPressed(_ sender: UIButton) { + locationManager.requestLocation() + } + +} + + +//MARK: - UITextFieldDelegate +extension WeatherViewController: UITextFieldDelegate { + + @IBAction func searchPressed(_ sender: UIButton) { + print(searchTextField.text ?? "\n\n") + searchTextField.endEditing(true) + } + + func textFieldShouldReturn(_ textField: UITextField) -> Bool { + print(searchTextField.text ?? "\n\n") + searchTextField.endEditing(true) + return true + } + + func textFieldShouldEndEditing(_ textField: UITextField) -> Bool { + if textField.text != "" { + return true + } else { + textField.placeholder = "Type something here" + return false + } + } + + func textFieldDidEndEditing(_ textField: UITextField) { + + // Use the searchTextField.text to get the weather for that city. + if let city = searchTextField.text { + + weatherManager.fetchWeather(cityName: city) + } + + searchTextField.text = "" + } + +} +//MARK: - WeatherManagerDelegate +extension WeatherViewController: WeatherManagerDelegate { + + func didUpdateWeather(_ weatherManager: WeatherManager, weather: WeatherModel) { + print(weather.temperature) + DispatchQueue.main.async { + self.temperatureLabel.text = weather.temperatureString + self.conditionImageView.image = UIImage(systemName: weather.conditionName) + self.cityLabel.text = weather.cityName + " - \(weather.description)" + } + } + + func didFailWithError(error: Error) { + + // Any error handling required + print(error) + } } + +//MARK: - CLLocationManagerDelegate +extension WeatherViewController: CLLocationManagerDelegate { + + func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) { + + if let location = locations.last { + // Dejamos de pillar ubicación para que no esté en segundo plano en bucle + locationManager.stopUpdatingLocation() + + let lat = location.coordinate.latitude + let lon = location.coordinate.longitude + + print("location:: \(location.description)") + + weatherManager.fetchWeather(latitude: lat, longitude: lon) + } + } + + func locationManager(_ manager: CLLocationManager, didFailWithError error: Error) { + + print(error) + } +} diff --git a/Clima/Info.plist b/Clima/Info.plist index b5f9c079..f8d5ed54 100644 --- a/Clima/Info.plist +++ b/Clima/Info.plist @@ -2,6 +2,8 @@ + NSLocationWhenInUseUsageDescription + We need your location to get the current weather for where you are. CFBundleDevelopmentRegion $(DEVELOPMENT_LANGUAGE) CFBundleExecutable diff --git a/Clima/Model/WeatherData.swift b/Clima/Model/WeatherData.swift new file mode 100644 index 00000000..8830c338 --- /dev/null +++ b/Clima/Model/WeatherData.swift @@ -0,0 +1,25 @@ +// +// WeatherData.swift +// Clima +// +// Created by Ramon Seoane Martin on 13/4/23. +// Copyright © 2023 App Brewery. All rights reserved. +// + +import Foundation + +struct WeatherData: Decodable { + let name: String + let main: Main + let weather: [Weather] +} + + +struct Main: Decodable { + let temp: Double +} + +struct Weather: Decodable { + let id: Int + let description: String +} diff --git a/Clima/Model/WeatherManager.swift b/Clima/Model/WeatherManager.swift new file mode 100644 index 00000000..c8642bd5 --- /dev/null +++ b/Clima/Model/WeatherManager.swift @@ -0,0 +1,89 @@ +// +// WeatherManager.swift +// Clima +// +// Created by Ramon Seoane Martin on 8/4/23. +// Copyright © 2023 App Brewery. All rights reserved. +// + +import Foundation +import CoreLocation + +protocol WeatherManagerDelegate { + func didUpdateWeather(_ weatherManager: WeatherManager, weather: WeatherModel) + func didFailWithError(error: Error) +} + +struct WeatherManager { + + var apiKey = "" // We'll retrieve it from a Keys.plist storign our API Key + + let weatherURL = "https://api.openweathermap.org/data/2.5/weather?lang=es&units=metric" + + var delegate: WeatherManagerDelegate? + + func fetchWeather(cityName: String) { + let urlString = "\(weatherURL)&q=\(cityName)&appid=\(apiKey)" + + print(urlString) + performRequest(with: urlString) + } + + func fetchWeather(latitude: CLLocationDegrees, longitude: CLLocationDegrees) { + let urlString = "\(weatherURL)&lat=\(latitude)&lon=\(longitude)" + + print(urlString) + performRequest(with: urlString) + } + + + func performRequest(with urlString: String) { + // 1. Create a URL + if let url = URL(string: urlString) { + + // 2. Create a URLSession + let session = URLSession(configuration: .default) + + // 3. Give the session a task + let task = session.dataTask(with: url) { (data, response, error) in + if error != nil { + delegate?.didFailWithError(error: error!) + return + } + + if let safeData = data { + if let weather = parseJSON(safeData) { + delegate?.didUpdateWeather(self, weather: weather) + } + } + } + // 4. Start the task + task.resume() + } + } + + func parseJSON(_ weatherData: Data) -> WeatherModel? { + let decoder = JSONDecoder() + do{ + let decodedData = try decoder.decode(WeatherData.self, from: weatherData) + + let id = decodedData.weather[0].id + let temp = decodedData.main.temp + let name = decodedData.name + let description = decodedData.weather[0].description + + let weather = WeatherModel(conditionId: id, cityName: name, temperature: temp, description: description) + +// print(weather.conditionName) +// print(weather.temperatureString) + return weather + + } catch { + delegate?.didFailWithError(error: error) + return nil + } + } + + + +} diff --git a/Clima/Model/WeatherModel.swift b/Clima/Model/WeatherModel.swift new file mode 100644 index 00000000..b4c87385 --- /dev/null +++ b/Clima/Model/WeatherModel.swift @@ -0,0 +1,42 @@ +// +// WeatherModel.swift +// Clima +// +// Created by Ramon Seoane Martin on 14/4/23. +// Copyright © 2023 App Brewery. All rights reserved. +// + +import Foundation + +struct WeatherModel { + + let conditionId: Int + let cityName: String + let temperature: Double + let description: String + + var temperatureString: String { + return String(format: "%.1f", temperature) + } + + var conditionName: String { + switch conditionId { + case 200...232: + return "cloud.bolt" + case 300...321: + return "cloud.drizzle" + case 500...531: + return "cloud.rain" + case 600...622: + return "cloud.snow" + case 701...781: + return "cloud.fog" + case 800: + return "sun.max" + case 801...804: + return "cloud" + default: + return "cloud" + } + } +} diff --git a/Clima/View/Base.lproj/Main.storyboard b/Clima/View/Base.lproj/Main.storyboard index fec3bb4e..b6f072d4 100644 --- a/Clima/View/Base.lproj/Main.storyboard +++ b/Clima/View/Base.lproj/Main.storyboard @@ -1,9 +1,12 @@ - + - + + + + @@ -19,47 +22,53 @@ - + - - + - + - + - - - - + + + - + - @@ -93,7 +102,8 @@ - + + @@ -104,11 +114,11 @@ - + @@ -118,9 +128,21 @@ - - - - + + + + + + + + + + + + + + + +