mirror of
https://github.com/null2264/yokai.git
synced 2025-06-21 10:44:42 +00:00
refactor: Switch to Coil3
This commit is contained in:
parent
2bffd8a653
commit
3412806bfc
33 changed files with 286 additions and 233 deletions
|
@ -256,9 +256,7 @@ dependencies {
|
|||
implementation(libs.injekt.core)
|
||||
|
||||
// Image library
|
||||
implementation(libs.coil)
|
||||
implementation(libs.coil.gif)
|
||||
implementation(libs.coil.svg)
|
||||
implementation(libs.bundles.coil)
|
||||
|
||||
// Logging
|
||||
implementation(libs.timber)
|
||||
|
@ -327,7 +325,7 @@ tasks {
|
|||
"-opt-in=androidx.compose.foundation.ExperimentalFoundationApi",
|
||||
"-opt-in=androidx.compose.animation.ExperimentalAnimationApi",
|
||||
"-opt-in=androidx.compose.animation.graphics.ExperimentalAnimationGraphicsApi",
|
||||
"-opt-in=coil.annotation.ExperimentalCoilApi",
|
||||
"-opt-in=coil3.annotation.ExperimentalCoilApi",
|
||||
"-opt-in=com.google.accompanist.permissions.ExperimentalPermissionsApi",
|
||||
"-opt-in=kotlinx.coroutines.ExperimentalCoroutinesApi",
|
||||
"-opt-in=kotlinx.coroutines.FlowPreview",
|
||||
|
|
|
@ -20,6 +20,9 @@ import androidx.lifecycle.LifecycleOwner
|
|||
import androidx.lifecycle.ProcessLifecycleOwner
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.multidex.MultiDex
|
||||
import coil3.ImageLoader
|
||||
import coil3.PlatformContext
|
||||
import coil3.SingletonImageLoader
|
||||
import dev.yokai.domain.AppState
|
||||
import eu.kanade.tachiyomi.appwidget.TachiyomiWidgetManager
|
||||
import eu.kanade.tachiyomi.data.image.coil.CoilSetup
|
||||
|
@ -44,7 +47,7 @@ import uy.kohesive.injekt.Injekt
|
|||
import uy.kohesive.injekt.injectLazy
|
||||
import java.security.Security
|
||||
|
||||
open class App : Application(), DefaultLifecycleObserver {
|
||||
open class App : Application(), DefaultLifecycleObserver, SingletonImageLoader.Factory {
|
||||
|
||||
val preferences: PreferencesHelper by injectLazy()
|
||||
|
||||
|
@ -71,7 +74,6 @@ open class App : Application(), DefaultLifecycleObserver {
|
|||
Injekt.importModule(PreferenceModule(this))
|
||||
Injekt.importModule(AppModule(this))
|
||||
|
||||
CoilSetup(this)
|
||||
setupNotificationChannels()
|
||||
|
||||
ProcessLifecycleOwner.get().lifecycle.addObserver(this)
|
||||
|
@ -171,6 +173,10 @@ open class App : Application(), DefaultLifecycleObserver {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun newImageLoader(context: PlatformContext): ImageLoader {
|
||||
return CoilSetup.setup(context)
|
||||
}
|
||||
}
|
||||
|
||||
private const val ACTION_DISABLE_INCOGNITO_MODE = "tachi.action.DISABLE_INCOGNITO_MODE"
|
||||
|
|
|
@ -16,13 +16,14 @@ import androidx.glance.appwidget.provideContent
|
|||
import androidx.glance.appwidget.updateAll
|
||||
import androidx.glance.background
|
||||
import androidx.glance.layout.fillMaxSize
|
||||
import coil.executeBlocking
|
||||
import coil.imageLoader
|
||||
import coil.request.CachePolicy
|
||||
import coil.request.ImageRequest
|
||||
import coil.size.Precision
|
||||
import coil.size.Scale
|
||||
import coil.transform.RoundedCornersTransformation
|
||||
import coil3.executeBlocking
|
||||
import coil3.imageLoader
|
||||
import coil3.request.CachePolicy
|
||||
import coil3.request.ImageRequest
|
||||
import coil3.request.transformations
|
||||
import coil3.size.Precision
|
||||
import coil3.size.Scale
|
||||
import coil3.transform.RoundedCornersTransformation
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.appwidget.components.CoverHeight
|
||||
import eu.kanade.tachiyomi.appwidget.components.CoverWidth
|
||||
|
@ -109,7 +110,7 @@ class UpdatesGridGlanceWidget : GlanceAppWidget() {
|
|||
}
|
||||
}
|
||||
.build()
|
||||
Pair(updatesView.id!!, app.imageLoader.executeBlocking(request).drawable?.toBitmap())
|
||||
Pair(updatesView.id!!, app.imageLoader.executeBlocking(request).image?.asDrawable(app.resources)?.toBitmap())
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -2,8 +2,8 @@ package eu.kanade.tachiyomi.data.cache
|
|||
|
||||
import android.content.Context
|
||||
import android.text.format.Formatter
|
||||
import coil.imageLoader
|
||||
import coil.memory.MemoryCache
|
||||
import coil3.imageLoader
|
||||
import coil3.memory.MemoryCache
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.data.database.DatabaseHelper
|
||||
import eu.kanade.tachiyomi.data.database.models.Manga
|
||||
|
|
|
@ -2,47 +2,38 @@ package eu.kanade.tachiyomi.data.image.coil
|
|||
|
||||
import android.app.ActivityManager
|
||||
import android.content.Context
|
||||
import android.os.Build
|
||||
import androidx.core.content.getSystemService
|
||||
import coil.Coil
|
||||
import coil.ImageLoader
|
||||
import coil.decode.GifDecoder
|
||||
import coil.decode.ImageDecoderDecoder
|
||||
import coil.disk.DiskCache
|
||||
import coil.memory.MemoryCache
|
||||
import coil.util.DebugLogger
|
||||
import eu.kanade.tachiyomi.BuildConfig
|
||||
import coil3.ImageLoader
|
||||
import coil3.disk.DiskCache
|
||||
import coil3.disk.directory
|
||||
import coil3.memory.MemoryCache
|
||||
import coil3.network.okhttp.OkHttpNetworkFetcherFactory
|
||||
import coil3.request.allowHardware
|
||||
import coil3.request.allowRgb565
|
||||
import coil3.request.crossfade
|
||||
import eu.kanade.tachiyomi.network.NetworkHelper
|
||||
import uy.kohesive.injekt.Injekt
|
||||
import uy.kohesive.injekt.api.get
|
||||
|
||||
class CoilSetup(context: Context) {
|
||||
init {
|
||||
val imageLoader = ImageLoader.Builder(context).apply {
|
||||
val callFactoryInit = { Injekt.get<NetworkHelper>().client }
|
||||
val diskCacheInit = { CoilDiskCache.get(context) }
|
||||
components {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
|
||||
add(ImageDecoderDecoder.Factory())
|
||||
} else {
|
||||
add(GifDecoder.Factory())
|
||||
class CoilSetup {
|
||||
companion object {
|
||||
fun setup(context: Context): ImageLoader {
|
||||
return ImageLoader.Builder(context).apply {
|
||||
val callFactoryLazy = lazy { Injekt.get<NetworkHelper>().client }
|
||||
val diskCacheLazy = lazy { CoilDiskCache.get(context) }
|
||||
components {
|
||||
add(OkHttpNetworkFetcherFactory(callFactoryLazy::value))
|
||||
add(TachiyomiImageDecoder.Factory())
|
||||
add(MangaCoverFetcher.Factory(callFactoryLazy, diskCacheLazy))
|
||||
add(MangaCoverKeyer())
|
||||
}
|
||||
add(TachiyomiImageDecoder.Factory())
|
||||
add(MangaCoverFetcher.Factory(lazy(callFactoryInit), lazy(diskCacheInit)))
|
||||
add(MangaCoverKeyer())
|
||||
add(InputStreamFetcher.Factory())
|
||||
}
|
||||
callFactory(callFactoryInit)
|
||||
diskCache(diskCacheInit)
|
||||
memoryCache { MemoryCache.Builder(context).maxSizePercent(0.40).build() }
|
||||
crossfade(true)
|
||||
allowRgb565(context.getSystemService<ActivityManager>()!!.isLowRamDevice)
|
||||
allowHardware(true)
|
||||
if (BuildConfig.DEBUG) {
|
||||
logger(DebugLogger())
|
||||
}
|
||||
}.build()
|
||||
Coil.setImageLoader(imageLoader)
|
||||
diskCache(diskCacheLazy::value)
|
||||
memoryCache { MemoryCache.Builder().maxSizePercent(context, 0.40).build() }
|
||||
crossfade(true)
|
||||
allowRgb565(context.getSystemService<ActivityManager>()!!.isLowRamDevice)
|
||||
allowHardware(true)
|
||||
}.build()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -5,7 +5,8 @@ import android.view.View
|
|||
import android.widget.ImageView
|
||||
import androidx.core.view.isVisible
|
||||
import androidx.vectordrawable.graphics.drawable.VectorDrawableCompat
|
||||
import coil.target.ImageViewTarget
|
||||
import coil3.Image
|
||||
import coil3.target.ImageViewTarget
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.util.system.getResourceColor
|
||||
|
||||
|
@ -15,7 +16,9 @@ class CoverViewTarget(
|
|||
val scaleType: ImageView.ScaleType = ImageView.ScaleType.CENTER_CROP,
|
||||
) : ImageViewTarget(view) {
|
||||
|
||||
override fun onError(error: Drawable?) {
|
||||
override fun onError(error: Image?) {
|
||||
//val drawable = error?.asDrawable(view.context.resources)
|
||||
|
||||
progress?.isVisible = false
|
||||
view.scaleType = ImageView.ScaleType.CENTER
|
||||
val vector = VectorDrawableCompat.create(
|
||||
|
@ -27,13 +30,17 @@ class CoverViewTarget(
|
|||
view.setImageDrawable(vector)
|
||||
}
|
||||
|
||||
override fun onStart(placeholder: Drawable?) {
|
||||
override fun onStart(placeholder: Image?) {
|
||||
//val drawable = placeholder?.asDrawable(view.context.resources)
|
||||
|
||||
progress?.isVisible = true
|
||||
view.scaleType = scaleType
|
||||
super.onStart(placeholder)
|
||||
}
|
||||
|
||||
override fun onSuccess(result: Drawable) {
|
||||
override fun onSuccess(result: Image) {
|
||||
//val drawable = result?.asDrawable(view.context.resources)
|
||||
|
||||
progress?.isVisible = false
|
||||
view.scaleType = scaleType
|
||||
super.onSuccess(result)
|
||||
|
|
|
@ -1,15 +1,15 @@
|
|||
package eu.kanade.tachiyomi.data.image.coil
|
||||
|
||||
import android.graphics.BitmapFactory
|
||||
import android.graphics.drawable.Drawable
|
||||
import android.widget.ImageView
|
||||
import androidx.palette.graphics.Palette
|
||||
import coil.ImageLoader
|
||||
import coil.imageLoader
|
||||
import coil.memory.MemoryCache
|
||||
import coil.request.Disposable
|
||||
import coil.request.ImageRequest
|
||||
import coil.target.ImageViewTarget
|
||||
import coil3.Image
|
||||
import coil3.ImageLoader
|
||||
import coil3.imageLoader
|
||||
import coil3.memory.MemoryCache
|
||||
import coil3.request.Disposable
|
||||
import coil3.request.ImageRequest
|
||||
import coil3.target.ImageViewTarget
|
||||
import eu.kanade.tachiyomi.data.cache.CoverCache
|
||||
import eu.kanade.tachiyomi.data.database.models.Manga
|
||||
import eu.kanade.tachiyomi.util.system.launchIO
|
||||
|
@ -22,7 +22,7 @@ class LibraryMangaImageTarget(
|
|||
|
||||
private val coverCache: CoverCache by injectLazy()
|
||||
|
||||
override fun onError(error: Drawable?) {
|
||||
override fun onError(error: Image?) {
|
||||
super.onError(error)
|
||||
if (manga.favorite) {
|
||||
launchIO {
|
||||
|
|
|
@ -1,16 +1,16 @@
|
|||
package eu.kanade.tachiyomi.data.image.coil
|
||||
|
||||
import android.webkit.MimeTypeMap
|
||||
import coil.ImageLoader
|
||||
import coil.decode.DataSource
|
||||
import coil.decode.ImageSource
|
||||
import coil.disk.DiskCache
|
||||
import coil.fetch.FetchResult
|
||||
import coil.fetch.Fetcher
|
||||
import coil.fetch.SourceResult
|
||||
import coil.network.HttpException
|
||||
import coil.request.Options
|
||||
import coil.request.Parameters
|
||||
import coil3.Extras
|
||||
import coil3.ImageLoader
|
||||
import coil3.decode.DataSource
|
||||
import coil3.decode.ImageSource
|
||||
import coil3.disk.DiskCache
|
||||
import coil3.fetch.FetchResult
|
||||
import coil3.fetch.Fetcher
|
||||
import coil3.fetch.SourceFetchResult
|
||||
import coil3.getOrDefault
|
||||
import coil3.request.Options
|
||||
import eu.kanade.tachiyomi.data.cache.CoverCache
|
||||
import eu.kanade.tachiyomi.data.database.models.Manga
|
||||
import eu.kanade.tachiyomi.network.await
|
||||
|
@ -26,17 +26,16 @@ import okhttp3.Call
|
|||
import okhttp3.Request
|
||||
import okhttp3.Response
|
||||
import okhttp3.internal.closeQuietly
|
||||
import okio.FileSystem
|
||||
import okio.Path.Companion.toOkioPath
|
||||
import okio.Source
|
||||
import okio.buffer
|
||||
import okio.sink
|
||||
import okio.source
|
||||
import timber.log.Timber
|
||||
import uy.kohesive.injekt.api.get
|
||||
import uy.kohesive.injekt.injectLazy
|
||||
import java.io.File
|
||||
import java.net.HttpURLConnection
|
||||
import java.util.Date
|
||||
import java.util.*
|
||||
|
||||
class MangaCoverFetcher(
|
||||
private val manga: Manga,
|
||||
|
@ -71,7 +70,7 @@ class MangaCoverFetcher(
|
|||
val networkRead = options.networkCachePolicy.readEnabled
|
||||
val onlyCache = !networkRead && diskRead
|
||||
val shouldFetchRemotely = networkRead && !diskRead && !onlyCache
|
||||
val useCustomCover = options.parameters.value(useCustomCover) ?: true
|
||||
val useCustomCover = options.extras.getOrDefault(USE_CUSTOM_COVER_KEY)
|
||||
// Use custom cover if exists
|
||||
if (!shouldFetchRemotely) {
|
||||
val customCoverFile by lazy { coverCache.getCustomCoverFile(manga) }
|
||||
|
@ -101,7 +100,7 @@ class MangaCoverFetcher(
|
|||
|
||||
// Read from snapshot
|
||||
setRatioAndColorsInScope(manga)
|
||||
return SourceResult(
|
||||
return SourceFetchResult(
|
||||
source = snapshot.toImageSource(),
|
||||
mimeType = "image/*",
|
||||
dataSource = DataSource.DISK,
|
||||
|
@ -122,7 +121,7 @@ class MangaCoverFetcher(
|
|||
// Read from disk cache
|
||||
snapshot = writeToDiskCache(snapshot, response)
|
||||
if (snapshot != null) {
|
||||
return SourceResult(
|
||||
return SourceFetchResult(
|
||||
source = snapshot.toImageSource(),
|
||||
mimeType = "image/*",
|
||||
dataSource = DataSource.NETWORK,
|
||||
|
@ -130,8 +129,8 @@ class MangaCoverFetcher(
|
|||
}
|
||||
|
||||
// Read from response if cache is unused or unusable
|
||||
return SourceResult(
|
||||
source = ImageSource(source = responseBody.source(), context = options.context),
|
||||
return SourceFetchResult(
|
||||
source = ImageSource(source = responseBody.source(), fileSystem = FileSystem.SYSTEM),
|
||||
mimeType = "image/*",
|
||||
dataSource = if (response.cacheResponse != null) DataSource.DISK else DataSource.NETWORK,
|
||||
)
|
||||
|
@ -149,18 +148,20 @@ class MangaCoverFetcher(
|
|||
val client = sourceLazy.value?.client ?: callFactoryLazy.value
|
||||
val response = client.newCall(newRequest()).await()
|
||||
if (!response.isSuccessful && response.code != HttpURLConnection.HTTP_NOT_MODIFIED) {
|
||||
response.body?.closeQuietly()
|
||||
throw HttpException(response)
|
||||
response.body.closeQuietly()
|
||||
throw Exception(response.message) // FIXME: Should probably use something else other than generic Exception
|
||||
}
|
||||
return response
|
||||
}
|
||||
|
||||
private fun newRequest(): Request {
|
||||
val request = Request.Builder()
|
||||
.url(url)
|
||||
.headers(sourceLazy.value?.headers ?: options.headers)
|
||||
// Support attaching custom data to the network request.
|
||||
.tag(Parameters::class.java, options.parameters)
|
||||
val request = Request.Builder().apply {
|
||||
url(url)
|
||||
|
||||
val sourceHeaders = sourceLazy.value?.headers
|
||||
if (sourceHeaders != null)
|
||||
headers(sourceHeaders)
|
||||
}
|
||||
|
||||
val diskRead = options.diskCachePolicy.readEnabled
|
||||
val networkRead = options.networkCachePolicy.readEnabled
|
||||
|
@ -227,7 +228,11 @@ class MangaCoverFetcher(
|
|||
}
|
||||
|
||||
private fun readFromDiskCache(): DiskCache.Snapshot? {
|
||||
return if (options.diskCachePolicy.readEnabled) diskCacheLazy.value[diskCacheKey!!] else null
|
||||
return if (options.diskCachePolicy.readEnabled) {
|
||||
diskCacheLazy.value.openSnapshot(diskCacheKey!!)
|
||||
} else {
|
||||
null
|
||||
}
|
||||
}
|
||||
|
||||
private fun writeToDiskCache(
|
||||
|
@ -239,15 +244,15 @@ class MangaCoverFetcher(
|
|||
return null
|
||||
}
|
||||
val editor = if (snapshot != null) {
|
||||
snapshot.closeAndEdit()
|
||||
snapshot.closeAndOpenEditor()
|
||||
} else {
|
||||
diskCacheLazy.value.edit(diskCacheKey!!)
|
||||
diskCacheLazy.value.openEditor(diskCacheKey!!)
|
||||
} ?: return null
|
||||
try {
|
||||
diskCacheLazy.value.fileSystem.write(editor.data) {
|
||||
response.body!!.source().readAll(this)
|
||||
response.body.source().readAll(this)
|
||||
}
|
||||
return editor.commitAndGet()
|
||||
return editor.commitAndOpenSnapshot()
|
||||
} catch (e: Exception) {
|
||||
try {
|
||||
editor.abort()
|
||||
|
@ -258,7 +263,12 @@ class MangaCoverFetcher(
|
|||
}
|
||||
|
||||
private fun DiskCache.Snapshot.toImageSource(): ImageSource {
|
||||
return ImageSource(file = data, diskCacheKey = diskCacheKey, closeable = this)
|
||||
return ImageSource(
|
||||
file = data,
|
||||
fileSystem = FileSystem.SYSTEM,
|
||||
diskCacheKey = diskCacheKey,
|
||||
closeable = this,
|
||||
)
|
||||
}
|
||||
|
||||
private fun setRatioAndColorsInScope(manga: Manga, ogFile: File? = null, force: Boolean = false) {
|
||||
|
@ -283,8 +293,12 @@ class MangaCoverFetcher(
|
|||
}
|
||||
|
||||
private fun fileLoader(file: File): FetchResult {
|
||||
return SourceResult(
|
||||
source = ImageSource(file = file.toOkioPath(), diskCacheKey = diskCacheKey),
|
||||
return SourceFetchResult(
|
||||
source = ImageSource(
|
||||
file = file.toOkioPath(),
|
||||
fileSystem = FileSystem.SYSTEM,
|
||||
diskCacheKey = diskCacheKey,
|
||||
),
|
||||
mimeType = "image/*",
|
||||
dataSource = DataSource.DISK,
|
||||
)
|
||||
|
@ -318,7 +332,7 @@ class MangaCoverFetcher(
|
|||
}
|
||||
|
||||
companion object {
|
||||
const val useCustomCover = "use_custom_cover"
|
||||
val USE_CUSTOM_COVER_KEY = Extras.Key(true)
|
||||
|
||||
private val CACHE_CONTROL_FORCE_NETWORK_NO_CACHE = CacheControl.Builder().noCache().noStore().build()
|
||||
private val CACHE_CONTROL_NO_NETWORK_NO_CACHE = CacheControl.Builder().noCache().onlyIfCached().build()
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
package eu.kanade.tachiyomi.data.image.coil
|
||||
|
||||
import coil.key.Keyer
|
||||
import coil.request.Options
|
||||
import coil3.key.Keyer
|
||||
import coil3.request.Options
|
||||
import eu.kanade.tachiyomi.data.database.models.Manga
|
||||
import eu.kanade.tachiyomi.util.storage.DiskUtil
|
||||
|
||||
|
|
|
@ -2,11 +2,15 @@ package eu.kanade.tachiyomi.data.image.coil
|
|||
|
||||
import android.graphics.Bitmap
|
||||
import android.os.Build
|
||||
import androidx.core.graphics.drawable.toDrawable
|
||||
import coil.ImageLoader
|
||||
import coil.decode.*
|
||||
import coil.fetch.SourceResult
|
||||
import coil.request.Options
|
||||
import coil3.ImageLoader
|
||||
import coil3.asCoilImage
|
||||
import coil3.decode.DecodeResult
|
||||
import coil3.decode.DecodeUtils
|
||||
import coil3.decode.Decoder
|
||||
import coil3.decode.ImageSource
|
||||
import coil3.fetch.SourceFetchResult
|
||||
import coil3.request.Options
|
||||
import coil3.request.bitmapConfig
|
||||
import eu.kanade.tachiyomi.util.system.GLUtil
|
||||
import eu.kanade.tachiyomi.util.system.ImageUtil
|
||||
import okio.BufferedSource
|
||||
|
@ -79,16 +83,16 @@ class TachiyomiImageDecoder(private val resources: ImageSource, private val opti
|
|||
*/
|
||||
|
||||
return DecodeResult(
|
||||
drawable = bitmap.toDrawable(options.context.resources),
|
||||
image = bitmap.asCoilImage(),
|
||||
isSampled = sampleSize > 1,
|
||||
)
|
||||
}
|
||||
|
||||
class Factory : Decoder.Factory {
|
||||
|
||||
override fun create(result: SourceResult, options: Options, imageLoader: ImageLoader): Decoder? {
|
||||
if (isApplicable(result.source.source()) || options.customDecoder) return TachiyomiImageDecoder(result.source, options)
|
||||
return null
|
||||
override fun create(result: SourceFetchResult, options: Options, imageLoader: ImageLoader): Decoder? {
|
||||
if (!isApplicable(result.source.source())) return null
|
||||
return TachiyomiImageDecoder(result.source, options)
|
||||
}
|
||||
|
||||
private fun isApplicable(source: BufferedSource): Boolean {
|
||||
|
|
|
@ -1,14 +1,14 @@
|
|||
package eu.kanade.tachiyomi.data.image.coil
|
||||
|
||||
import android.graphics.Bitmap
|
||||
import android.os.Build
|
||||
import coil.request.ImageRequest
|
||||
import coil.request.Options
|
||||
import coil.size.Dimension
|
||||
import coil.size.Scale
|
||||
import coil.size.Size
|
||||
import coil.size.isOriginal
|
||||
import coil.size.pxOrElse
|
||||
import coil3.Extras
|
||||
import coil3.getExtra
|
||||
import coil3.request.ImageRequest
|
||||
import coil3.request.Options
|
||||
import coil3.size.Dimension
|
||||
import coil3.size.Scale
|
||||
import coil3.size.Size
|
||||
import coil3.size.isOriginal
|
||||
import coil3.size.pxOrElse
|
||||
|
||||
internal inline fun Size.widthPx(scale: Scale, original: () -> Int): Int {
|
||||
return if (isOriginal) original() else width.toPx(scale)
|
||||
|
@ -26,22 +26,19 @@ internal fun Dimension.toPx(scale: Scale): Int = pxOrElse {
|
|||
}
|
||||
|
||||
fun ImageRequest.Builder.cropBorders(enable: Boolean) = apply {
|
||||
setParameter(cropBordersKey, enable)
|
||||
extras[cropBordersKey] = enable
|
||||
}
|
||||
|
||||
val Options.cropBorders: Boolean
|
||||
get() = parameters.value(cropBordersKey) ?: false
|
||||
get() = getExtra(cropBordersKey)
|
||||
|
||||
private val cropBordersKey = "crop_borders"
|
||||
private val cropBordersKey = Extras.Key(default = false)
|
||||
|
||||
fun ImageRequest.Builder.customDecoder(enable: Boolean) = apply {
|
||||
setParameter(customDecoderKey, enable)
|
||||
extras[customDecoderKey] = enable
|
||||
}
|
||||
|
||||
val Options.customDecoder: Boolean
|
||||
get() = parameters.value(customDecoderKey) ?: false
|
||||
get() = getExtra(customDecoderKey)
|
||||
|
||||
private val customDecoderKey = "custom_decoder"
|
||||
|
||||
val Options.bitmapConfig: Bitmap.Config
|
||||
get() = this.config
|
||||
private val customDecoderKey = Extras.Key(default = false)
|
||||
|
|
|
@ -16,9 +16,9 @@ import androidx.work.WorkInfo
|
|||
import androidx.work.WorkManager
|
||||
import androidx.work.WorkQuery
|
||||
import androidx.work.WorkerParameters
|
||||
import coil.Coil
|
||||
import coil.request.CachePolicy
|
||||
import coil.request.ImageRequest
|
||||
import coil3.imageLoader
|
||||
import coil3.request.CachePolicy
|
||||
import coil3.request.ImageRequest
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.data.cache.CoverCache
|
||||
import eu.kanade.tachiyomi.data.database.DatabaseHelper
|
||||
|
@ -261,21 +261,19 @@ class LibraryUpdateJob(private val context: Context, workerParams: WorkerParamet
|
|||
val thumbnailUrl = manga.thumbnail_url
|
||||
manga.copyFrom(networkManga)
|
||||
manga.initialized = true
|
||||
if (thumbnailUrl != manga.thumbnail_url) {
|
||||
coverCache.deleteFromCache(thumbnailUrl)
|
||||
// load new covers in background
|
||||
val request =
|
||||
val request: ImageRequest =
|
||||
if (thumbnailUrl != manga.thumbnail_url) {
|
||||
coverCache.deleteFromCache(thumbnailUrl)
|
||||
// load new covers in background
|
||||
ImageRequest.Builder(context).data(manga)
|
||||
.memoryCachePolicy(CachePolicy.DISABLED).build()
|
||||
Coil.imageLoader(context).execute(request)
|
||||
} else {
|
||||
val request =
|
||||
} else {
|
||||
ImageRequest.Builder(context).data(manga)
|
||||
.memoryCachePolicy(CachePolicy.DISABLED)
|
||||
.diskCachePolicy(CachePolicy.WRITE_ONLY)
|
||||
.build()
|
||||
Coil.imageLoader(context).execute(request)
|
||||
}
|
||||
}
|
||||
context.imageLoader.execute(request)
|
||||
db.insertManga(manga).executeAsBlocking()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -13,10 +13,11 @@ import androidx.core.app.ActivityCompat
|
|||
import androidx.core.app.NotificationCompat
|
||||
import androidx.core.app.NotificationManagerCompat
|
||||
import androidx.core.content.ContextCompat
|
||||
import coil.Coil
|
||||
import coil.request.CachePolicy
|
||||
import coil.request.ImageRequest
|
||||
import coil.transform.CircleCropTransformation
|
||||
import coil3.imageLoader
|
||||
import coil3.request.CachePolicy
|
||||
import coil3.request.ImageRequest
|
||||
import coil3.request.transformations
|
||||
import coil3.transform.CircleCropTransformation
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.data.database.models.Chapter
|
||||
import eu.kanade.tachiyomi.data.database.models.LibraryManga
|
||||
|
@ -191,11 +192,11 @@ class LibraryUpdateNotifier(private val context: Context) {
|
|||
.transformations(CircleCropTransformation())
|
||||
.size(width = ICON_SIZE, height = ICON_SIZE).build()
|
||||
|
||||
Coil.imageLoader(context)
|
||||
.execute(request).drawable?.let { drawable ->
|
||||
context.imageLoader
|
||||
.execute(request).image?.asDrawable(context.resources)?.let { drawable ->
|
||||
setLargeIcon((drawable as? BitmapDrawable)?.bitmap)
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
} catch (_: Exception) {
|
||||
}
|
||||
setGroupAlertBehavior(NotificationCompat.GROUP_ALERT_SUMMARY)
|
||||
setContentTitle(manga.title)
|
||||
|
|
|
@ -9,8 +9,8 @@ import androidx.core.text.color
|
|||
import androidx.core.text.scale
|
||||
import androidx.core.view.isGone
|
||||
import androidx.core.view.isVisible
|
||||
import coil.dispose
|
||||
import coil.load
|
||||
import coil3.dispose
|
||||
import coil3.load
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.data.image.coil.CoverViewTarget
|
||||
import eu.kanade.tachiyomi.databinding.ExtensionCardItemBinding
|
||||
|
|
|
@ -10,9 +10,9 @@ import androidx.constraintlayout.widget.ConstraintLayout
|
|||
import androidx.core.view.isVisible
|
||||
import androidx.core.view.marginBottom
|
||||
import androidx.core.view.updateLayoutParams
|
||||
import coil.dispose
|
||||
import coil.size.Precision
|
||||
import coil.size.Scale
|
||||
import coil3.dispose
|
||||
import coil3.size.Precision
|
||||
import coil3.size.Scale
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.data.database.models.Manga
|
||||
import eu.kanade.tachiyomi.data.image.coil.loadManga
|
||||
|
|
|
@ -4,7 +4,7 @@ import android.view.View
|
|||
import android.view.ViewGroup
|
||||
import androidx.core.view.isVisible
|
||||
import androidx.core.view.updateLayoutParams
|
||||
import coil.dispose
|
||||
import coil3.dispose
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.data.image.coil.loadManga
|
||||
import eu.kanade.tachiyomi.databinding.MangaListItemBinding
|
||||
|
|
|
@ -13,8 +13,7 @@ import android.view.inputmethod.InputMethodManager
|
|||
import androidx.core.graphics.ColorUtils
|
||||
import androidx.core.view.children
|
||||
import androidx.core.view.isVisible
|
||||
import coil.load
|
||||
import coil.request.Parameters
|
||||
import coil3.load
|
||||
import com.google.android.material.chip.Chip
|
||||
import com.google.android.material.chip.ChipGroup
|
||||
import eu.kanade.tachiyomi.R
|
||||
|
@ -215,10 +214,9 @@ class EditMangaDialog : DialogController {
|
|||
binding.resetCover.setOnClickListener {
|
||||
binding.mangaCover.load(
|
||||
manga,
|
||||
builder = {
|
||||
parameters(Parameters.Builder().set(MangaCoverFetcher.useCustomCover, false).build())
|
||||
},
|
||||
)
|
||||
) {
|
||||
extras[MangaCoverFetcher.USE_CUSTOM_COVER_KEY] = false
|
||||
}
|
||||
customCoverUri = null
|
||||
willResetCover = true
|
||||
}
|
||||
|
|
|
@ -7,6 +7,7 @@ import android.app.PendingIntent
|
|||
import android.content.ClipData
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.graphics.Bitmap
|
||||
import android.graphics.Color
|
||||
import android.graphics.drawable.BitmapDrawable
|
||||
import android.graphics.drawable.Icon
|
||||
|
@ -40,8 +41,9 @@ import androidx.palette.graphics.Palette
|
|||
import androidx.recyclerview.widget.ItemTouchHelper
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import coil.imageLoader
|
||||
import coil.request.ImageRequest
|
||||
import coil3.imageLoader
|
||||
import coil3.request.ImageRequest
|
||||
import coil3.request.allowHardware
|
||||
import com.bluelinelabs.conductor.ControllerChangeHandler
|
||||
import com.bluelinelabs.conductor.ControllerChangeType
|
||||
import com.google.android.material.chip.Chip
|
||||
|
@ -569,8 +571,20 @@ class MangaDetailsController :
|
|||
val request = ImageRequest.Builder(view.context).data(presenter.manga).allowHardware(false)
|
||||
.memoryCacheKey(presenter.manga.key())
|
||||
.target(
|
||||
onSuccess = { drawable ->
|
||||
val bitmap = (drawable as? BitmapDrawable)?.bitmap
|
||||
onSuccess = { image ->
|
||||
val drawable = image.asDrawable(view.context.resources)
|
||||
|
||||
val copy = (drawable as? BitmapDrawable)?.let {
|
||||
BitmapDrawable(
|
||||
view.context.resources,
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
|
||||
it.bitmap.copy(Bitmap.Config.HARDWARE, false)
|
||||
else
|
||||
it.bitmap.copy(it.bitmap.config, false),
|
||||
)
|
||||
} ?: drawable
|
||||
|
||||
val bitmap = (copy as? BitmapDrawable)?.bitmap
|
||||
// Generate the Palette on a background thread.
|
||||
if (bitmap != null) {
|
||||
Palette.from(bitmap).generate {
|
||||
|
@ -590,7 +604,7 @@ class MangaDetailsController :
|
|||
}
|
||||
}
|
||||
}
|
||||
binding.mangaCoverFull.setImageDrawable(drawable)
|
||||
binding.mangaCoverFull.setImageDrawable(copy)
|
||||
getHeader()?.updateCover(manga!!)
|
||||
},
|
||||
onError = {
|
||||
|
|
|
@ -4,12 +4,11 @@ import android.app.Application
|
|||
import android.graphics.Bitmap
|
||||
import android.net.Uri
|
||||
import android.os.Environment
|
||||
import coil.Coil
|
||||
import coil.imageLoader
|
||||
import coil.memory.MemoryCache
|
||||
import coil.request.CachePolicy
|
||||
import coil.request.ImageRequest
|
||||
import coil.request.SuccessResult
|
||||
import coil3.imageLoader
|
||||
import coil3.memory.MemoryCache
|
||||
import coil3.request.CachePolicy
|
||||
import coil3.request.ImageRequest
|
||||
import coil3.request.SuccessResult
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.data.cache.CoverCache
|
||||
import eu.kanade.tachiyomi.data.database.DatabaseHelper
|
||||
|
@ -379,7 +378,7 @@ class MangaDetailsPresenter(
|
|||
.diskCachePolicy(CachePolicy.WRITE_ONLY)
|
||||
.build()
|
||||
|
||||
if (Coil.imageLoader(preferences.context).execute(request) is SuccessResult) {
|
||||
if (preferences.context.imageLoader.execute(request) is SuccessResult) {
|
||||
preferences.context.imageLoader.memoryCache?.remove(MemoryCache.Key(manga.key()))
|
||||
withContext(Dispatchers.Main) {
|
||||
view?.setPaletteColor()
|
||||
|
|
|
@ -25,7 +25,9 @@ import androidx.core.view.updateLayoutParams
|
|||
import androidx.core.widget.TextViewCompat
|
||||
import androidx.transition.TransitionSet
|
||||
import androidx.vectordrawable.graphics.drawable.AnimatedVectorDrawableCompat
|
||||
import coil.request.CachePolicy
|
||||
import coil3.request.CachePolicy
|
||||
import coil3.request.placeholder
|
||||
import coil3.request.error
|
||||
import com.google.android.material.button.MaterialButton
|
||||
import com.google.android.material.chip.Chip
|
||||
import eu.kanade.tachiyomi.R
|
||||
|
@ -289,7 +291,7 @@ class MangaHeaderHolder(
|
|||
}
|
||||
}
|
||||
|
||||
@SuppressLint("SetTextI18n")
|
||||
@SuppressLint("SetTextI18n", "StringFormatInvalid")
|
||||
fun bind(item: MangaHeaderItem, manga: Manga) {
|
||||
val presenter = adapter.delegate.mangaPresenter()
|
||||
if (binding == null) {
|
||||
|
@ -680,9 +682,10 @@ class MangaHeaderHolder(
|
|||
diskCachePolicy(CachePolicy.READ_ONLY)
|
||||
target(
|
||||
onSuccess = {
|
||||
val bitmap = (it as? BitmapDrawable)?.bitmap
|
||||
val result = it.asDrawable(itemView.resources)
|
||||
val bitmap = (result as? BitmapDrawable)?.bitmap
|
||||
if (bitmap == null) {
|
||||
binding.backdrop.setImageDrawable(it)
|
||||
binding.backdrop.setImageDrawable(result)
|
||||
return@target
|
||||
}
|
||||
val yOffset = (bitmap.height / 2 * 0.33).toInt()
|
||||
|
|
|
@ -2,8 +2,9 @@ package eu.kanade.tachiyomi.ui.manga.track
|
|||
|
||||
import android.view.View
|
||||
import androidx.core.view.isVisible
|
||||
import coil.dispose
|
||||
import coil.load
|
||||
import coil3.dispose
|
||||
import coil3.load
|
||||
import coil3.request.allowHardware
|
||||
import com.google.android.material.shape.CornerFamily
|
||||
import com.mikepenz.fastadapter.FastAdapter
|
||||
import com.mikepenz.fastadapter.items.AbstractItem
|
||||
|
|
|
@ -2,7 +2,7 @@ package eu.kanade.tachiyomi.ui.migration
|
|||
|
||||
import android.view.View
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import coil.dispose
|
||||
import coil3.dispose
|
||||
import eu.davidea.flexibleadapter.FlexibleAdapter
|
||||
import eu.davidea.flexibleadapter.items.IFlexible
|
||||
import eu.kanade.tachiyomi.data.image.coil.loadManga
|
||||
|
|
|
@ -5,8 +5,8 @@ import androidx.appcompat.widget.PopupMenu
|
|||
import androidx.constraintlayout.widget.ConstraintLayout
|
||||
import androidx.core.view.isInvisible
|
||||
import androidx.core.view.isVisible
|
||||
import coil.Coil
|
||||
import coil.request.ImageRequest
|
||||
import coil3.imageLoader
|
||||
import coil3.request.ImageRequest
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.data.database.DatabaseHelper
|
||||
import eu.kanade.tachiyomi.data.database.models.Manga
|
||||
|
@ -20,6 +20,7 @@ import eu.kanade.tachiyomi.ui.base.holder.BaseFlexibleViewHolder
|
|||
import eu.kanade.tachiyomi.ui.library.setFreeformCoverRatio
|
||||
import eu.kanade.tachiyomi.ui.manga.MangaDetailsController
|
||||
import eu.kanade.tachiyomi.util.system.launchUI
|
||||
import eu.kanade.tachiyomi.util.system.setExtras
|
||||
import eu.kanade.tachiyomi.util.view.setCards
|
||||
import eu.kanade.tachiyomi.util.view.setVectorCompat
|
||||
import eu.kanade.tachiyomi.util.view.withFadeTransaction
|
||||
|
@ -147,9 +148,9 @@ class MigrationProcessHolder(
|
|||
|
||||
val request = ImageRequest.Builder(view.context).data(manga)
|
||||
.target(CoverViewTarget(coverThumbnail, progress))
|
||||
.setParameter(MangaCoverFetcher.useCustomCover, false)
|
||||
.setExtras(MangaCoverFetcher.USE_CUSTOM_COVER_KEY, false)
|
||||
.build()
|
||||
Coil.imageLoader(view.context).enqueue(request)
|
||||
view.context.imageLoader.enqueue(request)
|
||||
|
||||
compactTitle.isVisible = true
|
||||
gradient.isVisible = true
|
||||
|
|
|
@ -5,9 +5,9 @@ import android.graphics.Bitmap
|
|||
import android.graphics.drawable.BitmapDrawable
|
||||
import androidx.core.app.NotificationCompat
|
||||
import androidx.core.content.ContextCompat
|
||||
import coil.Coil
|
||||
import coil.request.CachePolicy
|
||||
import coil.request.ImageRequest
|
||||
import coil3.imageLoader
|
||||
import coil3.request.CachePolicy
|
||||
import coil3.request.ImageRequest
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.data.notification.NotificationHandler
|
||||
import eu.kanade.tachiyomi.data.notification.NotificationReceiver
|
||||
|
@ -51,7 +51,7 @@ class SaveImageNotifier(private val context: Context) {
|
|||
}
|
||||
},
|
||||
).build()
|
||||
Coil.imageLoader(context).enqueue(request)
|
||||
context.imageLoader.enqueue(request)
|
||||
}
|
||||
|
||||
private fun showCompleteNotification(file: File, image: Bitmap) {
|
||||
|
|
|
@ -18,12 +18,14 @@ import androidx.annotation.CallSuper
|
|||
import androidx.annotation.StyleRes
|
||||
import androidx.appcompat.widget.AppCompatImageView
|
||||
import androidx.core.view.isVisible
|
||||
import coil.dispose
|
||||
import coil.imageLoader
|
||||
import coil.request.CachePolicy
|
||||
import coil.request.ImageRequest
|
||||
import coil.size.Precision
|
||||
import coil.size.ViewSizeResolver
|
||||
import coil3.BitmapImage
|
||||
import coil3.dispose
|
||||
import coil3.imageLoader
|
||||
import coil3.request.CachePolicy
|
||||
import coil3.request.ImageRequest
|
||||
import coil3.request.crossfade
|
||||
import coil3.size.Precision
|
||||
import coil3.size.ViewSizeResolver
|
||||
import com.davemorrissey.labs.subscaleview.ImageSource
|
||||
import com.davemorrissey.labs.subscaleview.SubsamplingScaleImageView
|
||||
import com.davemorrissey.labs.subscaleview.SubsamplingScaleImageView.SCALE_TYPE_CENTER_INSIDE
|
||||
|
@ -180,7 +182,7 @@ open class ReaderPageImageView @JvmOverloads constructor(
|
|||
}
|
||||
|
||||
private fun setNonAnimatedImage(
|
||||
image: Any,
|
||||
data: Any,
|
||||
config: Config,
|
||||
) = (pageView as? SubsamplingScaleImageView)?.apply {
|
||||
setDoubleTapZoomDuration(config.zoomDuration.getSystemScaledDuration())
|
||||
|
@ -226,13 +228,13 @@ open class ReaderPageImageView @JvmOverloads constructor(
|
|||
val useCoilPipeline = false // FIXME: "Bitmap too large to be uploaded into a texture"
|
||||
if (isWebtoon && useCoilPipeline) {
|
||||
val request = ImageRequest.Builder(context)
|
||||
.data(image)
|
||||
.data(data)
|
||||
.memoryCachePolicy(CachePolicy.DISABLED)
|
||||
.diskCachePolicy(CachePolicy.DISABLED)
|
||||
.target(
|
||||
onSuccess = { result ->
|
||||
val drawable = result as BitmapDrawable
|
||||
setImage(ImageSource.bitmap(drawable.bitmap))
|
||||
val image = result as BitmapDrawable
|
||||
setImage(ImageSource.bitmap(image.bitmap))
|
||||
isVisible = true
|
||||
},
|
||||
onError = {
|
||||
|
@ -247,10 +249,10 @@ open class ReaderPageImageView @JvmOverloads constructor(
|
|||
.build()
|
||||
context.imageLoader.enqueue(request)
|
||||
} else {
|
||||
when (image) {
|
||||
is BitmapDrawable -> setImage(ImageSource.bitmap(image.bitmap))
|
||||
is InputStream -> setImage(ImageSource.inputStream(image))
|
||||
else -> throw IllegalArgumentException("Not implemented for class ${image::class.simpleName}")
|
||||
when (data) {
|
||||
is BitmapDrawable -> setImage(ImageSource.bitmap(data.bitmap))
|
||||
is InputStream -> setImage(ImageSource.inputStream(data))
|
||||
else -> throw IllegalArgumentException("Not implemented for class ${data::class.simpleName}")
|
||||
}
|
||||
isVisible = true
|
||||
}
|
||||
|
@ -314,8 +316,9 @@ open class ReaderPageImageView @JvmOverloads constructor(
|
|||
.diskCachePolicy(CachePolicy.DISABLED)
|
||||
.target(
|
||||
onSuccess = { result ->
|
||||
setImageDrawable(result)
|
||||
(result as? Animatable)?.start()
|
||||
val drawable = result.asDrawable(context.resources)
|
||||
setImageDrawable(drawable)
|
||||
(drawable as? Animatable)?.start()
|
||||
isVisible = true
|
||||
this@ReaderPageImageView.onImageLoaded()
|
||||
},
|
||||
|
|
|
@ -5,9 +5,9 @@ import android.view.View
|
|||
import androidx.core.graphics.ColorUtils
|
||||
import androidx.core.view.isVisible
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import coil.Coil
|
||||
import coil.dispose
|
||||
import coil.request.ImageRequest
|
||||
import coil3.dispose
|
||||
import coil3.imageLoader
|
||||
import coil3.request.ImageRequest
|
||||
import eu.davidea.flexibleadapter.FlexibleAdapter
|
||||
import eu.davidea.flexibleadapter.items.IFlexible
|
||||
import eu.kanade.tachiyomi.data.database.models.Manga
|
||||
|
@ -15,6 +15,7 @@ import eu.kanade.tachiyomi.data.image.coil.CoverViewTarget
|
|||
import eu.kanade.tachiyomi.data.image.coil.MangaCoverFetcher
|
||||
import eu.kanade.tachiyomi.databinding.MangaGridItemBinding
|
||||
import eu.kanade.tachiyomi.ui.library.LibraryCategoryAdapter
|
||||
import eu.kanade.tachiyomi.util.system.setExtras
|
||||
import eu.kanade.tachiyomi.util.view.setCards
|
||||
|
||||
/**
|
||||
|
@ -67,9 +68,9 @@ class BrowseSourceGridHolder(
|
|||
manga.id ?: return
|
||||
val request = ImageRequest.Builder(view.context).data(manga)
|
||||
.target(CoverViewTarget(binding.coverThumbnail, binding.progress))
|
||||
.setParameter(MangaCoverFetcher.useCustomCover, false)
|
||||
.setExtras(MangaCoverFetcher.USE_CUSTOM_COVER_KEY, false)
|
||||
.build()
|
||||
Coil.imageLoader(view.context).enqueue(request)
|
||||
view.context.imageLoader.enqueue(request)
|
||||
|
||||
binding.coverThumbnail.alpha = if (manga.favorite) 0.34f else 1.0f
|
||||
binding.card.strokeColorStateList?.defaultColor?.let { color ->
|
||||
|
|
|
@ -3,15 +3,16 @@ package eu.kanade.tachiyomi.ui.source.browse
|
|||
import android.view.View
|
||||
import androidx.core.view.isVisible
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import coil.Coil
|
||||
import coil.dispose
|
||||
import coil.request.ImageRequest
|
||||
import coil3.dispose
|
||||
import coil3.imageLoader
|
||||
import coil3.request.ImageRequest
|
||||
import eu.davidea.flexibleadapter.FlexibleAdapter
|
||||
import eu.davidea.flexibleadapter.items.IFlexible
|
||||
import eu.kanade.tachiyomi.data.database.models.Manga
|
||||
import eu.kanade.tachiyomi.data.image.coil.CoverViewTarget
|
||||
import eu.kanade.tachiyomi.data.image.coil.MangaCoverFetcher
|
||||
import eu.kanade.tachiyomi.databinding.MangaListItemBinding
|
||||
import eu.kanade.tachiyomi.util.system.setExtras
|
||||
import eu.kanade.tachiyomi.util.view.setCards
|
||||
|
||||
/**
|
||||
|
@ -56,9 +57,9 @@ class BrowseSourceListHolder(
|
|||
manga.id ?: return
|
||||
val request = ImageRequest.Builder(view.context).data(manga)
|
||||
.target(CoverViewTarget(binding.coverThumbnail))
|
||||
.setParameter(MangaCoverFetcher.useCustomCover, false)
|
||||
.setExtras(MangaCoverFetcher.USE_CUSTOM_COVER_KEY, false)
|
||||
.build()
|
||||
Coil.imageLoader(view.context).enqueue(request)
|
||||
view.context.imageLoader.enqueue(request)
|
||||
|
||||
binding.coverThumbnail.alpha = if (manga.favorite) 0.34f else 1.0f
|
||||
}
|
||||
|
|
|
@ -3,16 +3,18 @@ package eu.kanade.tachiyomi.ui.source.globalsearch
|
|||
import android.graphics.drawable.RippleDrawable
|
||||
import android.view.View
|
||||
import androidx.core.view.isVisible
|
||||
import coil.Coil
|
||||
import coil.dispose
|
||||
import coil.request.CachePolicy
|
||||
import coil.request.ImageRequest
|
||||
import coil3.dispose
|
||||
import coil3.imageLoader
|
||||
import coil3.request.CachePolicy
|
||||
import coil3.request.ImageRequest
|
||||
import coil3.request.placeholder
|
||||
import eu.kanade.tachiyomi.data.database.models.Manga
|
||||
import eu.kanade.tachiyomi.data.image.coil.CoverViewTarget
|
||||
import eu.kanade.tachiyomi.data.image.coil.MangaCoverFetcher
|
||||
import eu.kanade.tachiyomi.databinding.SourceGlobalSearchControllerCardItemBinding
|
||||
import eu.kanade.tachiyomi.ui.base.holder.BaseFlexibleViewHolder
|
||||
import eu.kanade.tachiyomi.util.system.dpToPx
|
||||
import eu.kanade.tachiyomi.util.system.setExtras
|
||||
import eu.kanade.tachiyomi.util.view.makeShapeCorners
|
||||
import eu.kanade.tachiyomi.util.view.setCards
|
||||
|
||||
|
@ -57,9 +59,9 @@ class GlobalSearchMangaHolder(view: View, adapter: GlobalSearchCardAdapter) :
|
|||
.placeholder(android.R.color.transparent)
|
||||
.memoryCachePolicy(CachePolicy.DISABLED)
|
||||
.target(CoverViewTarget(binding.itemImage, binding.progress))
|
||||
.setParameter(MangaCoverFetcher.useCustomCover, false)
|
||||
.setExtras(MangaCoverFetcher.USE_CUSTOM_COVER_KEY, false)
|
||||
.build()
|
||||
Coil.imageLoader(itemView.context).enqueue(request)
|
||||
itemView.context.imageLoader.enqueue(request)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,8 +7,8 @@ import android.content.pm.ShortcutManager
|
|||
import android.graphics.Bitmap
|
||||
import android.graphics.drawable.BitmapDrawable
|
||||
import android.graphics.drawable.Icon
|
||||
import coil.Coil
|
||||
import coil.request.ImageRequest
|
||||
import coil3.imageLoader
|
||||
import coil3.request.ImageRequest
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.appwidget.TachiyomiWidgetManager
|
||||
import eu.kanade.tachiyomi.data.cache.CoverCache
|
||||
|
@ -72,8 +72,8 @@ class MangaShortcutManager(
|
|||
is Manga -> {
|
||||
val request = ImageRequest.Builder(context).data(item).build()
|
||||
val bitmap = (
|
||||
Coil.imageLoader(context)
|
||||
.execute(request).drawable as? BitmapDrawable
|
||||
context.imageLoader
|
||||
.execute(request).image?.asDrawable(context.resources) as? BitmapDrawable
|
||||
)?.bitmap
|
||||
|
||||
ShortcutInfo.Builder(
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
package eu.kanade.tachiyomi.util.system
|
||||
|
||||
import coil3.Extras
|
||||
import coil3.request.ImageRequest
|
||||
|
||||
fun <T> ImageRequest.Builder.setExtras(extraKey: Extras.Key<T>, value: T): ImageRequest.Builder {
|
||||
this.extras[extraKey] = value
|
||||
return this
|
||||
}
|
|
@ -93,18 +93,20 @@ object ImageUtil {
|
|||
}
|
||||
|
||||
fun isAnimatedAndSupported(stream: InputStream): Boolean {
|
||||
try {
|
||||
return try {
|
||||
val type = getImageType(stream) ?: return false
|
||||
return when (type.format) {
|
||||
// https://coil-kt.github.io/coil/getting_started/#supported-image-formats
|
||||
when (type.format) {
|
||||
Format.Gif -> true
|
||||
// Coil supports animated WebP on Android 9.0+
|
||||
// https://coil-kt.github.io/coil/getting_started/#supported-image-formats
|
||||
// Animated WebP on Android 9+
|
||||
Format.Webp -> type.isAnimated && Build.VERSION.SDK_INT >= Build.VERSION_CODES.P
|
||||
// Animated Heif on Android 11+
|
||||
Format.Heif -> type.isAnimated && Build.VERSION.SDK_INT >= Build.VERSION_CODES.R
|
||||
else -> false
|
||||
}
|
||||
} catch (_: Exception) {
|
||||
false
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
enum class ImageType(val mime: String, val extension: String) {
|
||||
|
|
|
@ -1,20 +1,20 @@
|
|||
package eu.kanade.tachiyomi.widget
|
||||
|
||||
import android.graphics.drawable.Drawable
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.ImageView
|
||||
import androidx.core.view.isVisible
|
||||
import coil.target.ImageViewTarget
|
||||
import coil3.Image
|
||||
import coil3.target.ImageViewTarget
|
||||
|
||||
class GifViewTarget(view: ImageView, private val progressBar: View?, private val decodeErrorLayout: ViewGroup?) : ImageViewTarget(view) {
|
||||
|
||||
override fun onError(error: Drawable?) {
|
||||
override fun onError(error: Image?) {
|
||||
progressBar?.isVisible = false
|
||||
decodeErrorLayout?.isVisible = true
|
||||
}
|
||||
|
||||
override fun onSuccess(result: Drawable) {
|
||||
override fun onSuccess(result: Image) {
|
||||
progressBar?.isVisible = false
|
||||
decodeErrorLayout?.isVisible = false
|
||||
super.onSuccess(result)
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[versions]
|
||||
chucker = "3.5.2"
|
||||
coil = "2.4.0"
|
||||
coil3 = "3.0.0-alpha06"
|
||||
flexible-adapter = "c8013533"
|
||||
fast_adapter = "5.6.0"
|
||||
nucleus = "3.0.0"
|
||||
|
@ -11,9 +11,10 @@ shizuku = "12.1.0"
|
|||
accompanist-webview = { module = "com.google.accompanist:accompanist-webview", version = "0.30.1" }
|
||||
chucker-library-no-op = { module = "com.github.ChuckerTeam.Chucker:library-no-op", version.ref = "chucker" }
|
||||
chucker-library = { module = "com.github.ChuckerTeam.Chucker:library", version.ref = "chucker" }
|
||||
coil-svg = { module = "io.coil-kt:coil-svg", version.ref = "coil" }
|
||||
coil-gif = { module = "io.coil-kt:coil-gif", version.ref = "coil" }
|
||||
coil = { module = "io.coil-kt:coil", version.ref = "coil" }
|
||||
coil3 = { module = "io.coil-kt.coil3:coil", version.ref = "coil3" }
|
||||
coil3-svg = { module = "io.coil-kt.coil3:coil-svg", version.ref = "coil3" }
|
||||
coil3-gif = { module = "io.coil-kt.coil3:coil-gif", version.ref = "coil3" }
|
||||
coil3-okhttp = { module = "io.coil-kt.coil3:coil-network-okhttp", version.ref = "coil3" }
|
||||
compose-theme-adapter3 = { module = "com.google.accompanist:accompanist-themeadapter-material3", version = "0.33.2-alpha" }
|
||||
conductor = { module = "com.bluelinelabs:conductor", version = "4.0.0-preview-4" }
|
||||
conductor-support-preference = { module = "com.github.tachiyomiorg:conductor-support-preference", version = "3.0.0" }
|
||||
|
@ -77,4 +78,5 @@ kotlinter = { id = "org.jmailen.kotlinter", version = "4.1.1" }
|
|||
gradle-versions = { id = "com.github.ben-manes.versions", version = "0.42.0" }
|
||||
|
||||
[bundles]
|
||||
coil = [ "coil3", "coil3-svg", "coil3-gif", "coil3-okhttp" ]
|
||||
test = [ "junit", "mockk" ]
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue