import SwiftUI import MapKit import UIKit /// Detail sheet for a tapped station (when Settings → Tap station = More info). /// Shows a small map preview, the address, distance from the current location, /// and a Directions button that opens Apple Maps — the same destination a direct /// tap would have opened. The station name lives in the sheet header, not in a /// row. struct StationDetailView: View { let station: FuelStation let location: Coordinate? let distanceUnit: DistanceUnit var fuelSavings: FuelSavingsAvailability? = nil var fuelSavingsAmount: FuelSavingsFillAmount = FuelSavingsSettings.defaultPreferredAmount var savingsBaselineStationName: String? = nil /// Whether this station is starred for the fuel currently being viewed, and /// the toggle that flips it. Passed from the list that opened the sheet, so /// the star here and the star on the row are the same fuel-scoped /// favourite and cannot drift apart. var isFavourite: Bool = false var onToggleFavourite: (() -> Void)? = nil @Environment(\.dismiss) private var dismiss @State private var showingReportIssueConfirmation = false private let reportIssueURL = URL(string: "https://www.gov.uk/guidance/report-an-error-in-fuel-prices-or-forecourt-details")! private var stationCoordinate: CLLocationCoordinate2D { CLLocationCoordinate2D(latitude: station.lat, longitude: station.lng) } var body: some View { NavigationStack { List { Section { Map(position: .constant(.region(MKCoordinateRegion( center: stationCoordinate, span: MKCoordinateSpan(latitudeDelta: 0.02, longitudeDelta: 0.02) )))) { Marker(station.name, coordinate: stationCoordinate) .tint(.red) } .frame(height: 180) .clipShape(RoundedRectangle(cornerRadius: 12)) .allowsHitTesting(false) .listRowInsets(EdgeInsets()) } Section { // The station name is NOT repeated here: the sheet header // (navigationTitle, inline) already shows it, and the address // line below has any leading repeat of the name stripped, so // a "Name" row only said it twice. LabeledContent("Address", value: StationAddressLine.display(address: station.address, postcode: station.postcode, name: station.name)) if let location { let km = FuelStore.displayDistanceKM( station: station, userLat: location.lat, userLng: location.lng ) LabeledContent("Distance", value: distanceUnit.format(km)) .monospacedDigit() } ForEach(StationNotice.notices(for: station)) { notice in Label(notice.title, systemImage: notice.symbolName) .font(.subheadline.weight(.semibold)) .foregroundStyle(.orange) .padding(.horizontal, 10) .padding(.vertical, 6) .background(Capsule().fill(Color.orange.opacity(0.14))) } } // Only shown while Fuel Savings backs it. `fuelSavings` is nil // when the feature is off — `savingsLookup` returns nil when it // is not configured — so the heading cannot be left dangling // over an empty section. if let fuelSavings { Section { FuelSavingsSummaryView( availability: fuelSavings, amount: fuelSavingsAmount, baselineStationName: savingsBaselineStationName, distanceUnit: distanceUnit ) } header: { Text("Best Value") } } Section { Button { if let url = station.mapsDirectionsURL { UIApplication.shared.open(url) } } label: { Label("Directions", systemImage: "arrow.triangle.turn.up.right.diamond.fill") } Button(role: .destructive) { showingReportIssueConfirmation = true } label: { Label("Report issue", systemImage: "exclamationmark.bubble.fill") } } } .navigationTitle(station.name) .navigationBarTitleDisplayMode(.inline) .alert("Report an error?", isPresented: $showingReportIssueConfirmation) { Button("Cancel", role: .cancel) { } Button("Report") { UIApplication.shared.open(reportIssueURL) } } message: { Text("Are you sure you want to report an error in fuel prices or forecourt details? This will open in your chosen browser.") } .toolbar { ToolbarItem(placement: .cancellationAction) { Button("Done") { dismiss() } } ToolbarItem(placement: .confirmationAction) { Button { onToggleFavourite?() } label: { Image(systemName: isFavourite ? "star.fill" : "star") } .tint(isFavourite ? Color.yellow : nil) .disabled(onToggleFavourite == nil) .accessibilityLabel( isFavourite ? String(localized: "Remove from favourites", comment: "Unstar a station from the More info sheet") : String(localized: "Add to favourites", comment: "Star a station from the More info sheet") ) } } } } }