Add first-launch onboarding with location + notification permission prompts

- OnboardingView: 4-page flow (welcome + features, location, notifications, done)
- Triggers system prompts in-context via OnboardingPermissionPrompter
- Shown at initial launch only (FuelStore.onboardingCompleted flag, app-group defaults)
- Test hook: 'Show onboarding (testing)' button at bottom of Alerts tab
This commit is contained in:
FuelBoard Contributor
2026-08-12 07:10:54 +01:00
parent 2ed18d81a3
commit fb79cf0788
4 changed files with 422 additions and 2 deletions
+22 -2
View File
@@ -18,6 +18,7 @@ struct ContentView: View {
}()
@State private var isLoading = false
@State private var statusMessage = ""
@State private var showOnboarding = false
@State private var locationManager = LocationManager()
@StateObject private var monitor = ProximityMonitor()
@@ -132,18 +133,37 @@ struct ContentView: View {
enabled: $alertsEnabled,
radius: $alertsRadius,
monitoredCount: monitor.monitoredStationIDs.count,
lastAlert: monitor.lastAlert
lastAlert: monitor.lastAlert,
onShowOnboarding: { showOnboarding = true }
)
.tabItem { Label("Alerts", systemImage: "bell.fill") }
}
.fullScreenCover(isPresented: $showOnboarding) {
OnboardingView {
showOnboarding = false
}
}
.onAppear {
locationManager.startForegroundTracking()
// Onboarding runs first on a fresh install it owns the initial
// permission prompts. Location tracking starts once it's done.
if FuelStore.loadHasCompletedOnboarding() {
locationManager.startForegroundTracking()
} else {
showOnboarding = true
}
monitor.update(stations: stations, favourites: refreshedFavourites,
fuel: selectedFuel, radiusKM: alertsRadius)
monitor.setEnabled(alertsEnabled)
// Refresh only when the cache is stale (twice-a-day policy).
Task { await refresh() }
}
.onChange(of: showOnboarding) { _, showing in
// After onboarding finishes (or the test re-run is dismissed),
// begin foreground location tracking if permission allows.
if !showing, FuelStore.loadHasCompletedOnboarding() {
locationManager.startForegroundTracking()
}
}
.onChange(of: scenePhase) { _, newPhase in
if newPhase == .active {
locationManager.startForegroundTracking()