Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@ import kotlinx.coroutines.flow.update
import kotlinx.coroutines.launch
import javax.inject.Inject
import javax.inject.Singleton
import java.util.concurrent.ConcurrentHashMap

@Singleton
class ThemeStateHolder @Inject constructor(
Expand Down Expand Up @@ -139,30 +138,56 @@ class ThemeStateHolder @Inject constructor(
32, 0.75f, true
) {
override fun removeEldestEntry(eldest: MutableMap.MutableEntry<String, MutableStateFlow<ColorSchemePair?>>?): Boolean {
return size > 30
return size > 96
}
}

private val pendingAlbumColorSchemeRequests = ConcurrentHashMap.newKeySet<String>()
private val emptyAlbumColorScheme = MutableStateFlow<ColorSchemePair?>(null).asStateFlow()
private val pendingAlbumColorSchemeLock = Any()
private val pendingAlbumColorSchemeTargets = mutableMapOf<String, MutableSet<MutableStateFlow<ColorSchemePair?>>>()

private fun requestAlbumColorSchemeGeneration(
uriString: String,
targetFlow: MutableStateFlow<ColorSchemePair?>
) {
if (!pendingAlbumColorSchemeRequests.add(uriString)) return
if (uriString.isBlank()) return

val shouldStartRequest = synchronized(pendingAlbumColorSchemeLock) {
val existingTargets = pendingAlbumColorSchemeTargets[uriString]
if (existingTargets != null) {
existingTargets.add(targetFlow)
false
} else {
pendingAlbumColorSchemeTargets[uriString] = mutableSetOf(targetFlow)
true
}
}

if (!shouldStartRequest) return

val requestScope = scope
if (requestScope == null) {
synchronized(pendingAlbumColorSchemeLock) {
pendingAlbumColorSchemeTargets.remove(uriString)
}
return
}

scope?.launch(Dispatchers.IO) {
requestScope.launch(Dispatchers.IO) {
var scheme: ColorSchemePair? = null
try {
val scheme = colorSchemeProcessor.getOrGenerateColorScheme(
scheme = colorSchemeProcessor.getOrGenerateColorScheme(
albumArtUri = uriString,
paletteStyle = currentPaletteStyle,
colorAccuracyLevel = currentPaletteAccuracy
)
targetFlow.value = scheme
} catch (_: Exception) {
// Ignore or log
} finally {
pendingAlbumColorSchemeRequests.remove(uriString)
val targets = synchronized(pendingAlbumColorSchemeLock) {
pendingAlbumColorSchemeTargets.remove(uriString)?.toList().orEmpty()
}
targets.forEach { it.value = scheme }
}
}
}
Expand All @@ -171,6 +196,8 @@ class ThemeStateHolder @Inject constructor(
uriString: String,
eager: Boolean = true
): StateFlow<ColorSchemePair?> {
if (uriString.isBlank()) return emptyAlbumColorScheme

val existingFlow = individualAlbumColorSchemes[uriString]
if (existingFlow != null) {
if (eager && existingFlow.value == null) {
Expand All @@ -190,6 +217,8 @@ class ThemeStateHolder @Inject constructor(
}

fun ensureAlbumColorScheme(uriString: String) {
if (uriString.isBlank()) return

val targetFlow = individualAlbumColorSchemes[uriString]
?: MutableStateFlow<ColorSchemePair?>(null).also { individualAlbumColorSchemes[uriString] = it }

Expand Down Expand Up @@ -276,7 +305,9 @@ class ThemeStateHolder @Inject constructor(
level >= ComponentCallbacks2.TRIM_MEMORY_RUNNING_CRITICAL ||
level >= ComponentCallbacks2.TRIM_MEMORY_COMPLETE
) {
pendingAlbumColorSchemeRequests.clear()
synchronized(pendingAlbumColorSchemeLock) {
pendingAlbumColorSchemeTargets.clear()
}
}
}

Expand Down
Loading