From 60d4c30e9ae0261f8659b38b6dae41c71da0540b Mon Sep 17 00:00:00 2001 From: Jays2Kings Date: Sat, 7 Aug 2021 17:17:13 -0400 Subject: [PATCH] Splitting double pages (#961) * Split double pages * various fixes for split double page --- .../data/preference/PreferenceKeys.kt | 2 + .../data/preference/PreferencesHelper.kt | 2 + .../tachiyomi/ui/reader/ReaderActivity.kt | 76 ++++++++++++++---- .../tachiyomi/ui/reader/ReaderPresenter.kt | 2 +- .../tachiyomi/ui/reader/model/InsertPage.kt | 16 ++++ .../tachiyomi/ui/reader/model/ReaderPage.kt | 16 ++-- .../ui/reader/settings/PageLayout.kt | 1 + .../ui/reader/viewer/pager/PagerConfig.kt | 7 ++ .../ui/reader/viewer/pager/PagerPageHolder.kt | 73 +++++++++++++++-- .../ui/reader/viewer/pager/PagerViewer.kt | 17 +++- .../reader/viewer/pager/PagerViewerAdapter.kt | 78 +++++++++++++++---- .../ui/setting/SettingsReaderController.kt | 6 ++ .../kanade/tachiyomi/util/system/ImageUtil.kt | 18 +++++ .../res/drawable/ic_book_open_split_24dp.xml | 9 +++ app/src/main/res/values/arrays.xml | 1 + app/src/main/res/values/strings.xml | 2 + 16 files changed, 281 insertions(+), 45 deletions(-) create mode 100644 app/src/main/java/eu/kanade/tachiyomi/ui/reader/model/InsertPage.kt create mode 100644 app/src/main/res/drawable/ic_book_open_split_24dp.xml diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/preference/PreferenceKeys.kt b/app/src/main/java/eu/kanade/tachiyomi/data/preference/PreferenceKeys.kt index bed9ffce5a..4cfb21deb9 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/preference/PreferenceKeys.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/preference/PreferenceKeys.kt @@ -74,6 +74,8 @@ object PreferenceKeys { const val pageLayout = "page_layout" + const val automaticSplitsPage = "automatic_splits_page" + const val invertDoublePages = "invert_double_pages" const val readerBottomButtons = "reader_bottom_buttons" diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/preference/PreferencesHelper.kt b/app/src/main/java/eu/kanade/tachiyomi/data/preference/PreferencesHelper.kt index 457b40968f..e2d830e176 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/preference/PreferencesHelper.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/preference/PreferencesHelper.kt @@ -186,6 +186,8 @@ class PreferencesHelper(val context: Context) { fun pageLayout() = flowPrefs.getInt(Keys.pageLayout, PageLayout.AUTOMATIC.value) + fun automaticSplitsPage() = flowPrefs.getBoolean(Keys.automaticSplitsPage, false) + fun invertDoublePages() = flowPrefs.getBoolean(Keys.invertDoublePages, false) fun readerBottomButtons() = flowPrefs.getStringSet( diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderActivity.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderActivity.kt index 34af9e889f..64103f74cf 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderActivity.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderActivity.kt @@ -29,6 +29,7 @@ import androidx.core.view.GestureDetectorCompat import androidx.core.view.ViewCompat import androidx.core.view.isInvisible import androidx.core.view.isVisible +import androidx.lifecycle.Lifecycle import androidx.vectordrawable.graphics.drawable.AnimatedVectorDrawableCompat import com.afollestad.materialdialogs.MaterialDialog import com.davemorrissey.labs.subscaleview.SubsamplingScaleImageView @@ -342,8 +343,11 @@ class ReaderActivity : binding.chaptersSheet.doublePage.setImageDrawable( ContextCompat.getDrawable( this, - if (!isDoublePage) R.drawable.ic_single_page_24dp - else R.drawable.ic_book_open_variant_24dp + when { + isDoublePage -> R.drawable.ic_book_open_variant_24dp + (viewer as? PagerViewer)?.config?.splitPages == true -> R.drawable.ic_book_open_split_24dp + else -> R.drawable.ic_single_page_24dp + } ) ) with(binding.readerNav) { @@ -354,11 +358,6 @@ class ReaderActivity : } } } - binding.chaptersSheet.doublePage.compatToolTipText = - getString( - if (isDoublePage) R.string.switch_to_single - else R.string.switch_to_double - ) } private fun updateOrientationShortcut(preference: Int) { @@ -554,14 +553,39 @@ class ReaderActivity : } with(binding.chaptersSheet) { - doublePage.setOnClickListener { - if (preferences.pageLayout().get() == PageLayout.AUTOMATIC.value) { - (viewer as? PagerViewer)?.config?.let { config -> - config.doublePages = !config.doublePages - reloadChapters(config.doublePages, true) + with(doublePage) { + compatToolTipText = getString(R.string.page_layout) + setOnClickListener { + val config = (viewer as? PagerViewer)?.config + val selectedId = when { + config?.doublePages == true -> PageLayout.DOUBLE_PAGES + config?.splitPages == true -> PageLayout.SPLIT_PAGES + else -> PageLayout.SINGLE_PAGE + } + popupMenu( + items = listOf( + PageLayout.SINGLE_PAGE, + PageLayout.DOUBLE_PAGES, + PageLayout.SPLIT_PAGES, + ).map { it.value to it.stringRes }, + selectedItemId = selectedId.value, + ) { + val newLayout = PageLayout.fromPreference(itemId) + + if (preferences.pageLayout().get() == PageLayout.AUTOMATIC.value) { + (viewer as? PagerViewer)?.config?.let { config -> + config.doublePages = newLayout == PageLayout.DOUBLE_PAGES + if (newLayout == PageLayout.SINGLE_PAGE) { + preferences.automaticSplitsPage().set(false) + } else if (newLayout == PageLayout.SPLIT_PAGES) { + preferences.automaticSplitsPage().set(true) + } + reloadChapters(config.doublePages, true) + } + } else { + preferences.pageLayout().set(newLayout.value) + } } - } else { - preferences.pageLayout().set(1 - preferences.pageLayout().get()) } } cropBordersSheetButton.setOnClickListener { @@ -917,6 +941,9 @@ class ReaderActivity : setDoublePageMode(pViewer) } else { pViewer.config.doublePages = doublePages + if (pViewer.config.autoDoublePages) { + pViewer.config.splitPages = preferences.automaticSplitsPage().get() && !pViewer.config.doublePages + } } val currentChapter = presenter.getCurrentChapter() if (doublePages) { @@ -925,7 +952,7 @@ class ReaderActivity : binding.readerNav.pageSeekbar.progress + ( currentChapter?.pages?.take(binding.readerNav.pageSeekbar.progress) - ?.count { it.fullPage || it.isolatedPage } ?: 0 + ?.count { it.fullPage == true || it.isolatedPage } ?: 0 ) ) % 2 != 0 } @@ -953,7 +980,7 @@ class ReaderActivity : currentChapter.requestedPage + ( currentChapter.pages?.take(currentChapter.requestedPage) - ?.count { it.fullPage || it.isolatedPage } ?: 0 + ?.count { it.fullPage == true || it.isolatedPage } ?: 0 ) ) % 2 != 0 } @@ -1042,7 +1069,7 @@ class ReaderActivity : val currentPage = if (hasExtraPage) { if (resources.isLTR) "${page.number}-${page.number + 1}" else "${page.number + 1}-${page.number}" } else { - "${page.number}" + "${page.number}${if (page.firstHalf == false) "*" else ""}" } val totalPages = pages.size.toString() @@ -1347,6 +1374,9 @@ class ReaderActivity : private fun setDoublePageMode(viewer: PagerViewer) { val currentOrientation = resources.configuration.orientation viewer.config.doublePages = (currentOrientation == Configuration.ORIENTATION_LANDSCAPE) + if (viewer.config.autoDoublePages) { + viewer.config.splitPages = preferences.automaticSplitsPage().get() && !viewer.config.doublePages + } } private fun handleIntentAction(intent: Intent): Boolean { @@ -1438,6 +1468,18 @@ class ReaderActivity : preferences.pageLayout().asImmediateFlowIn(scope) { setBottomNavButtons(it) } + preferences.automaticSplitsPage().asFlow() + .drop(1) + .onEach { + val isPaused = !this@ReaderActivity.lifecycle.currentState.isAtLeast(Lifecycle.State.RESUMED) + if (isPaused) { + (viewer as? PagerViewer)?.config?.let { config -> + reloadChapters(config.doublePages, true) + } + } + } + .launchIn(scope) + preferences.readerBottomButtons().asImmediateFlowIn(scope) { updateBottomShortcuts() } preferences.readWithTapping().asImmediateFlowIn(scope) { diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderPresenter.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderPresenter.kt index e50384e9f8..66ed756f52 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderPresenter.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderPresenter.kt @@ -490,7 +490,7 @@ class ReaderPresenter( if (shouldTrack && // For double pages, check if the second to last page is doubled up ( - selectedChapter.pages?.lastIndex == page.index || + (selectedChapter.pages?.lastIndex == page.index && page.firstHalf != true) || (hasExtraPage && selectedChapter.pages?.lastIndex?.minus(1) == page.index) ) ) { diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/model/InsertPage.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/model/InsertPage.kt new file mode 100644 index 0000000000..9c2a7f95fd --- /dev/null +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/model/InsertPage.kt @@ -0,0 +1,16 @@ +package eu.kanade.tachiyomi.ui.reader.model + +class InsertPage(parent: ReaderPage) : ReaderPage( + parent.index, + parent.url, + parent.imageUrl +) { + + override var chapter: ReaderChapter = parent.chapter + + init { + fullPage = true + firstHalf = false + stream = parent.stream + } +} diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/model/ReaderPage.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/model/ReaderPage.kt index 30bc4faa1f..33b89dba8a 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/model/ReaderPage.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/model/ReaderPage.kt @@ -4,7 +4,7 @@ import android.graphics.drawable.Drawable import eu.kanade.tachiyomi.source.model.Page import java.io.InputStream -class ReaderPage( +open class ReaderPage( index: Int, url: String = "", imageUrl: String? = null, @@ -14,15 +14,21 @@ class ReaderPage( /** Value to check if this page is used to as if it was too wide */ var shiftedPage: Boolean = false, /** Value to check if a page is can be doubled up, but can't because the next page is too wide */ - var isolatedPage: Boolean = false + var isolatedPage: Boolean = false, + var firstHalf: Boolean? = null, + var longPage: Boolean? = null ) : Page(index, url, imageUrl, null) { - lateinit var chapter: ReaderChapter + open lateinit var chapter: ReaderChapter /** Value to check if a page is too wide to be doubled up */ - var fullPage: Boolean = false + var fullPage: Boolean? = null set(value) { field = value - if (value) shiftedPage = false + longPage = value + if (value == true) shiftedPage = false } + + fun isFromSamePage(page: ReaderPage): Boolean = + index == page.index && chapter.chapter.id == page.chapter.chapter.id } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/settings/PageLayout.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/settings/PageLayout.kt index 7fa43319a0..7677b1ccd9 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/settings/PageLayout.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/settings/PageLayout.kt @@ -7,6 +7,7 @@ enum class PageLayout(val value: Int, @StringRes val stringRes: Int, @StringRes SINGLE_PAGE(0, R.string.single_page), DOUBLE_PAGES(1, R.string.double_pages), AUTOMATIC(2, R.string.automatic, R.string.automatic_orientation), + SPLIT_PAGES(3, R.string.split_double_pages) ; @StringRes val fullStringRes = _fullStringRes ?: stringRes diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/pager/PagerConfig.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/pager/PagerConfig.kt index 60a3afa09d..1ca461f319 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/pager/PagerConfig.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/pager/PagerConfig.kt @@ -58,6 +58,9 @@ class PagerConfig( var autoDoublePages = preferences.pageLayout().get() == PageLayout.AUTOMATIC.value + var splitPages = preferences.pageLayout().get() == PageLayout.SPLIT_PAGES.value + var autoSplitPages = preferences.automaticSplitsPage().get() + init { preferences.pageTransitions() .register({ usePageTransitions = it }) @@ -103,6 +106,7 @@ class PagerConfig( .drop(1) .onEach { autoDoublePages = it == PageLayout.AUTOMATIC.value + splitPages = it == PageLayout.SPLIT_PAGES.value if (!autoDoublePages) { doublePages = it == PageLayout.DOUBLE_PAGES.value } @@ -114,9 +118,12 @@ class PagerConfig( autoDoublePages = it == PageLayout.AUTOMATIC.value if (!autoDoublePages) { doublePages = it == PageLayout.DOUBLE_PAGES.value + splitPages = it == PageLayout.SPLIT_PAGES.value } }) + preferences.automaticSplitsPage() + .register({ autoSplitPages = it }) navigationOverlayForNewUser = preferences.showNavigationOverlayNewUser().get() if (navigationOverlayForNewUser) { preferences.showNavigationOverlayNewUser().set(false) 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 c323cc5f6f..4c006e4d32 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 @@ -348,7 +348,7 @@ class PagerPageHolder( val stream = streamFn().buffered(16) val stream2 = if (extraPage != null) streamFn2?.invoke()?.buffered(16) else null - openStream = this@PagerPageHolder.mergePages(stream, stream2) + openStream = this@PagerPageHolder.mergeOrSplitPages(stream, stream2) ImageUtil.isAnimatedAndSupported(stream) || if (stream2 != null) ImageUtil.isAnimatedAndSupported(stream2) else false } @@ -507,6 +507,15 @@ class PagerPageHolder( } setOnImageEventListener( object : SubsamplingScaleImageView.DefaultOnImageEventListener() { + + override fun onImageLoaded() { + if (this@PagerPageHolder.extraPage == null && + this@PagerPageHolder.page.longPage == null && + sHeight < sWidth + ) { + this@PagerPageHolder.page.longPage = true + } + } override fun onReady() { var centerV = 0f when (config.imageZoomType) { @@ -651,9 +660,63 @@ class PagerPageHolder( return decodeLayout } - private fun mergePages(imageStream: InputStream, imageStream2: InputStream?): InputStream { - imageStream2 ?: return imageStream - if (page.fullPage) return imageStream + private fun mergeOrSplitPages(imageStream: InputStream, imageStream2: InputStream?): InputStream { + if (page.longPage == true && viewer.config.splitPages) { + val imageBytes = imageStream.readBytes() + val imageBitmap = try { + BitmapFactory.decodeByteArray(imageBytes, 0, imageBytes.size) + } catch (e: Exception) { + imageStream.close() + Timber.e("Cannot split page ${e.message}") + return imageBytes.inputStream() + } + val isLTR = (viewer !is R2LPagerViewer).xor(viewer.config.invertDoublePages) + return ImageUtil.splitBitmap(imageBitmap, (page.firstHalf == false).xor(!isLTR)) { + scope?.launchUI { + if (it == 100) { + progressBar.completeAndFadeOut() + } else { + progressBar.setProgress(it) + } + } + } + } + if (imageStream2 == null) { + if (viewer.config.splitPages && page.longPage == null) { + val imageBytes = imageStream.readBytes() + val imageBitmap = try { + BitmapFactory.decodeByteArray(imageBytes, 0, imageBytes.size) + } catch (e: Exception) { + imageStream.close() + page.longPage = true + skipExtra = true + Timber.e("Cannot split page ${e.message}") + return imageBytes.inputStream() + } + val height = imageBitmap.height + val width = imageBitmap.width + return if (height < width) { + imageStream.close() + page.longPage = true + skipExtra = true + val isLTR = (viewer !is R2LPagerViewer).xor(viewer.config.invertDoublePages) + return ImageUtil.splitBitmap(imageBitmap, !isLTR) { + scope?.launchUI { + if (it == 100) { + progressBar.completeAndFadeOut() + } else { + progressBar.setProgress(it) + } + } + } + } else { + page.longPage = false + imageBytes.inputStream() + } + } + return imageStream + } + if (page.fullPage == true) return imageStream if (ImageUtil.isAnimatedAndSupported(imageStream)) { page.fullPage = true skipExtra = true @@ -732,7 +795,7 @@ class PagerPageHolder( } private fun splitDoublePages() { - extraPage ?: return + // extraPage ?: return viewer.splitDoublePages(page) if (extraPage?.fullPage == true) { extraPage = null diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/pager/PagerViewer.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/pager/PagerViewer.kt index 1b50b52ab2..64ed9d7807 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/pager/PagerViewer.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/pager/PagerViewer.kt @@ -156,7 +156,11 @@ abstract class PagerViewer(val activity: ReaderActivity) : BaseViewer { val allowPreload = checkAllowPreload(page.first as? ReaderPage) currentPage = page.first when (val aPage = page.first) { - is ReaderPage -> onReaderPageSelected(aPage, allowPreload, page.second != null) + is ReaderPage -> onReaderPageSelected( + aPage, + allowPreload, + page.second is ReaderPage + ) is ChapterTransition -> onTransitionSelected(aPage) } } @@ -275,7 +279,14 @@ abstract class PagerViewer(val activity: ReaderActivity) : BaseViewer { */ override fun moveToPage(page: ReaderPage, animated: Boolean) { Timber.d("moveToPage ${page.number}") - val position = adapter.joinedItems.indexOfFirst { it.first == page || it.second == page } + val position = adapter.joinedItems.indexOfFirst { + it.first == page || it.second == page || + ( + config.splitPages && it.first is ReaderPage && + (it.first as? ReaderPage)?.isFromSamePage(page) == true && + (it.first as? ReaderPage)?.firstHalf != false + ) + } if (position != -1) { val currentPosition = pager.currentItem pager.setCurrentItem(position, animated) @@ -288,7 +299,7 @@ abstract class PagerViewer(val activity: ReaderActivity) : BaseViewer { val joinedItem = adapter.joinedItems.firstOrNull { it.first == page || it.second == page } activity.onPageSelected( joinedItem?.first as? ReaderPage ?: page, - joinedItem?.second != null + joinedItem?.second is ReaderPage ) } } else { 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 ee927fdc8f..793760531f 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 @@ -3,6 +3,7 @@ package eu.kanade.tachiyomi.ui.reader.viewer.pager import android.view.View import android.view.ViewGroup import eu.kanade.tachiyomi.ui.reader.model.ChapterTransition +import eu.kanade.tachiyomi.ui.reader.model.InsertPage import eu.kanade.tachiyomi.ui.reader.model.ReaderChapter import eu.kanade.tachiyomi.ui.reader.model.ReaderPage import eu.kanade.tachiyomi.ui.reader.model.ViewerChapters @@ -55,7 +56,7 @@ class PagerViewerAdapter(private val viewer: PagerViewer) : ViewPagerAdapter() { // however we should take account full pages when deciding val numberOfFullPages = ( - chapters.prevChapter.pages?.count { it.fullPage || it.isolatedPage } + chapters.prevChapter.pages?.count { it.fullPage == true || it.isolatedPage } ?: 0 ) if (prevPages != null) { @@ -134,7 +135,8 @@ class PagerViewerAdapter(private val viewer: PagerViewer) : ViewPagerAdapter() { override fun getItemPosition(view: Any): Int { if (view is PositionableView) { val position = joinedItems.indexOfFirst { - view.item == (it.first to it.second) + val secondPage = it.second as? ReaderPage + view.item == it.first to secondPage } if (position != -1) { return position @@ -148,13 +150,17 @@ class PagerViewerAdapter(private val viewer: PagerViewer) : ViewPagerAdapter() { 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 + if (viewer.config.splitPages) { + (oldCurrent?.first as? ReaderPage)?.firstHalf == false + } else { + oldCurrent?.second == current || + (current.index + 1) < ( + ( + oldCurrent?.second + ?: oldCurrent?.first + ) as? ReaderPage + )?.index ?: 0 + } ) // The listener may be removed when we split a page, so the ui may not have updated properly @@ -170,8 +176,36 @@ class PagerViewerAdapter(private val viewer: PagerViewer) : ViewPagerAdapter() { // If not in double mode, set up items like before subItems.forEach { (it as? ReaderPage)?.shiftedPage = false + (it as? ReaderPage)?.firstHalf = null + } + if (viewer.config.splitPages) { + var itemIndex = 0 + val pagedItems = subItems.toMutableList() + while (itemIndex < pagedItems.size) { + val page = pagedItems[itemIndex] as? ReaderPage + if (page == null) { + itemIndex++ + continue + } + if (page.longPage == true) { + page.firstHalf = true + // Add a second halved page after each full page. + pagedItems[itemIndex] = InsertPage(page).apply { firstHalf = true } + val secondHalf = InsertPage(page) + pagedItems.add(itemIndex + 1, secondHalf) + itemIndex++ + } + itemIndex++ + } + this.joinedItems = pagedItems.map { + Pair( + it, + if ((it as? ReaderPage)?.fullPage == true) (it as? ReaderPage)?.firstHalf else null + ) + }.toMutableList() + } else { + this.joinedItems = subItems.map { Pair(it, null) }.toMutableList() } - this.joinedItems = subItems.map { Pair(it, null) }.toMutableList() if (viewer is R2LPagerViewer) { joinedItems.reverse() } @@ -200,6 +234,7 @@ class PagerViewerAdapter(private val viewer: PagerViewer) : ViewPagerAdapter() { items.forEach { it?.shiftedPage = false + it?.firstHalf = null } // Step 3: If pages have been shifted, if (viewer.config.shiftDoublePage) { @@ -221,7 +256,7 @@ class PagerViewerAdapter(private val viewer: PagerViewer) : ViewPagerAdapter() { ) // Add a shifted page to the first place there isnt a full page (fullPageBeforeIndex until items.size).forEach { - if (items[it]?.fullPage == false) { + if (items[it]?.fullPage != true) { items[it]?.shiftedPage = true return@loop } @@ -281,10 +316,23 @@ class PagerViewerAdapter(private val viewer: PagerViewer) : ViewPagerAdapter() { 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) + useSecondPage && oldCurrent?.second is ReaderPage -> (oldCurrent.second ?: oldCurrent.first) else -> oldCurrent?.first ?: return } - var index = joinedItems.indexOfFirst { it.first == newPage || it.second == newPage } + var index = joinedItems.indexOfFirst { + val readerPage = it.first as? ReaderPage + val readerPage2 = it.second as? ReaderPage + val newReaderPage = newPage as? ReaderPage + it.first == newPage || it.second == newPage || + ( + readerPage != null && newReaderPage != null && + ( + readerPage.isFromSamePage(newReaderPage) || + readerPage2?.isFromSamePage(newReaderPage) == true + ) && + (readerPage.firstHalf == !useSecondPage || readerPage.firstHalf == null) + ) + } if (newPage is ChapterTransition && index == -1 && !forceTransition) { val newerPage = if (newPage is ChapterTransition.Next) { joinedItems.filter { @@ -297,6 +345,8 @@ class PagerViewerAdapter(private val viewer: PagerViewer) : ViewPagerAdapter() { } index = joinedItems.indexOfFirst { it.first == newerPage || it.second == newerPage } } - viewer.pager.setCurrentItem(index, false) + if (index > -1) { + viewer.pager.setCurrentItem(index, false) + } } } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsReaderController.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsReaderController.kt index 157c74724d..09fbb7cf3a 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsReaderController.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsReaderController.kt @@ -255,6 +255,12 @@ class SettingsReaderController : SettingsController() { infoPreference(R.string.automatic_can_still_switch).apply { preferences.pageLayout().asImmediateFlowIn(viewScope) { isVisible = it == PageLayout.AUTOMATIC.value } } + switchPreference { + key = Keys.automaticSplitsPage + titleRes = R.string.split_double_pages_portrait + defaultValue = false + preferences.pageLayout().asImmediateFlowIn(viewScope) { isVisible = it == PageLayout.AUTOMATIC.value } + } switchPreference { key = Keys.invertDoublePages titleRes = R.string.invert_double_pages diff --git a/app/src/main/java/eu/kanade/tachiyomi/util/system/ImageUtil.kt b/app/src/main/java/eu/kanade/tachiyomi/util/system/ImageUtil.kt index 93c5781a31..5eab0b11c1 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/util/system/ImageUtil.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/util/system/ImageUtil.kt @@ -278,6 +278,24 @@ object ImageUtil { return ColorDrawable(backgroundColor) } + fun splitBitmap( + imageBitmap: Bitmap, + secondHalf: Boolean, + progressCallback: ((Int) -> Unit)? = null + ): ByteArrayInputStream { + val height = imageBitmap.height + val width = imageBitmap.width + val result = Bitmap.createBitmap(width / 2, height, Bitmap.Config.ARGB_8888) + val canvas = Canvas(result) + progressCallback?.invoke(98) + canvas.drawBitmap(imageBitmap, Rect(if (!secondHalf) 0 else width / 2, 0, if (secondHalf) width else width / 2, height), result.rect, null) + progressCallback?.invoke(99) + val output = ByteArrayOutputStream() + result.compress(Bitmap.CompressFormat.JPEG, 100, output) + progressCallback?.invoke(100) + return ByteArrayInputStream(output.toByteArray()) + } + fun mergeBitmaps( imageBitmap: Bitmap, imageBitmap2: Bitmap, diff --git a/app/src/main/res/drawable/ic_book_open_split_24dp.xml b/app/src/main/res/drawable/ic_book_open_split_24dp.xml new file mode 100644 index 0000000000..95f8337a92 --- /dev/null +++ b/app/src/main/res/drawable/ic_book_open_split_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/values/arrays.xml b/app/src/main/res/values/arrays.xml index b31779561b..3efd177c65 100644 --- a/app/src/main/res/values/arrays.xml +++ b/app/src/main/res/values/arrays.xml @@ -113,6 +113,7 @@ @string/single_page @string/double_pages @string/automatic + @string/split_double_pages diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index bada17e9cf..6b8a1d8924 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -382,6 +382,7 @@ Reduces banding, but impacts performance Invert double pages + Split double pages in portrait Crop borders Crop borders (Paged) Crop borders (Webtoon) @@ -421,6 +422,7 @@ Original size Smart fit Zoom start position + Split double pages Double pages Single page Switch to double pages