Add tags blacklist option for suggestions
parent
6ca9608a80
commit
c92bdae842
@ -0,0 +1,118 @@
|
|||||||
|
package org.koitharu.kotatsu.settings.utils
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.util.AttributeSet
|
||||||
|
import android.widget.ArrayAdapter
|
||||||
|
import android.widget.EditText
|
||||||
|
import android.widget.Filter
|
||||||
|
import android.widget.MultiAutoCompleteTextView
|
||||||
|
import androidx.annotation.AttrRes
|
||||||
|
import androidx.annotation.MainThread
|
||||||
|
import androidx.annotation.StyleRes
|
||||||
|
import androidx.annotation.WorkerThread
|
||||||
|
import androidx.preference.EditTextPreference
|
||||||
|
import kotlinx.coroutines.runBlocking
|
||||||
|
import org.koitharu.kotatsu.R
|
||||||
|
import org.koitharu.kotatsu.parsers.util.replaceWith
|
||||||
|
|
||||||
|
class MultiAutoCompleteTextViewPreference @JvmOverloads constructor(
|
||||||
|
context: Context,
|
||||||
|
attrs: AttributeSet? = null,
|
||||||
|
@AttrRes defStyleAttr: Int = R.attr.multiAutoCompleteTextViewPreferenceStyle,
|
||||||
|
@StyleRes defStyleRes: Int = R.style.Preference_MultiAutoCompleteTextView,
|
||||||
|
) : EditTextPreference(context, attrs, defStyleAttr, defStyleRes) {
|
||||||
|
|
||||||
|
private val autoCompleteBindListener = AutoCompleteBindListener()
|
||||||
|
|
||||||
|
var autoCompleteProvider: AutoCompleteProvider? = null
|
||||||
|
|
||||||
|
init {
|
||||||
|
super.setOnBindEditTextListener(autoCompleteBindListener)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun setOnBindEditTextListener(onBindEditTextListener: OnBindEditTextListener?) {
|
||||||
|
autoCompleteBindListener.delegate = onBindEditTextListener
|
||||||
|
}
|
||||||
|
|
||||||
|
private inner class AutoCompleteBindListener : OnBindEditTextListener {
|
||||||
|
|
||||||
|
var delegate: OnBindEditTextListener? = null
|
||||||
|
|
||||||
|
override fun onBindEditText(editText: EditText) {
|
||||||
|
delegate?.onBindEditText(editText)
|
||||||
|
if (editText !is MultiAutoCompleteTextView) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
editText.setTokenizer(MultiAutoCompleteTextView.CommaTokenizer())
|
||||||
|
editText.setAdapter(
|
||||||
|
autoCompleteProvider?.let {
|
||||||
|
CompletionAdapter(editText.context, it, ArrayList())
|
||||||
|
}
|
||||||
|
)
|
||||||
|
editText.threshold = 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
interface AutoCompleteProvider {
|
||||||
|
|
||||||
|
suspend fun getSuggestions(query: String): List<String>
|
||||||
|
}
|
||||||
|
|
||||||
|
class SimpleSummaryProvider(
|
||||||
|
private val emptySummary: CharSequence?,
|
||||||
|
) : SummaryProvider<MultiAutoCompleteTextViewPreference> {
|
||||||
|
|
||||||
|
override fun provideSummary(preference: MultiAutoCompleteTextViewPreference): CharSequence? {
|
||||||
|
return if (preference.text.isNullOrEmpty()) {
|
||||||
|
emptySummary
|
||||||
|
} else {
|
||||||
|
preference.text?.trimEnd(' ', ',')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class CompletionAdapter(
|
||||||
|
context: Context,
|
||||||
|
private val completionProvider: AutoCompleteProvider,
|
||||||
|
private val dataset: MutableList<String>,
|
||||||
|
) : ArrayAdapter<String>(context, android.R.layout.simple_dropdown_item_1line, dataset) {
|
||||||
|
|
||||||
|
override fun getFilter(): Filter {
|
||||||
|
return CompletionFilter(this, completionProvider)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun publishResults(results: List<String>) {
|
||||||
|
dataset.replaceWith(results)
|
||||||
|
notifyDataSetChanged()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class CompletionFilter(
|
||||||
|
private val adapter: CompletionAdapter,
|
||||||
|
private val provider: AutoCompleteProvider,
|
||||||
|
) : Filter() {
|
||||||
|
|
||||||
|
@WorkerThread
|
||||||
|
override fun performFiltering(constraint: CharSequence?): FilterResults {
|
||||||
|
val query = constraint?.toString().orEmpty()
|
||||||
|
val suggestions = runBlocking { provider.getSuggestions(query) }
|
||||||
|
return CompletionResults(suggestions)
|
||||||
|
}
|
||||||
|
|
||||||
|
@MainThread
|
||||||
|
override fun publishResults(constraint: CharSequence?, results: FilterResults) {
|
||||||
|
val completions = (results as CompletionResults).completions
|
||||||
|
adapter.publishResults(completions)
|
||||||
|
}
|
||||||
|
|
||||||
|
private class CompletionResults(
|
||||||
|
val completions: List<String>,
|
||||||
|
) : FilterResults() {
|
||||||
|
|
||||||
|
init {
|
||||||
|
values = completions
|
||||||
|
count = completions.size
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,23 @@
|
|||||||
|
package org.koitharu.kotatsu.settings.utils
|
||||||
|
|
||||||
|
import org.koitharu.kotatsu.core.db.MangaDatabase
|
||||||
|
|
||||||
|
class TagsAutoCompleteProvider(
|
||||||
|
private val db: MangaDatabase,
|
||||||
|
) : MultiAutoCompleteTextViewPreference.AutoCompleteProvider {
|
||||||
|
|
||||||
|
override suspend fun getSuggestions(query: String): List<String> {
|
||||||
|
if (query.isEmpty()) {
|
||||||
|
return emptyList()
|
||||||
|
}
|
||||||
|
val tags = db.tagsDao.findTags(query = "$query%", limit = 6)
|
||||||
|
val set = HashSet<String>()
|
||||||
|
val result = ArrayList<String>(tags.size)
|
||||||
|
for (tag in tags) {
|
||||||
|
if (set.add(tag.title)) {
|
||||||
|
result.add(tag.title)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,42 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<ScrollView
|
||||||
|
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"
|
||||||
|
android:layout_marginTop="48dp"
|
||||||
|
android:layout_marginBottom="48dp"
|
||||||
|
android:overScrollMode="ifContentScrolls">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@android:id/message"
|
||||||
|
style="?android:attr/textAppearanceSmall"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="24dp"
|
||||||
|
android:layout_marginLeft="24dp"
|
||||||
|
android:layout_marginEnd="24dp"
|
||||||
|
android:layout_marginRight="24dp"
|
||||||
|
android:layout_marginBottom="48dp"
|
||||||
|
android:labelFor="@android:id/edit"
|
||||||
|
android:textColor="?android:attr/textColorSecondary"
|
||||||
|
tools:ignore="LabelFor" />
|
||||||
|
|
||||||
|
<MultiAutoCompleteTextView
|
||||||
|
android:id="@android:id/edit"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="20dp"
|
||||||
|
android:layout_marginLeft="20dp"
|
||||||
|
android:layout_marginEnd="20dp"
|
||||||
|
android:layout_marginRight="20dp"
|
||||||
|
android:importantForAutofill="no"
|
||||||
|
android:minHeight="48dp" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
</ScrollView>
|
||||||
Loading…
Reference in New Issue