changeset 94:fe26349780c8

Implement real-time prices
author Dennis Concepción Martín <66180929+denniscm190@users.noreply.github.com>
date Fri, 29 Jan 2021 20:37:20 +0100
parents 24543d06c24f
children a2ed7369be9f
files LazyBear.xcodeproj/project.pbxproj LazyBear.xcodeproj/project.xcworkspace/xcuserdata/dennis.xcuserdatad/UserInterfaceState.xcuserstate lazybear/ContentView.swift lazybear/Jobs/ReadJson.swift lazybear/Models/QuoteModel.swift lazybear/Network/IexApi.swift lazybear/Views/Price.swift lazybear/Views/WatchlistRow.swift
diffstat 8 files changed, 63 insertions(+), 20 deletions(-) [+]
line wrap: on
line diff
--- a/LazyBear.xcodeproj/project.pbxproj	Fri Jan 29 14:18:52 2021 +0100
+++ b/LazyBear.xcodeproj/project.pbxproj	Fri Jan 29 20:37:20 2021 +0100
@@ -12,6 +12,7 @@
 		950B79F625B1CB7A00E5DB5B /* CompanyList.swift in Sources */ = {isa = PBXBuildFile; fileRef = 950B79F525B1CB7A00E5DB5B /* CompanyList.swift */; };
 		9537923625BDF85D0001F82B /* LogoApi.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9537923525BDF85D0001F82B /* LogoApi.swift */; };
 		954D992525A2123B001F7F60 /* HistoricalPricesModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 954D992425A2123B001F7F60 /* HistoricalPricesModel.swift */; };
+		954DDF0425C456E800848A4B /* QuoteModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 954DDF0325C456E800848A4B /* QuoteModel.swift */; };
 		95612C512598D48200F7698F /* SearchBar.swift in Sources */ = {isa = PBXBuildFile; fileRef = 95612C4F2598D48200F7698F /* SearchBar.swift */; };
 		95621AD925BF2EDB00BB17FC /* CloudKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 95621AD825BF2EDB00BB17FC /* CloudKit.framework */; };
 		95700BC625BD9D12009CEEFE /* IexApi.swift in Sources */ = {isa = PBXBuildFile; fileRef = 95700BC525BD9D12009CEEFE /* IexApi.swift */; };
@@ -51,6 +52,7 @@
 		950B79F525B1CB7A00E5DB5B /* CompanyList.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CompanyList.swift; sourceTree = "<group>"; };
 		9537923525BDF85D0001F82B /* LogoApi.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = LogoApi.swift; path = LazyBear/Network/LogoApi.swift; sourceTree = SOURCE_ROOT; };
 		954D992425A2123B001F7F60 /* HistoricalPricesModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = HistoricalPricesModel.swift; path = lazybear/Models/HistoricalPricesModel.swift; sourceTree = SOURCE_ROOT; };
+		954DDF0325C456E800848A4B /* QuoteModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = QuoteModel.swift; path = lazybear/Models/QuoteModel.swift; sourceTree = SOURCE_ROOT; };
 		95612C4F2598D48200F7698F /* SearchBar.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SearchBar.swift; sourceTree = "<group>"; };
 		95621AD725BF2EC500BB17FC /* LazyBear.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = LazyBear.entitlements; sourceTree = "<group>"; };
 		95621AD825BF2EDB00BB17FC /* CloudKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CloudKit.framework; path = System/Library/Frameworks/CloudKit.framework; sourceTree = SDKROOT; };
@@ -121,6 +123,7 @@
 				95AB4A7C259DCC0C0064C9C1 /* CompanyModel.swift */,
 				954D992425A2123B001F7F60 /* HistoricalPricesModel.swift */,
 				95FE646A25C30B880052832E /* ApiModel.swift */,
+				954DDF0325C456E800848A4B /* QuoteModel.swift */,
 			);
 			path = Models;
 			sourceTree = "<group>";
@@ -293,6 +296,7 @@
 				95AB4A7A259DCBAE0064C9C1 /* ReadJson.swift in Sources */,
 				95F6F45C25C20D8D002AC66A /* Price.swift in Sources */,
 				9597CE0125C1DC0A004DDFED /* LogoModifier.swift in Sources */,
+				954DDF0425C456E800848A4B /* QuoteModel.swift in Sources */,
 				9597CE0425C1DFE7004DDFED /* LogoPlaceholder.swift in Sources */,
 				95FE646B25C30B880052832E /* ApiModel.swift in Sources */,
 				95F6C30525BAF599003CF389 /* CompanyHeader.swift in Sources */,
Binary file LazyBear.xcodeproj/project.xcworkspace/xcuserdata/dennis.xcuserdatad/UserInterfaceState.xcuserstate has changed
--- a/lazybear/ContentView.swift	Fri Jan 29 14:18:52 2021 +0100
+++ b/lazybear/ContentView.swift	Fri Jan 29 20:37:20 2021 +0100
@@ -12,11 +12,12 @@
 struct ContentView: View {
     @State var searchedCompany = String()
     @State public var showingSearch: Bool = false
-    let persistenceController = PersistenceController.shared
+    @State var cloudFetch = [CKRecord]() { didSet { cloudValues() }}   // CloudKit fetch arrives here
     
-    let cloud = CloudKitManager()
-    @State var cloudFetch = [CKRecord]() { didSet { cloudValues() }}  // On change, call function
-    @EnvironmentObject var apiAccess: ApiAccess
+    let persistenceController = PersistenceController.shared  // Core data
+    let cloud = CloudKitManager()  // CloudKit fetch function
+    
+    @EnvironmentObject var apiAccess: ApiAccess  // Env apis info
 
     var body: some View {
         VStack(alignment: .leading) {
@@ -34,10 +35,10 @@
                 }
             }
         }
-        .onAppear { cloud.query(recordType: "API") { self.cloudFetch = $0 } }  // Request CloudKit
+        .onAppear { cloud.query(recordType: "API") { cloudFetch = $0 } }  // Request CloudKit 
     }
     
-    // Assign values to the model
+    // Assign CloudKit fetch to model
     private func cloudValues() {
         var results = [ApiModel]()
         cloudFetch.forEach({ (result) in
--- a/lazybear/Jobs/ReadJson.swift	Fri Jan 29 14:18:52 2021 +0100
+++ b/lazybear/Jobs/ReadJson.swift	Fri Jan 29 20:37:20 2021 +0100
@@ -7,8 +7,6 @@
 
 import SwiftUI
 
-import SwiftUI
-
 // With this function I parse the local JSON file to read it and create a list with its items.
 let companiesData: [CompanyModel] = load("companies.json")
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lazybear/Models/QuoteModel.swift	Fri Jan 29 20:37:20 2021 +0100
@@ -0,0 +1,14 @@
+//
+//  QuoteModel.swift
+//  LazyBear
+//
+//  Created by Dennis Concepción Martín on 29/1/21.
+//
+
+import SwiftUI
+
+struct QuoteModel: Codable {
+    var latestPrice: Float
+    var changePercent: Double
+}
+
--- a/lazybear/Network/IexApi.swift	Fri Jan 29 14:18:52 2021 +0100
+++ b/lazybear/Network/IexApi.swift	Fri Jan 29 20:37:20 2021 +0100
@@ -8,6 +8,8 @@
 import SwiftUI
 
 struct IexApi {
+    @EnvironmentObject var apiAccess: ApiAccess  // Env apis info
+    
     enum Version {
         case stable
         
@@ -64,7 +66,7 @@
     
     
     // Create URL
-    func getURL(version: Version, stock: Stock, endpoint: Endpoint, range: Range?, parameters: Parameters?) -> String {
+    func getPath(version: Version, stock: Stock, endpoint: Endpoint, range: Range?, parameters: Parameters?) -> String {
         let version = version.path
         let stock = stock.path
         let endpoint = endpoint.path
@@ -78,7 +80,7 @@
     }
     
     // Request API
-    func request<T: Decodable>(url: String, model: T.Type, completion: @escaping (T) -> Void) {
+    func request<T: Decodable>(url: String, model: T.Type, completion: @escaping (_ result: T) -> Void) {
         // We take some model data T.Type
         guard let url = URL(string: url) else {
             print("Invalid URL")
--- a/lazybear/Views/Price.swift	Fri Jan 29 14:18:52 2021 +0100
+++ b/lazybear/Views/Price.swift	Fri Jan 29 20:37:20 2021 +0100
@@ -9,22 +9,46 @@
 import CloudKit
 
 struct Price: View {
-    let iexApi = IexApi()
+    @State var symbol: String
+    
+    @State var url = String() { didSet { giveMePrices() }}
+    @State var showingView = false
+    
+    @State var latestPrice = Float()
+    @State var changePercent = Double() { didSet { self.showingView = true }}
+    
+    let iexApi = IexApi()  // Request api function
+    //let timer = Timer.publish(every: 5, on: .main, in: .common).autoconnect()  // Set recurrent price request
+    
+    @EnvironmentObject var apiAccess: ApiAccess
     
     var body: some View {
-        Text("Price")
-            .onAppear {
-                //let url = api[1].url! as String
-                //let token = api[1].key! as String
-                //let path = iexApi.getURL(version: .stable, stock: .symbol(company: "AAPL"), endpoint: .quote, range: nil, parameters: nil)
-                //let endpoint = url + path + token
-                //print(endpoint)
+        VStack {
+            if self.showingView {
+                Text("\(latestPrice, specifier: "%.2f")")
             }
+        }
+        //.onReceive(timer) { _ in giveMePrices() }
+        .onAppear { getUrl() }
+    }
+    
+    private func getUrl() {
+        let baseUrl = apiAccess.results[1].url ?? ""  // 1 -> Sandbox / 2 -> Production
+        let token = apiAccess.results[1].key ?? ""
+        let path = iexApi.getPath(version: .stable, stock: .symbol(company: symbol), endpoint: .quote, range: nil, parameters: nil)
+        self.url = baseUrl + path + token
+    }
+    
+    private func giveMePrices() {
+        iexApi.request(url: url, model: QuoteModel.self) { result in
+            self.latestPrice = result.latestPrice
+            self.changePercent = result.changePercent
+        }
     }
 }
 
 struct Price_Previews: PreviewProvider {
     static var previews: some View {
-        Price()
+        Price(symbol: "AAPL")
     }
 }
--- a/lazybear/Views/WatchlistRow.swift	Fri Jan 29 14:18:52 2021 +0100
+++ b/lazybear/Views/WatchlistRow.swift	Fri Jan 29 20:37:20 2021 +0100
@@ -37,7 +37,7 @@
                 
                 Spacer()
                 if self.editMode?.wrappedValue.isEditing ?? true { } else { // If is not editing -> show prices
-                    Price()
+                    Price(symbol: company.symbol ?? "")
                 }
             }
         }