Splitting double pages (#961)

* Split double pages

* various fixes for split double page
This commit is contained in:
Jays2Kings 2021-08-07 17:17:13 -04:00 committed by GitHub
parent ff9f79f2fc
commit 60d4c30e9a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
16 changed files with 281 additions and 45 deletions

View File

@ -74,6 +74,8 @@ object PreferenceKeys {
const val pageLayout = "page_layout" const val pageLayout = "page_layout"
const val automaticSplitsPage = "automatic_splits_page"
const val invertDoublePages = "invert_double_pages" const val invertDoublePages = "invert_double_pages"
const val readerBottomButtons = "reader_bottom_buttons" const val readerBottomButtons = "reader_bottom_buttons"

View File

@ -186,6 +186,8 @@ class PreferencesHelper(val context: Context) {
fun pageLayout() = flowPrefs.getInt(Keys.pageLayout, PageLayout.AUTOMATIC.value) fun pageLayout() = flowPrefs.getInt(Keys.pageLayout, PageLayout.AUTOMATIC.value)
fun automaticSplitsPage() = flowPrefs.getBoolean(Keys.automaticSplitsPage, false)
fun invertDoublePages() = flowPrefs.getBoolean(Keys.invertDoublePages, false) fun invertDoublePages() = flowPrefs.getBoolean(Keys.invertDoublePages, false)
fun readerBottomButtons() = flowPrefs.getStringSet( fun readerBottomButtons() = flowPrefs.getStringSet(

View File

@ -29,6 +29,7 @@ import androidx.core.view.GestureDetectorCompat
import androidx.core.view.ViewCompat import androidx.core.view.ViewCompat
import androidx.core.view.isInvisible import androidx.core.view.isInvisible
import androidx.core.view.isVisible import androidx.core.view.isVisible
import androidx.lifecycle.Lifecycle
import androidx.vectordrawable.graphics.drawable.AnimatedVectorDrawableCompat import androidx.vectordrawable.graphics.drawable.AnimatedVectorDrawableCompat
import com.afollestad.materialdialogs.MaterialDialog import com.afollestad.materialdialogs.MaterialDialog
import com.davemorrissey.labs.subscaleview.SubsamplingScaleImageView import com.davemorrissey.labs.subscaleview.SubsamplingScaleImageView
@ -342,8 +343,11 @@ class ReaderActivity :
binding.chaptersSheet.doublePage.setImageDrawable( binding.chaptersSheet.doublePage.setImageDrawable(
ContextCompat.getDrawable( ContextCompat.getDrawable(
this, this,
if (!isDoublePage) R.drawable.ic_single_page_24dp when {
else R.drawable.ic_book_open_variant_24dp 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) { 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) { private fun updateOrientationShortcut(preference: Int) {
@ -554,14 +553,39 @@ class ReaderActivity :
} }
with(binding.chaptersSheet) { with(binding.chaptersSheet) {
doublePage.setOnClickListener { with(doublePage) {
if (preferences.pageLayout().get() == PageLayout.AUTOMATIC.value) { compatToolTipText = getString(R.string.page_layout)
(viewer as? PagerViewer)?.config?.let { config -> setOnClickListener {
config.doublePages = !config.doublePages val config = (viewer as? PagerViewer)?.config
reloadChapters(config.doublePages, true) 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 { cropBordersSheetButton.setOnClickListener {
@ -917,6 +941,9 @@ class ReaderActivity :
setDoublePageMode(pViewer) setDoublePageMode(pViewer)
} else { } else {
pViewer.config.doublePages = doublePages pViewer.config.doublePages = doublePages
if (pViewer.config.autoDoublePages) {
pViewer.config.splitPages = preferences.automaticSplitsPage().get() && !pViewer.config.doublePages
}
} }
val currentChapter = presenter.getCurrentChapter() val currentChapter = presenter.getCurrentChapter()
if (doublePages) { if (doublePages) {
@ -925,7 +952,7 @@ class ReaderActivity :
binding.readerNav.pageSeekbar.progress + binding.readerNav.pageSeekbar.progress +
( (
currentChapter?.pages?.take(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 ) % 2 != 0
} }
@ -953,7 +980,7 @@ class ReaderActivity :
currentChapter.requestedPage + currentChapter.requestedPage +
( (
currentChapter.pages?.take(currentChapter.requestedPage) currentChapter.pages?.take(currentChapter.requestedPage)
?.count { it.fullPage || it.isolatedPage } ?: 0 ?.count { it.fullPage == true || it.isolatedPage } ?: 0
) )
) % 2 != 0 ) % 2 != 0
} }
@ -1042,7 +1069,7 @@ class ReaderActivity :
val currentPage = if (hasExtraPage) { val currentPage = if (hasExtraPage) {
if (resources.isLTR) "${page.number}-${page.number + 1}" else "${page.number + 1}-${page.number}" if (resources.isLTR) "${page.number}-${page.number + 1}" else "${page.number + 1}-${page.number}"
} else { } else {
"${page.number}" "${page.number}${if (page.firstHalf == false) "*" else ""}"
} }
val totalPages = pages.size.toString() val totalPages = pages.size.toString()
@ -1347,6 +1374,9 @@ class ReaderActivity :
private fun setDoublePageMode(viewer: PagerViewer) { private fun setDoublePageMode(viewer: PagerViewer) {
val currentOrientation = resources.configuration.orientation val currentOrientation = resources.configuration.orientation
viewer.config.doublePages = (currentOrientation == Configuration.ORIENTATION_LANDSCAPE) 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 { private fun handleIntentAction(intent: Intent): Boolean {
@ -1438,6 +1468,18 @@ class ReaderActivity :
preferences.pageLayout().asImmediateFlowIn(scope) { setBottomNavButtons(it) } 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.readerBottomButtons().asImmediateFlowIn(scope) { updateBottomShortcuts() }
preferences.readWithTapping().asImmediateFlowIn(scope) { preferences.readWithTapping().asImmediateFlowIn(scope) {

View File

@ -490,7 +490,7 @@ class ReaderPresenter(
if (shouldTrack && if (shouldTrack &&
// For double pages, check if the second to last page is doubled up // 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) (hasExtraPage && selectedChapter.pages?.lastIndex?.minus(1) == page.index)
) )
) { ) {

View File

@ -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
}
}

View File

@ -4,7 +4,7 @@ import android.graphics.drawable.Drawable
import eu.kanade.tachiyomi.source.model.Page import eu.kanade.tachiyomi.source.model.Page
import java.io.InputStream import java.io.InputStream
class ReaderPage( open class ReaderPage(
index: Int, index: Int,
url: String = "", url: String = "",
imageUrl: String? = null, imageUrl: String? = null,
@ -14,15 +14,21 @@ class ReaderPage(
/** Value to check if this page is used to as if it was too wide */ /** Value to check if this page is used to as if it was too wide */
var shiftedPage: Boolean = false, 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 */ /** 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) { ) : 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 */ /** Value to check if a page is too wide to be doubled up */
var fullPage: Boolean = false var fullPage: Boolean? = null
set(value) { set(value) {
field = 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
} }

View File

@ -7,6 +7,7 @@ enum class PageLayout(val value: Int, @StringRes val stringRes: Int, @StringRes
SINGLE_PAGE(0, R.string.single_page), SINGLE_PAGE(0, R.string.single_page),
DOUBLE_PAGES(1, R.string.double_pages), DOUBLE_PAGES(1, R.string.double_pages),
AUTOMATIC(2, R.string.automatic, R.string.automatic_orientation), AUTOMATIC(2, R.string.automatic, R.string.automatic_orientation),
SPLIT_PAGES(3, R.string.split_double_pages)
; ;
@StringRes val fullStringRes = _fullStringRes ?: stringRes @StringRes val fullStringRes = _fullStringRes ?: stringRes

View File

@ -58,6 +58,9 @@ class PagerConfig(
var autoDoublePages = preferences.pageLayout().get() == PageLayout.AUTOMATIC.value var autoDoublePages = preferences.pageLayout().get() == PageLayout.AUTOMATIC.value
var splitPages = preferences.pageLayout().get() == PageLayout.SPLIT_PAGES.value
var autoSplitPages = preferences.automaticSplitsPage().get()
init { init {
preferences.pageTransitions() preferences.pageTransitions()
.register({ usePageTransitions = it }) .register({ usePageTransitions = it })
@ -103,6 +106,7 @@ class PagerConfig(
.drop(1) .drop(1)
.onEach { .onEach {
autoDoublePages = it == PageLayout.AUTOMATIC.value autoDoublePages = it == PageLayout.AUTOMATIC.value
splitPages = it == PageLayout.SPLIT_PAGES.value
if (!autoDoublePages) { if (!autoDoublePages) {
doublePages = it == PageLayout.DOUBLE_PAGES.value doublePages = it == PageLayout.DOUBLE_PAGES.value
} }
@ -114,9 +118,12 @@ class PagerConfig(
autoDoublePages = it == PageLayout.AUTOMATIC.value autoDoublePages = it == PageLayout.AUTOMATIC.value
if (!autoDoublePages) { if (!autoDoublePages) {
doublePages = it == PageLayout.DOUBLE_PAGES.value doublePages = it == PageLayout.DOUBLE_PAGES.value
splitPages = it == PageLayout.SPLIT_PAGES.value
} }
}) })
preferences.automaticSplitsPage()
.register({ autoSplitPages = it })
navigationOverlayForNewUser = preferences.showNavigationOverlayNewUser().get() navigationOverlayForNewUser = preferences.showNavigationOverlayNewUser().get()
if (navigationOverlayForNewUser) { if (navigationOverlayForNewUser) {
preferences.showNavigationOverlayNewUser().set(false) preferences.showNavigationOverlayNewUser().set(false)

View File

@ -348,7 +348,7 @@ class PagerPageHolder(
val stream = streamFn().buffered(16) val stream = streamFn().buffered(16)
val stream2 = if (extraPage != null) streamFn2?.invoke()?.buffered(16) else null 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) || ImageUtil.isAnimatedAndSupported(stream) ||
if (stream2 != null) ImageUtil.isAnimatedAndSupported(stream2) else false if (stream2 != null) ImageUtil.isAnimatedAndSupported(stream2) else false
} }
@ -507,6 +507,15 @@ class PagerPageHolder(
} }
setOnImageEventListener( setOnImageEventListener(
object : SubsamplingScaleImageView.DefaultOnImageEventListener() { 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() { override fun onReady() {
var centerV = 0f var centerV = 0f
when (config.imageZoomType) { when (config.imageZoomType) {
@ -651,9 +660,63 @@ class PagerPageHolder(
return decodeLayout return decodeLayout
} }
private fun mergePages(imageStream: InputStream, imageStream2: InputStream?): InputStream { private fun mergeOrSplitPages(imageStream: InputStream, imageStream2: InputStream?): InputStream {
imageStream2 ?: return imageStream if (page.longPage == true && viewer.config.splitPages) {
if (page.fullPage) return imageStream 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)) { if (ImageUtil.isAnimatedAndSupported(imageStream)) {
page.fullPage = true page.fullPage = true
skipExtra = true skipExtra = true
@ -732,7 +795,7 @@ class PagerPageHolder(
} }
private fun splitDoublePages() { private fun splitDoublePages() {
extraPage ?: return // extraPage ?: return
viewer.splitDoublePages(page) viewer.splitDoublePages(page)
if (extraPage?.fullPage == true) { if (extraPage?.fullPage == true) {
extraPage = null extraPage = null

View File

@ -156,7 +156,11 @@ abstract class PagerViewer(val activity: ReaderActivity) : BaseViewer {
val allowPreload = checkAllowPreload(page.first as? ReaderPage) val allowPreload = checkAllowPreload(page.first as? ReaderPage)
currentPage = page.first currentPage = page.first
when (val aPage = 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) is ChapterTransition -> onTransitionSelected(aPage)
} }
} }
@ -275,7 +279,14 @@ abstract class PagerViewer(val activity: ReaderActivity) : BaseViewer {
*/ */
override fun moveToPage(page: ReaderPage, animated: Boolean) { override fun moveToPage(page: ReaderPage, animated: Boolean) {
Timber.d("moveToPage ${page.number}") 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) { if (position != -1) {
val currentPosition = pager.currentItem val currentPosition = pager.currentItem
pager.setCurrentItem(position, animated) 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 } val joinedItem = adapter.joinedItems.firstOrNull { it.first == page || it.second == page }
activity.onPageSelected( activity.onPageSelected(
joinedItem?.first as? ReaderPage ?: page, joinedItem?.first as? ReaderPage ?: page,
joinedItem?.second != null joinedItem?.second is ReaderPage
) )
} }
} else { } else {

View File

@ -3,6 +3,7 @@ package eu.kanade.tachiyomi.ui.reader.viewer.pager
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import eu.kanade.tachiyomi.ui.reader.model.ChapterTransition 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.ReaderChapter
import eu.kanade.tachiyomi.ui.reader.model.ReaderPage import eu.kanade.tachiyomi.ui.reader.model.ReaderPage
import eu.kanade.tachiyomi.ui.reader.model.ViewerChapters 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 // however we should take account full pages when deciding
val numberOfFullPages = val numberOfFullPages =
( (
chapters.prevChapter.pages?.count { it.fullPage || it.isolatedPage } chapters.prevChapter.pages?.count { it.fullPage == true || it.isolatedPage }
?: 0 ?: 0
) )
if (prevPages != null) { if (prevPages != null) {
@ -134,7 +135,8 @@ class PagerViewerAdapter(private val viewer: PagerViewer) : ViewPagerAdapter() {
override fun getItemPosition(view: Any): Int { override fun getItemPosition(view: Any): Int {
if (view is PositionableView) { if (view is PositionableView) {
val position = joinedItems.indexOfFirst { 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) { if (position != -1) {
return position return position
@ -148,13 +150,17 @@ class PagerViewerAdapter(private val viewer: PagerViewer) : ViewPagerAdapter() {
fun splitDoublePages(current: ReaderPage) { fun splitDoublePages(current: ReaderPage) {
val oldCurrent = joinedItems.getOrNull(viewer.pager.currentItem) val oldCurrent = joinedItems.getOrNull(viewer.pager.currentItem)
setJoinedItems( setJoinedItems(
oldCurrent?.second == current || if (viewer.config.splitPages) {
(current.index + 1) < ( (oldCurrent?.first as? ReaderPage)?.firstHalf == false
( } else {
oldCurrent?.second oldCurrent?.second == current ||
?: oldCurrent?.first (current.index + 1) < (
) as? ReaderPage (
)?.index ?: 0 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 // 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 // If not in double mode, set up items like before
subItems.forEach { subItems.forEach {
(it as? ReaderPage)?.shiftedPage = false (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<Any, Any?>(
it,
if ((it as? ReaderPage)?.fullPage == true) (it as? ReaderPage)?.firstHalf else null
)
}.toMutableList()
} else {
this.joinedItems = subItems.map { Pair<Any, Any?>(it, null) }.toMutableList()
} }
this.joinedItems = subItems.map { Pair<Any, Any?>(it, null) }.toMutableList()
if (viewer is R2LPagerViewer) { if (viewer is R2LPagerViewer) {
joinedItems.reverse() joinedItems.reverse()
} }
@ -200,6 +234,7 @@ class PagerViewerAdapter(private val viewer: PagerViewer) : ViewPagerAdapter() {
items.forEach { items.forEach {
it?.shiftedPage = false it?.shiftedPage = false
it?.firstHalf = null
} }
// Step 3: If pages have been shifted, // Step 3: If pages have been shifted,
if (viewer.config.shiftDoublePage) { 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 // Add a shifted page to the first place there isnt a full page
(fullPageBeforeIndex until items.size).forEach { (fullPageBeforeIndex until items.size).forEach {
if (items[it]?.fullPage == false) { if (items[it]?.fullPage != true) {
items[it]?.shiftedPage = true items[it]?.shiftedPage = true
return@loop return@loop
} }
@ -281,10 +316,23 @@ class PagerViewerAdapter(private val viewer: PagerViewer) : ViewPagerAdapter() {
when { when {
(oldCurrent?.first as? ReaderPage)?.chapter != currentChapter && (oldCurrent?.first as? ReaderPage)?.chapter != currentChapter &&
(oldCurrent?.first as? ChapterTransition)?.from != currentChapter -> subItems.find { (it 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 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) { if (newPage is ChapterTransition && index == -1 && !forceTransition) {
val newerPage = if (newPage is ChapterTransition.Next) { val newerPage = if (newPage is ChapterTransition.Next) {
joinedItems.filter { joinedItems.filter {
@ -297,6 +345,8 @@ class PagerViewerAdapter(private val viewer: PagerViewer) : ViewPagerAdapter() {
} }
index = joinedItems.indexOfFirst { it.first == newerPage || it.second == newerPage } index = joinedItems.indexOfFirst { it.first == newerPage || it.second == newerPage }
} }
viewer.pager.setCurrentItem(index, false) if (index > -1) {
viewer.pager.setCurrentItem(index, false)
}
} }
} }

View File

@ -255,6 +255,12 @@ class SettingsReaderController : SettingsController() {
infoPreference(R.string.automatic_can_still_switch).apply { infoPreference(R.string.automatic_can_still_switch).apply {
preferences.pageLayout().asImmediateFlowIn(viewScope) { isVisible = it == PageLayout.AUTOMATIC.value } 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 { switchPreference {
key = Keys.invertDoublePages key = Keys.invertDoublePages
titleRes = R.string.invert_double_pages titleRes = R.string.invert_double_pages

View File

@ -278,6 +278,24 @@ object ImageUtil {
return ColorDrawable(backgroundColor) 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( fun mergeBitmaps(
imageBitmap: Bitmap, imageBitmap: Bitmap,
imageBitmap2: Bitmap, imageBitmap2: Bitmap,

View File

@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="#FF000000"
android:pathData="M13.9,12h6.5v1.4h-6.5M13.9,9.7h6.5v1.4h-6.5M13.9,14.4h6.5v1.4h-6.5M21.3,4.6H13l0.6,1L13,6.5v12.1l0.6,0.9L13,20.4h8.4c1,0 1.9,-0.8 1.9,-1.9V6.5C23.2,5.4 22.3,4.6 21.3,4.6M21.3,18.5H13V6.5h8.4M7.3,4.6H3c-1,0 -1.9,0.8 -1.9,1.9v12.1c0,1 0.8,1.9 1.9,1.9h8.4l-1.1,-1.9l1.1,-2.2l-1,-1.8l1,-2l-0.9,-2.2l0.9,-1.8l-0.9,-2l0.9,-1.9"/>
</vector>

View File

@ -113,6 +113,7 @@
<item>@string/single_page</item> <item>@string/single_page</item>
<item>@string/double_pages</item> <item>@string/double_pages</item>
<item>@string/automatic</item> <item>@string/automatic</item>
<item>@string/split_double_pages</item>
</string-array> </string-array>
<string-array name="invert_tapping_mode"> <string-array name="invert_tapping_mode">

View File

@ -382,6 +382,7 @@
<string name="reduces_banding_impacts_performance">Reduces banding, but impacts <string name="reduces_banding_impacts_performance">Reduces banding, but impacts
performance</string> performance</string>
<string name="invert_double_pages">Invert double pages</string> <string name="invert_double_pages">Invert double pages</string>
<string name="split_double_pages_portrait">Split double pages in portrait</string>
<string name="crop_borders">Crop borders</string> <string name="crop_borders">Crop borders</string>
<string name="crop_borders_paged">Crop borders (Paged)</string> <string name="crop_borders_paged">Crop borders (Paged)</string>
<string name="crop_borders_webtoon">Crop borders (Webtoon)</string> <string name="crop_borders_webtoon">Crop borders (Webtoon)</string>
@ -421,6 +422,7 @@
<string name="original_size">Original size</string> <string name="original_size">Original size</string>
<string name="smart_fit">Smart fit</string> <string name="smart_fit">Smart fit</string>
<string name="zoom_start_position">Zoom start position</string> <string name="zoom_start_position">Zoom start position</string>
<string name="split_double_pages">Split double pages</string>
<string name="double_pages">Double pages</string> <string name="double_pages">Double pages</string>
<string name="single_page">Single page</string> <string name="single_page">Single page</string>
<string name="switch_to_double">Switch to double pages</string> <string name="switch_to_double">Switch to double pages</string>