I am try to learning android jetpack compose, I have simple app, and I want to use mobile authentication with firebase for my project. I am using MVVM in the project, so when I debug the project, it throw an error like
You must specify an Activity on your PhoneAuthOptions. Please call #setActivity()
for the .build()
in the view model, how can I arrange my viewmodel, I did not find any solution on internet, any idea?
viewmodel:
@HiltViewModel
class AuthenticationViewModel @Inject constructor(
) : ViewModel() {
private val mAuth = FirebaseAuth.getInstance()
var verificationOtp = ""
var popNotification = mutableStateOf<Event<String>?>(null)
fun send(mobileNum: String) {
val options = PhoneAuthOptions.newBuilder(mAuth)
.setPhoneNumber(" 91$mobileNum")
.setTimeout(60L, TimeUnit.SECONDS)
.setCallbacks(object :
PhoneAuthProvider.OnVerificationStateChangedCallbacks() {
override fun onVerificationCompleted(p0: PhoneAuthCredential) {
handledException(customMessage = "Verification Completed")
}
override fun onVerificationFailed(p0: FirebaseException) {
handledException(customMessage = "Verification Failed")
}
override fun onCodeSent(otp: String, p1: PhoneAuthProvider.ForceResendingToken) {
super.onCodeSent(otp, p1)
verificationOtp = otp
handledException(customMessage = "Otp Send Successfully")
}
}).build()
PhoneAuthProvider.verifyPhoneNumber(options)
}
fun otpVerification(otp: String) {
val credential = PhoneAuthProvider.getCredential(verificationOtp, otp)
FirebaseAuth.getInstance().signInWithCredential(credential)
.addOnCompleteListener { task ->
if (task.isSuccessful) {
handledException(customMessage = "Verification Successful")
} else {
handledException(customMessage = "Wrong Otp")
}
}
}
private fun handledException(exception: Exception? = null, customMessage: String = "") {
exception?.printStackTrace()
val errorMsg = exception?.message ?: ""
val message = if (customMessage.isEmpty()) {
errorMsg
} else {
"$customMessage: $errorMsg"
}
popNotification.value = Event(message)
}
}
screen1:
@Composable
fun PhoneScreen(
navController: NavController,
modelAuthentication: AuthenticationViewModel,
onClick: (mobileNum: String, otp: String) -> Unit
) {
val phoneNumber = remember { mutableStateOf("") }
OutlinedTextField(
value = phoneNumber.value,
colors = TextFieldDefaults.textFieldColors(
backgroundColor = white,
focusedIndicatorColor = Grey,
unfocusedIndicatorColor = Grey,
focusedLabelColor = Grey,
unfocusedLabelColor = Grey,
),
onValueChange = { phoneNumber.value = it },
label = { Text(text = "Phone Number") },
placeholder = { Text(text = "Phone Number") },
singleLine = true,
modifier = Modifier.fillMaxWidth(0.8f)
)
Button(
modifier = Modifier
.width(285.dp)
.height(55.dp),
onClick = {
modelAuthentication.send(phoneNumber.value)
navController.navigate("phoneVerify")
},
colors = ButtonDefaults.buttonColors(
backgroundColor = Color.Custom
),
shape = RoundedCornerShape(60)
) {
Text(
text = "Next",
style = TextStyle(
fontSize = 18.sp,
color = white,
)
)
}
}
screen2:
@Composable
fun PhoneVerifyScreen(
navController: NavController,
modelAuthentication: AuthenticationViewModel,
onClick: (mobileNum: String, otp: String) -> Unit
) {
val phoneNumberOtp = remember { mutableStateOf("") }
OutlinedTextField(
value = phoneNumberOtp.value,
colors = TextFieldDefaults.textFieldColors(
backgroundColor = white,
focusedIndicatorColor = Grey,
unfocusedIndicatorColor = Grey,
focusedLabelColor = Grey,
unfocusedLabelColor = Grey,
),
onValueChange = { phoneNumberOtp.value = it },
label = { Text(text = "code") },
placeholder = { Text(text = "code") },
singleLine = true,
modifier = Modifier.fillMaxWidth(0.8f)
)
Button(
modifier = Modifier
.width(285.dp)
.height(55.dp),
onClick = {
modelAuthentication.otpVerification(phoneNumberOtp.value)
navController.navigate("home")
},
colors = ButtonDefaults.buttonColors(
backgroundColor = Color.Custom
),
shape = RoundedCornerShape(60)
) {
Text(
text = "Next",
style = TextStyle(
fontSize = 18.sp,
color = white,
)
)
}
}
CodePudding user response:
You need to specify Activity since it is a required parameter of the builder.
You will have to move the code of the builder to your Activity 'cause you're not allowed to have a link to Activity in a ViewModel.
Inside the verification result callback you can call ViewModel's methods to pass the result or exception.
CodePudding user response:
With hilt you can inject context using @ApplicationContext
:
@HiltViewModel
class AuthenticationViewModel @Inject constructor(
@ApplicationContext context: Context,
): ViewModel() {
// pass context to PhoneAuthOptions
}