changeset 343:ab909fc9ce55

Implement batch requests HomeView
author Dennis Concepción Martín <66180929+denniscm190@users.noreply.github.com>
date Tue, 06 Apr 2021 11:04:21 +0200
parents a6c49f1409f3
children 276e17f11c19
files LazyBear.xcodeproj/project.pbxproj LazyBear.xcodeproj/project.xcworkspace/xcuserdata/dennis.xcuserdatad/UserInterfaceState.xcuserstate LazyBear.xcodeproj/xcshareddata/xcschemes/LazyBear.xcscheme LazyBear/Global Models/IntradayPricesModel.swift LazyBear/Views/Global Helpers/PriceView.swift LazyBear/Views/Global Helpers/StockItem.swift LazyBear/Views/Global Helpers/StockRectangleRow.swift LazyBear/Views/Home/Helpers/TopStockRow.swift LazyBear/Views/Home/HomeView.swift LazyBear/Views/Home/Networking/HomeData.swift LazyBear/Views/Profile/Networking/ProfileData.swift LazyBear/Views/Profile/ProfileView.swift
diffstat 12 files changed, 197 insertions(+), 88 deletions(-) [+]
line wrap: on
line diff
--- a/LazyBear.xcodeproj/project.pbxproj	Mon Apr 05 20:08:19 2021 +0200
+++ b/LazyBear.xcodeproj/project.pbxproj	Tue Apr 06 11:04:21 2021 +0200
@@ -28,7 +28,7 @@
 		9550443A26111B2B000E0BCB /* HomeView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9550443926111B2B000E0BCB /* HomeView.swift */; };
 		9550444326111E7A000E0BCB /* SectorRow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9550444226111E7A000E0BCB /* SectorRow.swift */; };
 		9550444626111EE5000E0BCB /* SectorItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9550444526111EE5000E0BCB /* SectorItem.swift */; };
-		9550444926111FC9000E0BCB /* TopStockRow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9550444826111FC9000E0BCB /* TopStockRow.swift */; };
+		9550444926111FC9000E0BCB /* StockRectangleRow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9550444826111FC9000E0BCB /* StockRectangleRow.swift */; };
 		9550444C26111FED000E0BCB /* StockItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9550444B26111FED000E0BCB /* StockItem.swift */; };
 		95672B8F25DDA54700DCBE4A /* LazyBearApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 95672B8E25DDA54700DCBE4A /* LazyBearApp.swift */; };
 		95672B9325DDA54700DCBE4A /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 95672B9225DDA54700DCBE4A /* Assets.xcassets */; };
@@ -49,6 +49,7 @@
 		95ECCA5D2612169200A67EFA /* LineShape.swift in Sources */ = {isa = PBXBuildFile; fileRef = 95ECCA5C2612169200A67EFA /* LineShape.swift */; };
 		95ECCA60261216D500A67EFA /* LineView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 95ECCA5F261216D500A67EFA /* LineView.swift */; };
 		95FBE0DC2619CA7200440386 /* ProfileView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 95FBE0DB2619CA7200440386 /* ProfileView.swift */; };
+		95FD09CB261BA13800393042 /* ProfileData.swift in Sources */ = {isa = PBXBuildFile; fileRef = 95FD09CA261BA13800393042 /* ProfileData.swift */; };
 /* End PBXBuildFile section */
 
 /* Begin PBXFileReference section */
@@ -74,7 +75,7 @@
 		9550443926111B2B000E0BCB /* HomeView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HomeView.swift; sourceTree = "<group>"; };
 		9550444226111E7A000E0BCB /* SectorRow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SectorRow.swift; sourceTree = "<group>"; };
 		9550444526111EE5000E0BCB /* SectorItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SectorItem.swift; sourceTree = "<group>"; };
-		9550444826111FC9000E0BCB /* TopStockRow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TopStockRow.swift; sourceTree = "<group>"; };
+		9550444826111FC9000E0BCB /* StockRectangleRow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StockRectangleRow.swift; sourceTree = "<group>"; };
 		9550444B26111FED000E0BCB /* StockItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StockItem.swift; sourceTree = "<group>"; };
 		95672B8B25DDA54700DCBE4A /* LazyBear.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = LazyBear.app; sourceTree = BUILT_PRODUCTS_DIR; };
 		95672B8E25DDA54700DCBE4A /* LazyBearApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LazyBearApp.swift; sourceTree = "<group>"; };
@@ -98,6 +99,7 @@
 		95ECCA5C2612169200A67EFA /* LineShape.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LineShape.swift; sourceTree = "<group>"; };
 		95ECCA5F261216D500A67EFA /* LineView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LineView.swift; sourceTree = "<group>"; };
 		95FBE0DB2619CA7200440386 /* ProfileView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProfileView.swift; sourceTree = "<group>"; };
+		95FD09CA261BA13800393042 /* ProfileData.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProfileData.swift; sourceTree = "<group>"; };
 /* End PBXFileReference section */
 
 /* Begin PBXFrameworksBuildPhase section */
@@ -167,9 +169,9 @@
 		954D7E9D260BBA5200A13C50 /* Global Models */ = {
 			isa = PBXGroup;
 			children = (
-				95893DCD2613C46B003698C5 /* CompanyQuoteModel.swift */,
 				954D7EA5260BBA6600A13C50 /* WatchlistCompany+CoreDataClass.swift */,
 				954D7EA6260BBA6600A13C50 /* WatchlistCompany+CoreDataProperties.swift */,
+				95893DCD2613C46B003698C5 /* CompanyQuoteModel.swift */,
 				95A5187626186C830002D27C /* IntradayPricesModel.swift */,
 			);
 			path = "Global Models";
@@ -191,7 +193,6 @@
 			children = (
 				9550444226111E7A000E0BCB /* SectorRow.swift */,
 				9550444526111EE5000E0BCB /* SectorItem.swift */,
-				9550444826111FC9000E0BCB /* TopStockRow.swift */,
 				951566E92613A37C007C0F36 /* TradingDatesItem.swift */,
 			);
 			path = Helpers;
@@ -229,6 +230,7 @@
 				950C36E2260FB6180081CF53 /* HapticsManager.swift */,
 				950D0E322618B44800D17AD7 /* HudManager.swift */,
 				95B1874925DDAC4D0068A364 /* Views */,
+				95CD32E2261C5B0600901250 /* Secondary Views */,
 				952045132610C7A200A76362 /* Global functions */,
 				954D7E9D260BBA5200A13C50 /* Global Models */,
 				9523ED402615BD93006D3D6F /* Resources */,
@@ -265,6 +267,7 @@
 				95A5188526186F590002D27C /* PriceView.swift */,
 				950D0E2F2618B34600D17AD7 /* BlurBackground.swift */,
 				950D0E352618B61000D17AD7 /* BackgroundShadow.swift */,
+				9550444826111FC9000E0BCB /* StockRectangleRow.swift */,
 				9550444B26111FED000E0BCB /* StockItem.swift */,
 			);
 			path = "Global Helpers";
@@ -301,6 +304,21 @@
 			path = Views;
 			sourceTree = "<group>";
 		};
+		95CD32E2261C5B0600901250 /* Secondary Views */ = {
+			isa = PBXGroup;
+			children = (
+				95CD32E3261C5B2200901250 /* Company */,
+			);
+			path = "Secondary Views";
+			sourceTree = "<group>";
+		};
+		95CD32E3261C5B2200901250 /* Company */ = {
+			isa = PBXGroup;
+			children = (
+			);
+			path = Company;
+			sourceTree = "<group>";
+		};
 		95E745D72614622C00744A1E /* Home */ = {
 			isa = PBXGroup;
 			children = (
@@ -321,10 +339,19 @@
 			isa = PBXGroup;
 			children = (
 				95FBE0DB2619CA7200440386 /* ProfileView.swift */,
+				95FD09C9261BA12800393042 /* Networking */,
 			);
 			path = Profile;
 			sourceTree = "<group>";
 		};
+		95FD09C9261BA12800393042 /* Networking */ = {
+			isa = PBXGroup;
+			children = (
+				95FD09CA261BA13800393042 /* ProfileData.swift */,
+			);
+			path = Networking;
+			sourceTree = "<group>";
+		};
 /* End PBXGroup section */
 
 /* Begin PBXNativeTarget section */
@@ -407,9 +434,10 @@
 				95E745DA2614624500744A1E /* HomeDataPreview.swift in Sources */,
 				95A5187726186C830002D27C /* IntradayPricesModel.swift in Sources */,
 				95A5188626186F590002D27C /* PriceView.swift in Sources */,
-				9550444926111FC9000E0BCB /* TopStockRow.swift in Sources */,
+				9550444926111FC9000E0BCB /* StockRectangleRow.swift in Sources */,
 				9523ED542615CB7F006D3D6F /* HomeData.swift in Sources */,
 				9550444326111E7A000E0BCB /* SectorRow.swift in Sources */,
+				95FD09CB261BA13800393042 /* ProfileData.swift in Sources */,
 				950D0E302618B34600D17AD7 /* BlurBackground.swift in Sources */,
 				95ECCA60261216D500A67EFA /* LineView.swift in Sources */,
 				9550443A26111B2B000E0BCB /* HomeView.swift in Sources */,
Binary file LazyBear.xcodeproj/project.xcworkspace/xcuserdata/dennis.xcuserdatad/UserInterfaceState.xcuserstate has changed
--- a/LazyBear.xcodeproj/xcshareddata/xcschemes/LazyBear.xcscheme	Mon Apr 05 20:08:19 2021 +0200
+++ b/LazyBear.xcodeproj/xcshareddata/xcschemes/LazyBear.xcscheme	Tue Apr 06 11:04:21 2021 +0200
@@ -31,7 +31,7 @@
       </Testables>
    </TestAction>
    <LaunchAction
-      buildConfiguration = "Release"
+      buildConfiguration = "Debug"
       selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
       selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
       launchStyle = "0"
--- a/LazyBear/Global Models/IntradayPricesModel.swift	Mon Apr 05 20:08:19 2021 +0200
+++ b/LazyBear/Global Models/IntradayPricesModel.swift	Tue Apr 06 11:04:21 2021 +0200
@@ -7,6 +7,10 @@
 
 import SwiftUI
 
-struct IntradayPricesModel: Codable {
+struct IntradayPricesBatch: Codable {
+    var intradayprices: [IntradayPricesResult]
+}
+
+struct IntradayPricesResult: Codable {
     var open: Double?
 }
--- a/LazyBear/Views/Global Helpers/PriceView.swift	Mon Apr 05 20:08:19 2021 +0200
+++ b/LazyBear/Views/Global Helpers/PriceView.swift	Tue Apr 06 11:04:21 2021 +0200
@@ -12,7 +12,7 @@
     var changePercent: Double
     
     var body: some View {
-        VStack {
+        VStack(alignment: .leading) {
             Text("$\(latestPrice, specifier: "%.2f")")
                 .foregroundColor(changePercent < 0 ? .red: .green)
                 .fontWeight(.semibold)
--- a/LazyBear/Views/Global Helpers/StockItem.swift	Mon Apr 05 20:08:19 2021 +0200
+++ b/LazyBear/Views/Global Helpers/StockItem.swift	Tue Apr 06 11:04:21 2021 +0200
@@ -9,7 +9,7 @@
 
 struct StockItem: View {
     var company: CompanyQuoteModel
-    @State private var intradayPrices = [IntradayPricesModel]()
+    var intradayPrices: [IntradayPricesResult]
     
     private let baseUrl = Bundle.main.infoDictionary?["IEX_URL"] as? String ?? "Empty url"
     private let apiKey = Bundle.main.infoDictionary?["IEX_API"] as? String ?? "Empty key"
@@ -44,7 +44,7 @@
                         Text("No data available")
                             .font(.caption)
                             .opacity(0.6)
-                        
+
                         Spacer()
                     } else {
                         LineView(data: prices)
@@ -56,20 +56,13 @@
                 }
                 ,alignment: .leading
             )
-            .onAppear { requestIntradayPrices(company.symbol) }
-    }
-    
-    private func requestIntradayPrices(_ symbol: String) {
-        let url = "\(baseUrl)/stock/\(symbol)/intraday-prices?token=\(apiKey)"
-        genericRequest(url: url, model: [IntradayPricesModel].self) {
-            self.intradayPrices = $0
-        }
+            .onAppear {  }
     }
 }
 
-struct StockItem_Previews: PreviewProvider {
-    static var previews: some View {
-        StockItem(company: CompanyQuoteModel(companyName: "Akumin Inc", symbol: "AKU", latestPrice: 120.30, changePercent: 0.03))
-
-    }
-}
+//struct StockItem_Previews: PreviewProvider {
+//    static var previews: some View {
+//        StockItem(company: CompanyQuoteModel(companyName: "Akumin Inc", symbol: "AKU", latestPrice: 120.30, changePercent: 0.03))
+//
+//    }
+//}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/LazyBear/Views/Global Helpers/StockRectangleRow.swift	Tue Apr 06 11:04:21 2021 +0200
@@ -0,0 +1,50 @@
+//
+//  StockRectangleRow.swift
+//  LazyBear
+//
+//  Created by Dennis Concepción Martín on 28/3/21.
+//
+
+import SwiftUI
+
+
+struct StockRectangleRow: View {
+    var listType: String
+    var list: [CompanyQuoteModel]
+    var intradayPrices: [String: [IntradayPricesResult]]
+    
+    var body: some View {
+        VStack(alignment: .leading) {
+            Text(adaptTitle(listType))
+                .font(.title3)
+                .fontWeight(.semibold)
+                .padding([.top, .horizontal])
+            
+            ScrollView(.horizontal, showsIndicators: false) {
+                HStack(spacing: 20) {
+                    ForEach(list, id: \.self) { company in
+                        StockItem(company: company, intradayPrices: self.intradayPrices[company.symbol]!)
+                    }
+                }
+                .padding()
+            }
+            .frame(height: 250)
+        }
+        .padding(.bottom)
+    }
+}
+
+private func adaptTitle(_ listType: String) -> String {
+    if listType == "mostactive" {
+        return "Most active"
+    } else {
+        return listType.capitalized
+    }
+}
+
+
+//struct StockRectangleRow_Previews: PreviewProvider {
+//    static var previews: some View {
+//        StockRectangleRow(listType: "gainers", list: [CompanyQuoteModel(companyName: "apple inc", symbol: "aapl", latestPrice: 120.30, changePercent: 0.034)])
+//    }
+//}
--- a/LazyBear/Views/Home/Helpers/TopStockRow.swift	Mon Apr 05 20:08:19 2021 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,49 +0,0 @@
-//
-//  TopStockRow.swift
-//  LazyBear
-//
-//  Created by Dennis Concepción Martín on 28/3/21.
-//
-
-import SwiftUI
-
-struct TopStockRow: View {
-    var listType: String
-    var list: [CompanyQuoteModel]
-    
-    var body: some View {
-        VStack(alignment: .leading) {
-            Text(adaptTitle())
-                .font(.title3)
-                .fontWeight(.semibold)
-                .padding([.top, .horizontal])
-            
-            ScrollView(.horizontal, showsIndicators: false) {
-                HStack(spacing: 20) {
-                    ForEach(list, id: \.self) { company in
-                        StockItem(company: company)
-                    }
-                }
-                .padding()
-            }
-            .frame(height: 250)
-        }
-        .padding(.bottom)
-    }
-    
-    private func adaptTitle() -> String {
-        if listType == "mostactive" {
-            
-            return "Most active"
-        } else {
-            return listType.capitalized
-        }
-    }
-}
-
-
-struct TopStockRow_Previews: PreviewProvider {
-    static var previews: some View {
-        TopStockRow(listType: "gainers", list: [CompanyQuoteModel(companyName: "apple inc", symbol: "aapl", latestPrice: 120.30, changePercent: 0.034)])
-    }
-}
--- a/LazyBear/Views/Home/HomeView.swift	Mon Apr 05 20:08:19 2021 +0200
+++ b/LazyBear/Views/Home/HomeView.swift	Tue Apr 06 11:04:21 2021 +0200
@@ -10,6 +10,7 @@
 struct HomeView: View {
     @ObservedObject var homeData = HomeData()
     @State private var showTradingDates = false
+    
     // Set recurrent price request
     @State private var timer = Timer.publish(every: 10, on: .main, in: .common).autoconnect()
     
@@ -29,9 +30,11 @@
                         .listRowInsets(EdgeInsets())
                         
                     // Get keys of the dictionary list
-                    ForEach(homeData.topLists.keys.sorted(), id: \.self) { listType in
+                    let listTypes = ["mostactive", "losers", "gainers"]
+                    ForEach(listTypes.sorted(), id: \.self) { listType in
                         if let list = homeData.topLists[listType] {
-                            TopStockRow(listType: listType, list: list)
+                            StockRectangleRow(listType: listType, list: list, intradayPrices: homeData.intradayPrices)
+                                
                         }
                     }
                     .listRowInsets(EdgeInsets())
--- a/LazyBear/Views/Home/Networking/HomeData.swift	Mon Apr 05 20:08:19 2021 +0200
+++ b/LazyBear/Views/Home/Networking/HomeData.swift	Tue Apr 06 11:04:21 2021 +0200
@@ -9,13 +9,13 @@
 
 class HomeData: ObservableObject {
     @Published var showView = false
+    
+    // Data
     @Published var sectorPerformance = [SectorPerformanceModel]()
-    @Published var topLists = [
-        "gainers": [CompanyQuoteModel](),
-        "losers": [CompanyQuoteModel](),
-        "mostactive": [CompanyQuoteModel]()
-    ]
+    @Published var topLists = [String(): [CompanyQuoteModel]()]
+    @Published var intradayPrices = [String(): [IntradayPricesResult]()]
     
+    private var symbolsInLists = [String()]
     private let baseUrl = Bundle.main.infoDictionary?["IEX_URL"] as? String ?? "Empty url"
     private let apiKey = Bundle.main.infoDictionary?["IEX_API"] as? String ?? "Empty key"
     
@@ -24,7 +24,7 @@
         let dispatchGroup = DispatchGroup()
         var url = String()
         
-        // 1. REQUEST SECTOR PERFORMANCE
+        // 1. SECTOR PERFORMANCE REQUEST
         url = "\(baseUrl)/stock/market/sector-performance?token=\(apiKey)"
         dispatchGroup.enter()
         
@@ -33,18 +33,53 @@
             dispatchGroup.leave()
         }
         
-        // 2. STOCK LISTS
-        for listType in topLists.keys {
+        // 2. STOCK LISTS REQUEST
+        let listTypes = ["mostactive", "losers", "gainers"]
+        for listType in listTypes {
             url = "\(baseUrl)/stock/market/list/\(listType)?token=\(apiKey)"
             dispatchGroup.enter()
             
-            genericRequest(url: url, model: [CompanyQuoteModel].self) {
-                self.topLists[listType] = $0
+            genericRequest(url: url, model: [CompanyQuoteModel].self) { list in
+                self.topLists[listType] = list
+                // Append symbols in list to array
+                for company in list {
+                    self.symbolsInLists.append(company.symbol)
+                }
+        
                 dispatchGroup.leave()
             }
         }
         
         dispatchGroup.notify(queue: .main) {
+            if self.intradayPrices.count == 1 {
+                self.getIntradayPrices()
+            } else {
+                self.showView = true
+            }
+        }
+    }
+    
+    // 3. INTRADAY PRICES REQUEST
+    func getIntradayPrices() {
+        var url = "\(baseUrl)/stock/market/batch?symbols="
+        
+        var counter = 0
+        for symbol in symbolsInLists {
+            counter += 1
+            if counter == 1 {
+                url += symbol
+            } else {
+                url += ",\(symbol)"
+            }
+        }
+        
+        url += "&types=intradayprices&token=\(apiKey)"
+        
+        genericRequest(url: url, model: [String: IntradayPricesBatch].self) { dict in
+            for symbol in dict.keys {
+                self.intradayPrices[symbol] = dict[symbol]?.intradayprices
+            }
+            
             self.showView = true
         }
     }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/LazyBear/Views/Profile/Networking/ProfileData.swift	Tue Apr 06 11:04:21 2021 +0200
@@ -0,0 +1,46 @@
+//
+//  ProfileData.swift
+//  LazyBear
+//
+//  Created by Dennis Concepción Martín on 5/4/21.
+//
+
+import SwiftUI
+
+class ProfileData: ObservableObject {
+    @Published var companies = [CompanyQuoteModel]()
+    @Published var showView = false
+    @FetchRequest(entity: WatchlistCompany.entity(), sortDescriptors: [])
+    var watchlistCompanies: FetchedResults<WatchlistCompany>
+    
+    private let baseUrl = Bundle.main.infoDictionary?["IEX_URL"] as? String ?? "Empty url"
+    private let apiKey = Bundle.main.infoDictionary?["IEX_API"] as? String ?? "Empty key"
+    
+    private func get() {
+        var url = "\(baseUrl)/stock/market/batch?symbols="
+        
+        if !watchlistCompanies.isEmpty {
+            let symbols = watchlistCompanies.map { $0.symbol }
+            for symbol in symbols {
+                if symbols.firstIndex(of: symbol) == 0 {
+                    url += symbol!
+                } else {
+                    url += "\(symbol!),"
+                }
+            }
+            
+            url = "&types=quote&token=\(apiKey)"
+            genericRequest(url: url, model: [String: CompanyQuoteBatch].self) {
+                print($0)
+                self.showView = true
+            }
+        } else {
+            self.showView = true
+        }
+    }
+}
+
+
+struct CompanyQuoteBatch: Codable {
+    var quote: CompanyQuoteModel
+}
--- a/LazyBear/Views/Profile/ProfileView.swift	Mon Apr 05 20:08:19 2021 +0200
+++ b/LazyBear/Views/Profile/ProfileView.swift	Tue Apr 06 11:04:21 2021 +0200
@@ -8,13 +8,12 @@
 import SwiftUI
 
 struct ProfileView: View {
-    @FetchRequest(entity: WatchlistCompany.entity(), sortDescriptors: [])
-    var watchlistCompanies: FetchedResults<WatchlistCompany>
+    @ObservedObject var profileData = ProfileData()
     
     var body: some View {
         NavigationView {
             List {
-                ForEach(watchlistCompanies, id: \.self) { company in
+                ForEach(profileData.companies, id: \.self) { company in
                     Text("Hello company")
                 }
             }