Widget tap relay via fuelboard:// scheme; full station names; no check-again
- WidgetKit widgets can only open their containing app — the Link URL is delivered to FuelBoard via onOpenURL, never opened directly in Maps. The widget now links to a registered fuelboard://directions?lat=&lng= URL, and FuelBoardApp forwards it to native maps://?daddr= directions. (http://maps.apple.com and raw maps:// both silently dropped in-app.) - Widget rows (small + medium) now show the full station name (station.name) instead of just the brand. - Onboarding network page: removed the 'Check again' secondary screen after the Local Network prompt — Open Settings remains the only retry path. 35 tests pass.
This commit is contained in:
@@ -16,6 +16,17 @@
|
|||||||
<string>$(PRODUCT_NAME)</string>
|
<string>$(PRODUCT_NAME)</string>
|
||||||
<key>CFBundlePackageType</key>
|
<key>CFBundlePackageType</key>
|
||||||
<string>$(PRODUCT_BUNDLE_PACKAGE_TYPE)</string>
|
<string>$(PRODUCT_BUNDLE_PACKAGE_TYPE)</string>
|
||||||
|
<key>CFBundleURLTypes</key>
|
||||||
|
<array>
|
||||||
|
<dict>
|
||||||
|
<key>CFBundleURLName</key>
|
||||||
|
<string>com.apt.fuelboard</string>
|
||||||
|
<key>CFBundleURLSchemes</key>
|
||||||
|
<array>
|
||||||
|
<string>fuelboard</string>
|
||||||
|
</array>
|
||||||
|
</dict>
|
||||||
|
</array>
|
||||||
<key>CFBundleShortVersionString</key>
|
<key>CFBundleShortVersionString</key>
|
||||||
<string>1.0</string>
|
<string>1.0</string>
|
||||||
<key>CFBundleVersion</key>
|
<key>CFBundleVersion</key>
|
||||||
|
|||||||
@@ -5,6 +5,22 @@ struct FuelBoardApp: App {
|
|||||||
var body: some Scene {
|
var body: some Scene {
|
||||||
WindowGroup {
|
WindowGroup {
|
||||||
ContentView()
|
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)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -297,11 +297,6 @@ struct OnboardingView: View {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
.disabled(prompter.dataLoading)
|
.disabled(prompter.dataLoading)
|
||||||
if prompter.dataDenied {
|
|
||||||
Button("Check again") { prompter.requestDataAccess() }
|
|
||||||
.font(.subheadline)
|
|
||||||
.foregroundStyle(.secondary)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
primaryButton("Start Using FuelBoard") { finish() }
|
primaryButton("Start Using FuelBoard") { finish() }
|
||||||
|
|||||||
@@ -224,7 +224,7 @@ struct FuelPriceWidgetView: View {
|
|||||||
.font(.caption2)
|
.font(.caption2)
|
||||||
.foregroundStyle(.secondary)
|
.foregroundStyle(.secondary)
|
||||||
}
|
}
|
||||||
Text(station.brand.sanitizedStationTitle)
|
Text(station.name)
|
||||||
.font(.headline)
|
.font(.headline)
|
||||||
.lineLimit(1)
|
.lineLimit(1)
|
||||||
if let price = station.prices[entry.fuel] {
|
if let price = station.prices[entry.fuel] {
|
||||||
@@ -243,7 +243,7 @@ struct FuelPriceWidgetView: View {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
.frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .leading)
|
.frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .leading)
|
||||||
.widgetURL(station.mapsDirectionsURL)
|
.widgetURL(station.widgetDirectionsURL)
|
||||||
}
|
}
|
||||||
|
|
||||||
private var stationList: some View {
|
private var stationList: some View {
|
||||||
@@ -261,9 +261,9 @@ struct FuelPriceWidgetView: View {
|
|||||||
.foregroundStyle(.secondary)
|
.foregroundStyle(.secondary)
|
||||||
}
|
}
|
||||||
ForEach(entry.stations.prefix(3)) { station in
|
ForEach(entry.stations.prefix(3)) { station in
|
||||||
Link(destination: station.mapsDirectionsURL ?? URL(string: "maps://")!) {
|
Link(destination: station.widgetDirectionsURL ?? URL(string: "fuelboard://")!) {
|
||||||
HStack(spacing: 8) {
|
HStack(spacing: 8) {
|
||||||
Text(station.brand.sanitizedStationTitle)
|
Text(station.name)
|
||||||
.font(.caption.weight(.semibold))
|
.font(.caption.weight(.semibold))
|
||||||
.lineLimit(1)
|
.lineLimit(1)
|
||||||
if let location = entry.location {
|
if let location = entry.location {
|
||||||
|
|||||||
+11
-4
@@ -153,14 +153,21 @@ struct FuelStation: Identifiable, Codable, Equatable {
|
|||||||
return r * 2 * atan2(sqrt(a), sqrt(1 - a))
|
return r * 2 * atan2(sqrt(a), sqrt(1 - a))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Apple Maps directions URL — used by the widget tap and app rows.
|
/// Apple Maps directions URL — used by the app's rows/notifications, which
|
||||||
/// Uses the native `maps://` scheme (not `http://maps.apple.com`), which
|
/// open it directly via `UIApplication.shared.open`.
|
||||||
/// opens Maps directly; universal-link http URLs fall back to opening the
|
|
||||||
/// containing app when tapped from a widget.
|
|
||||||
var mapsDirectionsURL: URL? {
|
var mapsDirectionsURL: URL? {
|
||||||
URL(string: "maps://?daddr=\(lat),\(lng)&t=d")
|
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.
|
/// Name of the bundled brand logo asset, or nil if unknown.
|
||||||
/// Normalizes messy raw brand strings ("SHELL LEEDS ROAD" → "shell").
|
/// Normalizes messy raw brand strings ("SHELL LEEDS ROAD" → "shell").
|
||||||
var brandImageName: String? {
|
var brandImageName: String? {
|
||||||
|
|||||||
Reference in New Issue
Block a user