Add Reader Page Preload option
Based on jobobby04@68bfba4 Closes #544 Co-Authored-By: jobobby04 <17078382+jobobby04@users.noreply.github.com>
This commit is contained in:
parent
9eaea6507d
commit
74826bc51b
@ -6,9 +6,15 @@ import com.github.salomonbrys.kotson.fromJson
|
|||||||
import com.google.gson.Gson
|
import com.google.gson.Gson
|
||||||
import com.jakewharton.disklrucache.DiskLruCache
|
import com.jakewharton.disklrucache.DiskLruCache
|
||||||
import eu.kanade.tachiyomi.data.database.models.Chapter
|
import eu.kanade.tachiyomi.data.database.models.Chapter
|
||||||
|
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
||||||
import eu.kanade.tachiyomi.source.model.Page
|
import eu.kanade.tachiyomi.source.model.Page
|
||||||
import eu.kanade.tachiyomi.util.storage.DiskUtil
|
import eu.kanade.tachiyomi.util.storage.DiskUtil
|
||||||
import eu.kanade.tachiyomi.util.storage.saveTo
|
import eu.kanade.tachiyomi.util.storage.saveTo
|
||||||
|
import kotlinx.coroutines.CoroutineScope
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.Job
|
||||||
|
import kotlinx.coroutines.flow.launchIn
|
||||||
|
import kotlinx.coroutines.flow.onEach
|
||||||
import okhttp3.Response
|
import okhttp3.Response
|
||||||
import okio.buffer
|
import okio.buffer
|
||||||
import okio.sink
|
import okio.sink
|
||||||
@ -16,6 +22,8 @@ import rx.Observable
|
|||||||
import uy.kohesive.injekt.injectLazy
|
import uy.kohesive.injekt.injectLazy
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.io.IOException
|
import java.io.IOException
|
||||||
|
import kotlin.math.pow
|
||||||
|
import kotlin.math.roundToLong
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class used to create chapter cache
|
* Class used to create chapter cache
|
||||||
@ -39,19 +47,18 @@ class ChapterCache(private val context: Context) {
|
|||||||
const val PARAMETER_VALUE_COUNT = 1
|
const val PARAMETER_VALUE_COUNT = 1
|
||||||
|
|
||||||
/** The maximum number of bytes this cache should use to store. */
|
/** The maximum number of bytes this cache should use to store. */
|
||||||
const val PARAMETER_CACHE_SIZE = 75L * 1024 * 1024
|
const val PARAMETER_CACHE_SIZE = 50L * 1024 * 1024
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Google Json class used for parsing JSON files. */
|
/** Google Json class used for parsing JSON files. */
|
||||||
private val gson: Gson by injectLazy()
|
private val gson: Gson by injectLazy()
|
||||||
|
|
||||||
|
private val preferences: PreferencesHelper by injectLazy()
|
||||||
|
|
||||||
|
private val scope = CoroutineScope(Job() + Dispatchers.IO)
|
||||||
|
|
||||||
/** Cache class used for cache management. */
|
/** Cache class used for cache management. */
|
||||||
private val diskCache = DiskLruCache.open(
|
private var diskCache = setupDiskCache(preferences.preloadSize().get())
|
||||||
File(context.cacheDir, PARAMETER_CACHE_DIRECTORY),
|
|
||||||
PARAMETER_APP_VERSION,
|
|
||||||
PARAMETER_VALUE_COUNT,
|
|
||||||
PARAMETER_CACHE_SIZE
|
|
||||||
)
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns directory of cache.
|
* Returns directory of cache.
|
||||||
@ -71,6 +78,27 @@ class ChapterCache(private val context: Context) {
|
|||||||
val readableSize: String
|
val readableSize: String
|
||||||
get() = Formatter.formatFileSize(context, realSize)
|
get() = Formatter.formatFileSize(context, realSize)
|
||||||
|
|
||||||
|
init {
|
||||||
|
preferences.preloadSize().asFlow()
|
||||||
|
.onEach {
|
||||||
|
// Save old cache for destruction later
|
||||||
|
val oldCache = diskCache
|
||||||
|
diskCache = setupDiskCache(it)
|
||||||
|
oldCache.close()
|
||||||
|
}
|
||||||
|
.launchIn(scope)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun setupDiskCache(cacheSize: Int): DiskLruCache {
|
||||||
|
return DiskLruCache.open(
|
||||||
|
File(context.cacheDir, PARAMETER_CACHE_DIRECTORY),
|
||||||
|
PARAMETER_APP_VERSION,
|
||||||
|
PARAMETER_VALUE_COUNT,
|
||||||
|
// 4 pages = 115MB, 6 = ~150MB, 10 = ~200MB, 20 = ~300MB
|
||||||
|
(PARAMETER_CACHE_SIZE * cacheSize.toFloat().pow(0.6f)).roundToLong()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Remove file from cache.
|
* Remove file from cache.
|
||||||
*
|
*
|
||||||
|
@ -70,6 +70,8 @@ object PreferenceKeys {
|
|||||||
const val showNavigationOverlayNewUser = "reader_navigation_overlay_new_user"
|
const val showNavigationOverlayNewUser = "reader_navigation_overlay_new_user"
|
||||||
const val showNavigationOverlayNewUserWebtoon = "reader_navigation_overlay_new_user_webtoon"
|
const val showNavigationOverlayNewUserWebtoon = "reader_navigation_overlay_new_user_webtoon"
|
||||||
|
|
||||||
|
const val preloadSize = "preload_size"
|
||||||
|
|
||||||
const val webtoonSidePadding = "webtoon_side_padding"
|
const val webtoonSidePadding = "webtoon_side_padding"
|
||||||
|
|
||||||
const val webtoonEnableZoomOut = "webtoon_enable_zoom_out"
|
const val webtoonEnableZoomOut = "webtoon_enable_zoom_out"
|
||||||
|
@ -151,6 +151,8 @@ class PreferencesHelper(val context: Context) {
|
|||||||
|
|
||||||
fun showNavigationOverlayNewUserWebtoon() = flowPrefs.getBoolean(Keys.showNavigationOverlayNewUserWebtoon, true)
|
fun showNavigationOverlayNewUserWebtoon() = flowPrefs.getBoolean(Keys.showNavigationOverlayNewUserWebtoon, true)
|
||||||
|
|
||||||
|
fun preloadSize() = flowPrefs.getInt(Keys.preloadSize, 6)
|
||||||
|
|
||||||
fun updateOnlyNonCompleted() = prefs.getBoolean(Keys.updateOnlyNonCompleted, false)
|
fun updateOnlyNonCompleted() = prefs.getBoolean(Keys.updateOnlyNonCompleted, false)
|
||||||
|
|
||||||
fun autoUpdateTrack() = prefs.getBoolean(Keys.autoUpdateTrack, true)
|
fun autoUpdateTrack() = prefs.getBoolean(Keys.autoUpdateTrack, true)
|
||||||
|
@ -10,6 +10,12 @@ import eu.kanade.tachiyomi.ui.reader.model.ReaderPage
|
|||||||
import eu.kanade.tachiyomi.ui.reader.viewer.pager.PagerPageHolder
|
import eu.kanade.tachiyomi.ui.reader.viewer.pager.PagerPageHolder
|
||||||
import eu.kanade.tachiyomi.util.lang.plusAssign
|
import eu.kanade.tachiyomi.util.lang.plusAssign
|
||||||
import eu.kanade.tachiyomi.util.system.ImageUtil
|
import eu.kanade.tachiyomi.util.system.ImageUtil
|
||||||
|
import kotlinx.coroutines.CoroutineScope
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.Job
|
||||||
|
import kotlinx.coroutines.cancel
|
||||||
|
import kotlinx.coroutines.flow.launchIn
|
||||||
|
import kotlinx.coroutines.flow.onEach
|
||||||
import rx.Completable
|
import rx.Completable
|
||||||
import rx.Observable
|
import rx.Observable
|
||||||
import rx.schedulers.Schedulers
|
import rx.schedulers.Schedulers
|
||||||
@ -41,9 +47,16 @@ class HttpPageLoader(
|
|||||||
private val subscriptions = CompositeSubscription()
|
private val subscriptions = CompositeSubscription()
|
||||||
|
|
||||||
private val preferences by injectLazy<PreferencesHelper>()
|
private val preferences by injectLazy<PreferencesHelper>()
|
||||||
private val preloadSize = 4
|
private var preloadSize = preferences.preloadSize().get()
|
||||||
|
|
||||||
|
private val scope = CoroutineScope(Job() + Dispatchers.IO)
|
||||||
init {
|
init {
|
||||||
|
// Adding flow since we can reach reader settings after this is created
|
||||||
|
preferences.preloadSize().asFlow()
|
||||||
|
.onEach {
|
||||||
|
preloadSize = it
|
||||||
|
}
|
||||||
|
.launchIn(scope)
|
||||||
subscriptions += Observable.defer { Observable.just(queue.take().page) }
|
subscriptions += Observable.defer { Observable.just(queue.take().page) }
|
||||||
.filter { it.status == Page.QUEUE }
|
.filter { it.status == Page.QUEUE }
|
||||||
.concatMap { source.fetchImageFromCacheThenNet(it) }
|
.concatMap { source.fetchImageFromCacheThenNet(it) }
|
||||||
@ -65,6 +78,7 @@ class HttpPageLoader(
|
|||||||
*/
|
*/
|
||||||
override fun recycle() {
|
override fun recycle() {
|
||||||
super.recycle()
|
super.recycle()
|
||||||
|
scope.cancel()
|
||||||
subscriptions.unsubscribe()
|
subscriptions.unsubscribe()
|
||||||
queue.clear()
|
queue.clear()
|
||||||
|
|
||||||
|
@ -57,6 +57,14 @@ class SettingsReaderController : SettingsController() {
|
|||||||
defaultValue = false
|
defaultValue = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
intListPreference(activity) {
|
||||||
|
key = Keys.preloadSize
|
||||||
|
titleRes = R.string.page_preload_amount
|
||||||
|
entryValues = listOf(4, 6, 8, 10, 12, 14, 16, 20)
|
||||||
|
entries = entryValues.map { context.resources.getQuantityString(R.plurals.pages_plural, it, it) }
|
||||||
|
defaultValue = 6
|
||||||
|
summaryRes = R.string.amount_of_pages_to_preload
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
preferenceCategory {
|
preferenceCategory {
|
||||||
|
@ -330,6 +330,8 @@
|
|||||||
<string name="double_tap_anim_speed">Double tap animation speed</string>
|
<string name="double_tap_anim_speed">Double tap animation speed</string>
|
||||||
<string name="show_page_number">Show page number</string>
|
<string name="show_page_number">Show page number</string>
|
||||||
<string name="true_32bit_color">32-bit color</string>
|
<string name="true_32bit_color">32-bit color</string>
|
||||||
|
<string name="page_preload_amount">Page preload amount</string>
|
||||||
|
<string name="amount_of_pages_to_preload">The amount of pages to preload when reading. Higher values will result in a smoother reading experience, at the cost of higher cache and network usage.</string>
|
||||||
<string name="reduces_banding_impacts_performance">Reduces banding, but impacts
|
<string name="reduces_banding_impacts_performance">Reduces banding, but impacts
|
||||||
performance</string>
|
performance</string>
|
||||||
<string name="crop_borders">Crop borders</string>
|
<string name="crop_borders">Crop borders</string>
|
||||||
@ -406,6 +408,11 @@
|
|||||||
<string name="page_layout">Page layout</string>
|
<string name="page_layout">Page layout</string>
|
||||||
<string name="automatic_can_still_switch">While using automatic page layout, you can still switch between layouts while reading without overriding this setting</string>
|
<string name="automatic_can_still_switch">While using automatic page layout, you can still switch between layouts while reading without overriding this setting</string>
|
||||||
<string name="automatic_orientation">Automatic (based on orientation)</string>
|
<string name="automatic_orientation">Automatic (based on orientation)</string>
|
||||||
|
<plurals name="pages_plural">
|
||||||
|
<item quantity="one">%1$d page</item>
|
||||||
|
<item quantity="other">%1$d pages</item>
|
||||||
|
</plurals>
|
||||||
|
|
||||||
|
|
||||||
<!-- Manga details -->
|
<!-- Manga details -->
|
||||||
<string name="about_this_">About this %1$s</string>
|
<string name="about_this_">About this %1$s</string>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user