From 880407442c598d1b63db8be43f4848550dc17ff1 Mon Sep 17 00:00:00 2001 From: Andreas Date: Mon, 29 Aug 2022 19:10:30 +0200 Subject: [PATCH] Tweak flag classes for Library (#7829) * Tweak flag classes for Library - Add interface for Flag and Mask - Merge Sort Type and Direction into one class - Use custom serializers for preferences - Mainly to not break the old * Review changes --- app/build.gradle.kts | 2 +- .../data/category/CategoryRepositoryImpl.kt | 4 + .../interactor/CreateCategoryWithName.kt | 5 +- .../category/interactor/ResetCategoryFlags.kt | 12 +- .../interactor/SetDisplayModeForCategory.kt | 14 +- .../interactor/SetSortModeForCategory.kt | 17 ++- .../kanade/domain/category/model/Category.kt | 12 -- .../category/repository/CategoryRepository.kt | 2 + .../library/components/LibraryContent.kt | 4 +- .../library/components/LibraryPager.kt | 14 +- .../java/eu/kanade/tachiyomi/Migrations.kt | 56 ++++---- .../data/preference/PreferenceKeys.kt | 1 - .../data/preference/PreferencesHelper.kt | 12 +- .../source/browse/BrowseSourceController.kt | 16 +-- .../ui/browse/source/browse/SourceItem.kt | 16 +-- .../tachiyomi/ui/library/LibraryPresenter.kt | 57 ++++---- .../ui/library/LibrarySettingsSheet.kt | 77 +++++------ .../ui/library/setting/DisplayModeSetting.kt | 17 --- .../tachiyomi/ui/library/setting/Flag.kt | 35 +++++ .../ui/library/setting/LibraryDisplayMode.kt | 60 +++++++++ .../ui/library/setting/LibrarySort.kt | 122 ++++++++++++++++++ .../library/setting/SortDirectionSetting.kt | 20 --- .../ui/library/setting/SortModeSetting.kt | 42 ------ app/src/main/sqldelight/data/categories.sq | 6 + .../util/chapter/LibraryFlagsTest.kt | 69 ++++++++++ 25 files changed, 442 insertions(+), 250 deletions(-) delete mode 100644 app/src/main/java/eu/kanade/tachiyomi/ui/library/setting/DisplayModeSetting.kt create mode 100644 app/src/main/java/eu/kanade/tachiyomi/ui/library/setting/Flag.kt create mode 100644 app/src/main/java/eu/kanade/tachiyomi/ui/library/setting/LibraryDisplayMode.kt create mode 100644 app/src/main/java/eu/kanade/tachiyomi/ui/library/setting/LibrarySort.kt delete mode 100644 app/src/main/java/eu/kanade/tachiyomi/ui/library/setting/SortDirectionSetting.kt delete mode 100644 app/src/main/java/eu/kanade/tachiyomi/ui/library/setting/SortModeSetting.kt create mode 100644 app/src/test/java/eu/kanade/tachiyomi/util/chapter/LibraryFlagsTest.kt diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 595b7d1d95..5da0567618 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -27,7 +27,7 @@ android { applicationId = "eu.kanade.tachiyomi" minSdk = AndroidConfig.minSdk targetSdk = AndroidConfig.targetSdk - versionCode = 82 + versionCode = 83 versionName = "0.13.6" buildConfigField("String", "COMMIT_COUNT", "\"${getCommitCount()}\"") diff --git a/app/src/main/java/eu/kanade/data/category/CategoryRepositoryImpl.kt b/app/src/main/java/eu/kanade/data/category/CategoryRepositoryImpl.kt index e64bb0c6eb..49be1bae74 100644 --- a/app/src/main/java/eu/kanade/data/category/CategoryRepositoryImpl.kt +++ b/app/src/main/java/eu/kanade/data/category/CategoryRepositoryImpl.kt @@ -11,6 +11,10 @@ class CategoryRepositoryImpl( private val handler: DatabaseHandler, ) : CategoryRepository { + override suspend fun get(id: Long): Category? { + return handler.awaitOneOrNull { categoriesQueries.getCategory(id, categoryMapper) } + } + override suspend fun getAll(): List { return handler.awaitList { categoriesQueries.getCategories(categoryMapper) } } diff --git a/app/src/main/java/eu/kanade/domain/category/interactor/CreateCategoryWithName.kt b/app/src/main/java/eu/kanade/domain/category/interactor/CreateCategoryWithName.kt index efd615a7d4..50bb8036a5 100644 --- a/app/src/main/java/eu/kanade/domain/category/interactor/CreateCategoryWithName.kt +++ b/app/src/main/java/eu/kanade/domain/category/interactor/CreateCategoryWithName.kt @@ -16,9 +16,10 @@ class CreateCategoryWithName( private val initialFlags: Long get() { + val sort = preferences.librarySortingMode().get() return preferences.libraryDisplayMode().get().flag or - preferences.librarySortingMode().get().flag or - preferences.librarySortingAscending().get().flag + sort.type.flag or + sort.direction.flag } suspend fun await(name: String): Result = withContext(NonCancellable) { diff --git a/app/src/main/java/eu/kanade/domain/category/interactor/ResetCategoryFlags.kt b/app/src/main/java/eu/kanade/domain/category/interactor/ResetCategoryFlags.kt index 21504eddd7..7e92e557dc 100644 --- a/app/src/main/java/eu/kanade/domain/category/interactor/ResetCategoryFlags.kt +++ b/app/src/main/java/eu/kanade/domain/category/interactor/ResetCategoryFlags.kt @@ -2,9 +2,7 @@ package eu.kanade.domain.category.interactor import eu.kanade.domain.category.repository.CategoryRepository import eu.kanade.tachiyomi.data.preference.PreferencesHelper -import eu.kanade.tachiyomi.ui.library.setting.DisplayModeSetting -import eu.kanade.tachiyomi.ui.library.setting.SortDirectionSetting -import eu.kanade.tachiyomi.ui.library.setting.SortModeSetting +import eu.kanade.tachiyomi.ui.library.setting.plus class ResetCategoryFlags( private val preferences: PreferencesHelper, @@ -14,12 +12,6 @@ class ResetCategoryFlags( suspend fun await() { val display = preferences.libraryDisplayMode().get() val sort = preferences.librarySortingMode().get() - val sortDirection = preferences.librarySortingAscending().get() - - var flags = 0L - flags = flags and DisplayModeSetting.MASK.inv() or (display.flag and DisplayModeSetting.MASK) - flags = flags and SortModeSetting.MASK.inv() or (sort.flag and SortModeSetting.MASK) - flags = flags and SortDirectionSetting.MASK.inv() or (sortDirection.flag and SortDirectionSetting.MASK) - categoryRepository.updateAllFlags(flags) + categoryRepository.updateAllFlags(display + sort.type + sort.direction) } } diff --git a/app/src/main/java/eu/kanade/domain/category/interactor/SetDisplayModeForCategory.kt b/app/src/main/java/eu/kanade/domain/category/interactor/SetDisplayModeForCategory.kt index d1174db34d..6a476e316e 100644 --- a/app/src/main/java/eu/kanade/domain/category/interactor/SetDisplayModeForCategory.kt +++ b/app/src/main/java/eu/kanade/domain/category/interactor/SetDisplayModeForCategory.kt @@ -4,15 +4,17 @@ import eu.kanade.domain.category.model.Category import eu.kanade.domain.category.model.CategoryUpdate import eu.kanade.domain.category.repository.CategoryRepository import eu.kanade.tachiyomi.data.preference.PreferencesHelper -import eu.kanade.tachiyomi.ui.library.setting.DisplayModeSetting +import eu.kanade.tachiyomi.ui.library.setting.LibraryDisplayMode +import eu.kanade.tachiyomi.ui.library.setting.plus class SetDisplayModeForCategory( private val preferences: PreferencesHelper, private val categoryRepository: CategoryRepository, ) { - suspend fun await(category: Category, displayModeSetting: DisplayModeSetting) { - val flags = category.flags and DisplayModeSetting.MASK.inv() or (displayModeSetting.flag and DisplayModeSetting.MASK) + suspend fun await(categoryId: Long, display: LibraryDisplayMode) { + val category = categoryRepository.get(categoryId) ?: return + val flags = category.flags + display if (preferences.categorizedDisplaySettings().get()) { categoryRepository.updatePartial( CategoryUpdate( @@ -21,8 +23,12 @@ class SetDisplayModeForCategory( ), ) } else { - preferences.libraryDisplayMode().set(displayModeSetting) + preferences.libraryDisplayMode().set(display) categoryRepository.updateAllFlags(flags) } } + + suspend fun await(category: Category, display: LibraryDisplayMode) { + await(category.id, display) + } } diff --git a/app/src/main/java/eu/kanade/domain/category/interactor/SetSortModeForCategory.kt b/app/src/main/java/eu/kanade/domain/category/interactor/SetSortModeForCategory.kt index a122f21573..6966f6fab6 100644 --- a/app/src/main/java/eu/kanade/domain/category/interactor/SetSortModeForCategory.kt +++ b/app/src/main/java/eu/kanade/domain/category/interactor/SetSortModeForCategory.kt @@ -4,17 +4,17 @@ import eu.kanade.domain.category.model.Category import eu.kanade.domain.category.model.CategoryUpdate import eu.kanade.domain.category.repository.CategoryRepository import eu.kanade.tachiyomi.data.preference.PreferencesHelper -import eu.kanade.tachiyomi.ui.library.setting.SortDirectionSetting -import eu.kanade.tachiyomi.ui.library.setting.SortModeSetting +import eu.kanade.tachiyomi.ui.library.setting.LibrarySort +import eu.kanade.tachiyomi.ui.library.setting.plus class SetSortModeForCategory( private val preferences: PreferencesHelper, private val categoryRepository: CategoryRepository, ) { - suspend fun await(category: Category, sortModeSetting: SortModeSetting, sortDirectionSetting: SortDirectionSetting) { - var flags = category.flags and SortModeSetting.MASK.inv() or (sortModeSetting.flag and SortModeSetting.MASK) - flags = flags and SortDirectionSetting.MASK.inv() or (sortDirectionSetting.flag and SortDirectionSetting.MASK) + suspend fun await(categoryId: Long, type: LibrarySort.Type, direction: LibrarySort.Direction) { + val category = categoryRepository.get(categoryId) ?: return + val flags = category.flags + type + direction if (preferences.categorizedDisplaySettings().get()) { categoryRepository.updatePartial( CategoryUpdate( @@ -23,9 +23,12 @@ class SetSortModeForCategory( ), ) } else { - preferences.librarySortingMode().set(sortModeSetting) - preferences.librarySortingAscending().set(sortDirectionSetting) + preferences.librarySortingMode().set(LibrarySort(type, direction)) categoryRepository.updateAllFlags(flags) } } + + suspend fun await(category: Category, type: LibrarySort.Type, direction: LibrarySort.Direction) { + await(category.id, type, direction) + } } diff --git a/app/src/main/java/eu/kanade/domain/category/model/Category.kt b/app/src/main/java/eu/kanade/domain/category/model/Category.kt index 1b8b1d14ba..870cab2b6f 100644 --- a/app/src/main/java/eu/kanade/domain/category/model/Category.kt +++ b/app/src/main/java/eu/kanade/domain/category/model/Category.kt @@ -1,8 +1,5 @@ package eu.kanade.domain.category.model -import eu.kanade.tachiyomi.ui.library.setting.DisplayModeSetting -import eu.kanade.tachiyomi.ui.library.setting.SortDirectionSetting -import eu.kanade.tachiyomi.ui.library.setting.SortModeSetting import java.io.Serializable data class Category( @@ -14,15 +11,6 @@ data class Category( val isSystemCategory: Boolean = id == UNCATEGORIZED_ID - val displayMode: Long - get() = flags and DisplayModeSetting.MASK - - val sortMode: Long - get() = flags and SortModeSetting.MASK - - val sortDirection: Long - get() = flags and SortDirectionSetting.MASK - companion object { const val UNCATEGORIZED_ID = 0L diff --git a/app/src/main/java/eu/kanade/domain/category/repository/CategoryRepository.kt b/app/src/main/java/eu/kanade/domain/category/repository/CategoryRepository.kt index 76bb5cfab1..bda15edf73 100644 --- a/app/src/main/java/eu/kanade/domain/category/repository/CategoryRepository.kt +++ b/app/src/main/java/eu/kanade/domain/category/repository/CategoryRepository.kt @@ -6,6 +6,8 @@ import kotlinx.coroutines.flow.Flow interface CategoryRepository { + suspend fun get(id: Long): Category? + suspend fun getAll(): List fun getAllAsFlow(): Flow> diff --git a/app/src/main/java/eu/kanade/presentation/library/components/LibraryContent.kt b/app/src/main/java/eu/kanade/presentation/library/components/LibraryContent.kt index 8346843928..3e73aa8f84 100644 --- a/app/src/main/java/eu/kanade/presentation/library/components/LibraryContent.kt +++ b/app/src/main/java/eu/kanade/presentation/library/components/LibraryContent.kt @@ -24,7 +24,7 @@ import eu.kanade.presentation.library.LibraryState import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.data.database.models.LibraryManga import eu.kanade.tachiyomi.ui.library.LibraryItem -import eu.kanade.tachiyomi.ui.library.setting.DisplayModeSetting +import eu.kanade.tachiyomi.ui.library.setting.LibraryDisplayMode import eu.kanade.tachiyomi.widget.EmptyView import kotlinx.coroutines.delay import kotlinx.coroutines.launch @@ -45,7 +45,7 @@ fun LibraryContent( onRefresh: (Category?) -> Boolean, onGlobalSearchClicked: () -> Unit, getNumberOfMangaForCategory: @Composable (Long) -> State, - getDisplayModeForPage: @Composable (Int) -> State, + getDisplayModeForPage: @Composable (Int) -> State, getColumnsForOrientation: (Boolean) -> PreferenceMutableState, getLibraryForPage: @Composable (Int) -> State>, ) { diff --git a/app/src/main/java/eu/kanade/presentation/library/components/LibraryPager.kt b/app/src/main/java/eu/kanade/presentation/library/components/LibraryPager.kt index 432a6f47f7..648bcf72a6 100644 --- a/app/src/main/java/eu/kanade/presentation/library/components/LibraryPager.kt +++ b/app/src/main/java/eu/kanade/presentation/library/components/LibraryPager.kt @@ -15,7 +15,7 @@ import com.google.accompanist.pager.PagerState import eu.kanade.core.prefs.PreferenceMutableState import eu.kanade.tachiyomi.data.database.models.LibraryManga import eu.kanade.tachiyomi.ui.library.LibraryItem -import eu.kanade.tachiyomi.ui.library.setting.DisplayModeSetting +import eu.kanade.tachiyomi.ui.library.setting.LibraryDisplayMode @Composable fun LibraryPager( @@ -24,7 +24,7 @@ fun LibraryPager( selectedManga: List, searchQuery: String?, onGlobalSearchClicked: () -> Unit, - getDisplayModeForPage: @Composable (Int) -> State, + getDisplayModeForPage: @Composable (Int) -> State, getColumnsForOrientation: (Boolean) -> PreferenceMutableState, getLibraryForPage: @Composable (Int) -> State>, onClickManga: (LibraryManga) -> Unit, @@ -42,7 +42,7 @@ fun LibraryPager( } val library by getLibraryForPage(page) val displayMode by getDisplayModeForPage(page) - val columns by if (displayMode != DisplayModeSetting.LIST) { + val columns by if (displayMode != LibraryDisplayMode.List) { val configuration = LocalConfiguration.current val isLandscape = configuration.orientation == Configuration.ORIENTATION_LANDSCAPE @@ -52,7 +52,7 @@ fun LibraryPager( } when (displayMode) { - DisplayModeSetting.LIST -> { + LibraryDisplayMode.List -> { LibraryList( items = library, selection = selectedManga, @@ -62,7 +62,7 @@ fun LibraryPager( onGlobalSearchClicked = onGlobalSearchClicked, ) } - DisplayModeSetting.COMPACT_GRID -> { + LibraryDisplayMode.CompactGrid -> { LibraryCompactGrid( items = library, columns = columns, @@ -73,7 +73,7 @@ fun LibraryPager( onGlobalSearchClicked = onGlobalSearchClicked, ) } - DisplayModeSetting.COMFORTABLE_GRID -> { + LibraryDisplayMode.ComfortableGrid -> { LibraryComfortableGrid( items = library, columns = columns, @@ -84,7 +84,7 @@ fun LibraryPager( onGlobalSearchClicked = onGlobalSearchClicked, ) } - DisplayModeSetting.COVER_ONLY_GRID -> { + LibraryDisplayMode.CoverOnlyGrid -> { LibraryCoverOnlyGrid( items = library, columns = columns, diff --git a/app/src/main/java/eu/kanade/tachiyomi/Migrations.kt b/app/src/main/java/eu/kanade/tachiyomi/Migrations.kt index 2b5320897c..696ff7b2b6 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/Migrations.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/Migrations.kt @@ -13,8 +13,6 @@ import eu.kanade.tachiyomi.data.track.TrackManager import eu.kanade.tachiyomi.data.updater.AppUpdateJob import eu.kanade.tachiyomi.extension.ExtensionUpdateJob import eu.kanade.tachiyomi.network.PREF_DOH_CLOUDFLARE -import eu.kanade.tachiyomi.ui.library.setting.SortDirectionSetting -import eu.kanade.tachiyomi.ui.library.setting.SortModeSetting import eu.kanade.tachiyomi.ui.reader.setting.OrientationType import eu.kanade.tachiyomi.util.preference.minusAssign import eu.kanade.tachiyomi.util.preference.plusAssign @@ -196,33 +194,33 @@ object Migrations { } if (oldVersion < 64) { val oldSortingMode = prefs.getInt(PreferenceKeys.librarySortingMode, 0) - val oldSortingDirection = prefs.getBoolean(PreferenceKeys.librarySortingDirection, true) + val oldSortingDirection = prefs.getBoolean("library_sorting_ascending", true) val newSortingMode = when (oldSortingMode) { - 0 -> SortModeSetting.ALPHABETICAL - 1 -> SortModeSetting.LAST_READ - 2 -> SortModeSetting.LAST_CHECKED - 3 -> SortModeSetting.UNREAD - 4 -> SortModeSetting.TOTAL_CHAPTERS - 6 -> SortModeSetting.LATEST_CHAPTER - 8 -> SortModeSetting.DATE_FETCHED - 7 -> SortModeSetting.DATE_ADDED - else -> SortModeSetting.ALPHABETICAL + 0 -> "ALPHABETICAL" + 1 -> "LAST_READ" + 2 -> "LAST_CHECKED" + 3 -> "UNREAD" + 4 -> "TOTAL_CHAPTERS" + 6 -> "LATEST_CHAPTER" + 8 -> "DATE_FETCHED" + 7 -> "DATE_ADDED" + else -> "ALPHABETICAL" } val newSortingDirection = when (oldSortingDirection) { - true -> SortDirectionSetting.ASCENDING - else -> SortDirectionSetting.DESCENDING + true -> "ASCENDING" + else -> "DESCENDING" } prefs.edit(commit = true) { remove(PreferenceKeys.librarySortingMode) - remove(PreferenceKeys.librarySortingDirection) + remove("library_sorting_ascending") } prefs.edit { - putString(PreferenceKeys.librarySortingMode, newSortingMode.name) - putString(PreferenceKeys.librarySortingDirection, newSortingDirection.name) + putString(PreferenceKeys.librarySortingMode, newSortingMode) + putString("library_sorting_ascending", newSortingDirection) } } if (oldVersion < 70) { @@ -265,16 +263,24 @@ object Migrations { } if (oldVersion < 81) { // Handle renamed enum values - @Suppress("DEPRECATION") - val newSortingMode = when (val oldSortingMode = preferences.librarySortingMode().get()) { - SortModeSetting.LAST_CHECKED -> SortModeSetting.LAST_MANGA_UPDATE - SortModeSetting.UNREAD -> SortModeSetting.UNREAD_COUNT - SortModeSetting.DATE_FETCHED -> SortModeSetting.CHAPTER_FETCH_DATE - else -> oldSortingMode + prefs.edit { + val newSortingMode = when (val oldSortingMode = prefs.getString(PreferenceKeys.librarySortingMode, "ALPHABETICAL")) { + "LAST_CHECKED" -> "LAST_MANGA_UPDATE" + "UNREAD" -> "UNREAD_COUNT" + "DATE_FETCHED" -> "CHAPTER_FETCH_DATE" + else -> oldSortingMode + } + putString(PreferenceKeys.librarySortingMode, newSortingMode) + } + } + if (oldVersion < 82) { + prefs.edit { + val sort = prefs.getString(PreferenceKeys.librarySortingMode, null) ?: return@edit + val direction = prefs.getString("library_sorting_ascending", "ASCENDING")!! + putString(PreferenceKeys.librarySortingMode, "$sort,$direction") + remove("library_sorting_ascending") } - preferences.librarySortingMode().set(newSortingMode) } - return true } diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/preference/PreferenceKeys.kt b/app/src/main/java/eu/kanade/tachiyomi/data/preference/PreferenceKeys.kt index 2a1ca25d6b..0e2bdab360 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/preference/PreferenceKeys.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/preference/PreferenceKeys.kt @@ -36,7 +36,6 @@ object PreferenceKeys { const val filterTracked = "pref_filter_library_tracked" const val librarySortingMode = "library_sorting_mode" - const val librarySortingDirection = "library_sorting_ascending" const val migrationSortingMode = "pref_migration_sorting" const val migrationSortingDirection = "pref_migration_direction" diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/preference/PreferencesHelper.kt b/app/src/main/java/eu/kanade/tachiyomi/data/preference/PreferencesHelper.kt index 8f7c68f455..a9e68ae055 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/preference/PreferencesHelper.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/preference/PreferencesHelper.kt @@ -12,9 +12,8 @@ import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.data.database.models.Manga import eu.kanade.tachiyomi.data.track.TrackService import eu.kanade.tachiyomi.data.track.anilist.Anilist -import eu.kanade.tachiyomi.ui.library.setting.DisplayModeSetting -import eu.kanade.tachiyomi.ui.library.setting.SortDirectionSetting -import eu.kanade.tachiyomi.ui.library.setting.SortModeSetting +import eu.kanade.tachiyomi.ui.library.setting.LibraryDisplayMode +import eu.kanade.tachiyomi.ui.library.setting.LibrarySort import eu.kanade.tachiyomi.ui.reader.setting.OrientationType import eu.kanade.tachiyomi.ui.reader.setting.ReadingModeType import eu.kanade.tachiyomi.util.system.DeviceUtil @@ -169,7 +168,7 @@ class PreferencesHelper(val context: Context) { fun lastVersionCode() = flowPrefs.getInt("last_version_code", 0) - fun sourceDisplayMode() = flowPrefs.getEnum("pref_display_mode_catalogue", DisplayModeSetting.COMPACT_GRID) + fun sourceDisplayMode() = flowPrefs.getObject("pref_display_mode_catalogue", LibraryDisplayMode.Serializer, LibraryDisplayMode.default) fun enabledLanguages() = flowPrefs.getStringSet("source_languages", setOf("all", "en", Locale.getDefault().language)) @@ -230,7 +229,7 @@ class PreferencesHelper(val context: Context) { fun libraryUpdateCategories() = flowPrefs.getStringSet("library_update_categories", emptySet()) fun libraryUpdateCategoriesExclude() = flowPrefs.getStringSet("library_update_categories_exclude", emptySet()) - fun libraryDisplayMode() = flowPrefs.getEnum("pref_display_mode_library", DisplayModeSetting.COMPACT_GRID) + fun libraryDisplayMode() = flowPrefs.getObject("pref_display_mode_library", LibraryDisplayMode.Serializer, LibraryDisplayMode.default) fun downloadBadge() = flowPrefs.getBoolean("display_download_badge", false) @@ -256,8 +255,7 @@ class PreferencesHelper(val context: Context) { fun filterTracking(name: Int) = flowPrefs.getInt("${Keys.filterTracked}_$name", ExtendedNavigationView.Item.TriStateGroup.State.IGNORE.value) - fun librarySortingMode() = flowPrefs.getEnum(Keys.librarySortingMode, SortModeSetting.ALPHABETICAL) - fun librarySortingAscending() = flowPrefs.getEnum(Keys.librarySortingDirection, SortDirectionSetting.ASCENDING) + fun librarySortingMode() = flowPrefs.getObject(Keys.librarySortingMode, LibrarySort.Serializer, LibrarySort.default) fun migrationSortingMode() = flowPrefs.getEnum(Keys.migrationSortingMode, SetMigrateSorting.Mode.ALPHABETICAL) fun migrationSortingDirection() = flowPrefs.getEnum(Keys.migrationSortingDirection, SetMigrateSorting.Direction.ASCENDING) diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/browse/BrowseSourceController.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/browse/BrowseSourceController.kt index 94fae7d867..99450f3acb 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/browse/BrowseSourceController.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/browse/BrowseSourceController.kt @@ -37,7 +37,7 @@ import eu.kanade.tachiyomi.ui.base.controller.SearchableNucleusController import eu.kanade.tachiyomi.ui.base.controller.pushController import eu.kanade.tachiyomi.ui.browse.source.globalsearch.GlobalSearchController import eu.kanade.tachiyomi.ui.library.ChangeMangaCategoriesDialog -import eu.kanade.tachiyomi.ui.library.setting.DisplayModeSetting +import eu.kanade.tachiyomi.ui.library.setting.LibraryDisplayMode import eu.kanade.tachiyomi.ui.main.MainActivity import eu.kanade.tachiyomi.ui.manga.AddDuplicateMangaDialog import eu.kanade.tachiyomi.ui.manga.MangaController @@ -212,7 +212,7 @@ open class BrowseSourceController(bundle: Bundle) : binding.catalogueView.removeView(oldRecycler) } - val recycler = if (preferences.sourceDisplayMode().get() == DisplayModeSetting.LIST) { + val recycler = if (preferences.sourceDisplayMode().get() == LibraryDisplayMode.List) { RecyclerView(view.context).apply { id = R.id.recycler layoutManager = LinearLayoutManager(context) @@ -280,8 +280,8 @@ open class BrowseSourceController(bundle: Bundle) : ) val displayItem = when (preferences.sourceDisplayMode().get()) { - DisplayModeSetting.LIST -> R.id.action_list - DisplayModeSetting.COMFORTABLE_GRID -> R.id.action_comfortable_grid + LibraryDisplayMode.List -> R.id.action_list + LibraryDisplayMode.ComfortableGrid -> R.id.action_comfortable_grid else -> R.id.action_compact_grid } menu.findItem(displayItem).isChecked = true @@ -304,9 +304,9 @@ open class BrowseSourceController(bundle: Bundle) : override fun onOptionsItemSelected(item: MenuItem): Boolean { when (item.itemId) { R.id.action_search -> expandActionViewFromInteraction = true - R.id.action_compact_grid -> setDisplayMode(DisplayModeSetting.COMPACT_GRID) - R.id.action_comfortable_grid -> setDisplayMode(DisplayModeSetting.COMFORTABLE_GRID) - R.id.action_list -> setDisplayMode(DisplayModeSetting.LIST) + R.id.action_compact_grid -> setDisplayMode(LibraryDisplayMode.CompactGrid) + R.id.action_comfortable_grid -> setDisplayMode(LibraryDisplayMode.ComfortableGrid) + R.id.action_list -> setDisplayMode(LibraryDisplayMode.List) R.id.action_open_in_web_view -> openInWebView() R.id.action_local_source_help -> openLocalSourceHelpGuide() } @@ -503,7 +503,7 @@ open class BrowseSourceController(bundle: Bundle) : * * @param mode the mode to change to */ - private fun setDisplayMode(mode: DisplayModeSetting) { + private fun setDisplayMode(mode: LibraryDisplayMode) { val view = view ?: return val adapter = adapter ?: return diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/browse/SourceItem.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/browse/SourceItem.kt index d17c38b071..544c6dbe75 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/browse/SourceItem.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/browse/SourceItem.kt @@ -10,16 +10,16 @@ import eu.kanade.domain.manga.model.Manga import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.databinding.SourceComfortableGridItemBinding import eu.kanade.tachiyomi.databinding.SourceCompactGridItemBinding -import eu.kanade.tachiyomi.ui.library.setting.DisplayModeSetting +import eu.kanade.tachiyomi.ui.library.setting.LibraryDisplayMode -class SourceItem(val manga: Manga, private val displayMode: Preference) : +class SourceItem(val manga: Manga, private val displayMode: Preference) : AbstractFlexibleItem>() { override fun getLayoutRes(): Int { return when (displayMode.get()) { - DisplayModeSetting.COMPACT_GRID, DisplayModeSetting.COVER_ONLY_GRID -> R.layout.source_compact_grid_item - DisplayModeSetting.COMFORTABLE_GRID -> R.layout.source_comfortable_grid_item - DisplayModeSetting.LIST -> R.layout.source_list_item + LibraryDisplayMode.CompactGrid, LibraryDisplayMode.CoverOnlyGrid -> R.layout.source_compact_grid_item + LibraryDisplayMode.ComfortableGrid -> R.layout.source_comfortable_grid_item + LibraryDisplayMode.List -> R.layout.source_list_item } } @@ -28,13 +28,13 @@ class SourceItem(val manga: Manga, private val displayMode: Preference>, ): SourceHolder<*> { return when (displayMode.get()) { - DisplayModeSetting.COMPACT_GRID, DisplayModeSetting.COVER_ONLY_GRID -> { + LibraryDisplayMode.CompactGrid, LibraryDisplayMode.CoverOnlyGrid -> { SourceCompactGridHolder(SourceCompactGridItemBinding.bind(view), adapter) } - DisplayModeSetting.COMFORTABLE_GRID -> { + LibraryDisplayMode.ComfortableGrid -> { SourceComfortableGridHolder(SourceComfortableGridItemBinding.bind(view), adapter) } - DisplayModeSetting.LIST -> { + LibraryDisplayMode.List -> { SourceListHolder(view, adapter) } } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryPresenter.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryPresenter.kt index a10c010093..10647bc8c2 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryPresenter.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryPresenter.kt @@ -43,9 +43,10 @@ import eu.kanade.tachiyomi.source.SourceManager import eu.kanade.tachiyomi.source.model.SManga import eu.kanade.tachiyomi.source.online.HttpSource import eu.kanade.tachiyomi.ui.base.presenter.BasePresenter -import eu.kanade.tachiyomi.ui.library.setting.DisplayModeSetting -import eu.kanade.tachiyomi.ui.library.setting.SortDirectionSetting -import eu.kanade.tachiyomi.ui.library.setting.SortModeSetting +import eu.kanade.tachiyomi.ui.library.setting.LibraryDisplayMode +import eu.kanade.tachiyomi.ui.library.setting.LibrarySort +import eu.kanade.tachiyomi.ui.library.setting.display +import eu.kanade.tachiyomi.ui.library.setting.sort import eu.kanade.tachiyomi.util.lang.combineLatest import eu.kanade.tachiyomi.util.lang.launchIO import eu.kanade.tachiyomi.util.removeCovers @@ -334,12 +335,8 @@ class LibraryPresenter( } } - val sortingModes = categories.associate { category -> - category.id to SortModeSetting.get(preferences, category) - } - - val sortDirections = categories.associate { category -> - category.id to SortDirectionSetting.get(category) + val sortModes = categories.associate { category -> + category.id to category.sort } val locale = Locale.getDefault() @@ -347,53 +344,50 @@ class LibraryPresenter( strength = Collator.PRIMARY } val sortFn: (LibraryItem, LibraryItem) -> Int = { i1, i2 -> - val sortingMode = sortingModes[i1.manga.category.toLong()]!! - val sortAscending = sortDirections[i1.manga.category.toLong()]!! == SortDirectionSetting.ASCENDING - when (sortingMode) { - SortModeSetting.ALPHABETICAL -> { + val sort = sortModes[i1.manga.category.toLong()]!! + when (sort.type) { + LibrarySort.Type.Alphabetical -> { collator.compare(i1.manga.title.lowercase(locale), i2.manga.title.lowercase(locale)) } - SortModeSetting.LAST_READ -> { + LibrarySort.Type.LastRead -> { val manga1LastRead = lastReadManga[i1.manga.id!!] ?: 0 val manga2LastRead = lastReadManga[i2.manga.id!!] ?: 0 manga1LastRead.compareTo(manga2LastRead) } - SortModeSetting.LAST_MANGA_UPDATE -> { + LibrarySort.Type.LastUpdate -> { i1.manga.last_update.compareTo(i2.manga.last_update) } - SortModeSetting.UNREAD_COUNT -> when { + LibrarySort.Type.UnreadCount -> when { // Ensure unread content comes first i1.manga.unreadCount == i2.manga.unreadCount -> 0 - i1.manga.unreadCount == 0 -> if (sortAscending) 1 else -1 - i2.manga.unreadCount == 0 -> if (sortAscending) -1 else 1 + i1.manga.unreadCount == 0 -> if (sort.isAscending) 1 else -1 + i2.manga.unreadCount == 0 -> if (sort.isAscending) -1 else 1 else -> i1.manga.unreadCount.compareTo(i2.manga.unreadCount) } - SortModeSetting.TOTAL_CHAPTERS -> { + LibrarySort.Type.TotalChapters -> { i1.manga.totalChapters.compareTo(i2.manga.totalChapters) } - SortModeSetting.LATEST_CHAPTER -> { + LibrarySort.Type.LatestChapter -> { val manga1latestChapter = latestChapterManga[i1.manga.id!!] ?: latestChapterManga.size val manga2latestChapter = latestChapterManga[i2.manga.id!!] ?: latestChapterManga.size manga1latestChapter.compareTo(manga2latestChapter) } - SortModeSetting.CHAPTER_FETCH_DATE -> { + LibrarySort.Type.ChapterFetchDate -> { val manga1chapterFetchDate = chapterFetchDateManga[i1.manga.id!!] ?: 0 val manga2chapterFetchDate = chapterFetchDateManga[i2.manga.id!!] ?: 0 manga1chapterFetchDate.compareTo(manga2chapterFetchDate) } - SortModeSetting.DATE_ADDED -> { + LibrarySort.Type.DateAdded -> { i1.manga.date_added.compareTo(i2.manga.date_added) } - else -> throw IllegalStateException("Invalid SortModeSetting: $sortingMode") + else -> throw IllegalStateException("Invalid SortModeSetting: ${sort.type}") } } return map.mapValues { entry -> - val sortAscending = sortDirections[entry.key.toLong()]!! == SortDirectionSetting.ASCENDING - - val comparator = if (sortAscending) { + val comparator = if (sortModes[entry.key]!!.isAscending) { Comparator(sortFn) } else { Collections.reverseOrder(sortFn) @@ -416,13 +410,6 @@ class LibraryPresenter( dbCategories } - libraryManga.forEach { (categoryId, libraryManga) -> - val category = categories.first { category -> category.id == categoryId } - libraryManga.forEach { libraryItem -> - libraryItem.displayMode = category.displayMode - } - } - state.categories = categories Library(categories, libraryManga) }.asObservable() @@ -680,10 +667,10 @@ class LibraryPresenter( } @Composable - fun getDisplayMode(index: Int): androidx.compose.runtime.State { + fun getDisplayMode(index: Int): androidx.compose.runtime.State { val category = categories[index] return derivedStateOf { - DisplayModeSetting.fromFlag(category.displayMode) + category.display } } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibrarySettingsSheet.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibrarySettingsSheet.kt index 04bfeea5ce..d23ae5b9f6 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibrarySettingsSheet.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibrarySettingsSheet.kt @@ -11,9 +11,10 @@ import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.data.preference.PreferencesHelper import eu.kanade.tachiyomi.data.track.TrackManager import eu.kanade.tachiyomi.data.track.TrackService -import eu.kanade.tachiyomi.ui.library.setting.DisplayModeSetting -import eu.kanade.tachiyomi.ui.library.setting.SortDirectionSetting -import eu.kanade.tachiyomi.ui.library.setting.SortModeSetting +import eu.kanade.tachiyomi.ui.library.setting.LibraryDisplayMode +import eu.kanade.tachiyomi.ui.library.setting.LibrarySort +import eu.kanade.tachiyomi.ui.library.setting.display +import eu.kanade.tachiyomi.ui.library.setting.sort import eu.kanade.tachiyomi.util.lang.launchIO import eu.kanade.tachiyomi.widget.ExtendedNavigationView import eu.kanade.tachiyomi.widget.ExtendedNavigationView.Item.TriStateGroup.State @@ -202,29 +203,25 @@ class LibrarySettingsSheet( override val footer = null override fun initModels() { - val sorting = SortModeSetting.get(preferences, currentCategory) - val order = if (SortDirectionSetting.get(currentCategory) == SortDirectionSetting.ASCENDING) { - Item.MultiSort.SORT_ASC - } else { - Item.MultiSort.SORT_DESC - } + val sort = currentCategory?.sort ?: LibrarySort.default + val order = if (sort.isAscending) Item.MultiSort.SORT_ASC else Item.MultiSort.SORT_DESC alphabetically.state = - if (sorting == SortModeSetting.ALPHABETICAL) order else Item.MultiSort.SORT_NONE + if (sort.type == LibrarySort.Type.Alphabetical) order else Item.MultiSort.SORT_NONE lastRead.state = - if (sorting == SortModeSetting.LAST_READ) order else Item.MultiSort.SORT_NONE + if (sort.type == LibrarySort.Type.LastRead) order else Item.MultiSort.SORT_NONE lastChecked.state = - if (sorting == SortModeSetting.LAST_MANGA_UPDATE) order else Item.MultiSort.SORT_NONE + if (sort.type == LibrarySort.Type.LastUpdate) order else Item.MultiSort.SORT_NONE unread.state = - if (sorting == SortModeSetting.UNREAD_COUNT) order else Item.MultiSort.SORT_NONE + if (sort.type == LibrarySort.Type.UnreadCount) order else Item.MultiSort.SORT_NONE total.state = - if (sorting == SortModeSetting.TOTAL_CHAPTERS) order else Item.MultiSort.SORT_NONE + if (sort.type == LibrarySort.Type.TotalChapters) order else Item.MultiSort.SORT_NONE latestChapter.state = - if (sorting == SortModeSetting.LATEST_CHAPTER) order else Item.MultiSort.SORT_NONE + if (sort.type == LibrarySort.Type.LatestChapter) order else Item.MultiSort.SORT_NONE chapterFetchDate.state = - if (sorting == SortModeSetting.CHAPTER_FETCH_DATE) order else Item.MultiSort.SORT_NONE + if (sort.type == LibrarySort.Type.ChapterFetchDate) order else Item.MultiSort.SORT_NONE dateAdded.state = - if (sorting == SortModeSetting.DATE_ADDED) order else Item.MultiSort.SORT_NONE + if (sort.type == LibrarySort.Type.DateAdded) order else Item.MultiSort.SORT_NONE } override fun onItemClicked(item: Item) { @@ -249,20 +246,20 @@ class LibrarySettingsSheet( private fun setSortPreference(item: Item.MultiStateGroup) { val mode = when (item) { - alphabetically -> SortModeSetting.ALPHABETICAL - lastRead -> SortModeSetting.LAST_READ - lastChecked -> SortModeSetting.LAST_MANGA_UPDATE - unread -> SortModeSetting.UNREAD_COUNT - total -> SortModeSetting.TOTAL_CHAPTERS - latestChapter -> SortModeSetting.LATEST_CHAPTER - chapterFetchDate -> SortModeSetting.CHAPTER_FETCH_DATE - dateAdded -> SortModeSetting.DATE_ADDED + alphabetically -> LibrarySort.Type.Alphabetical + lastRead -> LibrarySort.Type.LastRead + lastChecked -> LibrarySort.Type.LastUpdate + unread -> LibrarySort.Type.UnreadCount + total -> LibrarySort.Type.TotalChapters + latestChapter -> LibrarySort.Type.LatestChapter + chapterFetchDate -> LibrarySort.Type.ChapterFetchDate + dateAdded -> LibrarySort.Type.DateAdded else -> throw NotImplementedError("Unknown display mode") } val direction = if (item.state == Item.MultiSort.SORT_ASC) { - SortDirectionSetting.ASCENDING + LibrarySort.Direction.Ascending } else { - SortDirectionSetting.DESCENDING + LibrarySort.Direction.Descending } sheetScope.launchIO { @@ -297,12 +294,8 @@ class LibrarySettingsSheet( } // Gets user preference of currently selected display mode at current category - private fun getDisplayModePreference(): DisplayModeSetting { - return if (currentCategory != null && preferences.categorizedDisplaySettings().get()) { - DisplayModeSetting.fromFlag(currentCategory!!.displayMode) - } else { - preferences.libraryDisplayMode().get() - } + private fun getDisplayModePreference(): LibraryDisplayMode { + return currentCategory?.display ?: LibraryDisplayMode.default } inner class DisplayGroup : Group { @@ -334,19 +327,19 @@ class LibrarySettingsSheet( } // Sets display group selections based on given mode - fun setGroupSelections(mode: DisplayModeSetting) { - compactGrid.checked = mode == DisplayModeSetting.COMPACT_GRID - comfortableGrid.checked = mode == DisplayModeSetting.COMFORTABLE_GRID - coverOnlyGrid.checked = mode == DisplayModeSetting.COVER_ONLY_GRID - list.checked = mode == DisplayModeSetting.LIST + fun setGroupSelections(mode: LibraryDisplayMode) { + compactGrid.checked = mode == LibraryDisplayMode.CompactGrid + comfortableGrid.checked = mode == LibraryDisplayMode.ComfortableGrid + coverOnlyGrid.checked = mode == LibraryDisplayMode.CoverOnlyGrid + list.checked = mode == LibraryDisplayMode.List } private fun setDisplayModePreference(item: Item) { val flag = when (item) { - compactGrid -> DisplayModeSetting.COMPACT_GRID - comfortableGrid -> DisplayModeSetting.COMFORTABLE_GRID - coverOnlyGrid -> DisplayModeSetting.COVER_ONLY_GRID - list -> DisplayModeSetting.LIST + compactGrid -> LibraryDisplayMode.CompactGrid + comfortableGrid -> LibraryDisplayMode.ComfortableGrid + coverOnlyGrid -> LibraryDisplayMode.CoverOnlyGrid + list -> LibraryDisplayMode.List else -> throw NotImplementedError("Unknown display mode") } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/library/setting/DisplayModeSetting.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/library/setting/DisplayModeSetting.kt deleted file mode 100644 index 1e00dd0886..0000000000 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/library/setting/DisplayModeSetting.kt +++ /dev/null @@ -1,17 +0,0 @@ -package eu.kanade.tachiyomi.ui.library.setting - -enum class DisplayModeSetting(val flag: Long) { - COMPACT_GRID(0b00000000), - COMFORTABLE_GRID(0b00000001), - LIST(0b00000010), - COVER_ONLY_GRID(0b00000011); - - companion object { - const val MASK = 0b00000011L - - fun fromFlag(flag: Long?): DisplayModeSetting { - return values() - .find { mode -> mode.flag == flag } ?: COMPACT_GRID - } - } -} diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/library/setting/Flag.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/library/setting/Flag.kt new file mode 100644 index 0000000000..a8653059b2 --- /dev/null +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/library/setting/Flag.kt @@ -0,0 +1,35 @@ +package eu.kanade.tachiyomi.ui.library.setting + +interface Flag { + val flag: Long +} + +interface Mask { + val mask: Long +} + +interface FlagWithMask : Flag, Mask + +operator fun Long.contains(other: Flag): Boolean { + return if (other is Mask) { + other.flag == this and other.mask + } else { + other.flag == this + } +} + +operator fun Long.plus(other: Flag): Long { + return if (other is Mask) { + this and other.mask.inv() or (other.flag and other.mask) + } else { + this or other.flag + } +} + +operator fun Flag.plus(other: Flag): Long { + return if (other is Mask) { + this.flag and other.mask.inv() or (other.flag and other.mask) + } else { + this.flag or other.flag + } +} diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/library/setting/LibraryDisplayMode.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/library/setting/LibraryDisplayMode.kt new file mode 100644 index 0000000000..5f5b0b15ba --- /dev/null +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/library/setting/LibraryDisplayMode.kt @@ -0,0 +1,60 @@ +package eu.kanade.tachiyomi.ui.library.setting + +import eu.kanade.domain.category.model.Category +import com.fredporciuncula.flow.preferences.Serializer as PreferencesSerializer + +sealed class LibraryDisplayMode( + override val flag: Long, +) : FlagWithMask { + + override val mask: Long = 0b00000011L + + object CompactGrid : LibraryDisplayMode(0b00000000) + object ComfortableGrid : LibraryDisplayMode(0b00000001) + object List : LibraryDisplayMode(0b00000010) + object CoverOnlyGrid : LibraryDisplayMode(0b00000011) + + object Serializer : PreferencesSerializer { + override fun deserialize(serialized: String): LibraryDisplayMode { + return LibraryDisplayMode.deserialize(serialized) + } + + override fun serialize(value: LibraryDisplayMode): String { + return value.serialize() + } + } + + companion object { + val values = setOf(CompactGrid, ComfortableGrid, List, CoverOnlyGrid) + val default = CompactGrid + + fun valueOf(flag: Long?): LibraryDisplayMode { + if (flag == null) return default + return values + .find { mode -> mode.flag == flag and mode.mask } + ?: default + } + + fun deserialize(serialized: String): LibraryDisplayMode { + return when (serialized) { + "COMFORTABLE_GRID" -> ComfortableGrid + "COMPACT_GRID" -> CompactGrid + "COVER_ONLY_GRID" -> CoverOnlyGrid + "LIST" -> List + else -> default + } + } + } + + fun serialize(): String { + return when (this) { + ComfortableGrid -> "COMFORTABLE_GRID" + CompactGrid -> "COMPACT_GRID" + CoverOnlyGrid -> "COVER_ONLY_GRID" + List -> "LIST" + } + } +} + +val Category.display: LibraryDisplayMode + get() = LibraryDisplayMode.valueOf(flags) diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/library/setting/LibrarySort.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/library/setting/LibrarySort.kt new file mode 100644 index 0000000000..1eb81d5c05 --- /dev/null +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/library/setting/LibrarySort.kt @@ -0,0 +1,122 @@ +package eu.kanade.tachiyomi.ui.library.setting + +import eu.kanade.domain.category.model.Category +import com.fredporciuncula.flow.preferences.Serializer as PreferencesSerializer + +data class LibrarySort( + val type: Type, + val direction: Direction, +) : FlagWithMask { + + override val flag: Long + get() = type + direction + + override val mask: Long + get() = type.mask or direction.mask + + val isAscending: Boolean + get() = direction == Direction.Ascending + + sealed class Type( + override val flag: Long, + ) : FlagWithMask { + + override val mask: Long = 0b00111100L + + object Alphabetical : Type(0b00000000) + object LastRead : Type(0b00000100) + object LastUpdate : Type(0b00001000) + object UnreadCount : Type(0b00001100) + object TotalChapters : Type(0b00010000) + object LatestChapter : Type(0b00010100) + object ChapterFetchDate : Type(0b00011000) + object DateAdded : Type(0b00011100) + + companion object { + + fun valueOf(flag: Long): Type { + return types.find { type -> type.flag == flag and type.mask } ?: default.type + } + } + } + + sealed class Direction( + override val flag: Long, + ) : FlagWithMask { + + override val mask: Long = 0b01000000L + + object Ascending : Direction(0b01000000) + object Descending : Direction(0b00000000) + + companion object { + + fun valueOf(flag: Long): Direction { + return directions.find { direction -> direction.flag == flag and direction.mask } ?: default.direction + } + } + } + + object Serializer : PreferencesSerializer { + override fun deserialize(serialized: String): LibrarySort { + return LibrarySort.deserialize(serialized) + } + + override fun serialize(value: LibrarySort): String { + return value.serialize() + } + } + + companion object { + val types = setOf(Type.Alphabetical, Type.LastRead, Type.LastUpdate, Type.UnreadCount, Type.TotalChapters, Type.LatestChapter, Type.ChapterFetchDate, Type.DateAdded) + val directions = setOf(Direction.Ascending, Direction.Descending) + val default = LibrarySort(Type.Alphabetical, Direction.Ascending) + + fun valueOf(flag: Long): LibrarySort { + return LibrarySort( + Type.valueOf(flag), + Direction.valueOf(flag), + ) + } + + fun deserialize(serialized: String): LibrarySort { + if (serialized.isEmpty()) return default + return try { + val values = serialized.split(",") + val type = when (values[0]) { + "ALPHABETICAL" -> Type.Alphabetical + "LAST_READ" -> Type.LastRead + "LAST_MANGA_UPDATE" -> Type.LastUpdate + "UNREAD_COUNT" -> Type.UnreadCount + "TOTAL_CHAPTERS" -> Type.TotalChapters + "LATEST_CHAPTER" -> Type.LatestChapter + "CHAPTER_FETCH_DATE" -> Type.ChapterFetchDate + "DATE_ADDED" -> Type.DateAdded + else -> Type.Alphabetical + } + val ascending = if (values[1] == "ASCENDING") Direction.Ascending else Direction.Descending + LibrarySort(type, ascending) + } catch (e: Exception) { + default + } + } + } + + fun serialize(): String { + val type = when (type) { + Type.Alphabetical -> "ALPHABETICAL" + Type.LastRead -> "LAST_READ" + Type.LastUpdate -> "LAST_MANGA_UPDATE" + Type.UnreadCount -> "UNREAD_COUNT" + Type.TotalChapters -> "TOTAL_CHAPTERS" + Type.LatestChapter -> "LATEST_CHAPTER" + Type.ChapterFetchDate -> "CHAPTER_FETCH_DATE" + Type.DateAdded -> "DATE_ADDED" + } + val direction = if (direction == Direction.Ascending) "ASCENDING" else "DESCENDING" + return "$type,$direction" + } +} + +val Category.sort: LibrarySort + get() = LibrarySort.valueOf(flags) diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/library/setting/SortDirectionSetting.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/library/setting/SortDirectionSetting.kt deleted file mode 100644 index 081f1c8f73..0000000000 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/library/setting/SortDirectionSetting.kt +++ /dev/null @@ -1,20 +0,0 @@ -package eu.kanade.tachiyomi.ui.library.setting - -import eu.kanade.domain.category.model.Category - -enum class SortDirectionSetting(val flag: Long) { - ASCENDING(0b01000000), - DESCENDING(0b00000000); - - companion object { - const val MASK = 0b01000000L - - private fun fromFlag(flag: Long?): SortDirectionSetting { - return values().find { mode -> mode.flag == flag } ?: ASCENDING - } - - fun get(category: Category?): SortDirectionSetting { - return fromFlag(category?.sortDirection) - } - } -} diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/library/setting/SortModeSetting.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/library/setting/SortModeSetting.kt deleted file mode 100644 index ee9664aad4..0000000000 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/library/setting/SortModeSetting.kt +++ /dev/null @@ -1,42 +0,0 @@ -package eu.kanade.tachiyomi.ui.library.setting - -import eu.kanade.domain.category.model.Category -import eu.kanade.tachiyomi.data.preference.PreferencesHelper - -enum class SortModeSetting(val flag: Long) { - ALPHABETICAL(0b00000000), - LAST_READ(0b00000100), - LAST_MANGA_UPDATE(0b00001000), - UNREAD_COUNT(0b00001100), - TOTAL_CHAPTERS(0b00010000), - LATEST_CHAPTER(0b00010100), - CHAPTER_FETCH_DATE(0b00011000), - DATE_ADDED(0b00011100), - - @Deprecated("Use LAST_MANGA_UPDATE") - LAST_CHECKED(0b00001000), - - @Deprecated("Use UNREAD_COUNT") - UNREAD(0b00001100), - - @Deprecated("Use CHAPTER_FETCH_DATE") - DATE_FETCHED(0b00011000), - ; - - companion object { - // Mask supports for more sorting flags if necessary - const val MASK = 0b00111100L - - fun fromFlag(flag: Long?): SortModeSetting { - return values().find { mode -> mode.flag == flag } ?: ALPHABETICAL - } - - fun get(preferences: PreferencesHelper, category: Category?): SortModeSetting { - return if (category != null && preferences.categorizedDisplaySettings().get()) { - fromFlag(category.sortMode) - } else { - preferences.librarySortingMode().get() - } - } - } -} diff --git a/app/src/main/sqldelight/data/categories.sq b/app/src/main/sqldelight/data/categories.sq index 33bf3da0ae..a25e6ca3ba 100644 --- a/app/src/main/sqldelight/data/categories.sq +++ b/app/src/main/sqldelight/data/categories.sq @@ -16,6 +16,12 @@ BEGIN SELECT CASE END; END; +getCategory: +SELECT * +FROM categories +WHERE _id = :id +LIMIT 1; + getCategories: SELECT _id AS id, diff --git a/app/src/test/java/eu/kanade/tachiyomi/util/chapter/LibraryFlagsTest.kt b/app/src/test/java/eu/kanade/tachiyomi/util/chapter/LibraryFlagsTest.kt new file mode 100644 index 0000000000..873dbf680d --- /dev/null +++ b/app/src/test/java/eu/kanade/tachiyomi/util/chapter/LibraryFlagsTest.kt @@ -0,0 +1,69 @@ +package eu.kanade.tachiyomi.util.chapter + +import eu.kanade.tachiyomi.ui.library.setting.LibraryDisplayMode +import eu.kanade.tachiyomi.ui.library.setting.LibrarySort +import eu.kanade.tachiyomi.ui.library.setting.plus +import org.junit.jupiter.api.Assertions.assertEquals +import org.junit.jupiter.api.Assertions.assertNotEquals +import org.junit.jupiter.api.Test + +class LibraryFlagsTest { + + @Test + fun `Check the amount of flags`() { + assertEquals(4, LibraryDisplayMode.values.size) + assertEquals(8, LibrarySort.types.size) + assertEquals(2, LibrarySort.directions.size) + } + + @Test + fun `Test Flag plus operator (LibraryDisplayMode)`() { + val current = LibraryDisplayMode.List + val new = LibraryDisplayMode.CoverOnlyGrid + val flag = current + new + + assertEquals(0b00000011, flag) + } + + @Test + fun `Test Flag plus operator (LibrarySort)`() { + val current = LibrarySort(LibrarySort.Type.LastRead, LibrarySort.Direction.Ascending) + val new = LibrarySort(LibrarySort.Type.DateAdded, LibrarySort.Direction.Ascending) + val flag = current + new + + assertEquals(0b01011100, flag) + } + + @Test + fun `Test Flag plus operator`() { + val display = LibraryDisplayMode.CoverOnlyGrid + val sort = LibrarySort(LibrarySort.Type.DateAdded, LibrarySort.Direction.Ascending) + val flag = display + sort + + assertEquals(0b01011111, flag) + } + + @Test + fun `Test Flag plus operator with old flag as base`() { + val currentDisplay = LibraryDisplayMode.List + val currentSort = LibrarySort(LibrarySort.Type.UnreadCount, LibrarySort.Direction.Descending) + val currentFlag = currentDisplay + currentSort + + val display = LibraryDisplayMode.CoverOnlyGrid + val sort = LibrarySort(LibrarySort.Type.DateAdded, LibrarySort.Direction.Ascending) + val flag = currentFlag + display + sort + + assertEquals(0b00001110, currentFlag) + assertEquals(0b01011111, flag) + assertNotEquals(currentFlag, flag) + } + + @Test + fun `Test default flags`() { + val sort = LibrarySort.default + val display = LibraryDisplayMode.default + val flag = display + sort.type + sort.direction + + assertEquals(0b01000000, flag) + } +}