Add custom AI onboarding flow#8852
Conversation
|
bugbot run |
11550b6 to
7515b63
Compare
|
bugbot run |
3db4691 to
396d5c0
Compare
7515b63 to
242789f
Compare
396d5c0 to
d92688f
Compare
e66917e to
28a032e
Compare
|
bugbot run |
There was a problem hiding this comment.
✅ Bugbot reviewed your changes and found no new issues!
1 issue from previous review remains unresolved.
Comment @cursor review or bugbot run to trigger another review on this PR
Reviewed by Cursor Bugbot for commit 28a032e. Configure here.
28a032e to
3568305
Compare
0b3d336 to
aaa4c4f
Compare
3568305 to
b0f79ef
Compare
b0f79ef to
d583a98
Compare
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, have a team admin enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit d583a98. Configure here.
d583a98 to
b6762cd
Compare
b6762cd to
6e776a3
Compare
lmac012
left a comment
There was a problem hiding this comment.
For some reason, in the "skip flow" scenario, I always end up on a search tab (instead of a chat tab). Everything else worked as expected 👍
…stom-ai-onboarding/integrate-flow # Conflicts: # app/src/main/java/com/duckduckgo/app/browser/BrowserTabFragment.kt # app/src/main/java/com/duckduckgo/app/browser/BrowserTabViewModel.kt # app/src/main/java/com/duckduckgo/app/browser/commands/Command.kt # app/src/main/java/com/duckduckgo/app/cta/ui/CtaViewModel.kt # duckchat/duckchat-api/src/main/java/com/duckduckgo/duckchat/api/inputscreen/InputScreenActivityParams.kt # duckchat/duckchat-impl/src/main/java/com/duckduckgo/duckchat/impl/inputscreen/ui/InputScreenFragment.kt # duckchat/duckchat-impl/src/main/res/values/donottranslate.xml
I pushed minor tweaks to fix that yesterday, should've been on the version you tested. Either way, let's follow up separately if needed. Screen_recording_20260618_103435.mp4 |
…preconditions (#8914) Task/Issue URL: https://app.asana.com/1/137249556945/project/1208671518894266/task/1215753390280440?focus=true Tech Design URL (if applicable): ### Description Stacked on #8852. - **`CustomAiOnboardingStore` / `CustomAiOnboardingStoreImpl`** — a single component that is both the referrer parser plugin (writes the `onboarding=ai` flag on first launch) and the reader of the custom AI onboarding decision. The decision is made once and then frozen. `resolve()` waits for the install referrer to resolve, then returns true only when the referral flag is set and the `customDuckAiOnboarding`, `linearOnboardingOrchestrator` and `brandDesignUpdate` flags are all enabled, and persists that result. `isEnabled()` is a cheap read of the persisted decision and does not re-evaluate, so the run is chosen once at plan build time and every later reader (onboarding pages, end-of-journey CTAs) sees the same value rather than recomputing and possibly diverging from the chosen plan. The two roles are split across `CustomAiOnboardingResolver` (decide and write) and `CustomAiOnboardingStore` (read). - **`NewUserOnboardingPlanProvider`** — picks the custom AI plan from `resolve()`, arms the in-context Duck.ai demo up front, and gates the input screen preview and Duck.ai demo steps behind the `singleTabFireDialog` flag as this feature is required for these steps to be executed. ### Steps to test this PR See [this](https://app.asana.com/1/137249556945/project/1207137509162935/task/1207930443876573?focus=true) for context on how to test referrals. Also see [Figma](https://www.figma.com/design/5QvJbyUBbeonblsjViDIkf/Mobile-Onboarding-AI-First?node-id=173-50969&t=w51SVY4Lvfst0gyJ-1). - [x] Uninstall the app - [x] Apply this patch: ```diff diff --git a/app/build.gradle b/app/build.gradle index 541dfe1..5f5570725f 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -142,7 +142,7 @@ android { } buildTypes { debug { - applicationIdSuffix ".debug" +// applicationIdSuffix ".debug" pseudoLocalesEnabled false manifestPlaceholders = [ appIcon : "@mipmap/ic_launcher_blue", } ``` - [x] Change build type to `PlayDebug` - [x] Open this link on the test device: https://play.google.com/store/apps/details?id=com.duckduckgo.mobile.android&referrer=utm_campaign%3Dappnosupport-atb-appnosupport%26origin%3Dfunnel_appnosupport_website - [x] Install the app (remember to use `PlayDebug`) - [x] Verify you **don't see** the `+ Duck.ai` on the intro animation and a **regular onboarding flow** launches - [x] Uninstall the app - [x] Open this link on the test device: https://play.google.com/store/apps/details?id=com.duckduckgo.mobile.android&referrer=utm_campaign%3Dappnosupport-atb-appnosupport%26origin%3Dfunnel_appnosupport_website%26onboarding%3Dai - [x] Install the app (remember to use `PlayDebug`) - [x] Verify you **don't see** the `+ Duck.ai` on the intro animation and a **regular onboarding flow** launches. - [x] Additionally apply this diff: ```diff diff --git a/app/src/main/java/com/duckduckgo/app/onboarding/CustomDuckAiOnboardingFeature.kt b/app/src/main/java/com/duckduckgo/app/onboarding/CustomDuckAiOnboardingFeature.kt index 8ccb40d..d862242281 100644 --- a/app/src/main/java/com/duckduckgo/app/onboarding/CustomDuckAiOnboardingFeature.kt +++ b/app/src/main/java/com/duckduckgo/app/onboarding/CustomDuckAiOnboardingFeature.kt @@ -27,6 +27,6 @@ import com.duckduckgo.feature.toggles.api.Toggle.DefaultFeatureValue ) interface CustomDuckAiOnboardingFeature { - @Toggle.DefaultValue(DefaultFeatureValue.FALSE) + @Toggle.DefaultValue(DefaultFeatureValue.TRUE) fun self(): Toggle ``` - [x] Open this same link on the test device again: https://play.google.com/store/apps/details?id=com.duckduckgo.mobile.android&referrer=utm_campaign%3Dappnosupport-atb-appnosupport%26origin%3Dfunnel_appnosupport_website%26onboarding%3Dai - [x] Install the app (remember to use `PlayDebug`) - [x] Verify you **see** the `+ Duck.ai` on the intro animation and a **custom AI onboarding flow** launches <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Medium Risk** > Changes first-launch onboarding plan selection and install-referrer timing, with broad wiring in browser CTAs and the linear orchestrator; mitigated by persisted frozen decisions and extensive unit tests. > > **Overview** > Introduces **`CustomAiOnboardingStore`** as the single place for the Play Install Referrer `onboarding=ai` signal, a one-time **`resolve()`** decision (referrer + feature toggles), and a frozen **`isEnabled()`** read so the whole app agrees on whether the custom AI plan ran. Custom-AI helpers are **removed from `OnboardingStore`** (no more stub `isCustomAiOnboardingFlow()`). > > **`NewUserOnboardingPlanProvider`** now branches on **`customAiOnboardingResolver.resolve()`**, arms the in-context Duck.ai demo at plan build, and gates the input preview / Duck.ai demo steps on **`singleTabFireDialog`**. Finish/skip of the custom path arms a one-shot **open input on Duck.ai** via the new store. > > Browser and CTA layers switch to **`customAiOnboardingStore`** for chat-tab launch, Privacy Pro `featurePage=duckai`, deferred fire-button dismissal in the custom flow, and **custom copy** on brand-design end/subscription bubbles (via an explicit `isCustomAiOnboardingFlow` flag). **`BrandDesignUpdatePageViewModel`** loads that flag asynchronously before orchestrator UI. **`NewUserBrowserOnboardingViewModel`** no longer arms the demo locally—arming stays in the plan provider. > > Tests move from `OnboardingStoreImpl` to **`CustomAiOnboardingStoreImplTest`** and update mocks across CTA/browser/plan/orchestrator tests. > > <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit d5dbb20. Bugbot is set up for automated code reviews on this repo. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup> <!-- /CURSOR_SUMMARY -->

Task/Issue URL: https://app.asana.com/1/137249556945/project/1208671518894266/task/1215636599294592?focus=true
Tech Design URL (if applicable): https://app.asana.com/1/137249556945/project/481882893211075/task/1215717267206369?focus=true
Description
Integrates the custom-AI variant of new-user onboarding on top of the
LinearOnboardingOrchestrator.buildCustomAiPlan: intro (with Duck.ai animation) → notifications → welcome → AI comparison chart → chat-only input preview → in-browser Duck.ai demo → comparison chart → set-default → address bar.BrowserActivity-hosted onboarding step (NewUserBrowserActivityStep+NewUserBrowserOnboardingViewModel) so the orchestrator can hand offOnboardingActivity⇄BrowserActivityfor the live Duck.ai demo and return.DuckAiOnboardingDemoto arm the demo (mark the flow + silence the standard DAX CTAs) identically from the legacy onboarding-done path and the new step.showsStepIndicator), and enables custom-AI copy variants for the relevant dialogs. The default flow retains 3 indicated steps while the custom-AI flow has 4.Compatibility notes:
isCustomAiOnboardingFlow()is still a stub (returnsfalse) — the flow is dark until it is wired to a real flag.Steps to test this PR
Apply below diff:
Base flow
Skip flow
Additional checks
Onboarding<->BrowserActivity boundariesUI changes
Screen_recording_20260612_195956.mp4
Note
Medium Risk
Large, user-visible onboarding changes with Activity handoffs and input-mode behavior, but the custom path stays off until
isCustomAiOnboardingFlow()is wired beyond the current stub.Overview
When
isCustomAiOnboardingFlow()is true,buildRootPlanselects a custom AI plan (Duck.ai intro, AI comparison chart, chat-only input preview, in-browserduck_ai_demo, then browser comparison/default/address steps) instead of the default sequence. Sync restore is skipped on that path, and plan completion/skip dismisses the Duck.ai fire CTA and arms a one-shot signal so the next auto-launched input opens on the Duck.ai (chat) tab viainitialInputMode/LaunchInputScreen.launchOnChat.BrowserActivity now participates in onboarding through
NewUserBrowserOnboardingViewModel: it hands off toOnboardingActivity, opens Duck.ai for the demo, and reportsDuckAiFireCompletedafter the onboarding fire flow. Duck.ai launch logic is centralized inlaunchDuckAi.DuckAiOnboardingDemo.arm()replaces duplicated “set flow + dismiss DAX CTAs” logic for both legacy onboarding-done and the orchestrator demo step. Custom AI defers early dismissal of the Duck.ai fire onboarding CTA until the orchestrator finishes (kill/resume safety).The welcome UI gains plan-derived step indicators (
showsStepIndicator), custom-AI copy, chat-only preview (toggle hidden), and fresh-entry handling when returning from BrowserActivity (comparison chart fade-in vs morph).CustomDuckAiOnboardingFeature.introAnimation()is removed in favor of plan-driven intro.OnboardingStoreImplmoves toSharedPreferencesProvider.CtaViewModelcompletes DAX stage when the root linear plan completes.Reviewed by Cursor Bugbot for commit 8d8d0ce. Bugbot is set up for automated code reviews on this repo. Configure here.