Skip to content

Commit

Permalink
Merge pull request #64 from Nexters/refactor/login
Browse files Browse the repository at this point in the history
LoginViewModel - Context 참조 제거
  • Loading branch information
eshc123 authored Oct 28, 2024
2 parents 0cf3c15 + 9267cfe commit 4c04010
Show file tree
Hide file tree
Showing 3 changed files with 96 additions and 52 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
package com.goalpanzi.mission_mate.feature.login

import android.content.Context
import androidx.credentials.CredentialManager
import androidx.credentials.CustomCredential
import androidx.credentials.GetCredentialRequest
import androidx.credentials.GetCredentialResponse
import com.google.android.libraries.identity.googleid.GetSignInWithGoogleOption
import com.google.android.libraries.identity.googleid.GoogleIdTokenCredential
import com.google.android.libraries.identity.googleid.GoogleIdTokenParsingException
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext

sealed class LoginData {
data class Success(val email : String) : LoginData()
data class Failed(val exception: Exception) : LoginData()
}

class LoginManager (
private val context : Context
) {
suspend fun request() : LoginData = withContext(Dispatchers.IO) {
val credentialManager = CredentialManager.create(context)
val signInWithGoogleOption: GetSignInWithGoogleOption =
GetSignInWithGoogleOption.Builder(BuildConfig.CREDENTIAL_WEB_CLIENT_ID)
.build()

val request: GetCredentialRequest = GetCredentialRequest.Builder()
.addCredentialOption(signInWithGoogleOption)
.build()

return@withContext try {
val result = credentialManager.getCredential(context, request)
handleSignIn(result)
} catch (e: Exception) {
e.printStackTrace()
LoginData.Failed(e)
}
}

private fun handleSignIn(response: GetCredentialResponse) : LoginData {
return when (val credential = response.credential) {
is CustomCredential -> {
if (credential.type == GoogleIdTokenCredential.TYPE_GOOGLE_ID_TOKEN_CREDENTIAL) {
try {
val googleIdTokenCredential = GoogleIdTokenCredential.createFrom(credential.data)
LoginData.Success(googleIdTokenCredential.id)
} catch (e: GoogleIdTokenParsingException) {
LoginData.Failed(e)
}
}else {
LoginData.Failed(RuntimeException("NoDataException"))
}
}

else -> {
LoginData.Failed(IllegalStateException())
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,14 @@ import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.navigationBarsPadding
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.statusBarsPadding
import androidx.compose.foundation.layout.widthIn
import androidx.compose.foundation.layout.wrapContentHeight
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
Expand All @@ -34,16 +35,18 @@ import com.goalpanzi.mission_mate.core.designsystem.component.StableImage
import com.goalpanzi.mission_mate.core.designsystem.theme.ColorWhite_FFFFFFFF
import com.goalpanzi.mission_mate.core.designsystem.theme.Color_FFFF5632
import com.goalpanzi.mission_mate.core.designsystem.theme.MissionMateTypography
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.launch

@Composable
fun LoginRoute(
onLoginSuccess: (Boolean) -> Unit,
modifier: Modifier = Modifier,
coroutineScope : CoroutineScope = rememberCoroutineScope(),
loginManager: LoginManager = rememberLoginManager(),
viewModel: LoginViewModel = hiltViewModel()
) {
val context = LocalContext.current

LaunchedEffect(true) {
viewModel.eventFlow.collectLatest {
when (it) {
Expand All @@ -55,10 +58,22 @@ fun LoginRoute(

LoginScreen(
modifier = modifier,
onGoogleLoginClick = { viewModel.request(context) }
onGoogleLoginClick = {
coroutineScope.launch {
viewModel.login(loginManager.request())
}
}
)
}

@Composable
private fun rememberLoginManager(): LoginManager {
val context = LocalContext.current
return remember {
LoginManager(context)
}
}

@Composable
fun LoginScreen(
modifier: Modifier = Modifier,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,16 +1,8 @@
package com.goalpanzi.mission_mate.feature.login

import android.content.Context
import androidx.credentials.CredentialManager
import androidx.credentials.CustomCredential
import androidx.credentials.GetCredentialRequest
import androidx.credentials.GetCredentialResponse
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.goalpanzi.mission_mate.core.domain.auth.usecase.LoginUseCase
import com.google.android.libraries.identity.googleid.GetSignInWithGoogleOption
import com.google.android.libraries.identity.googleid.GoogleIdTokenCredential
import com.google.android.libraries.identity.googleid.GoogleIdTokenParsingException
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.asSharedFlow
Expand All @@ -25,48 +17,24 @@ class LoginViewModel @Inject constructor(
private val _eventFlow = MutableSharedFlow<LoginEvent>()
val eventFlow = _eventFlow.asSharedFlow()

fun request(context: Context) {
viewModelScope.launch {
val credentialManager = CredentialManager.create(context)
val signInWithGoogleOption: GetSignInWithGoogleOption =
GetSignInWithGoogleOption.Builder(BuildConfig.CREDENTIAL_WEB_CLIENT_ID)
.build()

val request: GetCredentialRequest = GetCredentialRequest.Builder()
.addCredentialOption(signInWithGoogleOption)
.build()

try {
val result = credentialManager.getCredential(context, request)
handleSignIn(result)
} catch (e: Exception) {
e.printStackTrace()
}
}
}

private suspend fun handleSignIn(response: GetCredentialResponse) {
when (val credential = response.credential) {
is CustomCredential -> {
if (credential.type == GoogleIdTokenCredential.TYPE_GOOGLE_ID_TOKEN_CREDENTIAL) {
try {
val googleIdTokenCredential = GoogleIdTokenCredential.createFrom(credential.data)
val result = loginUseCase.requestGoogleLogin(email = googleIdTokenCredential.id)
_eventFlow.emit(
result?.let {
LoginEvent.Success(it.isProfileSet)
} ?: run {
LoginEvent.Error
}
)
} catch (e: GoogleIdTokenParsingException) {
e.printStackTrace()
}
suspend fun login(loginData: LoginData){
when(loginData){
is LoginData.Success -> {
try {
val result = loginUseCase.requestGoogleLogin(email = loginData.email)
_eventFlow.emit(
result?.let {
LoginEvent.Success(it.isProfileSet)
} ?: run {
LoginEvent.Error
}
)
}catch (e: Exception){
e.printStackTrace()
}
}

else -> {
// TODO : error event
is LoginData.Failed -> {
loginData.exception.printStackTrace()
}
}
}
Expand Down

0 comments on commit 4c04010

Please sign in to comment.