tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

commit f6758121fd3acd273fe46a78857ac1a938f5dd35
parent 8e267f9570961ef588d8a98f9d48c63e4288cc3f
Author: t-p-white <towhite@mozilla.com>
Date:   Mon, 24 Nov 2025 17:19:33 +0000

Bug 2001968 - Part 1: Add the Notification and Set search widgets cards to the redesign flow. r=android-reviewers,mavduevskiy

Differential Revision: https://phabricator.services.mozilla.com/D273800

Diffstat:
Mmobile/android/fenix/app/onboarding.fml.yaml | 9+--------
Mmobile/android/fenix/app/src/main/java/org/mozilla/fenix/onboarding/OnboardingFragment.kt | 15+++++++++++++++
Amobile/android/fenix/app/src/main/java/org/mozilla/fenix/onboarding/notification/NotificationMainImage.kt | 43+++++++++++++++++++++++++++++++++++++++++++
Mmobile/android/fenix/app/src/main/java/org/mozilla/fenix/onboarding/redesign/view/OnboardingPageRedesign.kt | 50++++++++++++++++++++++++++++++++++++++++++++++++++
Mmobile/android/fenix/app/src/main/java/org/mozilla/fenix/onboarding/redesign/view/OnboardingScreenRedesign.kt | 33+++++++++++++++++++++++++++++++--
Amobile/android/fenix/app/src/main/java/org/mozilla/fenix/onboarding/widget/SetSearchWidgetMainImage.kt | 43+++++++++++++++++++++++++++++++++++++++++++
6 files changed, 183 insertions(+), 10 deletions(-)

diff --git a/mobile/android/fenix/app/onboarding.fml.yaml b/mobile/android/fenix/app/onboarding.fml.yaml @@ -335,7 +335,6 @@ features: secondary-button-label: onboarding_redesign_sync_negative_button toolbar-placement: - ordering: 17 title: onboarding_redesign_customize_toolbar_title body: onboarding_customize_toolbar_description image-res: ic_onboarding_customize_toolbar @@ -360,13 +359,7 @@ features: body-line-one-link-text: onboarding_marketing_redesign_learn_more body-line-two-text: onboarding_marketing_redesign_opt_out_checkbox - # Disable the defaults that are not included in the redesign - add-search-widget: - enabled: false - - notification-permission: - enabled: false - + # Disable the defaults that are not included in the redesign. theme-selection: enabled: false diff --git a/mobile/android/fenix/app/src/main/java/org/mozilla/fenix/onboarding/OnboardingFragment.kt b/mobile/android/fenix/app/src/main/java/org/mozilla/fenix/onboarding/OnboardingFragment.kt @@ -252,6 +252,21 @@ class OnboardingFragment : Fragment() { pagesToDisplay.sequencePosition(OnboardingPageUiData.Type.SYNC_SIGN_IN), ) }, + onNotificationPermissionButtonClick = { + requireComponents.notificationsDelegate.requestNotificationPermission() + telemetryRecorder.onNotificationPermissionClick( + sequenceId = pagesToDisplay.telemetrySequenceId(), + sequencePosition = + pagesToDisplay.sequencePosition(OnboardingPageUiData.Type.NOTIFICATION_PERMISSION), + ) + }, + onSkipNotificationClick = { + telemetryRecorder.onSkipTurnOnNotificationsClick( + sequenceId = pagesToDisplay.telemetrySequenceId(), + sequencePosition = + pagesToDisplay.sequencePosition(OnboardingPageUiData.Type.NOTIFICATION_PERMISSION), + ) + }, onAddFirefoxWidgetClick = { telemetryRecorder.onAddSearchWidgetClick( pagesToDisplay.telemetrySequenceId(), diff --git a/mobile/android/fenix/app/src/main/java/org/mozilla/fenix/onboarding/notification/NotificationMainImage.kt b/mobile/android/fenix/app/src/main/java/org/mozilla/fenix/onboarding/notification/NotificationMainImage.kt @@ -0,0 +1,43 @@ +/* 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.notification + +import androidx.compose.foundation.Image +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.height +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.tooling.preview.PreviewLightDark +import androidx.compose.ui.unit.dp +import org.mozilla.fenix.R +import org.mozilla.fenix.theme.FirefoxTheme + +private val IMAGE_HEIGHT = 200.dp + +/** + * Renders the main image for the "Notification" onboarding screen. + * + * **This is a non-interactive, static image view only**. + */ +@Composable +fun NotificationMainImage() { + Image( + painter = painterResource(R.drawable.ic_notification_permission), + contentDescription = null, // Decorative only + modifier = Modifier.height(IMAGE_HEIGHT), + ) +} + +@PreviewLightDark +@Composable +private fun NotificationMainImagePreview() { + FirefoxTheme { + Box(Modifier.background(FirefoxTheme.colors.layer1)) { + NotificationMainImage() + } + } +} diff --git a/mobile/android/fenix/app/src/main/java/org/mozilla/fenix/onboarding/redesign/view/OnboardingPageRedesign.kt b/mobile/android/fenix/app/src/main/java/org/mozilla/fenix/onboarding/redesign/view/OnboardingPageRedesign.kt @@ -28,10 +28,12 @@ import androidx.compose.ui.unit.dp import mozilla.components.compose.base.button.FilledButton import mozilla.components.compose.base.button.TextButton import org.mozilla.fenix.R +import org.mozilla.fenix.onboarding.notification.NotificationMainImage import org.mozilla.fenix.onboarding.redesign.view.defaultbrowser.SetToDefaultMainImage import org.mozilla.fenix.onboarding.redesign.view.sync.SyncMainImage import org.mozilla.fenix.onboarding.view.Action import org.mozilla.fenix.onboarding.view.OnboardingPageState +import org.mozilla.fenix.onboarding.widget.SetSearchWidgetMainImage import org.mozilla.fenix.theme.FirefoxTheme const val TITLE_TOP_SPACER_WEIGHT = 0.3f @@ -193,3 +195,51 @@ private fun OnboardingPageSyncPreview() { ) } } + +@PreviewLightDark +@Composable +private fun OnboardingPageNotificationPreview() { + FirefoxTheme { + OnboardingPageRedesign( + pageState = OnboardingPageState( + imageRes = R.drawable.ic_notification_permission, // Unused in the redesign. + title = stringResource(R.string.juno_onboarding_enable_notifications_title_nimbus_2), + description = stringResource(R.string.juno_onboarding_enable_notifications_description_nimbus_2), + primaryButton = Action( + text = stringResource(R.string.juno_onboarding_enable_notifications_positive_button), + onClick = {}, + ), + secondaryButton = Action( + text = stringResource(R.string.juno_onboarding_enable_notifications_negative_button), + onClick = {}, + ), + onRecordImpressionEvent = {}, + ), + mainImage = { NotificationMainImage() }, + ) + } +} + +@PreviewLightDark +@Composable +private fun OnboardingPageSearchWidgetPreview() { + FirefoxTheme { + OnboardingPageRedesign( + pageState = OnboardingPageState( + imageRes = R.drawable.ic_notification_permission, // Unused in the redesign. + title = stringResource(R.string.juno_onboarding_add_search_widget_title), + description = stringResource(R.string.juno_onboarding_add_search_widget_description), + primaryButton = Action( + text = stringResource(R.string.juno_onboarding_add_search_widget_positive_button), + onClick = {}, + ), + secondaryButton = Action( + text = stringResource(R.string.juno_onboarding_add_search_widget_negative_button), + onClick = {}, + ), + onRecordImpressionEvent = {}, + ), + mainImage = { SetSearchWidgetMainImage() }, + ) + } +} diff --git a/mobile/android/fenix/app/src/main/java/org/mozilla/fenix/onboarding/redesign/view/OnboardingScreenRedesign.kt b/mobile/android/fenix/app/src/main/java/org/mozilla/fenix/onboarding/redesign/view/OnboardingScreenRedesign.kt @@ -56,6 +56,7 @@ import org.mozilla.fenix.compose.LinkTextState import org.mozilla.fenix.compose.PagerIndicator import org.mozilla.fenix.ext.components import org.mozilla.fenix.onboarding.WidgetPinnedReceiver.WidgetPinnedState +import org.mozilla.fenix.onboarding.notification.NotificationMainImage import org.mozilla.fenix.onboarding.redesign.view.defaultbrowser.SetToDefaultMainImage import org.mozilla.fenix.onboarding.redesign.view.sync.SyncMainImage import org.mozilla.fenix.onboarding.store.OnboardingAction.OnboardingToolbarAction @@ -68,6 +69,7 @@ import org.mozilla.fenix.onboarding.view.OnboardingTermsOfServiceEventHandler import org.mozilla.fenix.onboarding.view.ToolbarOption import org.mozilla.fenix.onboarding.view.ToolbarOptionType import org.mozilla.fenix.onboarding.view.mapToOnboardingPageState +import org.mozilla.fenix.onboarding.widget.SetSearchWidgetMainImage import org.mozilla.fenix.theme.FirefoxTheme import org.mozilla.fenix.utils.isLargeScreenSize @@ -104,6 +106,9 @@ private object GradientColors { * @param onSkipDefaultClick Invoked when negative button on default browser page is clicked. * @param onSignInButtonClick Invoked when the positive button on the sign in page is clicked. * @param onSkipSignInClick Invoked when the negative button on the sign in page is clicked. + * @param onNotificationPermissionButtonClick Invoked when positive button on notification page is + * clicked. + * @param onSkipNotificationClick Invoked when negative button on notification page is clicked. * @param onAddFirefoxWidgetClick Invoked when positive button on add search widget page is clicked. * @param onSkipFirefoxWidgetClick Invoked when negative button on add search widget page is clicked. * @param onboardingStore The store which contains all the state related to the add-ons onboarding screen. @@ -125,6 +130,8 @@ fun OnboardingScreenRedesign( onSkipDefaultClick: () -> Unit, onSignInButtonClick: () -> Unit, onSkipSignInClick: () -> Unit, + onNotificationPermissionButtonClick: () -> Unit, + onSkipNotificationClick: () -> Unit, onAddFirefoxWidgetClick: () -> Unit, onSkipFirefoxWidgetClick: () -> Unit, onboardingStore: OnboardingStore? = null, @@ -218,6 +225,14 @@ fun OnboardingScreenRedesign( scrollToNextPageOrDismiss() onSkipSignInClick() }, + onNotificationPermissionButtonClick = { + scrollToNextPageOrDismiss() + onNotificationPermissionButtonClick() + }, + onNotificationPermissionSkipClick = { + scrollToNextPageOrDismiss() + onSkipNotificationClick() + }, onAddFirefoxWidgetClick = { if (isWidgetPinnedState) { scrollToNextPageOrDismiss() @@ -279,6 +294,8 @@ private fun OnboardingContent( onMakeFirefoxDefaultSkipClick: () -> Unit, onSignInButtonClick: () -> Unit, onSignInSkipClick: () -> Unit, + onNotificationPermissionButtonClick: () -> Unit, + onNotificationPermissionSkipClick: () -> Unit, onAddFirefoxWidgetClick: () -> Unit, onSkipFirefoxWidgetClick: () -> Unit, onboardingStore: OnboardingStore? = null, @@ -334,6 +351,8 @@ private fun OnboardingContent( onMakeFirefoxDefaultSkipClick = onMakeFirefoxDefaultSkipClick, onSignInButtonClick = onSignInButtonClick, onSignInSkipClick = onSignInSkipClick, + onNotificationPermissionButtonClick = onNotificationPermissionButtonClick, + onNotificationPermissionSkipClick = onNotificationPermissionSkipClick, onAddFirefoxWidgetClick = onAddFirefoxWidgetClick, onAddFirefoxWidgetSkipClick = onSkipFirefoxWidgetClick, onCustomizeToolbarButtonClick = onCustomizeToolbarButtonClick, @@ -398,6 +417,16 @@ private fun OnboardingPageForType( mainImage = { SyncMainImage() }, ) + OnboardingPageUiData.Type.ADD_SEARCH_WIDGET -> OnboardingPageRedesign( + pageState = state, + mainImage = { SetSearchWidgetMainImage() }, + ) + + OnboardingPageUiData.Type.NOTIFICATION_PERMISSION -> OnboardingPageRedesign( + pageState = state, + mainImage = { NotificationMainImage() }, + ) + OnboardingPageUiData.Type.TOOLBAR_PLACEMENT -> { val context = LocalContext.current onboardingStore?.let { store -> @@ -430,8 +459,6 @@ private fun OnboardingPageForType( ) // no-ops - OnboardingPageUiData.Type.ADD_SEARCH_WIDGET, - OnboardingPageUiData.Type.NOTIFICATION_PERMISSION, OnboardingPageUiData.Type.THEME_SELECTION, -> { logger.error("Unsupported page type: $type used for onboarding redesign.") @@ -550,6 +577,8 @@ private fun OnboardingScreenPreview() { onMarketingDataLearnMoreClick = {}, onMarketingOptInToggle = {}, onMarketingDataContinueClick = {}, + onNotificationPermissionButtonClick = {}, + onNotificationPermissionSkipClick = {}, ) } } diff --git a/mobile/android/fenix/app/src/main/java/org/mozilla/fenix/onboarding/widget/SetSearchWidgetMainImage.kt b/mobile/android/fenix/app/src/main/java/org/mozilla/fenix/onboarding/widget/SetSearchWidgetMainImage.kt @@ -0,0 +1,43 @@ +/* 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.widget + +import androidx.compose.foundation.Image +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.height +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.tooling.preview.PreviewLightDark +import androidx.compose.ui.unit.dp +import org.mozilla.fenix.R +import org.mozilla.fenix.theme.FirefoxTheme + +private val IMAGE_HEIGHT = 200.dp + +/** + * Renders the main image for the "Set search widget" onboarding screen. + * + * **This is a non-interactive, static image view only**. + */ +@Composable +fun SetSearchWidgetMainImage() { + Image( + painter = painterResource(R.drawable.ic_onboarding_search_widget), + contentDescription = null, // Decorative only + modifier = Modifier.height(IMAGE_HEIGHT), + ) +} + +@PreviewLightDark +@Composable +private fun SetSearchWidgetMainImagePreview() { + FirefoxTheme { + Box(Modifier.background(FirefoxTheme.colors.layer1)) { + SetSearchWidgetMainImage() + } + } +}