Use PageLoader for thumbnails

This commit is contained in:
Koitharu
2022-04-20 12:57:07 +03:00
parent 44d8d0f246
commit 6bf4e0cf89
5 changed files with 69 additions and 43 deletions

View File

@@ -2,13 +2,13 @@ package org.koitharu.kotatsu.local.data
import android.content.Context import android.content.Context
import com.tomclaw.cache.DiskLruCache import com.tomclaw.cache.DiskLruCache
import java.io.File
import java.io.InputStream
import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.MutableStateFlow
import org.koitharu.kotatsu.parsers.util.longHashCode import org.koitharu.kotatsu.parsers.util.longHashCode
import org.koitharu.kotatsu.utils.FileSize import org.koitharu.kotatsu.utils.FileSize
import org.koitharu.kotatsu.utils.ext.subdir import org.koitharu.kotatsu.utils.ext.subdir
import org.koitharu.kotatsu.utils.ext.takeIfReadable import org.koitharu.kotatsu.utils.ext.takeIfReadable
import java.io.File
import java.io.InputStream
class PagesCache(context: Context) { class PagesCache(context: Context) {
@@ -60,4 +60,4 @@ class PagesCache(context: Context) {
progress.value = (bytesCopied.toDouble() / contentLength.toDouble()).toFloat() progress.value = (bytesCopied.toDouble() / contentLength.toDouble()).toFloat()
} }
} }
} }

View File

@@ -6,10 +6,6 @@ import android.graphics.BitmapFactory
import android.net.Uri import android.net.Uri
import androidx.collection.LongSparseArray import androidx.collection.LongSparseArray
import androidx.collection.set import androidx.collection.set
import java.io.File
import java.util.*
import java.util.concurrent.atomic.AtomicInteger
import java.util.zip.ZipFile
import kotlinx.coroutines.* import kotlinx.coroutines.*
import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.StateFlow
@@ -31,6 +27,10 @@ import org.koitharu.kotatsu.parsers.util.await
import org.koitharu.kotatsu.reader.ui.pager.ReaderPage import org.koitharu.kotatsu.reader.ui.pager.ReaderPage
import org.koitharu.kotatsu.utils.ext.connectivityManager import org.koitharu.kotatsu.utils.ext.connectivityManager
import org.koitharu.kotatsu.utils.progress.ProgressDeferred import org.koitharu.kotatsu.utils.progress.ProgressDeferred
import java.io.File
import java.util.*
import java.util.concurrent.atomic.AtomicInteger
import java.util.zip.ZipFile
private const val PROGRESS_UNDEFINED = -1f private const val PROGRESS_UNDEFINED = -1f
private const val PREFETCH_LIMIT_DEFAULT = 10 private const val PREFETCH_LIMIT_DEFAULT = 10
@@ -115,8 +115,13 @@ class PageLoader : KoinComponent, Closeable {
private fun onIdle() { private fun onIdle() {
synchronized(prefetchQueue) { synchronized(prefetchQueue) {
val page = prefetchQueue.pollFirst() ?: return while (prefetchQueue.isNotEmpty()) {
tasks[page.id] = loadPageAsyncImpl(page) val page = prefetchQueue.pollFirst() ?: return
if (cache[page.url] == null) {
tasks[page.id] = loadPageAsyncImpl(page)
return
}
}
} }
} }

View File

@@ -19,17 +19,20 @@ import org.koitharu.kotatsu.core.prefs.AppSettings
import org.koitharu.kotatsu.databinding.SheetPagesBinding import org.koitharu.kotatsu.databinding.SheetPagesBinding
import org.koitharu.kotatsu.list.ui.MangaListSpanResolver import org.koitharu.kotatsu.list.ui.MangaListSpanResolver
import org.koitharu.kotatsu.parsers.model.MangaPage import org.koitharu.kotatsu.parsers.model.MangaPage
import org.koitharu.kotatsu.reader.domain.PageLoader
import org.koitharu.kotatsu.reader.ui.thumbnails.adapter.PageThumbnailAdapter import org.koitharu.kotatsu.reader.ui.thumbnails.adapter.PageThumbnailAdapter
import org.koitharu.kotatsu.utils.BottomSheetToolbarController import org.koitharu.kotatsu.utils.BottomSheetToolbarController
import org.koitharu.kotatsu.utils.ext.viewLifecycleScope import org.koitharu.kotatsu.utils.ext.viewLifecycleScope
import org.koitharu.kotatsu.utils.ext.withArgs import org.koitharu.kotatsu.utils.ext.withArgs
class PagesThumbnailsSheet : BaseBottomSheet<SheetPagesBinding>(), class PagesThumbnailsSheet :
BaseBottomSheet<SheetPagesBinding>(),
OnListItemClickListener<MangaPage> { OnListItemClickListener<MangaPage> {
private lateinit var thumbnails: List<PageThumbnail> private lateinit var thumbnails: List<PageThumbnail>
private val spanResolver = MangaListSpanResolver() private val spanResolver = MangaListSpanResolver()
private var currentPageIndex = -1 private var currentPageIndex = -1
private var pageLoader: PageLoader? = null
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
@@ -75,11 +78,11 @@ class PagesThumbnailsSheet : BaseBottomSheet<SheetPagesBinding>(),
SpacingItemDecoration(resources.getDimensionPixelOffset(R.dimen.grid_spacing)) SpacingItemDecoration(resources.getDimensionPixelOffset(R.dimen.grid_spacing))
) )
adapter = PageThumbnailAdapter( adapter = PageThumbnailAdapter(
thumbnails, dataSet = thumbnails,
get(), coil = get(),
viewLifecycleScope, scope = viewLifecycleScope,
get(), loader = PageLoader().also { pageLoader = it },
this@PagesThumbnailsSheet clickListener = this@PagesThumbnailsSheet
) )
addOnLayoutChangeListener(spanResolver) addOnLayoutChangeListener(spanResolver)
spanResolver.setGridSize(get<AppSettings>().gridSize / 100f, this) spanResolver.setGridSize(get<AppSettings>().gridSize / 100f, this)
@@ -90,9 +93,17 @@ class PagesThumbnailsSheet : BaseBottomSheet<SheetPagesBinding>(),
} }
} }
override fun onDestroyView() {
super.onDestroyView()
pageLoader?.close()
pageLoader = null
}
override fun onItemClick(item: MangaPage, view: View) { override fun onItemClick(item: MangaPage, view: View) {
((parentFragment as? OnPageSelectListener) (
?: (activity as? OnPageSelectListener))?.run { (parentFragment as? OnPageSelectListener)
?: (activity as? OnPageSelectListener)
)?.run {
onPageSelected(item) onPageSelected(item)
dismiss() dismiss()
} }
@@ -127,6 +138,5 @@ class PagesThumbnailsSheet : BaseBottomSheet<SheetPagesBinding>(),
putString(ARG_TITLE, title) putString(ARG_TITLE, title)
putInt(ARG_CURRENT, currentPage) putInt(ARG_CURRENT, currentPage)
}.show(fm, TAG) }.show(fm, TAG)
} }
} }

View File

@@ -1,27 +1,26 @@
package org.koitharu.kotatsu.reader.ui.thumbnails.adapter package org.koitharu.kotatsu.reader.ui.thumbnails.adapter
import androidx.core.net.toUri import android.graphics.drawable.Drawable
import coil.ImageLoader import coil.ImageLoader
import coil.request.ImageRequest import coil.request.ImageRequest
import coil.size.PixelSize import coil.size.PixelSize
import com.google.android.material.R as materialR
import com.hannesdorfmann.adapterdelegates4.dsl.adapterDelegateViewBinding import com.hannesdorfmann.adapterdelegates4.dsl.adapterDelegateViewBinding
import kotlinx.coroutines.* import kotlinx.coroutines.*
import org.koitharu.kotatsu.R import org.koitharu.kotatsu.R
import org.koitharu.kotatsu.base.ui.list.OnListItemClickListener import org.koitharu.kotatsu.base.ui.list.OnListItemClickListener
import org.koitharu.kotatsu.databinding.ItemPageThumbBinding import org.koitharu.kotatsu.databinding.ItemPageThumbBinding
import org.koitharu.kotatsu.local.data.PagesCache
import org.koitharu.kotatsu.parsers.model.MangaPage import org.koitharu.kotatsu.parsers.model.MangaPage
import org.koitharu.kotatsu.reader.domain.PageLoader
import org.koitharu.kotatsu.reader.ui.thumbnails.PageThumbnail import org.koitharu.kotatsu.reader.ui.thumbnails.PageThumbnail
import org.koitharu.kotatsu.utils.ext.IgnoreErrors
import org.koitharu.kotatsu.utils.ext.referer import org.koitharu.kotatsu.utils.ext.referer
import org.koitharu.kotatsu.utils.ext.setTextColorAttr import org.koitharu.kotatsu.utils.ext.setTextColorAttr
import com.google.android.material.R as materialR
fun pageThumbnailAD( fun pageThumbnailAD(
coil: ImageLoader, coil: ImageLoader,
scope: CoroutineScope, scope: CoroutineScope,
cache: PagesCache, loader: PageLoader,
clickListener: OnListItemClickListener<MangaPage> clickListener: OnListItemClickListener<MangaPage>,
) = adapterDelegateViewBinding<PageThumbnail, PageThumbnail, ItemPageThumbBinding>( ) = adapterDelegateViewBinding<PageThumbnail, PageThumbnail, ItemPageThumbBinding>(
{ inflater, parent -> ItemPageThumbBinding.inflate(inflater, parent, false) } { inflater, parent -> ItemPageThumbBinding.inflate(inflater, parent, false) }
) { ) {
@@ -33,6 +32,29 @@ fun pageThumbnailAD(
height = (gridWidth * 13f / 18f).toInt() height = (gridWidth * 13f / 18f).toInt()
) )
suspend fun loadPageThumbnail(item: PageThumbnail): Drawable? = withContext(Dispatchers.Default) {
item.page.preview?.let { url ->
coil.execute(
ImageRequest.Builder(context)
.data(url)
.referer(item.page.referer)
.size(thumbSize)
.allowRgb565(true)
.build()
).drawable
}?.let { drawable ->
return@withContext drawable
}
val file = loader.loadPage(item.page, force = false)
coil.execute(
ImageRequest.Builder(context)
.data(file)
.size(thumbSize)
.allowRgb565(true)
.build()
).drawable
}
binding.root.setOnClickListener { binding.root.setOnClickListener {
clickListener.onItemClick(item.page, itemView) clickListener.onItemClick(item.page, itemView)
} }
@@ -45,22 +67,11 @@ fun pageThumbnailAD(
setTextColorAttr(if (item.isCurrent) materialR.attr.colorOnTertiary else android.R.attr.textColorPrimary) setTextColorAttr(if (item.isCurrent) materialR.attr.colorOnTertiary else android.R.attr.textColorPrimary)
text = (item.number).toString() text = (item.number).toString()
} }
job = scope.launch(Dispatchers.Default + IgnoreErrors) { job = scope.launch {
val url = item.page.preview ?: item.page.url.let { val drawable = runCatching {
val pageUrl = item.repository.getPageUrl(item.page) loadPageThumbnail(item)
cache[pageUrl]?.toUri()?.toString() ?: pageUrl }.getOrNull()
} binding.imageViewThumb.setImageDrawable(drawable)
val drawable = coil.execute(
ImageRequest.Builder(context)
.data(url)
.referer(item.page.referer)
.size(thumbSize)
.allowRgb565(true)
.build()
).drawable
withContext(Dispatchers.Main) {
binding.imageViewThumb.setImageDrawable(drawable)
}
} }
} }

View File

@@ -4,20 +4,20 @@ import coil.ImageLoader
import com.hannesdorfmann.adapterdelegates4.ListDelegationAdapter import com.hannesdorfmann.adapterdelegates4.ListDelegationAdapter
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
import org.koitharu.kotatsu.base.ui.list.OnListItemClickListener import org.koitharu.kotatsu.base.ui.list.OnListItemClickListener
import org.koitharu.kotatsu.local.data.PagesCache
import org.koitharu.kotatsu.parsers.model.MangaPage import org.koitharu.kotatsu.parsers.model.MangaPage
import org.koitharu.kotatsu.reader.domain.PageLoader
import org.koitharu.kotatsu.reader.ui.thumbnails.PageThumbnail import org.koitharu.kotatsu.reader.ui.thumbnails.PageThumbnail
class PageThumbnailAdapter( class PageThumbnailAdapter(
dataSet: List<PageThumbnail>, dataSet: List<PageThumbnail>,
coil: ImageLoader, coil: ImageLoader,
scope: CoroutineScope, scope: CoroutineScope,
cache: PagesCache, loader: PageLoader,
clickListener: OnListItemClickListener<MangaPage> clickListener: OnListItemClickListener<MangaPage>
) : ListDelegationAdapter<List<PageThumbnail>>() { ) : ListDelegationAdapter<List<PageThumbnail>>() {
init { init {
delegatesManager.addDelegate(pageThumbnailAD(coil, scope, cache, clickListener)) delegatesManager.addDelegate(pageThumbnailAD(coil, scope, loader, clickListener))
setItems(dataSet) setItems(dataSet)
} }
} }