This commit is contained in:
Koitharu
2025-03-01 17:07:02 +02:00
parent 7a01fdd04c
commit 7fc2d2f36f
4 changed files with 70 additions and 42 deletions

View File

@@ -1,13 +1,12 @@
package org.koitharu.kotatsu.core.ui.image
import android.view.View
import android.view.View.OnLayoutChangeListener
import android.view.ViewGroup
import android.view.ViewTreeObserver
import android.view.ViewTreeObserver.OnPreDrawListener
import android.widget.ImageView
import coil3.size.Dimension
import coil3.size.Size
import coil3.size.ViewSizeResolver
import kotlinx.coroutines.CancellableContinuation
import kotlinx.coroutines.suspendCancellableCoroutine
import kotlin.coroutines.resume
import kotlin.math.roundToInt
@@ -20,31 +19,67 @@ class CoverSizeResolver(
) : ViewSizeResolver<ImageView> {
override suspend fun size(): Size {
// Fast path: the view is already measured.
getSize()?.let { return it }
return suspendCancellableCoroutine { cont ->
val layoutListener = LayoutListener(cont)
view.addOnLayoutChangeListener(layoutListener)
cont.invokeOnCancellation {
view.removeOnLayoutChangeListener(layoutListener)
// Slow path: wait for the view to be measured.
return suspendCancellableCoroutine { continuation ->
val viewTreeObserver = view.viewTreeObserver
val preDrawListener = object : OnPreDrawListener {
private var isResumed = false
override fun onPreDraw(): Boolean {
val size = getSize()
if (size != null) {
viewTreeObserver.removePreDrawListenerSafe(this)
if (!isResumed) {
isResumed = true
continuation.resume(size)
}
}
return true
}
}
viewTreeObserver.addOnPreDrawListener(preDrawListener)
continuation.invokeOnCancellation {
viewTreeObserver.removePreDrawListenerSafe(preDrawListener)
}
}
}
private fun getSize(): Size? {
val lp = view.layoutParams
var width = getDimension(lp.width, view.width, view.paddingLeft + view.paddingRight)
var height = getDimension(lp.height, view.height, view.paddingTop + view.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())
var width = getWidth()
var height = getHeight()
when {
width == null && height == null -> {
return null
}
height == null && width != null -> {
height = Dimension((width.px * ASPECT_RATIO_HEIGHT / ASPECT_RATIO_WIDTH).roundToInt())
}
width == null && height != null -> {
width = Dimension((height.px * ASPECT_RATIO_WIDTH / ASPECT_RATIO_HEIGHT).roundToInt())
}
}
return Size(checkNotNull(width), checkNotNull(height))
}
private fun getWidth() = getDimension(
paramSize = view.layoutParams?.width ?: -1,
viewSize = view.width,
paddingSize = if (subtractPadding) view.paddingLeft + view.paddingRight else 0
)
private fun getHeight() = getDimension(
paramSize = view.layoutParams?.height ?: -1,
viewSize = view.height,
paddingSize = if (subtractPadding) view.paddingTop + view.paddingBottom else 0
)
private fun getDimension(paramSize: Int, viewSize: Int, paddingSize: Int): Dimension.Pixels? {
if (paramSize == ViewGroup.LayoutParams.WRAP_CONTENT) {
return null
@@ -60,24 +95,11 @@ class CoverSizeResolver(
return null
}
private inner class LayoutListener(
private val continuation: CancellableContinuation<Size>,
) : 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)
private fun ViewTreeObserver.removePreDrawListenerSafe(victim: OnPreDrawListener) {
if (isAlive) {
removeOnPreDrawListener(victim)
} else {
view.viewTreeObserver.removeOnPreDrawListener(victim)
}
}
}

View File

@@ -446,7 +446,7 @@ class DetailsActivity :
val manga = details.toManga()
with(viewBinding) {
textViewTitle.text = manga.title
textViewSubtitle.textAndVisible = manga.altTitle
textViewSubtitle.textAndVisible = manga.altTitles.joinToString("\n")
textViewNsfw.isVisible = manga.isNsfw
textViewDescription.text = details.description.ifNullOrEmpty { getString(R.string.no_description) }
}
@@ -561,6 +561,7 @@ class DetailsActivity :
}
private fun loadCover(imageUrl: String?) {
viewBinding.imageViewCover.isEnabled = !imageUrl.isNullOrEmpty()
val lastResult = CoilUtils.result(viewBinding.imageViewCover)
if (lastResult is SuccessResult && lastResult.request.data == imageUrl) {
return

View File

@@ -1,5 +1,6 @@
package org.koitharu.kotatsu.settings.userdata.storage
import coil3.ImageLoader
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
@@ -35,6 +36,7 @@ class StorageManageSettingsViewModel @Inject constructor(
private val cookieJar: MutableCookieJar,
private val deleteReadChaptersUseCase: DeleteReadChaptersUseCase,
private val mangaDataRepositoryProvider: Provider<MangaDataRepository>,
private val coil: ImageLoader,
) : BaseViewModel() {
val onActionDone = MutableEventFlow<ReversibleAction>()
@@ -78,6 +80,9 @@ class StorageManageSettingsViewModel @Inject constructor(
storageManager.clearCache(cache)
checkNotNull(cacheSizes[cache]).value = storageManager.computeCacheSize(cache)
loadStorageUsage()
if (cache == CacheDir.THUMBS || cache == CacheDir.FAVICONS) {
coil.memoryCache?.clear()
}
} finally {
loadingKeys.update { it - key }
}