From dd7c2f7eeccdfb9e2cea8ce79bc4fff0ec0dc79f Mon Sep 17 00:00:00 2001 From: mike a Date: Thu, 15 Sep 2022 13:52:40 -0700 Subject: [PATCH] [fenix] Closes https://github.com/mozilla-mobile/fenix/issues/26995: add sorting of wallpapers on wallpapers onboarding tool --- .../WallpaperOnboardingDialogFragment.kt | 10 +- .../fenix/settings/wallpaper/Extensions.kt | 67 ++++++++++--- .../settings/wallpaper/ExtensionsTest.kt | 97 +++++++++++++++++++ 3 files changed, 160 insertions(+), 14 deletions(-) diff --git a/app/src/main/java/org/mozilla/fenix/onboarding/WallpaperOnboardingDialogFragment.kt b/app/src/main/java/org/mozilla/fenix/onboarding/WallpaperOnboardingDialogFragment.kt index 765e44a1a8..fd42b1b572 100644 --- a/app/src/main/java/org/mozilla/fenix/onboarding/WallpaperOnboardingDialogFragment.kt +++ b/app/src/main/java/org/mozilla/fenix/onboarding/WallpaperOnboardingDialogFragment.kt @@ -28,6 +28,7 @@ import org.mozilla.fenix.components.FenixSnackbar import org.mozilla.fenix.ext.components import org.mozilla.fenix.ext.requireComponents import org.mozilla.fenix.ext.settings +import org.mozilla.fenix.settings.wallpaper.getWallpapersForOnboarding import org.mozilla.fenix.theme.FirefoxTheme import org.mozilla.fenix.wallpapers.Wallpaper import org.mozilla.fenix.wallpapers.WallpaperOnboarding @@ -84,7 +85,7 @@ class WallpaperOnboardingDialogFragment : BottomSheetDialogFragment() { setContent { FirefoxTheme { val wallpapers = appStore.observeAsComposableState { state -> - state.wallpaperState.availableWallpapers.take(THUMBNAILS_SELECTION_COUNT) + state.wallpaperState.availableWallpapers.getWallpapersForOnboarding() }.value ?: listOf() val currentWallpaper = appStore.observeAsComposableState { state -> state.wallpaperState.currentWallpaper @@ -147,6 +148,13 @@ class WallpaperOnboardingDialogFragment : BottomSheetDialogFragment() { } companion object { + // The number of wallpaper thumbnails to display. const val THUMBNAILS_SELECTION_COUNT = 6 + + // The desired amount of seasonal wallpapers inside of the selector. + const val SEASONAL_WALLPAPERS_COUNT = 3 + + // The desired amount of seasonal wallpapers inside of the selector. + const val CLASSIC_WALLPAPERS_COUNT = 2 } } diff --git a/app/src/main/java/org/mozilla/fenix/settings/wallpaper/Extensions.kt b/app/src/main/java/org/mozilla/fenix/settings/wallpaper/Extensions.kt index 724ba8e60b..32cbbbb3eb 100644 --- a/app/src/main/java/org/mozilla/fenix/settings/wallpaper/Extensions.kt +++ b/app/src/main/java/org/mozilla/fenix/settings/wallpaper/Extensions.kt @@ -4,24 +4,65 @@ package org.mozilla.fenix.settings.wallpaper +import org.mozilla.fenix.onboarding.WallpaperOnboardingDialogFragment.Companion.CLASSIC_WALLPAPERS_COUNT +import org.mozilla.fenix.onboarding.WallpaperOnboardingDialogFragment.Companion.SEASONAL_WALLPAPERS_COUNT +import org.mozilla.fenix.onboarding.WallpaperOnboardingDialogFragment.Companion.THUMBNAILS_SELECTION_COUNT import org.mozilla.fenix.wallpapers.Wallpaper /** * The extension function to group wallpapers according to their name. **/ -fun List.groupByDisplayableCollection(): Map> = groupBy { - it.collection -}.filter { - it.key.name != "default" -}.map { - val wallpapers = it.value.filter { wallpaper -> - wallpaper.thumbnailFileState == Wallpaper.ImageFileState.Downloaded +fun List.groupByDisplayableCollection(): Map> = + groupBy { + it.collection + }.filter { + it.key.name != "default" + }.map { + val wallpapers = it.value.filter { wallpaper -> + wallpaper.thumbnailFileState == Wallpaper.ImageFileState.Downloaded + } + if (it.key.name == "classic-firefox") { + it.key to listOf(Wallpaper.Default) + wallpapers + } else { + it.key to wallpapers + } + }.toMap().takeIf { + it.isNotEmpty() + } ?: mapOf(Wallpaper.DefaultCollection to listOf(Wallpaper.Default)) + +/** + * Returns a list of wallpapers to display in the wallpaper onboarding. + * + * The ideal scenario is to return a list of wallpaper in the following order: 1 default, 3 seasonal and + * 2 classic wallpapers, but in case where there are less than 3 seasonal wallpapers, the remaining + * wallpapers are filled by classic wallpapers. If we have less than 6 wallpapers, return all the available + * seasonal and classic wallpapers. + */ +fun List.getWallpapersForOnboarding(): List { + val result = mutableListOf(Wallpaper.Default) + val classicWallpapers = mutableListOf() + val seasonalWallpapers = mutableListOf() + + for (wallpaper in this) { + if (wallpaper == Wallpaper.Default) continue + + if (wallpaper.collection.name == "classic-firefox") { + classicWallpapers.add(wallpaper) + } else { + seasonalWallpapers.add(wallpaper) + } } - if (it.key.name == "classic-firefox") { - it.key to listOf(Wallpaper.Default) + wallpapers + + if (seasonalWallpapers.size < SEASONAL_WALLPAPERS_COUNT) { + result.addAll(seasonalWallpapers) + result.addAll(classicWallpapers.take((THUMBNAILS_SELECTION_COUNT - 1) - seasonalWallpapers.size)) + } else if (classicWallpapers.size < CLASSIC_WALLPAPERS_COUNT) { + result.addAll(seasonalWallpapers.take((THUMBNAILS_SELECTION_COUNT - 1) - classicWallpapers.size)) + result.addAll(classicWallpapers) } else { - it.key to wallpapers + result.addAll(seasonalWallpapers.take(SEASONAL_WALLPAPERS_COUNT)) + result.addAll(classicWallpapers.take(CLASSIC_WALLPAPERS_COUNT)) } -}.toMap().takeIf { - it.isNotEmpty() -} ?: mapOf(Wallpaper.DefaultCollection to listOf(Wallpaper.Default)) + + return result +} diff --git a/app/src/test/java/org/mozilla/fenix/settings/wallpaper/ExtensionsTest.kt b/app/src/test/java/org/mozilla/fenix/settings/wallpaper/ExtensionsTest.kt index f370f33625..58568aa349 100644 --- a/app/src/test/java/org/mozilla/fenix/settings/wallpaper/ExtensionsTest.kt +++ b/app/src/test/java/org/mozilla/fenix/settings/wallpaper/ExtensionsTest.kt @@ -5,6 +5,7 @@ package org.mozilla.fenix.settings.wallpaper import org.junit.Assert.assertEquals +import org.junit.Assert.assertTrue import org.junit.Test import org.mozilla.fenix.wallpapers.Wallpaper @@ -54,6 +55,102 @@ class ExtensionsTest { assertEquals(downloadedSeasonalWallpapers, result[seasonalCollection]) } + @Test + fun `GIVEN two collections of appropriate size WHEN fetched for onboarding THEN result contains 3 seasonal and 2 classic`() { + val seasonalCollection = getSeasonalCollection("finally fall") + val seasonalWallpapers = (0..5).map { generateSeasonalWallpaperCollection("${seasonalCollection.name}$it", seasonalCollection.name) } + val classicFirefoxWallpapers = (0..5).map { generateClassicFirefoxWallpaper("firefox$it") } + val allWallpapers = listOf(Wallpaper.Default) + classicFirefoxWallpapers + seasonalWallpapers + + val result = allWallpapers.getWallpapersForOnboarding() + + assertEquals(3, result.count { it.collection.name == "finally fall" }) + assertEquals(2, result.count { it.collection.name == classicCollection.name }) + assertTrue(result.contains(Wallpaper.Default)) + } + + @Test + fun `GIVEN five collections of insufficient size WHEN fetched for onboarding THEN result contains 3 seasonal and 2 classic`() { + val seasonalCollectionA = getSeasonalCollection("finally winter") + val seasonalWallpapers = generateSeasonalWallpaperCollection("${seasonalCollectionA.name}$0", seasonalCollectionA.name) + val seasonalCollectionB = getSeasonalCollection("finally spring") + val seasonalWallpaperB = generateSeasonalWallpaperCollection("${seasonalCollectionB.name}$0", seasonalCollectionB.name) + val seasonalCollectionC = getSeasonalCollection("finally summer") + val seasonalWallpapersC = generateSeasonalWallpaperCollection("${seasonalCollectionC.name}$0", seasonalCollectionC.name) + val seasonalCollectionD = getSeasonalCollection("finally autumn") + val seasonalWallpaperD = generateSeasonalWallpaperCollection("${seasonalCollectionD.name}$0", seasonalCollectionD.name) + val seasonalCollectionE = getSeasonalCollection("finally vacation") + val seasonalWallpapersE = generateSeasonalWallpaperCollection("${seasonalCollectionE.name}$0", seasonalCollectionE.name) + + val classicFirefoxWallpapers = (0..5).map { generateClassicFirefoxWallpaper("firefox$it") } + val allWallpapers = listOf(Wallpaper.Default) + classicFirefoxWallpapers + seasonalWallpapers + + seasonalWallpaperB + seasonalWallpapersC + seasonalWallpaperD + seasonalWallpapersE + + val result = allWallpapers.getWallpapersForOnboarding() + + assertEquals(3, result.count { it.collection.name != classicCollection.name && it != Wallpaper.Default }) + assertEquals(2, result.count { it.collection.name == classicCollection.name }) + assertTrue(result.contains(Wallpaper.Default)) + } + + @Test + fun `GIVEN seasonal collection of insufficient size WHEN grouped for onboarding THEN result contains all seasonal and the rest is classic`() { + val seasonalCollection = getSeasonalCollection("finally fall") + val seasonalWallpapers = generateSeasonalWallpaperCollection("${seasonalCollection.name}$0", seasonalCollection.name) + val classicFirefoxWallpapers = (0..5).map { generateClassicFirefoxWallpaper("firefox$it") } + val allWallpapers = listOf(Wallpaper.Default) + classicFirefoxWallpapers + seasonalWallpapers + + val result = allWallpapers.getWallpapersForOnboarding() + + assertEquals(1, result.count { it.collection.name == "finally fall" }) + assertEquals(4, result.count { it.collection.name == classicCollection.name }) + assertTrue(result.contains(Wallpaper.Default)) + } + + @Test + fun `GIVEN no seasonal collection WHEN grouped for onboarding THEN result contains all classic`() { + val classicFirefoxWallpapers = (0..5).map { generateClassicFirefoxWallpaper("firefox$it") } + val allWallpapers = listOf(Wallpaper.Default) + classicFirefoxWallpapers + + val result = allWallpapers.getWallpapersForOnboarding() + + assertEquals(5, result.count { it.collection.name == classicCollection.name }) + assertTrue(result.contains(Wallpaper.Default)) + } + + @Test + fun `GIVEN insufficient items in classic collection WHEN grouped for onboarding THEN result contains all classic`() { + val classicFirefoxWallpapers = (0..2).map { generateClassicFirefoxWallpaper("firefox$it") } + val allWallpapers = listOf(Wallpaper.Default) + classicFirefoxWallpapers + + val result = allWallpapers.getWallpapersForOnboarding() + + assertEquals(3, result.count { it.collection.name == classicCollection.name }) + assertTrue(result.contains(Wallpaper.Default)) + } + + @Test + fun `GIVEN no items in classic collection and some seasonal WHEN grouped for onboarding THEN result contains all seasonal`() { + val seasonalCollection = getSeasonalCollection("finally fall") + val seasonalWallpapers = (0..5).map { generateSeasonalWallpaperCollection("${seasonalCollection.name}$it", seasonalCollection.name) } + val allWallpapers = listOf(Wallpaper.Default) + seasonalWallpapers + + val result = allWallpapers.getWallpapersForOnboarding() + + assertEquals(5, result.count { it.collection.name == "finally fall" }) + assertTrue(result.contains(Wallpaper.Default)) + } + + @Test + fun `GIVEN no items WHEN grouped for onboarding THEN result contains the default option`() { + val allWallpapers = listOf(Wallpaper.Default) + + val result = allWallpapers.getWallpapersForOnboarding() + + assertEquals(1, result.size) + assertTrue(result.contains(Wallpaper.Default)) + } + private fun generateClassicFirefoxWallpaper(name: String) = Wallpaper( name = name, textColor = 0L,