Key sheet: card redesign matching the tip section

Price-rating legend now renders as five accent cards (tip-section style):
Best value (green, checkmark) / Okay (orange, equal) / Pricey (red,
exclamation) each with a RAG dot + threshold (≤1.5p / ≤4p / >4p) on the
right in the row's accent colour; TOP (blue capsule) and star (yellow)
as accent cards below a divider. Footer: 'Colours match each station's
rating on the list'. Copy split into title/blurb keys in Localizable.
Sheet chrome (medium detent, Done, info button) unchanged.
This commit is contained in:
FuelBoard Contributor
2026-08-16 09:18:27 +01:00
parent 9fdcc7370e
commit 86385d53a2
2 changed files with 95 additions and 35 deletions
+80 -24
View File
@@ -193,39 +193,54 @@ struct StationsView: View {
.sheet(isPresented: $showKey) { .sheet(isPresented: $showKey) {
NavigationStack { NavigationStack {
List { List {
Section("Key") { Section {
HStack(spacing: 8) { VStack(spacing: 10) {
Circle().fill(.green).frame(width: 12, height: 12) keyCard(
Text("Best value — within 1.5p of the cheapest") icon: "checkmark.circle.fill", color: .green,
.font(.caption) title: "Best value", blurb: "Within 1.5p of the cheapest",
} threshold: "≤1.5p")
HStack(spacing: 8) { keyCard(
Circle().fill(.orange).frame(width: 12, height: 12) icon: "equal.circle.fill", color: .orange,
Text("Okay — within 4p of the cheapest") title: "Okay", blurb: "Within 4p of the cheapest",
.font(.caption) threshold: "≤4p")
} keyCard(
HStack(spacing: 8) { icon: "exclamationmark.circle.fill", color: .red,
Circle().fill(.red).frame(width: 12, height: 12) title: "Pricey", blurb: "More than 4p over the cheapest",
Text("Pricey — more than 4p over the cheapest") threshold: ">4p")
.font(.caption) Rectangle()
} .fill(Color(.separator))
HStack(spacing: 8) { .frame(height: 0.5)
.padding(.vertical, 2)
HStack(spacing: 12) {
Text("TOP") Text("TOP")
.font(.caption2.bold()) .font(.caption2.bold())
.padding(.horizontal, 5) .padding(.horizontal, 7)
.padding(.vertical, 1) .padding(.vertical, 3)
.background(Capsule().fill(.blue.opacity(0.15))) .background(Capsule().fill(.blue.opacity(0.16)))
.foregroundStyle(.blue) .foregroundStyle(.blue)
Text("Top result for the current sort") Text("Top result for the current sort")
.font(.caption) .font(.subheadline.weight(.semibold))
Spacer(minLength: 0)
} }
HStack(spacing: 8) { .keyCardFill(color: .blue)
HStack(spacing: 12) {
Image(systemName: "star.fill") Image(systemName: "star.fill")
.font(.caption2) .font(.title3)
.foregroundStyle(.yellow) .foregroundStyle(.yellow)
.frame(width: 34)
Text("Star a station to add it to Favourites") Text("Star a station to add it to Favourites")
.font(.caption) .font(.subheadline.weight(.semibold))
Spacer(minLength: 0)
} }
.keyCardFill(color: .yellow)
Text("Colours match each station's rating on the list")
.font(.footnote)
.foregroundStyle(.secondary)
.frame(maxWidth: .infinity)
.padding(.top, 4)
}
.listRowBackground(Color.clear)
.listRowInsets(EdgeInsets(top: 4, leading: 16, bottom: 4, trailing: 16))
} }
} }
.navigationTitle("Key") .navigationTitle("Key")
@@ -240,6 +255,47 @@ struct StationsView: View {
} }
} }
} }
/// One price-rating card for the Key sheet: accent icon, title + blurb,
/// and the rating threshold in the accent colour (mirrors the tip cards).
private func keyCard(icon: String, color: Color, title: String, blurb: String, threshold: String) -> some View {
HStack(spacing: 12) {
Image(systemName: icon)
.font(.title3)
.foregroundStyle(color)
.frame(width: 34)
VStack(alignment: .leading, spacing: 2) {
Text(LocalizedStringKey(title)).font(.headline)
Text(LocalizedStringKey(blurb))
.font(.caption)
.foregroundStyle(.secondary)
}
Spacer(minLength: 8)
HStack(spacing: 6) {
Circle().fill(color).frame(width: 10, height: 10)
Text(threshold)
.font(.headline.weight(.bold))
.foregroundStyle(color)
.monospacedDigit()
}
}
.padding(.horizontal, 14)
.padding(.vertical, 10)
.frame(maxWidth: .infinity, alignment: .leading)
.keyCardFill(color: color)
}
}
/// Card background shared by the Key sheet cards subtle accent tint over
/// the grouped background, matching the tip-section card style.
private extension View {
func keyCardFill(color: Color) -> some View {
background(
RoundedRectangle(cornerRadius: 12)
.fill(Color(.secondarySystemGroupedBackground))
.overlay(RoundedRectangle(cornerRadius: 12).fill(color.opacity(0.08)))
)
}
} }
// MARK: - Fuel-type iconography (app target only FuelStore.swift is Foundation-only) // MARK: - Fuel-type iconography (app target only FuelStore.swift is Foundation-only)
+7 -3
View File
@@ -23,11 +23,15 @@
"Show %lld more (%lld remaining)" = "Show %lld more (%lld remaining)"; "Show %lld more (%lld remaining)" = "Show %lld more (%lld remaining)";
"All %lld stations shown" = "All %lld stations shown"; "All %lld stations shown" = "All %lld stations shown";
"Key" = "Key"; "Key" = "Key";
"Best value — within 1.5p of the cheapest" = "Best value — within 1.5p of the cheapest"; "Best value" = "Best value";
"Okay — within 4p of the cheapest" = "Okay — within 4p of the cheapest"; "Within 1.5p of the cheapest" = "Within 1.5p of the cheapest";
"Pricey — more than 4p over the cheapest" = "Pricey — more than 4p over the cheapest"; "Okay" = "Okay";
"Within 4p of the cheapest" = "Within 4p of the cheapest";
"Pricey" = "Pricey";
"More than 4p over the cheapest" = "More than 4p over 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";
"Colours match each station's rating on the list" = "Colours match each station's rating on the list";
/* Favourites tab */ /* Favourites tab */
"No favourites yet" = "No favourites yet"; "No favourites yet" = "No favourites yet";