I have a function that signs up a user and stores them in the Firestore database. For now, everything is happening inside the fragment but I would like to move it to the repo and connect via the view model.
fun signUp(){
val username = binding.signUpUsername.editText!!.text.toString()
val email = binding.singUpEmail.editText!!.text.toString()
val password = binding.signUpPassword.editText!!.text.toString()
auth.createUserWithEmailAndPassword(email, password)
.addOnCompleteListener { task ->
if (task.isSuccessful){
task.result.user!!.sendEmailVerification().addOnCompleteListener{
val newUser = User(uid = task.result.user!!.uid, username=username)
lifecycleScope.launch{
repository.addUser(newUser)
}.invokeOnCompletion {
Log.d("sign_up", "Your registration is successful: ${task.result.user!!.uid}")
Toast.makeText(this, "Account has been created. Confirm your email.", Toast.LENGTH_SHORT).show()
auth.signOut()
startActivity(Intent(this, LoginMainActivity::class.java))
finish()
}
}
} else {
Log.d("sign_up", task.exception.toString())
}
}
}
suspend fun addUser(user: User) {
db.collection(Constants.USERS).document(user.uid).set(user).await()
}
My question is how to invoke suspend function addUser() inside my repo. Can I just create CoroutineScope inside my main function? Is it acceptable? I would like to do it correctly but I haven't found any solution.
CodePudding user response:
My question is how to invoke suspend function addUser() inside my repo.
Since you call .await()
, your addUser()
function it's mandatory to be defined as a suspend
function. According to the official documentation:
Suspending functions can be used inside coroutines just like regular functions, but their additional feature is that they can, in turn, use other suspending functions to suspend the execution of a coroutine.
This basically means that a suspend function can only be called from within a coroutine body or from another suspend function.
Can I just create CoroutineScope inside my main function? Is it acceptable?
No. As I understand from your question, you want to use a ViewModel along with a repository class. That being said, you have to move the signUp()
function inside the repository class and leave all the staff that is related to the views inside your fragment class. Now I think that all it remains to be done is to call the addUser()
function.
The simplest solution to solving this problem would be to define a sealed class that looks like this:
sealed class Response<out T> {
object Loading: Response<Nothing>()
data class Success<out T>(
val data: T
): Response<T>()
data class Failure<out T>(
val errorMessage: String
): Response<T>()
}
Then the signUp()
function should also be defined as a suspending function and the most important thing is to return a Flow:
fun signUpInFirebase(email: String, password: String) = flow {
emit(Response.Loading)
val user = auth.createUserWithEmailAndPassword(email, password).await().user
val newUser = User(uid = user?.uid, username=user?.displayName)
addUser(newUser) //