BlueWallet/ios/Widgets/PriceWidget/PriceIntent.swift

162 lines
5.7 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-30 19:16:03 -04:00
static var description = IntentDescription("View the current Bitcoin market rate in your preferred 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(
2024-10-30 19:16:03 -04:00
title: "Currency",
description: "Choose your preferred currency."
2024-10-29 19:33:26 -04:00
)
var fiatCurrency: FiatUnitEnum?
2024-10-30 19:16:03 -04:00
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-30 19:16:03 -04:00
if let fiat = fiatCurrency {
print("Received fiatCurrency parameter: \(fiat.rawValue)")
} else {
print("fiatCurrency parameter not provided. Proceeding with fallback logic.")
}
2024-10-29 19:33:26 -04:00
// Determine the fiat currency to use:
2024-10-30 19:16:03 -04:00
// 1. Use the fiatCurrency parameter if provided
// 2. Fallback to Shared Group UserDefaults
// 3. Fallback to Device's preferred currency
// 4. Default to USD
2024-10-29 19:33:26 -04:00
let selectedFiatCurrency: FiatUnitEnum
2024-10-30 19:16:03 -04:00
if let fiat = fiatCurrency {
selectedFiatCurrency = fiat
print("Using fiatCurrency parameter: \(selectedFiatCurrency.rawValue)")
} else if let sharedCurrencyCode = getSharedCurrencyCode(),
let fiat = FiatUnitEnum(rawValue: sharedCurrencyCode.uppercased()) {
2024-10-29 19:33:26 -04:00
selectedFiatCurrency = fiat
2024-10-30 19:16:03 -04:00
print("Using shared user default currency: \(selectedFiatCurrency.rawValue)")
} else if let deviceCurrencyCode = Locale.current.currencyCode,
let fiat = FiatUnitEnum(rawValue: deviceCurrencyCode.uppercased()) {
2024-10-29 19:33:26 -04:00
selectedFiatCurrency = fiat
2024-10-30 19:16:03 -04:00
print("Using device's currency: \(selectedFiatCurrency.rawValue)")
2024-10-29 19:33:26 -04:00
} else {
selectedFiatCurrency = .USD
2024-10-30 19:16:03 -04:00
print("Defaulting to USD.")
}
2024-10-29 19:33:26 -04:00
let dataSource = selectedFiatCurrency.source
2024-10-30 19:16:03 -04:00
print("Data Source: \(dataSource)")
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 {
2024-10-30 19:16:03 -04:00
print("Failed to fetch price data.")
2024-10-29 19:33:26 -04:00
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-30 19:16:03 -04:00
print("Fetched Price: \(priceDouble)")
print("Last Updated: \(lastUpdated)")
2024-10-27 19:09:03 -04:00
2024-10-27 18:14:37 -04:00
} catch {
2024-10-30 19:16:03 -04:00
print("Error fetching price data: \(error.localizedDescription)")
2024-10-29 19:33:26 -04:00
let errorView = CompactPriceView(
price: "N/A",
lastUpdated: "--",
2024-10-30 19:16:03 -04:00
code: selectedFiatCurrency.rawValue,
dataSource: "Error fetching data"
)
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-30 19:16:03 -04:00
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-30 19:16:03 -04:00
code: selectedFiatCurrency.rawValue,
2024-10-27 19:09:03 -04:00
dataSource: dataSource
)
2024-10-27 18:14:37 -04:00
2024-10-30 19:16:03 -04:00
print("Formatted Price: \(formattedPrice)")
print("Currency Symbol: \(currencySymbol)")
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
2024-10-30 19:16:03 -04:00
formatter.locale = Locale.current // Use device's current locale
2024-10-28 12:20:40 -04:00
formatter.currencyCode = currencyCode
2024-10-30 19:16:03 -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
2024-10-30 19:16:03 -04:00
formatter.locale = Locale.current // Use device's current locale
2024-10-29 19:33:26 -04:00
formatter.currencyCode = currencyCode
return formatter.currencySymbol
}
private func getSharedCurrencyCode() -> String? {
2024-10-30 19:16:03 -04:00
let sharedDefaults = UserDefaults(suiteName: UserDefaultsGroupKey.GroupName.rawValue)
return sharedDefaults?.string(forKey: UserDefaultsGroupKey.PreferredCurrency.rawValue)
2024-10-27 18:14:37 -04:00
}
}