mirror of
https://github.com/tachiyomiorg/tachiyomi.git
synced 2024-11-20 06:09:19 +01:00
Splitting double pages (#961)
* Split double pages * various fixes for split double page
This commit is contained in:
parent
ff9f79f2fc
commit
60d4c30e9a
@ -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"
|
||||||
|
@ -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(
|
||||||
|
@ -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) {
|
||||||
|
@ -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)
|
||||||
)
|
)
|
||||||
) {
|
) {
|
||||||
|
@ -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
|
||||||
|
}
|
||||||
|
}
|
@ -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
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
|
@ -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)
|
||||||
|
@ -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
|
||||||
|
@ -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 {
|
||||||
|
@ -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)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
|
@ -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,
|
||||||
|
9
app/src/main/res/drawable/ic_book_open_split_24dp.xml
Normal file
9
app/src/main/res/drawable/ic_book_open_split_24dp.xml
Normal 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>
|
@ -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">
|
||||||
|
@ -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>
|
||||||
|
Loading…
Reference in New Issue
Block a user