Revert station capsule layout changes
This commit is contained in:
+31
-17
@@ -1842,13 +1842,26 @@ struct StationRow: View {
|
|||||||
/// 22pt keeps the price the row's loudest element after the station name.
|
/// 22pt keeps the price the row's loudest element after the station name.
|
||||||
@ScaledMetric(relativeTo: .title2) private var priceSize: CGFloat = 22
|
@ScaledMetric(relativeTo: .title2) private var priceSize: CGFloat = 22
|
||||||
|
|
||||||
|
/// The identity column's share of the ROW, for every row and both price
|
||||||
|
/// styles. The mockup's divider sits at ~53% of its row; this is that ratio,
|
||||||
|
/// held per row rather than derived from the row's text — the point is that
|
||||||
|
/// the hairline, the price axis and the star cannot move as the list scrolls.
|
||||||
|
/// The price column takes the remainder, and its savings capsule scales down
|
||||||
|
/// instead of widening the column and dragging the hairline with it.
|
||||||
|
///
|
||||||
|
/// One value for both price styles: the star used to sit at the end of the
|
||||||
|
/// price line and hold ~28pt of the price column, so the wide form `£1.58⁷/L`
|
||||||
|
/// — ~20pt wider than the bare `158.7` at the same point size — did not fit on
|
||||||
|
/// a 393pt screen. With the star now under the station logo the price column
|
||||||
|
/// has that width back, so the identity column no longer has to give width up
|
||||||
|
/// in pounds & pence, and names keep the same room in both styles.
|
||||||
|
private static let leftSectionShare: CGFloat = 0.52
|
||||||
|
|
||||||
/// The comparison label sits beside the capsule only where the row is wide
|
/// The comparison label sits beside the capsule only where the row is wide
|
||||||
/// enough for both (regular width). On an iPhone the mockup's canvas is
|
/// enough for both (regular width). On an iPhone the mockup's canvas is
|
||||||
/// wider than the whole screen, so the label drops under the capsule rather
|
/// wider than the whole screen, so the label drops under the capsule rather
|
||||||
/// than starving the station name.
|
/// than starving the station name.
|
||||||
@Environment(\.horizontalSizeClass) private var sizeClass
|
@Environment(\.horizontalSizeClass) private var sizeClass
|
||||||
@Environment(\.dynamicTypeSize) private var dynamicTypeSize
|
|
||||||
|
|
||||||
private var ragColor: Color {
|
private var ragColor: Color {
|
||||||
guard let price = station.prices[fuel], let baselinePrice else { return .gray }
|
guard let price = station.prices[fuel], let baselinePrice else { return .gray }
|
||||||
@@ -1918,9 +1931,13 @@ struct StationRow: View {
|
|||||||
// the detail sheet instead of being repeated on every row.
|
// the detail sheet instead of being repeated on every row.
|
||||||
HStack(alignment: .center, spacing: 12) {
|
HStack(alignment: .center, spacing: 12) {
|
||||||
// LEFT SECTION — station identity: brand logo, then name, address and
|
// LEFT SECTION — station identity: brand logo, then name, address and
|
||||||
// distance. This section yields horizontal space to the financial
|
// distance. Given a FIXED SHARE of the row (~52%, the mockup's ratio)
|
||||||
// column first: a truncated station identity is recoverable from the
|
// rather than sizing to its content: sized to content, this column
|
||||||
// detail sheet, while a truncated saving is materially misleading.
|
// grew and shrank with each row's badge and savings copy, which moved
|
||||||
|
// the hairline 23pt between adjacent rows (x767 on a BEST VALUE row,
|
||||||
|
// x699 on a "costs more" row) — so the divider and the price axis
|
||||||
|
// both jumped sideways as the list scrolled. One share for every row
|
||||||
|
// puts them on a single vertical line down the whole list.
|
||||||
HStack(alignment: .top, spacing: 12) {
|
HStack(alignment: .top, spacing: 12) {
|
||||||
// The logo, with the favourite star directly beneath it. Moving
|
// The logo, with the favourite star directly beneath it. Moving
|
||||||
// the star out of the price line is what gives the price column
|
// the star out of the price line is what gives the price column
|
||||||
@@ -1955,15 +1972,16 @@ struct StationRow: View {
|
|||||||
|
|
||||||
// Name, full address, distance
|
// Name, full address, distance
|
||||||
VStack(alignment: .leading, spacing: 2) {
|
VStack(alignment: .leading, spacing: 2) {
|
||||||
// Keep the established compact row. Long names yield space
|
// The name WRAPS instead of truncating: the row is tall
|
||||||
// to the complete price/verdict column rather than wrapping
|
// enough now, and a name cut to "Z A Service Stat…" cannot
|
||||||
// and forcing a financial amount to truncate.
|
// be told apart from the station next door. Baseline
|
||||||
|
// alignment keeps the notice symbols on the name's FIRST
|
||||||
|
// line instead of floating beside a two-line name.
|
||||||
HStack(alignment: .firstTextBaseline, spacing: 6) {
|
HStack(alignment: .firstTextBaseline, spacing: 6) {
|
||||||
Text(station.name)
|
Text(station.name)
|
||||||
.font(.headline)
|
.font(.headline)
|
||||||
.multilineTextAlignment(.leading)
|
.multilineTextAlignment(.leading)
|
||||||
.lineLimit(1)
|
.fixedSize(horizontal: false, vertical: true)
|
||||||
.truncationMode(.tail)
|
|
||||||
ForEach(StationNotice.notices(for: station)) { notice in
|
ForEach(StationNotice.notices(for: station)) { notice in
|
||||||
Image(systemName: notice.symbolName)
|
Image(systemName: notice.symbolName)
|
||||||
.font(.caption2.weight(.semibold))
|
.font(.caption2.weight(.semibold))
|
||||||
@@ -2001,10 +2019,11 @@ struct StationRow: View {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
.frame(maxWidth: .infinity, alignment: .leading)
|
.frame(maxWidth: .infinity, alignment: .leading)
|
||||||
.layoutPriority(0)
|
|
||||||
}
|
}
|
||||||
.frame(maxWidth: .infinity, alignment: .leading)
|
.frame(maxWidth: .infinity, alignment: .leading)
|
||||||
.layoutPriority(0)
|
.containerRelativeFrame(.horizontal, alignment: .leading) { length, _ in
|
||||||
|
length * Self.leftSectionShare
|
||||||
|
}
|
||||||
|
|
||||||
// 1pt hairline between the two sections. Inset top and bottom so it
|
// 1pt hairline between the two sections. Inset top and bottom so it
|
||||||
// spans the row's content without touching the row edges, and
|
// spans the row's content without touching the row edges, and
|
||||||
@@ -2056,12 +2075,7 @@ struct StationRow: View {
|
|||||||
savingsCapsule(result)
|
savingsCapsule(result)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// The verdict owns its natural one-line width at normal Dynamic Type
|
.frame(maxWidth: .infinity, alignment: .leading)
|
||||||
// sizes. The identity column compresses first, preventing "Approx.
|
|
||||||
// Save £…" while keeping the same two-column visual design.
|
|
||||||
.fixedSize(horizontal: !dynamicTypeSize.isAccessibilitySize,
|
|
||||||
vertical: false)
|
|
||||||
.layoutPriority(1)
|
|
||||||
// The spec's ~20-24pt of air between the divider and the price
|
// The spec's ~20-24pt of air between the divider and the price
|
||||||
// column: the row's own 12pt spacing plus this 10pt.
|
// column: the row's own 12pt spacing plus this 10pt.
|
||||||
.padding(.leading, 10)
|
.padding(.leading, 10)
|
||||||
|
|||||||
@@ -105,26 +105,25 @@ struct FuelSavingsCapsule: View {
|
|||||||
let result: FuelSavingsResult
|
let result: FuelSavingsResult
|
||||||
var compact: Bool = true
|
var compact: Bool = true
|
||||||
|
|
||||||
@Environment(\.dynamicTypeSize) private var dynamicTypeSize
|
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
HStack(spacing: compact ? 3 : 5) {
|
HStack(spacing: compact ? 3 : 5) {
|
||||||
Image(systemName: Self.symbol(for: result.status))
|
Image(systemName: Self.symbol(for: result.status))
|
||||||
.accessibilityHidden(true)
|
.accessibilityHidden(true)
|
||||||
Text(result.capsuleHeadline())
|
Text(result.capsuleHeadline())
|
||||||
// Financial verdicts stay complete and single-line at ordinary
|
.lineLimit(1)
|
||||||
// text sizes. Accessibility sizes may use a second line rather
|
// Measured on a 393pt screen: the capsule is handed ~101pt, of
|
||||||
// than clipping, shrinking or losing the amount to an ellipsis.
|
// which the icon, its spacing and the 8pt padding either side
|
||||||
.lineLimit(dynamicTypeSize.isAccessibilitySize ? 2 : 1)
|
// take 32pt, leaving ~69pt for the text. "Closest station" needs
|
||||||
.fixedSize(horizontal: !dynamicTypeSize.isAccessibilitySize,
|
// ~90pt at full size, so a 0.8 floor — 72pt — could not reach it
|
||||||
vertical: true)
|
// and the row showed "Closest stati…" instead. 0.7 leaves ~63pt,
|
||||||
|
// which clears it at ~10pt type: scaled, never truncated.
|
||||||
|
.minimumScaleFactor(0.7)
|
||||||
}
|
}
|
||||||
.font(compact ? .caption.weight(.semibold) : .headline)
|
.font(compact ? .caption.weight(.semibold) : .headline)
|
||||||
.foregroundStyle(Self.color(for: result.status))
|
.foregroundStyle(Self.color(for: result.status))
|
||||||
.padding(.horizontal, compact ? 8 : 12)
|
.padding(.horizontal, compact ? 8 : 12)
|
||||||
.padding(.vertical, compact ? 4 : 7)
|
.padding(.vertical, compact ? 4 : 7)
|
||||||
.background(Capsule().fill(Self.color(for: result.status).opacity(0.15)))
|
.background(Capsule().fill(Self.color(for: result.status).opacity(0.15)))
|
||||||
.accessibilityElement(children: .combine)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Verdict colour: green save, red worse off, grey break even, blue
|
/// Verdict colour: green save, red worse off, grey break even, blue
|
||||||
|
|||||||
Reference in New Issue
Block a user