Update FuelBoard onboarding copy, title formatting, key sheet card wrapping, and best-value button placement
This commit is contained in:
@@ -78,6 +78,7 @@ struct FuelSavingsSummaryView: View {
|
|||||||
/// Sizes the "extra return travel" caption in the user's own unit (the
|
/// Sizes the "extra return travel" caption in the user's own unit (the
|
||||||
/// stored figure is miles) — used by both the row banner and the detail sheet.
|
/// stored figure is miles) — used by both the row banner and the detail sheet.
|
||||||
var distanceUnit: DistanceUnit = .miles
|
var distanceUnit: DistanceUnit = .miles
|
||||||
|
var showInfoAction: (() -> Void)? = nil
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
switch availability {
|
switch availability {
|
||||||
@@ -166,6 +167,22 @@ struct FuelSavingsSummaryView: View {
|
|||||||
.font(.caption2)
|
.font(.caption2)
|
||||||
.foregroundStyle(.secondary)
|
.foregroundStyle(.secondary)
|
||||||
}
|
}
|
||||||
|
if let showInfoAction {
|
||||||
|
Rectangle()
|
||||||
|
.fill(Color(.separator))
|
||||||
|
.frame(height: 0.5)
|
||||||
|
.padding(.vertical, 4)
|
||||||
|
Button(action: showInfoAction) {
|
||||||
|
HStack(spacing: 8) {
|
||||||
|
Text("How Best Value works")
|
||||||
|
Spacer(minLength: 8)
|
||||||
|
Image(systemName: "chevron.forward")
|
||||||
|
.font(.footnote.weight(.semibold))
|
||||||
|
.foregroundStyle(.tertiary)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.buttonStyle(.plain)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
case .unavailable(let reason):
|
case .unavailable(let reason):
|
||||||
|
|||||||
@@ -108,10 +108,10 @@ struct OnboardingView: View {
|
|||||||
.frame(width: 96, height: 96)
|
.frame(width: 96, height: 96)
|
||||||
.clipShape(RoundedRectangle(cornerRadius: 21, style: .continuous))
|
.clipShape(RoundedRectangle(cornerRadius: 21, style: .continuous))
|
||||||
}
|
}
|
||||||
.padding(.bottom, 28)
|
.padding(.bottom, 16)
|
||||||
|
|
||||||
Text(String(localized: "Welcome to FuelBoard", comment: "Onboarding welcome title"))
|
Text(String(localized: "Welcome to\nFuelBoard", comment: "Onboarding welcome title"))
|
||||||
.font(.largeTitle.bold())
|
.font(.title.bold())
|
||||||
.multilineTextAlignment(.center)
|
.multilineTextAlignment(.center)
|
||||||
|
|
||||||
Text(String(localized: "The cheapest petrol, diesel and premium fuel near you — from the official UK Fuel Finder data.", comment: "Onboarding welcome subtitle"))
|
Text(String(localized: "The cheapest petrol, diesel and premium fuel near you — from the official UK Fuel Finder data.", comment: "Onboarding welcome subtitle"))
|
||||||
@@ -121,12 +121,13 @@ struct OnboardingView: View {
|
|||||||
.padding(.horizontal, 32)
|
.padding(.horizontal, 32)
|
||||||
.padding(.top, 12)
|
.padding(.top, 12)
|
||||||
|
|
||||||
featureRow(icon: "globe.europe.africa.fill", text: String(localized: "UK-wide prices — 8,000+ stations, updated twice a day", comment: "Onboarding feature row"))
|
featureRow(icon: "map.fill", title: String(localized: "Compare fuel prices near you", comment: "Onboarding feature row title"), subtitle: String(localized: "Over 8,000 stations across Great Britain, with prices updated daily.", comment: "Onboarding feature row subtitle"))
|
||||||
featureRow(icon: "scope", text: String(localized: "Cheapest within your chosen radius, or closest station first", comment: "Onboarding feature row"))
|
|
||||||
featureRow(icon: "star.fill", text: String(localized: "Favourites with instant price comparison", comment: "Onboarding feature row"))
|
featureRow(icon: "chart.line.uptrend.xyaxis", title: String(localized: "See how much you could save", comment: "Onboarding feature row title"), subtitle: String(localized: "Compare fill-up costs and potential savings at different stations.", comment: "Onboarding feature row subtitle"))
|
||||||
featureRow(icon: "chart.bar.fill", text: String(localized: "Green/amber/red rating vs the best nearby price", comment: "Onboarding feature row"))
|
|
||||||
featureRow(icon: "square.grid.2x2.fill", text: String(localized: "Home-screen widget showing the cheapest nearby", comment: "Onboarding feature row"))
|
featureRow(icon: "car.fill", title: String(localized: "Know if it's worth the drive", comment: "Onboarding feature row title"), subtitle: String(localized: "Factor in your journey and fuel costs to find the best value.", comment: "Onboarding feature row subtitle"))
|
||||||
featureRow(icon: "bell.fill", text: String(localized: "Alerts when you approach the cheapest station", comment: "Onboarding feature row"))
|
|
||||||
|
featureRow(icon: "star.fill", title: String(localized: "Keep your favourites close", comment: "Onboarding feature row title"), subtitle: String(localized: "Save stations and quickly compare their latest prices.", comment: "Onboarding feature row subtitle"))
|
||||||
|
|
||||||
Spacer()
|
Spacer()
|
||||||
}
|
}
|
||||||
@@ -298,18 +299,23 @@ struct OnboardingView: View {
|
|||||||
OnboardingPrimaryButton(title: title, action: action)
|
OnboardingPrimaryButton(title: title, action: action)
|
||||||
}
|
}
|
||||||
|
|
||||||
private func featureRow(icon: String, text: String) -> some View {
|
private func featureRow(icon: String, title: String, subtitle: String) -> some View {
|
||||||
HStack(spacing: 12) {
|
HStack(alignment: .top, spacing: 12) {
|
||||||
Image(systemName: icon)
|
Image(systemName: icon)
|
||||||
.font(.system(size: 20, weight: .semibold))
|
.font(.system(size: 20, weight: .semibold))
|
||||||
.foregroundStyle(Color.accentColor)
|
.foregroundStyle(Color.accentColor)
|
||||||
.frame(width: 32)
|
.frame(width: 32)
|
||||||
Text(text)
|
VStack(alignment: .leading, spacing: 2) {
|
||||||
|
Text(title)
|
||||||
|
.font(.subheadline.bold())
|
||||||
|
Text(subtitle)
|
||||||
.font(.subheadline)
|
.font(.subheadline)
|
||||||
|
.foregroundStyle(.secondary)
|
||||||
|
}
|
||||||
Spacer(minLength: 0)
|
Spacer(minLength: 0)
|
||||||
}
|
}
|
||||||
.padding(.horizontal, 36)
|
.padding(.horizontal, 36)
|
||||||
.padding(.vertical, 10)
|
.padding(.vertical, 8)
|
||||||
}
|
}
|
||||||
|
|
||||||
private func permissionStatusLabel(granted: Bool, denied: Bool, deniedText: String) -> some View {
|
private func permissionStatusLabel(granted: Bool, denied: Bool, deniedText: String) -> some View {
|
||||||
|
|||||||
@@ -238,18 +238,12 @@ struct StationDetailView: View {
|
|||||||
availability: fuelSavings,
|
availability: fuelSavings,
|
||||||
amount: fuelSavingsAmount,
|
amount: fuelSavingsAmount,
|
||||||
baselineStationName: savingsBaselineStationName,
|
baselineStationName: savingsBaselineStationName,
|
||||||
distanceUnit: distanceUnit
|
distanceUnit: distanceUnit,
|
||||||
|
showInfoAction: { showBestValueInfo = true }
|
||||||
)
|
)
|
||||||
} header: {
|
} header: {
|
||||||
Text("Best Value")
|
Text("Best Value")
|
||||||
}
|
}
|
||||||
|
|
||||||
// The explanation lives in its own sheet now, opened from this
|
|
||||||
// row. The row sits INSIDE the `if let` so it carries the same
|
|
||||||
// gate as the card above: no card, no row.
|
|
||||||
Section {
|
|
||||||
HowBestValueRow { showBestValueInfo = true }
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
|
|||||||
@@ -267,14 +267,14 @@ struct StationsView: View {
|
|||||||
keyCard(
|
keyCard(
|
||||||
icon: "checkmark.circle.fill", color: .green,
|
icon: "checkmark.circle.fill", color: .green,
|
||||||
title: "Good price", blurb: "Within 1.5p of the cheapest",
|
title: "Good price", blurb: "Within 1.5p of the cheapest",
|
||||||
threshold: "≤1.5p")
|
threshold: "0–1.5p")
|
||||||
keyCard(
|
keyCard(
|
||||||
icon: "equal.circle.fill", color: .orange,
|
icon: "equal.circle.fill", color: .orange,
|
||||||
title: "Okay", blurb: "Within 4p of the cheapest",
|
title: "Okay", blurb: "More than 1.5p, up to 4p above the cheapest",
|
||||||
threshold: "≤4p")
|
threshold: ">1.5–4p")
|
||||||
keyCard(
|
keyCard(
|
||||||
icon: "exclamationmark.circle.fill", color: .red,
|
icon: "exclamationmark.circle.fill", color: .red,
|
||||||
title: "Pricey", blurb: "More than 4p over the cheapest",
|
title: "Pricey", blurb: "More than 4p above the cheapest",
|
||||||
threshold: ">4p")
|
threshold: ">4p")
|
||||||
Rectangle()
|
Rectangle()
|
||||||
.fill(Color(.separator))
|
.fill(Color(.separator))
|
||||||
@@ -306,10 +306,11 @@ struct StationsView: View {
|
|||||||
.padding(.horizontal, 14)
|
.padding(.horizontal, 14)
|
||||||
.padding(.vertical, 12)
|
.padding(.vertical, 12)
|
||||||
.keyCardFill(color: .yellow)
|
.keyCardFill(color: .yellow)
|
||||||
Text("Colours match each station's rating on the list")
|
Text("Price differences are shown in pence per litre (p/litre). Colours match each station's rating on the list.")
|
||||||
.font(.footnote)
|
.font(.footnote)
|
||||||
.foregroundStyle(.secondary)
|
.foregroundStyle(.secondary)
|
||||||
.frame(maxWidth: .infinity)
|
.frame(maxWidth: .infinity, alignment: .center)
|
||||||
|
.multilineTextAlignment(.center)
|
||||||
.padding(.top, 4)
|
.padding(.top, 4)
|
||||||
}
|
}
|
||||||
.listRowBackground(Color.clear)
|
.listRowBackground(Color.clear)
|
||||||
@@ -377,6 +378,7 @@ struct StationsView: View {
|
|||||||
Text(LocalizedStringKey(blurb))
|
Text(LocalizedStringKey(blurb))
|
||||||
.font(.caption)
|
.font(.caption)
|
||||||
.foregroundStyle(.secondary)
|
.foregroundStyle(.secondary)
|
||||||
|
.fixedSize(horizontal: false, vertical: true)
|
||||||
}
|
}
|
||||||
Spacer(minLength: 8)
|
Spacer(minLength: 8)
|
||||||
HStack(spacing: 6) {
|
HStack(spacing: 6) {
|
||||||
|
|||||||
@@ -26,15 +26,15 @@
|
|||||||
"Good price" = "Good price";
|
"Good price" = "Good price";
|
||||||
"Within 1.5p of the cheapest" = "Within 1.5p of the cheapest";
|
"Within 1.5p of the cheapest" = "Within 1.5p of the cheapest";
|
||||||
"Okay" = "Okay";
|
"Okay" = "Okay";
|
||||||
"Within 4p of the cheapest" = "Within 4p of the cheapest";
|
"More than 1.5p, up to 4p above the cheapest" = "More than 1.5p, up to 4p above the cheapest";
|
||||||
"Pricey" = "Pricey";
|
"Pricey" = "Pricey";
|
||||||
"More than 4p over the cheapest" = "More than 4p over the cheapest";
|
"More than 4p above the cheapest" = "More than 4p above the cheapest";
|
||||||
"Top result for the current sort" = "Top result for the current sort";
|
"Top result for the current sort" = "Top result for the current sort";
|
||||||
"Star a station to add it to Favourites" = "Star a station to add it to Favourites";
|
"Star a station to add it to Favourites" = "Star a station to add it to Favourites";
|
||||||
/* Star button in the More info sheet heading (accessibility labels) */
|
/* Star button in the More info sheet heading (accessibility labels) */
|
||||||
"Add to favourites" = "Add to favourites";
|
"Add to favourites" = "Add to favourites";
|
||||||
"Remove from favourites" = "Remove from favourites";
|
"Remove from favourites" = "Remove from favourites";
|
||||||
"Colours match each station's rating on the list" = "Colours match each station's rating on the list";
|
"Price differences are shown in pence per litre (p/litre). Colours match each station's rating on the list." = "Price differences are shown in pence per litre (p/litre). Colours match each station's rating on the list.";
|
||||||
"How Best Value works" = "How Best Value works";
|
"How Best Value works" = "How Best Value works";
|
||||||
"Best Value compares each station with the closest one. It works out what you could save at the pump, then takes off the fuel used for the extra return journey." = "Best Value compares each station with the closest one. It works out what you could save at the pump, then takes off the fuel used for the extra return journey.";
|
"Best Value compares each station with the closest one. It works out what you could save at the pump, then takes off the fuel used for the extra return journey." = "Best Value compares each station with the closest one. It works out what you could save at the pump, then takes off the fuel used for the extra return journey.";
|
||||||
"Your fill-up amount and MPG are used to show whether you could save overall." = "Your fill-up amount and MPG are used to show whether you could save overall.";
|
"Your fill-up amount and MPG are used to show whether you could save overall." = "Your fill-up amount and MPG are used to show whether you could save overall.";
|
||||||
|
|||||||
Reference in New Issue
Block a user