App Store prep: privacy manifests, 1.0.1 (2), OGL attribution, UK empty state, screenshot harness
- PrivacyInfo.xcprivacy in app + widget targets (UserDefaults 1C8F.1; app declares Location linked + Diagnostics not-linked, no tracking) - Version bump 1.0.1 (2) in App + Widget plists - Settings → Data source footer: OGL attribution + 'refresh up to twice a day' - Stations empty state: friendly UK-only explainer + 'Browse all UK stations' - ContentView launch-arg harness (pattern of -showKeySheet): -skipOnboarding and -tab stations|favourites|alerts|settings for screenshot capture - APPSTORE.md updated (blockers struck, tasks done, yuzu-hub workflow) - BACKLOG.md hygiene: GitHub-first header, Trends merged note, offline-first-run DONE
This commit is contained in:
@@ -33,6 +33,7 @@ struct ContentView: View {
|
||||
@State private var isLoading = false
|
||||
@State private var statusMessage = ""
|
||||
@State private var showOnboarding = false
|
||||
@State private var selectedTab = 0
|
||||
@State private var locationManager = LocationManager()
|
||||
@StateObject private var monitor = ProximityMonitor()
|
||||
|
||||
@@ -137,12 +138,14 @@ struct ContentView: View {
|
||||
}
|
||||
|
||||
var body: some View {
|
||||
TabView {
|
||||
TabView(selection: $selectedTab) {
|
||||
stationsTab
|
||||
.tabItem { Label("Stations", systemImage: "fuelpump.fill") }
|
||||
.tag(0)
|
||||
|
||||
favouritesTab
|
||||
.tabItem { Label("Favourites", systemImage: "star.fill") }
|
||||
.tag(1)
|
||||
|
||||
AlertsView(
|
||||
enabled: $alertsEnabled,
|
||||
@@ -159,8 +162,10 @@ struct ContentView: View {
|
||||
lastAlert: monitor.lastAlert
|
||||
)
|
||||
.tabItem { Label("Alerts", systemImage: "bell.fill") }
|
||||
.tag(2)
|
||||
|
||||
settingsTab
|
||||
.tag(3)
|
||||
}
|
||||
.fullScreenCover(isPresented: $showOnboarding) {
|
||||
OnboardingView {
|
||||
@@ -171,11 +176,28 @@ struct ContentView: View {
|
||||
StationMapView(request: request)
|
||||
}
|
||||
.onAppear {
|
||||
// Launch-arg hooks for the screenshot/UI-test harness (same
|
||||
// pattern as StationsView's `-showKeySheet`): `-tab <name>`
|
||||
// opens the given tab; `-skipOnboarding` skips onboarding
|
||||
// without touching the stored flag.
|
||||
let args = ProcessInfo.processInfo.arguments
|
||||
if let i = args.firstIndex(of: "-tab"), i + 1 < args.count {
|
||||
switch args[i + 1] {
|
||||
case "favourites": selectedTab = 1
|
||||
case "alerts": selectedTab = 2
|
||||
case "settings": selectedTab = 3
|
||||
default: selectedTab = 0
|
||||
}
|
||||
}
|
||||
// Onboarding runs first on a fresh install — it owns the initial
|
||||
// permission prompts (location, notifications, and the data/local
|
||||
// network probe on the Data page). Location tracking and the first
|
||||
// network fetch start once it's done.
|
||||
if FuelStore.loadHasCompletedOnboarding() {
|
||||
// Launch-arg hook (UI-testing/screenshot harness, same pattern as
|
||||
// StationsView's `-showKeySheet`): skip onboarding without
|
||||
// touching the stored flag.
|
||||
if FuelStore.loadHasCompletedOnboarding()
|
||||
|| args.contains("-skipOnboarding") {
|
||||
locationManager.startForegroundTracking()
|
||||
// Geofences must follow the user even in the background:
|
||||
// wire the delegate hook (fires on every fix incl. background
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>NSPrivacyTracking</key>
|
||||
<false/>
|
||||
<key>NSPrivacyTrackingDomains</key>
|
||||
<array/>
|
||||
<key>NSPrivacyCollectedDataTypes</key>
|
||||
<array>
|
||||
<dict>
|
||||
<key>NSPrivacyCollectedDataType</key>
|
||||
<string>NSPrivacyCollectedDataTypeLocation</string>
|
||||
<key>NSPrivacyCollectedDataTypeLinked</key>
|
||||
<true/>
|
||||
<key>NSPrivacyCollectedDataTypeTracking</key>
|
||||
<false/>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>NSPrivacyCollectedDataType</key>
|
||||
<string>NSPrivacyCollectedDataTypeDiagnostics</string>
|
||||
<key>NSPrivacyCollectedDataTypeLinked</key>
|
||||
<false/>
|
||||
<key>NSPrivacyCollectedDataTypeTracking</key>
|
||||
<false/>
|
||||
</dict>
|
||||
</array>
|
||||
<key>NSPrivacyAccessedAPITypes</key>
|
||||
<array>
|
||||
<dict>
|
||||
<key>NSPrivacyAccessedAPIType</key>
|
||||
<string>NSPrivacyAccessedAPICategoryUserDefaults</string>
|
||||
<key>NSPrivacyAccessedAPITypeReasons</key>
|
||||
<array>
|
||||
<string>1C8F.1</string>
|
||||
</array>
|
||||
</dict>
|
||||
</array>
|
||||
</dict>
|
||||
</plist>
|
||||
@@ -229,7 +229,7 @@ struct SettingsView: View {
|
||||
} header: {
|
||||
Text("Data source")
|
||||
} footer: {
|
||||
Text("Connection shows whether prices come from the official Fuel Finder API or the CSV mirror. Data updated is the latest price change reported by the GOV.UK server itself.")
|
||||
Text("Connection shows whether prices come from the official Fuel Finder API or the CSV mirror. Data updated is the latest price change reported by the GOV.UK server itself. Prices use the UK Fuel Finder dataset (Open Government Licence) and refresh up to twice a day.")
|
||||
}
|
||||
|
||||
Section {
|
||||
|
||||
@@ -101,8 +101,20 @@ struct StationsView: View {
|
||||
Text("Fetching prices…")
|
||||
}
|
||||
} else if stations.isEmpty {
|
||||
Text("No \(selectedFuel.displayName) stations found.")
|
||||
.foregroundStyle(.secondary)
|
||||
let miles = distanceUnit.displayMiles(stationLimit)
|
||||
let unit = distanceUnit.label(for: Double(miles))
|
||||
VStack(alignment: .leading, spacing: 6) {
|
||||
Text("No \(selectedFuel.displayName) stations within \(miles) \(unit).")
|
||||
.foregroundStyle(.secondary)
|
||||
Text("FuelBoard covers England, Scotland and Wales — try Closest to browse every UK station.")
|
||||
.font(.caption)
|
||||
.foregroundStyle(.secondary)
|
||||
Button("Browse all UK stations") {
|
||||
sortMode = .closest
|
||||
}
|
||||
.font(.caption)
|
||||
}
|
||||
.padding(.vertical, 4)
|
||||
} else {
|
||||
ForEach(Array(stations.prefix(visibleCount)), id: \.id) { station in
|
||||
StationRow(
|
||||
|
||||
Reference in New Issue
Block a user