mirror of
				https://github.com/mihonapp/mihon.git
				synced 2025-10-31 14:27:57 +01:00 
			
		
		
		
	Changes in cover cache. Store covers in external cache dir
This commit is contained in:
		| @@ -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<in File>) { | ||||
|                         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) | ||||
|     } | ||||
|  | ||||
| } | ||||
|   | ||||
| @@ -12,7 +12,7 @@ import java.util.* | ||||
|  * | ||||
|  * @param fragment the fragment containing this adapter. | ||||
|  */ | ||||
| class CatalogueAdapter(private val fragment: CatalogueFragment) : FlexibleAdapter<CatalogueHolder, Manga>() { | ||||
| class CatalogueAdapter(val fragment: CatalogueFragment) : FlexibleAdapter<CatalogueHolder, Manga>() { | ||||
|  | ||||
|     /** | ||||
|      * 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) | ||||
|     } | ||||
|  | ||||
| } | ||||
|   | ||||
| @@ -370,7 +370,7 @@ class CatalogueFragment : BaseRxFragment<CataloguePresenter>(), FlexibleViewHold | ||||
|      * @param manga the manga initialized | ||||
|      */ | ||||
|     fun onMangaInitialized(manga: Manga) { | ||||
|         getHolder(manga)?.setImage(manga, presenter) | ||||
|         getHolder(manga)?.setImage(manga) | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|   | ||||
| @@ -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) | ||||
|         } | ||||
|   | ||||
| @@ -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) | ||||
| } | ||||
|   | ||||
| @@ -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) | ||||
|     } | ||||
|   | ||||
| @@ -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<CatalogueFragment>() { | ||||
|      */ | ||||
|     @Inject lateinit var db: DatabaseHelper | ||||
|  | ||||
|     /** | ||||
|      * Cover cache. | ||||
|      */ | ||||
|     @Inject lateinit var coverCache: CoverCache | ||||
|  | ||||
|     /** | ||||
|      * Preferences. | ||||
|      */ | ||||
|   | ||||
| @@ -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) | ||||
|         } | ||||
|     } | ||||
|  | ||||
|   | ||||
| @@ -280,7 +280,7 @@ class LibraryPresenter : BasePresenter<LibraryFragment>() { | ||||
|     @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 | ||||
|   | ||||
| @@ -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<MangaInfoPresenter>() { | ||||
|         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) | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|   | ||||
| @@ -130,7 +130,7 @@ class MangaInfoPresenter : BasePresenter<MangaInfoFragment>() { | ||||
|         if (isFavorite) { | ||||
|             coverCache.save(manga.thumbnail_url, source.glideHeaders) | ||||
|         } else { | ||||
|             coverCache.deleteCoverFromCache(manga.thumbnail_url) | ||||
|             coverCache.deleteFromCache(manga.thumbnail_url) | ||||
|         } | ||||
|     } | ||||
|  | ||||
|   | ||||
		Reference in New Issue
	
	Block a user