11package com.google.firebase.quickstart.auth.kotlin
22
3- import android.content.Intent
43import android.os.Bundle
5- import android.text.TextUtils
6- import android.util.Log
74import android.view.LayoutInflater
85import android.view.View
96import android.view.ViewGroup
10- import android.widget.Toast
11- import androidx.core.os.bundleOf
12- import androidx.navigation.fragment.findNavController
13- import com.google.firebase.auth.FirebaseAuth
14- import com.google.firebase.auth.FirebaseAuthMultiFactorException
15- import com.google.firebase.auth.FirebaseUser
16- import com.google.firebase.auth.ktx.auth
17- import com.google.firebase.ktx.Firebase
18- import com.google.firebase.quickstart.auth.R
7+ import androidx.core.view.isGone
8+ import androidx.fragment.app.viewModels
9+ import androidx.lifecycle.Lifecycle
10+ import androidx.lifecycle.lifecycleScope
11+ import androidx.lifecycle.repeatOnLifecycle
1912import com.google.firebase.quickstart.auth.databinding.FragmentEmailpasswordBinding
13+ import kotlinx.coroutines.launch
2014
2115class EmailPasswordFragment : BaseFragment () {
22-
23- private lateinit var auth: FirebaseAuth
24-
2516 private var _binding : FragmentEmailpasswordBinding ? = null
2617 private val binding: FragmentEmailpasswordBinding
2718 get() = _binding !!
2819
20+ private val viewModel by viewModels<EmailPasswordViewModel >()
21+
2922 override fun onCreateView (inflater : LayoutInflater , container : ViewGroup ? , savedInstanceState : Bundle ? ): View ? {
3023 _binding = FragmentEmailpasswordBinding .inflate(inflater, container, false )
3124 return binding.root
@@ -41,200 +34,50 @@ class EmailPasswordFragment : BaseFragment() {
4134 emailSignInButton.setOnClickListener {
4235 val email = binding.fieldEmail.text.toString()
4336 val password = binding.fieldPassword.text.toString()
44- signIn(email, password)
37+
38+ viewModel.signIn(email, password)
4539 }
4640 emailCreateAccountButton.setOnClickListener {
4741 val email = binding.fieldEmail.text.toString()
4842 val password = binding.fieldPassword.text.toString()
49- createAccount(email, password)
50- }
51- signOutButton.setOnClickListener { signOut() }
52- verifyEmailButton.setOnClickListener { sendEmailVerification() }
53- reloadButton.setOnClickListener { reload() }
54- }
5543
56- // Initialize Firebase Auth
57- auth = Firebase .auth
58- }
59-
60- public override fun onStart () {
61- super .onStart()
62- // Check if user is signed in (non-null) and update UI accordingly.
63- val currentUser = auth.currentUser
64- if (currentUser != null ){
65- reload();
66- }
67- }
68-
69- private fun createAccount (email : String , password : String ) {
70- Log .d(TAG , " createAccount:$email " )
71- if (! validateForm()) {
72- return
44+ viewModel.createAccount(email, password)
45+ }
46+ signOutButton.setOnClickListener { viewModel.signOut() }
47+ verifyEmailButton.setOnClickListener { viewModel.sendEmailVerification() }
48+ reloadButton.setOnClickListener { viewModel.reload() }
7349 }
7450
75- showProgressBar()
76-
77- auth.createUserWithEmailAndPassword(email, password)
78- .addOnCompleteListener(requireActivity()) { task ->
79- if (task.isSuccessful) {
80- // Sign in success, update UI with the signed-in user's information
81- Log .d(TAG , " createUserWithEmail:success" )
82- val user = auth.currentUser
83- updateUI(user)
84- } else {
85- // If sign in fails, display a message to the user.
86- Log .w(TAG , " createUserWithEmail:failure" , task.exception)
87- Toast .makeText(context, " Authentication failed." ,
88- Toast .LENGTH_SHORT ).show()
89- updateUI(null )
90- }
91-
92- hideProgressBar()
93- }
94- }
95-
96- private fun signIn (email : String , password : String ) {
97- Log .d(TAG , " signIn:$email " )
98- if (! validateForm()) {
99- return
100- }
51+ lifecycleScope.launch {
52+ viewLifecycleOwner.repeatOnLifecycle(Lifecycle .State .STARTED ) {
53+ viewModel.uiState.collect { uiState ->
54+ // Handle errors
55+ binding.fieldEmail.error = uiState.emailError
56+ binding.fieldPassword.error = uiState.passwordError
10157
102- showProgressBar()
58+ // Display texts
59+ binding.status.text = uiState.userId
60+ binding.detail.text = uiState.userEmail
10361
104- auth.signInWithEmailAndPassword(email, password)
105- .addOnCompleteListener(requireActivity()) { task ->
106- if (task.isSuccessful) {
107- // Sign in success, update UI with the signed-in user's information
108- Log .d(TAG , " signInWithEmail:success" )
109- val user = auth.currentUser
110- updateUI(user)
62+ // Toggle progress bar
63+ if (uiState.isProgressBarVisible) {
64+ showProgressBar()
11165 } else {
112- // If sign in fails, display a message to the user.
113- Log .w(TAG , " signInWithEmail:failure" , task.exception)
114- Toast .makeText(context, " Authentication failed." ,
115- Toast .LENGTH_SHORT ).show()
116- updateUI(null )
117- checkForMultiFactorFailure(task.exception!! )
66+ hideProgressBar()
11867 }
11968
120- if (! task.isSuccessful) {
121- binding.status.setText(R .string.auth_failed)
122- }
123- hideProgressBar()
69+ // Toggle button visibility
70+ binding.verifyEmailButton.isGone = ! uiState.isVerifyEmailVisible
71+ binding.emailPasswordButtons.isGone = ! uiState.isSignInEnabled
72+ binding.emailPasswordFields.isGone = ! uiState.isSignInEnabled
73+ binding.signedInButtons.isGone = uiState.isSignInEnabled
12474 }
125- }
126-
127- private fun signOut () {
128- auth.signOut()
129- updateUI(null )
130- }
131-
132- private fun sendEmailVerification () {
133- // Disable button
134- binding.verifyEmailButton.isEnabled = false
135-
136- // Send verification email
137- val user = auth.currentUser!!
138- user.sendEmailVerification()
139- .addOnCompleteListener(requireActivity()) { task ->
140- // Re-enable button
141- binding.verifyEmailButton.isEnabled = true
142-
143- if (task.isSuccessful) {
144- Toast .makeText(context,
145- " Verification email sent to ${user.email} " ,
146- Toast .LENGTH_SHORT ).show()
147- } else {
148- Log .e(TAG , " sendEmailVerification" , task.exception)
149- Toast .makeText(context,
150- " Failed to send verification email." ,
151- Toast .LENGTH_SHORT ).show()
152- }
153- }
154- }
155-
156- private fun reload () {
157- auth.currentUser!! .reload().addOnCompleteListener { task ->
158- if (task.isSuccessful) {
159- updateUI(auth.currentUser)
160- Toast .makeText(context, " Reload successful!" , Toast .LENGTH_SHORT ).show()
161- } else {
162- Log .e(TAG , " reload" , task.exception)
163- Toast .makeText(context, " Failed to reload user." , Toast .LENGTH_SHORT ).show()
16475 }
16576 }
16677 }
16778
168- private fun validateForm (): Boolean {
169- var valid = true
170-
171- val email = binding.fieldEmail.text.toString()
172- if (TextUtils .isEmpty(email)) {
173- binding.fieldEmail.error = " Required."
174- valid = false
175- } else {
176- binding.fieldEmail.error = null
177- }
178-
179- val password = binding.fieldPassword.text.toString()
180- if (TextUtils .isEmpty(password)) {
181- binding.fieldPassword.error = " Required."
182- valid = false
183- } else {
184- binding.fieldPassword.error = null
185- }
186-
187- return valid
188- }
189-
190- private fun updateUI (user : FirebaseUser ? ) {
191- hideProgressBar()
192- if (user != null ) {
193- binding.status.text = getString(R .string.emailpassword_status_fmt,
194- user.email, user.isEmailVerified)
195- binding.detail.text = getString(R .string.firebase_status_fmt, user.uid)
196-
197- binding.emailPasswordButtons.visibility = View .GONE
198- binding.emailPasswordFields.visibility = View .GONE
199- binding.signedInButtons.visibility = View .VISIBLE
200-
201- if (user.isEmailVerified) {
202- binding.verifyEmailButton.visibility = View .GONE
203- } else {
204- binding.verifyEmailButton.visibility = View .VISIBLE
205- }
206- } else {
207- binding.status.setText(R .string.signed_out)
208- binding.detail.text = null
209-
210- binding.emailPasswordButtons.visibility = View .VISIBLE
211- binding.emailPasswordFields.visibility = View .VISIBLE
212- binding.signedInButtons.visibility = View .GONE
213- }
214- }
215-
216- private fun checkForMultiFactorFailure (e : Exception ) {
217- // Multi-factor authentication with SMS is currently only available for
218- // Google Cloud Identity Platform projects. For more information:
219- // https://cloud.google.com/identity-platform/docs/android/mfa
220- if (e is FirebaseAuthMultiFactorException ) {
221- Log .w(TAG , " multiFactorFailure" , e)
222- val resolver = e.resolver
223- val args = bundleOf(
224- MultiFactorSignInFragment .EXTRA_MFA_RESOLVER to resolver,
225- MultiFactorFragment .RESULT_NEEDS_MFA_SIGN_IN to true
226- )
227- findNavController().navigate(R .id.action_emailpassword_to_mfa, args)
228- }
229- }
230-
23179 override fun onDestroyView () {
23280 super .onDestroyView()
23381 _binding = null
23482 }
235-
236- companion object {
237- private const val TAG = " EmailPassword"
238- private const val RC_MULTI_FACTOR = 9005
239- }
24083}
0 commit comments