# HG changeset patch # User Dennis Concepción Martín <66180929+denniscm190@users.noreply.github.com> # Date 1617287685 -7200 # Node ID 31f2838b2de7057fbeb94cfa048788fe86c62919 # Parent 6f904b1665646063653bb78525171eb82f9eb4e1 Improving API requests with DispatchGroup diff -r 6f904b166564 -r 31f2838b2de7 LazyBear.xcodeproj/project.pbxproj --- a/LazyBear.xcodeproj/project.pbxproj Wed Mar 31 20:42:44 2021 +0200 +++ b/LazyBear.xcodeproj/project.pbxproj Thu Apr 01 16:34:45 2021 +0200 @@ -14,8 +14,9 @@ 951566E72613A2B6007C0F36 /* TradingDates.swift in Sources */ = {isa = PBXBuildFile; fileRef = 951566E62613A2B6007C0F36 /* TradingDates.swift */; }; 951566EA2613A37C007C0F36 /* TradingDatesItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 951566E92613A37C007C0F36 /* TradingDatesItem.swift */; }; 952045152610C7C600A76362 /* ConvertEpoch.swift in Sources */ = {isa = PBXBuildFile; fileRef = 952045142610C7C600A76362 /* ConvertEpoch.swift */; }; - 952045182610C83600A76362 /* Request.swift in Sources */ = {isa = PBXBuildFile; fileRef = 952045172610C83600A76362 /* Request.swift */; }; - 952045242610FD7F00A76362 /* CompanyRowModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 952045232610FD7F00A76362 /* CompanyRowModel.swift */; }; + 9523ED422615BDB2006D3D6F /* Phrases.json in Resources */ = {isa = PBXBuildFile; fileRef = 9523ED412615BDB2006D3D6F /* Phrases.json */; }; + 9523ED542615CB7F006D3D6F /* HomeData.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9523ED532615CB7F006D3D6F /* HomeData.swift */; }; + 9523ED592615D1D8006D3D6F /* GenericRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9523ED582615D1D8006D3D6F /* GenericRequest.swift */; }; 954D7EA7260BBA6600A13C50 /* WatchlistCompany+CoreDataClass.swift in Sources */ = {isa = PBXBuildFile; fileRef = 954D7EA5260BBA6600A13C50 /* WatchlistCompany+CoreDataClass.swift */; }; 954D7EA8260BBA6600A13C50 /* WatchlistCompany+CoreDataProperties.swift in Sources */ = {isa = PBXBuildFile; fileRef = 954D7EA6260BBA6600A13C50 /* WatchlistCompany+CoreDataProperties.swift */; }; 954D7EC2260BE70C00A13C50 /* SwiftlySearch in Frameworks */ = {isa = PBXBuildFile; productRef = 954D7EC1260BE70C00A13C50 /* SwiftlySearch */; }; @@ -29,12 +30,9 @@ 95672B9625DDA54700DCBE4A /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 95672B9525DDA54700DCBE4A /* Preview Assets.xcassets */; }; 95672B9825DDA54700DCBE4A /* Persistence.swift in Sources */ = {isa = PBXBuildFile; fileRef = 95672B9725DDA54700DCBE4A /* Persistence.swift */; }; 95672B9B25DDA54800DCBE4A /* LazyBear.xcdatamodeld in Sources */ = {isa = PBXBuildFile; fileRef = 95672B9925DDA54800DCBE4A /* LazyBear.xcdatamodeld */; }; - 9585FE782614E5E60022CFD8 /* TradingDatesModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9585FE772614E5E60022CFD8 /* TradingDatesModel.swift */; }; - 95893DC92613C421003698C5 /* HomeData.swift in Sources */ = {isa = PBXBuildFile; fileRef = 95893DC82613C421003698C5 /* HomeData.swift */; }; - 95893DCE2613C46B003698C5 /* SectorPerformanceModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 95893DCD2613C46B003698C5 /* SectorPerformanceModel.swift */; }; + 95893DCE2613C46B003698C5 /* HomeModels.swift in Sources */ = {isa = PBXBuildFile; fileRef = 95893DCD2613C46B003698C5 /* HomeModels.swift */; }; 958A735225E0170900FD7ECA /* CloudKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 958A735125E0170900FD7ECA /* CloudKit.framework */; }; 95AD4A2D26078C1400498079 /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 95AD4A2C26078C1400498079 /* ContentView.swift */; }; - 95BC3B4F261476FB00FC3A12 /* IntradayPricesModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 95BC3B4E261476FB00FC3A12 /* IntradayPricesModel.swift */; }; 95E745DA2614624500744A1E /* HomeDataPreview.swift in Sources */ = {isa = PBXBuildFile; fileRef = 95E745D92614624500744A1E /* HomeDataPreview.swift */; }; 95ECCA5D2612169200A67EFA /* LineShape.swift in Sources */ = {isa = PBXBuildFile; fileRef = 95ECCA5C2612169200A67EFA /* LineShape.swift */; }; 95ECCA60261216D500A67EFA /* LineView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 95ECCA5F261216D500A67EFA /* LineView.swift */; }; @@ -50,8 +48,9 @@ 951566E62613A2B6007C0F36 /* TradingDates.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TradingDates.swift; sourceTree = ""; }; 951566E92613A37C007C0F36 /* TradingDatesItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TradingDatesItem.swift; sourceTree = ""; }; 952045142610C7C600A76362 /* ConvertEpoch.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConvertEpoch.swift; sourceTree = ""; }; - 952045172610C83600A76362 /* Request.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Request.swift; sourceTree = ""; }; - 952045232610FD7F00A76362 /* CompanyRowModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CompanyRowModel.swift; sourceTree = ""; }; + 9523ED412615BDB2006D3D6F /* Phrases.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; path = Phrases.json; sourceTree = ""; }; + 9523ED532615CB7F006D3D6F /* HomeData.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HomeData.swift; sourceTree = ""; }; + 9523ED582615D1D8006D3D6F /* GenericRequest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GenericRequest.swift; sourceTree = ""; }; 954D7EA5260BBA6600A13C50 /* WatchlistCompany+CoreDataClass.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "WatchlistCompany+CoreDataClass.swift"; sourceTree = ""; }; 954D7EA6260BBA6600A13C50 /* WatchlistCompany+CoreDataProperties.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "WatchlistCompany+CoreDataProperties.swift"; sourceTree = ""; }; 9550443926111B2B000E0BCB /* HomeView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HomeView.swift; sourceTree = ""; }; @@ -66,13 +65,10 @@ 95672B9725DDA54700DCBE4A /* Persistence.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Persistence.swift; sourceTree = ""; }; 95672B9A25DDA54800DCBE4A /* LazyBear.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = LazyBear.xcdatamodel; sourceTree = ""; }; 95672B9C25DDA54800DCBE4A /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - 9585FE772614E5E60022CFD8 /* TradingDatesModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TradingDatesModel.swift; sourceTree = ""; }; - 95893DC82613C421003698C5 /* HomeData.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HomeData.swift; sourceTree = ""; }; - 95893DCD2613C46B003698C5 /* SectorPerformanceModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SectorPerformanceModel.swift; sourceTree = ""; }; + 95893DCD2613C46B003698C5 /* HomeModels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HomeModels.swift; sourceTree = ""; }; 958A734E25E016FD00FD7ECA /* LazyBear.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = LazyBear.entitlements; sourceTree = ""; }; 958A735125E0170900FD7ECA /* CloudKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CloudKit.framework; path = System/Library/Frameworks/CloudKit.framework; sourceTree = SDKROOT; }; 95AD4A2C26078C1400498079 /* ContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = ""; }; - 95BC3B4E261476FB00FC3A12 /* IntradayPricesModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IntradayPricesModel.swift; sourceTree = ""; }; 95E745D92614624500744A1E /* HomeDataPreview.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HomeDataPreview.swift; sourceTree = ""; }; 95ECCA5C2612169200A67EFA /* LineShape.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LineShape.swift; sourceTree = ""; }; 95ECCA5F261216D500A67EFA /* LineView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LineView.swift; sourceTree = ""; }; @@ -110,11 +106,19 @@ isa = PBXGroup; children = ( 952045142610C7C600A76362 /* ConvertEpoch.swift */, - 952045172610C83600A76362 /* Request.swift */, + 9523ED582615D1D8006D3D6F /* GenericRequest.swift */, ); path = "Global functions"; sourceTree = ""; }; + 9523ED402615BD93006D3D6F /* Resources */ = { + isa = PBXGroup; + children = ( + 9523ED412615BDB2006D3D6F /* Phrases.json */, + ); + path = Resources; + sourceTree = ""; + }; 954D7E9D260BBA5200A13C50 /* Global Models */ = { isa = PBXGroup; children = ( @@ -122,8 +126,6 @@ 950C36E7260FBB550081CF53 /* UserSettings+CoreDataProperties.swift */, 954D7EA5260BBA6600A13C50 /* WatchlistCompany+CoreDataClass.swift */, 954D7EA6260BBA6600A13C50 /* WatchlistCompany+CoreDataProperties.swift */, - 952045232610FD7F00A76362 /* CompanyRowModel.swift */, - 95BC3B4E261476FB00FC3A12 /* IntradayPricesModel.swift */, ); path = "Global Models"; sourceTree = ""; @@ -134,6 +136,7 @@ 9550443926111B2B000E0BCB /* HomeView.swift */, 951566E62613A2B6007C0F36 /* TradingDates.swift */, 954D7EAF260BBBD500A13C50 /* Helpers */, + 95893DC72613C410003698C5 /* Networking */, ); path = Home; sourceTree = ""; @@ -183,6 +186,7 @@ 95B1874925DDAC4D0068A364 /* Views */, 952045132610C7A200A76362 /* Global functions */, 954D7E9D260BBA5200A13C50 /* Global Models */, + 9523ED402615BD93006D3D6F /* Resources */, 95201A36260CAD36007D5300 /* Tests */, 95672B9425DDA54700DCBE4A /* Preview Content */, ); @@ -201,9 +205,8 @@ 95893DC72613C410003698C5 /* Networking */ = { isa = PBXGroup; children = ( - 95893DC82613C421003698C5 /* HomeData.swift */, - 95893DCD2613C46B003698C5 /* SectorPerformanceModel.swift */, - 9585FE772614E5E60022CFD8 /* TradingDatesModel.swift */, + 9523ED532615CB7F006D3D6F /* HomeData.swift */, + 95893DCD2613C46B003698C5 /* HomeModels.swift */, ); path = Networking; sourceTree = ""; @@ -230,7 +233,6 @@ children = ( 951490572610BD3000BDEEB5 /* Welcome */, 954D7EAA260BBB0E00A13C50 /* Home */, - 95893DC72613C410003698C5 /* Networking */, 95893DD22613CAB5003698C5 /* Global Helpers */, ); path = Views; @@ -316,6 +318,7 @@ buildActionMask = 2147483647; files = ( 95672B9625DDA54700DCBE4A /* Preview Assets.xcassets in Resources */, + 9523ED422615BDB2006D3D6F /* Phrases.json in Resources */, 95672B9325DDA54700DCBE4A /* Assets.xcassets in Resources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -328,11 +331,11 @@ buildActionMask = 2147483647; files = ( 950C36E3260FB6180081CF53 /* HapticsManager.swift in Sources */, + 9523ED592615D1D8006D3D6F /* GenericRequest.swift in Sources */, 95E745DA2614624500744A1E /* HomeDataPreview.swift in Sources */, 9550444926111FC9000E0BCB /* TopStockRow.swift in Sources */, - 952045242610FD7F00A76362 /* CompanyRowModel.swift in Sources */, + 9523ED542615CB7F006D3D6F /* HomeData.swift in Sources */, 9550444326111E7A000E0BCB /* SectorRow.swift in Sources */, - 952045182610C83600A76362 /* Request.swift in Sources */, 95ECCA60261216D500A67EFA /* LineView.swift in Sources */, 9550443A26111B2B000E0BCB /* HomeView.swift in Sources */, 950C36E8260FBB550081CF53 /* UserSettings+CoreDataClass.swift in Sources */, @@ -340,11 +343,8 @@ 950C36E9260FBB550081CF53 /* UserSettings+CoreDataProperties.swift in Sources */, 954D7EA8260BBA6600A13C50 /* WatchlistCompany+CoreDataProperties.swift in Sources */, 951566E72613A2B6007C0F36 /* TradingDates.swift in Sources */, - 95BC3B4F261476FB00FC3A12 /* IntradayPricesModel.swift in Sources */, - 95893DC92613C421003698C5 /* HomeData.swift in Sources */, - 95893DCE2613C46B003698C5 /* SectorPerformanceModel.swift in Sources */, + 95893DCE2613C46B003698C5 /* HomeModels.swift in Sources */, 95672B8F25DDA54700DCBE4A /* LazyBearApp.swift in Sources */, - 9585FE782614E5E60022CFD8 /* TradingDatesModel.swift in Sources */, 95ECCA5D2612169200A67EFA /* LineShape.swift in Sources */, 9550444C26111FED000E0BCB /* TopStockItem.swift in Sources */, 951566EA2613A37C007C0F36 /* TradingDatesItem.swift in Sources */, diff -r 6f904b166564 -r 31f2838b2de7 LazyBear.xcodeproj/project.xcworkspace/xcuserdata/dennis.xcuserdatad/UserInterfaceState.xcuserstate Binary file LazyBear.xcodeproj/project.xcworkspace/xcuserdata/dennis.xcuserdatad/UserInterfaceState.xcuserstate has changed diff -r 6f904b166564 -r 31f2838b2de7 LazyBear/Global Models/CompanyRowModel.swift --- a/LazyBear/Global Models/CompanyRowModel.swift Wed Mar 31 20:42:44 2021 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,15 +0,0 @@ -// -// CompanyRowModel.swift -// LazyBear -// -// Created by Dennis Concepción Martín on 28/3/21. -// - -import SwiftUI - -struct CompanyRowModel: Codable, Hashable { - var symbol: String - var companyName: String - var latestPrice: Double - var changePercent: Double -} diff -r 6f904b166564 -r 31f2838b2de7 LazyBear/Global Models/IntradayPricesModel.swift --- a/LazyBear/Global Models/IntradayPricesModel.swift Wed Mar 31 20:42:44 2021 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,23 +0,0 @@ -// -// IntradayPricesModel.swift -// LazyBear -// -// Created by Dennis Concepción Martín on 31/3/21. -// - -import SwiftUI - -// Model prepared with batch - -struct IntradayPricesArray: Codable { - var intradayPrices: [IntradayPricesModel] - - // Change key name - private enum CodingKeys : String, CodingKey { - case intradayPrices = "intraday-prices" - } -} - -struct IntradayPricesModel: Codable { - var open: Double? -} diff -r 6f904b166564 -r 31f2838b2de7 LazyBear/Global functions/GenericRequest.swift --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/LazyBear/Global functions/GenericRequest.swift Thu Apr 01 16:34:45 2021 +0200 @@ -0,0 +1,36 @@ +// +// GenericRequest.swift +// LazyBear +// +// Created by Dennis Concepción Martín on 1/4/21. +// + +import SwiftUI + +// Network request +func genericRequest(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") + return + } + let request = URLRequest(url: url) + URLSession.shared.dataTask(with: request) { data, response, error in + if let data = data { + do { + // Decode response with the model passed + let decodedResponse = try JSONDecoder().decode(model, from: data) + DispatchQueue.main.async { + completion(decodedResponse) + } + return + } catch { + // Return error regarding the escaping code + print(error) + } + } + // Error with the request + print("Fetch failed: \(error?.localizedDescription ?? "Unknown error")") + } + .resume() +} diff -r 6f904b166564 -r 31f2838b2de7 LazyBear/Global functions/Request.swift --- a/LazyBear/Global functions/Request.swift Wed Mar 31 20:42:44 2021 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,36 +0,0 @@ -// -// Request.swift -// LazyBear -// -// Created by Dennis Concepción Martín on 28/3/21. -// - -import Foundation - -// Network request -func request(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") - return - } - let request = URLRequest(url: url) - URLSession.shared.dataTask(with: request) { data, response, error in - if let data = data { - do { - // Decode response with the model passed - let decodedResponse = try JSONDecoder().decode(model, from: data) - DispatchQueue.main.async { - completion(decodedResponse) - } - return - } catch { - // Return error regarding the escaping code - print(error) - } - } - // Error with the request - print("Fetch failed: \(error?.localizedDescription ?? "Unknown error")") - } - .resume() -} diff -r 6f904b166564 -r 31f2838b2de7 LazyBear/Resources/Phrases.json --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/LazyBear/Resources/Phrases.json Thu Apr 01 16:34:45 2021 +0200 @@ -0,0 +1,25 @@ +[ + { + "funny": [ + "Tomorrow is often the busiest day of the week", + "They shorted my stock, I shortened their lives", + "The stock market is still les volatile than most of my romantic relationships", + "Dear diary, today the stock market did not crash", + "If you want to trade in derivates, god bless you", + "When the market crash, just take the absolute value", + "I was losing money before the stock market crashed", + "The Lazybear of Wall Street", + "Can't lose your savings if you have no savings", + "Stonks", + "So you dont buy more when a stock goes down?", + "Hey the stock market is up AAAA It's down", + "Top 3 richest people: Musk, Bezos, not you", + "Oh no... my stock did what?", + "Are you a Redditor?", + "No I don't know what happened", + "Hey, Do you want some quantitative easing?", + "Money printer go Brrr", + "You have two cows. The State takes both of them and gives you the milk" + ] + } +] diff -r 6f904b166564 -r 31f2838b2de7 LazyBear/Views/Home/Helpers/TradingDatesItem.swift --- a/LazyBear/Views/Home/Helpers/TradingDatesItem.swift Wed Mar 31 20:42:44 2021 +0200 +++ b/LazyBear/Views/Home/Helpers/TradingDatesItem.swift Thu Apr 01 16:34:45 2021 +0200 @@ -29,18 +29,16 @@ .font(.title) .fontWeight(.semibold) .foregroundColor(Color("default")) + + Text(get(.year)) + .font(.caption) + .fontWeight(.semibold) } Spacer() VStack { - Text("US Markets open in regular hours") + Text("US Markets are closed") .fontWeight(.semibold) - - Text("Random funny phrase") - .font(.caption) - .fontWeight(.semibold) - .multilineTextAlignment(.center) - .opacity(0.6) } Spacer() diff -r 6f904b166564 -r 31f2838b2de7 LazyBear/Views/Home/HomeView.swift --- a/LazyBear/Views/Home/HomeView.swift Wed Mar 31 20:42:44 2021 +0200 +++ b/LazyBear/Views/Home/HomeView.swift Thu Apr 01 16:34:45 2021 +0200 @@ -21,32 +21,36 @@ let dueDate = Date() var body: some View { - NavigationView { - List { - SectorRow(sectorPerformance: homeData.sectorPerformance) + if homeData.showView { + NavigationView { + List { + SectorRow(sectorPerformance: homeData.sectorPerformance) + .listRowInsets(EdgeInsets()) + + // Get keys of the dictionary list + ForEach(homeData.list.keys.sorted(), id: \.self) { key in + TopStockRow(key: key, list: homeData.list[key] ?? [CompanyRowModel](), intradayPricesDict: homeData.intradayPrices) + } .listRowInsets(EdgeInsets()) - - // Get keys of the dictionary list - ForEach(homeData.list.keys.sorted(), id: \.self) { key in - TopStockRow(key: key, list: homeData.list[key] ?? [CompanyRowModel](), intradayPricesDict: homeData.intradayPrices) } - .listRowInsets(EdgeInsets()) - } - .navigationTitle("\(dueDate, formatter: Self.taskDateFormat)") - .navigationBarTitleDisplayMode(.inline) - .navigationViewStyle(StackNavigationViewStyle()) - .toolbar { - ToolbarItem(placement: .navigationBarTrailing) { - Button(action: { showTradingDates = true }) { - Image(systemName: "calendar.badge.clock") + .onReceive(timer) {_ in homeData.request() } + .navigationTitle("\(dueDate, formatter: Self.taskDateFormat)") + .navigationBarTitleDisplayMode(.inline) + .navigationViewStyle(StackNavigationViewStyle()) + .toolbar { + ToolbarItem(placement: .navigationBarTrailing) { + Button(action: { showTradingDates = true }) { + Image(systemName: "calendar.badge.clock") + } } } } - } - .onAppear { homeData.get() } - .onReceive(timer) {_ in homeData.get() } - .sheet(isPresented: $showTradingDates) { - TradingDates(stringDates: homeData.holidayDates) + .sheet(isPresented: $showTradingDates) { +// TradingDates(stringDates: homeData.holidayDates) + } + } else { + ProgressView() + .onAppear { homeData.request() } } } } diff -r 6f904b166564 -r 31f2838b2de7 LazyBear/Views/Home/Networking/HomeData.swift --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/LazyBear/Views/Home/Networking/HomeData.swift Thu Apr 01 16:34:45 2021 +0200 @@ -0,0 +1,85 @@ +// +// HomeData.swift +// LazyBear +// +// Created by Dennis Concepción Martín on 1/4/21. +// + +import SwiftUI + +class HomeData: ObservableObject { + @Published var showView = false + @Published var sectorPerformance = [SectorPerformanceModel]() + @Published var list = ["mostactive": [CompanyRowModel](), "gainers": [CompanyRowModel](), "losers": [CompanyRowModel]()] + @Published var intradayPrices = [String(): IntradayPricesArray(intradayPrices: [IntradayPricesModel(open: Double())])] + + private let baseUrl = Bundle.main.infoDictionary?["IEX_URL"] as? String ?? "Empty url" + private let apiKey = Bundle.main.infoDictionary?["IEX_API"] as? String ?? "Empty key" + + // Call this function to make the request + func request() { + let dispatchGroup = DispatchGroup() // Start dispatch group + var url = String() + +// 1. SECTOR PERFORMANCE REQUEST + url = "\(baseUrl)/stock/market/sector-performance?token=\(apiKey)" + print("Entering group: request Sector Performance") + dispatchGroup.enter() // Enter group + + // API Request + genericRequest(url: url, model: [SectorPerformanceModel].self) { + self.sectorPerformance = $0 + print("Leaving group: request Sector Performance") + dispatchGroup.leave() // Leave group + } + +// 2. LISTS REQUEST + var symbols = [String]() // Know what symbols are in each list + for key in self.list.keys { + url = "\(baseUrl)/stock/market/collection/list?collectionName=\(key)&token=\(apiKey)" + print("Entering group: request list \(key)") + dispatchGroup.enter() // Enter group + + // API Request + genericRequest(url: url, model: [CompanyRowModel].self) { + self.list[key] = $0 + print("Leaving group: request list \(key)") + dispatchGroup.leave() + + // Append symbols requested to a list + if let companies = self.list[key] { // Unwrap value + for company in companies { // Iterate inside the list through the companies + symbols.append(company.symbol) + } + } + + // Now that I have all the symbols I can request the intraday prices and save it to the @Published var + // First I have to concatenate the string to make the batch request + url = "\(self.baseUrl)/stock/market/batch?symbols=" + for symbol in symbols { // Concatenate symbol to the first part of the url + if symbols.firstIndex(of: symbol) == 0 { + url += symbol + } else { + url += ",\(symbol)" + } + } + } + } + + // This will run after the ForLoop and if it was successful + dispatchGroup.notify(queue: .main) { + +// 3. INTRADAY PRICES REQUEST + // Once the previous request are made, I can append the final part of the url and make the request + url = "\(url)&types=intraday-prices&token=\(self.apiKey)" + genericRequest(url: url, model: [String: IntradayPricesArray].self) { + self.intradayPrices = $0 + + print("Request done successfully -> showing view") + self.showView = true + } + } + } +} + + diff -r 6f904b166564 -r 31f2838b2de7 LazyBear/Views/Home/Networking/HomeModels.swift --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/LazyBear/Views/Home/Networking/HomeModels.swift Thu Apr 01 16:34:45 2021 +0200 @@ -0,0 +1,43 @@ +// +// SectorPerformanceModel.swift +// LazyBear +// +// Created by Dennis Concepción Martín on 30/3/21. +// + +import SwiftUI + +struct SectorPerformanceModel: Codable, Hashable { + var name: String + var performance: Double + var lastUpdated: Int +} + + +struct CompanyRowModel: Codable, Hashable { + var symbol: String + var companyName: String + var latestPrice: Double + var changePercent: Double +} + + +// Model prepared with batch +struct IntradayPricesArray: Codable { + var intradayPrices: [IntradayPricesModel] + + // Change key name + private enum CodingKeys : String, CodingKey { + case intradayPrices = "intraday-prices" + } +} + +struct IntradayPricesModel: Codable { + var open: Double? +} + + +struct TradingDatesModel: Codable { + var date: String + +} diff -r 6f904b166564 -r 31f2838b2de7 LazyBear/Views/Home/TradingDates.swift --- a/LazyBear/Views/Home/TradingDates.swift Wed Mar 31 20:42:44 2021 +0200 +++ b/LazyBear/Views/Home/TradingDates.swift Thu Apr 01 16:34:45 2021 +0200 @@ -13,7 +13,7 @@ var body: some View { NavigationView { ScrollView { - VStack(spacing: 30) { + VStack(spacing: 20) { ForEach(getArrayOfDates(), id: \.self) { date in TradingDatesItem(date: date) } diff -r 6f904b166564 -r 31f2838b2de7 LazyBear/Views/Networking/HomeData.swift --- a/LazyBear/Views/Networking/HomeData.swift Wed Mar 31 20:42:44 2021 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,65 +0,0 @@ -// -// HomeData.swift -// LazyBear -// -// Created by Dennis Concepción Martín on 30/3/21. -// - -import SwiftUI - -class HomeData: ObservableObject { - @Published var sectorPerformance = [SectorPerformanceModel]() - @Published var list = ["mostactive": [CompanyRowModel](), "gainers": [CompanyRowModel](), "losers": [CompanyRowModel]()] - @Published var intradayPrices = [String(): IntradayPricesArray(intradayPrices: [IntradayPricesModel(open: Double())])] - @Published var holidayDates = [TradingDatesModel]() - - private let baseUrl = Bundle.main.infoDictionary?["IEX_URL"] as? String ?? "Empty url" - private let apiKey = Bundle.main.infoDictionary?["IEX_API"] as? String ?? "Empty key" - - // PRINCIPAL FUNCTION TO CALL - func get() { - // 1. Request sector performance - var url = "\(baseUrl)/stock/market/sector-performance?token=\(apiKey)" - request(url: url, model: [SectorPerformanceModel].self) { self.sectorPerformance = $0 } - - // 2. Request lists - var semaphore = 0 - for key in self.list.keys { - url = "\(self.baseUrl)/stock/market/collection/list?collectionName=\(key)&token=\(self.apiKey)" - request(url: url, model: [CompanyRowModel].self) { self.list[key] = $0; semaphore += 1 // Finish modifying dictionary - - if semaphore == 3 { // When dictionary is modified - - // 3. Request intraday prices - var symbols = [String]() - for key in self.list.keys { // Iterate throught the list - if let companies = self.list[key] { // Unwrap value - for company in companies { // Iterate inside the list through the companies - symbols.append(company.symbol) // Append symbol - } - } - } - - // Now that I have all the symbols I can request the intraday prices and save it to the @Published var - // First I have to concatenate the string to make the batch request - url = "\(self.baseUrl)/stock/market/batch?symbols=" - for symbol in symbols { // Concatenate symbol to the first part of the url - if symbols.firstIndex(of: symbol) == 0 { - url += symbol - } else { - url += ",\(symbol)" - } - } - - // Once it's made, I can append the final part of the url and make the request - url = "\(url)&types=intraday-prices&token=\(self.apiKey)" - request(url: url, model: [String: IntradayPricesArray].self) { self.intradayPrices = $0 } - } - } - } - - // 4. Request trading and holiday days - url = "\(baseUrl)/ref-data/us/dates/holiday/next/30?token=\(apiKey)" - request(url: url, model: [TradingDatesModel].self) { self.holidayDates = $0 } - } -} diff -r 6f904b166564 -r 31f2838b2de7 LazyBear/Views/Networking/SectorPerformanceModel.swift --- a/LazyBear/Views/Networking/SectorPerformanceModel.swift Wed Mar 31 20:42:44 2021 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,14 +0,0 @@ -// -// SectorPerformanceModel.swift -// LazyBear -// -// Created by Dennis Concepción Martín on 30/3/21. -// - -import SwiftUI - -struct SectorPerformanceModel: Codable, Hashable { - var name: String - var performance: Double - var lastUpdated: Int -} diff -r 6f904b166564 -r 31f2838b2de7 LazyBear/Views/Networking/TradingDatesModel.swift --- a/LazyBear/Views/Networking/TradingDatesModel.swift Wed Mar 31 20:42:44 2021 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,13 +0,0 @@ -// -// TradingDatesModel.swift -// LazyBear -// -// Created by Dennis Concepción Martín on 31/3/21. -// - -import SwiftUI - -struct TradingDatesModel: Codable { - var date: String - -}