Skip to content

Commit

Permalink
Se agrega SignIn con google
Browse files Browse the repository at this point in the history
  • Loading branch information
AndresClz committed Nov 11, 2024
1 parent 5715200 commit 1063346
Show file tree
Hide file tree
Showing 4 changed files with 88 additions and 95 deletions.
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package com.example.jetnews.ui.signin

import androidx.activity.compose.rememberLauncherForActivityResult
import androidx.activity.result.contract.ActivityResultContracts
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
Expand All @@ -23,9 +25,12 @@ import androidx.compose.material3.lightColorScheme
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.text.input.ImeAction
import androidx.compose.ui.text.input.KeyboardType
import androidx.compose.ui.text.input.PasswordVisualTransformation
Expand All @@ -34,16 +39,17 @@ import androidx.compose.ui.unit.dp
import androidx.lifecycle.viewmodel.compose.viewModel
import androidx.navigation.NavHostController
import androidx.navigation.compose.rememberNavController
import com.example.jetnews.R
import com.example.jetnews.model.authentication.AuthResult
import com.example.jetnews.model.authentication.AuthUiState
import com.example.jetnews.ui.JetnewsDestinations
import com.example.jetnews.ui.ViewModelFactory
import com.example.jetnews.ui.components.buttons.AuthButton
import com.example.jetnews.ui.components.buttons.FirebaseGoogleButton
import com.example.jetnews.ui.components.buttons.rememberFirebaseAuthLauncher
import com.example.jetnews.ui.components.buttons.SocialAuthButton
import com.example.jetnews.ui.components.textfields.AuthTextField
import com.google.android.gms.auth.api.signin.GoogleSignIn
import com.google.android.gms.auth.api.signin.GoogleSignInOptions
import com.google.firebase.auth.GoogleAuthProvider
import kotlinx.coroutines.launch

@Suppress("ktlint:standard:function-naming")
@Composable
Expand All @@ -53,6 +59,7 @@ fun SignInScreen(
modifier: Modifier = Modifier,
) {
val context = LocalContext.current
val scope = rememberCoroutineScope()
// State
val email by viewModel.email
val password by viewModel.password
Expand All @@ -67,16 +74,28 @@ fun SignInScreen(
}

// Firebase Auth launcher
val launcher =
rememberFirebaseAuthLauncher(
onAuthComplete = { account ->
val credential = GoogleAuthProvider.getCredential(account.idToken, null)
viewModel.handleGoogleCredential(credential)
},
onAuthError = { exception ->
viewModel.handleError(exception.message ?: "Authentication failed")
},
)
// ActivityResultLauncher for Google Sign-In
val googleSignInLauncher =
rememberLauncherForActivityResult(
contract = ActivityResultContracts.StartActivityForResult(),
) { result ->
val task = GoogleSignIn.getSignedInAccountFromIntent(result.data)
when (val accountResult = viewModel.handleSignInResult(task)) {
is AuthResult.Success -> {
val account = accountResult.data
val credential = GoogleAuthProvider.getCredential(account?.idToken, null)
scope.launch {
viewModel.handleGoogleCredential(credential)
}
}
is AuthResult.Error -> {
viewModel.handleError(accountResult.message)
}
else -> {
viewModel.handleError("Unknown error during Google Sign-In")
}
}
}

Box(
modifier = modifier.fillMaxSize(),
Expand Down Expand Up @@ -169,18 +188,19 @@ fun SignInScreen(
}

// Social Sign In
FirebaseGoogleButton(
SocialAuthButton(
text = "Sign in with Google",
onClick = {
val gso =
GoogleSignInOptions
.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN)
.requestIdToken("") // No lo subi al repo, cualquier cosa pedirlo
.requestEmail()
.build()
val googleSignInClient = GoogleSignIn.getClient(context, gso)
launcher.launch(googleSignInClient.signInIntent)
viewModel.signInWithGoogle(googleSignInLauncher)
},
icon = {
Icon(
painter = painterResource(id = R.drawable.ic_google),
contentDescription = null,
modifier = Modifier.size(24.dp),
tint = Color.Unspecified,
)
},
enabled = uiState !is AuthUiState.Loading,
)

// Sign Up Link
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,22 @@
package com.example.jetnews.ui.signin

import android.content.Context
import android.content.Intent
import android.util.Log
import androidx.activity.result.ActivityResultLauncher
import androidx.compose.runtime.State
import androidx.compose.runtime.mutableStateOf
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.example.jetnews.data.authentication.AuthRepository
import com.example.jetnews.model.authentication.AuthResult
import com.example.jetnews.model.authentication.AuthUiState
import com.google.android.gms.auth.api.signin.GoogleSignIn
import com.google.android.gms.auth.api.signin.GoogleSignInAccount
import com.google.android.gms.auth.api.signin.GoogleSignInClient
import com.google.android.gms.auth.api.signin.GoogleSignInOptions
import com.google.android.gms.common.api.ApiException
import com.google.android.gms.tasks.Task
import com.google.firebase.auth.AuthCredential
import com.google.firebase.auth.FirebaseUser
import kotlinx.coroutines.launch
Expand All @@ -27,16 +35,34 @@ class SignInScreenViewModel(
private val _uiState = mutableStateOf<AuthUiState>(AuthUiState.Initial)
val uiState: State<AuthUiState> = _uiState

private val googleSignInClient: GoogleSignInClient by lazy {
val gso =
GoogleSignInOptions
.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN)
.requestIdToken("")
.requestEmail()
.build()
GoogleSignIn.getClient(context, gso)
}

fun signInWithGoogle(googleSignInLauncher: ActivityResultLauncher<Intent>) {
val signInIntent = googleSignInClient.signInIntent
googleSignInLauncher.launch(signInIntent)
}

fun handleSignInResult(task: Task<GoogleSignInAccount>): AuthResult<GoogleSignInAccount> =
try {
val account = task.getResult(ApiException::class.java)
AuthResult.Success(account)
} catch (e: ApiException) {
AuthResult.Error(e.message ?: "Google sign-in failed")
}

fun handleGoogleCredential(credential: AuthCredential) {
viewModelScope.launch {
_uiState.value = AuthUiState.Loading
try {
val result = repository.signInWithGoogle(credential)
handleAuthResult(result)
} catch (e: Exception) {
Log.e("GoogleSignInError", "Error during Google sign-in", e)
handleError(e.message ?: "Google sign-in failed")
}
val result = repository.signInWithGoogle(credential)
handleAuthResult(result)
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.rounded.PersonAdd
import androidx.compose.material3.Divider
import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Surface
Expand All @@ -39,12 +38,7 @@ import com.example.jetnews.model.authentication.AuthUiState
import com.example.jetnews.ui.JetnewsDestinations
import com.example.jetnews.ui.ViewModelFactory
import com.example.jetnews.ui.components.buttons.AuthButton
import com.example.jetnews.ui.components.buttons.FirebaseGoogleButton
import com.example.jetnews.ui.components.buttons.rememberFirebaseAuthLauncher
import com.example.jetnews.ui.components.textfields.AuthTextField
import com.google.android.gms.auth.api.signin.GoogleSignIn
import com.google.android.gms.auth.api.signin.GoogleSignInOptions
import com.google.firebase.auth.GoogleAuthProvider

@Suppress("ktlint:standard:function-naming")
@Composable
Expand All @@ -69,18 +63,6 @@ fun SignUpScreen(
}
}

// Firebase Auth launcher
val launcher =
rememberFirebaseAuthLauncher(
onAuthComplete = { account ->
val credential = GoogleAuthProvider.getCredential(account.idToken, null)
viewModel.handleGoogleCredential(credential)
},
onAuthError = { exception ->
viewModel.handleError(exception.message ?: "Authentication failed")
},
)

Box(
modifier = modifier.fillMaxSize(),
contentAlignment = Alignment.Center,
Expand All @@ -89,19 +71,21 @@ fun SignUpScreen(
modifier =
Modifier
.fillMaxWidth()
.padding(24.dp)
.padding(horizontal = 24.dp)
.verticalScroll(rememberScrollState()),
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.spacedBy(16.dp),
verticalArrangement = Arrangement.Center,
) {
// Header
Icon(
imageVector = Icons.Rounded.PersonAdd,
contentDescription = null,
modifier = Modifier.size(64.dp),
modifier = Modifier.size(80.dp),
tint = MaterialTheme.colorScheme.primary,
)

Spacer(modifier = Modifier.height(16.dp))

Text(
text = "Create Account",
style = MaterialTheme.typography.headlineMedium,
Expand All @@ -114,7 +98,7 @@ fun SignUpScreen(
color = MaterialTheme.colorScheme.onSurfaceVariant,
)

Spacer(modifier = Modifier.height(8.dp))
Spacer(modifier = Modifier.height(24.dp))

// Form
AuthTextField(
Expand Down Expand Up @@ -153,47 +137,23 @@ fun SignUpScreen(
text = (uiState as AuthUiState.Error).message,
color = MaterialTheme.colorScheme.error,
style = MaterialTheme.typography.bodyMedium,
modifier = Modifier.padding(top = 8.dp),
)
}

Spacer(modifier = Modifier.height(24.dp))

// Sign Up Button
AuthButton(
text = "Create Account",
onClick = viewModel::onSignUpClick,
isLoading = uiState is AuthUiState.Loading,
)

// OR Divider
Row(
modifier = Modifier.fillMaxWidth(),
verticalAlignment = Alignment.CenterVertically,
) {
Divider(modifier = Modifier.weight(1f))
Text(
text = "OR",
modifier = Modifier.padding(horizontal = 16.dp),
color = MaterialTheme.colorScheme.onSurfaceVariant,
)
Divider(modifier = Modifier.weight(1f))
}

// Firebase Google Button
FirebaseGoogleButton(
onClick = {
val gso =
GoogleSignInOptions
.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN)
.requestIdToken("") // No lo subi al repo, cualquier cosa pedirlo
.requestEmail()
.build()
val googleSignInClient = GoogleSignIn.getClient(context, gso)
launcher.launch(googleSignInClient.signInIntent)
},
enabled = uiState !is AuthUiState.Loading,
)
Spacer(modifier = Modifier.height(16.dp))

// Sign In Link
Row(
modifier = Modifier.padding(top = 8.dp),
verticalAlignment = Alignment.CenterVertically,
) {
Text(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import androidx.lifecycle.viewModelScope
import com.example.jetnews.data.authentication.AuthRepository
import com.example.jetnews.model.authentication.AuthResult
import com.example.jetnews.model.authentication.AuthUiState
import com.google.firebase.auth.AuthCredential
import com.google.firebase.auth.FirebaseUser
import kotlinx.coroutines.launch

Expand Down Expand Up @@ -69,20 +68,8 @@ class SignUpScreenViewModel(
}
}

fun handleGoogleCredential(credential: AuthCredential) {
viewModelScope.launch {
_uiState.value = AuthUiState.Loading
try {
val result = repository.signInWithGoogle(credential)
handleAuthResult(result)
} catch (e: Exception) {
handleError(e.message ?: "Google sign in failed")
}
}
}

fun handleError(message: String) {
Log.e("SignInError", message)
Log.e("SignUpError", message)
_uiState.value = AuthUiState.Error(message)
}

Expand Down

0 comments on commit 1063346

Please sign in to comment.