Worth the Drive: calculation audit + listing/detail polish
Calculation audit (brief config: 30 MPG imperial, £60 fill-up, baseline
Rontec Shelf 171.9p at 0.4 mi):
- One mile<->kilometre constant pair (kilometresPerMile 1.609344,
metresPerMile 1609.344) replaces the mixed 1609.34 / 0.621371 / 1.60934
used in the savings path. Effect ~2 ppm (invisible), but the conversions
are now auditable in one place.
- New FuelSavingsCalculationAuditTests (20 deterministic tests, no live
MKDirections) pins the brief's three stations - Tesco 170.9p/2.0 mi,
MFG Hare & Hounds 172.9p/2.8 mi, PGG Napoleon 171.9p/2.8 mi - plus
imperial-vs-US gallon, MPG and budget scaling, the break-even tolerance
boundary, the nearer-candidate clamp, route-unavailable, mixed-basis
estimates and display-rounding boundaries.
- Formula unchanged, and verified correct: fixed quantity (budget / baseline
price), pump saving, round-trip extra distance clamped at zero, travel fuel
priced at the candidate station, +/-5p break even, baseline labelled
"Closest station", sorting on the unrounded net saving. The brief's "£0.18"
for Tesco is the rounded 1 dp extra-distance caption (2.02-2.05 mi reads as
"2.0 mi"), not a rounding bug in the money.
UI (uncommitted since d7a0ecb):
- Done bar drawn in the bottom safe area from keyboard notifications:
.toolbar(placement: .keyboard) is device-dependent (present on the 15 Pro,
absent on the SE on the same iOS build).
- Favourite star in the More-info heading, wired to the same fuel-scoped
toggle as the listing rows at all three call sites.
- CHEAPEST/TOP badge moved above the price so it reads as part of it.
- Listing rows carry the real session fill-up amount instead of a hard zero
(the compact banner does not print it today; a future row layout would).
153 tests, 0 failures. Simulator and device builds succeed.
This commit is contained in:
@@ -13,6 +13,12 @@ struct StationDetailView: View {
|
||||
var fuelSavings: FuelSavingsAvailability? = nil
|
||||
var fuelSavingsAmount: FuelSavingsFillAmount = FuelSavingsSettings.defaultPreferredAmount
|
||||
var savingsBaselineStationName: String? = nil
|
||||
/// Whether this station is starred for the fuel currently being viewed, and
|
||||
/// the toggle that flips it. Passed from the list that opened the sheet, so
|
||||
/// the star here and the star on the row are the same fuel-scoped
|
||||
/// favourite and cannot drift apart.
|
||||
var isFavourite: Bool = false
|
||||
var onToggleFavourite: (() -> Void)? = nil
|
||||
@Environment(\.dismiss) private var dismiss
|
||||
@State private var showingReportIssueConfirmation = false
|
||||
|
||||
@@ -61,7 +67,8 @@ struct StationDetailView: View {
|
||||
FuelSavingsSummaryView(
|
||||
availability: fuelSavings,
|
||||
amount: fuelSavingsAmount,
|
||||
baselineStationName: savingsBaselineStationName
|
||||
baselineStationName: savingsBaselineStationName,
|
||||
distanceUnit: distanceUnit
|
||||
)
|
||||
} header: {
|
||||
Text("Worth the drive?")
|
||||
@@ -96,6 +103,20 @@ struct StationDetailView: View {
|
||||
ToolbarItem(placement: .cancellationAction) {
|
||||
Button("Done") { dismiss() }
|
||||
}
|
||||
ToolbarItem(placement: .confirmationAction) {
|
||||
Button {
|
||||
onToggleFavourite?()
|
||||
} label: {
|
||||
Image(systemName: isFavourite ? "star.fill" : "star")
|
||||
}
|
||||
.tint(isFavourite ? Color.yellow : nil)
|
||||
.disabled(onToggleFavourite == nil)
|
||||
.accessibilityLabel(
|
||||
isFavourite
|
||||
? String(localized: "Remove from favourites", comment: "Unstar a station from the More info sheet")
|
||||
: String(localized: "Add to favourites", comment: "Star a station from the More info sheet")
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user