From e14cc134a0b0b1c7c74304332e7d92fee975e084 Mon Sep 17 00:00:00 2001 From: Caleb Morris Date: Sat, 4 Nov 2023 12:31:59 -0700 Subject: [PATCH] Added library sort by mean Tracker score (#10005) (cherry picked from commit 5d91b77c9340604436c63073c83ad8b37794ddf0) # Conflicts: # app/src/main/java/eu/kanade/presentation/library/LibrarySettingsDialog.kt # app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryScreenModel.kt # domain/src/main/java/tachiyomi/domain/library/model/LibrarySortMode.kt # domain/src/main/java/tachiyomi/domain/track/interactor/GetTracksPerManga.kt --- .../library/LibrarySettingsDialog.kt | 13 ++++++- .../tachiyomi/data/track/TrackerManager.kt | 2 ++ .../ui/library/LibraryScreenModel.kt | 35 ++++++++++++++++--- .../domain/library/model/LibrarySortMode.kt | 8 ++++- .../track/interactor/GetTracksPerManga.kt | 14 ++++---- .../domain/library/model/LibraryFlagsTest.kt | 2 +- i18n/src/main/res/values/strings.xml | 1 + 7 files changed, 59 insertions(+), 16 deletions(-) diff --git a/app/src/main/java/eu/kanade/presentation/library/LibrarySettingsDialog.kt b/app/src/main/java/eu/kanade/presentation/library/LibrarySettingsDialog.kt index a8daf3011..fba83e1a6 100644 --- a/app/src/main/java/eu/kanade/presentation/library/LibrarySettingsDialog.kt +++ b/app/src/main/java/eu/kanade/presentation/library/LibrarySettingsDialog.kt @@ -185,6 +185,13 @@ private fun ColumnScope.SortPage( }.collectAsState(initial = screenModel.libraryPreferences.sortTagsForLibrary().get().isNotEmpty()) // SY <-- + val trackerSortOption = + if (screenModel.trackers.isEmpty()) { + emptyList() + } else { + listOf(R.string.action_sort_tracker_score to LibrarySort.Type.TrackerMean) + } + listOfNotNull( R.string.action_sort_alpha to LibrarySort.Type.Alphabetical, R.string.action_sort_total to LibrarySort.Type.TotalChapters, @@ -194,12 +201,14 @@ private fun ColumnScope.SortPage( R.string.action_sort_latest_chapter to LibrarySort.Type.LatestChapter, R.string.action_sort_chapter_fetch_date to LibrarySort.Type.ChapterFetchDate, R.string.action_sort_date_added to LibrarySort.Type.DateAdded, + // SY --> if (hasSortTags) { R.string.tag_sorting to LibrarySort.Type.TagList } else { null }, - ).map { (titleRes, mode) -> + // SY <-- + ).plus(trackerSortOption).map { (titleRes, mode) -> SortItem( label = stringResource(titleRes), sortDescending = sortDescending.takeIf { sortingMode == mode }, @@ -290,6 +299,7 @@ private fun ColumnScope.DisplayPage( ) } +// SY --> data class GroupMode( val int: Int, val nameRes: Int, @@ -342,3 +352,4 @@ private fun ColumnScope.GroupPage( ) } } +// SY <-- diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/track/TrackerManager.kt b/app/src/main/java/eu/kanade/tachiyomi/data/track/TrackerManager.kt index ff9a1b8f1..11f3a6a75 100755 --- a/app/src/main/java/eu/kanade/tachiyomi/data/track/TrackerManager.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/track/TrackerManager.kt @@ -37,6 +37,8 @@ class TrackerManager { val trackers = listOf(mdList, myAnimeList, aniList, kitsu, shikimori, bangumi, komga, mangaUpdates, kavita, suwayomi) + fun loggedInTrackers() = trackers.filter { it.isLoggedIn } + fun get(id: Long) = trackers.find { it.id == id } fun hasLoggedIn() = trackers.any { it.isLoggedIn } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryScreenModel.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryScreenModel.kt index e630e1112..5d05f4d80 100755 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryScreenModel.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryScreenModel.kt @@ -176,7 +176,7 @@ class LibraryScreenModel( .applyGrouping(groupType) // SY <-- .applyFilters(tracks, loggedInTrackers) - .applySort(/* SY --> */sort.takeIf { groupType != LibraryGroup.BY_DEFAULT } /* SY <-- */) + .applySort(tracks, /* SY --> */sort.takeIf { groupType != LibraryGroup.BY_DEFAULT } /* SY <-- */) .mapValues { (_, value) -> if (searchQuery != null) { // Filter query @@ -267,7 +267,7 @@ class LibraryScreenModel( * Applies library filters to the given map of manga. */ private suspend fun LibraryMap.applyFilters( - trackMap: Map>, + trackMap: Map>, loggedInTrackers: Map, ): LibraryMap { val prefs = getLibraryItemPreferencesFlow().first() @@ -322,7 +322,9 @@ class LibraryScreenModel( val filterFnTracking: (LibraryItem) -> Boolean = tracking@{ item -> if (isNotLoggedInAnyTrack || trackFiltersIsIgnored) return@tracking true - val mangaTracks = trackMap[item.libraryManga.id].orEmpty() + val mangaTracks = trackMap + .mapValues { entry -> entry.value.map { it.syncId } }[item.libraryManga.id] + .orEmpty() val isExcluded = excludedTracks.isNotEmpty() && mangaTracks.fastAny { it in excludedTracks } val isIncluded = includedTracks.isEmpty() || mangaTracks.fastAny { it in includedTracks } @@ -348,7 +350,11 @@ class LibraryScreenModel( /** * Applies library sorting to the given map of manga. */ - private fun LibraryMap.applySort(/* SY --> */ groupSort: LibrarySort? = null /* SY <-- */): LibraryMap { + private fun LibraryMap.applySort( + // Map> + trackMap: Map>, + /* SY --> */ groupSort: LibrarySort? = null, /* SY <-- */ + ): LibraryMap { // SY --> val listOfTags by lazy { libraryPreferences.sortTagsForLibrary().get() @@ -371,6 +377,20 @@ class LibraryScreenModel( collator.compare(i1.libraryManga.manga.title.lowercase(locale), i2.libraryManga.manga.title.lowercase(locale)) } + val defaultTrackerScoreSortValue = -1.0 + val trackerScores by lazy { + val trackerMap = trackerManager.loggedInTrackers().associateBy { e -> e.id } + trackMap.mapValues { entry -> + when { + entry.value.isEmpty() -> null + else -> + entry.value + .mapNotNull { trackerMap[it.syncId]?.get10PointScore(it) } + .average() + } + } + } + val sortFn: (LibraryItem, LibraryItem) -> Int = { i1, i2 -> // SY --> val sort = groupSort ?: keys.find { it.id == i1.libraryManga.category }!!.sort @@ -404,6 +424,11 @@ class LibraryScreenModel( LibrarySort.Type.DateAdded -> { i1.libraryManga.manga.dateAdded.compareTo(i2.libraryManga.manga.dateAdded) } + LibrarySort.Type.TrackerMean -> { + val item1Score = trackerScores[i1.libraryManga.id] ?: defaultTrackerScoreSortValue + val item2Score = trackerScores[i2.libraryManga.id] ?: defaultTrackerScoreSortValue + item1Score.compareTo(item2Score) + } // SY --> LibrarySort.Type.TagList -> { val manga1IndexOfTag = listOfTags.indexOfFirst { i1.libraryManga.manga.genre?.contains(it) ?: false } @@ -550,7 +575,7 @@ class LibraryScreenModel( * @return map of track id with the filter value */ private fun getTrackingFilterFlow(): Flow> { - val loggedInTrackers = trackerManager.trackers.filter { it.isLoggedIn } + val loggedInTrackers = trackerManager.loggedInTrackers() return if (loggedInTrackers.isNotEmpty()) { val prefFlows = loggedInTrackers .map { libraryPreferences.filterTracking(it.id.toInt()).changes() } diff --git a/domain/src/main/java/tachiyomi/domain/library/model/LibrarySortMode.kt b/domain/src/main/java/tachiyomi/domain/library/model/LibrarySortMode.kt index d2d0775ad..ea79cbba7 100644 --- a/domain/src/main/java/tachiyomi/domain/library/model/LibrarySortMode.kt +++ b/domain/src/main/java/tachiyomi/domain/library/model/LibrarySortMode.kt @@ -30,9 +30,10 @@ data class LibrarySort( data object LatestChapter : Type(0b00010100) data object ChapterFetchDate : Type(0b00011000) data object DateAdded : Type(0b00011100) + data object TrackerMean : Type(0b000100000) // SY --> - object TagList : Type(0b00100100) + data object TagList : Type(0b00100100) // SY <-- companion object { @@ -79,6 +80,7 @@ data class LibrarySort( Type.LatestChapter, Type.ChapterFetchDate, Type.DateAdded, + Type.TrackerMean, /* SY -->*/ Type.TagList, /* SY <--*/ ) } @@ -106,6 +108,7 @@ data class LibrarySort( "LATEST_CHAPTER" -> Type.LatestChapter "CHAPTER_FETCH_DATE" -> Type.ChapterFetchDate "DATE_ADDED" -> Type.DateAdded + "TRACKER_MEAN" -> Type.TrackerMean // SY --> "TAG_LIST" -> Type.TagList // SY <-- @@ -129,7 +132,10 @@ data class LibrarySort( Type.LatestChapter -> "LATEST_CHAPTER" Type.ChapterFetchDate -> "CHAPTER_FETCH_DATE" Type.DateAdded -> "DATE_ADDED" + Type.TrackerMean -> "TRACKER_MEAN" + // SY --> Type.TagList -> "TAG_LIST" + // SY <-- } val direction = if (direction == Direction.Ascending) "ASCENDING" else "DESCENDING" return "$type,$direction" diff --git a/domain/src/main/java/tachiyomi/domain/track/interactor/GetTracksPerManga.kt b/domain/src/main/java/tachiyomi/domain/track/interactor/GetTracksPerManga.kt index e590455a8..405f257cc 100644 --- a/domain/src/main/java/tachiyomi/domain/track/interactor/GetTracksPerManga.kt +++ b/domain/src/main/java/tachiyomi/domain/track/interactor/GetTracksPerManga.kt @@ -2,6 +2,7 @@ package tachiyomi.domain.track.interactor import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.map +import tachiyomi.domain.track.model.Track import tachiyomi.domain.track.repository.TrackRepository class GetTracksPerManga( @@ -9,17 +10,14 @@ class GetTracksPerManga( private val isTrackUnfollowed: IsTrackUnfollowed, ) { - fun subscribe(): Flow>> { + fun subscribe(): Flow>> { return trackRepository.getTracksAsFlow().map { tracks -> - tracks - .groupBy { it.mangaId } + tracks.groupBy { it.mangaId } + // SY --> .mapValues { entry -> - entry.value - // SY --> - .filterNot { isTrackUnfollowed.await(it) } - // SY <-- - .map { it.syncId } + entry.value.filterNot { isTrackUnfollowed.await(it) } } + // SY <-- } } } 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 408dee18a..a3a223782 100644 --- a/domain/src/test/java/tachiyomi/domain/library/model/LibraryFlagsTest.kt +++ b/domain/src/test/java/tachiyomi/domain/library/model/LibraryFlagsTest.kt @@ -12,7 +12,7 @@ class LibraryFlagsTest { @Test fun `Check the amount of flags`() { LibraryDisplayMode.values.size shouldBe 4 - LibrarySort.types.size shouldBe 8 + LibrarySort.types.size shouldBe 9 LibrarySort.directions.size shouldBe 2 } diff --git a/i18n/src/main/res/values/strings.xml b/i18n/src/main/res/values/strings.xml index 6efd919ce..4711f0b38 100755 --- a/i18n/src/main/res/values/strings.xml +++ b/i18n/src/main/res/values/strings.xml @@ -66,6 +66,7 @@ Latest chapter Chapter fetch date Date added + Tracker score Search Search… Search settings