changeset 79:096dbea11d43

Implement SDWebImageSwiftUI to load remote image from google api
author Dennis Concepción Martín <66180929+denniscm190@users.noreply.github.com>
date Sun, 24 Jan 2021 20:13:37 +0100
parents 7fef171d4820
children d914ef7734a9
files LazyBear.xcodeproj/project.pbxproj LazyBear.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved LazyBear.xcodeproj/project.xcworkspace/xcuserdata/dennis.xcuserdatad/UserInterfaceState.xcuserstate lazybear/API.swift lazybear/ContentView.swift lazybear/GoogleApi.swift lazybear/IexApi.swift lazybear/LazyBearApp.swift lazybear/Tests/LoadImageTest.swift
diffstat 9 files changed, 211 insertions(+), 125 deletions(-) [+]
line wrap: on
line diff
--- a/LazyBear.xcodeproj/project.pbxproj	Sun Jan 24 19:44:15 2021 +0100
+++ b/LazyBear.xcodeproj/project.pbxproj	Sun Jan 24 20:13:37 2021 +0100
@@ -11,13 +11,16 @@
 		950B79F625B1CB7A00E5DB5B /* CompanyList.swift in Sources */ = {isa = PBXBuildFile; fileRef = 950B79F525B1CB7A00E5DB5B /* CompanyList.swift */; };
 		952498B325BB381300B00E22 /* CurrentPrice.swift in Sources */ = {isa = PBXBuildFile; fileRef = 952498B225BB381300B00E22 /* CurrentPrice.swift */; };
 		952498B625BB47A700B00E22 /* LatestPriceModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 952498B525BB47A700B00E22 /* LatestPriceModel.swift */; };
+		9537923625BDF85D0001F82B /* GoogleApi.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9537923525BDF85D0001F82B /* GoogleApi.swift */; };
+		9537924A25BDFCD70001F82B /* LoadImageTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9537924925BDFCD70001F82B /* LoadImageTest.swift */; };
+		9537924F25BDFD940001F82B /* SDWebImageSwiftUI in Frameworks */ = {isa = PBXBuildFile; productRef = 9537924E25BDFD940001F82B /* SDWebImageSwiftUI */; };
 		954D992525A2123B001F7F60 /* HistoricalPricesModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 954D992425A2123B001F7F60 /* HistoricalPricesModel.swift */; };
 		954D996D25A2461B001F7F60 /* SwiftUICharts in Frameworks */ = {isa = PBXBuildFile; productRef = 954D996C25A2461B001F7F60 /* SwiftUICharts */; };
 		954D997125A253A9001F7F60 /* Config.swift in Sources */ = {isa = PBXBuildFile; fileRef = 954D997025A253A9001F7F60 /* Config.swift */; };
 		95612C512598D48200F7698F /* SearchBar.swift in Sources */ = {isa = PBXBuildFile; fileRef = 95612C4F2598D48200F7698F /* SearchBar.swift */; };
 		956FAF7B25AF421E0002B2C1 /* FavCompany+CoreDataClass.swift in Sources */ = {isa = PBXBuildFile; fileRef = 956FAF7925AF421E0002B2C1 /* FavCompany+CoreDataClass.swift */; };
 		956FAF7C25AF421E0002B2C1 /* FavCompany+CoreDataProperties.swift in Sources */ = {isa = PBXBuildFile; fileRef = 956FAF7A25AF421E0002B2C1 /* FavCompany+CoreDataProperties.swift */; };
-		95700BC625BD9D12009CEEFE /* API.swift in Sources */ = {isa = PBXBuildFile; fileRef = 95700BC525BD9D12009CEEFE /* API.swift */; };
+		95700BC625BD9D12009CEEFE /* IexApi.swift in Sources */ = {isa = PBXBuildFile; fileRef = 95700BC525BD9D12009CEEFE /* IexApi.swift */; };
 		958E472B25B1CA8B0048E770 /* FavCompanyList.swift in Sources */ = {isa = PBXBuildFile; fileRef = 958E472A25B1CA8B0048E770 /* FavCompanyList.swift */; };
 		95AB4A7A259DCBAE0064C9C1 /* ReadJson.swift in Sources */ = {isa = PBXBuildFile; fileRef = 95AB4A79259DCBAE0064C9C1 /* ReadJson.swift */; };
 		95AB4A7D259DCC0C0064C9C1 /* CompanyModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 95AB4A7C259DCC0C0064C9C1 /* CompanyModel.swift */; };
@@ -48,12 +51,14 @@
 		950B79F525B1CB7A00E5DB5B /* CompanyList.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CompanyList.swift; sourceTree = "<group>"; };
 		952498B225BB381300B00E22 /* CurrentPrice.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CurrentPrice.swift; sourceTree = "<group>"; };
 		952498B525BB47A700B00E22 /* LatestPriceModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = LatestPriceModel.swift; path = lazybear/Models/LatestPriceModel.swift; sourceTree = SOURCE_ROOT; };
+		9537923525BDF85D0001F82B /* GoogleApi.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = GoogleApi.swift; path = lazybear/GoogleApi.swift; sourceTree = SOURCE_ROOT; };
+		9537924925BDFCD70001F82B /* LoadImageTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = LoadImageTest.swift; path = lazybear/Tests/LoadImageTest.swift; sourceTree = SOURCE_ROOT; };
 		954D992425A2123B001F7F60 /* HistoricalPricesModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = HistoricalPricesModel.swift; path = lazybear/Models/HistoricalPricesModel.swift; sourceTree = SOURCE_ROOT; };
 		954D997025A253A9001F7F60 /* Config.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = Config.swift; path = lazybear/Config.swift; sourceTree = SOURCE_ROOT; };
 		95612C4F2598D48200F7698F /* SearchBar.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SearchBar.swift; sourceTree = "<group>"; };
 		956FAF7925AF421E0002B2C1 /* FavCompany+CoreDataClass.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "FavCompany+CoreDataClass.swift"; sourceTree = "<group>"; };
 		956FAF7A25AF421E0002B2C1 /* FavCompany+CoreDataProperties.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "FavCompany+CoreDataProperties.swift"; sourceTree = "<group>"; };
-		95700BC525BD9D12009CEEFE /* API.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = API.swift; path = lazybear/API.swift; sourceTree = SOURCE_ROOT; };
+		95700BC525BD9D12009CEEFE /* IexApi.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = IexApi.swift; path = lazybear/IexApi.swift; sourceTree = SOURCE_ROOT; };
 		958E472A25B1CA8B0048E770 /* FavCompanyList.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = FavCompanyList.swift; path = "lazybear/Supply views/FavCompanyList.swift"; sourceTree = SOURCE_ROOT; };
 		95AB4A79259DCBAE0064C9C1 /* ReadJson.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = ReadJson.swift; path = lazybear/Functions/ReadJson.swift; sourceTree = SOURCE_ROOT; };
 		95AB4A7C259DCC0C0064C9C1 /* CompanyModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = CompanyModel.swift; path = lazybear/Models/CompanyModel.swift; sourceTree = SOURCE_ROOT; };
@@ -85,6 +90,7 @@
 			isa = PBXFrameworksBuildPhase;
 			buildActionMask = 2147483647;
 			files = (
+				9537924F25BDFD940001F82B /* SDWebImageSwiftUI in Frameworks */,
 				95002580256D17D9008FFD28 /* StoreKit.framework in Frameworks */,
 				954D996D25A2461B001F7F60 /* SwiftUICharts in Frameworks */,
 			);
@@ -104,6 +110,7 @@
 		952F791C2598B1CD00FF929F /* Tests */ = {
 			isa = PBXGroup;
 			children = (
+				9537924925BDFCD70001F82B /* LoadImageTest.swift */,
 			);
 			path = Tests;
 			sourceTree = "<group>";
@@ -187,7 +194,8 @@
 				95002578256D1564008FFD28 /* Configuration.storekit */,
 				95F7CAF425ADC7B7009E0E7C /* LazyBear.xcdatamodeld */,
 				954D997025A253A9001F7F60 /* Config.swift */,
-				95700BC525BD9D12009CEEFE /* API.swift */,
+				95700BC525BD9D12009CEEFE /* IexApi.swift */,
+				9537923525BDF85D0001F82B /* GoogleApi.swift */,
 				95B04EB225212369000AD27F /* LazyBearApp.swift */,
 				95B04EB425212369000AD27F /* ContentView.swift */,
 				95612C4D2598D48200F7698F /* Supply views */,
@@ -225,6 +233,7 @@
 			name = LazyBear;
 			packageProductDependencies = (
 				954D996C25A2461B001F7F60 /* SwiftUICharts */,
+				9537924E25BDFD940001F82B /* SDWebImageSwiftUI */,
 			);
 			productName = LazyBear;
 			productReference = 95B04EAF25212369000AD27F /* LazyBear.app */;
@@ -255,6 +264,7 @@
 			mainGroup = 95B04EA625212369000AD27F;
 			packageReferences = (
 				954D996B25A2461B001F7F60 /* XCRemoteSwiftPackageReference "ChartView" */,
+				9537924D25BDFD940001F82B /* XCRemoteSwiftPackageReference "SDWebImageSwiftUI" */,
 			);
 			productRefGroup = 95B04EB025212369000AD27F /* Products */;
 			projectDirPath = "";
@@ -304,9 +314,11 @@
 				95F6C2F325BAE3D1003CF389 /* Stock.swift in Sources */,
 				95AB4A7D259DCC0C0064C9C1 /* CompanyModel.swift in Sources */,
 				95F6C2DD25BAD394003CF389 /* FavCompanyRow.swift in Sources */,
-				95700BC625BD9D12009CEEFE /* API.swift in Sources */,
+				95700BC625BD9D12009CEEFE /* IexApi.swift in Sources */,
+				9537923625BDF85D0001F82B /* GoogleApi.swift in Sources */,
 				95F6C2E425BAD529003CF389 /* RandomColor.swift in Sources */,
 				95C28AB625BC45CF0033D16A /* ChartStyle.swift in Sources */,
+				9537924A25BDFCD70001F82B /* LoadImageTest.swift in Sources */,
 				954D997125A253A9001F7F60 /* Config.swift in Sources */,
 				95C28AB925BC46250033D16A /* ScalateChart.swift in Sources */,
 				954D992525A2123B001F7F60 /* HistoricalPricesModel.swift in Sources */,
@@ -511,6 +523,14 @@
 /* End XCConfigurationList section */
 
 /* Begin XCRemoteSwiftPackageReference section */
+		9537924D25BDFD940001F82B /* XCRemoteSwiftPackageReference "SDWebImageSwiftUI" */ = {
+			isa = XCRemoteSwiftPackageReference;
+			repositoryURL = "https://github.com/SDWebImage/SDWebImageSwiftUI.git";
+			requirement = {
+				kind = upToNextMajorVersion;
+				minimumVersion = 1.5.0;
+			};
+		};
 		954D996B25A2461B001F7F60 /* XCRemoteSwiftPackageReference "ChartView" */ = {
 			isa = XCRemoteSwiftPackageReference;
 			repositoryURL = "https://github.com/AppPear/ChartView.git";
@@ -522,6 +542,11 @@
 /* End XCRemoteSwiftPackageReference section */
 
 /* Begin XCSwiftPackageProductDependency section */
+		9537924E25BDFD940001F82B /* SDWebImageSwiftUI */ = {
+			isa = XCSwiftPackageProductDependency;
+			package = 9537924D25BDFD940001F82B /* XCRemoteSwiftPackageReference "SDWebImageSwiftUI" */;
+			productName = SDWebImageSwiftUI;
+		};
 		954D996C25A2461B001F7F60 /* SwiftUICharts */ = {
 			isa = XCSwiftPackageProductDependency;
 			package = 954D996B25A2461B001F7F60 /* XCRemoteSwiftPackageReference "ChartView" */;
--- a/LazyBear.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved	Sun Jan 24 19:44:15 2021 +0100
+++ b/LazyBear.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved	Sun Jan 24 20:13:37 2021 +0100
@@ -9,6 +9,24 @@
           "revision": "4699847a9ac0c694666cea3acef133498952566e",
           "version": "1.5.4"
         }
+      },
+      {
+        "package": "SDWebImage",
+        "repositoryURL": "https://github.com/SDWebImage/SDWebImage.git",
+        "state": {
+          "branch": null,
+          "revision": "4aaca57fb2f6dc5554a2228cf1d94289bd0a6c7d",
+          "version": "5.10.3"
+        }
+      },
+      {
+        "package": "SDWebImageSwiftUI",
+        "repositoryURL": "https://github.com/SDWebImage/SDWebImageSwiftUI.git",
+        "state": {
+          "branch": null,
+          "revision": "4c7f169e39bc35d6b80d42b8eb8301bee9cd0907",
+          "version": "1.5.0"
+        }
       }
     ]
   },
Binary file LazyBear.xcodeproj/project.xcworkspace/xcuserdata/dennis.xcuserdatad/UserInterfaceState.xcuserstate has changed
--- a/lazybear/API.swift	Sun Jan 24 19:44:15 2021 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,119 +0,0 @@
-//
-//  API.swift
-//  LazyBear
-//
-//  Created by Dennis Concepción Martín on 24/1/21.
-//
-
-import SwiftUI
-
-struct API {
-    enum BaseURL {
-        case sandbox
-        case production
-        
-        var path: (String, String) {
-            let token = Token()
-            switch self {
-            case .sandbox:
-                return ("https://sandbox.iexapis.com", token.sandbox)
-            case .production:
-                return ("https://cloud.iexapis.com", token.production)
-            }
-        }
-    }
-
-    enum Version {
-        case stable
-        
-        var path: String {
-            switch self {
-            case .stable:
-                return "/stable"
-            }
-        }
-    }
-    
-    enum Stock {
-        case symbol(company: String)
-        var path: String {
-            switch self {
-            case let .symbol(company):
-                return "/stock/\(company)"
-            }
-        }
-    }
-    
-    enum Endpoint {
-        case historicalPrices
-        var path: String {
-            switch self {
-            case .historicalPrices:
-                return "/chart"
-            }
-        }
-    }
-    
-    enum Range {
-        case period(range: String)
-        var path: String {
-            switch self {
-            case let .period(range):
-                return "/\(range)?"
-            }
-        }
-    }
-    
-    enum Parameters {
-        case chartCloseOnly
-        var path: String {
-            switch self {
-            case .chartCloseOnly:
-                return "chartCloseOnly=true"
-            }
-        }
-    }
-    
-    
-    // Create URL
-    func getURL(baseURL: BaseURL, version: Version, stock: Stock, endpoint: Endpoint, range: Range, parameters: Parameters) -> String {
-        let (baseURL, token) = baseURL.path
-        let version = version.path
-        let stock = stock.path
-        let endpoint = endpoint.path
-        let range = range.path
-        let parameters = parameters.path
-        
-        let url = "\(baseURL)\(version)\(stock)\(endpoint)\(range)\(parameters)&token=\(token)"
-        
-        return url
-        
-    }
-    
-    // Request API
-    func request<T: Decodable>(url: String, model: T.Type, completion: @escaping (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()
-    }
-}
--- a/lazybear/ContentView.swift	Sun Jan 24 19:44:15 2021 +0100
+++ b/lazybear/ContentView.swift	Sun Jan 24 20:13:37 2021 +0100
@@ -9,7 +9,7 @@
 import CoreData
 
 struct ContentView: View {
-    @State var searchedCompany: String = ""
+    @State var searchedCompany = String()
     @State public var showingSearch: Bool = false
     let persistenceController = PersistenceController.shared
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lazybear/GoogleApi.swift	Sun Jan 24 20:13:37 2021 +0100
@@ -0,0 +1,12 @@
+//
+//  GoogleApi.swift
+//  LazyBear
+//
+//  Created by Dennis Concepción Martín on 24/1/21.
+//
+
+import SwiftUI
+
+struct GoogleApi {
+    
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lazybear/IexApi.swift	Sun Jan 24 20:13:37 2021 +0100
@@ -0,0 +1,119 @@
+//
+//  API.swift
+//  LazyBear
+//
+//  Created by Dennis Concepción Martín on 24/1/21.
+//
+
+import SwiftUI
+
+struct IexApi {
+    enum BaseURL {
+        case sandbox
+        case production
+        
+        var path: (String, String) {
+            let token = Token()
+            switch self {
+            case .sandbox:
+                return ("https://sandbox.iexapis.com", token.sandbox)
+            case .production:
+                return ("https://cloud.iexapis.com", token.production)
+            }
+        }
+    }
+
+    enum Version {
+        case stable
+        
+        var path: String {
+            switch self {
+            case .stable:
+                return "/stable"
+            }
+        }
+    }
+    
+    enum Stock {
+        case symbol(company: String)
+        var path: String {
+            switch self {
+            case let .symbol(company):
+                return "/stock/\(company)"
+            }
+        }
+    }
+    
+    enum Endpoint {
+        case historicalPrices
+        var path: String {
+            switch self {
+            case .historicalPrices:
+                return "/chart"
+            }
+        }
+    }
+    
+    enum Range {
+        case period(range: String)
+        var path: String {
+            switch self {
+            case let .period(range):
+                return "/\(range)?"
+            }
+        }
+    }
+    
+    enum Parameters {
+        case chartCloseOnly
+        var path: String {
+            switch self {
+            case .chartCloseOnly:
+                return "chartCloseOnly=true"
+            }
+        }
+    }
+    
+    
+    // Create URL
+    func getURL(baseURL: BaseURL, version: Version, stock: Stock, endpoint: Endpoint, range: Range, parameters: Parameters) -> String {
+        let (baseURL, token) = baseURL.path
+        let version = version.path
+        let stock = stock.path
+        let endpoint = endpoint.path
+        let range = range.path
+        let parameters = parameters.path
+        
+        let url = "\(baseURL)\(version)\(stock)\(endpoint)\(range)\(parameters)&token=\(token)"
+        
+        return url
+        
+    }
+    
+    // Request API
+    func request<T: Decodable>(url: String, model: T.Type, completion: @escaping (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()
+    }
+}
--- a/lazybear/LazyBearApp.swift	Sun Jan 24 19:44:15 2021 +0100
+++ b/lazybear/LazyBearApp.swift	Sun Jan 24 20:13:37 2021 +0100
@@ -13,7 +13,7 @@
 
     var body: some Scene {
         WindowGroup {
-            ContentView()
+            LoadImageTest()
                 .environment(\.managedObjectContext, persistenceController.container.viewContext)
         }
     }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lazybear/Tests/LoadImageTest.swift	Sun Jan 24 20:13:37 2021 +0100
@@ -0,0 +1,31 @@
+//
+//  LoadImageTest.swift
+//  LazyBear
+//
+//  Created by Dennis Concepción Martín on 24/1/21.
+//
+
+import SwiftUI
+import SDWebImageSwiftUI
+
+struct LoadImageTest: View {
+    var body: some View {
+        WebImage(url: URL(string: "https://storage.googleapis.com/iex/api/logos/AAPL.png"))
+        // Supports options and context, like `.delayPlaceholder` to show placeholder only when error
+        .onSuccess { image, data, cacheType in
+            // Success
+            // Note: Data exist only when queried from disk cache or network. Use `.queryMemoryData` if you really need data
+        }
+        .resizable() // Resizable like SwiftUI.Image, you must use this modifier or the view will use the image bitmap size
+        .placeholder(Image(systemName: "photo")) // Placeholder Image
+        // Supports ViewBuilder as well
+        .placeholder {
+            Rectangle().foregroundColor(.gray)
+        }
+        .indicator(.activity) // Activity Indicator
+        .transition(.fade(duration: 0.5)) // Fade Transition with duration
+        .scaledToFit()
+        .frame(width: 300, height: 300, alignment: .center)
+    }
+}
+