From f062baf909f10166c1022959764b868ae657ee2f Mon Sep 17 00:00:00 2001 From: Seishirou101 <57241064+Seishirou101@users.noreply.github.com> Date: Fri, 24 Sep 2021 04:49:02 +0000 Subject: [PATCH] add scanlation filter (#1006) * add scanlation filter * add hide logic and remove sql cmd * add suggested fixes * use button colored instead * move filter scanlation code to getChaptersSorted * invert scanlation filter and remove strings * fix ChapterSort issue and add filter logic to getNextUnreadChapter * remove log import * filter chapterlist in reader presenter * make new method and replace logic * add missed comma * add suggested improvements * add missed suggestion --- .../tachiyomi/data/database/DbOpenCallback.kt | 5 ++- .../data/database/mappers/MangaTypeMapping.kt | 3 ++ .../tachiyomi/data/database/models/Manga.kt | 2 ++ .../data/database/models/MangaImpl.kt | 2 ++ .../data/database/queries/MangaQueries.kt | 6 ++++ .../MangaFilteredScanlatorsPutResolver.kt | 31 ++++++++++++++++++ .../data/database/tables/MangaTable.kt | 8 ++++- .../ui/manga/MangaDetailsPresenter.kt | 11 +++++-- .../manga/chapter/ChaptersSortBottomSheet.kt | 32 +++++++++++++++++++ .../tachiyomi/util/chapter/ChapterFilter.kt | 19 ++++++++--- .../tachiyomi/util/chapter/ChapterSort.kt | 3 +- .../tachiyomi/util/chapter/ChapterUtil.kt | 11 +++++++ .../res/layout/chapter_sort_bottom_sheet.xml | 15 ++++++++- app/src/main/res/values/strings.xml | 1 + 14 files changed, 138 insertions(+), 11 deletions(-) create mode 100644 app/src/main/java/eu/kanade/tachiyomi/data/database/resolvers/MangaFilteredScanlatorsPutResolver.kt diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/database/DbOpenCallback.kt b/app/src/main/java/eu/kanade/tachiyomi/data/database/DbOpenCallback.kt index 5bbf4b7d2e..684c12a9ea 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/database/DbOpenCallback.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/database/DbOpenCallback.kt @@ -20,7 +20,7 @@ class DbOpenCallback : SupportSQLiteOpenHelper.Callback(DATABASE_VERSION) { /** * Version of the database. */ - const val DATABASE_VERSION = 13 + const val DATABASE_VERSION = 14 } override fun onCreate(db: SupportSQLiteDatabase) = with(db) { @@ -87,6 +87,9 @@ class DbOpenCallback : SupportSQLiteOpenHelper.Callback(DATABASE_VERSION) { db.execSQL(TrackTable.addStartDate) db.execSQL(TrackTable.addFinishDate) } + if (oldVersion < 14) { + db.execSQL(MangaTable.addFilteredScanlators) + } } override fun onConfigure(db: SupportSQLiteDatabase) { diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/database/mappers/MangaTypeMapping.kt b/app/src/main/java/eu/kanade/tachiyomi/data/database/mappers/MangaTypeMapping.kt index d5b933460e..956ea3eb62 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/database/mappers/MangaTypeMapping.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/database/mappers/MangaTypeMapping.kt @@ -17,6 +17,7 @@ import eu.kanade.tachiyomi.data.database.tables.MangaTable.COL_CHAPTER_FLAGS import eu.kanade.tachiyomi.data.database.tables.MangaTable.COL_DATE_ADDED import eu.kanade.tachiyomi.data.database.tables.MangaTable.COL_DESCRIPTION import eu.kanade.tachiyomi.data.database.tables.MangaTable.COL_FAVORITE +import eu.kanade.tachiyomi.data.database.tables.MangaTable.COL_FILTERED_SCANLATORS import eu.kanade.tachiyomi.data.database.tables.MangaTable.COL_GENRE import eu.kanade.tachiyomi.data.database.tables.MangaTable.COL_HIDE_TITLE import eu.kanade.tachiyomi.data.database.tables.MangaTable.COL_ID @@ -66,6 +67,7 @@ class MangaPutResolver : DefaultPutResolver() { put(COL_HIDE_TITLE, obj.hide_title) put(COL_CHAPTER_FLAGS, obj.chapter_flags) put(COL_DATE_ADDED, obj.date_added) + put(COL_FILTERED_SCANLATORS, obj.filtered_scanlators) } } @@ -88,6 +90,7 @@ interface BaseMangaGetResolver { chapter_flags = cursor.getInt(cursor.getColumnIndex(COL_CHAPTER_FLAGS)) hide_title = cursor.getInt(cursor.getColumnIndex(COL_HIDE_TITLE)) == 1 date_added = cursor.getLong(cursor.getColumnIndex(COL_DATE_ADDED)) + filtered_scanlators = cursor.getString(cursor.getColumnIndex(COL_FILTERED_SCANLATORS)) } } diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/database/models/Manga.kt b/app/src/main/java/eu/kanade/tachiyomi/data/database/models/Manga.kt index 577e428237..eb8b34c856 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/database/models/Manga.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/database/models/Manga.kt @@ -31,6 +31,8 @@ interface Manga : SManga { var hide_title: Boolean + var filtered_scanlators: String? + fun isBlank() = id == Long.MIN_VALUE fun isHidden() = status == -1 diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/database/models/MangaImpl.kt b/app/src/main/java/eu/kanade/tachiyomi/data/database/models/MangaImpl.kt index 932ce0a4d3..aad63cd3a9 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/database/models/MangaImpl.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/database/models/MangaImpl.kt @@ -64,6 +64,8 @@ open class MangaImpl : Manga { override var date_added: Long = 0 + override var filtered_scanlators: String? = null + lateinit var ogTitle: String private set var ogAuthor: String? = null diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/database/queries/MangaQueries.kt b/app/src/main/java/eu/kanade/tachiyomi/data/database/queries/MangaQueries.kt index 440dc5edd7..f3a82f78f7 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/database/queries/MangaQueries.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/database/queries/MangaQueries.kt @@ -9,6 +9,7 @@ import eu.kanade.tachiyomi.data.database.models.Manga import eu.kanade.tachiyomi.data.database.resolvers.LibraryMangaGetResolver import eu.kanade.tachiyomi.data.database.resolvers.MangaDateAddedPutResolver import eu.kanade.tachiyomi.data.database.resolvers.MangaFavoritePutResolver +import eu.kanade.tachiyomi.data.database.resolvers.MangaFilteredScanlatorsPutResolver import eu.kanade.tachiyomi.data.database.resolvers.MangaFlagsPutResolver import eu.kanade.tachiyomi.data.database.resolvers.MangaInfoPutResolver import eu.kanade.tachiyomi.data.database.resolvers.MangaLastUpdatedPutResolver @@ -167,4 +168,9 @@ interface MangaQueries : DbProvider { fun getTotalChapterManga() = db.get().listOfObjects(Manga::class.java) .withQuery(RawQuery.builder().query(getTotalChapterMangaQuery()).observesTables(MangaTable.TABLE).build()).prepare() + + fun updateMangaFilteredScanlators(manga: Manga) = db.put() + .`object`(manga) + .withPutResolver(MangaFilteredScanlatorsPutResolver()) + .prepare() } diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/database/resolvers/MangaFilteredScanlatorsPutResolver.kt b/app/src/main/java/eu/kanade/tachiyomi/data/database/resolvers/MangaFilteredScanlatorsPutResolver.kt new file mode 100644 index 0000000000..3c82ff9cec --- /dev/null +++ b/app/src/main/java/eu/kanade/tachiyomi/data/database/resolvers/MangaFilteredScanlatorsPutResolver.kt @@ -0,0 +1,31 @@ +package eu.kanade.tachiyomi.data.database.resolvers + +import androidx.core.content.contentValuesOf +import com.pushtorefresh.storio.sqlite.StorIOSQLite +import com.pushtorefresh.storio.sqlite.operations.put.PutResolver +import com.pushtorefresh.storio.sqlite.operations.put.PutResult +import com.pushtorefresh.storio.sqlite.queries.UpdateQuery +import eu.kanade.tachiyomi.data.database.inTransactionReturn +import eu.kanade.tachiyomi.data.database.models.Manga +import eu.kanade.tachiyomi.data.database.tables.MangaTable + +class MangaFilteredScanlatorsPutResolver : PutResolver() { + + override fun performPut(db: StorIOSQLite, manga: Manga) = db.inTransactionReturn { + val updateQuery = mapToUpdateQuery(manga) + val contentValues = mapToContentValues(manga) + + val numberOfRowsUpdated = db.lowLevel().update(updateQuery, contentValues) + PutResult.newUpdateResult(numberOfRowsUpdated, updateQuery.table()) + } + + fun mapToUpdateQuery(manga: Manga) = UpdateQuery.builder() + .table(MangaTable.TABLE) + .where("${MangaTable.COL_ID} = ?") + .whereArgs(manga.id) + .build() + + fun mapToContentValues(manga: Manga) = contentValuesOf( + MangaTable.COL_FILTERED_SCANLATORS to manga.filtered_scanlators + ) +} diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/database/tables/MangaTable.kt b/app/src/main/java/eu/kanade/tachiyomi/data/database/tables/MangaTable.kt index 1778dd8cb3..d14cbb5618 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/database/tables/MangaTable.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/database/tables/MangaTable.kt @@ -44,6 +44,8 @@ object MangaTable { const val COL_DATE_ADDED = "date_added" + const val COL_FILTERED_SCANLATORS = "filtered_scanlators" + val createTableQuery: String get() = """CREATE TABLE $TABLE( @@ -63,7 +65,8 @@ object MangaTable { $COL_VIEWER INTEGER NOT NULL, $COL_HIDE_TITLE INTEGER NOT NULL, $COL_CHAPTER_FLAGS INTEGER NOT NULL, - $COL_DATE_ADDED LONG + $COL_DATE_ADDED LONG, + $COL_FILTERED_SCANLATORS TEXT )""" @@ -79,4 +82,7 @@ object MangaTable { val addDateAddedCol: String get() = "ALTER TABLE $TABLE ADD COLUMN $COL_DATE_ADDED LONG DEFAULT 0" + + val addFilteredScanlators: String + get() = "ALTER TABLE $TABLE ADD COLUMN $COL_FILTERED_SCANLATORS TEXT" } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaDetailsPresenter.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaDetailsPresenter.kt index a4f23bad39..4549151f6b 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaDetailsPresenter.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaDetailsPresenter.kt @@ -109,7 +109,7 @@ class MangaDetailsPresenter( var headerItem = MangaHeaderItem(manga, controller.fromCatalogue) var tabletChapterHeaderItem: MangaHeaderItem? = null - + var allChapterScanlators: Set = emptySet() fun onCreate() { headerItem.isTablet = controller.isTablet if (controller.isTablet) { @@ -158,7 +158,7 @@ class MangaDetailsPresenter( // Find downloaded chapters setDownloadedChapters(chapters) - + allChapterScanlators = chapters.flatMap { ChapterUtil.getScanlators(it.chapter.scanlator) }.toSet() // Store the last emission allChapters = chapters this.chapters = applyChapterFilters(chapters) @@ -629,6 +629,13 @@ class MangaDetailsPresenter( return filtersId.filterNotNull().joinToString(", ") { preferences.context.getString(it) } } + fun setScanlatorFilter(filteredScanlators: Set) { + val manga = manga + manga.filtered_scanlators = if (filteredScanlators.size == allChapterScanlators.size || filteredScanlators.isEmpty()) null else ChapterUtil.getScanlatorString(filteredScanlators) + db.updateMangaFilteredScanlators(manga).executeAsBlocking() + asyncUpdateMangaAndChapters() + } + fun toggleFavorite(): Boolean { manga.favorite = !manga.favorite diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/chapter/ChaptersSortBottomSheet.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/chapter/ChaptersSortBottomSheet.kt index 86f111bc25..a49cfc5516 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/chapter/ChaptersSortBottomSheet.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/chapter/ChaptersSortBottomSheet.kt @@ -4,10 +4,15 @@ import android.os.Bundle import android.view.LayoutInflater import android.view.View import androidx.core.view.isInvisible +import androidx.core.view.isVisible +import com.afollestad.materialdialogs.MaterialDialog +import com.afollestad.materialdialogs.list.listItemsMultiChoice import com.google.android.material.bottomsheet.BottomSheetBehavior +import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.data.database.models.Manga import eu.kanade.tachiyomi.databinding.ChapterSortBottomSheetBinding import eu.kanade.tachiyomi.ui.manga.MangaDetailsController +import eu.kanade.tachiyomi.util.chapter.ChapterUtil import eu.kanade.tachiyomi.util.system.dpToPx import eu.kanade.tachiyomi.util.view.setBottomEdge import eu.kanade.tachiyomi.widget.E2EBottomSheetDialog @@ -148,6 +153,33 @@ class ChaptersSortBottomSheet(controller: MangaDetailsController) : binding.chapterFilterLayout.setAsDefaultFilter.isInvisible = true binding.chapterFilterLayout.resetAsDefaultFilter.isInvisible = true } + binding.filterGroupsButton.isVisible = presenter.allChapterScanlators.isNotEmpty() + + binding.filterGroupsButton.setOnClickListener { + val scanlators = presenter.allChapterScanlators.toList() + val filteredScanlators = + presenter.manga.filtered_scanlators?.let { ChapterUtil.getScanlators(it) } + ?: scanlators.toSet() + val preselected = if (scanlators.size == filteredScanlators.size) { + IntArray(0) + } else { + filteredScanlators.map { scanlators.indexOf(it) }.toIntArray() + } + MaterialDialog(activity!!) + .listItemsMultiChoice( + items = scanlators, + initialSelection = preselected, + allowEmptySelection = true, + ) { _, selections, _ -> + val selected = selections.map { scanlators[it] }.toSet() + presenter.setScanlatorFilter(selected) + } + .negativeButton(R.string.reset) { + presenter.setScanlatorFilter(presenter.allChapterScanlators) + } + .positiveButton(R.string.filter) + .show() + } } private fun setFilters(filterLayout: ChapterFilterLayout) { diff --git a/app/src/main/java/eu/kanade/tachiyomi/util/chapter/ChapterFilter.kt b/app/src/main/java/eu/kanade/tachiyomi/util/chapter/ChapterFilter.kt index 73826642e0..156404ac08 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/util/chapter/ChapterFilter.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/util/chapter/ChapterFilter.kt @@ -19,8 +19,9 @@ class ChapterFilter(val preferences: PreferencesHelper = Injekt.get(), val downl val notBookmarkEnabled = manga.bookmarkedFilter(preferences) == Manga.CHAPTER_SHOW_NOT_BOOKMARKED // if none of the filters are enabled skip the filtering of them + val filteredChapters = filterChaptersByScanlators(chapters, manga) return if (readEnabled || unreadEnabled || downloadEnabled || notDownloadEnabled || bookmarkEnabled || notBookmarkEnabled) { - chapters.filter { + filteredChapters.filter { if (readEnabled && it.read.not() || (unreadEnabled && it.read) || (bookmarkEnabled && it.bookmark.not()) || @@ -33,25 +34,24 @@ class ChapterFilter(val preferences: PreferencesHelper = Injekt.get(), val downl return@filter true } } else { - chapters + filteredChapters } } // filter chapters for the reader fun filterChaptersForReader(chapters: List, manga: Manga, selectedChapter: T? = null): List { + var filteredChapters = filterChaptersByScanlators(chapters, manga) // if neither preference is enabled don't even filter if (!preferences.skipRead() && !preferences.skipFiltered()) { - return chapters + return filteredChapters } - var filteredChapters = chapters if (preferences.skipRead()) { filteredChapters = filteredChapters.filter { !it.read } } if (preferences.skipFiltered()) { filteredChapters = filterChapters(filteredChapters, manga) } - // add the selected chapter to the list in case it was filtered out if (selectedChapter?.id != null) { val find = filteredChapters.find { it.id == selectedChapter.id } @@ -61,6 +61,15 @@ class ChapterFilter(val preferences: PreferencesHelper = Injekt.get(), val downl filteredChapters = mutableList.toList() } } + return filteredChapters } + // filters chapters for scanlators + + fun filterChaptersByScanlators(chapters: List, manga: Manga): List { + return manga.filtered_scanlators?.let { filteredScanlatorString -> + val filteredScanlators = ChapterUtil.getScanlators(filteredScanlatorString) + chapters.filter { ChapterUtil.getScanlators(it.scanlator).none { group -> filteredScanlators.contains(group) } } + } ?: chapters + } } diff --git a/app/src/main/java/eu/kanade/tachiyomi/util/chapter/ChapterSort.kt b/app/src/main/java/eu/kanade/tachiyomi/util/chapter/ChapterSort.kt index ddb91d2773..555f5fe644 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/util/chapter/ChapterSort.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/util/chapter/ChapterSort.kt @@ -30,8 +30,9 @@ class ChapterSort(val manga: Manga, val chapterFilter: ChapterFilter = Injekt.ge fun getNextUnreadChapter(rawChapters: List, andFiltered: Boolean = true,): T? { val chapters = when { andFiltered -> chapterFilter.filterChapters(rawChapters, manga) - else -> rawChapters + else -> chapterFilter.filterChaptersByScanlators(rawChapters, manga) } + return chapters.sortedWith(sortComparator(true)).find { !it.read } } diff --git a/app/src/main/java/eu/kanade/tachiyomi/util/chapter/ChapterUtil.kt b/app/src/main/java/eu/kanade/tachiyomi/util/chapter/ChapterUtil.kt index d0429db5d9..ed3335ad81 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/util/chapter/ChapterUtil.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/util/chapter/ChapterUtil.kt @@ -140,5 +140,16 @@ class ChapterUtil { fun hasTensOfChapters(chapters: List): Boolean { return chapters.size > 20 } + + private const val scanlatorSeparator = " & " + + fun getScanlators(scanlators: String?): List { + if (scanlators.isNullOrBlank()) return emptyList() + return scanlators.split(scanlatorSeparator).distinct() + } + + fun getScanlatorString(scanlators: Set): String { + return scanlators.toList().sorted().joinToString(scanlatorSeparator) + } } } diff --git a/app/src/main/res/layout/chapter_sort_bottom_sheet.xml b/app/src/main/res/layout/chapter_sort_bottom_sheet.xml index 663d088b42..aa2bd3c089 100644 --- a/app/src/main/res/layout/chapter_sort_bottom_sheet.xml +++ b/app/src/main/res/layout/chapter_sort_bottom_sheet.xml @@ -88,12 +88,25 @@ android:layout_width="match_parent" android:layout_height="wrap_content" /> + + diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 4df30333a1..046a528e87 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -531,6 +531,7 @@ Error sharing cover Custom manga info Set as default + Filter scanlator groups A chapter has been removed from the source:\n%2$s\nDelete its download?