diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..039525bb --- /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 +/ByteCoin/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/ByteCoin.xcodeproj/project.pbxproj b/ByteCoin.xcodeproj/project.pbxproj index 1e46853b..30af13bf 100644 --- a/ByteCoin.xcodeproj/project.pbxproj +++ b/ByteCoin.xcodeproj/project.pbxproj @@ -3,10 +3,13 @@ archiveVersion = 1; classes = { }; - objectVersion = 50; + objectVersion = 53; objects = { /* Begin PBXBuildFile section */ + 1253AF352A4DF01C0015ACD3 /* Keys.plist in Resources */ = {isa = PBXBuildFile; fileRef = 1253AF342A4DF01C0015ACD3 /* Keys.plist */; }; + 126AAECD29F2E4EE00173620 /* CoinModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 126AAECC29F2E4EE00173620 /* CoinModel.swift */; }; + 126AAECF29F2E77200173620 /* CoinData.swift in Sources */ = {isa = PBXBuildFile; fileRef = 126AAECE29F2E77200173620 /* CoinData.swift */; }; ADA8AC092329367100626376 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = ADA8AC082329367100626376 /* AppDelegate.swift */; }; ADA8AC0B2329367100626376 /* SceneDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = ADA8AC0A2329367100626376 /* SceneDelegate.swift */; }; ADA8AC0D2329367100626376 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = ADA8AC0C2329367100626376 /* ViewController.swift */; }; @@ -17,6 +20,9 @@ /* End PBXBuildFile section */ /* Begin PBXFileReference section */ + 1253AF342A4DF01C0015ACD3 /* Keys.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Keys.plist; sourceTree = ""; }; + 126AAECC29F2E4EE00173620 /* CoinModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CoinModel.swift; sourceTree = ""; }; + 126AAECE29F2E77200173620 /* CoinData.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CoinData.swift; sourceTree = ""; }; ADA8AC052329367100626376 /* ByteCoin.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = ByteCoin.app; sourceTree = BUILT_PRODUCTS_DIR; }; ADA8AC082329367100626376 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; ADA8AC0A2329367100626376 /* SceneDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SceneDelegate.swift; sourceTree = ""; }; @@ -66,6 +72,7 @@ ADA8AC112329367300626376 /* Assets.xcassets */, ADA8AC132329367300626376 /* LaunchScreen.storyboard */, ADA8AC162329367300626376 /* Info.plist */, + 1253AF342A4DF01C0015ACD3 /* Keys.plist */, ); path = ByteCoin; sourceTree = ""; @@ -90,6 +97,8 @@ isa = PBXGroup; children = ( ADA8AC1F2329398300626376 /* CoinManager.swift */, + 126AAECC29F2E4EE00173620 /* CoinModel.swift */, + 126AAECE29F2E77200173620 /* CoinData.swift */, ); path = Model; sourceTree = ""; @@ -120,8 +129,9 @@ ADA8ABFD2329367100626376 /* Project object */ = { isa = PBXProject; attributes = { + BuildIndependentTargetsInParallel = YES; LastSwiftUpdateCheck = 1100; - LastUpgradeCheck = 1100; + LastUpgradeCheck = 1430; ORGANIZATIONNAME = "The App Brewery"; TargetAttributes = { ADA8AC042329367100626376 = { @@ -152,6 +162,7 @@ isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( + 1253AF352A4DF01C0015ACD3 /* Keys.plist in Resources */, ADA8AC152329367300626376 /* LaunchScreen.storyboard in Resources */, ADA8AC122329367300626376 /* Assets.xcassets in Resources */, ADA8AC102329367100626376 /* Main.storyboard in Resources */, @@ -165,6 +176,8 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + 126AAECF29F2E77200173620 /* CoinData.swift in Sources */, + 126AAECD29F2E4EE00173620 /* CoinModel.swift in Sources */, ADA8AC202329398300626376 /* CoinManager.swift in Sources */, ADA8AC0D2329367100626376 /* ViewController.swift in Sources */, ADA8AC092329367100626376 /* AppDelegate.swift in Sources */, @@ -220,6 +233,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; @@ -280,6 +294,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; @@ -313,12 +328,15 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CODE_SIGN_STYLE = Automatic; + DEVELOPMENT_TEAM = 5422CL2MVH; INFOPLIST_FILE = ByteCoin/Info.plist; + INFOPLIST_KEY_CFBundleDisplayName = ByteCoin; + INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.finance"; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", ); - PRODUCT_BUNDLE_IDENTIFIER = co.appbrewery.ByteCoin; + PRODUCT_BUNDLE_IDENTIFIER = seoanemartin.ramon..ByteCoin; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; @@ -330,12 +348,15 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CODE_SIGN_STYLE = Automatic; + DEVELOPMENT_TEAM = 5422CL2MVH; INFOPLIST_FILE = ByteCoin/Info.plist; + INFOPLIST_KEY_CFBundleDisplayName = ByteCoin; + INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.finance"; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", ); - PRODUCT_BUNDLE_IDENTIFIER = co.appbrewery.ByteCoin; + PRODUCT_BUNDLE_IDENTIFIER = seoanemartin.ramon..ByteCoin; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; diff --git a/ByteCoin.xcodeproj/xcuserdata/angelayu.xcuserdatad/xcschemes/xcschememanagement.plist b/ByteCoin.xcodeproj/xcuserdata/angelayu.xcuserdatad/xcschemes/xcschememanagement.plist deleted file mode 100644 index 0e8a3bb9..00000000 --- a/ByteCoin.xcodeproj/xcuserdata/angelayu.xcuserdatad/xcschemes/xcschememanagement.plist +++ /dev/null @@ -1,14 +0,0 @@ - - - - - SchemeUserState - - ByteCoin.xcscheme_^#shared#^_ - - orderHint - 0 - - - - diff --git a/ByteCoin/AppDelegate.swift b/ByteCoin/AppDelegate.swift index 6a0946bc..8148b971 100644 --- a/ByteCoin/AppDelegate.swift +++ b/ByteCoin/AppDelegate.swift @@ -11,10 +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. + + // Override point for customization after application launch. + if let path = Bundle.main.path(forResource: "Keys", ofType: "plist") { + keys = NSDictionary(contentsOfFile: path) + } + return true } diff --git a/ByteCoin/Controller/ViewController.swift b/ByteCoin/Controller/ViewController.swift index e3ffe9a8..5a6bd312 100644 --- a/ByteCoin/Controller/ViewController.swift +++ b/ByteCoin/Controller/ViewController.swift @@ -9,12 +9,84 @@ import UIKit class ViewController: UIViewController { + + @IBOutlet weak var bitcoinLabel: UILabel! + @IBOutlet weak var currencyLabel: UILabel! + @IBOutlet weak var currencyPicker: UIPickerView! + + @IBOutlet weak var stackInterno: UIStackView! + @IBOutlet weak var coinViewInterno: UIView! + + var coinManager = CoinManager() + + + override func viewDidLoad() { + super.viewDidLoad() + // Do any additional setup after loading the view. + + coinManager.delegate = self + + let appDelegate = UIApplication.shared.delegate as! AppDelegate + let keys = appDelegate.keys! + + coinManager.apiKey = keys["apiKey"] as! String + + // Setting the VC as the Picker's DataSource & Delegate + currencyPicker.dataSource = self + currencyPicker.delegate = self + } + + override func viewWillAppear(_ animated: Bool) { + // Para meter el break point + + } + +} - override func viewDidLoad() { - super.viewDidLoad() - // Do any additional setup after loading the view. - } +//MARK: - UIPickerView DataSource and Delegate +extension ViewController: UIPickerViewDataSource, UIPickerViewDelegate { + + func numberOfComponents(in pickerView: UIPickerView) -> Int { + return 1 + } + + func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int { + return coinManager.currencyArray.count + } + + func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? { + return coinManager.currencyArray[row] + } + + func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) { + + let selectedCurrency = coinManager.currencyArray[row] + + print(coinManager.getCoinPrice(for: selectedCurrency)) + + coinManager.getCoinPrice(for: selectedCurrency) + } } + +//MARK: - CoinManager Delegate + +extension ViewController: CoinManagerDelegate { + + // CAMBIOS DE LOS ELEMENTOS DEL VC + + func didUpdateCurrency(_ coinManager: CoinManager, coin: CoinModel) { + print(coin.rate) + + DispatchQueue.main.async { + self.bitcoinLabel.text = String(format: "%.2f", coin.rate) + self.currencyLabel.text = coin.selectedCurrency + } + } + + func didFailWithError(error: Error) { + print(error) + } +} diff --git a/ByteCoin/Model/CoinData.swift b/ByteCoin/Model/CoinData.swift new file mode 100644 index 00000000..6afdd116 --- /dev/null +++ b/ByteCoin/Model/CoinData.swift @@ -0,0 +1,19 @@ +// +// CoinData.swift +// ByteCoin +// +// Created by Ramon Seoane Martin on 21/4/23. +// Copyright © 2023 The App Brewery. All rights reserved. +// + +import Foundation + +struct CoinData: Decodable { + + // En realidad solo voy a necesitar el campo "rate" + + let time: String + let asset_id_base: String + let asset_id_quote: String + let rate: Double +} diff --git a/ByteCoin/Model/CoinManager.swift b/ByteCoin/Model/CoinManager.swift new file mode 100644 index 00000000..74855101 --- /dev/null +++ b/ByteCoin/Model/CoinManager.swift @@ -0,0 +1,88 @@ +// +// CoinManager.swift +// ByteCoin +// +// Created by Angela Yu on 11/09/2019. +// Copyright © 2019 The App Brewery. All rights reserved. +// + +import Foundation +import UIKit + +protocol CoinManagerDelegate { + func didUpdateCurrency(_ coinManager: CoinManager, coin: CoinModel) + func didFailWithError(error: Error) +} + +struct CoinManager { + + + let baseURL = "https://rest.coinapi.io/v1/exchangerate/BTC" + var apiKey = "" // We'll retrieve it from a Keys.plist storign our API Key + + var delegate: CoinManagerDelegate? + + let currencyArray = ["AUD", "BRL","CAD","CNY","EUR","GBP","HKD","IDR","ILS","INR","JPY","MXN","NOK","NZD","PLN","RON","RUB","SEK","SGD","USD","ZAR"] + + func getCoinPrice(for currency: String) { + + fetchCurrencyRate(currency: currency) + } + + func fetchCurrencyRate(currency: String) { + let urlString = "\(baseURL)/\(currency)?apikey=\(apiKey)" + + print(urlString) + performRequest(with: urlString) + } + + func performRequest(with urlString: String) { + // 1. Create URL + if let url = URL(string: urlString) { + + // 2. Create session URLSession + let session = URLSession(configuration: .default) + + // 3. Add task to the session + let task = session.dataTask(with: url) { (data, response, error) in + + if error != nil { + delegate?.didFailWithError(error: error!) + return + } + + if let safeData = data { + print(String(data: safeData, encoding: .utf8)!) + if let coin = parseJSON(safeData) { + delegate?.didUpdateCurrency(self, coin: coin) + } + } + } + // 4. Start the task + task.resume() + } + } + + func parseJSON(_ coinData: Data) -> CoinModel? { + // Create a JSON decoder + let decoder = JSONDecoder() + + do{ + // Trying to decode de data using the CoinData structure + let decodedData = try decoder.decode(CoinData.self, from: coinData) + + let time = decodedData.time + let bitcoin = decodedData.asset_id_base + let selectedCurrency = decodedData.asset_id_quote + let price = decodedData.rate + + let coin = CoinModel(time: time, bitcoin: bitcoin, selectedCurrency: selectedCurrency, rate: price) + + return coin + } catch { + delegate?.didFailWithError(error: error) + return nil + } + } + +} diff --git a/ByteCoin/Model/CoinModel.swift b/ByteCoin/Model/CoinModel.swift new file mode 100644 index 00000000..a4a98371 --- /dev/null +++ b/ByteCoin/Model/CoinModel.swift @@ -0,0 +1,19 @@ +// +// CoinModel.swift +// ByteCoin +// +// Created by Ramon Seoane Martin on 21/4/23. +// Copyright © 2023 The App Brewery. All rights reserved. +// + +import Foundation + +struct CoinModel { + + var time: String + var bitcoin: String + var selectedCurrency: String + var rate: Double + + +} diff --git a/ByteCoin/Model/coinManager.swift b/ByteCoin/Model/coinManager.swift deleted file mode 100644 index 2fc38866..00000000 --- a/ByteCoin/Model/coinManager.swift +++ /dev/null @@ -1,16 +0,0 @@ -// -// CoinManager.swift -// ByteCoin -// -// Created by Angela Yu on 11/09/2019. -// Copyright © 2019 The App Brewery. All rights reserved. -// - -import Foundation - -struct CoinManager { - - let baseURL = "https://apiv2.bitcoinaverage.com/indices/global/ticker/BTC" - let currencyArray = ["AUD", "BRL","CAD","CNY","EUR","GBP","HKD","IDR","ILS","INR","JPY","MXN","NOK","NZD","PLN","RON","RUB","SEK","SGD","USD","ZAR"] - -} diff --git a/ByteCoin/View/Base.lproj/Main.storyboard b/ByteCoin/View/Base.lproj/Main.storyboard index 0e98b47a..7f0680da 100644 --- a/ByteCoin/View/Base.lproj/Main.storyboard +++ b/ByteCoin/View/Base.lproj/Main.storyboard @@ -1,10 +1,12 @@ - + - + + + @@ -16,12 +18,14 @@ - + - + + + - + - + - + - + - - + @@ -80,16 +84,30 @@ + + + + + + + + - + + + + + + + @@ -97,15 +115,18 @@ - + - + - + + + +