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-28 22:48:55 -04:00
|
|
|
}
|
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-28 22:48:55 -04:00
|
|
|
|
2024-10-29 19:33:26 -04:00
|
|
|
var lastUpdated = "--"
|
|
|
|
var priceDouble: Double = 0.0
|
2024-10-28 12:36:58 -04:00
|
|
|
|
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
|
|
|
}
|
|
|
|
}
|