mirror of
https://github.com/tachiyomiorg/tachiyomi.git
synced 2024-11-19 01:59:19 +01:00
Viewer navigation (#3869)
* Viewer navigation Co-authored-by: Harsh Parekh <h.x.dev@outlook.com> * Match current reader behavior and add ability to invert it * A bit of clean up * Clean up inversion * Only create navigator when changed and change tap zone when invertTapping is changed * Clean up PagerConfig * Change how Viewer navigation works * Add Edge Navigation Co-authored-by: Harsh Parekh <h.x.dev@outlook.com>
This commit is contained in:
parent
71ece73d99
commit
d69e9034ab
@ -65,6 +65,10 @@ object PreferenceKeys {
|
|||||||
|
|
||||||
const val readWithVolumeKeysInverted = "reader_volume_keys_inverted"
|
const val readWithVolumeKeysInverted = "reader_volume_keys_inverted"
|
||||||
|
|
||||||
|
const val navigationModePager = "reader_navigation_mode_pager"
|
||||||
|
|
||||||
|
const val navigationModeWebtoon = "reader_navigation_mode_webtoon"
|
||||||
|
|
||||||
const val webtoonSidePadding = "webtoon_side_padding"
|
const val webtoonSidePadding = "webtoon_side_padding"
|
||||||
|
|
||||||
const val portraitColumns = "pref_library_columns_portrait_key"
|
const val portraitColumns = "pref_library_columns_portrait_key"
|
||||||
|
@ -31,10 +31,10 @@ object PreferenceValues {
|
|||||||
LIST,
|
LIST,
|
||||||
}
|
}
|
||||||
|
|
||||||
enum class TappingInvertMode {
|
enum class TappingInvertMode(val shouldInvertHorizontal: Boolean = false, val shouldInvertVertical: Boolean = false) {
|
||||||
NONE,
|
NONE,
|
||||||
HORIZONTAL,
|
HORIZONTAL(shouldInvertHorizontal = true),
|
||||||
VERTICAL,
|
VERTICAL(shouldInvertVertical = true),
|
||||||
BOTH
|
BOTH(shouldInvertHorizontal = true, shouldInvertVertical = true)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -138,6 +138,10 @@ class PreferencesHelper(val context: Context) {
|
|||||||
|
|
||||||
fun readWithVolumeKeysInverted() = flowPrefs.getBoolean(Keys.readWithVolumeKeysInverted, false)
|
fun readWithVolumeKeysInverted() = flowPrefs.getBoolean(Keys.readWithVolumeKeysInverted, false)
|
||||||
|
|
||||||
|
fun navigationModePager() = flowPrefs.getInt(Keys.navigationModePager, 0)
|
||||||
|
|
||||||
|
fun navigationModeWebtoon() = flowPrefs.getInt(Keys.navigationModeWebtoon, 0)
|
||||||
|
|
||||||
fun portraitColumns() = flowPrefs.getInt(Keys.portraitColumns, 0)
|
fun portraitColumns() = flowPrefs.getInt(Keys.portraitColumns, 0)
|
||||||
|
|
||||||
fun landscapeColumns() = flowPrefs.getInt(Keys.landscapeColumns, 0)
|
fun landscapeColumns() = flowPrefs.getInt(Keys.landscapeColumns, 0)
|
||||||
|
@ -86,6 +86,7 @@ class ReaderSettingsSheet(private val activity: ReaderActivity) : BottomSheetDia
|
|||||||
binding.webtoonPrefsGroup.isInvisible = true
|
binding.webtoonPrefsGroup.isInvisible = true
|
||||||
binding.pagerPrefsGroup.isVisible = true
|
binding.pagerPrefsGroup.isVisible = true
|
||||||
|
|
||||||
|
binding.pagerNav.bindToPreference(preferences.navigationModePager())
|
||||||
binding.scaleType.bindToPreference(preferences.imageScaleType(), 1)
|
binding.scaleType.bindToPreference(preferences.imageScaleType(), 1)
|
||||||
binding.zoomStart.bindToPreference(preferences.zoomStart(), 1)
|
binding.zoomStart.bindToPreference(preferences.zoomStart(), 1)
|
||||||
binding.cropBorders.bindToPreference(preferences.cropBorders())
|
binding.cropBorders.bindToPreference(preferences.cropBorders())
|
||||||
@ -98,6 +99,7 @@ class ReaderSettingsSheet(private val activity: ReaderActivity) : BottomSheetDia
|
|||||||
binding.pagerPrefsGroup.isInvisible = true
|
binding.pagerPrefsGroup.isInvisible = true
|
||||||
binding.webtoonPrefsGroup.isVisible = true
|
binding.webtoonPrefsGroup.isVisible = true
|
||||||
|
|
||||||
|
binding.webtoonNav.bindToPreference(preferences.navigationModeWebtoon())
|
||||||
binding.cropBordersWebtoon.bindToPreference(preferences.cropBordersWebtoon())
|
binding.cropBordersWebtoon.bindToPreference(preferences.cropBordersWebtoon())
|
||||||
binding.webtoonSidePadding.bindToIntPreference(preferences.webtoonSidePadding(), R.array.webtoon_side_padding_values)
|
binding.webtoonSidePadding.bindToIntPreference(preferences.webtoonSidePadding(), R.array.webtoon_side_padding_values)
|
||||||
}
|
}
|
||||||
|
@ -28,13 +28,18 @@ abstract class ViewerConfig(preferences: PreferencesHelper) {
|
|||||||
var volumeKeysInverted = false
|
var volumeKeysInverted = false
|
||||||
var trueColor = false
|
var trueColor = false
|
||||||
var alwaysShowChapterTransition = true
|
var alwaysShowChapterTransition = true
|
||||||
|
var navigationMode = 0
|
||||||
|
protected set
|
||||||
|
|
||||||
|
abstract var navigator: ViewerNavigation
|
||||||
|
protected set
|
||||||
|
|
||||||
init {
|
init {
|
||||||
preferences.readWithTapping()
|
preferences.readWithTapping()
|
||||||
.register({ tappingEnabled = it })
|
.register({ tappingEnabled = it })
|
||||||
|
|
||||||
preferences.readWithTappingInverted()
|
preferences.readWithTappingInverted()
|
||||||
.register({ tappingInverted = it })
|
.register({ tappingInverted = it }, { navigator.invertMode = it })
|
||||||
|
|
||||||
preferences.readWithLongTap()
|
preferences.readWithLongTap()
|
||||||
.register({ longTapEnabled = it })
|
.register({ longTapEnabled = it })
|
||||||
@ -58,6 +63,10 @@ abstract class ViewerConfig(preferences: PreferencesHelper) {
|
|||||||
.register({ alwaysShowChapterTransition = it })
|
.register({ alwaysShowChapterTransition = it })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected abstract fun defaultNavigation(): ViewerNavigation
|
||||||
|
|
||||||
|
abstract fun updateNavigation(navigationMode: Int)
|
||||||
|
|
||||||
fun <T> Preference<T>.register(
|
fun <T> Preference<T>.register(
|
||||||
valueAssignment: (T) -> Unit,
|
valueAssignment: (T) -> Unit,
|
||||||
onChanged: (T) -> Unit = {}
|
onChanged: (T) -> Unit = {}
|
||||||
|
@ -0,0 +1,43 @@
|
|||||||
|
package eu.kanade.tachiyomi.ui.reader.viewer
|
||||||
|
|
||||||
|
import android.graphics.PointF
|
||||||
|
import android.graphics.RectF
|
||||||
|
import eu.kanade.tachiyomi.data.preference.PreferenceValues
|
||||||
|
import eu.kanade.tachiyomi.util.lang.invert
|
||||||
|
|
||||||
|
abstract class ViewerNavigation {
|
||||||
|
|
||||||
|
enum class NavigationRegion {
|
||||||
|
NEXT, PREV, MENU
|
||||||
|
}
|
||||||
|
|
||||||
|
data class Region(
|
||||||
|
val rectF: RectF,
|
||||||
|
val type: NavigationRegion
|
||||||
|
) {
|
||||||
|
fun invert(invertMode: PreferenceValues.TappingInvertMode): Region {
|
||||||
|
if (invertMode == PreferenceValues.TappingInvertMode.NONE) return this
|
||||||
|
return this.copy(
|
||||||
|
rectF = this.rectF.invert(invertMode)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private var constantMenuRegion: RectF = RectF(0f, 0f, 1f, 0.05f)
|
||||||
|
|
||||||
|
abstract var regions: List<Region>
|
||||||
|
|
||||||
|
var invertMode: PreferenceValues.TappingInvertMode = PreferenceValues.TappingInvertMode.NONE
|
||||||
|
|
||||||
|
fun getAction(pos: PointF): NavigationRegion {
|
||||||
|
val x = pos.x
|
||||||
|
val y = pos.y
|
||||||
|
val region = regions.map { it.invert(invertMode) }
|
||||||
|
.find { it.rectF.contains(x, y) }
|
||||||
|
return when {
|
||||||
|
region != null -> region.type
|
||||||
|
constantMenuRegion.contains(x, y) -> NavigationRegion.MENU
|
||||||
|
else -> NavigationRegion.MENU
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,32 @@
|
|||||||
|
package eu.kanade.tachiyomi.ui.reader.viewer.navigation
|
||||||
|
|
||||||
|
import android.graphics.RectF
|
||||||
|
import eu.kanade.tachiyomi.ui.reader.viewer.ViewerNavigation
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Visualization of default state without any inversion
|
||||||
|
* +---+---+---+
|
||||||
|
* | N | N | N | P: Previous
|
||||||
|
* +---+---+---+
|
||||||
|
* | N | M | N | M: Menu
|
||||||
|
* +---+---+---+
|
||||||
|
* | N | P | N | N: Next
|
||||||
|
* +---+---+---+
|
||||||
|
*/
|
||||||
|
class EdgeNavigation : ViewerNavigation() {
|
||||||
|
|
||||||
|
override var regions: List<Region> = listOf(
|
||||||
|
Region(
|
||||||
|
rectF = RectF(0f, 0f, 0.33f, 1f),
|
||||||
|
type = NavigationRegion.NEXT
|
||||||
|
),
|
||||||
|
Region(
|
||||||
|
rectF = RectF(0.33f, 0.66f, 0.66f, 1f),
|
||||||
|
type = NavigationRegion.PREV
|
||||||
|
),
|
||||||
|
Region(
|
||||||
|
rectF = RectF(0.66f, 0f, 1f, 1f),
|
||||||
|
type = NavigationRegion.NEXT
|
||||||
|
),
|
||||||
|
)
|
||||||
|
}
|
@ -0,0 +1,28 @@
|
|||||||
|
package eu.kanade.tachiyomi.ui.reader.viewer.navigation
|
||||||
|
|
||||||
|
import android.graphics.RectF
|
||||||
|
import eu.kanade.tachiyomi.ui.reader.viewer.ViewerNavigation
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Visualization of default state without any inversion
|
||||||
|
* +---+---+---+
|
||||||
|
* | M | M | M | P: Previous
|
||||||
|
* +---+---+---+
|
||||||
|
* | P | N | N | M: Menu
|
||||||
|
* +---+---+---+
|
||||||
|
* | P | N | N | N: Next
|
||||||
|
* +---+---+---+
|
||||||
|
*/
|
||||||
|
class KindlishNavigation : ViewerNavigation() {
|
||||||
|
|
||||||
|
override var regions: List<Region> = listOf(
|
||||||
|
Region(
|
||||||
|
rectF = RectF(0.33f, 0.33f, 1f, 1f),
|
||||||
|
type = NavigationRegion.NEXT
|
||||||
|
),
|
||||||
|
Region(
|
||||||
|
rectF = RectF(0f, 0.33f, 0.33f, 1f),
|
||||||
|
type = NavigationRegion.PREV
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
@ -0,0 +1,36 @@
|
|||||||
|
package eu.kanade.tachiyomi.ui.reader.viewer.navigation
|
||||||
|
|
||||||
|
import android.graphics.RectF
|
||||||
|
import eu.kanade.tachiyomi.ui.reader.viewer.ViewerNavigation
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Visualization of default state without any inversion
|
||||||
|
* +---+---+---+
|
||||||
|
* | N | N | N | P: Previous
|
||||||
|
* +---+---+---+
|
||||||
|
* | N | M | P | M: Menu
|
||||||
|
* +---+---+---+
|
||||||
|
* | P | P | P | N: Next
|
||||||
|
* +---+---+---+
|
||||||
|
*/
|
||||||
|
open class LNavigation : ViewerNavigation() {
|
||||||
|
|
||||||
|
override var regions: List<Region> = listOf(
|
||||||
|
Region(
|
||||||
|
rectF = RectF(0f, 0.33f, 0.33f, 0.66f),
|
||||||
|
type = NavigationRegion.NEXT
|
||||||
|
),
|
||||||
|
Region(
|
||||||
|
rectF = RectF(0f, 0f, 1f, 0.33f),
|
||||||
|
type = NavigationRegion.NEXT
|
||||||
|
),
|
||||||
|
Region(
|
||||||
|
rectF = RectF(0.66f, 0.33f, 1f, 0.66f),
|
||||||
|
type = NavigationRegion.PREV
|
||||||
|
),
|
||||||
|
Region(
|
||||||
|
rectF = RectF(0f, 0.66f, 1f, 1f),
|
||||||
|
type = NavigationRegion.PREV
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
@ -2,6 +2,10 @@ package eu.kanade.tachiyomi.ui.reader.viewer.pager
|
|||||||
|
|
||||||
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
||||||
import eu.kanade.tachiyomi.ui.reader.viewer.ViewerConfig
|
import eu.kanade.tachiyomi.ui.reader.viewer.ViewerConfig
|
||||||
|
import eu.kanade.tachiyomi.ui.reader.viewer.ViewerNavigation
|
||||||
|
import eu.kanade.tachiyomi.ui.reader.viewer.navigation.EdgeNavigation
|
||||||
|
import eu.kanade.tachiyomi.ui.reader.viewer.navigation.KindlishNavigation
|
||||||
|
import eu.kanade.tachiyomi.ui.reader.viewer.navigation.LNavigation
|
||||||
import uy.kohesive.injekt.Injekt
|
import uy.kohesive.injekt.Injekt
|
||||||
import uy.kohesive.injekt.api.get
|
import uy.kohesive.injekt.api.get
|
||||||
|
|
||||||
@ -29,6 +33,9 @@ class PagerConfig(private val viewer: PagerViewer, preferences: PreferencesHelpe
|
|||||||
|
|
||||||
preferences.cropBorders()
|
preferences.cropBorders()
|
||||||
.register({ imageCropBorders = it }, { imagePropertyChangedListener?.invoke() })
|
.register({ imageCropBorders = it }, { imagePropertyChangedListener?.invoke() })
|
||||||
|
|
||||||
|
preferences.navigationModePager()
|
||||||
|
.register({ navigationMode = it }, { updateNavigation(navigationMode) })
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun zoomTypeFromPreference(value: Int) {
|
private fun zoomTypeFromPreference(value: Int) {
|
||||||
@ -48,6 +55,28 @@ class PagerConfig(private val viewer: PagerViewer, preferences: PreferencesHelpe
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override var navigator: ViewerNavigation = defaultNavigation()
|
||||||
|
set(value) {
|
||||||
|
field = value.also { it.invertMode = this.tappingInverted }
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun defaultNavigation(): ViewerNavigation {
|
||||||
|
return when (viewer) {
|
||||||
|
is VerticalPagerViewer -> VerticalPagerDefaultNavigation()
|
||||||
|
else -> PagerDefaultNavigation()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun updateNavigation(navigationMode: Int) {
|
||||||
|
navigator = when (navigationMode) {
|
||||||
|
0 -> defaultNavigation()
|
||||||
|
1 -> LNavigation()
|
||||||
|
2 -> KindlishNavigation()
|
||||||
|
3 -> EdgeNavigation()
|
||||||
|
else -> defaultNavigation()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
enum class ZoomType {
|
enum class ZoomType {
|
||||||
Left, Center, Right
|
Left, Center, Right
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,31 @@
|
|||||||
|
package eu.kanade.tachiyomi.ui.reader.viewer.pager
|
||||||
|
|
||||||
|
import android.graphics.RectF
|
||||||
|
import eu.kanade.tachiyomi.ui.reader.viewer.ViewerNavigation
|
||||||
|
import eu.kanade.tachiyomi.ui.reader.viewer.navigation.LNavigation
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Visualization of default state without any inversion
|
||||||
|
* +---+---+---+
|
||||||
|
* | N | M | P | P: Previous
|
||||||
|
* +---+---+---+
|
||||||
|
* | N | M | P | M: Menu
|
||||||
|
* +---+---+---+
|
||||||
|
* | N | M | P | N: Next
|
||||||
|
* +---+---+---+
|
||||||
|
*/
|
||||||
|
class PagerDefaultNavigation : ViewerNavigation() {
|
||||||
|
|
||||||
|
override var regions: List<Region> = listOf(
|
||||||
|
Region(
|
||||||
|
rectF = RectF(0f, 0f, 0.33f, 1f),
|
||||||
|
type = NavigationRegion.NEXT
|
||||||
|
),
|
||||||
|
Region(
|
||||||
|
rectF = RectF(0.66f, 0f, 1f, 1f),
|
||||||
|
type = NavigationRegion.PREV
|
||||||
|
),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
class VerticalPagerDefaultNavigation : LNavigation()
|
@ -1,5 +1,6 @@
|
|||||||
package eu.kanade.tachiyomi.ui.reader.viewer.pager
|
package eu.kanade.tachiyomi.ui.reader.viewer.pager
|
||||||
|
|
||||||
|
import android.graphics.PointF
|
||||||
import android.view.InputDevice
|
import android.view.InputDevice
|
||||||
import android.view.KeyEvent
|
import android.view.KeyEvent
|
||||||
import android.view.MotionEvent
|
import android.view.MotionEvent
|
||||||
@ -9,12 +10,12 @@ 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
|
||||||
import eu.kanade.tachiyomi.R
|
import eu.kanade.tachiyomi.R
|
||||||
import eu.kanade.tachiyomi.data.preference.PreferenceValues.TappingInvertMode
|
|
||||||
import eu.kanade.tachiyomi.ui.reader.ReaderActivity
|
import eu.kanade.tachiyomi.ui.reader.ReaderActivity
|
||||||
import eu.kanade.tachiyomi.ui.reader.model.ChapterTransition
|
import eu.kanade.tachiyomi.ui.reader.model.ChapterTransition
|
||||||
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
|
||||||
import eu.kanade.tachiyomi.ui.reader.viewer.BaseViewer
|
import eu.kanade.tachiyomi.ui.reader.viewer.BaseViewer
|
||||||
|
import eu.kanade.tachiyomi.ui.reader.viewer.ViewerNavigation
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
import kotlin.math.min
|
import kotlin.math.min
|
||||||
|
|
||||||
@ -89,34 +90,12 @@ abstract class PagerViewer(val activity: ReaderActivity) : BaseViewer {
|
|||||||
return@f
|
return@f
|
||||||
}
|
}
|
||||||
|
|
||||||
val positionX = event.x
|
val pos = PointF(event.rawX / pager.width, event.rawY / pager.height)
|
||||||
val positionY = event.y
|
val navigator = config.navigator
|
||||||
val topSideTap = positionY < pager.height * 0.25f
|
when (navigator.getAction(pos)) {
|
||||||
val bottomSideTap = positionY > pager.height * 0.75f
|
ViewerNavigation.NavigationRegion.MENU -> activity.toggleMenu()
|
||||||
val leftSideTap = positionX < pager.width * 0.33f
|
ViewerNavigation.NavigationRegion.NEXT -> moveToNext()
|
||||||
val rightSideTap = positionX > pager.width * 0.66f
|
ViewerNavigation.NavigationRegion.PREV -> moveToPrevious()
|
||||||
|
|
||||||
val invertMode = config.tappingInverted
|
|
||||||
val invertVertical = invertMode == TappingInvertMode.VERTICAL || invertMode == TappingInvertMode.BOTH
|
|
||||||
val invertHorizontal = invertMode == TappingInvertMode.HORIZONTAL || invertMode == TappingInvertMode.BOTH
|
|
||||||
|
|
||||||
if (this is VerticalPagerViewer) {
|
|
||||||
when {
|
|
||||||
topSideTap && !invertVertical || bottomSideTap && invertVertical -> moveLeft()
|
|
||||||
bottomSideTap && !invertVertical || topSideTap && invertVertical -> moveRight()
|
|
||||||
|
|
||||||
leftSideTap && !invertHorizontal || rightSideTap && invertHorizontal -> moveLeft()
|
|
||||||
rightSideTap && !invertHorizontal || leftSideTap && invertHorizontal -> moveRight()
|
|
||||||
|
|
||||||
else -> activity.toggleMenu()
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
when {
|
|
||||||
leftSideTap && !invertHorizontal || rightSideTap && invertHorizontal -> moveLeft()
|
|
||||||
rightSideTap && !invertHorizontal || leftSideTap && invertHorizontal -> moveRight()
|
|
||||||
|
|
||||||
else -> activity.toggleMenu()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pager.longTapListener = f@{
|
pager.longTapListener = f@{
|
||||||
|
@ -2,6 +2,10 @@ package eu.kanade.tachiyomi.ui.reader.viewer.webtoon
|
|||||||
|
|
||||||
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
||||||
import eu.kanade.tachiyomi.ui.reader.viewer.ViewerConfig
|
import eu.kanade.tachiyomi.ui.reader.viewer.ViewerConfig
|
||||||
|
import eu.kanade.tachiyomi.ui.reader.viewer.ViewerNavigation
|
||||||
|
import eu.kanade.tachiyomi.ui.reader.viewer.navigation.EdgeNavigation
|
||||||
|
import eu.kanade.tachiyomi.ui.reader.viewer.navigation.KindlishNavigation
|
||||||
|
import eu.kanade.tachiyomi.ui.reader.viewer.navigation.LNavigation
|
||||||
import uy.kohesive.injekt.Injekt
|
import uy.kohesive.injekt.Injekt
|
||||||
import uy.kohesive.injekt.api.get
|
import uy.kohesive.injekt.api.get
|
||||||
|
|
||||||
@ -22,5 +26,27 @@ class WebtoonConfig(preferences: PreferencesHelper = Injekt.get()) : ViewerConfi
|
|||||||
|
|
||||||
preferences.webtoonSidePadding()
|
preferences.webtoonSidePadding()
|
||||||
.register({ sidePadding = it }, { imagePropertyChangedListener?.invoke() })
|
.register({ sidePadding = it }, { imagePropertyChangedListener?.invoke() })
|
||||||
|
|
||||||
|
preferences.navigationModeWebtoon()
|
||||||
|
.register({ navigationMode = it }, { updateNavigation(it) })
|
||||||
|
}
|
||||||
|
|
||||||
|
override var navigator: ViewerNavigation = defaultNavigation()
|
||||||
|
set(value) {
|
||||||
|
field = value.also { it.invertMode = tappingInverted }
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun defaultNavigation(): ViewerNavigation {
|
||||||
|
return WebtoonDefaultNavigation()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun updateNavigation(navigationMode: Int) {
|
||||||
|
this.navigator = when (navigationMode) {
|
||||||
|
0 -> defaultNavigation()
|
||||||
|
1 -> LNavigation()
|
||||||
|
2 -> KindlishNavigation()
|
||||||
|
3 -> EdgeNavigation()
|
||||||
|
else -> defaultNavigation()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,5 @@
|
|||||||
|
package eu.kanade.tachiyomi.ui.reader.viewer.webtoon
|
||||||
|
|
||||||
|
import eu.kanade.tachiyomi.ui.reader.viewer.navigation.LNavigation
|
||||||
|
|
||||||
|
class WebtoonDefaultNavigation : LNavigation()
|
@ -1,5 +1,6 @@
|
|||||||
package eu.kanade.tachiyomi.ui.reader.viewer.webtoon
|
package eu.kanade.tachiyomi.ui.reader.viewer.webtoon
|
||||||
|
|
||||||
|
import android.graphics.PointF
|
||||||
import android.view.KeyEvent
|
import android.view.KeyEvent
|
||||||
import android.view.MotionEvent
|
import android.view.MotionEvent
|
||||||
import android.view.View
|
import android.view.View
|
||||||
@ -9,12 +10,12 @@ import androidx.core.view.isGone
|
|||||||
import androidx.core.view.isVisible
|
import androidx.core.view.isVisible
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
import androidx.recyclerview.widget.WebtoonLayoutManager
|
import androidx.recyclerview.widget.WebtoonLayoutManager
|
||||||
import eu.kanade.tachiyomi.data.preference.PreferenceValues.TappingInvertMode
|
|
||||||
import eu.kanade.tachiyomi.ui.reader.ReaderActivity
|
import eu.kanade.tachiyomi.ui.reader.ReaderActivity
|
||||||
import eu.kanade.tachiyomi.ui.reader.model.ChapterTransition
|
import eu.kanade.tachiyomi.ui.reader.model.ChapterTransition
|
||||||
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
|
||||||
import eu.kanade.tachiyomi.ui.reader.viewer.BaseViewer
|
import eu.kanade.tachiyomi.ui.reader.viewer.BaseViewer
|
||||||
|
import eu.kanade.tachiyomi.ui.reader.viewer.ViewerNavigation
|
||||||
import rx.subscriptions.CompositeSubscription
|
import rx.subscriptions.CompositeSubscription
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
import kotlin.math.max
|
import kotlin.math.max
|
||||||
@ -101,25 +102,15 @@ class WebtoonViewer(val activity: ReaderActivity, val isContinuous: Boolean = tr
|
|||||||
return@f
|
return@f
|
||||||
}
|
}
|
||||||
|
|
||||||
val positionX = event.rawX
|
val pos = PointF(event.rawX / recycler.width, event.rawY / recycler.height)
|
||||||
val positionY = event.rawY
|
if (!config.tappingEnabled) activity.toggleMenu()
|
||||||
val topSideTap = positionY < recycler.height * 0.25f
|
else {
|
||||||
val bottomSideTap = positionY > recycler.height * 0.75f
|
val navigator = config.navigator
|
||||||
val leftSideTap = positionX < recycler.width * 0.33f
|
when (navigator.getAction(pos)) {
|
||||||
val rightSideTap = positionX > recycler.width * 0.66f
|
ViewerNavigation.NavigationRegion.MENU -> activity.toggleMenu()
|
||||||
|
ViewerNavigation.NavigationRegion.NEXT -> scrollDown()
|
||||||
val invertMode = config.tappingInverted
|
ViewerNavigation.NavigationRegion.PREV -> scrollUp()
|
||||||
val invertVertical = invertMode == TappingInvertMode.VERTICAL || invertMode == TappingInvertMode.BOTH
|
}
|
||||||
val invertHorizontal = invertMode == TappingInvertMode.HORIZONTAL || invertMode == TappingInvertMode.BOTH
|
|
||||||
|
|
||||||
when {
|
|
||||||
topSideTap && !invertVertical || bottomSideTap && invertVertical -> scrollUp()
|
|
||||||
bottomSideTap && !invertVertical || topSideTap && invertVertical -> scrollDown()
|
|
||||||
|
|
||||||
leftSideTap && !invertHorizontal || rightSideTap && invertHorizontal -> scrollUp()
|
|
||||||
rightSideTap && !invertHorizontal || leftSideTap && invertHorizontal -> scrollDown()
|
|
||||||
|
|
||||||
else -> activity.toggleMenu()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
recycler.longTapListener = f@{ event ->
|
recycler.longTapListener = f@{ event ->
|
||||||
|
@ -0,0 +1,15 @@
|
|||||||
|
package eu.kanade.tachiyomi.util.lang
|
||||||
|
|
||||||
|
import android.graphics.RectF
|
||||||
|
import eu.kanade.tachiyomi.data.preference.PreferenceValues
|
||||||
|
|
||||||
|
fun RectF.invert(invertMode: PreferenceValues.TappingInvertMode): RectF {
|
||||||
|
val horizontal = invertMode.shouldInvertHorizontal
|
||||||
|
val vertical = invertMode.shouldInvertVertical
|
||||||
|
return when {
|
||||||
|
horizontal && vertical -> RectF(1f - this.right, 1f - this.bottom, 1f - this.left, 1f - this.top)
|
||||||
|
vertical -> RectF(this.left, 1f - this.bottom, this.right, 1f - this.top)
|
||||||
|
horizontal -> RectF(1f - this.right, this.top, 1f - this.left, this.bottom)
|
||||||
|
else -> this
|
||||||
|
}
|
||||||
|
}
|
@ -203,6 +203,25 @@
|
|||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintTop_toBottomOf="@id/end_navigation_preferences" />
|
app:layout_constraintTop_toBottomOf="@id/end_navigation_preferences" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/pager_nav_text"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="@string/pref_viewer_nav"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintEnd_toStartOf="@id/verticalcenter"
|
||||||
|
app:layout_constraintBaseline_toBaselineOf="@id/pager_nav"/>
|
||||||
|
|
||||||
|
<androidx.appcompat.widget.AppCompatSpinner
|
||||||
|
android:id="@+id/pager_nav"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:entries="@array/pager_nav"
|
||||||
|
android:layout_marginTop="16dp"
|
||||||
|
app:layout_constraintTop_toBottomOf="@id/pager_prefs"
|
||||||
|
app:layout_constraintStart_toEndOf="@id/verticalcenter"
|
||||||
|
app:layout_constraintEnd_toEndOf="@id/spinner_end" />
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/scale_type_text"
|
android:id="@+id/scale_type_text"
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
@ -220,7 +239,7 @@
|
|||||||
android:entries="@array/image_scale_type"
|
android:entries="@array/image_scale_type"
|
||||||
app:layout_constraintEnd_toEndOf="@id/spinner_end"
|
app:layout_constraintEnd_toEndOf="@id/spinner_end"
|
||||||
app:layout_constraintStart_toEndOf="@id/verticalcenter"
|
app:layout_constraintStart_toEndOf="@id/verticalcenter"
|
||||||
app:layout_constraintTop_toBottomOf="@id/pager_prefs" />
|
app:layout_constraintTop_toBottomOf="@+id/pager_nav" />
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/zoom_start_text"
|
android:id="@+id/zoom_start_text"
|
||||||
@ -326,6 +345,26 @@
|
|||||||
app:layout_constraintRight_toRightOf="@id/spinner_end"
|
app:layout_constraintRight_toRightOf="@id/spinner_end"
|
||||||
app:layout_constraintTop_toBottomOf="@id/webtoon_prefs" />
|
app:layout_constraintTop_toBottomOf="@id/webtoon_prefs" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/webtoon_nav_text"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="@string/pref_viewer_nav"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintEnd_toStartOf="@id/verticalcenter"
|
||||||
|
app:layout_constraintBaseline_toBaselineOf="@id/webtoon_nav"/>
|
||||||
|
|
||||||
|
<androidx.appcompat.widget.AppCompatSpinner
|
||||||
|
android:id="@+id/webtoon_nav"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="20dp"
|
||||||
|
android:entries="@array/webtoon_nav"
|
||||||
|
app:layout_constraintEnd_toEndOf="@id/spinner_end"
|
||||||
|
app:layout_constraintHorizontal_bias="0.0"
|
||||||
|
app:layout_constraintStart_toEndOf="@id/verticalcenter"
|
||||||
|
app:layout_constraintTop_toBottomOf="@+id/webtoon_side_padding" />
|
||||||
|
|
||||||
<com.google.android.material.switchmaterial.SwitchMaterial
|
<com.google.android.material.switchmaterial.SwitchMaterial
|
||||||
android:id="@+id/crop_borders_webtoon"
|
android:id="@+id/crop_borders_webtoon"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
@ -333,7 +372,7 @@
|
|||||||
android:layout_marginTop="10dp"
|
android:layout_marginTop="10dp"
|
||||||
android:text="@string/pref_crop_borders"
|
android:text="@string/pref_crop_borders"
|
||||||
android:textColor="?android:attr/textColorSecondary"
|
android:textColor="?android:attr/textColorSecondary"
|
||||||
app:layout_constraintTop_toBottomOf="@id/webtoon_side_padding" />
|
app:layout_constraintTop_toBottomOf="@+id/webtoon_nav" />
|
||||||
|
|
||||||
<!-- Groups of preferences -->
|
<!-- Groups of preferences -->
|
||||||
|
|
||||||
@ -342,7 +381,7 @@
|
|||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:visibility="gone"
|
android:visibility="gone"
|
||||||
app:constraint_referenced_ids="pager_prefs,scale_type_text,scale_type,zoom_start_text,zoom_start,crop_borders"
|
app:constraint_referenced_ids="pager_prefs,pager_nav_text,pager_nav,scale_type_text,scale_type,zoom_start_text,zoom_start,crop_borders"
|
||||||
tools:visibility="visible" />
|
tools:visibility="visible" />
|
||||||
|
|
||||||
<androidx.constraintlayout.widget.Group
|
<androidx.constraintlayout.widget.Group
|
||||||
@ -350,7 +389,7 @@
|
|||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:visibility="gone"
|
android:visibility="gone"
|
||||||
app:constraint_referenced_ids="webtoon_prefs,crop_borders_webtoon,webtoon_side_padding_text,webtoon_side_padding" />
|
app:constraint_referenced_ids="webtoon_prefs,webtoon_nav_text,webtoon_nav,crop_borders_webtoon,webtoon_side_padding_text,webtoon_side_padding" />
|
||||||
|
|
||||||
<androidx.constraintlayout.widget.Guideline
|
<androidx.constraintlayout.widget.Guideline
|
||||||
android:id="@+id/verticalcenter"
|
android:id="@+id/verticalcenter"
|
||||||
|
@ -91,4 +91,18 @@
|
|||||||
<item>@string/manga_from_library</item>
|
<item>@string/manga_from_library</item>
|
||||||
<item>@string/downloaded_chapters</item>
|
<item>@string/downloaded_chapters</item>
|
||||||
</string-array>
|
</string-array>
|
||||||
|
|
||||||
|
<string-array name="pager_nav">
|
||||||
|
<item>@string/default_nav</item>
|
||||||
|
<item>@string/l_nav</item>
|
||||||
|
<item>@string/kindlish_nav</item>
|
||||||
|
<item>@string/edge_nav</item>
|
||||||
|
</string-array>
|
||||||
|
|
||||||
|
<string-array name="webtoon_nav">
|
||||||
|
<item>@string/default_nav</item>
|
||||||
|
<item>@string/l_nav</item>
|
||||||
|
<item>@string/kindlish_nav</item>
|
||||||
|
<item>@string/edge_nav</item>
|
||||||
|
</string-array>
|
||||||
</resources>
|
</resources>
|
||||||
|
@ -277,12 +277,17 @@
|
|||||||
<string name="black_background">Black</string>
|
<string name="black_background">Black</string>
|
||||||
<string name="pref_viewer_type">Default reading mode</string>
|
<string name="pref_viewer_type">Default reading mode</string>
|
||||||
<string name="default_viewer">Default</string>
|
<string name="default_viewer">Default</string>
|
||||||
|
<string name="default_nav">Default</string>
|
||||||
|
<string name="l_nav">L shaped</string>
|
||||||
|
<string name="kindlish_nav">Kindle-ish</string>
|
||||||
|
<string name="edge_nav">Edge</string>
|
||||||
<string name="left_to_right_viewer">Left to right</string>
|
<string name="left_to_right_viewer">Left to right</string>
|
||||||
<string name="right_to_left_viewer">Right to left</string>
|
<string name="right_to_left_viewer">Right to left</string>
|
||||||
<string name="vertical_viewer">Vertical</string>
|
<string name="vertical_viewer">Vertical</string>
|
||||||
<string name="webtoon_viewer">Webtoon</string>
|
<string name="webtoon_viewer">Webtoon</string>
|
||||||
<string name="vertical_plus_viewer">Continuous vertical</string>
|
<string name="vertical_plus_viewer">Continuous vertical</string>
|
||||||
<string name="pager_viewer">Paged</string>
|
<string name="pager_viewer">Paged</string>
|
||||||
|
<string name="pref_viewer_nav">Navigation layout</string>
|
||||||
<string name="pref_image_decoder">Image decoder</string>
|
<string name="pref_image_decoder">Image decoder</string>
|
||||||
<string name="pref_image_scale_type">Scale type</string>
|
<string name="pref_image_scale_type">Scale type</string>
|
||||||
<string name="scale_type_fit_screen">Fit screen</string>
|
<string name="scale_type_fit_screen">Fit screen</string>
|
||||||
|
Loading…
Reference in New Issue
Block a user