Invalidate manga cache on config changes

This commit is contained in:
Koitharu
2024-03-14 13:44:13 +02:00
parent 24fe83aa5c
commit 2573d150f9
8 changed files with 62 additions and 7 deletions

View File

@@ -42,7 +42,7 @@ class AlternativesUseCase @Inject constructor(
}
}.getOrDefault(emptyList())
for (item in list) {
if (item != manga && item.matches(manga)) {
if (item.matches(manga)) {
send(item)
}
}

View File

@@ -20,6 +20,8 @@ interface ContentCache {
fun putRelatedManga(source: MangaSource, url: String, related: SafeDeferred<List<Manga>>)
fun clear(source: MangaSource)
data class Key(
val source: MangaSource,
val url: String,

View File

@@ -7,10 +7,12 @@ class ExpiringLruCache<T>(
val maxSize: Int,
private val lifetime: Long,
private val timeUnit: TimeUnit,
) {
) : Iterable<ContentCache.Key> {
private val cache = LruCache<ContentCache.Key, ExpiringValue<T>>(maxSize)
override fun iterator(): Iterator<ContentCache.Key> = cache.snapshot().keys.iterator()
operator fun get(key: ContentCache.Key): T? {
val value = cache[key] ?: return null
if (value.isExpired) {
@@ -30,4 +32,8 @@ class ExpiringLruCache<T>(
fun trimToSize(size: Int) {
cache.trimToSize(size)
}
fun remove(key: ContentCache.Key) {
cache.remove(key)
}
}

View File

@@ -44,6 +44,12 @@ class MemoryContentCache(application: Application) : ContentCache, ComponentCall
relatedMangaCache[ContentCache.Key(source, url)] = related
}
override fun clear(source: MangaSource) {
clearCache(detailsCache, source)
clearCache(pagesCache, source)
clearCache(relatedMangaCache, source)
}
override fun onConfigurationChanged(newConfig: Configuration) = Unit
override fun onLowMemory() = Unit
@@ -67,4 +73,12 @@ class MemoryContentCache(application: Application) : ContentCache, ComponentCall
else -> cache.trimToSize(cache.maxSize / 2)
}
}
private fun clearCache(cache: ExpiringLruCache<*>, source: MangaSource) {
cache.forEach { key ->
if (key.source == source) {
cache.remove(key)
}
}
}
}

View File

@@ -19,4 +19,6 @@ class StubContentCache : ContentCache {
override suspend fun getRelatedManga(source: MangaSource, url: String): List<Manga>? = null
override fun putRelatedManga(source: MangaSource, url: String, related: SafeDeferred<List<Manga>>) = Unit
override fun clear(source: MangaSource) = Unit
}

View File

@@ -171,7 +171,11 @@ class RemoteMangaRepository(
return getConfig().isSlowdownEnabled
}
private fun getConfig() = parser.config as SourceSettings
fun invalidateCache() {
cache.clear(source)
}
fun getConfig() = parser.config as SourceSettings
private suspend fun <T> asyncSafe(block: suspend CoroutineScope.() -> T): SafeDeferred<T> {
var dispatcher = currentCoroutineContext()[CoroutineDispatcher.Key]

View File

@@ -1,6 +1,7 @@
package org.koitharu.kotatsu.core.prefs
import android.content.Context
import android.content.SharedPreferences.OnSharedPreferenceChangeListener
import androidx.core.content.edit
import org.koitharu.kotatsu.core.util.ext.getEnumValue
import org.koitharu.kotatsu.core.util.ext.ifNullOrEmpty
@@ -10,9 +11,6 @@ import org.koitharu.kotatsu.parsers.config.MangaSourceConfig
import org.koitharu.kotatsu.parsers.model.MangaSource
import org.koitharu.kotatsu.parsers.model.SortOrder
private const val KEY_SORT_ORDER = "sort_order"
private const val KEY_SLOWDOWN = "slowdown"
class SourceSettings(context: Context, source: MangaSource) : MangaSourceConfig {
private val prefs = context.getSharedPreferences(source.name, Context.MODE_PRIVATE)
@@ -42,4 +40,18 @@ class SourceSettings(context: Context, source: MangaSource) : MangaSourceConfig
is ConfigKey.SplitByTranslations -> putBoolean(key.key, value as Boolean)
}
}
fun subscribe(listener: OnSharedPreferenceChangeListener) {
prefs.registerOnSharedPreferenceChangeListener(listener)
}
fun unsubscribe(listener: OnSharedPreferenceChangeListener) {
prefs.unregisterOnSharedPreferenceChangeListener(listener)
}
companion object {
const val KEY_SORT_ORDER = "sort_order"
const val KEY_SLOWDOWN = "slowdown"
}
}

View File

@@ -1,5 +1,6 @@
package org.koitharu.kotatsu.settings.sources
import android.content.SharedPreferences
import androidx.lifecycle.SavedStateHandle
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.Dispatchers
@@ -10,11 +11,13 @@ import org.koitharu.kotatsu.R
import org.koitharu.kotatsu.core.network.cookies.MutableCookieJar
import org.koitharu.kotatsu.core.parser.MangaRepository
import org.koitharu.kotatsu.core.parser.RemoteMangaRepository
import org.koitharu.kotatsu.core.prefs.SourceSettings
import org.koitharu.kotatsu.core.ui.BaseViewModel
import org.koitharu.kotatsu.core.ui.util.ReversibleAction
import org.koitharu.kotatsu.core.util.ext.MutableEventFlow
import org.koitharu.kotatsu.core.util.ext.call
import org.koitharu.kotatsu.core.util.ext.require
import org.koitharu.kotatsu.parsers.config.ConfigKey
import org.koitharu.kotatsu.parsers.exception.AuthRequiredException
import org.koitharu.kotatsu.parsers.model.MangaSource
import javax.inject.Inject
@@ -24,7 +27,7 @@ class SourceSettingsViewModel @Inject constructor(
savedStateHandle: SavedStateHandle,
mangaRepositoryFactory: MangaRepository.Factory,
private val cookieJar: MutableCookieJar,
) : BaseViewModel() {
) : BaseViewModel(), SharedPreferences.OnSharedPreferenceChangeListener {
val source = savedStateHandle.require<MangaSource>(SourceSettingsFragment.EXTRA_SOURCE)
val repository = mangaRepositoryFactory.create(source) as RemoteMangaRepository
@@ -34,9 +37,21 @@ class SourceSettingsViewModel @Inject constructor(
private var usernameLoadJob: Job? = null
init {
repository.getConfig().subscribe(this)
loadUsername()
}
override fun onCleared() {
repository.getConfig().unsubscribe(this)
super.onCleared()
}
override fun onSharedPreferenceChanged(sharedPreferences: SharedPreferences?, key: String?) {
if (key != SourceSettings.KEY_SLOWDOWN && key != SourceSettings.KEY_SORT_ORDER) {
repository.invalidateCache()
}
}
fun onResume() {
if (usernameLoadJob?.isActive != true) {
loadUsername()