changeset 232:439e94a2200d

Implement PriceView
author Dennis Concepción Martín <66180929+denniscm190@users.noreply.github.com>
date Tue, 02 Mar 2021 18:45:55 +0000
parents 5bf2fcb7ad66
children 108fe992c703
files LazyBear/Functions/Request.swift LazyBear/Models/PriceModel.swift LazyBear/Tests/TestPullScroll.swift LazyBear/UI/CompanyView.swift LazyBear/UI/IexAttribution.swift LazyBear/UI/PriceView.swift LazyBear/UI/Settings.swift
diffstat 7 files changed, 120 insertions(+), 65 deletions(-) [+]
line wrap: on
line diff
--- a/LazyBear/Functions/Request.swift	Mon Mar 01 18:42:34 2021 +0000
+++ b/LazyBear/Functions/Request.swift	Tue Mar 02 18:45:55 2021 +0000
@@ -7,29 +7,33 @@
 
 import Foundation
 
-// Network request
-func request<T: Decodable>(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
+class Network: ObservableObject {
+    @Published var showingProgress = false
+    
+    // Network request
+    func request<T: Decodable>(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 {
+                        //print(decodedResponse)
+                        completion(decodedResponse)
+                    }
+                    return
+                } catch {
+                    print(error)
+                }
+            }
+            print("Fetch failed: \(error?.localizedDescription ?? "Unknown error")")
+        }
+        .resume()
     }
-    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 {
-                    //print(decodedResponse)
-                    completion(decodedResponse)
-                }
-                return
-            } catch {
-                print(error)
-            }
-        }
-        print("Fetch failed: \(error?.localizedDescription ?? "Unknown error")")
-    }
-    .resume()
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/LazyBear/Models/PriceModel.swift	Tue Mar 02 18:45:55 2021 +0000
@@ -0,0 +1,13 @@
+//
+//  PriceModel.swift
+//  LazyBear
+//
+//  Created by Dennis Concepción Martín on 2/3/21.
+//
+
+import SwiftUI
+
+struct PriceModel: Codable {
+    var latestPrice: Float
+    var changePercent: Double
+}
--- a/LazyBear/Tests/TestPullScroll.swift	Mon Mar 01 18:42:34 2021 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,37 +0,0 @@
-//
-//  TestPullScroll.swift
-//  LazyBear
-//
-//  Created by Dennis Concepción Martín on 28/2/21.
-//
-
-import SwiftUI
-
-struct TestPullScroll: View {
-    var body: some View {
-        NavigationView {
-            ScrollView {
-                ForEach((1...10), id: \.self) {
-                    Text("Row \($0)")
-                    Divider()
-                }
-            }
-        }
-    }
-    
-    func action() {
-        print("Action")
-    }
-}
-
-struct Row: View {
-    var body: some View {
-        Text("Hello row")
-    }
-}
-
-struct TestPullScroll_Previews: PreviewProvider {
-    static var previews: some View {
-        TestPullScroll()
-    }
-}
--- a/LazyBear/UI/CompanyView.swift	Mon Mar 01 18:42:34 2021 +0000
+++ b/LazyBear/UI/CompanyView.swift	Tue Mar 02 18:45:55 2021 +0000
@@ -18,14 +18,14 @@
     var body: some View {
         GeometryReader { geo in
             ScrollView {
-                //PriceView(symbol: symbol)
+                PriceView(symbol: symbol)
                 HistoricalPriceView(symbol: symbol, chartHeight: geo.size.width / 2)
                 NewsView(symbol: symbol)
             }
         }
         .toolbar {
             ToolbarItem(placement: .principal) {
-                Text("Change view")
+                // Here I will add the view selector (Stock news, insiders, etc)
             }
             
             ToolbarItem(placement: .navigationBarTrailing) {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/LazyBear/UI/IexAttribution.swift	Tue Mar 02 18:45:55 2021 +0000
@@ -0,0 +1,27 @@
+//
+//  IexAttribution.swift
+//  LazyBear
+//
+//  Created by Dennis Concepción Martín on 2/3/21.
+//
+
+import SwiftUI
+
+struct IexAttribution: View {
+    var text: String
+    
+    var body: some View {
+        Link(destination: URL(string: "https://iexcloud.io")!) {
+            Text(text)
+                .font(.caption)
+                .opacity(0.6)
+                
+        }
+    }
+}
+
+struct IexAttribution_Previews: PreviewProvider {
+    static var previews: some View {
+        IexAttribution(text: "IEX Cloud")
+    }
+}
--- a/LazyBear/UI/PriceView.swift	Mon Mar 01 18:42:34 2021 +0000
+++ b/LazyBear/UI/PriceView.swift	Tue Mar 02 18:45:55 2021 +0000
@@ -9,12 +9,60 @@
 
 struct PriceView: View {
     var symbol: String
+    @State private var latestPrice = Float()
+    @State private var changePercent = Double()
+    @State private var negativeChange = false
+    
+    @State private var timer = Timer.publish(every: 10, on: .main, in: .common).autoconnect()  // Set recurrent price request
     
     var body: some View {
-        Text("Price View")
+        VStack(alignment: .leading) {
+            HStack {
+                Text("\(latestPrice, specifier: "%.2f")")
+                    .font(.title3)
+                    .fontWeight(.bold)
+                    .padding(.horizontal)
+
+                Text("\(changePercent*100, specifier: "%.2f")%")
+                    .font(.headline)
+                    .foregroundColor(negativeChange ? Color(.systemRed) : Color(.systemGreen))
+                    .padding(.trailing)
+                
+                IexAttribution(text: "IEX Cloud")
+                Spacer()
+            
+            }
+            
+        }
+        .onReceive(timer) { _ in call(); print("requested") }
+        .onAppear {
+            call()
+            self.timer = Timer.publish(every: 10, on: .main, in: .common).autoconnect()  // Restart timer
+        }
+        .onDisappear { self.timer.upstream.connect().cancel() }  // Stop timer
+    }
+    
+    private func getUrl() -> String {
+        let baseUrl = Bundle.main.infoDictionary?["IEX_URL"] as? String ?? "Empty url"
+        let apiKey = Bundle.main.infoDictionary?["IEX_API"] as? String ?? "Empty key"
+        let url = "\(baseUrl)/stock/\(symbol)/quote?token=\(apiKey)"
+
+        return url
+    }
+    
+    private func call() {
+        request(url: getUrl(), model: PriceModel.self) { result in
+            self.latestPrice = result.latestPrice
+            if result.changePercent < 0 {
+                self.negativeChange  = true
+            }
+            
+            self.changePercent = result.changePercent
+        }
     }
 }
 
+
 struct PriceView_Previews: PreviewProvider {
     static var previews: some View {
         PriceView(symbol: "aapl")
--- a/LazyBear/UI/Settings.swift	Mon Mar 01 18:42:34 2021 +0000
+++ b/LazyBear/UI/Settings.swift	Tue Mar 02 18:45:55 2021 +0000
@@ -26,7 +26,7 @@
                     Text("App icon")
                 }
                 
-                Section {
+                Section(footer: IexAttribution(text: "Data provided by IEX Cloud").padding(.top)) {
                     ForEach((0...3), id: \.self) { index in
                         Link(destination: URL(string: setting.links[index])!) {
                             HStack {