Add support for manual price entry
This commit is contained in:
@@ -8,6 +8,7 @@
|
|||||||
|
|
||||||
/* Begin PBXBuildFile section */
|
/* Begin PBXBuildFile section */
|
||||||
3A7B2AA32B86407A00ACC4A7 /* FakePriceFetcher.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3A7B2AA22B86407A00ACC4A7 /* FakePriceFetcher.swift */; };
|
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 */; };
|
3AE2D39D2B83338D00DE5F31 /* SatsPriceApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3AE2D39C2B83338D00DE5F31 /* SatsPriceApp.swift */; };
|
||||||
3AE2D3A22B83338D00DE5F31 /* SatsPrice.xcdatamodeld in Sources */ = {isa = PBXBuildFile; fileRef = 3AE2D3A02B83338D00DE5F31 /* SatsPrice.xcdatamodeld */; };
|
3AE2D3A22B83338D00DE5F31 /* SatsPrice.xcdatamodeld in Sources */ = {isa = PBXBuildFile; fileRef = 3AE2D3A02B83338D00DE5F31 /* SatsPrice.xcdatamodeld */; };
|
||||||
3AE2D3A42B83338D00DE5F31 /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3AE2D3A32B83338D00DE5F31 /* ContentView.swift */; };
|
3AE2D3A42B83338D00DE5F31 /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3AE2D3A32B83338D00DE5F31 /* ContentView.swift */; };
|
||||||
@@ -45,6 +46,7 @@
|
|||||||
|
|
||||||
/* Begin PBXFileReference section */
|
/* Begin PBXFileReference section */
|
||||||
3A7B2AA22B86407A00ACC4A7 /* FakePriceFetcher.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FakePriceFetcher.swift; sourceTree = "<group>"; };
|
3A7B2AA22B86407A00ACC4A7 /* FakePriceFetcher.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FakePriceFetcher.swift; sourceTree = "<group>"; };
|
||||||
|
3A8E5DA62C810C9900E9E6BD /* ManualPriceFetcher.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ManualPriceFetcher.swift; sourceTree = "<group>"; };
|
||||||
3AE2D3992B83338D00DE5F31 /* SatsPrice.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = SatsPrice.app; sourceTree = BUILT_PRODUCTS_DIR; };
|
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 = "<group>"; };
|
3AE2D39C2B83338D00DE5F31 /* SatsPriceApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SatsPriceApp.swift; sourceTree = "<group>"; };
|
||||||
3AE2D3A12B83338D00DE5F31 /* SatsPrice.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = SatsPrice.xcdatamodel; sourceTree = "<group>"; };
|
3AE2D3A12B83338D00DE5F31 /* SatsPrice.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = SatsPrice.xcdatamodel; sourceTree = "<group>"; };
|
||||||
@@ -159,6 +161,7 @@
|
|||||||
3AE2D3E02B8459D600DE5F31 /* CoinbasePriceFetcher.swift */,
|
3AE2D3E02B8459D600DE5F31 /* CoinbasePriceFetcher.swift */,
|
||||||
3AE2D3E22B8461FE00DE5F31 /* CoinGeckoPriceFetcher.swift */,
|
3AE2D3E22B8461FE00DE5F31 /* CoinGeckoPriceFetcher.swift */,
|
||||||
3A7B2AA22B86407A00ACC4A7 /* FakePriceFetcher.swift */,
|
3A7B2AA22B86407A00ACC4A7 /* FakePriceFetcher.swift */,
|
||||||
|
3A8E5DA62C810C9900E9E6BD /* ManualPriceFetcher.swift */,
|
||||||
3AE2D3DE2B84597100DE5F31 /* PriceFetcher.swift */,
|
3AE2D3DE2B84597100DE5F31 /* PriceFetcher.swift */,
|
||||||
3AE2D3E62B85690200DE5F31 /* PriceFetcherDelegator.swift */,
|
3AE2D3E62B85690200DE5F31 /* PriceFetcherDelegator.swift */,
|
||||||
3AE2D3E42B846A8600DE5F31 /* PriceSource.swift */,
|
3AE2D3E42B846A8600DE5F31 /* PriceSource.swift */,
|
||||||
@@ -309,6 +312,7 @@
|
|||||||
3AE2D39D2B83338D00DE5F31 /* SatsPriceApp.swift in Sources */,
|
3AE2D39D2B83338D00DE5F31 /* SatsPriceApp.swift in Sources */,
|
||||||
3AE2D3A22B83338D00DE5F31 /* SatsPrice.xcdatamodeld in Sources */,
|
3AE2D3A22B83338D00DE5F31 /* SatsPrice.xcdatamodeld in Sources */,
|
||||||
3AE2D3A42B83338D00DE5F31 /* ContentView.swift in Sources */,
|
3AE2D3A42B83338D00DE5F31 /* ContentView.swift in Sources */,
|
||||||
|
3A8E5DA72C810C9900E9E6BD /* ManualPriceFetcher.swift in Sources */,
|
||||||
3AE2D3D52B83E58500DE5F31 /* SatsViewModel.swift in Sources */,
|
3AE2D3D52B83E58500DE5F31 /* SatsViewModel.swift in Sources */,
|
||||||
3AE2D3E32B8461FE00DE5F31 /* CoinGeckoPriceFetcher.swift in Sources */,
|
3AE2D3E32B8461FE00DE5F31 /* CoinGeckoPriceFetcher.swift in Sources */,
|
||||||
3AE2D3DF2B84597100DE5F31 /* PriceFetcher.swift in Sources */,
|
3AE2D3DF2B84597100DE5F31 /* PriceFetcher.swift in Sources */,
|
||||||
|
|||||||
@@ -50,16 +50,14 @@ struct ContentView: View {
|
|||||||
Text($0.description)
|
Text($0.description)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.onChange(of: priceSource) { newPriceSource in
|
|
||||||
priceFetcherDelegator.priceSource = newPriceSource
|
|
||||||
Task {
|
|
||||||
await updatePrice()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
HStack {
|
HStack {
|
||||||
TextField("", text: $satsViewModel.btcToUsdString)
|
TextField("", text: $satsViewModel.btcToUsdString)
|
||||||
.disabled(true)
|
.disabled(priceSource != .manual)
|
||||||
|
#if os(iOS)
|
||||||
|
.keyboardType(.decimalPad)
|
||||||
|
#endif
|
||||||
|
if priceSource != .manual {
|
||||||
Button(action: {
|
Button(action: {
|
||||||
Task {
|
Task {
|
||||||
await updatePrice()
|
await updatePrice()
|
||||||
@@ -68,6 +66,7 @@ struct ContentView: View {
|
|||||||
Image(systemName: "arrow.clockwise")
|
Image(systemName: "arrow.clockwise")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
} header: {
|
} header: {
|
||||||
Text("1 BTC to USD")
|
Text("1 BTC to USD")
|
||||||
} footer: {
|
} footer: {
|
||||||
@@ -104,6 +103,12 @@ struct ContentView: View {
|
|||||||
.task {
|
.task {
|
||||||
await updatePrice()
|
await updatePrice()
|
||||||
}
|
}
|
||||||
|
.onChange(of: priceSource) { newPriceSource in
|
||||||
|
priceFetcherDelegator.priceSource = newPriceSource
|
||||||
|
Task {
|
||||||
|
await updatePrice()
|
||||||
|
}
|
||||||
|
}
|
||||||
#if os(macOS)
|
#if os(macOS)
|
||||||
.formStyle(.grouped)
|
.formStyle(.grouped)
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
18
SatsPrice/Network/ManualPriceFetcher.swift
Normal file
18
SatsPrice/Network/ManualPriceFetcher.swift
Normal file
@@ -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
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -11,6 +11,7 @@ import BigDecimal
|
|||||||
class PriceFetcherDelegator: PriceFetcher {
|
class PriceFetcherDelegator: PriceFetcher {
|
||||||
private let coinbasePriceFetcher = CoinbasePriceFetcher()
|
private let coinbasePriceFetcher = CoinbasePriceFetcher()
|
||||||
private let coinGeckoPriceFetcher = CoinGeckoPriceFetcher()
|
private let coinGeckoPriceFetcher = CoinGeckoPriceFetcher()
|
||||||
|
private let manualPriceFetcher = ManualPriceFetcher()
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
private let fakePriceFetcher = FakePriceFetcher()
|
private let fakePriceFetcher = FakePriceFetcher()
|
||||||
#endif
|
#endif
|
||||||
@@ -27,6 +28,8 @@ class PriceFetcherDelegator: PriceFetcher {
|
|||||||
coinbasePriceFetcher
|
coinbasePriceFetcher
|
||||||
case .coingecko:
|
case .coingecko:
|
||||||
coinGeckoPriceFetcher
|
coinGeckoPriceFetcher
|
||||||
|
case .manual:
|
||||||
|
manualPriceFetcher
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
case .fake:
|
case .fake:
|
||||||
fakePriceFetcher
|
fakePriceFetcher
|
||||||
|
|||||||
@@ -11,14 +11,15 @@ enum PriceSource: CaseIterable, CustomStringConvertible {
|
|||||||
|
|
||||||
static var allCases: [PriceSource] {
|
static var allCases: [PriceSource] {
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
[.coinbase, .coingecko, .fake]
|
[.coinbase, .coingecko, .manual, .fake]
|
||||||
#else
|
#else
|
||||||
[.coinbase, .coingecko]
|
[.coinbase, .coingecko, .manual]
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
case coinbase
|
case coinbase
|
||||||
case coingecko
|
case coingecko
|
||||||
|
case manual
|
||||||
|
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
case fake
|
case fake
|
||||||
@@ -30,6 +31,8 @@ enum PriceSource: CaseIterable, CustomStringConvertible {
|
|||||||
"Coinbase"
|
"Coinbase"
|
||||||
case .coingecko:
|
case .coingecko:
|
||||||
"CoinGecko"
|
"CoinGecko"
|
||||||
|
case .manual:
|
||||||
|
"Manual"
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
case .fake:
|
case .fake:
|
||||||
"Fake"
|
"Fake"
|
||||||
|
|||||||
Reference in New Issue
Block a user