|
|
|
@ -8,14 +8,17 @@ import android.annotation.SuppressLint
|
|
|
|
|
import android.content.Context
|
|
|
|
|
import android.graphics.PorterDuff.Mode.SRC_IN
|
|
|
|
|
import android.graphics.PorterDuffColorFilter
|
|
|
|
|
import android.graphics.drawable.Drawable
|
|
|
|
|
import android.util.AttributeSet
|
|
|
|
|
import android.view.MotionEvent
|
|
|
|
|
import android.view.MotionEvent.ACTION_UP
|
|
|
|
|
import androidx.appcompat.widget.AppCompatEditText
|
|
|
|
|
import androidx.core.content.ContextCompat.getColor
|
|
|
|
|
import mozilla.components.support.ktx.android.view.putCompoundDrawablesRelativeWithIntrinsicBounds
|
|
|
|
|
import org.mozilla.fenix.R
|
|
|
|
|
import org.mozilla.fenix.ThemeManager
|
|
|
|
|
import org.mozilla.fenix.ext.getColorFromAttr
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* An [AppCompatEditText] that shows a clear button to the user.
|
|
|
|
|
*/
|
|
|
|
|
class ClearableEditText @JvmOverloads constructor(
|
|
|
|
|
context: Context,
|
|
|
|
|
attrs: AttributeSet? = null,
|
|
|
|
@ -23,27 +26,49 @@ class ClearableEditText @JvmOverloads constructor(
|
|
|
|
|
) :
|
|
|
|
|
AppCompatEditText(context, attrs, defStyleAttr) {
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Clears the text when the clear icon is touched.
|
|
|
|
|
*
|
|
|
|
|
* Since the icon is just a compound drawable, we check the tap location
|
|
|
|
|
* to see if the X position of the tap is where the drawable is located.
|
|
|
|
|
*/
|
|
|
|
|
@SuppressLint("ClickableViewAccessibility")
|
|
|
|
|
override fun onTouchEvent(event: MotionEvent?): Boolean {
|
|
|
|
|
if (length() != 0 && event?.action == MotionEvent.ACTION_UP &&
|
|
|
|
|
event.rawX >= (this@ClearableEditText.right - this@ClearableEditText.compoundPaddingRight)
|
|
|
|
|
) {
|
|
|
|
|
this@ClearableEditText.setText("")
|
|
|
|
|
override fun onTouchEvent(event: MotionEvent): Boolean {
|
|
|
|
|
if (shouldShowClearButton(length()) && event.action == ACTION_UP && event.endDrawableTouched()) {
|
|
|
|
|
setText("")
|
|
|
|
|
return true
|
|
|
|
|
}
|
|
|
|
|
return super.onTouchEvent(event)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Displays a clear icon if text has been entered.
|
|
|
|
|
*/
|
|
|
|
|
override fun onTextChanged(text: CharSequence?, start: Int, lengthBefore: Int, lengthAfter: Int) {
|
|
|
|
|
super.onTextChanged(text, start, lengthBefore, lengthAfter)
|
|
|
|
|
if (lengthAfter != 0 && error == null) {
|
|
|
|
|
setCompoundDrawablesWithIntrinsicBounds(0, 0, R.drawable.ic_clear, 0)
|
|
|
|
|
for (drawable: Drawable in compoundDrawables.filterNotNull()) {
|
|
|
|
|
val color = ThemeManager.resolveAttribute(R.attr.primaryText, context!!)
|
|
|
|
|
drawable.colorFilter = PorterDuffColorFilter(getColor(context, color), SRC_IN)
|
|
|
|
|
val drawable = if (shouldShowClearButton(lengthAfter)) {
|
|
|
|
|
context.getDrawable(R.drawable.ic_clear)?.apply {
|
|
|
|
|
colorFilter = PorterDuffColorFilter(R.attr.primaryText.getColorFromAttr(context), SRC_IN)
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
setCompoundDrawablesWithIntrinsicBounds(0, 0, 0, 0)
|
|
|
|
|
null
|
|
|
|
|
}
|
|
|
|
|
putCompoundDrawablesRelativeWithIntrinsicBounds(end = drawable)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Checks if the clear button should be displayed.
|
|
|
|
|
*
|
|
|
|
|
* The button should be displayed if the user has entered valid text.
|
|
|
|
|
* @param length Length of the text the user has entered.
|
|
|
|
|
*/
|
|
|
|
|
private fun shouldShowClearButton(length: Int) =
|
|
|
|
|
length > 0 && error == null
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Returns true if the location of the [MotionEvent] is on top of the end drawable.
|
|
|
|
|
*/
|
|
|
|
|
private fun MotionEvent.endDrawableTouched() =
|
|
|
|
|
(layoutDirection == LAYOUT_DIRECTION_LTR && rawX >= (right - compoundPaddingRight)) ||
|
|
|
|
|
(layoutDirection == LAYOUT_DIRECTION_RTL && rawX <= (left + compoundPaddingLeft))
|
|
|
|
|
}
|
|
|
|
|