Clarify fuel savings comparison labels
This commit is contained in:
@@ -143,6 +143,13 @@ enum FuelSavingsFormat {
|
||||
: "\(distanceText) extra return travel"
|
||||
}
|
||||
|
||||
/// Compact comparison copy kept outside the coloured verdict capsule.
|
||||
/// "Nearest" refers to the existing shortest-journey baseline selection;
|
||||
/// it does not claim a straight-line comparison.
|
||||
static func comparisonLabel(status: FuelSavingsStatus) -> String {
|
||||
status == .baseline ? "your baseline" : "vs nearest station"
|
||||
}
|
||||
|
||||
/// VoiceOver form of `extraTravelLabel`. The abbreviation and the unit suffix
|
||||
/// are spoken as words ("Approximately 6.4 miles extra return travel") because
|
||||
/// synthesizers render "Approx." and "mi" inconsistently.
|
||||
|
||||
+59
-32
@@ -183,13 +183,13 @@ enum DistanceUnit: String, Codable, CaseIterable, Identifiable {
|
||||
/// shown in this unit, rounded to a whole number for picker labels:
|
||||
/// 5 miles -> "5" (miles unit) or "8" (km unit).
|
||||
func displayMiles(_ miles: Int) -> Int {
|
||||
Int(fromKM(Double(miles) * 1.60934).rounded())
|
||||
Int(fromKM(Double(miles) * FuelSavingsCalculator.kilometresPerMile).rounded())
|
||||
}
|
||||
|
||||
/// Convert a value expressed in this unit to km.
|
||||
func toKM(_ value: Double) -> Double {
|
||||
switch self {
|
||||
case .miles: return value * 1.60934
|
||||
case .miles: return value * FuelSavingsCalculator.kilometresPerMile
|
||||
case .kilometers: return value
|
||||
}
|
||||
}
|
||||
@@ -197,7 +197,7 @@ enum DistanceUnit: String, Codable, CaseIterable, Identifiable {
|
||||
/// Convert a km value to this unit.
|
||||
func fromKM(_ km: Double) -> Double {
|
||||
switch self {
|
||||
case .miles: return km * 0.621371
|
||||
case .miles: return km / FuelSavingsCalculator.kilometresPerMile
|
||||
case .kilometers: return km
|
||||
}
|
||||
}
|
||||
@@ -979,7 +979,7 @@ struct FuelStore {
|
||||
|
||||
/// "Follow search" caps the geofence at 8 miles so a 10/15-mile Stations
|
||||
/// search never creates huge region-monitoring circles.
|
||||
static let alertFollowCapKM: Double = 8 * 1.60934
|
||||
static let alertFollowCapKM: Double = 8 * FuelSavingsCalculator.kilometresPerMile
|
||||
|
||||
/// The effective alert radius: the manual radius, or — when alerts follow
|
||||
/// the Stations-tab search — that distance (miles, converted via the
|
||||
@@ -1618,10 +1618,22 @@ struct FuelStore {
|
||||
// what the rows show.
|
||||
if accurateDistancesEnabled,
|
||||
accurateDistancesReady(userLat: userLat, userLng: userLng),
|
||||
let meters = roadDistanceMeters(for: station, userLat: userLat, userLng: userLng) {
|
||||
return StationDistanceDisplay(km: meters / 1000.0, isApproximate: false)
|
||||
let entry = roadDistanceEntry(for: station, userLat: userLat, userLng: userLng) {
|
||||
let returnKM = (entry.meters + (entry.returnMeters ?? entry.meters)) / 1000.0
|
||||
return StationDistanceDisplay(
|
||||
km: entry.meters / 1000.0,
|
||||
isApproximate: false,
|
||||
returnKM: returnKM,
|
||||
returnIsApproximate: entry.returnMeters == nil
|
||||
)
|
||||
}
|
||||
return StationDistanceDisplay(km: station.distanceKM(to: userLat, lng2: userLng), isApproximate: true)
|
||||
let km = station.distanceKM(to: userLat, lng2: userLng)
|
||||
return StationDistanceDisplay(
|
||||
km: km,
|
||||
isApproximate: true,
|
||||
returnKM: km * 2,
|
||||
returnIsApproximate: true
|
||||
)
|
||||
}
|
||||
|
||||
/// Radius test on the SAME distance the UI shows. Filtering straight-line
|
||||
@@ -1710,35 +1722,50 @@ struct RoadDistanceDiagnostics: Equatable {
|
||||
/// road distance or the straight-line fallback. The confidence travels WITH the
|
||||
/// value, so a label can never claim a confidence the figure doesn't have.
|
||||
struct StationDistanceDisplay: Equatable {
|
||||
let km: Double
|
||||
let isApproximate: Bool
|
||||
let km: Double
|
||||
let isApproximate: Bool
|
||||
let returnKM: Double
|
||||
let returnIsApproximate: Bool
|
||||
|
||||
/// Row/sheet label: a straight-line fallback is marked "Approx." so a figure
|
||||
/// that is NOT a routed road distance can never be read as one, and a cached
|
||||
/// road distance stays a bare figure. It updates by itself once routing lands,
|
||||
/// because `FuelStore.stationDistanceDisplay` re-reads the cache every call.
|
||||
func label(unit: DistanceUnit) -> String {
|
||||
let text = unit.format(km)
|
||||
return isApproximate ? "Approx. \(text)" : text
|
||||
}
|
||||
init(km: Double,
|
||||
isApproximate: Bool,
|
||||
returnKM: Double? = nil,
|
||||
returnIsApproximate: Bool? = nil) {
|
||||
self.km = km
|
||||
self.isApproximate = isApproximate
|
||||
self.returnKM = returnKM ?? km * 2
|
||||
self.returnIsApproximate = returnIsApproximate ?? isApproximate
|
||||
}
|
||||
|
||||
/// Row/sheet label that keeps the one-way station distance primary, then
|
||||
/// adds the out-and-back distance in brackets. This matches Best Value's
|
||||
/// "extra return travel" basis without changing the actual distance model.
|
||||
func labelWithReturn(unit: DistanceUnit) -> String {
|
||||
"\(label(unit: unit)) (\(unit.format(km * 2)) return)"
|
||||
}
|
||||
/// Row/sheet label: a straight-line fallback is marked "Approx." so a figure
|
||||
/// that is NOT a routed road distance can never be read as one, and a cached
|
||||
/// road distance stays a bare figure. It updates by itself once routing lands,
|
||||
/// because `FuelStore.stationDistanceDisplay` re-reads the cache every call.
|
||||
func label(unit: DistanceUnit) -> String {
|
||||
let text = unit.format(km)
|
||||
return isApproximate ? "Approx. \(text)" : text
|
||||
}
|
||||
|
||||
/// VoiceOver form of `label(unit:)`.
|
||||
func spokenLabel(unit: DistanceUnit) -> String {
|
||||
let text = unit.spoken(km)
|
||||
return isApproximate ? "Approximately \(text)" : text
|
||||
}
|
||||
/// Row/sheet label that keeps the one-way station distance primary, then
|
||||
/// adds the independently measured or estimated out-and-back distance.
|
||||
func labelWithReturn(unit: DistanceUnit) -> String {
|
||||
let returnText = unit.format(returnKM)
|
||||
let returnLabel = returnIsApproximate ? "Approx. \(returnText)" : returnText
|
||||
return "\(label(unit: unit)) (\(returnLabel) return)"
|
||||
}
|
||||
|
||||
/// VoiceOver form of `labelWithReturn(unit:)`.
|
||||
func spokenLabelWithReturn(unit: DistanceUnit) -> String {
|
||||
"\(spokenLabel(unit: unit)), \(unit.spoken(km * 2)) return"
|
||||
}
|
||||
/// VoiceOver form of `label(unit:)`.
|
||||
func spokenLabel(unit: DistanceUnit) -> String {
|
||||
let text = unit.spoken(km)
|
||||
return isApproximate ? "Approximately \(text)" : text
|
||||
}
|
||||
|
||||
/// VoiceOver form of `labelWithReturn(unit:)`.
|
||||
func spokenLabelWithReturn(unit: DistanceUnit) -> String {
|
||||
let returnText = unit.spoken(returnKM)
|
||||
let returnLabel = returnIsApproximate ? "Approximately \(returnText)" : returnText
|
||||
return "\(spokenLabel(unit: unit)), \(returnLabel) return"
|
||||
}
|
||||
}
|
||||
|
||||
/// Cached Apple-Maps road distances for nearby stations (see
|
||||
|
||||
@@ -21,7 +21,7 @@ enum SiriCheapestLookup {
|
||||
lng: Double,
|
||||
withinMiles: Double
|
||||
) -> FuelStation? {
|
||||
let radiusKM = withinMiles * 1.60934
|
||||
let radiusKM = withinMiles * FuelSavingsCalculator.kilometresPerMile
|
||||
// Same radius rule as the app list: the distance the answer would SHOW
|
||||
// (cached road route where there is one).
|
||||
return stations
|
||||
|
||||
Reference in New Issue
Block a user