mirror of
https://github.com/mihonapp/mihon.git
synced 2024-11-21 20:47:03 -05:00
Navigate to pan / landscape zoom (#6481)
* pan if the image is zoomed instead of navigating away quickly display full landscape image before zooming to fit height in fit to screen * add Tap to pan preference, defaults to true add landscape zoom preference, defaults to false * hide landscape image zoom option if scale is not fit screen * fix landscape image zoom for first image and loading image * properly reload pagerholders when landscape zoom option is changed * enable landscape zoom by default
This commit is contained in:
parent
71ddb16574
commit
d8719ceee9
10 changed files with 223 additions and 15 deletions
|
@ -129,6 +129,10 @@ class PreferencesHelper(val context: Context) {
|
||||||
|
|
||||||
fun cropBorders() = flowPrefs.getBoolean("crop_borders", false)
|
fun cropBorders() = flowPrefs.getBoolean("crop_borders", false)
|
||||||
|
|
||||||
|
fun navigateToPan() = flowPrefs.getBoolean("navigate_pan", true)
|
||||||
|
|
||||||
|
fun landscapeZoom() = flowPrefs.getBoolean("landscape_zoom", true)
|
||||||
|
|
||||||
fun cropBordersWebtoon() = flowPrefs.getBoolean("crop_borders_webtoon", false)
|
fun cropBordersWebtoon() = flowPrefs.getBoolean("crop_borders_webtoon", false)
|
||||||
|
|
||||||
fun webtoonSidePadding() = flowPrefs.getInt("webtoon_side_padding", 0)
|
fun webtoonSidePadding() = flowPrefs.getInt("webtoon_side_padding", 0)
|
||||||
|
|
|
@ -74,9 +74,17 @@ class ReaderReadingModeSettings @JvmOverloads constructor(context: Context, attr
|
||||||
binding.pagerPrefsGroup.tappingInverted.bindToPreference(preferences.pagerNavInverted())
|
binding.pagerPrefsGroup.tappingInverted.bindToPreference(preferences.pagerNavInverted())
|
||||||
|
|
||||||
binding.pagerPrefsGroup.pagerNav.bindToPreference(preferences.navigationModePager())
|
binding.pagerPrefsGroup.pagerNav.bindToPreference(preferences.navigationModePager())
|
||||||
|
|
||||||
|
// Makes so that landscape zoom gets hidden away when image scale type is not fit screen
|
||||||
binding.pagerPrefsGroup.scaleType.bindToPreference(preferences.imageScaleType(), 1)
|
binding.pagerPrefsGroup.scaleType.bindToPreference(preferences.imageScaleType(), 1)
|
||||||
|
preferences.imageScaleType()
|
||||||
|
.asImmediateFlow { binding.pagerPrefsGroup.landscapeZoom.isVisible = it == 1 }
|
||||||
|
.launchIn((context as ReaderActivity).lifecycleScope)
|
||||||
|
binding.pagerPrefsGroup.landscapeZoom.bindToPreference(preferences.landscapeZoom())
|
||||||
|
|
||||||
binding.pagerPrefsGroup.zoomStart.bindToPreference(preferences.zoomStart(), 1)
|
binding.pagerPrefsGroup.zoomStart.bindToPreference(preferences.zoomStart(), 1)
|
||||||
binding.pagerPrefsGroup.cropBorders.bindToPreference(preferences.cropBorders())
|
binding.pagerPrefsGroup.cropBorders.bindToPreference(preferences.cropBorders())
|
||||||
|
binding.pagerPrefsGroup.navigatePan.bindToPreference(preferences.navigateToPan())
|
||||||
|
|
||||||
// Makes so that dual page invert gets hidden away when turning of dual page split
|
// Makes so that dual page invert gets hidden away when turning of dual page split
|
||||||
binding.pagerPrefsGroup.dualPageSplit.bindToPreference(preferences.dualPageSplitPaged())
|
binding.pagerPrefsGroup.dualPageSplit.bindToPreference(preferences.dualPageSplitPaged())
|
||||||
|
|
|
@ -2,6 +2,7 @@ package eu.kanade.tachiyomi.ui.reader.viewer
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.graphics.PointF
|
import android.graphics.PointF
|
||||||
|
import android.graphics.RectF
|
||||||
import android.graphics.drawable.Animatable
|
import android.graphics.drawable.Animatable
|
||||||
import android.graphics.drawable.BitmapDrawable
|
import android.graphics.drawable.BitmapDrawable
|
||||||
import android.graphics.drawable.Drawable
|
import android.graphics.drawable.Drawable
|
||||||
|
@ -22,11 +23,14 @@ import coil.request.CachePolicy
|
||||||
import coil.request.ImageRequest
|
import coil.request.ImageRequest
|
||||||
import com.davemorrissey.labs.subscaleview.ImageSource
|
import com.davemorrissey.labs.subscaleview.ImageSource
|
||||||
import com.davemorrissey.labs.subscaleview.SubsamplingScaleImageView
|
import com.davemorrissey.labs.subscaleview.SubsamplingScaleImageView
|
||||||
|
import com.davemorrissey.labs.subscaleview.SubsamplingScaleImageView.EASE_IN_OUT_QUAD
|
||||||
|
import com.davemorrissey.labs.subscaleview.SubsamplingScaleImageView.EASE_OUT_QUAD
|
||||||
import com.davemorrissey.labs.subscaleview.SubsamplingScaleImageView.SCALE_TYPE_CENTER_INSIDE
|
import com.davemorrissey.labs.subscaleview.SubsamplingScaleImageView.SCALE_TYPE_CENTER_INSIDE
|
||||||
import com.github.chrisbanes.photoview.PhotoView
|
import com.github.chrisbanes.photoview.PhotoView
|
||||||
import eu.kanade.tachiyomi.ui.reader.viewer.webtoon.WebtoonSubsamplingImageView
|
import eu.kanade.tachiyomi.ui.reader.viewer.webtoon.WebtoonSubsamplingImageView
|
||||||
import eu.kanade.tachiyomi.util.system.GLUtil
|
import eu.kanade.tachiyomi.util.system.GLUtil
|
||||||
import eu.kanade.tachiyomi.util.system.animatorDurationScale
|
import eu.kanade.tachiyomi.util.system.animatorDurationScale
|
||||||
|
import eu.kanade.tachiyomi.util.view.isVisible
|
||||||
import java.io.InputStream
|
import java.io.InputStream
|
||||||
import java.nio.ByteBuffer
|
import java.nio.ByteBuffer
|
||||||
|
|
||||||
|
@ -48,6 +52,8 @@ open class ReaderPageImageView @JvmOverloads constructor(
|
||||||
|
|
||||||
private var pageView: View? = null
|
private var pageView: View? = null
|
||||||
|
|
||||||
|
private var config: Config? = null
|
||||||
|
|
||||||
var onImageLoaded: (() -> Unit)? = null
|
var onImageLoaded: (() -> Unit)? = null
|
||||||
var onImageLoadError: (() -> Unit)? = null
|
var onImageLoadError: (() -> Unit)? = null
|
||||||
var onScaleChanged: ((newScale: Float) -> Unit)? = null
|
var onScaleChanged: ((newScale: Float) -> Unit)? = null
|
||||||
|
@ -79,7 +85,50 @@ open class ReaderPageImageView @JvmOverloads constructor(
|
||||||
onViewClicked?.invoke()
|
onViewClicked?.invoke()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
open fun onPageSelected(forward: Boolean) {
|
||||||
|
with(pageView as? SubsamplingScaleImageView) {
|
||||||
|
if (this == null) return
|
||||||
|
if (isReady) {
|
||||||
|
landscapeZoom(forward)
|
||||||
|
} else {
|
||||||
|
setOnImageEventListener(
|
||||||
|
object : SubsamplingScaleImageView.DefaultOnImageEventListener() {
|
||||||
|
override fun onReady() {
|
||||||
|
setupZoom(config)
|
||||||
|
landscapeZoom(forward)
|
||||||
|
this@ReaderPageImageView.onImageLoaded()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onImageLoadError(e: Exception) {
|
||||||
|
onImageLoadError()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun SubsamplingScaleImageView.landscapeZoom(forward: Boolean) {
|
||||||
|
if (config != null && config!!.landscapeZoom && config!!.minimumScaleType == SCALE_TYPE_CENTER_INSIDE && sWidth > sHeight && scale == minScale) {
|
||||||
|
handler.postDelayed({
|
||||||
|
val point = when (config!!.zoomStartPosition) {
|
||||||
|
ZoomStartPosition.LEFT -> if (forward) PointF(0F, 0F) else PointF(sWidth.toFloat(), 0F)
|
||||||
|
ZoomStartPosition.RIGHT -> if (forward) PointF(sWidth.toFloat(), 0F) else PointF(0F, 0F)
|
||||||
|
ZoomStartPosition.CENTER -> center.also { it?.y = 0F }
|
||||||
|
}
|
||||||
|
|
||||||
|
val targetScale = height.toFloat() / sHeight.toFloat()
|
||||||
|
animateScaleAndCenter(targetScale, point)!!
|
||||||
|
.withDuration(500)
|
||||||
|
.withEasing(EASE_IN_OUT_QUAD)
|
||||||
|
.withInterruptible(true)
|
||||||
|
.start()
|
||||||
|
}, 500)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fun setImage(drawable: Drawable, config: Config) {
|
fun setImage(drawable: Drawable, config: Config) {
|
||||||
|
this.config = config
|
||||||
if (drawable is Animatable) {
|
if (drawable is Animatable) {
|
||||||
prepareAnimatedImageView()
|
prepareAnimatedImageView()
|
||||||
setAnimatedImage(drawable, config)
|
setAnimatedImage(drawable, config)
|
||||||
|
@ -90,6 +139,7 @@ open class ReaderPageImageView @JvmOverloads constructor(
|
||||||
}
|
}
|
||||||
|
|
||||||
fun setImage(inputStream: InputStream, isAnimated: Boolean, config: Config) {
|
fun setImage(inputStream: InputStream, isAnimated: Boolean, config: Config) {
|
||||||
|
this.config = config
|
||||||
if (isAnimated) {
|
if (isAnimated) {
|
||||||
prepareAnimatedImageView()
|
prepareAnimatedImageView()
|
||||||
setAnimatedImage(inputStream, config)
|
setAnimatedImage(inputStream, config)
|
||||||
|
@ -107,6 +157,60 @@ open class ReaderPageImageView @JvmOverloads constructor(
|
||||||
it.isVisible = false
|
it.isVisible = false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if the image can be panned to the left
|
||||||
|
*/
|
||||||
|
fun canPanLeft(): Boolean = canPan { it.left }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if the image can be panned to the right
|
||||||
|
*/
|
||||||
|
fun canPanRight(): Boolean = canPan { it.right }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check whether the image can be panned.
|
||||||
|
* @param fn a function that returns the direction to check for
|
||||||
|
*/
|
||||||
|
private fun canPan(fn: (RectF) -> Float): Boolean {
|
||||||
|
(pageView as? SubsamplingScaleImageView)?.let { view ->
|
||||||
|
RectF().let {
|
||||||
|
view.getPanRemaining(it)
|
||||||
|
return fn(it) > 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Pans the image to the left by a screen's width worth.
|
||||||
|
*/
|
||||||
|
fun panLeft() {
|
||||||
|
pan { center, view -> center.also { it.x -= view.width / view.scale } }
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Pans the image to the right by a screen's width worth.
|
||||||
|
*/
|
||||||
|
fun panRight() {
|
||||||
|
pan { center, view -> center.also { it.x += view.width / view.scale } }
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Pans the image.
|
||||||
|
* @param fn a function that computes the new center of the image
|
||||||
|
*/
|
||||||
|
private fun pan(fn: (PointF, SubsamplingScaleImageView) -> PointF) {
|
||||||
|
(pageView as? SubsamplingScaleImageView)?.let { view ->
|
||||||
|
|
||||||
|
val target = fn(view.center ?: return, view)
|
||||||
|
view.animateCenter(target)!!
|
||||||
|
.withEasing(EASE_OUT_QUAD)
|
||||||
|
.withDuration(250)
|
||||||
|
.withInterruptible(true)
|
||||||
|
.start()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private fun prepareNonAnimatedImageView() {
|
private fun prepareNonAnimatedImageView() {
|
||||||
if (pageView is SubsamplingScaleImageView) return
|
if (pageView is SubsamplingScaleImageView) return
|
||||||
removeView(pageView)
|
removeView(pageView)
|
||||||
|
@ -136,6 +240,18 @@ open class ReaderPageImageView @JvmOverloads constructor(
|
||||||
addView(pageView, MATCH_PARENT, MATCH_PARENT)
|
addView(pageView, MATCH_PARENT, MATCH_PARENT)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun SubsamplingScaleImageView.setupZoom(config: Config?) {
|
||||||
|
// 5x zoom
|
||||||
|
maxScale = scale * MAX_ZOOM_SCALE
|
||||||
|
setDoubleTapZoomScale(scale * 2)
|
||||||
|
|
||||||
|
when (config?.zoomStartPosition) {
|
||||||
|
ZoomStartPosition.LEFT -> setScaleAndCenter(scale, PointF(0F, 0F))
|
||||||
|
ZoomStartPosition.RIGHT -> setScaleAndCenter(scale, PointF(sWidth.toFloat(), 0F))
|
||||||
|
ZoomStartPosition.CENTER -> setScaleAndCenter(scale, center.also { it?.y = 0F })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private fun setNonAnimatedImage(
|
private fun setNonAnimatedImage(
|
||||||
image: Any,
|
image: Any,
|
||||||
config: Config
|
config: Config
|
||||||
|
@ -147,15 +263,8 @@ open class ReaderPageImageView @JvmOverloads constructor(
|
||||||
setOnImageEventListener(
|
setOnImageEventListener(
|
||||||
object : SubsamplingScaleImageView.DefaultOnImageEventListener() {
|
object : SubsamplingScaleImageView.DefaultOnImageEventListener() {
|
||||||
override fun onReady() {
|
override fun onReady() {
|
||||||
// 5x zoom
|
setupZoom(config)
|
||||||
maxScale = scale * MAX_ZOOM_SCALE
|
if (isVisible()) landscapeZoom(true)
|
||||||
setDoubleTapZoomScale(scale * 2)
|
|
||||||
|
|
||||||
when (config.zoomStartPosition) {
|
|
||||||
ZoomStartPosition.LEFT -> setScaleAndCenter(scale, PointF(0F, 0F))
|
|
||||||
ZoomStartPosition.RIGHT -> setScaleAndCenter(scale, PointF(sWidth.toFloat(), 0F))
|
|
||||||
ZoomStartPosition.CENTER -> setScaleAndCenter(scale, center.also { it?.y = 0F })
|
|
||||||
}
|
|
||||||
this@ReaderPageImageView.onImageLoaded()
|
this@ReaderPageImageView.onImageLoaded()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -259,7 +368,8 @@ open class ReaderPageImageView @JvmOverloads constructor(
|
||||||
val zoomDuration: Int,
|
val zoomDuration: Int,
|
||||||
val minimumScaleType: Int = SCALE_TYPE_CENTER_INSIDE,
|
val minimumScaleType: Int = SCALE_TYPE_CENTER_INSIDE,
|
||||||
val cropBorders: Boolean = false,
|
val cropBorders: Boolean = false,
|
||||||
val zoomStartPosition: ZoomStartPosition = ZoomStartPosition.CENTER
|
val zoomStartPosition: ZoomStartPosition = ZoomStartPosition.CENTER,
|
||||||
|
val landscapeZoom: Boolean = false,
|
||||||
)
|
)
|
||||||
|
|
||||||
enum class ZoomStartPosition {
|
enum class ZoomStartPosition {
|
||||||
|
|
|
@ -41,6 +41,12 @@ class PagerConfig(
|
||||||
var imageCropBorders = false
|
var imageCropBorders = false
|
||||||
private set
|
private set
|
||||||
|
|
||||||
|
var navigateToPan = false
|
||||||
|
private set
|
||||||
|
|
||||||
|
var landscapeZoom = false
|
||||||
|
private set
|
||||||
|
|
||||||
init {
|
init {
|
||||||
preferences.readerTheme()
|
preferences.readerTheme()
|
||||||
.register(
|
.register(
|
||||||
|
@ -60,6 +66,12 @@ class PagerConfig(
|
||||||
preferences.cropBorders()
|
preferences.cropBorders()
|
||||||
.register({ imageCropBorders = it }, { imagePropertyChangedListener?.invoke() })
|
.register({ imageCropBorders = it }, { imagePropertyChangedListener?.invoke() })
|
||||||
|
|
||||||
|
preferences.navigateToPan()
|
||||||
|
.register({ navigateToPan = it })
|
||||||
|
|
||||||
|
preferences.landscapeZoom()
|
||||||
|
.register({ landscapeZoom = it }, { imagePropertyChangedListener?.invoke() })
|
||||||
|
|
||||||
preferences.navigationModePager()
|
preferences.navigationModePager()
|
||||||
.register({ navigationMode = it }, { updateNavigation(navigationMode) })
|
.register({ navigationMode = it }, { updateNavigation(navigationMode) })
|
||||||
|
|
||||||
|
|
|
@ -226,7 +226,8 @@ class PagerPageHolder(
|
||||||
zoomDuration = viewer.config.doubleTapAnimDuration,
|
zoomDuration = viewer.config.doubleTapAnimDuration,
|
||||||
minimumScaleType = viewer.config.imageScaleType,
|
minimumScaleType = viewer.config.imageScaleType,
|
||||||
cropBorders = viewer.config.imageCropBorders,
|
cropBorders = viewer.config.imageCropBorders,
|
||||||
zoomStartPosition = viewer.config.imageZoomType
|
zoomStartPosition = viewer.config.imageZoomType,
|
||||||
|
landscapeZoom = viewer.config.landscapeZoom,
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
if (!isAnimated) {
|
if (!isAnimated) {
|
||||||
|
|
|
@ -6,6 +6,7 @@ import android.view.KeyEvent
|
||||||
import android.view.MotionEvent
|
import android.view.MotionEvent
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup.LayoutParams
|
import android.view.ViewGroup.LayoutParams
|
||||||
|
import androidx.core.view.children
|
||||||
import androidx.core.view.isGone
|
import androidx.core.view.isGone
|
||||||
import androidx.core.view.isVisible
|
import androidx.core.view.isVisible
|
||||||
import androidx.viewpager.widget.ViewPager
|
import androidx.viewpager.widget.ViewPager
|
||||||
|
@ -154,6 +155,14 @@ abstract class PagerViewer(val activity: ReaderActivity) : BaseViewer {
|
||||||
return pager
|
return pager
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the PagerPageHolder for the provided page
|
||||||
|
*/
|
||||||
|
private fun getPageHolder(page: ReaderPage): PagerPageHolder? =
|
||||||
|
pager.children
|
||||||
|
.filterIsInstance(PagerPageHolder::class.java)
|
||||||
|
.firstOrNull { it.item.index == page.index }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called when a new page (either a [ReaderPage] or [ChapterTransition]) is marked as active
|
* Called when a new page (either a [ReaderPage] or [ChapterTransition]) is marked as active
|
||||||
*/
|
*/
|
||||||
|
@ -161,9 +170,16 @@ abstract class PagerViewer(val activity: ReaderActivity) : BaseViewer {
|
||||||
val page = adapter.items.getOrNull(position)
|
val page = adapter.items.getOrNull(position)
|
||||||
if (page != null && currentPage != page) {
|
if (page != null && currentPage != page) {
|
||||||
val allowPreload = checkAllowPreload(page as? ReaderPage)
|
val allowPreload = checkAllowPreload(page as? ReaderPage)
|
||||||
|
val forward = when {
|
||||||
|
currentPage is ReaderPage && page is ReaderPage ->
|
||||||
|
page.number > (currentPage as ReaderPage).number
|
||||||
|
currentPage is ChapterTransition.Prev && page is ReaderPage ->
|
||||||
|
false
|
||||||
|
else -> true
|
||||||
|
}
|
||||||
currentPage = page
|
currentPage = page
|
||||||
when (page) {
|
when (page) {
|
||||||
is ReaderPage -> onReaderPageSelected(page, allowPreload)
|
is ReaderPage -> onReaderPageSelected(page, allowPreload, forward)
|
||||||
is ChapterTransition -> onTransitionSelected(page)
|
is ChapterTransition -> onTransitionSelected(page)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -192,11 +208,14 @@ abstract class PagerViewer(val activity: ReaderActivity) : BaseViewer {
|
||||||
* Called when a [ReaderPage] is marked as active. It notifies the
|
* Called when a [ReaderPage] is marked as active. It notifies the
|
||||||
* activity of the change and requests the preload of the next chapter if this is the last page.
|
* activity of the change and requests the preload of the next chapter if this is the last page.
|
||||||
*/
|
*/
|
||||||
private fun onReaderPageSelected(page: ReaderPage, allowPreload: Boolean) {
|
private fun onReaderPageSelected(page: ReaderPage, allowPreload: Boolean, forward: Boolean) {
|
||||||
val pages = page.chapter.pages ?: return
|
val pages = page.chapter.pages ?: return
|
||||||
logcat { "onReaderPageSelected: ${page.number}/${pages.size}" }
|
logcat { "onReaderPageSelected: ${page.number}/${pages.size}" }
|
||||||
activity.onPageSelected(page)
|
activity.onPageSelected(page)
|
||||||
|
|
||||||
|
// Notify holder of page change
|
||||||
|
getPageHolder(page)?.onPageSelected(forward)
|
||||||
|
|
||||||
// Skip preload on inserts it causes unwanted page jumping
|
// Skip preload on inserts it causes unwanted page jumping
|
||||||
if (page is InsertPage) {
|
if (page is InsertPage) {
|
||||||
return
|
return
|
||||||
|
@ -294,7 +313,12 @@ abstract class PagerViewer(val activity: ReaderActivity) : BaseViewer {
|
||||||
*/
|
*/
|
||||||
protected open fun moveRight() {
|
protected open fun moveRight() {
|
||||||
if (pager.currentItem != adapter.count - 1) {
|
if (pager.currentItem != adapter.count - 1) {
|
||||||
pager.setCurrentItem(pager.currentItem + 1, config.usePageTransitions)
|
val holder = (currentPage as? ReaderPage)?.let { getPageHolder(it) }
|
||||||
|
if (holder != null && config.navigateToPan && holder.canPanRight()) {
|
||||||
|
holder.panRight()
|
||||||
|
} else {
|
||||||
|
pager.setCurrentItem(pager.currentItem + 1, config.usePageTransitions)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -303,7 +327,12 @@ abstract class PagerViewer(val activity: ReaderActivity) : BaseViewer {
|
||||||
*/
|
*/
|
||||||
protected open fun moveLeft() {
|
protected open fun moveLeft() {
|
||||||
if (pager.currentItem != 0) {
|
if (pager.currentItem != 0) {
|
||||||
pager.setCurrentItem(pager.currentItem - 1, config.usePageTransitions)
|
val holder = (currentPage as? ReaderPage)?.let { getPageHolder(it) }
|
||||||
|
if (holder != null && config.navigateToPan && holder.canPanLeft()) {
|
||||||
|
holder.panLeft()
|
||||||
|
} else {
|
||||||
|
pager.setCurrentItem(pager.currentItem - 1, config.usePageTransitions)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -183,6 +183,11 @@ class SettingsReaderController : SettingsController() {
|
||||||
entryValues = arrayOf("1", "2", "3", "4", "5", "6")
|
entryValues = arrayOf("1", "2", "3", "4", "5", "6")
|
||||||
summary = "%s"
|
summary = "%s"
|
||||||
}
|
}
|
||||||
|
switchPreference {
|
||||||
|
bindTo(preferences.landscapeZoom())
|
||||||
|
titleRes = R.string.pref_landscape_zoom
|
||||||
|
visibleIf(preferences.imageScaleType()) { it == 1 }
|
||||||
|
}
|
||||||
intListPreference {
|
intListPreference {
|
||||||
bindTo(preferences.zoomStart())
|
bindTo(preferences.zoomStart())
|
||||||
titleRes = R.string.pref_zoom_start
|
titleRes = R.string.pref_zoom_start
|
||||||
|
@ -199,6 +204,10 @@ class SettingsReaderController : SettingsController() {
|
||||||
bindTo(preferences.cropBorders())
|
bindTo(preferences.cropBorders())
|
||||||
titleRes = R.string.pref_crop_borders
|
titleRes = R.string.pref_crop_borders
|
||||||
}
|
}
|
||||||
|
switchPreference {
|
||||||
|
bindTo(preferences.navigateToPan())
|
||||||
|
titleRes = R.string.pref_navigate_pan
|
||||||
|
}
|
||||||
switchPreference {
|
switchPreference {
|
||||||
bindTo(preferences.dualPageSplitPaged())
|
bindTo(preferences.dualPageSplitPaged())
|
||||||
titleRes = R.string.pref_dual_page_split
|
titleRes = R.string.pref_dual_page_split
|
||||||
|
|
|
@ -4,7 +4,9 @@ package eu.kanade.tachiyomi.util.view
|
||||||
|
|
||||||
import android.annotation.SuppressLint
|
import android.annotation.SuppressLint
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
|
import android.content.res.Resources
|
||||||
import android.graphics.Point
|
import android.graphics.Point
|
||||||
|
import android.graphics.Rect
|
||||||
import android.graphics.drawable.Drawable
|
import android.graphics.drawable.Drawable
|
||||||
import android.text.TextUtils
|
import android.text.TextUtils
|
||||||
import android.view.Gravity
|
import android.view.Gravity
|
||||||
|
@ -259,3 +261,16 @@ inline fun <reified T : Drawable> T.copy(context: Context): T? {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun View?.isVisible(): Boolean {
|
||||||
|
if (this == null) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if (!this.isShown) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
val actualPosition = Rect()
|
||||||
|
this.getGlobalVisibleRect(actualPosition)
|
||||||
|
val screen = Rect(0, 0, Resources.getSystem().displayMetrics.widthPixels, Resources.getSystem().displayMetrics.heightPixels)
|
||||||
|
return actualPosition.intersect(screen)
|
||||||
|
}
|
||||||
|
|
|
@ -37,6 +37,15 @@
|
||||||
android:entries="@array/image_scale_type"
|
android:entries="@array/image_scale_type"
|
||||||
app:title="@string/pref_image_scale_type" />
|
app:title="@string/pref_image_scale_type" />
|
||||||
|
|
||||||
|
<com.google.android.material.switchmaterial.SwitchMaterial
|
||||||
|
android:id="@+id/landscape_zoom"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:paddingStart="16dp"
|
||||||
|
android:paddingEnd="16dp"
|
||||||
|
android:text="@string/pref_landscape_zoom"
|
||||||
|
android:textColor="?android:attr/textColorSecondary" />
|
||||||
|
|
||||||
<eu.kanade.tachiyomi.widget.MaterialSpinnerView
|
<eu.kanade.tachiyomi.widget.MaterialSpinnerView
|
||||||
android:id="@+id/zoom_start"
|
android:id="@+id/zoom_start"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
|
@ -53,6 +62,15 @@
|
||||||
android:text="@string/pref_crop_borders"
|
android:text="@string/pref_crop_borders"
|
||||||
android:textColor="?android:attr/textColorSecondary" />
|
android:textColor="?android:attr/textColorSecondary" />
|
||||||
|
|
||||||
|
<com.google.android.material.switchmaterial.SwitchMaterial
|
||||||
|
android:id="@+id/navigate_pan"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:paddingStart="16dp"
|
||||||
|
android:paddingEnd="16dp"
|
||||||
|
android:text="@string/pref_navigate_pan"
|
||||||
|
android:textColor="?android:attr/textColorSecondary" />
|
||||||
|
|
||||||
<com.google.android.material.switchmaterial.SwitchMaterial
|
<com.google.android.material.switchmaterial.SwitchMaterial
|
||||||
android:id="@+id/dual_page_split"
|
android:id="@+id/dual_page_split"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
|
|
|
@ -805,4 +805,6 @@
|
||||||
<!-- S Pen actions -->
|
<!-- S Pen actions -->
|
||||||
<string name="spen_previous_page">Previous page</string>
|
<string name="spen_previous_page">Previous page</string>
|
||||||
<string name="spen_next_page">Next page</string>
|
<string name="spen_next_page">Next page</string>
|
||||||
|
<string name="pref_navigate_pan">Navigate to pan</string>
|
||||||
|
<string name="pref_landscape_zoom">Zoom landscape image</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|
Loading…
Reference in a new issue