BlueWallet/ios/Widgets/PriceWidget/PriceIntent.swift

106 lines
3.4 KiB
Swift
Raw Normal View History

2024-10-27 18:14:37 -04:00
import AppIntents
import SwiftUI
@available(iOS 16.0, *)
struct PriceIntent: AppIntent {
static var title: LocalizedStringResource = "Market Rate"
static var description = IntentDescription("View the current Bitcoin market rate.")
2024-10-27 19:09:03 -04:00
static var openAppWhenRun: Bool { false }
2024-10-27 18:14:37 -04:00
static var parameterSummary: some ParameterSummary {
Summary("View the current Bitcoin market rate.")
}
@MainActor
2024-10-27 19:09:03 -04:00
func perform() async throws -> some IntentResult & ReturnsValue<Double> & ProvidesDialog & ShowsSnippetView {
2024-10-27 18:14:37 -04:00
let userPreferredCurrency = Currency.getUserPreferredCurrency()
2024-10-27 19:09:03 -04:00
let currencyCode = userPreferredCurrency.uppercased()
let dataSource = fiatUnit(currency: userPreferredCurrency)?.source ?? "Unknown Source"
2024-10-27 18:14:37 -04:00
if userPreferredCurrency != Currency.getLastSelectedCurrency() {
Currency.saveNewSelectedCurrency()
}
var lastUpdated = "--"
2024-10-27 19:09:03 -04:00
var resultValue: Double = 0.0
2024-10-27 18:14:37 -04:00
do {
2024-10-27 19:09:03 -04:00
guard let data = try await MarketAPI.fetchPrice(currency: userPreferredCurrency) 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
resultValue = data.rateDouble
lastUpdated = formattedDate(from: data.lastUpdate)
2024-10-27 18:14:37 -04:00
} catch {
2024-10-27 19:09:03 -04:00
throw error
2024-10-27 18:14:37 -04:00
}
2024-10-27 19:09:03 -04:00
let view = CompactPriceView(
price: resultValue,
lastUpdated: lastUpdated,
currencyCode: currencyCode,
dataSource: dataSource
)
2024-10-27 18:14:37 -04:00
return .result(
2024-10-27 19:09:03 -04:00
value: resultValue,
2024-10-27 18:14:37 -04:00
dialog: "Current Bitcoin Market Rate",
view: view
)
}
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()
formatter.dateStyle = .none
formatter.timeStyle = .short
return formatter.string(from: date)
}
return "--"
}
}
2024-10-27 19:09:03 -04:00
@available(iOS 16.0, *)
2024-10-27 18:14:37 -04:00
struct CompactPriceView: View {
2024-10-27 19:09:03 -04:00
let price: Double
2024-10-27 18:14:37 -04:00
let lastUpdated: String
2024-10-27 19:09:03 -04:00
let currencyCode: String
let dataSource: String
2024-10-27 18:14:37 -04:00
var body: some View {
VStack {
2024-10-27 19:09:03 -04:00
Text(priceFormatted)
2024-10-27 18:14:37 -04:00
.font(.title)
.accessibilityLabel("Bitcoin price: \(priceFormatted)")
2024-10-27 19:09:03 -04:00
Text(detailsText)
.font(.caption)
2024-10-27 18:14:37 -04:00
.foregroundColor(.gray)
.accessibilityLabel("Last updated \(lastUpdated) from \(dataSource)")
2024-10-27 19:09:03 -04:00
.padding(.top, 8)
.lineLimit(1)
.minimumScaleFactor(0.5)
.multilineTextAlignment(.center)
2024-10-27 18:14:37 -04:00
}
.frame(maxWidth: .infinity)
.frame(idealWidth: 200)
2024-10-27 18:14:37 -04:00
.padding()
2024-10-27 19:09:03 -04:00
}
private var priceFormatted: String {
let formatter = NumberFormatter()
formatter.numberStyle = .currency
formatter.currencyCode = currencyCode
formatter.locale = Locale(identifier: Locale.current.identifier)
2024-10-27 19:09:03 -04:00
formatter.maximumFractionDigits = 2
formatter.minimumFractionDigits = 2
2024-10-27 19:09:03 -04:00
return formatter.string(from: NSNumber(value: price)) ?? "--"
}
private var detailsText: String {
"\(lastUpdated) - \(currencyCode) - \(dataSource)"
2024-10-27 18:14:37 -04:00
}
}