Upgrade coil to v2

pull/162/head
Koitharu 4 years ago
parent 4c5314fe59
commit ffad6a4ae6
No known key found for this signature in database
GPG Key ID: 8E861F8CE6E7CE27

@ -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 create(data: Uri, options: Options, imageLoader: ImageLoader): Fetcher? {
return if (data.scheme == "cbz") {
CbzFetcher(data, options)
} else {
null
}
}
}
override fun handles(data: Uri) = data.scheme == "cbz" 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()
} }
Loading…
Cancel
Save