mirror of
https://github.com/austinried/subtracks.git
synced 2026-11-10 15:11:58 +01:00
extract album colours from the thumbnail off the main thread
This commit is contained in:
@@ -74,7 +74,7 @@ fun AlbumDetailRoute(
|
||||
album = album,
|
||||
songs = songs,
|
||||
coverArt = viewModel::coverArt,
|
||||
artwork = rememberArtworkColors(viewModel.coverArt(album?.coverArt, false)),
|
||||
artwork = rememberArtworkColors(viewModel.coverArt(album?.coverArt, true)),
|
||||
onBack = onBack,
|
||||
onSongClick = viewModel::play,
|
||||
playingSongId = playback.item?.id.takeIf { context?.kind == QueueKind.Album && context.refId == albumId },
|
||||
|
||||
@@ -19,11 +19,15 @@ import coil3.SingletonImageLoader
|
||||
import coil3.compose.LocalPlatformContext
|
||||
import coil3.request.ImageRequest
|
||||
import coil3.request.SuccessResult
|
||||
import coil3.request.allowHardware
|
||||
import coil3.toBitmap
|
||||
import com.subtracks.data.model.CoverArtRef
|
||||
import kotlinx.coroutines.CancellationException
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.withContext
|
||||
|
||||
private const val SEED_ART_SIZE_PX = 128
|
||||
|
||||
data class ArtworkColors(
|
||||
val scheme: ColorScheme,
|
||||
val gradientHigh: Color,
|
||||
@@ -97,16 +101,24 @@ private fun rememberArtworkSeed(ref: CoverArtRef?): State<Int?> {
|
||||
value = null
|
||||
val art = ref ?: return@produceState
|
||||
value =
|
||||
withContext(Dispatchers.Default) {
|
||||
val request =
|
||||
ImageRequest
|
||||
.Builder(context)
|
||||
.data(art.url)
|
||||
.memoryCacheKey(art.cacheKey)
|
||||
.diskCacheKey(art.cacheKey)
|
||||
.build()
|
||||
val image = (SingletonImageLoader.get(context).execute(request) as? SuccessResult)?.image
|
||||
image?.let { seedFrom(it.toBitmap()) }
|
||||
withContext(Dispatchers.IO) {
|
||||
try {
|
||||
val request =
|
||||
ImageRequest
|
||||
.Builder(context)
|
||||
.data(art.url)
|
||||
.memoryCacheKey(art.cacheKey)
|
||||
.diskCacheKey(art.cacheKey)
|
||||
.size(SEED_ART_SIZE_PX)
|
||||
.allowHardware(false)
|
||||
.build()
|
||||
val image = (SingletonImageLoader.get(context).execute(request) as? SuccessResult)?.image
|
||||
image?.let { seedFrom(it.toBitmap()) }
|
||||
} catch (e: CancellationException) {
|
||||
throw e
|
||||
} catch (_: Exception) {
|
||||
null
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,64 @@
|
||||
package com.subtracks.ui.theme
|
||||
|
||||
import android.content.Context
|
||||
import android.graphics.Bitmap
|
||||
import android.graphics.Color
|
||||
import androidx.activity.ComponentActivity
|
||||
import androidx.compose.ui.graphics.luminance
|
||||
import androidx.compose.ui.test.junit4.v2.createAndroidComposeRule
|
||||
import androidx.test.core.app.ApplicationProvider
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||
import coil3.ImageLoader
|
||||
import coil3.SingletonImageLoader
|
||||
import coil3.annotation.DelicateCoilApi
|
||||
import coil3.asImage
|
||||
import coil3.test.FakeImageLoaderEngine
|
||||
import com.subtracks.data.model.CoverArtRef
|
||||
import org.junit.After
|
||||
import org.junit.Assert.assertNotNull
|
||||
import org.junit.Assert.assertTrue
|
||||
import org.junit.Before
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.robolectric.annotation.GraphicsMode
|
||||
|
||||
@OptIn(DelicateCoilApi::class)
|
||||
@RunWith(AndroidJUnit4::class)
|
||||
@GraphicsMode(GraphicsMode.Mode.NATIVE)
|
||||
class ArtworkExtractionTest {
|
||||
@get:Rule
|
||||
val composeRule = createAndroidComposeRule<ComponentActivity>()
|
||||
|
||||
private val bitmap =
|
||||
Bitmap.createBitmap(64, 64, Bitmap.Config.ARGB_8888).apply {
|
||||
eraseColor(Color.rgb(30, 120, 200))
|
||||
}
|
||||
|
||||
@Before
|
||||
fun installImageLoader() {
|
||||
SingletonImageLoader.reset()
|
||||
SingletonImageLoader.setUnsafe(
|
||||
ImageLoader
|
||||
.Builder(ApplicationProvider.getApplicationContext<Context>())
|
||||
.components { add(FakeImageLoaderEngine.Builder().intercept("art", bitmap.asImage()).build()) }
|
||||
.build(),
|
||||
)
|
||||
}
|
||||
|
||||
@After
|
||||
fun resetImageLoader() {
|
||||
SingletonImageLoader.reset()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun resolvesColorsFromCoverArt() {
|
||||
var colors: ArtworkColors? = null
|
||||
composeRule.setContent {
|
||||
colors = rememberArtworkColors(CoverArtRef(url = "art", cacheKey = "art"))
|
||||
}
|
||||
composeRule.waitUntil(timeoutMillis = 5_000) { colors != null }
|
||||
assertNotNull(colors)
|
||||
assertTrue(colors!!.scheme.background.luminance() < 0.1f)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user