mirror of
				https://github.com/mihonapp/mihon.git
				synced 2025-10-30 22:07:57 +01:00 
			
		
		
		
	Glide v4
This commit is contained in:
		| @@ -1,35 +1,51 @@ | ||||
| package eu.kanade.tachiyomi.data.glide | ||||
|  | ||||
| import com.bumptech.glide.Priority | ||||
| import com.bumptech.glide.load.data.DataFetcher | ||||
| import java.io.File | ||||
| import java.io.IOException | ||||
| import java.io.InputStream | ||||
|  | ||||
| open class FileFetcher(private val file: File) : DataFetcher<InputStream> { | ||||
|  | ||||
|     private var data: InputStream? = null | ||||
|  | ||||
|     override fun loadData(priority: Priority): InputStream { | ||||
|         data = file.inputStream() | ||||
|         return data!! | ||||
|     } | ||||
|  | ||||
|     override fun cleanup() { | ||||
|         data?.let { data -> | ||||
|             try { | ||||
|                 data.close() | ||||
|             } catch (e: IOException) { | ||||
|                 // Ignore | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     override fun cancel() { | ||||
|         // Do nothing. | ||||
|     } | ||||
|  | ||||
|     override fun getId(): String { | ||||
|         return file.toString() | ||||
|     } | ||||
| package eu.kanade.tachiyomi.data.glide | ||||
|  | ||||
| import android.content.ContentValues.TAG | ||||
| import android.util.Log | ||||
| import com.bumptech.glide.Priority | ||||
| import com.bumptech.glide.load.DataSource | ||||
| import com.bumptech.glide.load.data.DataFetcher | ||||
| import java.io.* | ||||
|  | ||||
| open class FileFetcher(private val file: File) : DataFetcher<InputStream> { | ||||
|  | ||||
|     private var data: InputStream? = null | ||||
|  | ||||
|     override fun loadData(priority: Priority, callback: DataFetcher.DataCallback<in InputStream>) { | ||||
|         loadFromFile(callback) | ||||
|     } | ||||
|  | ||||
|     protected fun loadFromFile(callback: DataFetcher.DataCallback<in InputStream>) { | ||||
|         try { | ||||
|             data = FileInputStream(file) | ||||
|         } catch (e: FileNotFoundException) { | ||||
|             if (Log.isLoggable(TAG, Log.DEBUG)) { | ||||
|                 Log.d(TAG, "Failed to open file", e) | ||||
|             } | ||||
|             callback.onLoadFailed(e) | ||||
|             return | ||||
|         } | ||||
|  | ||||
|         callback.onDataReady(data) | ||||
|     } | ||||
|  | ||||
|     override fun cleanup() { | ||||
|         try { | ||||
|             data?.close() | ||||
|         } catch (e: IOException) { | ||||
|             // Ignored. | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     override fun cancel() { | ||||
|         // Do nothing. | ||||
|     } | ||||
|  | ||||
|     override fun getDataClass(): Class<InputStream> { | ||||
|         return InputStream::class.java | ||||
|     } | ||||
|  | ||||
|     override fun getDataSource(): DataSource { | ||||
|         return DataSource.LOCAL | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,72 @@ | ||||
| package eu.kanade.tachiyomi.data.glide | ||||
|  | ||||
| import com.bumptech.glide.Priority | ||||
| import com.bumptech.glide.load.data.DataFetcher | ||||
| import eu.kanade.tachiyomi.data.database.models.Manga | ||||
| import java.io.File | ||||
| import java.io.FileNotFoundException | ||||
| import java.io.InputStream | ||||
|  | ||||
| /** | ||||
|  * A [DataFetcher] for loading a cover of a library manga. | ||||
|  * It tries to load the cover from our custom cache, and if it's not found, it fallbacks to network | ||||
|  * and copies the result to the cache. | ||||
|  * | ||||
|  * @param networkFetcher the network fetcher for this cover. | ||||
|  * @param manga the manga of the cover to load. | ||||
|  * @param file the file where this cover should be. It may exists or not. | ||||
|  */ | ||||
| class LibraryMangaUrlFetcher(private val networkFetcher: DataFetcher<InputStream>, | ||||
|                              private val manga: Manga, | ||||
|                              private val file: File) | ||||
| : FileFetcher(file) { | ||||
|  | ||||
|     override fun loadData(priority: Priority, callback: DataFetcher.DataCallback<in InputStream>) { | ||||
|         if (!file.exists()) { | ||||
|             networkFetcher.loadData(priority, object : DataFetcher.DataCallback<InputStream> { | ||||
|                 override fun onDataReady(data: InputStream?) { | ||||
|                     if (data != null) { | ||||
|                         val tmpFile = File(file.path + ".tmp") | ||||
|                         try { | ||||
|                             // Retrieve destination stream, create parent folders if needed. | ||||
|                             val output = try { | ||||
|                                 tmpFile.outputStream() | ||||
|                             } catch (e: FileNotFoundException) { | ||||
|                                 tmpFile.parentFile.mkdirs() | ||||
|                                 tmpFile.outputStream() | ||||
|                             } | ||||
|  | ||||
|                             // Copy the file and rename to the original. | ||||
|                             data.use { output.use { data.copyTo(output) } } | ||||
|                             tmpFile.renameTo(file) | ||||
|                         } catch (e: Exception) { | ||||
|                             tmpFile.delete() | ||||
|                             callback.onLoadFailed(e) | ||||
|                         } | ||||
|                         loadFromFile(callback) | ||||
|                     } else { | ||||
|                         callback.onLoadFailed(Exception("Null data")) | ||||
|                     } | ||||
|                 } | ||||
|  | ||||
|                 override fun onLoadFailed(e: Exception) { | ||||
|                     callback.onLoadFailed(e) | ||||
|                 } | ||||
|  | ||||
|             }) | ||||
|         } else { | ||||
|             loadFromFile(callback) | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     override fun cleanup() { | ||||
|         super.cleanup() | ||||
|         networkFetcher.cleanup() | ||||
|     } | ||||
|  | ||||
|     override fun cancel() { | ||||
|         super.cancel() | ||||
|         networkFetcher.cancel() | ||||
|     } | ||||
|  | ||||
| } | ||||
| @@ -1,18 +0,0 @@ | ||||
| package eu.kanade.tachiyomi.data.glide | ||||
|  | ||||
| import eu.kanade.tachiyomi.data.database.models.Manga | ||||
| import java.io.File | ||||
|  | ||||
| open class MangaFileFetcher(private val file: File, private val manga: Manga) : FileFetcher(file) { | ||||
|  | ||||
|     /** | ||||
|      * Returns the id for this manga's cover. | ||||
|      * | ||||
|      * Appending the file's modified date to the url, we can force Glide to skip its memory and disk | ||||
|      * lookup step and fetch from our custom cache. This allows us to invalidate Glide's cache when | ||||
|      * the file has changed. If the file doesn't exist it will append a 0. | ||||
|      */ | ||||
|     override fun getId(): String { | ||||
|         return manga.thumbnail_url + file.lastModified() | ||||
|     } | ||||
| } | ||||
| @@ -1,23 +1,24 @@ | ||||
| package eu.kanade.tachiyomi.data.glide | ||||
|  | ||||
| import android.content.Context | ||||
| import android.util.LruCache | ||||
| import com.bumptech.glide.Glide | ||||
| import com.bumptech.glide.integration.okhttp3.OkHttpStreamFetcher | ||||
| import com.bumptech.glide.load.data.DataFetcher | ||||
| import com.bumptech.glide.load.Options | ||||
| import com.bumptech.glide.load.model.* | ||||
| import com.bumptech.glide.load.model.stream.StreamModelLoader | ||||
| import eu.kanade.tachiyomi.data.cache.CoverCache | ||||
| import eu.kanade.tachiyomi.data.database.models.Manga | ||||
| import eu.kanade.tachiyomi.network.NetworkHelper | ||||
| import eu.kanade.tachiyomi.source.SourceManager | ||||
| import eu.kanade.tachiyomi.source.online.HttpSource | ||||
| import uy.kohesive.injekt.Injekt | ||||
| import uy.kohesive.injekt.api.get | ||||
| import uy.kohesive.injekt.injectLazy | ||||
| import java.io.File | ||||
| import java.io.InputStream | ||||
|  | ||||
|  | ||||
| /** | ||||
|  * A class for loading a cover associated with a [Manga] that can be present in our own cache. | ||||
|  * Coupled with [MangaUrlFetcher], this class allows to implement the following flow: | ||||
|  * Coupled with [LibraryMangaUrlFetcher], this class allows to implement the following flow: | ||||
|  * | ||||
|  * - Check in RAM LRU. | ||||
|  * - Check in disk LRU. | ||||
| @@ -26,7 +27,7 @@ import java.io.InputStream | ||||
|  * | ||||
|  * @param context the application context. | ||||
|  */ | ||||
| class MangaModelLoader(context: Context) : StreamModelLoader<Manga> { | ||||
| class MangaModelLoader : ModelLoader<Manga, InputStream> { | ||||
|  | ||||
|     /** | ||||
|      * Cover cache where persistent covers are stored. | ||||
| @@ -39,16 +40,15 @@ class MangaModelLoader(context: Context) : StreamModelLoader<Manga> { | ||||
|     private val sourceManager: SourceManager by injectLazy() | ||||
|  | ||||
|     /** | ||||
|      * Base network loader. | ||||
|      * Default network client. | ||||
|      */ | ||||
|     private val baseUrlLoader = Glide.buildModelLoader(GlideUrl::class.java, | ||||
|             InputStream::class.java, context) | ||||
|     private val defaultClient = Injekt.get<NetworkHelper>().client | ||||
|  | ||||
|     /** | ||||
|      * LRU cache whose key is the thumbnail url of the manga, and the value contains the request url | ||||
|      * and the file where it should be stored in case the manga is a favorite. | ||||
|      */ | ||||
|     private val lruCache = LruCache<String, Pair<GlideUrl, File>>(100) | ||||
|     private val lruCache = LruCache<GlideUrl, File>(100) | ||||
|  | ||||
|     /** | ||||
|      * Map where request headers are stored for a source. | ||||
| @@ -60,12 +60,17 @@ class MangaModelLoader(context: Context) : StreamModelLoader<Manga> { | ||||
|      */ | ||||
|     class Factory : ModelLoaderFactory<Manga, InputStream> { | ||||
|  | ||||
|         override fun build(context: Context, factories: GenericLoaderFactory) | ||||
|                 = MangaModelLoader(context) | ||||
|         override fun build(multiFactory: MultiModelLoaderFactory): ModelLoader<Manga, InputStream> { | ||||
|             return MangaModelLoader() | ||||
|         } | ||||
|  | ||||
|         override fun teardown() {} | ||||
|     } | ||||
|  | ||||
|     override fun handles(model: Manga): Boolean { | ||||
|         return true | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Returns a fetcher for the given manga or null if the url is empty. | ||||
|      * | ||||
| @@ -73,10 +78,8 @@ class MangaModelLoader(context: Context) : StreamModelLoader<Manga> { | ||||
|      * @param width the width of the view where the resource will be loaded. | ||||
|      * @param height the height of the view where the resource will be loaded. | ||||
|      */ | ||||
|     override fun getResourceFetcher(manga: Manga, | ||||
|                                     width: Int, | ||||
|                                     height: Int): DataFetcher<InputStream>? { | ||||
|  | ||||
|     override fun buildLoadData(manga: Manga, width: Int, height: Int, | ||||
|                                options: Options?): ModelLoader.LoadData<InputStream>? { | ||||
|         // Check thumbnail is not null or empty | ||||
|         val url = manga.thumbnail_url | ||||
|         if (url == null || url.isEmpty()) { | ||||
| @@ -85,26 +88,28 @@ class MangaModelLoader(context: Context) : StreamModelLoader<Manga> { | ||||
|  | ||||
|         if (url.startsWith("http")) { | ||||
|             val source = sourceManager.get(manga.source) as? HttpSource | ||||
|  | ||||
|             // Obtain the request url and the file for this url from the LRU cache, or calculate it | ||||
|             // and add them to the cache. | ||||
|             val (glideUrl, file) = lruCache.get(url) ?: | ||||
|                     Pair(GlideUrl(url, getHeaders(manga, source)), coverCache.getCoverFile(url)).apply { | ||||
|                         lruCache.put(url, this) | ||||
|                     } | ||||
|             val glideUrl = GlideUrl(url, getHeaders(manga, source)) | ||||
|  | ||||
|             // Get the resource fetcher for this request url. | ||||
|             val networkFetcher = source?.let { OkHttpStreamFetcher(it.client, glideUrl) } | ||||
|                 ?: baseUrlLoader.getResourceFetcher(glideUrl, width, height) | ||||
|             val networkFetcher = OkHttpStreamFetcher(source?.client ?: defaultClient, glideUrl) | ||||
|  | ||||
|             if (!manga.favorite) { | ||||
|                 return ModelLoader.LoadData(glideUrl, networkFetcher) | ||||
|             } | ||||
|  | ||||
|             // Obtain the file for this url from the LRU cache, or retrieve and add it to the cache. | ||||
|             val file = lruCache.getOrPut(glideUrl) { coverCache.getCoverFile(url) } | ||||
|  | ||||
|             val libraryFetcher = LibraryMangaUrlFetcher(networkFetcher, manga, file) | ||||
|  | ||||
|             // Return an instance of the fetcher providing the needed elements. | ||||
|             return MangaUrlFetcher(networkFetcher, file, manga) | ||||
|             return ModelLoader.LoadData(MangaSignature(manga, file), libraryFetcher) | ||||
|         } else { | ||||
|             // Get the file from the url, removing the scheme if present. | ||||
|             val file = File(url.substringAfter("file://")) | ||||
|  | ||||
|             // Return an instance of the fetcher providing the needed elements. | ||||
|             return MangaFileFetcher(file, manga) | ||||
|             return ModelLoader.LoadData(MangaSignature(manga, file), FileFetcher(file)) | ||||
|         } | ||||
|     } | ||||
|  | ||||
| @@ -127,4 +132,15 @@ class MangaModelLoader(context: Context) : StreamModelLoader<Manga> { | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     private inline fun <K, V> LruCache<K, V>.getOrPut(key: K, defaultValue: () -> V): V { | ||||
|         val value = get(key) | ||||
|         return if (value == null) { | ||||
|             val answer = defaultValue() | ||||
|             put(key, answer) | ||||
|             answer | ||||
|         } else { | ||||
|             value | ||||
|         } | ||||
|     } | ||||
|  | ||||
| } | ||||
|   | ||||
| @@ -0,0 +1,27 @@ | ||||
| package eu.kanade.tachiyomi.data.glide | ||||
|  | ||||
| import com.bumptech.glide.load.Key | ||||
| import eu.kanade.tachiyomi.data.database.models.Manga | ||||
| import java.io.File | ||||
| import java.security.MessageDigest | ||||
|  | ||||
| class MangaSignature(manga: Manga, file: File) : Key { | ||||
|  | ||||
|     private val key = manga.thumbnail_url + file.lastModified() | ||||
|  | ||||
|     override fun equals(other: Any?): Boolean { | ||||
|         return if (other is MangaSignature) { | ||||
|             key == other.key | ||||
|         } else { | ||||
|             false | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     override fun hashCode(): Int { | ||||
|         return key.hashCode() | ||||
|     } | ||||
|  | ||||
|     override fun updateDiskCacheKey(md: MessageDigest) { | ||||
|         md.update(key.toByteArray(Key.CHARSET)) | ||||
|     } | ||||
| } | ||||
| @@ -1,71 +0,0 @@ | ||||
| package eu.kanade.tachiyomi.data.glide | ||||
|  | ||||
| import com.bumptech.glide.Priority | ||||
| import com.bumptech.glide.load.data.DataFetcher | ||||
| import eu.kanade.tachiyomi.data.database.models.Manga | ||||
| import java.io.File | ||||
| import java.io.FileNotFoundException | ||||
| import java.io.InputStream | ||||
|  | ||||
| /** | ||||
|  * A [DataFetcher] for loading a cover of a manga depending on its favorite status. | ||||
|  * If the manga is favorite, it tries to load the cover from our cache, and if it's not found, it | ||||
|  * fallbacks to network and copies it to the cache. | ||||
|  * If the manga is not favorite, it tries to delete the cover from our cache and always fallback | ||||
|  * to network for fetching. | ||||
|  * | ||||
|  * @param networkFetcher the network fetcher for this cover. | ||||
|  * @param file the file where this cover should be. It may exists or not. | ||||
|  * @param manga the manga of the cover to load. | ||||
|  */ | ||||
| class MangaUrlFetcher(private val networkFetcher: DataFetcher<InputStream>, | ||||
|                       private val file: File, | ||||
|                       private val manga: Manga) | ||||
| : MangaFileFetcher(file, manga) { | ||||
|  | ||||
|     override fun loadData(priority: Priority): InputStream { | ||||
|         if (manga.favorite) { | ||||
|             synchronized(file) { | ||||
|                 if (!file.exists()) { | ||||
|                     val tmpFile = File(file.path + ".tmp") | ||||
|                     try { | ||||
|                         // Retrieve source stream. | ||||
|                         val input = networkFetcher.loadData(priority) | ||||
|                                 ?: throw Exception("Couldn't open source stream") | ||||
|  | ||||
|                         // Retrieve destination stream, create parent folders if needed. | ||||
|                         val output = try { | ||||
|                             tmpFile.outputStream() | ||||
|                         } catch (e: FileNotFoundException) { | ||||
|                             tmpFile.parentFile.mkdirs() | ||||
|                             tmpFile.outputStream() | ||||
|                         } | ||||
|  | ||||
|                         // Copy the file and rename to the original. | ||||
|                         input.use { output.use { input.copyTo(output) } } | ||||
|                         tmpFile.renameTo(file) | ||||
|                     } catch (e: Exception) { | ||||
|                         tmpFile.delete() | ||||
|                         throw e | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|             return super.loadData(priority) | ||||
|         } else { | ||||
|             if (file.exists()) { | ||||
|                 file.delete() | ||||
|             } | ||||
|             return networkFetcher.loadData(priority) | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     override fun cancel() { | ||||
|         networkFetcher.cancel() | ||||
|     } | ||||
|  | ||||
|     override fun cleanup() { | ||||
|         super.cleanup() | ||||
|         networkFetcher.cleanup() | ||||
|     } | ||||
|  | ||||
| } | ||||
| @@ -1,12 +1,18 @@ | ||||
| package eu.kanade.tachiyomi.data.glide | ||||
| 
 | ||||
| import android.content.Context | ||||
| import android.graphics.drawable.Drawable | ||||
| import com.bumptech.glide.Glide | ||||
| import com.bumptech.glide.GlideBuilder | ||||
| import com.bumptech.glide.Registry | ||||
| import com.bumptech.glide.annotation.GlideModule | ||||
| import com.bumptech.glide.integration.okhttp3.OkHttpUrlLoader | ||||
| import com.bumptech.glide.load.DecodeFormat | ||||
| import com.bumptech.glide.load.engine.cache.InternalCacheDiskCacheFactory | ||||
| import com.bumptech.glide.load.model.GlideUrl | ||||
| import com.bumptech.glide.module.GlideModule | ||||
| import com.bumptech.glide.load.resource.drawable.DrawableTransitionOptions | ||||
| import com.bumptech.glide.module.AppGlideModule | ||||
| import com.bumptech.glide.request.RequestOptions | ||||
| import eu.kanade.tachiyomi.data.database.models.Manga | ||||
| import eu.kanade.tachiyomi.network.NetworkHelper | ||||
| import uy.kohesive.injekt.Injekt | ||||
| @@ -16,17 +22,20 @@ import java.io.InputStream | ||||
| /** | ||||
|  * Class used to update Glide module settings | ||||
|  */ | ||||
| class AppGlideModule : GlideModule { | ||||
| @GlideModule | ||||
| class TachiGlideModule : AppGlideModule() { | ||||
| 
 | ||||
|     override fun applyOptions(context: Context, builder: GlideBuilder) { | ||||
|         // Set the cache size of Glide to 15 MiB | ||||
|         builder.setDiskCache(InternalCacheDiskCacheFactory(context, 15 * 1024 * 1024)) | ||||
|         builder.setDiskCache(InternalCacheDiskCacheFactory(context, 50 * 1024 * 1024)) | ||||
|         builder.setDefaultRequestOptions(RequestOptions().format(DecodeFormat.PREFER_RGB_565)) | ||||
|         builder.setDefaultTransitionOptions(Drawable::class.java, | ||||
|                 DrawableTransitionOptions.withCrossFade()) | ||||
|     } | ||||
| 
 | ||||
|     override fun registerComponents(context: Context, glide: Glide) { | ||||
|     override fun registerComponents(context: Context, glide: Glide, registry: Registry) { | ||||
|         val networkFactory = OkHttpUrlLoader.Factory(Injekt.get<NetworkHelper>().client) | ||||
| 
 | ||||
|         glide.register(GlideUrl::class.java, InputStream::class.java, networkFactory) | ||||
|         glide.register(Manga::class.java, InputStream::class.java, MangaModelLoader.Factory()) | ||||
|         registry.replace(GlideUrl::class.java, InputStream::class.java, networkFactory) | ||||
|         registry.append(Manga::class.java, InputStream::class.java, MangaModelLoader.Factory()) | ||||
|     } | ||||
| } | ||||
| @@ -1,10 +1,10 @@ | ||||
| package eu.kanade.tachiyomi.ui.catalogue | ||||
|  | ||||
| import android.view.View | ||||
| import com.bumptech.glide.Glide | ||||
| import com.bumptech.glide.load.engine.DiskCacheStrategy | ||||
| import eu.davidea.flexibleadapter.FlexibleAdapter | ||||
| import eu.kanade.tachiyomi.data.database.models.Manga | ||||
| import eu.kanade.tachiyomi.data.glide.GlideApp | ||||
| import eu.kanade.tachiyomi.widget.StateImageViewTarget | ||||
| import kotlinx.android.synthetic.main.catalogue_grid_item.view.* | ||||
|  | ||||
| @@ -36,16 +36,15 @@ class CatalogueGridHolder(private val view: View, private val adapter: FlexibleA | ||||
|     } | ||||
|  | ||||
|     override fun setImage(manga: Manga) { | ||||
|         Glide.clear(view.thumbnail) | ||||
|         GlideApp.with(view.context).clear(view.thumbnail) | ||||
|         if (!manga.thumbnail_url.isNullOrEmpty()) { | ||||
|             Glide.with(view.context) | ||||
|             GlideApp.with(view.context) | ||||
|                     .load(manga) | ||||
|                     .diskCacheStrategy(DiskCacheStrategy.SOURCE) | ||||
|                     .diskCacheStrategy(DiskCacheStrategy.DATA) | ||||
|                     .centerCrop() | ||||
|                     .skipMemoryCache(true) | ||||
|                     .placeholder(android.R.color.transparent) | ||||
|                     .into(StateImageViewTarget(view.thumbnail, view.progress)) | ||||
|  | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @@ -1,12 +1,11 @@ | ||||
| package eu.kanade.tachiyomi.ui.catalogue | ||||
|  | ||||
| import android.view.View | ||||
| import com.bumptech.glide.Glide | ||||
| import com.bumptech.glide.load.engine.DiskCacheStrategy | ||||
| import eu.davidea.flexibleadapter.FlexibleAdapter | ||||
| import eu.kanade.tachiyomi.data.database.models.Manga | ||||
| import eu.kanade.tachiyomi.data.glide.GlideApp | ||||
| import eu.kanade.tachiyomi.util.getResourceColor | ||||
| import jp.wasabeef.glide.transformations.CropCircleTransformation | ||||
| import kotlinx.android.synthetic.main.catalogue_list_item.view.* | ||||
|  | ||||
| /** | ||||
| @@ -37,13 +36,13 @@ class CatalogueListHolder(private val view: View, adapter: FlexibleAdapter<*>) : | ||||
|     } | ||||
|  | ||||
|     override fun setImage(manga: Manga) { | ||||
|         Glide.clear(view.thumbnail) | ||||
|         GlideApp.with(view.context).clear(view.thumbnail) | ||||
|         if (!manga.thumbnail_url.isNullOrEmpty()) { | ||||
|             Glide.with(view.context) | ||||
|             GlideApp.with(view.context) | ||||
|                     .load(manga) | ||||
|                     .diskCacheStrategy(DiskCacheStrategy.SOURCE) | ||||
|                     .diskCacheStrategy(DiskCacheStrategy.DATA) | ||||
|                     .centerCrop() | ||||
|                     .bitmapTransform(CropCircleTransformation(view.context)) | ||||
|                     .circleCrop() | ||||
|                     .dontAnimate() | ||||
|                     .skipMemoryCache(true) | ||||
|                     .placeholder(android.R.color.transparent) | ||||
|   | ||||
| @@ -1,10 +1,10 @@ | ||||
| package eu.kanade.tachiyomi.ui.catalogue.global_search | ||||
|  | ||||
| import android.view.View | ||||
| import com.bumptech.glide.Glide | ||||
| import com.bumptech.glide.load.engine.DiskCacheStrategy | ||||
| import eu.davidea.viewholders.FlexibleViewHolder | ||||
| import eu.kanade.tachiyomi.data.database.models.Manga | ||||
| import eu.kanade.tachiyomi.data.glide.GlideApp | ||||
| import eu.kanade.tachiyomi.widget.StateImageViewTarget | ||||
| import kotlinx.android.synthetic.main.catalogue_global_search_controller_card_item.view.* | ||||
|  | ||||
| @@ -28,11 +28,11 @@ class CatalogueSearchCardHolder(view: View, adapter: CatalogueSearchCardAdapter) | ||||
|     } | ||||
|  | ||||
|     fun setImage(manga: Manga) { | ||||
|         Glide.clear(itemView.itemImage) | ||||
|         GlideApp.with(itemView.context).clear(itemView.itemImage) | ||||
|         if (!manga.thumbnail_url.isNullOrEmpty()) { | ||||
|             Glide.with(itemView.context) | ||||
|             GlideApp.with(itemView.context) | ||||
|                     .load(manga) | ||||
|                     .diskCacheStrategy(DiskCacheStrategy.SOURCE) | ||||
|                     .diskCacheStrategy(DiskCacheStrategy.DATA) | ||||
|                     .centerCrop() | ||||
|                     .skipMemoryCache(true) | ||||
|                     .placeholder(android.R.color.transparent) | ||||
|   | ||||
| @@ -1,10 +1,10 @@ | ||||
| package eu.kanade.tachiyomi.ui.library | ||||
|  | ||||
| import android.view.View | ||||
| import com.bumptech.glide.Glide | ||||
| import com.bumptech.glide.load.engine.DiskCacheStrategy | ||||
| import eu.davidea.flexibleadapter.FlexibleAdapter | ||||
| import eu.kanade.tachiyomi.data.database.models.Manga | ||||
| import eu.kanade.tachiyomi.data.glide.GlideApp | ||||
| import kotlinx.android.synthetic.main.catalogue_grid_item.view.* | ||||
|  | ||||
| /** | ||||
| @@ -38,10 +38,10 @@ class LibraryGridHolder( | ||||
|         } | ||||
|  | ||||
|         // Update the cover. | ||||
|         Glide.clear(view.thumbnail) | ||||
|         Glide.with(view.context) | ||||
|         GlideApp.with(view.context).clear(view.thumbnail) | ||||
|         GlideApp.with(view.context) | ||||
|                 .load(manga) | ||||
|                 .diskCacheStrategy(DiskCacheStrategy.RESULT) | ||||
|                 .diskCacheStrategy(DiskCacheStrategy.RESOURCE) | ||||
|                 .centerCrop() | ||||
|                 .into(view.thumbnail) | ||||
|     } | ||||
|   | ||||
| @@ -1,11 +1,10 @@ | ||||
| package eu.kanade.tachiyomi.ui.library | ||||
|  | ||||
| import android.view.View | ||||
| import com.bumptech.glide.Glide | ||||
| import com.bumptech.glide.load.engine.DiskCacheStrategy | ||||
| import eu.davidea.flexibleadapter.FlexibleAdapter | ||||
| import eu.kanade.tachiyomi.data.database.models.Manga | ||||
| import jp.wasabeef.glide.transformations.CropCircleTransformation | ||||
| import eu.kanade.tachiyomi.data.glide.GlideApp | ||||
| import kotlinx.android.synthetic.main.catalogue_list_item.view.* | ||||
|  | ||||
| /** | ||||
| @@ -46,12 +45,12 @@ class LibraryListHolder( | ||||
|         } | ||||
|  | ||||
|         // Update the cover. | ||||
|         Glide.clear(itemView.thumbnail) | ||||
|         Glide.with(itemView.context) | ||||
|         GlideApp.with(itemView.context).clear(itemView.thumbnail) | ||||
|         GlideApp.with(itemView.context) | ||||
|                 .load(manga) | ||||
|                 .diskCacheStrategy(DiskCacheStrategy.RESULT) | ||||
|                 .diskCacheStrategy(DiskCacheStrategy.RESOURCE) | ||||
|                 .centerCrop() | ||||
|                 .bitmapTransform(CropCircleTransformation(itemView.context)) | ||||
|                 .circleCrop() | ||||
|                 .dontAnimate() | ||||
|                 .into(itemView.thumbnail) | ||||
|     } | ||||
|   | ||||
| @@ -1,8 +1,10 @@ | ||||
| package eu.kanade.tachiyomi.ui.manga.info | ||||
|  | ||||
| import android.app.Dialog | ||||
| import android.app.PendingIntent | ||||
| import android.content.Intent | ||||
| import android.graphics.Bitmap | ||||
| import android.graphics.drawable.Drawable | ||||
| import android.net.Uri | ||||
| import android.os.Build | ||||
| import android.os.Bundle | ||||
| @@ -12,20 +14,22 @@ import android.support.v4.content.pm.ShortcutManagerCompat | ||||
| import android.support.v4.graphics.drawable.IconCompat | ||||
| import android.view.* | ||||
| import com.afollestad.materialdialogs.MaterialDialog | ||||
| import com.bumptech.glide.BitmapRequestBuilder | ||||
| import com.bumptech.glide.Glide | ||||
| import com.bumptech.glide.load.engine.DiskCacheStrategy | ||||
| import com.bumptech.glide.load.resource.bitmap.CenterCrop | ||||
| import com.bumptech.glide.load.resource.bitmap.RoundedCorners | ||||
| import com.bumptech.glide.request.target.SimpleTarget | ||||
| import com.bumptech.glide.request.transition.Transition | ||||
| import com.jakewharton.rxbinding.support.v4.widget.refreshes | ||||
| import com.jakewharton.rxbinding.view.clicks | ||||
| import eu.kanade.tachiyomi.R | ||||
| import eu.kanade.tachiyomi.data.database.models.Category | ||||
| import eu.kanade.tachiyomi.data.database.models.Manga | ||||
| import eu.kanade.tachiyomi.data.glide.GlideApp | ||||
| import eu.kanade.tachiyomi.data.notification.NotificationReceiver | ||||
| import eu.kanade.tachiyomi.data.preference.PreferencesHelper | ||||
| import eu.kanade.tachiyomi.source.Source | ||||
| import eu.kanade.tachiyomi.source.model.SManga | ||||
| import eu.kanade.tachiyomi.source.online.HttpSource | ||||
| import eu.kanade.tachiyomi.ui.base.controller.DialogController | ||||
| import eu.kanade.tachiyomi.ui.base.controller.NucleusController | ||||
| import eu.kanade.tachiyomi.ui.library.ChangeMangaCategoriesDialog | ||||
| import eu.kanade.tachiyomi.ui.main.MainActivity | ||||
| @@ -33,15 +37,9 @@ import eu.kanade.tachiyomi.ui.manga.MangaController | ||||
| import eu.kanade.tachiyomi.util.getResourceColor | ||||
| import eu.kanade.tachiyomi.util.snack | ||||
| import eu.kanade.tachiyomi.util.toast | ||||
| import jp.wasabeef.glide.transformations.CropCircleTransformation | ||||
| import jp.wasabeef.glide.transformations.CropSquareTransformation | ||||
| import jp.wasabeef.glide.transformations.MaskTransformation | ||||
| import jp.wasabeef.glide.transformations.RoundedCornersTransformation | ||||
| import kotlinx.android.synthetic.main.manga_info_controller.view.* | ||||
| import rx.Observable | ||||
| import rx.android.schedulers.AndroidSchedulers | ||||
| import rx.schedulers.Schedulers | ||||
| import rx.subscriptions.Subscriptions | ||||
| import uy.kohesive.injekt.injectLazy | ||||
| import java.text.DecimalFormat | ||||
|  | ||||
| @@ -157,16 +155,16 @@ class MangaInfoController : NucleusController<MangaInfoPresenter>(), | ||||
|  | ||||
|             // Set cover if it wasn't already. | ||||
|             if (manga_cover.drawable == null && !manga.thumbnail_url.isNullOrEmpty()) { | ||||
|                 Glide.with(context) | ||||
|                 GlideApp.with(context) | ||||
|                         .load(manga) | ||||
|                         .diskCacheStrategy(DiskCacheStrategy.RESULT) | ||||
|                         .diskCacheStrategy(DiskCacheStrategy.RESOURCE) | ||||
|                         .centerCrop() | ||||
|                         .into(manga_cover) | ||||
|  | ||||
|                 if (backdrop != null) { | ||||
|                     Glide.with(context) | ||||
|                     GlideApp.with(context) | ||||
|                             .load(manga) | ||||
|                             .diskCacheStrategy(DiskCacheStrategy.RESULT) | ||||
|                             .diskCacheStrategy(DiskCacheStrategy.RESOURCE) | ||||
|                             .centerCrop() | ||||
|                             .into(backdrop) | ||||
|                 } | ||||
| @@ -316,51 +314,78 @@ class MangaInfoController : NucleusController<MangaInfoPresenter>(), | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Choose the shape of the icon | ||||
|      * Only use for pre Oreo devices. | ||||
|      * Add a shortcut of the manga to the home screen | ||||
|      */ | ||||
|     private fun chooseIconDialog() { | ||||
|         val activity = activity ?: return | ||||
|  | ||||
|         val modes = intArrayOf(R.string.circular_icon, | ||||
|                 R.string.rounded_icon, | ||||
|                 R.string.square_icon, | ||||
|                 R.string.star_icon) | ||||
|  | ||||
|         val request = Glide.with(activity).load(presenter.manga).asBitmap() | ||||
|  | ||||
|         fun getIcon(i: Int): Bitmap? = when (i) { | ||||
|             0 -> request.transform(CropCircleTransformation(activity)).toIcon() | ||||
|             1 -> request.transform(RoundedCornersTransformation(activity, 5, 0)).toIcon() | ||||
|             2 -> request.transform(CropSquareTransformation(activity)).toIcon() | ||||
|             3 -> request.transform(CenterCrop(activity), | ||||
|                     MaskTransformation(activity, R.drawable.mask_star)).toIcon() | ||||
|             else -> null | ||||
|     private fun addToHomeScreen() { | ||||
|         if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { | ||||
|             // TODO are transformations really unsupported or is it just the Pixel Launcher? | ||||
|             createShortcutForShape() | ||||
|         } else { | ||||
|             ChooseShapeDialog(this).showDialog(router) | ||||
|         } | ||||
|  | ||||
|         val dialog = MaterialDialog.Builder(activity) | ||||
|                 .title(R.string.icon_shape) | ||||
|                 .negativeText(android.R.string.cancel) | ||||
|                 .items(modes.map { activity.getString(it) }) | ||||
|                 .itemsCallback { _, _, i, _ -> | ||||
|                     Observable.fromCallable { getIcon(i) } | ||||
|                             .subscribeOn(Schedulers.io()) | ||||
|                             .observeOn(AndroidSchedulers.mainThread()) | ||||
|                             .subscribe({ icon -> | ||||
|                                 if (icon != null) createShortcut(icon) | ||||
|                             }, { | ||||
|                                 activity.toast(R.string.icon_creation_fail) | ||||
|                             }) | ||||
|                 } | ||||
|                 .show() | ||||
|  | ||||
|         untilDestroySubscriptions.add(Subscriptions.create { dialog.dismiss() }) | ||||
|     } | ||||
|  | ||||
|     private fun BitmapRequestBuilder<out Any, Bitmap>.toIcon() = this.into(96,96).get() | ||||
|     /** | ||||
|      * Dialog to choose a shape for the icon. | ||||
|      */ | ||||
|     private class ChooseShapeDialog(bundle: Bundle? = null) : DialogController(bundle) { | ||||
|  | ||||
|         constructor(target: MangaInfoController) : this() { | ||||
|             targetController = target | ||||
|         } | ||||
|  | ||||
|         override fun onCreateDialog(savedViewState: Bundle?): Dialog { | ||||
|             val modes = intArrayOf(R.string.circular_icon, | ||||
|                     R.string.rounded_icon, | ||||
|                     R.string.square_icon, | ||||
|                     R.string.star_icon) | ||||
|  | ||||
|             return MaterialDialog.Builder(activity!!) | ||||
|                     .title(R.string.icon_shape) | ||||
|                     .negativeText(android.R.string.cancel) | ||||
|                     .items(modes.map { activity?.getString(it) }) | ||||
|                     .itemsCallback { _, _, i, _ -> | ||||
|                         (targetController as? MangaInfoController)?.createShortcutForShape(i) | ||||
|                     } | ||||
|                     .build() | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Retrieves the bitmap of the shortcut with the requested shape and calls [createShortcut] when | ||||
|      * the resource is available. | ||||
|      * | ||||
|      * @param i The shape index to apply. No transformation is performed if the parameter is not | ||||
|      *          provided. | ||||
|      */ | ||||
|     private fun createShortcutForShape(i: Int = 0) { | ||||
|         GlideApp.with(activity) | ||||
|                 .asBitmap() | ||||
|                 .load(presenter.manga) | ||||
|                 .diskCacheStrategy(DiskCacheStrategy.NONE) | ||||
|                 .apply { | ||||
|                     when (i) { | ||||
|                         0 -> circleCrop() | ||||
|                         1 -> transform(RoundedCorners(5)) | ||||
|                         2 -> transform(CropSquareTransformation()) | ||||
|                         3 -> centerCrop().transform(MaskTransformation(R.drawable.mask_star)) | ||||
|                     } | ||||
|                 } | ||||
|                 .into(object : SimpleTarget<Bitmap>(96, 96) { | ||||
|                     override fun onResourceReady(resource: Bitmap, transition: Transition<in Bitmap>?) { | ||||
|                         createShortcut(resource) | ||||
|                     } | ||||
|  | ||||
|                     override fun onLoadFailed(errorDrawable: Drawable?) { | ||||
|                         activity?.toast(R.string.icon_creation_fail) | ||||
|                     } | ||||
|                 }) | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Create shortcut using ShortcutManager. | ||||
|      * | ||||
|      * @param icon The image of the shortcut. | ||||
|      */ | ||||
|     private fun createShortcut(icon: Bitmap) { | ||||
|         val activity = activity ?: return | ||||
| @@ -375,49 +400,29 @@ class MangaInfoController : NucleusController<MangaInfoPresenter>(), | ||||
|  | ||||
|         // Check if shortcut placement is supported | ||||
|         if (ShortcutManagerCompat.isRequestPinShortcutSupported(activity)) { | ||||
|             val shortcutId = "manga-shortcut-${presenter.manga.title}-${presenter.source.name}" | ||||
|  | ||||
|             // Create shortcut info | ||||
|             val pinShortcutInfo = ShortcutInfoCompat.Builder(activity, "manga-shortcut-${presenter.manga.title}-${presenter.source.name}") | ||||
|             val shortcutInfo = ShortcutInfoCompat.Builder(activity, shortcutId) | ||||
|                     .setShortLabel(presenter.manga.title) | ||||
|                     .setIcon(IconCompat.createWithBitmap(icon)) | ||||
|                     .setIntent(shortcutIntent).build() | ||||
|                     .setIntent(shortcutIntent) | ||||
|                     .build() | ||||
|  | ||||
|             val successCallback: PendingIntent | ||||
|  | ||||
|             successCallback = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { | ||||
|             val successCallback = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { | ||||
|                 // Create the CallbackIntent. | ||||
|                 val pinnedShortcutCallbackIntent = ShortcutManagerCompat.createShortcutResultIntent(activity, pinShortcutInfo) | ||||
|                 val intent = ShortcutManagerCompat.createShortcutResultIntent(activity, shortcutInfo) | ||||
|  | ||||
|                 // Configure the intent so that the broadcast receiver gets the callback successfully. | ||||
|                 PendingIntent.getBroadcast(activity, 0, pinnedShortcutCallbackIntent, 0) | ||||
|             } else{ | ||||
|                 PendingIntent.getBroadcast(activity, 0, intent, 0) | ||||
|             } else { | ||||
|                 NotificationReceiver.shortcutCreatedBroadcast(activity) | ||||
|             } | ||||
|  | ||||
|             // Request shortcut. | ||||
|             ShortcutManagerCompat.requestPinShortcut(activity, pinShortcutInfo, | ||||
|             ShortcutManagerCompat.requestPinShortcut(activity, shortcutInfo, | ||||
|                     successCallback.intentSender) | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Add a shortcut of the manga to the home screen | ||||
|      */ | ||||
|     private fun addToHomeScreen() { | ||||
|         // Get bitmap icon | ||||
|         val bitmap = Glide.with(activity).load(presenter.manga).asBitmap() | ||||
|  | ||||
|         if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O){ | ||||
|             Observable.fromCallable { | ||||
|                 bitmap.toIcon() | ||||
|             } | ||||
|                     .subscribeOn(Schedulers.io()) | ||||
|                     .observeOn(AndroidSchedulers.mainThread()) | ||||
|                     .subscribe({icon -> | ||||
|                         createShortcut(icon) | ||||
|                     }) | ||||
|         }else{ | ||||
|             chooseIconDialog() | ||||
|         } | ||||
|     } | ||||
| } | ||||
| } | ||||
| @@ -3,9 +3,9 @@ package eu.kanade.tachiyomi.ui.reader | ||||
| import android.content.Context | ||||
| import android.graphics.Bitmap | ||||
| import android.support.v4.app.NotificationCompat | ||||
| import com.bumptech.glide.Glide | ||||
| import com.bumptech.glide.load.engine.DiskCacheStrategy | ||||
| import eu.kanade.tachiyomi.R | ||||
| import eu.kanade.tachiyomi.data.glide.GlideApp | ||||
| import eu.kanade.tachiyomi.data.notification.NotificationHandler | ||||
| import eu.kanade.tachiyomi.data.notification.NotificationReceiver | ||||
| import eu.kanade.tachiyomi.data.notification.Notifications | ||||
| @@ -34,12 +34,12 @@ class SaveImageNotifier(private val context: Context) { | ||||
|      * @param file image file containing downloaded page image. | ||||
|      */ | ||||
|     fun onComplete(file: File) { | ||||
|         val bitmap = Glide.with(context) | ||||
|                 .load(file) | ||||
|         val bitmap = GlideApp.with(context) | ||||
|                 .asBitmap() | ||||
|                 .load(file) | ||||
|                 .diskCacheStrategy(DiskCacheStrategy.NONE) | ||||
|                 .skipMemoryCache(true) | ||||
|                 .into(720, 1280) | ||||
|                 .submit(720, 1280) | ||||
|                 .get() | ||||
|  | ||||
|         if (bitmap != null) { | ||||
|   | ||||
| @@ -2,14 +2,13 @@ package eu.kanade.tachiyomi.ui.recent_updates | ||||
|  | ||||
| import android.view.View | ||||
| import android.widget.PopupMenu | ||||
| import com.bumptech.glide.Glide | ||||
| import com.bumptech.glide.load.engine.DiskCacheStrategy | ||||
| import eu.davidea.viewholders.FlexibleViewHolder | ||||
| import eu.kanade.tachiyomi.R | ||||
| import eu.kanade.tachiyomi.data.download.model.Download | ||||
| import eu.kanade.tachiyomi.data.glide.GlideApp | ||||
| import eu.kanade.tachiyomi.util.getResourceColor | ||||
| import eu.kanade.tachiyomi.util.setVectorCompat | ||||
| import jp.wasabeef.glide.transformations.CropCircleTransformation | ||||
| import kotlinx.android.synthetic.main.recent_chapters_item.view.* | ||||
|  | ||||
| /** | ||||
| @@ -68,12 +67,12 @@ class RecentChapterHolder(private val view: View, private val adapter: RecentCha | ||||
|         view.chapter_menu_icon.setVectorCompat(R.drawable.ic_more_horiz_black_24dp, view.context.getResourceColor(R.attr.icon_color)) | ||||
|  | ||||
|         // Set cover | ||||
|         Glide.clear(itemView.manga_cover) | ||||
|         GlideApp.with(itemView.context).clear(itemView.manga_cover) | ||||
|         if (!item.manga.thumbnail_url.isNullOrEmpty()) { | ||||
|             Glide.with(itemView.context) | ||||
|             GlideApp.with(itemView.context) | ||||
|                     .load(item.manga) | ||||
|                     .diskCacheStrategy(DiskCacheStrategy.RESULT) | ||||
|                     .bitmapTransform(CropCircleTransformation(view.context)) | ||||
|                     .diskCacheStrategy(DiskCacheStrategy.RESOURCE) | ||||
|                     .circleCrop() | ||||
|                     .into(itemView.manga_cover) | ||||
|         } | ||||
|  | ||||
|   | ||||
| @@ -1,11 +1,11 @@ | ||||
| package eu.kanade.tachiyomi.ui.recently_read | ||||
|  | ||||
| import android.view.View | ||||
| import com.bumptech.glide.Glide | ||||
| import com.bumptech.glide.load.engine.DiskCacheStrategy | ||||
| import eu.davidea.viewholders.FlexibleViewHolder | ||||
| import eu.kanade.tachiyomi.R | ||||
| import eu.kanade.tachiyomi.data.database.models.MangaChapterHistory | ||||
| import eu.kanade.tachiyomi.data.glide.GlideApp | ||||
| import kotlinx.android.synthetic.main.recently_read_item.view.* | ||||
| import java.util.* | ||||
|  | ||||
| @@ -58,15 +58,15 @@ class RecentlyReadHolder( | ||||
|         itemView.last_read.text = adapter.dateFormat.format(Date(history.last_read)) | ||||
|  | ||||
|         // Set cover | ||||
|         Glide.clear(itemView.cover) | ||||
|         GlideApp.with(itemView.context).clear(itemView.cover) | ||||
|         if (!manga.thumbnail_url.isNullOrEmpty()) { | ||||
|             Glide.with(itemView.context) | ||||
|             GlideApp.with(itemView.context) | ||||
|                     .load(manga) | ||||
|                     .diskCacheStrategy(DiskCacheStrategy.RESULT) | ||||
|                     .diskCacheStrategy(DiskCacheStrategy.RESOURCE) | ||||
|                     .centerCrop() | ||||
|                     .into(itemView.cover) | ||||
|         } | ||||
|  | ||||
|     } | ||||
|  | ||||
|  | ||||
| } | ||||
|   | ||||
| @@ -5,9 +5,8 @@ import android.support.graphics.drawable.VectorDrawableCompat | ||||
| import android.view.View | ||||
| import android.widget.ImageView | ||||
| import android.widget.ImageView.ScaleType | ||||
| import com.bumptech.glide.load.resource.drawable.GlideDrawable | ||||
| import com.bumptech.glide.request.animation.GlideAnimation | ||||
| import com.bumptech.glide.request.target.GlideDrawableImageViewTarget | ||||
| import com.bumptech.glide.request.target.ImageViewTarget | ||||
| import com.bumptech.glide.request.transition.Transition | ||||
| import eu.kanade.tachiyomi.R | ||||
| import eu.kanade.tachiyomi.util.getResourceColor | ||||
| import eu.kanade.tachiyomi.util.gone | ||||
| @@ -26,16 +25,23 @@ class StateImageViewTarget(view: ImageView, | ||||
|                            val progress: View? = null, | ||||
|                            val errorDrawableRes: Int = R.drawable.ic_broken_image_grey_24dp, | ||||
|                            val errorScaleType: ScaleType = ScaleType.CENTER) : | ||||
|         GlideDrawableImageViewTarget(view) { | ||||
|  | ||||
|         ImageViewTarget<Drawable>(view) { | ||||
|  | ||||
|     private var resource: Drawable? = null | ||||
|  | ||||
|     private val imageScaleType = view.scaleType | ||||
|  | ||||
|     override fun setResource(resource: Drawable?) { | ||||
|         view.setImageDrawable(resource) | ||||
|     } | ||||
|  | ||||
|     override fun onLoadStarted(placeholder: Drawable?) { | ||||
|         progress?.visible() | ||||
|         super.onLoadStarted(placeholder) | ||||
|     } | ||||
|  | ||||
|     override fun onLoadFailed(e: Exception?, errorDrawable: Drawable?) { | ||||
|     override fun onLoadFailed(errorDrawable: Drawable?) { | ||||
|         progress?.gone() | ||||
|         view.scaleType = errorScaleType | ||||
|  | ||||
| @@ -49,9 +55,10 @@ class StateImageViewTarget(view: ImageView, | ||||
|         super.onLoadCleared(placeholder) | ||||
|     } | ||||
|  | ||||
|     override fun onResourceReady(resource: GlideDrawable?, animation: GlideAnimation<in GlideDrawable>?) { | ||||
|     override fun onResourceReady(resource: Drawable?, transition: Transition<in Drawable>?) { | ||||
|         progress?.gone() | ||||
|         view.scaleType = imageScaleType | ||||
|         super.onResourceReady(resource, animation) | ||||
|         super.onResourceReady(resource, transition) | ||||
|         this.resource = resource | ||||
|     } | ||||
| } | ||||
		Reference in New Issue
	
	Block a user