Mercurial > public > lazybear
changeset 335:2dad5828ccf6
HomeView implemented
author | Dennis Concepción Martín <66180929+denniscm190@users.noreply.github.com> |
---|---|
date | Wed, 31 Mar 2021 17:06:57 +0200 |
parents | d7927e7eeff1 |
children | 6f904b166564 |
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/Preview Content/Home/Networking/HomeDataPreview.swift LazyBear/Views/Global Helpers/LineView.swift LazyBear/Views/Home/Helpers/TopStockItem.swift LazyBear/Views/Home/Helpers/TopStockRow.swift LazyBear/Views/Home/HomeView.swift LazyBear/Views/Networking/HomeData.swift |
diffstat | 10 files changed, 181 insertions(+), 53 deletions(-) [+] |
line wrap: on
line diff
--- a/LazyBear.xcodeproj/project.pbxproj Tue Mar 30 23:15:57 2021 +0200 +++ b/LazyBear.xcodeproj/project.pbxproj Wed Mar 31 17:06:57 2021 +0200 @@ -33,6 +33,8 @@ 95893DCE2613C46B003698C5 /* SectorPerformanceModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 95893DCD2613C46B003698C5 /* SectorPerformanceModel.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 */; }; /* End PBXBuildFile section */ @@ -68,6 +70,8 @@ 958A734E25E016FD00FD7ECA /* LazyBear.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = LazyBear.entitlements; sourceTree = "<group>"; }; 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 = "<group>"; }; + 95BC3B4E261476FB00FC3A12 /* IntradayPricesModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IntradayPricesModel.swift; sourceTree = "<group>"; }; + 95E745D92614624500744A1E /* HomeDataPreview.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HomeDataPreview.swift; sourceTree = "<group>"; }; 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>"; }; /* End PBXFileReference section */ @@ -117,6 +121,7 @@ 954D7EA5260BBA6600A13C50 /* WatchlistCompany+CoreDataClass.swift */, 954D7EA6260BBA6600A13C50 /* WatchlistCompany+CoreDataProperties.swift */, 952045232610FD7F00A76362 /* CompanyRowModel.swift */, + 95BC3B4E261476FB00FC3A12 /* IntradayPricesModel.swift */, ); path = "Global Models"; sourceTree = "<group>"; @@ -185,6 +190,7 @@ 95672B9425DDA54700DCBE4A /* Preview Content */ = { isa = PBXGroup; children = ( + 95E745D72614622C00744A1E /* Home */, 95672B9525DDA54700DCBE4A /* Preview Assets.xcassets */, ); path = "Preview Content"; @@ -227,6 +233,22 @@ path = Views; sourceTree = "<group>"; }; + 95E745D72614622C00744A1E /* Home */ = { + isa = PBXGroup; + children = ( + 95E745D82614623700744A1E /* Networking */, + ); + path = Home; + sourceTree = "<group>"; + }; + 95E745D82614623700744A1E /* Networking */ = { + isa = PBXGroup; + children = ( + 95E745D92614624500744A1E /* HomeDataPreview.swift */, + ); + path = Networking; + sourceTree = "<group>"; + }; /* End PBXGroup section */ /* Begin PBXNativeTarget section */ @@ -303,6 +325,7 @@ buildActionMask = 2147483647; files = ( 950C36E3260FB6180081CF53 /* HapticsManager.swift in Sources */, + 95E745DA2614624500744A1E /* HomeDataPreview.swift in Sources */, 9550444926111FC9000E0BCB /* TopStockRow.swift in Sources */, 952045242610FD7F00A76362 /* CompanyRowModel.swift in Sources */, 9550444326111E7A000E0BCB /* SectorRow.swift in Sources */, @@ -314,6 +337,7 @@ 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 */, 95672B8F25DDA54700DCBE4A /* LazyBearApp.swift in Sources */,
Binary file LazyBear.xcodeproj/project.xcworkspace/xcuserdata/dennis.xcuserdatad/UserInterfaceState.xcuserstate has changed
--- a/LazyBear.xcodeproj/xcshareddata/xcschemes/LazyBear.xcscheme Tue Mar 30 23:15:57 2021 +0200 +++ b/LazyBear.xcodeproj/xcshareddata/xcschemes/LazyBear.xcscheme Wed Mar 31 17:06:57 2021 +0200 @@ -31,7 +31,7 @@ </Testables> </TestAction> <LaunchAction - buildConfiguration = "Debug" + buildConfiguration = "Release" selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" launchStyle = "0"
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/LazyBear/Global Models/IntradayPricesModel.swift Wed Mar 31 17:06:57 2021 +0200 @@ -0,0 +1,23 @@ +// +// 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? +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/LazyBear/Preview Content/Home/Networking/HomeDataPreview.swift Wed Mar 31 17:06:57 2021 +0200 @@ -0,0 +1,27 @@ +// +// HomeDataPreview.swift +// LazyBear +// +// Created by Dennis Concepción Martín on 31/3/21. +// + +import SwiftUI + +class HomeDataPreview: ObservableObject { + @Published var sectorPerformance = [ + SectorPerformanceModel(name: "Communication Services", performance: 0.043, lastUpdated: 1617177387000), + SectorPerformanceModel(name: "Consumer Discretionary", performance: 0.043, lastUpdated: 1617177387000), + SectorPerformanceModel(name: "Consumer Staples", performance: 0.043, lastUpdated: 1617177387000), + SectorPerformanceModel(name: "Energy", performance: 0.043, lastUpdated: 1617177387000), + SectorPerformanceModel(name: "Financials", performance: 0.043, lastUpdated: 1617177387000), + SectorPerformanceModel(name: "Health Care", performance: 0.043, lastUpdated: 1617177387000), + SectorPerformanceModel(name: "Industrials", performance: 0.043, lastUpdated: 1617177387000), + SectorPerformanceModel(name: "Materials", performance: 0.043, lastUpdated: 1617177387000), + SectorPerformanceModel(name: "Real Estate", performance: 0.043, lastUpdated: 1617177387000), + SectorPerformanceModel(name: "Technology", performance: 0.043, lastUpdated: 1617177387000), + SectorPerformanceModel(name: "Utilities", performance: 0.043, lastUpdated: 1617177387000), + ] + + + +}
--- a/LazyBear/Views/Global Helpers/LineView.swift Tue Mar 30 23:15:57 2021 +0200 +++ b/LazyBear/Views/Global Helpers/LineView.swift Wed Mar 31 17:06:57 2021 +0200 @@ -8,11 +8,12 @@ import SwiftUI struct LineView: View { + var data: [Double] + var body: some View { GeometryReader { proxy in VStack { - let sampleData = generateRandomSample() - LineShape(width: proxy.size.width, height: proxy.size.height, normalizedData: normalize(sampleData)) + LineShape(width: proxy.size.width, height: proxy.size.height, normalizedData: normalize(data)) .stroke(lineWidth: 2) .rotationEffect(.degrees(180), anchor: .center) .rotation3DEffect(.degrees(180), axis: (x: 0.0, y: 1.0, z: 0.0)) @@ -33,9 +34,14 @@ return normalData } +} + +struct LineView_Previews: PreviewProvider { + static var previews: some View { + LineView(data: generateRandomSample()) + } - // DELETE THIS FUNCTION ON PRODUCTION - private func generateRandomSample() -> [Double] { + static private func generateRandomSample() -> [Double] { var randomSample = [Double]() for _ in 1..<10 { randomSample.append(Double.random(in: 1...100)) @@ -44,9 +50,3 @@ return randomSample } } - -struct LineView_Previews: PreviewProvider { - static var previews: some View { - LineView() - } -}
--- a/LazyBear/Views/Home/Helpers/TopStockItem.swift Tue Mar 30 23:15:57 2021 +0200 +++ b/LazyBear/Views/Home/Helpers/TopStockItem.swift Wed Mar 31 17:06:57 2021 +0200 @@ -8,6 +8,8 @@ import SwiftUI struct TopStockItem: View { + var company: CompanyRowModel + var intradayPricesArray: IntradayPricesArray var body: some View { RoundedRectangle(cornerRadius: 20) @@ -17,21 +19,23 @@ .overlay( VStack(alignment: .leading) { Group { - Text("Symbol".uppercased()) + Text(company.symbol.uppercased()) .fontWeight(.semibold) .padding(.top) - Text("Company name".capitalized) + Text(company.companyName.capitalized) + .font(.callout) .fontWeight(.semibold) .opacity(0.6) + .lineLimit(1) - Text("$120.20") - .foregroundColor(.green) + Text("$\(company.latestPrice, specifier: "%.2f")") + .foregroundColor(company.changePercent < 0 ? .red: .green) .fontWeight(.semibold) .padding(.top) - Text("+\(1.22, specifier: "%.2f")%") - .foregroundColor(.green) + Text("\(company.changePercent*100, specifier: "%.2f")%") + .foregroundColor(company.changePercent < 0 ? .red: .green) .fontWeight(.semibold) } @@ -39,21 +43,21 @@ Spacer() - - LineView() - .foregroundColor(.green) + let prices = intradayPricesArray.intradayPrices.compactMap { $0.open } + // Compact Map will return an array without the nil values + LineView(data: prices) + .foregroundColor(company.changePercent < 0 ? .red: .green) .padding(.vertical) .clipped() - } ) } } -struct TopStockItem_Previews: PreviewProvider { - static var previews: some View { - TopStockItem() - - } -} +//struct TopStockItem_Previews: PreviewProvider { +// static var previews: some View { +// TopStockItem(company: CompanyRowModel(symbol: "aapl", companyName: "apple inc", latestPrice: 120.30, changePercent: 0.03), intradayPrices: <#IntradayPricesArray#>) +// +// } +//}
--- a/LazyBear/Views/Home/Helpers/TopStockRow.swift Tue Mar 30 23:15:57 2021 +0200 +++ b/LazyBear/Views/Home/Helpers/TopStockRow.swift Wed Mar 31 17:06:57 2021 +0200 @@ -8,19 +8,25 @@ import SwiftUI struct TopStockRow: View { - var keyTitle: String + var key: String + var list: [CompanyRowModel] + var intradayPricesDict: [String: IntradayPricesArray] var body: some View { VStack(alignment: .leading) { - Text(keyTitle) + Text(adaptTitle()) .font(.title3) .fontWeight(.semibold) .padding([.top, .horizontal]) ScrollView(.horizontal, showsIndicators: false) { HStack(spacing: 20) { - ForEach((1..<10)) { _ in - TopStockItem() + ForEach(list, id: \.self) { company in + let symbol = company.symbol.uppercased() + if let prices = intradayPricesDict[symbol] { + TopStockItem(company: company, intradayPricesArray: prices) + } + } } .padding() @@ -29,10 +35,20 @@ } .padding(.bottom) } + + private func adaptTitle() -> String { + if key == "mostactive" { + + return "Most active" + } else { + return key.capitalized + } + } } -struct TopStockRow_Previews: PreviewProvider { - static var previews: some View { - TopStockRow(keyTitle: "Sample title") - } -} +// +//struct TopStockRow_Previews: PreviewProvider { +// static var previews: some View { +// TopStockRow(key: "Gainers", list:[CompanyRowModel](), intradayPrices: <#[String : IntradayPricesArray]#>) +// } +//}
--- a/LazyBear/Views/Home/HomeView.swift Tue Mar 30 23:15:57 2021 +0200 +++ b/LazyBear/Views/Home/HomeView.swift Wed Mar 31 17:06:57 2021 +0200 @@ -10,6 +10,7 @@ struct HomeView: View { @ObservedObject var homeData = HomeData() @State private var showTradingDates = false + @State private var timer = Timer.publish(every: 10, on: .main, in: .common).autoconnect() // Set recurrent price request static let taskDateFormat: DateFormatter = { let formatter = DateFormatter() @@ -25,10 +26,9 @@ SectorRow(sectorPerformance: homeData.sectorPerformance) .listRowInsets(EdgeInsets()) - let keyTitles = ["Top gainers", "Top losers", "Most active"] - ForEach(keyTitles, id: \.self) { keyTitle in - TopStockRow(keyTitle: keyTitle) - + // 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()) } @@ -41,15 +41,10 @@ Image(systemName: "calendar.badge.clock") } } - - ToolbarItem(placement: .navigationBarLeading) { - Button(action: { homeData.getSectorPerformance() }) { - Text("Test recall") - } - } } } - .onAppear { homeData.getSectorPerformance() } + .onAppear { homeData.get() } + .onReceive(timer) {_ in homeData.get() } .sheet(isPresented: $showTradingDates) { TradingDates() }
--- a/LazyBear/Views/Networking/HomeData.swift Tue Mar 30 23:15:57 2021 +0200 +++ b/LazyBear/Views/Networking/HomeData.swift Wed Mar 31 17:06:57 2021 +0200 @@ -8,14 +8,53 @@ import SwiftUI class HomeData: ObservableObject { - @Published var sectorPerformance = [SectorPerformanceModel]() { didSet { print(sectorPerformance) }} + @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" - let baseUrl = Bundle.main.infoDictionary?["IEX_URL"] as? String ?? "Empty url" - let apiKey = Bundle.main.infoDictionary?["IEX_API"] as? String ?? "Empty key" - - func getSectorPerformance() { - let url = "\(baseUrl)/stock/market/sector-performance?token=\(apiKey)" + // 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 } + } + } + } } }