Add voice search

This commit is contained in:
Koitharu
2022-05-06 10:52:51 +03:00
parent 6969f40fa0
commit 878df24a64
9 changed files with 148 additions and 15 deletions

View File

@@ -14,4 +14,6 @@ interface SearchSuggestionListener {
fun onClearSearchHistory()
fun onTagClick(tag: MangaTag)
fun onVoiceSearchClick()
}

View File

@@ -2,15 +2,20 @@ package org.koitharu.kotatsu.search.ui.widget
import android.annotation.SuppressLint
import android.content.Context
import android.os.Parcelable
import android.util.AttributeSet
import android.view.KeyEvent
import android.view.MotionEvent
import android.view.SoundEffectConstants
import android.view.accessibility.AccessibilityEvent
import android.view.inputmethod.EditorInfo
import androidx.annotation.AttrRes
import androidx.appcompat.widget.AppCompatEditText
import androidx.core.content.ContextCompat
import com.google.android.material.R
import com.google.android.material.R as materialR
import org.koitharu.kotatsu.R
import org.koitharu.kotatsu.search.ui.suggestion.SearchSuggestionListener
import org.koitharu.kotatsu.utils.ext.drawableEnd
import org.koitharu.kotatsu.utils.ext.drawableStart
private const val DRAWABLE_END = 2
@@ -18,11 +23,19 @@ private const val DRAWABLE_END = 2
class SearchEditText @JvmOverloads constructor(
context: Context,
attrs: AttributeSet? = null,
@AttrRes defStyleAttr: Int = R.attr.editTextStyle,
@AttrRes defStyleAttr: Int = materialR.attr.editTextStyle,
) : AppCompatEditText(context, attrs, defStyleAttr) {
var searchSuggestionListener: SearchSuggestionListener? = null
private val clearIcon = ContextCompat.getDrawable(context, R.drawable.abc_ic_clear_material)
private val clearIcon = ContextCompat.getDrawable(context, materialR.drawable.abc_ic_clear_material)
private val voiceIcon = ContextCompat.getDrawable(context, R.drawable.ic_voice_input)
private var isEmpty = text.isNullOrEmpty()
var isVoiceSearchEnabled: Boolean = false
set(value) {
field = value
updateActionIcon()
}
var query: String
get() = text?.trim()?.toString().orEmpty()
@@ -57,15 +70,19 @@ class SearchEditText @JvmOverloads constructor(
lengthAfter: Int,
) {
super.onTextChanged(text, start, lengthBefore, lengthAfter)
setCompoundDrawablesRelativeWithIntrinsicBounds(
drawableStart,
null,
if (text.isNullOrEmpty()) null else clearIcon,
null,
)
val empty = text.isNullOrEmpty()
if (isEmpty != empty) {
isEmpty = empty
updateActionIcon()
}
searchSuggestionListener?.onQueryChanged(query)
}
override fun onRestoreInstanceState(state: Parcelable?) {
super.onRestoreInstanceState(state)
updateActionIcon()
}
@SuppressLint("ClickableViewAccessibility")
override fun onTouchEvent(event: MotionEvent): Boolean {
if (event.action == MotionEvent.ACTION_UP) {
@@ -76,7 +93,9 @@ class SearchEditText @JvmOverloads constructor(
event.x.toInt() in (width - drawable.bounds.width() - paddingRight)..(width - paddingRight)
}
if (isOnDrawable) {
text?.clear()
sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_CLICKED)
playSoundEffect(SoundEffectConstants.CLICK)
onActionIconClick()
return true
}
}
@@ -87,4 +106,22 @@ class SearchEditText @JvmOverloads constructor(
super.clearFocus()
text?.clear()
}
private fun onActionIconClick() {
when {
!text.isNullOrEmpty() -> text?.clear()
isVoiceSearchEnabled -> searchSuggestionListener?.onVoiceSearchClick()
}
}
private fun updateActionIcon() {
val icon = when {
!text.isNullOrEmpty() -> clearIcon
isVoiceSearchEnabled -> voiceIcon
else -> null
}
if (icon !== drawableEnd) {
setCompoundDrawablesRelativeWithIntrinsicBounds(drawableStart, null, icon, null)
}
}
}