Reader fixes
This commit is contained in:
@@ -132,7 +132,7 @@ dependencies {
|
|||||||
|
|
||||||
implementation 'io.coil-kt:coil-base:2.5.0'
|
implementation 'io.coil-kt:coil-base:2.5.0'
|
||||||
implementation 'io.coil-kt:coil-svg:2.5.0'
|
implementation 'io.coil-kt:coil-svg:2.5.0'
|
||||||
implementation 'com.github.KotatsuApp:subsampling-scale-image-view:771c8753ae'
|
implementation 'com.github.KotatsuApp:subsampling-scale-image-view:02e6d6cfe9'
|
||||||
implementation 'com.github.solkin:disk-lru-cache:1.4'
|
implementation 'com.github.solkin:disk-lru-cache:1.4'
|
||||||
implementation 'io.noties.markwon:core:4.6.2'
|
implementation 'io.noties.markwon:core:4.6.2'
|
||||||
|
|
||||||
|
|||||||
@@ -58,7 +58,7 @@ class TagsCatalogSheet : BaseAdaptiveSheet<SheetTagsBinding>(), OnListItemClickL
|
|||||||
|
|
||||||
override fun onItemClick(item: TagCatalogItem, view: View) {
|
override fun onItemClick(item: TagCatalogItem, view: View) {
|
||||||
val filter = (requireActivity() as FilterOwner).filter
|
val filter = (requireActivity() as FilterOwner).filter
|
||||||
filter.setTag(item.tag, true)
|
filter.setTag(item.tag, !item.isChecked)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onClick(v: View) {
|
override fun onClick(v: View) {
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import android.content.Context
|
|||||||
import androidx.annotation.CallSuper
|
import androidx.annotation.CallSuper
|
||||||
import androidx.lifecycle.LifecycleOwner
|
import androidx.lifecycle.LifecycleOwner
|
||||||
import androidx.viewbinding.ViewBinding
|
import androidx.viewbinding.ViewBinding
|
||||||
|
import com.davemorrissey.labs.subscaleview.SubsamplingScaleImageView
|
||||||
import org.koitharu.kotatsu.core.exceptions.resolve.ExceptionResolver
|
import org.koitharu.kotatsu.core.exceptions.resolve.ExceptionResolver
|
||||||
import org.koitharu.kotatsu.core.os.NetworkState
|
import org.koitharu.kotatsu.core.os.NetworkState
|
||||||
import org.koitharu.kotatsu.core.ui.list.lifecycle.LifecycleAwareViewHolder
|
import org.koitharu.kotatsu.core.ui.list.lifecycle.LifecycleAwareViewHolder
|
||||||
@@ -69,9 +70,11 @@ abstract class BasePageHolder<B : ViewBinding>(
|
|||||||
delegate.onRecycle()
|
delegate.onRecycle()
|
||||||
}
|
}
|
||||||
|
|
||||||
protected fun getBackgroundDownsampling() = when {
|
protected fun SubsamplingScaleImageView.applyDownsampling(isForeground: Boolean) {
|
||||||
!settings.isReaderOptimizationEnabled -> 1
|
downsampling = when {
|
||||||
context.isLowRamDevice() -> 8
|
isForeground || !settings.isReaderOptimizationEnabled -> 1
|
||||||
else -> 4
|
context.isLowRamDevice() -> 8
|
||||||
|
else -> 4
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -47,12 +47,12 @@ open class PageHolder(
|
|||||||
|
|
||||||
override fun onResume() {
|
override fun onResume() {
|
||||||
super.onResume()
|
super.onResume()
|
||||||
binding.ssiv.downsampling = 1
|
binding.ssiv.applyDownsampling(isForeground = true)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onPause() {
|
override fun onPause() {
|
||||||
super.onPause()
|
super.onPause()
|
||||||
binding.ssiv.downsampling = getBackgroundDownsampling()
|
binding.ssiv.applyDownsampling(isForeground = false)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onConfigChanged() {
|
override fun onConfigChanged() {
|
||||||
@@ -60,7 +60,7 @@ open class PageHolder(
|
|||||||
if (settings.applyBitmapConfig(binding.ssiv)) {
|
if (settings.applyBitmapConfig(binding.ssiv)) {
|
||||||
delegate.reload()
|
delegate.reload()
|
||||||
}
|
}
|
||||||
binding.ssiv.downsampling = if (isResumed()) 1 else getBackgroundDownsampling()
|
binding.ssiv.applyDownsampling(isResumed())
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressLint("SetTextI18n")
|
@SuppressLint("SetTextI18n")
|
||||||
|
|||||||
@@ -5,7 +5,6 @@ import android.view.View
|
|||||||
import androidx.core.view.isVisible
|
import androidx.core.view.isVisible
|
||||||
import androidx.lifecycle.LifecycleOwner
|
import androidx.lifecycle.LifecycleOwner
|
||||||
import com.davemorrissey.labs.subscaleview.ImageSource
|
import com.davemorrissey.labs.subscaleview.ImageSource
|
||||||
import com.davemorrissey.labs.subscaleview.SubsamplingScaleImageView
|
|
||||||
import org.koitharu.kotatsu.R
|
import org.koitharu.kotatsu.R
|
||||||
import org.koitharu.kotatsu.core.exceptions.resolve.ExceptionResolver
|
import org.koitharu.kotatsu.core.exceptions.resolve.ExceptionResolver
|
||||||
import org.koitharu.kotatsu.core.os.NetworkState
|
import org.koitharu.kotatsu.core.os.NetworkState
|
||||||
@@ -38,22 +37,22 @@ class WebtoonHolder(
|
|||||||
bindingInfo.buttonErrorDetails.setOnClickListener(this)
|
bindingInfo.buttonErrorDetails.setOnClickListener(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun onResume() {
|
||||||
|
super.onResume()
|
||||||
|
binding.ssiv.applyDownsampling(isForeground = true)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onPause() {
|
||||||
|
super.onPause()
|
||||||
|
binding.ssiv.applyDownsampling(isForeground = false)
|
||||||
|
}
|
||||||
|
|
||||||
override fun onConfigChanged() {
|
override fun onConfigChanged() {
|
||||||
super.onConfigChanged()
|
super.onConfigChanged()
|
||||||
if (settings.applyBitmapConfig(binding.ssiv)) {
|
if (settings.applyBitmapConfig(binding.ssiv)) {
|
||||||
delegate.reload()
|
delegate.reload()
|
||||||
}
|
}
|
||||||
// FIXME binding.ssiv.downsampling = if (isResumed()) 1 else getBackgroundDownsampling()
|
binding.ssiv.applyDownsampling(isResumed())
|
||||||
}
|
|
||||||
|
|
||||||
override fun onResume() {
|
|
||||||
super.onResume()
|
|
||||||
binding.ssiv.downsampling = 1
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onPause() {
|
|
||||||
super.onPause()
|
|
||||||
// FIXME binding.ssiv.downsampling = getBackgroundDownsampling()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onBind(data: ReaderPage) {
|
override fun onBind(data: ReaderPage) {
|
||||||
@@ -97,9 +96,6 @@ class WebtoonHolder(
|
|||||||
override fun onImageShowing(settings: ReaderSettings) {
|
override fun onImageShowing(settings: ReaderSettings) {
|
||||||
binding.ssiv.colorFilter = settings.colorFilter?.toColorFilter()
|
binding.ssiv.colorFilter = settings.colorFilter?.toColorFilter()
|
||||||
with(binding.ssiv) {
|
with(binding.ssiv) {
|
||||||
minimumScaleType = SubsamplingScaleImageView.SCALE_TYPE_CUSTOM
|
|
||||||
minScale = width / sWidth.toFloat()
|
|
||||||
maxScale = minScale
|
|
||||||
scrollTo(
|
scrollTo(
|
||||||
when {
|
when {
|
||||||
scrollToRestore != 0 -> scrollToRestore
|
scrollToRestore != 0 -> scrollToRestore
|
||||||
|
|||||||
@@ -88,6 +88,18 @@ class WebtoonImageView @JvmOverloads constructor(
|
|||||||
setMeasuredDimension(width, height)
|
setMeasuredDimension(width, height)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun onDownsamplingChanged() {
|
||||||
|
super.onDownsamplingChanged()
|
||||||
|
adjustScale()
|
||||||
|
computeScrollRange()
|
||||||
|
ancestors.firstNotNullOfOrNull { it as? WebtoonRecyclerView }?.updateChildrenScroll()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onReady() {
|
||||||
|
super.onReady()
|
||||||
|
adjustScale()
|
||||||
|
}
|
||||||
|
|
||||||
override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) {
|
override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) {
|
||||||
super.onSizeChanged(w, h, oldw, oldh)
|
super.onSizeChanged(w, h, oldw, oldh)
|
||||||
if (oldh == h || oldw == 0 || oldh == 0 || scrollRange == SCROLL_UNKNOWN) return
|
if (oldh == h || oldw == 0 || oldh == 0 || scrollRange == SCROLL_UNKNOWN) return
|
||||||
@@ -101,6 +113,8 @@ class WebtoonImageView @JvmOverloads constructor(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun scrollToInternal(pos: Int) {
|
private fun scrollToInternal(pos: Int) {
|
||||||
|
minScale = width / sWidth.toFloat()
|
||||||
|
maxScale = minScale
|
||||||
scrollPos = pos
|
scrollPos = pos
|
||||||
ct.set(sWidth / 2f, (height / 2f + pos.toFloat()) / minScale)
|
ct.set(sWidth / 2f, (height / 2f + pos.toFloat()) / minScale)
|
||||||
setScaleAndCenter(minScale, ct)
|
setScaleAndCenter(minScale, ct)
|
||||||
@@ -114,6 +128,12 @@ class WebtoonImageView @JvmOverloads constructor(
|
|||||||
scrollRange = (totalHeight - height).coerceAtLeast(0)
|
scrollRange = (totalHeight - height).coerceAtLeast(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun adjustScale() {
|
||||||
|
minScale = width / sWidth.toFloat()
|
||||||
|
maxScale = minScale
|
||||||
|
minimumScaleType = SCALE_TYPE_CUSTOM
|
||||||
|
}
|
||||||
|
|
||||||
private fun parentHeight(): Int {
|
private fun parentHeight(): Int {
|
||||||
return ancestors.firstNotNullOfOrNull { it as? RecyclerView }?.height ?: 0
|
return ancestors.firstNotNullOfOrNull { it as? RecyclerView }?.height ?: 0
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,9 +3,11 @@ package org.koitharu.kotatsu.reader.ui.pager.webtoon
|
|||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.util.AttributeSet
|
import android.util.AttributeSet
|
||||||
import android.view.View
|
import android.view.View
|
||||||
|
import android.widget.Toast
|
||||||
import androidx.core.view.ViewCompat.TYPE_TOUCH
|
import androidx.core.view.ViewCompat.TYPE_TOUCH
|
||||||
import androidx.core.view.forEach
|
import androidx.core.view.forEach
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
|
import org.koitharu.kotatsu.BuildConfig
|
||||||
import org.koitharu.kotatsu.core.util.ext.findCenterViewPosition
|
import org.koitharu.kotatsu.core.util.ext.findCenterViewPosition
|
||||||
import java.util.LinkedList
|
import java.util.LinkedList
|
||||||
import java.util.WeakHashMap
|
import java.util.WeakHashMap
|
||||||
@@ -104,12 +106,16 @@ class WebtoonRecyclerView @JvmOverloads constructor(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun notifyScrollChanged(dy: Int) {
|
private fun notifyScrollChanged(dy: Int) {
|
||||||
|
updateChildrenScroll()
|
||||||
val listeners = onPageScrollListeners
|
val listeners = onPageScrollListeners
|
||||||
if (listeners.isNullOrEmpty()) {
|
if (listeners.isNullOrEmpty()) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
val centerPosition = findCenterViewPosition()
|
val centerPosition = findCenterViewPosition()
|
||||||
listeners.forEach { it.dispatchScroll(this, dy, centerPosition) }
|
listeners.forEach { it.dispatchScroll(this, dy, centerPosition) }
|
||||||
|
if (BuildConfig.DEBUG) {
|
||||||
|
validateLayout()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun relayoutChildren() {
|
fun relayoutChildren() {
|
||||||
@@ -121,6 +127,32 @@ class WebtoonRecyclerView @JvmOverloads constructor(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun updateChildrenScroll() {
|
||||||
|
forEach { child ->
|
||||||
|
val ssiv = (child as WebtoonFrameLayout).target
|
||||||
|
when {
|
||||||
|
child.top < 0 -> ssiv.scrollTo(ssiv.getScrollRange())
|
||||||
|
child.top > 0 -> ssiv.scrollTo(0)
|
||||||
|
else -> ssiv.scrollBy(0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun validateLayout() {
|
||||||
|
forEach { child ->
|
||||||
|
val ssiv = (child as WebtoonFrameLayout).target
|
||||||
|
val scroll = ssiv.getScroll()
|
||||||
|
val assertion = when {
|
||||||
|
child.top < 0 -> scroll == ssiv.getScrollRange()
|
||||||
|
child.top > 0 -> scroll == 0
|
||||||
|
else -> true
|
||||||
|
}
|
||||||
|
if (!assertion) {
|
||||||
|
Toast.makeText(context, "Scroll = $scroll for view with top: ${child.top}", Toast.LENGTH_SHORT).show()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
abstract class OnPageScrollListener {
|
abstract class OnPageScrollListener {
|
||||||
|
|
||||||
private var lastPosition = NO_POSITION
|
private var lastPosition = NO_POSITION
|
||||||
|
|||||||
Reference in New Issue
Block a user