Fix hiding page loading indicator (close #1357)

This commit is contained in:
Koitharu
2025-04-07 08:05:27 +03:00
parent 92f6221ba0
commit fe5d37f45e
6 changed files with 42 additions and 98 deletions

View File

@@ -1,28 +0,0 @@
package org.koitharu.kotatsu.core.util
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)
onGlobalLayout()
}
fun detach() {
view.viewTreeObserver.removeOnGlobalLayoutListener(this)
}
}

View File

@@ -10,7 +10,6 @@ import androidx.appcompat.widget.ActionMenuView
import androidx.appcompat.widget.Toolbar
import androidx.core.view.children
import androidx.core.view.descendants
import androidx.core.view.isVisible
import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentManager
import androidx.recyclerview.widget.RecyclerView
@@ -155,9 +154,9 @@ fun TabLayout.setTabsEnabled(enabled: Boolean) {
fun BaseProgressIndicator<*>.showOrHide(value: Boolean) {
if (value) {
if (!isVisible) show()
show()
} else {
if (isVisible) hide()
hide()
}
}

View File

@@ -1,6 +1,9 @@
package org.koitharu.kotatsu.reader.ui.pager
import android.content.ComponentCallbacks2
import android.content.ComponentCallbacks2.TRIM_MEMORY_COMPLETE
import android.content.Context
import android.content.res.Configuration
import android.view.View
import androidx.annotation.CallSuper
import androidx.core.view.isGone
@@ -21,7 +24,6 @@ import org.koitharu.kotatsu.core.util.ext.getDisplayMessage
import org.koitharu.kotatsu.core.util.ext.isLowRamDevice
import org.koitharu.kotatsu.core.util.ext.isSerializable
import org.koitharu.kotatsu.core.util.ext.observe
import org.koitharu.kotatsu.core.util.ext.showOrHide
import org.koitharu.kotatsu.databinding.LayoutPageInfoBinding
import org.koitharu.kotatsu.parsers.util.ifZero
import org.koitharu.kotatsu.reader.domain.PageLoader
@@ -37,7 +39,7 @@ abstract class BasePageHolder<B : ViewBinding>(
networkState: NetworkState,
exceptionResolver: ExceptionResolver,
lifecycleOwner: LifecycleOwner,
) : LifecycleAwareViewHolder(binding.root, lifecycleOwner), DefaultOnImageEventListener {
) : LifecycleAwareViewHolder(binding.root, lifecycleOwner), DefaultOnImageEventListener, ComponentCallbacks2 {
protected val viewModel = PageViewModel(
loader = loader,
@@ -82,9 +84,12 @@ abstract class BasePageHolder<B : ViewBinding>(
@CallSuper
protected open fun onConfigChanged(settings: ReaderSettings) {
settings.applyBackground(itemView)
if (viewModel.state.value is PageState.Shown) {
if (settings.applyBitmapConfig(ssiv)) {
reloadImage()
} else if (viewModel.state.value is PageState.Shown) {
onReady()
}
ssiv.applyDownSampling(isResumed())
}
fun reloadImage() {
@@ -103,7 +108,7 @@ abstract class BasePageHolder<B : ViewBinding>(
override fun onCreate() {
super.onCreate()
context.registerComponentCallbacks(viewModel)
context.registerComponentCallbacks(this)
viewModel.state.observe(this, ::onStateChanged)
viewModel.settingsProducer.observe(this, ::onConfigChanged)
}
@@ -122,7 +127,7 @@ abstract class BasePageHolder<B : ViewBinding>(
}
override fun onDestroy() {
context.unregisterComponentCallbacks(viewModel)
context.unregisterComponentCallbacks(this)
super.onDestroy()
}
@@ -136,9 +141,18 @@ abstract class BasePageHolder<B : ViewBinding>(
ssiv.recycle()
}
override fun onTrimMemory(level: Int) {
// TODO
}
override fun onConfigurationChanged(newConfig: Configuration) = Unit
@Deprecated("Deprecated in Java")
final override fun onLowMemory() = onTrimMemory(TRIM_MEMORY_COMPLETE)
protected open fun onStateChanged(state: PageState) {
bindingInfo.layoutError.isVisible = state is PageState.Error
bindingInfo.progressBar.showOrHide(!state.isFinalState())
bindingInfo.progressBar.isGone = state.isFinalState()
bindingInfo.textViewStatus.isGone = state.isFinalState()
val progress = (state as? PageState.Loading)?.progress ?: -1
if (progress in 0..100) {

View File

@@ -30,17 +30,12 @@ open class PageHolder(
networkState = networkState,
exceptionResolver = exceptionResolver,
lifecycleOwner = owner,
),
ZoomControl.ZoomControlListener {
), ZoomControl.ZoomControlListener {
override val ssiv = binding.ssiv
override fun onConfigChanged(settings: ReaderSettings) {
super.onConfigChanged(settings)
if (settings.applyBitmapConfig(binding.ssiv)) {
reloadImage()
}
binding.ssiv.applyDownSampling(isResumed())
binding.textViewNumber.isVisible = settings.isPagesNumbersEnabled
}
@@ -50,11 +45,6 @@ open class PageHolder(
binding.textViewNumber.text = (data.index + 1).toString()
}
override fun onRecycled() {
super.onRecycled()
binding.ssiv.recycle()
}
override fun onReady() {
binding.ssiv.maxScale = 2f * maxOf(
binding.ssiv.width / binding.ssiv.sWidth.toFloat(),

View File

@@ -1,7 +1,5 @@
package org.koitharu.kotatsu.reader.ui.pager.vm
import android.content.ComponentCallbacks2
import android.content.res.Configuration
import android.graphics.Rect
import android.net.Uri
import androidx.annotation.WorkerThread
@@ -20,6 +18,7 @@ import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.flow.update
import kotlinx.coroutines.launch
import kotlinx.coroutines.plus
import kotlinx.coroutines.withContext
import okio.IOException
import org.koitharu.kotatsu.core.exceptions.resolve.ExceptionResolver
import org.koitharu.kotatsu.core.os.NetworkState
@@ -35,7 +34,7 @@ class PageViewModel(
private val networkState: NetworkState,
private val exceptionResolver: ExceptionResolver,
private val isWebtoon: Boolean,
) : DefaultOnImageEventListener, ComponentCallbacks2 {
) : DefaultOnImageEventListener {
private val scope = loader.loaderScope + Dispatchers.Main.immediate
private var job: Job? = null
@@ -43,12 +42,6 @@ class PageViewModel(
val state = MutableStateFlow<PageState>(PageState.Empty)
init {
scope.launch(Dispatchers.Main) { // the same as post() -- wait until child fields init
// callback.onConfigChanged()
}
}
fun isLoading() = job?.isActive == true
fun onBind(page: MangaPage) {
@@ -64,13 +57,14 @@ class PageViewModel(
job = scope.launch {
prevJob?.cancelAndJoin()
val e = (state.value as? PageState.Error)?.error
if (e != null && ExceptionResolver.Companion.canResolve(e)) {
if (!isFromUser) {
return@launch
if (e != null && ExceptionResolver.canResolve(e)) {
if (isFromUser) {
exceptionResolver.resolve(e)
}
exceptionResolver.resolve(e)
}
doLoad(page, force = true)
withContext(Dispatchers.Default) {
doLoad(page, force = true)
}
}
}
@@ -86,8 +80,12 @@ class PageViewModel(
}
override fun onImageLoaded() {
state.update {
if (it is PageState.Loaded) PageState.Shown(it.source, it.isConverted) else it
state.update { currentState ->
if (currentState is PageState.Loaded) {
PageState.Shown(currentState.source, currentState.isConverted)
} else {
currentState
}
}
}
@@ -109,18 +107,9 @@ class PageViewModel(
}
}
override fun onConfigurationChanged(newConfig: Configuration) = Unit
@Suppress("OVERRIDE_DEPRECATION")
override fun onLowMemory() = Unit
override fun onTrimMemory(level: Int) {
// callback.onTrimMemory()
}
private fun tryConvert(uri: Uri, e: Exception) {
val prevJob = job
job = scope.launch {
job = scope.launch(Dispatchers.Default) {
prevJob?.join()
state.value = PageState.Converting()
try {
@@ -143,7 +132,7 @@ class PageViewModel(
@WorkerThread
private suspend fun doLoad(data: MangaPage, force: Boolean) = coroutineScope {
state.value = PageState.Loading(null/* TODO */, -1)
state.value = PageState.Loading(null, -1)
val previewJob = launch {
val preview = loader.loadPreview(data) ?: return@launch
state.update {

View File

@@ -1,9 +1,9 @@
package org.koitharu.kotatsu.reader.ui.pager.webtoon
import android.view.View
import androidx.lifecycle.LifecycleOwner
import org.koitharu.kotatsu.core.exceptions.resolve.ExceptionResolver
import org.koitharu.kotatsu.core.os.NetworkState
import org.koitharu.kotatsu.core.util.GoneOnInvisibleListener
import org.koitharu.kotatsu.databinding.ItemPageWebtoonBinding
import org.koitharu.kotatsu.reader.domain.PageLoader
import org.koitharu.kotatsu.reader.ui.config.ReaderSettings
@@ -28,29 +28,9 @@ class WebtoonHolder(
override val ssiv = binding.ssiv
private var scrollToRestore = 0
private val goneOnInvisibleListener = GoneOnInvisibleListener(bindingInfo.progressBar)
override fun onConfigChanged(settings: ReaderSettings) {
super.onConfigChanged(settings)
if (settings.applyBitmapConfig(binding.ssiv)) {
reloadImage()
}
binding.ssiv.applyDownSampling(isResumed())
}
override fun onRecycled() {
super.onRecycled()
binding.ssiv.recycle()
}
override fun onAttachedToWindow() {
super.onAttachedToWindow()
goneOnInvisibleListener.attach()
}
override fun onDetachedFromWindow() {
super.onDetachedFromWindow()
goneOnInvisibleListener.detach()
init {
bindingInfo.progressBar.setVisibilityAfterHide(View.GONE)
}
override fun onReady() {