1
1
package com.google.firebase.quickstart.auth.kotlin
2
2
3
- import android.content.Intent
4
3
import android.os.Bundle
5
- import android.text.TextUtils
6
- import android.util.Log
7
4
import android.view.LayoutInflater
8
5
import android.view.View
9
6
import 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
19
12
import com.google.firebase.quickstart.auth.databinding.FragmentEmailpasswordBinding
13
+ import kotlinx.coroutines.launch
20
14
21
15
class EmailPasswordFragment : BaseFragment () {
22
-
23
- private lateinit var auth: FirebaseAuth
24
-
25
16
private var _binding : FragmentEmailpasswordBinding ? = null
26
17
private val binding: FragmentEmailpasswordBinding
27
18
get() = _binding !!
28
19
20
+ private val viewModel by viewModels<EmailPasswordViewModel >()
21
+
29
22
override fun onCreateView (inflater : LayoutInflater , container : ViewGroup ? , savedInstanceState : Bundle ? ): View ? {
30
23
_binding = FragmentEmailpasswordBinding .inflate(inflater, container, false )
31
24
return binding.root
@@ -41,200 +34,50 @@ class EmailPasswordFragment : BaseFragment() {
41
34
emailSignInButton.setOnClickListener {
42
35
val email = binding.fieldEmail.text.toString()
43
36
val password = binding.fieldPassword.text.toString()
44
- signIn(email, password)
37
+
38
+ viewModel.signIn(email, password)
45
39
}
46
40
emailCreateAccountButton.setOnClickListener {
47
41
val email = binding.fieldEmail.text.toString()
48
42
val password = binding.fieldPassword.text.toString()
49
- createAccount(email, password)
50
- }
51
- signOutButton.setOnClickListener { signOut() }
52
- verifyEmailButton.setOnClickListener { sendEmailVerification() }
53
- reloadButton.setOnClickListener { reload() }
54
- }
55
43
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() }
73
49
}
74
50
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
101
57
102
- showProgressBar()
58
+ // Display texts
59
+ binding.status.text = uiState.userId
60
+ binding.detail.text = uiState.userEmail
103
61
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()
111
65
} 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()
118
67
}
119
68
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
124
74
}
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()
164
75
}
165
76
}
166
77
}
167
78
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
-
231
79
override fun onDestroyView () {
232
80
super .onDestroyView()
233
81
_binding = null
234
82
}
235
-
236
- companion object {
237
- private const val TAG = " EmailPassword"
238
- private const val RC_MULTI_FACTOR = 9005
239
- }
240
83
}
0 commit comments