Filter scanlators on delegated manga
This commit is contained in:
parent
32232c80aa
commit
e9cef78d19
@ -547,6 +547,7 @@ class MangaController :
|
||||
if (mainSource is MetadataSource<*, *>) {
|
||||
presenter.meta = flatMetadata.raise(mainSource.metaClass)
|
||||
mangaMetaInfoAdapter?.notifyDataSetChanged()
|
||||
updateFilterIconState()
|
||||
}
|
||||
}
|
||||
// SY <--
|
||||
|
@ -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.
|
||||
|
@ -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
|
||||
|
@ -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>()
|
||||
|
@ -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")
|
||||
}
|
||||
|
@ -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?) {
|
||||
|
@ -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>
|
||||
|
Loading…
x
Reference in New Issue
Block a user