Bug/2894 covers not updating (#2908)

* Use a wrapper around Manga to supply glide with proper equals() and hashCode() impl. for caching

* reload image if url has changed

* ignore case for http scheme comparison

* more ignore case for http scheme comparison

* fix indenting

* use data class for MangaThumbnail
This commit is contained in:
MCAxiaz 2020-04-21 06:13:23 -07:00 committed by GitHub
parent a68c1adba6
commit b3611eef9d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 49 additions and 26 deletions

View File

@ -0,0 +1,7 @@
package eu.kanade.tachiyomi.data.glide
import eu.kanade.tachiyomi.data.database.models.Manga
data class MangaThumbnail(val manga: Manga, val url: String?)
fun Manga.toMangaThumbnail() = MangaThumbnail(this, this.thumbnail_url)

View File

@ -31,7 +31,7 @@ import uy.kohesive.injekt.injectLazy
* *
* @param context the application context. * @param context the application context.
*/ */
class MangaModelLoader : ModelLoader<Manga, InputStream> { class MangaThumbnailModelLoader : ModelLoader<MangaThumbnail, InputStream> {
/** /**
* Cover cache where persistent covers are stored. * Cover cache where persistent covers are stored.
@ -60,18 +60,18 @@ class MangaModelLoader : ModelLoader<Manga, InputStream> {
private val cachedHeaders = hashMapOf<Long, LazyHeaders>() private val cachedHeaders = hashMapOf<Long, LazyHeaders>()
/** /**
* Factory class for creating [MangaModelLoader] instances. * Factory class for creating [MangaThumbnailModelLoader] instances.
*/ */
class Factory : ModelLoaderFactory<Manga, InputStream> { class Factory : ModelLoaderFactory<MangaThumbnail, InputStream> {
override fun build(multiFactory: MultiModelLoaderFactory): ModelLoader<Manga, InputStream> { override fun build(multiFactory: MultiModelLoaderFactory): ModelLoader<MangaThumbnail, InputStream> {
return MangaModelLoader() return MangaThumbnailModelLoader()
} }
override fun teardown() {} override fun teardown() {}
} }
override fun handles(model: Manga): Boolean { override fun handles(model: MangaThumbnail): Boolean {
return true return true
} }
@ -83,18 +83,20 @@ class MangaModelLoader : ModelLoader<Manga, InputStream> {
* @param height the height of the view where the resource will be loaded. * @param height the height of the view where the resource will be loaded.
*/ */
override fun buildLoadData( override fun buildLoadData(
manga: Manga, mangaThumbnail: MangaThumbnail,
width: Int, width: Int,
height: Int, height: Int,
options: Options options: Options
): ModelLoader.LoadData<InputStream>? { ): ModelLoader.LoadData<InputStream>? {
// Check thumbnail is not null or empty // Check thumbnail is not null or empty
val url = manga.thumbnail_url val url = mangaThumbnail.url
if (url == null || url.isEmpty()) { if (url == null || url.isEmpty()) {
return null return null
} }
if (url.startsWith("http")) { val manga = mangaThumbnail.manga
if (url.startsWith("http", true)) {
val source = sourceManager.get(manga.source) as? HttpSource val source = sourceManager.get(manga.source) as? HttpSource
val glideUrl = GlideUrl(url, getHeaders(manga, source)) val glideUrl = GlideUrl(url, getHeaders(manga, source))
@ -126,7 +128,7 @@ class MangaModelLoader : ModelLoader<Manga, InputStream> {
* *
* @param manga the model. * @param manga the model.
*/ */
fun getHeaders(manga: Manga, source: HttpSource?): Headers { private fun getHeaders(manga: Manga, source: HttpSource?): Headers {
if (source == null) return LazyHeaders.DEFAULT if (source == null) return LazyHeaders.DEFAULT
return cachedHeaders.getOrPut(manga.source) { return cachedHeaders.getOrPut(manga.source) {

View File

@ -13,7 +13,6 @@ import com.bumptech.glide.load.model.GlideUrl
import com.bumptech.glide.load.resource.drawable.DrawableTransitionOptions import com.bumptech.glide.load.resource.drawable.DrawableTransitionOptions
import com.bumptech.glide.module.AppGlideModule import com.bumptech.glide.module.AppGlideModule
import com.bumptech.glide.request.RequestOptions import com.bumptech.glide.request.RequestOptions
import eu.kanade.tachiyomi.data.database.models.Manga
import eu.kanade.tachiyomi.network.NetworkHelper import eu.kanade.tachiyomi.network.NetworkHelper
import java.io.InputStream import java.io.InputStream
import uy.kohesive.injekt.Injekt import uy.kohesive.injekt.Injekt
@ -36,7 +35,7 @@ class TachiGlideModule : AppGlideModule() {
val networkFactory = OkHttpUrlLoader.Factory(Injekt.get<NetworkHelper>().client) val networkFactory = OkHttpUrlLoader.Factory(Injekt.get<NetworkHelper>().client)
registry.replace(GlideUrl::class.java, InputStream::class.java, networkFactory) registry.replace(GlideUrl::class.java, InputStream::class.java, networkFactory)
registry.append(Manga::class.java, InputStream::class.java, MangaModelLoader.Factory()) registry.append(MangaThumbnail::class.java, InputStream::class.java, MangaThumbnailModelLoader.Factory())
registry.append(InputStream::class.java, InputStream::class.java, PassthroughModelLoader registry.append(InputStream::class.java, InputStream::class.java, PassthroughModelLoader
.Factory()) .Factory())
} }

View File

@ -22,6 +22,7 @@ import eu.kanade.tachiyomi.data.database.models.LibraryManga
import eu.kanade.tachiyomi.data.database.models.Manga import eu.kanade.tachiyomi.data.database.models.Manga
import eu.kanade.tachiyomi.data.download.DownloadManager import eu.kanade.tachiyomi.data.download.DownloadManager
import eu.kanade.tachiyomi.data.download.DownloadService import eu.kanade.tachiyomi.data.download.DownloadService
import eu.kanade.tachiyomi.data.glide.toMangaThumbnail
import eu.kanade.tachiyomi.data.library.LibraryUpdateRanker.rankingScheme import eu.kanade.tachiyomi.data.library.LibraryUpdateRanker.rankingScheme
import eu.kanade.tachiyomi.data.library.LibraryUpdateService.Companion.start import eu.kanade.tachiyomi.data.library.LibraryUpdateService.Companion.start
import eu.kanade.tachiyomi.data.notification.NotificationReceiver import eu.kanade.tachiyomi.data.notification.NotificationReceiver
@ -557,7 +558,7 @@ class LibraryUpdateService(
return try { return try {
Glide.with(this) Glide.with(this)
.asBitmap() .asBitmap()
.load(manga) .load(manga.toMangaThumbnail())
.dontTransform() .dontTransform()
.centerCrop() .centerCrop()
.circleCrop() .circleCrop()

View File

@ -4,6 +4,7 @@ import android.view.View
import com.bumptech.glide.load.engine.DiskCacheStrategy import com.bumptech.glide.load.engine.DiskCacheStrategy
import eu.davidea.flexibleadapter.FlexibleAdapter import eu.davidea.flexibleadapter.FlexibleAdapter
import eu.kanade.tachiyomi.data.glide.GlideApp import eu.kanade.tachiyomi.data.glide.GlideApp
import eu.kanade.tachiyomi.data.glide.toMangaThumbnail
import eu.kanade.tachiyomi.source.LocalSource import eu.kanade.tachiyomi.source.LocalSource
import eu.kanade.tachiyomi.util.view.visibleIf import eu.kanade.tachiyomi.util.view.visibleIf
import kotlinx.android.synthetic.main.source_grid_item.download_text import kotlinx.android.synthetic.main.source_grid_item.download_text
@ -52,7 +53,7 @@ class LibraryGridHolder(
// Update the cover. // Update the cover.
GlideApp.with(view.context).clear(thumbnail) GlideApp.with(view.context).clear(thumbnail)
GlideApp.with(view.context) GlideApp.with(view.context)
.load(item.manga) .load(item.manga.toMangaThumbnail())
.diskCacheStrategy(DiskCacheStrategy.RESOURCE) .diskCacheStrategy(DiskCacheStrategy.RESOURCE)
.centerCrop() .centerCrop()
.into(thumbnail) .into(thumbnail)

View File

@ -4,6 +4,7 @@ import android.view.View
import com.bumptech.glide.load.engine.DiskCacheStrategy import com.bumptech.glide.load.engine.DiskCacheStrategy
import eu.davidea.flexibleadapter.FlexibleAdapter import eu.davidea.flexibleadapter.FlexibleAdapter
import eu.kanade.tachiyomi.data.glide.GlideApp import eu.kanade.tachiyomi.data.glide.GlideApp
import eu.kanade.tachiyomi.data.glide.toMangaThumbnail
import eu.kanade.tachiyomi.source.LocalSource import eu.kanade.tachiyomi.source.LocalSource
import eu.kanade.tachiyomi.util.view.visibleIf import eu.kanade.tachiyomi.util.view.visibleIf
import kotlinx.android.synthetic.main.source_list_item.download_text import kotlinx.android.synthetic.main.source_list_item.download_text
@ -59,7 +60,7 @@ class LibraryListHolder(
// Update the cover. // Update the cover.
GlideApp.with(itemView.context).clear(thumbnail) GlideApp.with(itemView.context).clear(thumbnail)
GlideApp.with(itemView.context) GlideApp.with(itemView.context)
.load(item.manga) .load(item.manga.toMangaThumbnail())
.diskCacheStrategy(DiskCacheStrategy.RESOURCE) .diskCacheStrategy(DiskCacheStrategy.RESOURCE)
.centerCrop() .centerCrop()
.circleCrop() .circleCrop()

View File

@ -16,6 +16,7 @@ import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.data.database.models.Category import eu.kanade.tachiyomi.data.database.models.Category
import eu.kanade.tachiyomi.data.database.models.Manga import eu.kanade.tachiyomi.data.database.models.Manga
import eu.kanade.tachiyomi.data.glide.GlideApp import eu.kanade.tachiyomi.data.glide.GlideApp
import eu.kanade.tachiyomi.data.glide.toMangaThumbnail
import eu.kanade.tachiyomi.data.preference.PreferencesHelper import eu.kanade.tachiyomi.data.preference.PreferencesHelper
import eu.kanade.tachiyomi.databinding.MangaInfoControllerBinding import eu.kanade.tachiyomi.databinding.MangaInfoControllerBinding
import eu.kanade.tachiyomi.source.Source import eu.kanade.tachiyomi.source.Source
@ -61,6 +62,8 @@ class MangaInfoController(private val fromSource: Boolean = false) :
private var initialLoad: Boolean = true private var initialLoad: Boolean = true
private var thumbnailUrl: String? = null
override fun createPresenter(): MangaInfoPresenter { override fun createPresenter(): MangaInfoPresenter {
val ctrl = parentController as MangaController val ctrl = parentController as MangaController
return MangaInfoPresenter(ctrl.manga!!, ctrl.source!!, ctrl.mangaFavoriteRelay) return MangaInfoPresenter(ctrl.manga!!, ctrl.source!!, ctrl.mangaFavoriteRelay)
@ -224,15 +227,18 @@ class MangaInfoController(private val fromSource: Boolean = false) :
setFavoriteButtonState(manga.favorite) setFavoriteButtonState(manga.favorite)
// Set cover if it wasn't already. // Set cover if it wasn't already.
if (binding.mangaCover.drawable == null && !manga.thumbnail_url.isNullOrEmpty()) { if (binding.mangaCover.drawable == null || manga.thumbnail_url != thumbnailUrl) {
thumbnailUrl = manga.thumbnail_url
val mangaThumbnail = manga.toMangaThumbnail()
GlideApp.with(view.context) GlideApp.with(view.context)
.load(manga) .load(mangaThumbnail)
.diskCacheStrategy(DiskCacheStrategy.RESOURCE) .diskCacheStrategy(DiskCacheStrategy.RESOURCE)
.centerCrop() .centerCrop()
.into(binding.mangaCover) .into(binding.mangaCover)
GlideApp.with(view.context) GlideApp.with(view.context)
.load(manga) .load(mangaThumbnail)
.diskCacheStrategy(DiskCacheStrategy.RESOURCE) .diskCacheStrategy(DiskCacheStrategy.RESOURCE)
.centerCrop() .centerCrop()
.into(binding.backdrop) .into(binding.backdrop)

View File

@ -4,6 +4,7 @@ import android.view.View
import com.bumptech.glide.load.engine.DiskCacheStrategy import com.bumptech.glide.load.engine.DiskCacheStrategy
import eu.davidea.flexibleadapter.FlexibleAdapter import eu.davidea.flexibleadapter.FlexibleAdapter
import eu.kanade.tachiyomi.data.glide.GlideApp import eu.kanade.tachiyomi.data.glide.GlideApp
import eu.kanade.tachiyomi.data.glide.toMangaThumbnail
import eu.kanade.tachiyomi.ui.base.holder.BaseFlexibleViewHolder import eu.kanade.tachiyomi.ui.base.holder.BaseFlexibleViewHolder
import kotlinx.android.synthetic.main.source_list_item.thumbnail import kotlinx.android.synthetic.main.source_list_item.thumbnail
import kotlinx.android.synthetic.main.source_list_item.title import kotlinx.android.synthetic.main.source_list_item.title
@ -26,7 +27,7 @@ class MangaHolder(
// Update the cover. // Update the cover.
GlideApp.with(itemView.context).clear(thumbnail) GlideApp.with(itemView.context).clear(thumbnail)
GlideApp.with(itemView.context) GlideApp.with(itemView.context)
.load(item.manga) .load(item.manga.toMangaThumbnail())
.diskCacheStrategy(DiskCacheStrategy.RESOURCE) .diskCacheStrategy(DiskCacheStrategy.RESOURCE)
.centerCrop() .centerCrop()
.circleCrop() .circleCrop()

View File

@ -411,7 +411,7 @@ class PagerPageHolder(
} }
val imageUrl = page.imageUrl val imageUrl = page.imageUrl
if (imageUrl.orEmpty().startsWith("http")) { if (imageUrl.orEmpty().startsWith("http", true)) {
PagerButton(context, viewer).apply { PagerButton(context, viewer).apply {
layoutParams = LayoutParams(WRAP_CONTENT, WRAP_CONTENT).apply { layoutParams = LayoutParams(WRAP_CONTENT, WRAP_CONTENT).apply {
setMargins(margins, margins, margins, margins) setMargins(margins, margins, margins, margins)

View File

@ -454,7 +454,7 @@ class WebtoonPageHolder(
} }
val imageUrl = page?.imageUrl val imageUrl = page?.imageUrl
if (imageUrl.orEmpty().startsWith("http")) { if (imageUrl.orEmpty().startsWith("http", true)) {
AppCompatButton(context).apply { AppCompatButton(context).apply {
layoutParams = FrameLayout.LayoutParams(WRAP_CONTENT, WRAP_CONTENT).apply { layoutParams = FrameLayout.LayoutParams(WRAP_CONTENT, WRAP_CONTENT).apply {
setMargins(0, margins, 0, margins) setMargins(0, margins, 0, margins)

View File

@ -5,6 +5,7 @@ import com.bumptech.glide.load.engine.DiskCacheStrategy
import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.data.database.models.MangaChapterHistory import eu.kanade.tachiyomi.data.database.models.MangaChapterHistory
import eu.kanade.tachiyomi.data.glide.GlideApp import eu.kanade.tachiyomi.data.glide.GlideApp
import eu.kanade.tachiyomi.data.glide.toMangaThumbnail
import eu.kanade.tachiyomi.ui.base.holder.BaseFlexibleViewHolder import eu.kanade.tachiyomi.ui.base.holder.BaseFlexibleViewHolder
import eu.kanade.tachiyomi.util.lang.toTimestampString import eu.kanade.tachiyomi.util.lang.toTimestampString
import java.util.Date import java.util.Date
@ -67,7 +68,7 @@ class HistoryHolder(
GlideApp.with(itemView.context).clear(cover) GlideApp.with(itemView.context).clear(cover)
if (!manga.thumbnail_url.isNullOrEmpty()) { if (!manga.thumbnail_url.isNullOrEmpty()) {
GlideApp.with(itemView.context) GlideApp.with(itemView.context)
.load(manga) .load(manga.toMangaThumbnail())
.diskCacheStrategy(DiskCacheStrategy.RESOURCE) .diskCacheStrategy(DiskCacheStrategy.RESOURCE)
.centerCrop() .centerCrop()
.into(cover) .into(cover)

View File

@ -6,6 +6,7 @@ import com.bumptech.glide.load.engine.DiskCacheStrategy
import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.data.download.model.Download import eu.kanade.tachiyomi.data.download.model.Download
import eu.kanade.tachiyomi.data.glide.GlideApp import eu.kanade.tachiyomi.data.glide.GlideApp
import eu.kanade.tachiyomi.data.glide.toMangaThumbnail
import eu.kanade.tachiyomi.ui.base.holder.BaseFlexibleViewHolder import eu.kanade.tachiyomi.ui.base.holder.BaseFlexibleViewHolder
import eu.kanade.tachiyomi.util.system.getResourceColor import eu.kanade.tachiyomi.util.system.getResourceColor
import kotlinx.android.synthetic.main.updates_item.chapter_title import kotlinx.android.synthetic.main.updates_item.chapter_title
@ -58,7 +59,7 @@ class UpdatesHolder(private val view: View, private val adapter: UpdatesAdapter)
GlideApp.with(itemView.context).clear(manga_cover) GlideApp.with(itemView.context).clear(manga_cover)
if (!item.manga.thumbnail_url.isNullOrEmpty()) { if (!item.manga.thumbnail_url.isNullOrEmpty()) {
GlideApp.with(itemView.context) GlideApp.with(itemView.context)
.load(item.manga) .load(item.manga.toMangaThumbnail())
.diskCacheStrategy(DiskCacheStrategy.RESOURCE) .diskCacheStrategy(DiskCacheStrategy.RESOURCE)
.circleCrop() .circleCrop()
.into(manga_cover) .into(manga_cover)

View File

@ -5,6 +5,7 @@ import com.bumptech.glide.load.engine.DiskCacheStrategy
import eu.davidea.flexibleadapter.FlexibleAdapter import eu.davidea.flexibleadapter.FlexibleAdapter
import eu.kanade.tachiyomi.data.database.models.Manga import eu.kanade.tachiyomi.data.database.models.Manga
import eu.kanade.tachiyomi.data.glide.GlideApp import eu.kanade.tachiyomi.data.glide.GlideApp
import eu.kanade.tachiyomi.data.glide.toMangaThumbnail
import eu.kanade.tachiyomi.widget.StateImageViewTarget import eu.kanade.tachiyomi.widget.StateImageViewTarget
import kotlinx.android.synthetic.main.source_grid_item.progress import kotlinx.android.synthetic.main.source_grid_item.progress
import kotlinx.android.synthetic.main.source_grid_item.thumbnail import kotlinx.android.synthetic.main.source_grid_item.thumbnail
@ -41,7 +42,7 @@ class SourceGridHolder(private val view: View, private val adapter: FlexibleAdap
GlideApp.with(view.context).clear(thumbnail) GlideApp.with(view.context).clear(thumbnail)
if (!manga.thumbnail_url.isNullOrEmpty()) { if (!manga.thumbnail_url.isNullOrEmpty()) {
GlideApp.with(view.context) GlideApp.with(view.context)
.load(manga) .load(manga.toMangaThumbnail())
.diskCacheStrategy(DiskCacheStrategy.DATA) .diskCacheStrategy(DiskCacheStrategy.DATA)
.centerCrop() .centerCrop()
.placeholder(android.R.color.transparent) .placeholder(android.R.color.transparent)

View File

@ -7,6 +7,7 @@ import eu.davidea.flexibleadapter.FlexibleAdapter
import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.data.database.models.Manga import eu.kanade.tachiyomi.data.database.models.Manga
import eu.kanade.tachiyomi.data.glide.GlideApp import eu.kanade.tachiyomi.data.glide.GlideApp
import eu.kanade.tachiyomi.data.glide.toMangaThumbnail
import eu.kanade.tachiyomi.util.system.getResourceColor import eu.kanade.tachiyomi.util.system.getResourceColor
import kotlinx.android.synthetic.main.source_list_item.thumbnail import kotlinx.android.synthetic.main.source_list_item.thumbnail
import kotlinx.android.synthetic.main.source_list_item.title import kotlinx.android.synthetic.main.source_list_item.title
@ -42,7 +43,7 @@ class SourceListHolder(private val view: View, adapter: FlexibleAdapter<*>) :
GlideApp.with(view.context).clear(thumbnail) GlideApp.with(view.context).clear(thumbnail)
if (!manga.thumbnail_url.isNullOrEmpty()) { if (!manga.thumbnail_url.isNullOrEmpty()) {
GlideApp.with(view.context) GlideApp.with(view.context)
.load(manga) .load(manga.toMangaThumbnail())
.diskCacheStrategy(DiskCacheStrategy.DATA) .diskCacheStrategy(DiskCacheStrategy.DATA)
.centerCrop() .centerCrop()
.circleCrop() .circleCrop()

View File

@ -4,6 +4,7 @@ import android.view.View
import com.bumptech.glide.load.engine.DiskCacheStrategy import com.bumptech.glide.load.engine.DiskCacheStrategy
import eu.kanade.tachiyomi.data.database.models.Manga import eu.kanade.tachiyomi.data.database.models.Manga
import eu.kanade.tachiyomi.data.glide.GlideApp import eu.kanade.tachiyomi.data.glide.GlideApp
import eu.kanade.tachiyomi.data.glide.toMangaThumbnail
import eu.kanade.tachiyomi.ui.base.holder.BaseFlexibleViewHolder import eu.kanade.tachiyomi.ui.base.holder.BaseFlexibleViewHolder
import eu.kanade.tachiyomi.widget.StateImageViewTarget import eu.kanade.tachiyomi.widget.StateImageViewTarget
import kotlinx.android.synthetic.main.global_search_controller_card_item.itemImage import kotlinx.android.synthetic.main.global_search_controller_card_item.itemImage
@ -42,7 +43,7 @@ class GlobalSearchCardHolder(view: View, adapter: GlobalSearchCardAdapter) :
GlideApp.with(itemView.context).clear(itemImage) GlideApp.with(itemView.context).clear(itemImage)
if (!manga.thumbnail_url.isNullOrEmpty()) { if (!manga.thumbnail_url.isNullOrEmpty()) {
GlideApp.with(itemView.context) GlideApp.with(itemView.context)
.load(manga) .load(manga.toMangaThumbnail())
.diskCacheStrategy(DiskCacheStrategy.DATA) .diskCacheStrategy(DiskCacheStrategy.DATA)
.centerCrop() .centerCrop()
.skipMemoryCache(true) .skipMemoryCache(true)