0

I have the following functions:

fun validateEmail(email: String) = flowOf {
    when {
        email.isEmpty() -> throw EmailError.Empty
        email.contains("@") -> email
        else -> throw EmailError.NotValid
    }
}
fun validatePassword(password: String) = flowOf {
    when {
        password.isEmpty() -> throw PasswordError.Empty
        else -> password
    }
}

fun useCaseLogin(email: String, password: String) = flow {
    //response: MyResponse = make and http request
    emit(response)
}

Then i would like to know if is posible to run this flows in the following way:

fun login(email: String, password: String) = 
    validateEmail(email).then(validatePassword(password))
                        .then(useCaseLogin(email, password)) { response: MyResponse -> 
        if (response==200) {
           emit("Login success!!")
        } else {
           emit("Login failed")
        }
 }.catch { e: Throwable ->
  when (e) {
    is EmailError.NotValid -> {
        print(e.localizedMessage)
    }
    is EmailError.Empty -> {
        print(e.localizedMessage)
    }
    is PasswordError.Empty -> {
        print(e.localizedMessage)
    }
  }
}.asLiveData(viewModelScope.coroutineContext)

Is there a way to write something like this?

Ricardo
  • 7,921
  • 14
  • 64
  • 111

1 Answers1

2

What you are looking for is the combine operator:

val emailFlow = validateEmail(email)
val pwdFlow = validatePassword(pwd)

emailFlow
    .combine(pwdFlow) { email, pass -> Pair(email, pass) }
    // In case your useCaseLogin is just a suspending function
    .map { (email, pass) ->
        val result = useCaseLogin(email, pass)
    }
    // In case your useCaseLogin returns a Flow with some result
    .flatMap { (email, pass) -> useCaseLogin(email, pass) }

While the comments are right and it's a little bit overkill to make the validation a Flow. You can build a nullable error Flow that you can use to map to the UI and display perhaps a little label below each field.

I would approach such thing as follows:

class YourViewModel() : ViewModel() {
     val emailFlow = MutableStateFlow("");
     val passwFlow = MutableStateFlow("");

     val emailError = emailFlow.map { validateEmail(it) }
     val passwError = emailFlow.map { validatePassword(it) }

     fun validateEmail(email: String) : Error? =
         when {
             email.isEmpty() -> throw EmailError.Empty
             email.contains("@") -> null
             else -> throw EmailError.NotValid
        }
// Similarly for password …
}

And on the OnChangeListener from your text inputs call viewModel.setEmailValue(value) so you get an updated emailError and passwError for each keystroke

Some random IT boy
  • 7,569
  • 2
  • 21
  • 47