diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/cache/CoverCache.kt b/app/src/main/java/eu/kanade/tachiyomi/data/cache/CoverCache.kt index fe91ca5fd0..7ff72605b7 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/cache/CoverCache.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/cache/CoverCache.kt @@ -1,14 +1,11 @@ package eu.kanade.tachiyomi.data.cache import android.content.Context -import android.widget.ImageView import com.bumptech.glide.Glide -import com.bumptech.glide.load.engine.DiskCacheStrategy import com.bumptech.glide.load.model.GlideUrl import com.bumptech.glide.load.model.LazyHeaders import com.bumptech.glide.request.animation.GlideAnimation import com.bumptech.glide.request.target.SimpleTarget -import com.bumptech.glide.signature.StringSignature import eu.kanade.tachiyomi.util.DiskUtils import java.io.File import java.io.IOException @@ -28,17 +25,15 @@ class CoverCache(private val context: Context) { /** * Cache directory used for cache management. */ - private val CACHE_DIRNAME = "cover_disk_cache" - private val cacheDir: File = File(context.cacheDir, CACHE_DIRNAME) + private val cacheDir: File = File(context.externalCacheDir, "cover_disk_cache") /** * Download the cover with Glide and save the file. * @param thumbnailUrl url of thumbnail. * @param headers headers included in Glide request. - * @param imageView imageView where picture should be displayed. + * @param onReady function to call when the image is ready */ - @JvmOverloads - fun save(thumbnailUrl: String?, headers: LazyHeaders, imageView: ImageView? = null) { + fun save(thumbnailUrl: String?, headers: LazyHeaders, onReady: ((File) -> Unit)? = null) { // Check if url is empty. if (thumbnailUrl.isNullOrEmpty()) return @@ -51,12 +46,9 @@ class CoverCache(private val context: Context) { override fun onResourceReady(resource: File, anim: GlideAnimation) { try { // Copy the cover from Glide's cache to local cache. - copyToLocalCache(thumbnailUrl!!, resource) + copyToCache(thumbnailUrl!!, resource) - // Check if imageView isn't null and show picture in imageView. - if (imageView != null) { - loadFromCache(imageView, resource) - } + onReady?.invoke(resource) } catch (e: IOException) { // Do nothing. } @@ -64,6 +56,35 @@ class CoverCache(private val context: Context) { }) } + /** + * Save or load the image from cache + * @param thumbnailUrl the thumbnail url. + * @param headers headers included in Glide request. + * @param onReady function to call when the image is ready + */ + fun saveOrLoadFromCache(thumbnailUrl: String?, headers: LazyHeaders, onReady: ((File) -> Unit)?) { + // Check if url is empty. + if (thumbnailUrl.isNullOrEmpty()) + return + + // If file exist load it otherwise save it. + val localCover = getCoverFromCache(thumbnailUrl!!) + if (localCover.exists()) { + onReady?.invoke(localCover) + } else { + save(thumbnailUrl, headers, onReady) + } + } + + /** + * Returns the cover from cache. + * @param thumbnailUrl the thumbnail url. + * @return cover image. + */ + private fun getCoverFromCache(thumbnailUrl: String): File { + return File(cacheDir, DiskUtils.hashKeyForDisk(thumbnailUrl)) + } + /** * Copy the given file to this cache. * @param thumbnailUrl url of thumbnail. @@ -71,7 +92,7 @@ class CoverCache(private val context: Context) { * @throws IOException if there's any error. */ @Throws(IOException::class) - fun copyToLocalCache(thumbnailUrl: String, sourceFile: File) { + fun copyToCache(thumbnailUrl: String, sourceFile: File) { // Get destination file. val destFile = getCoverFromCache(thumbnailUrl) @@ -85,28 +106,19 @@ class CoverCache(private val context: Context) { * @throws IOException if there's any error. */ @Throws(IOException::class) - fun copyToLocalCache(thumbnailUrl: String, inputStream: InputStream) { + fun copyToCache(thumbnailUrl: String, inputStream: InputStream) { // Get destination file. val destFile = getCoverFromCache(thumbnailUrl) destFile.outputStream().use { inputStream.copyTo(it) } } - /** - * Returns the cover from cache. - * @param thumbnailUrl the thumbnail url. - * @return cover image. - */ - private fun getCoverFromCache(thumbnailUrl: String): File { - return File(cacheDir, DiskUtils.hashKeyForDisk(thumbnailUrl)) - } - /** * Delete the cover file from the cache. * @param thumbnailUrl the thumbnail url. * @return status of deletion. */ - fun deleteCoverFromCache(thumbnailUrl: String?): Boolean { + fun deleteFromCache(thumbnailUrl: String?): Boolean { // Check if url is empty. if (thumbnailUrl.isNullOrEmpty()) return false @@ -116,56 +128,4 @@ class CoverCache(private val context: Context) { return file.exists() && file.delete() } - /** - * Save or load the image from cache - * @param imageView imageView where picture should be displayed. - * @param thumbnailUrl the thumbnail url. - * @param headers headers included in Glide request. - */ - fun saveOrLoadFromCache(imageView: ImageView, thumbnailUrl: String, headers: LazyHeaders) { - // If file exist load it otherwise save it. - val localCover = getCoverFromCache(thumbnailUrl) - if (localCover.exists()) { - loadFromCache(imageView, localCover) - } else { - save(thumbnailUrl, headers, imageView) - } - } - - /** - * Helper method to load the cover from the cache directory into the specified image view. - * Glide stores the resized image in its cache to improve performance. - * @param imageView imageView where picture should be displayed. - * @param file file to load. Must exist!. - */ - private fun loadFromCache(imageView: ImageView, file: File) { - Glide.with(context) - .load(file) - .diskCacheStrategy(DiskCacheStrategy.RESULT) - .centerCrop() - .signature(StringSignature(file.lastModified().toString())) - .into(imageView) - } - - /** - * Helper method to load the cover from network into the specified image view. - * The source image is stored in Glide's cache so that it can be easily copied to this cache - * if the manga is added to the library. - * @param imageView imageView where picture should be displayed. - * @param thumbnailUrl url of thumbnail. - * @param headers headers included in Glide request. - */ - fun loadFromNetwork(imageView: ImageView, thumbnailUrl: String?, headers: LazyHeaders) { - // Check if url is empty. - if (thumbnailUrl.isNullOrEmpty()) - return - - val url = GlideUrl(thumbnailUrl, headers) - Glide.with(context) - .load(url) - .diskCacheStrategy(DiskCacheStrategy.SOURCE) - .centerCrop() - .into(imageView) - } - } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/catalogue/CatalogueAdapter.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/catalogue/CatalogueAdapter.kt index d67f28d953..8999873339 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/catalogue/CatalogueAdapter.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/catalogue/CatalogueAdapter.kt @@ -12,7 +12,7 @@ import java.util.* * * @param fragment the fragment containing this adapter. */ -class CatalogueAdapter(private val fragment: CatalogueFragment) : FlexibleAdapter() { +class CatalogueAdapter(val fragment: CatalogueFragment) : FlexibleAdapter() { /** * Property to get the list of manga in the adapter. @@ -83,7 +83,7 @@ class CatalogueAdapter(private val fragment: CatalogueFragment) : FlexibleAdapte */ override fun onBindViewHolder(holder: CatalogueHolder, position: Int) { val manga = getItem(position) - holder.onSetValues(manga, fragment.presenter) + holder.onSetValues(manga) } } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/catalogue/CatalogueFragment.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/catalogue/CatalogueFragment.kt index 7fe75a443f..52c0f10109 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/catalogue/CatalogueFragment.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/catalogue/CatalogueFragment.kt @@ -370,7 +370,7 @@ class CatalogueFragment : BaseRxFragment(), FlexibleViewHold * @param manga the manga initialized */ fun onMangaInitialized(manga: Manga) { - getHolder(manga)?.setImage(manga, presenter) + getHolder(manga)?.setImage(manga) } /** diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/catalogue/CatalogueGridHolder.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/catalogue/CatalogueGridHolder.kt index da7055c469..c071fc1de3 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/catalogue/CatalogueGridHolder.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/catalogue/CatalogueGridHolder.kt @@ -1,6 +1,9 @@ package eu.kanade.tachiyomi.ui.catalogue import android.view.View +import com.bumptech.glide.Glide +import com.bumptech.glide.load.engine.DiskCacheStrategy +import com.bumptech.glide.load.model.GlideUrl import eu.kanade.tachiyomi.data.database.models.Manga import kotlinx.android.synthetic.main.item_catalogue_grid.view.* @@ -13,7 +16,7 @@ import kotlinx.android.synthetic.main.item_catalogue_grid.view.* * @param listener a listener to react to single tap and long tap events. * @constructor creates a new catalogue holder. */ -class CatalogueGridHolder(private val view: View, adapter: CatalogueAdapter, listener: OnListItemClickListener) : +class CatalogueGridHolder(private val view: View, private val adapter: CatalogueAdapter, listener: OnListItemClickListener) : CatalogueHolder(view, adapter, listener) { /** @@ -21,16 +24,15 @@ class CatalogueGridHolder(private val view: View, adapter: CatalogueAdapter, lis * holder with the given manga. * * @param manga the manga to bind. - * @param presenter the catalogue presenter. */ - override fun onSetValues(manga: Manga, presenter: CataloguePresenter) { + override fun onSetValues(manga: Manga) { // Set manga title view.title.text = manga.title // Set alpha of thumbnail. view.thumbnail.alpha = if (manga.favorite) 0.3f else 1.0f - setImage(manga, presenter) + setImage(manga) } /** @@ -38,12 +40,18 @@ class CatalogueGridHolder(private val view: View, adapter: CatalogueAdapter, lis * and the url is now known. * * @param manga the manga to bind. - * @param presenter the catalogue presenter. */ - fun setImage(manga: Manga, presenter: CataloguePresenter) { + fun setImage(manga: Manga) { if (manga.thumbnail_url != null) { - presenter.coverCache.loadFromNetwork(view.thumbnail, manga.thumbnail_url, - presenter.source.glideHeaders) + val url = manga.thumbnail_url!! + val headers = adapter.fragment.presenter.source.glideHeaders + + Glide.with(view.context) + .load(if (headers != null) GlideUrl(url, headers) else url) + .diskCacheStrategy(DiskCacheStrategy.SOURCE) + .centerCrop() + .into(view.thumbnail) + } else { view.thumbnail.setImageResource(android.R.color.transparent) } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/catalogue/CatalogueHolder.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/catalogue/CatalogueHolder.kt index 3cc9a8bb9e..1280a0be82 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/catalogue/CatalogueHolder.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/catalogue/CatalogueHolder.kt @@ -19,7 +19,6 @@ abstract class CatalogueHolder(view: View, adapter: CatalogueAdapter, listener: * holder with the given manga. * * @param manga the manga to bind. - * @param presenter the catalogue presenter. */ - abstract fun onSetValues(manga: Manga, presenter: CataloguePresenter) + abstract fun onSetValues(manga: Manga) } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/catalogue/CatalogueListHolder.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/catalogue/CatalogueListHolder.kt index c1eb21dd50..262311cc2a 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/catalogue/CatalogueListHolder.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/catalogue/CatalogueListHolder.kt @@ -25,9 +25,8 @@ class CatalogueListHolder(private val view: View, adapter: CatalogueAdapter, lis * holder with the given manga. * * @param manga the manga to bind. - * @param presenter the catalogue presenter. */ - override fun onSetValues(manga: Manga, presenter: CataloguePresenter) { + override fun onSetValues(manga: Manga) { view.title.text = manga.title view.title.setTextColor(if (manga.favorite) favoriteColor else unfavoriteColor) } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/catalogue/CataloguePresenter.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/catalogue/CataloguePresenter.kt index a598512875..92f137f94f 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/catalogue/CataloguePresenter.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/catalogue/CataloguePresenter.kt @@ -1,7 +1,6 @@ package eu.kanade.tachiyomi.ui.catalogue import android.os.Bundle -import eu.kanade.tachiyomi.data.cache.CoverCache import eu.kanade.tachiyomi.data.database.DatabaseHelper import eu.kanade.tachiyomi.data.database.models.Manga import eu.kanade.tachiyomi.data.preference.PreferencesHelper @@ -33,11 +32,6 @@ class CataloguePresenter : BasePresenter() { */ @Inject lateinit var db: DatabaseHelper - /** - * Cover cache. - */ - @Inject lateinit var coverCache: CoverCache - /** * Preferences. */ diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryHolder.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryHolder.kt index 1b59864693..d341a34ab7 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryHolder.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryHolder.kt @@ -1,6 +1,9 @@ package eu.kanade.tachiyomi.ui.library import android.view.View +import com.bumptech.glide.Glide +import com.bumptech.glide.load.engine.DiskCacheStrategy +import com.bumptech.glide.signature.StringSignature import eu.kanade.tachiyomi.data.cache.CoverCache import eu.kanade.tachiyomi.data.database.models.Manga import eu.kanade.tachiyomi.data.source.base.Source @@ -16,9 +19,11 @@ import kotlinx.android.synthetic.main.item_catalogue_grid.view.* * @param listener a listener to react to single tap and long tap events. * @constructor creates a new library holder. */ -class LibraryHolder(view: View, adapter: LibraryCategoryAdapter, listener: FlexibleViewHolder.OnListItemClickListener) : +class LibraryHolder(private val view: View, adapter: LibraryCategoryAdapter, listener: FlexibleViewHolder.OnListItemClickListener) : FlexibleViewHolder(view, adapter, listener) { + private var manga: Manga? = null + /** * Method called from [LibraryCategoryAdapter.onBindViewHolder]. It updates the data for this * holder with the given manga. @@ -27,11 +32,13 @@ class LibraryHolder(view: View, adapter: LibraryCategoryAdapter, listener: Flexi * @param presenter the library presenter. */ fun onSetValues(manga: Manga, presenter: LibraryPresenter) { + this.manga = manga + // Update the title of the manga. - itemView.title.text = manga.title + view.title.text = manga.title // Update the unread count and its visibility. - with(itemView.unreadText) { + with(view.unreadText) { visibility = if (manga.unread > 0) View.VISIBLE else View.GONE text = manga.unread.toString() } @@ -49,9 +56,18 @@ class LibraryHolder(view: View, adapter: LibraryCategoryAdapter, listener: Flexi */ private fun loadCover(manga: Manga, source: Source, coverCache: CoverCache) { if (manga.thumbnail_url != null) { - coverCache.saveOrLoadFromCache(itemView.thumbnail, manga.thumbnail_url, source.glideHeaders) + coverCache.saveOrLoadFromCache(manga.thumbnail_url, source.glideHeaders) { + if (this.manga == manga) { + Glide.with(view.context) + .load(it) + .diskCacheStrategy(DiskCacheStrategy.RESULT) + .centerCrop() + .signature(StringSignature(it.lastModified().toString())) + .into(itemView.thumbnail) + } + } } else { - itemView.thumbnail.setImageResource(android.R.color.transparent) + view.thumbnail.setImageResource(android.R.color.transparent) } } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryPresenter.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryPresenter.kt index 322666a953..9e9a7add53 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryPresenter.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryPresenter.kt @@ -280,7 +280,7 @@ class LibraryPresenter : BasePresenter() { @Throws(IOException::class) fun editCoverWithStream(inputStream: InputStream, manga: Manga): Boolean { if (manga.thumbnail_url != null && manga.favorite) { - coverCache.copyToLocalCache(manga.thumbnail_url, inputStream) + coverCache.copyToCache(manga.thumbnail_url, inputStream) return true } return false diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/info/MangaInfoFragment.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/info/MangaInfoFragment.kt index 689fa20e86..5222e3275d 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/info/MangaInfoFragment.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/info/MangaInfoFragment.kt @@ -4,6 +4,10 @@ import android.os.Bundle import android.view.LayoutInflater import android.view.View import android.view.ViewGroup +import com.bumptech.glide.Glide +import com.bumptech.glide.load.engine.DiskCacheStrategy +import com.bumptech.glide.load.model.GlideUrl +import com.bumptech.glide.signature.StringSignature import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.data.database.models.Manga import eu.kanade.tachiyomi.data.source.base.Source @@ -95,26 +99,37 @@ class MangaInfoFragment : BaseRxFragment() { val headers = presenter.source.glideHeaders // Check if thumbnail_url is given. - if (manga.thumbnail_url != null) { - // Check if cover is already drawn. - if (manga_cover.drawable == null) { - // If manga is in library then (download / save) (from / to) local cache if available, - // else download from network. - if (manga.favorite) { - coverCache.saveOrLoadFromCache(manga_cover, manga.thumbnail_url, headers) - } else { - coverCache.loadFromNetwork(manga_cover, manga.thumbnail_url, headers) - } - } - // Check if backdrop is already drawn. - if (backdrop.drawable == null) { - // If manga is in library then (download / save) (from / to) local cache if available, - // else download from network. - if (manga.favorite) { - coverCache.saveOrLoadFromCache(backdrop, manga.thumbnail_url, headers) - } else { - coverCache.loadFromNetwork(backdrop, manga.thumbnail_url, headers) + manga.thumbnail_url?.let { url -> + if (manga.favorite) { + coverCache.saveOrLoadFromCache(url, headers) { + if (isResumed) { + Glide.with(context) + .load(it) + .diskCacheStrategy(DiskCacheStrategy.RESULT) + .centerCrop() + .signature(StringSignature(it.lastModified().toString())) + .into(manga_cover) + + Glide.with(context) + .load(it) + .diskCacheStrategy(DiskCacheStrategy.RESULT) + .centerCrop() + .signature(StringSignature(it.lastModified().toString())) + .into(backdrop) + } } + } else { + Glide.with(context) + .load(if (headers != null) GlideUrl(url, headers) else url) + .diskCacheStrategy(DiskCacheStrategy.SOURCE) + .centerCrop() + .into(manga_cover) + + Glide.with(context) + .load(if (headers != null) GlideUrl(url, headers) else url) + .diskCacheStrategy(DiskCacheStrategy.SOURCE) + .centerCrop() + .into(backdrop) } } } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/info/MangaInfoPresenter.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/info/MangaInfoPresenter.kt index 4ff860b3f1..dc8360406c 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/info/MangaInfoPresenter.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/info/MangaInfoPresenter.kt @@ -130,7 +130,7 @@ class MangaInfoPresenter : BasePresenter() { if (isFavorite) { coverCache.save(manga.thumbnail_url, source.glideHeaders) } else { - coverCache.deleteCoverFromCache(manga.thumbnail_url) + coverCache.deleteFromCache(manga.thumbnail_url) } }