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

Commit

Permalink
Closes #26211: Download wallpapers when thumbnails clicked
Browse files Browse the repository at this point in the history
  • Loading branch information
MatthewTighe committed Aug 23, 2022
1 parent c17a084 commit f89203b
Show file tree
Hide file tree
Showing 14 changed files with 269 additions and 75 deletions.
11 changes: 10 additions & 1 deletion app/src/main/java/org/mozilla/fenix/components/UseCases.kt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand Down Expand Up @@ -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)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -161,5 +161,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()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -199,6 +199,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)
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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) },
)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
Expand Down
4 changes: 3 additions & 1 deletion app/src/main/java/org/mozilla/fenix/wallpapers/Wallpaper.kt
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,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.
Expand Down Expand Up @@ -67,6 +68,7 @@ data class Wallpaper(
textColor = null,
cardColor = null,
thumbnailFileState = ImageFileState.Downloaded,
assetsFileState = ImageFileState.Downloaded,
)

/**
Expand Down Expand Up @@ -106,7 +108,7 @@ data class Wallpaper(
* Defines the download state of wallpaper asset.
*/
enum class ImageFileState {
NotAvailable,
Unavailable,
Downloading,
Downloaded,
Error,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -83,7 +92,7 @@ class WallpaperDownloader(
localFile.delete()
}
}
Wallpaper.ImageFileState.Downloaded
Wallpaper.ImageFileState.Error
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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()
}

/**
Expand All @@ -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)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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,
)
}
}
Expand Down
Loading

0 comments on commit f89203b

Please sign in to comment.