Skip to content

Commit

Permalink
Issues boostcampwm-2022#287 feat: GoogleAuthViewModel 로 모듈 분리
Browse files Browse the repository at this point in the history
  • Loading branch information
audxo112 committed Mar 1, 2023
1 parent bb7ddb5 commit 80c12fa
Show file tree
Hide file tree
Showing 20 changed files with 248 additions and 150 deletions.
3 changes: 3 additions & 0 deletions auth-google/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@ dependencies {
implementation(projects.model)
implementation(projects.common)
implementation(projects.commonAndroid)
implementation(projects.domain)

implementation(libs.androidX.fragment.ktx)

implementation(libs.gms.play.services.auth)

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package com.lighthouse.auth.google.model

import com.lighthouse.core.android.utils.resource.UIText

sealed class GoogleAuthEvent {

data class SnackBar(val text: UIText) : GoogleAuthEvent()
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
package com.lighthouse.auth.google.ui

import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.lighthouse.auth.google.R
import com.lighthouse.auth.google.exception.FailedConnectException
import com.lighthouse.auth.google.model.GoogleAuthEvent
import com.lighthouse.beep.model.exception.auth.FailedSaveLoginUserException
import com.lighthouse.core.android.utils.resource.UIText
import com.lighthouse.core.utils.flow.MutableEventFlow
import com.lighthouse.core.utils.flow.asEventFlow
import com.lighthouse.domain.usecase.user.GetUserIdUseCase
import com.lighthouse.domain.usecase.user.LoginUseCase
import com.lighthouse.domain.usecase.user.SignOutUseCase
import com.lighthouse.domain.usecase.user.TransferDataUseCase
import com.lighthouse.domain.usecase.user.WithdrawalUseCase
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.launch
import java.lang.Exception
import javax.inject.Inject

@HiltViewModel
class GoogleAuthViewModel @Inject constructor(
private val getUserIdUseCase: GetUserIdUseCase,
private val loginUseCase: LoginUseCase,
private val transferDataUseCase: TransferDataUseCase,
private val signOutUseCase: SignOutUseCase,
private val withdrawalUseCase: WithdrawalUseCase
) : ViewModel() {

private val _eventFlow = MutableEventFlow<GoogleAuthEvent>()
val eventFlow = _eventFlow.asEventFlow()

private val _signInLoading = MutableStateFlow(false)
val signInLoading = _signInLoading.asStateFlow()

fun getUserId() = getUserIdUseCase()

fun login() {
viewModelScope.launch {
finishSignIn(loginUseCase().exceptionOrNull())
}
}

fun transferData(oldUserId: String) {
viewModelScope.launch {
finishSignIn(transferDataUseCase(oldUserId).exceptionOrNull())
}
}

fun startSignIn() {
_signInLoading.value = true
}

fun finishSignIn(throwable: Throwable? = null) {
finishSignIn(throwable as? Exception)
}

private fun finishSignIn(exception: Exception? = null) {
_signInLoading.value = false
viewModelScope.launch {
val stringRes = when (exception) {
null -> R.string.login_success
is FailedSaveLoginUserException -> R.string.error_save_login_user
is FailedConnectException -> R.string.google_connect_fail
else -> R.string.error_unknown
}
_eventFlow.emit(GoogleAuthEvent.SnackBar(UIText.StringResource(stringRes)))
}
}

fun signOut() {
viewModelScope.launch {
val exception = signOutUseCase().exceptionOrNull()
if (exception != null) {
_eventFlow.emit(
GoogleAuthEvent.SnackBar(
UIText.StringResource(R.string.error_sign_out)
)
)
}
}
}

fun withdrawal() {
viewModelScope.launch {
val exception = withdrawalUseCase().exceptionOrNull()
if (exception != null) {
_eventFlow.emit(
GoogleAuthEvent.SnackBar(
UIText.StringResource(R.string.error_withdrawal)
)
)
}
}
}
}
13 changes: 13 additions & 0 deletions auth-google/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="google_login_failed">구글 로그인 실패</string>
<string name="google_connect_fail">구글 연결 실패</string>
<string name="login_success">로그인 성공</string>
<string name="login_failed">로그인 실패</string>

<string name="error_save_login_user">로그인 정보를 저장하는데 실패 했습니다.</string>
<string name="error_unknown">알 수 없는 오류 입니다.</string>

<string name="error_sign_out">로그아웃에 실패 했습니다.</string>
<string name="error_withdrawal">회원 탈퇴에 실패 했습니다.</string>
</resources>
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,10 @@ internal class AuthRepositoryImpl @Inject constructor() : AuthRepository {
return Firebase.auth.currentUser?.uid ?: GUEST_ID
}

override fun signOut() {
Firebase.auth.signOut()
}

override suspend fun withdrawal(): Result<Unit> {
val user = Firebase.auth.currentUser ?: return Result.success(Unit)
return runCatching {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -80,9 +80,11 @@ internal class UserRepositoryImpl @Inject constructor(
return userPreferenceRepository.getFilterExpired(userId)
}

override suspend fun transferData(userId: String, newUserId: String): Result<Unit> {
return userPreferenceRepository.transferData(userId, newUserId)
}
override suspend fun transferData(userId: String, newUserId: String): Result<Unit> =
runCatching {
userPreferenceRepository.transferData(userId, newUserId).getOrThrow()
userPreferenceRepository.setLoginUserUid(newUserId).getOrThrow()
}

override suspend fun withdrawal(userId: String): Result<Unit> = runCatching {
userPreferenceRepository.withdrawal(userId).getOrThrow()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,7 @@ interface AuthRepository {

fun getCurrentUserId(): String

fun signOut()

suspend fun withdrawal(): Result<Unit>
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package com.lighthouse.domain.usecase.user

import com.lighthouse.domain.repository.auth.AuthRepository
import javax.inject.Inject

class GetUserIdUseCase @Inject constructor(
private val authRepository: AuthRepository
) {

operator fun invoke(): String {
return authRepository.getCurrentUserId()
}
}
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
package com.lighthouse.domain.usecase.user

import com.lighthouse.domain.repository.auth.AuthRepository
import com.lighthouse.domain.repository.user.UserRepository
import javax.inject.Inject

class SignOutUseCase @Inject constructor(
private val authRepository: AuthRepository,
private val userRepository: UserRepository
) {

suspend operator fun invoke(): Result<Unit> = runCatching {
authRepository.signOut()
userRepository.signOut().getOrThrow()
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package com.lighthouse.domain.usecase.user

import com.lighthouse.domain.repository.auth.AuthRepository
import com.lighthouse.domain.repository.user.UserRepository
import javax.inject.Inject

class TransferDataUseCase @Inject constructor(
private val authRepository: AuthRepository,
private val userRepository: UserRepository
) {

suspend operator fun invoke(oldUserId: String): Result<Unit> {
val newUserId = authRepository.getCurrentUserId()
return userRepository.transferData(oldUserId, newUserId)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ class WithdrawalUseCase @Inject constructor(
suspend operator fun invoke(): Result<Unit> = runCatching {
val userId = authRepository.getCurrentUserId()
authRepository.withdrawal().getOrThrow()
authRepository.signOut()
userRepository.withdrawal(userId).getOrThrow()
}
}

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -8,17 +8,17 @@ import androidx.fragment.app.Fragment
import androidx.fragment.app.viewModels
import androidx.lifecycle.lifecycleScope
import com.google.android.material.snackbar.Snackbar
import com.lighthouse.auth.google.exception.FailedConnectException
import com.lighthouse.auth.google.model.GoogleAuthEvent
import com.lighthouse.auth.google.repository.GoogleClient
import com.lighthouse.auth.google.ui.GoogleAuthViewModel
import com.lighthouse.core.android.utils.resource.UIText
import com.lighthouse.features.common.binding.viewBindings
import com.lighthouse.features.common.dialog.progress.ProgressDialog
import com.lighthouse.features.common.ext.repeatOnStarted
import com.lighthouse.features.common.ext.show
import com.lighthouse.features.common.utils.throttle.onThrottleClick
import com.lighthouse.features.intro.R
import com.lighthouse.features.intro.databinding.FragmentIntroBinding
import com.lighthouse.features.intro.exception.FailedSaveLoginUserException
import com.lighthouse.features.intro.model.SignInState
import dagger.hilt.android.AndroidEntryPoint
import kotlinx.coroutines.launch
import javax.inject.Inject
Expand All @@ -28,7 +28,7 @@ class IntroFragment : Fragment(R.layout.fragment_intro) {

private val binding by viewBindings<FragmentIntroBinding>()

private val viewModel: IntroViewModel by viewModels()
private val googleAuthViewModel: GoogleAuthViewModel by viewModels()

@Inject
lateinit var googleClient: GoogleClient
Expand All @@ -40,9 +40,9 @@ class IntroFragment : Fragment(R.layout.fragment_intro) {
lifecycleScope.launch {
val exception = googleClient.signIn(result).exceptionOrNull()
if (exception != null) {
viewModel.setState(SignInState.Failed(exception))
googleAuthViewModel.finishSignIn(exception)
} else {
signIn()
googleAuthViewModel.login()
}
}
}
Expand All @@ -51,7 +51,8 @@ class IntroFragment : Fragment(R.layout.fragment_intro) {
super.onViewCreated(view, savedInstanceState)

animateLogo()
setUpSignInStateFlow()
setUpGoogleAuthEvent()
setUpSignInLoading()
setUpBtnGoogleLogin()
setUpTvGuestSignIn()
}
Expand All @@ -61,10 +62,20 @@ class IntroFragment : Fragment(R.layout.fragment_intro) {
drawable.start()
}

private fun setUpSignInStateFlow() {
private fun setUpGoogleAuthEvent() {
repeatOnStarted {
viewModel.signInState.collect { state ->
if (state == SignInState.Loading) {
googleAuthViewModel.eventFlow.collect { event ->
when (event) {
is GoogleAuthEvent.SnackBar -> showSnackBar(event.text)
}
}
}
}

private fun setUpSignInLoading() {
repeatOnStarted {
googleAuthViewModel.signInLoading.collect { loading ->
if (loading) {
if (progressDialog?.isAdded == true) {
progressDialog?.dismiss()
}
Expand All @@ -73,56 +84,29 @@ class IntroFragment : Fragment(R.layout.fragment_intro) {
} else {
progressDialog?.dismiss()
}

when (state) {
is SignInState.Success -> signInSuccess()
is SignInState.Failed -> signInFailed(state.e)
else -> {}
}
}
}
}

private fun setUpBtnGoogleLogin() {
binding.btnGoogleLogin.onThrottleClick {
viewModel.setState(SignInState.Loading)
googleAuthViewModel.startSignIn()
loginLauncher.launch(googleClient.signInIntent())
}
}

private fun setUpTvGuestSignIn() {
binding.tvGuestSignin.onThrottleClick {
viewModel.setState(SignInState.Loading)
signIn()
googleAuthViewModel.startSignIn()
googleAuthViewModel.login()
}
}

private fun signIn() {
lifecycleScope.launch {
val state = if (viewModel.login().isSuccess) {
SignInState.Success
} else {
SignInState.Failed(FailedSaveLoginUserException())
}
viewModel.setState(state)
}
}

private fun signInSuccess() {
val message = getString(R.string.login_success)
showSnackBar(message)
}

private fun signInFailed(e: Exception) {
val message = when (e) {
is FailedSaveLoginUserException -> getString(R.string.error_save_login_user)
is FailedConnectException -> getString(R.string.google_connect_fail)
else -> getString(R.string.error_unknown)
}
showSnackBar(message)
}

private fun showSnackBar(string: String) {
Snackbar.make(binding.root, string, Snackbar.LENGTH_SHORT).show()
}

private fun showSnackBar(text: UIText) {
showSnackBar(text.asString(requireContext()).toString())
}
}
Loading

0 comments on commit 80c12fa

Please sign in to comment.