Browse Source

Add manga-wised rotation mode settings (#4841)

* Add manga-wised rotation mode settings

Based on #3522

Co-authored-by: bboyz269 <[email protected]>

* Fix small mistakes

* Complete TODOs

* Rename functions

rotation -> orientation

* Fix orientation icon not changing

Bug from video

* Fix bug with force portrait not being force if a default value

Bug from video

* Backup viewer_flag as a seperate field in so legacy/forks doesn't crash

* Make viewer_flags nullable so old backups viewer gets restored

* Add migration for old rotation and viewer to new defaults ones

* Rename variable in enums

* Fix migration after OrientationType was changed

* Remove untrue comment

Co-authored-by: bboyz269 <[email protected]>
Andreas 3 years ago
parent
commit
0fef546a0d
30 changed files with 313 additions and 234 deletions
  1. 1 1
      app/build.gradle.kts
  2. 29 1
      app/src/main/java/eu/kanade/tachiyomi/Migrations.kt
  3. 5 3
      app/src/main/java/eu/kanade/tachiyomi/data/backup/full/models/BackupManga.kt
  4. 2 2
      app/src/main/java/eu/kanade/tachiyomi/data/backup/legacy/serializer/MangaTypeAdapter.kt
  5. 2 2
      app/src/main/java/eu/kanade/tachiyomi/data/database/mappers/MangaTypeMapping.kt
  6. 48 34
      app/src/main/java/eu/kanade/tachiyomi/data/database/models/Manga.kt
  7. 1 1
      app/src/main/java/eu/kanade/tachiyomi/data/database/models/MangaImpl.kt
  8. 15 11
      app/src/main/java/eu/kanade/tachiyomi/data/database/queries/MangaQueries.kt
  9. 3 2
      app/src/main/java/eu/kanade/tachiyomi/data/database/resolvers/MangaFlagsPutResolver.kt
  10. 0 32
      app/src/main/java/eu/kanade/tachiyomi/data/database/resolvers/MangaViewerPutResolver.kt
  11. 3 3
      app/src/main/java/eu/kanade/tachiyomi/data/preference/PreferenceKeys.kt
  12. 9 7
      app/src/main/java/eu/kanade/tachiyomi/data/preference/PreferencesHelper.kt
  13. 3 3
      app/src/main/java/eu/kanade/tachiyomi/ui/browse/migration/search/SearchPresenter.kt
  14. 22 22
      app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaPresenter.kt
  15. 1 1
      app/src/main/java/eu/kanade/tachiyomi/ui/manga/chapter/ChapterHolder.kt
  16. 10 10
      app/src/main/java/eu/kanade/tachiyomi/ui/manga/chapter/ChaptersSettingsSheet.kt
  17. 18 26
      app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderActivity.kt
  18. 48 13
      app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderPresenter.kt
  19. 13 9
      app/src/main/java/eu/kanade/tachiyomi/ui/reader/setting/OrientationType.kt
  20. 0 1
      app/src/main/java/eu/kanade/tachiyomi/ui/reader/setting/ReaderGeneralSettings.kt
  21. 11 4
      app/src/main/java/eu/kanade/tachiyomi/ui/reader/setting/ReaderReadingModeSettings.kt
  22. 12 8
      app/src/main/java/eu/kanade/tachiyomi/ui/reader/setting/ReadingModeType.kt
  23. 6 6
      app/src/main/java/eu/kanade/tachiyomi/ui/recent/history/HistoryPresenter.kt
  24. 10 6
      app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsReaderController.kt
  25. 6 3
      app/src/main/java/eu/kanade/tachiyomi/util/chapter/ChapterSettingsHelper.kt
  26. 0 7
      app/src/main/res/layout/reader_general_settings.xml
  27. 19 2
      app/src/main/res/layout/reader_reading_mode_settings.xml
  28. 1 8
      app/src/main/res/values/arrays.xml
  29. 3 1
      app/src/main/res/values/strings.xml
  30. 12 5
      app/src/test/java/eu/kanade/tachiyomi/data/backup/BackupTest.kt

+ 1 - 1
app/build.gradle.kts

@@ -29,7 +29,7 @@ android {
         minSdkVersion(AndroidConfig.minSdk)
         targetSdkVersion(AndroidConfig.targetSdk)
         testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
-        versionCode = 59
+        versionCode = 60
         versionName = "0.10.12"
 
         buildConfigField("String", "COMMIT_COUNT", "\"${getCommitCount()}\"")

+ 29 - 1
app/src/main/java/eu/kanade/tachiyomi/Migrations.kt

@@ -12,6 +12,7 @@ import eu.kanade.tachiyomi.data.updater.UpdaterJob
 import eu.kanade.tachiyomi.extension.ExtensionUpdateJob
 import eu.kanade.tachiyomi.network.PREF_DOH_CLOUDFLARE
 import eu.kanade.tachiyomi.ui.library.LibrarySort
+import eu.kanade.tachiyomi.ui.reader.setting.OrientationType
 import eu.kanade.tachiyomi.util.system.toast
 import eu.kanade.tachiyomi.widget.ExtendedNavigationView
 import uy.kohesive.injekt.Injekt
@@ -142,13 +143,40 @@ object Migrations {
             }
             if (oldVersion < 59) {
                 // Reset rotation to Free after replacing Lock
-                preferences.rotation().set(1)
+                val prefs = PreferenceManager.getDefaultSharedPreferences(context)
+                if (prefs.contains("pref_rotation_type_key")) {
+                    prefs.edit {
+                        putInt("pref_rotation_type_key", 1)
+                    }
+                }
 
                 // Disable update check for Android 5.x users
                 if (BuildConfig.INCLUDE_UPDATER && Build.VERSION.SDK_INT <= Build.VERSION_CODES.M) {
                     UpdaterJob.cancelTask(context)
                 }
             }
+            if (oldVersion < 60) {
+                // Migrate Rotation and Viewer values to default values for viewer_flags
+                val prefs = PreferenceManager.getDefaultSharedPreferences(context)
+                val newOrientation = when (prefs.getInt("pref_rotation_type_key", 1)) {
+                    1 -> OrientationType.FREE.flagValue
+                    2 -> OrientationType.PORTRAIT.flagValue
+                    3 -> OrientationType.LANDSCAPE.flagValue
+                    4 -> OrientationType.LOCKED_PORTRAIT.flagValue
+                    5 -> OrientationType.LOCKED_LANDSCAPE.flagValue
+                    else -> OrientationType.FREE.flagValue
+                }
+
+                // Reading mode flag and prefValue is the same value
+                val newReadingMode = prefs.getInt("pref_default_viewer_key", 1)
+
+                prefs.edit {
+                    putInt("pref_default_orientation_type_key", newOrientation)
+                    remove("pref_rotation_type_key")
+                    putInt("pref_default_reading_mode_key", newReadingMode)
+                    remove("pref_default_viewer_key")
+                }
+            }
             return true
         }
 

+ 5 - 3
app/src/main/java/eu/kanade/tachiyomi/data/backup/full/models/BackupManga.kt

@@ -25,7 +25,7 @@ data class BackupManga(
     // @ProtoNumber(11) val lastUpdate: Long = 0, 1.x value, not used in 0.x
     // @ProtoNumber(12) val lastInit: Long = 0, 1.x value, not used in 0.x
     @ProtoNumber(13) var dateAdded: Long = 0,
-    @ProtoNumber(14) var viewer: Int = 0,
+    @ProtoNumber(14) var viewer: Int = 0, // Replaced by viewer_flags
     // @ProtoNumber(15) val flags: Int = 0, 1.x value, not used in 0.x
     @ProtoNumber(16) var chapters: List<BackupChapter> = emptyList(),
     @ProtoNumber(17) var categories: List<Int> = emptyList(),
@@ -34,6 +34,7 @@ data class BackupManga(
     @ProtoNumber(100) var favorite: Boolean = true,
     @ProtoNumber(101) var chapterFlags: Int = 0,
     @ProtoNumber(102) var history: List<BackupHistory> = emptyList(),
+    @ProtoNumber(103) var viewer_flags: Int? = null
 ) {
     fun getMangaImpl(): MangaImpl {
         return MangaImpl().apply {
@@ -48,7 +49,7 @@ data class BackupManga(
             favorite = [email protected]
             source = [email protected]
             date_added = [email protected]
-            viewer = [email protected]
+            viewer_flags = [email protected]_flags ?: [email protected]
             chapter_flags = [email protected]
         }
     }
@@ -79,7 +80,8 @@ data class BackupManga(
                 favorite = manga.favorite,
                 source = manga.source,
                 dateAdded = manga.date_added,
-                viewer = manga.viewer,
+                viewer = manga.readingModeType,
+                viewer_flags = manga.viewer_flags,
                 chapterFlags = manga.chapter_flags
             )
         }

+ 2 - 2
app/src/main/java/eu/kanade/tachiyomi/data/backup/legacy/serializer/MangaTypeAdapter.kt

@@ -16,7 +16,7 @@ object MangaTypeAdapter {
                 value(it.url)
                 value(it.title)
                 value(it.source)
-                value(it.viewer)
+                value(it.viewer_flags)
                 value(it.chapter_flags)
                 endArray()
             }
@@ -27,7 +27,7 @@ object MangaTypeAdapter {
                 manga.url = nextString()
                 manga.title = nextString()
                 manga.source = nextLong()
-                manga.viewer = nextInt()
+                manga.viewer_flags = nextInt()
                 manga.chapter_flags = nextInt()
                 endArray()
                 manga

+ 2 - 2
app/src/main/java/eu/kanade/tachiyomi/data/database/mappers/MangaTypeMapping.kt

@@ -63,7 +63,7 @@ class MangaPutResolver : DefaultPutResolver<Manga>() {
             COL_FAVORITE to obj.favorite,
             COL_LAST_UPDATE to obj.last_update,
             COL_INITIALIZED to obj.initialized,
-            COL_VIEWER to obj.viewer,
+            COL_VIEWER to obj.viewer_flags,
             COL_CHAPTER_FLAGS to obj.chapter_flags,
             COL_COVER_LAST_MODIFIED to obj.cover_last_modified,
             COL_DATE_ADDED to obj.date_added
@@ -85,7 +85,7 @@ interface BaseMangaGetResolver {
         favorite = cursor.getInt(cursor.getColumnIndex(COL_FAVORITE)) == 1
         last_update = cursor.getLong(cursor.getColumnIndex(COL_LAST_UPDATE))
         initialized = cursor.getInt(cursor.getColumnIndex(COL_INITIALIZED)) == 1
-        viewer = cursor.getInt(cursor.getColumnIndex(COL_VIEWER))
+        viewer_flags = cursor.getInt(cursor.getColumnIndex(COL_VIEWER))
         chapter_flags = cursor.getInt(cursor.getColumnIndex(COL_CHAPTER_FLAGS))
         cover_last_modified = cursor.getLong(cursor.getColumnIndex(COL_COVER_LAST_MODIFIED))
         date_added = cursor.getLong(cursor.getColumnIndex(COL_DATE_ADDED))

+ 48 - 34
app/src/main/java/eu/kanade/tachiyomi/data/database/models/Manga.kt

@@ -1,6 +1,8 @@
 package eu.kanade.tachiyomi.data.database.models
 
 import eu.kanade.tachiyomi.source.model.SManga
+import eu.kanade.tachiyomi.ui.reader.setting.OrientationType
+import eu.kanade.tachiyomi.ui.reader.setting.ReadingModeType
 import tachiyomi.source.model.MangaInfo
 
 interface Manga : SManga {
@@ -15,78 +17,90 @@ interface Manga : SManga {
 
     var date_added: Long
 
-    var viewer: Int
+    var viewer_flags: Int
 
     var chapter_flags: Int
 
     var cover_last_modified: Long
 
     fun setChapterOrder(order: Int) {
-        setFlags(order, SORT_MASK)
+        setChapterFlags(order, CHAPTER_SORT_MASK)
     }
 
     fun sortDescending(): Boolean {
-        return chapter_flags and SORT_MASK == SORT_DESC
+        return chapter_flags and CHAPTER_SORT_MASK == CHAPTER_SORT_DESC
     }
 
     fun getGenres(): List<String>? {
         return genre?.split(", ")?.map { it.trim() }
     }
 
-    private fun setFlags(flag: Int, mask: Int) {
+    private fun setChapterFlags(flag: Int, mask: Int) {
         chapter_flags = chapter_flags and mask.inv() or (flag and mask)
     }
 
+    private fun setViewerFlags(flag: Int, mask: Int) {
+        viewer_flags = viewer_flags and mask.inv() or (flag and mask)
+    }
+
     // Used to display the chapter's title one way or another
     var displayMode: Int
-        get() = chapter_flags and DISPLAY_MASK
-        set(mode) = setFlags(mode, DISPLAY_MASK)
+        get() = chapter_flags and CHAPTER_DISPLAY_MASK
+        set(mode) = setChapterFlags(mode, CHAPTER_DISPLAY_MASK)
 
     var readFilter: Int
-        get() = chapter_flags and READ_MASK
-        set(filter) = setFlags(filter, READ_MASK)
+        get() = chapter_flags and CHAPTER_READ_MASK
+        set(filter) = setChapterFlags(filter, CHAPTER_READ_MASK)
 
     var downloadedFilter: Int
-        get() = chapter_flags and DOWNLOADED_MASK
-        set(filter) = setFlags(filter, DOWNLOADED_MASK)
+        get() = chapter_flags and CHAPTER_DOWNLOADED_MASK
+        set(filter) = setChapterFlags(filter, CHAPTER_DOWNLOADED_MASK)
 
     var bookmarkedFilter: Int
-        get() = chapter_flags and BOOKMARKED_MASK
-        set(filter) = setFlags(filter, BOOKMARKED_MASK)
+        get() = chapter_flags and CHAPTER_BOOKMARKED_MASK
+        set(filter) = setChapterFlags(filter, CHAPTER_BOOKMARKED_MASK)
 
     var sorting: Int
-        get() = chapter_flags and SORTING_MASK
-        set(sort) = setFlags(sort, SORTING_MASK)
+        get() = chapter_flags and CHAPTER_SORTING_MASK
+        set(sort) = setChapterFlags(sort, CHAPTER_SORTING_MASK)
 
-    companion object {
+    var readingModeType: Int
+        get() = viewer_flags and ReadingModeType.MASK
+        set(readingMode) = setViewerFlags(readingMode, ReadingModeType.MASK)
 
-        const val SORT_DESC = 0x00000000
-        const val SORT_ASC = 0x00000001
-        const val SORT_MASK = 0x00000001
+    var orientationType: Int
+        get() = viewer_flags and OrientationType.MASK
+        set(rotationType) = setViewerFlags(rotationType, OrientationType.MASK)
+
+    companion object {
 
         // Generic filter that does not filter anything
         const val SHOW_ALL = 0x00000000
 
-        const val SHOW_UNREAD = 0x00000002
-        const val SHOW_READ = 0x00000004
-        const val READ_MASK = 0x00000006
+        const val CHAPTER_SORT_DESC = 0x00000000
+        const val CHAPTER_SORT_ASC = 0x00000001
+        const val CHAPTER_SORT_MASK = 0x00000001
+
+        const val CHAPTER_SHOW_UNREAD = 0x00000002
+        const val CHAPTER_SHOW_READ = 0x00000004
+        const val CHAPTER_READ_MASK = 0x00000006
 
-        const val SHOW_DOWNLOADED = 0x00000008
-        const val SHOW_NOT_DOWNLOADED = 0x00000010
-        const val DOWNLOADED_MASK = 0x00000018
+        const val CHAPTER_SHOW_DOWNLOADED = 0x00000008
+        const val CHAPTER_SHOW_NOT_DOWNLOADED = 0x00000010
+        const val CHAPTER_DOWNLOADED_MASK = 0x00000018
 
-        const val SHOW_BOOKMARKED = 0x00000020
-        const val SHOW_NOT_BOOKMARKED = 0x00000040
-        const val BOOKMARKED_MASK = 0x00000060
+        const val CHAPTER_SHOW_BOOKMARKED = 0x00000020
+        const val CHAPTER_SHOW_NOT_BOOKMARKED = 0x00000040
+        const val CHAPTER_BOOKMARKED_MASK = 0x00000060
 
-        const val SORTING_SOURCE = 0x00000000
-        const val SORTING_NUMBER = 0x00000100
-        const val SORTING_UPLOAD_DATE = 0x00000200
-        const val SORTING_MASK = 0x00000300
+        const val CHAPTER_SORTING_SOURCE = 0x00000000
+        const val CHAPTER_SORTING_NUMBER = 0x00000100
+        const val CHAPTER_SORTING_UPLOAD_DATE = 0x00000200
+        const val CHAPTER_SORTING_MASK = 0x00000300
 
-        const val DISPLAY_NAME = 0x00000000
-        const val DISPLAY_NUMBER = 0x00100000
-        const val DISPLAY_MASK = 0x00100000
+        const val CHAPTER_DISPLAY_NAME = 0x00000000
+        const val CHAPTER_DISPLAY_NUMBER = 0x00100000
+        const val CHAPTER_DISPLAY_MASK = 0x00100000
 
         fun create(source: Long): Manga = MangaImpl().apply {
             this.source = source

+ 1 - 1
app/src/main/java/eu/kanade/tachiyomi/data/database/models/MangaImpl.kt

@@ -30,7 +30,7 @@ open class MangaImpl : Manga {
 
     override var initialized: Boolean = false
 
-    override var viewer: Int = 0
+    override var viewer_flags: Int = 0
 
     override var chapter_flags: Int = 0
 

+ 15 - 11
app/src/main/java/eu/kanade/tachiyomi/data/database/queries/MangaQueries.kt

@@ -12,7 +12,6 @@ import eu.kanade.tachiyomi.data.database.resolvers.MangaFavoritePutResolver
 import eu.kanade.tachiyomi.data.database.resolvers.MangaFlagsPutResolver
 import eu.kanade.tachiyomi.data.database.resolvers.MangaLastUpdatedPutResolver
 import eu.kanade.tachiyomi.data.database.resolvers.MangaTitlePutResolver
-import eu.kanade.tachiyomi.data.database.resolvers.MangaViewerPutResolver
 import eu.kanade.tachiyomi.data.database.tables.CategoryTable
 import eu.kanade.tachiyomi.data.database.tables.ChapterTable
 import eu.kanade.tachiyomi.data.database.tables.MangaCategoryTable
@@ -78,14 +77,24 @@ interface MangaQueries : DbProvider {
 
     fun insertMangas(mangas: List<Manga>) = db.put().objects(mangas).prepare()
 
-    fun updateFlags(manga: Manga) = db.put()
+    fun updateChapterFlags(manga: Manga) = db.put()
         .`object`(manga)
-        .withPutResolver(MangaFlagsPutResolver())
+        .withPutResolver(MangaFlagsPutResolver(MangaTable.COL_CHAPTER_FLAGS, Manga::chapter_flags))
         .prepare()
 
-    fun updateFlags(mangas: List<Manga>) = db.put()
-        .objects(mangas)
-        .withPutResolver(MangaFlagsPutResolver(true))
+    fun updateChapterFlags(manga: List<Manga>) = db.put()
+        .objects(manga)
+        .withPutResolver(MangaFlagsPutResolver(MangaTable.COL_CHAPTER_FLAGS, Manga::chapter_flags, true))
+        .prepare()
+
+    fun updateViewerFlags(manga: Manga) = db.put()
+        .`object`(manga)
+        .withPutResolver(MangaFlagsPutResolver(MangaTable.COL_VIEWER, Manga::viewer_flags))
+        .prepare()
+
+    fun updateViewerFlags(manga: List<Manga>) = db.put()
+        .objects(manga)
+        .withPutResolver(MangaFlagsPutResolver(MangaTable.COL_VIEWER, Manga::viewer_flags, true))
         .prepare()
 
     fun updateLastUpdated(manga: Manga) = db.put()
@@ -98,11 +107,6 @@ interface MangaQueries : DbProvider {
         .withPutResolver(MangaFavoritePutResolver())
         .prepare()
 
-    fun updateMangaViewer(manga: Manga) = db.put()
-        .`object`(manga)
-        .withPutResolver(MangaViewerPutResolver())
-        .prepare()
-
     fun updateMangaTitle(manga: Manga) = db.put()
         .`object`(manga)
         .withPutResolver(MangaTitlePutResolver())

+ 3 - 2
app/src/main/java/eu/kanade/tachiyomi/data/database/resolvers/MangaFlagsPutResolver.kt

@@ -8,8 +8,9 @@ import com.pushtorefresh.storio.sqlite.queries.UpdateQuery
 import eu.kanade.tachiyomi.data.database.inTransactionReturn
 import eu.kanade.tachiyomi.data.database.models.Manga
 import eu.kanade.tachiyomi.data.database.tables.MangaTable
+import kotlin.reflect.KProperty1
 
-class MangaFlagsPutResolver(private val updateAll: Boolean = false) : PutResolver<Manga>() {
+class MangaFlagsPutResolver(private val colName: String, private val fieldGetter: KProperty1<Manga, Int>, private val updateAll: Boolean = false) : PutResolver<Manga>() {
 
     override fun performPut(db: StorIOSQLite, manga: Manga) = db.inTransactionReturn {
         val updateQuery = mapToUpdateQuery(manga)
@@ -37,6 +38,6 @@ class MangaFlagsPutResolver(private val updateAll: Boolean = false) : PutResolve
 
     fun mapToContentValues(manga: Manga) =
         contentValuesOf(
-            MangaTable.COL_CHAPTER_FLAGS to manga.chapter_flags
+            colName to fieldGetter.get(manga)
         )
 }

+ 0 - 32
app/src/main/java/eu/kanade/tachiyomi/data/database/resolvers/MangaViewerPutResolver.kt

@@ -1,32 +0,0 @@
-package eu.kanade.tachiyomi.data.database.resolvers
-
-import androidx.core.content.contentValuesOf
-import com.pushtorefresh.storio.sqlite.StorIOSQLite
-import com.pushtorefresh.storio.sqlite.operations.put.PutResolver
-import com.pushtorefresh.storio.sqlite.operations.put.PutResult
-import com.pushtorefresh.storio.sqlite.queries.UpdateQuery
-import eu.kanade.tachiyomi.data.database.inTransactionReturn
-import eu.kanade.tachiyomi.data.database.models.Manga
-import eu.kanade.tachiyomi.data.database.tables.MangaTable
-
-class MangaViewerPutResolver : PutResolver<Manga>() {
-
-    override fun performPut(db: StorIOSQLite, manga: Manga) = db.inTransactionReturn {
-        val updateQuery = mapToUpdateQuery(manga)
-        val contentValues = mapToContentValues(manga)
-
-        val numberOfRowsUpdated = db.lowLevel().update(updateQuery, contentValues)
-        PutResult.newUpdateResult(numberOfRowsUpdated, updateQuery.table())
-    }
-
-    fun mapToUpdateQuery(manga: Manga) = UpdateQuery.builder()
-        .table(MangaTable.TABLE)
-        .where("${MangaTable.COL_ID} = ?")
-        .whereArgs(manga.id)
-        .build()
-
-    fun mapToContentValues(manga: Manga) =
-        contentValuesOf(
-            MangaTable.COL_VIEWER to manga.viewer
-        )
-}

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

@@ -15,8 +15,6 @@ object PreferenceKeys {
 
     const val hideBottomBar = "pref_hide_bottom_bar_on_scroll"
 
-    const val rotation = "pref_rotation_type_key"
-
     const val enableTransitions = "pref_enable_transitions_key"
 
     const val doubleTapAnimationSpeed = "pref_double_tap_anim_speed"
@@ -51,7 +49,9 @@ object PreferenceKeys {
 
     const val colorFilterMode = "color_filter_mode"
 
-    const val defaultViewer = "pref_default_viewer_key"
+    const val defaultReadingMode = "pref_default_reading_mode_key"
+
+    const val defaultOrientationType = "pref_default_orientation_type_key"
 
     const val imageScaleType = "pref_image_scale_type_key"
 

+ 9 - 7
app/src/main/java/eu/kanade/tachiyomi/data/preference/PreferencesHelper.kt

@@ -12,6 +12,8 @@ import eu.kanade.tachiyomi.data.database.models.Manga
 import eu.kanade.tachiyomi.data.preference.PreferenceValues.DisplayMode
 import eu.kanade.tachiyomi.data.track.TrackService
 import eu.kanade.tachiyomi.data.track.anilist.Anilist
+import eu.kanade.tachiyomi.ui.reader.setting.OrientationType
+import eu.kanade.tachiyomi.ui.reader.setting.ReadingModeType
 import eu.kanade.tachiyomi.widget.ExtendedNavigationView
 import kotlinx.coroutines.flow.Flow
 import kotlinx.coroutines.flow.onEach
@@ -85,8 +87,6 @@ class PreferencesHelper(val context: Context) {
 
     fun themeDark() = flowPrefs.getEnum(Keys.themeDark, Values.DarkThemeVariant.default)
 
-    fun rotation() = flowPrefs.getInt(Keys.rotation, 1)
-
     fun pageTransitions() = flowPrefs.getBoolean(Keys.enableTransitions, true)
 
     fun doubleTapAnimSpeed() = flowPrefs.getInt(Keys.doubleTapAnimationSpeed, 500)
@@ -121,7 +121,9 @@ class PreferencesHelper(val context: Context) {
 
     fun colorFilterMode() = flowPrefs.getInt(Keys.colorFilterMode, 0)
 
-    fun defaultViewer() = prefs.getInt(Keys.defaultViewer, 2)
+    fun defaultReadingMode() = prefs.getInt(Keys.defaultReadingMode, ReadingModeType.RIGHT_TO_LEFT.flagValue)
+
+    fun defaultOrientationType() = prefs.getInt(Keys.defaultOrientationType, OrientationType.FREE.flagValue)
 
     fun imageScaleType() = flowPrefs.getInt(Keys.imageScaleType, 1)
 
@@ -291,11 +293,11 @@ class PreferencesHelper(val context: Context) {
 
     fun filterChapterByBookmarked() = prefs.getInt(Keys.defaultChapterFilterByBookmarked, Manga.SHOW_ALL)
 
-    fun sortChapterBySourceOrNumber() = prefs.getInt(Keys.defaultChapterSortBySourceOrNumber, Manga.SORTING_SOURCE)
+    fun sortChapterBySourceOrNumber() = prefs.getInt(Keys.defaultChapterSortBySourceOrNumber, Manga.CHAPTER_SORTING_SOURCE)
 
-    fun displayChapterByNameOrNumber() = prefs.getInt(Keys.defaultChapterDisplayByNameOrNumber, Manga.DISPLAY_NAME)
+    fun displayChapterByNameOrNumber() = prefs.getInt(Keys.defaultChapterDisplayByNameOrNumber, Manga.CHAPTER_DISPLAY_NAME)
 
-    fun sortChapterByAscendingOrDescending() = prefs.getInt(Keys.defaultChapterSortByAscendingOrDescending, Manga.SORT_DESC)
+    fun sortChapterByAscendingOrDescending() = prefs.getInt(Keys.defaultChapterSortByAscendingOrDescending, Manga.CHAPTER_SORT_DESC)
 
     fun incognitoMode() = flowPrefs.getBoolean(Keys.incognitoMode, false)
 
@@ -308,7 +310,7 @@ class PreferencesHelper(val context: Context) {
             putInt(Keys.defaultChapterFilterByBookmarked, manga.bookmarkedFilter)
             putInt(Keys.defaultChapterSortBySourceOrNumber, manga.sorting)
             putInt(Keys.defaultChapterDisplayByNameOrNumber, manga.displayMode)
-            putInt(Keys.defaultChapterSortByAscendingOrDescending, if (manga.sortDescending()) Manga.SORT_DESC else Manga.SORT_ASC)
+            putInt(Keys.defaultChapterSortByAscendingOrDescending, if (manga.sortDescending()) Manga.CHAPTER_SORT_DESC else Manga.CHAPTER_SORT_ASC)
         }
     }
 }

+ 3 - 3
app/src/main/java/eu/kanade/tachiyomi/ui/browse/migration/search/SearchPresenter.kt

@@ -149,9 +149,9 @@ class SearchPresenter(
 
             // Update reading preferences
             manga.chapter_flags = prevManga.chapter_flags
-            db.updateFlags(manga).executeAsBlocking()
-            manga.viewer = prevManga.viewer
-            db.updateMangaViewer(manga).executeAsBlocking()
+            db.updateChapterFlags(manga).executeAsBlocking()
+            manga.viewer_flags = prevManga.viewer_flags
+            db.updateViewerFlags(manga).executeAsBlocking()
 
             // Update date added
             if (replace) {

+ 22 - 22
app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaPresenter.kt

@@ -436,15 +436,15 @@ class MangaPresenter(
 
     fun getChapterSort(): (Chapter, Chapter) -> Int {
         return when (manga.sorting) {
-            Manga.SORTING_SOURCE -> when (sortDescending()) {
+            Manga.CHAPTER_SORTING_SOURCE -> when (sortDescending()) {
                 true -> { c1, c2 -> c1.source_order.compareTo(c2.source_order) }
                 false -> { c1, c2 -> c2.source_order.compareTo(c1.source_order) }
             }
-            Manga.SORTING_NUMBER -> when (sortDescending()) {
+            Manga.CHAPTER_SORTING_NUMBER -> when (sortDescending()) {
                 true -> { c1, c2 -> c2.chapter_number.compareTo(c1.chapter_number) }
                 false -> { c1, c2 -> c1.chapter_number.compareTo(c2.chapter_number) }
             }
-            Manga.SORTING_UPLOAD_DATE -> when (sortDescending()) {
+            Manga.CHAPTER_SORTING_UPLOAD_DATE -> when (sortDescending()) {
                 true -> { c1, c2 -> c2.date_upload.compareTo(c1.date_upload) }
                 false -> { c1, c2 -> c1.date_upload.compareTo(c2.date_upload) }
             }
@@ -564,8 +564,8 @@ class MangaPresenter(
      * Reverses the sorting and requests an UI update.
      */
     fun reverseSortOrder() {
-        manga.setChapterOrder(if (sortDescending()) Manga.SORT_ASC else Manga.SORT_DESC)
-        db.updateFlags(manga).executeAsBlocking()
+        manga.setChapterOrder(if (sortDescending()) Manga.CHAPTER_SORT_ASC else Manga.CHAPTER_SORT_DESC)
+        db.updateChapterFlags(manga).executeAsBlocking()
         refreshChapters()
     }
 
@@ -576,10 +576,10 @@ class MangaPresenter(
     fun setUnreadFilter(state: State) {
         manga.readFilter = when (state) {
             State.IGNORE -> Manga.SHOW_ALL
-            State.INCLUDE -> Manga.SHOW_UNREAD
-            State.EXCLUDE -> Manga.SHOW_READ
+            State.INCLUDE -> Manga.CHAPTER_SHOW_UNREAD
+            State.EXCLUDE -> Manga.CHAPTER_SHOW_READ
         }
-        db.updateFlags(manga).executeAsBlocking()
+        db.updateChapterFlags(manga).executeAsBlocking()
         refreshChapters()
     }
 
@@ -590,10 +590,10 @@ class MangaPresenter(
     fun setDownloadedFilter(state: State) {
         manga.downloadedFilter = when (state) {
             State.IGNORE -> Manga.SHOW_ALL
-            State.INCLUDE -> Manga.SHOW_DOWNLOADED
-            State.EXCLUDE -> Manga.SHOW_NOT_DOWNLOADED
+            State.INCLUDE -> Manga.CHAPTER_SHOW_DOWNLOADED
+            State.EXCLUDE -> Manga.CHAPTER_SHOW_NOT_DOWNLOADED
         }
-        db.updateFlags(manga).executeAsBlocking()
+        db.updateChapterFlags(manga).executeAsBlocking()
         refreshChapters()
     }
 
@@ -604,10 +604,10 @@ class MangaPresenter(
     fun setBookmarkedFilter(state: State) {
         manga.bookmarkedFilter = when (state) {
             State.IGNORE -> Manga.SHOW_ALL
-            State.INCLUDE -> Manga.SHOW_BOOKMARKED
-            State.EXCLUDE -> Manga.SHOW_NOT_BOOKMARKED
+            State.INCLUDE -> Manga.CHAPTER_SHOW_BOOKMARKED
+            State.EXCLUDE -> Manga.CHAPTER_SHOW_NOT_BOOKMARKED
         }
-        db.updateFlags(manga).executeAsBlocking()
+        db.updateChapterFlags(manga).executeAsBlocking()
         refreshChapters()
     }
 
@@ -617,7 +617,7 @@ class MangaPresenter(
      */
     fun setDisplayMode(mode: Int) {
         manga.displayMode = mode
-        db.updateFlags(manga).executeAsBlocking()
+        db.updateChapterFlags(manga).executeAsBlocking()
     }
 
     /**
@@ -626,7 +626,7 @@ class MangaPresenter(
      */
     fun setSorting(sort: Int) {
         manga.sorting = sort
-        db.updateFlags(manga).executeAsBlocking()
+        db.updateChapterFlags(manga).executeAsBlocking()
         refreshChapters()
     }
 
@@ -645,8 +645,8 @@ class MangaPresenter(
             return State.INCLUDE
         }
         return when (manga.downloadedFilter) {
-            Manga.SHOW_DOWNLOADED -> State.INCLUDE
-            Manga.SHOW_NOT_DOWNLOADED -> State.EXCLUDE
+            Manga.CHAPTER_SHOW_DOWNLOADED -> State.INCLUDE
+            Manga.CHAPTER_SHOW_NOT_DOWNLOADED -> State.EXCLUDE
             else -> State.IGNORE
         }
     }
@@ -656,8 +656,8 @@ class MangaPresenter(
      */
     fun onlyBookmarked(): State {
         return when (manga.bookmarkedFilter) {
-            Manga.SHOW_BOOKMARKED -> State.INCLUDE
-            Manga.SHOW_NOT_BOOKMARKED -> State.EXCLUDE
+            Manga.CHAPTER_SHOW_BOOKMARKED -> State.INCLUDE
+            Manga.CHAPTER_SHOW_NOT_BOOKMARKED -> State.EXCLUDE
             else -> State.IGNORE
         }
     }
@@ -667,8 +667,8 @@ class MangaPresenter(
      */
     fun onlyUnread(): State {
         return when (manga.readFilter) {
-            Manga.SHOW_UNREAD -> State.INCLUDE
-            Manga.SHOW_READ -> State.EXCLUDE
+            Manga.CHAPTER_SHOW_UNREAD -> State.INCLUDE
+            Manga.CHAPTER_SHOW_READ -> State.EXCLUDE
             else -> State.IGNORE
         }
     }

+ 1 - 1
app/src/main/java/eu/kanade/tachiyomi/ui/manga/chapter/ChapterHolder.kt

@@ -29,7 +29,7 @@ class ChapterHolder(
         val chapter = item.chapter
 
         binding.chapterTitle.text = when (manga.displayMode) {
-            Manga.DISPLAY_NUMBER -> {
+            Manga.CHAPTER_DISPLAY_NUMBER -> {
                 val number = adapter.decimalFormat.format(chapter.chapter_number.toDouble())
                 itemView.context.getString(R.string.display_mode_chapter, number)
             }

+ 10 - 10
app/src/main/java/eu/kanade/tachiyomi/ui/manga/chapter/ChaptersSettingsSheet.kt

@@ -152,11 +152,11 @@ class ChaptersSettingsSheet(
                 }
 
                 source.state =
-                    if (sorting == Manga.SORTING_SOURCE) order else Item.MultiSort.SORT_NONE
+                    if (sorting == Manga.CHAPTER_SORTING_SOURCE) order else Item.MultiSort.SORT_NONE
                 chapterNum.state =
-                    if (sorting == Manga.SORTING_NUMBER) order else Item.MultiSort.SORT_NONE
+                    if (sorting == Manga.CHAPTER_SORTING_NUMBER) order else Item.MultiSort.SORT_NONE
                 uploadDate.state =
-                    if (sorting == Manga.SORTING_UPLOAD_DATE) order else Item.MultiSort.SORT_NONE
+                    if (sorting == Manga.CHAPTER_SORTING_UPLOAD_DATE) order else Item.MultiSort.SORT_NONE
             }
 
             override fun onItemClicked(item: Item) {
@@ -175,9 +175,9 @@ class ChaptersSettingsSheet(
                 }
 
                 when (item) {
-                    source -> presenter.setSorting(Manga.SORTING_SOURCE)
-                    chapterNum -> presenter.setSorting(Manga.SORTING_NUMBER)
-                    uploadDate -> presenter.setSorting(Manga.SORTING_UPLOAD_DATE)
+                    source -> presenter.setSorting(Manga.CHAPTER_SORTING_SOURCE)
+                    chapterNum -> presenter.setSorting(Manga.CHAPTER_SORTING_NUMBER)
+                    uploadDate -> presenter.setSorting(Manga.CHAPTER_SORTING_UPLOAD_DATE)
                     else -> throw Exception("Unknown sorting")
                 }
 
@@ -209,8 +209,8 @@ class ChaptersSettingsSheet(
 
             override fun initModels() {
                 val mode = presenter.manga.displayMode
-                displayTitle.checked = mode == Manga.DISPLAY_NAME
-                displayChapterNum.checked = mode == Manga.DISPLAY_NUMBER
+                displayTitle.checked = mode == Manga.CHAPTER_DISPLAY_NAME
+                displayChapterNum.checked = mode == Manga.CHAPTER_DISPLAY_NUMBER
             }
 
             override fun onItemClicked(item: Item) {
@@ -221,8 +221,8 @@ class ChaptersSettingsSheet(
                 item.checked = true
 
                 when (item) {
-                    displayTitle -> presenter.setDisplayMode(Manga.DISPLAY_NAME)
-                    displayChapterNum -> presenter.setDisplayMode(Manga.DISPLAY_NUMBER)
+                    displayTitle -> presenter.setDisplayMode(Manga.CHAPTER_DISPLAY_NAME)
+                    displayChapterNum -> presenter.setDisplayMode(Manga.CHAPTER_DISPLAY_NUMBER)
                     else -> throw NotImplementedError("Unknown display mode")
                 }
 

+ 18 - 26
app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderActivity.kt

@@ -31,7 +31,6 @@ import eu.kanade.tachiyomi.data.database.models.Manga
 import eu.kanade.tachiyomi.data.notification.NotificationReceiver
 import eu.kanade.tachiyomi.data.notification.Notifications
 import eu.kanade.tachiyomi.data.preference.PreferencesHelper
-import eu.kanade.tachiyomi.data.preference.asImmediateFlow
 import eu.kanade.tachiyomi.data.preference.toggle
 import eu.kanade.tachiyomi.databinding.ReaderActivityBinding
 import eu.kanade.tachiyomi.ui.base.activity.BaseRxActivity
@@ -63,7 +62,6 @@ import eu.kanade.tachiyomi.util.view.setTooltip
 import eu.kanade.tachiyomi.util.view.showBar
 import eu.kanade.tachiyomi.widget.SimpleAnimationListener
 import eu.kanade.tachiyomi.widget.SimpleSeekBarListener
-import kotlinx.coroutines.delay
 import kotlinx.coroutines.flow.drop
 import kotlinx.coroutines.flow.launchIn
 import kotlinx.coroutines.flow.onEach
@@ -358,12 +356,12 @@ class ReaderActivity : BaseRxActivity<ReaderActivityBinding, ReaderPresenter>()
 
             setOnClickListener {
                 popupMenu(
-                    items = ReadingModeType.values().map { it.prefValue to it.stringRes },
-                    selectedItemId = presenter.getMangaViewer(resolveDefault = false),
+                    items = ReadingModeType.values().map { it.flagValue to it.stringRes },
+                    selectedItemId = presenter.getMangaReadingMode(resolveDefault = false),
                 ) {
                     val newReadingMode = ReadingModeType.fromPreference(itemId)
 
-                    presenter.setMangaViewer(newReadingMode.prefValue)
+                    presenter.setMangaReadingMode(newReadingMode.flagValue)
 
                     menuToggleToast?.cancel()
                     if (!preferences.showReadingMode()) {
@@ -379,28 +377,28 @@ class ReaderActivity : BaseRxActivity<ReaderActivityBinding, ReaderPresenter>()
 
             setOnClickListener {
                 popupMenu(
-                    items = OrientationType.values().map { it.prefValue to it.stringRes },
-                    selectedItemId = preferences.rotation().get(),
+                    items = OrientationType.values().map { it.flagValue to it.stringRes },
+                    selectedItemId = presenter.manga?.orientationType
+                        ?: preferences.defaultOrientationType(),
                 ) {
                     val newOrientation = OrientationType.fromPreference(itemId)
 
-                    preferences.rotation().set(newOrientation.prefValue)
-                    setOrientation(newOrientation.flag)
+                    presenter.setMangaOrientationType(newOrientation.flagValue)
+
+                    updateOrientationShortcut(newOrientation.flagValue)
 
                     menuToggleToast?.cancel()
                     menuToggleToast = toast(newOrientation.stringRes)
                 }
             }
         }
-        preferences.rotation().asImmediateFlow { updateRotationShortcut(it) }
-            .launchIn(lifecycleScope)
 
         // Crop borders
         with(binding.actionCropBorders) {
             setTooltip(R.string.pref_crop_borders)
 
             setOnClickListener {
-                val isPagerType = ReadingModeType.isPagerType(presenter.getMangaViewer())
+                val isPagerType = ReadingModeType.isPagerType(presenter.getMangaReadingMode())
                 if (isPagerType) {
                     preferences.cropBorders().toggle()
                 } else {
@@ -431,13 +429,13 @@ class ReaderActivity : BaseRxActivity<ReaderActivityBinding, ReaderPresenter>()
         }
     }
 
-    private fun updateRotationShortcut(preference: Int) {
+    private fun updateOrientationShortcut(preference: Int) {
         val orientation = OrientationType.fromPreference(preference)
         binding.actionRotation.setImageResource(orientation.iconRes)
     }
 
     private fun updateCropBordersShortcut() {
-        val isPagerType = ReadingModeType.isPagerType(presenter.getMangaViewer())
+        val isPagerType = ReadingModeType.isPagerType(presenter.getMangaReadingMode())
         val enabled = if (isPagerType) {
             preferences.cropBorders().get()
         } else {
@@ -529,10 +527,10 @@ class ReaderActivity : BaseRxActivity<ReaderActivityBinding, ReaderPresenter>()
     fun setManga(manga: Manga) {
         val prevViewer = viewer
 
-        val viewerMode = ReadingModeType.fromPreference(presenter.getMangaViewer(resolveDefault = false))
+        val viewerMode = ReadingModeType.fromPreference(presenter.getMangaReadingMode(resolveDefault = false))
         binding.actionReadingMode.setImageResource(viewerMode.iconRes)
 
-        val newViewer = when (presenter.getMangaViewer()) {
+        val newViewer = when (presenter.getMangaReadingMode()) {
             ReadingModeType.LEFT_TO_RIGHT.prefValue -> L2RPagerViewer(this)
             ReadingModeType.VERTICAL.prefValue -> VerticalPagerViewer(this)
             ReadingModeType.WEBTOON.prefValue -> WebtoonViewer(this)
@@ -540,6 +538,8 @@ class ReaderActivity : BaseRxActivity<ReaderActivityBinding, ReaderPresenter>()
             else -> R2LPagerViewer(this)
         }
 
+        setOrientation(presenter.getMangaOrientationType())
+
         // Destroy previous viewer if there was one
         if (prevViewer != null) {
             prevViewer.destroy()
@@ -549,7 +549,7 @@ class ReaderActivity : BaseRxActivity<ReaderActivityBinding, ReaderPresenter>()
         binding.viewerContainer.addView(newViewer.getView())
 
         if (preferences.showReadingMode()) {
-            showReadingModeToast(presenter.getMangaViewer())
+            showReadingModeToast(presenter.getMangaReadingMode())
         }
 
         binding.toolbar.title = manga.title
@@ -777,7 +777,7 @@ class ReaderActivity : BaseRxActivity<ReaderActivityBinding, ReaderPresenter>()
     /**
      * Forces the user preferred [orientation] on the activity.
      */
-    private fun setOrientation(orientation: Int) {
+    fun setOrientation(orientation: Int) {
         val newOrientation = OrientationType.fromPreference(orientation)
         if (newOrientation.flag != requestedOrientation) {
             requestedOrientation = newOrientation.flag
@@ -793,14 +793,6 @@ class ReaderActivity : BaseRxActivity<ReaderActivityBinding, ReaderPresenter>()
          * Initializes the reader subscriptions.
          */
         init {
-            preferences.rotation().asImmediateFlow { setOrientation(it) }
-                .drop(1)
-                .onEach {
-                    delay(250)
-                    setOrientation(it)
-                }
-                .launchIn(lifecycleScope)
-
             preferences.readerTheme().asFlow()
                 .drop(1) // We only care about updates
                 .onEach { recreate() }

+ 48 - 13
app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderPresenter.kt

@@ -20,6 +20,8 @@ import eu.kanade.tachiyomi.ui.reader.loader.ChapterLoader
 import eu.kanade.tachiyomi.ui.reader.model.ReaderChapter
 import eu.kanade.tachiyomi.ui.reader.model.ReaderPage
 import eu.kanade.tachiyomi.ui.reader.model.ViewerChapters
+import eu.kanade.tachiyomi.ui.reader.setting.OrientationType
+import eu.kanade.tachiyomi.ui.reader.setting.ReadingModeType
 import eu.kanade.tachiyomi.util.isLocal
 import eu.kanade.tachiyomi.util.lang.byteSize
 import eu.kanade.tachiyomi.util.lang.launchIO
@@ -101,13 +103,13 @@ class ReaderPresenter(
                             return@filter false
                         } else if (preferences.skipFiltered()) {
                             if (
-                                (manga.readFilter == Manga.SHOW_READ && !it.read) ||
-                                (manga.readFilter == Manga.SHOW_UNREAD && it.read) ||
+                                (manga.readFilter == Manga.CHAPTER_SHOW_READ && !it.read) ||
+                                (manga.readFilter == Manga.CHAPTER_SHOW_UNREAD && it.read) ||
                                 (
-                                    manga.downloadedFilter == Manga.SHOW_DOWNLOADED &&
+                                    manga.downloadedFilter == Manga.CHAPTER_SHOW_DOWNLOADED &&
                                         !downloadManager.isChapterDownloaded(it, manga)
                                     ) ||
-                                (manga.bookmarkedFilter == Manga.SHOW_BOOKMARKED && !it.bookmark)
+                                (manga.bookmarkedFilter == Manga.CHAPTER_SHOW_BOOKMARKED && !it.bookmark)
                             ) {
                                 return@filter false
                             }
@@ -127,9 +129,9 @@ class ReaderPresenter(
             }
 
         when (manga.sorting) {
-            Manga.SORTING_SOURCE -> ChapterLoadBySource().get(chaptersForReader)
-            Manga.SORTING_NUMBER -> ChapterLoadByNumber().get(chaptersForReader, selectedChapter)
-            Manga.SORTING_UPLOAD_DATE -> ChapterLoadByUploadDate().get(chaptersForReader)
+            Manga.CHAPTER_SORTING_SOURCE -> ChapterLoadBySource().get(chaptersForReader)
+            Manga.CHAPTER_SORTING_NUMBER -> ChapterLoadByNumber().get(chaptersForReader, selectedChapter)
+            Manga.CHAPTER_SORTING_UPLOAD_DATE -> ChapterLoadByUploadDate().get(chaptersForReader)
             else -> error("Unknown sorting method")
         }.map(::ReaderChapter)
     }
@@ -489,18 +491,21 @@ class ReaderPresenter(
     /**
      * Returns the viewer position used by this manga or the default one.
      */
-    fun getMangaViewer(resolveDefault: Boolean = true): Int {
-        val manga = manga ?: return preferences.defaultViewer()
-        return if (resolveDefault && manga.viewer == 0) preferences.defaultViewer() else manga.viewer
+    fun getMangaReadingMode(resolveDefault: Boolean = true): Int {
+        val default = preferences.defaultReadingMode()
+        return when {
+            resolveDefault && manga?.readingModeType == ReadingModeType.DEFAULT.flagValue -> default
+            else -> manga?.readingModeType ?: default
+        }
     }
 
     /**
      * Updates the viewer position for the open manga.
      */
-    fun setMangaViewer(viewer: Int) {
+    fun setMangaReadingMode(readingModeType: Int) {
         val manga = manga ?: return
-        manga.viewer = viewer
-        db.updateMangaViewer(manga).executeAsBlocking()
+        manga.readingModeType = readingModeType
+        db.updateViewerFlags(manga).executeAsBlocking()
 
         Observable.timer(250, TimeUnit.MILLISECONDS, AndroidSchedulers.mainThread())
             .subscribeFirst({ view, _ ->
@@ -517,6 +522,36 @@ class ReaderPresenter(
             })
     }
 
+    /**
+     * Returns the orientation type used by this manga or the default one.
+     */
+    fun getMangaOrientationType(): Int {
+        val default = preferences.defaultOrientationType()
+        return when (manga?.orientationType) {
+            OrientationType.DEFAULT.flagValue -> default
+            else -> manga?.orientationType ?: default
+        }
+    }
+
+    /**
+     * Updates the orientation type for the open manga.
+     */
+    fun setMangaOrientationType(rotationType: Int) {
+        val manga = manga ?: return
+        manga.orientationType = rotationType
+        db.updateViewerFlags(manga).executeAsBlocking()
+
+        Timber.i("Manga orientation is ${manga.orientationType}")
+
+        Observable.timer(250, TimeUnit.MILLISECONDS, AndroidSchedulers.mainThread())
+            .subscribeFirst({ view, _ ->
+                val currChapters = viewerChaptersRelay.value
+                if (currChapters != null) {
+                    view.setOrientation(getMangaOrientationType())
+                }
+            })
+    }
+
     /**
      * Saves the image of this [page] in the given [directory] and returns the file location.
      */

+ 13 - 9
app/src/main/java/eu/kanade/tachiyomi/ui/reader/setting/OrientationType.kt

@@ -5,16 +5,20 @@ import androidx.annotation.DrawableRes
 import androidx.annotation.StringRes
 import eu.kanade.tachiyomi.R
 
-enum class OrientationType(val prefValue: Int, val flag: Int, @StringRes val stringRes: Int, @DrawableRes val iconRes: Int) {
-    FREE(1, ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED, R.string.rotation_free, R.drawable.ic_screen_rotation_24dp),
-    PORTRAIT(2, ActivityInfo.SCREEN_ORIENTATION_SENSOR_PORTRAIT, R.string.rotation_portrait, R.drawable.ic_stay_current_portrait_24dp),
-    LANDSCAPE(3, ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE, R.string.rotation_landscape, R.drawable.ic_stay_current_landscape_24dp),
-    LOCKED_PORTRAIT(4, ActivityInfo.SCREEN_ORIENTATION_PORTRAIT, R.string.rotation_force_portrait, R.drawable.ic_screen_lock_portrait_24dp),
-    LOCKED_LANDSCAPE(5, ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE, R.string.rotation_force_landscape, R.drawable.ic_screen_lock_landscape_24dp),
-    ;
+enum class OrientationType(val prefValue: Int, val flag: Int, @StringRes val stringRes: Int, @DrawableRes val iconRes: Int, val flagValue: Int) {
+    // TODO Default icon
+    DEFAULT(0, ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED, R.string.default_rotation_type, R.drawable.ic_screen_rotation_24dp, 0x00000000),
+    FREE(1, ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED, R.string.rotation_free, R.drawable.ic_screen_rotation_24dp, 0x00000008),
+    PORTRAIT(2, ActivityInfo.SCREEN_ORIENTATION_SENSOR_PORTRAIT, R.string.rotation_portrait, R.drawable.ic_stay_current_portrait_24dp, 0x00000010),
+    LANDSCAPE(3, ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE, R.string.rotation_landscape, R.drawable.ic_stay_current_landscape_24dp, 0x00000018),
+    LOCKED_PORTRAIT(4, ActivityInfo.SCREEN_ORIENTATION_PORTRAIT, R.string.rotation_force_portrait, R.drawable.ic_screen_lock_portrait_24dp, 0x00000020),
+    LOCKED_LANDSCAPE(5, ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE, R.string.rotation_force_landscape, R.drawable.ic_screen_lock_landscape_24dp, 0x00000028);
 
     companion object {
-        fun fromPreference(preference: Int): OrientationType =
-            values().find { it.prefValue == preference } ?: FREE
+        const val MASK = 0x00000038
+
+        fun fromPreference(preference: Int?): OrientationType = values().find { it.flagValue == preference } ?: FREE
+
+        fun fromSpinner(position: Int?) = values().find { value -> value.prefValue == position } ?: DEFAULT
     }
 }

+ 0 - 1
app/src/main/java/eu/kanade/tachiyomi/ui/reader/setting/ReaderGeneralSettings.kt

@@ -32,7 +32,6 @@ class ReaderGeneralSettings @JvmOverloads constructor(context: Context, attrs: A
      * Init general reader preferences.
      */
     private fun initGeneralPreferences() {
-        binding.rotationMode.bindToPreference(preferences.rotation(), 1)
         binding.backgroundColor.bindToIntPreference(preferences.readerTheme(), R.array.reader_themes_values)
         binding.showPageNumber.bindToPreference(preferences.showPageNumber())
         binding.fullscreen.bindToPreference(preferences.fullscreen())

+ 11 - 4
app/src/main/java/eu/kanade/tachiyomi/ui/reader/setting/ReaderReadingModeSettings.kt

@@ -43,16 +43,23 @@ class ReaderReadingModeSettings @JvmOverloads constructor(context: Context, attr
      */
     private fun initGeneralPreferences() {
         binding.viewer.onItemSelectedListener = { position ->
-            (context as ReaderActivity).presenter.setMangaViewer(position)
+            val readingModeType = ReadingModeType.fromSpinner(position)
+            (context as ReaderActivity).presenter.setMangaReadingMode(readingModeType.flagValue)
 
-            val mangaViewer = (context as ReaderActivity).presenter.getMangaViewer()
-            if (mangaViewer == ReadingModeType.WEBTOON.prefValue || mangaViewer == ReadingModeType.CONTINUOUS_VERTICAL.prefValue) {
+            val mangaViewer = (context as ReaderActivity).presenter.getMangaReadingMode()
+            if (mangaViewer == ReadingModeType.WEBTOON.flagValue || mangaViewer == ReadingModeType.CONTINUOUS_VERTICAL.flagValue) {
                 initWebtoonPreferences()
             } else {
                 initPagerPreferences()
             }
         }
-        binding.viewer.setSelection((context as ReaderActivity).presenter.manga?.viewer ?: 0)
+        binding.viewer.setSelection((context as ReaderActivity).presenter.manga?.readingModeType.let { ReadingModeType.fromPreference(it).prefValue })
+
+        binding.rotationMode.onItemSelectedListener = { position ->
+            val rotationType = OrientationType.fromSpinner(position)
+            (context as ReaderActivity).presenter.setMangaOrientationType(rotationType.flagValue)
+        }
+        binding.rotationMode.setSelection((context as ReaderActivity).presenter.manga?.orientationType.let { OrientationType.fromPreference(it).prefValue })
     }
 
     /**

+ 12 - 8
app/src/main/java/eu/kanade/tachiyomi/ui/reader/setting/ReadingModeType.kt

@@ -4,21 +4,25 @@ import androidx.annotation.DrawableRes
 import androidx.annotation.StringRes
 import eu.kanade.tachiyomi.R
 
-enum class ReadingModeType(val prefValue: Int, @StringRes val stringRes: Int, @DrawableRes val iconRes: Int) {
-    DEFAULT(0, R.string.default_viewer, R.drawable.ic_reader_default_24dp),
-    LEFT_TO_RIGHT(1, R.string.left_to_right_viewer, R.drawable.ic_reader_ltr_24dp),
-    RIGHT_TO_LEFT(2, R.string.right_to_left_viewer, R.drawable.ic_reader_rtl_24dp),
-    VERTICAL(3, R.string.vertical_viewer, R.drawable.ic_reader_vertical_24dp),
-    WEBTOON(4, R.string.webtoon_viewer, R.drawable.ic_reader_webtoon_24dp),
-    CONTINUOUS_VERTICAL(5, R.string.vertical_plus_viewer, R.drawable.ic_reader_continuous_vertical_24dp),
+enum class ReadingModeType(val prefValue: Int, @StringRes val stringRes: Int, @DrawableRes val iconRes: Int, val flagValue: Int) {
+    DEFAULT(0, R.string.default_viewer, R.drawable.ic_reader_default_24dp, 0x00000000),
+    LEFT_TO_RIGHT(1, R.string.left_to_right_viewer, R.drawable.ic_reader_ltr_24dp, 0x00000001),
+    RIGHT_TO_LEFT(2, R.string.right_to_left_viewer, R.drawable.ic_reader_rtl_24dp, 0x00000002),
+    VERTICAL(3, R.string.vertical_viewer, R.drawable.ic_reader_vertical_24dp, 0x00000003),
+    WEBTOON(4, R.string.webtoon_viewer, R.drawable.ic_reader_webtoon_24dp, 0x00000004),
+    CONTINUOUS_VERTICAL(5, R.string.vertical_plus_viewer, R.drawable.ic_reader_continuous_vertical_24dp, 0x00000005),
     ;
 
     companion object {
-        fun fromPreference(preference: Int): ReadingModeType = values().find { it.prefValue == preference } ?: DEFAULT
+        const val MASK = 0x00000007
+
+        fun fromPreference(preference: Int?): ReadingModeType = values().find { it.flagValue == preference } ?: DEFAULT
 
         fun isPagerType(preference: Int): Boolean {
             val mode = fromPreference(preference)
             return mode == LEFT_TO_RIGHT || mode == RIGHT_TO_LEFT || mode == VERTICAL
         }
+
+        fun fromSpinner(position: Int?) = values().find { value -> value.prefValue == position } ?: DEFAULT
     }
 }

+ 6 - 6
app/src/main/java/eu/kanade/tachiyomi/ui/recent/history/HistoryPresenter.kt

@@ -122,9 +122,9 @@ class HistoryPresenter : BasePresenter<HistoryController>() {
         }
 
         val sortFunction: (Chapter, Chapter) -> Int = when (manga.sorting) {
-            Manga.SORTING_SOURCE -> { c1, c2 -> c2.source_order.compareTo(c1.source_order) }
-            Manga.SORTING_NUMBER -> { c1, c2 -> c1.chapter_number.compareTo(c2.chapter_number) }
-            Manga.SORTING_UPLOAD_DATE -> { c1, c2 -> c1.date_upload.compareTo(c2.date_upload) }
+            Manga.CHAPTER_SORTING_SOURCE -> { c1, c2 -> c2.source_order.compareTo(c1.source_order) }
+            Manga.CHAPTER_SORTING_NUMBER -> { c1, c2 -> c1.chapter_number.compareTo(c2.chapter_number) }
+            Manga.CHAPTER_SORTING_UPLOAD_DATE -> { c1, c2 -> c1.date_upload.compareTo(c2.date_upload) }
             else -> throw NotImplementedError("Unknown sorting method")
         }
 
@@ -133,8 +133,8 @@ class HistoryPresenter : BasePresenter<HistoryController>() {
 
         val currChapterIndex = chapters.indexOfFirst { chapter.id == it.id }
         return when (manga.sorting) {
-            Manga.SORTING_SOURCE -> chapters.getOrNull(currChapterIndex + 1)
-            Manga.SORTING_NUMBER -> {
+            Manga.CHAPTER_SORTING_SOURCE -> chapters.getOrNull(currChapterIndex + 1)
+            Manga.CHAPTER_SORTING_NUMBER -> {
                 val chapterNumber = chapter.chapter_number
 
                 ((currChapterIndex + 1) until chapters.size)
@@ -144,7 +144,7 @@ class HistoryPresenter : BasePresenter<HistoryController>() {
                             it.chapter_number <= chapterNumber + 1
                     }
             }
-            Manga.SORTING_UPLOAD_DATE -> {
+            Manga.CHAPTER_SORTING_UPLOAD_DATE -> {
                 chapters.drop(currChapterIndex + 1)
                     .firstOrNull { it.date_upload >= chapter.date_upload }
             }

+ 10 - 6
app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsReaderController.kt

@@ -5,6 +5,8 @@ import androidx.preference.PreferenceScreen
 import eu.kanade.tachiyomi.R
 import eu.kanade.tachiyomi.data.preference.PreferenceValues.TappingInvertMode
 import eu.kanade.tachiyomi.data.preference.asImmediateFlow
+import eu.kanade.tachiyomi.ui.reader.setting.OrientationType
+import eu.kanade.tachiyomi.ui.reader.setting.ReadingModeType
 import eu.kanade.tachiyomi.util.preference.defaultValue
 import eu.kanade.tachiyomi.util.preference.entriesRes
 import eu.kanade.tachiyomi.util.preference.intListPreference
@@ -23,7 +25,7 @@ class SettingsReaderController : SettingsController() {
         titleRes = R.string.pref_category_reader
 
         intListPreference {
-            key = Keys.defaultViewer
+            key = Keys.defaultReadingMode
             titleRes = R.string.pref_viewer_type
             entriesRes = arrayOf(
                 R.string.left_to_right_viewer,
@@ -32,8 +34,9 @@ class SettingsReaderController : SettingsController() {
                 R.string.webtoon_viewer,
                 R.string.vertical_plus_viewer
             )
-            entryValues = arrayOf("1", "2", "3", "4", "5")
-            defaultValue = "2"
+            entryValues = ReadingModeType.values().drop(1)
+                    .map { value -> "${value.flagValue}" }.toTypedArray()
+            defaultValue = "${ReadingModeType.RIGHT_TO_LEFT.flagValue}"
             summary = "%s"
         }
         intListPreference {
@@ -74,7 +77,7 @@ class SettingsReaderController : SettingsController() {
             titleRes = R.string.pref_category_display
 
             intListPreference {
-                key = Keys.rotation
+                key = Keys.defaultOrientationType
                 titleRes = R.string.pref_rotation_type
                 entriesRes = arrayOf(
                     R.string.rotation_free,
@@ -83,8 +86,9 @@ class SettingsReaderController : SettingsController() {
                     R.string.rotation_force_portrait,
                     R.string.rotation_force_landscape,
                 )
-                entryValues = arrayOf("1", "2", "3", "4", "5")
-                defaultValue = "1"
+                entryValues = OrientationType.values().drop(1)
+                    .map { value -> "${value.flagValue}" }.toTypedArray()
+                defaultValue = "${OrientationType.FREE.flagValue}"
                 summary = "%s"
             }
             intListPreference {

+ 6 - 3
app/src/main/java/eu/kanade/tachiyomi/util/chapter/ChapterSettingsHelper.kt

@@ -17,7 +17,8 @@ object ChapterSettingsHelper {
     fun setGlobalSettings(manga: Manga?) {
         manga?.let {
             prefs.setChapterSettingsDefault(it)
-            db.updateFlags(it).executeAsBlocking()
+            db.updateChapterFlags(it).executeAsBlocking()
+            db.updateViewerFlags(it).executeAsBlocking()
         }
     }
 
@@ -34,7 +35,8 @@ object ChapterSettingsHelper {
             setChapterOrder(prefs.sortChapterByAscendingOrDescending())
         }
 
-        db.updateFlags(manga).executeAsBlocking()
+        db.updateChapterFlags(manga).executeAsBlocking()
+        db.updateViewerFlags(manga).executeAsBlocking()
     }
 
     /**
@@ -54,7 +56,8 @@ object ChapterSettingsHelper {
                 manga
             }
 
-            db.updateFlags(updatedMangas).executeAsBlocking()
+            db.updateChapterFlags(updatedMangas).executeAsBlocking()
+            db.updateViewerFlags(updatedMangas).executeAsBlocking()
         }
     }
 }

+ 0 - 7
app/src/main/res/layout/reader_general_settings.xml

@@ -10,13 +10,6 @@
         android:layout_height="wrap_content"
         android:orientation="vertical">
 
-        <eu.kanade.tachiyomi.widget.MaterialSpinnerView
-            android:id="@+id/rotation_mode"
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            android:entries="@array/rotation_type"
-            app:title="@string/pref_rotation_type" />
-
         <eu.kanade.tachiyomi.widget.MaterialSpinnerView
             android:id="@+id/background_color"
             android:layout_width="match_parent"

+ 19 - 2
app/src/main/res/layout/reader_reading_mode_settings.xml

@@ -10,13 +10,30 @@
         android:layout_height="wrap_content"
         android:orientation="vertical">
 
+        <TextView
+            android:id="@+id/for_this_series_prefs"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:text="@string/pref_category_for_this_series"
+            android:paddingStart="16dp"
+            android:paddingEnd="16dp"
+            android:layout_marginTop="16dp"
+            android:textAppearance="@style/TextAppearance.Medium.SubHeading" />
+
         <eu.kanade.tachiyomi.widget.MaterialSpinnerView
             android:id="@+id/viewer"
             android:layout_width="match_parent"
             android:layout_height="wrap_content"
-            android:layout_marginBottom="24dp"
             android:entries="@array/viewers_selector"
-            app:title="@string/pref_category_for_this_series" />
+            app:title="@string/pref_category_reading_mode" />
+
+        <eu.kanade.tachiyomi.widget.MaterialSpinnerView
+            android:id="@+id/rotation_mode"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_marginBottom="24dp"
+            android:entries="@array/rotation_type"
+            app:title="@string/rotation_type" />
 
         <!-- Pager preferences -->
         <include

+ 1 - 8
app/src/main/res/values/arrays.xml

@@ -61,6 +61,7 @@
     </string-array>
 
     <string-array name="rotation_type">
+        <item>@string/default_rotation_type</item>
         <item>@string/rotation_free</item>
         <item>@string/rotation_portrait</item>
         <item>@string/rotation_landscape</item>
@@ -68,14 +69,6 @@
         <item>@string/rotation_force_landscape</item>
     </string-array>
 
-    <string-array name="rotation_type_values">
-        <item>1</item>
-        <item>2</item>
-        <item>3</item>
-        <item>4</item>
-        <item>5</item>
-    </string-array>
-
     <string-array name="color_filter_modes">
         <item>@string/filter_mode_default</item>
         <item>@string/filter_mode_multiply</item>

+ 3 - 1
app/src/main/res/values/strings.xml

@@ -333,7 +333,9 @@
     <string name="double_tap_anim_speed_0">No animation</string>
     <string name="double_tap_anim_speed_normal">Normal</string>
     <string name="double_tap_anim_speed_fast">Fast</string>
-    <string name="pref_rotation_type">Rotation</string>
+    <string name="pref_rotation_type">Default rotation type</string>
+    <string name="default_rotation_type">Default</string>
+    <string name="rotation_type">Rotation type</string>
     <string name="rotation_free">Free</string>
     <string name="rotation_portrait">Portrait</string>
     <string name="rotation_landscape">Landscape</string>

+ 12 - 5
app/src/test/java/eu/kanade/tachiyomi/data/backup/BackupTest.kt

@@ -20,6 +20,8 @@ import eu.kanade.tachiyomi.data.database.models.MangaImpl
 import eu.kanade.tachiyomi.data.database.models.TrackImpl
 import eu.kanade.tachiyomi.source.SourceManager
 import eu.kanade.tachiyomi.source.online.HttpSource
+import eu.kanade.tachiyomi.ui.reader.setting.OrientationType
+import eu.kanade.tachiyomi.ui.reader.setting.ReadingModeType
 import kotlinx.coroutines.runBlocking
 import org.assertj.core.api.Assertions.assertThat
 import org.junit.Before
@@ -156,12 +158,14 @@ class BackupTest {
     fun testRestoreManga() {
         // Add manga to database
         val manga = getSingleManga("One Piece")
-        manga.viewer = 3
+        manga.readingModeType = ReadingModeType.VERTICAL.flagValue
+        manga.orientationType = OrientationType.PORTRAIT.flagValue
         manga.id = db.insertManga(manga).executeAsBlocking().insertedId()
 
         var favoriteManga = legacyBackupManager.databaseHelper.getFavoriteMangas().executeAsBlocking()
         assertThat(favoriteManga).hasSize(1)
-        assertThat(favoriteManga[0].viewer).isEqualTo(3)
+        assertThat(favoriteManga[0].readingModeType).isEqualTo(ReadingModeType.VERTICAL.flagValue)
+        assertThat(favoriteManga[0].orientationType).isEqualTo(OrientationType.PORTRAIT.flagValue)
 
         // Update json with all options enabled
         mangaEntries.add(legacyBackupManager.backupMangaObject(manga, 1))
@@ -173,7 +177,8 @@ class BackupTest {
 
         favoriteManga = legacyBackupManager.databaseHelper.getFavoriteMangas().executeAsBlocking()
         assertThat(favoriteManga).hasSize(1)
-        assertThat(favoriteManga[0].viewer).isEqualTo(0)
+        assertThat(favoriteManga[0].readingModeType).isEqualTo(ReadingModeType.DEFAULT.flagValue)
+        assertThat(favoriteManga[0].orientationType).isEqualTo(OrientationType.DEFAULT.flagValue)
 
         // Restore local manga
         legacyBackupManager.restoreMangaNoFetch(manga, dbManga)
@@ -181,7 +186,8 @@ class BackupTest {
         // Test if restore successful
         favoriteManga = legacyBackupManager.databaseHelper.getFavoriteMangas().executeAsBlocking()
         assertThat(favoriteManga).hasSize(1)
-        assertThat(favoriteManga[0].viewer).isEqualTo(3)
+        assertThat(favoriteManga[0].readingModeType).isEqualTo(ReadingModeType.VERTICAL.flagValue)
+        assertThat(favoriteManga[0].orientationType).isEqualTo(OrientationType.PORTRAIT.flagValue)
 
         // Clear database to test manga fetch
         clearDatabase()
@@ -207,7 +213,8 @@ class BackupTest {
             // Check if restore successful
             val dbCats = legacyBackupManager.databaseHelper.getFavoriteMangas().executeAsBlocking()
             assertThat(dbCats).hasSize(1)
-            assertThat(dbCats[0].viewer).isEqualTo(3)
+            assertThat(dbCats[0].readingModeType).isEqualTo(ReadingModeType.VERTICAL.flagValue)
+            assertThat(dbCats[0].orientationType).isEqualTo(OrientationType.PORTRAIT.flagValue)
             assertThat(dbCats[0].description).isEqualTo("This is a description")
         }
     }