Browse Source

Manage sources from extension details (closes #3152)

arkon 4 years ago
parent
commit
54cfb2acdf

+ 215 - 11
app/src/main/java/eu/kanade/tachiyomi/ui/browse/extension/ExtensionDetailsController.kt

@@ -1,23 +1,61 @@
 package eu.kanade.tachiyomi.ui.browse.extension
 
 import android.annotation.SuppressLint
+import android.content.Context
 import android.os.Bundle
+import android.util.TypedValue
 import android.view.LayoutInflater
+import android.view.Menu
+import android.view.MenuInflater
+import android.view.MenuItem
 import android.view.View
 import android.view.ViewGroup
+import androidx.appcompat.view.ContextThemeWrapper
+import androidx.preference.DialogPreference
+import androidx.preference.EditTextPreference
+import androidx.preference.EditTextPreferenceDialogController
+import androidx.preference.ListPreference
+import androidx.preference.ListPreferenceDialogController
+import androidx.preference.MultiSelectListPreference
+import androidx.preference.MultiSelectListPreferenceDialogController
+import androidx.preference.Preference
+import androidx.preference.PreferenceGroupAdapter
+import androidx.preference.PreferenceManager
+import androidx.preference.PreferenceScreen
+import androidx.recyclerview.widget.DividerItemDecoration
+import androidx.recyclerview.widget.DividerItemDecoration.VERTICAL
+import androidx.recyclerview.widget.LinearLayoutManager
 import eu.kanade.tachiyomi.R
+import eu.kanade.tachiyomi.data.preference.EmptyPreferenceDataStore
+import eu.kanade.tachiyomi.data.preference.PreferencesHelper
+import eu.kanade.tachiyomi.data.preference.SharedPreferencesDataStore
 import eu.kanade.tachiyomi.databinding.ExtensionDetailControllerBinding
+import eu.kanade.tachiyomi.extension.model.Extension
+import eu.kanade.tachiyomi.source.CatalogueSource
 import eu.kanade.tachiyomi.source.ConfigurableSource
+import eu.kanade.tachiyomi.source.Source
 import eu.kanade.tachiyomi.ui.base.controller.NucleusController
-import eu.kanade.tachiyomi.ui.base.controller.withFadeTransaction
+import eu.kanade.tachiyomi.util.preference.checkBoxPreference
+import eu.kanade.tachiyomi.util.preference.onChange
+import eu.kanade.tachiyomi.util.preference.preference
+import eu.kanade.tachiyomi.util.preference.preferenceCategory
 import eu.kanade.tachiyomi.util.system.LocaleHelper
 import eu.kanade.tachiyomi.util.view.visible
 import kotlinx.coroutines.flow.launchIn
 import kotlinx.coroutines.flow.onEach
 import reactivecircus.flowbinding.android.view.clicks
+import uy.kohesive.injekt.injectLazy
 
+@SuppressLint("RestrictedApi")
 class ExtensionDetailsController(bundle: Bundle? = null) :
-    NucleusController<ExtensionDetailControllerBinding, ExtensionDetailsPresenter>(bundle) {
+    NucleusController<ExtensionDetailControllerBinding, ExtensionDetailsPresenter>(bundle),
+    PreferenceManager.OnDisplayPreferenceDialogListener,
+    DialogPreference.TargetFragment {
+
+    private val preferences: PreferencesHelper by injectLazy()
+
+    private var preferenceScreen: PreferenceScreen? = null
+    private var lastOpenPreferencePosition: Int? = null
 
     constructor(pkgName: String) : this(
         Bundle().apply {
@@ -25,8 +63,13 @@ class ExtensionDetailsController(bundle: Bundle? = null) :
         }
     )
 
+    init {
+        setHasOptionsMenu(true)
+    }
+
     override fun inflateView(inflater: LayoutInflater, container: ViewGroup): View {
-        binding = ExtensionDetailControllerBinding.inflate(inflater)
+        val themedInflater = inflater.cloneInContext(getPreferenceThemeContext())
+        binding = ExtensionDetailControllerBinding.inflate(themedInflater)
         return binding.root
     }
 
@@ -65,25 +108,186 @@ class ExtensionDetailsController(bundle: Bundle? = null) :
             binding.extensionWarningBanner.setText(R.string.unofficial_extension_message)
         }
 
-        if (presenter.extension?.sources?.find { it is ConfigurableSource } != null) {
-            binding.extensionPrefs.visible()
-            binding.extensionPrefs.clicks()
-                .onEach { openPreferences() }
-                .launchIn(scope)
+        initPreferences(context, extension)
+    }
+
+    private fun initPreferences(context: Context, extension: Extension.Installed) {
+        val themedContext by lazy { getPreferenceThemeContext() }
+        val manager = PreferenceManager(themedContext)
+        manager.preferenceDataStore = EmptyPreferenceDataStore()
+        manager.onDisplayPreferenceDialogListener = this
+        val screen = manager.createPreferenceScreen(themedContext)
+        preferenceScreen = screen
+
+        with(screen) {
+            extension.sources
+                .groupBy { (it as CatalogueSource).lang }
+                .toSortedMap(compareBy { LocaleHelper.getSourceDisplayName(it, context) })
+                .forEach {
+                    preferenceCategory {
+                        title = LocaleHelper.getSourceDisplayName(it.key, context)
+                        it.value
+                            .sortedWith(compareBy({ !it.isEnabled() }, { it.name }))
+                            .forEach { source ->
+                                val sourcePrefs = mutableListOf<Preference>()
+
+                                // Source enable/disable
+                                checkBoxPreference {
+                                    key = getSourceKey(source.id)
+                                    title = source.toString()
+                                    isPersistent = false
+                                    isChecked = source.isEnabled()
+
+                                    onChange { newValue ->
+                                        val checked = newValue as Boolean
+                                        toggleSource(source, checked)
+                                        true
+                                    }
+
+                                    // React to enable/disable all changes
+                                    preferences.hiddenCatalogues().asFlow()
+                                        .onEach {
+                                            val enabled = source.isEnabled()
+                                            isChecked = enabled
+                                            sourcePrefs.forEach { pref -> pref.isVisible = enabled }
+                                        }
+                                        .launchIn(scope)
+                                }
+
+                                // Source preferences
+                                if (source is ConfigurableSource) {
+                                    // TODO
+                                    val dataStore = SharedPreferencesDataStore(/*if (source is HttpSource) {
+                                        source.preferences
+                                    } else {*/
+                                        context.getSharedPreferences(getSourceKey(source.id), Context.MODE_PRIVATE)
+                                        /*}*/
+                                    )
+
+                                    val newScreen = screen.preferenceManager.createPreferenceScreen(context)
+                                    source.setupPreferenceScreen(newScreen)
+
+                                    // Reparent the preferences
+                                    while (newScreen.preferenceCount != 0) {
+                                        val pref = newScreen.getPreference(0)
+                                        sourcePrefs.add(pref)
+
+                                        pref.preferenceDataStore = dataStore
+                                        pref.order = Int.MAX_VALUE // reset to default order
+                                        pref.isVisible = source.isEnabled()
+
+                                        newScreen.removePreference(pref)
+                                        screen.addPreference(pref)
+                                    }
+                                }
+                            }
+                    }
+                }
         }
+
+        binding.extensionPrefsRecycler.layoutManager = LinearLayoutManager(context)
+        binding.extensionPrefsRecycler.adapter = PreferenceGroupAdapter(screen)
+        binding.extensionPrefsRecycler.addItemDecoration(DividerItemDecoration(context, VERTICAL))
+    }
+
+    override fun onSaveInstanceState(outState: Bundle) {
+        lastOpenPreferencePosition?.let { outState.putInt(LASTOPENPREFERENCE_KEY, it) }
+        super.onSaveInstanceState(outState)
+    }
+
+    override fun onRestoreInstanceState(savedInstanceState: Bundle) {
+        super.onRestoreInstanceState(savedInstanceState)
+        lastOpenPreferencePosition = savedInstanceState.get(LASTOPENPREFERENCE_KEY) as? Int
+    }
+
+    override fun onDestroyView(view: View) {
+        preferenceScreen = null
+        super.onDestroyView(view)
+    }
+
+    override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
+        inflater.inflate(R.menu.extension_details, menu)
+    }
+
+    override fun onOptionsItemSelected(item: MenuItem): Boolean {
+        when (item.itemId) {
+            R.id.action_enable_all -> toggleAllSources(true)
+            R.id.action_disable_all -> toggleAllSources(false)
+        }
+        return super.onOptionsItemSelected(item)
     }
 
     fun onExtensionUninstalled() {
         router.popCurrentController()
     }
 
-    private fun openPreferences() {
-        router.pushController(
-            ExtensionPreferencesController(presenter.extension!!.pkgName).withFadeTransaction()
+    private fun toggleAllSources(enable: Boolean) {
+        presenter.extension?.sources?.forEach { toggleSource(it, enable) }
+    }
+
+    private fun toggleSource(source: Source, enable: Boolean) {
+        val current = preferences.hiddenCatalogues().get()
+
+        preferences.hiddenCatalogues().set(
+            if (enable) {
+                current - source.id.toString()
+            } else {
+                current + source.id.toString()
+            }
         )
     }
 
+    private fun Source.isEnabled(): Boolean {
+        return id.toString() !in preferences.hiddenCatalogues().get()
+    }
+
+    private fun getSourceKey(sourceId: Long): String {
+        return "source_$sourceId"
+    }
+
+    private fun getPreferenceThemeContext(): Context {
+        val tv = TypedValue()
+        activity!!.theme.resolveAttribute(R.attr.preferenceTheme, tv, true)
+        return ContextThemeWrapper(activity, tv.resourceId)
+    }
+
+    override fun onDisplayPreferenceDialog(preference: Preference) {
+        if (!isAttached) return
+
+        val screen = preference.parent!!
+
+        lastOpenPreferencePosition = (0 until screen.preferenceCount).indexOfFirst {
+            screen.getPreference(it) === preference
+        }
+
+        val f = when (preference) {
+            is EditTextPreference ->
+                EditTextPreferenceDialogController
+                    .newInstance(preference.getKey())
+            is ListPreference ->
+                ListPreferenceDialogController
+                    .newInstance(preference.getKey())
+            is MultiSelectListPreference ->
+                MultiSelectListPreferenceDialogController
+                    .newInstance(preference.getKey())
+            else -> throw IllegalArgumentException(
+                "Tried to display dialog for unknown " +
+                    "preference type. Did you forget to override onDisplayPreferenceDialog()?"
+            )
+        }
+        f.targetController = this
+        f.showDialog(router)
+    }
+
+    @Suppress("UNCHECKED_CAST")
+    override fun <T : Preference> findPreference(key: CharSequence): T? {
+        // We track [lastOpenPreferencePosition] when displaying the dialog
+        // [key] isn't useful since there may be duplicates
+        return preferenceScreen!!.getPreference(lastOpenPreferencePosition!!) as T
+    }
+
     private companion object {
         const val PKGNAME_KEY = "pkg_name"
+        const val LASTOPENPREFERENCE_KEY = "last_open_preference"
     }
 }

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

@@ -36,11 +36,13 @@ class ExtensionFilterController : SettingsController() {
                     val checked = newValue as Boolean
                     val currentActiveLangs = preferences.enabledLanguages().get()
 
-                    preferences.enabledLanguages().set(if (checked) {
-                        currentActiveLangs + it
-                    } else {
-                        currentActiveLangs - it
-                    })
+                    preferences.enabledLanguages().set(
+                        if (checked) {
+                            currentActiveLangs + it
+                        } else {
+                            currentActiveLangs - it
+                        }
+                    )
                     true
                 }
             }

+ 0 - 196
app/src/main/java/eu/kanade/tachiyomi/ui/browse/extension/ExtensionPreferencesController.kt

@@ -1,196 +0,0 @@
-package eu.kanade.tachiyomi.ui.browse.extension
-
-import android.annotation.SuppressLint
-import android.content.Context
-import android.os.Bundle
-import android.util.TypedValue
-import android.view.ContextThemeWrapper
-import android.view.LayoutInflater
-import android.view.View
-import android.view.ViewGroup
-import androidx.preference.DialogPreference
-import androidx.preference.EditTextPreference
-import androidx.preference.EditTextPreferenceDialogController
-import androidx.preference.ListPreference
-import androidx.preference.ListPreferenceDialogController
-import androidx.preference.MultiSelectListPreference
-import androidx.preference.MultiSelectListPreferenceDialogController
-import androidx.preference.Preference
-import androidx.preference.PreferenceGroupAdapter
-import androidx.preference.PreferenceManager
-import androidx.preference.PreferenceScreen
-import androidx.recyclerview.widget.DividerItemDecoration
-import androidx.recyclerview.widget.DividerItemDecoration.VERTICAL
-import androidx.recyclerview.widget.LinearLayoutManager
-import eu.kanade.tachiyomi.R
-import eu.kanade.tachiyomi.data.preference.EmptyPreferenceDataStore
-import eu.kanade.tachiyomi.data.preference.SharedPreferencesDataStore
-import eu.kanade.tachiyomi.databinding.ExtensionPreferencesControllerBinding
-import eu.kanade.tachiyomi.source.ConfigurableSource
-import eu.kanade.tachiyomi.source.Source
-import eu.kanade.tachiyomi.ui.base.controller.NucleusController
-import eu.kanade.tachiyomi.util.preference.preferenceCategory
-import timber.log.Timber
-
-@SuppressLint("RestrictedApi")
-class ExtensionPreferencesController(bundle: Bundle? = null) :
-    NucleusController<ExtensionPreferencesControllerBinding, ExtensionPreferencesPresenter>(bundle),
-    PreferenceManager.OnDisplayPreferenceDialogListener,
-    DialogPreference.TargetFragment {
-
-    private var lastOpenPreferencePosition: Int? = null
-
-    private var preferenceScreen: PreferenceScreen? = null
-
-    constructor(pkgName: String) : this(
-        Bundle().apply {
-            putString(PKGNAME_KEY, pkgName)
-        }
-    )
-
-    override fun inflateView(inflater: LayoutInflater, container: ViewGroup): View {
-        val themedInflater = inflater.cloneInContext(getPreferenceThemeContext())
-        binding = ExtensionPreferencesControllerBinding.inflate(themedInflater)
-        return binding.root
-    }
-
-    override fun createPresenter(): ExtensionPreferencesPresenter {
-        return ExtensionPreferencesPresenter(args.getString(PKGNAME_KEY)!!)
-    }
-
-    override fun getTitle(): String? {
-        return resources?.getString(R.string.label_extension_info)
-    }
-
-    @SuppressLint("PrivateResource")
-    override fun onViewCreated(view: View) {
-        super.onViewCreated(view)
-
-        val extension = presenter.extension ?: return
-        val context = view.context
-
-        val themedContext by lazy { getPreferenceThemeContext() }
-        val manager = PreferenceManager(themedContext)
-        manager.preferenceDataStore = EmptyPreferenceDataStore()
-        manager.onDisplayPreferenceDialogListener = this
-        val screen = manager.createPreferenceScreen(themedContext)
-        preferenceScreen = screen
-
-        val multiSource = extension.sources.size > 1
-
-        extension.sources
-            .filterIsInstance<ConfigurableSource>()
-            .forEach { source ->
-                try {
-                    addPreferencesForSource(screen, source, multiSource)
-                } catch (e: AbstractMethodError) {
-                    Timber.e("Source did not implement [addPreferencesForSource]: ${source.name}")
-                }
-            }
-
-        manager.setPreferences(screen)
-
-        binding.extensionPrefsRecycler.layoutManager = LinearLayoutManager(context)
-        binding.extensionPrefsRecycler.adapter = PreferenceGroupAdapter(screen)
-        binding.extensionPrefsRecycler.addItemDecoration(DividerItemDecoration(context, VERTICAL))
-
-        if (screen.preferenceCount == 0) {
-            binding.extensionPrefsEmptyView.show(R.string.ext_empty_preferences)
-        }
-    }
-
-    override fun onDestroyView(view: View) {
-        preferenceScreen = null
-        super.onDestroyView(view)
-    }
-
-    override fun onSaveInstanceState(outState: Bundle) {
-        lastOpenPreferencePosition?.let { outState.putInt(LASTOPENPREFERENCE_KEY, it) }
-        super.onSaveInstanceState(outState)
-    }
-
-    override fun onRestoreInstanceState(savedInstanceState: Bundle) {
-        super.onRestoreInstanceState(savedInstanceState)
-        lastOpenPreferencePosition = savedInstanceState.get(LASTOPENPREFERENCE_KEY) as? Int
-    }
-
-    private fun addPreferencesForSource(screen: PreferenceScreen, source: Source, multiSource: Boolean) {
-        val context = screen.context
-
-        // TODO
-        val dataStore = SharedPreferencesDataStore(/*if (source is HttpSource) {
-            source.preferences
-        } else {*/
-            context.getSharedPreferences("source_${source.id}", Context.MODE_PRIVATE)
-            /*}*/
-        )
-
-        if (source is ConfigurableSource) {
-            if (multiSource) {
-                screen.preferenceCategory {
-                    title = source.toString()
-                }
-            }
-
-            val newScreen = screen.preferenceManager.createPreferenceScreen(context)
-            source.setupPreferenceScreen(newScreen)
-
-            // Reparent the preferences
-            while (newScreen.preferenceCount != 0) {
-                val pref = newScreen.getPreference(0)
-                pref.isIconSpaceReserved = false
-                pref.preferenceDataStore = dataStore
-                pref.order = Int.MAX_VALUE // reset to default order
-
-                newScreen.removePreference(pref)
-                screen.addPreference(pref)
-            }
-        }
-    }
-
-    private fun getPreferenceThemeContext(): Context {
-        val tv = TypedValue()
-        activity!!.theme.resolveAttribute(R.attr.preferenceTheme, tv, true)
-        return ContextThemeWrapper(activity, tv.resourceId)
-    }
-
-    override fun onDisplayPreferenceDialog(preference: Preference) {
-        if (!isAttached) return
-
-        val screen = preference.parent!!
-
-        lastOpenPreferencePosition = (0 until screen.preferenceCount).indexOfFirst {
-            screen.getPreference(it) === preference
-        }
-
-        val f = when (preference) {
-            is EditTextPreference ->
-                EditTextPreferenceDialogController
-                    .newInstance(preference.getKey())
-            is ListPreference ->
-                ListPreferenceDialogController
-                    .newInstance(preference.getKey())
-            is MultiSelectListPreference ->
-                MultiSelectListPreferenceDialogController
-                    .newInstance(preference.getKey())
-            else -> throw IllegalArgumentException(
-                "Tried to display dialog for unknown " +
-                    "preference type. Did you forget to override onDisplayPreferenceDialog()?"
-            )
-        }
-        f.targetController = this
-        f.showDialog(router)
-    }
-
-    @Suppress("UNCHECKED_CAST")
-    override fun <T : Preference> findPreference(key: CharSequence): T? {
-        // We track [lastOpenPreferencePosition] when displaying the dialog
-        // [key] isn't useful since there may be duplicates
-        return preferenceScreen!!.getPreference(lastOpenPreferencePosition!!) as T
-    }
-
-    private companion object {
-        const val PKGNAME_KEY = "pkg_name"
-        const val LASTOPENPREFERENCE_KEY = "last_open_preference"
-    }
-}

+ 0 - 14
app/src/main/java/eu/kanade/tachiyomi/ui/browse/extension/ExtensionPreferencesPresenter.kt

@@ -1,14 +0,0 @@
-package eu.kanade.tachiyomi.ui.browse.extension
-
-import eu.kanade.tachiyomi.extension.ExtensionManager
-import eu.kanade.tachiyomi.ui.base.presenter.BasePresenter
-import uy.kohesive.injekt.Injekt
-import uy.kohesive.injekt.api.get
-
-class ExtensionPreferencesPresenter(
-    val pkgName: String,
-    extensionManager: ExtensionManager = Injekt.get()
-) : BasePresenter<ExtensionPreferencesController>() {
-
-    val extension = extensionManager.installedExtensions.find { it.pkgName == pkgName }
-}

+ 9 - 64
app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsSourcesController.kt

@@ -1,15 +1,11 @@
 package eu.kanade.tachiyomi.ui.setting
 
 import android.graphics.drawable.Drawable
-import androidx.preference.CheckBoxPreference
-import androidx.preference.PreferenceGroup
 import androidx.preference.PreferenceScreen
 import eu.kanade.tachiyomi.R
 import eu.kanade.tachiyomi.source.SourceManager
-import eu.kanade.tachiyomi.source.icon
-import eu.kanade.tachiyomi.source.online.HttpSource
 import eu.kanade.tachiyomi.util.preference.onChange
-import eu.kanade.tachiyomi.util.preference.switchPreferenceCategory
+import eu.kanade.tachiyomi.util.preference.switchPreference
 import eu.kanade.tachiyomi.util.preference.titleRes
 import eu.kanade.tachiyomi.util.system.LocaleHelper
 import java.util.TreeMap
@@ -33,80 +29,29 @@ class SettingsSourcesController : SettingsController() {
         val orderedLangs = sourcesByLang.keys.sortedWith(compareBy({ it !in activeLangsCodes }, { LocaleHelper.getSourceDisplayName(it, context) }))
 
         orderedLangs.forEach { lang ->
-            val sources = sourcesByLang[lang].orEmpty().sortedBy { it.name }
-
-            // Create a preference group and set initial state and change listener
-            switchPreferenceCategory {
+            switchPreference {
                 preferenceScreen.addPreference(this)
                 title = LocaleHelper.getSourceDisplayName(lang, context)
                 isPersistent = false
-                if (lang in activeLangsCodes) {
-                    setChecked(true)
-                    addLanguageSources(this, sources)
-                }
+                isChecked = lang in activeLangsCodes
 
                 onChange { newValue ->
                     val checked = newValue as Boolean
                     val current = preferences.enabledLanguages().get()
-                    if (!checked) {
-                        preferences.enabledLanguages().set(current - lang)
-                        removeAll()
-                    } else {
-                        preferences.enabledLanguages().set(current + lang)
-                        addLanguageSources(this, sources)
-                    }
-                    true
-                }
-            }
-        }
-    }
-
-    override fun setDivider(divider: Drawable?) {
-        super.setDivider(null)
-    }
-
-    /**
-     * Adds the source list for the given group (language).
-     *
-     * @param group the language category.
-     */
-    private fun addLanguageSources(group: PreferenceGroup, sources: List<HttpSource>) {
-        val hiddenCatalogues = preferences.hiddenCatalogues().get()
-
-        sources.forEach { source ->
-            val sourcePreference = CheckBoxPreference(group.context).apply {
-                val id = source.id.toString()
-                title = source.name
-                key = getSourceKey(source.id)
-                isPersistent = false
-                isChecked = id !in hiddenCatalogues
-
-                val sourceIcon = source.icon()
-                if (sourceIcon != null) {
-                    icon = sourceIcon
-                }
-
-                onChange { newValue ->
-                    val checked = newValue as Boolean
-                    val current = preferences.hiddenCatalogues().get()
-
-                    preferences.hiddenCatalogues().set(
-                        if (checked) {
-                            current - id
+                    preferences.enabledLanguages().set(
+                        if (!checked) {
+                            current - lang
                         } else {
-                            current + id
+                            current + lang
                         }
                     )
-
                     true
                 }
             }
-
-            group.addPreference(sourcePreference)
         }
     }
 
-    private fun getSourceKey(sourceId: Long): String {
-        return "source_$sourceId"
+    override fun setDivider(divider: Drawable?) {
+        super.setDivider(null)
     }
 }

+ 5 - 10
app/src/main/res/layout/extension_detail_controller.xml

@@ -88,19 +88,14 @@
         app:layout_constraintEnd_toEndOf="parent"
         app:layout_constraintTop_toBottomOf="@id/extension_lang" />
 
-    <TextView
-        android:id="@+id/extension_prefs"
+    <androidx.recyclerview.widget.RecyclerView
+        android:id="@+id/extension_prefs_recycler"
         android:layout_width="0dp"
-        android:layout_height="@dimen/material_component_lists_two_line_height"
+        android:layout_height="0dp"
         android:layout_marginTop="16dp"
-        android:background="@drawable/list_item_selector"
-        android:gravity="center_vertical"
-        android:padding="16dp"
-        android:text="@string/label_settings"
-        android:visibility="gone"
+        app:layout_constraintBottom_toBottomOf="parent"
         app:layout_constraintEnd_toEndOf="parent"
         app:layout_constraintStart_toStartOf="parent"
-        app:layout_constraintTop_toBottomOf="@id/extension_uninstall_button"
-        tools:visibility="visible" />
+        app:layout_constraintTop_toBottomOf="@id/extension_uninstall_button" />
 
 </androidx.constraintlayout.widget.ConstraintLayout>

+ 0 - 20
app/src/main/res/layout/extension_preferences_controller.xml

@@ -1,20 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:tools="http://schemas.android.com/tools"
-    android:layout_width="match_parent"
-    android:layout_height="match_parent">
-
-    <androidx.recyclerview.widget.RecyclerView
-        android:id="@+id/extension_prefs_recycler"
-        android:layout_width="match_parent"
-        android:layout_height="match_parent" />
-
-    <eu.kanade.tachiyomi.widget.EmptyView
-        android:id="@+id/extension_prefs_empty_view"
-        android:layout_width="match_parent"
-        android:layout_height="match_parent"
-        android:gravity="center"
-        android:visibility="gone"
-        tools:visibility="visible" />
-
-</FrameLayout>

+ 14 - 0
app/src/main/res/menu/extension_details.xml

@@ -0,0 +1,14 @@
+<menu xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto">
+
+    <item
+        android:id="@+id/action_enable_all"
+        android:title="@string/action_enable_all"
+        app:showAsAction="never" />
+
+    <item
+        android:id="@+id/action_disable_all"
+        android:title="@string/action_disable_all"
+        app:showAsAction="never" />
+
+</menu>

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

@@ -55,6 +55,8 @@
     <string name="action_delete">Delete</string>
     <string name="action_update">Update</string>
     <string name="action_update_library">Update library</string>
+    <string name="action_enable_all">Enable all</string>
+    <string name="action_disable_all">Disable all</string>
     <string name="action_edit">Edit</string>
     <string name="action_add">Add</string>
     <string name="action_add_category">Add category</string>
@@ -222,7 +224,6 @@
     <string name="unofficial_extension_message">This extension is not from the official Tachiyomi extensions list.</string>
     <string name="ext_version_info">Version: %1$s</string>
     <string name="ext_language_info">Language: %1$s</string>
-    <string name="ext_empty_preferences">No preferences to edit for this extension</string>
 
       <!-- Reader section -->
     <string name="pref_fullscreen">Fullscreen</string>