Mercurial > public > lazybear
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") } }