Android Livedata not updating EditText - android

I am using Android LiveData in 3 different EditText. I have to show the result of multiplying the values of the first two EditText into the third EditText. I took advantage of an advice given to me on this site, and actually the third value is updated with the result of the multiplication of the first two. The problem is that the update does not happen live, but only happens when I leave and re-enter the activity. I am attaching the XML file, the activity, and the viewmodel.
XML:
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toStartOf="parent"
tools:context=".MainActivity">
<EditText
android:id="#+id/num1"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_centerHorizontal="true"
android:layout_centerVertical="true"
android:backgroundTint="#color/white"
android:inputType="number" />
<EditText
android:id="#+id/num2"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_centerHorizontal="true"
android:layout_centerVertical="true"
android:backgroundTint="#color/white"
android:inputType="numberDecimal" />
<EditText
android:id="#+id/num3"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_centerHorizontal="true"
android:layout_centerVertical="true"
android:backgroundTint="#color/white"
android:inputType="numberDecimal" />
</LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
Activity
class MainActivity: AppCompatActivity() {
private lateinit var binding: MainActivityBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.main_activity)
binding = DataBindingUtil.setContentView(
this,
R.layout.main_activity
)
viewModel=
ViewModelProvider(this, factory)[MainActivityViewModel::class.java]
initView(binding)
}
private fun initView(
binding:
MainActivityBinding
) {
viewModel.num1.value = root?.num1?: 0
viewModel.num2.value = root?.num2?: 0.0
viewModel.num1.observe(lifecycleOwner, Observer { newNum1->
binding.num1.setText(
newNum1.toString()
)
})
viewModel.num2.observe(lifecycleOwner, Observer { newNum2->
binding.num2.setText(
newNum2.toString()
)
})
binding.num1.addTextChangedListener(object : TextWatcher {
override fun afterTextChanged(s: Editable?) {
viewModel.num1.value =
binding.num1.text?.toString()?.toInt()
?: 0
}
override fun beforeTextChanged(
s: CharSequence?,
start: Int,
count: Int,
after: Int
) {
}
override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
}
})
binding.num2.addTextChangedListener(object : TextWatcher {
override fun afterTextChanged(s: Editable?) {
viewModel.num2.value =
binding.num2.text?.toString()?.toDouble()
?: 0.0
}
override fun beforeTextChanged(
s: CharSequence?,
start: Int,
count: Int,
after: Int
) {
}
override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
}
})
fun <A, B> LiveData<A>.combineWith(b: LiveData<B>): LiveData<Pair<A?, B?>> =
MediatorLiveData<Pair<A?, B?>>().apply {
var lastA: A? = this#combineWith.value
var lastB: B? = b.value
addSource(this#combineWith) {
lastA = it
value = Pair(lastA, lastB)
}
addSource(b) {
lastB = it
value = Pair(lastA, lastB)
}
}
viewModel.num1.combineWith(viewModel.num2)
.observe(
this,
Observer { (first, second) ->
if (first != null && second != null) {
binding.num3.setText((first * second).toString())
}
}
)
}
binding.num1.isFocusableInTouchMode = true
binding.num2.isFocusableInTouchMode = true
binding.num3.isFocusableInTouchMode = true
}
}
ViewModel
class RapportiAltriCostiViewModel(private val repositoryDB: DbRepository) : ViewModel() {
var num1= MutableLiveData<Int>()
var num2= MutableLiveData<Double>()
}
Would anyone know how to solve?
Thank you for your patience and help!
UPDATE
I tried with TextWatcher but it goes in loop:
binding.num1.addTextChangedListener(object : TextWatcher {
override fun afterTextChanged(s: Editable?) {
viewModel.num1.value =
binding.num1.text?.toString()?.toInt()
?: 0
}
override fun beforeTextChanged(
s: CharSequence?,
start: Int,
count: Int,
after: Int
) {
}
override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
}
})
binding.num2.addTextChangedListener(object : TextWatcher {
override fun afterTextChanged(s: Editable?) {
viewModel.num2.value =
binding.num2.text?.toString()?.toDouble()
?: 0.0
}
override fun beforeTextChanged(
s: CharSequence?,
start: Int,
count: Int,
after: Int
) {
}
override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
}
})
And I can't remove the TextWatcher after assigning the value, as I read on another question on the site, because I need them to always listen.
Thanks for the patience once again!

Something similar to this. To avoid cyclic updates you may just compare new value inside onFirstChanged/onSecondChanged with value in your liveData and skip liveData.value = newValue in that way.
class MainActivity : AppCompatActivity() {
private lateinit var binding: MainActivityBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.main_activity)
binding = DataBindingUtil.setContentView(
this,
R.layout.main_activity
)
viewModel =
ViewModelProvider(this, factory)[MainActivityViewModel::class.java]
initView(binding)
}
private fun initView(
binding:
MainActivityBinding
) {
binding.num1.listenChanges { viewModel.onFirstChanged(it) }
binding.num2.listenChanges { viewModel.onSecondChanged(it) }
viewModel.num1
.observe(
lifecycleOwner,
Observer { num1Value ->
binding.num1.setText(num1Value.toString())
}
)
viewModel.num2
.observe(
lifecycleOwner,
Observer { num2Value ->
binding.num2.setText(num2Value.toString())
}
)
viewModel.num3
.observe(
lifecycleOwner,
Observer { result ->
binding.num3.setText(result.toString())
}
)
}
binding.num1.isFocusableInTouchMode = true
binding.num2.isFocusableInTouchMode = true
binding.num3.isFocusableInTouchMode = true
}
private fun EditText.listenChanges(textChanged: (String) -> Unit) {
addTextChangedListener(object : TextWatcher {
override fun afterTextChanged(s: Editable?) {
}
override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {
}
override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) {
textChanged(s.toString())
}
})
}
class RapportiAltriCostiViewModel(private val repositoryDB: DbRepository) : ViewModel() {
val num1 = MutableLiveData<Int>(0)
val num2 = MutableLiveData<Double>(0.0)
val num3: LiveData<Double>
get() = num1.combineWith(num2) { first, second ->
(first ?: 0) * (second ?: 0.0)
}
fun onFirstChanged(newValue: Int) {
if (num1.value != newValue) {
num1.value = newValue
}
}
fun onSecondChanged(newValue: Double) {
if (num2.value != newValue) {
num2.value = newValue
}
}
private companion object {
private fun <A, B, R> LiveData<A>.combineWith(b: LiveData<B>, combine: (A?, B?) -> R?): LiveData<R> =
MediatorLiveData<R>().apply {
var lastA: A? = this#combineWith.value
var lastB: B? = b.value
addSource(this#combineWith) {
lastA = it
value = combine.invoke(lastA, lastB)
}
addSource(b) {
lastB = it
value = combine.invoke(lastA, lastB)
}
}
}
}

Related

How to pass a parameter to a extension function in Kotlin

I have an extension function in kotlin to check is it a valid string or not as stated below.
fun EditText.onAfterTextChanged(listener: (String) -> Unit) {
addTextChangedListener(object : TextWatcher {
override fun afterTextChanged(editable: Editable?) {
val input = editable?.toString()
val allowedChars = context.getString(R.string.supported_digits)
val newValue = replaceInvalidCharacters(input, allowedChars)
if (newValue != input) {
setText(newValue)
setSelection(text.length)
}
listener(newValue)
}
override fun beforeTextChanged(s: CharSequence?, p1: Int, p2: Int, p3: Int) {
}
override fun onTextChanged(s: CharSequence?, p1: Int, p2: Int, p3: Int) {
}
})
}
private fun replaceInvalidCharacters(value: String?, allowedChars: String): String {
var finalValue = value ?: ""
if (finalValue.isNotEmpty()) {
val lastChar = finalValue.last()
if (!allowedChars.contains(lastChar, false)) {
finalValue = finalValue.dropLast(1)
}
}
return finalValue
}
I am using it like:
editText.onAfterTextChanged {
val length = it.length
if (length >= 250) {
activity?.toast(getString(R.string.max_limit_reached))
return#onAfterTextChanged
}
}
Here I want to pass allowedChars as a parameter to this extension as there are different strings are there for different EditText's in the application. Like 1 EditText may allow only number's but not +,- and some edit text may allow only alphanumeric, etc. Is there any way to pass a parameter to the extension?
What you can do is update the extension function signature by adding a parameter before the callback function. So, it'll look something like this
fun EditText.onAfterTextChanged(allowedChars: String, listener: (String) -> Unit) {
addTextChangedListener(object : TextWatcher {
override fun afterTextChanged(editable: Editable?) {
val input = editable?.toString()
val allowedChars = context.getString(R.string.supported_digits)
val newValue = replaceInvalidCharacters(input, allowedChars)
if (newValue != input) {
setText(newValue)
setSelection(text.length)
}
listener(newValue)
}
override fun beforeTextChanged(s: CharSequence?, p1: Int, p2: Int, p3: Int) {
}
override fun onTextChanged(s: CharSequence?, p1: Int, p2: Int, p3: Int) {
}
})
}
And you can call it like so:
editText.onAfterTextChanged("123abc") {
val length = it.length
if (length >= 250) {
activity?.toast(getString(R.string.max_limit_reached))
return#onAfterTextChanged
}
}

How to get Call Back in another class when text size 4 from TextWatcher

This is my GenericTextEnterPin Class
class GenericTextEnterPinPassword (private val view: View, private val editText: ArrayList<EditText>) : TextWatcher {
override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {
}
override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
}
override fun afterTextChanged(s: Editable?) {
val string = s.toString()
when (view.id) {
R.id.otp_edit_box5 -> {
if (string.length == 1) editText[1].requestFocus()
}
R.id.otp_edit_box6 -> {
if (string.length == 1) editText[2].requestFocus() else if (string.isEmpty()) editText[0].requestFocus()
}
R.id.otp_edit_box7 -> {
if (string.length == 1) editText[3].requestFocus() else if (string.isEmpty()) editText[1].requestFocus()
}
R.id.otp_edit_box8 -> {
if (string.isEmpty()) editText[2].requestFocus()
// here we are getting 4 size i want sethere and want to get callback in another class
}
}
}
}
i want to getCall Back in my widget class where we are displaying some other view but i am not getting how to get call back in another class below is my class where i want to call back .
class AppLockWidgetImpl #Inject constructor(
private val context: Context,
override val onClicked: SingleLiveData<CallToAction>
) : AppLockWidget {
}
You can pass your callback as a lambda function to GenericTextEnterPinPassword.
class GenericTextEnterPinPassword (
private val view: View,
private val editText: ArrayList<EditText>,
private val callback: () -> Unit
): TextWatcher {
// ...
R.id.otp_edit_box8 -> {
if (string.isEmpty()) editText[2].requestFocus()
callback()
}
// ...
}
Usage:
val textWatcher = GenericTextConfirmPassword(otp_edit_box11, edit) {
// Whatever you wish to do upon callback
}
otp_edit_box11.addTextChangedListener(textWatcher)

How to give business logic to the ViewModel Kotlin?

I'm working on a training project as a student, but I can't figure out how to transfer my business logic from NewItemActivity to the NewItemViewModel. It turned out that I have all the logic for validating and creating the ItemModel inside the fragment. It's not good to do this, these are all parts of the business logic that need to be given to the viewModel. How can I transfer business logic to the ViewModel, but at the same time keep the application working correctly? Otherwise I tried and everything broke for me.
NewItemActivity.kt
class NewItemActivity : AppCompatActivity() {
private val calendar: Calendar = Calendar.getInstance()
private val viewModel: NewItemViewModel by viewModels(factoryProducer = {
NewItemViewModel.Factory()
})
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_new_item)
val saveButton = findViewById<Button>(R.id.saveButton)
val editDate = findViewById<EditText>(R.id.editDate)
val date = SimpleDateFormat("dd.MM.yyyy")
val dateDefault = date.format(calendar.timeInMillis)
editDate.setText(dateDefault)
editDate.setOnClickListener {
showDatePickerDialog()
}
saveButton.setOnClickListener {
checkStateDescriptionLayout()
if (checkStateTitleLayout()) return#setOnClickListener
if (checkStateDescriptionLayout()) return#setOnClickListener
val newItem = ItemModel(
title = editTitle.text.toString(),
description = editDescription.text.toString(),
date = Date(),
isFavorite = false
)
viewModel.saveNewItem(newItem)
Toast.makeText(this, "New item added", Toast.LENGTH_SHORT).show()
finish()
}
textChangedListener()
}
private fun showDatePickerDialog() {
val datePickerDialog = DatePickerDialog(
this#NewItemActivity,
{ _, year, monthOfYear, dayOfMonth ->
val selectedDate: String =
dayOfMonth.toString() + "." + (monthOfYear + 1) + "." + year
editDate?.setText(selectedDate)
},
calendar.get(Calendar.YEAR),
calendar.get(Calendar.MONTH),
calendar.get(Calendar.DAY_OF_MONTH)
)
datePickerDialog.datePicker.maxDate = calendar.timeInMillis
datePickerDialog.show()
}
private fun checkStateTitleLayout(): Boolean {
val titleLayout = findViewById<TextInputLayout>(R.id.editTitleLayout)
val checkTitleLayoutState = titleLayout.editText?.text?.toString()
val fieldIsRequired = getString(R.string.fieldIsRequired)
val error: Boolean = checkTitleLayoutState!!.isEmpty()
if (error) titleLayout.error = fieldIsRequired
return error
}
private fun checkStateDescriptionLayout(): Boolean {
val descriptionLayout = findViewById<TextInputLayout>(R.id.editDescriptionLayout)
val checkDescriptionLayoutState = descriptionLayout.editText?.text?.toString()
val fieldIsRequired = getString(R.string.fieldIsRequired)
val error: Boolean = checkDescriptionLayoutState!!.isEmpty()
if (error) descriptionLayout.error = fieldIsRequired
return error
}
private fun textChangedListener() {
val titleLayout = findViewById<TextInputLayout>(R.id.editTitleLayout)
val descriptionLayout = findViewById<TextInputLayout>(R.id.editDescriptionLayout)
titleLayout.editText?.addTextChangedListener(object : TextWatcher {
override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {}
override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {}
override fun afterTextChanged(s: Editable?) {
titleLayout.error = null
titleLayout.isErrorEnabled = false
}
})
descriptionLayout.editText?.addTextChangedListener(object : TextWatcher {
override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {}
override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {}
override fun afterTextChanged(s: Editable?) {
descriptionLayout.error = null
descriptionLayout.isErrorEnabled = false
}
})
}
}
NewItemViewModel.kt
class NewItemViewModel(
private val repository: MyItemsRepository
) : ViewModel() {
fun saveNewItem(item: ItemModel) = repository.saveNewItem(item)
class Factory : ViewModelProvider.Factory {
override fun <T : ViewModel?> create(modelClass: Class<T>): T {
return NewItemViewModel(MyItemsRepositoryImpl.getInstance()) as T
}
}
}
It seems like your main business logic is contained in onCreate, and that's not a big problem when you have little business logic, plus your logic is basically one event (saving the ItemModel object).
If you still want to move more logic to the ViewModel, move the creation of ItemModel to the ViewModel and provide functions to change each parameter of ItemModel there. It should look like this:
class NewItemViewModel(
private val repository: MyItemsRepository
) : ViewModel() {
private var title = ""
private var description = ""
private var date = Date()
private var isFavorite = false
fun setTitle(s: String) { title = s }
fun setDescription(s: String) { description = s }
fun setDate(d: Date) { date = d }
fun setIsFavorite(b: Boolean) { isFavorite = b }
fun saveNewItem() = repository.saveNewItem(Item(title, description, date, isFavorite))
class Factory : ViewModelProvider.Factory {
override fun <T : ViewModel?> create(modelClass: Class<T>): T {
return NewItemViewModel(MyItemsRepositoryImpl.getInstance()) as T
}
}
}
You might think it's more trouble than it's worth, and you will be right. However, there's no harm to preparing for more complicated logic ;)
P.S. I have not tested this code, but it should be basically correct.

Using roomdatabase query for search between products

before get to my issue let me tell you how my app works.
I have A little Grocery App and fetch data from an api with retrofit and after that save it to Roomdatabase.
For better Ui experiment I need to implement searchview with an edittext on my main screen .
So , I decide to code a query in my dao and get all data by title filter .
But the problem is that , when I fill the edittext and click on button to get the product that I filter it nothing happened and doesn't any search .
Well , I guess maybe my problem would be with my code that I implement in repository and viewmodel to insert data to roomdatabase . if not , what's wrong with my code ?
I will be appreciated if you look at my code .
and here is my code :
This is room table :
#Entity(tableName = "newTable")
data class RoomEntity(
#PrimaryKey
(autoGenerate = true)
val id : Int? ,
#ColumnInfo val title: String,
#ColumnInfo val image: String
)
Dao :
#Dao
interface RoomDaoQuery {
#Query("SELECT * FROM newTable")
fun getAllProduct () : LiveData<List<RoomEntity>>
#Insert(onConflict = OnConflictStrategy.REPLACE)
fun insertDataToDatabase(model : List<RoomEntity>)
#Query("SELECT * FROM newTable WHERE title LIKE '%' || :search || '%'")
fun searchByName(search: String): List<RoomEntity>
}
Repository :
class Repository(private val database: DatabaseRoom) {
fun getAllProduct() = database.GetDao.getAllProduct()
private fun retrofit(): ApiRetrofit {
return Retrofit.Builder()
.baseUrl("http://192.168.43.106/")
.addConverterFactory(GsonConverterFactory.create(GsonBuilder().create()))
.build()
.create(ApiRetrofit::class.java)
}
suspend fun fettchAllDat(): List<RoomEntity> {
return retrofit().getProduct()
}
suspend fun insertToDatabase(model : List<RoomEntity>) {
database.GetDao.insertDataToDatabase(fettchAllDat())
}
// this is for local search
fun searchWithName (title : String) : List<RoomEntity> {
return database.GetDao.searchByName(title)
}
}
Viewmodel:
class ViewmodelRoom(application: Application) : AndroidViewModel(application) {
val product = MutableLiveData<List<RoomEntity>>()
private val repository = Repository(DatabaseRoom.getInstance(application))
private var viewModelJob = SupervisorJob()
private val viewModelScope = CoroutineScope(viewModelJob + Dispatchers.Default)
fun getAllProduct() = repository.getAllProduct()
fun setup() {
viewModelScope.launch{
product.postValue(repository.fettchAllDat())
insertall()
}
}
fun insertall() {
viewModelScope.launch {
repository.insertToDatabase(repository.fettchAllDat())
}
}
fun searchByTitle(title : String) = CoroutineScope(Dispatchers.Default).launch{
repository.searchWithName(title)
}
}
and MainActivity :
class MainActivity : AppCompatActivity() {
val viewModel: ViewmodelRoom by lazy {
ViewModelProvider(this).get(ViewmodelRoom::class.java)
}
#RequiresApi(Build.VERSION_CODES.M)
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val editText: EditText = findViewById(R.id.edittext)
val search: ImageView = findViewById(R.id.searchview)
val recyclerView = findViewById<RecyclerView>(R.id.recyclerview)
search.setOnClickListener {
viewModel.searchByTitle(editText.text.toString())
editText.text.clear()
}
editText.addTextChangedListener(object : TextWatcher {
override fun onTextChanged(p0: CharSequence?, p1: Int, p2: Int, p3: Int) {
viewModel.searchByTitle(editText.text.toString())
}
override fun afterTextChanged(p0: Editable?) {
}
override fun beforeTextChanged(p0: CharSequence?, p1: Int, p2: Int, p3: Int) {
}
})
if (isNetworkAvaliable(applicationContext)) {
viewModel.setup()
viewModel.product.observe(this, Observer {
recyclerView.apply {
layoutManager = GridLayoutManager(this#MainActivity, 2)
adapter = RecyclerAdapterMain(it, this#MainActivity)
}
})
} else {
viewModel.getAllProduct().observe(this, Observer { list ->
recyclerView.apply {
layoutManager = GridLayoutManager(this#MainActivity, 2)
adapter = RecyclerAdapterMain(list, this#MainActivity)
}
})
}
}
finally I get to a proper result .
I put my code here , I hope maybe useful for someone .
the Dao :
#Query("SELECT * FROM newTable WHERE title LIKE :name")
fun search (name : String) :LiveData<List<RoomEntity>>
Repository :
fun search(name : String): LiveData<List<RoomEntity>>{
return database.GetDao.search(name)
}
fun search(name : String) : LiveData<List<RoomEntity>> {
return repository.search(name)
}
MainActivity :
val editText: EditText = findViewById(R.id.edittext)
val search: ImageView = findViewById(R.id.searchview)
recyclerView = findViewById(R.id.recyclerview)
search.setOnClickListener {
// this is an extention function that observe data
searchProduct(editText.text.toString())
}
editText.addTextChangedListener(object : TextWatcher {
override fun onTextChanged(p0: CharSequence?, p1: Int, p2: Int, p3: Int) {
searchProduct(editText.text.toString())
}
override fun afterTextChanged(p0: Editable?) {
}
override fun beforeTextChanged(p0: CharSequence?, p1: Int, p2: Int, p3: Int) {
}
})
private fun searchProduct(title : String) {
var searchText = title
searchText = "%$title%"
viewModel.search(searchText).observe(this#MainActivity , Observer {
d("main" , "$it")
recyclerView.apply {
layoutManager = GridLayoutManager(this#MainActivity, 2)
adapter = RecyclerAdapterMain(it, this#MainActivity)
}
})
}

How can i validate multiple editText fields and enable button?

I am trying to figure out how to validate 6 EditText input fields and enable button
button_step_one_next_FSF.isEnabled = true
when everything fits my condition. I want to validate everything using this util class without creating TextWatcher object.
Here is my editText util class
inline fun EditText.onTextChange(crossinline f: (s: CharSequence?) -> Unit) {
val listener = object : TextWatcher {
override fun onTextChanged(s: CharSequence, start: Int,
before: Int, count: Int) {
f(s)
}
override fun afterTextChanged(s: Editable?) {}
override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {}
}
addTextChangedListener(listener)
}
Here is short validation method example
private fun validateInput() {
edit_text_name.onTextChange { s ->
val name: String = s?.toString() ?: ""
if (!name.isNameNotValid()) {
text_input_name.isEndIconVisible = true
text_input_name.isErrorEnabled = false
} else {
text_input_name.error = getString(R.string.error_not_valid_name)
text_input_name.isEndIconVisible = false
}
}
edit_text_surname.onTextChange { s ->
val surname: String = s?.toString() ?: ""
if (!surname.isNameNotValid()) {
text_input_surname.isEndIconVisible = true
text_input_surname.isErrorEnabled = false
} else {
text_input_surname.error = getString(R.string.error_not_valid_surname)
text_input_surname.isEndIconVisible = false
}
}
I just added this method checkButtonEnableState() at the end of each validation in TextWatcher lambda expression and it solved my problem!
private fun checkButtonEnableState() {
button_step_one_next_FSF.isEnabled =
(!edit_text_name.text.toString().isNameNotValid()
&& !edit_text_surname.text.toString().isNameNotValid()
&& edit_text_password_FSF.text.toString().isValidPassword()
&& edit_text_password_confirm_FSF.text.toString().isValidPassword()) &&
(edit_text_password_confirm_FSF.text.toString() == edit_text_password_FSF.text.toString())
}

Categories

Resources