diff --git a/app/src/main/java/org/koitharu/kotatsu/details/ui/DetailsFragment.kt b/app/src/main/java/org/koitharu/kotatsu/details/ui/DetailsFragment.kt index 21c6541ea..677d7e3f1 100644 --- a/app/src/main/java/org/koitharu/kotatsu/details/ui/DetailsFragment.kt +++ b/app/src/main/java/org/koitharu/kotatsu/details/ui/DetailsFragment.kt @@ -46,6 +46,7 @@ import org.koitharu.kotatsu.search.ui.SearchActivity import org.koitharu.kotatsu.utils.FileSize import org.koitharu.kotatsu.utils.ShareHelper import org.koitharu.kotatsu.utils.ext.* +import org.koitharu.kotatsu.utils.image.CoverSizeResolver class DetailsFragment : BaseFragment(), @@ -354,13 +355,22 @@ class DetailsFragment : } val request = ImageRequest.Builder(context ?: return) .target(binding.imageViewCover) + .size(CoverSizeResolver(binding.imageViewCover)) .data(imageUrl) .crossfade(true) .referer(manga.publicUrl) .lifecycle(viewLifecycleOwner) - lastResult?.drawable?.let { - request.fallback(it) - } ?: request.fallback(R.drawable.ic_placeholder) + .placeholderMemoryCacheKey(manga.coverUrl) + val previousDrawable = lastResult?.drawable + if (previousDrawable != null) { + request.fallback(previousDrawable) + .placeholder(previousDrawable) + .error(previousDrawable) + } else { + request.fallback(R.drawable.ic_placeholder) + .placeholder(R.drawable.ic_placeholder) + .error(R.drawable.ic_placeholder) + } request.enqueueWith(coil) } diff --git a/app/src/main/java/org/koitharu/kotatsu/list/ui/adapter/MangaGridItemAD.kt b/app/src/main/java/org/koitharu/kotatsu/list/ui/adapter/MangaGridItemAD.kt index 82b77d11f..6af70140e 100644 --- a/app/src/main/java/org/koitharu/kotatsu/list/ui/adapter/MangaGridItemAD.kt +++ b/app/src/main/java/org/koitharu/kotatsu/list/ui/adapter/MangaGridItemAD.kt @@ -17,6 +17,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.referer +import org.koitharu.kotatsu.utils.image.CoverSizeResolver fun mangaGridItemAD( coil: ImageLoader, @@ -24,9 +25,8 @@ fun mangaGridItemAD( clickListener: OnListItemClickListener, sizeResolver: ItemSizeResolver?, ) = adapterDelegateViewBinding( - { inflater, parent -> ItemMangaGridBinding.inflate(inflater, parent, false) } + { inflater, parent -> ItemMangaGridBinding.inflate(inflater, parent, false) }, ) { - var badge: BadgeDrawable? = null itemView.setOnClickListener { @@ -46,6 +46,7 @@ fun mangaGridItemAD( binding.progressView.setPercent(item.progress, MangaListAdapter.PAYLOAD_PROGRESS in payloads) binding.imageViewCover.newImageRequest(item.coverUrl)?.run { referer(item.manga.publicUrl) + size(CoverSizeResolver(binding.imageViewCover)) placeholder(R.drawable.ic_placeholder) fallback(R.drawable.ic_placeholder) error(R.drawable.ic_placeholder) diff --git a/app/src/main/java/org/koitharu/kotatsu/list/ui/adapter/MangaListDetailedItemAD.kt b/app/src/main/java/org/koitharu/kotatsu/list/ui/adapter/MangaListDetailedItemAD.kt index edf38d33a..4c1443b72 100644 --- a/app/src/main/java/org/koitharu/kotatsu/list/ui/adapter/MangaListDetailedItemAD.kt +++ b/app/src/main/java/org/koitharu/kotatsu/list/ui/adapter/MangaListDetailedItemAD.kt @@ -2,7 +2,6 @@ package org.koitharu.kotatsu.list.ui.adapter import androidx.lifecycle.LifecycleOwner import coil.ImageLoader -import org.koitharu.kotatsu.utils.ext.* import com.google.android.material.badge.BadgeDrawable import com.hannesdorfmann.adapterdelegates4.dsl.adapterDelegateViewBinding import org.koitharu.kotatsu.R @@ -12,15 +11,16 @@ import org.koitharu.kotatsu.history.domain.PROGRESS_NONE import org.koitharu.kotatsu.list.ui.model.ListModel import org.koitharu.kotatsu.list.ui.model.MangaListDetailedModel import org.koitharu.kotatsu.parsers.model.Manga +import org.koitharu.kotatsu.utils.ext.* +import org.koitharu.kotatsu.utils.image.CoverSizeResolver fun mangaListDetailedItemAD( coil: ImageLoader, lifecycleOwner: LifecycleOwner, clickListener: OnListItemClickListener, ) = adapterDelegateViewBinding( - { inflater, parent -> ItemMangaListDetailsBinding.inflate(inflater, parent, false) } + { inflater, parent -> ItemMangaListDetailsBinding.inflate(inflater, parent, false) }, ) { - var badge: BadgeDrawable? = null itemView.setOnClickListener { @@ -36,6 +36,7 @@ fun mangaListDetailedItemAD( binding.progressView.setPercent(item.progress, MangaListAdapter.PAYLOAD_PROGRESS in payloads) binding.imageViewCover.newImageRequest(item.coverUrl)?.run { referer(item.manga.publicUrl) + size(CoverSizeResolver(binding.imageViewCover)) placeholder(R.drawable.ic_placeholder) fallback(R.drawable.ic_placeholder) error(R.drawable.ic_placeholder) diff --git a/app/src/main/java/org/koitharu/kotatsu/list/ui/adapter/MangaListItemAD.kt b/app/src/main/java/org/koitharu/kotatsu/list/ui/adapter/MangaListItemAD.kt index 48c157ed1..fb8f5e216 100644 --- a/app/src/main/java/org/koitharu/kotatsu/list/ui/adapter/MangaListItemAD.kt +++ b/app/src/main/java/org/koitharu/kotatsu/list/ui/adapter/MangaListItemAD.kt @@ -2,7 +2,6 @@ package org.koitharu.kotatsu.list.ui.adapter import androidx.lifecycle.LifecycleOwner import coil.ImageLoader -import org.koitharu.kotatsu.utils.ext.* import com.google.android.material.badge.BadgeDrawable import com.hannesdorfmann.adapterdelegates4.dsl.adapterDelegateViewBinding import org.koitharu.kotatsu.R @@ -11,15 +10,15 @@ import org.koitharu.kotatsu.databinding.ItemMangaListBinding import org.koitharu.kotatsu.list.ui.model.ListModel import org.koitharu.kotatsu.list.ui.model.MangaListModel import org.koitharu.kotatsu.parsers.model.Manga +import org.koitharu.kotatsu.utils.ext.* fun mangaListItemAD( coil: ImageLoader, lifecycleOwner: LifecycleOwner, clickListener: OnListItemClickListener, ) = adapterDelegateViewBinding( - { inflater, parent -> ItemMangaListBinding.inflate(inflater, parent, false) } + { inflater, parent -> ItemMangaListBinding.inflate(inflater, parent, false) }, ) { - var badge: BadgeDrawable? = null itemView.setOnClickListener { diff --git a/app/src/main/java/org/koitharu/kotatsu/utils/image/CoverSizeResolver.kt b/app/src/main/java/org/koitharu/kotatsu/utils/image/CoverSizeResolver.kt new file mode 100644 index 000000000..69f61133f --- /dev/null +++ b/app/src/main/java/org/koitharu/kotatsu/utils/image/CoverSizeResolver.kt @@ -0,0 +1,83 @@ +package org.koitharu.kotatsu.utils.image + +import android.view.View +import android.view.View.OnLayoutChangeListener +import android.view.ViewGroup +import android.widget.ImageView +import coil.size.Dimension +import coil.size.Size +import coil.size.SizeResolver +import kotlin.coroutines.resume +import kotlin.math.roundToInt +import kotlinx.coroutines.CancellableContinuation +import kotlinx.coroutines.suspendCancellableCoroutine + +private const val ASPECT_RATIO_HEIGHT = 18f +private const val ASPECT_RATIO_WIDTH = 13f + +class CoverSizeResolver( + private val imageView: ImageView, +) : SizeResolver { + + override suspend fun size(): Size { + getSize()?.let { return it } + return suspendCancellableCoroutine { cont -> + val layoutListener = LayoutListener(cont) + imageView.addOnLayoutChangeListener(layoutListener) + cont.invokeOnCancellation { + imageView.removeOnLayoutChangeListener(layoutListener) + } + } + } + + private fun getSize(): Size? { + val lp = imageView.layoutParams + var width = getDimension(lp.width, imageView.width, imageView.paddingLeft + imageView.paddingRight) + var height = getDimension(lp.height, imageView.height, imageView.paddingTop + imageView.paddingBottom) + if (width == null && height == null) { + return null + } + if (height == null && width != null) { + height = Dimension((width.px * ASPECT_RATIO_HEIGHT / ASPECT_RATIO_WIDTH).roundToInt()) + } else if (width == null && height != null) { + width = Dimension((height.px * ASPECT_RATIO_WIDTH / ASPECT_RATIO_HEIGHT).roundToInt()) + } + return Size(checkNotNull(width), checkNotNull(height)) + } + + private fun getDimension(paramSize: Int, viewSize: Int, paddingSize: Int): Dimension.Pixels? { + if (paramSize == ViewGroup.LayoutParams.WRAP_CONTENT) { + return null + } + val insetParamSize = paramSize - paddingSize + if (insetParamSize > 0) { + return Dimension(insetParamSize) + } + val insetViewSize = viewSize - paddingSize + if (insetViewSize > 0) { + return Dimension(insetViewSize) + } + return null + } + + private inner class LayoutListener( + private val continuation: CancellableContinuation, + ) : OnLayoutChangeListener { + + override fun onLayoutChange( + v: View, + left: Int, + top: Int, + right: Int, + bottom: Int, + oldLeft: Int, + oldTop: Int, + oldRight: Int, + oldBottom: Int, + ) { + val size = getSize() ?: return + v.removeOnLayoutChangeListener(this) + continuation.resume(size) + } + } +} \ No newline at end of file diff --git a/app/src/main/res/layout/item_feed.xml b/app/src/main/res/layout/item_feed.xml index 1dcb660b8..69a94a29f 100644 --- a/app/src/main/res/layout/item_feed.xml +++ b/app/src/main/res/layout/item_feed.xml @@ -12,10 +12,9 @@