Allow partially loading extensions with individually marked NSFW sources

This commit is contained in:
arkon 2020-08-08 18:17:42 -04:00
parent abaca6e676
commit 421dfb4a2d
8 changed files with 55 additions and 13 deletions

View file

@ -0,0 +1,5 @@
package eu.kanade.tachiyomi.annoations
@Retention(AnnotationRetention.RUNTIME)
@Target(AnnotationTarget.CLASS)
annotation class Nsfw

View file

@ -117,7 +117,7 @@ object PreferenceKeys {
const val automaticExtUpdates = "automatic_ext_updates" const val automaticExtUpdates = "automatic_ext_updates"
const val allowNsfwSources = "allow_nsfw_sources" const val allowNsfwSource = "allow_nsfw_source"
const val startScreen = "start_screen" const val startScreen = "start_screen"

View file

@ -37,4 +37,10 @@ object PreferenceValues {
VERTICAL, VERTICAL,
BOTH BOTH
} }
enum class NsfwAllowance {
ALLOWED,
PARTIAL,
BLOCKED
}
} }

View file

@ -10,6 +10,7 @@ import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.data.preference.PreferenceKeys as Keys import eu.kanade.tachiyomi.data.preference.PreferenceKeys as Keys
import eu.kanade.tachiyomi.data.preference.PreferenceValues as Values import eu.kanade.tachiyomi.data.preference.PreferenceValues as Values
import eu.kanade.tachiyomi.data.preference.PreferenceValues.DisplayMode import eu.kanade.tachiyomi.data.preference.PreferenceValues.DisplayMode
import eu.kanade.tachiyomi.data.preference.PreferenceValues.NsfwAllowance
import eu.kanade.tachiyomi.data.track.TrackService import eu.kanade.tachiyomi.data.track.TrackService
import eu.kanade.tachiyomi.data.track.anilist.Anilist import eu.kanade.tachiyomi.data.track.anilist.Anilist
import java.io.File import java.io.File
@ -217,7 +218,7 @@ class PreferencesHelper(val context: Context) {
fun automaticExtUpdates() = flowPrefs.getBoolean(Keys.automaticExtUpdates, true) fun automaticExtUpdates() = flowPrefs.getBoolean(Keys.automaticExtUpdates, true)
fun allowNsfwSources() = prefs.getBoolean(Keys.allowNsfwSources, true) fun allowNsfwSource() = flowPrefs.getEnum(Keys.allowNsfwSource, NsfwAllowance.ALLOWED)
fun extensionUpdatesCount() = flowPrefs.getInt("ext_updates_count", 0) fun extensionUpdatesCount() = flowPrefs.getInt("ext_updates_count", 0)

View file

@ -5,6 +5,8 @@ import android.content.Context
import android.content.pm.PackageInfo import android.content.pm.PackageInfo
import android.content.pm.PackageManager import android.content.pm.PackageManager
import dalvik.system.PathClassLoader import dalvik.system.PathClassLoader
import eu.kanade.tachiyomi.annoations.Nsfw
import eu.kanade.tachiyomi.data.preference.PreferenceValues
import eu.kanade.tachiyomi.data.preference.PreferencesHelper import eu.kanade.tachiyomi.data.preference.PreferencesHelper
import eu.kanade.tachiyomi.extension.model.Extension import eu.kanade.tachiyomi.extension.model.Extension
import eu.kanade.tachiyomi.extension.model.LoadResult import eu.kanade.tachiyomi.extension.model.LoadResult
@ -15,7 +17,6 @@ import eu.kanade.tachiyomi.util.lang.Hash
import kotlinx.coroutines.async import kotlinx.coroutines.async
import kotlinx.coroutines.runBlocking import kotlinx.coroutines.runBlocking
import timber.log.Timber import timber.log.Timber
import uy.kohesive.injekt.api.get
import uy.kohesive.injekt.injectLazy import uy.kohesive.injekt.injectLazy
/** /**
@ -128,7 +129,7 @@ internal object ExtensionLoader {
} }
val isNsfw = appInfo.metaData.getInt(METADATA_NSFW) == 1 val isNsfw = appInfo.metaData.getInt(METADATA_NSFW) == 1
if (!preferences.allowNsfwSources() && isNsfw) { if (preferences.allowNsfwSource().get() == PreferenceValues.NsfwAllowance.BLOCKED && isNsfw) {
return LoadResult.Error("NSFW extension $pkgName not allowed") return LoadResult.Error("NSFW extension $pkgName not allowed")
} }
@ -156,10 +157,11 @@ internal object ExtensionLoader {
return LoadResult.Error(e) return LoadResult.Error(e)
} }
} }
.filter { preferences.allowNsfwSource().get() == PreferenceValues.NsfwAllowance.ALLOWED || !isSourceNsfw(it) }
val langs = sources.filterIsInstance<CatalogueSource>() val langs = sources.filterIsInstance<CatalogueSource>()
.map { it.lang } .map { it.lang }
.toSet() .toSet()
val lang = when (langs.size) { val lang = when (langs.size) {
0 -> "" 0 -> ""
1 -> langs.first() 1 -> langs.first()
@ -195,4 +197,14 @@ internal object ExtensionLoader {
null null
} }
} }
/**
* Checks whether a source is annotated with @Nsfw.
*/
private fun isSourceNsfw(source: Source): Boolean {
// Annotations are proxied, hence this janky way of checking for them
return source.javaClass.annotations
.flatMap { it.javaClass.interfaces.map { it.simpleName } }
.firstOrNull { it == Nsfw::class.java.simpleName } != null
}
} }

View file

@ -3,6 +3,7 @@ package eu.kanade.tachiyomi.ui.browse.extension
import android.app.Application import android.app.Application
import android.os.Bundle import android.os.Bundle
import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.data.preference.PreferenceValues
import eu.kanade.tachiyomi.data.preference.PreferencesHelper import eu.kanade.tachiyomi.data.preference.PreferencesHelper
import eu.kanade.tachiyomi.extension.ExtensionManager import eu.kanade.tachiyomi.extension.ExtensionManager
import eu.kanade.tachiyomi.extension.model.Extension import eu.kanade.tachiyomi.extension.model.Extension
@ -55,14 +56,14 @@ open class ExtensionPresenter(
private fun toItems(tuple: ExtensionTuple): List<ExtensionItem> { private fun toItems(tuple: ExtensionTuple): List<ExtensionItem> {
val context = Injekt.get<Application>() val context = Injekt.get<Application>()
val activeLangs = preferences.enabledLanguages().get() val activeLangs = preferences.enabledLanguages().get()
val allowNsfw = preferences.allowNsfwSources() val showNsfwExtensions = preferences.allowNsfwSource().get() != PreferenceValues.NsfwAllowance.BLOCKED
val (installed, untrusted, available) = tuple val (installed, untrusted, available) = tuple
val items = mutableListOf<ExtensionItem>() val items = mutableListOf<ExtensionItem>()
val updatesSorted = installed.filter { it.hasUpdate && (allowNsfw || !it.isNsfw) }.sortedBy { it.pkgName } val updatesSorted = installed.filter { it.hasUpdate && (showNsfwExtensions || !it.isNsfw) }.sortedBy { it.pkgName }
val installedSorted = installed.filter { !it.hasUpdate && (allowNsfw || !it.isNsfw) }.sortedWith(compareBy({ !it.isObsolete }, { it.pkgName })) val installedSorted = installed.filter { !it.hasUpdate && (showNsfwExtensions || !it.isNsfw) }.sortedWith(compareBy({ !it.isObsolete }, { it.pkgName }))
val untrustedSorted = untrusted.sortedBy { it.pkgName } val untrustedSorted = untrusted.sortedBy { it.pkgName }
val availableSorted = available val availableSorted = available
// Filter out already installed extensions and disabled languages // Filter out already installed extensions and disabled languages
@ -70,7 +71,7 @@ open class ExtensionPresenter(
installed.none { it.pkgName == avail.pkgName } && installed.none { it.pkgName == avail.pkgName } &&
untrusted.none { it.pkgName == avail.pkgName } && untrusted.none { it.pkgName == avail.pkgName } &&
(avail.lang in activeLangs || avail.lang == "all") && (avail.lang in activeLangs || avail.lang == "all") &&
(allowNsfw || !avail.isNsfw) (showNsfwExtensions || !avail.isNsfw)
} }
.sortedBy { it.pkgName } .sortedBy { it.pkgName }

View file

@ -3,8 +3,11 @@ package eu.kanade.tachiyomi.ui.setting
import androidx.preference.PreferenceScreen import androidx.preference.PreferenceScreen
import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.data.preference.PreferenceKeys as Keys import eu.kanade.tachiyomi.data.preference.PreferenceKeys as Keys
import eu.kanade.tachiyomi.data.preference.PreferenceValues as Values
import eu.kanade.tachiyomi.extension.ExtensionUpdateJob import eu.kanade.tachiyomi.extension.ExtensionUpdateJob
import eu.kanade.tachiyomi.util.preference.defaultValue import eu.kanade.tachiyomi.util.preference.defaultValue
import eu.kanade.tachiyomi.util.preference.entriesRes
import eu.kanade.tachiyomi.util.preference.listPreference
import eu.kanade.tachiyomi.util.preference.onChange import eu.kanade.tachiyomi.util.preference.onChange
import eu.kanade.tachiyomi.util.preference.preferenceCategory import eu.kanade.tachiyomi.util.preference.preferenceCategory
import eu.kanade.tachiyomi.util.preference.switchPreference import eu.kanade.tachiyomi.util.preference.switchPreference
@ -29,10 +32,21 @@ class SettingsBrowseController : SettingsController() {
true true
} }
} }
switchPreference { listPreference {
key = Keys.allowNsfwSources key = Keys.allowNsfwSource
titleRes = R.string.pref_allow_nsfw_sources titleRes = R.string.pref_allow_nsfw_sources
defaultValue = true entriesRes = arrayOf(
R.string.pref_allow_nsfw_sources_allowed,
R.string.pref_allow_nsfw_sources_allowed_multisource,
R.string.pref_allow_nsfw_sources_blocked
)
entryValues = arrayOf(
Values.NsfwAllowance.ALLOWED.name,
Values.NsfwAllowance.PARTIAL.name,
Values.NsfwAllowance.BLOCKED.name
)
defaultValue = Values.NsfwAllowance.ALLOWED.name
summary = "%s"
} }
} }

View file

@ -330,7 +330,10 @@
<!-- Browse section --> <!-- Browse section -->
<string name="pref_enable_automatic_extension_updates">Check for extension updates</string> <string name="pref_enable_automatic_extension_updates">Check for extension updates</string>
<string name="pref_allow_nsfw_sources">Allow sources with NSFW content</string> <string name="pref_allow_nsfw_sources">NSFW sources</string>
<string name="pref_allow_nsfw_sources_allowed">Allowed</string>
<string name="pref_allow_nsfw_sources_allowed_multisource">Block source but show in extensions list</string>
<string name="pref_allow_nsfw_sources_blocked">Blocked</string>
<string name="pref_search_pinned_sources_only">Only include pinned sources</string> <string name="pref_search_pinned_sources_only">Only include pinned sources</string>
<!-- Backup section --> <!-- Backup section -->