From cd4c19585dc8b25e7669fe60ae01a1b04ad87a87 Mon Sep 17 00:00:00 2001 From: Secozzi Date: Wed, 30 Oct 2024 21:25:16 +0100 Subject: [PATCH] Added random library sort Co-authored-by: Jack Hamilton <4615800+jackhamilton@users.noreply.github.com> Co-authored-by: AntsyLich <59261191+AntsyLich@users.noreply.github.com> --- .../library/anime/AnimeLibrarySettingsDialog.kt | 15 +++++++++++++++ .../library/manga/MangaLibrarySettingsDialog.kt | 15 +++++++++++++++ .../ui/library/anime/AnimeLibraryScreenModel.kt | 8 ++++++++ .../ui/library/manga/MangaLibraryScreenModel.kt | 8 ++++++++ .../interactor/SetSortModeForAnimeCategory.kt | 4 ++++ .../interactor/SetSortModeForMangaCategory.kt | 4 ++++ .../library/anime/model/AnimeLibrarySortMode.kt | 4 ++++ .../library/manga/model/MangaLibrarySortMode.kt | 4 ++++ .../domain/library/service/LibraryPreferences.kt | 5 +++++ .../domain/library/model/LibraryFlagsTest.kt | 4 ++-- .../commonMain/moko-resources/base/strings.xml | 1 + .../presentation/core/components/SettingsItems.kt | 13 +++++++++++-- 12 files changed, 81 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/eu/kanade/presentation/library/anime/AnimeLibrarySettingsDialog.kt b/app/src/main/java/eu/kanade/presentation/library/anime/AnimeLibrarySettingsDialog.kt index 3172cf6f9..45215fc86 100644 --- a/app/src/main/java/eu/kanade/presentation/library/anime/AnimeLibrarySettingsDialog.kt +++ b/app/src/main/java/eu/kanade/presentation/library/anime/AnimeLibrarySettingsDialog.kt @@ -6,6 +6,8 @@ import androidx.compose.foundation.layout.ColumnScope import androidx.compose.foundation.layout.padding import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.verticalScroll +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.Refresh import androidx.compose.material3.FilterChip import androidx.compose.material3.Text import androidx.compose.runtime.Composable @@ -27,6 +29,7 @@ import tachiyomi.domain.library.anime.model.sort import tachiyomi.domain.library.model.LibraryDisplayMode import tachiyomi.domain.library.service.LibraryPreferences import tachiyomi.i18n.MR +import tachiyomi.presentation.core.components.BaseSortItem import tachiyomi.presentation.core.components.CheckboxItem import tachiyomi.presentation.core.components.HeadingItem import tachiyomi.presentation.core.components.SettingsChipRow @@ -183,7 +186,19 @@ private fun ColumnScope.SortPage( MR.strings.action_sort_episode_fetch_date to AnimeLibrarySort.Type.EpisodeFetchDate, MR.strings.action_sort_date_added to AnimeLibrarySort.Type.DateAdded, MR.strings.action_sort_airing_time to AnimeLibrarySort.Type.AiringTime, + MR.strings.action_sort_random to AnimeLibrarySort.Type.Random, ).plus(trackerSortOption).map { (titleRes, mode) -> + if (mode == AnimeLibrarySort.Type.Random) { + BaseSortItem( + label = stringResource(titleRes), + icon = Icons.Default.Refresh + .takeIf { sortingMode == AnimeLibrarySort.Type.Random }, + onClick = { + screenModel.setSort(category, mode, AnimeLibrarySort.Direction.Ascending) + }, + ) + return@map + } SortItem( label = stringResource(titleRes), sortDescending = sortDescending.takeIf { sortingMode == mode }, diff --git a/app/src/main/java/eu/kanade/presentation/library/manga/MangaLibrarySettingsDialog.kt b/app/src/main/java/eu/kanade/presentation/library/manga/MangaLibrarySettingsDialog.kt index d3ecf5785..0b70b2656 100644 --- a/app/src/main/java/eu/kanade/presentation/library/manga/MangaLibrarySettingsDialog.kt +++ b/app/src/main/java/eu/kanade/presentation/library/manga/MangaLibrarySettingsDialog.kt @@ -6,6 +6,8 @@ import androidx.compose.foundation.layout.ColumnScope import androidx.compose.foundation.layout.padding import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.verticalScroll +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.Refresh import androidx.compose.material3.FilterChip import androidx.compose.material3.Text import androidx.compose.runtime.Composable @@ -27,6 +29,7 @@ import tachiyomi.domain.library.manga.model.sort import tachiyomi.domain.library.model.LibraryDisplayMode import tachiyomi.domain.library.service.LibraryPreferences import tachiyomi.i18n.MR +import tachiyomi.presentation.core.components.BaseSortItem import tachiyomi.presentation.core.components.CheckboxItem import tachiyomi.presentation.core.components.HeadingItem import tachiyomi.presentation.core.components.SettingsChipRow @@ -182,7 +185,19 @@ private fun ColumnScope.SortPage( MR.strings.action_sort_latest_chapter to MangaLibrarySort.Type.LatestChapter, MR.strings.action_sort_chapter_fetch_date to MangaLibrarySort.Type.ChapterFetchDate, MR.strings.action_sort_date_added to MangaLibrarySort.Type.DateAdded, + MR.strings.action_sort_random to MangaLibrarySort.Type.Random, ).plus(trackerSortOption).map { (titleRes, mode) -> + if (mode == MangaLibrarySort.Type.Random) { + BaseSortItem( + label = stringResource(titleRes), + icon = Icons.Default.Refresh + .takeIf { sortingMode == MangaLibrarySort.Type.Random }, + onClick = { + screenModel.setSort(category, mode, MangaLibrarySort.Direction.Ascending) + }, + ) + return@map + } SortItem( label = stringResource(titleRes), sortDescending = sortDescending.takeIf { sortingMode == mode }, diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/library/anime/AnimeLibraryScreenModel.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/library/anime/AnimeLibraryScreenModel.kt index a7ef0330e..a45bc5aa4 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/library/anime/AnimeLibraryScreenModel.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/library/anime/AnimeLibraryScreenModel.kt @@ -72,6 +72,7 @@ import tachiyomi.domain.track.anime.model.AnimeTrack import tachiyomi.source.local.entries.anime.isLocal import uy.kohesive.injekt.Injekt import uy.kohesive.injekt.api.get +import kotlin.random.Random /** * Typealias for the library anime, using the category as keys, and list of anime as values. @@ -314,10 +315,17 @@ class AnimeLibraryScreenModel( ) else -> i1.libraryAnime.unseenCount.compareTo(i2.libraryAnime.unseenCount) } + AnimeLibrarySort.Type.Random -> { + error("Why Are We Still Here? Just To Suffer?") + } } } return mapValues { (key, value) -> + if (key.sort.type == AnimeLibrarySort.Type.Random) { + return@mapValues value.shuffled(Random(libraryPreferences.randomAnimeSortSeed().get())) + } + val comparator = key.sort.comparator() .let { if (key.sort.isAscending) it else it.reversed() } .thenComparator(sortAlphabetically) diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/library/manga/MangaLibraryScreenModel.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/library/manga/MangaLibraryScreenModel.kt index f9fb88a1d..0fce01456 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/library/manga/MangaLibraryScreenModel.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/library/manga/MangaLibraryScreenModel.kt @@ -72,6 +72,7 @@ import tachiyomi.domain.track.manga.model.MangaTrack import tachiyomi.source.local.entries.manga.isLocal import uy.kohesive.injekt.Injekt import uy.kohesive.injekt.api.get +import kotlin.random.Random /** * Typealias for the library manga, using the category as keys, and list of manga as values. @@ -305,10 +306,17 @@ class MangaLibraryScreenModel( val item2Score = trackerScores[i2.libraryManga.id] ?: defaultTrackerScoreSortValue item1Score.compareTo(item2Score) } + MangaLibrarySort.Type.Random -> { + error("Why Are We Still Here? Just To Suffer?") + } } } return mapValues { (key, value) -> + if (key.sort.type == MangaLibrarySort.Type.Random) { + return@mapValues value.shuffled(Random(libraryPreferences.randomMangaSortSeed().get())) + } + val comparator = key.sort.comparator() .let { if (key.sort.isAscending) it else it.reversed() } .thenComparator(sortAlphabetically) diff --git a/domain/src/main/java/tachiyomi/domain/category/anime/interactor/SetSortModeForAnimeCategory.kt b/domain/src/main/java/tachiyomi/domain/category/anime/interactor/SetSortModeForAnimeCategory.kt index 997492792..3d9d6423a 100644 --- a/domain/src/main/java/tachiyomi/domain/category/anime/interactor/SetSortModeForAnimeCategory.kt +++ b/domain/src/main/java/tachiyomi/domain/category/anime/interactor/SetSortModeForAnimeCategory.kt @@ -6,6 +6,7 @@ import tachiyomi.domain.category.model.CategoryUpdate import tachiyomi.domain.library.anime.model.AnimeLibrarySort import tachiyomi.domain.library.model.plus import tachiyomi.domain.library.service.LibraryPreferences +import kotlin.random.Random class SetSortModeForAnimeCategory( private val preferences: LibraryPreferences, @@ -19,6 +20,9 @@ class SetSortModeForAnimeCategory( ) { val category = categoryId?.let { categoryRepository.getAnimeCategory(it) } val flags = (category?.flags ?: 0) + type + direction + if (type == AnimeLibrarySort.Type.Random) { + preferences.randomAnimeSortSeed().set(Random.nextInt()) + } if (category != null && preferences.categorizedDisplaySettings().get()) { categoryRepository.updatePartialAnimeCategory( CategoryUpdate( diff --git a/domain/src/main/java/tachiyomi/domain/category/manga/interactor/SetSortModeForMangaCategory.kt b/domain/src/main/java/tachiyomi/domain/category/manga/interactor/SetSortModeForMangaCategory.kt index bd496e951..a692b2e66 100644 --- a/domain/src/main/java/tachiyomi/domain/category/manga/interactor/SetSortModeForMangaCategory.kt +++ b/domain/src/main/java/tachiyomi/domain/category/manga/interactor/SetSortModeForMangaCategory.kt @@ -6,6 +6,7 @@ import tachiyomi.domain.category.model.CategoryUpdate import tachiyomi.domain.library.manga.model.MangaLibrarySort import tachiyomi.domain.library.model.plus import tachiyomi.domain.library.service.LibraryPreferences +import kotlin.random.Random class SetSortModeForMangaCategory( private val preferences: LibraryPreferences, @@ -19,6 +20,9 @@ class SetSortModeForMangaCategory( ) { val category = categoryId?.let { categoryRepository.getMangaCategory(it) } val flags = (category?.flags ?: 0) + type + direction + if (type == MangaLibrarySort.Type.Random) { + preferences.randomMangaSortSeed().set(Random.nextInt()) + } if (category != null && preferences.categorizedDisplaySettings().get()) { categoryRepository.updatePartialMangaCategory( CategoryUpdate( diff --git a/domain/src/main/java/tachiyomi/domain/library/anime/model/AnimeLibrarySortMode.kt b/domain/src/main/java/tachiyomi/domain/library/anime/model/AnimeLibrarySortMode.kt index ea24ad938..28ed5094c 100644 --- a/domain/src/main/java/tachiyomi/domain/library/anime/model/AnimeLibrarySortMode.kt +++ b/domain/src/main/java/tachiyomi/domain/library/anime/model/AnimeLibrarySortMode.kt @@ -34,6 +34,7 @@ data class AnimeLibrarySort( data object DateAdded : Type(0b00011100) data object TrackerMean : Type(0b000100000) data object AiringTime : Type(0b00110000) + data object Random : Type(0b00111100) companion object { fun valueOf(flag: Long): Type { @@ -81,6 +82,7 @@ data class AnimeLibrarySort( Type.DateAdded, Type.TrackerMean, Type.AiringTime, + Type.Random, ) } val directions by lazy { setOf(Direction.Ascending, Direction.Descending) } @@ -109,6 +111,7 @@ data class AnimeLibrarySort( "DATE_ADDED" -> Type.DateAdded "TRACKER_MEAN" -> Type.TrackerMean "AIRING_TIME" -> Type.AiringTime + "RANDOM" -> Type.Random else -> Type.Alphabetical } val ascending = if (values[1] == "ASCENDING") Direction.Ascending else Direction.Descending @@ -131,6 +134,7 @@ data class AnimeLibrarySort( Type.DateAdded -> "DATE_ADDED" Type.TrackerMean -> "TRACKER_MEAN" Type.AiringTime -> "AIRING_TIME" + Type.Random -> "RANDOM" } val direction = if (direction == Direction.Ascending) "ASCENDING" else "DESCENDING" return "$type,$direction" diff --git a/domain/src/main/java/tachiyomi/domain/library/manga/model/MangaLibrarySortMode.kt b/domain/src/main/java/tachiyomi/domain/library/manga/model/MangaLibrarySortMode.kt index bc69e08d0..993ad1d85 100644 --- a/domain/src/main/java/tachiyomi/domain/library/manga/model/MangaLibrarySortMode.kt +++ b/domain/src/main/java/tachiyomi/domain/library/manga/model/MangaLibrarySortMode.kt @@ -33,6 +33,7 @@ data class MangaLibrarySort( data object ChapterFetchDate : Type(0b00011000) data object DateAdded : Type(0b00011100) data object TrackerMean : Type(0b000100000) + data object Random : Type(0b00111100) companion object { fun valueOf(flag: Long): Type { @@ -79,6 +80,7 @@ data class MangaLibrarySort( Type.ChapterFetchDate, Type.DateAdded, Type.TrackerMean, + Type.Random, ) } val directions by lazy { setOf(Direction.Ascending, Direction.Descending) } @@ -106,6 +108,7 @@ data class MangaLibrarySort( "CHAPTER_FETCH_DATE" -> Type.ChapterFetchDate "DATE_ADDED" -> Type.DateAdded "TRACKER_MEAN" -> Type.TrackerMean + "RANDOM" -> Type.Random else -> Type.Alphabetical } val ascending = if (values[1] == "ASCENDING") Direction.Ascending else Direction.Descending @@ -127,6 +130,7 @@ data class MangaLibrarySort( Type.ChapterFetchDate -> "CHAPTER_FETCH_DATE" Type.DateAdded -> "DATE_ADDED" Type.TrackerMean -> "TRACKER_MEAN" + Type.Random -> "RANDOM" } val direction = if (direction == Direction.Ascending) "ASCENDING" else "DESCENDING" return "$type,$direction" diff --git a/domain/src/main/java/tachiyomi/domain/library/service/LibraryPreferences.kt b/domain/src/main/java/tachiyomi/domain/library/service/LibraryPreferences.kt index cce3b4fe7..9ef088b9c 100644 --- a/domain/src/main/java/tachiyomi/domain/library/service/LibraryPreferences.kt +++ b/domain/src/main/java/tachiyomi/domain/library/service/LibraryPreferences.kt @@ -89,6 +89,11 @@ class LibraryPreferences( fun autoClearItemCache() = preferenceStore.getBoolean("auto_clear_chapter_cache", false) + // Random Sort Seed + + fun randomAnimeSortSeed() = preferenceStore.getInt("library_random_anime_sort_seed", 0) + fun randomMangaSortSeed() = preferenceStore.getInt("library_random_manga_sort_seed", 0) + // Mixture Columns fun animePortraitColumns() = preferenceStore.getInt("pref_animelib_columns_portrait_key", 0) diff --git a/domain/src/test/java/tachiyomi/domain/library/model/LibraryFlagsTest.kt b/domain/src/test/java/tachiyomi/domain/library/model/LibraryFlagsTest.kt index f2e382ec2..796ba5ff3 100644 --- a/domain/src/test/java/tachiyomi/domain/library/model/LibraryFlagsTest.kt +++ b/domain/src/test/java/tachiyomi/domain/library/model/LibraryFlagsTest.kt @@ -14,9 +14,9 @@ class LibraryFlagsTest { @Test fun `Check the amount of flags`() { LibraryDisplayMode.values.size shouldBe 4 - MangaLibrarySort.types.size shouldBe 9 + MangaLibrarySort.types.size shouldBe 10 MangaLibrarySort.directions.size shouldBe 2 - AnimeLibrarySort.types.size shouldBe 10 + AnimeLibrarySort.types.size shouldBe 11 AnimeLibrarySort.directions.size shouldBe 2 } diff --git a/i18n/src/commonMain/moko-resources/base/strings.xml b/i18n/src/commonMain/moko-resources/base/strings.xml index a01980c66..84f9fc3c6 100644 --- a/i18n/src/commonMain/moko-resources/base/strings.xml +++ b/i18n/src/commonMain/moko-resources/base/strings.xml @@ -58,6 +58,7 @@ Chapter fetch date Date added Tracker score + Random Airing time Search Search… diff --git a/presentation-core/src/main/java/tachiyomi/presentation/core/components/SettingsItems.kt b/presentation-core/src/main/java/tachiyomi/presentation/core/components/SettingsItems.kt index 5ce5c0bf8..d3a3620d3 100644 --- a/presentation-core/src/main/java/tachiyomi/presentation/core/components/SettingsItems.kt +++ b/presentation-core/src/main/java/tachiyomi/presentation/core/components/SettingsItems.kt @@ -122,12 +122,21 @@ fun SortItem( null -> null } + BaseSortItem( + label = label, + icon = arrowIcon, + onClick = onClick, + ) +} + +@Composable +fun BaseSortItem(label: String, icon: ImageVector?, onClick: () -> Unit) { BaseSettingsItem( label = label, widget = { - if (arrowIcon != null) { + if (icon != null) { Icon( - imageVector = arrowIcon, + imageVector = icon, contentDescription = null, tint = MaterialTheme.colorScheme.primary, )