feat(android): add HomeArtistPrewarmer (top-8 artists, session-deduped)
This commit is contained in:
@@ -0,0 +1,33 @@
|
||||
package com.fabledsword.minstrel.metadata
|
||||
|
||||
import java.util.Collections
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
|
||||
private const val TOP_N = 8
|
||||
|
||||
/**
|
||||
* Pre-warms the Room cache for likely-tap artist tiles on Home. Mirrors
|
||||
* Flutter's `MetadataPrefetcher`: conservative — artists only (a single
|
||||
* round-trip per id), top-8 per call, and once per id per session so
|
||||
* repeated index refreshes don't re-fetch. Albums are intentionally not
|
||||
* pre-warmed (their detail fetch fans out a track list).
|
||||
*
|
||||
* Fetches go through [MetadataProvider.refreshArtist], so they share the
|
||||
* same per-id dedup AND the 4-slot concurrency gate as on-render
|
||||
* hydration — the prewarm can't starve the tiles the user is looking at.
|
||||
*/
|
||||
@Singleton
|
||||
class HomeArtistPrewarmer @Inject constructor(
|
||||
private val metadataProvider: MetadataProvider,
|
||||
) {
|
||||
private val warmed = Collections.synchronizedSet(mutableSetOf<String>())
|
||||
|
||||
fun warm(artistIds: List<String>) {
|
||||
artistIds.asSequence()
|
||||
.filter { it.isNotEmpty() }
|
||||
.filter { warmed.add(it) }
|
||||
.take(TOP_N)
|
||||
.forEach { metadataProvider.refreshArtist(it) }
|
||||
}
|
||||
}
|
||||
+25
@@ -0,0 +1,25 @@
|
||||
package com.fabledsword.minstrel.metadata
|
||||
|
||||
import io.mockk.every
|
||||
import io.mockk.mockk
|
||||
import io.mockk.verify
|
||||
import org.junit.jupiter.api.Test
|
||||
|
||||
class HomeArtistPrewarmerTest {
|
||||
private val provider = mockk<MetadataProvider>()
|
||||
|
||||
@Test
|
||||
fun `warms at most the top eight distinct ids, once per session`() {
|
||||
every { provider.refreshArtist(any()) } returns mockk(relaxed = true)
|
||||
val prewarmer = HomeArtistPrewarmer(provider)
|
||||
|
||||
// 10 ids with a duplicate and a blank -> 8 distinct non-blank warmed.
|
||||
prewarmer.warm(listOf("a1", "a2", "a3", "a4", "a5", "a6", "a7", "a8", "a9", ""))
|
||||
// Re-warm: already-warmed ids are skipped.
|
||||
prewarmer.warm(listOf("a1", "a2"))
|
||||
|
||||
(1..8).forEach { i -> verify(exactly = 1) { provider.refreshArtist("a$i") } }
|
||||
verify(exactly = 0) { provider.refreshArtist("a9") } // past the top-8 cap
|
||||
verify(exactly = 0) { provider.refreshArtist("") } // blank skipped
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user