diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaController.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaController.kt index 0c231cca8..54186e462 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaController.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaController.kt @@ -547,6 +547,7 @@ class MangaController : if (mainSource is MetadataSource<*, *>) { presenter.meta = flatMetadata.raise(mainSource.metaClass) mangaMetaInfoAdapter?.notifyDataSetChanged() + updateFilterIconState() } } // SY <-- diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaPresenter.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaPresenter.kt index 0596ad69c..fd5e204a2 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaPresenter.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaPresenter.kt @@ -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() var dedupe: Boolean = true + + var allChapterScanlators: Set = 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) { + 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. diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/chapter/ChaptersSettingsSheet.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/chapter/ChaptersSettingsSheet.kt index b1bdce8d1..3b2fa8152 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/chapter/ChaptersSettingsSheet.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/chapter/ChaptersSettingsSheet.kt @@ -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 diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderPresenter.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderPresenter.kt index e853bcada..2e7268eb2 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderPresenter.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderPresenter.kt @@ -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() diff --git a/app/src/main/java/exh/md/utils/MdUtil.kt b/app/src/main/java/exh/md/utils/MdUtil.kt index 5aea911b1..5d77f8f5f 100644 --- a/app/src/main/java/exh/md/utils/MdUtil.kt +++ b/app/src/main/java/exh/md/utils/MdUtil.kt @@ -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 { + return this.scanlator?.let { + MdUtil.getScanlators(it) + } ?: listOf("No scanlator") +} diff --git a/app/src/main/java/exh/metadata/metadata/base/RaisedSearchMetadata.kt b/app/src/main/java/exh/metadata/metadata/base/RaisedSearchMetadata.kt index 85282a4a4..57515abcb 100644 --- a/app/src/main/java/exh/metadata/metadata/base/RaisedSearchMetadata.kt +++ b/app/src/main/java/exh/metadata/metadata/base/RaisedSearchMetadata.kt @@ -46,6 +46,8 @@ abstract class RaisedSearchMetadata { @Transient val titles = mutableListOf() + var filteredScanlators: String? = null + fun getTitleOfType(type: Int): String? = titles.find { it.type == type }?.title fun replaceTitleOfType(type: Int, newTitle: String?) { diff --git a/app/src/main/res/values/strings_sy.xml b/app/src/main/res/values/strings_sy.xml index f0f2f8fd8..2d9470001 100644 --- a/app/src/main/res/values/strings_sy.xml +++ b/app/src/main/res/values/strings_sy.xml @@ -567,4 +567,10 @@ Syncs any non MdList tracked manga to MangaDex as reading. Pushed %d manga to MangaDex + + + Scanlator groups to show + Metadata corrupted, please refresh the manga + No scanlators available +