diff --git a/Config/App-Info.plist b/Config/App-Info.plist index a5269bf..b0afc51 100644 --- a/Config/App-Info.plist +++ b/Config/App-Info.plist @@ -16,6 +16,17 @@ $(PRODUCT_NAME) CFBundlePackageType $(PRODUCT_BUNDLE_PACKAGE_TYPE) + CFBundleURLTypes + + + CFBundleURLName + com.apt.fuelboard + CFBundleURLSchemes + + fuelboard + + + CFBundleShortVersionString 1.0 CFBundleVersion diff --git a/FuelBoard/FuelBoardApp.swift b/FuelBoard/FuelBoardApp.swift index d635841..a11e230 100644 --- a/FuelBoard/FuelBoardApp.swift +++ b/FuelBoard/FuelBoardApp.swift @@ -5,6 +5,22 @@ struct FuelBoardApp: App { var body: some Scene { WindowGroup { ContentView() + .onOpenURL(perform: handleOpenURL) } } + + /// WidgetKit widgets can only open their containing app, so a widget tap + /// delivers a `fuelboard://directions?lat=..&lng=..` URL here instead of + /// opening Apple Maps itself. Forward it to the native Maps directions + /// URL (`maps://?daddr=`), which is what the app's own rows use. + private func handleOpenURL(_ url: URL) { + guard url.scheme == "fuelboard", + url.host == "directions", + let components = URLComponents(url: url, resolvingAgainstBaseURL: false), + let lat = components.queryItems?.first(where: { $0.name == "lat" })?.value.flatMap(Double.init), + let lng = components.queryItems?.first(where: { $0.name == "lng" })?.value.flatMap(Double.init), + let mapsURL = URL(string: "maps://?daddr=\(lat),\(lng)&t=d") + else { return } + UIApplication.shared.open(mapsURL) + } } diff --git a/FuelBoard/OnboardingView.swift b/FuelBoard/OnboardingView.swift index 08afcab..7215724 100644 --- a/FuelBoard/OnboardingView.swift +++ b/FuelBoard/OnboardingView.swift @@ -297,11 +297,6 @@ struct OnboardingView: View { } } .disabled(prompter.dataLoading) - if prompter.dataDenied { - Button("Check again") { prompter.requestDataAccess() } - .font(.subheadline) - .foregroundStyle(.secondary) - } } default: primaryButton("Start Using FuelBoard") { finish() } diff --git a/FuelBoardWidgets/FuelPriceWidget.swift b/FuelBoardWidgets/FuelPriceWidget.swift index b7d0d59..36d4068 100644 --- a/FuelBoardWidgets/FuelPriceWidget.swift +++ b/FuelBoardWidgets/FuelPriceWidget.swift @@ -224,7 +224,7 @@ struct FuelPriceWidgetView: View { .font(.caption2) .foregroundStyle(.secondary) } - Text(station.brand.sanitizedStationTitle) + Text(station.name) .font(.headline) .lineLimit(1) if let price = station.prices[entry.fuel] { @@ -243,7 +243,7 @@ struct FuelPriceWidgetView: View { } } .frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .leading) - .widgetURL(station.mapsDirectionsURL) + .widgetURL(station.widgetDirectionsURL) } private var stationList: some View { @@ -261,9 +261,9 @@ struct FuelPriceWidgetView: View { .foregroundStyle(.secondary) } ForEach(entry.stations.prefix(3)) { station in - Link(destination: station.mapsDirectionsURL ?? URL(string: "maps://")!) { + Link(destination: station.widgetDirectionsURL ?? URL(string: "fuelboard://")!) { HStack(spacing: 8) { - Text(station.brand.sanitizedStationTitle) + Text(station.name) .font(.caption.weight(.semibold)) .lineLimit(1) if let location = entry.location { diff --git a/Shared/FuelStore.swift b/Shared/FuelStore.swift index 5345c05..3879ea4 100644 --- a/Shared/FuelStore.swift +++ b/Shared/FuelStore.swift @@ -153,14 +153,21 @@ struct FuelStation: Identifiable, Codable, Equatable { return r * 2 * atan2(sqrt(a), sqrt(1 - a)) } - /// Apple Maps directions URL — used by the widget tap and app rows. - /// Uses the native `maps://` scheme (not `http://maps.apple.com`), which - /// opens Maps directly; universal-link http URLs fall back to opening the - /// containing app when tapped from a widget. + /// Apple Maps directions URL — used by the app's rows/notifications, which + /// open it directly via `UIApplication.shared.open`. var mapsDirectionsURL: URL? { URL(string: "maps://?daddr=\(lat),\(lng)&t=d") } + /// Widget tap URL. WidgetKit widgets can ONLY open their containing app: + /// the system hands this URL to FuelBoard via `onOpenURL`, which then + /// forwards to Apple Maps. So the widget link uses our own registered + /// `fuelboard://` scheme rather than `maps://` (which would arrive in the + /// app and be silently dropped). + var widgetDirectionsURL: URL? { + URL(string: "fuelboard://directions?lat=\(lat)&lng=\(lng)") + } + /// Name of the bundled brand logo asset, or nil if unknown. /// Normalizes messy raw brand strings ("SHELL LEEDS ROAD" → "shell"). var brandImageName: String? {