diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/preference/PreferenceKeys.kt b/app/src/main/java/eu/kanade/tachiyomi/data/preference/PreferenceKeys.kt index 14246b57e..c4e50ea94 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/preference/PreferenceKeys.kt +++ b/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" diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/preference/PreferencesHelper.kt b/app/src/main/java/eu/kanade/tachiyomi/data/preference/PreferencesHelper.kt index 401951f66..e6ff999b8 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/preference/PreferencesHelper.kt +++ b/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) diff --git a/app/src/main/java/eu/kanade/tachiyomi/extension/api/ExtensionGithubApi.kt b/app/src/main/java/eu/kanade/tachiyomi/extension/api/ExtensionGithubApi.kt index 41d249902..2b989efc0 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/extension/api/ExtensionGithubApi.kt +++ b/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) } } diff --git a/app/src/main/java/eu/kanade/tachiyomi/extension/model/Extension.kt b/app/src/main/java/eu/kanade/tachiyomi/extension/model/Extension.kt index c8f8626da..480c3b095 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/extension/model/Extension.kt +++ b/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, override val lang: String, + override val isNsfw: Boolean, + val sources: List, 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() } diff --git a/app/src/main/java/eu/kanade/tachiyomi/extension/util/ExtensionLoader.kt b/app/src/main/java/eu/kanade/tachiyomi/extension/util/ExtensionLoader.kt index 20dfd14c4..e0caa0e2c 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/extension/util/ExtensionLoader.kt +++ b/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() + - Injekt.get().trustedSignatures().get() + officialSignature + var trustedSignatures = mutableSetOf() + 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) diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/extension/ExtensionPresenter.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/browse/extension/ExtensionPresenter.kt index cf1be5fe4..7731b737d 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/browse/extension/ExtensionPresenter.kt +++ b/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 { val context = Injekt.get() val activeLangs = preferences.enabledLanguages().get() + val allowNsfw = preferences.allowNsfwSources() val (installed, untrusted, available) = tuple val items = mutableListOf() - 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 } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsBrowseController.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsBrowseController.kt index ab4d0bd7b..4aa6a109c 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsBrowseController.kt +++ b/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 { diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 173524ae5..bb787f879 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -330,6 +330,7 @@ Check for extension updates + Allow sources with NSFW content Only include pinned sources