# HG changeset patch # User Dennis Concepción Martín <66180929+denniscm190@users.noreply.github.com> # Date 1617699861 -7200 # Node ID ab909fc9ce55b37a908f124c0bdf94eea4981e37 # Parent a6c49f1409f3633639f8475e17582d09b83639be Implement batch requests HomeView diff -r a6c49f1409f3 -r ab909fc9ce55 LazyBear.xcodeproj/project.pbxproj --- 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 = ""; }; 9550444226111E7A000E0BCB /* SectorRow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SectorRow.swift; sourceTree = ""; }; 9550444526111EE5000E0BCB /* SectorItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SectorItem.swift; sourceTree = ""; }; - 9550444826111FC9000E0BCB /* TopStockRow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TopStockRow.swift; sourceTree = ""; }; + 9550444826111FC9000E0BCB /* StockRectangleRow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StockRectangleRow.swift; sourceTree = ""; }; 9550444B26111FED000E0BCB /* StockItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StockItem.swift; sourceTree = ""; }; 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 = ""; }; @@ -98,6 +99,7 @@ 95ECCA5C2612169200A67EFA /* LineShape.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LineShape.swift; sourceTree = ""; }; 95ECCA5F261216D500A67EFA /* LineView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LineView.swift; sourceTree = ""; }; 95FBE0DB2619CA7200440386 /* ProfileView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProfileView.swift; sourceTree = ""; }; + 95FD09CA261BA13800393042 /* ProfileData.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProfileData.swift; sourceTree = ""; }; /* 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 = ""; }; + 95CD32E2261C5B0600901250 /* Secondary Views */ = { + isa = PBXGroup; + children = ( + 95CD32E3261C5B2200901250 /* Company */, + ); + path = "Secondary Views"; + sourceTree = ""; + }; + 95CD32E3261C5B2200901250 /* Company */ = { + isa = PBXGroup; + children = ( + ); + path = Company; + sourceTree = ""; + }; 95E745D72614622C00744A1E /* Home */ = { isa = PBXGroup; children = ( @@ -321,10 +339,19 @@ isa = PBXGroup; children = ( 95FBE0DB2619CA7200440386 /* ProfileView.swift */, + 95FD09C9261BA12800393042 /* Networking */, ); path = Profile; sourceTree = ""; }; + 95FD09C9261BA12800393042 /* Networking */ = { + isa = PBXGroup; + children = ( + 95FD09CA261BA13800393042 /* ProfileData.swift */, + ); + path = Networking; + sourceTree = ""; + }; /* 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 */, diff -r a6c49f1409f3 -r ab909fc9ce55 LazyBear.xcodeproj/project.xcworkspace/xcuserdata/dennis.xcuserdatad/UserInterfaceState.xcuserstate Binary file LazyBear.xcodeproj/project.xcworkspace/xcuserdata/dennis.xcuserdatad/UserInterfaceState.xcuserstate has changed diff -r a6c49f1409f3 -r ab909fc9ce55 LazyBear.xcodeproj/xcshareddata/xcschemes/LazyBear.xcscheme --- 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 @@ 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)]) +// } +//} diff -r a6c49f1409f3 -r ab909fc9ce55 LazyBear/Views/Home/Helpers/TopStockRow.swift --- 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)]) - } -} diff -r a6c49f1409f3 -r ab909fc9ce55 LazyBear/Views/Home/HomeView.swift --- 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()) diff -r a6c49f1409f3 -r ab909fc9ce55 LazyBear/Views/Home/Networking/HomeData.swift --- 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 } } diff -r a6c49f1409f3 -r ab909fc9ce55 LazyBear/Views/Profile/Networking/ProfileData.swift --- /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 + + 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 +} diff -r a6c49f1409f3 -r ab909fc9ce55 LazyBear/Views/Profile/ProfileView.swift --- 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 + @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") } }