diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/pager/PagerPageHolder.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/pager/PagerPageHolder.kt index 0400fb16e..273200fce 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/pager/PagerPageHolder.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/pager/PagerPageHolder.kt @@ -2,6 +2,7 @@ package eu.kanade.tachiyomi.ui.reader.viewer.pager import android.annotation.SuppressLint import android.content.Context +import android.graphics.Bitmap import android.view.LayoutInflater import androidx.core.view.isVisible import eu.kanade.tachiyomi.databinding.ReaderErrorBinding @@ -244,16 +245,7 @@ class PagerPageHolder( private fun mergePages(imageSource: BufferedSource, imageSource2: BufferedSource?): BufferedSource { // Handle adding a center margin to wide images if requested if (imageSource2 == null) { - return if ( - !ImageUtil.isAnimatedAndSupported(imageSource) && - ImageUtil.isWideImage(imageSource) && - viewer.config.centerMarginType and PagerConfig.CenterMarginType.WIDE_PAGE_CENTER_MARGIN > 0 && - !viewer.config.imageCropBorders - ) { - ImageUtil.addHorizontalCenterMargin(imageSource, height, context) - } else { - imageSource - } + return handleWideImage(imageSource) } if (page.fullPage) return imageSource @@ -268,12 +260,7 @@ class PagerPageHolder( return imageSource } - val imageBitmap = try { - ImageDecoder.newInstance(imageSource.inputStream())?.decode() - } catch (e: Exception) { - logcat(LogPriority.ERROR, e) { "Cannot combine pages" } - null - } + val imageBitmap = decodeImage(imageSource) if (imageBitmap == null) { imageSource2.close() page.fullPage = true @@ -281,23 +268,16 @@ class PagerPageHolder( logcat(LogPriority.ERROR) { "Cannot combine pages" } return imageSource } - scope.launch { progressIndicator.setProgress(96) } - val height = imageBitmap.height - val width = imageBitmap.width - if (height < width) { + scope.launch { progressIndicator.setProgress(96) } + if (imageBitmap.height < imageBitmap.width) { imageSource2.close() page.fullPage = true splitDoublePages() return imageSource } - val imageBitmap2 = try { - ImageDecoder.newInstance(imageSource2.inputStream())?.decode() - } catch (e: Exception) { - logcat(LogPriority.ERROR, e) { "Cannot combine pages" } - null - } + val imageBitmap2 = decodeImage(imageSource2) if (imageBitmap2 == null) { imageSource2.close() extraPage?.fullPage = true @@ -306,35 +286,63 @@ class PagerPageHolder( logcat(LogPriority.ERROR) { "Cannot combine pages" } return imageSource } - scope.launch { progressIndicator.setProgress(97) } - val height2 = imageBitmap2.height - val width2 = imageBitmap2.width - if (height2 < width2) { + scope.launch { progressIndicator.setProgress(97) } + if (imageBitmap2.height < imageBitmap2.width) { imageSource2.close() extraPage?.fullPage = true page.isolatedPage = true splitDoublePages() return imageSource } + val isLTR = (viewer !is R2LPagerViewer) xor viewer.config.invertDoublePages + val centerMargin = calculateCenterMargin(imageBitmap.height, imageBitmap2.height) imageSource.close() imageSource2.close() - val centerMargin = if (viewer.config.centerMarginType and PagerConfig.CenterMarginType.DOUBLE_PAGE_CENTER_MARGIN > 0 && !viewer.config.imageCropBorders) { + return ImageUtil.mergeBitmaps(imageBitmap, imageBitmap2, isLTR, centerMargin, viewer.config.pageCanvasColor) { + updateProgress(it) + } + } + + private fun handleWideImage(imageSource: BufferedSource): BufferedSource { + return if ( + !ImageUtil.isAnimatedAndSupported(imageSource) && + ImageUtil.isWideImage(imageSource) && + viewer.config.centerMarginType and PagerConfig.CenterMarginType.WIDE_PAGE_CENTER_MARGIN > 0 && + !viewer.config.imageCropBorders + ) { + ImageUtil.addHorizontalCenterMargin(imageSource, height, context) + } else { + imageSource + } + } + + private fun decodeImage(imageSource: BufferedSource): Bitmap? { + return try { + ImageDecoder.newInstance(imageSource.inputStream())?.decode() + } catch (e: Exception) { + logcat(LogPriority.ERROR, e) { "Cannot decode image" } + null + } + } + + private fun calculateCenterMargin(height: Int, height2: Int): Int { + return if (viewer.config.centerMarginType and PagerConfig.CenterMarginType.DOUBLE_PAGE_CENTER_MARGIN > 0 && !viewer.config.imageCropBorders) { 96 / (this.height.coerceAtLeast(1) / max(height, height2).coerceAtLeast(1)).coerceAtLeast(1) } else { 0 } + } - return ImageUtil.mergeBitmaps(imageBitmap, imageBitmap2, isLTR, centerMargin, viewer.config.pageCanvasColor) { - scope.launch { - if (it == 100) { - progressIndicator.hide() - } else { - progressIndicator.setProgress(it) - } + private fun updateProgress(progress: Int) { + scope.launch { + if (progress == 100) { + progressIndicator.hide() + } else { + progressIndicator.setProgress(progress) } } } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/pager/PagerViewerAdapter.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/pager/PagerViewerAdapter.kt index 53d94d13b..8f63d1563 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/pager/PagerViewerAdapter.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/pager/PagerViewerAdapter.kt @@ -14,7 +14,6 @@ import eu.kanade.tachiyomi.widget.ViewPagerAdapter import kotlinx.coroutines.delay import tachiyomi.core.common.util.lang.launchUI import tachiyomi.core.common.util.system.logcat -import kotlin.math.max /** * Pager adapter used by this [viewer] to where [ViewerChapters] updates are posted. @@ -231,10 +230,12 @@ class PagerViewerAdapter(private val viewer: PagerViewer) : ViewPagerAdapter() { val oldCurrent = joinedItems.getOrNull(viewer.pager.currentItem) if (!viewer.config.doublePages) { // If not in double mode, set up items like before - subItems.forEach { - (it as? ReaderPage)?.shiftedPage = false + subItems.forEach { readerItem -> + if (readerItem is ReaderPage) { + readerItem.shiftedPage = false + } } - this.joinedItems = subItems.map { Pair(it, null) }.toMutableList() + this.joinedItems = subItems.map { Pair(it, null) }.toMutableList() if (viewer is R2LPagerViewer) { joinedItems.reverse() } @@ -242,54 +243,43 @@ class PagerViewerAdapter(private val viewer: PagerViewer) : ViewPagerAdapter() { val pagedItems = mutableListOf>() val otherItems = mutableListOf() pagedItems.add(mutableListOf()) + // Step 1: segment the pages and transition pages - subItems.forEach { - when (it) { + subItems.forEach { readerItem -> + when (readerItem) { is ReaderPage -> { - if (pagedItems.last().lastOrNull() != null && - pagedItems.last().last()?.chapter?.chapter?.id != it.chapter.chapter.id - ) { + if (pagedItems.last().isNotEmpty() && pagedItems.last().last()?.chapter?.chapter?.id != readerItem.chapter.chapter.id) { pagedItems.add(mutableListOf()) } - pagedItems.last().add(it) + pagedItems.last().add(readerItem) } is ChapterTransition -> { - otherItems.add(it) + otherItems.add(readerItem) pagedItems.add(mutableListOf()) } } } - var pagedIndex = 0 + val subJoinedItems = mutableListOf>() + // Step 2: run through each set of pages pagedItems.forEach { items -> + items.forEach { it?.shiftedPage = false } - items.forEach { - it?.shiftedPage = false - } // Step 3: If pages have been shifted, if (viewer.config.shiftDoublePage) { + val index = items.indexOf(pageToShift) + // Go from the current page and work your way back to the first page, + // or the first page that's a full page. + // This is done in case user tries to shift a page after a full page + val fullPageBeforeIndex = if (index > -1) { + items.take(index).indexOfLast { it?.fullPage == true } + } else { + -1 + }.coerceAtLeast(0) + + // Add a shifted page to the first place there isnt a full page run loop@{ - var index = items.indexOf(pageToShift) - if (pageToShift?.fullPage == true) { - index = max(0, index - 1) - } - // Go from the current page and work your way back to the first page, - // or the first page that's a full page. - // This is done in case user tries to shift a page after a full page - val fullPageBeforeIndex = max( - 0, - ( - if (index > -1) { - ( - items.take(index).indexOfLast { it?.fullPage == true } - ) - } else { - -1 - } - ), - ) - // Add a shifted page to the first place there isnt a full page (fullPageBeforeIndex until items.size).forEach { if (items[it]?.fullPage == false) { items[it]?.shiftedPage = true @@ -302,12 +292,15 @@ class PagerViewerAdapter(private val viewer: PagerViewer) : ViewPagerAdapter() { // Step 4: Add blanks for chunking var itemIndex = 0 while (itemIndex < items.size) { - items[itemIndex]?.isolatedPage = false - if (items[itemIndex]?.fullPage == true || items[itemIndex]?.shiftedPage == true) { + val currentItem = items[itemIndex] + currentItem?.isolatedPage = false + if (currentItem?.fullPage == true || currentItem?.shiftedPage == true) { // Add a 'blank' page after each full page. It will be used when chunked to solo a page items.add(itemIndex + 1, null) - if (items[itemIndex]?.fullPage == true && itemIndex > 0 && - items[itemIndex - 1] != null && (itemIndex - 1) % 2 == 0 + if ( + currentItem.fullPage && itemIndex > 0 && + items[itemIndex - 1] != null && + (itemIndex - 1) % 2 == 0 ) { // If a page is a full page, check if the previous page needs to be isolated // we should check if it's an even or odd page, since even pages need shifting @@ -325,15 +318,14 @@ class PagerViewerAdapter(private val viewer: PagerViewer) : ViewPagerAdapter() { // Step 5: chunk em if (items.isNotEmpty()) { - subJoinedItems.addAll( - items.chunked(2).map { Pair(it.first()!!, it.getOrNull(1)) }, - ) + subJoinedItems.addAll(items.chunked(2).map { Pair(it.first()!!, it.getOrNull(1)) }) } - otherItems.getOrNull(pagedIndex)?.let { + + otherItems.getOrNull(pagedItems.indexOf(items))?.let { subJoinedItems.add(Pair(it, null)) - pagedIndex++ } } + if (viewer is R2LPagerViewer) { subJoinedItems.reverse() } @@ -347,42 +339,37 @@ class PagerViewerAdapter(private val viewer: PagerViewer) : ViewPagerAdapter() { // we need to set the page back correctly // We will however shift to the first page of the new chapter if the last page we were are // on is not in the new chapter that has loaded - val newPage = - when { - (oldCurrent?.first as? ReaderPage)?.chapter != currentChapter && - (oldCurrent?.first as? ChapterTransition)?.from != currentChapter -> subItems.find { - (it as? ReaderPage)?.chapter == currentChapter - } - useSecondPage -> (oldCurrent?.second ?: oldCurrent?.first) - else -> oldCurrent?.first ?: return - } - var index = joinedItems.indexOfFirst { it.first == newPage || it.second == newPage } - if (newPage is ChapterTransition && index == -1) { - val newerPage = if (newPage is ChapterTransition.Next) { - joinedItems.filter { - (it.first as? ReaderPage)?.chapter == newPage.to - }.minByOrNull { (it.first as? ReaderPage)?.index ?: Int.MAX_VALUE }?.first - } else { - joinedItems.filter { - (it.first as? ReaderPage)?.chapter == newPage.to - }.maxByOrNull { (it.first as? ReaderPage)?.index ?: Int.MIN_VALUE }?.first - } - index = joinedItems.indexOfFirst { it.first == newerPage || it.second == newerPage } + val newPage = when { + oldCurrent?.first is ReaderPage && (oldCurrent.first as ReaderPage).chapter != currentChapter && + (oldCurrent.second as? ChapterTransition)?.from != currentChapter -> + subItems.find { it is ReaderPage && it.chapter == currentChapter } + useSecondPage -> oldCurrent?.second ?: oldCurrent?.first + else -> oldCurrent?.first ?: return } + + val index = when (newPage) { + is ChapterTransition -> { + val filteredPages = joinedItems.filter { it.first is ReaderPage && (it.first as ReaderPage).chapter == newPage.to } + val page = if (newPage is ChapterTransition.Next) { + filteredPages.minByOrNull { (it.first as ReaderPage).index }?.first + } else { + filteredPages.maxByOrNull { (it.first as ReaderPage).index }?.first + } + joinedItems.indexOfFirst { it.first == page || it.second == page } + } + else -> joinedItems.indexOfFirst { it.first == newPage || it.second == newPage } + } + viewer.pager.setCurrentItem(index, false) } fun splitDoublePages(current: ReaderPage) { val oldCurrent = joinedItems.getOrNull(viewer.pager.currentItem) - setJoinedItems( - oldCurrent?.second == current || - (current.index + 1) < ( - ( - oldCurrent?.second - ?: oldCurrent?.first - ) as? ReaderPage - )?.index ?: 0, - ) + val oldSecondPage = oldCurrent?.second as? ReaderPage + val oldFirstPage = oldCurrent?.first as? ReaderPage + val oldPage = oldSecondPage ?: oldFirstPage + + setJoinedItems(oldSecondPage == current || (current.index + 1) < (oldPage?.index ?: 0)) // The listener may be removed when we split a page, so the ui may not have updated properly // This case usually happens when we load a new chapter and the first 2 pages need to split og