Upgrade coil to v2
This commit is contained in:
@@ -52,6 +52,7 @@ android {
|
|||||||
'-opt-in=kotlinx.coroutines.ExperimentalCoroutinesApi',
|
'-opt-in=kotlinx.coroutines.ExperimentalCoroutinesApi',
|
||||||
'-opt-in=kotlinx.coroutines.FlowPreview',
|
'-opt-in=kotlinx.coroutines.FlowPreview',
|
||||||
'-opt-in=kotlin.contracts.ExperimentalContracts',
|
'-opt-in=kotlin.contracts.ExperimentalContracts',
|
||||||
|
'-opt-in=coil.annotation.ExperimentalCoilApi',
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
lint {
|
lint {
|
||||||
@@ -86,7 +87,7 @@ dependencies {
|
|||||||
implementation 'androidx.viewpager2:viewpager2:1.1.0-beta01'
|
implementation 'androidx.viewpager2:viewpager2:1.1.0-beta01'
|
||||||
implementation 'androidx.preference:preference-ktx:1.2.0'
|
implementation 'androidx.preference:preference-ktx:1.2.0'
|
||||||
implementation 'androidx.work:work-runtime-ktx:2.7.1'
|
implementation 'androidx.work:work-runtime-ktx:2.7.1'
|
||||||
implementation 'com.google.android.material:material:1.6.0-rc01'
|
implementation 'com.google.android.material:material:1.7.0-alpha01'
|
||||||
//noinspection LifecycleAnnotationProcessorWithJava8
|
//noinspection LifecycleAnnotationProcessorWithJava8
|
||||||
kapt 'androidx.lifecycle:lifecycle-compiler:2.4.1'
|
kapt 'androidx.lifecycle:lifecycle-compiler:2.4.1'
|
||||||
|
|
||||||
@@ -101,11 +102,11 @@ dependencies {
|
|||||||
implementation 'com.hannesdorfmann:adapterdelegates4-kotlin-dsl-viewbinding:4.3.2'
|
implementation 'com.hannesdorfmann:adapterdelegates4-kotlin-dsl-viewbinding:4.3.2'
|
||||||
|
|
||||||
implementation 'io.insert-koin:koin-android:3.1.6'
|
implementation 'io.insert-koin:koin-android:3.1.6'
|
||||||
implementation 'io.coil-kt:coil-base:1.4.0'
|
implementation 'io.coil-kt:coil-base:2.0.0-rc03'
|
||||||
implementation 'com.davemorrissey.labs:subsampling-scale-image-view-androidx:3.10.0'
|
implementation 'com.davemorrissey.labs:subsampling-scale-image-view-androidx:3.10.0'
|
||||||
implementation 'com.github.solkin:disk-lru-cache:1.4'
|
implementation 'com.github.solkin:disk-lru-cache:1.4'
|
||||||
|
|
||||||
debugImplementation 'com.squareup.leakcanary:leakcanary-android:2.8.1'
|
debugImplementation 'com.squareup.leakcanary:leakcanary-android:2.9.1'
|
||||||
|
|
||||||
testImplementation 'junit:junit:4.13.2'
|
testImplementation 'junit:junit:4.13.2'
|
||||||
testImplementation 'org.jetbrains.kotlinx:kotlinx-coroutines-test:1.6.1'
|
testImplementation 'org.jetbrains.kotlinx:kotlinx-coroutines-test:1.6.1'
|
||||||
|
|||||||
@@ -5,12 +5,12 @@ import android.content.Context
|
|||||||
import android.content.pm.ShortcutManager
|
import android.content.pm.ShortcutManager
|
||||||
import android.media.ThumbnailUtils
|
import android.media.ThumbnailUtils
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
|
import android.util.Size
|
||||||
import androidx.core.content.pm.ShortcutInfoCompat
|
import androidx.core.content.pm.ShortcutInfoCompat
|
||||||
import androidx.core.content.pm.ShortcutManagerCompat
|
import androidx.core.content.pm.ShortcutManagerCompat
|
||||||
import androidx.core.graphics.drawable.IconCompat
|
import androidx.core.graphics.drawable.IconCompat
|
||||||
import coil.ImageLoader
|
import coil.ImageLoader
|
||||||
import coil.request.ImageRequest
|
import coil.request.ImageRequest
|
||||||
import coil.size.PixelSize
|
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
import org.koitharu.kotatsu.R
|
import org.koitharu.kotatsu.R
|
||||||
@@ -54,7 +54,7 @@ class ShortcutsRepository(
|
|||||||
val bmp = coil.execute(
|
val bmp = coil.execute(
|
||||||
ImageRequest.Builder(context)
|
ImageRequest.Builder(context)
|
||||||
.data(manga.coverUrl)
|
.data(manga.coverUrl)
|
||||||
.size(iconSize)
|
.size(iconSize.width, iconSize.height)
|
||||||
.build()
|
.build()
|
||||||
).requireBitmap()
|
).requireBitmap()
|
||||||
ThumbnailUtils.extractThumbnail(bmp, iconSize.width, iconSize.height, 0)
|
ThumbnailUtils.extractThumbnail(bmp, iconSize.width, iconSize.height, 0)
|
||||||
@@ -74,14 +74,14 @@ class ShortcutsRepository(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getIconSize(context: Context): PixelSize {
|
private fun getIconSize(context: Context): Size {
|
||||||
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N_MR1) {
|
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N_MR1) {
|
||||||
(context.getSystemService(Context.SHORTCUT_SERVICE) as ShortcutManager).let {
|
(context.getSystemService(Context.SHORTCUT_SERVICE) as ShortcutManager).let {
|
||||||
PixelSize(it.iconMaxWidth, it.iconMaxHeight)
|
Size(it.iconMaxWidth, it.iconMaxHeight)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
(context.getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager).launcherLargeIconSize.let {
|
(context.getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager).launcherLargeIconSize.let {
|
||||||
PixelSize(it, it)
|
Size(it, it)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,17 +2,19 @@ package org.koitharu.kotatsu.core.parser
|
|||||||
|
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
import coil.map.Mapper
|
import coil.map.Mapper
|
||||||
|
import coil.request.Options
|
||||||
import okhttp3.HttpUrl
|
import okhttp3.HttpUrl
|
||||||
import okhttp3.HttpUrl.Companion.toHttpUrl
|
import okhttp3.HttpUrl.Companion.toHttpUrl
|
||||||
import org.koitharu.kotatsu.parsers.model.MangaSource
|
import org.koitharu.kotatsu.parsers.model.MangaSource
|
||||||
|
|
||||||
class FaviconMapper() : Mapper<Uri, HttpUrl> {
|
class FaviconMapper : Mapper<Uri, HttpUrl> {
|
||||||
|
|
||||||
override fun map(data: Uri): HttpUrl {
|
override fun map(data: Uri, options: Options): HttpUrl? {
|
||||||
|
if (data.scheme != "favicon") {
|
||||||
|
return null
|
||||||
|
}
|
||||||
val mangaSource = MangaSource.valueOf(data.schemeSpecificPart)
|
val mangaSource = MangaSource.valueOf(data.schemeSpecificPart)
|
||||||
val repo = MangaRepository(mangaSource) as RemoteMangaRepository
|
val repo = MangaRepository(mangaSource) as RemoteMangaRepository
|
||||||
return repo.getFaviconUrl().toHttpUrl()
|
return repo.getFaviconUrl().toHttpUrl()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun handles(data: Uri) = data.scheme == "favicon"
|
|
||||||
}
|
}
|
||||||
@@ -2,11 +2,13 @@ package org.koitharu.kotatsu.core.ui
|
|||||||
|
|
||||||
import coil.ComponentRegistry
|
import coil.ComponentRegistry
|
||||||
import coil.ImageLoader
|
import coil.ImageLoader
|
||||||
import coil.util.CoilUtils
|
import coil.disk.DiskCache
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
import okhttp3.OkHttpClient
|
import okhttp3.OkHttpClient
|
||||||
import org.koin.android.ext.koin.androidContext
|
import org.koin.android.ext.koin.androidContext
|
||||||
import org.koin.dsl.module
|
import org.koin.dsl.module
|
||||||
import org.koitharu.kotatsu.core.parser.FaviconMapper
|
import org.koitharu.kotatsu.core.parser.FaviconMapper
|
||||||
|
import org.koitharu.kotatsu.local.data.CacheDir
|
||||||
import org.koitharu.kotatsu.local.data.CbzFetcher
|
import org.koitharu.kotatsu.local.data.CbzFetcher
|
||||||
|
|
||||||
val uiModule
|
val uiModule
|
||||||
@@ -14,15 +16,23 @@ val uiModule
|
|||||||
single {
|
single {
|
||||||
val httpClientFactory = {
|
val httpClientFactory = {
|
||||||
get<OkHttpClient>().newBuilder()
|
get<OkHttpClient>().newBuilder()
|
||||||
.cache(CoilUtils.createDefaultCache(androidContext()))
|
.cache(null)
|
||||||
|
.build()
|
||||||
|
}
|
||||||
|
val diskCacheFactory = {
|
||||||
|
val context = androidContext()
|
||||||
|
val rootDir = context.externalCacheDir ?: context.cacheDir
|
||||||
|
DiskCache.Builder()
|
||||||
|
.directory(rootDir.resolve(CacheDir.THUMBS.dir))
|
||||||
.build()
|
.build()
|
||||||
}
|
}
|
||||||
ImageLoader.Builder(androidContext())
|
ImageLoader.Builder(androidContext())
|
||||||
.okHttpClient(httpClientFactory)
|
.okHttpClient(httpClientFactory)
|
||||||
.launchInterceptorChainOnMainThread(false)
|
.interceptorDispatcher(Dispatchers.Default)
|
||||||
.componentRegistry(
|
.diskCache(diskCacheFactory)
|
||||||
|
.components(
|
||||||
ComponentRegistry.Builder()
|
ComponentRegistry.Builder()
|
||||||
.add(CbzFetcher())
|
.add(CbzFetcher.Factory())
|
||||||
.add(FaviconMapper())
|
.add(FaviconMapper())
|
||||||
.build()
|
.build()
|
||||||
).build()
|
).build()
|
||||||
|
|||||||
@@ -283,7 +283,7 @@ class DetailsFragment :
|
|||||||
.target(binding.imageViewCover)
|
.target(binding.imageViewCover)
|
||||||
if (currentCover != null) {
|
if (currentCover != null) {
|
||||||
request.data(manga.largeCoverUrl ?: return)
|
request.data(manga.largeCoverUrl ?: return)
|
||||||
.placeholderMemoryCacheKey(CoilUtils.metadata(binding.imageViewCover)?.memoryCacheKey)
|
.placeholderMemoryCacheKey(CoilUtils.result(binding.imageViewCover)?.request?.memoryCacheKey)
|
||||||
.fallback(currentCover)
|
.fallback(currentCover)
|
||||||
} else {
|
} else {
|
||||||
request.crossfade(true)
|
request.crossfade(true)
|
||||||
|
|||||||
@@ -6,7 +6,6 @@ import android.graphics.drawable.Drawable
|
|||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import androidx.appcompat.app.AppCompatDelegate
|
|
||||||
import androidx.core.graphics.Insets
|
import androidx.core.graphics.Insets
|
||||||
import androidx.core.graphics.drawable.toBitmap
|
import androidx.core.graphics.drawable.toBitmap
|
||||||
import androidx.core.view.updateLayoutParams
|
import androidx.core.view.updateLayoutParams
|
||||||
@@ -14,7 +13,7 @@ import androidx.core.view.updatePadding
|
|||||||
import coil.ImageLoader
|
import coil.ImageLoader
|
||||||
import coil.request.CachePolicy
|
import coil.request.CachePolicy
|
||||||
import coil.request.ImageRequest
|
import coil.request.ImageRequest
|
||||||
import coil.target.PoolableViewTarget
|
import coil.target.ViewTarget
|
||||||
import com.davemorrissey.labs.subscaleview.ImageSource
|
import com.davemorrissey.labs.subscaleview.ImageSource
|
||||||
import com.davemorrissey.labs.subscaleview.SubsamplingScaleImageView
|
import com.davemorrissey.labs.subscaleview.SubsamplingScaleImageView
|
||||||
import org.koin.android.ext.android.inject
|
import org.koin.android.ext.android.inject
|
||||||
@@ -61,16 +60,12 @@ class ImageActivity : BaseActivity<ActivityImageBinding>() {
|
|||||||
|
|
||||||
private class SsivTarget(
|
private class SsivTarget(
|
||||||
override val view: SubsamplingScaleImageView,
|
override val view: SubsamplingScaleImageView,
|
||||||
) : PoolableViewTarget<SubsamplingScaleImageView> {
|
) : ViewTarget<SubsamplingScaleImageView> {
|
||||||
|
|
||||||
override fun onStart(placeholder: Drawable?) = setDrawable(placeholder)
|
|
||||||
|
|
||||||
override fun onError(error: Drawable?) = setDrawable(error)
|
override fun onError(error: Drawable?) = setDrawable(error)
|
||||||
|
|
||||||
override fun onSuccess(result: Drawable) = setDrawable(result)
|
override fun onSuccess(result: Drawable) = setDrawable(result)
|
||||||
|
|
||||||
override fun onClear() = setDrawable(null)
|
|
||||||
|
|
||||||
override fun equals(other: Any?): Boolean {
|
override fun equals(other: Any?): Boolean {
|
||||||
return (this === other) || (other is SsivTarget && view == other.view)
|
return (this === other) || (other is SsivTarget && view == other.view)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -53,7 +53,7 @@ fun mangaGridItemAD(
|
|||||||
badge = null
|
badge = null
|
||||||
imageRequest?.dispose()
|
imageRequest?.dispose()
|
||||||
imageRequest = null
|
imageRequest = null
|
||||||
CoilUtils.clear(binding.imageViewCover)
|
CoilUtils.dispose(binding.imageViewCover)
|
||||||
binding.imageViewCover.setImageDrawable(null)
|
binding.imageViewCover.setImageDrawable(null)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -57,7 +57,7 @@ fun mangaListDetailedItemAD(
|
|||||||
badge = null
|
badge = null
|
||||||
imageRequest?.dispose()
|
imageRequest?.dispose()
|
||||||
imageRequest = null
|
imageRequest = null
|
||||||
CoilUtils.clear(binding.imageViewCover)
|
CoilUtils.dispose(binding.imageViewCover)
|
||||||
binding.imageViewCover.setImageDrawable(null)
|
binding.imageViewCover.setImageDrawable(null)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -55,7 +55,7 @@ fun mangaListItemAD(
|
|||||||
badge = null
|
badge = null
|
||||||
imageRequest?.dispose()
|
imageRequest?.dispose()
|
||||||
imageRequest = null
|
imageRequest = null
|
||||||
CoilUtils.clear(binding.imageViewCover)
|
CoilUtils.dispose(binding.imageViewCover)
|
||||||
binding.imageViewCover.setImageDrawable(null)
|
binding.imageViewCover.setImageDrawable(null)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2,41 +2,52 @@ package org.koitharu.kotatsu.local.data
|
|||||||
|
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
import android.webkit.MimeTypeMap
|
import android.webkit.MimeTypeMap
|
||||||
import coil.bitmap.BitmapPool
|
import coil.ImageLoader
|
||||||
import coil.decode.DataSource
|
import coil.decode.DataSource
|
||||||
import coil.decode.Options
|
import coil.decode.ImageSource
|
||||||
import coil.fetch.FetchResult
|
|
||||||
import coil.fetch.Fetcher
|
import coil.fetch.Fetcher
|
||||||
import coil.fetch.SourceResult
|
import coil.fetch.SourceResult
|
||||||
import coil.size.Size
|
import coil.request.Options
|
||||||
import java.util.zip.ZipFile
|
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.runInterruptible
|
import kotlinx.coroutines.runInterruptible
|
||||||
import okio.buffer
|
import okio.buffer
|
||||||
import okio.source
|
import okio.source
|
||||||
|
import java.util.zip.ZipFile
|
||||||
|
|
||||||
class CbzFetcher : Fetcher<Uri> {
|
class CbzFetcher(
|
||||||
|
private val uri: Uri,
|
||||||
|
private val options: Options
|
||||||
|
) : Fetcher {
|
||||||
|
|
||||||
override suspend fun fetch(
|
override suspend fun fetch() = runInterruptible(Dispatchers.IO) {
|
||||||
pool: BitmapPool,
|
val zip = ZipFile(uri.schemeSpecificPart)
|
||||||
data: Uri,
|
val entry = zip.getEntry(uri.fragment)
|
||||||
size: Size,
|
|
||||||
options: Options,
|
|
||||||
): FetchResult = runInterruptible(Dispatchers.IO) {
|
|
||||||
val zip = ZipFile(data.schemeSpecificPart)
|
|
||||||
val entry = zip.getEntry(data.fragment)
|
|
||||||
val ext = MimeTypeMap.getFileExtensionFromUrl(entry.name)
|
val ext = MimeTypeMap.getFileExtensionFromUrl(entry.name)
|
||||||
|
val bufferedSource = ExtraCloseableBufferedSource(
|
||||||
|
zip.getInputStream(entry).source().buffer(),
|
||||||
|
zip,
|
||||||
|
)
|
||||||
SourceResult(
|
SourceResult(
|
||||||
source = ExtraCloseableBufferedSource(
|
source = ImageSource(
|
||||||
zip.getInputStream(entry).source().buffer(),
|
source = bufferedSource,
|
||||||
zip,
|
context = options.context,
|
||||||
|
metadata = CbzMetadata(uri),
|
||||||
),
|
),
|
||||||
mimeType = MimeTypeMap.getSingleton().getMimeTypeFromExtension(ext),
|
mimeType = MimeTypeMap.getSingleton().getMimeTypeFromExtension(ext),
|
||||||
dataSource = DataSource.DISK
|
dataSource = DataSource.DISK,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun key(data: Uri) = data.toString()
|
class Factory : Fetcher.Factory<Uri> {
|
||||||
|
|
||||||
override fun handles(data: Uri) = data.scheme == "cbz"
|
override fun create(data: Uri, options: Options, imageLoader: ImageLoader): Fetcher? {
|
||||||
|
return if (data.scheme == "cbz") {
|
||||||
|
CbzFetcher(data, options)
|
||||||
|
} else {
|
||||||
|
null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class CbzMetadata(val uri: Uri) : ImageSource.Metadata()
|
||||||
}
|
}
|
||||||
@@ -3,7 +3,7 @@ package org.koitharu.kotatsu.reader.ui.thumbnails.adapter
|
|||||||
import android.graphics.drawable.Drawable
|
import android.graphics.drawable.Drawable
|
||||||
import coil.ImageLoader
|
import coil.ImageLoader
|
||||||
import coil.request.ImageRequest
|
import coil.request.ImageRequest
|
||||||
import coil.size.PixelSize
|
import coil.size.Size
|
||||||
import com.google.android.material.R as materialR
|
import com.google.android.material.R as materialR
|
||||||
import com.hannesdorfmann.adapterdelegates4.dsl.adapterDelegateViewBinding
|
import com.hannesdorfmann.adapterdelegates4.dsl.adapterDelegateViewBinding
|
||||||
import kotlinx.coroutines.*
|
import kotlinx.coroutines.*
|
||||||
@@ -27,7 +27,7 @@ fun pageThumbnailAD(
|
|||||||
|
|
||||||
var job: Job? = null
|
var job: Job? = null
|
||||||
val gridWidth = itemView.context.resources.getDimensionPixelSize(R.dimen.preferred_grid_width)
|
val gridWidth = itemView.context.resources.getDimensionPixelSize(R.dimen.preferred_grid_width)
|
||||||
val thumbSize = PixelSize(
|
val thumbSize = Size(
|
||||||
width = gridWidth,
|
width = gridWidth,
|
||||||
height = (gridWidth * 13f / 18f).toInt()
|
height = (gridWidth * 13f / 18f).toInt()
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
package org.koitharu.kotatsu.utils.progress
|
package org.koitharu.kotatsu.utils.progress
|
||||||
|
|
||||||
|
import coil.request.ErrorResult
|
||||||
import coil.request.ImageRequest
|
import coil.request.ImageRequest
|
||||||
import coil.request.ImageResult
|
import coil.request.SuccessResult
|
||||||
import com.google.android.material.progressindicator.BaseProgressIndicator
|
import com.google.android.material.progressindicator.BaseProgressIndicator
|
||||||
|
|
||||||
class ImageRequestIndicatorListener(
|
class ImageRequestIndicatorListener(
|
||||||
@@ -10,9 +11,9 @@ class ImageRequestIndicatorListener(
|
|||||||
|
|
||||||
override fun onCancel(request: ImageRequest) = indicator.hide()
|
override fun onCancel(request: ImageRequest) = indicator.hide()
|
||||||
|
|
||||||
override fun onError(request: ImageRequest, throwable: Throwable) = indicator.hide()
|
override fun onError(request: ImageRequest, result: ErrorResult) = indicator.hide()
|
||||||
|
|
||||||
override fun onStart(request: ImageRequest) = indicator.show()
|
override fun onStart(request: ImageRequest) = indicator.show()
|
||||||
|
|
||||||
override fun onSuccess(request: ImageRequest, metadata: ImageResult.Metadata) = indicator.hide()
|
override fun onSuccess(request: ImageRequest, result: SuccessResult) = indicator.hide()
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user