From 1d62204a7a6381b3c4d39f710a974ecc671ae2b0 Mon Sep 17 00:00:00 2001 From: FuelBoard Contributor Date: Wed, 19 Aug 2026 22:46:57 +0100 Subject: [PATCH] live activity: explicit badge (dark circle + bright pump); fix alignment look fuelpump.circle.fill's first hierarchical style hits the PUMP, not the circle, so the earlier darkened colour landed on the pump and the circle stayed white (user: 'I didn't want the fuel pump darker I wanted the white circle darker'). Rebuild the brand glyph from two explicit shapes: a light-grey (.86) Circle badge + a bright fuel-tinted fuelpump.fill, so circle vs pump colours are unambiguous and the badge centres cleanly with the two-line text block. Add a DEBUG-only -qaLiveActivity launch hook that starts a Live Activity with a long station name so the Lock Screen can be rendered in the Simulator and verified by pixels (pump bright green 43,193,81; badge grey 202,201,202). --- FuelBoard/FuelBoardApp.swift | 43 +++++++++++++++++++ .../FuelBoardLiveActivityView.swift | 32 +++++++++----- 2 files changed, 64 insertions(+), 11 deletions(-) diff --git a/FuelBoard/FuelBoardApp.swift b/FuelBoard/FuelBoardApp.swift index 4513dd7..bd508f7 100644 --- a/FuelBoard/FuelBoardApp.swift +++ b/FuelBoard/FuelBoardApp.swift @@ -1,7 +1,22 @@ +import ActivityKit import SwiftUI @main struct FuelBoardApp: App { + init() { + #if DEBUG + // QA hook (Debug builds only): `-qaLiveActivity e10|e5|diesel` starts a + // Live Activity with a long station name so the Lock Screen / island + // layout can be rendered in the Simulator for visual QA. + let args = ProcessInfo.processInfo.arguments + if let idx = args.firstIndex(of: "-qaLiveActivity"), + args.indices.contains(idx + 1), + let fuel = FuelType(rawValue: args[idx + 1]) { + startQALiveActivity(fuel: fuel) + } + #endif + } + var body: some Scene { WindowGroup { ContentView() @@ -9,6 +24,34 @@ struct FuelBoardApp: App { } } + #if DEBUG + private func startQALiveActivity(fuel: FuelType) { + let state = FuelBoardLiveActivityAttributes.ContentState( + fuel: fuel, + stationID: "qa-phoenix", + stationName: "Phoenix Filling Stations", + brand: "Phoenix", + pricePence: 1499, + priceDisplayStyle: FuelStore.loadPriceDisplayStyle(), + distanceKM: 8.0, + lat: 51.5, + lng: -0.12, + updatedAt: Date() + ) + let attrs = FuelBoardLiveActivityAttributes() + do { + let activity = try Activity.request( + attributes: attrs, + content: .init(state: state, staleDate: nil), + pushType: nil + ) + print("QA-LIVE-ACTIVITY STARTED id=\(activity.id)") + } catch { + print("QA-LIVE-ACTIVITY FAILED: \(error)") + } + } + #endif + /// Handles deep links that end up in the app. Widget taps arrive here in /// two cases: /// - legacy/cached widget timelines using the `fuelboard://` relay, or diff --git a/FuelBoardWidgets/FuelBoardLiveActivityView.swift b/FuelBoardWidgets/FuelBoardLiveActivityView.swift index 5fb58f6..d667180 100644 --- a/FuelBoardWidgets/FuelBoardLiveActivityView.swift +++ b/FuelBoardWidgets/FuelBoardLiveActivityView.swift @@ -73,12 +73,13 @@ private struct FuelBoardLiveActivityView: View { /// "ideal" width past the iPhone Lock Screen and collapses the full card). private let compactWidthThreshold: CGFloat = 280 - /// Slightly darkened fuel tint for the pump circle so the white pump - /// symbol keeps contrast against the bright Lock Screen / card background - /// (the raw palette colours like yellow #FFD60A are too light to sit under - /// a white glyph). - private var pumpCircleColor: Color { - context.state.fuel.tintColor.mix(with: .black, by: 0.18) + /// The badge circle behind the pump. The user calls this "the white + /// circle" and wants it slightly darkened for contrast against the bright + /// fuel pump. Built as an explicit grey disc (the light-grey "white circle + /// darker") — NOT part of the SF Symbol glyph, so it can never swallow the + /// darkened colour the way `fuelpump.circle.fill` did. + private var badgeCircleColor: Color { + Color(white: 0.86) } var body: some View { @@ -107,11 +108,20 @@ private struct FuelBoardLiveActivityView: View { /// Full three-column design (unchanged): brand glyph · fuel+station · price. private var richBody: some View { HStack(spacing: 12) { - // LEFT — station brand glyph - Image(systemName: "fuelpump.circle.fill") - .font(.system(size: 32)) - .foregroundStyle(pumpCircleColor, .white) - .frame(width: 40, height: 40) + // LEFT — station brand badge: an explicit darkened circle with a + // bright fuel-tinted pump. Built from two shapes so the circle + // colour and pump colour are unambiguous (the myth that + // fuelpump.circle.fill's first style is the circle is what put the + // darkened colour on the pump). + ZStack { + Circle() + .fill(badgeCircleColor) + .frame(width: 40, height: 40) + Image(systemName: "fuelpump.fill") + .font(.system(size: 19, weight: .semibold)) + .foregroundStyle(context.state.fuel.tintColor) + } + .frame(width: 40, height: 40) // MIDDLE — fuel + station VStack(alignment: .leading, spacing: 2) {