mirror of
https://github.com/null2264/yokai.git
synced 2025-06-21 10:44:42 +00:00
feat: Content type (NSFW/SFW) filter
This commit is contained in:
parent
ff30fa5683
commit
995f41f2df
5 changed files with 77 additions and 5 deletions
31
app/src/main/java/dev/yokai/util/LewdMangaChecker.kt
Normal file
31
app/src/main/java/dev/yokai/util/LewdMangaChecker.kt
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
package dev.yokai.util
|
||||||
|
|
||||||
|
import eu.kanade.tachiyomi.data.database.models.Manga
|
||||||
|
import eu.kanade.tachiyomi.source.SourceManager
|
||||||
|
import uy.kohesive.injekt.Injekt
|
||||||
|
import uy.kohesive.injekt.api.get
|
||||||
|
import java.util.Locale
|
||||||
|
|
||||||
|
fun Manga.isLewd(): Boolean {
|
||||||
|
val sourceName = Injekt.get<SourceManager>().get(source)?.name
|
||||||
|
val tags = genre?.split(",")?.map { it.trim().lowercase(Locale.US) } ?: emptyList()
|
||||||
|
|
||||||
|
if (!tags.none { isNonHentai(it) }) return false
|
||||||
|
return (sourceName != null && sourceName.isFromHentaiSource()) || tags.any { isHentai(it) }
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun isNonHentai(tag: String) = tag.contains("non-h", true)
|
||||||
|
|
||||||
|
private fun String.isFromHentaiSource() =
|
||||||
|
contains("hentai", true) ||
|
||||||
|
contains("adult", true)
|
||||||
|
|
||||||
|
private fun isHentai(tag: String) =
|
||||||
|
tag.contains("hentai", true) ||
|
||||||
|
tag.contains("adult", true) ||
|
||||||
|
tag.contains("smut", true) ||
|
||||||
|
tag.contains("lewd", true) ||
|
||||||
|
tag.contains("nsfw", true) ||
|
||||||
|
tag.contains("erotic", true) ||
|
||||||
|
tag.contains("pornographic", true) ||
|
||||||
|
tag.contains("18+", true)
|
|
@ -284,6 +284,8 @@ class PreferencesHelper(val context: Context, val preferenceStore: PreferenceSto
|
||||||
|
|
||||||
fun filterMangaType() = preferenceStore.getInt(Keys.filterMangaType, 0)
|
fun filterMangaType() = preferenceStore.getInt(Keys.filterMangaType, 0)
|
||||||
|
|
||||||
|
fun filterContentType() = preferenceStore.getInt("pref_filter_content_type_key", 0)
|
||||||
|
|
||||||
fun showEmptyCategoriesWhileFiltering() = preferenceStore.getBoolean(Keys.showEmptyCategoriesFiltering, false)
|
fun showEmptyCategoriesWhileFiltering() = preferenceStore.getBoolean(Keys.showEmptyCategoriesFiltering, false)
|
||||||
|
|
||||||
fun librarySortingMode() = preferenceStore.getInt("library_sorting_mode", 0)
|
fun librarySortingMode() = preferenceStore.getInt("library_sorting_mode", 0)
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
package eu.kanade.tachiyomi.ui.library
|
package eu.kanade.tachiyomi.ui.library
|
||||||
|
|
||||||
|
import dev.yokai.util.isLewd
|
||||||
import eu.kanade.tachiyomi.R
|
import eu.kanade.tachiyomi.R
|
||||||
import eu.kanade.tachiyomi.core.preference.getAndSet
|
|
||||||
import eu.kanade.tachiyomi.data.cache.CoverCache
|
import eu.kanade.tachiyomi.data.cache.CoverCache
|
||||||
import eu.kanade.tachiyomi.data.database.DatabaseHelper
|
import eu.kanade.tachiyomi.data.database.DatabaseHelper
|
||||||
import eu.kanade.tachiyomi.data.database.models.Category
|
import eu.kanade.tachiyomi.data.database.models.Category
|
||||||
|
@ -121,7 +121,16 @@ class LibraryPresenter(
|
||||||
|
|
||||||
val filterMangaType = preferences.filterMangaType().get()
|
val filterMangaType = preferences.filterMangaType().get()
|
||||||
|
|
||||||
!(filterDownloaded == 0 && filterUnread == 0 && filterCompleted == 0 && filterTracked == 0 && filterMangaType == 0)
|
val filterContentType = preferences.filterContentType().get()
|
||||||
|
|
||||||
|
!(
|
||||||
|
filterDownloaded == 0 &&
|
||||||
|
filterUnread == 0 &&
|
||||||
|
filterCompleted == 0 &&
|
||||||
|
filterTracked == 0 &&
|
||||||
|
filterMangaType == 0 &&
|
||||||
|
filterContentType == 0
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Save the current list to speed up loading later */
|
/** Save the current list to speed up loading later */
|
||||||
|
@ -282,6 +291,8 @@ class LibraryPresenter(
|
||||||
|
|
||||||
val filterMangaType = preferences.filterMangaType().get()
|
val filterMangaType = preferences.filterMangaType().get()
|
||||||
|
|
||||||
|
val filterContentType = preferences.filterContentType().get()
|
||||||
|
|
||||||
val filterBookmarked = preferences.filterBookmarked().get()
|
val filterBookmarked = preferences.filterBookmarked().get()
|
||||||
|
|
||||||
val showEmptyCategoriesWhileFiltering = preferences.showEmptyCategoriesWhileFiltering().get()
|
val showEmptyCategoriesWhileFiltering = preferences.showEmptyCategoriesWhileFiltering().get()
|
||||||
|
@ -289,7 +300,14 @@ class LibraryPresenter(
|
||||||
val filterTrackers = FilterBottomSheet.FILTER_TRACKER
|
val filterTrackers = FilterBottomSheet.FILTER_TRACKER
|
||||||
|
|
||||||
val filtersOff = view?.isSubClass != true &&
|
val filtersOff = view?.isSubClass != true &&
|
||||||
(filterDownloaded == 0 && filterUnread == 0 && filterCompleted == 0 && filterTracked == 0 && filterMangaType == 0)
|
(
|
||||||
|
filterDownloaded == 0 &&
|
||||||
|
filterUnread == 0 &&
|
||||||
|
filterCompleted == 0 &&
|
||||||
|
filterTracked == 0 &&
|
||||||
|
filterMangaType == 0 &&
|
||||||
|
filterContentType == 0
|
||||||
|
)
|
||||||
hasActiveFilters = !filtersOff
|
hasActiveFilters = !filtersOff
|
||||||
val missingCategorySet = categories.mapNotNull { it.id }.toMutableSet()
|
val missingCategorySet = categories.mapNotNull { it.id }.toMutableSet()
|
||||||
val filteredItems = items.filter f@{ item ->
|
val filteredItems = items.filter f@{ item ->
|
||||||
|
@ -309,6 +327,7 @@ class LibraryPresenter(
|
||||||
filterMangaType,
|
filterMangaType,
|
||||||
filterBookmarked,
|
filterBookmarked,
|
||||||
filterTrackers,
|
filterTrackers,
|
||||||
|
filterContentType,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -329,6 +348,7 @@ class LibraryPresenter(
|
||||||
filterMangaType,
|
filterMangaType,
|
||||||
filterBookmarked,
|
filterBookmarked,
|
||||||
filterTrackers,
|
filterTrackers,
|
||||||
|
filterContentType,
|
||||||
)
|
)
|
||||||
if (matches) {
|
if (matches) {
|
||||||
missingCategorySet.remove(item.manga.category)
|
missingCategorySet.remove(item.manga.category)
|
||||||
|
@ -352,6 +372,7 @@ class LibraryPresenter(
|
||||||
filterMangaType: Int,
|
filterMangaType: Int,
|
||||||
filterBookmarked: Int,
|
filterBookmarked: Int,
|
||||||
filterTrackers: String,
|
filterTrackers: String,
|
||||||
|
filterContentType: Int,
|
||||||
): Boolean {
|
): Boolean {
|
||||||
(view as? FilteredLibraryController)?.let {
|
(view as? FilteredLibraryController)?.let {
|
||||||
return matchesCustomFilters(item, it, filterTrackers)
|
return matchesCustomFilters(item, it, filterTrackers)
|
||||||
|
@ -393,6 +414,10 @@ class LibraryPresenter(
|
||||||
}
|
}
|
||||||
return if (filterDownloaded == STATE_INCLUDE) isDownloaded else !isDownloaded
|
return if (filterDownloaded == STATE_INCLUDE) isDownloaded else !isDownloaded
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Filter for NSFW/SFW contents
|
||||||
|
if (filterContentType == STATE_INCLUDE) return !item.manga.isLewd()
|
||||||
|
if (filterContentType == STATE_EXCLUDE) return item.manga.isLewd()
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -73,6 +73,8 @@ class FilterBottomSheet @JvmOverloads constructor(context: Context, attrs: Attri
|
||||||
|
|
||||||
private lateinit var bookmarked: FilterTagGroup
|
private lateinit var bookmarked: FilterTagGroup
|
||||||
|
|
||||||
|
private lateinit var contentType: FilterTagGroup
|
||||||
|
|
||||||
private var tracked: FilterTagGroup? = null
|
private var tracked: FilterTagGroup? = null
|
||||||
|
|
||||||
private var trackers: FilterTagGroup? = null
|
private var trackers: FilterTagGroup? = null
|
||||||
|
@ -98,6 +100,7 @@ class FilterBottomSheet @JvmOverloads constructor(context: Context, attrs: Attri
|
||||||
if (hasTracking) {
|
if (hasTracking) {
|
||||||
tracked?.let { list.add(it) }
|
tracked?.let { list.add(it) }
|
||||||
}
|
}
|
||||||
|
list.add(contentType)
|
||||||
list
|
list
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -347,6 +350,9 @@ class FilterBottomSheet @JvmOverloads constructor(context: Context, attrs: Attri
|
||||||
tracked?.setup(this, R.string.tracked, R.string.not_tracked)
|
tracked?.setup(this, R.string.tracked, R.string.not_tracked)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
contentType = inflate(R.layout.filter_tag_group) as FilterTagGroup
|
||||||
|
contentType.setup(this, R.string.sfw, R.string.nsfw)
|
||||||
|
|
||||||
reSortViews()
|
reSortViews()
|
||||||
|
|
||||||
controller?.viewScope?.launch {
|
controller?.viewScope?.launch {
|
||||||
|
@ -436,6 +442,7 @@ class FilterBottomSheet @JvmOverloads constructor(context: Context, attrs: Attri
|
||||||
unreadProgress.state = unreadP - 3
|
unreadProgress.state = unreadP - 3
|
||||||
}
|
}
|
||||||
tracked?.setState(preferences.filterTracked())
|
tracked?.setState(preferences.filterTracked())
|
||||||
|
contentType.setState(preferences.filterContentType())
|
||||||
reorderFilters()
|
reorderFilters()
|
||||||
reSortViews()
|
reSortViews()
|
||||||
}
|
}
|
||||||
|
@ -449,7 +456,7 @@ class FilterBottomSheet @JvmOverloads constructor(context: Context, attrs: Attri
|
||||||
filterItems.add(it)
|
filterItems.add(it)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
listOfNotNull(unreadProgress, unread, downloaded, completed, mangaType, bookmarked, tracked)
|
listOfNotNull(unreadProgress, unread, downloaded, completed, mangaType, bookmarked, tracked, contentType)
|
||||||
.forEach {
|
.forEach {
|
||||||
if (!filterItems.contains(it)) {
|
if (!filterItems.contains(it)) {
|
||||||
filterItems.add(it)
|
filterItems.add(it)
|
||||||
|
@ -470,6 +477,7 @@ class FilterBottomSheet @JvmOverloads constructor(context: Context, attrs: Attri
|
||||||
Filters.SeriesType -> mangaType
|
Filters.SeriesType -> mangaType
|
||||||
Filters.Bookmarked -> bookmarked
|
Filters.Bookmarked -> bookmarked
|
||||||
Filters.Tracked -> if (hasTracking) tracked else null
|
Filters.Tracked -> if (hasTracking) tracked else null
|
||||||
|
Filters.ContentType -> contentType
|
||||||
else -> null
|
else -> null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -531,6 +539,7 @@ class FilterBottomSheet @JvmOverloads constructor(context: Context, attrs: Attri
|
||||||
preferences.filterMangaType().set(newIndex)
|
preferences.filterMangaType().set(newIndex)
|
||||||
null
|
null
|
||||||
}
|
}
|
||||||
|
contentType -> preferences.filterContentType()
|
||||||
else -> null
|
else -> null
|
||||||
}?.set(index + 1)
|
}?.set(index + 1)
|
||||||
}
|
}
|
||||||
|
@ -624,6 +633,7 @@ class FilterBottomSheet @JvmOverloads constructor(context: Context, attrs: Attri
|
||||||
SeriesType('m', R.string.series_type),
|
SeriesType('m', R.string.series_type),
|
||||||
Bookmarked('b', R.string.bookmarked),
|
Bookmarked('b', R.string.bookmarked),
|
||||||
Tracked('t', R.string.tracking),
|
Tracked('t', R.string.tracking),
|
||||||
|
ContentType('s', R.string.content_type);
|
||||||
;
|
;
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
@ -635,6 +645,7 @@ class FilterBottomSheet @JvmOverloads constructor(context: Context, attrs: Attri
|
||||||
SeriesType,
|
SeriesType,
|
||||||
Bookmarked,
|
Bookmarked,
|
||||||
Tracked,
|
Tracked,
|
||||||
|
ContentType,
|
||||||
).joinToString("") { it.value.toString() }
|
).joinToString("") { it.value.toString() }
|
||||||
|
|
||||||
fun filterOf(char: Char) = entries.find { it.value == char }
|
fun filterOf(char: Char) = entries.find { it.value == char }
|
||||||
|
|
|
@ -1201,4 +1201,7 @@
|
||||||
<string name="wifi">Wi-Fi</string>
|
<string name="wifi">Wi-Fi</string>
|
||||||
<string name="webcomic">Webcomic</string>
|
<string name="webcomic">Webcomic</string>
|
||||||
<string name="internal_error">Internal error: %s</string>
|
<string name="internal_error">Internal error: %s</string>
|
||||||
|
<string name="sfw">SFW</string>
|
||||||
|
<string name="nsfw">NSFW</string>
|
||||||
|
<string name="content_type">Content Type</string>
|
||||||
</resources>
|
</resources>
|
Loading…
Add table
Add a link
Reference in a new issue