Implement scanlator filter (#8803)

* Implement scanlator filter

* Visual improvement to scanlator filter dialog

* Review changes + Bug fixes

Backup not containing filtered chapters and similar issue fix

* Review Changes + Fix SQL query

* Lint mamma mia
This commit is contained in:
AntsyLich
2023-11-05 21:34:35 +06:00
committed by GitHub
parent e6ca54fd04
commit b97aa23548
26 changed files with 462 additions and 33 deletions

View File

@@ -414,7 +414,7 @@ class LibraryScreenModel(
}
suspend fun getNextUnreadChapter(manga: Manga): Chapter? {
return getChaptersByMangaId.await(manga.id).getNextUnread(manga, downloadManager)
return getChaptersByMangaId.await(manga.id, applyScanlatorFilter = true).getNextUnread(manga, downloadManager)
}
/**

View File

@@ -9,8 +9,10 @@ import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.hapticfeedback.HapticFeedbackType
import androidx.compose.ui.platform.LocalContext
@@ -30,6 +32,7 @@ import eu.kanade.presentation.manga.EditCoverAction
import eu.kanade.presentation.manga.MangaScreen
import eu.kanade.presentation.manga.components.DeleteChaptersDialog
import eu.kanade.presentation.manga.components.MangaCoverDialog
import eu.kanade.presentation.manga.components.ScanlatorFilterDialog
import eu.kanade.presentation.manga.components.SetIntervalDialog
import eu.kanade.presentation.util.AssistContentScreen
import eu.kanade.presentation.util.Screen
@@ -152,6 +155,8 @@ class MangaScreen(
onInvertSelection = screenModel::invertSelection,
)
var showScanlatorsDialog by remember { mutableStateOf(false) }
val onDismissRequest = { screenModel.dismissDialog() }
when (val dialog = successState.dialog) {
null -> {}
@@ -189,6 +194,8 @@ class MangaScreen(
onDisplayModeChanged = screenModel::setDisplayMode,
onSetAsDefault = screenModel::setCurrentSettingsAsDefault,
onResetToDefault = screenModel::resetToDefaultSettings,
scanlatorFilterActive = successState.scanlatorFilterActive,
onScanlatorFilterClicked = { showScanlatorsDialog = true },
)
MangaScreenModel.Dialog.TrackSheet -> {
NavigatorAdaptiveSheet(
@@ -235,6 +242,15 @@ class MangaScreen(
)
}
}
if (showScanlatorsDialog) {
ScanlatorFilterDialog(
availableScanlators = successState.availableScanlators,
excludedScanlators = successState.excludedScanlators,
onDismissRequest = { showScanlatorsDialog = false },
onConfirm = screenModel::setExcludedScanlators,
)
}
}
private fun continueReading(context: Context, unreadChapter: Chapter?) {

View File

@@ -11,9 +11,13 @@ import cafe.adriel.voyager.core.model.screenModelScope
import eu.kanade.core.preference.asState
import eu.kanade.core.util.addOrRemove
import eu.kanade.core.util.insertSeparators
import eu.kanade.domain.chapter.interactor.GetAvailableScanlators
import eu.kanade.domain.chapter.interactor.SetReadStatus
import eu.kanade.domain.chapter.interactor.SyncChaptersWithSource
import eu.kanade.domain.manga.interactor.GetExcludedScanlators
import eu.kanade.domain.manga.interactor.SetExcludedScanlators
import eu.kanade.domain.manga.interactor.UpdateManga
import eu.kanade.domain.manga.model.chaptersFiltered
import eu.kanade.domain.manga.model.downloadedFilter
import eu.kanade.domain.manga.model.toSManga
import eu.kanade.domain.track.interactor.AddTracks
@@ -92,6 +96,9 @@ class MangaScreenModel(
private val downloadCache: DownloadCache = Injekt.get(),
private val getMangaAndChapters: GetMangaWithChapters = Injekt.get(),
private val getDuplicateLibraryManga: GetDuplicateLibraryManga = Injekt.get(),
private val getAvailableScanlators: GetAvailableScanlators = Injekt.get(),
private val getExcludedScanlators: GetExcludedScanlators = Injekt.get(),
private val setExcludedScanlators: SetExcludedScanlators = Injekt.get(),
private val setMangaChapterFlags: SetMangaChapterFlags = Injekt.get(),
private val setMangaDefaultChapterFlags: SetMangaDefaultChapterFlags = Injekt.get(),
private val setReadStatus: SetReadStatus = Injekt.get(),
@@ -154,7 +161,7 @@ class MangaScreenModel(
init {
screenModelScope.launchIO {
combine(
getMangaAndChapters.subscribe(mangaId).distinctUntilChanged(),
getMangaAndChapters.subscribe(mangaId, applyScanlatorFilter = true).distinctUntilChanged(),
downloadCache.changes,
downloadManager.queueState,
) { mangaAndChapters, _, _ -> mangaAndChapters }
@@ -168,11 +175,31 @@ class MangaScreenModel(
}
}
screenModelScope.launchIO {
getExcludedScanlators.subscribe(mangaId)
.distinctUntilChanged()
.collectLatest { excludedScanlators ->
updateSuccessState {
it.copy(excludedScanlators = excludedScanlators)
}
}
}
screenModelScope.launchIO {
getAvailableScanlators.subscribe(mangaId)
.distinctUntilChanged()
.collectLatest { availableScanlators ->
updateSuccessState {
it.copy(availableScanlators = availableScanlators)
}
}
}
observeDownloads()
screenModelScope.launchIO {
val manga = getMangaAndChapters.awaitManga(mangaId)
val chapters = getMangaAndChapters.awaitChapters(mangaId)
val chapters = getMangaAndChapters.awaitChapters(mangaId, applyScanlatorFilter = true)
.toChapterListItems(manga)
if (!manga.favorite) {
@@ -189,6 +216,8 @@ class MangaScreenModel(
source = Injekt.get<SourceManager>().getOrStub(manga.source),
isFromSource = isFromSource,
chapters = chapters,
availableScanlators = getAvailableScanlators.await(mangaId),
excludedScanlators = getExcludedScanlators.await(mangaId),
isRefreshingData = needRefreshInfo || needRefreshChapter,
dialog = null,
)
@@ -995,6 +1024,12 @@ class MangaScreenModel(
updateSuccessState { it.copy(dialog = Dialog.FullCover) }
}
fun setExcludedScanlators(excludedScanlators: Set<String>) {
screenModelScope.launchIO {
setExcludedScanlators.await(mangaId, excludedScanlators)
}
}
sealed interface State {
@Immutable
data object Loading : State
@@ -1005,12 +1040,13 @@ class MangaScreenModel(
val source: Source,
val isFromSource: Boolean,
val chapters: List<ChapterList.Item>,
val availableScanlators: Set<String>,
val excludedScanlators: Set<String>,
val trackItems: List<TrackItem> = emptyList(),
val isRefreshingData: Boolean = false,
val dialog: Dialog? = null,
val hasPromptedToAddBefore: Boolean = false,
) : State {
val processedChapters by lazy {
chapters.applyFilters(manga).toList()
}
@@ -1042,6 +1078,12 @@ class MangaScreenModel(
}
}
val scanlatorFilterActive: Boolean
get() = excludedScanlators.intersect(availableScanlators).isNotEmpty()
val filterActive: Boolean
get() = scanlatorFilterActive || manga.chaptersFiltered()
val trackingAvailable: Boolean
get() = trackItems.isNotEmpty()

View File

@@ -147,7 +147,7 @@ class ReaderViewModel @JvmOverloads constructor(
*/
private val chapterList by lazy {
val manga = manga!!
val chapters = runBlocking { getChaptersByMangaId.await(manga.id) }
val chapters = runBlocking { getChaptersByMangaId.await(manga.id, applyScanlatorFilter = true) }
val selectedChapter = chapters.find { it.id == chapterId }
?: error("Requested chapter of id $chapterId not found in chapter list")