Added search/sorting/mass enable/disable to catalouge sources

This commit is contained in:
Jay 2019-12-17 00:18:19 -08:00
parent dd214f98fc
commit 5448a16b35
8 changed files with 186 additions and 20 deletions

View File

@ -67,6 +67,8 @@ object PreferenceKeys {
const val enabledLanguages = "source_languages"
const val sourcesSort = "sources_sort"
const val backupDirectory = "backup_directory"
const val downloadsDirectory = "download_directory"

View File

@ -98,6 +98,8 @@ class PreferencesHelper(val context: Context) {
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 sourcePassword(source: Source) = prefs.getString(Keys.sourcePassword(source.id), "")

View File

@ -1,9 +1,13 @@
package eu.kanade.tachiyomi.ui.catalogue
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 android.view.*
import com.bluelinelabs.conductor.ControllerChangeHandler
import com.bluelinelabs.conductor.ControllerChangeType
import com.bluelinelabs.conductor.RouterTransaction
@ -194,7 +198,7 @@ class CatalogueController : NucleusController<CataloguePresenter>(),
.subscribeUntilDestroy { performGlobalSearch(it.queryText().toString()) }
}
fun performGlobalSearch(query: String){
private fun performGlobalSearch(query: String){
router.pushController(CatalogueSearchController(query).withFadeTransaction())
}

View File

@ -81,7 +81,7 @@ open class ExtensionController : NucleusController<ExtensionPresenter>(),
override fun onOptionsItemSelected(item: MenuItem): Boolean {
when (item.itemId) {
R.id.action_settings -> {
R.id.action_filter -> {
router.pushController((RouterTransaction.with(SettingsExtensionsController()))
.popChangeHandler(SettingsExtensionsFadeChangeHandler())
.pushChangeHandler(FadeChangeHandler()))

View File

@ -1,8 +1,14 @@
package eu.kanade.tachiyomi.ui.setting
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.PreferenceScreen
import com.jakewharton.rxbinding.support.v7.widget.queryTextChanges
import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.data.preference.getOrDefault
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 uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.get
import java.util.*
import java.util.TreeMap
class SettingsSourcesController : SettingsController(),
SourceLoginDialog.Listener {
init {
setHasOptionsMenu(true)
}
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) {
titleRes = R.string.pref_category_sources
sorting = SourcesSort.from(preferences.sourceSorting().getOrDefault()) ?: SourcesSort.Alpha
activity?.invalidateOptionsMenu()
// Get the list of active language codes.
val activeLangsCodes = preferences.enabledLanguages().getOrDefault()
// 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
val orderedLangs = sourcesByLang.keys.filter { it in activeLangsCodes } +
sourcesByLang.keys.filterNot { it in activeLangsCodes }
orderedLangs = sourcesByLang.keys.filter { it in activeLangsCodes } + sourcesByLang.keys
.filterNot { it in activeLangsCodes }
orderedLangs.forEach { lang ->
val sources = sourcesByLang[lang].orEmpty().sortedBy { it.name }
// Create a preference group and set initial state and change listener
SwitchPreferenceCategory(context).apply {
langPrefs.add(Pair(lang, SwitchPreferenceCategory(context).apply {
preferenceScreen.addPreference(this)
title = LocaleHelper.getDisplayName(lang, context)
isPersistent = false
if (lang in activeLangsCodes) {
setChecked(true)
addLanguageSources(this, sources)
addLanguageSources(this, sortedSources(sourcesByLang[lang]))
}
onChange { newValue ->
@ -55,11 +71,11 @@ class SettingsSourcesController : SettingsController(),
removeAll()
} else {
preferences.enabledLanguages().set(current + lang)
addLanguageSources(this, sources)
addLanguageSources(this, sortedSources(sourcesByLang[lang]))
}
true
}
}
}))
}
}
@ -75,6 +91,29 @@ class SettingsSourcesController : SettingsController(),
private fun addLanguageSources(group: PreferenceGroup, sources: List<HttpSource>) {
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 ->
val sourcePreference = LoginCheckBoxPreference(group.context, source).apply {
val id = source.id.toString()
@ -82,16 +121,19 @@ class SettingsSourcesController : SettingsController(),
key = getSourceKey(source.id)
isPersistent = false
isChecked = id !in hiddenCatalogues
isVisible = query.isEmpty() || source.name.contains(query, ignoreCase = true)
onChange { newValue ->
val checked = newValue as Boolean
val current = preferences.hiddenCatalogues().getOrDefault()
preferences.hiddenCatalogues().set(if (checked)
current - id
else
current + id)
preferences.hiddenCatalogues().set(
if (checked) current - id
else current + id
)
group.removeAll()
addLanguageSources(group, sortedSources(sources))
true
}
@ -115,4 +157,90 @@ class SettingsSourcesController : SettingsController(),
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 }
}
}
}

View File

@ -9,7 +9,7 @@
app:actionViewClass="androidx.appcompat.widget.SearchView"/>
<item
android:id="@+id/action_settings"
android:id="@+id/action_filter"
android:title="@string/action_filter"
android:icon="@drawable/ic_filter_list_white_24dp"
app:showAsAction="always"/>

View 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>

View File

@ -38,6 +38,7 @@
<string name="action_filter_read">Read</string>
<string name="action_filter_empty">Remove filter</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_last_read">Last read</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_downloads">Downloads</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_advanced">Advanced</string>
<string name="pref_category_about">About</string>