[fenix] Fixes https://github.com/mozilla-mobile/fenix/issues/26245: refactor the WallpaperManager as several WallpaperUseCases
parent
4ee1f0ea64
commit
346427f73a
@ -0,0 +1,48 @@
|
||||
package org.mozilla.fenix.ext
|
||||
|
||||
import android.graphics.Bitmap
|
||||
import android.graphics.Matrix
|
||||
import android.view.View
|
||||
import android.widget.ImageView
|
||||
|
||||
/**
|
||||
* This will scale the received [Bitmap] to the size of the [view]. It retains the bitmap's
|
||||
* original aspect ratio, but will shrink or enlarge it to fit the viewport. If bitmap does not
|
||||
* correctly fit the aspect ratio of the view, it will be shifted to prioritize the bottom-left
|
||||
* of the bitmap.
|
||||
*/
|
||||
fun Bitmap.scaleToBottomOfView(view: ImageView) {
|
||||
val bitmap = this
|
||||
view.setImageBitmap(bitmap)
|
||||
view.scaleType = ImageView.ScaleType.MATRIX
|
||||
val matrix = Matrix()
|
||||
view.addOnLayoutChangeListener(object : View.OnLayoutChangeListener {
|
||||
override fun onLayoutChange(
|
||||
v: View?,
|
||||
left: Int,
|
||||
top: Int,
|
||||
right: Int,
|
||||
bottom: Int,
|
||||
oldLeft: Int,
|
||||
oldTop: Int,
|
||||
oldRight: Int,
|
||||
oldBottom: Int
|
||||
) {
|
||||
val viewWidth: Float = view.width.toFloat()
|
||||
val viewHeight: Float = view.height.toFloat()
|
||||
val bitmapWidth = bitmap.width
|
||||
val bitmapHeight = bitmap.height
|
||||
val widthScale = viewWidth / bitmapWidth
|
||||
val heightScale = viewHeight / bitmapHeight
|
||||
val scale = widthScale.coerceAtLeast(heightScale)
|
||||
matrix.postScale(scale, scale)
|
||||
// The image is translated to its bottom such that any pertinent information is
|
||||
// guaranteed to be shown.
|
||||
// Majority of this math borrowed from // https://medium.com/@tokudu/how-to-whitelist-strictmode-violations-on-android-based-on-stacktrace-eb0018e909aa
|
||||
// except that there is no need to translate horizontally in our case.
|
||||
matrix.postTranslate(0f, (viewHeight - bitmapHeight * scale))
|
||||
view.imageMatrix = matrix
|
||||
view.removeOnLayoutChangeListener(this)
|
||||
}
|
||||
})
|
||||
}
|
@ -0,0 +1,255 @@
|
||||
/* 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.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.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
|
||||
|
||||
/**
|
||||
* Contains use cases related to the wallpaper feature.
|
||||
*
|
||||
* @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.
|
||||
*
|
||||
* @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.
|
||||
* @property loadBitmap Usecase for loading specific wallpaper bitmaps.
|
||||
* @property selectWallpaper Usecase for selecting a new wallpaper.
|
||||
*/
|
||||
class WallpapersUseCases(
|
||||
context: Context,
|
||||
store: AppStore,
|
||||
client: Client,
|
||||
strictMode: StrictModeManager
|
||||
) {
|
||||
val initialize: InitializeWallpapersUseCase by lazy {
|
||||
// Required to even access context.filesDir property and to retrieve current locale
|
||||
val (fileManager, currentLocale) = strictMode.resetAfter(StrictMode.allowThreadDiskReads()) {
|
||||
val fileManager = WallpaperFileManager(context.filesDir)
|
||||
val currentLocale = LocaleManager.getCurrentLocale(context)?.toLanguageTag()
|
||||
?: LocaleManager.getSystemDefault().toLanguageTag()
|
||||
fileManager to currentLocale
|
||||
}
|
||||
val downloader = WallpaperDownloader(context, client)
|
||||
DefaultInitializeWallpaperUseCase(
|
||||
store = store,
|
||||
downloader = downloader,
|
||||
fileManager = fileManager,
|
||||
settings = context.settings(),
|
||||
currentLocale = currentLocale
|
||||
)
|
||||
}
|
||||
val loadBitmap: LoadBitmapUseCase by lazy { DefaultLoadBitmapUseCase(context) }
|
||||
val selectWallpaper: SelectWallpaperUseCase by lazy { DefaultSelectWallpaperUseCase(context.settings(), store) }
|
||||
|
||||
/**
|
||||
* Contract for usecases that initialize the wallpaper feature.
|
||||
*/
|
||||
interface InitializeWallpapersUseCase {
|
||||
/**
|
||||
* Start operations that should be down during initialization, like remote metadata
|
||||
* retrieval and determining the currently selected wallpaper.
|
||||
*/
|
||||
suspend operator fun invoke()
|
||||
}
|
||||
|
||||
@VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
|
||||
internal class DefaultInitializeWallpaperUseCase(
|
||||
private val store: AppStore,
|
||||
private val downloader: WallpaperDownloader,
|
||||
private val fileManager: WallpaperFileManager,
|
||||
private val settings: Settings,
|
||||
private val currentLocale: String,
|
||||
private val possibleWallpapers: List<Wallpaper> = allWallpapers,
|
||||
) : InitializeWallpapersUseCase {
|
||||
|
||||
/**
|
||||
* Downloads the currently available wallpaper metadata from a remote source.
|
||||
* Updates the [store] with that metadata and with the selected wallpaper found in storage.
|
||||
* Removes any unused promotional or time-limited assets from local storage.
|
||||
* Should usually be called early the app's lifetime to ensure that metadata and thumbnails
|
||||
* are available as soon as they are needed.
|
||||
*/
|
||||
override suspend operator fun invoke() {
|
||||
// Quite a bit of code needs to be executed off the main thread in some of this setup.
|
||||
// This should be cleaned up as improvements are made to the storage, file management,
|
||||
// and download utilities.
|
||||
withContext(Dispatchers.IO) {
|
||||
val availableWallpapers = getAvailableWallpapers()
|
||||
val currentWallpaperName = settings.currentWallpaper
|
||||
val currentWallpaper = possibleWallpapers.find { it.name == currentWallpaperName }
|
||||
?: fileManager.lookupExpiredWallpaper(currentWallpaperName)
|
||||
?: Wallpaper.Default
|
||||
|
||||
fileManager.clean(
|
||||
currentWallpaper,
|
||||
possibleWallpapers.filterIsInstance<Wallpaper.Remote>()
|
||||
)
|
||||
downloadAllRemoteWallpapers(availableWallpapers)
|
||||
store.dispatch(AppAction.WallpaperAction.UpdateAvailableWallpapers(availableWallpapers))
|
||||
store.dispatch(AppAction.WallpaperAction.UpdateCurrentWallpaper(currentWallpaper))
|
||||
}
|
||||
}
|
||||
|
||||
private fun getAvailableWallpapers() = possibleWallpapers
|
||||
.filter { !it.isExpired() && it.isAvailableInLocale() }
|
||||
|
||||
private suspend fun downloadAllRemoteWallpapers(availableWallpapers: List<Wallpaper>) {
|
||||
for (wallpaper in availableWallpapers.filterIsInstance<Wallpaper.Remote>()) {
|
||||
downloader.downloadWallpaper(wallpaper)
|
||||
}
|
||||
}
|
||||
|
||||
private fun Wallpaper.isExpired(): Boolean = when (this) {
|
||||
is Wallpaper.Remote -> {
|
||||
val expired = this.expirationDate?.let { Date().after(it) } ?: false
|
||||
expired && this.name != settings.currentWallpaper
|
||||
}
|
||||
else -> false
|
||||
}
|
||||
|
||||
private fun Wallpaper.isAvailableInLocale(): Boolean =
|
||||
if (this is Wallpaper.Promotional) {
|
||||
this.isAvailableInLocale(currentLocale)
|
||||
} else {
|
||||
true
|
||||
}
|
||||
|
||||
companion object {
|
||||
private val localWallpapers: List<Wallpaper.Local> = listOf(
|
||||
Wallpaper.Local.Firefox("amethyst", R.drawable.amethyst),
|
||||
Wallpaper.Local.Firefox("cerulean", R.drawable.cerulean),
|
||||
Wallpaper.Local.Firefox("sunrise", R.drawable.sunrise),
|
||||
)
|
||||
private val remoteWallpapers: List<Wallpaper.Remote> = listOf(
|
||||
Wallpaper.Remote.Firefox(
|
||||
"twilight-hills"
|
||||
),
|
||||
Wallpaper.Remote.Firefox(
|
||||
"beach-vibe"
|
||||
),
|
||||
)
|
||||
val allWallpapers = listOf(Wallpaper.Default) + localWallpapers + remoteWallpapers
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Contract for usecase for loading bitmaps related to a specific wallpaper.
|
||||
*/
|
||||
interface LoadBitmapUseCase {
|
||||
/**
|
||||
* Load the bitmap for a [wallpaper], if available.
|
||||
*
|
||||
* @param wallpaper The wallpaper to load a bitmap for.
|
||||
*/
|
||||
suspend operator fun invoke(wallpaper: Wallpaper): Bitmap?
|
||||
}
|
||||
|
||||
@VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
|
||||
internal class DefaultLoadBitmapUseCase(private val context: Context) : LoadBitmapUseCase {
|
||||
/**
|
||||
* Load the bitmap for a [wallpaper], if available.
|
||||
*
|
||||
* @param wallpaper The wallpaper to load a bitmap for.
|
||||
*/
|
||||
override suspend operator fun invoke(wallpaper: Wallpaper): Bitmap? = when (wallpaper) {
|
||||
is Wallpaper.Local -> loadWallpaperFromDrawable(context, wallpaper)
|
||||
is Wallpaper.Remote -> loadWallpaperFromDisk(context, wallpaper)
|
||||
else -> null
|
||||
}
|
||||
|
||||
private suspend fun loadWallpaperFromDrawable(
|
||||
context: Context,
|
||||
wallpaper: Wallpaper.Local
|
||||
): Bitmap? = Result.runCatching {
|
||||
withContext(Dispatchers.IO) {
|
||||
BitmapFactory.decodeResource(context.resources, wallpaper.drawableId)
|
||||
}
|
||||
}.getOrNull()
|
||||
|
||||
private suspend fun loadWallpaperFromDisk(
|
||||
context: Context,
|
||||
wallpaper: Wallpaper.Remote
|
||||
): Bitmap? = Result.runCatching {
|
||||
val path = wallpaper.getLocalPathFromContext(context)
|
||||
withContext(Dispatchers.IO) {
|
||||
val file = File(context.filesDir, path)
|
||||
BitmapFactory.decodeStream(file.inputStream())
|
||||
}
|
||||
}.getOrNull()
|
||||
|
||||
/**
|
||||
* Get the expected local path on disk for a wallpaper. This will differ depending
|
||||
* on orientation and app theme.
|
||||
*/
|
||||
private fun Wallpaper.Remote.getLocalPathFromContext(context: Context): String {
|
||||
val orientation = if (context.isLandscape()) "landscape" else "portrait"
|
||||
val theme = if (context.isDark()) "dark" else "light"
|
||||
return Wallpaper.getBaseLocalPath(orientation, theme, name)
|
||||
}
|
||||
|
||||
private fun Context.isLandscape(): Boolean {
|
||||
return resources.configuration.orientation == Configuration.ORIENTATION_LANDSCAPE
|
||||
}
|
||||
|
||||
private fun Context.isDark(): Boolean {
|
||||
return resources.configuration.uiMode and
|
||||
Configuration.UI_MODE_NIGHT_MASK == Configuration.UI_MODE_NIGHT_YES
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Contract for usecase of selecting a new wallpaper.
|
||||
*/
|
||||
interface SelectWallpaperUseCase {
|
||||
/**
|
||||
* Select a new wallpaper.
|
||||
*
|
||||
* @param wallpaper The selected wallpaper.
|
||||
*/
|
||||
operator fun invoke(wallpaper: Wallpaper)
|
||||
}
|
||||
|
||||
@VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
|
||||
internal class DefaultSelectWallpaperUseCase(
|
||||
private val settings: Settings,
|
||||
private val store: AppStore,
|
||||
) : SelectWallpaperUseCase {
|
||||
/**
|
||||
* Select a new wallpaper. Storage and the store will be updated appropriately.
|
||||
*
|
||||
* @param wallpaper The selected wallpaper.
|
||||
*/
|
||||
override fun invoke(wallpaper: Wallpaper) {
|
||||
settings.currentWallpaper = wallpaper.name
|
||||
store.dispatch(AppAction.WallpaperAction.UpdateCurrentWallpaper(wallpaper))
|
||||
Wallpapers.wallpaperSelected.record(
|
||||
Wallpapers.WallpaperSelectedExtra(
|
||||
name = wallpaper.name,
|
||||
themeCollection = wallpaper::class.simpleName
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,230 @@
|
||||
package org.mozilla.fenix.wallpapers
|
||||
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||
import io.mockk.coEvery
|
||||
import io.mockk.coVerify
|
||||
import io.mockk.every
|
||||
import io.mockk.just
|
||||
import io.mockk.mockk
|
||||
import io.mockk.runs
|
||||
import io.mockk.slot
|
||||
import io.mockk.verify
|
||||
import kotlinx.coroutines.test.runTest
|
||||
import mozilla.components.service.glean.testing.GleanTestRule
|
||||
import mozilla.components.support.test.libstate.ext.waitUntilIdle
|
||||
import mozilla.components.support.test.robolectric.testContext
|
||||
import org.junit.Assert.assertEquals
|
||||
import org.junit.Assert.assertFalse
|
||||
import org.junit.Assert.assertTrue
|
||||
import org.junit.Rule
|
||||
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.utils.Settings
|
||||
import java.util.Calendar
|
||||
import java.util.Date
|
||||
|
||||
@RunWith(AndroidJUnit4::class)
|
||||
class WallpapersUseCasesTest {
|
||||
|
||||
@get:Rule
|
||||
val gleanTestRule = GleanTestRule(testContext)
|
||||
|
||||
// initialize this once, so it can be shared throughout tests
|
||||
private val baseFakeDate = Date()
|
||||
private val fakeCalendar = Calendar.getInstance()
|
||||
|
||||
private val appStore = AppStore()
|
||||
private val mockSettings = mockk<Settings>()
|
||||
private val mockDownloader = mockk<WallpaperDownloader>(relaxed = true)
|
||||
private val mockFileManager = mockk<WallpaperFileManager> {
|
||||
every { clean(any(), any()) } just runs
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `GIVEN wallpapers that expired WHEN invoking initialize use case THEN expired wallpapers are filtered out and cleaned up`() = runTest {
|
||||
val fakeRemoteWallpapers = listOf("first", "second", "third").map { name ->
|
||||
makeFakeRemoteWallpaper(TimeRelation.LATER, name)
|
||||
}
|
||||
val fakeExpiredRemoteWallpapers = listOf("expired").map { name ->
|
||||
makeFakeRemoteWallpaper(TimeRelation.BEFORE, name)
|
||||
}
|
||||
val possibleWallpapers = fakeRemoteWallpapers + fakeExpiredRemoteWallpapers
|
||||
every { mockSettings.currentWallpaper } returns ""
|
||||
coEvery { mockFileManager.lookupExpiredWallpaper(any()) } returns null
|
||||
|
||||
WallpapersUseCases.DefaultInitializeWallpaperUseCase(
|
||||
appStore,
|
||||
mockDownloader,
|
||||
mockFileManager,
|
||||
mockSettings,
|
||||
"en-US",
|
||||
possibleWallpapers = possibleWallpapers
|
||||
).invoke()
|
||||
|
||||
val expectedFilteredWallpaper = fakeExpiredRemoteWallpapers[0]
|
||||
appStore.waitUntilIdle()
|
||||
assertFalse(appStore.state.wallpaperState.availableWallpapers.contains(expectedFilteredWallpaper))
|
||||
verify { mockFileManager.clean(Wallpaper.Default, possibleWallpapers) }
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `GIVEN wallpapers that expired and an expired one is selected WHEN invoking initialize use case THEN selected wallpaper is not filtered out`() = runTest {
|
||||
val fakeRemoteWallpapers = listOf("first", "second", "third").map { name ->
|
||||
makeFakeRemoteWallpaper(TimeRelation.LATER, name)
|
||||
}
|
||||
val expiredWallpaper = makeFakeRemoteWallpaper(TimeRelation.BEFORE, "expired")
|
||||
every { mockSettings.currentWallpaper } returns expiredWallpaper.name
|
||||
coEvery { mockFileManager.lookupExpiredWallpaper(any()) } returns null
|
||||
|
||||
WallpapersUseCases.DefaultInitializeWallpaperUseCase(
|
||||
appStore,
|
||||
mockDownloader,
|
||||
mockFileManager,
|
||||
mockSettings,
|
||||
"en-US",
|
||||
possibleWallpapers = fakeRemoteWallpapers + listOf(expiredWallpaper)
|
||||
).invoke()
|
||||
|
||||
appStore.waitUntilIdle()
|
||||
assertTrue(appStore.state.wallpaperState.availableWallpapers.contains(expiredWallpaper))
|
||||
assertEquals(expiredWallpaper, appStore.state.wallpaperState.currentWallpaper)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `GIVEN wallpapers that are in promotions outside of locale WHEN invoking initialize use case THEN promotional wallpapers are filtered out`() = runTest {
|
||||
val fakeRemoteWallpapers = listOf("first", "second", "third").map { name ->
|
||||
makeFakeRemoteWallpaper(TimeRelation.LATER, name)
|
||||
}
|
||||
val locale = "en-CA"
|
||||
every { mockSettings.currentWallpaper } returns ""
|
||||
coEvery { mockFileManager.lookupExpiredWallpaper(any()) } returns null
|
||||
|
||||
WallpapersUseCases.DefaultInitializeWallpaperUseCase(
|
||||
appStore,
|
||||
mockDownloader,
|
||||
mockFileManager,
|
||||
mockSettings,
|
||||
locale,
|
||||
possibleWallpapers = fakeRemoteWallpapers
|
||||
).invoke()
|
||||
|
||||
appStore.waitUntilIdle()
|
||||
assertTrue(appStore.state.wallpaperState.availableWallpapers.isEmpty())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `GIVEN available wallpapers WHEN invoking initialize use case THEN available wallpapers downloaded`() = runTest {
|
||||
val fakeRemoteWallpapers = listOf("first", "second", "third").map { name ->
|
||||
makeFakeRemoteWallpaper(TimeRelation.LATER, name)
|
||||
}
|
||||
every { mockSettings.currentWallpaper } returns ""
|
||||
coEvery { mockFileManager.lookupExpiredWallpaper(any()) } returns null
|
||||
|
||||
WallpapersUseCases.DefaultInitializeWallpaperUseCase(
|
||||
appStore,
|
||||
mockDownloader,
|
||||
mockFileManager,
|
||||
mockSettings,
|
||||
"en-US",
|
||||
possibleWallpapers = fakeRemoteWallpapers
|
||||
).invoke()
|
||||
|
||||
for (fakeRemoteWallpaper in fakeRemoteWallpapers) {
|
||||
coVerify { mockDownloader.downloadWallpaper(fakeRemoteWallpaper) }
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `GIVEN a wallpaper has not been selected WHEN invoking initialize use case THEN store contains default`() = runTest {
|
||||
val fakeRemoteWallpapers = listOf("first", "second", "third").map { name ->
|
||||
makeFakeRemoteWallpaper(TimeRelation.LATER, name)
|
||||
}
|
||||
every { mockSettings.currentWallpaper } returns ""
|
||||
coEvery { mockFileManager.lookupExpiredWallpaper(any()) } returns null
|
||||
|
||||
WallpapersUseCases.DefaultInitializeWallpaperUseCase(
|
||||
appStore,
|
||||
mockDownloader,
|
||||
mockFileManager,
|
||||
mockSettings,
|
||||
"en-US",
|
||||
possibleWallpapers = fakeRemoteWallpapers
|
||||
).invoke()
|
||||
|
||||
appStore.waitUntilIdle()
|
||||
assertTrue(appStore.state.wallpaperState.currentWallpaper is Wallpaper.Default)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `GIVEN a wallpaper is selected and there are available wallpapers WHEN invoking initialize use case THEN these are dispatched to the store`() = runTest {
|
||||
val selectedWallpaper = makeFakeRemoteWallpaper(TimeRelation.LATER, "selected")
|
||||
val fakeRemoteWallpapers = listOf("first", "second", "third").map { name ->
|
||||
makeFakeRemoteWallpaper(TimeRelation.LATER, name)
|
||||
}
|
||||
val possibleWallpapers = listOf(selectedWallpaper) + fakeRemoteWallpapers
|
||||
every { mockSettings.currentWallpaper } returns selectedWallpaper.name
|
||||
coEvery { mockFileManager.lookupExpiredWallpaper(any()) } returns null
|
||||
|
||||
WallpapersUseCases.DefaultInitializeWallpaperUseCase(
|
||||
appStore,
|
||||
mockDownloader,
|
||||
mockFileManager,
|
||||
mockSettings,
|
||||
"en-US",
|
||||
possibleWallpapers = possibleWallpapers
|
||||
).invoke()
|
||||
|
||||
appStore.waitUntilIdle()
|
||||
assertEquals(selectedWallpaper, appStore.state.wallpaperState.currentWallpaper)
|
||||
assertEquals(possibleWallpapers, appStore.state.wallpaperState.availableWallpapers)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `WHEN selected wallpaper usecase invoked THEN storage updated and store receives dispatch`() {
|
||||
val selectedWallpaper = makeFakeRemoteWallpaper(TimeRelation.LATER, "selected")
|
||||
val slot = slot<String>()
|
||||
coEvery { mockFileManager.lookupExpiredWallpaper(any()) } returns null
|
||||
every { mockSettings.currentWallpaper } returns ""
|
||||
every { mockSettings.currentWallpaper = capture(slot) } just runs
|
||||
|
||||
WallpapersUseCases.DefaultSelectWallpaperUseCase(
|
||||
mockSettings,
|
||||
appStore
|
||||
).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")!!)
|
||||
}
|
||||
|
||||
private enum class TimeRelation {
|
||||
BEFORE,
|
||||
NOW,
|
||||
LATER,
|
||||
}
|
||||
|
||||
/**
|
||||
* [timeRelation] should specify a time relative to the time the tests are run
|
||||
*/
|
||||
private fun makeFakeRemoteWallpaper(
|
||||
timeRelation: TimeRelation,
|
||||
name: String = "name",
|
||||
isInPromo: Boolean = true
|
||||
): Wallpaper.Remote {
|
||||
fakeCalendar.time = baseFakeDate
|
||||
when (timeRelation) {
|
||||
TimeRelation.BEFORE -> fakeCalendar.add(Calendar.DATE, -5)
|
||||
TimeRelation.NOW -> Unit
|
||||
TimeRelation.LATER -> fakeCalendar.add(Calendar.DATE, 5)
|
||||
}
|
||||
val relativeTime = fakeCalendar.time
|
||||
return if (isInPromo) {
|
||||
Wallpaper.Remote.House(name = name, expirationDate = relativeTime)
|
||||
} else {
|
||||
Wallpaper.Remote.Firefox(name = name)
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue