1
0
Fork 0
fenix/app/src/main/java/org/mozilla/fenix/utils/ClearableEditText.kt

77 lines
3.0 KiB
Kotlin

/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
package org.mozilla.fenix.utils
import android.annotation.SuppressLint
import android.content.Context
import android.util.AttributeSet
import android.view.MotionEvent
import android.view.MotionEvent.ACTION_UP
import androidx.appcompat.content.res.AppCompatResources
import androidx.appcompat.widget.AppCompatEditText
import androidx.core.graphics.BlendModeColorFilterCompat.createBlendModeColorFilterCompat
import androidx.core.graphics.BlendModeCompat.SRC_IN
import mozilla.components.support.ktx.android.content.getColorFromAttr
import mozilla.components.support.ktx.android.view.putCompoundDrawablesRelativeWithIntrinsicBounds
import org.mozilla.fenix.R
/**
* An [AppCompatEditText] that shows a clear button to the user.
*/
class ClearableEditText @JvmOverloads constructor(
context: Context,
attrs: AttributeSet? = null,
defStyleAttr: Int = R.attr.editTextStyle
) :
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 (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) {
// lengthAfter has inconsistent behaviour when there are spaces in the entered text, so we'll use text.length.
val textLength = text?.length ?: 0
val drawable = if (shouldShowClearButton(textLength)) {
AppCompatResources.getDrawable(context, R.drawable.ic_clear)?.apply {
colorFilter = createBlendModeColorFilterCompat(context.getColorFromAttr(R.attr.primaryText), SRC_IN)
}
} else {
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))
}