From ba2ed6a2ef831d9d48df5867b0bd8ffc9471fe65 Mon Sep 17 00:00:00 2001 From: Koitharu Date: Wed, 7 Feb 2024 10:25:23 +0200 Subject: [PATCH] Webtoon reader improvements --- .../ui/pager/webtoon/WebtoonImageView.kt | 32 ++++------ .../ui/pager/webtoon/WebtoonRecyclerView.kt | 61 +++++-------------- 2 files changed, 27 insertions(+), 66 deletions(-) diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/reader/ui/pager/webtoon/WebtoonImageView.kt b/app/src/main/kotlin/org/koitharu/kotatsu/reader/ui/pager/webtoon/WebtoonImageView.kt index b4a2de35c..e4f9a90f9 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/reader/ui/pager/webtoon/WebtoonImageView.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/reader/ui/pager/webtoon/WebtoonImageView.kt @@ -80,26 +80,28 @@ class WebtoonImageView @JvmOverloads constructor( val parentHeight = MeasureSpec.getSize(heightMeasureSpec) val resizeWidth = widthSpecMode != MeasureSpec.EXACTLY val resizeHeight = heightSpecMode != MeasureSpec.EXACTLY - var width = parentWidth - var height = parentHeight + var desiredWidth = parentWidth + var desiredHeight = parentHeight if (sWidth > 0 && sHeight > 0) { if (resizeWidth && resizeHeight) { - width = sWidth - height = sHeight + desiredWidth = sWidth + desiredHeight = sHeight } else if (resizeHeight) { - height = (sHeight.toDouble() / sWidth.toDouble() * width).toInt() + desiredHeight = (sHeight.toDouble() / sWidth.toDouble() * desiredWidth).roundToInt() } else if (resizeWidth) { - width = (sWidth.toDouble() / sHeight.toDouble() * height).toInt() + desiredWidth = (sWidth.toDouble() / sHeight.toDouble() * desiredHeight).roundToInt() } } - width = width.coerceAtLeast(suggestedMinimumWidth) - height = height.coerceAtLeast(suggestedMinimumHeight).coerceAtMost(parentHeight()) - setMeasuredDimension(width, height) + desiredWidth = desiredWidth.coerceAtLeast(suggestedMinimumWidth) + desiredHeight = desiredHeight.coerceAtLeast(suggestedMinimumHeight).coerceAtMost(parentHeight()) + setMeasuredDimension(desiredWidth, desiredHeight) } override fun onDownsamplingChanged() { super.onDownsamplingChanged() - adjustScale() + post { + adjustScale() + } } override fun onReady() { @@ -107,15 +109,6 @@ class WebtoonImageView @JvmOverloads constructor( adjustScale() } - override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) { - super.onSizeChanged(w, h, oldw, oldh) - if (oldh != h && oldw != 0 && oldh != 0 && isReady) { - ancestors.firstNotNullOfOrNull { it as? WebtoonRecyclerView }?.updateChildrenScroll() - } else { - return - } - } - private fun scrollToInternal(pos: Int) { minScale = width / sWidth.toFloat() maxScale = minScale @@ -128,6 +121,7 @@ class WebtoonImageView @JvmOverloads constructor( minScale = width / sWidth.toFloat() maxScale = minScale minimumScaleType = SCALE_TYPE_CUSTOM + requestLayout() } private fun parentHeight(): Int { diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/reader/ui/pager/webtoon/WebtoonRecyclerView.kt b/app/src/main/kotlin/org/koitharu/kotatsu/reader/ui/pager/webtoon/WebtoonRecyclerView.kt index 346ea2b5f..f4261786b 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/reader/ui/pager/webtoon/WebtoonRecyclerView.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/reader/ui/pager/webtoon/WebtoonRecyclerView.kt @@ -5,9 +5,9 @@ import android.util.AttributeSet import android.view.View import androidx.core.view.ViewCompat.TYPE_TOUCH import androidx.core.view.forEach -import androidx.core.view.iterator import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.RecyclerView +import java.util.Collections import java.util.LinkedList import java.util.WeakHashMap @@ -17,12 +17,11 @@ class WebtoonRecyclerView @JvmOverloads constructor( private var onPageScrollListeners = LinkedList() private val scrollDispatcher = WebtoonScrollDispatcher() - private val detachedViews = WeakHashMap() - private var isFixingScroll: Boolean = false + private val detachedViews = Collections.newSetFromMap(WeakHashMap()) override fun onChildDetachedFromWindow(child: View) { super.onChildDetachedFromWindow(child) - detachedViews[child] = Unit + detachedViews.add(child) } override fun onChildAttachedToWindow(child: View) { @@ -32,7 +31,7 @@ class WebtoonRecyclerView @JvmOverloads constructor( override fun startNestedScroll(axes: Int) = startNestedScroll(axes, TYPE_TOUCH) - override fun startNestedScroll(axes: Int, type: Int): Boolean = true + override fun startNestedScroll(axes: Int, type: Int): Boolean = childCount != 0 override fun dispatchNestedPreScroll( dx: Int, @@ -57,13 +56,6 @@ class WebtoonRecyclerView @JvmOverloads constructor( return consumedY != 0 || dy == 0 } - override fun onScrollStateChanged(state: Int) { - super.onScrollStateChanged(state) - if (state == SCROLL_STATE_IDLE) { - updateChildrenScroll() - } - } - private fun consumeVerticalScroll(dy: Int): Int { if (childCount == 0) { return 0 @@ -124,43 +116,11 @@ class WebtoonRecyclerView @JvmOverloads constructor( forEach { child -> (child as WebtoonFrameLayout).target.requestLayout() } - detachedViews.keys.forEach { child -> + detachedViews.forEach { child -> (child as WebtoonFrameLayout).target.requestLayout() } } - fun updateChildrenScroll() { - if (isFixingScroll) { - return - } - isFixingScroll = true - for (child in this) { - val ssiv = (child as WebtoonFrameLayout).target - if (adjustScroll(child, ssiv)) { - break - } - } - isFixingScroll = false - } - - private fun adjustScroll(child: View, ssiv: WebtoonImageView): Boolean = when { - child.bottom < height && ssiv.getScroll() < ssiv.getScrollRange() -> { - val distance = minOf(height - child.bottom, ssiv.getScrollRange() - ssiv.getScroll()) - scrollBy(0, -distance) - ssiv.scrollBy(distance) - true - } - - child.top > 0 && ssiv.getScroll() > 0 -> { - val distance = minOf(child.top, ssiv.getScroll()) - scrollBy(0, distance) - ssiv.scrollBy(-distance) - true - } - - else -> false - } - private class WebtoonScrollDispatcher { private var firstPos = NO_POSITION @@ -178,13 +138,20 @@ class WebtoonRecyclerView @JvmOverloads constructor( if (newFirstPos != firstPos || newLastPos != lastPos) { firstPos = newFirstPos lastPos = newLastPos - rv.onPageScrollListeners.forEach { it.onScrollChanged(rv, dy, newFirstPos, newLastPos) } + if (newFirstPos != NO_POSITION && newLastPos != NO_POSITION) { + rv.onPageScrollListeners.forEach { it.onScrollChanged(rv, dy, newFirstPos, newLastPos) } + } } } } interface OnWebtoonScrollListener { - fun onScrollChanged(recyclerView: WebtoonRecyclerView, dy: Int, firstVisiblePosition: Int, lastVisiblePosition: Int) + fun onScrollChanged( + recyclerView: WebtoonRecyclerView, + dy: Int, + firstVisiblePosition: Int, + lastVisiblePosition: Int, + ) } }