changeset 161:3913aff613e8

Fix bug that didn't request API on symbol change
author Dennis Concepcion Martin <dennisconcepcionmartin@gmail.com>
date Tue, 31 Aug 2021 10:57:34 +0100
parents 0c589138a6f3
children f5de15e06c77
files Simoleon.xcodeproj/project.pbxproj Simoleon/ConversionView.swift Simoleon/Models/CurrencyConversion.swift Simoleon/Models/CurrencyPair.swift Simoleon/UI/ConversionBox.swift Simoleon/UI/CurrencyList.swift Simoleon/UI/CurrencySelector.swift Simoleon/UI/FavoriteButton.swift SimoleonTests/SimoleonTests.swift
diffstat 9 files changed, 105 insertions(+), 88 deletions(-) [+]
line wrap: on
line diff
--- a/Simoleon.xcodeproj/project.pbxproj	Sun Aug 29 19:04:34 2021 +0100
+++ b/Simoleon.xcodeproj/project.pbxproj	Tue Aug 31 10:57:34 2021 +0100
@@ -20,7 +20,7 @@
 		95562D4D26A8962A0047E778 /* StoreKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 95562D4C26A8962A0047E778 /* StoreKit.framework */; };
 		95562D5226A8AEF60047E778 /* Purchases in Frameworks */ = {isa = PBXBuildFile; productRef = 95562D5126A8AEF60047E778 /* Purchases */; };
 		957065E226A5FE0400523E68 /* SettingsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 957065E126A5FE0400523E68 /* SettingsView.swift */; };
-		957DCF3326D7ADEA00BCAB1E /* CurrencyPair.swift in Sources */ = {isa = PBXBuildFile; fileRef = 957DCF3226D7ADEA00BCAB1E /* CurrencyPair.swift */; };
+		957DCF3326D7ADEA00BCAB1E /* CurrencyConversion.swift in Sources */ = {isa = PBXBuildFile; fileRef = 957DCF3226D7ADEA00BCAB1E /* CurrencyConversion.swift */; };
 		95851CE326D4DAAE004ADA79 /* CurrencyButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 95851CE226D4DAAE004ADA79 /* CurrencyButton.swift */; };
 		95851CE526D4DB4C004ADA79 /* Flag.swift in Sources */ = {isa = PBXBuildFile; fileRef = 95851CE426D4DB4C004ADA79 /* Flag.swift */; };
 		9585BB1426A6B7F400E3193E /* NetworkHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9585BB1326A6B7F400E3193E /* NetworkHelper.swift */; };
@@ -125,7 +125,7 @@
 		95562D4C26A8962A0047E778 /* StoreKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = StoreKit.framework; path = System/Library/Frameworks/StoreKit.framework; sourceTree = SDKROOT; };
 		956088B526B9307600A4FD6C /* SnapshotHelper.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SnapshotHelper.swift; sourceTree = "<group>"; };
 		957065E126A5FE0400523E68 /* SettingsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsView.swift; sourceTree = "<group>"; };
-		957DCF3226D7ADEA00BCAB1E /* CurrencyPair.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CurrencyPair.swift; sourceTree = "<group>"; };
+		957DCF3226D7ADEA00BCAB1E /* CurrencyConversion.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CurrencyConversion.swift; sourceTree = "<group>"; };
 		95851CE226D4DAAE004ADA79 /* CurrencyButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CurrencyButton.swift; sourceTree = "<group>"; };
 		95851CE426D4DB4C004ADA79 /* Flag.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Flag.swift; sourceTree = "<group>"; };
 		9585BB0F26A6B58500E3193E /* Config.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Config.xcconfig; sourceTree = "<group>"; };
@@ -259,7 +259,7 @@
 				95AC820626DAA3ED00CD5C3F /* FavoritePair+CoreDataProperties.swift */,
 				95AEBCA226A0900E00613729 /* CurrencyQuoteModel.swift */,
 				953B8B1626D3A970003CF530 /* CurrencyDetailsModel.swift */,
-				957DCF3226D7ADEA00BCAB1E /* CurrencyPair.swift */,
+				957DCF3226D7ADEA00BCAB1E /* CurrencyConversion.swift */,
 			);
 			path = Models;
 			sourceTree = "<group>";
@@ -711,7 +711,7 @@
 				95D8C8D126A9BC6200BCC188 /* LockedCurrencyPicker.swift in Sources */,
 				95C517A126A5F6C000BC2B24 /* ResignKeyboard.swift in Sources */,
 				95CE6A3626D50B7700D9DCBD /* CurrencyList.swift in Sources */,
-				957DCF3326D7ADEA00BCAB1E /* CurrencyPair.swift in Sources */,
+				957DCF3326D7ADEA00BCAB1E /* CurrencyConversion.swift in Sources */,
 				95AEBC9D26A04D4600613729 /* CurrencyRow.swift in Sources */,
 				95AEBCA326A0900E00613729 /* CurrencyQuoteModel.swift in Sources */,
 				9585BB1426A6B7F400E3193E /* NetworkHelper.swift in Sources */,
--- a/Simoleon/ConversionView.swift	Sun Aug 29 19:04:34 2021 +0100
+++ b/Simoleon/ConversionView.swift	Tue Aug 31 10:57:34 2021 +0100
@@ -10,17 +10,17 @@
 
 struct ConversionView: View {
     var showNavigationView: Bool?
-    @StateObject var currencyPair = CurrencyPair()
+    @StateObject var currencyConversion = CurrencyConversion()
     
     var body: some View {
         ScrollView(showsIndicators: false) {
             VStack(alignment: .leading, spacing: 20) {
                 HStack {
-                    CurrencySelector(currencyPair: currencyPair)
-                    FavoriteButton(currencyPair: currencyPair)
+                    CurrencySelector(currencyConversion: currencyConversion)
+                    FavoriteButton(currencyConversion: currencyConversion)
                 }
                 
-                ConversionBox(currencyPair: currencyPair)
+                ConversionBox(currencyConversion: currencyConversion)
                     .padding(.top)
             }
             .padding()
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Simoleon/Models/CurrencyConversion.swift	Tue Aug 31 10:57:34 2021 +0100
@@ -0,0 +1,47 @@
+//
+//  CurrencyConversion.swift
+//  Simoleon
+//
+//  Created by Dennis Concepción Martín on 26/8/21.
+//
+
+import Foundation
+
+class CurrencyConversion: ObservableObject {
+    // Forex pair -> XXX/YYY where XXX = base symbol, YYY = quote symbol
+    
+    @Published var baseSymbol = "USD" {
+        didSet {
+            getQuote()
+        }
+    }
+    @Published var quoteSymbol = "EUR" {
+        didSet {
+            getQuote()
+        }
+    }
+    @Published var quote = CurrencyQuoteModel()
+    @Published var isShowing = false
+    @Published var showingAlert = false
+    
+    let networkHelper = NetworkHelper()
+    
+    init() {
+        getQuote()
+    }
+    
+    func getQuote() {
+        self.isShowing = false
+        let pair = "\(baseSymbol)/\(quoteSymbol)"
+        let apiKey = readConfig(withKey: "API_KEY")!
+        let url = "https://api.1forge.com/quotes?pairs=\(pair)&api_key=\(apiKey)"
+        
+        try? networkHelper.httpRequest(url: url, model: [CurrencyQuoteModel].self) { response in
+            if let quote = response.first {
+                self.quote = quote
+            }
+            
+            self.isShowing = true
+        }
+    }
+}
--- a/Simoleon/Models/CurrencyPair.swift	Sun Aug 29 19:04:34 2021 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,18 +0,0 @@
-//
-//  CurrencyPair.swift
-//  Simoleon
-//
-//  Created by Dennis Concepción Martín on 26/8/21.
-//
-
-import Foundation
-
-class CurrencyPair: ObservableObject {
-    /*
-     Forex pair -> XXX/YYY
-     Where XXX is the base currency, and YYY the quote currency
-     */
-    
-    @Published var baseSymbol = "USD"
-    @Published var quoteSymbol = "EUR"
-}
--- a/Simoleon/UI/ConversionBox.swift	Sun Aug 29 19:04:34 2021 +0100
+++ b/Simoleon/UI/ConversionBox.swift	Tue Aug 31 10:57:34 2021 +0100
@@ -8,32 +8,29 @@
 import SwiftUI
 
 struct ConversionBox: View {
-    @ObservedObject var currencyPair: CurrencyPair
+    @ObservedObject var currencyConversion: CurrencyConversion
     @State private var amount = ""
     @State private var isEditing = false
-    @State private var showingConversion = false
-    @State private var currencyQuote = CurrencyQuoteModel()
-    @State private var showingAlert = false
-    
+
     let networkHelper = NetworkHelper()
     let currencyDetails: [String: CurrencyModel] = try! readJson(from: "Currencies.json")
     
     var body: some View {
         VStack(alignment: .leading) {
-            let baseCurrencyName = currencyDetails[currencyPair.baseSymbol]!.name
-            Text("\(baseCurrencyName) (\(currencyPair.baseSymbol))")
+            let baseCurrencyName = currencyDetails[currencyConversion.baseSymbol]!.name
+            Text("\(baseCurrencyName) (\(currencyConversion.baseSymbol))")
                 .font(.callout)
                 .fontWeight(.semibold)
             
             ConversionTextfield(amount: $amount, isEditing: $isEditing)
             Divider()
-            
-            let quoteCurrencyName = currencyDetails[currencyPair.quoteSymbol]!.name
-            Text("\(quoteCurrencyName) (\(currencyPair.quoteSymbol))")
+
+            let quoteCurrencyName = currencyDetails[currencyConversion.quoteSymbol]!.name
+            Text("\(quoteCurrencyName) (\(currencyConversion.quoteSymbol))")
                 .font(.callout)
                 .fontWeight(.semibold)
             
-            if showingConversion {
+            if currencyConversion.isShowing {
                 let conversion = convert()
                 Text("\(conversion, specifier: "%.2f")")
                     .font(Font.title.weight(.semibold))
@@ -54,42 +51,18 @@
                 }
             }
         }
-        
-        .onAppear {
-            showingConversion = false
-            let pair = "\(currencyPair.baseSymbol)/\(currencyPair.quoteSymbol)"
-            let apiKey = readConfig(withKey: "API_KEY")!
-            let url = "https://api.1forge.com/quotes?pairs=\(pair)&api_key=\(apiKey)"
-            try? networkHelper.httpRequest(url: url, model: [CurrencyQuoteModel].self) { response in
-                if let currencyQuote = response.first {
-                    self.currencyQuote = currencyQuote
-                } else {
-                    showingAlert = true
-                }
-                
-                showingConversion = true
-            }
-        }
-        .alert(isPresented: $showingAlert) {
-            Alert(
-                title: Text("Currencies not supported."),
-                message: Text("Currently, we are unable to convert from \(currencyPair.baseSymbol) to \(currencyPair.quoteSymbol)."),
-                dismissButton: .default(Text("Dismiss")
-                )
-            )
-        }
     }
     
     private func convert() -> Double {
         guard let amount = Double(amount) else { return 0  }
-        guard let price = currencyQuote.price else { return 0 }
-        
+        guard let price = currencyConversion.quote.price else { return 0 }
+
         return amount * price
     }
 }
 
 struct ConversionBox_Previews: PreviewProvider {
     static var previews: some View {
-        ConversionBox(currencyPair: CurrencyPair())
+        ConversionBox(currencyConversion: CurrencyConversion())
     }
 }
--- a/Simoleon/UI/CurrencyList.swift	Sun Aug 29 19:04:34 2021 +0100
+++ b/Simoleon/UI/CurrencyList.swift	Tue Aug 31 10:57:34 2021 +0100
@@ -9,8 +9,10 @@
 
 struct CurrencyList: View {
     var currencies: [String]
-    @Binding var selectedCurrency: String
+    var selection: Selection
+    @ObservedObject var currencyConversion: CurrencyConversion
     @State private var searchCurrency = ""
+    
     @Environment(\.presentationMode) private var presentation
     let currencyDetails: [String: CurrencyModel] = try! readJson(from: "Currencies.json")
     
@@ -30,7 +32,15 @@
                     .accessibilityIdentifier("CurrencySearchBar")
                 
                 ForEach(searchResults, id: \.self) { symbol in
-                    Button(action: {selectedCurrency = symbol; presentation.wrappedValue.dismiss()}) {
+                    Button(action: {
+                        if selection == .baseSymbol {
+                            currencyConversion.baseSymbol = symbol
+                        } else {
+                            currencyConversion.quoteSymbol = symbol
+                        }
+                        
+                        presentation.wrappedValue.dismiss()
+                    }) {
                         let currency = currencyDetails[symbol]!
                         CurrencyRow(currency: currency)
                     }
@@ -48,6 +58,10 @@
             }
         }
     }
+    
+    enum Selection {
+        case baseSymbol, quoteSymbol
+    }
 }
 extension View {
     func listStyle() -> some View {
@@ -57,6 +71,6 @@
 
 struct CurrencyList_Previews: PreviewProvider {
     static var previews: some View {
-        CurrencyList(currencies: ["USD"], selectedCurrency: .constant("USD"))
+        CurrencyList(currencies: ["USD"], selection: .baseSymbol, currencyConversion: CurrencyConversion())
     }
 }
--- a/Simoleon/UI/CurrencySelector.swift	Sun Aug 29 19:04:34 2021 +0100
+++ b/Simoleon/UI/CurrencySelector.swift	Tue Aug 31 10:57:34 2021 +0100
@@ -8,9 +8,10 @@
 import SwiftUI
 
 struct CurrencySelector: View {
-    @ObservedObject var currencyPair: CurrencyPair
+    @ObservedObject var currencyConversion: CurrencyConversion
+    @State private var modalSelection: ModalType = .allCurrencies
     @State private var showingList = false
-    @State private var modalSelection: ModalType = .allCurrencies
+    
     let currencyPairsSupported: [String] = try! readJson(from: "CurrencyPairsSupported.json")
     
     private enum ModalType {
@@ -23,31 +24,31 @@
                 modalSelection = .allCurrencies
                 showingList = true
             }) {
-                CurrencyButton(selectedCurrency: currencyPair.baseSymbol)
+                CurrencyButton(selectedCurrency: currencyConversion.baseSymbol)
             }
             
             Button(action: {
                 modalSelection = .compatibleCurrencies
                 showingList = true
             }) {
-                CurrencyButton(selectedCurrency: currencyPair.quoteSymbol)
+                CurrencyButton(selectedCurrency: currencyConversion.quoteSymbol)
             }
         }
-        .onChange(of: currencyPair.baseSymbol) { _ in
+        .onChange(of: currencyConversion.baseSymbol) { _ in
             // If the previous quote symbol is not compatible anymore with base symbol
             // return the first symbol of the new compatible symbols list
-            let compatibleCurrencies = get(currencyType: .compatible(with: currencyPair.baseSymbol), from: currencyPairsSupported)
-            if !compatibleCurrencies.contains(currencyPair.quoteSymbol) {
-                currencyPair.quoteSymbol = compatibleCurrencies.sorted().first!
+            let compatibleCurrencies = get(currencyType: .compatible(with: currencyConversion.baseSymbol), from: currencyPairsSupported)
+            if !compatibleCurrencies.contains(currencyConversion.quoteSymbol) {
+                currencyConversion.quoteSymbol = compatibleCurrencies.sorted().first!
             }
         }
         .sheet(isPresented: $showingList) {
             if modalSelection == .allCurrencies {
                 let currencies = get(currencyType: .all, from: currencyPairsSupported)
-                CurrencyList(currencies: currencies, selectedCurrency: $currencyPair.baseSymbol)
+                CurrencyList(currencies: currencies, selection: .baseSymbol, currencyConversion: currencyConversion)
             } else {
-                let currencies = get(currencyType: .compatible(with: currencyPair.baseSymbol), from: currencyPairsSupported)
-                CurrencyList(currencies: currencies, selectedCurrency: $currencyPair.quoteSymbol)
+                let currencies = get(currencyType: .compatible(with: currencyConversion.baseSymbol), from: currencyPairsSupported)
+                CurrencyList(currencies: currencies, selection: .quoteSymbol, currencyConversion: currencyConversion)
             }
         }
     }
@@ -84,6 +85,6 @@
 
 struct CurrencySelector_Previews: PreviewProvider {
     static var previews: some View {
-        CurrencySelector(currencyPair: CurrencyPair())
+        CurrencySelector(currencyConversion: CurrencyConversion())
     }
 }
--- a/Simoleon/UI/FavoriteButton.swift	Sun Aug 29 19:04:34 2021 +0100
+++ b/Simoleon/UI/FavoriteButton.swift	Tue Aug 31 10:57:34 2021 +0100
@@ -8,7 +8,7 @@
 import SwiftUI
 
 struct FavoriteButton: View {
-    @ObservedObject var currencyPair: CurrencyPair
+    @ObservedObject var currencyConversion: CurrencyConversion
     @State private var scale: CGFloat = 1
     @Environment(\.managedObjectContext) private var viewContext
     @FetchRequest(sortDescriptors: []) private var favoritePairs: FetchedResults<FavoritePair>
@@ -43,8 +43,8 @@
     
     func add() {
         let favoritePair = FavoritePair(context: viewContext)
-        favoritePair.baseSymbol = currencyPair.baseSymbol
-        favoritePair.quoteSymbol = currencyPair.quoteSymbol
+        favoritePair.baseSymbol = currencyConversion.baseSymbol
+        favoritePair.quoteSymbol = currencyConversion.quoteSymbol
         
         do {
             try viewContext.save()
@@ -57,7 +57,7 @@
     func remove() {
         let favoritePair = favoritePairs.first(
             where: {
-                $0.baseSymbol == currencyPair.baseSymbol && $0.quoteSymbol == currencyPair.quoteSymbol
+                $0.baseSymbol == currencyConversion.baseSymbol && $0.quoteSymbol == currencyConversion.quoteSymbol
         })
         
         viewContext.delete(favoritePair!)
@@ -73,7 +73,7 @@
     func isFavorite() -> Bool {
         let favoritePair = favoritePairs.first(
             where: {
-                $0.baseSymbol == currencyPair.baseSymbol && $0.quoteSymbol == currencyPair.quoteSymbol
+                $0.baseSymbol == currencyConversion.baseSymbol && $0.quoteSymbol == currencyConversion.quoteSymbol
         })
         
         guard let _ = favoritePair else { return false }
@@ -91,6 +91,6 @@
 
 struct FavoriteButton_Previews: PreviewProvider {
     static var previews: some View {
-        FavoriteButton(currencyPair: CurrencyPair())
+        FavoriteButton(currencyConversion: CurrencyConversion())
     }
 }
--- a/SimoleonTests/SimoleonTests.swift	Sun Aug 29 19:04:34 2021 +0100
+++ b/SimoleonTests/SimoleonTests.swift	Tue Aug 31 10:57:34 2021 +0100
@@ -24,7 +24,7 @@
         let expectedResults = [1: ["USD", "EUR"], 2: ["USD"]]
         
         // Test
-        let currencySelector = CurrencySelector(currencyPair: CurrencyPair())
+        let currencySelector = CurrencySelector(currencyConversion: CurrencyConversion())
         for testCaseNumber in testCases.keys {
             print("Testing case: \(testCaseNumber)")
             let mockData = testCases[testCaseNumber]!
@@ -41,13 +41,13 @@
         let expectedResults = [1: ["GBP"], 2: ["GBP", "EUR"], 3: []]
         
         // Test
-        let currencySelector = CurrencySelector(currencyPair: CurrencyPair())
+        let currencySelector = CurrencySelector(currencyConversion: CurrencyConversion())
         for testCaseNumber in testCases.keys {
             print("Testing case: \(testCaseNumber)")
             let mockData = testCases[testCaseNumber]!
             let compatibleCurrencies =
                 currencySelector.get(
-                    currencyType: .compatible(with: currencySelector.currencyPair.baseSymbol), from: mockData
+                    currencyType: .compatible(with: currencySelector.currencyConversion.baseSymbol), from: mockData
                 )
             
             // Assert