BlueWallet/ios/Widgets/PriceWidget/PriceIntent.swift

139 lines
4.5 KiB
Swift
Raw Normal View History

2024-10-29 19:33:26 -04:00
//
// PriceIntent.swift
// BlueWallet
//
2024-10-27 18:14:37 -04:00
import AppIntents
import SwiftUI
2024-10-30 08:43:51 -04:00
@available(iOS 16.0, *)
2024-10-27 18:14:37 -04:00
struct PriceIntent: AppIntent {
2024-10-29 19:33:26 -04:00
// MARK: - Intent Metadata
2024-10-27 18:14:37 -04:00
static var title: LocalizedStringResource = "Market Rate"
2024-10-29 19:33:26 -04:00
static var description = IntentDescription("View the current Bitcoin market rate in your preferred fiat currency.")
2024-10-27 19:09:03 -04:00
static var openAppWhenRun: Bool { false }
2024-10-29 19:33:26 -04:00
// MARK: - Parameters
@Parameter(
title: "Currency"
)
var fiatCurrency: FiatUnitEnum?
2024-10-27 18:14:37 -04:00
@MainActor
2024-10-28 13:27:53 -04:00
func perform() async throws -> some IntentResult & ReturnsValue<Double> & ProvidesDialog & ShowsSnippetView {
2024-10-29 19:33:26 -04:00
// Determine the fiat currency to use:
// 1. UserDefaults in Shared Group
// 2. Device's preferred currency
// 3. Default to USD
let selectedFiatCurrency: FiatUnitEnum
if let sharedCurrencyCode = getSharedCurrencyCode(),
let fiat = FiatUnitEnum(rawValue: sharedCurrencyCode.uppercased()) {
selectedFiatCurrency = fiat
} else if let preferredCurrencyCode = Locale.current.currencyCode,
let fiat = FiatUnitEnum(rawValue: preferredCurrencyCode.uppercased()) {
selectedFiatCurrency = fiat
} else {
selectedFiatCurrency = .USD
}
2024-10-29 19:33:26 -04:00
let dataSource = selectedFiatCurrency.source
2024-10-29 19:33:26 -04:00
var lastUpdated = "--"
var priceDouble: Double = 0.0
2024-10-27 18:14:37 -04:00
do {
2024-10-29 19:33:26 -04:00
guard let fetchedData = try await MarketAPI.fetchPrice(currency: selectedFiatCurrency.rawValue) else {
throw NSError(
domain: "PriceIntentErrorDomain",
code: -1,
userInfo: [NSLocalizedDescriptionKey: "Failed to fetch price data."]
)
2024-10-27 18:14:37 -04:00
}
2024-10-27 19:09:03 -04:00
2024-10-29 19:33:26 -04:00
priceDouble = fetchedData.rateDouble
lastUpdated = formattedDate(from: fetchedData.lastUpdate)
2024-10-27 19:09:03 -04:00
2024-10-27 18:14:37 -04:00
} catch {
2024-10-29 19:33:26 -04:00
let errorView = CompactPriceView(
price: "N/A",
lastUpdated: "--",
currencySymbol: getCurrencySymbol(for: selectedFiatCurrency.rawValue),
2024-10-30 08:43:51 -04:00
dataSource: "Error fetching data")
2024-10-29 19:59:38 -04:00
2024-10-29 19:33:26 -04:00
return .result(
value: 0.0,
dialog: "Failed to retrieve the Bitcoin market rate.",
view: errorView
)
2024-10-27 18:14:37 -04:00
}
2024-10-29 19:33:26 -04:00
let formattedPrice = formatPrice(priceDouble, currencyCode: selectedFiatCurrency.rawValue)
let currencySymbol = getCurrencySymbol(for: selectedFiatCurrency.rawValue)
2024-10-27 19:09:03 -04:00
let view = CompactPriceView(
2024-10-28 23:17:52 -04:00
price: formattedPrice,
2024-10-27 19:09:03 -04:00
lastUpdated: lastUpdated,
2024-10-29 19:33:26 -04:00
currencySymbol: currencySymbol,
2024-10-27 19:09:03 -04:00
dataSource: dataSource
)
2024-10-27 18:14:37 -04:00
return .result(
2024-10-29 19:33:26 -04:00
value: priceDouble,
2024-10-27 18:14:37 -04:00
dialog: "Current Bitcoin Market Rate",
view: view
)
}
2024-10-29 19:33:26 -04:00
// MARK: - Helper Methods
2024-10-27 19:09:03 -04:00
private func formattedDate(from isoString: String?) -> String {
guard let isoString = isoString else { return "--" }
2024-10-27 18:14:37 -04:00
let isoFormatter = ISO8601DateFormatter()
if let date = isoFormatter.date(from: isoString) {
let formatter = DateFormatter()
2024-10-28 12:20:40 -04:00
formatter.dateStyle = .medium
2024-10-27 18:14:37 -04:00
formatter.timeStyle = .short
return formatter.string(from: date)
}
return "--"
}
2024-10-29 19:33:26 -04:00
2024-10-28 12:20:40 -04:00
private func formatPrice(_ price: Double, currencyCode: String) -> String {
let formatter = NumberFormatter()
formatter.numberStyle = .currency
formatter.currencyCode = currencyCode
2024-10-29 19:33:26 -04:00
2024-10-28 13:27:53 -04:00
// Omit cents if price is a whole number
2024-10-28 12:20:40 -04:00
if price.truncatingRemainder(dividingBy: 1) == 0 {
formatter.maximumFractionDigits = 0
formatter.minimumFractionDigits = 0
} else {
formatter.maximumFractionDigits = 2
formatter.minimumFractionDigits = 2
}
2024-10-29 19:33:26 -04:00
guard let formattedNumber = formatter.string(from: NSNumber(value: price)) else {
return "\(price)"
2024-10-27 18:14:37 -04:00
}
2024-10-29 19:33:26 -04:00
return formattedNumber
}
private func getCurrencySymbol(for currencyCode: String) -> String {
let formatter = NumberFormatter()
formatter.numberStyle = .currency
formatter.currencyCode = currencyCode
return formatter.currencySymbol
}
private func getSharedCurrencyCode() -> String? {
let sharedDefaults = UserDefaults(suiteName: UserDefaultsGroupKey.GroupName.rawValue)
return sharedDefaults?.string(forKey: "selectedFiatCurrency")
2024-10-27 18:14:37 -04:00
}
}