From 8205e6f90781ddc39dabbfa442a156a12277a7bd Mon Sep 17 00:00:00 2001 From: mike a Date: Mon, 12 Sep 2022 11:09:09 -0700 Subject: [PATCH] [fenix] Closes https://github.com/mozilla-mobile/fenix/issues/26750: add Wallpapers Onboarding dialog --- .../fenix/helpers/FeatureSettingsHelper.kt | 6 + .../mozilla/fenix/ui/CrashReportingTest.kt | 1 + .../org/mozilla/fenix/ui/HomeScreenTest.kt | 2 + .../fenix/ui/NoNetworkAccessStartupTests.kt | 1 + .../java/org/mozilla/fenix/ui/SearchTest.kt | 1 + .../mozilla/fenix/ui/SettingsBasicsTest.kt | 1 + .../mozilla/fenix/ui/SettingsHomepageTest.kt | 1 + .../mozilla/fenix/ui/SettingsPrivacyTest.kt | 1 + .../mozilla/fenix/ui/SettingsSearchTest.kt | 1 + .../java/org/mozilla/fenix/ui/SmokeTest.kt | 1 + .../StrictEnhancedTrackingProtectionTest.kt | 1 + .../mozilla/fenix/ui/TabbedBrowsingTest.kt | 1 + .../java/org/mozilla/fenix/ui/TopSitesTest.kt | 1 + .../SessionControlController.kt | 21 +++ .../SessionControlInteractor.kt | 14 ++ .../home/sessioncontrol/SessionControlView.kt | 33 +++-- .../fenix/onboarding/HomeCFRPresenter.kt | 16 +- .../WallpaperOnboardingDialogFragment.kt | 97 ++++++++++++ .../settings/wallpaper/WallpaperSettings.kt | 25 +++- .../java/org/mozilla/fenix/utils/Settings.kt | 2 +- .../fenix/wallpapers/WallpaperOnboarding.kt | 138 ++++++++++++++++++ app/src/main/res/navigation/nav_graph.xml | 9 ++ app/src/main/res/values/strings.xml | 6 + app/src/main/res/values/styles.xml | 4 + 24 files changed, 360 insertions(+), 24 deletions(-) create mode 100644 app/src/main/java/org/mozilla/fenix/onboarding/WallpaperOnboardingDialogFragment.kt create mode 100644 app/src/main/java/org/mozilla/fenix/wallpapers/WallpaperOnboarding.kt diff --git a/app/src/androidTest/java/org/mozilla/fenix/helpers/FeatureSettingsHelper.kt b/app/src/androidTest/java/org/mozilla/fenix/helpers/FeatureSettingsHelper.kt index 1fa4df11b5..5cb27ea940 100644 --- a/app/src/androidTest/java/org/mozilla/fenix/helpers/FeatureSettingsHelper.kt +++ b/app/src/androidTest/java/org/mozilla/fenix/helpers/FeatureSettingsHelper.kt @@ -19,6 +19,7 @@ class FeatureSettingsHelper { private var isRecentlyVisitedFeatureEnabled: Boolean = settings.historyMetadataUIFeature private var isUserKnowsAboutPwasTrue: Boolean = settings.userKnowsAboutPwas private var isTCPCFREnabled: Boolean = settings.shouldShowTotalCookieProtectionCFR + private var isWallpaperOnboardingEnabled: Boolean = settings.showWallpaperOnboarding fun setPocketEnabled(enabled: Boolean) { settings.showPocketRecommendationsFeature = enabled @@ -28,6 +29,10 @@ class FeatureSettingsHelper { settings.shouldShowJumpBackInCFR = enabled } + fun setShowWallpaperOnboarding(enabled: Boolean) { + settings.showWallpaperOnboarding = enabled + } + fun setRecentTabsFeatureEnabled(enabled: Boolean) { settings.showRecentTabsFeature = enabled } @@ -65,5 +70,6 @@ class FeatureSettingsHelper { settings.historyMetadataUIFeature = isRecentlyVisitedFeatureEnabled settings.userKnowsAboutPwas = isUserKnowsAboutPwasTrue settings.shouldShowTotalCookieProtectionCFR = isTCPCFREnabled + settings.showWallpaperOnboarding = isWallpaperOnboardingEnabled } } diff --git a/app/src/androidTest/java/org/mozilla/fenix/ui/CrashReportingTest.kt b/app/src/androidTest/java/org/mozilla/fenix/ui/CrashReportingTest.kt index a8b690302d..b81f571698 100644 --- a/app/src/androidTest/java/org/mozilla/fenix/ui/CrashReportingTest.kt +++ b/app/src/androidTest/java/org/mozilla/fenix/ui/CrashReportingTest.kt @@ -35,6 +35,7 @@ class CrashReportingTest { fun setUp() { featureSettingsHelper.setJumpBackCFREnabled(false) featureSettingsHelper.setPocketEnabled(false) + featureSettingsHelper.setShowWallpaperOnboarding(false) mDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation()) mockWebServer = MockWebServer().apply { diff --git a/app/src/androidTest/java/org/mozilla/fenix/ui/HomeScreenTest.kt b/app/src/androidTest/java/org/mozilla/fenix/ui/HomeScreenTest.kt index 9c6c257a3c..c21e54dece 100644 --- a/app/src/androidTest/java/org/mozilla/fenix/ui/HomeScreenTest.kt +++ b/app/src/androidTest/java/org/mozilla/fenix/ui/HomeScreenTest.kt @@ -151,6 +151,7 @@ class HomeScreenTest { @Test fun dismissOnboardingUsingHelpTest() { featureSettingsHelper.setJumpBackCFREnabled(false) + featureSettingsHelper.setShowWallpaperOnboarding(false) homeScreen { verifyWelcomeHeader() @@ -200,6 +201,7 @@ class HomeScreenTest { fun verifyCustomizeHomepageTest() { val defaultWebPage = TestAssetHelper.getGenericAsset(mockWebServer, 1) featureSettingsHelper.setJumpBackCFREnabled(false) + featureSettingsHelper.setShowWallpaperOnboarding(false) navigationToolbar { }.enterURLAndEnterToBrowser(defaultWebPage.url) { diff --git a/app/src/androidTest/java/org/mozilla/fenix/ui/NoNetworkAccessStartupTests.kt b/app/src/androidTest/java/org/mozilla/fenix/ui/NoNetworkAccessStartupTests.kt index 3ac6dd6d06..d5e38abc03 100644 --- a/app/src/androidTest/java/org/mozilla/fenix/ui/NoNetworkAccessStartupTests.kt +++ b/app/src/androidTest/java/org/mozilla/fenix/ui/NoNetworkAccessStartupTests.kt @@ -37,6 +37,7 @@ class NoNetworkAccessStartupTests { @Before fun setUp() { featureSettingsHelper.setTCPCFREnabled(false) + featureSettingsHelper.setShowWallpaperOnboarding(false) } @After diff --git a/app/src/androidTest/java/org/mozilla/fenix/ui/SearchTest.kt b/app/src/androidTest/java/org/mozilla/fenix/ui/SearchTest.kt index d855f99569..63aec4b740 100644 --- a/app/src/androidTest/java/org/mozilla/fenix/ui/SearchTest.kt +++ b/app/src/androidTest/java/org/mozilla/fenix/ui/SearchTest.kt @@ -66,6 +66,7 @@ class SearchTest { featureSettingsHelper.setJumpBackCFREnabled(false) featureSettingsHelper.setTCPCFREnabled(false) featureSettingsHelper.setPocketEnabled(false) + featureSettingsHelper.setShowWallpaperOnboarding(false) } @After diff --git a/app/src/androidTest/java/org/mozilla/fenix/ui/SettingsBasicsTest.kt b/app/src/androidTest/java/org/mozilla/fenix/ui/SettingsBasicsTest.kt index b2f64ca32d..cd1265a15f 100644 --- a/app/src/androidTest/java/org/mozilla/fenix/ui/SettingsBasicsTest.kt +++ b/app/src/androidTest/java/org/mozilla/fenix/ui/SettingsBasicsTest.kt @@ -70,6 +70,7 @@ class SettingsBasicsTest { featureSettingsHelper.setJumpBackCFREnabled(false) featureSettingsHelper.setTCPCFREnabled(false) + featureSettingsHelper.setShowWallpaperOnboarding(false) } @After diff --git a/app/src/androidTest/java/org/mozilla/fenix/ui/SettingsHomepageTest.kt b/app/src/androidTest/java/org/mozilla/fenix/ui/SettingsHomepageTest.kt index 8e3e60481d..0a72cd8742 100644 --- a/app/src/androidTest/java/org/mozilla/fenix/ui/SettingsHomepageTest.kt +++ b/app/src/androidTest/java/org/mozilla/fenix/ui/SettingsHomepageTest.kt @@ -44,6 +44,7 @@ class SettingsHomepageTest { } featureSettingsHelper.setJumpBackCFREnabled(false) featureSettingsHelper.setTCPCFREnabled(false) + featureSettingsHelper.setShowWallpaperOnboarding(false) } @After diff --git a/app/src/androidTest/java/org/mozilla/fenix/ui/SettingsPrivacyTest.kt b/app/src/androidTest/java/org/mozilla/fenix/ui/SettingsPrivacyTest.kt index e9eb814fa6..0f22eedd82 100644 --- a/app/src/androidTest/java/org/mozilla/fenix/ui/SettingsPrivacyTest.kt +++ b/app/src/androidTest/java/org/mozilla/fenix/ui/SettingsPrivacyTest.kt @@ -64,6 +64,7 @@ class SettingsPrivacyTest { featureSettingsHelper.setJumpBackCFREnabled(false) featureSettingsHelper.setTCPCFREnabled(false) + featureSettingsHelper.setShowWallpaperOnboarding(false) featureSettingsHelper.disablePwaCFR(true) if (Build.VERSION.SDK_INT == Build.VERSION_CODES.R) { diff --git a/app/src/androidTest/java/org/mozilla/fenix/ui/SettingsSearchTest.kt b/app/src/androidTest/java/org/mozilla/fenix/ui/SettingsSearchTest.kt index 935920bf9a..fa223a2736 100644 --- a/app/src/androidTest/java/org/mozilla/fenix/ui/SettingsSearchTest.kt +++ b/app/src/androidTest/java/org/mozilla/fenix/ui/SettingsSearchTest.kt @@ -34,6 +34,7 @@ class SettingsSearchTest { start() } featureSettingsHelper.setJumpBackCFREnabled(false) + featureSettingsHelper.setShowWallpaperOnboarding(false) } @After diff --git a/app/src/androidTest/java/org/mozilla/fenix/ui/SmokeTest.kt b/app/src/androidTest/java/org/mozilla/fenix/ui/SmokeTest.kt index c03f566e4a..6ec35f9d89 100644 --- a/app/src/androidTest/java/org/mozilla/fenix/ui/SmokeTest.kt +++ b/app/src/androidTest/java/org/mozilla/fenix/ui/SmokeTest.kt @@ -95,6 +95,7 @@ class SmokeTest { // disabling the new homepage pop-up that interferes with the tests. featureSettingsHelper.setJumpBackCFREnabled(false) featureSettingsHelper.setTCPCFREnabled(false) + featureSettingsHelper.setShowWallpaperOnboarding(false) mDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation()) mockWebServer = MockWebServer().apply { diff --git a/app/src/androidTest/java/org/mozilla/fenix/ui/StrictEnhancedTrackingProtectionTest.kt b/app/src/androidTest/java/org/mozilla/fenix/ui/StrictEnhancedTrackingProtectionTest.kt index 191f43e230..0dca06a52f 100644 --- a/app/src/androidTest/java/org/mozilla/fenix/ui/StrictEnhancedTrackingProtectionTest.kt +++ b/app/src/androidTest/java/org/mozilla/fenix/ui/StrictEnhancedTrackingProtectionTest.kt @@ -49,6 +49,7 @@ class StrictEnhancedTrackingProtectionTest { featureSettingsHelper.setStrictETPEnabled() featureSettingsHelper.setJumpBackCFREnabled(false) featureSettingsHelper.setTCPCFREnabled(false) + featureSettingsHelper.setShowWallpaperOnboarding(false) } @After diff --git a/app/src/androidTest/java/org/mozilla/fenix/ui/TabbedBrowsingTest.kt b/app/src/androidTest/java/org/mozilla/fenix/ui/TabbedBrowsingTest.kt index 0f363ccef5..5e7dcea69e 100644 --- a/app/src/androidTest/java/org/mozilla/fenix/ui/TabbedBrowsingTest.kt +++ b/app/src/androidTest/java/org/mozilla/fenix/ui/TabbedBrowsingTest.kt @@ -58,6 +58,7 @@ class TabbedBrowsingTest { // disabling the new homepage pop-up that interferes with the tests. featureSettingsHelper.setJumpBackCFREnabled(false) featureSettingsHelper.setTCPCFREnabled(false) + featureSettingsHelper.setShowWallpaperOnboarding(false) mDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation()) mockWebServer = MockWebServer().apply { diff --git a/app/src/androidTest/java/org/mozilla/fenix/ui/TopSitesTest.kt b/app/src/androidTest/java/org/mozilla/fenix/ui/TopSitesTest.kt index f811d1eb60..ff3b81ad41 100644 --- a/app/src/androidTest/java/org/mozilla/fenix/ui/TopSitesTest.kt +++ b/app/src/androidTest/java/org/mozilla/fenix/ui/TopSitesTest.kt @@ -55,6 +55,7 @@ class TopSitesTest { featureSettingsHelper.setJumpBackCFREnabled(false) featureSettingsHelper.setTCPCFREnabled(false) + featureSettingsHelper.setShowWallpaperOnboarding(false) } @After diff --git a/app/src/main/java/org/mozilla/fenix/home/sessioncontrol/SessionControlController.kt b/app/src/main/java/org/mozilla/fenix/home/sessioncontrol/SessionControlController.kt index e4093479b1..fbbebe4b95 100644 --- a/app/src/main/java/org/mozilla/fenix/home/sessioncontrol/SessionControlController.kt +++ b/app/src/main/java/org/mozilla/fenix/home/sessioncontrol/SessionControlController.kt @@ -56,9 +56,12 @@ import org.mozilla.fenix.gleanplumb.MessageController import org.mozilla.fenix.home.HomeFragment import org.mozilla.fenix.home.HomeFragmentDirections import org.mozilla.fenix.home.Mode +import org.mozilla.fenix.onboarding.WallpaperOnboardingDialogFragment import org.mozilla.fenix.settings.SupportUtils import org.mozilla.fenix.settings.SupportUtils.SumoTopic.PRIVATE_BROWSING_MYTHS import org.mozilla.fenix.utils.Settings +import org.mozilla.fenix.wallpapers.Wallpaper +import org.mozilla.fenix.wallpapers.WallpaperState import mozilla.components.feature.tab.collections.Tab as ComponentTab /** @@ -197,6 +200,11 @@ interface SessionControlController { */ fun handleCustomizeHomeTapped() + /** + * @see [OnboardingInteractor.showWallpapersOnboardingDialog] + */ + fun handleShowWallpapersOnboardingDialog(state: WallpaperState): Boolean + /** * @see [SessionControlInteractor.reportSessionMetrics] */ @@ -501,6 +509,19 @@ class DefaultSessionControlController( HomeScreen.customizeHomeClicked.record(NoExtras()) } + override fun handleShowWallpapersOnboardingDialog(state: WallpaperState): Boolean { + if (state.availableWallpapers.all { it.thumbnailFileState == Wallpaper.ImageFileState.Downloaded } && + state.availableWallpapers.size >= WallpaperOnboardingDialogFragment.THUMBNAILS_COUNT + ) { + navController.nav( + R.id.homeFragment, + HomeFragmentDirections.actionGlobalWallpaperOnboardingDialog(), + ) + return true + } + return false + } + override fun handleReadPrivacyNoticeClicked() { activity.openToBrowserAndLoad( searchTermOrURL = SupportUtils.getMozillaPageUrl(SupportUtils.MozillaPage.PRIVATE_NOTICE), diff --git a/app/src/main/java/org/mozilla/fenix/home/sessioncontrol/SessionControlInteractor.kt b/app/src/main/java/org/mozilla/fenix/home/sessioncontrol/SessionControlInteractor.kt index 656578b7c9..82a84e74ee 100644 --- a/app/src/main/java/org/mozilla/fenix/home/sessioncontrol/SessionControlInteractor.kt +++ b/app/src/main/java/org/mozilla/fenix/home/sessioncontrol/SessionControlInteractor.kt @@ -27,6 +27,7 @@ import org.mozilla.fenix.home.recentvisits.RecentlyVisitedItem.RecentHistoryGrou import org.mozilla.fenix.home.recentvisits.RecentlyVisitedItem.RecentHistoryHighlight import org.mozilla.fenix.home.recentvisits.controller.RecentVisitsController import org.mozilla.fenix.home.recentvisits.interactor.RecentVisitsInteractor +import org.mozilla.fenix.wallpapers.WallpaperState /** * Interface for tab related actions in the [SessionControlInteractor]. @@ -162,6 +163,15 @@ interface OnboardingInteractor { * Opens a custom tab to privacy notice url. Called when a user clicks on the "read our privacy notice" button. */ fun onReadPrivacyNoticeClicked() + + /** + * Show Wallpapers onboarding dialog to onboard users about the feature if conditions are met. + * Returns true if the call has been passed down to the controller. + * + * @param state The wallpaper state. + * @return Whether the onboarding dialog is currently shown. + */ + fun showWallpapersOnboardingDialog(state: WallpaperState): Boolean } interface CustomizeHomeIteractor { @@ -322,6 +332,10 @@ class SessionControlInteractor( controller.handleReadPrivacyNoticeClicked() } + override fun showWallpapersOnboardingDialog(state: WallpaperState): Boolean { + return controller.handleShowWallpapersOnboardingDialog(state) + } + override fun onToggleCollectionExpanded(collection: TabCollection, expand: Boolean) { controller.handleToggleCollectionExpanded(collection, expand) } 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 5e60333a6a..d1c40b8adf 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 @@ -199,6 +199,9 @@ class SessionControlView( val view: RecyclerView = containerView as RecyclerView + // We want to limit feature recommendations to one per HomePage visit. + var featureRecommended = false + private val sessionControlAdapter = SessionControlAdapter( interactor, viewLifecycleOwner, @@ -206,21 +209,33 @@ class SessionControlView( ) init { + @Suppress("NestedBlockDepth") view.apply { adapter = sessionControlAdapter layoutManager = object : LinearLayoutManager(containerView.context) { override fun onLayoutCompleted(state: RecyclerView.State?) { super.onLayoutCompleted(state) - if (!context.settings().showHomeOnboardingDialog && ( - context.settings().showSyncCFR || - context.settings().shouldShowJumpBackInCFR - ) - ) { - HomeCFRPresenter( - context = context, - recyclerView = view, - ).show() + if (!featureRecommended && !context.settings().showHomeOnboardingDialog) { + if (!context.settings().showHomeOnboardingDialog && ( + context.settings().showSyncCFR || + context.settings().shouldShowJumpBackInCFR + ) + ) { + featureRecommended = HomeCFRPresenter( + context = context, + recyclerView = view, + ).show() + } + + if (!context.settings().shouldShowJumpBackInCFR && + context.settings().showWallpaperOnboarding && + !featureRecommended + ) { + featureRecommended = interactor.showWallpapersOnboardingDialog( + context.components.appStore.state.wallpaperState, + ) + } } // We want some parts of the home screen UI to be rendered first if they are diff --git a/app/src/main/java/org/mozilla/fenix/onboarding/HomeCFRPresenter.kt b/app/src/main/java/org/mozilla/fenix/onboarding/HomeCFRPresenter.kt index 266c66c318..00eeb8bbed 100644 --- a/app/src/main/java/org/mozilla/fenix/onboarding/HomeCFRPresenter.kt +++ b/app/src/main/java/org/mozilla/fenix/onboarding/HomeCFRPresenter.kt @@ -38,13 +38,17 @@ class HomeCFRPresenter( * Determine the CFR to be shown on the Home screen and show a CFR for the resultant view * if any. */ - fun show() { - when (val result = getCFRToShow()) { - is Result.SyncedTab -> showSyncedTabCFR(view = result.view) - is Result.JumpBackIn -> showJumpBackInCFR(view = result.view) - else -> { - // no-op + fun show(): Boolean { + return when (val result = getCFRToShow()) { + is Result.SyncedTab -> { + showSyncedTabCFR(view = result.view) + true } + is Result.JumpBackIn -> { + showJumpBackInCFR(view = result.view) + true + } + else -> false } } diff --git a/app/src/main/java/org/mozilla/fenix/onboarding/WallpaperOnboardingDialogFragment.kt b/app/src/main/java/org/mozilla/fenix/onboarding/WallpaperOnboardingDialogFragment.kt new file mode 100644 index 0000000000..0108e8f215 --- /dev/null +++ b/app/src/main/java/org/mozilla/fenix/onboarding/WallpaperOnboardingDialogFragment.kt @@ -0,0 +1,97 @@ +/* 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.annotation.SuppressLint +import android.content.pm.ActivityInfo +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.compose.material.ExperimentalMaterialApi +import androidx.compose.runtime.rememberCoroutineScope +import androidx.compose.ui.platform.ComposeView +import androidx.compose.ui.platform.ViewCompositionStrategy +import androidx.navigation.fragment.findNavController +import com.google.android.material.bottomsheet.BottomSheetDialogFragment +import kotlinx.coroutines.launch +import mozilla.components.lib.state.ext.observeAsComposableState +import org.mozilla.fenix.NavGraphDirections +import org.mozilla.fenix.R +import org.mozilla.fenix.ext.requireComponents +import org.mozilla.fenix.ext.settings +import org.mozilla.fenix.theme.FirefoxTheme +import org.mozilla.fenix.wallpapers.Wallpaper +import org.mozilla.fenix.wallpapers.WallpaperOnboarding + +/** + * Dialog displaying the wallpapers onboarding. + */ +@OptIn(ExperimentalMaterialApi::class) +class WallpaperOnboardingDialogFragment : BottomSheetDialogFragment() { + private val appStore by lazy { + requireComponents.appStore + } + + private val wallpaperUseCases by lazy { + requireComponents.useCases.wallpaperUseCases + } + + @SuppressLint("SourceLockedOrientationActivity") + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setStyle(STYLE_NO_TITLE, R.style.WallpaperOnboardingDialogStyle) + activity?.requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT + } + + override fun onDestroy() { + super.onDestroy() + activity?.requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + requireContext().settings().showWallpaperOnboarding = false + } + + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle?, + ): View = ComposeView(requireContext()).apply { + setViewCompositionStrategy(ViewCompositionStrategy.DisposeOnViewTreeLifecycleDestroyed) + + setContent { + FirefoxTheme { + val wallpapers = appStore.observeAsComposableState { state -> + state.wallpaperState.availableWallpapers.take(THUMBNAILS_COUNT) + }.value ?: listOf() + val currentWallpaper = appStore.observeAsComposableState { state -> + state.wallpaperState.currentWallpaper + }.value ?: Wallpaper.Default + + val coroutineScope = rememberCoroutineScope() + + WallpaperOnboarding( + wallpapers = wallpapers, + currentWallpaper = currentWallpaper, + onCloseClicked = { dismiss() }, + onExploreMoreButtonClicked = { + val directions = NavGraphDirections.actionGlobalWallpaperSettingsFragment() + findNavController().navigate(directions) + }, + loadWallpaperResource = { wallpaperUseCases.loadThumbnail(it) }, + onSelectWallpaper = { + coroutineScope.launch { wallpaperUseCases.selectWallpaper(it) } + }, + ) + } + } + } + + companion object { + const val THUMBNAILS_COUNT = 6 + } +} diff --git a/app/src/main/java/org/mozilla/fenix/settings/wallpaper/WallpaperSettings.kt b/app/src/main/java/org/mozilla/fenix/settings/wallpaper/WallpaperSettings.kt index 7455b99ff9..b74cf59e29 100644 --- a/app/src/main/java/org/mozilla/fenix/settings/wallpaper/WallpaperSettings.kt +++ b/app/src/main/java/org/mozilla/fenix/settings/wallpaper/WallpaperSettings.kt @@ -7,7 +7,6 @@ package org.mozilla.fenix.settings.wallpaper import android.annotation.SuppressLint import android.graphics.Bitmap import androidx.compose.foundation.BorderStroke -import androidx.compose.foundation.ExperimentalFoundationApi import androidx.compose.foundation.Image import androidx.compose.foundation.border import androidx.compose.foundation.clickable @@ -91,8 +90,8 @@ fun WallpaperSettings( WallpaperThumbnails( wallpapers = wallpapers, defaultWallpaper = defaultWallpaper, - loadWallpaperResource = loadWallpaperResource, selectedWallpaper = selectedWallpaper, + loadWallpaperResource = loadWallpaperResource, onSelectWallpaper = { updatedWallpaper -> coroutineScope.launch { scaffoldState.snackbarHostState.showSnackbar( @@ -147,19 +146,27 @@ private fun WallpaperSnackbar( * @param selectedWallpaper The currently selected wallpaper. * @param numColumns The number of columns that will occupy the grid. * @param onSelectWallpaper Action to take when a new wallpaper is selected. + * @param verticalPadding Vertical content padding inside the block. + * @param horizontalPadding Horizontal content padding inside the block. */ -@OptIn(ExperimentalFoundationApi::class) @Composable @Suppress("LongParameterList") -private fun WallpaperThumbnails( +fun WallpaperThumbnails( wallpapers: List, defaultWallpaper: Wallpaper, - loadWallpaperResource: suspend (Wallpaper) -> Bitmap?, selectedWallpaper: Wallpaper, - numColumns: Int = 3, + loadWallpaperResource: suspend (Wallpaper) -> Bitmap?, onSelectWallpaper: (Wallpaper) -> Unit, + numColumns: Int = 3, + verticalPadding: Int = 30, + horizontalPadding: Int = 20, ) { - Column(modifier = Modifier.padding(vertical = 30.dp, horizontal = 20.dp)) { + Column( + modifier = Modifier.padding( + vertical = verticalPadding.dp, + horizontal = horizontalPadding.dp, + ), + ) { val numRows = (wallpapers.size + numColumns - 1) / numColumns for (rowIndex in 0 until numRows) { Row { @@ -167,7 +174,9 @@ private fun WallpaperThumbnails( val itemIndex = rowIndex * numColumns + columnIndex if (itemIndex < wallpapers.size) { Box( - modifier = Modifier.weight(1f, fill = true).padding(4.dp), + modifier = Modifier + .weight(1f, fill = true) + .padding(4.dp), ) { WallpaperThumbnailItem( wallpaper = wallpapers[itemIndex], diff --git a/app/src/main/java/org/mozilla/fenix/utils/Settings.kt b/app/src/main/java/org/mozilla/fenix/utils/Settings.kt index c262030596..b566b352a6 100644 --- a/app/src/main/java/org/mozilla/fenix/utils/Settings.kt +++ b/app/src/main/java/org/mozilla/fenix/utils/Settings.kt @@ -210,7 +210,7 @@ class Settings(private val appContext: Context) : PreferencesHolder { /** * Indicates if the wallpaper onboarding dialog should be shown. */ - val showWallpaperOnboarding by lazyFeatureFlagPreference( + var showWallpaperOnboarding by lazyFeatureFlagPreference( key = appContext.getPreferenceKey(R.string.pref_key_wallpapers_onboarding), featureFlag = FeatureFlags.wallpaperOnboardingEnabled, default = { mr2022Sections[Mr2022Section.WALLPAPERS_SELECTION_TOOL] == true }, diff --git a/app/src/main/java/org/mozilla/fenix/wallpapers/WallpaperOnboarding.kt b/app/src/main/java/org/mozilla/fenix/wallpapers/WallpaperOnboarding.kt new file mode 100644 index 0000000000..9fd370af66 --- /dev/null +++ b/app/src/main/java/org/mozilla/fenix/wallpapers/WallpaperOnboarding.kt @@ -0,0 +1,138 @@ +/* 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.wallpapers + +import android.graphics.Bitmap +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material.ExperimentalMaterialApi +import androidx.compose.material.Icon +import androidx.compose.material.Surface +import androidx.compose.material.Text +import androidx.compose.material.TextButton +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.text.style.TextOverflow +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import org.mozilla.fenix.R +import org.mozilla.fenix.settings.wallpaper.WallpaperThumbnails +import org.mozilla.fenix.theme.FirefoxTheme +import org.mozilla.fenix.theme.Theme + +/** + * A view that shows content of a WallpaperOnboarding dialog. + * + * @param wallpapers Wallpapers to add to grid. + * @param currentWallpaper The currently selected wallpaper. + * @param loadWallpaperResource Callback to handle loading a wallpaper bitmap. Only optional in the default case. + * @param onCloseClicked Callback for when the close button is clicked. + * @param onExploreMoreButtonClicked Callback for when the bottom text button is clicked. + * @param onSelectWallpaper Callback for when a new wallpaper is selected. + */ + +@Suppress("LongParameterList") +@ExperimentalMaterialApi +@Composable +fun WallpaperOnboarding( + wallpapers: List, + currentWallpaper: Wallpaper, + loadWallpaperResource: suspend (Wallpaper) -> Bitmap?, + onCloseClicked: () -> Unit, + onExploreMoreButtonClicked: () -> Unit, + onSelectWallpaper: (Wallpaper) -> Unit, +) { + Surface( + color = FirefoxTheme.colors.layer2, + shape = RoundedCornerShape(topStart = 16.dp, topEnd = 16.dp), + ) { + Column( + modifier = Modifier.padding(16.dp), + horizontalAlignment = Alignment.CenterHorizontally, + ) { + Icon( + painter = painterResource(id = R.drawable.mozac_ic_close), + contentDescription = stringResource(id = R.string.close_tab), + tint = FirefoxTheme.colors.iconPrimary, + modifier = Modifier + .clickable { onCloseClicked() } + .size(24.dp) + .align(Alignment.End), + ) + + Spacer(modifier = Modifier.height(8.dp)) + + Text( + text = stringResource(R.string.wallpapers_onboarding_dialog_title_text), + color = FirefoxTheme.colors.textPrimary, + overflow = TextOverflow.Ellipsis, + maxLines = 1, + style = FirefoxTheme.typography.headline7, + ) + + Spacer(modifier = Modifier.height(4.dp)) + + Text( + text = stringResource(R.string.wallpapers_onboarding_dialog_body_text), + color = FirefoxTheme.colors.textSecondary, + overflow = TextOverflow.Ellipsis, + maxLines = 1, + style = FirefoxTheme.typography.caption, + ) + + WallpaperThumbnails( + wallpapers = wallpapers, + defaultWallpaper = Wallpaper.Default, + selectedWallpaper = currentWallpaper, + loadWallpaperResource = { loadWallpaperResource(it) }, + onSelectWallpaper = { onSelectWallpaper(it) }, + verticalPadding = 16, + horizontalPadding = 0, + ) + + TextButton( + modifier = Modifier + .align(Alignment.CenterHorizontally) + .fillMaxWidth(), + onClick = { onExploreMoreButtonClicked() }, + ) { + Text( + text = stringResource(R.string.wallpapers_onboarding_dialog_explore_more_button_text), + color = FirefoxTheme.colors.textAccent, + overflow = TextOverflow.Ellipsis, + maxLines = 1, + style = FirefoxTheme.typography.button, + ) + } + + Spacer(modifier = Modifier.height(12.dp)) + } + } +} + +@Preview +@ExperimentalMaterialApi +@Composable +private fun WallpaperSnackbarPreview() { + FirefoxTheme(theme = Theme.getTheme()) { + WallpaperOnboarding( + wallpapers = listOf(Wallpaper.Default), + currentWallpaper = Wallpaper.Default, + onCloseClicked = {}, + onExploreMoreButtonClicked = {}, + loadWallpaperResource = { null }, + onSelectWallpaper = {}, + ) + } +} diff --git a/app/src/main/res/navigation/nav_graph.xml b/app/src/main/res/navigation/nav_graph.xml index 67cdcfd78b..de5afa496f 100644 --- a/app/src/main/res/navigation/nav_graph.xml +++ b/app/src/main/res/navigation/nav_graph.xml @@ -34,6 +34,11 @@ app:destination="@id/homeOnboardingDialogFragment" app:popUpTo="@id/homeFragment" /> + + + + Firefox logo - change the wallpaper, button + + Try a splash of color + + Choose a wallpaper that speaks to you. + + Explore more wallpapers diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml index fa55696aa0..2808c56b17 100644 --- a/app/src/main/res/values/styles.xml +++ b/app/src/main/res/values/styles.xml @@ -564,6 +564,10 @@