diff --git a/app/metrics.yaml b/app/metrics.yaml index c4264aa84..818cf629d 100644 --- a/app/metrics.yaml +++ b/app/metrics.yaml @@ -447,6 +447,56 @@ events: expires: 113 onboarding: + syn_cfr_shown: + type: event + description: | + The Sync Onboarding CFR was shown to the user + bugs: + - https://github.com/mozilla-mobile/fenix/issues/26489 + data_reviews: + - https://github.com/mozilla-mobile/fenix/pull/26507 + data_sensitivity: + - interaction + notification_emails: + - android-probes@mozilla.com + expires: 119 + metadata: + tags: + - Onboarding + sync_cfr_implicit_dismissal: + type: event + description: | + The Sync Onboarding CFR was dismissed by the user by interacting + with the outside of the popup. + bugs: + - https://github.com/mozilla-mobile/fenix/issues/26489 + data_reviews: + - https://github.com/mozilla-mobile/fenix/pull/26507 + data_sensitivity: + - interaction + notification_emails: + - android-probes@mozilla.com + expires: 119 + metadata: + tags: + - Onboarding + sync_cfr_explicit_dismissal: + type: event + description: | + The Sync Onboarding CFR was dismissed by the user by clicking on + the "X" button to close the popup. + bugs: + - https://github.com/mozilla-mobile/fenix/issues/26489 + data_reviews: + - https://github.com/mozilla-mobile/fenix/pull/26507 + data_sensitivity: + - interaction + notification_emails: + - android-probes@mozilla.com + expires: 119 + metadata: + tags: + - Onboarding fxa_auto_signin: type: event description: diff --git a/app/src/main/java/org/mozilla/fenix/home/sessioncontrol/SessionControlView.kt b/app/src/main/java/org/mozilla/fenix/home/sessioncontrol/SessionControlView.kt index 17d4e172a..89839a790 100644 --- a/app/src/main/java/org/mozilla/fenix/home/sessioncontrol/SessionControlView.kt +++ b/app/src/main/java/org/mozilla/fenix/home/sessioncontrol/SessionControlView.kt @@ -23,6 +23,7 @@ import org.mozilla.fenix.home.OnboardingState import org.mozilla.fenix.home.recentbookmarks.RecentBookmark import org.mozilla.fenix.home.recentvisits.RecentlyVisitedItem import org.mozilla.fenix.onboarding.JumpBackInCFRDialog +import org.mozilla.fenix.onboarding.SyncCFRPresenter import org.mozilla.fenix.utils.Settings // This method got a little complex with the addition of the tab tray feature flag @@ -198,6 +199,14 @@ class SessionControlView( super.onLayoutCompleted(state) JumpBackInCFRDialog(view).showIfNeeded() + + if (context.settings().showSyncCFR) { + SyncCFRPresenter( + context = context, + recyclerView = view, + ).showSyncCFR() + context.settings().showSyncCFR = false + } } } } diff --git a/app/src/main/java/org/mozilla/fenix/onboarding/SyncCFRPresenter.kt b/app/src/main/java/org/mozilla/fenix/onboarding/SyncCFRPresenter.kt new file mode 100644 index 000000000..0f27a9041 --- /dev/null +++ b/app/src/main/java/org/mozilla/fenix/onboarding/SyncCFRPresenter.kt @@ -0,0 +1,75 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +package org.mozilla.fenix.onboarding + +import android.content.Context +import android.view.View +import androidx.compose.ui.unit.dp +import androidx.recyclerview.widget.RecyclerView +import mozilla.components.service.glean.private.NoExtras +import org.mozilla.fenix.GleanMetrics.Onboarding +import org.mozilla.fenix.R +import org.mozilla.fenix.compose.cfr.CFRPopup +import org.mozilla.fenix.compose.cfr.CFRPopupProperties +import org.mozilla.fenix.home.recentsyncedtabs.view.RecentSyncedTabViewHolder + +/** + * Vertical padding needed to improve the visual alignment of the popup and respect the UX design. + */ +private const val CFR_TO_ANCHOR_VERTICAL_PADDING = -16 + +/** + * Delegate for handling sync onboarding CFR. + * + * @param [Context] used for various Android interactions. + * @param [RecyclerView] will serve as anchor for the sync CFR. + */ +class SyncCFRPresenter( + private val context: Context, + private val recyclerView: RecyclerView, +) { + + private var syncCFR: CFRPopup? = null + + /** + * Check if [view] is available to show sync CFR. + */ + fun showSyncCFR() { + findSyncTabsView()?.let { + CFRPopup( + text = context.getString(R.string.sync_cfr_message), + anchor = it, + properties = CFRPopupProperties( + indicatorDirection = CFRPopup.IndicatorDirection.DOWN, + popupVerticalOffset = CFR_TO_ANCHOR_VERTICAL_PADDING.dp, + ), + onDismiss = { + when (it) { + true -> Onboarding.syncCfrExplicitDismissal.record(NoExtras()) + false -> Onboarding.syncCfrImplicitDismissal.record(NoExtras()) + } + } + ) { + }.apply { + syncCFR = this + show() + Onboarding.synCfrShown.record(NoExtras()) + } + } + } + + private fun findSyncTabsView(): View? { + val count = recyclerView.adapter?.itemCount ?: return null + + for (index in count downTo 0) { + val viewHolder = recyclerView.findViewHolderForAdapterPosition(index) + if (viewHolder is RecentSyncedTabViewHolder) { + return viewHolder.composeView + } + } + + return null + } +} diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 99ab2a476..f8bc7c04a 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -281,6 +281,8 @@ Sign in Skip + + Your tabs are syncing! Pick up where you left off on your other device.