diff --git a/core/common/src/main/java/com/teamwiney/core/common/model/UserStatus.kt b/core/common/src/main/java/com/teamwiney/core/common/model/UserStatus.kt new file mode 100644 index 00000000..bacd7a71 --- /dev/null +++ b/core/common/src/main/java/com/teamwiney/core/common/model/UserStatus.kt @@ -0,0 +1,5 @@ +package com.teamwiney.core.common.model + +enum class UserStatus { + ACTIVE, INACTIVE +} \ No newline at end of file diff --git a/data/src/main/java/com/teamwiney/data/datasource/auth/AuthDataSource.kt b/data/src/main/java/com/teamwiney/data/datasource/auth/AuthDataSource.kt index 83f6875b..84794821 100644 --- a/data/src/main/java/com/teamwiney/data/datasource/auth/AuthDataSource.kt +++ b/data/src/main/java/com/teamwiney/data/datasource/auth/AuthDataSource.kt @@ -16,6 +16,7 @@ import com.teamwiney.data.network.model.response.DeleteUser import com.teamwiney.data.network.model.response.GoogleAccessToken import com.teamwiney.data.network.model.response.SetPreferences import com.teamwiney.data.network.model.response.SocialLogin +import com.teamwiney.data.network.model.response.UserInfo import com.teamwiney.data.network.model.response.VerifyAuthenticationMessage import kotlinx.coroutines.flow.Flow @@ -47,6 +48,8 @@ interface AuthDataSource { fun refreshToken(refreshToken: String): Flow>> + fun getUserInfo(): Flow>> + fun getConnections(): Flow> fun registerFcmToken(fcmTokenRequest: FcmTokenRequest): Flow> diff --git a/data/src/main/java/com/teamwiney/data/datasource/auth/AuthDataSourceImpl.kt b/data/src/main/java/com/teamwiney/data/datasource/auth/AuthDataSourceImpl.kt index 8b30a820..aa943361 100644 --- a/data/src/main/java/com/teamwiney/data/datasource/auth/AuthDataSourceImpl.kt +++ b/data/src/main/java/com/teamwiney/data/datasource/auth/AuthDataSourceImpl.kt @@ -62,6 +62,10 @@ class AuthDataSourceImpl @Inject constructor( emit(authService.refreshToken(refreshToken)) }.flowOn(ioDispatcher) + override fun getUserInfo() = flow { + emit(authService.getUserInfo()) + }.flowOn(ioDispatcher) + override fun getConnections() = flow { emit(authService.getConnections()) }.flowOn(ioDispatcher) diff --git a/data/src/main/java/com/teamwiney/data/network/model/response/SocialLogin.kt b/data/src/main/java/com/teamwiney/data/network/model/response/SocialLogin.kt index 9fc2babb..043a9e5d 100644 --- a/data/src/main/java/com/teamwiney/data/network/model/response/SocialLogin.kt +++ b/data/src/main/java/com/teamwiney/data/network/model/response/SocialLogin.kt @@ -1,5 +1,7 @@ package com.teamwiney.data.network.model.response +import com.teamwiney.core.common.model.UserStatus + /** * - userStatus 1. 취향설정 까지 모두 마쳐 회원 가입이 완료된 경우 → `ACTIVE` @@ -21,12 +23,7 @@ data class SocialLogin( val accessToken: String, val userId: Int, val refreshToken: String, - val userStatus: String, + val userStatus: UserStatus, val messageStatus: String, val preferenceStatus: String -) { - companion object { - const val USER_STATUS_ACTIVE = "ACTIVE" - const val USER_STATUS_INACTIVE = "INACTIVE" - } -} \ No newline at end of file +) \ No newline at end of file diff --git a/data/src/main/java/com/teamwiney/data/network/model/response/UserInfo.kt b/data/src/main/java/com/teamwiney/data/network/model/response/UserInfo.kt new file mode 100644 index 00000000..9659cae7 --- /dev/null +++ b/data/src/main/java/com/teamwiney/data/network/model/response/UserInfo.kt @@ -0,0 +1,9 @@ +package com.teamwiney.data.network.model.response + +import com.google.gson.annotations.SerializedName +import com.teamwiney.core.common.model.UserStatus + +data class UserInfo( + @SerializedName("userId") val userId: Int, + @SerializedName("status") val status: UserStatus +) diff --git a/data/src/main/java/com/teamwiney/data/network/service/AuthService.kt b/data/src/main/java/com/teamwiney/data/network/service/AuthService.kt index 5a6967d8..79184ced 100644 --- a/data/src/main/java/com/teamwiney/data/network/service/AuthService.kt +++ b/data/src/main/java/com/teamwiney/data/network/service/AuthService.kt @@ -16,6 +16,7 @@ import com.teamwiney.data.network.model.response.DeleteUser import com.teamwiney.data.network.model.response.GoogleAccessToken import com.teamwiney.data.network.model.response.SetPreferences import com.teamwiney.data.network.model.response.SocialLogin +import com.teamwiney.data.network.model.response.UserInfo import com.teamwiney.data.network.model.response.VerifyAuthenticationMessage import retrofit2.Response import retrofit2.http.Body @@ -69,6 +70,9 @@ interface AuthService { @Body preferences: SetPreferencesRequest ): ApiResult> + /** 유저 상태 정보 조회 API */ + @GET("/info") + suspend fun getUserInfo(): ApiResult> /** 토큰 리프레쉬 API */ @POST("/refresh") diff --git a/data/src/main/java/com/teamwiney/data/repository/auth/AuthRepository.kt b/data/src/main/java/com/teamwiney/data/repository/auth/AuthRepository.kt index e4c37a4c..156fb534 100644 --- a/data/src/main/java/com/teamwiney/data/repository/auth/AuthRepository.kt +++ b/data/src/main/java/com/teamwiney/data/repository/auth/AuthRepository.kt @@ -13,6 +13,7 @@ import com.teamwiney.data.network.model.response.DeleteUser import com.teamwiney.data.network.model.response.GoogleAccessToken import com.teamwiney.data.network.model.response.SetPreferences import com.teamwiney.data.network.model.response.SocialLogin +import com.teamwiney.data.network.model.response.UserInfo import com.teamwiney.data.network.model.response.VerifyAuthenticationMessage import kotlinx.coroutines.flow.Flow @@ -49,6 +50,8 @@ interface AuthRepository { refreshToken: String ): Flow>> + fun getUserInfo(): Flow>> + fun getConnections(): Flow> fun registerFcmToken( diff --git a/data/src/main/java/com/teamwiney/data/repository/auth/AuthRepositoryImpl.kt b/data/src/main/java/com/teamwiney/data/repository/auth/AuthRepositoryImpl.kt index b7501627..1f4f95c5 100644 --- a/data/src/main/java/com/teamwiney/data/repository/auth/AuthRepositoryImpl.kt +++ b/data/src/main/java/com/teamwiney/data/repository/auth/AuthRepositoryImpl.kt @@ -59,6 +59,8 @@ class AuthRepositoryImpl @Inject constructor( request: PhoneNumberWithVerificationCodeRequest ) = authDataSource.verifyAuthCodeMessage(userId, request) + override fun getUserInfo() = authDataSource.getUserInfo() + override fun getConnections() = authDataSource.getConnections() override fun registerFcmToken( diff --git a/feature/auth/src/main/java/com/teamwiney/auth/login/LoginViewModel.kt b/feature/auth/src/main/java/com/teamwiney/auth/login/LoginViewModel.kt index 2cdd1d02..30a3dcd8 100644 --- a/feature/auth/src/main/java/com/teamwiney/auth/login/LoginViewModel.kt +++ b/feature/auth/src/main/java/com/teamwiney/auth/login/LoginViewModel.kt @@ -10,6 +10,7 @@ import com.kakao.sdk.common.model.ClientErrorCause import com.kakao.sdk.user.UserApiClient import com.teamwiney.core.common.base.BaseViewModel import com.teamwiney.core.common.model.SocialType +import com.teamwiney.core.common.model.UserStatus import com.teamwiney.core.common.navigation.AuthDestinations import com.teamwiney.core.common.navigation.HomeDestinations import com.teamwiney.core.common.util.Constants @@ -17,7 +18,6 @@ import com.teamwiney.core.common.util.Constants.ACCESS_TOKEN import com.teamwiney.core.common.util.Constants.LOGIN_TYPE import com.teamwiney.core.common.util.Constants.REFRESH_TOKEN import com.teamwiney.data.network.adapter.ApiResult -import com.teamwiney.data.network.model.response.SocialLogin import com.teamwiney.data.repository.auth.AuthRepository import com.teamwiney.data.repository.persistence.DataStoreRepository import dagger.hilt.android.lifecycle.HiltViewModel @@ -111,26 +111,27 @@ class LoginViewModel @Inject constructor( updateState(currentState.copy(isLoading = false)) when (result) { is ApiResult.Success -> { + runBlocking { + dataStoreRepository.setStringValue(ACCESS_TOKEN, result.data.result.accessToken) + dataStoreRepository.setStringValue(REFRESH_TOKEN, result.data.result.refreshToken) + dataStoreRepository.setIntValue(Constants.USER_ID, result.data.result.userId) + } + + Log.i( + "[ACCESS_TOKEN]", + "accessToken: ${result.data.result.accessToken}" + ) + Log.i( + "[REFRESH_TOKEN]", + "refreshToken: ${result.data.result.refreshToken}" + ) + val userStatus = result.data.result.userStatus - if (userStatus == SocialLogin.USER_STATUS_ACTIVE) { - Log.i( - "[ACCESS_TOKEN]", - "accessToken: ${result.data.result.accessToken}" - ) - Log.i( - "[REFRESH_TOKEN]", - "refreshToken: ${result.data.result.refreshToken}" - ) - dataStoreRepository.setStringValue( - ACCESS_TOKEN, - result.data.result.accessToken - ) - dataStoreRepository.setStringValue( - REFRESH_TOKEN, - result.data.result.refreshToken - ) + if (userStatus == UserStatus.ACTIVE) { dataStoreRepository.setStringValue(LOGIN_TYPE, socialType.name) + registerFcmToken() + postEffect(LoginContract.Effect.NavigateTo( destination = HomeDestinations.ROUTE, navOptions = navOptions { @@ -142,10 +143,6 @@ class LoginViewModel @Inject constructor( } else { postEffect(LoginContract.Effect.NavigateTo("${AuthDestinations.SignUp.ROUTE}?userId=${result.data.result.userId}")) } - - runBlocking { - dataStoreRepository.setIntValue(Constants.USER_ID, result.data.result.userId) - } } is ApiResult.ApiError -> { @@ -160,4 +157,23 @@ class LoginViewModel @Inject constructor( } } + private fun registerFcmToken() = viewModelScope.launch { + val fcmToken = dataStoreRepository.getStringValue(Constants.FCM_TOKEN).first() + val deviceId = dataStoreRepository.getStringValue(Constants.DEVICE_ID).first() + + authRepository.registerFcmToken(fcmToken, deviceId).collectLatest { + when (it) { + is ApiResult.ApiError -> { + postEffect(LoginContract.Effect.ShowSnackBar(it.message)) + } + + is ApiResult.NetworkError -> { + postEffect(LoginContract.Effect.ShowSnackBar("네트워크 오류가 발생했습니다.")) + } + + else -> { } + } + } + } + } \ No newline at end of file diff --git a/feature/auth/src/main/java/com/teamwiney/auth/signup/SignUpViewModel.kt b/feature/auth/src/main/java/com/teamwiney/auth/signup/SignUpViewModel.kt index 6a2aa8c0..f524f8de 100644 --- a/feature/auth/src/main/java/com/teamwiney/auth/signup/SignUpViewModel.kt +++ b/feature/auth/src/main/java/com/teamwiney/auth/signup/SignUpViewModel.kt @@ -4,20 +4,24 @@ import androidx.lifecycle.viewModelScope import com.teamwiney.auth.signup.component.state.SignUpFavoriteCategoryUiState import com.teamwiney.core.common.base.BaseViewModel import com.teamwiney.core.common.navigation.AuthDestinations +import com.teamwiney.core.common.util.Constants import com.teamwiney.data.network.adapter.ApiResult import com.teamwiney.data.network.model.request.PhoneNumberRequest import com.teamwiney.data.network.model.request.PhoneNumberWithVerificationCodeRequest import com.teamwiney.data.network.model.request.SetPreferencesRequest import com.teamwiney.data.repository.auth.AuthRepository +import com.teamwiney.data.repository.persistence.DataStoreRepository import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.flow.collectLatest +import kotlinx.coroutines.flow.first import kotlinx.coroutines.flow.onStart import kotlinx.coroutines.launch import javax.inject.Inject @HiltViewModel class SignUpViewModel @Inject constructor( - private val authRepository: AuthRepository + private val authRepository: AuthRepository, + private val dataStoreRepository: DataStoreRepository ) : BaseViewModel( initialState = SignUpContract.State() ) { @@ -57,6 +61,7 @@ class SignUpViewModel @Inject constructor( ).collectLatest { when (it) { is ApiResult.Success -> { + registerFcmToken() // 회원가입 완료 후 FCM 토큰 등록 postEffect(SignUpContract.Effect.NavigateTo(AuthDestinations.SignUp.COMPLETE)) } @@ -132,6 +137,25 @@ class SignUpViewModel @Inject constructor( } } + private fun registerFcmToken() = viewModelScope.launch { + val fcmToken = dataStoreRepository.getStringValue(Constants.FCM_TOKEN).first() + val deviceId = dataStoreRepository.getStringValue(Constants.DEVICE_ID).first() + + authRepository.registerFcmToken(fcmToken, deviceId).collectLatest { + when (it) { + is ApiResult.ApiError -> { + postEffect(SignUpContract.Effect.ShowSnackBar(it.message)) + } + + is ApiResult.NetworkError -> { + postEffect(SignUpContract.Effect.ShowSnackBar("네트워크 오류가 발생했습니다.")) + } + + else -> { } + } + } + } + fun updateUserId(userId: String) = viewModelScope.launch { updateState(currentState.copy(userId = userId)) } diff --git a/feature/auth/src/main/java/com/teamwiney/auth/splash/SplashContract.kt b/feature/auth/src/main/java/com/teamwiney/auth/splash/SplashContract.kt index f0bad440..ef9c862b 100644 --- a/feature/auth/src/main/java/com/teamwiney/auth/splash/SplashContract.kt +++ b/feature/auth/src/main/java/com/teamwiney/auth/splash/SplashContract.kt @@ -13,7 +13,7 @@ class SplashContract { ) : UiState sealed class Event : UiEvent { - object AutoLoginCheck : Event() + object CheckUserStatus : Event() } sealed class Effect : UiEffect { diff --git a/feature/auth/src/main/java/com/teamwiney/auth/splash/SplashScreen.kt b/feature/auth/src/main/java/com/teamwiney/auth/splash/SplashScreen.kt index 80f61bde..0f57de70 100644 --- a/feature/auth/src/main/java/com/teamwiney/auth/splash/SplashScreen.kt +++ b/feature/auth/src/main/java/com/teamwiney/auth/splash/SplashScreen.kt @@ -46,10 +46,8 @@ fun SplashScreen( LaunchedEffect(true) { viewModel.checkIsFirstLaunch() - viewModel.getConnections() - viewModel.registerFcmToken() delay(1500) - viewModel.processEvent(SplashContract.Event.AutoLoginCheck) + viewModel.processEvent(SplashContract.Event.CheckUserStatus) effectFlow.collectLatest { effect -> when (effect) { diff --git a/feature/auth/src/main/java/com/teamwiney/auth/splash/SplashViewModel.kt b/feature/auth/src/main/java/com/teamwiney/auth/splash/SplashViewModel.kt index eeb98912..23c5b831 100644 --- a/feature/auth/src/main/java/com/teamwiney/auth/splash/SplashViewModel.kt +++ b/feature/auth/src/main/java/com/teamwiney/auth/splash/SplashViewModel.kt @@ -1,16 +1,13 @@ package com.teamwiney.auth.splash -import android.util.Log import androidx.lifecycle.viewModelScope import com.teamwiney.core.common.base.BaseViewModel +import com.teamwiney.core.common.model.UserStatus import com.teamwiney.core.common.navigation.AuthDestinations import com.teamwiney.core.common.navigation.HomeDestinations import com.teamwiney.core.common.util.Constants -import com.teamwiney.core.common.util.Constants.ACCESS_TOKEN -import com.teamwiney.core.common.util.Constants.DEVICE_ID -import com.teamwiney.core.common.util.Constants.FCM_TOKEN import com.teamwiney.core.common.util.Constants.IS_NOT_FIRST_LAUNCH -import com.teamwiney.core.common.util.Constants.REFRESH_TOKEN +import com.teamwiney.core.common.util.Constants.USER_ID import com.teamwiney.data.di.DispatcherModule import com.teamwiney.data.network.adapter.ApiResult import com.teamwiney.data.repository.auth.AuthRepository @@ -20,7 +17,7 @@ import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.flow.collectLatest import kotlinx.coroutines.flow.first import kotlinx.coroutines.launch -import kotlinx.coroutines.withContext +import kotlinx.coroutines.runBlocking import javax.inject.Inject @@ -42,8 +39,8 @@ class SplashViewModel @Inject constructor( override fun reduceState(event: SplashContract.Event) { viewModelScope.launch { when (event) { - SplashContract.Event.AutoLoginCheck -> { - autoLoginCheck() + SplashContract.Event.CheckUserStatus -> { + checkUserStatus() } } } @@ -58,55 +55,34 @@ class SplashViewModel @Inject constructor( } } - private fun autoLoginCheck() = viewModelScope.launch { - val refreshToken = - withContext(ioDispatcher) { dataStoreRepository.getStringValue(REFRESH_TOKEN).first() } - Log.i("[REFRESH_TOKEN] : ", refreshToken) - if (refreshToken.isNotEmpty()) { - refreshToken(refreshToken) - } else { - naviagateToLogin() - } - } - - private fun refreshToken(refreshToken: String) = viewModelScope.launch { - authRepository.refreshToken(refreshToken).collectLatest { apiResult -> - when (apiResult) { + private fun checkUserStatus() = viewModelScope.launch { + authRepository.getUserInfo().collectLatest { + when (it) { is ApiResult.Success -> { - val accessToken = apiResult.data.result.accessToken - withContext(ioDispatcher) { - dataStoreRepository.setStringValue(ACCESS_TOKEN, accessToken) - } - navigateToMain() - } + val userInfo = it.data.result - else -> { - naviagateToLogin() - } - } - } - } + runBlocking { dataStoreRepository.setIntValue(USER_ID, userInfo.userId) } - fun registerFcmToken() = viewModelScope.launch { - val fcmToken = dataStoreRepository.getStringValue(FCM_TOKEN).first() - val deviceId = dataStoreRepository.getStringValue(DEVICE_ID).first() + if (userInfo.status == UserStatus.ACTIVE) { + getConnections() + navigateToMain() + } else { + naviagateToLogin() + } + } - authRepository.registerFcmToken(fcmToken, deviceId).collectLatest { - when (it) { is ApiResult.ApiError -> { - postEffect(SplashContract.Effect.ShowSnackBar(it.message)) + naviagateToLogin() } is ApiResult.NetworkError -> { postEffect(SplashContract.Effect.ShowSnackBar("네트워크 오류가 발생했습니다.")) } - - else -> { } } } } - fun getConnections() = viewModelScope.launch { + private fun getConnections() = viewModelScope.launch { authRepository.getConnections().collectLatest { when (it) { is ApiResult.ApiError -> {