Onboarding: prompts fire on forward-leave of their page, not arrival
b634c06 fired on page arrival, so swiping stacked Location + Notifications
before a screen was read. Now each permission fires only when the user
ADVANCES PAST its page (swipe forward or Continue) — the screen has been
read by then. Forward-only (swiping back never fires), idempotent
(already-determined → status refresh), so replay and auto-advance stay
clean. Continue buttons are now pure navigation; denied paths unchanged.
This commit is contained in:
@@ -54,15 +54,17 @@ struct OnboardingView: View {
|
||||
.onChange(of: prompter.notificationsGranted) { _, granted in
|
||||
if granted, page == 2 { page = 3 }
|
||||
}
|
||||
// Fire the permission the moment its page comes into view — swiping
|
||||
// must trigger the prompt exactly like tapping Continue does. Both
|
||||
// request methods are idempotent: an already-determined permission
|
||||
// just refreshes the status (no duplicate system alert), so this is
|
||||
// safe for replay and for the auto-advance path.
|
||||
.onChange(of: page) { _, newPage in
|
||||
if newPage == 1 {
|
||||
// Fire each permission when the user LEAVES its page by advancing
|
||||
// forward (swipe or Continue) — by then the screen has been read.
|
||||
// Never on arrival: a fast swipe can't stack prompts before a page
|
||||
// is seen. Forward-only: swiping back never fires. Idempotent —
|
||||
// an already-determined permission just refreshes, so the
|
||||
// auto-advance path and replays stay clean (no duplicate alerts).
|
||||
.onChange(of: page) { oldPage, newPage in
|
||||
guard newPage > oldPage else { return }
|
||||
if oldPage == 1 {
|
||||
prompter.requestLocation()
|
||||
} else if newPage == 2 {
|
||||
} else if oldPage == 2 {
|
||||
prompter.requestNotifications()
|
||||
}
|
||||
}
|
||||
@@ -246,12 +248,10 @@ struct OnboardingView: View {
|
||||
) {
|
||||
if prompter.locationDenied {
|
||||
openSettings()
|
||||
} else if !prompter.locationGranted {
|
||||
// Safety net — the prompt already fired when this page
|
||||
// came into view (see onChange(of: page)); re-requesting
|
||||
// is a no-op unless the status is still undetermined.
|
||||
prompter.requestLocation()
|
||||
} else {
|
||||
// The prompt fires on LEAVING this page (onChange(of:
|
||||
// page), forward advance only) — the description is on
|
||||
// screen until the user moves on.
|
||||
page = 2
|
||||
}
|
||||
}
|
||||
@@ -259,13 +259,8 @@ struct OnboardingView: View {
|
||||
primaryButton(
|
||||
prompter.notificationsDenied ? "Continue without alerts" : (prompter.notificationsGranted ? "Continue" : "Allow Notifications")
|
||||
) {
|
||||
if prompter.notificationsDenied {
|
||||
// Prompt fires on leaving this page (same rule as Location).
|
||||
page = 3
|
||||
} else if !prompter.notificationsGranted {
|
||||
prompter.requestNotifications()
|
||||
} else {
|
||||
page = 3
|
||||
}
|
||||
}
|
||||
case 3:
|
||||
// No permission on this page — prices need none. Straight on.
|
||||
|
||||
Reference in New Issue
Block a user