diff --git a/SatsPrice.xcodeproj/project.pbxproj b/SatsPrice.xcodeproj/project.pbxproj index 785ee15..e352055 100644 --- a/SatsPrice.xcodeproj/project.pbxproj +++ b/SatsPrice.xcodeproj/project.pbxproj @@ -8,6 +8,7 @@ /* Begin PBXBuildFile section */ 3A7B2AA32B86407A00ACC4A7 /* FakePriceFetcher.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3A7B2AA22B86407A00ACC4A7 /* FakePriceFetcher.swift */; }; + 3A8E5DA72C810C9900E9E6BD /* ManualPriceFetcher.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3A8E5DA62C810C9900E9E6BD /* ManualPriceFetcher.swift */; }; 3AE2D39D2B83338D00DE5F31 /* SatsPriceApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3AE2D39C2B83338D00DE5F31 /* SatsPriceApp.swift */; }; 3AE2D3A22B83338D00DE5F31 /* SatsPrice.xcdatamodeld in Sources */ = {isa = PBXBuildFile; fileRef = 3AE2D3A02B83338D00DE5F31 /* SatsPrice.xcdatamodeld */; }; 3AE2D3A42B83338D00DE5F31 /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3AE2D3A32B83338D00DE5F31 /* ContentView.swift */; }; @@ -45,6 +46,7 @@ /* Begin PBXFileReference section */ 3A7B2AA22B86407A00ACC4A7 /* FakePriceFetcher.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FakePriceFetcher.swift; sourceTree = ""; }; + 3A8E5DA62C810C9900E9E6BD /* ManualPriceFetcher.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ManualPriceFetcher.swift; sourceTree = ""; }; 3AE2D3992B83338D00DE5F31 /* SatsPrice.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = SatsPrice.app; sourceTree = BUILT_PRODUCTS_DIR; }; 3AE2D39C2B83338D00DE5F31 /* SatsPriceApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SatsPriceApp.swift; sourceTree = ""; }; 3AE2D3A12B83338D00DE5F31 /* SatsPrice.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = SatsPrice.xcdatamodel; sourceTree = ""; }; @@ -159,6 +161,7 @@ 3AE2D3E02B8459D600DE5F31 /* CoinbasePriceFetcher.swift */, 3AE2D3E22B8461FE00DE5F31 /* CoinGeckoPriceFetcher.swift */, 3A7B2AA22B86407A00ACC4A7 /* FakePriceFetcher.swift */, + 3A8E5DA62C810C9900E9E6BD /* ManualPriceFetcher.swift */, 3AE2D3DE2B84597100DE5F31 /* PriceFetcher.swift */, 3AE2D3E62B85690200DE5F31 /* PriceFetcherDelegator.swift */, 3AE2D3E42B846A8600DE5F31 /* PriceSource.swift */, @@ -309,6 +312,7 @@ 3AE2D39D2B83338D00DE5F31 /* SatsPriceApp.swift in Sources */, 3AE2D3A22B83338D00DE5F31 /* SatsPrice.xcdatamodeld in Sources */, 3AE2D3A42B83338D00DE5F31 /* ContentView.swift in Sources */, + 3A8E5DA72C810C9900E9E6BD /* ManualPriceFetcher.swift in Sources */, 3AE2D3D52B83E58500DE5F31 /* SatsViewModel.swift in Sources */, 3AE2D3E32B8461FE00DE5F31 /* CoinGeckoPriceFetcher.swift in Sources */, 3AE2D3DF2B84597100DE5F31 /* PriceFetcher.swift in Sources */, diff --git a/SatsPrice/ContentView.swift b/SatsPrice/ContentView.swift index b7b3bdc..7864bc2 100644 --- a/SatsPrice/ContentView.swift +++ b/SatsPrice/ContentView.swift @@ -50,22 +50,21 @@ struct ContentView: View { Text($0.description) } } - .onChange(of: priceSource) { newPriceSource in - priceFetcherDelegator.priceSource = newPriceSource - Task { - await updatePrice() - } - } HStack { TextField("", text: $satsViewModel.btcToUsdString) - .disabled(true) - Button(action: { - Task { - await updatePrice() + .disabled(priceSource != .manual) +#if os(iOS) + .keyboardType(.decimalPad) +#endif + if priceSource != .manual { + Button(action: { + Task { + await updatePrice() + } + }) { + Image(systemName: "arrow.clockwise") } - }) { - Image(systemName: "arrow.clockwise") } } } header: { @@ -104,6 +103,12 @@ struct ContentView: View { .task { await updatePrice() } + .onChange(of: priceSource) { newPriceSource in + priceFetcherDelegator.priceSource = newPriceSource + Task { + await updatePrice() + } + } #if os(macOS) .formStyle(.grouped) #endif diff --git a/SatsPrice/Network/ManualPriceFetcher.swift b/SatsPrice/Network/ManualPriceFetcher.swift new file mode 100644 index 0000000..23d6c39 --- /dev/null +++ b/SatsPrice/Network/ManualPriceFetcher.swift @@ -0,0 +1,18 @@ +// +// ManualPriceFetcher.swift +// SatsPrice +// +// Created by Terry Yiu on 8/29/24. +// + +import Foundation +import BigDecimal + +/// Fake price fetcher that returns a randomized price. Useful for development testing without requiring a network call. +class ManualPriceFetcher: PriceFetcher { + var price: BigDecimal = 1 + + func btcToUsd() async throws -> BigDecimal? { + return price + } +} diff --git a/SatsPrice/Network/PriceFetcherDelegator.swift b/SatsPrice/Network/PriceFetcherDelegator.swift index 6077003..21e7a6d 100644 --- a/SatsPrice/Network/PriceFetcherDelegator.swift +++ b/SatsPrice/Network/PriceFetcherDelegator.swift @@ -11,6 +11,7 @@ import BigDecimal class PriceFetcherDelegator: PriceFetcher { private let coinbasePriceFetcher = CoinbasePriceFetcher() private let coinGeckoPriceFetcher = CoinGeckoPriceFetcher() + private let manualPriceFetcher = ManualPriceFetcher() #if DEBUG private let fakePriceFetcher = FakePriceFetcher() #endif @@ -27,6 +28,8 @@ class PriceFetcherDelegator: PriceFetcher { coinbasePriceFetcher case .coingecko: coinGeckoPriceFetcher + case .manual: + manualPriceFetcher #if DEBUG case .fake: fakePriceFetcher diff --git a/SatsPrice/Network/PriceSource.swift b/SatsPrice/Network/PriceSource.swift index 6631b80..a2e2809 100644 --- a/SatsPrice/Network/PriceSource.swift +++ b/SatsPrice/Network/PriceSource.swift @@ -11,14 +11,15 @@ enum PriceSource: CaseIterable, CustomStringConvertible { static var allCases: [PriceSource] { #if DEBUG - [.coinbase, .coingecko, .fake] + [.coinbase, .coingecko, .manual, .fake] #else - [.coinbase, .coingecko] + [.coinbase, .coingecko, .manual] #endif } case coinbase case coingecko + case manual #if DEBUG case fake @@ -30,6 +31,8 @@ enum PriceSource: CaseIterable, CustomStringConvertible { "Coinbase" case .coingecko: "CoinGecko" + case .manual: + "Manual" #if DEBUG case .fake: "Fake"