Forráskód Böngészése

Viewer navigation (#3869)

* Viewer navigation

Co-authored-by: Harsh Parekh <[email protected]>

* 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 <[email protected]>
Andreas E 4 éve
szülő
commit
d69e9034ab
19 módosított fájl, 350 hozzáadás és 58 törlés
  1. 4 0
      app/src/main/java/eu/kanade/tachiyomi/data/preference/PreferenceKeys.kt
  2. 4 4
      app/src/main/java/eu/kanade/tachiyomi/data/preference/PreferenceValues.kt
  3. 4 0
      app/src/main/java/eu/kanade/tachiyomi/data/preference/PreferencesHelper.kt
  4. 2 0
      app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderSettingsSheet.kt
  5. 10 1
      app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/ViewerConfig.kt
  6. 43 0
      app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/ViewerNavigation.kt
  7. 32 0
      app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/navigation/EdgeNavigation.kt
  8. 28 0
      app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/navigation/KindlishNavigation.kt
  9. 36 0
      app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/navigation/LNavigation.kt
  10. 29 0
      app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/pager/PagerConfig.kt
  11. 31 0
      app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/pager/PagerDefaultNavigation.kt
  12. 8 29
      app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/pager/PagerViewer.kt
  13. 26 0
      app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/webtoon/WebtoonConfig.kt
  14. 5 0
      app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/webtoon/WebtoonDefaultNavigation.kt
  15. 11 20
      app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/webtoon/WebtoonViewer.kt
  16. 15 0
      app/src/main/java/eu/kanade/tachiyomi/util/lang/RectFExtensions.kt
  17. 43 4
      app/src/main/res/layout/reader_settings_sheet.xml
  18. 14 0
      app/src/main/res/values/arrays.xml
  19. 5 0
      app/src/main/res/values/strings.xml

+ 4 - 0
app/src/main/java/eu/kanade/tachiyomi/data/preference/PreferenceKeys.kt

@@ -65,6 +65,10 @@ object PreferenceKeys {
 
     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 portraitColumns = "pref_library_columns_portrait_key"

+ 4 - 4
app/src/main/java/eu/kanade/tachiyomi/data/preference/PreferenceValues.kt

@@ -31,10 +31,10 @@ object PreferenceValues {
         LIST,
     }
 
-    enum class TappingInvertMode {
+    enum class TappingInvertMode(val shouldInvertHorizontal: Boolean = false, val shouldInvertVertical: Boolean = false) {
         NONE,
-        HORIZONTAL,
-        VERTICAL,
-        BOTH
+        HORIZONTAL(shouldInvertHorizontal = true),
+        VERTICAL(shouldInvertVertical = true),
+        BOTH(shouldInvertHorizontal = true, shouldInvertVertical = true)
     }
 }

+ 4 - 0
app/src/main/java/eu/kanade/tachiyomi/data/preference/PreferencesHelper.kt

@@ -138,6 +138,10 @@ class PreferencesHelper(val context: Context) {
 
     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 landscapeColumns() = flowPrefs.getInt(Keys.landscapeColumns, 0)

+ 2 - 0
app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderSettingsSheet.kt

@@ -86,6 +86,7 @@ class ReaderSettingsSheet(private val activity: ReaderActivity) : BottomSheetDia
         binding.webtoonPrefsGroup.isInvisible = true
         binding.pagerPrefsGroup.isVisible = true
 
+        binding.pagerNav.bindToPreference(preferences.navigationModePager())
         binding.scaleType.bindToPreference(preferences.imageScaleType(), 1)
         binding.zoomStart.bindToPreference(preferences.zoomStart(), 1)
         binding.cropBorders.bindToPreference(preferences.cropBorders())
@@ -98,6 +99,7 @@ class ReaderSettingsSheet(private val activity: ReaderActivity) : BottomSheetDia
         binding.pagerPrefsGroup.isInvisible = true
         binding.webtoonPrefsGroup.isVisible = true
 
+        binding.webtoonNav.bindToPreference(preferences.navigationModeWebtoon())
         binding.cropBordersWebtoon.bindToPreference(preferences.cropBordersWebtoon())
         binding.webtoonSidePadding.bindToIntPreference(preferences.webtoonSidePadding(), R.array.webtoon_side_padding_values)
     }

+ 10 - 1
app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/ViewerConfig.kt

@@ -28,13 +28,18 @@ abstract class ViewerConfig(preferences: PreferencesHelper) {
     var volumeKeysInverted = false
     var trueColor = false
     var alwaysShowChapterTransition = true
+    var navigationMode = 0
+        protected set
+
+    abstract var navigator: ViewerNavigation
+        protected set
 
     init {
         preferences.readWithTapping()
             .register({ tappingEnabled = it })
 
         preferences.readWithTappingInverted()
-            .register({ tappingInverted = it })
+            .register({ tappingInverted = it }, { navigator.invertMode = it })
 
         preferences.readWithLongTap()
             .register({ longTapEnabled = it })
@@ -58,6 +63,10 @@ abstract class ViewerConfig(preferences: PreferencesHelper) {
             .register({ alwaysShowChapterTransition = it })
     }
 
+    protected abstract fun defaultNavigation(): ViewerNavigation
+
+    abstract fun updateNavigation(navigationMode: Int)
+
     fun <T> Preference<T>.register(
         valueAssignment: (T) -> Unit,
         onChanged: (T) -> Unit = {}

+ 43 - 0
app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/ViewerNavigation.kt

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

+ 32 - 0
app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/navigation/EdgeNavigation.kt

@@ -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
+        ),
+    )
+}

+ 28 - 0
app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/navigation/KindlishNavigation.kt

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

+ 36 - 0
app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/navigation/LNavigation.kt

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

+ 29 - 0
app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/pager/PagerConfig.kt

@@ -2,6 +2,10 @@ package eu.kanade.tachiyomi.ui.reader.viewer.pager
 
 import eu.kanade.tachiyomi.data.preference.PreferencesHelper
 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.api.get
 
@@ -29,6 +33,9 @@ class PagerConfig(private val viewer: PagerViewer, preferences: PreferencesHelpe
 
         preferences.cropBorders()
             .register({ imageCropBorders = it }, { imagePropertyChangedListener?.invoke() })
+
+        preferences.navigationModePager()
+            .register({ navigationMode = it }, { updateNavigation(navigationMode) })
     }
 
     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 {
         Left, Center, Right
     }

+ 31 - 0
app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/pager/PagerDefaultNavigation.kt

@@ -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()

+ 8 - 29
app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/pager/PagerViewer.kt

@@ -1,5 +1,6 @@
 package eu.kanade.tachiyomi.ui.reader.viewer.pager
 
+import android.graphics.PointF
 import android.view.InputDevice
 import android.view.KeyEvent
 import android.view.MotionEvent
@@ -9,12 +10,12 @@ import androidx.core.view.isGone
 import androidx.core.view.isVisible
 import androidx.viewpager.widget.ViewPager
 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.model.ChapterTransition
 import eu.kanade.tachiyomi.ui.reader.model.ReaderPage
 import eu.kanade.tachiyomi.ui.reader.model.ViewerChapters
 import eu.kanade.tachiyomi.ui.reader.viewer.BaseViewer
+import eu.kanade.tachiyomi.ui.reader.viewer.ViewerNavigation
 import timber.log.Timber
 import kotlin.math.min
 
@@ -89,34 +90,12 @@ abstract class PagerViewer(val activity: ReaderActivity) : BaseViewer {
                 return@f
             }
 
-            val positionX = event.x
-            val positionY = event.y
-            val topSideTap = positionY < pager.height * 0.25f
-            val bottomSideTap = positionY > pager.height * 0.75f
-            val leftSideTap = positionX < pager.width * 0.33f
-            val rightSideTap = positionX > pager.width * 0.66f
-
-            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()
-                }
+            val pos = PointF(event.rawX / pager.width, event.rawY / pager.height)
+            val navigator = config.navigator
+            when (navigator.getAction(pos)) {
+                ViewerNavigation.NavigationRegion.MENU -> activity.toggleMenu()
+                ViewerNavigation.NavigationRegion.NEXT -> moveToNext()
+                ViewerNavigation.NavigationRegion.PREV -> moveToPrevious()
             }
         }
         pager.longTapListener = f@{

+ 26 - 0
app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/webtoon/WebtoonConfig.kt

@@ -2,6 +2,10 @@ package eu.kanade.tachiyomi.ui.reader.viewer.webtoon
 
 import eu.kanade.tachiyomi.data.preference.PreferencesHelper
 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.api.get
 
@@ -22,5 +26,27 @@ class WebtoonConfig(preferences: PreferencesHelper = Injekt.get()) : ViewerConfi
 
         preferences.webtoonSidePadding()
             .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()
+        }
     }
 }

+ 5 - 0
app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/webtoon/WebtoonDefaultNavigation.kt

@@ -0,0 +1,5 @@
+package eu.kanade.tachiyomi.ui.reader.viewer.webtoon
+
+import eu.kanade.tachiyomi.ui.reader.viewer.navigation.LNavigation
+
+class WebtoonDefaultNavigation : LNavigation()

+ 11 - 20
app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/webtoon/WebtoonViewer.kt

@@ -1,5 +1,6 @@
 package eu.kanade.tachiyomi.ui.reader.viewer.webtoon
 
+import android.graphics.PointF
 import android.view.KeyEvent
 import android.view.MotionEvent
 import android.view.View
@@ -9,12 +10,12 @@ import androidx.core.view.isGone
 import androidx.core.view.isVisible
 import androidx.recyclerview.widget.RecyclerView
 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.model.ChapterTransition
 import eu.kanade.tachiyomi.ui.reader.model.ReaderPage
 import eu.kanade.tachiyomi.ui.reader.model.ViewerChapters
 import eu.kanade.tachiyomi.ui.reader.viewer.BaseViewer
+import eu.kanade.tachiyomi.ui.reader.viewer.ViewerNavigation
 import rx.subscriptions.CompositeSubscription
 import timber.log.Timber
 import kotlin.math.max
@@ -101,25 +102,15 @@ class WebtoonViewer(val activity: ReaderActivity, val isContinuous: Boolean = tr
                 return@f
             }
 
-            val positionX = event.rawX
-            val positionY = event.rawY
-            val topSideTap = positionY < recycler.height * 0.25f
-            val bottomSideTap = positionY > recycler.height * 0.75f
-            val leftSideTap = positionX < recycler.width * 0.33f
-            val rightSideTap = positionX > recycler.width * 0.66f
-
-            val invertMode = config.tappingInverted
-            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()
+            val pos = PointF(event.rawX / recycler.width, event.rawY / recycler.height)
+            if (!config.tappingEnabled) activity.toggleMenu()
+            else {
+                val navigator = config.navigator
+                when (navigator.getAction(pos)) {
+                    ViewerNavigation.NavigationRegion.MENU -> activity.toggleMenu()
+                    ViewerNavigation.NavigationRegion.NEXT -> scrollDown()
+                    ViewerNavigation.NavigationRegion.PREV -> scrollUp()
+                }
             }
         }
         recycler.longTapListener = f@{ event ->

+ 15 - 0
app/src/main/java/eu/kanade/tachiyomi/util/lang/RectFExtensions.kt

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

+ 43 - 4
app/src/main/res/layout/reader_settings_sheet.xml

@@ -203,6 +203,25 @@
         app:layout_constraintStart_toStartOf="parent"
         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
         android:id="@+id/scale_type_text"
         android:layout_width="0dp"
@@ -220,7 +239,7 @@
         android:entries="@array/image_scale_type"
         app:layout_constraintEnd_toEndOf="@id/spinner_end"
         app:layout_constraintStart_toEndOf="@id/verticalcenter"
-        app:layout_constraintTop_toBottomOf="@id/pager_prefs" />
+        app:layout_constraintTop_toBottomOf="@+id/pager_nav" />
 
     <TextView
         android:id="@+id/zoom_start_text"
@@ -326,6 +345,26 @@
         app:layout_constraintRight_toRightOf="@id/spinner_end"
         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
         android:id="@+id/crop_borders_webtoon"
         android:layout_width="match_parent"
@@ -333,7 +372,7 @@
         android:layout_marginTop="10dp"
         android:text="@string/pref_crop_borders"
         android:textColor="?android:attr/textColorSecondary"
-        app:layout_constraintTop_toBottomOf="@id/webtoon_side_padding" />
+        app:layout_constraintTop_toBottomOf="@+id/webtoon_nav" />
 
     <!-- Groups of preferences -->
 
@@ -342,7 +381,7 @@
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
         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" />
 
     <androidx.constraintlayout.widget.Group
@@ -350,7 +389,7 @@
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
         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
         android:id="@+id/verticalcenter"

+ 14 - 0
app/src/main/res/values/arrays.xml

@@ -91,4 +91,18 @@
         <item>@string/manga_from_library</item>
         <item>@string/downloaded_chapters</item>
     </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>

+ 5 - 0
app/src/main/res/values/strings.xml

@@ -277,12 +277,17 @@
     <string name="black_background">Black</string>
     <string name="pref_viewer_type">Default reading mode</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="right_to_left_viewer">Right to left</string>
     <string name="vertical_viewer">Vertical</string>
     <string name="webtoon_viewer">Webtoon</string>
     <string name="vertical_plus_viewer">Continuous vertical</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_scale_type">Scale type</string>
     <string name="scale_type_fit_screen">Fit screen</string>