diff --git a/auth/app/src/main/java/com/google/firebase/quickstart/auth/kotlin/FirebaseUIFragment.kt b/auth/app/src/main/java/com/google/firebase/quickstart/auth/kotlin/FirebaseUIFragment.kt index 86ec069c6..56bea5721 100644 --- a/auth/app/src/main/java/com/google/firebase/quickstart/auth/kotlin/FirebaseUIFragment.kt +++ b/auth/app/src/main/java/com/google/firebase/quickstart/auth/kotlin/FirebaseUIFragment.kt @@ -5,18 +5,20 @@ import android.os.Bundle import android.view.LayoutInflater import android.view.View import android.view.ViewGroup -import android.widget.Toast +import androidx.core.view.isGone import androidx.fragment.app.Fragment +import androidx.fragment.app.viewModels +import androidx.lifecycle.Lifecycle +import androidx.lifecycle.lifecycleScope +import androidx.lifecycle.repeatOnLifecycle import com.firebase.ui.auth.AuthUI import com.firebase.ui.auth.FirebaseAuthUIActivityResultContract import com.firebase.ui.auth.data.model.FirebaseAuthUIAuthenticationResult -import com.google.firebase.auth.FirebaseAuth -import com.google.firebase.auth.FirebaseUser -import com.google.firebase.auth.ktx.auth -import com.google.firebase.ktx.Firebase +import com.google.android.material.snackbar.Snackbar import com.google.firebase.quickstart.auth.BuildConfig import com.google.firebase.quickstart.auth.R import com.google.firebase.quickstart.auth.databinding.FragmentFirebaseUiBinding +import kotlinx.coroutines.launch /** * Demonstrate authentication using the FirebaseUI-Android library. This fragment demonstrates @@ -26,7 +28,7 @@ import com.google.firebase.quickstart.auth.databinding.FragmentFirebaseUiBinding */ class FirebaseUIFragment : Fragment() { - private lateinit var auth: FirebaseAuth + private val viewModel by viewModels() private var _binding: FragmentFirebaseUiBinding? = null private val binding: FragmentFirebaseUiBinding @@ -36,7 +38,7 @@ class FirebaseUIFragment : Fragment() { // possible customization see: https://github.com/firebase/firebaseui-android private val signInLauncher = registerForActivityResult( FirebaseAuthUIActivityResultContract() - ) { result -> this.onSignInResult(result)} + ) { result -> this.onSignInResult(result) } override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View { _binding = FragmentFirebaseUiBinding.inflate(inflater, container, false) @@ -46,62 +48,42 @@ class FirebaseUIFragment : Fragment() { override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) - // Initialize Firebase Auth - auth = Firebase.auth - binding.signInButton.setOnClickListener { startSignIn() } - binding.signOutButton.setOnClickListener { signOut() } - } - - override fun onStart() { - super.onStart() - updateUI(auth.currentUser) + binding.signOutButton.setOnClickListener { viewModel.signOut() } + + lifecycleScope.launch { + viewLifecycleOwner.repeatOnLifecycle(Lifecycle.State.STARTED) { + viewModel.uiState.collect { uiState -> + binding.status.text = uiState.status + binding.detail.text = uiState.detail + + binding.signInButton.isGone = !uiState.isSignInVisible + binding.signOutButton.isGone = uiState.isSignInVisible + } + } + } } private fun onSignInResult(result: FirebaseAuthUIAuthenticationResult) { if (result.resultCode == Activity.RESULT_OK) { // Sign in succeeded - updateUI(auth.currentUser) } else { // Sign in failed - Toast.makeText(context, "Sign In Failed", Toast.LENGTH_SHORT).show() - updateUI(null) + Snackbar.make(requireView(), "Sign In Failed", Snackbar.LENGTH_SHORT).show() } + viewModel.showSignedInUser() } private fun startSignIn() { val intent = AuthUI.getInstance().createSignInIntentBuilder() - .setIsSmartLockEnabled(!BuildConfig.DEBUG) - .setAvailableProviders(listOf(AuthUI.IdpConfig.EmailBuilder().build())) - .setLogo(R.mipmap.ic_launcher) - .build() + .setIsSmartLockEnabled(!BuildConfig.DEBUG) + .setAvailableProviders(listOf(AuthUI.IdpConfig.EmailBuilder().build())) + .setLogo(R.mipmap.ic_launcher) + .build() signInLauncher.launch(intent) } - private fun updateUI(user: FirebaseUser?) { - if (user != null) { - // Signed in - binding.status.text = getString(R.string.firebaseui_status_fmt, user.email) - binding.detail.text = getString(R.string.id_fmt, user.uid) - - binding.signInButton.visibility = View.GONE - binding.signOutButton.visibility = View.VISIBLE - } else { - // Signed out - binding.status.setText(R.string.signed_out) - binding.detail.text = null - - binding.signInButton.visibility = View.VISIBLE - binding.signOutButton.visibility = View.GONE - } - } - - private fun signOut() { - AuthUI.getInstance().signOut(requireContext()) - updateUI(null) - } - override fun onDestroyView() { super.onDestroyView() _binding = null diff --git a/auth/app/src/main/java/com/google/firebase/quickstart/auth/kotlin/FirebaseUIViewModel.kt b/auth/app/src/main/java/com/google/firebase/quickstart/auth/kotlin/FirebaseUIViewModel.kt new file mode 100644 index 000000000..95ef70b11 --- /dev/null +++ b/auth/app/src/main/java/com/google/firebase/quickstart/auth/kotlin/FirebaseUIViewModel.kt @@ -0,0 +1,61 @@ +package com.google.firebase.quickstart.auth.kotlin + +import androidx.lifecycle.ViewModel +import com.google.firebase.auth.FirebaseAuth +import com.google.firebase.auth.FirebaseUser +import com.google.firebase.auth.ktx.auth +import com.google.firebase.ktx.Firebase +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.update + +class FirebaseUIViewModel( + private val firebaseAuth: FirebaseAuth = Firebase.auth +) : ViewModel() { + private val _uiState = MutableStateFlow(UiState()) + val uiState: StateFlow = _uiState + + data class UiState( + var status: String = "", + var detail: String? = null, + var isSignInVisible: Boolean = true + ) + + init { + // Check if user is signed in (non-null) and update UI accordingly. + showSignedInUser() + } + + fun showSignedInUser() { + val firebaseUser = firebaseAuth.currentUser + updateUiState(firebaseUser) + } + + fun signOut() { + updateUiState(null) + } + + private fun updateUiState(user: FirebaseUser?) { + if (user != null) { + _uiState.update { currentUiState -> + currentUiState.copy( + status = "Firebase User: ${user.displayName}", + detail = "Firebase UID: ${user.uid}", + isSignInVisible = false + ) + } + } else { + _uiState.update { currentUiState -> + currentUiState.copy( + status = "Signed out", + detail = null, + isSignInVisible = true + ) + } + } + } + + companion object { + const val TAG = "FirebaseUIViewModel" + } +} \ No newline at end of file