Filter scanlators on delegated manga

This commit is contained in:
Jobobby04 2020-10-25 20:24:30 -04:00
parent 32232c80aa
commit e9cef78d19
7 changed files with 128 additions and 10 deletions

View File

@ -547,6 +547,7 @@ class MangaController :
if (mainSource is MetadataSource<*, *>) {
presenter.meta = flatMetadata.raise(mainSource.metaClass)
mangaMetaInfoAdapter?.notifyDataSetChanged()
updateFilterIconState()
}
}
// SY <--

View File

@ -4,7 +4,6 @@ import android.content.Context
import android.net.Uri
import android.os.Bundle
import android.os.Environment
import com.elvishew.xlog.XLog
import com.jakewharton.rxrelay.BehaviorRelay
import com.jakewharton.rxrelay.PublishRelay
import eu.kanade.tachiyomi.R
@ -44,10 +43,13 @@ import exh.debug.DebugToggles
import exh.eh.EHentaiUpdateHelper
import exh.isEhBasedSource
import exh.md.utils.FollowStatus
import exh.md.utils.MdUtil
import exh.md.utils.scanlatorList
import exh.merged.sql.models.MergedMangaReference
import exh.metadata.metadata.base.FlatMetadata
import exh.metadata.metadata.base.RaisedSearchMetadata
import exh.metadata.metadata.base.getFlatMetadataForManga
import exh.metadata.metadata.base.insertFlatMetadata
import exh.source.EnhancedHttpSource.Companion.getMainSource
import exh.util.asObservable
import exh.util.await
@ -133,6 +135,8 @@ class MangaPresenter(
private var mergedManga = emptyList<Manga>()
var dedupe: Boolean = true
var allChapterScanlators: Set<String> = emptySet()
// EXH <--
override fun onCreate(savedState: Bundle?) {
@ -163,7 +167,14 @@ class MangaPresenter(
}
}
.subscribeLatestCache({ view, (manga, flatMetadata) ->
if (flatMetadata != null) view.onNextMetaInfo(flatMetadata) else XLog.d("Invalid metadata")
flatMetadata?.let { metadata ->
view.onNextMetaInfo(metadata)
meta?.let {
it.filteredScanlators?.let {
if (chapters.isNotEmpty()) chaptersRelay.call(chapters)
}
}
}
// SY <--
view.onNextMangaInfo(manga, source)
})
@ -193,6 +204,8 @@ class MangaPresenter(
// Find downloaded chapters
setDownloadedChapters(chapters)
allChapterScanlators = chapters.flatMap { it.chapter.scanlatorList() }.toSet()
// Store the last emission
this.chapters = chapters
@ -803,6 +816,15 @@ class MangaPresenter(
observable = observable.filter { !it.bookmark }
}
// SY -->
meta?.let { metadata ->
metadata.filteredScanlators?.let { filteredScanlatorString ->
val filteredScanlators = MdUtil.getScanlators(filteredScanlatorString)
observable = observable.filter { it.scanlatorList().any { group -> filteredScanlators.contains(group) } }
}
}
// SY <--
val sortFunction: (Chapter, Chapter) -> Int = when (manga.sorting) {
Manga.SORTING_SOURCE -> when (sortDescending()) {
true -> { c1, c2 -> c1.source_order.compareTo(c2.source_order) }
@ -994,6 +1016,17 @@ class MangaPresenter(
refreshChapters()
}
// SY -->
fun setScanlatorFilter(filteredScanlators: Set<String>) {
val meta = meta ?: return
meta.filteredScanlators = if (filteredScanlators.size == allChapterScanlators.size) null else MdUtil.getScanlatorString(filteredScanlators)
meta.flatten().let {
db.insertFlatMetadata(it).await()
}
refreshChapters()
}
// SY <--
/**
* Sets the active display mode.
* @param mode the mode to set.

View File

@ -4,14 +4,21 @@ import android.content.Context
import android.util.AttributeSet
import android.view.View
import androidx.core.view.isVisible
import com.afollestad.materialdialogs.MaterialDialog
import com.afollestad.materialdialogs.list.listItemsMultiChoice
import com.bluelinelabs.conductor.Router
import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.data.database.models.Manga
import eu.kanade.tachiyomi.source.online.MetadataSource
import eu.kanade.tachiyomi.ui.manga.MangaPresenter
import eu.kanade.tachiyomi.util.system.toast
import eu.kanade.tachiyomi.util.view.popupMenu
import eu.kanade.tachiyomi.widget.ExtendedNavigationView
import eu.kanade.tachiyomi.widget.ExtendedNavigationView.Item.TriStateGroup.State
import eu.kanade.tachiyomi.widget.TabbedBottomSheetDialog
import exh.md.utils.MdUtil
import exh.metadata.metadata.MangaDexSearchMetadata
import exh.source.EnhancedHttpSource.Companion.getMainSource
class ChaptersSettingsSheet(
private val router: Router,
@ -82,7 +89,7 @@ class ChaptersSettingsSheet(
* Returns true if there's at least one filter from [FilterGroup] active.
*/
fun hasActiveFilters(): Boolean {
return filterGroup.items.any { it.state != State.IGNORE.value }
return filterGroup.items.any { it.state != State.IGNORE.value } || (presenter.meta?.let { it is MangaDexSearchMetadata && it.filteredScanlators != null } ?: false)
}
inner class FilterGroup : Group {
@ -91,8 +98,10 @@ class ChaptersSettingsSheet(
private val unread = Item.TriStateGroup(R.string.action_filter_unread, this)
private val bookmarked = Item.TriStateGroup(R.string.action_filter_bookmarked, this)
private val scanlatorFilters = Item.DrawableSelection(0, this, R.string.scanlator, R.drawable.ic_outline_people_alt_24dp)
override val header = null
override val items = listOf(downloaded, unread, bookmarked)
override val items = listOf(downloaded, unread, bookmarked) + if (presenter.source.getMainSource() is MetadataSource<*, *>) listOf(scanlatorFilters) else emptyList()
override val footer = null
override fun initModels() {
@ -107,6 +116,34 @@ class ChaptersSettingsSheet(
}
override fun onItemClicked(item: Item) {
if (item is Item.DrawableSelection) {
val meta = presenter.meta
if (meta == null) {
context.toast(R.string.metadata_corrupted)
return
} else if (presenter.allChapterScanlators.isEmpty()) {
context.toast(R.string.no_scanlators)
return
}
val scanlators = presenter.allChapterScanlators.toList()
val filteredScanlators = meta.filteredScanlators?.let { MdUtil.getScanlators(it) }
val preselected = if (filteredScanlators.isNullOrEmpty()) scanlators.mapIndexed { index, _ -> index }.toIntArray() else filteredScanlators.map { scanlators.indexOf(it) }.toIntArray()
MaterialDialog(context)
.title(R.string.select_scanlators)
.listItemsMultiChoice(items = presenter.allChapterScanlators.toList(), initialSelection = preselected) { _, selections, _ ->
val selected = selections.map { scanlators[it] }.toSet()
presenter.setScanlatorFilter(selected)
onGroupClicked(this)
}
.negativeButton(R.string.action_reset) {
presenter.setScanlatorFilter(presenter.allChapterScanlators)
onGroupClicked(this)
}
.positiveButton(android.R.string.ok)
.show()
return
}
item as Item.TriStateGroup
val newState = when (item.state) {
State.IGNORE.value -> State.INCLUDE

View File

@ -17,6 +17,7 @@ import eu.kanade.tachiyomi.data.track.TrackManager
import eu.kanade.tachiyomi.source.LocalSource
import eu.kanade.tachiyomi.source.SourceManager
import eu.kanade.tachiyomi.source.model.Page
import eu.kanade.tachiyomi.source.online.MetadataSource
import eu.kanade.tachiyomi.source.online.all.MergedSource
import eu.kanade.tachiyomi.ui.base.presenter.BasePresenter
import eu.kanade.tachiyomi.ui.reader.chapter.ReaderChapterItem
@ -35,6 +36,11 @@ import exh.EH_SOURCE_ID
import exh.EXH_SOURCE_ID
import exh.MERGED_SOURCE_ID
import exh.md.utils.FollowStatus
import exh.md.utils.MdUtil
import exh.md.utils.scanlatorList
import exh.metadata.metadata.base.RaisedSearchMetadata
import exh.metadata.metadata.base.getFlatMetadataForManga
import exh.source.EnhancedHttpSource.Companion.getMainSource
import exh.util.awaitSingleOrNull
import exh.util.defaultReaderType
import exh.util.shouldDeleteChapters
@ -72,6 +78,11 @@ class ReaderPresenter(
var manga: Manga? = null
private set
// SY -->
var meta: RaisedSearchMetadata? = null
private set
// SY <--
/**
* The chapter id of the currently loaded chapter. Used to restore from process kill.
*/
@ -103,7 +114,11 @@ class ReaderPresenter(
*/
private val chapterList by lazy {
val manga = manga!!
val dbChapters = if (manga.source == MERGED_SOURCE_ID) runBlocking { (sourceManager.get(MERGED_SOURCE_ID) as? MergedSource)?.getChaptersFromDB(manga)?.awaitSingleOrNull() ?: emptyList() } else db.getChapters(manga).executeAsBlocking()
// SY -->
val meta = meta
val filteredScanlators = MdUtil.getScanlators(meta?.filteredScanlators.orEmpty())
// SY <--
val dbChapters = /* SY --> */if (manga.source == MERGED_SOURCE_ID) runBlocking { (sourceManager.get(MERGED_SOURCE_ID) as? MergedSource)?.getChaptersFromDB(manga)?.awaitSingleOrNull() ?: emptyList() } else /* SY <-- */ db.getChapters(manga).executeAsBlocking()
val selectedChapter = dbChapters.find { it.id == chapterId }
?: error("Requested chapter of id $chapterId not found in chapter list")
@ -122,7 +137,10 @@ class ReaderPresenter(
manga.downloadedFilter == Manga.SHOW_DOWNLOADED &&
!downloadManager.isChapterDownloaded(it, manga)
) ||
(manga.bookmarkedFilter == Manga.SHOW_BOOKMARKED && !it.bookmark)
(manga.bookmarkedFilter == Manga.SHOW_BOOKMARKED && !it.bookmark) ||
// SY -->
(meta != null && it.scanlatorList().none { group -> filteredScanlators.contains(group) })
// SY <--
) {
return@filter false
}
@ -221,7 +239,19 @@ class ReaderPresenter(
db.getManga(mangaId).asRxObservable()
.first()
.observeOn(AndroidSchedulers.mainThread())
.doOnNext { init(it, initialChapterId) }
// SY -->
.flatMap { manga ->
val source = sourceManager.get(manga.source)?.getMainSource()
if (manga.initialized && source is MetadataSource<*, *>) {
db.getFlatMetadataForManga(mangaId).asRxSingle().map {
manga to it?.raise(source.metaClass)
}.toObservable()
} else {
Observable.just(manga to null)
}
}
.doOnNext { init(it.first, initialChapterId, it.second) }
// SY <--
.subscribeFirst(
{ _, _ ->
// Ignore onNext event
@ -234,10 +264,13 @@ class ReaderPresenter(
* Initializes this presenter with the given [manga] and [initialChapterId]. This method will
* set the chapter loader, view subscriptions and trigger an initial load.
*/
private fun init(manga: Manga, initialChapterId: Long) {
private fun init(manga: Manga, initialChapterId: Long /* SY --> */, metadata: RaisedSearchMetadata?/* SY <-- */) {
if (!needsInit()) return
this.manga = manga
// SY -->
this.meta = metadata
// SY <--
if (chapterId == -1L) chapterId = initialChapterId
val context = Injekt.get<Application>()

View File

@ -1,5 +1,6 @@
package exh.md.utils
import eu.kanade.tachiyomi.data.database.models.Chapter
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
import eu.kanade.tachiyomi.source.SourceManager
import eu.kanade.tachiyomi.source.model.SChapter
@ -37,8 +38,7 @@ class MdUtil {
prettyPrint = true
}
private const
val scanlatorSeparator = " & "
private const val scanlatorSeparator = " & "
val validOneShotFinalChapters = listOf("0", "1")
@ -276,3 +276,9 @@ private fun getMDUrlWithoutDomain(orig: String): String {
orig
}
}
fun Chapter.scanlatorList(): List<String> {
return this.scanlator?.let {
MdUtil.getScanlators(it)
} ?: listOf("No scanlator")
}

View File

@ -46,6 +46,8 @@ abstract class RaisedSearchMetadata {
@Transient
val titles = mutableListOf<RaisedTitle>()
var filteredScanlators: String? = null
fun getTitleOfType(type: Int): String? = titles.find { it.type == type }?.title
fun replaceTitleOfType(type: Int, newTitle: String?) {

View File

@ -567,4 +567,10 @@
<string name="mangadex_push_favorites_to_mangadex_summary">Syncs any non MdList tracked manga to MangaDex as reading.</string>
<string name="mangadex_push_favorites_to_mangadex_toast">Pushed %d manga to MangaDex</string>
<!-- Scanlator filters -->
<string name="select_scanlators">Scanlator groups to show</string>
<string name="metadata_corrupted">Metadata corrupted, please refresh the manga</string>
<string name="no_scanlators">No scanlators available</string>
</resources>