Issue
I have phone authentication project in android jetpack compose, so I can do it in my code and I am success to get OTP code from firebase, but I want to use resend code again in my project, so when I click this line of code;
.clickable { modelAuthentication.resendCode(phoneNumberOTP)}
it is throw an error like "lateinit property resendToken has not been initialized", I am not get it what I missed, any idea?
Phone.kt:
@Composable
fun PhoneScreen(
navController: NavController,
modelAuthentication: AuthenticationViewModel
) {
val phoneNumberState = remember { mutableStateOf("") }
OutlinedTextField(
value = phoneNumberState.value,
colors = TextFieldDefaults.textFieldColors(
backgroundColor = white,
focusedIndicatorColor = Grey,
unfocusedIndicatorColor = Grey,
focusedLabelColor = Grey,
unfocusedLabelColor = Grey,
cursorColor = color,
textColor = color,
),
onValueChange = { phoneNumberState.value = it },
label = { Text(text = "Phone Number") },
placeholder = { Text(text = "Phone Number") },
singleLine = true,
)
Button(
modifier = Modifier
.width(285.dp)
.height(55.dp)
,
onClick = {
modelAuthentication.send(phoneNumberState.value)
},
colors = ButtonDefaults.buttonColors(
backgroundColor = color
),
shape = RoundedCornerShape(40),
) {
Text(
text = "send",
style = TextStyle(
fontSize = 18.sp,
color = white,
)
)
}
PhoneVerify.kt
@Composable
fun PhoneVerifyScreen(
navController: NavController,
modelAuthentication: AuthenticationViewModel,
) {
lateinit var resendToken: PhoneAuthProvider.ForceResendingToken
val focusManager = LocalFocusManager.current
val phoneNumberPatientOTP = remember { mutableStateOf("") }
val context = LocalContext.current
LaunchedEffect(Unit) {
println("found activity? ${context.findActivity()}")
val activity = context.findActivity() ?: return@LaunchedEffect
modelAuthentication.setActivity(activity)
}
Column(
Modifier.fillMaxSize(),
verticalArrangement = Arrangement.Center,
horizontalAlignment = Alignment.CenterHorizontally
) {
OutlinedTextField(
value = phoneNumberOTP.value,
colors = TextFieldDefaults.textFieldColors(
backgroundColor = white,
focusedIndicatorColor = Grey,
unfocusedIndicatorColor = Grey,
focusedLabelColor = Grey,
unfocusedLabelColor = Grey,
cursorColor = color,
textColor = color,
),
onValueChange = { phoneNumberOTP.value = it },
label = { Text(text = "Verify code") },
placeholder = { Text(text = "Verify code") },
modifier = Modifier.fillMaxWidth(0.8f),
)
}
Spacer(modifier = Modifier.padding(7.dp))
Row(
Modifier
.width(300.dp),
horizontalArrangement = Arrangement.Center,
verticalAlignment = Alignment.CenterVertically,
) {
Text(
"Resend Code",
modifier = Modifier
.height(20.dp)
.clickable {
modelAuthentication.resendCode(phoneNumberOTP)
}
,
textAlign = TextAlign.End,
fontWeight = FontWeight.Medium,
fontSize = 14.sp,
color = color
)
} }
ViewModel.kt
@HiltViewModel
class AuthenticationViewModel @Inject constructor(
private val auth: FirebaseAuth
) : ViewModel() {
lateinit var otp: String
var verificationOtp = ""
var popNotification = mutableStateOf<Event<String>?>(null)
private lateinit var baseBuilder: PhoneAuthOptions.Builder
fun setActivity(activity: Activity) {
baseBuilder = PhoneAuthOptions.newBuilder(auth).setActivity(activity)
}
lateinit var resendToken: PhoneAuthProvider.ForceResendingToken
val mCallBack = 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
resendToken = p1
handledException(customMessage = "Otp Send Successfully")
}}
fun sendVerificationCode(mobileNum: String) {
val options = baseBuilder
.setPhoneNumber(mobileNum)
.setTimeout(5L, TimeUnit.SECONDS)
.setCallbacks(mCallBack)
.build()
PhoneAuthProvider.verifyPhoneNumber(options)
}
fun signInWithPhoneAuthCredential(otp: String) {
val credential = PhoneAuthProvider.getCredential(verificationOtp, otp)
auth.currentUser?.linkWithCredential(credential)
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)
}
}
Solution
Modify your viewmodel looks like this
1 Define the callback on the top
val mCallBack = 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
resendToken = p1
handledException(customMessage = "Otp Send Successfully")
}}
2 Update the send function
fun sendVerificationCode(mobileNum: String) {
val options = baseBuilder
.setPhoneNumber(mobileNum)
.setTimeout(5L, TimeUnit.SECONDS)
.setCallbacks(mCallBack)
.build()
PhoneAuthProvider.verifyPhoneNumber(options)
}
3 Remove the resend function
Note: p1 parameter is the Resend token
If you want resend verification, call the same function (sendVerificationCode)
Answered By - Gobu CSG
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.