Added search/sorting/mass enable/disable to catalouge sources
This commit is contained in:
parent
dd214f98fc
commit
5448a16b35
@ -67,6 +67,8 @@ object PreferenceKeys {
|
|||||||
|
|
||||||
const val enabledLanguages = "source_languages"
|
const val enabledLanguages = "source_languages"
|
||||||
|
|
||||||
|
const val sourcesSort = "sources_sort"
|
||||||
|
|
||||||
const val backupDirectory = "backup_directory"
|
const val backupDirectory = "backup_directory"
|
||||||
|
|
||||||
const val downloadsDirectory = "download_directory"
|
const val downloadsDirectory = "download_directory"
|
||||||
|
@ -98,6 +98,8 @@ class PreferencesHelper(val context: Context) {
|
|||||||
|
|
||||||
fun enabledLanguages() = rxPrefs.getStringSet(Keys.enabledLanguages, setOf("en", Locale.getDefault().language))
|
fun enabledLanguages() = rxPrefs.getStringSet(Keys.enabledLanguages, setOf("en", Locale.getDefault().language))
|
||||||
|
|
||||||
|
fun sourceSorting() = rxPrefs.getInteger(Keys.sourcesSort, 0)
|
||||||
|
|
||||||
fun sourceUsername(source: Source) = prefs.getString(Keys.sourceUsername(source.id), "")
|
fun sourceUsername(source: Source) = prefs.getString(Keys.sourceUsername(source.id), "")
|
||||||
|
|
||||||
fun sourcePassword(source: Source) = prefs.getString(Keys.sourcePassword(source.id), "")
|
fun sourcePassword(source: Source) = prefs.getString(Keys.sourcePassword(source.id), "")
|
||||||
|
@ -1,9 +1,13 @@
|
|||||||
package eu.kanade.tachiyomi.ui.catalogue
|
package eu.kanade.tachiyomi.ui.catalogue
|
||||||
|
|
||||||
import android.Manifest.permission.WRITE_EXTERNAL_STORAGE
|
import android.Manifest.permission.WRITE_EXTERNAL_STORAGE
|
||||||
import androidx.recyclerview.widget.LinearLayoutManager
|
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.widget.SearchView
|
import androidx.appcompat.widget.SearchView
|
||||||
import android.view.*
|
|
||||||
import com.bluelinelabs.conductor.ControllerChangeHandler
|
import com.bluelinelabs.conductor.ControllerChangeHandler
|
||||||
import com.bluelinelabs.conductor.ControllerChangeType
|
import com.bluelinelabs.conductor.ControllerChangeType
|
||||||
import com.bluelinelabs.conductor.RouterTransaction
|
import com.bluelinelabs.conductor.RouterTransaction
|
||||||
@ -194,7 +198,7 @@ class CatalogueController : NucleusController<CataloguePresenter>(),
|
|||||||
.subscribeUntilDestroy { performGlobalSearch(it.queryText().toString()) }
|
.subscribeUntilDestroy { performGlobalSearch(it.queryText().toString()) }
|
||||||
}
|
}
|
||||||
|
|
||||||
fun performGlobalSearch(query: String){
|
private fun performGlobalSearch(query: String){
|
||||||
router.pushController(CatalogueSearchController(query).withFadeTransaction())
|
router.pushController(CatalogueSearchController(query).withFadeTransaction())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -81,7 +81,7 @@ open class ExtensionController : NucleusController<ExtensionPresenter>(),
|
|||||||
|
|
||||||
override fun onOptionsItemSelected(item: MenuItem): Boolean {
|
override fun onOptionsItemSelected(item: MenuItem): Boolean {
|
||||||
when (item.itemId) {
|
when (item.itemId) {
|
||||||
R.id.action_settings -> {
|
R.id.action_filter -> {
|
||||||
router.pushController((RouterTransaction.with(SettingsExtensionsController()))
|
router.pushController((RouterTransaction.with(SettingsExtensionsController()))
|
||||||
.popChangeHandler(SettingsExtensionsFadeChangeHandler())
|
.popChangeHandler(SettingsExtensionsFadeChangeHandler())
|
||||||
.pushChangeHandler(FadeChangeHandler()))
|
.pushChangeHandler(FadeChangeHandler()))
|
||||||
|
@ -1,8 +1,14 @@
|
|||||||
package eu.kanade.tachiyomi.ui.setting
|
package eu.kanade.tachiyomi.ui.setting
|
||||||
|
|
||||||
import android.graphics.drawable.Drawable
|
import android.graphics.drawable.Drawable
|
||||||
|
import android.view.Menu
|
||||||
|
import android.view.MenuInflater
|
||||||
|
import android.view.MenuItem
|
||||||
|
import androidx.appcompat.widget.SearchView
|
||||||
|
import androidx.preference.CheckBoxPreference
|
||||||
import androidx.preference.PreferenceGroup
|
import androidx.preference.PreferenceGroup
|
||||||
import androidx.preference.PreferenceScreen
|
import androidx.preference.PreferenceScreen
|
||||||
|
import com.jakewharton.rxbinding.support.v7.widget.queryTextChanges
|
||||||
import eu.kanade.tachiyomi.R
|
import eu.kanade.tachiyomi.R
|
||||||
import eu.kanade.tachiyomi.data.preference.getOrDefault
|
import eu.kanade.tachiyomi.data.preference.getOrDefault
|
||||||
import eu.kanade.tachiyomi.source.SourceManager
|
import eu.kanade.tachiyomi.source.SourceManager
|
||||||
@ -14,37 +20,47 @@ import eu.kanade.tachiyomi.widget.preference.SourceLoginDialog
|
|||||||
import eu.kanade.tachiyomi.widget.preference.SwitchPreferenceCategory
|
import eu.kanade.tachiyomi.widget.preference.SwitchPreferenceCategory
|
||||||
import uy.kohesive.injekt.Injekt
|
import uy.kohesive.injekt.Injekt
|
||||||
import uy.kohesive.injekt.api.get
|
import uy.kohesive.injekt.api.get
|
||||||
import java.util.*
|
import java.util.TreeMap
|
||||||
|
|
||||||
class SettingsSourcesController : SettingsController(),
|
class SettingsSourcesController : SettingsController(),
|
||||||
SourceLoginDialog.Listener {
|
SourceLoginDialog.Listener {
|
||||||
|
|
||||||
|
init {
|
||||||
|
setHasOptionsMenu(true)
|
||||||
|
}
|
||||||
|
|
||||||
private val onlineSources by lazy { Injekt.get<SourceManager>().getOnlineSources() }
|
private val onlineSources by lazy { Injekt.get<SourceManager>().getOnlineSources() }
|
||||||
|
|
||||||
|
private var query = ""
|
||||||
|
|
||||||
|
private var orderedLangs = listOf<String>()
|
||||||
|
private var langPrefs = mutableListOf<Pair<String, SwitchPreferenceCategory>>()
|
||||||
|
private var sourcesByLang:TreeMap<String, MutableList<HttpSource>> = TreeMap()
|
||||||
|
private var sorting = SourcesSort.Alpha
|
||||||
|
|
||||||
override fun setupPreferenceScreen(screen: PreferenceScreen) = with(screen) {
|
override fun setupPreferenceScreen(screen: PreferenceScreen) = with(screen) {
|
||||||
titleRes = R.string.pref_category_sources
|
titleRes = R.string.pref_category_sources
|
||||||
|
sorting = SourcesSort.from(preferences.sourceSorting().getOrDefault()) ?: SourcesSort.Alpha
|
||||||
|
activity?.invalidateOptionsMenu()
|
||||||
// Get the list of active language codes.
|
// Get the list of active language codes.
|
||||||
val activeLangsCodes = preferences.enabledLanguages().getOrDefault()
|
val activeLangsCodes = preferences.enabledLanguages().getOrDefault()
|
||||||
|
|
||||||
// Get a map of sources grouped by language.
|
// Get a map of sources grouped by language.
|
||||||
val sourcesByLang = onlineSources.groupByTo(TreeMap(), { it.lang })
|
sourcesByLang = onlineSources.groupByTo(TreeMap(), { it.lang })
|
||||||
|
|
||||||
// Order first by active languages, then inactive ones
|
// Order first by active languages, then inactive ones
|
||||||
val orderedLangs = sourcesByLang.keys.filter { it in activeLangsCodes } +
|
orderedLangs = sourcesByLang.keys.filter { it in activeLangsCodes } + sourcesByLang.keys
|
||||||
sourcesByLang.keys.filterNot { it in activeLangsCodes }
|
.filterNot { it in activeLangsCodes }
|
||||||
|
|
||||||
orderedLangs.forEach { lang ->
|
orderedLangs.forEach { lang ->
|
||||||
val sources = sourcesByLang[lang].orEmpty().sortedBy { it.name }
|
|
||||||
|
|
||||||
// Create a preference group and set initial state and change listener
|
// Create a preference group and set initial state and change listener
|
||||||
SwitchPreferenceCategory(context).apply {
|
langPrefs.add(Pair(lang, SwitchPreferenceCategory(context).apply {
|
||||||
preferenceScreen.addPreference(this)
|
preferenceScreen.addPreference(this)
|
||||||
title = LocaleHelper.getDisplayName(lang, context)
|
title = LocaleHelper.getDisplayName(lang, context)
|
||||||
isPersistent = false
|
isPersistent = false
|
||||||
if (lang in activeLangsCodes) {
|
if (lang in activeLangsCodes) {
|
||||||
setChecked(true)
|
setChecked(true)
|
||||||
addLanguageSources(this, sources)
|
addLanguageSources(this, sortedSources(sourcesByLang[lang]))
|
||||||
}
|
}
|
||||||
|
|
||||||
onChange { newValue ->
|
onChange { newValue ->
|
||||||
@ -55,11 +71,11 @@ class SettingsSourcesController : SettingsController(),
|
|||||||
removeAll()
|
removeAll()
|
||||||
} else {
|
} else {
|
||||||
preferences.enabledLanguages().set(current + lang)
|
preferences.enabledLanguages().set(current + lang)
|
||||||
addLanguageSources(this, sources)
|
addLanguageSources(this, sortedSources(sourcesByLang[lang]))
|
||||||
}
|
}
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
}
|
}))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -75,6 +91,29 @@ class SettingsSourcesController : SettingsController(),
|
|||||||
private fun addLanguageSources(group: PreferenceGroup, sources: List<HttpSource>) {
|
private fun addLanguageSources(group: PreferenceGroup, sources: List<HttpSource>) {
|
||||||
val hiddenCatalogues = preferences.hiddenCatalogues().getOrDefault()
|
val hiddenCatalogues = preferences.hiddenCatalogues().getOrDefault()
|
||||||
|
|
||||||
|
val selectAllPreference = CheckBoxPreference(group.context).apply {
|
||||||
|
|
||||||
|
title = "\t\t${context.getString(R.string.pref_category_all_sources)}"
|
||||||
|
key = "all_${sources.first().lang}"
|
||||||
|
isPersistent = false
|
||||||
|
isChecked = sources.all { it.id.toString() !in hiddenCatalogues }
|
||||||
|
isVisible = query.isEmpty()
|
||||||
|
|
||||||
|
onChange { newValue ->
|
||||||
|
val checked = newValue as Boolean
|
||||||
|
val current = preferences.hiddenCatalogues().getOrDefault()
|
||||||
|
if (checked)
|
||||||
|
current.removeAll(sources.map { it.id.toString() })
|
||||||
|
else
|
||||||
|
current.addAll(sources.map { it.id.toString() })
|
||||||
|
preferences.hiddenCatalogues().set(current)
|
||||||
|
group.removeAll()
|
||||||
|
addLanguageSources(group, sortedSources(sources))
|
||||||
|
true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
group.addPreference(selectAllPreference)
|
||||||
|
|
||||||
sources.forEach { source ->
|
sources.forEach { source ->
|
||||||
val sourcePreference = LoginCheckBoxPreference(group.context, source).apply {
|
val sourcePreference = LoginCheckBoxPreference(group.context, source).apply {
|
||||||
val id = source.id.toString()
|
val id = source.id.toString()
|
||||||
@ -82,16 +121,19 @@ class SettingsSourcesController : SettingsController(),
|
|||||||
key = getSourceKey(source.id)
|
key = getSourceKey(source.id)
|
||||||
isPersistent = false
|
isPersistent = false
|
||||||
isChecked = id !in hiddenCatalogues
|
isChecked = id !in hiddenCatalogues
|
||||||
|
isVisible = query.isEmpty() || source.name.contains(query, ignoreCase = true)
|
||||||
|
|
||||||
onChange { newValue ->
|
onChange { newValue ->
|
||||||
val checked = newValue as Boolean
|
val checked = newValue as Boolean
|
||||||
val current = preferences.hiddenCatalogues().getOrDefault()
|
val current = preferences.hiddenCatalogues().getOrDefault()
|
||||||
|
|
||||||
preferences.hiddenCatalogues().set(if (checked)
|
preferences.hiddenCatalogues().set(
|
||||||
current - id
|
if (checked) current - id
|
||||||
else
|
else current + id
|
||||||
current + id)
|
)
|
||||||
|
|
||||||
|
group.removeAll()
|
||||||
|
addLanguageSources(group, sortedSources(sources))
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -115,4 +157,90 @@ class SettingsSourcesController : SettingsController(),
|
|||||||
return "source_$sourceId"
|
return "source_$sourceId"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds items to the options menu.
|
||||||
|
*
|
||||||
|
* @param menu menu containing options.
|
||||||
|
* @param inflater used to load the menu xml.
|
||||||
|
*/
|
||||||
|
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
|
||||||
|
inflater.inflate(R.menu.settings_sources, menu)
|
||||||
|
if (sorting == SourcesSort.Alpha) menu.findItem(R.id.action_sort_alpha).isChecked = true
|
||||||
|
else menu.findItem(R.id.action_sort_enabled).isChecked = true
|
||||||
|
|
||||||
|
val searchItem = menu.findItem(R.id.action_search)
|
||||||
|
val searchView = searchItem.actionView as SearchView
|
||||||
|
searchView.maxWidth = Int.MAX_VALUE
|
||||||
|
|
||||||
|
if (query.isNotEmpty()) {
|
||||||
|
searchItem.expandActionView()
|
||||||
|
searchView.setQuery(query, true)
|
||||||
|
searchView.clearFocus()
|
||||||
|
}
|
||||||
|
|
||||||
|
searchView.queryTextChanges().filter { router.backstack.lastOrNull()?.controller() == this }
|
||||||
|
.subscribeUntilDestroy {
|
||||||
|
query = it.toString()
|
||||||
|
drawSources()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fixes problem with the overflow icon showing up in lieu of search
|
||||||
|
searchItem.setOnActionExpandListener(object : MenuItem.OnActionExpandListener {
|
||||||
|
override fun onMenuItemActionExpand(item: MenuItem): Boolean {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onMenuItemActionCollapse(item: MenuItem): Boolean {
|
||||||
|
activity?.invalidateOptionsMenu()
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun drawSources() {
|
||||||
|
val activeLangsCodes = preferences.enabledLanguages().getOrDefault()
|
||||||
|
langPrefs.forEach { group ->
|
||||||
|
if (group.first in activeLangsCodes) {
|
||||||
|
group.second.removeAll()
|
||||||
|
addLanguageSources(group.second, sortedSources(sourcesByLang[group.first]))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun sortedSources(sources: List<HttpSource>?): List<HttpSource> {
|
||||||
|
val sourceAlpha = sources.orEmpty().sortedBy { it.name }
|
||||||
|
return if (sorting == SourcesSort.Enabled) {
|
||||||
|
val hiddenCatalogues = preferences.hiddenCatalogues().getOrDefault()
|
||||||
|
sourceAlpha.filter { it.id.toString() !in hiddenCatalogues } +
|
||||||
|
sourceAlpha.filterNot { it.id.toString() !in hiddenCatalogues }
|
||||||
|
} else {
|
||||||
|
sourceAlpha
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called when an option menu item has been selected by the user.
|
||||||
|
*
|
||||||
|
* @param item The selected item.
|
||||||
|
* @return True if this event has been consumed, false if it has not.
|
||||||
|
*/
|
||||||
|
override fun onOptionsItemSelected(item: MenuItem): Boolean {
|
||||||
|
sorting = when (item.itemId) {
|
||||||
|
R.id.action_sort_alpha -> SourcesSort.Alpha
|
||||||
|
R.id.action_sort_enabled -> SourcesSort.Enabled
|
||||||
|
else -> return super.onOptionsItemSelected(item)
|
||||||
|
}
|
||||||
|
item.isChecked = true
|
||||||
|
preferences.sourceSorting().set(sorting.value)
|
||||||
|
drawSources()
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
enum class SourcesSort(val value: Int) {
|
||||||
|
Alpha(0), Enabled(1);
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
fun from(i: Int): SourcesSort? = values().find { it.value == i }
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
@ -9,7 +9,7 @@
|
|||||||
app:actionViewClass="androidx.appcompat.widget.SearchView"/>
|
app:actionViewClass="androidx.appcompat.widget.SearchView"/>
|
||||||
|
|
||||||
<item
|
<item
|
||||||
android:id="@+id/action_settings"
|
android:id="@+id/action_filter"
|
||||||
android:title="@string/action_filter"
|
android:title="@string/action_filter"
|
||||||
android:icon="@drawable/ic_filter_list_white_24dp"
|
android:icon="@drawable/ic_filter_list_white_24dp"
|
||||||
app:showAsAction="always"/>
|
app:showAsAction="always"/>
|
||||||
|
28
app/src/main/res/menu/settings_sources.xml
Normal file
28
app/src/main/res/menu/settings_sources.xml
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<menu xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||||
|
<item
|
||||||
|
android:id="@+id/action_search"
|
||||||
|
android:title="@string/action_search"
|
||||||
|
android:icon="@drawable/ic_search_white_24dp"
|
||||||
|
app:showAsAction="collapseActionView|ifRoom"
|
||||||
|
app:actionViewClass="androidx.appcompat.widget.SearchView"/>
|
||||||
|
|
||||||
|
<item
|
||||||
|
android:id="@+id/action_sort"
|
||||||
|
android:title="@string/action_sort"
|
||||||
|
android:icon="@drawable/ic_sort_white_24dp"
|
||||||
|
app:showAsAction="ifRoom">
|
||||||
|
<menu>
|
||||||
|
<group android:id="@+id/group"
|
||||||
|
android:checkableBehavior="single">
|
||||||
|
<item
|
||||||
|
android:id="@+id/action_sort_alpha"
|
||||||
|
android:title="@string/action_sort_alpha"/>
|
||||||
|
<item
|
||||||
|
android:id="@+id/action_sort_enabled"
|
||||||
|
android:title="@string/action_sort_enabled"/>
|
||||||
|
</group>
|
||||||
|
</menu>
|
||||||
|
</item>
|
||||||
|
</menu>
|
@ -38,6 +38,7 @@
|
|||||||
<string name="action_filter_read">Read</string>
|
<string name="action_filter_read">Read</string>
|
||||||
<string name="action_filter_empty">Remove filter</string>
|
<string name="action_filter_empty">Remove filter</string>
|
||||||
<string name="action_sort_alpha">Alphabetically</string>
|
<string name="action_sort_alpha">Alphabetically</string>
|
||||||
|
<string name="action_sort_enabled">Enabled</string>
|
||||||
<string name="action_sort_total">Total chapters</string>
|
<string name="action_sort_total">Total chapters</string>
|
||||||
<string name="action_sort_last_read">Last read</string>
|
<string name="action_sort_last_read">Last read</string>
|
||||||
<string name="action_sort_last_updated">Last updated</string>
|
<string name="action_sort_last_updated">Last updated</string>
|
||||||
@ -116,6 +117,7 @@
|
|||||||
<string name="pref_category_reader">Reader</string>
|
<string name="pref_category_reader">Reader</string>
|
||||||
<string name="pref_category_downloads">Downloads</string>
|
<string name="pref_category_downloads">Downloads</string>
|
||||||
<string name="pref_category_sources">Sources</string>
|
<string name="pref_category_sources">Sources</string>
|
||||||
|
<string name="pref_category_all_sources">All Sources</string>
|
||||||
<string name="pref_category_tracking">Tracking</string>
|
<string name="pref_category_tracking">Tracking</string>
|
||||||
<string name="pref_category_advanced">Advanced</string>
|
<string name="pref_category_advanced">Advanced</string>
|
||||||
<string name="pref_category_about">About</string>
|
<string name="pref_category_about">About</string>
|
||||||
|
Loading…
Reference in New Issue
Block a user