Best Value: explain price age per surface instead of one blanket warning
- Station detail now separates the station's own report age from the selected fuel's update time, so a recent station-wide report no longer reads as an old price. - Warning copy names the fuel and says which side is weak: the station's price is not individually dated, or the baseline's is. The misleading "unverified or older than 7 days" line is gone. - Wording stays "Closest" throughout; new copy uses Unleaded / Premium / Diesel rather than the internal grade codes. - Localisation: new and updated keys for the added copy.
This commit is contained in:
@@ -2,7 +2,8 @@ import SwiftUI
|
||||
|
||||
struct FuelSavingsAdjustmentView: View {
|
||||
@Binding var amount: FuelSavingsFillAmount
|
||||
let referencePricePencePerLitre: Double?
|
||||
|
||||
@State private var unitChangeNotice: String?
|
||||
|
||||
private var range: ClosedRange<Double> {
|
||||
FuelSavingsCalculator.fillAmountSliderRange(for: amount.unit)
|
||||
@@ -44,6 +45,14 @@ struct FuelSavingsAdjustmentView: View {
|
||||
Text("Changes the estimate for this session only — your Settings default stays unchanged.")
|
||||
.font(.caption2)
|
||||
.foregroundStyle(.secondary)
|
||||
Text("£ compares the litres your budget buys at each station; Litres compares one fixed quantity.")
|
||||
.font(.caption2)
|
||||
.foregroundStyle(.secondary)
|
||||
if let unitChangeNotice {
|
||||
Text(unitChangeNotice)
|
||||
.font(.caption2)
|
||||
.foregroundStyle(.orange)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -52,12 +61,10 @@ struct FuelSavingsAdjustmentView: View {
|
||||
get: { amount.unit },
|
||||
set: { newUnit in
|
||||
guard newUnit != amount.unit else { return }
|
||||
if let referencePricePencePerLitre,
|
||||
let converted = try? FuelSavingsCalculator.convert(amount: amount, to: newUnit, referencePricePencePerLitre: referencePricePencePerLitre) {
|
||||
amount = converted
|
||||
} else {
|
||||
amount = FuelSavingsFillAmount(value: newUnit == .pounds ? 40 : 30, unit: newUnit)
|
||||
}
|
||||
// No one litre figure equals a budget at every candidate price.
|
||||
// A unit change starts a new, explicitly labelled comparison.
|
||||
amount = FuelSavingsCalculator.newComparisonAmount(afterSwitching: amount, to: newUnit)
|
||||
unitChangeNotice = "New comparison basis — adjust the \(newUnit.displayName) amount to your intended fill-up."
|
||||
}
|
||||
)
|
||||
}
|
||||
@@ -73,6 +80,9 @@ struct FuelSavingsAdjustmentView: View {
|
||||
struct FuelSavingsSummaryView: View {
|
||||
let availability: FuelSavingsAvailability?
|
||||
let amount: FuelSavingsFillAmount
|
||||
/// Candidate/baseline price confidence for every Best Value result.
|
||||
var priceConfidence: FuelPriceFreshness.ComparisonConfidence = .ineligible
|
||||
var priceWarning: String? = nil
|
||||
var baselineStationName: String? = nil
|
||||
var compact: Bool = false
|
||||
/// Sizes the "extra return travel" caption in the user's own unit (the
|
||||
@@ -107,6 +117,12 @@ struct FuelSavingsSummaryView: View {
|
||||
.layoutPriority(1)
|
||||
.accessibilityLabel("Comparison: \(comparisonLabel(for: result))")
|
||||
}
|
||||
if let warning = priceWarning ?? priceConfidence.warningText {
|
||||
Text(warning)
|
||||
.font(.caption2)
|
||||
.foregroundStyle(.orange)
|
||||
.accessibilityLabel(warning)
|
||||
}
|
||||
if let extraTravel = FuelSavingsFormat.extraTravelLabel(
|
||||
extraDistanceMiles: result.extraDistanceMiles,
|
||||
unit: distanceUnit,
|
||||
@@ -143,6 +159,17 @@ struct FuelSavingsSummaryView: View {
|
||||
LabeledContent("Your fill-up", value: amountText)
|
||||
LabeledContent("Fuel you'll receive", value: String(format: "%.2f litres", result.fillLitres))
|
||||
.monospacedDigit()
|
||||
if amount.unit == .pounds {
|
||||
Text("You pay the selected budget here. The saving compares the same litres at your closest eligible station; litres differ between stations, and this is not a refund.")
|
||||
.font(.caption2)
|
||||
.foregroundStyle(.secondary)
|
||||
}
|
||||
if let warning = priceWarning ?? priceConfidence.warningText {
|
||||
Text(warning)
|
||||
.font(.caption2)
|
||||
.foregroundStyle(.orange)
|
||||
.accessibilityLabel(warning)
|
||||
}
|
||||
if let extraTravel = FuelSavingsFormat.extraTravelLabel(
|
||||
extraDistanceMiles: result.extraDistanceMiles,
|
||||
unit: distanceUnit,
|
||||
@@ -158,7 +185,7 @@ struct FuelSavingsSummaryView: View {
|
||||
.font(.caption)
|
||||
.foregroundStyle(.secondary)
|
||||
} else {
|
||||
Text("Compared with \(baselineStationName ?? "your closest station").")
|
||||
Text(baselineStationName.map { "Compared with \($0)." } ?? "Compared with your closest eligible station.")
|
||||
.font(.caption)
|
||||
.foregroundStyle(.secondary)
|
||||
LabeledContent(
|
||||
@@ -233,7 +260,7 @@ struct FuelSavingsSummaryView: View {
|
||||
}
|
||||
|
||||
/// VoiceOver form of the verdict. `spokenHeadline()` spells "Approx." out for
|
||||
/// estimated comparisons and leaves the plain words ("Break even", "Closest
|
||||
/// and leaves the plain words ("Break even", "Closest eligible
|
||||
/// station") alone — one source, so visible and spoken copy cannot drift.
|
||||
private func accessibilityHeadline(for result: FuelSavingsResult) -> String {
|
||||
result.spokenHeadline()
|
||||
|
||||
Reference in New Issue
Block a user