Skip to content
This repository has been archived by the owner on Feb 20, 2023. It is now read-only.

Commit

Permalink
Closes #26750: add Wallpapers Onboarding dialog
Browse files Browse the repository at this point in the history
  • Loading branch information
mike a committed Sep 1, 2022
1 parent ca0cfd7 commit fbc7e3c
Show file tree
Hide file tree
Showing 12 changed files with 289 additions and 7 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -202,6 +202,11 @@ interface SessionControlController {
*/
fun handleShowOnboardingDialog()

/**
* @see [OnboardingInteractor.showWallpapersOnboardingDialog]
*/
fun handleShowWallpapersOnboardingDialog()

/**
* @see [SessionControlInteractor.reportSessionMetrics]
*/
Expand Down Expand Up @@ -513,6 +518,13 @@ class DefaultSessionControlController(
)
}

override fun handleShowWallpapersOnboardingDialog() {
navController.nav(
R.id.homeFragment,
HomeFragmentDirections.actionGlobalWallpaperOnboardingDialog()
)
}

override fun handleReadPrivacyNoticeClicked() {
activity.openToBrowserAndLoad(
searchTermOrURL = SupportUtils.getMozillaPageUrl(SupportUtils.MozillaPage.PRIVATE_NOTICE),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,11 @@ interface OnboardingInteractor {
* historyMetadata and pocketArticles sections.
*/
fun showOnboardingDialog()

/**
* Show the Wallpapers onboarding dialog to onboard users about the feature.
*/
fun showWallpapersOnboardingDialog()
}

interface CustomizeHomeIteractor {
Expand Down Expand Up @@ -332,6 +337,10 @@ class SessionControlInteractor(
controller.handleShowOnboardingDialog()
}

override fun showWallpapersOnboardingDialog() {
controller.handleShowWallpapersOnboardingDialog()
}

override fun onToggleCollectionExpanded(collection: TabCollection, expand: Boolean) {
controller.handleToggleCollectionExpanded(collection, expand)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -217,16 +217,26 @@ class SessionControlView(
override fun onLayoutCompleted(state: RecyclerView.State?) {
super.onLayoutCompleted(state)

var isCFRDisplayed = false
if (!context.settings().showHomeOnboardingDialog) {
if (context.settings().shouldShowJumpBackInCFR) {
JumpBackInCFRDialog(view).showIfNeeded()
isCFRDisplayed = JumpBackInCFRDialog(view).showIfNeeded()
} else if (context.settings().showSyncCFR) {
SyncCFRPresenter(
isCFRDisplayed = SyncCFRPresenter(
context = context,
recyclerView = view,
).showSyncCFR()
}
}
if (!isCFRDisplayed &&
!context.settings().showHomeOnboardingDialog &&
(!context.settings().shouldShowJumpBackInCFR ||
!context.settings().showSyncCFR) &&
context.settings().showWallpaperOnboarding &&
onboarding.userHasBeenOnboarded()
) {
interactor.showWallpapersOnboardingDialog()
}

// We want some parts of the home screen UI to be rendered first if they are
// the most prominent parts of the visible part of the screen.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,16 +25,18 @@ class JumpBackInCFRDialog(val recyclerView: RecyclerView) {
/**
* Try to show the crf dialog if it hasn't been shown before.
*/
fun showIfNeeded() {
fun showIfNeeded(): Boolean {
val jumpBackInView = findJumpBackInView()
jumpBackInView?.let {
val crfDialog = createJumpCRF(anchor = jumpBackInView)
crfDialog?.let {
val context = jumpBackInView.context
context.settings().shouldShowJumpBackInCFR = false
it.show()
return true
}
}
return false
}

private fun findJumpBackInView(): View? {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ class SyncCFRPresenter(
/**
* Find the synced view and if it is available, then show the synced tab CFR.
*/
fun showSyncCFR() {
fun showSyncCFR() : Boolean {
findSyncTabsView()?.let {
CFRPopup(
text = context.getString(R.string.sync_cfr_message),
Expand All @@ -61,7 +61,9 @@ class SyncCFRPresenter(
context.settings().shouldShowJumpBackInCFR = false

Onboarding.synCfrShown.record(NoExtras())
return true
}
return false
}

private fun findSyncTabsView(): View? {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -149,16 +149,18 @@ private fun WallpaperSnackbar(
@OptIn(ExperimentalFoundationApi::class)
@Composable
@Suppress("LongParameterList")
private fun WallpaperThumbnails(
fun WallpaperThumbnails(
wallpapers: List<Wallpaper>,
defaultWallpaper: Wallpaper,
loadWallpaperResource: suspend (Wallpaper) -> Bitmap?,
selectedWallpaper: Wallpaper,
numColumns: Int = 3,
onSelectWallpaper: (Wallpaper) -> Unit,
verticalPadding: Int = 30,
horizontalPadding: Int = 20
) {
Surface(color = FirefoxTheme.colors.layer2) {
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 {
Expand Down
2 changes: 1 addition & 1 deletion app/src/main/java/org/mozilla/fenix/utils/Settings.kt
Original file line number Diff line number Diff line change
Expand Up @@ -209,7 +209,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 },
Expand Down
135 changes: 135 additions & 0 deletions app/src/main/java/org/mozilla/fenix/wallpapers/WallpaperOnboarding.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
/* 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.font.FontWeight
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
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 onCloseClicked Callback for when the close button is clicked.
* @param onButtonClicked Callback for when the bottom text button is clicked.
* @param loadWallpaperResource Callback to handle loading a wallpaper bitmap. Only optional in the default case.
* @param onSelectWallpaper Callback for when a new wallpaper is selected.
*/

@Suppress("LongParameterList")
@ExperimentalMaterialApi
@Composable
fun WallpaperOnboarding(
wallpapers: List<Wallpaper>,
currentWallpaper: Wallpaper,
onCloseClicked: () -> Unit,
onButtonClicked: () -> Unit,
loadWallpaperResource: suspend (Wallpaper) -> Bitmap?,
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,
fontWeight = FontWeight.Bold,
fontSize = 16.sp,
overflow = TextOverflow.Ellipsis,
maxLines = 1,
)
Spacer(modifier = Modifier.height(4.dp))
Text(
text = stringResource(R.string.wallpapers_onboarding_dialog_body_text),
color = FirefoxTheme.colors.textSecondary,
fontSize = 12.sp,
overflow = TextOverflow.Ellipsis,
maxLines = 1,
)
WallpaperThumbnails(
wallpapers = wallpapers,
defaultWallpaper = Wallpaper.Default,
loadWallpaperResource = { loadWallpaperResource(it) },
selectedWallpaper = currentWallpaper,
onSelectWallpaper = { onSelectWallpaper(it) },
verticalPadding = 16,
horizontalPadding = 0
)
TextButton(
modifier = Modifier
.align(Alignment.CenterHorizontally)
.fillMaxWidth(),
onClick = { onButtonClicked() }
) {
Text(
text = stringResource(R.string.wallpapers_onboarding_dialog_explore_more_button_text),
fontWeight = FontWeight.Bold,
color = FirefoxTheme.colors.textAccent,
fontSize = 14.sp,
overflow = TextOverflow.Ellipsis,
maxLines = 1,
)
}
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 = {},
onButtonClicked = {},
loadWallpaperResource = { null },
onSelectWallpaper = {}
)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
/* 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.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

/**
* 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
}.value ?: listOf()
val currentWallpaper = appStore.observeAsComposableState { state ->
state.wallpaperState.currentWallpaper
}.value ?: Wallpaper.Default

val coroutineScope = rememberCoroutineScope()

WallpaperOnboarding(
wallpapers = wallpapers,
currentWallpaper = currentWallpaper,
onCloseClicked = { dismiss() },
onButtonClicked = {
val directions = NavGraphDirections.actionGlobalWallpaperSettingsFragment()
findNavController().navigate(directions)
},
loadWallpaperResource = { wallpaperUseCases.loadThumbnail(it) },
onSelectWallpaper = {
coroutineScope.launch { wallpaperUseCases.selectWallpaper(it) }
}
)
}
}
}
}
9 changes: 9 additions & 0 deletions app/src/main/res/navigation/nav_graph.xml
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,11 @@
app:destination="@id/homeOnboardingDialogFragment"
app:popUpTo="@id/homeFragment" />

<action
android:id="@+id/action_global_wallpaper_onboarding_dialog"
app:destination="@id/wallpaperOnboardingDialogFragment"
app:popUpTo="@id/homeFragment" />

<action
android:id="@+id/action_global_search_dialog"
app:destination="@id/searchDialogFragment"
Expand Down Expand Up @@ -189,6 +194,10 @@
android:id="@+id/homeOnboardingDialogFragment"
android:name="org.mozilla.fenix.onboarding.HomeOnboardingDialogFragment" />

<dialog
android:id="@+id/wallpaperOnboardingDialogFragment"
android:name="org.mozilla.fenix.wallpapers.WallpaperOnboardingDialogFragment" />

<dialog
android:id="@+id/searchDialogFragment"
android:name="org.mozilla.fenix.search.SearchDialogFragment"
Expand Down
Loading

0 comments on commit fbc7e3c

Please sign in to comment.