Allow user to read all read manga stats

This commit is contained in:
Jobobby04 2023-05-10 17:30:52 -04:00
parent 197f729023
commit e9a3463455
9 changed files with 82 additions and 9 deletions

View File

@ -43,6 +43,7 @@ import tachiyomi.domain.manga.interactor.GetMergedManga
import tachiyomi.domain.manga.interactor.GetMergedMangaById import tachiyomi.domain.manga.interactor.GetMergedMangaById
import tachiyomi.domain.manga.interactor.GetMergedMangaForDownloading import tachiyomi.domain.manga.interactor.GetMergedMangaForDownloading
import tachiyomi.domain.manga.interactor.GetMergedReferencesById import tachiyomi.domain.manga.interactor.GetMergedReferencesById
import tachiyomi.domain.manga.interactor.GetReadMangaNotInLibrary
import tachiyomi.domain.manga.interactor.GetSearchMetadata import tachiyomi.domain.manga.interactor.GetSearchMetadata
import tachiyomi.domain.manga.interactor.GetSearchTags import tachiyomi.domain.manga.interactor.GetSearchTags
import tachiyomi.domain.manga.interactor.GetSearchTitles import tachiyomi.domain.manga.interactor.GetSearchTitles
@ -108,6 +109,7 @@ class SYDomainModule : InjektModule {
addFactory { GetPagePreviews(get(), get()) } addFactory { GetPagePreviews(get(), get()) }
addFactory { SearchEngine() } addFactory { SearchEngine() }
addFactory { IsTrackUnfollowed() } addFactory { IsTrackUnfollowed() }
addFactory { GetReadMangaNotInLibrary(get()) }
// Required for [MetadataSource] // Required for [MetadataSource]
addFactory<MetadataSource.GetMangaId> { GetManga(get()) } addFactory<MetadataSource.GetMangaId> { GetManga(get()) }

View File

@ -8,6 +8,7 @@ import cafe.adriel.voyager.core.model.rememberScreenModel
import cafe.adriel.voyager.navigator.LocalNavigator import cafe.adriel.voyager.navigator.LocalNavigator
import cafe.adriel.voyager.navigator.currentOrThrow import cafe.adriel.voyager.navigator.currentOrThrow
import eu.kanade.presentation.components.AppBar import eu.kanade.presentation.components.AppBar
import eu.kanade.presentation.components.AppBarActions
import eu.kanade.presentation.more.stats.StatsScreenContent import eu.kanade.presentation.more.stats.StatsScreenContent
import eu.kanade.presentation.more.stats.StatsScreenState import eu.kanade.presentation.more.stats.StatsScreenState
import eu.kanade.presentation.util.Screen import eu.kanade.presentation.util.Screen
@ -35,11 +36,28 @@ class StatsScreen : Screen() {
title = stringResource(R.string.label_stats), title = stringResource(R.string.label_stats),
navigateUp = navigator::pop, navigateUp = navigator::pop,
scrollBehavior = scrollBehavior, scrollBehavior = scrollBehavior,
// SY -->
actions = {
val allRead by screenModel.allRead.collectAsState()
AppBarActions(
listOf(
AppBar.OverflowAction(
title = if (allRead) {
stringResource(R.string.ignore_non_library_entries)
} else {
stringResource(R.string.include_all_read_entries)
},
onClick = screenModel::toggleReadManga,
),
),
)
},
// SY <--
) )
}, },
) { paddingValues -> ) { paddingValues ->
StatsScreenContent( StatsScreenContent(
state = state as StatsScreenState.Success, state = state as? StatsScreenState.Success ?: return@Scaffold,
paddingValues = paddingValues, paddingValues = paddingValues,
) )
} }

View File

@ -12,8 +12,11 @@ import eu.kanade.presentation.more.stats.data.StatsData
import eu.kanade.tachiyomi.data.download.DownloadManager import eu.kanade.tachiyomi.data.download.DownloadManager
import eu.kanade.tachiyomi.data.track.TrackManager import eu.kanade.tachiyomi.data.track.TrackManager
import eu.kanade.tachiyomi.source.model.SManga import eu.kanade.tachiyomi.source.model.SManga
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.flow.update import kotlinx.coroutines.flow.update
import tachiyomi.core.util.lang.launchIO
import tachiyomi.domain.history.interactor.GetTotalReadDuration import tachiyomi.domain.history.interactor.GetTotalReadDuration
import tachiyomi.domain.library.model.LibraryManga import tachiyomi.domain.library.model.LibraryManga
import tachiyomi.domain.library.service.LibraryPreferences import tachiyomi.domain.library.service.LibraryPreferences
@ -21,6 +24,7 @@ import tachiyomi.domain.library.service.LibraryPreferences.Companion.MANGA_HAS_U
import tachiyomi.domain.library.service.LibraryPreferences.Companion.MANGA_NON_COMPLETED import tachiyomi.domain.library.service.LibraryPreferences.Companion.MANGA_NON_COMPLETED
import tachiyomi.domain.library.service.LibraryPreferences.Companion.MANGA_NON_READ import tachiyomi.domain.library.service.LibraryPreferences.Companion.MANGA_NON_READ
import tachiyomi.domain.manga.interactor.GetLibraryManga import tachiyomi.domain.manga.interactor.GetLibraryManga
import tachiyomi.domain.manga.interactor.GetReadMangaNotInLibrary
import tachiyomi.domain.track.interactor.GetTracks import tachiyomi.domain.track.interactor.GetTracks
import tachiyomi.domain.track.model.Track import tachiyomi.domain.track.model.Track
import tachiyomi.source.local.isLocal import tachiyomi.source.local.isLocal
@ -34,13 +38,28 @@ class StatsScreenModel(
private val getTracks: GetTracks = Injekt.get(), private val getTracks: GetTracks = Injekt.get(),
private val preferences: LibraryPreferences = Injekt.get(), private val preferences: LibraryPreferences = Injekt.get(),
private val trackManager: TrackManager = Injekt.get(), private val trackManager: TrackManager = Injekt.get(),
// SY -->
private val getReadMangaNotInLibrary: GetReadMangaNotInLibrary = Injekt.get(),
// SY <--
) : StateScreenModel<StatsScreenState>(StatsScreenState.Loading) { ) : StateScreenModel<StatsScreenState>(StatsScreenState.Loading) {
private val loggedServices by lazy { trackManager.services.fastFilter { it.isLogged } } private val loggedServices by lazy { trackManager.services.fastFilter { it.isLogged } }
// SY -->
private val _allRead = MutableStateFlow(false)
val allRead = _allRead.asStateFlow()
// SY <--
init { init {
coroutineScope.launchIO { // SY -->
val libraryManga = getLibraryManga.await() _allRead.onEach { allRead ->
mutableState.update { StatsScreenState.Loading }
val libraryManga = getLibraryManga.await() + if (allRead) {
getReadMangaNotInLibrary.await()
} else {
emptyList()
}
// SY <--
val distinctLibraryManga = libraryManga.fastDistinctBy { it.id } val distinctLibraryManga = libraryManga.fastDistinctBy { it.id }
@ -83,7 +102,9 @@ class StatsScreenModel(
trackers = trackersStatData, trackers = trackersStatData,
) )
} }
} // SY -->
}.launchIn(coroutineScope)
// SY <--
} }
private fun getGlobalUpdateItemCount(libraryManga: List<LibraryManga>): Int { private fun getGlobalUpdateItemCount(libraryManga: List<LibraryManga>): Int {
@ -149,4 +170,8 @@ class StatsScreenModel(
val service = trackManager.getService(track.syncId)!! val service = trackManager.getService(track.syncId)!!
return service.get10PointScore(track) return service.get10PointScore(track)
} }
fun toggleReadManga() {
_allRead.value = !_allRead.value
}
} }

View File

@ -88,7 +88,7 @@ class AndroidDatabaseHandler(
} }
// SY --> // SY -->
fun getLibraryQuery() = LibraryQuery(driver) fun getLibraryQuery(condition: String = "M.favorite = 1") = LibraryQuery(driver, condition)
fun getUpdatesQuery(after: Long) = UpdatesQuery(driver, after) fun getUpdatesQuery(after: Long) = UpdatesQuery(driver, after)
// SY <-- // SY <--

View File

@ -40,7 +40,10 @@ private val mapper = { cursor: SqlCursor ->
) )
} }
class LibraryQuery(val driver: SqlDriver) : Query<LibraryView>(copyOnWriteList(), mapper) { class LibraryQuery(
val driver: SqlDriver,
val condition: String = "M.favorite = 1",
) : Query<LibraryView>(copyOnWriteList(), mapper) {
override fun execute(): SqlCursor { override fun execute(): SqlCursor {
return driver.executeQuery( return driver.executeQuery(
null, null,
@ -72,7 +75,7 @@ class LibraryQuery(val driver: SqlDriver) : Query<LibraryView>(copyOnWriteList()
ON M._id = C.manga_id ON M._id = C.manga_id
LEFT JOIN mangas_categories AS MC LEFT JOIN mangas_categories AS MC
ON MC.manga_id = M._id ON MC.manga_id = M._id
WHERE M.favorite = 1 AND M.source <> $MERGED_SOURCE_ID WHERE $condition AND M.source <> $MERGED_SOURCE_ID
UNION UNION
SELECT SELECT
M.*, M.*,
@ -109,7 +112,7 @@ class LibraryQuery(val driver: SqlDriver) : Query<LibraryView>(copyOnWriteList()
ON ME.merge_id = C.merge_id ON ME.merge_id = C.merge_id
LEFT JOIN mangas_categories AS MC LEFT JOIN mangas_categories AS MC
ON MC.manga_id = M._id ON MC.manga_id = M._id
WHERE M.favorite = 1 AND M.source = $MERGED_SOURCE_ID; WHERE $condition AND M.source = $MERGED_SOURCE_ID;
""".trimIndent(), """.trimIndent(),
1, 1,
) )

View File

@ -179,5 +179,11 @@ class MangaRepositoryImpl(
override suspend fun deleteManga(mangaId: Long) { override suspend fun deleteManga(mangaId: Long) {
handler.await { mangasQueries.deleteById(mangaId) } handler.await { mangasQueries.deleteById(mangaId) }
} }
override suspend fun getReadMangaNotInLibrary(): List<LibraryManga> {
return handler.awaitList {
(handler as AndroidDatabaseHandler).getLibraryQuery("M.favorite = 0 AND C.readCount != 0")
}.map(libraryViewMapper)
}
// SY <-- // SY <--
} }

View File

@ -0,0 +1,13 @@
package tachiyomi.domain.manga.interactor
import tachiyomi.domain.library.model.LibraryManga
import tachiyomi.domain.manga.repository.MangaRepository
class GetReadMangaNotInLibrary(
private val mangaRepository: MangaRepository,
) {
suspend fun await(): List<LibraryManga> {
return mangaRepository.getReadMangaNotInLibrary()
}
}

View File

@ -41,5 +41,7 @@ interface MangaRepository {
suspend fun getAll(): List<Manga> suspend fun getAll(): List<Manga>
suspend fun deleteManga(mangaId: Long) suspend fun deleteManga(mangaId: Long)
suspend fun getReadMangaNotInLibrary(): List<LibraryManga>
// SY <-- // SY <--
} }

View File

@ -709,6 +709,10 @@
<string name="relation_serialization">Serialization</string> <string name="relation_serialization">Serialization</string>
<string name="relation_alternate_version">Alternate version</string> <string name="relation_alternate_version">Alternate version</string>
<!-- Stats page -->
<string name="include_all_read_entries">Include all read entries</string>
<string name="ignore_non_library_entries">Ignore non-library entries</string>
<!-- Humanize time --> <!-- Humanize time -->
<plurals name="humanize_year"> <plurals name="humanize_year">
<item quantity="one">%1$d year ago</item> <item quantity="one">%1$d year ago</item>