mirror of
https://github.com/fork-maintainers/iceraven-browser
synced 2024-11-19 09:25:34 +00:00
[fenix] Closes https://github.com/mozilla-mobile/fenix/issues/26211: Download wallpapers when thumbnails clicked
This commit is contained in:
parent
a3f055a36e
commit
e70f6d19af
@ -5,6 +5,7 @@
|
||||
package org.mozilla.fenix.components
|
||||
|
||||
import android.content.Context
|
||||
import android.os.StrictMode
|
||||
import mozilla.components.browser.state.store.BrowserStore
|
||||
import mozilla.components.concept.engine.Engine
|
||||
import mozilla.components.concept.fetch.Client
|
||||
@ -23,6 +24,7 @@ import mozilla.components.feature.tabs.CustomTabsUseCases
|
||||
import mozilla.components.feature.tabs.TabsUseCases
|
||||
import mozilla.components.feature.top.sites.TopSitesStorage
|
||||
import mozilla.components.feature.top.sites.TopSitesUseCases
|
||||
import mozilla.components.support.locale.LocaleManager
|
||||
import mozilla.components.support.locale.LocaleUseCases
|
||||
import org.mozilla.fenix.components.bookmarks.BookmarksUseCase
|
||||
import org.mozilla.fenix.perf.StrictModeManager
|
||||
@ -107,6 +109,13 @@ class UseCases(
|
||||
val bookmarksUseCases by lazyMonitored { BookmarksUseCase(bookmarksStorage, historyStorage) }
|
||||
|
||||
val wallpaperUseCases by lazyMonitored {
|
||||
WallpapersUseCases(context, appStore, client, strictMode)
|
||||
// Required to even access context.filesDir property and to retrieve current locale
|
||||
val (rootStorageDirectory, currentLocale) = strictMode.resetAfter(StrictMode.allowThreadDiskReads()) {
|
||||
val rootStorageDirectory = context.filesDir
|
||||
val currentLocale = LocaleManager.getCurrentLocale(context)?.toLanguageTag()
|
||||
?: LocaleManager.getSystemDefault().toLanguageTag()
|
||||
rootStorageDirectory to currentLocale
|
||||
}
|
||||
WallpapersUseCases(context, appStore, client, rootStorageDirectory, currentLocale)
|
||||
}
|
||||
}
|
||||
|
@ -169,5 +169,17 @@ sealed class AppAction : Action {
|
||||
* Indicates that the list of potential wallpapers has changed.
|
||||
*/
|
||||
data class UpdateAvailableWallpapers(val wallpapers: List<Wallpaper>) : WallpaperAction()
|
||||
|
||||
/**
|
||||
* Indicates a change in the download state of a wallpaper. Note that this is meant to be
|
||||
* used for full size images, not thumbnails.
|
||||
*
|
||||
* @property wallpaper The wallpaper that is being updated.
|
||||
* @property imageState The updated image state for the wallpaper.
|
||||
*/
|
||||
data class UpdateWallpaperDownloadState(
|
||||
val wallpaper: Wallpaper,
|
||||
val imageState: Wallpaper.ImageFileState
|
||||
) : WallpaperAction()
|
||||
}
|
||||
}
|
||||
|
@ -209,6 +209,17 @@ internal object AppStoreReducer {
|
||||
state.copy(
|
||||
wallpaperState = state.wallpaperState.copy(availableWallpapers = action.wallpapers)
|
||||
)
|
||||
is AppAction.WallpaperAction.UpdateWallpaperDownloadState -> {
|
||||
val wallpapers = state.wallpaperState.availableWallpapers.map {
|
||||
if (it == action.wallpaper) {
|
||||
it.copy(assetsFileState = action.imageState)
|
||||
} else {
|
||||
it
|
||||
}
|
||||
}
|
||||
val wallpaperState = state.wallpaperState.copy(availableWallpapers = wallpapers)
|
||||
state.copy(wallpaperState = wallpaperState)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -8,10 +8,12 @@ import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.compose.runtime.rememberCoroutineScope
|
||||
import androidx.compose.ui.platform.ComposeView
|
||||
import androidx.compose.ui.platform.ViewCompositionStrategy
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.navigation.fragment.findNavController
|
||||
import kotlinx.coroutines.launch
|
||||
import mozilla.components.lib.state.ext.observeAsComposableState
|
||||
import mozilla.components.service.glean.private.NoExtras
|
||||
import org.mozilla.fenix.GleanMetrics.Wallpapers
|
||||
@ -47,12 +49,18 @@ class WallpaperSettingsFragment : Fragment() {
|
||||
state.wallpaperState.currentWallpaper
|
||||
}.value ?: Wallpaper.Default
|
||||
|
||||
var coroutineScope = rememberCoroutineScope()
|
||||
|
||||
WallpaperSettings(
|
||||
wallpapers = wallpapers,
|
||||
defaultWallpaper = Wallpaper.Default,
|
||||
loadWallpaperResource = { wallpaperUseCases.loadBitmap(it) },
|
||||
selectedWallpaper = currentWallpaper,
|
||||
onSelectWallpaper = { wallpaperUseCases.selectWallpaper(it) },
|
||||
loadWallpaperResource = {
|
||||
wallpaperUseCases.loadThumbnail(it)
|
||||
},
|
||||
onSelectWallpaper = {
|
||||
coroutineScope.launch { wallpaperUseCases.selectWallpaper(it) }
|
||||
},
|
||||
onViewWallpaper = { findNavController().navigate(R.id.homeFragment) },
|
||||
)
|
||||
}
|
||||
|
@ -38,7 +38,8 @@ class LegacyWallpaperFileManager(
|
||||
collection = Wallpaper.DefaultCollection,
|
||||
textColor = null,
|
||||
cardColor = null,
|
||||
thumbnailFileState = Wallpaper.ImageFileState.NotAvailable,
|
||||
thumbnailFileState = Wallpaper.ImageFileState.Unavailable,
|
||||
assetsFileState = Wallpaper.ImageFileState.Downloaded,
|
||||
)
|
||||
} else null
|
||||
}
|
||||
|
@ -22,6 +22,7 @@ data class Wallpaper(
|
||||
val textColor: Long?,
|
||||
val cardColor: Long?,
|
||||
val thumbnailFileState: ImageFileState,
|
||||
val assetsFileState: ImageFileState,
|
||||
) {
|
||||
/**
|
||||
* Type that represents a collection that a [Wallpaper] belongs to.
|
||||
@ -68,6 +69,7 @@ data class Wallpaper(
|
||||
textColor = null,
|
||||
cardColor = null,
|
||||
thumbnailFileState = ImageFileState.Downloaded,
|
||||
assetsFileState = ImageFileState.Downloaded,
|
||||
)
|
||||
|
||||
/**
|
||||
@ -104,6 +106,7 @@ data class Wallpaper(
|
||||
cardColor = cardColor,
|
||||
collection = DefaultCollection,
|
||||
thumbnailFileState = ImageFileState.Downloaded,
|
||||
assetsFileState = ImageFileState.Downloaded,
|
||||
)
|
||||
} else null
|
||||
}
|
||||
@ -127,9 +130,21 @@ data class Wallpaper(
|
||||
* Defines the download state of wallpaper asset.
|
||||
*/
|
||||
enum class ImageFileState {
|
||||
NotAvailable,
|
||||
Unavailable,
|
||||
Downloading,
|
||||
Downloaded,
|
||||
Error,
|
||||
}
|
||||
|
||||
override fun hashCode(): Int {
|
||||
return name.hashCode()
|
||||
}
|
||||
|
||||
override fun equals(other: Any?): Boolean {
|
||||
return if (other is Wallpaper) {
|
||||
this.name == other.name
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -37,30 +37,39 @@ class WallpaperDownloader(
|
||||
* and will be stored in the local path:
|
||||
* wallpapers/<wallpaper name>/<orientation>.png
|
||||
*/
|
||||
suspend fun downloadWallpaper(wallpaper: Wallpaper) = withContext(dispatcher) {
|
||||
listOf(Wallpaper.ImageType.Portrait, Wallpaper.ImageType.Landscape).map { imageType ->
|
||||
wallpaper.downloadAsset(imageType)
|
||||
suspend fun downloadWallpaper(wallpaper: Wallpaper): Wallpaper.ImageFileState = withContext(dispatcher) {
|
||||
val portraitResult = downloadAsset(wallpaper, Wallpaper.ImageType.Portrait)
|
||||
val landscapeResult = downloadAsset(wallpaper, Wallpaper.ImageType.Landscape)
|
||||
return@withContext if (portraitResult == Wallpaper.ImageFileState.Downloaded &&
|
||||
landscapeResult == Wallpaper.ImageFileState.Downloaded
|
||||
) {
|
||||
Wallpaper.ImageFileState.Downloaded
|
||||
} else {
|
||||
Wallpaper.ImageFileState.Error
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Downloads a thumbnail for a wallpaper from the network. This is expected to be found remotely
|
||||
* at:
|
||||
* <WALLPAPER_URL>/<collection name>/<wallpaper name>/<orientation>.png
|
||||
* <WALLPAPER_URL>/<collection name>/<wallpaper name>/thumbnail.png
|
||||
* and stored locally at:
|
||||
* wallpapers/<wallpaper name>/<orientation>.png
|
||||
* wallpapers/<wallpaper name>/thumbnail.png
|
||||
*/
|
||||
suspend fun downloadThumbnail(wallpaper: Wallpaper): Wallpaper.ImageFileState = withContext(dispatcher) {
|
||||
wallpaper.downloadAsset(Wallpaper.ImageType.Thumbnail)
|
||||
downloadAsset(wallpaper, Wallpaper.ImageType.Thumbnail)
|
||||
}
|
||||
|
||||
private suspend fun Wallpaper.downloadAsset(
|
||||
private suspend fun downloadAsset(
|
||||
wallpaper: Wallpaper,
|
||||
imageType: Wallpaper.ImageType
|
||||
): Wallpaper.ImageFileState = withContext(dispatcher) {
|
||||
val localFile = File(storageRootDirectory, getLocalPath(name, imageType))
|
||||
if (localFile.exists()) return@withContext Wallpaper.ImageFileState.Downloaded
|
||||
val localFile = File(storageRootDirectory, getLocalPath(wallpaper.name, imageType))
|
||||
if (localFile.exists()) {
|
||||
return@withContext Wallpaper.ImageFileState.Downloaded
|
||||
}
|
||||
|
||||
val remotePath = "${collection.name}/${name}/${imageType.lowercase()}.png"
|
||||
val remotePath = "${wallpaper.collection.name}/${wallpaper.name}/${imageType.lowercase()}.png"
|
||||
val request = Request(
|
||||
url = "$remoteHost/$remotePath",
|
||||
method = Request.Method.GET
|
||||
@ -83,7 +92,7 @@ class WallpaperDownloader(
|
||||
localFile.delete()
|
||||
}
|
||||
}
|
||||
Wallpaper.ImageFileState.Downloaded
|
||||
Wallpaper.ImageFileState.Error
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -31,20 +31,21 @@ class WallpaperFileManager(
|
||||
* files for each of a portrait and landscape orientation as well as a thumbnail.
|
||||
*/
|
||||
suspend fun lookupExpiredWallpaper(name: String): Wallpaper? = withContext(Dispatchers.IO) {
|
||||
if (getAllLocalWallpaperPaths(name).all { File(storageRootDirectory, it).exists() }) {
|
||||
if (allAssetsExist(name)) {
|
||||
Wallpaper(
|
||||
name = name,
|
||||
collection = Wallpaper.DefaultCollection,
|
||||
textColor = null,
|
||||
cardColor = null,
|
||||
thumbnailFileState = Wallpaper.ImageFileState.Downloaded,
|
||||
assetsFileState = Wallpaper.ImageFileState.Downloaded,
|
||||
)
|
||||
} else null
|
||||
}
|
||||
|
||||
private fun getAllLocalWallpaperPaths(name: String): List<String> =
|
||||
Wallpaper.ImageType.values().map { orientation ->
|
||||
getLocalPath(name, orientation)
|
||||
private fun allAssetsExist(name: String): Boolean =
|
||||
Wallpaper.ImageType.values().all { type ->
|
||||
File(storageRootDirectory, getLocalPath(name, type)).exists()
|
||||
}
|
||||
|
||||
/**
|
||||
@ -60,4 +61,11 @@ class WallpaperFileManager(
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether all the assets for a wallpaper exist on the file system.
|
||||
*/
|
||||
suspend fun wallpaperImagesExist(wallpaper: Wallpaper): Boolean = withContext(Dispatchers.IO) {
|
||||
return@withContext allAssetsExist(wallpaper.name)
|
||||
}
|
||||
}
|
||||
|
@ -83,7 +83,8 @@ class WallpaperMetadataFetcher(
|
||||
textColor = getArgbValueAsLong("text-color"),
|
||||
cardColor = getArgbValueAsLong("card-color"),
|
||||
collection = collection,
|
||||
thumbnailFileState = Wallpaper.ImageFileState.NotAvailable,
|
||||
thumbnailFileState = Wallpaper.ImageFileState.Unavailable,
|
||||
assetsFileState = Wallpaper.ImageFileState.Unavailable,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -8,19 +8,16 @@ import android.content.Context
|
||||
import android.content.res.Configuration
|
||||
import android.graphics.Bitmap
|
||||
import android.graphics.BitmapFactory
|
||||
import android.os.StrictMode
|
||||
import androidx.annotation.VisibleForTesting
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.withContext
|
||||
import mozilla.components.concept.fetch.Client
|
||||
import mozilla.components.support.locale.LocaleManager
|
||||
import org.mozilla.fenix.FeatureFlags
|
||||
import org.mozilla.fenix.GleanMetrics.Wallpapers
|
||||
import org.mozilla.fenix.R
|
||||
import org.mozilla.fenix.components.AppStore
|
||||
import org.mozilla.fenix.components.appstate.AppAction
|
||||
import org.mozilla.fenix.ext.settings
|
||||
import org.mozilla.fenix.perf.StrictModeManager
|
||||
import org.mozilla.fenix.utils.Settings
|
||||
import java.io.File
|
||||
import java.util.Date
|
||||
@ -31,7 +28,8 @@ import java.util.Date
|
||||
* @param context Used for various file and configuration checks.
|
||||
* @param store Will receive dispatches of metadata updates like the currently selected wallpaper.
|
||||
* @param client Handles downloading wallpapers and their metadata.
|
||||
* @param strictMode Required for determining some device state like current locale and file paths.
|
||||
* @param storageRootDirectory The top level app-local storage directory.
|
||||
* @param currentLocale The locale currently being used on the device.
|
||||
*
|
||||
* @property initialize Usecase for initializing wallpaper feature. Should usually be called early
|
||||
* in the app's lifetime to ensure that any potential long-running tasks can complete quickly.
|
||||
@ -42,20 +40,13 @@ class WallpapersUseCases(
|
||||
context: Context,
|
||||
store: AppStore,
|
||||
client: Client,
|
||||
strictMode: StrictModeManager,
|
||||
filesDir: File,
|
||||
storageRootDirectory: File,
|
||||
currentLocale: String,
|
||||
) {
|
||||
private val downloader = WallpaperDownloader(storageRootDirectory, client)
|
||||
private val fileManager = WallpaperFileManager(storageRootDirectory)
|
||||
val initialize: InitializeWallpapersUseCase by lazy {
|
||||
if (FeatureFlags.wallpaperV2Enabled) {
|
||||
// Required to even access context.filesDir property and to retrieve current locale
|
||||
val (storageRootDirectory, currentLocale) = strictMode.resetAfter(StrictMode.allowThreadDiskReads()) {
|
||||
val storageRootDirectory = context.filesDir
|
||||
val currentLocale = LocaleManager.getCurrentLocale(context)?.toLanguageTag()
|
||||
?: LocaleManager.getSystemDefault().toLanguageTag()
|
||||
storageRootDirectory to currentLocale
|
||||
}
|
||||
val downloader = WallpaperDownloader(storageRootDirectory, client)
|
||||
val fileManager = WallpaperFileManager(storageRootDirectory)
|
||||
val metadataFetcher = WallpaperMetadataFetcher(client)
|
||||
DefaultInitializeWallpaperUseCase(
|
||||
store = store,
|
||||
@ -66,13 +57,7 @@ class WallpapersUseCases(
|
||||
currentLocale = currentLocale
|
||||
)
|
||||
} else {
|
||||
// Required to even access context.filesDir property and to retrieve current locale
|
||||
val (fileManager, currentLocale) = strictMode.resetAfter(StrictMode.allowThreadDiskReads()) {
|
||||
val fileManager = LegacyWallpaperFileManager(context.filesDir)
|
||||
val currentLocale = LocaleManager.getCurrentLocale(context)?.toLanguageTag()
|
||||
?: LocaleManager.getSystemDefault().toLanguageTag()
|
||||
fileManager to currentLocale
|
||||
}
|
||||
val fileManager = LegacyWallpaperFileManager(storageRootDirectory)
|
||||
val downloader = LegacyWallpaperDownloader(context, client)
|
||||
LegacyInitializeWallpaperUseCase(
|
||||
store = store,
|
||||
@ -92,12 +77,18 @@ class WallpapersUseCases(
|
||||
}
|
||||
val loadThumbnail: LoadThumbnailUseCase by lazy {
|
||||
if (FeatureFlags.wallpaperV2Enabled) {
|
||||
DefaultLoadThumbnailUseCase(filesDir)
|
||||
DefaultLoadThumbnailUseCase(storageRootDirectory)
|
||||
} else {
|
||||
LegacyLoadThumbnailUseCase(context)
|
||||
}
|
||||
}
|
||||
val selectWallpaper: SelectWallpaperUseCase by lazy { DefaultSelectWallpaperUseCase(context.settings(), store) }
|
||||
val selectWallpaper: SelectWallpaperUseCase by lazy {
|
||||
if (FeatureFlags.wallpaperV2Enabled) {
|
||||
DefaultSelectWallpaperUseCase(context.settings(), store, fileManager, downloader)
|
||||
} else {
|
||||
LegacySelectWallpaperUseCase(context.settings(), store)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Contract for usecases that initialize the wallpaper feature.
|
||||
@ -190,21 +181,24 @@ class WallpapersUseCases(
|
||||
collection = firefoxClassicCollection,
|
||||
textColor = null,
|
||||
cardColor = null,
|
||||
thumbnailFileState = Wallpaper.ImageFileState.NotAvailable,
|
||||
thumbnailFileState = Wallpaper.ImageFileState.Unavailable,
|
||||
assetsFileState = Wallpaper.ImageFileState.Downloaded,
|
||||
),
|
||||
Wallpaper(
|
||||
name = Wallpaper.ceruleanName,
|
||||
collection = firefoxClassicCollection,
|
||||
textColor = null,
|
||||
cardColor = null,
|
||||
thumbnailFileState = Wallpaper.ImageFileState.NotAvailable,
|
||||
thumbnailFileState = Wallpaper.ImageFileState.Unavailable,
|
||||
assetsFileState = Wallpaper.ImageFileState.Downloaded,
|
||||
),
|
||||
Wallpaper(
|
||||
name = Wallpaper.sunriseName,
|
||||
collection = firefoxClassicCollection,
|
||||
textColor = null,
|
||||
cardColor = null,
|
||||
thumbnailFileState = Wallpaper.ImageFileState.NotAvailable,
|
||||
thumbnailFileState = Wallpaper.ImageFileState.Unavailable,
|
||||
assetsFileState = Wallpaper.ImageFileState.Downloaded,
|
||||
),
|
||||
)
|
||||
private val remoteWallpapers: List<Wallpaper> = listOf(
|
||||
@ -213,14 +207,16 @@ class WallpapersUseCases(
|
||||
collection = firefoxClassicCollection,
|
||||
textColor = null,
|
||||
cardColor = null,
|
||||
thumbnailFileState = Wallpaper.ImageFileState.NotAvailable,
|
||||
thumbnailFileState = Wallpaper.ImageFileState.Unavailable,
|
||||
assetsFileState = Wallpaper.ImageFileState.Downloaded,
|
||||
),
|
||||
Wallpaper(
|
||||
name = Wallpaper.beachVibeName,
|
||||
collection = firefoxClassicCollection,
|
||||
textColor = null,
|
||||
cardColor = null,
|
||||
thumbnailFileState = Wallpaper.ImageFileState.NotAvailable,
|
||||
thumbnailFileState = Wallpaper.ImageFileState.Unavailable,
|
||||
assetsFileState = Wallpaper.ImageFileState.Downloaded,
|
||||
),
|
||||
)
|
||||
val allWallpapers = listOf(Wallpaper.Default) + localWallpapers + remoteWallpapers
|
||||
@ -257,8 +253,6 @@ class WallpapersUseCases(
|
||||
possibleWallpapers
|
||||
)
|
||||
|
||||
possibleWallpapers.forEach { downloader.downloadWallpaper(it) }
|
||||
|
||||
val wallpapersWithUpdatedThumbnailState = possibleWallpapers.map { wallpaper ->
|
||||
val result = downloader.downloadThumbnail(wallpaper)
|
||||
wallpaper.copy(thumbnailFileState = result)
|
||||
@ -401,13 +395,13 @@ class WallpapersUseCases(
|
||||
}
|
||||
|
||||
@VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
|
||||
internal class LegacyLoadThumbnailUseCase(private val context: Context): LoadThumbnailUseCase {
|
||||
internal class LegacyLoadThumbnailUseCase(private val context: Context) : LoadThumbnailUseCase {
|
||||
override suspend fun invoke(wallpaper: Wallpaper): Bitmap? =
|
||||
LegacyLoadBitmapUseCase(context).invoke(wallpaper)
|
||||
}
|
||||
|
||||
@VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
|
||||
internal class DefaultLoadThumbnailUseCase(private val filesDir: File): LoadThumbnailUseCase {
|
||||
internal class DefaultLoadThumbnailUseCase(private val filesDir: File) : LoadThumbnailUseCase {
|
||||
override suspend fun invoke(wallpaper: Wallpaper): Bitmap? = withContext(Dispatchers.IO) {
|
||||
Result.runCatching {
|
||||
val path = Wallpaper.getLocalPath(wallpaper.name, Wallpaper.ImageType.Thumbnail)
|
||||
@ -428,11 +422,11 @@ class WallpapersUseCases(
|
||||
*
|
||||
* @param wallpaper The selected wallpaper.
|
||||
*/
|
||||
operator fun invoke(wallpaper: Wallpaper)
|
||||
suspend operator fun invoke(wallpaper: Wallpaper)
|
||||
}
|
||||
|
||||
@VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
|
||||
internal class DefaultSelectWallpaperUseCase(
|
||||
internal class LegacySelectWallpaperUseCase(
|
||||
private val settings: Settings,
|
||||
private val store: AppStore,
|
||||
) : SelectWallpaperUseCase {
|
||||
@ -441,7 +435,7 @@ class WallpapersUseCases(
|
||||
*
|
||||
* @param wallpaper The selected wallpaper.
|
||||
*/
|
||||
override fun invoke(wallpaper: Wallpaper) {
|
||||
override suspend fun invoke(wallpaper: Wallpaper) {
|
||||
settings.currentWallpaperName = wallpaper.name
|
||||
settings.currentWallpaperTextColor = wallpaper.textColor ?: 0
|
||||
settings.currentWallpaperCardColor = wallpaper.cardColor ?: 0
|
||||
@ -454,4 +448,46 @@ class WallpapersUseCases(
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
|
||||
internal class DefaultSelectWallpaperUseCase(
|
||||
private val settings: Settings,
|
||||
private val store: AppStore,
|
||||
private val fileManager: WallpaperFileManager,
|
||||
private val downloader: WallpaperDownloader,
|
||||
) : SelectWallpaperUseCase {
|
||||
/**
|
||||
* Select a new wallpaper. Storage and the store will be updated appropriately.
|
||||
*
|
||||
* @param wallpaper The selected wallpaper.
|
||||
*/
|
||||
override suspend fun invoke(wallpaper: Wallpaper) {
|
||||
if (wallpaper == Wallpaper.Default || fileManager.wallpaperImagesExist(wallpaper)) {
|
||||
selectWallpaper(wallpaper)
|
||||
dispatchDownloadState(wallpaper, Wallpaper.ImageFileState.Downloaded)
|
||||
} else {
|
||||
dispatchDownloadState(wallpaper, Wallpaper.ImageFileState.Downloading)
|
||||
val result = downloader.downloadWallpaper(wallpaper)
|
||||
dispatchDownloadState(wallpaper, result)
|
||||
if (result == Wallpaper.ImageFileState.Downloaded) {
|
||||
selectWallpaper(wallpaper)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun selectWallpaper(wallpaper: Wallpaper) {
|
||||
settings.currentWallpaperName = wallpaper.name
|
||||
store.dispatch(AppAction.WallpaperAction.UpdateCurrentWallpaper(wallpaper))
|
||||
Wallpapers.wallpaperSelected.record(
|
||||
Wallpapers.WallpaperSelectedExtra(
|
||||
name = wallpaper.name,
|
||||
themeCollection = wallpaper.collection.name
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
private fun dispatchDownloadState(wallpaper: Wallpaper, downloadState: Wallpaper.ImageFileState) {
|
||||
store.dispatch(AppAction.WallpaperAction.UpdateWallpaperDownloadState(wallpaper, downloadState))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -98,7 +98,8 @@ class LegacyWallpaperFileManagerTest {
|
||||
name = name,
|
||||
textColor = null,
|
||||
cardColor = null,
|
||||
thumbnailFileState = Wallpaper.ImageFileState.NotAvailable,
|
||||
thumbnailFileState = Wallpaper.ImageFileState.Unavailable,
|
||||
assetsFileState = Wallpaper.ImageFileState.Downloaded,
|
||||
collection = Wallpaper.Collection(
|
||||
name = Wallpaper.defaultName,
|
||||
heading = null,
|
||||
|
@ -74,10 +74,7 @@ class WallpaperDownloaderTest {
|
||||
@Test
|
||||
fun `GIVEN that thumbnail request is successful WHEN downloading THEN file is created in expected location`() = runTest {
|
||||
val wallpaper = generateWallpaper()
|
||||
val thumbnailRequest = Request(
|
||||
url = "$remoteHost/${wallpaper.collection.name}/${wallpaper.name}/thumbnail.png",
|
||||
method = Request.Method.GET
|
||||
)
|
||||
val thumbnailRequest = wallpaper.generateRequest("thumbnail")
|
||||
val mockThumbnailResponse = mockk<Response>()
|
||||
every { mockThumbnailResponse.status } returns 200
|
||||
every { mockThumbnailResponse.body } returns Response.Body(wallpaperBytes.byteInputStream())
|
||||
@ -132,7 +129,8 @@ class WallpaperDownloaderTest {
|
||||
collection = wallpaperCollection,
|
||||
textColor = null,
|
||||
cardColor = null,
|
||||
thumbnailFileState = Wallpaper.ImageFileState.NotAvailable
|
||||
thumbnailFileState = Wallpaper.ImageFileState.Unavailable,
|
||||
assetsFileState = Wallpaper.ImageFileState.Unavailable,
|
||||
)
|
||||
|
||||
private fun Wallpaper.generateRequest(type: String) = Request(
|
||||
|
@ -3,6 +3,7 @@ package org.mozilla.fenix.wallpapers
|
||||
import kotlinx.coroutines.test.UnconfinedTestDispatcher
|
||||
import kotlinx.coroutines.test.runTest
|
||||
import org.junit.Assert.assertEquals
|
||||
import org.junit.Assert.assertFalse
|
||||
import org.junit.Assert.assertTrue
|
||||
import org.junit.Before
|
||||
import org.junit.Rule
|
||||
@ -109,6 +110,30 @@ class WallpaperFileManagerTest {
|
||||
assertTrue(getAllFiles(unavailableName).none { it.exists() })
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `WHEN both wallpaper assets exist THEN the file lookup will succeed`() = runTest {
|
||||
val wallpaper = generateWallpaper("name")
|
||||
createAllFiles(wallpaper.name)
|
||||
|
||||
val result = fileManager.wallpaperImagesExist(wallpaper)
|
||||
|
||||
assertTrue(result)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `WHEN at least one wallpaper asset does not exist THEN the file lookup will fail`() = runTest {
|
||||
val wallpaper = generateWallpaper("name")
|
||||
val allFiles = getAllFiles(wallpaper.name)
|
||||
(0 until (allFiles.size - 1)).forEach {
|
||||
allFiles[it].mkdirs()
|
||||
allFiles[it].createNewFile()
|
||||
}
|
||||
|
||||
val result = fileManager.wallpaperImagesExist(wallpaper)
|
||||
|
||||
assertFalse(result)
|
||||
}
|
||||
|
||||
private fun createAllFiles(name: String) {
|
||||
for (file in getAllFiles(name)) {
|
||||
file.mkdirs()
|
||||
@ -131,6 +156,7 @@ class WallpaperFileManagerTest {
|
||||
textColor = null,
|
||||
cardColor = null,
|
||||
thumbnailFileState = Wallpaper.ImageFileState.Downloaded,
|
||||
collection = Wallpaper.DefaultCollection
|
||||
assetsFileState = Wallpaper.ImageFileState.Downloaded,
|
||||
collection = Wallpaper.DefaultCollection,
|
||||
)
|
||||
}
|
||||
|
@ -22,6 +22,7 @@ import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.mozilla.fenix.GleanMetrics.Wallpapers
|
||||
import org.mozilla.fenix.components.AppStore
|
||||
import org.mozilla.fenix.components.appstate.AppAction
|
||||
import org.mozilla.fenix.utils.Settings
|
||||
import java.util.Calendar
|
||||
import java.util.Date
|
||||
@ -319,11 +320,11 @@ class WallpapersUseCasesTest {
|
||||
}
|
||||
val expiredWallpaper = makeFakeRemoteWallpaper(TimeRelation.BEFORE, "expired")
|
||||
val allWallpapers = listOf(expiredWallpaper) + fakeRemoteWallpapers
|
||||
every { mockSettings.currentWallpaperName } returns "expired"
|
||||
coEvery { mockFileManager.lookupExpiredWallpaper(any()) } returns expiredWallpaper
|
||||
coEvery { mockMetadataFetcher.downloadWallpaperList() } returns allWallpapers
|
||||
coEvery { mockDownloader.downloadThumbnail(any()) } returns Wallpaper.ImageFileState.Downloaded
|
||||
|
||||
|
||||
WallpapersUseCases.DefaultInitializeWallpaperUseCase(
|
||||
appStore,
|
||||
mockDownloader,
|
||||
@ -366,7 +367,7 @@ class WallpapersUseCasesTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `GIVEN available wallpapers WHEN invoking initialize use case THEN available wallpapers downloaded`() = runTest {
|
||||
fun `GIVEN available wallpapers WHEN invoking initialize use case THEN available wallpaper thumbnails downloaded`() = runTest {
|
||||
val fakeRemoteWallpapers = listOf("first", "second", "third").map { name ->
|
||||
makeFakeRemoteWallpaper(TimeRelation.LATER, name)
|
||||
}
|
||||
@ -385,12 +386,12 @@ class WallpapersUseCasesTest {
|
||||
).invoke()
|
||||
|
||||
for (fakeRemoteWallpaper in fakeRemoteWallpapers) {
|
||||
coVerify { mockDownloader.downloadWallpaper(fakeRemoteWallpaper) }
|
||||
coVerify { mockDownloader.downloadThumbnail(fakeRemoteWallpaper) }
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `GIVEN available wallpapers WHEN invoking initialize use case THEN thumbnails downloaded and store state reflects that`() = runTest {
|
||||
fun `GIVEN available wallpapers WHEN invoking initialize use case THEN thumbnails downloaded and the store state is updated to reflect that`() = runTest {
|
||||
val fakeRemoteWallpapers = listOf("first", "second", "third").map { name ->
|
||||
makeFakeRemoteWallpaper(TimeRelation.LATER, name)
|
||||
}
|
||||
@ -412,13 +413,15 @@ class WallpapersUseCasesTest {
|
||||
coVerify { mockDownloader.downloadThumbnail(fakeRemoteWallpaper) }
|
||||
}
|
||||
appStore.waitUntilIdle()
|
||||
assertTrue(appStore.state.wallpaperState.availableWallpapers.all {
|
||||
it.thumbnailFileState == Wallpaper.ImageFileState.Downloaded
|
||||
})
|
||||
assertTrue(
|
||||
appStore.state.wallpaperState.availableWallpapers.all {
|
||||
it.thumbnailFileState == Wallpaper.ImageFileState.Downloaded
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `GIVEN thumbnail download fails WHEN invoking initialize use case THEN store state reflects that`() = runTest {
|
||||
fun `GIVEN thumbnail download fails WHEN invoking initialize use case THEN the store state is updated to reflect that`() = runTest {
|
||||
val fakeRemoteWallpapers = listOf("first", "second", "third").map { name ->
|
||||
makeFakeRemoteWallpaper(TimeRelation.LATER, name)
|
||||
}
|
||||
@ -496,14 +499,14 @@ class WallpapersUseCasesTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `WHEN selected wallpaper usecase invoked THEN storage updated and store receives dispatch`() {
|
||||
fun `WHEN legacy selected wallpaper usecase invoked THEN storage updated and store receives dispatch`() = runTest {
|
||||
val selectedWallpaper = makeFakeRemoteWallpaper(TimeRelation.LATER, "selected")
|
||||
val slot = slot<String>()
|
||||
coEvery { mockFileManager.lookupExpiredWallpaper(any()) } returns null
|
||||
every { mockSettings.currentWallpaperName } returns ""
|
||||
every { mockSettings.currentWallpaperName = capture(slot) } just runs
|
||||
|
||||
WallpapersUseCases.DefaultSelectWallpaperUseCase(
|
||||
WallpapersUseCases.LegacySelectWallpaperUseCase(
|
||||
mockSettings,
|
||||
appStore
|
||||
).invoke(selectedWallpaper)
|
||||
@ -514,6 +517,73 @@ class WallpapersUseCasesTest {
|
||||
assertEquals(selectedWallpaper.name, Wallpapers.wallpaperSelected.testGetValue()?.first()?.extra?.get("name")!!)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `GIVEN wallpaper downloaded WHEN selecting a wallpaper THEN storage updated and store receives dispatch`() = runTest {
|
||||
val selectedWallpaper = makeFakeRemoteWallpaper(TimeRelation.LATER, "selected")
|
||||
val slot = slot<String>()
|
||||
coEvery { mockFileManager.lookupExpiredWallpaper(any()) } returns null
|
||||
every { mockSettings.currentWallpaperName } returns ""
|
||||
every { mockSettings.currentWallpaperName = capture(slot) } just runs
|
||||
coEvery { mockFileManager.wallpaperImagesExist(selectedWallpaper) } returns true
|
||||
|
||||
WallpapersUseCases.DefaultSelectWallpaperUseCase(
|
||||
mockSettings,
|
||||
appStore,
|
||||
mockFileManager,
|
||||
mockDownloader,
|
||||
).invoke(selectedWallpaper)
|
||||
|
||||
appStore.waitUntilIdle()
|
||||
assertEquals(selectedWallpaper.name, slot.captured)
|
||||
assertEquals(selectedWallpaper, appStore.state.wallpaperState.currentWallpaper)
|
||||
assertEquals(selectedWallpaper.name, Wallpapers.wallpaperSelected.testGetValue()?.first()?.extra?.get("name")!!)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `GIVEN wallpaper is not downloaded WHEN selecting a wallpaper and download succeeds THEN storage updated and store receives dispatch`() = runTest {
|
||||
val selectedWallpaper = makeFakeRemoteWallpaper(TimeRelation.LATER, "selected")
|
||||
val slot = slot<String>()
|
||||
val mockStore = mockk<AppStore>(relaxed = true)
|
||||
coEvery { mockFileManager.lookupExpiredWallpaper(any()) } returns null
|
||||
every { mockSettings.currentWallpaperName } returns ""
|
||||
every { mockSettings.currentWallpaperName = capture(slot) } just runs
|
||||
coEvery { mockFileManager.wallpaperImagesExist(selectedWallpaper) } returns false
|
||||
coEvery { mockDownloader.downloadWallpaper(selectedWallpaper) } returns Wallpaper.ImageFileState.Downloaded
|
||||
|
||||
WallpapersUseCases.DefaultSelectWallpaperUseCase(
|
||||
mockSettings,
|
||||
mockStore,
|
||||
mockFileManager,
|
||||
mockDownloader,
|
||||
).invoke(selectedWallpaper)
|
||||
|
||||
verify { mockStore.dispatch(AppAction.WallpaperAction.UpdateWallpaperDownloadState(selectedWallpaper, Wallpaper.ImageFileState.Downloading)) }
|
||||
verify { mockStore.dispatch(AppAction.WallpaperAction.UpdateWallpaperDownloadState(selectedWallpaper, Wallpaper.ImageFileState.Downloaded)) }
|
||||
verify { mockStore.dispatch(AppAction.WallpaperAction.UpdateCurrentWallpaper(selectedWallpaper)) }
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `GIVEN wallpaper is not downloaded WHEN selecting a wallpaper and any download fails THEN wallpaper not set and store receives dispatch`() = runTest {
|
||||
val selectedWallpaper = makeFakeRemoteWallpaper(TimeRelation.LATER, "selected")
|
||||
val slot = slot<String>()
|
||||
val mockStore = mockk<AppStore>(relaxed = true)
|
||||
coEvery { mockFileManager.lookupExpiredWallpaper(any()) } returns null
|
||||
every { mockSettings.currentWallpaperName } returns ""
|
||||
every { mockSettings.currentWallpaperName = capture(slot) } just runs
|
||||
coEvery { mockFileManager.wallpaperImagesExist(selectedWallpaper) } returns false
|
||||
coEvery { mockDownloader.downloadWallpaper(selectedWallpaper) } returns Wallpaper.ImageFileState.Error
|
||||
|
||||
WallpapersUseCases.DefaultSelectWallpaperUseCase(
|
||||
mockSettings,
|
||||
mockStore,
|
||||
mockFileManager,
|
||||
mockDownloader,
|
||||
).invoke(selectedWallpaper)
|
||||
|
||||
verify { mockStore.dispatch(AppAction.WallpaperAction.UpdateWallpaperDownloadState(selectedWallpaper, Wallpaper.ImageFileState.Downloading)) }
|
||||
verify { mockStore.dispatch(AppAction.WallpaperAction.UpdateWallpaperDownloadState(selectedWallpaper, Wallpaper.ImageFileState.Error)) }
|
||||
}
|
||||
|
||||
private enum class TimeRelation {
|
||||
BEFORE,
|
||||
NOW,
|
||||
@ -549,7 +619,8 @@ class WallpapersUseCasesTest {
|
||||
),
|
||||
textColor = null,
|
||||
cardColor = null,
|
||||
thumbnailFileState = Wallpaper.ImageFileState.NotAvailable,
|
||||
thumbnailFileState = Wallpaper.ImageFileState.Unavailable,
|
||||
assetsFileState = Wallpaper.ImageFileState.Unavailable,
|
||||
)
|
||||
} else {
|
||||
Wallpaper(
|
||||
@ -565,7 +636,8 @@ class WallpapersUseCasesTest {
|
||||
),
|
||||
textColor = null,
|
||||
cardColor = null,
|
||||
thumbnailFileState = Wallpaper.ImageFileState.NotAvailable,
|
||||
thumbnailFileState = Wallpaper.ImageFileState.Unavailable,
|
||||
assetsFileState = Wallpaper.ImageFileState.Unavailable,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user