You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
81 lines
3.1 KiB
Kotlin
81 lines
3.1 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) {
|
|
onTextChanged(text)
|
|
}
|
|
|
|
fun onTextChanged(text: CharSequence?) {
|
|
// 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))
|
|
}
|