live activity: compact CarPlay strip shows fuel + price + station distance
Restore .supplementalActivityFamilies([.small]) + a ViewThatFits compact fallback so CarPlay's small slot renders our shared compact strip (fuel type, bold price, station · distance) instead of falling back to the Dynamic Island compact closure, which showed the app name and omitted the distance the user wants. Full iPhone/iPad card is preserved via the richMinWidth gate on richBody plus its flexible, truncating middle column (long names can no longer collapse it).
This commit is contained in:
@@ -49,12 +49,15 @@ struct FuelBoardLiveActivity: Widget {
|
||||
.font(.caption2.bold().monospacedDigit())
|
||||
}
|
||||
}
|
||||
// NOTE: deliberately NO `.supplementalActivityFamilies([.small])`.
|
||||
// That modifier makes iOS eligible to render this activity in the
|
||||
// narrow `.small` form on the iPhone/iPad Lock Screen, which is what
|
||||
// produced the squeezed, small-text card. Dropping it keeps the
|
||||
// full-width Lock Screen card on iPhone/iPad; CarPlay still shows a
|
||||
// small form via the Dynamic Island compact closures below.
|
||||
.supplementalActivityFamilies([.small])
|
||||
// Why `.small` is kept: it lets the SHARED body render a compact form
|
||||
// in genuinely small slots (CarPlay small / Apple Watch smart stack)
|
||||
// instead of falling back to the Dynamic Island compact closure —
|
||||
// which could NOT show the station distance the user wants on CarPlay.
|
||||
// The full-width iPhone/iPad card is protected by the `richMinWidth`
|
||||
// gate on `richBody` + its flexible, truncating middle column, so
|
||||
// iPhone/iPad still get the full card; only truly small space picks
|
||||
// the compact strip below.
|
||||
}
|
||||
}
|
||||
|
||||
@@ -62,19 +65,28 @@ struct FuelBoardLiveActivity: Widget {
|
||||
private struct FuelBoardLiveActivityView: View {
|
||||
let context: ActivityViewContext<FuelBoardLiveActivityAttributes>
|
||||
|
||||
/// Full card needs at least this much width; iPhone/iPad Lock Screen is
|
||||
/// always wider, so they always get it. Only genuinely small slots
|
||||
/// (CarPlay small / Watch smart stack) fall through to `compactBody`.
|
||||
private let richMinWidth: CGFloat = 280
|
||||
/// Cap the compact strip so a mid-width surface can't sneak it in.
|
||||
private let compactMaxWidth: CGFloat = 230
|
||||
|
||||
var body: some View {
|
||||
Link(destination: context.state.mapsURL) {
|
||||
// Always the full three-column card. The station caption is
|
||||
// line-limited + scale-down + tail-truncated, so a LONG station
|
||||
// name truncates in place instead of inflating this view's ideal
|
||||
// width and tricking ViewThatFits into falling back to the compact
|
||||
// strip (that is exactly what made 5-mi / long-named activities
|
||||
// render small while 10-15-mi / short names stayed full).
|
||||
//
|
||||
// No ViewThatFits / compactBody: with `.supplementalActivityFamilies`
|
||||
// removed, this body is only ever handed Lock-Screen width, so the
|
||||
// compact fallback was both dead weight and the cause of the bug.
|
||||
richBody
|
||||
ViewThatFits(in: .horizontal) {
|
||||
// rich FIRST — wins on the full-width iPhone/iPad Lock Screen.
|
||||
// Its middle column is flexible + line-limited, so a LONG
|
||||
// station name truncates in place and never inflates the ideal
|
||||
// width (which used to trick ViewThatFits into falling back to
|
||||
// compact on iPhone).
|
||||
richBody
|
||||
.frame(minWidth: richMinWidth)
|
||||
// compact fallback — the small CarPlay / Watch smart-stack
|
||||
// strip: fuel · price · station distance (no app name).
|
||||
compactBody
|
||||
.frame(maxWidth: compactMaxWidth)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -113,7 +125,31 @@ private struct FuelBoardLiveActivityView: View {
|
||||
.padding()
|
||||
}
|
||||
|
||||
// NOTE: `compactBody` was removed — always render `richBody` (see body).
|
||||
/// Minimal strip for small space (CarPlay small / Watch smart stack):
|
||||
/// fuel type + bold price on one line, station · distance below.
|
||||
/// Deliberately no app name and no "Tap for directions" — CarPlay is
|
||||
/// display-only, and the user's asks here are just fuel + price + distance.
|
||||
private var compactBody: some View {
|
||||
VStack(alignment: .leading, spacing: 3) {
|
||||
HStack(spacing: 5) {
|
||||
Text(context.state.fuel.displayName)
|
||||
.font(.caption.bold())
|
||||
.lineLimit(1)
|
||||
Spacer(minLength: 4)
|
||||
FuelStore.priceTextAttributed(context.state.pricePence,
|
||||
style: context.state.priceDisplayStyle,
|
||||
size: 15, weight: .bold)
|
||||
.lineLimit(1)
|
||||
}
|
||||
Text("\\(context.state.stationName) · \\(context.state.distanceText)")
|
||||
.font(.system(size: 9))
|
||||
.foregroundStyle(.secondary)
|
||||
.lineLimit(1)
|
||||
.minimumScaleFactor(0.7)
|
||||
.truncationMode(.tail)
|
||||
}
|
||||
.padding(8)
|
||||
}
|
||||
}
|
||||
|
||||
/// Dynamic Island expanded regions + compact trailing — price only.
|
||||
|
||||
Reference in New Issue
Block a user