mirror of
https://github.com/tachiyomiorg/tachiyomi.git
synced 2024-12-23 12:11:49 +01:00
Use the same logic in the mangadetails filter as the reader filter (#543)
* use the same chapter filter for the mangadetails and the reader presenter page * removed unused class * move volume detection logic to chapter utils
This commit is contained in:
parent
813a3c6e68
commit
7372109520
@ -12,6 +12,7 @@ import eu.kanade.tachiyomi.data.track.TrackManager
|
||||
import eu.kanade.tachiyomi.extension.ExtensionManager
|
||||
import eu.kanade.tachiyomi.network.NetworkHelper
|
||||
import eu.kanade.tachiyomi.source.SourceManager
|
||||
import eu.kanade.tachiyomi.util.chapter.ChapterFilter
|
||||
import kotlinx.coroutines.GlobalScope
|
||||
import kotlinx.coroutines.launch
|
||||
import uy.kohesive.injekt.api.InjektModule
|
||||
@ -48,6 +49,8 @@ class AppModule(val app: Application) : InjektModule {
|
||||
|
||||
addSingletonFactory { Gson() }
|
||||
|
||||
addSingletonFactory { ChapterFilter() }
|
||||
|
||||
// Asynchronously init expensive components for a faster cold start
|
||||
|
||||
GlobalScope.launch { get<PreferencesHelper>() }
|
||||
|
@ -7,6 +7,7 @@ import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
||||
import eu.kanade.tachiyomi.ui.manga.chapter.BaseChapterAdapter
|
||||
import eu.kanade.tachiyomi.ui.manga.chapter.ChapterItem
|
||||
import eu.kanade.tachiyomi.util.chapter.ChapterUtil
|
||||
import uy.kohesive.injekt.injectLazy
|
||||
import java.text.DecimalFormat
|
||||
import java.text.DecimalFormatSymbols
|
||||
@ -26,7 +27,7 @@ class MangaDetailsAdapter(
|
||||
val presenter = controller.presenter
|
||||
|
||||
val decimalFormat = DecimalFormat("#.###", DecimalFormatSymbols()
|
||||
.apply { decimalSeparator = '.' })
|
||||
.apply { decimalSeparator = '.' })
|
||||
|
||||
fun setChapters(items: List<ChapterItem>?) {
|
||||
this.items = items ?: emptyList()
|
||||
@ -46,8 +47,10 @@ class MangaDetailsAdapter(
|
||||
if (s.isNullOrBlank()) {
|
||||
updateDataSet(items)
|
||||
} else {
|
||||
updateDataSet(items.filter { it.name.contains(s, true) ||
|
||||
it.scanlator?.contains(s, true) == true })
|
||||
updateDataSet(items.filter {
|
||||
it.name.contains(s, true) ||
|
||||
it.scanlator?.contains(s, true) == true
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@ -64,7 +67,7 @@ class MangaDetailsAdapter(
|
||||
getItem(position) as? ChapterItem ?: return recyclerView.context.getString(R.string.top)
|
||||
return when (val scrollType = presenter.scrollType) {
|
||||
MangaDetailsPresenter.MULTIPLE_VOLUMES, MangaDetailsPresenter.MULTIPLE_SEASONS -> {
|
||||
val volume = presenter.getGroupNumber(chapter)
|
||||
val volume = ChapterUtil.getGroupNumber(chapter)
|
||||
if (volume != null) {
|
||||
recyclerView.context.getString(
|
||||
if (scrollType == MangaDetailsPresenter.MULTIPLE_SEASONS) R.string.season_
|
||||
|
@ -30,6 +30,8 @@ import eu.kanade.tachiyomi.source.model.SChapter
|
||||
import eu.kanade.tachiyomi.ui.manga.chapter.ChapterItem
|
||||
import eu.kanade.tachiyomi.ui.manga.track.TrackItem
|
||||
import eu.kanade.tachiyomi.ui.security.SecureActivityDelegate
|
||||
import eu.kanade.tachiyomi.util.chapter.ChapterFilter
|
||||
import eu.kanade.tachiyomi.util.chapter.ChapterUtil
|
||||
import eu.kanade.tachiyomi.util.chapter.syncChaptersWithSource
|
||||
import eu.kanade.tachiyomi.util.lang.trimOrNull
|
||||
import eu.kanade.tachiyomi.util.storage.DiskUtil
|
||||
@ -57,7 +59,8 @@ class MangaDetailsPresenter(
|
||||
val preferences: PreferencesHelper = Injekt.get(),
|
||||
val coverCache: CoverCache = Injekt.get(),
|
||||
private val db: DatabaseHelper = Injekt.get(),
|
||||
private val downloadManager: DownloadManager = Injekt.get()
|
||||
private val downloadManager: DownloadManager = Injekt.get(),
|
||||
private val chapterFilter: ChapterFilter = Injekt.get()
|
||||
) : DownloadQueue.DownloadListener, LibraryServiceListener {
|
||||
|
||||
private var scope = CoroutineScope(Job() + Dispatchers.Default)
|
||||
@ -68,8 +71,6 @@ class MangaDetailsPresenter(
|
||||
var hasRequested = false
|
||||
var isLoading = false
|
||||
var scrollType = 0
|
||||
private val volumeRegex = Regex("""(vol|volume)\.? *([0-9]+)?""", RegexOption.IGNORE_CASE)
|
||||
private val seasonRegex = Regex("""(Season |S)([0-9]+)?""")
|
||||
|
||||
private val loggedServices by lazy { Injekt.get<TrackManager>().services.filter { it.isLogged } }
|
||||
private var tracks = emptyList<Track>()
|
||||
@ -199,26 +200,6 @@ class MangaDetailsPresenter(
|
||||
controller.refreshAdapter()
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether the display only downloaded filter is enabled.
|
||||
*/
|
||||
fun onlyDownloaded() = manga.downloadedFilter == Manga.SHOW_DOWNLOADED
|
||||
|
||||
/**
|
||||
* Whether the display only downloaded filter is enabled.
|
||||
*/
|
||||
fun onlyBookmarked() = manga.bookmarkedFilter == Manga.SHOW_BOOKMARKED
|
||||
|
||||
/**
|
||||
* Whether the display only unread filter is enabled.
|
||||
*/
|
||||
fun onlyUnread() = manga.readFilter == Manga.SHOW_UNREAD
|
||||
|
||||
/**
|
||||
* Whether the display only read filter is enabled.
|
||||
*/
|
||||
fun onlyRead() = manga.readFilter == Manga.SHOW_READ
|
||||
|
||||
/**
|
||||
* Whether the sorting method is descending or ascending.
|
||||
*/
|
||||
@ -232,18 +213,9 @@ class MangaDetailsPresenter(
|
||||
private fun applyChapterFilters(chapterList: List<ChapterItem>): List<ChapterItem> {
|
||||
if (isLockedFromSearch)
|
||||
return chapterList
|
||||
var chapters = chapterList
|
||||
if (onlyUnread()) {
|
||||
chapters = chapters.filter { !it.read }
|
||||
} else if (onlyRead()) {
|
||||
chapters = chapters.filter { it.read }
|
||||
}
|
||||
if (onlyDownloaded()) {
|
||||
chapters = chapters.filter { it.isDownloaded || it.manga.source == LocalSource.ID }
|
||||
}
|
||||
if (onlyBookmarked()) {
|
||||
chapters = chapters.filter { it.bookmark }
|
||||
}
|
||||
|
||||
val chapters = chapterFilter.filterChapters(chapterList, manga) as List<ChapterItem>
|
||||
|
||||
val sortFunction: (Chapter, Chapter) -> Int = when (manga.sorting) {
|
||||
Manga.SORTING_SOURCE -> when (sortDescending()) {
|
||||
true -> { c1, c2 -> c1.source_order.compareTo(c2.source_order) }
|
||||
@ -255,68 +227,19 @@ class MangaDetailsPresenter(
|
||||
}
|
||||
else -> { c1, c2 -> c1.source_order.compareTo(c2.source_order) }
|
||||
}
|
||||
chapters = chapters.sortedWith(Comparator(sortFunction))
|
||||
getScrollType(chapters)
|
||||
return chapters
|
||||
return chapters.sortedWith(Comparator(sortFunction))
|
||||
}
|
||||
|
||||
private fun getScrollType(chapters: List<ChapterItem>) {
|
||||
scrollType = when {
|
||||
hasMultipleVolumes(chapters) -> MULTIPLE_VOLUMES
|
||||
hasMultipleSeasons(chapters) -> MULTIPLE_SEASONS
|
||||
hasTensOfChapters(chapters) -> TENS_OF_CHAPTERS
|
||||
ChapterUtil.hasMultipleVolumes(chapters) -> MULTIPLE_VOLUMES
|
||||
ChapterUtil.hasMultipleSeasons(chapters) -> MULTIPLE_SEASONS
|
||||
ChapterUtil.hasTensOfChapters(chapters) -> TENS_OF_CHAPTERS
|
||||
else -> 0
|
||||
}
|
||||
}
|
||||
|
||||
fun getGroupNumber(chapter: ChapterItem): Int? {
|
||||
val groups = volumeRegex.find(chapter.name)?.groups
|
||||
if (groups != null) return groups[2]?.value?.toIntOrNull()
|
||||
val seasonGroups = seasonRegex.find(chapter.name)?.groups
|
||||
if (seasonGroups != null) return seasonGroups[2]?.value?.toIntOrNull()
|
||||
return null
|
||||
}
|
||||
|
||||
private fun getVolumeNumber(chapter: ChapterItem): Int? {
|
||||
val groups = volumeRegex.find(chapter.name)?.groups
|
||||
if (groups != null) return groups[2]?.value?.toIntOrNull()
|
||||
return null
|
||||
}
|
||||
|
||||
private fun getSeasonNumber(chapter: ChapterItem): Int? {
|
||||
val groups = seasonRegex.find(chapter.name)?.groups
|
||||
if (groups != null) return groups[2]?.value?.toIntOrNull()
|
||||
return null
|
||||
}
|
||||
|
||||
private fun hasMultipleVolumes(chapters: List<ChapterItem>): Boolean {
|
||||
val volumeSet = mutableSetOf<Int>()
|
||||
chapters.forEach {
|
||||
val volNum = getVolumeNumber(it)
|
||||
if (volNum != null) {
|
||||
volumeSet.add(volNum)
|
||||
if (volumeSet.size >= 2) return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
private fun hasMultipleSeasons(chapters: List<ChapterItem>): Boolean {
|
||||
val volumeSet = mutableSetOf<Int>()
|
||||
chapters.forEach {
|
||||
val volNum = getSeasonNumber(it)
|
||||
if (volNum != null) {
|
||||
volumeSet.add(volNum)
|
||||
if (volumeSet.size >= 2) return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
private fun hasTensOfChapters(chapters: List<ChapterItem>): Boolean {
|
||||
return chapters.size > 20
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the next unread chapter or null if everything is read.
|
||||
*/
|
||||
@ -596,10 +519,10 @@ class MangaDetailsPresenter(
|
||||
|
||||
fun currentFilters(): String {
|
||||
val filtersId = mutableListOf<Int?>()
|
||||
filtersId.add(if (onlyRead()) R.string.read else null)
|
||||
filtersId.add(if (onlyUnread()) R.string.unread else null)
|
||||
filtersId.add(if (onlyDownloaded()) R.string.downloaded else null)
|
||||
filtersId.add(if (onlyBookmarked()) R.string.bookmarked else null)
|
||||
filtersId.add(if (manga.readFilter == Manga.SHOW_READ) R.string.read else null)
|
||||
filtersId.add(if (manga.readFilter == Manga.SHOW_UNREAD) R.string.unread else null)
|
||||
filtersId.add(if (manga.downloadedFilter == Manga.SHOW_DOWNLOADED) R.string.downloaded else null)
|
||||
filtersId.add(if (manga.bookmarkedFilter == Manga.SHOW_BOOKMARKED) R.string.bookmarked else null)
|
||||
return filtersId.filterNotNull().joinToString(", ") { preferences.context.getString(it) }
|
||||
}
|
||||
|
||||
|
@ -1,64 +0,0 @@
|
||||
package eu.kanade.tachiyomi.ui.reader
|
||||
|
||||
import eu.kanade.tachiyomi.data.database.models.Chapter
|
||||
import eu.kanade.tachiyomi.data.database.models.Manga
|
||||
import eu.kanade.tachiyomi.data.download.DownloadManager
|
||||
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
||||
|
||||
/**
|
||||
* This class filters chapters for the reader based on the user enabled preferences and filters
|
||||
*/
|
||||
class ReaderChapterFilter(
|
||||
private val downloadManager: DownloadManager,
|
||||
private val preferences: PreferencesHelper
|
||||
) {
|
||||
|
||||
fun filterChapter(
|
||||
dbChapters: List<Chapter>,
|
||||
manga: Manga,
|
||||
selectedChapter: Chapter? = null
|
||||
): List<Chapter> {
|
||||
|
||||
// if neither preference is enabled don't even filter
|
||||
if (!preferences.skipRead() && !preferences.skipFiltered()) {
|
||||
return dbChapters
|
||||
}
|
||||
|
||||
var filteredChapters = dbChapters
|
||||
if (preferences.skipRead()) {
|
||||
filteredChapters = filteredChapters.filter { !it.read }
|
||||
}
|
||||
if (preferences.skipFiltered()) {
|
||||
val readEnabled = manga.readFilter == Manga.SHOW_READ
|
||||
val unreadEnabled = manga.readFilter == Manga.SHOW_UNREAD
|
||||
val downloadEnabled = manga.downloadedFilter == Manga.SHOW_DOWNLOADED
|
||||
val bookmarkEnabled = manga.bookmarkedFilter == Manga.SHOW_BOOKMARKED
|
||||
|
||||
// if none of the filters are enabled skip the filtering of them
|
||||
if (readEnabled || unreadEnabled || downloadEnabled || bookmarkEnabled) {
|
||||
|
||||
filteredChapters = filteredChapters.filter {
|
||||
if (readEnabled && it.read.not() ||
|
||||
(unreadEnabled && it.read) ||
|
||||
(bookmarkEnabled && it.bookmark.not()) ||
|
||||
(downloadEnabled && downloadManager.isChapterDownloaded(it, manga).not())
|
||||
) {
|
||||
return@filter false
|
||||
}
|
||||
return@filter true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 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 }
|
||||
if (find == null) {
|
||||
val mutableList = filteredChapters.toMutableList()
|
||||
mutableList.add(selectedChapter)
|
||||
filteredChapters = mutableList.toList()
|
||||
}
|
||||
}
|
||||
return filteredChapters
|
||||
}
|
||||
}
|
@ -27,6 +27,7 @@ import eu.kanade.tachiyomi.ui.reader.loader.DownloadPageLoader
|
||||
import eu.kanade.tachiyomi.ui.reader.model.ReaderChapter
|
||||
import eu.kanade.tachiyomi.ui.reader.model.ReaderPage
|
||||
import eu.kanade.tachiyomi.ui.reader.model.ViewerChapters
|
||||
import eu.kanade.tachiyomi.util.chapter.ChapterFilter
|
||||
import eu.kanade.tachiyomi.util.storage.DiskUtil
|
||||
import eu.kanade.tachiyomi.util.system.ImageUtil
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
@ -53,11 +54,10 @@ class ReaderPresenter(
|
||||
private val sourceManager: SourceManager = Injekt.get(),
|
||||
private val downloadManager: DownloadManager = Injekt.get(),
|
||||
private val coverCache: CoverCache = Injekt.get(),
|
||||
private val preferences: PreferencesHelper = Injekt.get()
|
||||
private val preferences: PreferencesHelper = Injekt.get(),
|
||||
private val chapterFilter: ChapterFilter = Injekt.get()
|
||||
) : BasePresenter<ReaderActivity>() {
|
||||
|
||||
private val readerChapterFilter = ReaderChapterFilter(downloadManager, preferences)
|
||||
|
||||
/**
|
||||
* The manga loaded in the reader. It can be null when instantiated for a short time.
|
||||
*/
|
||||
@ -101,7 +101,7 @@ class ReaderPresenter(
|
||||
?: error("Requested chapter of id $chapterId not found in chapter list")
|
||||
|
||||
val chaptersForReader =
|
||||
readerChapterFilter.filterChapter(dbChapters, manga, selectedChapter)
|
||||
chapterFilter.filterChaptersForReader(dbChapters, manga, selectedChapter)
|
||||
|
||||
when (manga.sorting) {
|
||||
Manga.SORTING_SOURCE -> ChapterLoadBySource().get(chaptersForReader)
|
||||
@ -187,7 +187,7 @@ class ReaderPresenter(
|
||||
chapterItems = withContext(Dispatchers.IO) {
|
||||
val dbChapters = db.getChapters(manga).executeAsBlocking()
|
||||
val list =
|
||||
readerChapterFilter.filterChapter(dbChapters, manga, getCurrentChapter()?.chapter)
|
||||
chapterFilter.filterChaptersForReader(dbChapters, manga, getCurrentChapter()?.chapter)
|
||||
.sortedBy {
|
||||
when (manga.sorting) {
|
||||
Manga.SORTING_NUMBER -> it.chapter_number
|
||||
|
@ -0,0 +1,62 @@
|
||||
package eu.kanade.tachiyomi.util.chapter
|
||||
|
||||
import eu.kanade.tachiyomi.data.database.models.Chapter
|
||||
import eu.kanade.tachiyomi.data.database.models.Manga
|
||||
import eu.kanade.tachiyomi.data.download.DownloadManager
|
||||
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
||||
import uy.kohesive.injekt.Injekt
|
||||
import uy.kohesive.injekt.api.get
|
||||
|
||||
class ChapterFilter(val preferences: PreferencesHelper = Injekt.get(), val downloadManager: DownloadManager = Injekt.get()) {
|
||||
|
||||
// filters chapters based on the manga values
|
||||
fun filterChapters(chapters: List<Chapter>, manga: Manga): List<Chapter> {
|
||||
val readEnabled = manga.readFilter == Manga.SHOW_READ
|
||||
val unreadEnabled = manga.readFilter == Manga.SHOW_UNREAD
|
||||
val downloadEnabled = manga.downloadedFilter == Manga.SHOW_DOWNLOADED
|
||||
val bookmarkEnabled = manga.bookmarkedFilter == Manga.SHOW_BOOKMARKED
|
||||
|
||||
// if none of the filters are enabled skip the filtering of them
|
||||
return if (readEnabled || unreadEnabled || downloadEnabled || bookmarkEnabled) {
|
||||
chapters.filter {
|
||||
if (readEnabled && it.read.not() ||
|
||||
(unreadEnabled && it.read) ||
|
||||
(bookmarkEnabled && it.bookmark.not()) ||
|
||||
(downloadEnabled && downloadManager.isChapterDownloaded(it, manga).not())
|
||||
) {
|
||||
return@filter false
|
||||
}
|
||||
return@filter true
|
||||
}
|
||||
} else {
|
||||
chapters
|
||||
}
|
||||
}
|
||||
|
||||
// filter chapters for the reader
|
||||
fun filterChaptersForReader(chapters: List<Chapter>, manga: Manga, selectedChapter: Chapter? = null): List<Chapter> {
|
||||
// if neither preference is enabled don't even filter
|
||||
if (!preferences.skipRead() && !preferences.skipFiltered()) {
|
||||
return chapters
|
||||
}
|
||||
|
||||
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 }
|
||||
if (find == null) {
|
||||
val mutableList = filteredChapters.toMutableList()
|
||||
mutableList.add(selectedChapter)
|
||||
filteredChapters = mutableList.toList()
|
||||
}
|
||||
}
|
||||
return filteredChapters
|
||||
}
|
||||
}
|
@ -3,10 +3,10 @@ package eu.kanade.tachiyomi.util.chapter
|
||||
import android.content.Context
|
||||
import android.content.res.ColorStateList
|
||||
import android.widget.TextView
|
||||
import androidx.core.graphics.ColorUtils
|
||||
import androidx.vectordrawable.graphics.drawable.VectorDrawableCompat
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.data.database.models.Chapter
|
||||
import eu.kanade.tachiyomi.ui.manga.chapter.ChapterItem
|
||||
import eu.kanade.tachiyomi.util.system.contextCompatColor
|
||||
import eu.kanade.tachiyomi.util.system.dpToPx
|
||||
import eu.kanade.tachiyomi.util.system.dpToPxEnd
|
||||
@ -84,6 +84,55 @@ class ChapterUtil {
|
||||
|
||||
private fun bookmarkedColor(context: Context): Int = context.contextCompatColor(R.color.bookmarked_chapter)
|
||||
|
||||
private fun bookmarkedAndReadColor(context: Context): Int = ColorUtils.setAlphaComponent(context.contextCompatColor(R.color.bookmarked_chapter), 150)
|
||||
private val volumeRegex = Regex("""(vol|volume)\.? *([0-9]+)?""", RegexOption.IGNORE_CASE)
|
||||
private val seasonRegex = Regex("""(Season |S)([0-9]+)?""")
|
||||
|
||||
fun getGroupNumber(chapter: Chapter): Int? {
|
||||
val groups = volumeRegex.find(chapter.name)?.groups
|
||||
if (groups != null) return groups[2]?.value?.toIntOrNull()
|
||||
val seasonGroups = seasonRegex.find(chapter.name)?.groups
|
||||
if (seasonGroups != null) return seasonGroups[2]?.value?.toIntOrNull()
|
||||
return null
|
||||
}
|
||||
|
||||
private fun getVolumeNumber(chapter: Chapter): Int? {
|
||||
val groups = volumeRegex.find(chapter.name)?.groups
|
||||
if (groups != null) return groups[2]?.value?.toIntOrNull()
|
||||
return null
|
||||
}
|
||||
|
||||
private fun getSeasonNumber(chapter: Chapter): Int? {
|
||||
val groups = seasonRegex.find(chapter.name)?.groups
|
||||
if (groups != null) return groups[2]?.value?.toIntOrNull()
|
||||
return null
|
||||
}
|
||||
|
||||
fun hasMultipleVolumes(chapters: List<Chapter>): Boolean {
|
||||
val volumeSet = mutableSetOf<Int>()
|
||||
chapters.forEach {
|
||||
val volNum = getVolumeNumber(it)
|
||||
if (volNum != null) {
|
||||
volumeSet.add(volNum)
|
||||
if (volumeSet.size >= 2) return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
fun hasMultipleSeasons(chapters: List<Chapter>): Boolean {
|
||||
val volumeSet = mutableSetOf<Int>()
|
||||
chapters.forEach {
|
||||
val volNum = getSeasonNumber(it)
|
||||
if (volNum != null) {
|
||||
volumeSet.add(volNum)
|
||||
if (volumeSet.size >= 2) return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
fun hasTensOfChapters(chapters: List<ChapterItem>): Boolean {
|
||||
return chapters.size > 20
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user