Browse Source

Option to hide NSFW extensions (closes #1312)

arkon 4 years ago
parent
commit
abaca6e676

+ 2 - 0
app/src/main/java/eu/kanade/tachiyomi/data/preference/PreferenceKeys.kt

@@ -117,6 +117,8 @@ object PreferenceKeys {
 
     const val automaticExtUpdates = "automatic_ext_updates"
 
+    const val allowNsfwSources = "allow_nsfw_sources"
+
     const val startScreen = "start_screen"
 
     const val useBiometricLock = "use_biometric_lock"

+ 2 - 0
app/src/main/java/eu/kanade/tachiyomi/data/preference/PreferencesHelper.kt

@@ -217,6 +217,8 @@ class PreferencesHelper(val context: Context) {
 
     fun automaticExtUpdates() = flowPrefs.getBoolean(Keys.automaticExtUpdates, true)
 
+    fun allowNsfwSources() = prefs.getBoolean(Keys.allowNsfwSources, true)
+
     fun extensionUpdatesCount() = flowPrefs.getInt("ext_updates_count", 0)
 
     fun lastExtCheck() = flowPrefs.getLong("last_ext_check", 0)

+ 2 - 1
app/src/main/java/eu/kanade/tachiyomi/extension/api/ExtensionGithubApi.kt

@@ -64,9 +64,10 @@ internal class ExtensionGithubApi {
                 val versionName = element["version"].string
                 val versionCode = element["code"].int
                 val lang = element["lang"].string
+                val nsfw = element["nsfw"].int == 1
                 val icon = "$REPO_URL_PREFIX/icon/${apkName.replace(".apk", ".png")}"
 
-                Extension.Available(name, pkgName, versionName, versionCode, lang, apkName, icon)
+                Extension.Available(name, pkgName, versionName, versionCode, lang, nsfw, apkName, icon)
             }
     }
 

+ 6 - 2
app/src/main/java/eu/kanade/tachiyomi/extension/model/Extension.kt

@@ -9,14 +9,16 @@ sealed class Extension {
     abstract val versionName: String
     abstract val versionCode: Int
     abstract val lang: String?
+    abstract val isNsfw: Boolean
 
     data class Installed(
         override val name: String,
         override val pkgName: String,
         override val versionName: String,
         override val versionCode: Int,
-        val sources: List<Source>,
         override val lang: String,
+        override val isNsfw: Boolean,
+        val sources: List<Source>,
         val hasUpdate: Boolean = false,
         val isObsolete: Boolean = false,
         val isUnofficial: Boolean = false
@@ -28,6 +30,7 @@ sealed class Extension {
         override val versionName: String,
         override val versionCode: Int,
         override val lang: String,
+        override val isNsfw: Boolean,
         val apkName: String,
         val iconUrl: String
     ) : Extension()
@@ -38,6 +41,7 @@ sealed class Extension {
         override val versionName: String,
         override val versionCode: Int,
         val signatureHash: String,
-        override val lang: String? = null
+        override val lang: String? = null,
+        override val isNsfw: Boolean = false
     ) : Extension()
 }

+ 11 - 4
app/src/main/java/eu/kanade/tachiyomi/extension/util/ExtensionLoader.kt

@@ -15,8 +15,8 @@ import eu.kanade.tachiyomi.util.lang.Hash
 import kotlinx.coroutines.async
 import kotlinx.coroutines.runBlocking
 import timber.log.Timber
-import uy.kohesive.injekt.Injekt
 import uy.kohesive.injekt.api.get
+import uy.kohesive.injekt.injectLazy
 
 /**
  * Class that handles the loading of the extensions installed in the system.
@@ -24,8 +24,11 @@ import uy.kohesive.injekt.api.get
 @SuppressLint("PackageManagerGetSignatures")
 internal object ExtensionLoader {
 
+    private val preferences: PreferencesHelper by injectLazy()
+
     private const val EXTENSION_FEATURE = "tachiyomi.extension"
     private const val METADATA_SOURCE_CLASS = "tachiyomi.extension.class"
+    private const val METADATA_NSFW = "tachiyomi.extension.nsfw"
     const val LIB_VERSION_MIN = 1.2
     const val LIB_VERSION_MAX = 1.2
 
@@ -36,8 +39,7 @@ internal object ExtensionLoader {
     /**
      * List of the trusted signatures.
      */
-    var trustedSignatures = mutableSetOf<String>() +
-        Injekt.get<PreferencesHelper>().trustedSignatures().get() + officialSignature
+    var trustedSignatures = mutableSetOf<String>() + preferences.trustedSignatures().get() + officialSignature
 
     /**
      * Return a list of all the installed extensions initialized concurrently.
@@ -125,6 +127,11 @@ internal object ExtensionLoader {
             return LoadResult.Untrusted(extension)
         }
 
+        val isNsfw = appInfo.metaData.getInt(METADATA_NSFW) == 1
+        if (!preferences.allowNsfwSources() && isNsfw) {
+            return LoadResult.Error("NSFW extension $pkgName not allowed")
+        }
+
         val classLoader = PathClassLoader(appInfo.sourceDir, null, context.classLoader)
 
         val sources = appInfo.metaData.getString(METADATA_SOURCE_CLASS)!!
@@ -160,7 +167,7 @@ internal object ExtensionLoader {
         }
 
         val extension = Extension.Installed(
-            extName, pkgName, versionName, versionCode, sources, lang,
+            extName, pkgName, versionName, versionCode, lang, isNsfw, sources,
             isUnofficial = signatureHash != officialSignature
         )
         return LoadResult.Success(extension)

+ 5 - 3
app/src/main/java/eu/kanade/tachiyomi/ui/browse/extension/ExtensionPresenter.kt

@@ -55,20 +55,22 @@ open class ExtensionPresenter(
     private fun toItems(tuple: ExtensionTuple): List<ExtensionItem> {
         val context = Injekt.get<Application>()
         val activeLangs = preferences.enabledLanguages().get()
+        val allowNsfw = preferences.allowNsfwSources()
 
         val (installed, untrusted, available) = tuple
 
         val items = mutableListOf<ExtensionItem>()
 
-        val updatesSorted = installed.filter { it.hasUpdate }.sortedBy { it.pkgName }
-        val installedSorted = installed.filter { !it.hasUpdate }.sortedWith(compareBy({ !it.isObsolete }, { it.pkgName }))
+        val updatesSorted = installed.filter { it.hasUpdate && (allowNsfw || !it.isNsfw) }.sortedBy { it.pkgName }
+        val installedSorted = installed.filter { !it.hasUpdate && (allowNsfw || !it.isNsfw) }.sortedWith(compareBy({ !it.isObsolete }, { it.pkgName }))
         val untrustedSorted = untrusted.sortedBy { it.pkgName }
         val availableSorted = available
             // Filter out already installed extensions and disabled languages
             .filter { avail ->
                 installed.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)
             }
             .sortedBy { it.pkgName }
 

+ 5 - 0
app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsBrowseController.kt

@@ -29,6 +29,11 @@ class SettingsBrowseController : SettingsController() {
                     true
                 }
             }
+            switchPreference {
+                key = Keys.allowNsfwSources
+                titleRes = R.string.pref_allow_nsfw_sources
+                defaultValue = true
+            }
         }
 
         preferenceCategory {

+ 1 - 0
app/src/main/res/values/strings.xml

@@ -330,6 +330,7 @@
 
       <!-- Browse section -->
     <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_search_pinned_sources_only">Only include pinned sources</string>
 
       <!-- Backup section -->