Auto refresh page on connection restored

This commit is contained in:
Koitharu
2022-11-17 19:02:20 +02:00
parent c896ac72e8
commit b4eb8d56a6
14 changed files with 100 additions and 23 deletions

View File

@@ -6,9 +6,6 @@ import androidx.activity.result.ActivityResultLauncher
import androidx.annotation.StringRes
import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentActivity
import kotlin.coroutines.Continuation
import kotlin.coroutines.resume
import kotlin.coroutines.suspendCoroutine
import kotlinx.coroutines.suspendCancellableCoroutine
import org.koitharu.kotatsu.R
import org.koitharu.kotatsu.browser.BrowserActivity
@@ -20,6 +17,9 @@ import org.koitharu.kotatsu.parsers.model.MangaSource
import org.koitharu.kotatsu.settings.sources.auth.SourceAuthActivity
import org.koitharu.kotatsu.utils.TaggedActivityResult
import org.koitharu.kotatsu.utils.isSuccess
import kotlin.coroutines.Continuation
import kotlin.coroutines.resume
import kotlin.coroutines.suspendCoroutine
class ExceptionResolver private constructor(
private val activity: FragmentActivity?,
@@ -49,6 +49,7 @@ class ExceptionResolver private constructor(
openInBrowser(e.url)
false
}
else -> false
}

View File

@@ -12,6 +12,7 @@ import kotlinx.coroutines.channels.trySendBlocking
import kotlinx.coroutines.flow.FlowCollector
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.callbackFlow
import kotlinx.coroutines.flow.first
import org.koitharu.kotatsu.utils.ext.connectivityManager
import org.koitharu.kotatsu.utils.ext.isNetworkAvailable
import javax.inject.Inject
@@ -37,6 +38,13 @@ class NetworkStateObserver @Inject constructor(
}
}
suspend fun awaitForConnection(): Unit {
if (value) {
return
}
first { it }
}
private fun observeImpl() = callbackFlow<Boolean> {
val request = NetworkRequest.Builder().build()
val callback = FlowNetworkCallback(this)

View File

@@ -5,6 +5,7 @@ import androidx.annotation.CallSuper
import androidx.recyclerview.widget.RecyclerView
import androidx.viewbinding.ViewBinding
import org.koitharu.kotatsu.core.exceptions.resolve.ExceptionResolver
import org.koitharu.kotatsu.core.os.NetworkStateObserver
import org.koitharu.kotatsu.databinding.LayoutPageInfoBinding
import org.koitharu.kotatsu.reader.domain.PageLoader
import org.koitharu.kotatsu.reader.ui.config.ReaderSettings
@@ -13,11 +14,12 @@ abstract class BasePageHolder<B : ViewBinding>(
protected val binding: B,
loader: PageLoader,
settings: ReaderSettings,
networkStateObserver: NetworkStateObserver,
exceptionResolver: ExceptionResolver,
) : RecyclerView.ViewHolder(binding.root), PageHolderDelegate.Callback {
@Suppress("LeakingThis")
protected val delegate = PageHolderDelegate(loader, settings, this, exceptionResolver)
protected val delegate = PageHolderDelegate(loader, settings, this, networkStateObserver, exceptionResolver)
protected val bindingInfo = LayoutPageInfoBinding.bind(binding.root)
val context: Context

View File

@@ -4,17 +4,19 @@ import android.view.ViewGroup
import androidx.recyclerview.widget.AsyncListDiffer
import androidx.recyclerview.widget.DiffUtil
import androidx.recyclerview.widget.RecyclerView
import kotlin.coroutines.resume
import kotlin.coroutines.suspendCoroutine
import org.koitharu.kotatsu.core.exceptions.resolve.ExceptionResolver
import org.koitharu.kotatsu.core.os.NetworkStateObserver
import org.koitharu.kotatsu.reader.domain.PageLoader
import org.koitharu.kotatsu.reader.ui.config.ReaderSettings
import org.koitharu.kotatsu.utils.ext.resetTransformations
import kotlin.coroutines.resume
import kotlin.coroutines.suspendCoroutine
@Suppress("LeakingThis")
abstract class BaseReaderAdapter<H : BasePageHolder<*>>(
private val loader: PageLoader,
private val readerSettings: ReaderSettings,
private val networkState: NetworkStateObserver,
private val exceptionResolver: ExceptionResolver,
) : RecyclerView.Adapter<H>() {
@@ -56,9 +58,9 @@ abstract class BaseReaderAdapter<H : BasePageHolder<*>>(
final override fun onCreateViewHolder(
parent: ViewGroup,
viewType: Int,
): H = onCreateViewHolder(parent, loader, readerSettings, exceptionResolver)
): H = onCreateViewHolder(parent, loader, readerSettings, networkState, exceptionResolver)
suspend fun setItems(items: List<ReaderPage>) = suspendCoroutine<Unit> { cont ->
suspend fun setItems(items: List<ReaderPage>) = suspendCoroutine { cont ->
differ.submitList(items) {
cont.resume(Unit)
}
@@ -68,6 +70,7 @@ abstract class BaseReaderAdapter<H : BasePageHolder<*>>(
parent: ViewGroup,
loader: PageLoader,
settings: ReaderSettings,
networkState: NetworkStateObserver,
exceptionResolver: ExceptionResolver,
): H

View File

@@ -17,6 +17,7 @@ import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.launch
import kotlinx.coroutines.plus
import org.koitharu.kotatsu.core.exceptions.resolve.ExceptionResolver
import org.koitharu.kotatsu.core.os.NetworkStateObserver
import org.koitharu.kotatsu.parsers.model.MangaPage
import org.koitharu.kotatsu.reader.domain.PageLoader
import org.koitharu.kotatsu.reader.ui.config.ReaderSettings
@@ -27,6 +28,7 @@ class PageHolderDelegate(
private val loader: PageLoader,
private val readerSettings: ReaderSettings,
private val callback: Callback,
private val networkState: NetworkStateObserver,
private val exceptionResolver: ExceptionResolver,
) : DefaultOnImageEventListener, Observer<ReaderSettings> {
@@ -139,6 +141,10 @@ class PageHolderDelegate(
state = State.ERROR
error = e
callback.onError(e)
if (e is IOException && !networkState.value) {
networkState.awaitForConnection()
retry(data)
}
}
}

View File

@@ -6,6 +6,7 @@ import android.widget.FrameLayout
import com.davemorrissey.labs.subscaleview.SubsamplingScaleImageView
import org.koitharu.kotatsu.core.exceptions.resolve.ExceptionResolver
import org.koitharu.kotatsu.core.model.ZoomMode
import org.koitharu.kotatsu.core.os.NetworkStateObserver
import org.koitharu.kotatsu.databinding.ItemPageBinding
import org.koitharu.kotatsu.reader.domain.PageLoader
import org.koitharu.kotatsu.reader.ui.config.ReaderSettings
@@ -15,8 +16,9 @@ class ReversedPageHolder(
binding: ItemPageBinding,
loader: PageLoader,
settings: ReaderSettings,
networkState: NetworkStateObserver,
exceptionResolver: ExceptionResolver,
) : PageHolder(binding, loader, settings, exceptionResolver) {
) : PageHolder(binding, loader, settings, networkState, exceptionResolver) {
init {
(binding.textViewNumber.layoutParams as FrameLayout.LayoutParams)
@@ -35,6 +37,7 @@ class ReversedPageHolder(
minimumScaleType = SubsamplingScaleImageView.SCALE_TYPE_CENTER_INSIDE
resetScaleAndCenter()
}
ZoomMode.FIT_HEIGHT -> {
minimumScaleType = SubsamplingScaleImageView.SCALE_TYPE_CUSTOM
minScale = height / sHeight.toFloat()
@@ -43,6 +46,7 @@ class ReversedPageHolder(
PointF(sWidth.toFloat(), sHeight / 2f),
)
}
ZoomMode.FIT_WIDTH -> {
minimumScaleType = SubsamplingScaleImageView.SCALE_TYPE_CUSTOM
minScale = width / sWidth.toFloat()
@@ -51,6 +55,7 @@ class ReversedPageHolder(
PointF(sWidth / 2f, 0f),
)
}
ZoomMode.KEEP_START -> {
minimumScaleType = SubsamplingScaleImageView.SCALE_TYPE_CENTER_INSIDE
setScaleAndCenter(

View File

@@ -3,6 +3,7 @@ package org.koitharu.kotatsu.reader.ui.pager.reversed
import android.view.LayoutInflater
import android.view.ViewGroup
import org.koitharu.kotatsu.core.exceptions.resolve.ExceptionResolver
import org.koitharu.kotatsu.core.os.NetworkStateObserver
import org.koitharu.kotatsu.databinding.ItemPageBinding
import org.koitharu.kotatsu.reader.domain.PageLoader
import org.koitharu.kotatsu.reader.ui.config.ReaderSettings
@@ -11,18 +12,21 @@ import org.koitharu.kotatsu.reader.ui.pager.BaseReaderAdapter
class ReversedPagesAdapter(
loader: PageLoader,
settings: ReaderSettings,
networkState: NetworkStateObserver,
exceptionResolver: ExceptionResolver,
) : BaseReaderAdapter<ReversedPageHolder>(loader, settings, exceptionResolver) {
) : BaseReaderAdapter<ReversedPageHolder>(loader, settings, networkState, exceptionResolver) {
override fun onCreateViewHolder(
parent: ViewGroup,
loader: PageLoader,
settings: ReaderSettings,
networkState: NetworkStateObserver,
exceptionResolver: ExceptionResolver,
) = ReversedPageHolder(
binding = ItemPageBinding.inflate(LayoutInflater.from(parent.context), parent, false),
loader = loader,
settings = settings,
networkState = networkState,
exceptionResolver = exceptionResolver,
)
}

View File

@@ -7,8 +7,8 @@ import android.view.View
import android.view.ViewGroup
import androidx.core.view.children
import dagger.hilt.android.AndroidEntryPoint
import kotlin.math.absoluteValue
import kotlinx.coroutines.async
import org.koitharu.kotatsu.core.os.NetworkStateObserver
import org.koitharu.kotatsu.databinding.FragmentReaderStandardBinding
import org.koitharu.kotatsu.reader.ui.ReaderState
import org.koitharu.kotatsu.reader.ui.pager.BaseReader
@@ -19,10 +19,15 @@ import org.koitharu.kotatsu.utils.ext.doOnPageChanged
import org.koitharu.kotatsu.utils.ext.recyclerView
import org.koitharu.kotatsu.utils.ext.resetTransformations
import org.koitharu.kotatsu.utils.ext.viewLifecycleScope
import javax.inject.Inject
import kotlin.math.absoluteValue
@AndroidEntryPoint
class ReversedReaderFragment : BaseReader<FragmentReaderStandardBinding>() {
@Inject
lateinit var networkStateObserver: NetworkStateObserver
private var pagerAdapter: ReversedPagesAdapter? = null
override fun onInflateView(
@@ -33,7 +38,12 @@ class ReversedReaderFragment : BaseReader<FragmentReaderStandardBinding>() {
@SuppressLint("NotifyDataSetChanged")
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
pagerAdapter = ReversedPagesAdapter(viewModel.pageLoader, viewModel.readerSettings, exceptionResolver)
pagerAdapter = ReversedPagesAdapter(
viewModel.pageLoader,
viewModel.readerSettings,
networkStateObserver,
exceptionResolver,
)
with(binding.pager) {
adapter = pagerAdapter
offscreenPageLimit = 2
@@ -44,8 +54,8 @@ class ReversedReaderFragment : BaseReader<FragmentReaderStandardBinding>() {
val transformer = if (it) ReversedPageAnimTransformer() else null
binding.pager.setPageTransformer(transformer)
if (transformer == null) {
binding.pager.recyclerView?.children?.forEach {
it.resetTransformations()
binding.pager.recyclerView?.children?.forEach { v ->
v.resetTransformations()
}
}
}

View File

@@ -10,6 +10,7 @@ import com.davemorrissey.labs.subscaleview.SubsamplingScaleImageView
import org.koitharu.kotatsu.R
import org.koitharu.kotatsu.core.exceptions.resolve.ExceptionResolver
import org.koitharu.kotatsu.core.model.ZoomMode
import org.koitharu.kotatsu.core.os.NetworkStateObserver
import org.koitharu.kotatsu.databinding.ItemPageBinding
import org.koitharu.kotatsu.reader.domain.PageLoader
import org.koitharu.kotatsu.reader.ui.config.ReaderSettings
@@ -21,8 +22,9 @@ open class PageHolder(
binding: ItemPageBinding,
loader: PageLoader,
settings: ReaderSettings,
networkState: NetworkStateObserver,
exceptionResolver: ExceptionResolver,
) : BasePageHolder<ItemPageBinding>(binding, loader, settings, exceptionResolver),
) : BasePageHolder<ItemPageBinding>(binding, loader, settings, networkState, exceptionResolver),
View.OnClickListener {
init {
@@ -74,6 +76,7 @@ open class PageHolder(
binding.ssiv.minimumScaleType = SubsamplingScaleImageView.SCALE_TYPE_CENTER_INSIDE
binding.ssiv.resetScaleAndCenter()
}
ZoomMode.FIT_HEIGHT -> {
binding.ssiv.minimumScaleType = SubsamplingScaleImageView.SCALE_TYPE_CUSTOM
binding.ssiv.minScale = binding.ssiv.height / binding.ssiv.sHeight.toFloat()
@@ -82,6 +85,7 @@ open class PageHolder(
PointF(0f, binding.ssiv.sHeight / 2f),
)
}
ZoomMode.FIT_WIDTH -> {
binding.ssiv.minimumScaleType = SubsamplingScaleImageView.SCALE_TYPE_CUSTOM
binding.ssiv.minScale = binding.ssiv.width / binding.ssiv.sWidth.toFloat()
@@ -90,6 +94,7 @@ open class PageHolder(
PointF(binding.ssiv.sWidth / 2f, 0f),
)
}
ZoomMode.KEEP_START -> {
binding.ssiv.minimumScaleType = SubsamplingScaleImageView.SCALE_TYPE_CENTER_INSIDE
binding.ssiv.setScaleAndCenter(

View File

@@ -7,8 +7,8 @@ import android.view.View
import android.view.ViewGroup
import androidx.core.view.children
import dagger.hilt.android.AndroidEntryPoint
import kotlin.math.absoluteValue
import kotlinx.coroutines.async
import org.koitharu.kotatsu.core.os.NetworkStateObserver
import org.koitharu.kotatsu.databinding.FragmentReaderStandardBinding
import org.koitharu.kotatsu.reader.ui.ReaderState
import org.koitharu.kotatsu.reader.ui.pager.BaseReader
@@ -18,10 +18,15 @@ import org.koitharu.kotatsu.utils.ext.doOnPageChanged
import org.koitharu.kotatsu.utils.ext.recyclerView
import org.koitharu.kotatsu.utils.ext.resetTransformations
import org.koitharu.kotatsu.utils.ext.viewLifecycleScope
import javax.inject.Inject
import kotlin.math.absoluteValue
@AndroidEntryPoint
class PagerReaderFragment : BaseReader<FragmentReaderStandardBinding>() {
@Inject
lateinit var networkStateObserver: NetworkStateObserver
private var pagesAdapter: PagesAdapter? = null
override fun onInflateView(
@@ -32,7 +37,12 @@ class PagerReaderFragment : BaseReader<FragmentReaderStandardBinding>() {
@SuppressLint("NotifyDataSetChanged")
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
pagesAdapter = PagesAdapter(viewModel.pageLoader, viewModel.readerSettings, exceptionResolver)
pagesAdapter = PagesAdapter(
viewModel.pageLoader,
viewModel.readerSettings,
networkStateObserver,
exceptionResolver,
)
with(binding.pager) {
adapter = pagesAdapter
offscreenPageLimit = 2

View File

@@ -3,6 +3,7 @@ package org.koitharu.kotatsu.reader.ui.pager.standard
import android.view.LayoutInflater
import android.view.ViewGroup
import org.koitharu.kotatsu.core.exceptions.resolve.ExceptionResolver
import org.koitharu.kotatsu.core.os.NetworkStateObserver
import org.koitharu.kotatsu.databinding.ItemPageBinding
import org.koitharu.kotatsu.reader.domain.PageLoader
import org.koitharu.kotatsu.reader.ui.config.ReaderSettings
@@ -11,18 +12,21 @@ import org.koitharu.kotatsu.reader.ui.pager.BaseReaderAdapter
class PagesAdapter(
loader: PageLoader,
settings: ReaderSettings,
networkStateObserver: NetworkStateObserver,
exceptionResolver: ExceptionResolver,
) : BaseReaderAdapter<PageHolder>(loader, settings, exceptionResolver) {
) : BaseReaderAdapter<PageHolder>(loader, settings, networkStateObserver, exceptionResolver) {
override fun onCreateViewHolder(
parent: ViewGroup,
loader: PageLoader,
settings: ReaderSettings,
networkState: NetworkStateObserver,
exceptionResolver: ExceptionResolver,
) = PageHolder(
binding = ItemPageBinding.inflate(LayoutInflater.from(parent.context), parent, false),
loader = loader,
settings = settings,
networkState = networkState,
exceptionResolver = exceptionResolver,
)
}

View File

@@ -3,7 +3,7 @@ package org.koitharu.kotatsu.reader.ui.pager.webtoon
import android.view.LayoutInflater
import android.view.ViewGroup
import org.koitharu.kotatsu.core.exceptions.resolve.ExceptionResolver
import org.koitharu.kotatsu.core.prefs.AppSettings
import org.koitharu.kotatsu.core.os.NetworkStateObserver
import org.koitharu.kotatsu.databinding.ItemPageWebtoonBinding
import org.koitharu.kotatsu.reader.domain.PageLoader
import org.koitharu.kotatsu.reader.ui.config.ReaderSettings
@@ -12,13 +12,15 @@ import org.koitharu.kotatsu.reader.ui.pager.BaseReaderAdapter
class WebtoonAdapter(
loader: PageLoader,
settings: ReaderSettings,
networkState: NetworkStateObserver,
exceptionResolver: ExceptionResolver,
) : BaseReaderAdapter<WebtoonHolder>(loader, settings, exceptionResolver) {
) : BaseReaderAdapter<WebtoonHolder>(loader, settings, networkState, exceptionResolver) {
override fun onCreateViewHolder(
parent: ViewGroup,
loader: PageLoader,
settings: ReaderSettings,
networkState: NetworkStateObserver,
exceptionResolver: ExceptionResolver,
) = WebtoonHolder(
binding = ItemPageWebtoonBinding.inflate(
@@ -28,6 +30,7 @@ class WebtoonAdapter(
),
loader = loader,
settings = settings,
networkState = networkState,
exceptionResolver = exceptionResolver,
)
}

View File

@@ -8,20 +8,26 @@ import com.davemorrissey.labs.subscaleview.SubsamplingScaleImageView
import com.davemorrissey.labs.subscaleview.decoder.SkiaPooledImageRegionDecoder
import org.koitharu.kotatsu.R
import org.koitharu.kotatsu.core.exceptions.resolve.ExceptionResolver
import org.koitharu.kotatsu.core.os.NetworkStateObserver
import org.koitharu.kotatsu.databinding.ItemPageWebtoonBinding
import org.koitharu.kotatsu.reader.domain.PageLoader
import org.koitharu.kotatsu.reader.ui.config.ReaderSettings
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.*
import org.koitharu.kotatsu.utils.ext.getDisplayMessage
import org.koitharu.kotatsu.utils.ext.hideCompat
import org.koitharu.kotatsu.utils.ext.ifZero
import org.koitharu.kotatsu.utils.ext.setProgressCompat
import org.koitharu.kotatsu.utils.ext.showCompat
class WebtoonHolder(
binding: ItemPageWebtoonBinding,
loader: PageLoader,
settings: ReaderSettings,
networkState: NetworkStateObserver,
exceptionResolver: ExceptionResolver,
) : BasePageHolder<ItemPageWebtoonBinding>(binding, loader, settings, exceptionResolver),
) : BasePageHolder<ItemPageWebtoonBinding>(binding, loader, settings, networkState, exceptionResolver),
View.OnClickListener {
private var scrollToRestore = 0

View File

@@ -7,6 +7,7 @@ import android.view.ViewGroup
import android.view.animation.AccelerateDecelerateInterpolator
import dagger.hilt.android.AndroidEntryPoint
import kotlinx.coroutines.async
import org.koitharu.kotatsu.core.os.NetworkStateObserver
import org.koitharu.kotatsu.databinding.FragmentReaderWebtoonBinding
import org.koitharu.kotatsu.reader.ui.ReaderState
import org.koitharu.kotatsu.reader.ui.pager.BaseReader
@@ -15,10 +16,14 @@ import org.koitharu.kotatsu.reader.ui.pager.ReaderPage
import org.koitharu.kotatsu.utils.ext.findCenterViewPosition
import org.koitharu.kotatsu.utils.ext.firstVisibleItemPosition
import org.koitharu.kotatsu.utils.ext.viewLifecycleScope
import javax.inject.Inject
@AndroidEntryPoint
class WebtoonReaderFragment : BaseReader<FragmentReaderWebtoonBinding>() {
@Inject
lateinit var networkStateObserver: NetworkStateObserver
private val scrollInterpolator = AccelerateDecelerateInterpolator()
private var webtoonAdapter: WebtoonAdapter? = null
@@ -29,7 +34,12 @@ class WebtoonReaderFragment : BaseReader<FragmentReaderWebtoonBinding>() {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
webtoonAdapter = WebtoonAdapter(viewModel.pageLoader, viewModel.readerSettings, exceptionResolver)
webtoonAdapter = WebtoonAdapter(
viewModel.pageLoader,
viewModel.readerSettings,
networkStateObserver,
exceptionResolver,
)
with(binding.recyclerView) {
setHasFixedSize(true)
adapter = webtoonAdapter