mirror of
https://git.mihon.tech/mihonapp/mihon
synced 2024-11-27 17:49:16 +03:00
Manage sources from extension details (closes #3152)
This commit is contained in:
parent
0bf14fd31c
commit
54cfb2acdf
9 changed files with 253 additions and 322 deletions
|
@ -1,23 +1,61 @@
|
||||||
package eu.kanade.tachiyomi.ui.browse.extension
|
package eu.kanade.tachiyomi.ui.browse.extension
|
||||||
|
|
||||||
import android.annotation.SuppressLint
|
import android.annotation.SuppressLint
|
||||||
|
import android.content.Context
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
|
import android.util.TypedValue
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
|
import android.view.Menu
|
||||||
|
import android.view.MenuInflater
|
||||||
|
import android.view.MenuItem
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
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.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.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.ConfigurableSource
|
||||||
|
import eu.kanade.tachiyomi.source.Source
|
||||||
import eu.kanade.tachiyomi.ui.base.controller.NucleusController
|
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.system.LocaleHelper
|
||||||
import eu.kanade.tachiyomi.util.view.visible
|
import eu.kanade.tachiyomi.util.view.visible
|
||||||
import kotlinx.coroutines.flow.launchIn
|
import kotlinx.coroutines.flow.launchIn
|
||||||
import kotlinx.coroutines.flow.onEach
|
import kotlinx.coroutines.flow.onEach
|
||||||
import reactivecircus.flowbinding.android.view.clicks
|
import reactivecircus.flowbinding.android.view.clicks
|
||||||
|
import uy.kohesive.injekt.injectLazy
|
||||||
|
|
||||||
|
@SuppressLint("RestrictedApi")
|
||||||
class ExtensionDetailsController(bundle: Bundle? = null) :
|
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(
|
constructor(pkgName: String) : this(
|
||||||
Bundle().apply {
|
Bundle().apply {
|
||||||
|
@ -25,8 +63,13 @@ class ExtensionDetailsController(bundle: Bundle? = null) :
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
init {
|
||||||
|
setHasOptionsMenu(true)
|
||||||
|
}
|
||||||
|
|
||||||
override fun inflateView(inflater: LayoutInflater, container: ViewGroup): View {
|
override fun inflateView(inflater: LayoutInflater, container: ViewGroup): View {
|
||||||
binding = ExtensionDetailControllerBinding.inflate(inflater)
|
val themedInflater = inflater.cloneInContext(getPreferenceThemeContext())
|
||||||
|
binding = ExtensionDetailControllerBinding.inflate(themedInflater)
|
||||||
return binding.root
|
return binding.root
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -65,25 +108,186 @@ class ExtensionDetailsController(bundle: Bundle? = null) :
|
||||||
binding.extensionWarningBanner.setText(R.string.unofficial_extension_message)
|
binding.extensionWarningBanner.setText(R.string.unofficial_extension_message)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (presenter.extension?.sources?.find { it is ConfigurableSource } != null) {
|
initPreferences(context, extension)
|
||||||
binding.extensionPrefs.visible()
|
}
|
||||||
binding.extensionPrefs.clicks()
|
|
||||||
.onEach { openPreferences() }
|
private fun initPreferences(context: Context, extension: Extension.Installed) {
|
||||||
.launchIn(scope)
|
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() {
|
fun onExtensionUninstalled() {
|
||||||
router.popCurrentController()
|
router.popCurrentController()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun openPreferences() {
|
private fun toggleAllSources(enable: Boolean) {
|
||||||
router.pushController(
|
presenter.extension?.sources?.forEach { toggleSource(it, enable) }
|
||||||
ExtensionPreferencesController(presenter.extension!!.pkgName).withFadeTransaction()
|
}
|
||||||
|
|
||||||
|
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 {
|
private companion object {
|
||||||
const val PKGNAME_KEY = "pkg_name"
|
const val PKGNAME_KEY = "pkg_name"
|
||||||
|
const val LASTOPENPREFERENCE_KEY = "last_open_preference"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -36,11 +36,13 @@ class ExtensionFilterController : SettingsController() {
|
||||||
val checked = newValue as Boolean
|
val checked = newValue as Boolean
|
||||||
val currentActiveLangs = preferences.enabledLanguages().get()
|
val currentActiveLangs = preferences.enabledLanguages().get()
|
||||||
|
|
||||||
preferences.enabledLanguages().set(if (checked) {
|
preferences.enabledLanguages().set(
|
||||||
currentActiveLangs + it
|
if (checked) {
|
||||||
} else {
|
currentActiveLangs + it
|
||||||
currentActiveLangs - it
|
} else {
|
||||||
})
|
currentActiveLangs - it
|
||||||
|
}
|
||||||
|
)
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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"
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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 }
|
|
||||||
}
|
|
|
@ -1,15 +1,11 @@
|
||||||
package eu.kanade.tachiyomi.ui.setting
|
package eu.kanade.tachiyomi.ui.setting
|
||||||
|
|
||||||
import android.graphics.drawable.Drawable
|
import android.graphics.drawable.Drawable
|
||||||
import androidx.preference.CheckBoxPreference
|
|
||||||
import androidx.preference.PreferenceGroup
|
|
||||||
import androidx.preference.PreferenceScreen
|
import androidx.preference.PreferenceScreen
|
||||||
import eu.kanade.tachiyomi.R
|
import eu.kanade.tachiyomi.R
|
||||||
import eu.kanade.tachiyomi.source.SourceManager
|
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.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.preference.titleRes
|
||||||
import eu.kanade.tachiyomi.util.system.LocaleHelper
|
import eu.kanade.tachiyomi.util.system.LocaleHelper
|
||||||
import java.util.TreeMap
|
import java.util.TreeMap
|
||||||
|
@ -33,28 +29,22 @@ class SettingsSourcesController : SettingsController() {
|
||||||
val orderedLangs = sourcesByLang.keys.sortedWith(compareBy({ it !in activeLangsCodes }, { LocaleHelper.getSourceDisplayName(it, context) }))
|
val orderedLangs = sourcesByLang.keys.sortedWith(compareBy({ it !in activeLangsCodes }, { LocaleHelper.getSourceDisplayName(it, context) }))
|
||||||
|
|
||||||
orderedLangs.forEach { lang ->
|
orderedLangs.forEach { lang ->
|
||||||
val sources = sourcesByLang[lang].orEmpty().sortedBy { it.name }
|
switchPreference {
|
||||||
|
|
||||||
// Create a preference group and set initial state and change listener
|
|
||||||
switchPreferenceCategory {
|
|
||||||
preferenceScreen.addPreference(this)
|
preferenceScreen.addPreference(this)
|
||||||
title = LocaleHelper.getSourceDisplayName(lang, context)
|
title = LocaleHelper.getSourceDisplayName(lang, context)
|
||||||
isPersistent = false
|
isPersistent = false
|
||||||
if (lang in activeLangsCodes) {
|
isChecked = lang in activeLangsCodes
|
||||||
setChecked(true)
|
|
||||||
addLanguageSources(this, sources)
|
|
||||||
}
|
|
||||||
|
|
||||||
onChange { newValue ->
|
onChange { newValue ->
|
||||||
val checked = newValue as Boolean
|
val checked = newValue as Boolean
|
||||||
val current = preferences.enabledLanguages().get()
|
val current = preferences.enabledLanguages().get()
|
||||||
if (!checked) {
|
preferences.enabledLanguages().set(
|
||||||
preferences.enabledLanguages().set(current - lang)
|
if (!checked) {
|
||||||
removeAll()
|
current - lang
|
||||||
} else {
|
} else {
|
||||||
preferences.enabledLanguages().set(current + lang)
|
current + lang
|
||||||
addLanguageSources(this, sources)
|
}
|
||||||
}
|
)
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -64,49 +54,4 @@ class SettingsSourcesController : SettingsController() {
|
||||||
override fun setDivider(divider: Drawable?) {
|
override fun setDivider(divider: Drawable?) {
|
||||||
super.setDivider(null)
|
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
|
|
||||||
} else {
|
|
||||||
current + id
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
group.addPreference(sourcePreference)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun getSourceKey(sourceId: Long): String {
|
|
||||||
return "source_$sourceId"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -88,19 +88,14 @@
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
app:layout_constraintTop_toBottomOf="@id/extension_lang" />
|
app:layout_constraintTop_toBottomOf="@id/extension_lang" />
|
||||||
|
|
||||||
<TextView
|
<androidx.recyclerview.widget.RecyclerView
|
||||||
android:id="@+id/extension_prefs"
|
android:id="@+id/extension_prefs_recycler"
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
android:layout_height="@dimen/material_component_lists_two_line_height"
|
android:layout_height="0dp"
|
||||||
android:layout_marginTop="16dp"
|
android:layout_marginTop="16dp"
|
||||||
android:background="@drawable/list_item_selector"
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
android:gravity="center_vertical"
|
|
||||||
android:padding="16dp"
|
|
||||||
android:text="@string/label_settings"
|
|
||||||
android:visibility="gone"
|
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintTop_toBottomOf="@id/extension_uninstall_button"
|
app:layout_constraintTop_toBottomOf="@id/extension_uninstall_button" />
|
||||||
tools:visibility="visible" />
|
|
||||||
|
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
|
|
|
@ -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
app/src/main/res/menu/extension_details.xml
Normal file
14
app/src/main/res/menu/extension_details.xml
Normal file
|
@ -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>
|
|
@ -55,6 +55,8 @@
|
||||||
<string name="action_delete">Delete</string>
|
<string name="action_delete">Delete</string>
|
||||||
<string name="action_update">Update</string>
|
<string name="action_update">Update</string>
|
||||||
<string name="action_update_library">Update library</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_edit">Edit</string>
|
||||||
<string name="action_add">Add</string>
|
<string name="action_add">Add</string>
|
||||||
<string name="action_add_category">Add category</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="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_version_info">Version: %1$s</string>
|
||||||
<string name="ext_language_info">Language: %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 -->
|
<!-- Reader section -->
|
||||||
<string name="pref_fullscreen">Fullscreen</string>
|
<string name="pref_fullscreen">Fullscreen</string>
|
||||||
|
|
Loading…
Reference in a new issue