This class which basically does validation on inpu...
# android
a
This class which basically does validation on input fields. Using 
LiveData
 to how can i convert the 
MediatorLiveData
 part to 
StateFlow
Copy code
import androidx.lifecycle.LiveData
import androidx.lifecycle.MediatorLiveData
import androidx.lifecycle.MutableLiveData

abstract class InputFrom {
    private val _isFromValid = MediatorLiveData<Boolean>()
    val isFromValid: LiveData<Boolean>
        get() = _isFromValid

    abstract val fields: List<LiveInputField<*>>

    fun init() {
        fields.forEach { inputField ->
            _isFromValid.addSource(inputField.value) { changedValue ->
                inputField.validate(changedValue)
                _isFromValid.value = fields.all {
                    it.isValid
                }
            }
        }
    }

    inner class LiveInputField<T>(
        private val errorMessage: String? = null,
        private val predicate: (T?) -> Boolean
    ) {

        val value = MutableLiveData<T>()

        private val _error = MutableLiveData<String>()
        val errorText: LiveData<String>
            get() = _error

        var isValid: Boolean = false

        fun validate(value: Any?) {
            @Suppress("UNCHECKED_CAST")
            return if (predicate(value as? T)) {
                _error.value = null
                isValid = true
            } else {
                _error.value = errorMessage
                isValid = false
            }
        }
    }
}
Example Usages:
Copy code
class LoginFrom : InputFrom() {

    val username =
        LiveInputField<String>("At least 4 characters, only letters, numbers, ., _ allowed.") {
            !it.isNullOrBlank() &&
                Pattern.compile("[a-zA-Z0-9_.]{4,}")
                    .matcher(it)
                    .matches()
        }

    val password =
        LiveInputField<String>(
            "8 characters or more, at least one number, one uppercase, one lowercase."
        ) {
            !it.isNullOrBlank()/* &&
          Pattern.compile("((?=.*\\d)(?=.*[a-z])(?=.*[A-Z]).{8,})")
              .matcher(it)
              .matches()*/
        }

    override val fields: List<LiveInputField<*>>
        get() = listOf(
            username,
            password
        )
}
Conversion
Copy code
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.SharedFlow
import kotlinx.coroutines.flow.StateFlow

abstract class InputForm {
    private val _isValid = MutableStateFlow(false)
    val isValid: SharedFlow<Boolean>
        get() = _isValid

    abstract val fields: List<Field<*>>

    fun init() {
        // TODO: implement validation when Field#value changes
    }

    inner class Field<T>(
        initialValue: T? = null,
        private val errorMessage: String? = null,
        private val validator: (T?) -> Boolean
    ) {
        val value = MutableStateFlow(initialValue)

        private val _error = MutableStateFlow<String?>(null)
        val errorText: StateFlow<String?>
            get() = _error

        var isValid: Boolean = false

        fun validate(value: Any?) {
            @Suppress("UNCHECKED_CAST")
            return if (validator(value as? T)) {
                _error.value = null
                isValid = true
            } else {
                _error.value = errorMessage
                isValid = false
            }
        }
    }
}