From acba312e8daf8929447045192403f0ed5844963b Mon Sep 17 00:00:00 2001 From: Koitharu Date: Sat, 25 Nov 2023 09:15:57 +0200 Subject: [PATCH] Misc fixes --- app/build.gradle | 4 ++-- .../list/lifecycle/PagerLifecycleDispatcher.kt | 4 ++++ .../RecyclerViewLifecycleDispatcher.kt | 4 ++++ .../koitharu/kotatsu/local/data/CbzFilter.kt | 7 +++++-- .../local/data/input/LocalMangaDirInput.kt | 4 ++-- .../kotatsu/reader/domain/PageLoader.kt | 10 +++++++--- .../pager/reversed/ReversedReaderFragment.kt | 16 ++++++++++++---- .../ui/pager/standard/PagerReaderFragment.kt | 16 +++++++++++----- .../ui/pager/webtoon/WebtoonReaderFragment.kt | 18 +++++++++++++----- .../reader/ui/thumbnails/MangaPageFetcher.kt | 4 ++-- 10 files changed, 62 insertions(+), 25 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index 3e24f319c..c9c8e1761 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -17,7 +17,7 @@ android { minSdk = 21 targetSdk = 34 versionCode = 599 - versionName = '6.3.2' + versionName = '6.4-a1' generatedDensities = [] testInstrumentationRunner "org.koitharu.kotatsu.HiltTestRunner" ksp { @@ -134,7 +134,7 @@ dependencies { implementation 'io.coil-kt:coil-base:2.5.0' implementation 'io.coil-kt:coil-svg:2.5.0' - implementation 'com.github.KotatsuApp:subsampling-scale-image-view:826d7b4512' + implementation 'com.github.KotatsuApp:subsampling-scale-image-view:c7dab3aefe' implementation 'com.github.solkin:disk-lru-cache:1.4' implementation 'io.noties.markwon:core:4.6.2' diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/core/ui/list/lifecycle/PagerLifecycleDispatcher.kt b/app/src/main/kotlin/org/koitharu/kotatsu/core/ui/list/lifecycle/PagerLifecycleDispatcher.kt index c6d9a72a3..b767396e1 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/core/ui/list/lifecycle/PagerLifecycleDispatcher.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/core/ui/list/lifecycle/PagerLifecycleDispatcher.kt @@ -16,4 +16,8 @@ class PagerLifecycleDispatcher( (wh as? LifecycleAwareViewHolder)?.setIsCurrent(wh.absoluteAdapterPosition == position) } } + + fun invalidate() { + onPageSelected(pager.currentItem) + } } diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/core/ui/list/lifecycle/RecyclerViewLifecycleDispatcher.kt b/app/src/main/kotlin/org/koitharu/kotatsu/core/ui/list/lifecycle/RecyclerViewLifecycleDispatcher.kt index bf8d940ff..7772d928b 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/core/ui/list/lifecycle/RecyclerViewLifecycleDispatcher.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/core/ui/list/lifecycle/RecyclerViewLifecycleDispatcher.kt @@ -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() diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/local/data/CbzFilter.kt b/app/src/main/kotlin/org/koitharu/kotatsu/local/data/CbzFilter.kt index 225840bed..b9f2eebb4 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/local/data/CbzFilter.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/local/data/CbzFilter.kt @@ -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" +} diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/local/data/input/LocalMangaDirInput.kt b/app/src/main/kotlin/org/koitharu/kotatsu/local/data/input/LocalMangaDirInput.kt index 43739b74b..f8e6879ea 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/local/data/input/LocalMangaDirInput.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/local/data/input/LocalMangaDirInput.kt @@ -121,13 +121,13 @@ class LocalMangaDirInput(root: File) : LocalMangaInput(root) { private fun String.toHumanReadable() = replace("_", " ").toCamelCase() private fun getChaptersFiles(): List = 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) } diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/reader/domain/PageLoader.kt b/app/src/main/kotlin/org/koitharu/kotatsu/reader/domain/PageLoader.kt index 1f13a10d1..ab1eb039c 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/reader/domain/PageLoader.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/reader/domain/PageLoader.kt @@ -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 -> diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/reader/ui/pager/reversed/ReversedReaderFragment.kt b/app/src/main/kotlin/org/koitharu/kotatsu/reader/ui/pager/reversed/ReversedReaderFragment.kt index 66aa702f3..e9ccb68ab 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/reader/ui/pager/reversed/ReversedReaderFragment.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/reader/ui/pager/reversed/ReversedReaderFragment.kt @@ -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 @Inject lateinit var pageLoader: PageLoader + private var pagerLifecycleDispatcher: PagerLifecycleDispatcher? = null + override fun onCreateViewBinding( inflater: LayoutInflater, container: ViewGroup?, @@ -62,6 +65,9 @@ class ReversedReaderFragment : BaseReaderFragment recyclerView?.defaultFocusHighlightEnabled = false } PagerEventSupplier(this).attach() + pagerLifecycleDispatcher = PagerLifecycleDispatcher(this).also { + registerOnPageChangeCallback(it) + } } viewModel.pageAnimation.observe(viewLifecycleOwner) { @@ -80,6 +86,7 @@ class ReversedReaderFragment : BaseReaderFragment } override fun onDestroyView() { + pagerLifecycleDispatcher = null requireViewBinding().pager.adapter = null super.onDestroyView() } @@ -132,15 +139,16 @@ class ReversedReaderFragment : BaseReaderFragment override suspend fun onPagesChanged(pages: List, 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 .show() } } else { - items.await() + items.join() } } diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/reader/ui/pager/standard/PagerReaderFragment.kt b/app/src/main/kotlin/org/koitharu/kotatsu/reader/ui/pager/standard/PagerReaderFragment.kt index fae8b9f75..70a2cbc28 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/reader/ui/pager/standard/PagerReaderFragment.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/reader/ui/pager/standard/PagerReaderFragment.kt @@ -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(), @Inject lateinit var pageLoader: PageLoader + private var pagerLifecycleDispatcher: PagerLifecycleDispatcher? = null + override fun onCreateViewBinding( inflater: LayoutInflater, container: ViewGroup?, @@ -62,7 +64,9 @@ class PagerReaderFragment : BaseReaderFragment(), 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(), } override fun onDestroyView() { + pagerLifecycleDispatcher = null requireViewBinding().pager.adapter = null super.onDestroyView() } @@ -109,15 +114,16 @@ class PagerReaderFragment : BaseReaderFragment(), override suspend fun onPagesChanged(pages: List, 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(), .show() } } else { - items.await() + items.join() } } diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/reader/ui/pager/webtoon/WebtoonReaderFragment.kt b/app/src/main/kotlin/org/koitharu/kotatsu/reader/ui/pager/webtoon/WebtoonReaderFragment.kt index 75decb499..f3c1d2f89 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/reader/ui/pager/webtoon/WebtoonReaderFragment.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/reader/ui/pager/webtoon/WebtoonReaderFragment.kt @@ -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() private val scrollInterpolator = DecelerateInterpolator() + private var recyclerLifecycleDispatcher: RecyclerViewLifecycleDispatcher? = null + override fun onCreateViewBinding( inflater: LayoutInflater, container: ViewGroup?, @@ -45,7 +47,9 @@ class WebtoonReaderFragment : BaseReaderFragment() 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() } override fun onDestroyView() { + recyclerLifecycleDispatcher = null requireViewBinding().recyclerView.adapter = null super.onDestroyView() } @@ -66,15 +71,18 @@ class WebtoonReaderFragment : BaseReaderFragment() ) override suspend fun onPagesChanged(pages: List, 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() .show() } } else { - setItems.await() + setItems.join() } } diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/reader/ui/thumbnails/MangaPageFetcher.kt b/app/src/main/kotlin/org/koitharu/kotatsu/reader/ui/thumbnails/MangaPageFetcher.kt index fc16164e6..2861cd870 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/reader/ui/thumbnails/MangaPageFetcher.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/reader/ui/thumbnails/MangaPageFetcher.kt @@ -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)