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())
|
.font(.caption2.bold().monospacedDigit())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// NOTE: deliberately NO `.supplementalActivityFamilies([.small])`.
|
.supplementalActivityFamilies([.small])
|
||||||
// That modifier makes iOS eligible to render this activity in the
|
// Why `.small` is kept: it lets the SHARED body render a compact form
|
||||||
// narrow `.small` form on the iPhone/iPad Lock Screen, which is what
|
// in genuinely small slots (CarPlay small / Apple Watch smart stack)
|
||||||
// produced the squeezed, small-text card. Dropping it keeps the
|
// instead of falling back to the Dynamic Island compact closure —
|
||||||
// full-width Lock Screen card on iPhone/iPad; CarPlay still shows a
|
// which could NOT show the station distance the user wants on CarPlay.
|
||||||
// small form via the Dynamic Island compact closures below.
|
// 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 {
|
private struct FuelBoardLiveActivityView: View {
|
||||||
let context: ActivityViewContext<FuelBoardLiveActivityAttributes>
|
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 {
|
var body: some View {
|
||||||
Link(destination: context.state.mapsURL) {
|
Link(destination: context.state.mapsURL) {
|
||||||
// Always the full three-column card. The station caption is
|
ViewThatFits(in: .horizontal) {
|
||||||
// line-limited + scale-down + tail-truncated, so a LONG station
|
// rich FIRST — wins on the full-width iPhone/iPad Lock Screen.
|
||||||
// name truncates in place instead of inflating this view's ideal
|
// Its middle column is flexible + line-limited, so a LONG
|
||||||
// width and tricking ViewThatFits into falling back to the compact
|
// station name truncates in place and never inflates the ideal
|
||||||
// strip (that is exactly what made 5-mi / long-named activities
|
// width (which used to trick ViewThatFits into falling back to
|
||||||
// render small while 10-15-mi / short names stayed full).
|
// compact on iPhone).
|
||||||
//
|
richBody
|
||||||
// No ViewThatFits / compactBody: with `.supplementalActivityFamilies`
|
.frame(minWidth: richMinWidth)
|
||||||
// removed, this body is only ever handed Lock-Screen width, so the
|
// compact fallback — the small CarPlay / Watch smart-stack
|
||||||
// compact fallback was both dead weight and the cause of the bug.
|
// strip: fuel · price · station distance (no app name).
|
||||||
richBody
|
compactBody
|
||||||
|
.frame(maxWidth: compactMaxWidth)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -113,7 +125,31 @@ private struct FuelBoardLiveActivityView: View {
|
|||||||
.padding()
|
.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.
|
/// Dynamic Island expanded regions + compact trailing — price only.
|
||||||
|
|||||||
Reference in New Issue
Block a user