diff --git a/app/src/main/java/org/koitharu/kotatsu/bookmarks/ui/adapter/BookmarkListAD.kt b/app/src/main/java/org/koitharu/kotatsu/bookmarks/ui/adapter/BookmarkListAD.kt index 8bbd70ba5..1ffa3bac3 100644 --- a/app/src/main/java/org/koitharu/kotatsu/bookmarks/ui/adapter/BookmarkListAD.kt +++ b/app/src/main/java/org/koitharu/kotatsu/bookmarks/ui/adapter/BookmarkListAD.kt @@ -8,10 +8,12 @@ import org.koitharu.kotatsu.base.ui.list.AdapterDelegateClickListenerAdapter import org.koitharu.kotatsu.base.ui.list.OnListItemClickListener import org.koitharu.kotatsu.bookmarks.domain.Bookmark import org.koitharu.kotatsu.databinding.ItemBookmarkBinding +import org.koitharu.kotatsu.utils.ext.decodeRegion import org.koitharu.kotatsu.utils.ext.disposeImageRequest import org.koitharu.kotatsu.utils.ext.enqueueWith import org.koitharu.kotatsu.utils.ext.newImageRequest import org.koitharu.kotatsu.utils.ext.source +import org.koitharu.kotatsu.utils.image.CoverSizeResolver fun bookmarkListAD( coil: ImageLoader, @@ -27,10 +29,12 @@ fun bookmarkListAD( bind { binding.imageViewThumb.newImageRequest(lifecycleOwner, item.imageUrl)?.run { + size(CoverSizeResolver(binding.imageViewThumb)) placeholder(R.drawable.ic_placeholder) fallback(R.drawable.ic_placeholder) error(R.drawable.ic_error_placeholder) allowRgb565(true) + decodeRegion(item.scroll) source(item.manga.source) enqueueWith(coil) } diff --git a/app/src/main/java/org/koitharu/kotatsu/bookmarks/ui/adapter/BookmarksGroupAD.kt b/app/src/main/java/org/koitharu/kotatsu/bookmarks/ui/adapter/BookmarksGroupAD.kt index e4e32fa93..a4d33d0eb 100644 --- a/app/src/main/java/org/koitharu/kotatsu/bookmarks/ui/adapter/BookmarksGroupAD.kt +++ b/app/src/main/java/org/koitharu/kotatsu/bookmarks/ui/adapter/BookmarksGroupAD.kt @@ -19,6 +19,7 @@ import org.koitharu.kotatsu.utils.ext.disposeImageRequest import org.koitharu.kotatsu.utils.ext.enqueueWith import org.koitharu.kotatsu.utils.ext.newImageRequest import org.koitharu.kotatsu.utils.ext.source +import org.koitharu.kotatsu.utils.image.CoverSizeResolver fun bookmarksGroupAD( coil: ImageLoader, @@ -54,6 +55,7 @@ fun bookmarksGroupAD( fallback(R.drawable.ic_placeholder) error(R.drawable.ic_error_placeholder) allowRgb565(true) + size(CoverSizeResolver(binding.imageViewCover)) source(item.manga.source) enqueueWith(coil) } diff --git a/app/src/main/java/org/koitharu/kotatsu/reader/ui/thumbnails/adapter/PageThumbnailAD.kt b/app/src/main/java/org/koitharu/kotatsu/reader/ui/thumbnails/adapter/PageThumbnailAD.kt index 96534ea8a..7d2c6c3bd 100644 --- a/app/src/main/java/org/koitharu/kotatsu/reader/ui/thumbnails/adapter/PageThumbnailAD.kt +++ b/app/src/main/java/org/koitharu/kotatsu/reader/ui/thumbnails/adapter/PageThumbnailAD.kt @@ -57,7 +57,7 @@ fun pageThumbnailAD( ImageRequest.Builder(context) .data(file) .size(thumbSize) - .decodeRegion() + .decodeRegion(0) .allowRgb565(isLowRamDevice(context)) .build(), ).drawable diff --git a/app/src/main/java/org/koitharu/kotatsu/utils/ext/CoilExt.kt b/app/src/main/java/org/koitharu/kotatsu/utils/ext/CoilExt.kt index 4aa630e2f..4a1c18d98 100644 --- a/app/src/main/java/org/koitharu/kotatsu/utils/ext/CoilExt.kt +++ b/app/src/main/java/org/koitharu/kotatsu/utils/ext/CoilExt.kt @@ -54,9 +54,10 @@ fun ImageRequest.Builder.indicator(indicator: BaseProgressIndicator<*>): ImageRe return listener(ImageRequestIndicatorListener(indicator)) } -fun ImageRequest.Builder.decodeRegion(): ImageRequest.Builder { - return decoderFactory(RegionBitmapDecoder.Factory()) -} +fun ImageRequest.Builder.decodeRegion( + scroll: Int = RegionBitmapDecoder.SCROLL_UNDEFINED, +): ImageRequest.Builder = decoderFactory(RegionBitmapDecoder.Factory()) + .setParameter(RegionBitmapDecoder.PARAM_SCROLL, scroll) @Suppress("SpellCheckingInspection") fun ImageRequest.Builder.crossfade(context: Context): ImageRequest.Builder { diff --git a/app/src/main/java/org/koitharu/kotatsu/utils/image/RegionBitmapDecoder.kt b/app/src/main/java/org/koitharu/kotatsu/utils/image/RegionBitmapDecoder.kt index 891ae70fd..9736f6776 100644 --- a/app/src/main/java/org/koitharu/kotatsu/utils/image/RegionBitmapDecoder.kt +++ b/app/src/main/java/org/koitharu/kotatsu/utils/image/RegionBitmapDecoder.kt @@ -14,10 +14,10 @@ import coil.decode.ImageSource import coil.fetch.SourceResult import coil.request.Options import coil.size.* -import kotlin.math.roundToInt import kotlinx.coroutines.runInterruptible import kotlinx.coroutines.sync.Semaphore import kotlinx.coroutines.sync.withPermit +import kotlin.math.roundToInt class RegionBitmapDecoder( private val source: ImageSource, @@ -83,14 +83,22 @@ class RegionBitmapDecoder( val dstRatio = dstWidth / dstHeight.toDouble() val rect = if (srcRatio < dstRatio) { // probably manga - Rect(0, 0, srcWidth, (srcWidth / dstRatio).toInt()) + Rect(0, 0, srcWidth, (srcWidth / dstRatio).toInt().coerceAtLeast(1)) } else { - Rect(0, 0, (srcHeight / dstRatio).toInt(), srcHeight) + Rect(0, 0, (srcHeight / dstRatio).toInt().coerceAtLeast(1), srcHeight) + } + val scroll = options.parameters.value(PARAM_SCROLL) ?: SCROLL_UNDEFINED + if (scroll == SCROLL_UNDEFINED) { + rect.offsetTo( + (srcWidth - rect.width()) / 2, + (srcHeight - rect.height()) / 2, + ) + } else { + rect.offsetTo( + (srcWidth - rect.width()) / 2, + (scroll * dstRatio).toInt().coerceAtMost(srcHeight - rect.height()), + ) } - rect.offsetTo( - (srcWidth - rect.width()) / 2, - (srcHeight - rect.height()) / 2, - ) // Calculate the image's sample size. inSampleSize = DecodeUtils.calculateInSampleSize( @@ -148,21 +156,26 @@ class RegionBitmapDecoder( override fun hashCode() = javaClass.hashCode() } -} -private const val DEFAULT_MAX_PARALLELISM = 4 + companion object { -private inline fun Size.widthPx(scale: Scale, original: () -> Int): Int { - return if (isOriginal) original() else width.toPx(scale) -} + const val PARAM_SCROLL = "scroll" + const val SCROLL_UNDEFINED = -1 + private const val DEFAULT_MAX_PARALLELISM = 4 -private inline fun Size.heightPx(scale: Scale, original: () -> Int): Int { - return if (isOriginal) original() else height.toPx(scale) -} + private inline fun Size.widthPx(scale: Scale, original: () -> Int): Int { + return if (isOriginal) original() else width.toPx(scale) + } -private fun Dimension.toPx(scale: Scale) = pxOrElse { - when (scale) { - Scale.FILL -> Int.MIN_VALUE - Scale.FIT -> Int.MAX_VALUE + private inline fun Size.heightPx(scale: Scale, original: () -> Int): Int { + return if (isOriginal) original() else height.toPx(scale) + } + + private fun Dimension.toPx(scale: Scale) = pxOrElse { + when (scale) { + Scale.FILL -> Int.MIN_VALUE + Scale.FIT -> Int.MAX_VALUE + } + } } }