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)
|
2024-10-27 23:17:09 -04:00
|
|
|
.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)
|
2024-10-27 23:17:09 -04:00
|
|
|
.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
|
|
|
}
|
2024-10-27 23:17:09 -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
|
2024-10-27 23:17:09 -04:00
|
|
|
formatter.locale = Locale(identifier: Locale.current.identifier)
|
2024-10-27 19:09:03 -04:00
|
|
|
formatter.maximumFractionDigits = 2
|
2024-10-27 23:17:09 -04:00
|
|
|
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
|
|
|
}
|
|
|
|
}
|