I am trying to log a message when there is a change in state, but apparently it's not working, I am not sure where I am going wrong.
I want to update the UI when the state is changed to user logged in, but for starters I am only trying to log a message.
I also don't quiet understand the registering it and unregistering it.
This is my login activity's code.
val TAG = "LoginActivity"
//private var mDatabaseReference: DatabaseReference? = null
//private var mDatabase: FirebaseDatabase? = null
// Firebase refferences for Authentication.
private var mAuth: FirebaseAuth? = null
private var mUser : FirebaseUser? = null
private var mDatabase : DatabaseReference? = null
private var mAuthListener : FirebaseAuth.AuthStateListener? = null
//global variables
private var emailString : String? = null
private var passwordString : String? = null
// ActivityState : ONCREATE.
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_login)
// initializing firebase Auth and database Reference.
mAuth = FirebaseAuth.getInstance()
mDatabase = FirebaseDatabase.getInstance().reference
// getting the currently logined user.
mUser = mAuth?.currentUser
//[START auth_state_listener]
FirebaseAuth.AuthStateListener { firebaseAuth ->
val cuser = firebaseAuth.currentUser
if(mUser != null) {
Log.d("WOWOWOWOWO : ", "you dont girl!")
}
}
}
//ActivityState : ONSTART.
override fun onStart() {
super.onStart()
mAuth?.addAuthStateListener(mAuthListener!!)
}
//ActivityState : ONPAUSE.
override fun onPause() {
super.onPause()
}
// function for when the login button is clicked.
// TODO : Login Activity : Function# 1.
fun loginBtnClicked(view : View) {
emailString = loginEmailTxt.text.toString()
passwordString = loginPasswordtxt.text.toString()
if(!emailString.isNullOrEmpty() && !passwordString.isNullOrEmpty()) {
// Checking if the login cridentials are correct. and then changing the Auth State to logged in.
//TODO : Login Activity : Function# 3.
mAuth!!.signInWithEmailAndPassword(emailString!!, passwordString!!).addOnCompleteListener(this) { task ->
if(task.isSuccessful) {
// User ID token retrival TODO: not sure what to do with the token yet.
mUser!!.getIdToken(true)
.addOnCompleteListener(OnCompleteListener {task: Task<GetTokenResult> ->
if(task.isSuccessful) {
var idToken = task.getResult().token
Log.d(TAG, "signInWithEmail:success :" + idToken)
} else {
}
})
} else {
Log.e(TAG, "signInWithEmail:failure", task.exception)
Toast.makeText(this#LoginActivity, "Authentication failed. Make sure email and password are correct",
Toast.LENGTH_SHORT).show()
}
}
} else {
Toast.makeText(this, "Email or Password can not be empty.", Toast.LENGTH_LONG).show()
}
}
// TODO : Login Activity : Function#2
fun getHelpImgClicked(view : View) {
val builder = AlertDialog.Builder(this)
val dialogView = layoutInflater.inflate(R.layout.get_help_dialog, null)
builder.setView(dialogView)
.setNegativeButton("Close" ){ _, _ -> }.show()
}
You're never assigning a non-null value to your mAuthListener. This is the only time it's assigned:
private var mAuthListener : FirebaseAuth.AuthStateListener? = null
And this is where you pass that null value to become an auth state listener:
override fun onStart() {
super.onStart()
mAuth?.addAuthStateListener(mAuthListener!!)
}
You also create an auth state listener, but never assign that object anywhere, so it doesn't do anything:
//[START auth_state_listener]
FirebaseAuth.AuthStateListener { firebaseAuth ->
val cuser = firebaseAuth.currentUser
if(mUser != null) {
Log.d("WOWOWOWOWO : ", "you dont girl!")
}
}
Did you mean to take that AuthStateListener object and assign it to mAuthListener during onCreate()?
Related
1) This is the create campaign activity which creates the campaign and candidate
class CreateCampaignActivity : AppCompatActivity() {
private lateinit var startDateTimeTextView: TextView
private lateinit var endDateTimeTextView: TextView
private lateinit var titleEditText: TextInputEditText
private lateinit var db: FirebaseFirestore
private lateinit var candidate1Text: TextInputEditText
private lateinit var candidate2Text: TextInputEditText
private lateinit var candidate3Text: TextInputEditText
private lateinit var addCampaignButton : Button
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_create_campaign)
supportActionBar!!.setDisplayHomeAsUpEnabled(true)
supportActionBar!!.title = "Create New Campaign"
titleEditText = findViewById(R.id.textTitle)
startDateTimeTextView = findViewById(R.id.start_date_time)
endDateTimeTextView = findViewById(R.id.end_date_time)
addCampaignButton = findViewById(R.id.btnAddCampaign)
candidate1Text = findViewById(R.id.textCandidate1)
candidate2Text = findViewById(R.id.textCandidate2)
candidate3Text = findViewById(R.id.textCandidate3)
db = FirebaseFirestore.getInstance()
addCampaignButton.setOnClickListener {
val title = titleEditText.text.toString().trim()
val startDateTime = startDateTimeTextView.text.toString().trim()
val endDateTime = endDateTimeTextView.text.toString().trim()
val candidate1Name = candidate1Text.text.toString().trim()
val candidate2Name = candidate2Text.text.toString().trim()
val candidate3Name = candidate3Text.text.toString().trim()
if (title.isEmpty() || startDateTime.isEmpty() || endDateTime.isEmpty() || candidate1Name.isEmpty() || candidate2Name.isEmpty() || candidate3Name.isEmpty()) {
Toast.makeText(this#CreateCampaignActivity, "Please fill up empty fields", Toast.LENGTH_SHORT).show()
} else if (!isEndTimeValid(startDateTime, endDateTime)) {
// Show error message or toast indicating that end time must be after start time
Toast.makeText(this#CreateCampaignActivity, "The end time must be after start time", Toast.LENGTH_SHORT).show()
} else {
val format = SimpleDateFormat("yyyy-MM-dd HH:mm", Locale.US)
val startTimestamp = Timestamp(format.parse(startDateTime)!!)
val endTimestamp = Timestamp(format.parse(endDateTime)!!)
val campaign = Campaign(
id = UUID.randomUUID().toString(),
title = title,
startDateTime = startTimestamp,
endDateTime = endTimestamp,
candidate1 = Candidate(
id = UUID.randomUUID().toString(),
name = candidate1Name
),
candidate2 = Candidate(
id = UUID.randomUUID().toString(),
name = candidate2Name
),
candidate3 = Candidate(id = UUID.randomUUID().toString(), name = candidate3Name)
)
// Add the campaign to the Firestore database
db.collection("campaigns")
.add(campaign)
.addOnSuccessListener { documentReference ->
campaign.id = documentReference.id
Log.d(
TAG,
"Campaign successfully added to Firestore with ID: ${documentReference.id}"
)
// Show success message or toast indicating that the campaign was successfully added
Toast.makeText(this#CreateCampaignActivity, "Campaign successfully added", Toast.LENGTH_SHORT).show()
// Clear the input fields
titleEditText.setText("")
startDateTimeTextView.text = ""
endDateTimeTextView.text = ""
candidate1Text.setText("")
candidate2Text.setText("")
candidate3Text.setText("")
// Navigate back to the previous activity
finish()
}
.addOnFailureListener { e ->
Log.w(TAG, "Error adding campaign to Firestore", e)
// Show error message or toast indicating that there was an error adding the campaign
Toast.makeText(this#CreateCampaignActivity, "Error adding campaign", Toast.LENGTH_SHORT).show()
}
}
startDateTimeTextView.setOnClickListener {
showStartDateTimeDialog()
}
endDateTimeTextView.setOnClickListener {
showEndDateTimeDialog()
}
}
}
private fun showStartDateTimeDialog() {
// Code to show the DatePicker and TimePicker dialogs
val calendar = Calendar.getInstance()
val dateSetListener = DatePickerDialog.OnDateSetListener { _, year, month, day ->
calendar.set(Calendar.YEAR, year)
calendar.set(Calendar.MONTH, month)
calendar.set(Calendar.DAY_OF_MONTH, day)
val timeSetListener = TimePickerDialog.OnTimeSetListener { _, hour, minute ->
calendar.set(Calendar.HOUR_OF_DAY, hour)
calendar.set(Calendar.MINUTE, minute)
startDateTimeTextView.text =
SimpleDateFormat("yyyy-MM-dd HH:mm", Locale.getDefault()).format(calendar.time)
}
TimePickerDialog(
this#CreateCampaignActivity,
timeSetListener,
calendar.get(Calendar.HOUR_OF_DAY),
calendar.get(Calendar.MINUTE),
true
).show()
}
DatePickerDialog(
this#CreateCampaignActivity,
dateSetListener,
calendar.get(Calendar.YEAR),
calendar.get(Calendar.MONTH),
calendar.get(Calendar.DAY_OF_MONTH)
).show()
}
private fun showEndDateTimeDialog() {
// Code to show the DatePicker and TimePicker dialogs
val calendar = Calendar.getInstance()
val dateSetListener = DatePickerDialog.OnDateSetListener { _, year, month, day ->
calendar.set(Calendar.YEAR, year)
calendar.set(Calendar.MONTH, month)
calendar.set(Calendar.DAY_OF_MONTH, day)
val timeSetListener = TimePickerDialog.OnTimeSetListener { _, hour, minute ->
calendar.set(Calendar.HOUR_OF_DAY, hour)
calendar.set(Calendar.MINUTE, minute)
endDateTimeTextView.text =
SimpleDateFormat("yyyy-MM-dd HH:mm", Locale.getDefault()).format(calendar.time)
}
TimePickerDialog(
this#CreateCampaignActivity,
timeSetListener,
calendar.get(Calendar.HOUR_OF_DAY),calendar.get(Calendar.MINUTE),
true
).show()
}
DatePickerDialog(
this#CreateCampaignActivity,
dateSetListener,
calendar.get(Calendar.YEAR),
calendar.get(Calendar.MONTH),
calendar.get(Calendar.DAY_OF_MONTH)
).show()
}
private fun isEndTimeValid(startDateTime: String, endDateTime: String): Boolean {
// Code to check if the end time is valid (i.e. after the start time)
val sdf = SimpleDateFormat("yyyy-MM-dd HH:mm", Locale.getDefault())
val startDate = sdf.parse(startDateTime)
val endDate = sdf.parse(endDateTime)
return endDate?.after(startDate) ?: false
}
companion object {
private const val TAG = "CreateCampaignActivity"
}
}
2) This is the edit campaign Activity to edit and delete campaign
class EditCampaignActivity : AppCompatActivity() {
private lateinit var datetimeTextView: TextView
private lateinit var titleEditText: TextInputEditText
private lateinit var db: FirebaseFirestore
private lateinit var candidate1Text: TextInputEditText
private lateinit var candidate2Text: TextInputEditText
private lateinit var candidate3Text: TextInputEditText
private lateinit var editCampaign : Button
private lateinit var delCampaign: Button
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_edit_campaign)
supportActionBar!!.setDisplayHomeAsUpEnabled(true)
supportActionBar!!.title = "Edit Campaign"
titleEditText = findViewById(R.id.textTitle)
datetimeTextView = findViewById(R.id.DateTime)
delCampaign = findViewById(R.id.btndelCampaign)
editCampaign = findViewById(R.id.btnSaveCampaign)
db = FirebaseFirestore.getInstance()
candidate1Text = findViewById(R.id.textCandidate1)
candidate2Text = findViewById(R.id.textCandidate2)
candidate3Text = findViewById(R.id.textCandidate3)
intent.getStringExtra("CAMPAIGN_ID")
val campaign = intent.getParcelableExtra<Campaign>("CAMPAIGN_DATA")
if (campaign != null) {
intent.putExtra("CAMPAIGN_ID", campaign.id)
}
if (campaign != null) {
titleEditText.setText(campaign.title)
}
if (campaign != null) {
datetimeTextView.text = campaign.endDateTime.toDate().toString()
}
if (campaign != null) {
candidate1Text.setText(campaign.candidate1.name)
}
if (campaign != null) {
candidate2Text.setText(campaign.candidate2.name)
}
if (campaign != null) {
candidate3Text.setText(campaign.candidate3.name)
}
//Update function
editCampaign.setOnClickListener {
// Update the fields of the Campaign object
val updatedTitle = titleEditText.text.toString()
val updatedCandidate1 = candidate1Text.text.toString()
val updatedCandidate2 = candidate2Text.text.toString()
val updatedCandidate3 = candidate3Text.text.toString()
campaign?.apply {
title = updatedTitle
endDateTime = Timestamp.now()
candidate1.name = updatedCandidate1
candidate2.name = updatedCandidate2
candidate3.name = updatedCandidate3
}
if (campaign != null) {
db.collection("campaigns").document(campaign.id)
.update(mapOf(
"title" to updatedTitle,
"endDateTime" to Timestamp.now(),
"candidate1" to mapOf(
"name" to updatedCandidate1
),
"candidate2" to mapOf(
"name" to updatedCandidate2
),
"candidate3" to mapOf(
"name" to updatedCandidate3
)
))
.addOnSuccessListener {
// Update successful, show a message to the user
Toast.makeText(this, "Campaign updated", Toast.LENGTH_SHORT).show()
}
.addOnFailureListener {
// Update failed, show an error message
Toast.makeText(this, "Error updating campaign: $it", Toast.LENGTH_SHORT).show()
}
}
// Confirm the edit action with the user
AlertDialog.Builder(this)
.setTitle("Edit Campaign")
.setMessage("Are you sure you want to save the changes to this campaign?")
.setPositiveButton("Yes") { _, _ ->
// Navigate back to the OrganiserActivity
finish()
}
.setNegativeButton("No", null)
.show()
}
// perform delete function
delCampaign.setOnClickListener {
// Show a message dialog to confirm the delete action
AlertDialog.Builder(this)
.setTitle("Delete Campaign")
.setMessage("Are you sure you want to delete this campaign?")
.setPositiveButton("Yes") { _, _ ->
if (campaign != null) {
deleteCampaign(campaign)
}
}
.setNegativeButton("No", null)
.show()
}
}
private fun deleteCampaign(campaign: Campaign) {
db.collection("campaigns").document(campaign.id).delete()
.addOnSuccessListener {
// Navigate back to the OrganiserActivity
finish()
}
.addOnFailureListener { e ->
// Show an error message
Toast.makeText(this, "Error deleting campaign: ${e.message}", Toast.LENGTH_SHORT).show()
}
}
}
The problem is I can't perform the delete and update function in the edit campaign activity. Whenever I created a new campaign from createCampaignActivity, I tried to edit the campaign and it states in the message dialog that firestore database has no document to update even though the document exists in the firestorm. How to solve this issue?
I am trying to get the user uid after creating an account, so I can create a document on Firestore with the uid as document id. The problem is that I get only null, everything is working fine and I'm able to sign the user and receive the code but the uid is always null.
I know I'm accessing the uid before it's initialized because it takes time to restore the authentication state when the app starts so any idea how to wait for it until it's initialized?
First of all, if the data entered is correct then we call login() function, then we send the verification code, when the code is sent inside the onCodeSent(), the method we call uploadSelectedImageToFirebaseStorage() to upload the user image then we call saveUserToDatabase() function, and here is the problem. Inside the saveUserToDatabase() function, the UID is always null no matter what I tried, am I missing something?
#file:Suppress("DEPRECATION")
class SignUpActivity : AppCompatActivity() {
private lateinit var binding: ActivitySignUpBinding
private lateinit var auth: FirebaseAuth
private lateinit var callbacks: PhoneAuthProvider.OnVerificationStateChangedCallbacks
lateinit var storedVerificationId: String
lateinit var resendToken: PhoneAuthProvider.ForceResendingToken
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivitySignUpBinding.inflate(LayoutInflater.from(this))
auth = FirebaseAuth.getInstance()
setContentView(binding.root)
val flProfilePicture = binding.frameProfilePicture
val tilUserName = binding.tilUserName
val tilPhoneNumber = binding.tilPhoneNumber
val startButton = binding.startButton
val currentUser = auth.currentUser
if (currentUser != null) {
val intent = Intent(this#SignUpActivity, MainChatsActivity::class.java)
startActivity(intent)
finish()
}
callbacks = object : PhoneAuthProvider.OnVerificationStateChangedCallbacks() {
override fun onVerificationCompleted(credential: PhoneAuthCredential) { }
override fun onVerificationFailed(e: FirebaseException) { }
override fun onCodeSent(
verificationId: String,
token: PhoneAuthProvider.ForceResendingToken,
) {
Toast.makeText(baseContext, "Code Sent", Toast.LENGTH_SHORT).show()
storedVerificationId = verificationId
resendToken = token
val intent = Intent(applicationContext, AuthenticatePhoneActivity::class.java)
intent.putExtra("storedVerificationId", storedVerificationId)
uploadSelectedImageToFirebaseStorage()
startActivity(intent)
finish()
}
}
flProfilePicture.setOnClickListener {
val intent = Intent(Intent.ACTION_PICK)
intent.type = "image/*"
startActivityForResult(intent, 0)
}
startButton.setOnClickListener {
if (TextUtils.isEmpty(tilUserName.text.toString())) {
tilUserName.error = "Enter valid Name"
}
if (TextUtils.isEmpty(tilPhoneNumber.text.toString())) {
tilPhoneNumber.error = "Enter valid phone number"
} else {
val userName: String = tilUserName.text.toString()
val userPhoneNumber: String = tilPhoneNumber.text.toString()
login()
}
}
}
private var selectedProfilePicture: Uri? = null
#Deprecated("Deprecated in Java")
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
if (requestCode == 0 && data != null) {
selectedProfilePicture = data.data
val bitmap = MediaStore.Images.Media.getBitmap(contentResolver, selectedProfilePicture)
val flProfilePicture = binding.frameProfilePicture
val selectedCircleFrame = binding.selectedPictureCircleFrame
selectedCircleFrame.setImageBitmap(bitmap)
flProfilePicture.alpha = 0f
}
}
private fun login() {
val mobileNumber = binding.tilPhoneNumber
val number = mobileNumber.text.toString().trim()
if (number.isNotEmpty()) {
sendVerificationCode(number)
} else {
mobileNumber.error = "Enter a valid phone number"
}
}
private fun sendVerificationCode(number: String) {
val options = PhoneAuthOptions.newBuilder(auth)
.setPhoneNumber(number)
.setTimeout(60L, TimeUnit.SECONDS)
.setActivity(this)
.setCallbacks(callbacks)
.build()
PhoneAuthProvider.verifyPhoneNumber(options)
}
private fun uploadSelectedImageToFirebaseStorage() {
if (selectedProfilePicture == null) {
return
}
val fileName = UUID.randomUUID().toString()
val ref = FirebaseStorage.getInstance().getReference("/images/$fileName")
ref.putFile(selectedProfilePicture!!)
.addOnSuccessListener {
ref.downloadUrl.addOnSuccessListener {
it.toString()
Log.d("SignUpActivity", "image uploaded successfully")
saveUserToDatabase(it.toString())
}
}
.addOnFailureListener {
saveUserToDatabase(it.toString())
}
}
private fun saveUserToDatabase(profileImageUrl: String) {
val tilUserName = binding.tilUserName.text.toString()
val tilPhoneNumber = binding.tilPhoneNumber.text.toString()
val uid = FirebaseAuth.getInstance().uid.toString()
val database = Firebase.database("https://blend-4a9e4-default-rtdb.asia-southeast1.firebasedatabase.app")
val myRef = database.getReference("/users/$uid")
val user = User(uid, tilPhoneNumber, tilUserName, profileImageUrl)
Log.d("currentUser", uid)
myRef.setValue(user)
.addOnFailureListener {
Toast.makeText(baseContext, "Something went wrong, try again.", Toast.LENGTH_SHORT).show()
}
}
}
I created a number sending activity and confirmation/otp fragment using firebase phone auth. When directed to the confirmation page, a 6-digit sms code from Firebase is sent to the phone number entered, but no matter what I do, the entered edittext and the codes from firebase do not match.
When I leave the edit text blank, it redirects to the fragment I want as if it were correct. Can you help me where am I making a mistake? My codes in the confirmation fragment are as follows;
class FragmentRegisterTelOnay : Fragment() {
var comingNumber = ""
lateinit var auth : FirebaseAuth
lateinit var callbacks : PhoneAuthProvider.OnVerificationStateChangedCallbacks
var verificationID = ""
var comingCode : String = ""
override fun onCreateView(inflater: LayoutInflater,container: ViewGroup?,savedInstanceState: Bundle?): View? {
var view = inflater.inflate(R.layout.fragment_register_activity_phone,container,false)
view.tvKullaniciTelNo.setText("+90"+comingNumber)
auth = Firebase.auth
setupCallBack()
view.ileriButton.setOnClickListener {
if (comingCode.equals(editTextOnayKodu.text.toString())){
EventBus.getDefault().postSticky(EventBusDataEvents.KayitBilgileriniGonder("+90$comingNumber",null,verificationID,comingCode))
val transaction = requireActivity().supportFragmentManager.beginTransaction()
transaction.replace(R.id.telefonOnayKod,FragmentRegisterDetailPhone())
transaction.addToBackStack("TelOnayfragmentEklendi")
transaction.commit()}
else{
Toast.makeText(activity,"Wrong Code",Toast.LENGTH_LONG).show()
}
}
val options = PhoneAuthOptions.newBuilder(auth)
.setPhoneNumber("+90"+comingNumber) // Phone number to verify
.setTimeout(60L, TimeUnit.SECONDS) // Timeout and unit
.setActivity(requireActivity()) // Activity (for callback binding)
.setCallbacks(callbacks) // OnVerificationStateChangedCallbacks
.build()
PhoneAuthProvider.verifyPhoneNumber(options)
return view
}
private fun setupCallBack() {
callbacks = object : PhoneAuthProvider.OnVerificationStateChangedCallbacks() {
override fun onVerificationCompleted(credential: PhoneAuthCredential) {
if(!credential.smsCode.isNullOrEmpty()){
comingCode = credential.smsCode!!
progressBarOnayKod.visibility = View.GONE
Log.e("Success","on verificationcompleted sms: " + comingCode)}
else{
Log.e("Error","onverification has not completed")
}
}
override fun onVerificationFailed(e: FirebaseException) {
Log.e("Error: ",e.localizedMessage)
progressBarOnayKod.visibility = View.GONE
}
override fun onCodeSent(verificationId: String,token: PhoneAuthProvider.ForceResendingToken) {
verificationID = verificationId
progressBarOnayKod.visibility = View.VISIBLE
Log.e("Codesent","oncodesent worked")
}
}
}
#Subscribe (sticky = true)
internal fun onTelefonEvent(kayitBilgileri: EventBusDataEvents.KayitBilgileriniGonder){
comingNumber = kayitBilgileri.telNo.toString()
Log.e("test",comingNumber)
}
override fun onAttach(context: Context) {
super.onAttach(context)
EventBus.getDefault().register(this)
}
override fun onDetach() {
super.onDetach()
EventBus.getDefault().unregister(this)
}
}
first set the sha1 to firebase setting and generate google config.json then add to poject's root directory and add to build.gradle dependency.
it'll work properly
resources: https://github.com/firebase/quickstart-android/issues/283
I need to login users with Google Sign On onto Firebase. But since I need to use the Calendar API, I have to do a custom login (and not the one provided through Firebase on default), as I need the Oauth refresh token - which is not provided by Firebase. I have looked at the docs but none seem to work, I am using the below code as of now... can anybody suggest how do I use the token obtained from Google to login/register with Firebase?
private const val TAG = "WelcomeActivity"
class WelcomeActivity : AppCompatActivity() {
var firebaseUser: FirebaseUser? = null
//For Google Sign In
val RC_SIGN_IN: Int = 9001
private lateinit var mGoogleSignInClient: GoogleSignInClient
lateinit var mGoogleSignInOptions: GoogleSignInOptions
private lateinit var firebaseAuth: FirebaseAuth
private var firebaseUserID: String = ""
private lateinit var refUsers: DatabaseReference
//get data from google signin in handlesigninresult
private var googleId = ""
private var googleFirstName = ""
private var googleLastName = ""
private var googleEmail = ""
private var googleProfilePicURL = ""
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_welcome)
// //For google sign in
// configureGoogleSignIn()
// setupUI()
// enablePersistence()
firebaseAuth = FirebaseAuth.getInstance()
val gso = GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN)
.requestIdToken("")
.requestEmail()
.build()
mGoogleSignInClient = GoogleSignIn.getClient(this, gso)
google_login.setOnClickListener {
signIn()
}
login_welcome.setOnClickListener {
val intent = Intent(this#WelcomeActivity, LoginActivity::class.java)
startActivity(intent)
finish()
}
}
private fun signIn() {
val signInIntent = mGoogleSignInClient.signInIntent
startActivityForResult(signInIntent, RC_SIGN_IN)
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
if (requestCode == RC_SIGN_IN) {
val task =
GoogleSignIn.getSignedInAccountFromIntent(data)
handleSignInResult(task)
}
}
private fun handleSignInResult(completedTask: Task<GoogleSignInAccount>) {
try {
val account = completedTask.getResult(
ApiException::class.java
)
// Signed in successfully
googleId = account?.id ?: ""
Log.i("Google ID", googleId)
googleFirstName = account.givenName ?: ""
Log.i("Google First Name", googleFirstName)
googleLastName = account?.familyName ?: ""
Log.i("Google Last Name", googleLastName)
googleEmail = account?.email ?: ""
Log.i("Google Email", googleEmail)
val googleIdToken: String = account?.idToken ?: ""
Log.i("Google ID Token", googleIdToken)
googleProfilePicURL = account?.photoUrl.toString()
Log.i("Google Profile Pic URL", googleProfilePicURL)
firebaseAuthWithGoogle(googleIdToken)
} catch (e: ApiException) {
// Sign in was unsuccessful
Log.e(
"failed code=", e.statusCode.toString()
)
}
}
private fun enablePersistence() {
// [START rtdb_enable_persistence]
Firebase.database.setPersistenceEnabled(true)
// [END rtdb_enable_persistence]
}
private fun firebaseAuthWithGoogle(idToken: String) {
val credential = GoogleAuthProvider.getCredential(idToken, null)
firebaseAuth.signInWithCredential(credential)
.addOnCompleteListener(this) { task ->
if (task.isSuccessful) {
// Sign in success, update UI with the signed-in user's information
Log.d(TAG, "signInWithCredential:success")
firebaseUserID = firebaseAuth.currentUser!!.uid
refUsers = FirebaseDatabase.getInstance().reference.child("Users").child(firebaseUserID)
refUsers.addListenerForSingleValueEvent(object : ValueEventListener {
override fun onDataChange(p0: DataSnapshot) {
if (p0.exists()) {
val user: Users? = p0.getValue(Users::class.java)
//Check if user exists in the database
if (user!!.getFirstName() != null) {
val intent = Intent(
this#WelcomeActivity,
IntroSplashScreen::class.java
)
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK or Intent.FLAG_ACTIVITY_NEW_TASK)
startActivity(intent)
finish()
} else {
val usersHashMap = HashMap<String, Any>()
usersHashMap["uid"] = firebaseUserID
usersHashMap["firstname"] = googleFirstName
usersHashMap["surname"] = googleLastName
usersHashMap["profile"] = googleProfilePicURL
usersHashMap["primaryEmail"] = googleEmail
usersHashMap["search"] =
googleFirstName.toLowerCase(Locale.ROOT)
refUsers.updateChildren(usersHashMap)
.addOnCompleteListener {
if (task.isSuccessful) {
val intent = Intent(
this#WelcomeActivity,
NewProfileData::class.java
)
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK or Intent.FLAG_ACTIVITY_NEW_TASK)
startActivity(intent)
finish()
}
}
}
}
}
override fun onCancelled(error: DatabaseError) {
TODO("Not yet implemented")
}
})
} else {
// If sign in fails, display a message to the user.
Log.w(TAG, "signInWithCredential:failure", task.exception)
// ...
}
// ...
}
}
private fun refreshIdToken() {
// Attempt to silently refresh the GoogleSignInAccount. If the GoogleSignInAccount
// already has a valid token this method may complete immediately.
//
// If the user has not previously signed in on this device or the sign-in has expired,
// this asynchronous branch will attempt to sign in the user silently and get a valid
// ID token. Cross-device single sign on will occur in this branch.
mGoogleSignInClient.silentSignIn()
.addOnCompleteListener(
this
) { task -> handleSignInResult(task) }
}
override fun onStart() {
super.onStart()
//Checks if the Google IDToken has expired, if yes it refreshes by SilentSign in and generates new Firebase Token
refreshIdToken()
//Checks if user is logged in to firebase
firebaseUser = FirebaseAuth.getInstance().currentUser
//If logged in then sends to MainActivity
if (firebaseUser != null) {
startActivity(IntroSplashScreen.getLaunchIntent(this))
finish()
}
}
override fun onResume() {
super.onResume()
refreshIdToken()
}
}
My method of checking if the user exists was incorrect with the currect process being to put the check on Datasnapshot exits or not. If exists then login else register.
maybe my code will mess here beacuse I'm new into firebase stuff and there is lack doc for newbie like me, so I want to make save and load data from firebase, there is 2 scene the first for main menu and second one the main game,so when firstime login or auto login, user will load current user data from realtime database (I'm using firebase) also applies to user when back to main menu.
in the second scene itself, user load current user highscore data at first start then when game over if the score > lasthighscore that will save/update latest highscore to realtime database.
here the preview this is when I auto-login then playgame until game over:
it's supposed to be updated but not when back to main menu, I already try with player prefs since i erase all data when sign out so the highscore always be 0 and if login with other account that highscore is not belong to other account.
here my firebase script on main menu:
private void Start()
{
Time.timeScale = 1;
mainPanel.SetActive(true);
InitializeFirebase();
}
void InitializeFirebase()
{
auth = FirebaseAuth.DefaultInstance;
DBreference = FirebaseDatabase.DefaultInstance.RootReference;
auth.StateChanged += AuthStateChanged;
AuthStateChanged(this, null);
}
void AuthStateChanged(object sender, System.EventArgs eventArgs)
{
//This checks if the user (your local user) is the same as the one from the auth
if (auth.CurrentUser != User)
{
//this seems the same, but user could have been null before
bool signedIn = User != auth.CurrentUser && auth.CurrentUser != null;
if (!signedIn && User != null)
{
Debug.Log("Signed out " + User.UserId);
loginPanel.SetActive(true);
}
//this is important step, this user is the one you should be working with
User = auth.CurrentUser;
if (signedIn)
{
Debug.Log("Signed in " + User.UserId);
userNameShowText.text = User.DisplayName;
StartCoroutine(LoadUserData());
loginPanel.SetActive(false);
// //highScoreMainMenu.text = PlayerPrefs.GetInt("highscore").ToString("0000000");
}
else
{
loginPanel.SetActive(true);
}
}
}
public IEnumerator Login(string _email, string _password)
{
//Call the Firebase auth signin function passing the email and password
var LoginTask = auth.SignInWithEmailAndPasswordAsync(_email, _password);
//Wait until the task completes
yield return new WaitUntil(predicate: () => LoginTask.IsCompleted);
if (LoginTask.Exception != null)
{
//If there are errors handle them
Debug.LogWarning(message: $"Failed to register task with {LoginTask.Exception}");
FirebaseException firebaseEx = LoginTask.Exception.GetBaseException() as FirebaseException;
AuthError errorCode = (AuthError)firebaseEx.ErrorCode;
string message = "Login Failed!";
switch (errorCode)
{
case AuthError.MissingEmail:
message = "Missing Email";
break;
case AuthError.MissingPassword:
message = "Missing Password";
break;
case AuthError.WrongPassword:
message = "Wrong Password";
break;
case AuthError.InvalidEmail:
message = "Invalid Email";
break;
case AuthError.UserNotFound:
message = "Account does not exist";
break;
}
warningLoginText.text = message;
}
else
{
//User is now logged in
//Now get the result
User = LoginTask.Result;
Debug.LogFormat("User signed in successfully: {0} ({1})", User.DisplayName, User.Email);
warningLoginText.text = "";
confirmLoginText.text = "Logged In";
StartCoroutine(LoadUserData());
yield return new WaitForSeconds(2);
userNameShowText.text = User.DisplayName;
UserDataScreen(); // Change to user data UI
confirmLoginText.text = "";
ClearLoginFeilds();
ClearRegisterFeilds();
}
}
public IEnumerator UpdateHighScore(int _highScore)
{
var DBTask = DBreference.Child("users").Child(auth.CurrentUser.UserId).Child("highscore").SetValueAsync(_highScore);
yield return new WaitUntil(predicate: () => DBTask.IsCompleted);
if (DBTask.Exception != null)
{
Debug.LogWarning(message: $"Failed to register task with {DBTask.Exception}");
}
else
{
//giscrore now updated
}
}
and this is for the game scene also same function for update higscore like on main menu.
void Start()
{
InitializeFirebase();
YetGameOver();
//GetScore
score = 0;
scoreText.text = score.ToString("00000");
//highScoreText.text = "HI :" + PlayerPrefs.GetInt("highscore", 0).ToString("00000");
maxTime = .1f;
}
void InitializeFirebase()
{
auth = FirebaseAuth.DefaultInstance;
DBreference = FirebaseDatabase.DefaultInstance.RootReference;
auth.StateChanged += AuthStateChanged;
AuthStateChanged(this, null);
}
void AuthStateChanged(object sender, System.EventArgs eventArgs)
{
//This checks if the user (your local user) is the same as the one from the auth
if (auth.CurrentUser != User)
{
//this seems the same, but user could have been null before
bool signedIn = User != auth.CurrentUser && auth.CurrentUser != null;
if (!signedIn && User != null)
{
Debug.Log("Signed out " + User.UserId);
}
//this is important step, this user is the one you should be working with
User = auth.CurrentUser;
if (signedIn)
{
Debug.Log("Signed in " + User.UserId);
StartCoroutine(LoadUserData());
//highScoreMainMenu.text = PlayerPrefs.GetInt("highscore").ToString("0000000");
}
}
}
public void GameOver()
{
SaveData();
StartCoroutine(WaitToDeath());
}
public void SaveData()
{
Debug.Log("Saved");
StartCoroutine(UpdateHighScore(PlayerPrefs.GetInt("highscore", 0)));
}
public IEnumerator WaitToDeath()
{
_CamShake.instance.shouldShake = true;
DeathSound();
gameOverPanel.SetActive(true);
endHighScoreText.text = "HI :" + PlayerPrefs.GetInt("highscore").ToString("0000000");
scoreText.gameObject.SetActive(false);
highScoreText.gameObject.SetActive(false);
yield return new WaitForSeconds(.1f);
//_AdmobAds.instance.ShowInterstitialAd();
isStarted = false;
isGameOver = true;
Time.timeScale = 0;
}
//same function like main menu
public IEnumerator UpdateHighScore(int _highScore)
{
var DBTask = DBreference.Child("users").Child(auth.CurrentUser.UserId).Child("highscore").SetValueAsync(_highScore);
yield return new WaitUntil(predicate: () => DBTask.IsCompleted);
if (DBTask.Exception != null)
{
Debug.LogWarning(message: $"Failed to register task with {DBTask.Exception}");
}
else
{
//highscore are now updated
}
}
public IEnumerator LoadUserData()
{
//Get the currently logged in user data
var DBTask = DBreference.Child("users").Child(User.UserId).GetValueAsync();
yield return new WaitUntil(predicate: () => DBTask.IsCompleted);
if (DBTask.Exception != null)
{
Debug.LogWarning(message: $"Failed to register task with {DBTask.Exception}");
}
else if (DBTask.Result.Value == null)
{
//No data exists yet
highScoreText.text = "0";
endHighScoreText.text = "0";
}
else
{
//Data has been retrieved
DataSnapshot snapshot = DBTask.Result;
highScoreText.text = endHighScoreText.text = snapshot.Child("highscore").Value.ToString();
}
}
You don't capture child in this method. You can only capture all the data from the root. So, simply remove the child. It will work.
my solution to firebase realtime database not working was that my google-services.json wasnt updated after adding the google-services.json from firebase auth. firebase, project overview cogwheel, project settings, json on that page somewhere.
and my problem with firebase auth before that was that i didnt set the Client ID in unity, window, google play games, setup, android setup.. get the id from google play console, play games services, setup & management, configuration, and figure out how to add game server credentials