Misc fixes

This commit is contained in:
Koitharu
2023-11-25 09:15:57 +02:00
parent 880dd6da27
commit acba312e8d
10 changed files with 62 additions and 25 deletions

View File

@@ -16,4 +16,8 @@ class PagerLifecycleDispatcher(
(wh as? LifecycleAwareViewHolder)?.setIsCurrent(wh.absoluteAdapterPosition == position)
}
}
fun invalidate() {
onPageSelected(pager.currentItem)
}
}

View File

@@ -12,6 +12,10 @@ class RecyclerViewLifecycleDispatcher : RecyclerView.OnScrollListener() {
override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
super.onScrolled(recyclerView, dx, dy)
invalidate(recyclerView)
}
fun invalidate(recyclerView: RecyclerView) {
val lm = recyclerView.layoutManager as? LinearLayoutManager ?: return
val first = lm.findFirstVisibleItemPosition()
val last = lm.findLastVisibleItemPosition()

View File

@@ -1,6 +1,7 @@
package org.koitharu.kotatsu.local.data
import android.net.Uri
import org.koitharu.kotatsu.core.util.ext.URI_SCHEME_ZIP
import java.io.File
private fun isCbzExtension(ext: String?): Boolean {
@@ -12,6 +13,8 @@ fun hasCbzExtension(string: String): Boolean {
return isCbzExtension(ext)
}
fun hasCbzExtension(file: File) = isCbzExtension(file.extension)
fun File.hasCbzExtension() = isCbzExtension(extension)
fun isCbzUri(uri: Uri) = isCbzExtension(uri.scheme)
fun Uri.isZipUri() = scheme.let {
it == URI_SCHEME_ZIP || it == "cbz" || it == "zip"
}

View File

@@ -121,13 +121,13 @@ class LocalMangaDirInput(root: File) : LocalMangaInput(root) {
private fun String.toHumanReadable() = replace("_", " ").toCamelCase()
private fun getChaptersFiles(): List<File> = root.walkCompat()
.filter { hasCbzExtension(it) }
.filter { it.hasCbzExtension() }
.toListSorted(compareBy(AlphanumComparator()) { it.name })
private fun findFirstImageEntry(): String? {
return root.walkCompat().firstOrNull { hasImageExtension(it) }?.toUri()?.toString()
?: run {
val cbz = root.walkCompat().firstOrNull { hasCbzExtension(it) } ?: return null
val cbz = root.walkCompat().firstOrNull { it.hasCbzExtension() } ?: return null
ZipFile(cbz).use { zip ->
zip.entries().asSequence()
.firstOrNull { !it.isDirectory && hasImageExtension(it.name) }

View File

@@ -45,7 +45,7 @@ import org.koitharu.kotatsu.core.util.ext.ramAvailable
import org.koitharu.kotatsu.core.util.ext.withProgress
import org.koitharu.kotatsu.core.util.progress.ProgressDeferred
import org.koitharu.kotatsu.local.data.PagesCache
import org.koitharu.kotatsu.local.data.isCbzUri
import org.koitharu.kotatsu.local.data.isZipUri
import org.koitharu.kotatsu.parsers.model.MangaPage
import org.koitharu.kotatsu.parsers.model.MangaSource
import org.koitharu.kotatsu.reader.ui.pager.ReaderPage
@@ -199,8 +199,12 @@ class PageLoader @Inject constructor(
val pageUrl = getPageUrl(page)
check(pageUrl.isNotBlank()) { "Cannot obtain full image url" }
val uri = Uri.parse(pageUrl)
return if (isCbzUri(uri)) {
uri.buildUpon().scheme(URI_SCHEME_ZIP).build()
return if (uri.isZipUri()) {
if (uri.scheme == URI_SCHEME_ZIP) {
uri
} else { // legacy uri
uri.buildUpon().scheme(URI_SCHEME_ZIP).build()
}
} else {
val request = createPageRequest(page, pageUrl)
imageProxyInterceptor.interceptPageRequest(request, okHttp).ensureSuccess().use { response ->

View File

@@ -11,12 +11,13 @@ import android.view.ViewGroup
import androidx.core.view.children
import com.google.android.material.snackbar.Snackbar
import dagger.hilt.android.AndroidEntryPoint
import kotlinx.coroutines.async
import kotlinx.coroutines.coroutineScope
import kotlinx.coroutines.launch
import kotlinx.coroutines.yield
import org.koitharu.kotatsu.R
import org.koitharu.kotatsu.core.os.NetworkState
import org.koitharu.kotatsu.core.prefs.ReaderAnimation
import org.koitharu.kotatsu.core.ui.list.lifecycle.PagerLifecycleDispatcher
import org.koitharu.kotatsu.core.util.ext.doOnPageChanged
import org.koitharu.kotatsu.core.util.ext.findCurrentViewHolder
import org.koitharu.kotatsu.core.util.ext.observe
@@ -46,6 +47,8 @@ class ReversedReaderFragment : BaseReaderFragment<FragmentReaderStandardBinding>
@Inject
lateinit var pageLoader: PageLoader
private var pagerLifecycleDispatcher: PagerLifecycleDispatcher? = null
override fun onCreateViewBinding(
inflater: LayoutInflater,
container: ViewGroup?,
@@ -62,6 +65,9 @@ class ReversedReaderFragment : BaseReaderFragment<FragmentReaderStandardBinding>
recyclerView?.defaultFocusHighlightEnabled = false
}
PagerEventSupplier(this).attach()
pagerLifecycleDispatcher = PagerLifecycleDispatcher(this).also {
registerOnPageChangeCallback(it)
}
}
viewModel.pageAnimation.observe(viewLifecycleOwner) {
@@ -80,6 +86,7 @@ class ReversedReaderFragment : BaseReaderFragment<FragmentReaderStandardBinding>
}
override fun onDestroyView() {
pagerLifecycleDispatcher = null
requireViewBinding().pager.adapter = null
super.onDestroyView()
}
@@ -132,15 +139,16 @@ class ReversedReaderFragment : BaseReaderFragment<FragmentReaderStandardBinding>
override suspend fun onPagesChanged(pages: List<ReaderPage>, pendingState: ReaderState?) = coroutineScope {
val reversedPages = pages.asReversed()
val items = async {
val items = launch {
requireAdapter().setItems(reversedPages)
yield()
pagerLifecycleDispatcher?.invalidate()
}
if (pendingState != null) {
val position = reversedPages.indexOfLast {
it.chapterId == pendingState.chapterId && it.index == pendingState.page
}
items.await()
items.join()
if (position != -1) {
requireViewBinding().pager.setCurrentItem(position, false)
notifyPageChanged(position)
@@ -149,7 +157,7 @@ class ReversedReaderFragment : BaseReaderFragment<FragmentReaderStandardBinding>
.show()
}
} else {
items.await()
items.join()
}
}

View File

@@ -11,8 +11,8 @@ import android.view.ViewGroup
import androidx.core.view.children
import com.google.android.material.snackbar.Snackbar
import dagger.hilt.android.AndroidEntryPoint
import kotlinx.coroutines.async
import kotlinx.coroutines.coroutineScope
import kotlinx.coroutines.launch
import kotlinx.coroutines.yield
import org.koitharu.kotatsu.R
import org.koitharu.kotatsu.core.os.NetworkState
@@ -43,6 +43,8 @@ class PagerReaderFragment : BaseReaderFragment<FragmentReaderStandardBinding>(),
@Inject
lateinit var pageLoader: PageLoader
private var pagerLifecycleDispatcher: PagerLifecycleDispatcher? = null
override fun onCreateViewBinding(
inflater: LayoutInflater,
container: ViewGroup?,
@@ -62,7 +64,9 @@ class PagerReaderFragment : BaseReaderFragment<FragmentReaderStandardBinding>(),
recyclerView?.defaultFocusHighlightEnabled = false
}
PagerEventSupplier(this).attach()
registerOnPageChangeCallback(PagerLifecycleDispatcher(this))
pagerLifecycleDispatcher = PagerLifecycleDispatcher(this).also {
registerOnPageChangeCallback(it)
}
}
viewModel.pageAnimation.observe(viewLifecycleOwner) {
@@ -81,6 +85,7 @@ class PagerReaderFragment : BaseReaderFragment<FragmentReaderStandardBinding>(),
}
override fun onDestroyView() {
pagerLifecycleDispatcher = null
requireViewBinding().pager.adapter = null
super.onDestroyView()
}
@@ -109,15 +114,16 @@ class PagerReaderFragment : BaseReaderFragment<FragmentReaderStandardBinding>(),
override suspend fun onPagesChanged(pages: List<ReaderPage>, pendingState: ReaderState?) =
coroutineScope {
val items = async {
val items = launch {
requireAdapter().setItems(pages)
yield()
pagerLifecycleDispatcher?.invalidate()
}
if (pendingState != null) {
val position = pages.indexOfFirst {
it.chapterId == pendingState.chapterId && it.index == pendingState.page
}
items.await()
items.join()
if (position != -1) {
requireViewBinding().pager.setCurrentItem(position, false)
notifyPageChanged(position)
@@ -126,7 +132,7 @@ class PagerReaderFragment : BaseReaderFragment<FragmentReaderStandardBinding>(),
.show()
}
} else {
items.await()
items.join()
}
}

View File

@@ -6,8 +6,8 @@ import android.view.ViewGroup
import android.view.animation.DecelerateInterpolator
import com.google.android.material.snackbar.Snackbar
import dagger.hilt.android.AndroidEntryPoint
import kotlinx.coroutines.async
import kotlinx.coroutines.coroutineScope
import kotlinx.coroutines.launch
import kotlinx.coroutines.yield
import org.koitharu.kotatsu.R
import org.koitharu.kotatsu.core.os.NetworkState
@@ -34,6 +34,8 @@ class WebtoonReaderFragment : BaseReaderFragment<FragmentReaderWebtoonBinding>()
private val scrollInterpolator = DecelerateInterpolator()
private var recyclerLifecycleDispatcher: RecyclerViewLifecycleDispatcher? = null
override fun onCreateViewBinding(
inflater: LayoutInflater,
container: ViewGroup?,
@@ -45,7 +47,9 @@ class WebtoonReaderFragment : BaseReaderFragment<FragmentReaderWebtoonBinding>()
setHasFixedSize(true)
adapter = readerAdapter
addOnPageScrollListener(PageScrollListener())
addOnScrollListener(RecyclerViewLifecycleDispatcher())
recyclerLifecycleDispatcher = RecyclerViewLifecycleDispatcher().also {
addOnScrollListener(it)
}
}
viewModel.isWebtoonZooEnabled.observe(viewLifecycleOwner) {
binding.frame.isZoomEnable = it
@@ -53,6 +57,7 @@ class WebtoonReaderFragment : BaseReaderFragment<FragmentReaderWebtoonBinding>()
}
override fun onDestroyView() {
recyclerLifecycleDispatcher = null
requireViewBinding().recyclerView.adapter = null
super.onDestroyView()
}
@@ -66,15 +71,18 @@ class WebtoonReaderFragment : BaseReaderFragment<FragmentReaderWebtoonBinding>()
)
override suspend fun onPagesChanged(pages: List<ReaderPage>, pendingState: ReaderState?) = coroutineScope {
val setItems = async {
val setItems = launch {
requireAdapter().setItems(pages)
yield()
viewBinding?.recyclerView?.let { rv ->
recyclerLifecycleDispatcher?.invalidate(rv)
}
}
if (pendingState != null) {
val position = pages.indexOfFirst {
it.chapterId == pendingState.chapterId && it.index == pendingState.page
}
setItems.await()
setItems.join()
if (position != -1) {
with(requireViewBinding().recyclerView) {
firstVisibleItemPosition = position
@@ -89,7 +97,7 @@ class WebtoonReaderFragment : BaseReaderFragment<FragmentReaderWebtoonBinding>()
.show()
}
} else {
setItems.await()
setItems.join()
}
}

View File

@@ -20,7 +20,7 @@ import org.koitharu.kotatsu.core.network.ImageProxyInterceptor
import org.koitharu.kotatsu.core.network.MangaHttpClient
import org.koitharu.kotatsu.core.parser.MangaRepository
import org.koitharu.kotatsu.local.data.PagesCache
import org.koitharu.kotatsu.local.data.isCbzUri
import org.koitharu.kotatsu.local.data.isZipUri
import org.koitharu.kotatsu.local.data.util.withExtraCloseable
import org.koitharu.kotatsu.parsers.model.MangaPage
import org.koitharu.kotatsu.parsers.util.mimeType
@@ -56,7 +56,7 @@ class MangaPageFetcher(
private suspend fun loadPage(pageUrl: String): SourceResult {
val uri = pageUrl.toUri()
return if (isCbzUri(uri)) {
return if (uri.isZipUri()) {
runInterruptible(Dispatchers.IO) {
val zip = ZipFile(uri.schemeSpecificPart)
val entry = zip.getEntry(uri.fragment)