Skip to content

Commit

Permalink
[feat] #49 자동 로그인 구현
Browse files Browse the repository at this point in the history
  • Loading branch information
HAJIEUN02 committed Jan 21, 2025
1 parent 10db2c1 commit d967748
Show file tree
Hide file tree
Showing 3 changed files with 85 additions and 67 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ class LoginContract {
R.drawable.img_login2,
R.drawable.img_login1,
),
val loginSuccess: Boolean = false,
val loginState: Boolean = false,
) : BaseContract.State, Parcelable {
override fun toParcelable(): Parcelable = this
}
Expand All @@ -29,7 +29,7 @@ class LoginContract {
sealed interface LoginReduce : BaseContract.Reduce {
data class UpdateState(val state: LoginState) : LoginReduce

data object UpdateLoginSuccess : LoginReduce
data class UpdateLoginSuccess(val success: Boolean) : LoginReduce
}

sealed interface LoginSideEffect : BaseContract.SideEffect {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ import androidx.hilt.navigation.compose.hiltViewModel
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import kotlinx.coroutines.flow.collectLatest
import org.android.bbangzip.UserPreferences
import timber.log.Timber

@Composable
fun LoginRoute(
Expand All @@ -21,10 +20,16 @@ fun LoginRoute(
) {
val state by viewModel.uiState.collectAsStateWithLifecycle()
val pagerState = rememberPagerState(pageCount = { state.onBoardingList.size })

val userPreferences by viewModel.userPreferencesFlow.collectAsStateWithLifecycle(initialValue = UserPreferences.getDefaultInstance())

LaunchedEffect(userPreferences) {
Timber.d("[Access Token]: ${userPreferences.accessToken}")
if (userPreferences.isLogin) {
if (state.isOnboardingCompleted) {
navigateToOnboarding()
} else {
navigateToOnboarding()
}
}
}

LaunchedEffect(viewModel.uiSideEffect) {
Expand All @@ -38,6 +43,7 @@ fun LoginRoute(

LaunchedEffect(pagerState) {
snapshotFlow { pagerState.currentPage }.collectLatest { page ->

}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,80 +16,92 @@ import javax.inject.Inject

@HiltViewModel
class LoginViewModel
@Inject
constructor(
private val kakaoAuthService: KakaoAuthService,
private val userLocalRepository: UserLocalRepository,
private val userRepository: UserRepository,
savedStateHandle: SavedStateHandle,
) : BaseViewModel<LoginContract.LoginEvent, LoginContract.LoginState, LoginContract.LoginReduce, LoginContract.LoginSideEffect>(
savedStateHandle = savedStateHandle,
) {
val userPreferencesFlow: Flow<UserPreferences> = userLocalRepository.userPreferenceFlow
@Inject
constructor(
private val kakaoAuthService: KakaoAuthService,
private val userLocalRepository: UserLocalRepository,
private val userRepository: UserRepository,
savedStateHandle: SavedStateHandle,
) : BaseViewModel<LoginContract.LoginEvent, LoginContract.LoginState, LoginContract.LoginReduce, LoginContract.LoginSideEffect>(
savedStateHandle = savedStateHandle,
) {
val userPreferencesFlow: Flow<UserPreferences> = userLocalRepository.userPreferenceFlow

override fun createInitialState(savedState: Parcelable?): LoginContract.LoginState {
return savedState as? LoginContract.LoginState ?: LoginContract.LoginState()
}
override fun createInitialState(savedState: Parcelable?): LoginContract.LoginState {
return savedState as? LoginContract.LoginState ?: LoginContract.LoginState()
}

override fun handleEvent(event: LoginContract.LoginEvent) {
when (event) {
is LoginContract.LoginEvent.OnClickKakaoLoginBtn -> {
if (currentUiState.isOnboardingCompleted) {
setSideEffect(LoginContract.LoginSideEffect.NavigateToSubject)
} else {
Timber.d("[카카오 로그인] -> 버튼 누름")
kakaoAuthService.loginKakao(
context = event.context,
loginListener = { accessToken ->
Timber.d("[카카오 로그인] -> 카카오에서 받은 액세스 토큰 $accessToken")
login(accessToken)
},
)
}
// setSideEffect(LoginContract.LoginSideEffect.NavigateToOnboarding)
override fun handleEvent(event: LoginContract.LoginEvent) {
when (event) {
is LoginContract.LoginEvent.OnClickKakaoLoginBtn -> {
if (currentUiState.isOnboardingCompleted) {
setSideEffect(LoginContract.LoginSideEffect.NavigateToSubject)
} else {
Timber.d("[카카오 로그인] -> 버튼 누름")
kakaoAuthService.loginKakao(
context = event.context,
loginListener = { accessToken ->
Timber.d("[카카오 로그인] -> 카카오에서 받은 액세스 토큰 $accessToken")
login(accessToken)
},
)
}
}
}
}

override fun reduceState(
state: LoginContract.LoginState,
reduce: LoginContract.LoginReduce,
): LoginContract.LoginState {
return when (reduce) {
is LoginContract.LoginReduce.UpdateState -> reduce.state
is LoginContract.LoginReduce.UpdateLoginSuccess -> state.copy(loginSuccess = !currentUiState.loginSuccess)
}
override fun reduceState(
state: LoginContract.LoginState,
reduce: LoginContract.LoginReduce,
): LoginContract.LoginState {
return when (reduce) {
is LoginContract.LoginReduce.UpdateState -> reduce.state
is LoginContract.LoginReduce.UpdateLoginSuccess -> state.copy(loginState = !currentUiState.loginState)
}
}

private fun login(accessToken: String) {
viewModelScope.launch {
userRepository.login(accessToken)
.onSuccess { userEntity ->
updateState(LoginContract.LoginReduce.UpdateLoginSuccess)
saveUserInfoInLocal(
accessToken = BEARER + userEntity.accessToken,
refreshToken = BEARER + userEntity.refreshToken,
private fun login(accessToken: String) {
viewModelScope.launch {
userRepository.login(accessToken)
.onSuccess { userEntity ->
updateState(
LoginContract.LoginReduce.UpdateState(
currentUiState.copy(
loginState = true,
isOnboardingCompleted = userEntity.isOnboardingComplete
)
)
Timber.d("[카카오 로그인] -> 서버에서 LoginViewModel login 성공")
}.onFailure {
updateState(LoginContract.LoginReduce.UpdateLoginSuccess)
Timber.d("[카카오 로그인] -> 서버에서 LoginViewModel login 실패")
)
saveUserInfoInLocal(
accessToken = BEARER + userEntity.accessToken,
refreshToken = BEARER + userEntity.refreshToken,
isLogin = true
)
if (userEntity.isOnboardingComplete) {
setSideEffect(LoginContract.LoginSideEffect.NavigateToSubject)
} else {
setSideEffect(LoginContract.LoginSideEffect.NavigateToOnboarding)
}
}
}.onFailure {
updateState(LoginContract.LoginReduce.UpdateLoginSuccess(success = false))
Timber.d("[카카오 로그인] -> 서버에서 LoginViewModel login 실패")
}
}
}

private suspend fun saveUserInfoInLocal(
accessToken: String,
refreshToken: String,
) {
with(userLocalRepository) {
setAccessToken(accessToken = accessToken)
setRefreshToken(refreshToken = refreshToken)
setIsLogin(isLogin = true)
}
private suspend fun saveUserInfoInLocal(
accessToken: String,
refreshToken: String,
isLogin: Boolean
) {
with(userLocalRepository) {
setAccessToken(accessToken = accessToken)
setRefreshToken(refreshToken = refreshToken)
setIsLogin(isLogin = isLogin)
}
}

companion object {
const val BEARER = "Bearer "
}
companion object {
const val BEARER = "Bearer "
}
}

0 comments on commit d967748

Please sign in to comment.