Suggestion

This commit is contained in:
tom5079
2020-12-02 09:57:16 +09:00
parent 26c5e07f04
commit 730a3baedc
17 changed files with 227 additions and 241 deletions

View File

@@ -44,8 +44,10 @@ android {
}
buildTypes {
debug {
minifyEnabled true
shrinkResources true
minifyEnabled false
shrinkResources false
multiDexEnabled true
debuggable true
applicationIdSuffix ".debug"
@@ -128,7 +130,7 @@ dependencies {
implementation "xyz.quaver:libpupil:1.9.7"
implementation "xyz.quaver:documentfilex:0.4-alpha02"
implementation "xyz.quaver:floatingsearchview:1.0.9"
implementation "xyz.quaver:floatingsearchview:1.1.1"
testImplementation "junit:junit:4.13.1"
androidTestImplementation "androidx.test.ext:junit:1.1.2"

View File

@@ -20,18 +20,18 @@ package xyz.quaver.pupil.adapters
import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.core.graphics.drawable.DrawableCompat
import androidx.recyclerview.widget.RecyclerView
import xyz.quaver.floatingsearchview.suggestions.model.SearchSuggestion
import xyz.quaver.pupil.databinding.SourceSelectDialogItemBinding
import xyz.quaver.pupil.sources.Source
import xyz.quaver.pupil.sources.sourceIcons
class SourceAdapter(private val sources: List<Source<*>>) : RecyclerView.Adapter<SourceAdapter.ViewHolder>() {
class SourceAdapter(private val sources: List<Source<*, SearchSuggestion>>) : RecyclerView.Adapter<SourceAdapter.ViewHolder>() {
var onSourceSelectedListener: ((Source<*>) -> Unit)? = null
var onSourceSelectedListener: ((Source<*, SearchSuggestion>) -> Unit)? = null
inner class ViewHolder(private val binding: SourceSelectDialogItemBinding) : RecyclerView.ViewHolder(binding.root) {
lateinit var source: Source<*>
lateinit var source: Source<*, SearchSuggestion>
init {
binding.go.setOnClickListener {
@@ -39,7 +39,7 @@ class SourceAdapter(private val sources: List<Source<*>>) : RecyclerView.Adapter
}
}
fun bind(source: Source<*>) {
fun bind(source: Source<*, SearchSuggestion>) {
this.source = source
binding.icon.setImageDrawable(sourceIcons[source.name])

View File

@@ -22,9 +22,10 @@ import android.content.Context
import android.graphics.drawable.Drawable
import androidx.core.content.ContextCompat
import kotlinx.coroutines.channels.Channel
import kotlinx.parcelize.Parcelize
import xyz.quaver.floatingsearchview.databinding.SearchSuggestionItemBinding
import xyz.quaver.floatingsearchview.suggestions.model.SearchSuggestion
import xyz.quaver.pupil.R
import xyz.quaver.pupil.sources.hitomi.Hitomi
import xyz.quaver.pupil.sources.hitomi.Hiyobi
data class SearchResult(
val id: String,
@@ -56,15 +57,24 @@ data class SearchResult(
enum class DefaultSortMode {
DEFAULT
}
interface Source<Query_SortMode : Enum<Query_SortMode>> {
val name: String
val iconResID: Int
val availableSortMode: Array<Query_SortMode>
suspend fun query(query: String, range: IntRange, sortMode: Enum<*>) : Pair<Channel<SearchResult>, Int>
@Parcelize
class DefaultSearchSuggestion(override val body: String) : SearchSuggestion
abstract class Source<Query_SortMode: Enum<Query_SortMode>, Suggestion: SearchSuggestion> {
abstract val name: String
abstract val iconResID: Int
abstract val availableSortMode: Array<Query_SortMode>
abstract suspend fun search(query: String, range: IntRange, sortMode: Enum<*>) : Pair<Channel<SearchResult>, Int>
abstract suspend fun suggestion(query: String) : List<Suggestion>
open fun onSuggestionBind(binding: SearchSuggestionItemBinding, item: Suggestion) {
binding.leftIcon.setImageResource(R.drawable.tag)
}
}
val sources = mutableMapOf<String, Source<*>>()
val sources = mutableMapOf<String, Source<*, SearchSuggestion>>()
val sourceIcons = mutableMapOf<String, Drawable?>()
@Suppress("UNCHECKED_CAST")
@@ -74,7 +84,7 @@ fun initSources(context: Context) {
Hitomi(),
Hiyobi()
).forEach {
sources[it.name] = it
sources[it.name] = it as Source<*, SearchSuggestion>
sourceIcons[it.name] = ContextCompat.getDrawable(context, it.iconResID)
}
}

View File

@@ -16,26 +16,45 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package xyz.quaver.pupil.sources.hitomi
package xyz.quaver.pupil.sources
import android.view.LayoutInflater
import android.widget.TextView
import androidx.core.content.ContextCompat
import kotlinx.coroutines.*
import kotlinx.coroutines.channels.Channel
import kotlinx.parcelize.IgnoredOnParcel
import kotlinx.parcelize.Parcelize
import xyz.quaver.floatingsearchview.databinding.SearchSuggestionItemBinding
import xyz.quaver.floatingsearchview.suggestions.model.SearchSuggestion
import xyz.quaver.hitomi.*
import xyz.quaver.pupil.R
import xyz.quaver.pupil.sources.SearchResult
import xyz.quaver.pupil.sources.SearchResult.ExtraType
import xyz.quaver.pupil.sources.Source
import xyz.quaver.pupil.util.translations
import xyz.quaver.pupil.util.wordCapitalize
import kotlin.math.max
import kotlin.math.min
class Hitomi : Source<Hitomi.SortMode> {
class Hitomi : Source<Hitomi.SortMode, Hitomi.TagSuggestion>() {
enum class SortMode {
NEWEST,
POPULAR
}
@Parcelize
data class TagSuggestion(val s: String, val t: Int, val u: String, val n: String) :
SearchSuggestion {
constructor(s: Suggestion) : this(s.s, s.t, s.u, s.n)
@IgnoredOnParcel
override val body =
if (translations[s] != null)
"${translations[s]} ($s)"
else
s
}
override val name: String = "hitomi.la"
override val iconResID: Int = R.drawable.hitomi
override val availableSortMode: Array<SortMode> = SortMode.values()
@@ -44,7 +63,7 @@ class Hitomi : Source<Hitomi.SortMode> {
var cachedSortMode: SortMode? = null
val cache = mutableListOf<Int>()
override suspend fun query(query: String, range: IntRange, sortMode: Enum<*>): Pair<Channel<SearchResult>, Int> {
override suspend fun search(query: String, range: IntRange, sortMode: Enum<*>): Pair<Channel<SearchResult>, Int> {
if (cachedQuery != query || cachedSortMode != sortMode || cache.isEmpty()) {
cachedQuery = null
cache.clear()
@@ -79,6 +98,44 @@ class Hitomi : Source<Hitomi.SortMode> {
return Pair(channel, cache.size)
}
override suspend fun suggestion(query: String) : List<TagSuggestion> {
return getSuggestionsForQuery(query.takeLastWhile { !it.isWhitespace() }).map {
TagSuggestion(it)
}
}
override fun onSuggestionBind(binding: SearchSuggestionItemBinding, item: TagSuggestion) {
binding.leftIcon.setImageResource(
when(item.n) {
"female" -> R.drawable.gender_female
"male" -> R.drawable.gender_male
"language" -> R.drawable.translate
"group" -> R.drawable.account_group
"character" -> R.drawable.account_star
"series" -> R.drawable.book_open
"artist" -> R.drawable.brush
else -> R.drawable.tag
}
)
if (item.t > 0) {
with (binding.root) {
val count = findViewById<TextView>(R.id.count)
if (count == null)
addView(
LayoutInflater.from(context).inflate(R.layout.suggestion_count, binding.root, false)
.apply {
this as TextView
text = item.t.toString()
}, 2
)
else
count.text = item.t.toString()
}
}
}
companion object {
val languageMap = mapOf(
"indonesian" to "Bahasa Indonesia",

View File

@@ -16,27 +16,30 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package xyz.quaver.pupil.sources.hitomi
package xyz.quaver.pupil.sources
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import androidx.core.content.ContextCompat
import kotlinx.coroutines.*
import kotlinx.coroutines.channels.Channel
import kotlinx.coroutines.launch
import xyz.quaver.hitomi.galleryblockdir
import kotlinx.serialization.decodeFromString
import kotlinx.serialization.json.Json
import okhttp3.Request
import xyz.quaver.floatingsearchview.databinding.SearchSuggestionItemBinding
import xyz.quaver.floatingsearchview.suggestions.model.SearchSuggestion
import xyz.quaver.hiyobi.*
import xyz.quaver.pupil.R
import xyz.quaver.pupil.sources.DefaultSortMode
import xyz.quaver.pupil.sources.SearchResult
import xyz.quaver.pupil.sources.Source
import xyz.quaver.pupil.client
import xyz.quaver.pupil.util.wordCapitalize
import java.io.IOException
import java.util.*
class Hiyobi : Source<DefaultSortMode> {
class Hiyobi : Source<DefaultSortMode, DefaultSearchSuggestion>() {
override val name: String = "hiyobi.me"
override val iconResID: Int = R.drawable.ic_hiyobi
override val availableSortMode: Array<DefaultSortMode> = DefaultSortMode.values()
override suspend fun query(query: String, range: IntRange, sortMode: Enum<*>): Pair<Channel<SearchResult>, Int> {
override suspend fun search(query: String, range: IntRange, sortMode: Enum<*>): Pair<Channel<SearchResult>, Int> {
val channel = Channel<SearchResult>()
val (results, total) = if (query.isEmpty())
@@ -55,7 +58,58 @@ class Hiyobi : Source<DefaultSortMode> {
return Pair(channel, total)
}
override suspend fun suggestion(query: String): List<DefaultSearchSuggestion> {
val result = mutableSetOf<String>()
for (tag in allTags.await()) {
if (result.size >= 10)
break
val lowQuery = query.toLowerCase(Locale.ROOT)
if (tag.contains(lowQuery, true))
result.add(tag)
}
return result.map { DefaultSearchSuggestion(it) }
}
override fun onSuggestionBind(binding: SearchSuggestionItemBinding, item: DefaultSearchSuggestion) {
val split = item.body.split(':', limit = 2)
if (split.size != 2)
return
binding.leftIcon.setImageResource(
when(split.first()) {
"female" -> R.drawable.gender_female
"male" -> R.drawable.gender_male
"language" -> R.drawable.translate
"group" -> R.drawable.account_group
"character" -> R.drawable.account_star
"series" -> R.drawable.book_open
"artist" -> R.drawable.brush
else -> R.drawable.tag
}
)
binding.body.text = split.last()
}
companion object {
private fun downloadAllTags(): Deferred<List<String>> = CoroutineScope(Dispatchers.IO).async {
Json.decodeFromString(kotlin.runCatching {
client.newCall(Request.Builder().url("https://api.hiyobi.me/auto.json").build()).execute().also { if (it.code() != 200) throw IOException() }.body()?.use { it.string() }
}.getOrNull() ?: "[]")
}
private var _allTags: Deferred<List<String>>? = null
val allTags: Deferred<List<String>>
get() = if (_allTags == null || (_allTags!!.isCompleted && runBlocking { _allTags!!.await() }.isEmpty())) downloadAllTags().also {
_allTags = it
} else _allTags!!
fun transform(galleryBlock: GalleryBlock): SearchResult =
SearchResult(
galleryBlock.id,

View File

@@ -18,26 +18,11 @@
package xyz.quaver.pupil.types
import kotlinx.parcelize.IgnoredOnParcel
import kotlinx.parcelize.Parcelize
import xyz.quaver.floatingsearchview.suggestions.model.SearchSuggestion
import xyz.quaver.hitomi.Suggestion
import xyz.quaver.pupil.util.translations
@Parcelize
data class TagSuggestion(val s: String, val t: Int, val u: String, val n: String) : SearchSuggestion {
constructor(s: Suggestion) : this(s.s, s.t, s.u, s.n)
@IgnoredOnParcel
override val body =
if (translations[s] != null)
"${translations[s]} ($s)"
else
s
}
@Parcelize
class Suggestion(override val body: String) : SearchSuggestion
class HistorySuggestion(override val body: String) : SearchSuggestion
@Parcelize
class NoResultSuggestion(override val body: String) : SearchSuggestion

View File

@@ -47,7 +47,6 @@ import kotlinx.coroutines.channels.Channel
import xyz.quaver.floatingsearchview.FloatingSearchView
import xyz.quaver.floatingsearchview.suggestions.model.SearchSuggestion
import xyz.quaver.floatingsearchview.util.view.SearchInputView
import xyz.quaver.hitomi.getSuggestionsForQuery
import xyz.quaver.pupil.*
import xyz.quaver.pupil.adapters.SearchResultsAdapter
import xyz.quaver.pupil.databinding.MainActivityBinding
@@ -84,7 +83,7 @@ class MainActivity :
}
private var queryStack = mutableListOf<String>()
private lateinit var source: Source<*>
private lateinit var source: Source<*, SearchSuggestion>
private lateinit var sortMode: Enum<*>
private var searchJob: Deferred<Pair<Channel<SearchResult>, Int>>? = null
@@ -168,7 +167,7 @@ class MainActivity :
}
}
private fun setSource(source: Source<*>) {
private fun setSource(source: Source<*, SearchSuggestion>) {
this.source = source
sortMode = source.availableSortMode.first()
@@ -259,7 +258,7 @@ class MainActivity :
val random = Random.Default.nextInt(totalItems)
val randomResult =
source.query(
source.search(
query + Preferences["default_query", ""],
random .. random,
sortMode
@@ -406,21 +405,6 @@ class MainActivity :
}
}
private var isFavorite = false
private val defaultSuggestions: List<SearchSuggestion>
get() = when {
isFavorite -> {
favoriteTags.map {
TagSuggestion(it.tag, -1, "", it.area ?: "tag")
} + FavoriteHistorySwitch(getString(R.string.search_show_histories))
}
else -> {
searchHistory.map {
Suggestion(it)
}.takeLast(10) + FavoriteHistorySwitch(getString(R.string.search_show_tags))
}
}.reversed()
private var suggestionJob : Job? = null
private fun setupSearchBar() {
with (binding.contents.searchview) {
@@ -434,15 +418,6 @@ class MainActivity :
}
}
onHistoryDeleteClickedListener = {
searchHistory.remove(it)
swapSuggestions(defaultSuggestions)
}
onFavoriteHistorySwitchClickListener = {
isFavorite = !isFavorite
swapSuggestions(defaultSuggestions)
}
onMenuItemClickListener = {
onActionMenuItemSelected(it)
}
@@ -452,12 +427,6 @@ class MainActivity :
suggestionJob?.cancel()
if (query.isEmpty() or query.endsWith(' ')) {
swapSuggestions(defaultSuggestions)
return@lambda
}
swapSuggestions(listOf(LoadingSuggestion(getText(R.string.reader_loading).toString())))
val currentQuery = query.split(" ").last()
@@ -466,16 +435,8 @@ class MainActivity :
suggestionJob = CoroutineScope(Dispatchers.IO).launch {
val suggestions = kotlin.runCatching {
getSuggestionsForQuery(currentQuery).map { TagSuggestion(it) }.toMutableList()
}.getOrElse { mutableListOf() }
suggestions.filter {
val tag = "${it.n}:${it.s.replace(Regex("\\s"), "_")}"
favoriteTags.contains(Tag.parse(tag))
}.reversed().forEach {
suggestions.remove(it)
suggestions.add(0, it)
}
source.suggestion(currentQuery)
}.getOrElse { emptyList() }
withContext(Dispatchers.Main) {
swapSuggestions(if (suggestions.isNotEmpty()) suggestions else listOf(NoResultSuggestion(getText(R.string.main_no_result).toString())))
@@ -483,10 +444,13 @@ class MainActivity :
}
}
onSuggestionBinding = { binding, item ->
source.onSuggestionBind(binding, item)
}
onFocusChangeListener = object: FloatingSearchView.OnFocusChangeListener {
override fun onFocus() {
if (query.isEmpty() or query.endsWith(' '))
swapSuggestions(defaultSuggestions)
}
override fun onFocusCleared() {
@@ -577,7 +541,7 @@ class MainActivity :
CoroutineScope(Dispatchers.Main).launch {
searchJob = async(Dispatchers.IO) {
source.query(
source.search(
query + Preferences["default_query", ""],
(currentPage - 1) * perPage until currentPage * perPage,
sortMode

View File

@@ -27,7 +27,7 @@ import androidx.appcompat.app.AlertDialog
import androidx.fragment.app.DialogFragment
import xyz.quaver.pupil.R
import xyz.quaver.pupil.databinding.DefaultQueryDialogBinding
import xyz.quaver.pupil.sources.hitomi.Hitomi
import xyz.quaver.pupil.sources.Hitomi
import xyz.quaver.pupil.types.Tags
import xyz.quaver.pupil.util.Preferences

View File

@@ -42,7 +42,7 @@ import xyz.quaver.pupil.adapters.SearchResultsAdapter
import xyz.quaver.pupil.adapters.ThumbnailPageAdapter
import xyz.quaver.pupil.databinding.*
import xyz.quaver.pupil.favoriteTags
import xyz.quaver.pupil.sources.hitomi.Hitomi
import xyz.quaver.pupil.sources.Hitomi
import xyz.quaver.pupil.sources.SearchResult
import xyz.quaver.pupil.types.Tag
import xyz.quaver.pupil.ui.ReaderActivity

View File

@@ -25,13 +25,14 @@ import android.view.Window
import androidx.fragment.app.DialogFragment
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import xyz.quaver.floatingsearchview.suggestions.model.SearchSuggestion
import xyz.quaver.pupil.adapters.SourceAdapter
import xyz.quaver.pupil.sources.Source
import xyz.quaver.pupil.sources.sources
class SourceSelectDialog : DialogFragment() {
var onSourceSelectedListener: ((Source<*>) -> Unit)? = null
var onSourceSelectedListener: ((Source<*, SearchSuggestion>) -> Unit)? = null
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
return Dialog(requireContext()).apply {

View File

@@ -28,18 +28,20 @@ import android.util.AttributeSet
import android.view.LayoutInflater
import android.view.View
import android.view.inputmethod.EditorInfo
import android.widget.ImageView
import android.widget.LinearLayout
import android.widget.TextView
import androidx.core.content.ContextCompat
import androidx.core.content.res.ResourcesCompat
import androidx.swiperefreshlayout.widget.CircularProgressDrawable
import androidx.vectordrawable.graphics.drawable.AnimatedVectorDrawableCompat
import xyz.quaver.floatingsearchview.FloatingSearchView
import xyz.quaver.floatingsearchview.databinding.SearchSuggestionItemBinding
import xyz.quaver.floatingsearchview.suggestions.model.SearchSuggestion
import xyz.quaver.floatingsearchview.util.view.SearchInputView
import xyz.quaver.pupil.R
import xyz.quaver.pupil.databinding.SuggestionCountBinding
import xyz.quaver.pupil.favoriteTags
import xyz.quaver.pupil.sources.DefaultSearchSuggestion
import xyz.quaver.pupil.sources.Hitomi
import xyz.quaver.pupil.types.*
import java.util.*
@@ -53,13 +55,15 @@ class FloatingSearchView @JvmOverloads constructor(context: Context, attrs: Attr
var onHistoryDeleteClickedListener: ((String) -> Unit)? = null
var onFavoriteHistorySwitchClickListener: (() -> Unit)? = null
var onSuggestionBinding: ((SearchSuggestionItemBinding, SearchSuggestion) -> Unit)? = null
init {
searchInputView.imeOptions = EditorInfo.IME_FLAG_NO_EXTRACT_UI or searchInputView.imeOptions
searchInputView.addTextChangedListener(this)
onSearchListener = this
onBindSuggestionCallback = { a, b, c, d, e ->
onBindSuggestion(a, b, c, d, e)
onBindSuggestionCallback = { binding, item, _ ->
onBindSuggestion(binding, item)
}
}
@@ -80,7 +84,7 @@ class FloatingSearchView @JvmOverloads constructor(context: Context, attrs: Attr
override fun onSuggestionClicked(searchSuggestion: SearchSuggestion?) {
when (searchSuggestion) {
is TagSuggestion -> {
is Hitomi.TagSuggestion -> {
val tag = "${searchSuggestion.n}:${searchSuggestion.s.replace(Regex("\\s"), "_")}"
with (searchInputView.text!!) {
delete(if (lastIndexOf(' ') == -1) 0 else lastIndexOf(' ') + 1, length)
@@ -89,7 +93,7 @@ class FloatingSearchView @JvmOverloads constructor(context: Context, attrs: Attr
append("$tag ")
}
}
is Suggestion -> {
is HistorySuggestion -> {
with (searchInputView.text!!) {
clear()
append(searchSuggestion.body)
@@ -101,114 +105,23 @@ class FloatingSearchView @JvmOverloads constructor(context: Context, attrs: Attr
override fun onSearchAction(currentQuery: String?) {}
fun onBindSuggestion(
suggestionView: View?,
leftIcon: ImageView?,
textView: TextView?,
item: SearchSuggestion?,
itemPosition: Int
) {
private fun onBindSuggestion(binding: SearchSuggestionItemBinding, item: SearchSuggestion) {
when(item) {
is TagSuggestion -> {
val tag = "${item.n}:${item.s.replace(Regex("\\s"), "_")}"
leftIcon?.setImageDrawable(
ResourcesCompat.getDrawable(
resources,
when(item.n) {
"female" -> R.drawable.gender_female
"male" -> R.drawable.gender_male
"language" -> R.drawable.translate
"group" -> R.drawable.account_group
"character" -> R.drawable.account_star
"series" -> R.drawable.book_open
"artist" -> R.drawable.brush
else -> R.drawable.tag
},
context.theme)
)
with(suggestionView?.findViewById<ImageView>(R.id.right_icon)) {
this ?: return@with
if (favoriteTags.contains(Tag.parse(tag)))
setImageResource(R.drawable.ic_star_filled)
else
setImageResource(R.drawable.ic_star_empty)
visibility = View.VISIBLE
rotation = 0f
isEnabled = true
isClickable = true
setOnClickListener {
val tag = Tag.parse(tag)
if (favoriteTags.contains(tag)) {
setImageResource(R.drawable.ic_star_empty)
favoriteTags.remove(tag)
}
else {
setImageDrawable(
AnimatedVectorDrawableCompat.create(context,
R.drawable.avd_star
))
(drawable as Animatable).start()
favoriteTags.add(tag)
}
}
}
if (item.t > 0) {
(suggestionView as? LinearLayout)?.let {
val count = it.findViewById<TextView>(R.id.count)
if (count == null)
it.addView(
LayoutInflater.from(context).inflate(R.layout.suggestion_count, suggestionView, false)
.apply {
this as TextView
text = item.t.toString()
}, 2
)
else
count.text = item.t.toString()
}
}
}
is FavoriteHistorySwitch -> {
leftIcon?.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.swap_horizontal, context.theme))
}
is Suggestion -> {
leftIcon?.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.history, context.theme))
with(suggestionView?.findViewById<ImageView>(R.id.right_icon)) {
this ?: return@with
setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.delete, context.theme))
visibility = View.VISIBLE
rotation = 0f
isEnabled = true
isClickable = true
setOnClickListener {
onHistoryDeleteClickedListener?.invoke(item.body)
}
}
binding.leftIcon.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.swap_horizontal, context.theme))
}
is LoadingSuggestion -> {
leftIcon?.setImageDrawable(CircularProgressDrawable(context).also {
binding.leftIcon.setImageDrawable(CircularProgressDrawable(context).also {
it.setStyle(CircularProgressDrawable.DEFAULT)
it.colorFilter = PorterDuffColorFilter(ContextCompat.getColor(context, R.color.colorAccent), PorterDuff.Mode.SRC_IN)
it.start()
})
}
is NoResultSuggestion -> {
leftIcon?.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.close, context.theme))
binding.leftIcon.setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.close, context.theme))
}
else -> {
onSuggestionBinding?.invoke(binding, item)
}
}
}

View File

@@ -24,7 +24,7 @@ import androidx.core.content.ContextCompat
import com.google.android.material.chip.Chip
import xyz.quaver.pupil.R
import xyz.quaver.pupil.favoriteTags
import xyz.quaver.pupil.sources.hitomi.Hitomi
import xyz.quaver.pupil.sources.Hitomi
import xyz.quaver.pupil.types.Tag
import xyz.quaver.pupil.util.translations
import xyz.quaver.pupil.util.wordCapitalize