Add voice search
This commit is contained in:
@@ -14,4 +14,6 @@ interface SearchSuggestionListener {
|
||||
fun onClearSearchHistory()
|
||||
|
||||
fun onTagClick(tag: MangaTag)
|
||||
|
||||
fun onVoiceSearchClick()
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user