From d6781e1d14a89908d63c73d442845f2d8d620c5f Mon Sep 17 00:00:00 2001 From: Koitharu Date: Fri, 29 Jul 2022 15:20:54 +0300 Subject: [PATCH] Yet another attempt to make webtoon reader great again --- .../reader/ui/pager/standard/PageHolder.kt | 4 +++ .../ui/pager/webtoon/WebtoonFrameLayout.kt | 7 +++-- .../reader/ui/pager/webtoon/WebtoonHolder.kt | 7 +++-- .../ui/pager/webtoon/WebtoonImageView.kt | 30 +++++++++++++------ .../ui/pager/webtoon/WebtoonLayoutManager.kt | 1 + .../ui/pager/webtoon/WebtoonReaderFragment.kt | 2 +- .../ui/thumbnails/adapter/PageThumbnailAD.kt | 3 +- .../kotatsu/utils/GoneOnInvisibleListener.kt | 23 ++++++++++++++ .../koitharu/kotatsu/utils/ext/AndroidExt.kt | 9 ++++++ .../org/koitharu/kotatsu/utils/ext/ViewExt.kt | 12 +++++++- 10 files changed, 81 insertions(+), 17 deletions(-) create mode 100644 app/src/main/java/org/koitharu/kotatsu/utils/GoneOnInvisibleListener.kt diff --git a/app/src/main/java/org/koitharu/kotatsu/reader/ui/pager/standard/PageHolder.kt b/app/src/main/java/org/koitharu/kotatsu/reader/ui/pager/standard/PageHolder.kt index 58aba0ee6..a4d60c861 100644 --- a/app/src/main/java/org/koitharu/kotatsu/reader/ui/pager/standard/PageHolder.kt +++ b/app/src/main/java/org/koitharu/kotatsu/reader/ui/pager/standard/PageHolder.kt @@ -7,6 +7,8 @@ import android.view.View import androidx.core.view.isVisible import com.davemorrissey.labs.subscaleview.ImageSource import com.davemorrissey.labs.subscaleview.SubsamplingScaleImageView +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.asExecutor import org.koitharu.kotatsu.R import org.koitharu.kotatsu.core.exceptions.resolve.ExceptionResolver import org.koitharu.kotatsu.core.model.ZoomMode @@ -26,6 +28,8 @@ open class PageHolder( View.OnClickListener { init { + binding.ssiv.setExecutor(Dispatchers.Default.asExecutor()) + binding.ssiv.setEagerLoadingEnabled(!isLowRamDevice(context)) binding.ssiv.setOnImageEventListener(delegate) @Suppress("LeakingThis") bindingInfo.buttonRetry.setOnClickListener(this) diff --git a/app/src/main/java/org/koitharu/kotatsu/reader/ui/pager/webtoon/WebtoonFrameLayout.kt b/app/src/main/java/org/koitharu/kotatsu/reader/ui/pager/webtoon/WebtoonFrameLayout.kt index 2fe267156..fd1e45290 100644 --- a/app/src/main/java/org/koitharu/kotatsu/reader/ui/pager/webtoon/WebtoonFrameLayout.kt +++ b/app/src/main/java/org/koitharu/kotatsu/reader/ui/pager/webtoon/WebtoonFrameLayout.kt @@ -3,13 +3,16 @@ package org.koitharu.kotatsu.reader.ui.pager.webtoon import android.content.Context import android.util.AttributeSet import android.widget.FrameLayout +import androidx.annotation.AttrRes import org.koitharu.kotatsu.R class WebtoonFrameLayout @JvmOverloads constructor( - context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0 + context: Context, + attrs: AttributeSet? = null, + @AttrRes defStyleAttr: Int = 0, ) : FrameLayout(context, attrs, defStyleAttr) { - private val target by lazy { + private val target by lazy(LazyThreadSafetyMode.NONE) { findViewById(R.id.ssiv) } diff --git a/app/src/main/java/org/koitharu/kotatsu/reader/ui/pager/webtoon/WebtoonHolder.kt b/app/src/main/java/org/koitharu/kotatsu/reader/ui/pager/webtoon/WebtoonHolder.kt index cc4370748..4d9fc1ed8 100644 --- a/app/src/main/java/org/koitharu/kotatsu/reader/ui/pager/webtoon/WebtoonHolder.kt +++ b/app/src/main/java/org/koitharu/kotatsu/reader/ui/pager/webtoon/WebtoonHolder.kt @@ -13,14 +13,14 @@ import org.koitharu.kotatsu.databinding.ItemPageWebtoonBinding import org.koitharu.kotatsu.reader.domain.PageLoader import org.koitharu.kotatsu.reader.ui.pager.BasePageHolder import org.koitharu.kotatsu.reader.ui.pager.ReaderPage +import org.koitharu.kotatsu.utils.GoneOnInvisibleListener import org.koitharu.kotatsu.utils.ext.* - class WebtoonHolder( binding: ItemPageWebtoonBinding, loader: PageLoader, settings: AppSettings, - exceptionResolver: ExceptionResolver + exceptionResolver: ExceptionResolver, ) : BasePageHolder(binding, loader, settings, exceptionResolver), View.OnClickListener { @@ -29,6 +29,7 @@ class WebtoonHolder( init { binding.ssiv.setOnImageEventListener(delegate) bindingInfo.buttonRetry.setOnClickListener(this) + GoneOnInvisibleListener(bindingInfo.progressBar).attach() } override fun onBind(data: ReaderPage) { @@ -61,9 +62,9 @@ class WebtoonHolder( override fun onImageShowing(zoom: ZoomMode) { with(binding.ssiv) { - maxScale = 2f * width / sWidth.toFloat() setMinimumScaleType(SubsamplingScaleImageView.SCALE_TYPE_CUSTOM) minScale = width / sWidth.toFloat() + maxScale = minScale scrollTo( when { scrollToRestore != 0 -> scrollToRestore diff --git a/app/src/main/java/org/koitharu/kotatsu/reader/ui/pager/webtoon/WebtoonImageView.kt b/app/src/main/java/org/koitharu/kotatsu/reader/ui/pager/webtoon/WebtoonImageView.kt index 31396bd06..3404d2911 100644 --- a/app/src/main/java/org/koitharu/kotatsu/reader/ui/pager/webtoon/WebtoonImageView.kt +++ b/app/src/main/java/org/koitharu/kotatsu/reader/ui/pager/webtoon/WebtoonImageView.kt @@ -1,11 +1,15 @@ package org.koitharu.kotatsu.reader.ui.pager.webtoon -import android.app.Activity import android.content.Context import android.graphics.PointF import android.util.AttributeSet +import androidx.recyclerview.widget.RecyclerView import com.davemorrissey.labs.subscaleview.SubsamplingScaleImageView +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.asExecutor import org.koitharu.kotatsu.parsers.util.toIntUp +import org.koitharu.kotatsu.utils.ext.isLowRamDevice +import org.koitharu.kotatsu.utils.ext.parents private const val SCROLL_UNKNOWN = -1 @@ -15,15 +19,15 @@ class WebtoonImageView @JvmOverloads constructor( ) : SubsamplingScaleImageView(context, attr) { private val ct = PointF() - private val displayHeight = if (context is Activity) { - context.window.decorView.height - } else { - context.resources.displayMetrics.heightPixels - } private var scrollPos = 0 private var scrollRange = SCROLL_UNKNOWN + init { + setExecutor(Dispatchers.Default.asExecutor()) + setEagerLoadingEnabled(!isLowRamDevice(context)) + } + fun scrollBy(delta: Int) { val maxScroll = getScrollRange() if (maxScroll == 0) { @@ -36,6 +40,7 @@ class WebtoonImageView @JvmOverloads constructor( fun scrollTo(y: Int) { val maxScroll = getScrollRange() if (maxScroll == 0) { + resetScaleAndCenter() return } scrollToInternal(y.coerceIn(0, maxScroll)) @@ -58,8 +63,11 @@ class WebtoonImageView @JvmOverloads constructor( override fun getSuggestedMinimumHeight(): Int { var desiredHeight = super.getSuggestedMinimumHeight() - if (sHeight == 0 && desiredHeight < displayHeight) { - desiredHeight = displayHeight + if (sHeight == 0) { + val parentHeight = parentHeight() + if (desiredHeight < parentHeight) { + desiredHeight = parentHeight + } } return desiredHeight } @@ -84,7 +92,7 @@ class WebtoonImageView @JvmOverloads constructor( } } width = width.coerceAtLeast(suggestedMinimumWidth) - height = height.coerceIn(suggestedMinimumHeight, displayHeight) + height = height.coerceIn(suggestedMinimumHeight, parentHeight()) setMeasuredDimension(width, height) } @@ -101,4 +109,8 @@ class WebtoonImageView @JvmOverloads constructor( val totalHeight = (sHeight * minScale).toIntUp() scrollRange = (totalHeight - height).coerceAtLeast(0) } + + private fun parentHeight(): Int { + return parents.firstNotNullOfOrNull { it as? RecyclerView }?.height ?: 0 + } } \ No newline at end of file diff --git a/app/src/main/java/org/koitharu/kotatsu/reader/ui/pager/webtoon/WebtoonLayoutManager.kt b/app/src/main/java/org/koitharu/kotatsu/reader/ui/pager/webtoon/WebtoonLayoutManager.kt index 29f21d08e..067ada3ac 100644 --- a/app/src/main/java/org/koitharu/kotatsu/reader/ui/pager/webtoon/WebtoonLayoutManager.kt +++ b/app/src/main/java/org/koitharu/kotatsu/reader/ui/pager/webtoon/WebtoonLayoutManager.kt @@ -6,6 +6,7 @@ import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.RecyclerView import kotlin.math.sign +@Suppress("unused") class WebtoonLayoutManager : LinearLayoutManager { private var scrollDirection: Int = 0 diff --git a/app/src/main/java/org/koitharu/kotatsu/reader/ui/pager/webtoon/WebtoonReaderFragment.kt b/app/src/main/java/org/koitharu/kotatsu/reader/ui/pager/webtoon/WebtoonReaderFragment.kt index d0c25311d..751a82808 100644 --- a/app/src/main/java/org/koitharu/kotatsu/reader/ui/pager/webtoon/WebtoonReaderFragment.kt +++ b/app/src/main/java/org/koitharu/kotatsu/reader/ui/pager/webtoon/WebtoonReaderFragment.kt @@ -23,7 +23,7 @@ class WebtoonReaderFragment : BaseReader() { override fun onInflateView( inflater: LayoutInflater, - container: ViewGroup? + container: ViewGroup?, ) = FragmentReaderWebtoonBinding.inflate(inflater, container, false) override fun onViewCreated(view: View, savedInstanceState: Bundle?) { 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 8cddae963..42529810b 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 @@ -3,6 +3,7 @@ package org.koitharu.kotatsu.reader.ui.thumbnails.adapter import android.graphics.drawable.Drawable import coil.ImageLoader import coil.request.ImageRequest +import coil.size.Scale import coil.size.Size import com.google.android.material.R as materialR import com.hannesdorfmann.adapterdelegates4.dsl.adapterDelegateViewBinding @@ -24,7 +25,6 @@ fun pageThumbnailAD( ) = adapterDelegateViewBinding( { inflater, parent -> ItemPageThumbBinding.inflate(inflater, parent, false) } ) { - var job: Job? = null val gridWidth = itemView.context.resources.getDimensionPixelSize(R.dimen.preferred_grid_width) val thumbSize = Size( @@ -39,6 +39,7 @@ fun pageThumbnailAD( .data(url) .referer(item.page.referer) .size(thumbSize) + .scale(Scale.FILL) .allowRgb565(true) .build() ).drawable diff --git a/app/src/main/java/org/koitharu/kotatsu/utils/GoneOnInvisibleListener.kt b/app/src/main/java/org/koitharu/kotatsu/utils/GoneOnInvisibleListener.kt new file mode 100644 index 000000000..da4fe3f3f --- /dev/null +++ b/app/src/main/java/org/koitharu/kotatsu/utils/GoneOnInvisibleListener.kt @@ -0,0 +1,23 @@ +package org.koitharu.kotatsu.utils + +import android.view.View +import android.view.ViewTreeObserver + +/** + * ProgressIndicator become INVISIBLE instead of GONE by hide() call. + * It`s final so we need this workaround + */ +class GoneOnInvisibleListener( + private val view: View, +) : ViewTreeObserver.OnGlobalLayoutListener { + + override fun onGlobalLayout() { + if (view.visibility == View.INVISIBLE) { + view.visibility = View.GONE + } + } + + fun attach() { + view.viewTreeObserver.addOnGlobalLayoutListener(this) + } +} \ No newline at end of file diff --git a/app/src/main/java/org/koitharu/kotatsu/utils/ext/AndroidExt.kt b/app/src/main/java/org/koitharu/kotatsu/utils/ext/AndroidExt.kt index a7320ad43..7cfa80db9 100644 --- a/app/src/main/java/org/koitharu/kotatsu/utils/ext/AndroidExt.kt +++ b/app/src/main/java/org/koitharu/kotatsu/utils/ext/AndroidExt.kt @@ -1,6 +1,8 @@ package org.koitharu.kotatsu.utils.ext +import android.app.ActivityManager import android.content.Context +import android.content.Context.ACTIVITY_SERVICE import android.content.SharedPreferences import android.content.pm.ResolveInfo import android.net.ConnectivityManager @@ -27,6 +29,9 @@ import kotlinx.coroutines.suspendCancellableCoroutine val Context.connectivityManager: ConnectivityManager get() = getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager +val Context.activityManager: ActivityManager? + get() = getSystemService(ACTIVITY_SERVICE) as? ActivityManager + suspend fun ConnectivityManager.waitForNetwork(): Network { val request = NetworkRequest.Builder().build() if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { @@ -92,4 +97,8 @@ fun Lifecycle.postDelayed(runnable: Runnable, delay: Long) { delay(delay) runnable.run() } +} + +fun isLowRamDevice(context: Context): Boolean { + return context.activityManager?.isLowRamDevice ?: false } \ No newline at end of file diff --git a/app/src/main/java/org/koitharu/kotatsu/utils/ext/ViewExt.kt b/app/src/main/java/org/koitharu/kotatsu/utils/ext/ViewExt.kt index bfd3959a9..18fa66cc2 100644 --- a/app/src/main/java/org/koitharu/kotatsu/utils/ext/ViewExt.kt +++ b/app/src/main/java/org/koitharu/kotatsu/utils/ext/ViewExt.kt @@ -4,6 +4,7 @@ import android.app.Activity import android.graphics.Rect import android.view.View import android.view.ViewGroup +import android.view.ViewParent import android.view.inputmethod.InputMethodManager import androidx.core.view.children import androidx.recyclerview.widget.LinearLayoutManager @@ -138,4 +139,13 @@ fun ViewGroup.findViewsByType(clazz: Class): Sequence { } } } -} \ No newline at end of file +} + +val View.parents: Sequence + get() = sequence { + var p: ViewParent? = parent + while (p != null) { + yield(p) + p = p.parent + } + } \ No newline at end of file