Skip to content

Commit

Permalink
Onboarding end Dax dialog (#4603)
Browse files Browse the repository at this point in the history
Task/Issue URL:
https://app.asana.com/0/1201807753394693/1207353075657638/f

### Description
Add new onboarding _End_ dialog when the onboarding flow finishes
without the fire button animation

### Steps to test this PR

- [x] Fresh install
- [x] Go to the browser
- [x] Select a search suggestion
- [x] Tap on 'Got it!' button in the onboarding dialog
- [x] Select a site suggestion
- [x] Tap on 'Got It!' button in the onboarding dialog
- [x] Fire dialog should appear
- [x] Navigate away tapping on a site link or typing something in the
search bar
- [x] Check new End dialog will appear ('You've got this!')
- [x] Open a new tap (without dismissing the dialog)
- [x] Check End dialog won't appear in the new tab page

### UI changes
| Light  | Dark |
| ------ | ----- |

![Screenshot_20240605_164050_DuckDuckGo](https://github.com/duckduckgo/Android/assets/20798495/26064df3-9998-438b-bc01-8c32e8028481)|![Screenshot_20240605_164107_DuckDuckGo](https://github.com/duckduckgo/Android/assets/20798495/aa75c135-a30d-49ff-a7a4-eba7d886759d)|

---------

Co-authored-by: Josh Leibstein <[email protected]>
  • Loading branch information
nalcalag and joshliebe authored Jun 6, 2024
1 parent f74e465 commit df7968d
Show file tree
Hide file tree
Showing 6 changed files with 104 additions and 8 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -466,6 +466,29 @@ class CtaViewModelTest {
assertFalse(value is OnboardingDaxDialogCta)
}

@Test
fun whenRefreshOnboardingCtaAndCanShowDaxCtaEndOfJourneyButNotFireDialogShownThenOnboardingEndCtaDontShow() = runTest {
givenDaxOnboardingActive()
whenever(mockDismissedCtaDao.exists(CtaId.DAX_INTRO)).thenReturn(true)
whenever(mockDismissedCtaDao.exists(CtaId.DAX_DIALOG_TRACKERS_FOUND)).thenReturn(true)

val site = site(url = "http://www.cnn.com", trackerCount = 1)
val value = testee.refreshCta(coroutineRule.testDispatcher, isBrowserShowing = true, site = site)
assertFalse(value is OnboardingDaxDialogCta.DaxEndCta)
}

@Test
fun whenRefreshOnboardingCtaAndCanShowDaxCtaEndThenOnboardingEndCtaShown() = runTest {
givenDaxOnboardingActive()
whenever(mockDismissedCtaDao.exists(CtaId.DAX_INTRO)).thenReturn(true)
whenever(mockDismissedCtaDao.exists(CtaId.DAX_DIALOG_TRACKERS_FOUND)).thenReturn(true)
whenever(mockDismissedCtaDao.exists(CtaId.DAX_FIRE_BUTTON)).thenReturn(true)

val site = site(url = "http://www.cnn.com", trackerCount = 1)
val value = testee.refreshCta(coroutineRule.testDispatcher, isBrowserShowing = true, site = site)
assertTrue(value is OnboardingDaxDialogCta.DaxEndCta)
}

@Test
fun whenRefreshCtaOnHomeTabAndIntroCtaWasNotPreviouslyShownThenIntroCtaShown() = runTest {
givenDaxOnboardingActive()
Expand Down Expand Up @@ -687,6 +710,20 @@ class CtaViewModelTest {
assertFalse(value is DaxBubbleCta.DaxIntroVisitSiteOptionsCta)
}

@Test
fun whenCtaShownIfCtaIsNotMarkedAsReadOnShowThenCtaNotInsertedInDatabase() {
testee.onCtaShown(OnboardingDaxDialogCta.DaxSerpCta(mockOnboardingStore, mockAppInstallStore))

verify(mockDismissedCtaDao, never()).insert(DismissedCta(CtaId.DAX_DIALOG_SERP))
}

@Test
fun whenCtaShownIfCtaIsMarkedAsReadOnShowThenCtaInsertedInDatabase() {
testee.onCtaShown(OnboardingDaxDialogCta.DaxEndCta(mockOnboardingStore, mockAppInstallStore))

verify(mockDismissedCtaDao).insert(DismissedCta(CtaId.DAX_END))
}

private suspend fun givenDaxOnboardingActive() {
whenever(mockUserStageStore.getUserAppStage()).thenReturn(AppStage.DAX_ONBOARDING)
}
Expand Down
46 changes: 44 additions & 2 deletions app/src/main/java/com/duckduckgo/app/cta/ui/Cta.kt
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,9 @@ interface Cta {
}

interface OnboardingDaxCta {
val markAsReadOnShow: Boolean
get() = false

fun showOnboardingCta(
binding: FragmentBrowserTabBinding,
onPrimaryCtaClicked: () -> Unit,
Expand Down Expand Up @@ -113,6 +116,7 @@ sealed class OnboardingDaxDialogCta(
}

internal fun setOnboardingDialogView(
daxTitle: String? = null,
daxText: String,
buttonText: String?,
binding: FragmentBrowserTabBinding,
Expand All @@ -123,6 +127,10 @@ sealed class OnboardingDaxDialogCta(
daxDialog.root.show()
daxDialog.dialogTextCta.text = ""
daxDialog.hiddenTextCta.text = daxText.html(binding.root.context)
daxTitle?.let {
daxDialog.onboardingDialogTitle.show()
daxDialog.onboardingDialogTitle.text = daxTitle
} ?: daxDialog.onboardingDialogTitle.gone()
buttonText?.let {
daxDialog.primaryCta.show()
daxDialog.primaryCta.alpha = MIN_ALPHA
Expand Down Expand Up @@ -234,7 +242,6 @@ sealed class OnboardingDaxDialogCta(
onboardingStore,
appInstallStore,
) {

override fun showOnboardingCta(
binding: FragmentBrowserTabBinding,
onPrimaryCtaClicked: () -> Unit,
Expand Down Expand Up @@ -387,6 +394,38 @@ sealed class OnboardingDaxDialogCta(
}
}

class DaxEndCta(
override val onboardingStore: OnboardingStore,
override val appInstallStore: AppInstallStore,
) : OnboardingDaxDialogCta(
CtaId.DAX_END,
R.string.onboardingEndDaxDialogDescription,
R.string.daxDialogHighFive,
AppPixelName.ONBOARDING_DAX_CTA_SHOWN,
AppPixelName.ONBOARDING_DAX_CTA_OK_BUTTON,
null,
Pixel.PixelValues.DAX_ONBOARDING_END_CTA,
onboardingStore,
appInstallStore,
) {
override val markAsReadOnShow: Boolean = true

override fun showOnboardingCta(
binding: FragmentBrowserTabBinding,
onPrimaryCtaClicked: () -> Unit,
onTypingAnimationFinished: () -> Unit,
) {
val context = binding.root.context
setOnboardingDialogView(
daxTitle = context.getString(R.string.onboardingEndDaxDialogTitle),
daxText = description?.let { context.getString(it) }.orEmpty(),
buttonText = buttonText?.let { context.getString(it) },
binding = binding,
)
binding.includeOnboardingDaxDialog.primaryCta.setOnClickListener { onPrimaryCtaClicked.invoke() }
}
}

companion object {

const val SERP = "duckduckgo"
Expand Down Expand Up @@ -567,7 +606,10 @@ sealed class BubbleCta(
super.showCta(view)
val accessibilityDelegate: View.AccessibilityDelegate =
object : View.AccessibilityDelegate() {
override fun onInitializeAccessibilityNodeInfo(host: View, info: AccessibilityNodeInfo) {
override fun onInitializeAccessibilityNodeInfo(
host: View,
info: AccessibilityNodeInfo,
) {
super.onInitializeAccessibilityNodeInfo(host, info)
info.text = host.context?.getString(R.string.daxFavoritesOnboardingCtaContentDescription)
}
Expand Down
8 changes: 8 additions & 0 deletions app/src/main/java/com/duckduckgo/app/cta/ui/CtaViewModel.kt
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,9 @@ class CtaViewModel @Inject constructor(
pixel.fire(it, cta.pixelShownParameters())
}
}
if (cta is OnboardingDaxDialogCta && cta.markAsReadOnShow) {
dismissedCtaDao.insert(DismissedCta(cta.ctaId))
}
}

suspend fun registerDaxBubbleCtaDismissed(cta: Cta) {
Expand Down Expand Up @@ -300,6 +303,11 @@ class CtaViewModel @Inject constructor(
if (!isSerpUrl(it.url) && !daxDialogOtherShown() && !daxDialogTrackersFoundShown() && !daxDialogNetworkShown()) {
return OnboardingDaxDialogCta.DaxNoTrackersCta(onboardingStore, appInstallStore)
}

// End
if (canShowDaxCtaEndOfJourney() && daxDialogFireEducationShown()) {
return OnboardingDaxDialogCta.DaxEndCta(onboardingStore, appInstallStore)
}
}
return null
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,14 @@
android:layout_height="wrap_content"
android:orientation="vertical">

<com.duckduckgo.common.ui.view.text.DaxTextView
android:id="@+id/onboardingDialogTitle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/onboardingEndDaxDialogTitle"
android:layout_marginBottom="@dimen/keyline_1"
app:typography="h2" />

<FrameLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
Expand Down
12 changes: 6 additions & 6 deletions app/src/main/res/layout/pre_onboarding_comparison_chart.xml
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@
android:id="@+id/chromeLogo"
android:layout_width="wrap_content"
android:layout_height="55dp"
android:layout_marginEnd="@dimen/keyline_5"
android:layout_marginEnd="@dimen/keyline_2"
android:adjustViewBounds="true"
app:layout_constraintEnd_toStartOf="@id/ddgLogo"
app:layout_constraintTop_toTopOf="parent"
Expand Down Expand Up @@ -79,7 +79,7 @@
app:layout_constraintEnd_toStartOf="@id/chromeLogo"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/chromeLogo"
app:typography="body2" />
app:typography="body1" />

<com.duckduckgo.common.ui.view.divider.HorizontalDivider
android:layout_width="0dp"
Expand Down Expand Up @@ -118,7 +118,7 @@
app:layout_constraintEnd_toStartOf="@id/chromeLogo"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/feature1"
app:typography="body2" />
app:typography="body1" />

<com.duckduckgo.common.ui.view.divider.HorizontalDivider
android:layout_width="0dp"
Expand Down Expand Up @@ -157,7 +157,7 @@
app:layout_constraintEnd_toStartOf="@id/chromeLogo"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/feature2"
app:typography="body2" />
app:typography="body1" />

<com.duckduckgo.common.ui.view.divider.HorizontalDivider
android:layout_width="0dp"
Expand Down Expand Up @@ -196,7 +196,7 @@
app:layout_constraintEnd_toStartOf="@id/chromeLogo"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/feature3"
app:typography="body2" />
app:typography="body1" />

<com.duckduckgo.common.ui.view.divider.HorizontalDivider
android:layout_width="0dp"
Expand Down Expand Up @@ -235,6 +235,6 @@
app:layout_constraintEnd_toStartOf="@id/chromeLogo"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/feature4"
app:typography="body2" />
app:typography="body1" />

</androidx.constraintlayout.widget.ConstraintLayout>
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ interface Pixel {
const val DAX_INITIAL_CTA = "i"
const val DAX_INITIAL_VISIT_SITE_CTA = "visit_site"
const val DAX_END_CTA = "e"
const val DAX_ONBOARDING_END_CTA = "end"
const val DAX_SERP_CTA = "s"
const val DAX_NETWORK_CTA_1 = "n"
const val DAX_TRACKERS_BLOCKED_CTA = "t"
Expand Down

0 comments on commit df7968d

Please sign in to comment.