Limit cache max-age and action to clear cache manually
This commit is contained in:
@@ -23,6 +23,7 @@ import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.flow.MutableSharedFlow
|
||||
import kotlinx.coroutines.flow.SharedFlow
|
||||
import kotlinx.coroutines.flow.asSharedFlow
|
||||
import okhttp3.Cache
|
||||
import okhttp3.CookieJar
|
||||
import okhttp3.OkHttpClient
|
||||
import org.koitharu.kotatsu.BuildConfig
|
||||
@@ -90,14 +91,19 @@ interface AppModule {
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
fun provideOkHttpClient(
|
||||
fun provideHttpCache(
|
||||
localStorageManager: LocalStorageManager,
|
||||
): Cache = localStorageManager.createHttpCache()
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
fun provideOkHttpClient(
|
||||
cache: Cache,
|
||||
commonHeadersInterceptor: CommonHeadersInterceptor,
|
||||
mirrorSwitchInterceptor: MirrorSwitchInterceptor,
|
||||
cookieJar: CookieJar,
|
||||
settings: AppSettings,
|
||||
): OkHttpClient {
|
||||
val cache = localStorageManager.createHttpCache()
|
||||
return OkHttpClient.Builder().apply {
|
||||
connectTimeout(20, TimeUnit.SECONDS)
|
||||
readTimeout(60, TimeUnit.SECONDS)
|
||||
@@ -108,6 +114,7 @@ interface AppModule {
|
||||
bypassSSLErrors()
|
||||
}
|
||||
cache(cache)
|
||||
addNetworkInterceptor(CacheLimitInterceptor())
|
||||
addInterceptor(GZipInterceptor())
|
||||
addInterceptor(commonHeadersInterceptor)
|
||||
addInterceptor(CloudFlareInterceptor())
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
package org.koitharu.kotatsu.core.network
|
||||
|
||||
import okhttp3.CacheControl
|
||||
import okhttp3.Interceptor
|
||||
import okhttp3.Response
|
||||
import java.util.concurrent.TimeUnit
|
||||
|
||||
class CacheLimitInterceptor : Interceptor {
|
||||
|
||||
private val defaultMaxAge = TimeUnit.HOURS.toSeconds(1)
|
||||
private val defaultCacheControl = CacheControl.Builder()
|
||||
.maxAge(defaultMaxAge.toInt(), TimeUnit.SECONDS)
|
||||
.build()
|
||||
.toString()
|
||||
|
||||
override fun intercept(chain: Interceptor.Chain): Response {
|
||||
val response = chain.proceed(chain.request())
|
||||
val responseCacheControl = CacheControl.parse(response.headers)
|
||||
if (responseCacheControl.noStore || responseCacheControl.maxAgeSeconds <= defaultMaxAge) {
|
||||
return response
|
||||
}
|
||||
return response.newBuilder()
|
||||
.header(CommonHeaders.CACHE_CONTROL, defaultCacheControl)
|
||||
.build()
|
||||
}
|
||||
}
|
||||
@@ -13,6 +13,7 @@ object CommonHeaders {
|
||||
const val CONTENT_ENCODING = "Content-Encoding"
|
||||
const val ACCEPT_ENCODING = "Accept-Encoding"
|
||||
const val AUTHORIZATION = "Authorization"
|
||||
const val CACHE_CONTROL = "Cache-Control"
|
||||
|
||||
val CACHE_CONTROL_NO_STORE: CacheControl
|
||||
get() = CacheControl.Builder().noStore().build()
|
||||
|
||||
@@ -345,6 +345,7 @@ class AppSettings @Inject constructor(@ApplicationContext context: Context) {
|
||||
const val KEY_SOURCES_HIDDEN = "sources_hidden"
|
||||
const val KEY_TRAFFIC_WARNING = "traffic_warning"
|
||||
const val KEY_PAGES_CACHE_CLEAR = "pages_cache_clear"
|
||||
const val KEY_HTTP_CACHE_CLEAR = "http_cache_clear"
|
||||
const val KEY_COOKIES_CLEAR = "cookies_clear"
|
||||
const val KEY_THUMBS_CACHE_CLEAR = "thumbs_cache_clear"
|
||||
const val KEY_SEARCH_HISTORY_CLEAR = "search_history_clear"
|
||||
|
||||
@@ -8,7 +8,10 @@ import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||
import com.google.android.material.snackbar.Snackbar
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
import kotlinx.coroutines.CancellationException
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.runInterruptible
|
||||
import okhttp3.Cache
|
||||
import org.koitharu.kotatsu.R
|
||||
import org.koitharu.kotatsu.core.network.cookies.MutableCookieJar
|
||||
import org.koitharu.kotatsu.core.os.ShortcutsUpdater
|
||||
@@ -39,6 +42,9 @@ class HistorySettingsFragment : BasePreferenceFragment(R.string.history_and_cach
|
||||
@Inject
|
||||
lateinit var cookieJar: MutableCookieJar
|
||||
|
||||
@Inject
|
||||
lateinit var cache: Cache
|
||||
|
||||
@Inject
|
||||
lateinit var shortcutsUpdater: ShortcutsUpdater
|
||||
|
||||
@@ -52,6 +58,7 @@ class HistorySettingsFragment : BasePreferenceFragment(R.string.history_and_cach
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
findPreference<Preference>(AppSettings.KEY_PAGES_CACHE_CLEAR)?.bindSummaryToCacheSize(CacheDir.PAGES)
|
||||
findPreference<Preference>(AppSettings.KEY_THUMBS_CACHE_CLEAR)?.bindSummaryToCacheSize(CacheDir.THUMBS)
|
||||
findPreference<Preference>(AppSettings.KEY_HTTP_CACHE_CLEAR)?.bindSummaryToHttpCacheSize()
|
||||
findPreference<Preference>(AppSettings.KEY_SEARCH_HISTORY_CLEAR)?.let { pref ->
|
||||
viewLifecycleScope.launch {
|
||||
lifecycle.awaitStateAtLeast(Lifecycle.State.RESUMED)
|
||||
@@ -90,6 +97,11 @@ class HistorySettingsFragment : BasePreferenceFragment(R.string.history_and_cach
|
||||
true
|
||||
}
|
||||
|
||||
AppSettings.KEY_HTTP_CACHE_CLEAR -> {
|
||||
clearHttpCache()
|
||||
true
|
||||
}
|
||||
|
||||
AppSettings.KEY_UPDATES_FEED_CLEAR -> {
|
||||
viewLifecycleScope.launch {
|
||||
trackerRepo.clearLogs()
|
||||
@@ -131,6 +143,32 @@ class HistorySettingsFragment : BasePreferenceFragment(R.string.history_and_cach
|
||||
summary = FileSize.BYTES.format(context, size)
|
||||
}
|
||||
|
||||
private fun Preference.bindSummaryToHttpCacheSize() = viewLifecycleScope.launch {
|
||||
val size = runInterruptible(Dispatchers.IO) { cache.size() }
|
||||
summary = FileSize.BYTES.format(context, size)
|
||||
}
|
||||
|
||||
private fun clearHttpCache() {
|
||||
val preference = findPreference<Preference>(AppSettings.KEY_HTTP_CACHE_CLEAR) ?: return
|
||||
val ctx = preference.context.applicationContext
|
||||
viewLifecycleScope.launch {
|
||||
try {
|
||||
preference.isEnabled = false
|
||||
val size = runInterruptible(Dispatchers.IO) {
|
||||
cache.evictAll()
|
||||
cache.size()
|
||||
}
|
||||
preference.summary = FileSize.BYTES.format(ctx, size)
|
||||
} catch (e: CancellationException) {
|
||||
throw e
|
||||
} catch (e: Exception) {
|
||||
preference.summary = e.getDisplayMessage(ctx.resources)
|
||||
} finally {
|
||||
preference.isEnabled = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun clearSearchHistory(preference: Preference) {
|
||||
MaterialAlertDialogBuilder(context ?: return)
|
||||
.setTitle(R.string.clear_search_history)
|
||||
|
||||
@@ -416,4 +416,5 @@
|
||||
<string name="suggestions_enable_prompt">Do you want to receive personalized manga suggestions?</string>
|
||||
<string name="translations">Translations</string>
|
||||
<string name="web_view_unavailable">WebView not available: check if WebView provider is installed</string>
|
||||
<string name="clear_network_cache">Clear network cache</string>
|
||||
</resources>
|
||||
|
||||
@@ -39,6 +39,12 @@
|
||||
android:summary="@string/computing_"
|
||||
android:title="@string/clear_pages_cache" />
|
||||
|
||||
<Preference
|
||||
android:key="http_cache_clear"
|
||||
android:persistent="false"
|
||||
android:summary="@string/loading_"
|
||||
android:title="@string/clear_network_cache" />
|
||||
|
||||
<Preference
|
||||
android:key="cookies_clear"
|
||||
android:persistent="false"
|
||||
|
||||
Reference in New Issue
Block a user