diff --git a/app/src/main/java/com/into/websoso/data/remote/api/AuthApi.kt b/app/src/main/java/com/into/websoso/data/remote/api/AuthApi.kt index 34ba169e6..44c0ba53c 100644 --- a/app/src/main/java/com/into/websoso/data/remote/api/AuthApi.kt +++ b/app/src/main/java/com/into/websoso/data/remote/api/AuthApi.kt @@ -1,7 +1,6 @@ package com.into.websoso.data.remote.api import com.into.websoso.data.remote.request.FCMTokenRequestDto -import com.into.websoso.data.remote.request.LogoutRequestDto import com.into.websoso.data.remote.request.UserProfileRequestDto import com.into.websoso.data.remote.request.WithdrawRequestDto import com.into.websoso.data.remote.response.UserNicknameValidityResponseDto @@ -24,12 +23,6 @@ interface AuthApi { @Body userProfileRequestDto: UserProfileRequestDto, ) - @POST("auth/logout") - suspend fun logout( - @Header("Authorization") authorization: String, - @Body loginResponseDto: LogoutRequestDto, - ) - @POST("auth/withdraw") suspend fun withdraw( @Header("Authorization") authorization: String, diff --git a/app/src/main/java/com/into/websoso/data/repository/AuthRepository.kt b/app/src/main/java/com/into/websoso/data/repository/AuthRepository.kt index 1214ea6b4..4cdf4071e 100644 --- a/app/src/main/java/com/into/websoso/data/repository/AuthRepository.kt +++ b/app/src/main/java/com/into/websoso/data/repository/AuthRepository.kt @@ -3,7 +3,6 @@ package com.into.websoso.data.repository import android.content.SharedPreferences import com.into.websoso.data.remote.api.AuthApi import com.into.websoso.data.remote.request.FCMTokenRequestDto -import com.into.websoso.data.remote.request.LogoutRequestDto import com.into.websoso.data.remote.request.UserProfileRequestDto import com.into.websoso.data.remote.request.WithdrawRequestDto import javax.inject.Inject @@ -44,21 +43,6 @@ class AuthRepository ) } - suspend fun logout(deviceIdentifier: String) { - runCatching { - if (accessToken.isNotEmpty() && refreshToken.isNotEmpty()) { - authApi.logout( - "Bearer $accessToken", - LogoutRequestDto(refreshToken, deviceIdentifier), - ) - } - }.onSuccess { - clearTokens() - }.onFailure { - it.printStackTrace() - } - } - suspend fun withdraw(reason: String) { runCatching { if (accessToken.isNotEmpty() && refreshToken.isNotEmpty()) { diff --git a/app/src/main/java/com/into/websoso/ui/accountInfo/AccountInfoViewModel.kt b/app/src/main/java/com/into/websoso/ui/accountInfo/AccountInfoViewModel.kt index ba2b7c306..e7c3898c8 100644 --- a/app/src/main/java/com/into/websoso/ui/accountInfo/AccountInfoViewModel.kt +++ b/app/src/main/java/com/into/websoso/ui/accountInfo/AccountInfoViewModel.kt @@ -1,13 +1,19 @@ package com.into.websoso.ui.accountInfo -import androidx.lifecycle.LiveData -import androidx.lifecycle.MutableLiveData import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope -import com.into.websoso.data.repository.AuthRepository +import com.into.websoso.data.account.AccountRepository import com.into.websoso.data.repository.PushMessageRepository import com.into.websoso.data.repository.UserRepository +import com.into.websoso.ui.accountInfo.UiEffect.NavigateToLogin import dagger.hilt.android.lifecycle.HiltViewModel +import kotlinx.coroutines.channels.Channel +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.asStateFlow +import kotlinx.coroutines.flow.receiveAsFlow +import kotlinx.coroutines.flow.update import kotlinx.coroutines.launch import javax.inject.Inject @@ -16,14 +22,14 @@ class AccountInfoViewModel @Inject constructor( private val userRepository: UserRepository, - private val authRepository: AuthRepository, private val pushMessageRepository: PushMessageRepository, + private val accountRepository: AccountRepository, ) : ViewModel() { - private val _userEmail: MutableLiveData = MutableLiveData() - val userEmail: LiveData get() = _userEmail + private val _userEmail: MutableStateFlow = MutableStateFlow("") + val userEmail: StateFlow get() = _userEmail.asStateFlow() - private val _isLogoutSuccess: MutableLiveData = MutableLiveData(false) - val isLogoutSuccess: LiveData get() = _isLogoutSuccess + private val _uiEffect = Channel(Channel.BUFFERED) + val uiEffect: Flow get() = _uiEffect.receiveAsFlow() init { updateUserEmail() @@ -34,23 +40,26 @@ class AccountInfoViewModel runCatching { userRepository.fetchUserInfoDetail() }.onSuccess { userInfo -> - _userEmail.value = userInfo.email + _userEmail.update { userInfo.email } } } } - fun logout() { + fun signOut() { viewModelScope.launch { runCatching { val userDeviceIdentifier = userRepository.fetchUserDeviceIdentifier() - authRepository.logout(userDeviceIdentifier) + accountRepository.deleteToken(userDeviceIdentifier) }.onSuccess { - _isLogoutSuccess.value = true - authRepository.updateIsAutoLogin(false) pushMessageRepository.clearFCMToken() + _uiEffect.send(NavigateToLogin) }.onFailure { - _isLogoutSuccess.value = false + _uiEffect.send(NavigateToLogin) } } } } + +sealed interface UiEffect { + data object NavigateToLogin : UiEffect +} diff --git a/app/src/main/java/com/into/websoso/ui/accountInfo/LogoutDialogFragment.kt b/app/src/main/java/com/into/websoso/ui/accountInfo/LogoutDialogFragment.kt index 91d1362cd..d85308b5a 100644 --- a/app/src/main/java/com/into/websoso/ui/accountInfo/LogoutDialogFragment.kt +++ b/app/src/main/java/com/into/websoso/ui/accountInfo/LogoutDialogFragment.kt @@ -4,46 +4,47 @@ import android.os.Bundle import android.view.View import androidx.fragment.app.activityViewModels import com.into.websoso.R +import com.into.websoso.core.common.navigator.NavigatorProvider import com.into.websoso.core.common.ui.base.BaseDialogFragment import com.into.websoso.core.common.util.SingleEventHandler +import com.into.websoso.core.common.util.collectWithLifecycle import com.into.websoso.databinding.DialogLogoutBinding -import com.into.websoso.ui.login.LoginActivity +import dagger.hilt.android.AndroidEntryPoint +import javax.inject.Inject +@AndroidEntryPoint class LogoutDialogFragment : BaseDialogFragment(R.layout.dialog_logout) { private val accountInfoViewModel: AccountInfoViewModel by activityViewModels() private val singleEventHandler: SingleEventHandler by lazy { SingleEventHandler.from() } + @Inject + lateinit var websosoNavigator: NavigatorProvider + override fun onViewCreated( view: View, savedInstanceState: Bundle?, ) { super.onViewCreated(view, savedInstanceState) - binding.lifecycleOwner = this - onCancelButtonClick() - onLogoutButtonClick() - setupObserver() + setClickListener() + collectUiEffect() } - private fun setupObserver() { - accountInfoViewModel.isLogoutSuccess.observe(viewLifecycleOwner) { isSuccess -> - if (isSuccess) { - startActivity(LoginActivity.getIntent(requireContext())) + private fun collectUiEffect() { + accountInfoViewModel.uiEffect.collectWithLifecycle(viewLifecycleOwner) { uiEffect -> + when (uiEffect) { + UiEffect.NavigateToLogin -> websosoNavigator.navigateToLoginActivity() } } } - private fun onCancelButtonClick() { + private fun setClickListener() { binding.tvLogoutCancelButton.setOnClickListener { dismiss() } - } - private fun onLogoutButtonClick() { binding.tvLogoutButton.setOnClickListener { - singleEventHandler.throttleFirst { - accountInfoViewModel.logout() - } + singleEventHandler.throttleFirst(event = accountInfoViewModel::signOut) } } diff --git a/app/src/main/java/com/into/websoso/ui/splash/SplashViewModel.kt b/app/src/main/java/com/into/websoso/ui/splash/SplashViewModel.kt index ee7f3e105..4e74ad6ba 100644 --- a/app/src/main/java/com/into/websoso/ui/splash/SplashViewModel.kt +++ b/app/src/main/java/com/into/websoso/ui/splash/SplashViewModel.kt @@ -23,7 +23,7 @@ class SplashViewModel private val userRepository: UserRepository, private val accountRepository: AccountRepository, ) : ViewModel() { - private var _uiEffect = Channel(Channel.BUFFERED) + private val _uiEffect = Channel(Channel.BUFFERED) val uiEffect: Flow get() = _uiEffect.receiveAsFlow() init { diff --git a/core/auth-kakao/src/main/java/com/into/websoso/core/auth_kakao/KakaoAuthClient.kt b/core/auth-kakao/src/main/java/com/into/websoso/core/auth_kakao/KakaoAuthClient.kt index 7a8a684e6..afe9f104b 100644 --- a/core/auth-kakao/src/main/java/com/into/websoso/core/auth_kakao/KakaoAuthClient.kt +++ b/core/auth-kakao/src/main/java/com/into/websoso/core/auth_kakao/KakaoAuthClient.kt @@ -32,18 +32,6 @@ class KakaoAuthClient } } - override suspend fun signOut() { - suspendCancellableCoroutine { - client.logout { error -> - if (error != null) { - it.resumeWithException(error) - } else { - it.resume(Unit) - } - } - } - } - override suspend fun withdraw() { suspendCancellableCoroutine { client.unlink { error -> diff --git a/core/auth/src/main/java/com/into/websoso/core/auth/AuthClient.kt b/core/auth/src/main/java/com/into/websoso/core/auth/AuthClient.kt index 9b8c02224..5c36ddfb2 100644 --- a/core/auth/src/main/java/com/into/websoso/core/auth/AuthClient.kt +++ b/core/auth/src/main/java/com/into/websoso/core/auth/AuthClient.kt @@ -3,7 +3,5 @@ package com.into.websoso.core.auth interface AuthClient { suspend fun signIn(): AuthToken - suspend fun signOut() - suspend fun withdraw() } diff --git a/core/datastore/src/main/java/com/into/websoso/core/datastore/datasource/account/DefaultAccountDataSource.kt b/core/datastore/src/main/java/com/into/websoso/core/datastore/datasource/account/DefaultAccountDataSource.kt index 5ef46621d..817193677 100644 --- a/core/datastore/src/main/java/com/into/websoso/core/datastore/datasource/account/DefaultAccountDataSource.kt +++ b/core/datastore/src/main/java/com/into/websoso/core/datastore/datasource/account/DefaultAccountDataSource.kt @@ -44,6 +44,13 @@ internal class DefaultAccountDataSource } } + override suspend fun clearTokens() { + accountDataStore.edit { preferences -> + preferences.remove(ACCESS_TOKEN) + preferences.remove(REFRESH_TOKEN) + } + } + companion object { private val ACCESS_TOKEN = stringPreferencesKey("ACCESS_TOKEN") private val REFRESH_TOKEN = stringPreferencesKey("REFRESH_TOKEN") diff --git a/core/network/src/main/java/com/into/websoso/core/network/datasource/account/AccountApi.kt b/core/network/src/main/java/com/into/websoso/core/network/datasource/account/AccountApi.kt index c9f15a18d..e5d1d78ad 100644 --- a/core/network/src/main/java/com/into/websoso/core/network/datasource/account/AccountApi.kt +++ b/core/network/src/main/java/com/into/websoso/core/network/datasource/account/AccountApi.kt @@ -1,6 +1,7 @@ package com.into.websoso.core.network.datasource.account import com.into.websoso.core.network.datasource.account.model.KakaoLoginResponseDto +import com.into.websoso.core.network.datasource.account.model.KakaoLogoutRequestDto import com.into.websoso.core.network.datasource.account.model.TokenReissueRequestDto import com.into.websoso.core.network.datasource.account.model.TokenReissueResponseDto import dagger.Module @@ -19,6 +20,11 @@ internal interface AccountApi { @Header("Kakao-Access-Token") accessToken: String, ): KakaoLoginResponseDto + @POST("auth/logout") + suspend fun postLogoutWithKakao( + @Body kakaoLogoutRequestDto: KakaoLogoutRequestDto, + ) + @POST("reissue") suspend fun postReissueToken( @Body tokenReissueRequestDto: TokenReissueRequestDto, diff --git a/core/network/src/main/java/com/into/websoso/core/network/datasource/account/DefaultAccountDataSource.kt b/core/network/src/main/java/com/into/websoso/core/network/datasource/account/DefaultAccountDataSource.kt index 9b5447a87..9cd6286ee 100644 --- a/core/network/src/main/java/com/into/websoso/core/network/datasource/account/DefaultAccountDataSource.kt +++ b/core/network/src/main/java/com/into/websoso/core/network/datasource/account/DefaultAccountDataSource.kt @@ -2,6 +2,7 @@ package com.into.websoso.core.network.datasource.account import com.into.websoso.core.auth.AuthPlatform import com.into.websoso.core.auth.AuthToken +import com.into.websoso.core.network.datasource.account.model.KakaoLogoutRequestDto import com.into.websoso.core.network.datasource.account.model.TokenReissueRequestDto import com.into.websoso.data.account.datasource.AccountRemoteDataSource import com.into.websoso.data.account.model.AccountEntity @@ -30,6 +31,18 @@ internal class DefaultAccountDataSource ).toData() } + override suspend fun postLogout( + refreshToken: String, + deviceIdentifier: String, + ) { + accountApi.postLogoutWithKakao( + kakaoLogoutRequestDto = KakaoLogoutRequestDto( + refreshToken = refreshToken, + deviceIdentifier = deviceIdentifier, + ), + ) + } + override suspend fun postReissue(refreshToken: String): TokenEntity = accountApi .postReissueToken( diff --git a/app/src/main/java/com/into/websoso/data/remote/request/LogoutRequestDto.kt b/core/network/src/main/java/com/into/websoso/core/network/datasource/account/model/KakaoLogoutRequestDto.kt similarity index 68% rename from app/src/main/java/com/into/websoso/data/remote/request/LogoutRequestDto.kt rename to core/network/src/main/java/com/into/websoso/core/network/datasource/account/model/KakaoLogoutRequestDto.kt index 601fa3be8..15ef59cbd 100644 --- a/app/src/main/java/com/into/websoso/data/remote/request/LogoutRequestDto.kt +++ b/core/network/src/main/java/com/into/websoso/core/network/datasource/account/model/KakaoLogoutRequestDto.kt @@ -1,10 +1,10 @@ -package com.into.websoso.data.remote.request +package com.into.websoso.core.network.datasource.account.model import kotlinx.serialization.SerialName import kotlinx.serialization.Serializable @Serializable -data class LogoutRequestDto( +internal data class KakaoLogoutRequestDto( @SerialName("refreshToken") val refreshToken: String, @SerialName("deviceIdentifier") diff --git a/data/account/src/main/java/com/into/websoso/data/account/AccountRepository.kt b/data/account/src/main/java/com/into/websoso/data/account/AccountRepository.kt index c87644969..fa035d498 100644 --- a/data/account/src/main/java/com/into/websoso/data/account/AccountRepository.kt +++ b/data/account/src/main/java/com/into/websoso/data/account/AccountRepository.kt @@ -7,7 +7,7 @@ import com.into.websoso.data.account.datasource.AccountRemoteDataSource import javax.inject.Inject import javax.inject.Singleton -// TODO: 인스턴스 싱글톤 참고하기 +// TODO: 인스턴스 싱글톤 참고하기, tokens 네이밍수정, result 객체 적용 @Singleton class AccountRepository @Inject @@ -34,6 +34,14 @@ class AccountRepository return account.isRegister } + suspend fun deleteToken(deviceIdentifier: String) { + accountRemoteDataSource + .postLogout( + refreshToken = refreshToken(), + deviceIdentifier = deviceIdentifier, + ).also { accountLocalDataSource.clearTokens() } + } + suspend fun renewToken(): String { val tokens = accountRemoteDataSource.postReissue(refreshToken = refreshToken()) diff --git a/data/account/src/main/java/com/into/websoso/data/account/datasource/AccountLocalDataSource.kt b/data/account/src/main/java/com/into/websoso/data/account/datasource/AccountLocalDataSource.kt index 693d2593d..41a7d6ec0 100644 --- a/data/account/src/main/java/com/into/websoso/data/account/datasource/AccountLocalDataSource.kt +++ b/data/account/src/main/java/com/into/websoso/data/account/datasource/AccountLocalDataSource.kt @@ -8,4 +8,6 @@ interface AccountLocalDataSource { suspend fun saveAccessToken(accessToken: String) suspend fun saveRefreshToken(refreshToken: String) + + suspend fun clearTokens() } diff --git a/data/account/src/main/java/com/into/websoso/data/account/datasource/AccountRemoteDataSource.kt b/data/account/src/main/java/com/into/websoso/data/account/datasource/AccountRemoteDataSource.kt index bc13f2444..20c7c455d 100644 --- a/data/account/src/main/java/com/into/websoso/data/account/datasource/AccountRemoteDataSource.kt +++ b/data/account/src/main/java/com/into/websoso/data/account/datasource/AccountRemoteDataSource.kt @@ -11,5 +11,10 @@ interface AccountRemoteDataSource { authToken: AuthToken, ): AccountEntity + suspend fun postLogout( + refreshToken: String, + deviceIdentifier: String, + ) + suspend fun postReissue(refreshToken: String): TokenEntity } diff --git a/feature/signin/src/main/java/com/into/websoso/feature/signin/SignInScreen.kt b/feature/signin/src/main/java/com/into/websoso/feature/signin/SignInScreen.kt index be68a169a..279a865b2 100644 --- a/feature/signin/src/main/java/com/into/websoso/feature/signin/SignInScreen.kt +++ b/feature/signin/src/main/java/com/into/websoso/feature/signin/SignInScreen.kt @@ -62,7 +62,7 @@ fun SignInScreen( onClick = { platform -> signInViewModel.signIn( platform = platform, - getToken = authClient(platform)::signIn, + signInToPlatform = authClient(platform)::signIn, ) }, ) diff --git a/feature/signin/src/main/java/com/into/websoso/feature/signin/SignInViewModel.kt b/feature/signin/src/main/java/com/into/websoso/feature/signin/SignInViewModel.kt index 03b29bdef..7b38e588b 100644 --- a/feature/signin/src/main/java/com/into/websoso/feature/signin/SignInViewModel.kt +++ b/feature/signin/src/main/java/com/into/websoso/feature/signin/SignInViewModel.kt @@ -27,11 +27,11 @@ class SignInViewModel fun signIn( platform: AuthPlatform, - getToken: suspend () -> AuthToken, + signInToPlatform: suspend () -> AuthToken, ) { viewModelScope.launch { runCatching { - getToken() + signInToPlatform() }.onSuccess { authToken -> signInWithSuccess(platform, authToken) }.onFailure {