address the review: keep the stored seed on a failed decode, one cache, static bar colour

- resolve() no longer discards a stored seed when the bitmap cannot be decoded (it used to
  return null, dropping the theme for pre-v12 rows); it falls back to the stored pair
- fold the busy flag into the seed cache value so eviction is atomic (a busy entry could be
  evicted from the separate flag LRU while its seed stayed, silently disabling the scrim)
- the artist top bar samples heroBarColor at scroll 0 to match the static HeroGradient, and
  drops the wrong scroll estimate and per-pixel recomposition
- rememberOverlaidNameBusy keys its state so the cached flag is read on key change, not only
  the first composition; bottomBandBusy bails out on an empty bitmap
This commit is contained in:
austinried
2026-10-04 00:29:58 +00:00
parent f4ca0fd6d4
commit a356226e48
5 changed files with 68 additions and 31 deletions
@@ -17,7 +17,10 @@ import coil3.SingletonImageLoader
import coil3.annotation.DelicateCoilApi
import coil3.asImage
import coil3.test.FakeImageLoaderEngine
import com.subtracks.data.model.ArtworkSeed
import com.subtracks.data.model.CoverArtRef
import com.subtracks.data.repo.ArtworkSeedStore
import kotlinx.coroutines.runBlocking
import org.junit.After
import org.junit.Assert.assertEquals
import org.junit.Assert.assertNotNull
@@ -55,6 +58,7 @@ class ArtworkExtractionTest {
@After
fun resetImageLoader() {
ArtworkSeedCache.clear()
ArtworkSeedCache.install(null)
SingletonImageLoader.reset()
}
@@ -87,4 +91,20 @@ class ArtworkExtractionTest {
composeRule.waitForIdle()
assertEquals(42, state.value)
}
@Test
fun keepsTheStoredSeedWhenTheArtCannotBeDecoded() {
val key = "missing-${System.nanoTime()}"
val stored = ArtworkSeed(key, 0xFF3A7BD5.toInt(), 0xFFD53A3A.toInt(), null)
ArtworkSeedCache.install(
object : ArtworkSeedStore {
override suspend fun seed(cacheKey: String): ArtworkSeed? = stored.takeIf { it.cacheKey == cacheKey }
override suspend fun save(seed: ArtworkSeed) = Unit
},
)
val ref = CoverArtRef(url = key, cacheKey = key)
val seeds = runBlocking { ArtworkSeedCache.seeds(ApplicationProvider.getApplicationContext(), ref) }
assertEquals(stored.primary, seeds?.first)
}
}