[2026-07-10] eagle: work/projects/ios-subscription-day7-promo-pr.md
This commit is contained in:
@@ -11,6 +11,7 @@ CC: N/A
|
||||
- `SubscriptionPromoExistingUserCoordinator` implements a softer gate: eligible when onboarding is complete **or** no contextual onboarding dialog is currently visible on screen (`isShowingContextualOnboardingDialog`) — allowing single-tab users who never reached the fire/EOJ flow to see the launch promo, while preventing the promo from appearing on top of active onboarding dialogs on cold launch.
|
||||
- All other providers (`WinBackOffer`, `DefaultBrowser`, `NewAddressBarPicker`, `WhatsNew`) use the default implementation, which returns the passed `isOnboardingComplete` value — preserving their previous behaviour without each owning an `onboardingStatusProvider` dependency.
|
||||
- Inserts `subscriptionPromoExistingUser` at priority 3 in the modal prompt queue (after reinstaller promo, before address bar picker).
|
||||
- Adds `SubscriptionPromoUITests` covering promo appearance after onboarding and suppression while contextual onboarding dialogs are active.
|
||||
|
||||
### Testing Steps
|
||||
|
||||
@@ -37,7 +38,7 @@ Contextual onboarding then starts on the browser. The *"Ready to get started? Tr
|
||||
|
||||
2. **Select a search chip; "Try Visiting a Site" appears; hide app, restore; stop app, cold launch**
|
||||
On *"Ready to get started? Try a search!"* select a search suggestion chip → SERP loads → *"That's DuckDuckGo Search!"* dialog → tap **"Got it!"** → *"Next, try visiting a site!"* appears → press home button → switch back to DuckDuckGo → **No promo sheet** (foregrounding; `isShowingContextualOnboardingDialog = true`) → force-quit → wait ≥1 min → cold launch
|
||||
→ **Day-7 promo sheet appears** (`tryVisitASiteShown` already persisted; dialog won't reappear; `isStillOnboarding() = false`, `isShowingContextualOnboardingDialog = false` on fresh launch)
|
||||
→ **Day-7 promo sheet appears** (`tryVisitASiteShown` already persisted; dialog won't reappear; `isShowingContextualOnboardingDialog = false` on fresh launch)
|
||||
|
||||
3. **"Try Visiting a Site" dialog visible; tap X; stop app; cold launch**
|
||||
On *"Next, try visiting a site!"* tap the **X** (skip/close) → confirm skip if prompted → force-quit → wait ≥1 min → cold launch
|
||||
@@ -168,7 +169,7 @@ Contextual onboarding starts with *"Ready to get started? Try a search or AI cha
|
||||
|
||||
#### What could go wrong?
|
||||
|
||||
- **Promo appears during active contextual onboarding** — would create two overlapping subscription-related sheets. Mitigated by the `isEligibleToPresent` gate checking `isStillOnboarding() || isShowingContextualOnboardingDialog`; covered by testing flows #5, #9, #12.
|
||||
- **Promo appears during active contextual onboarding** — would create two overlapping subscription-related sheets. Mitigated by the `isEligibleToPresent` gate checking `isShowingContextualOnboardingDialog`; covered by testing flows #5, #9, #12.
|
||||
- **Promo shown twice** — duplicate impression if `subscriptionPromotionDialogSeen` is not persisted correctly. Mitigated by setting the flag in `markLaunchPromptPresented()` before presenting; covered by flows #14–16.
|
||||
- **Other modal prompts regressed by gate refactor** — existing providers could break if the per-provider default gate behaves differently from the removed global gate. The default `isEligibleToPresent` returns `isOnboardingComplete`, which is functionally equivalent; covered by flow #23.
|
||||
- **Cooldown bypassed by date manipulation** — low risk for production; the debug override (1-min) must be reverted before shipping.
|
||||
@@ -184,6 +185,6 @@ Contextual onboarding starts with *"Ready to get started? Try a search or AI cha
|
||||
|
||||
### Notes to Reviewer
|
||||
|
||||
- The `isEligibleToPresent(isOnboardingComplete:)` protocol method replaces the old global service-level `hasSeenOnboarding` guard. The net behaviour for existing providers is identical — they now check onboarding state per-provider via the default implementation rather than a single service gate. The only change in observable behaviour is that `SubscriptionPromoExistingUserCoordinator` can present to users who haven't fully completed contextual onboarding, as long as neither `isStillOnboarding()` nor `isShowingContextualOnboardingDialog` is true.
|
||||
- The `isEligibleToPresent(isOnboardingComplete:)` protocol method replaces the old global service-level `hasSeenOnboarding` guard. The net behaviour for existing providers is identical — they now check onboarding state per-provider via the default implementation rather than a single service gate. The only change in observable behaviour is that `SubscriptionPromoExistingUserCoordinator` can present to users who haven't fully completed contextual onboarding, as long as `isShowingContextualOnboardingDialog` is false.
|
||||
- `hasAppStoreProductsAvailable` check is commented out in `shouldPresentLaunchPrompt()` — intentional for the current testing phase; evaluate whether to re-enable before rollout.
|
||||
- The reinstaller promo coordinator (`SubscriptionPromoCoordinator`) and the existing-user coordinator share `SubscriptionPromoCoordinating` and `SubscriptionPromoModalPromptProvider`, keeping the sheet UI consistent.
|
||||
|
||||
Reference in New Issue
Block a user