diff --git a/data/src/main/java/com/susu/data/di/NetworkModule.kt b/data/src/main/java/com/susu/data/di/NetworkModule.kt index 3541ac94..dd797db8 100644 --- a/data/src/main/java/com/susu/data/di/NetworkModule.kt +++ b/data/src/main/java/com/susu/data/di/NetworkModule.kt @@ -72,7 +72,6 @@ object NetworkModule { @AuthOkHttpClient fun provideAuthOkHttpClient( loggingInterceptor: HttpLoggingInterceptor, - json: Json, ): OkHttpClient = OkHttpClient.Builder() .addInterceptor(loggingInterceptor) .build() diff --git a/domain/src/main/java/com/susu/domain/usecase/LogoutUseCase.kt b/domain/src/main/java/com/susu/domain/usecase/LogoutUseCase.kt new file mode 100644 index 00000000..62817032 --- /dev/null +++ b/domain/src/main/java/com/susu/domain/usecase/LogoutUseCase.kt @@ -0,0 +1,16 @@ +package com.susu.domain.usecase + +import com.susu.core.common.runCatchingIgnoreCancelled +import com.susu.domain.repository.LoginRepository +import com.susu.domain.repository.TokenRepository +import javax.inject.Inject + +class LogoutUseCase @Inject constructor( + private val loginRepository: LoginRepository, + private val tokenRepository: TokenRepository, +) { + suspend operator fun invoke() = runCatchingIgnoreCancelled { + loginRepository.logout() + tokenRepository.deleteTokens() + } +} diff --git a/domain/src/main/java/com/susu/domain/usecase/WithdrawUseCase.kt b/domain/src/main/java/com/susu/domain/usecase/WithdrawUseCase.kt new file mode 100644 index 00000000..77d9c355 --- /dev/null +++ b/domain/src/main/java/com/susu/domain/usecase/WithdrawUseCase.kt @@ -0,0 +1,16 @@ +package com.susu.domain.usecase + +import com.susu.core.common.runCatchingIgnoreCancelled +import com.susu.domain.repository.LoginRepository +import com.susu.domain.repository.TokenRepository +import javax.inject.Inject + +class WithdrawUseCase @Inject constructor( + private val loginRepository: LoginRepository, + private val tokenRepository: TokenRepository, +) { + suspend operator fun invoke() = runCatchingIgnoreCancelled { + loginRepository.withdraw() + tokenRepository.deleteTokens() + } +} diff --git a/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/VoteScreen.kt b/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/VoteScreen.kt new file mode 100644 index 00000000..d0bed1d9 --- /dev/null +++ b/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/VoteScreen.kt @@ -0,0 +1,14 @@ +package com.susu.feature.loginsignup + +import androidx.compose.material3.Button +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable + +@Composable +fun VoteScreen( + navigateToLogin: () -> Unit +) { + Button(onClick = navigateToLogin) { + Text("대충 회원가입 투표") + } +} diff --git a/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/navigation/LoginSignupNavigation.kt b/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/navigation/LoginSignupNavigation.kt index 281be13b..efc02902 100644 --- a/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/navigation/LoginSignupNavigation.kt +++ b/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/navigation/LoginSignupNavigation.kt @@ -4,41 +4,41 @@ import androidx.navigation.NavController import androidx.navigation.NavGraphBuilder import androidx.navigation.NavOptions import androidx.navigation.compose.composable -import androidx.navigation.navigation +import com.susu.feature.loginsignup.VoteScreen import com.susu.feature.loginsignup.login.LoginScreen import com.susu.feature.loginsignup.signup.SignUpScreen -import com.susu.feature.loginsignup.test.TestScreen @Suppress("unused") fun NavController.navigateLoginSignup(navOptions: NavOptions) { navigate(LoginSignupRoute.Parent.route, navOptions) } -fun NavGraphBuilder.loginSignupNavGraph(navController: NavController) { - navigation(startDestination = LoginSignupRoute.Parent.Login.route, route = LoginSignupRoute.Parent.route) { - composable(route = LoginSignupRoute.Parent.Login.route) { - LoginScreen( - navigateToReceived = { navController.navigate(LoginSignupRoute.Parent.Test.route) }, - navigateToSignUp = { navController.navigate(LoginSignupRoute.Parent.SignUp.route) }, - ) - } - composable(route = LoginSignupRoute.Parent.SignUp.route) { - SignUpScreen( - navigateToReceived = { navController.navigate(LoginSignupRoute.Parent.Test.route) }, - ) - } - composable(route = LoginSignupRoute.Parent.Test.route) { - TestScreen( - navigateToLogin = { navController.popBackStack() }, - ) - } +fun NavGraphBuilder.loginSignupNavGraph( + navController: NavController, + navigateToReceived: () -> Unit, +) { + composable(route = LoginSignupRoute.Parent.Vote.route) { + VoteScreen( + navigateToLogin = { navController.navigate(LoginSignupRoute.Parent.Login.route) }, + ) + } + composable(route = LoginSignupRoute.Parent.Login.route) { + LoginScreen( + navigateToReceived = navigateToReceived, + navigateToSignUp = { navController.navigate(LoginSignupRoute.Parent.SignUp.route) }, + ) + } + composable(route = LoginSignupRoute.Parent.SignUp.route) { + SignUpScreen( + navigateToReceived = navigateToReceived, + ) } } sealed class LoginSignupRoute(val route: String) { data object Parent : LoginSignupRoute("login-signup") { + data object Vote : LoginSignupRoute("vote") data object Login : LoginSignupRoute("login") data object SignUp : LoginSignupRoute("signup") - data object Test : LoginSignupRoute("test") } } diff --git a/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/social/KakaoLoginHelper.kt b/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/social/KakaoLoginHelper.kt index 1a33abd1..2856c2eb 100644 --- a/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/social/KakaoLoginHelper.kt +++ b/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/social/KakaoLoginHelper.kt @@ -26,7 +26,7 @@ object KakaoLoginHelper { loginWithKakaoAccount( onSuccess = onSuccess, onFailed = onFailed, - context = context + context = context, ) } }, @@ -87,21 +87,4 @@ object KakaoLoginHelper { } } } - - // 기능 테스트를 위함. - fun logout() = runCatching { - UserApiClient.instance.logout { error -> - if (error != null) { - throw error - } - } - } - - fun unlink() = runCatching { - UserApiClient.instance.unlink { error -> - if (error != null) { - throw error - } - } - } } diff --git a/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/test/TestContract.kt b/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/test/TestContract.kt deleted file mode 100644 index 2136d5e7..00000000 --- a/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/test/TestContract.kt +++ /dev/null @@ -1,12 +0,0 @@ -package com.susu.feature.loginsignup.test - -import com.susu.core.ui.base.SideEffect -import com.susu.core.ui.base.UiState - -sealed interface TestContract { - sealed class TestEffect : SideEffect { - data object NavigateToLogin : TestEffect() - } - - object TestState : UiState -} diff --git a/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/test/TestScreen.kt b/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/test/TestScreen.kt deleted file mode 100644 index cbda00b6..00000000 --- a/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/test/TestScreen.kt +++ /dev/null @@ -1,33 +0,0 @@ -package com.susu.feature.loginsignup.test - -import androidx.compose.foundation.layout.Column -import androidx.compose.material3.Button -import androidx.compose.material3.Text -import androidx.compose.runtime.Composable -import androidx.compose.runtime.LaunchedEffect -import androidx.hilt.navigation.compose.hiltViewModel - -@Composable -fun TestScreen( - viewModel: TestViewModel = hiltViewModel(), - navigateToLogin: () -> Unit, -) { - LaunchedEffect(key1 = viewModel.sideEffect) { - viewModel.sideEffect.collect { sideEffect -> - when (sideEffect) { - TestContract.TestEffect.NavigateToLogin -> navigateToLogin() - } - } - } - - Column { - Button(onClick = viewModel::logout) { - Text(text = "로그아웃") - } - Button( - onClick = viewModel::withdraw, - ) { - Text(text = "탈퇴") - } - } -} diff --git a/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/test/TestViewModel.kt b/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/test/TestViewModel.kt deleted file mode 100644 index 991db4b4..00000000 --- a/feature/loginsignup/src/main/java/com/susu/feature/loginsignup/test/TestViewModel.kt +++ /dev/null @@ -1,38 +0,0 @@ -package com.susu.feature.loginsignup.test - -import androidx.lifecycle.viewModelScope -import com.susu.core.ui.base.BaseViewModel -import com.susu.domain.repository.LoginRepository -import com.susu.domain.repository.SignUpRepository -import com.susu.domain.repository.TokenRepository -import com.susu.feature.loginsignup.social.KakaoLoginHelper -import dagger.hilt.android.lifecycle.HiltViewModel -import kotlinx.coroutines.launch -import kotlinx.coroutines.runBlocking -import javax.inject.Inject - -// 마이페이지에 들어갈 기능입니다. -@HiltViewModel -class TestViewModel @Inject constructor( - private val loginRepository: LoginRepository, - private val tokenRepository: TokenRepository, -) : BaseViewModel(TestContract.TestState) { - fun logout() { - viewModelScope.launch { - loginRepository.logout() - KakaoLoginHelper.logout() - tokenRepository.deleteTokens() - } - postSideEffect(TestContract.TestEffect.NavigateToLogin) - } - - fun withdraw() { - KakaoLoginHelper.unlink().onSuccess { - viewModelScope.launch { - runBlocking { loginRepository.withdraw() } - tokenRepository.deleteTokens() - } - } - postSideEffect(TestContract.TestEffect.NavigateToLogin) - } -} diff --git a/feature/mypage/src/main/java/com/susu/feature/mypage/MyPageContract.kt b/feature/mypage/src/main/java/com/susu/feature/mypage/MyPageContract.kt new file mode 100644 index 00000000..b66aa66b --- /dev/null +++ b/feature/mypage/src/main/java/com/susu/feature/mypage/MyPageContract.kt @@ -0,0 +1,13 @@ +package com.susu.feature.mypage + +import com.susu.core.ui.base.SideEffect +import com.susu.core.ui.base.UiState + +interface MyPageContract { + sealed class MyPageEffect : SideEffect { + data object NavigateToLogin : MyPageEffect() + data class ShowToast(val msg: String) : MyPageEffect() + } + + object MyPageState : UiState +} diff --git a/feature/mypage/src/main/java/com/susu/feature/mypage/MyPageScreen.kt b/feature/mypage/src/main/java/com/susu/feature/mypage/MyPageScreen.kt index 95aac460..ca19fa4b 100644 --- a/feature/mypage/src/main/java/com/susu/feature/mypage/MyPageScreen.kt +++ b/feature/mypage/src/main/java/com/susu/feature/mypage/MyPageScreen.kt @@ -1,28 +1,52 @@ package com.susu.feature.mypage +import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.padding +import androidx.compose.material3.Button import androidx.compose.material3.Text import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect import androidx.compose.ui.Modifier import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp +import androidx.hilt.navigation.compose.hiltViewModel import com.susu.core.designsystem.theme.SusuTheme @Composable fun MyPageScreen( padding: PaddingValues, + viewModel: MyPageViewModel = hiltViewModel(), + navigateToLogin: () -> Unit, ) { - Text( - modifier = Modifier.padding(padding), - text = "마이 페이지", - ) + LaunchedEffect(key1 = viewModel.sideEffect) { + viewModel.sideEffect.collect { sideEffect -> + when (sideEffect) { + MyPageContract.MyPageEffect.NavigateToLogin -> navigateToLogin() + is MyPageContract.MyPageEffect.ShowToast -> { + //TODO: UI 작업 시 에러 메세지 표시 + navigateToLogin() + } + } + } + } + + Column { + Button(onClick = viewModel::logout) { + Text(text = "로그아웃") + } + Button( + onClick = viewModel::withdraw, + ) { + Text(text = "탈퇴") + } + } } @Preview @Composable fun MyPageScreenPreview() { SusuTheme { - MyPageScreen(padding = PaddingValues(0.dp)) + MyPageScreen(padding = PaddingValues(0.dp)) {} } } diff --git a/feature/mypage/src/main/java/com/susu/feature/mypage/MyPageViewModel.kt b/feature/mypage/src/main/java/com/susu/feature/mypage/MyPageViewModel.kt new file mode 100644 index 00000000..f3ac1a97 --- /dev/null +++ b/feature/mypage/src/main/java/com/susu/feature/mypage/MyPageViewModel.kt @@ -0,0 +1,45 @@ +package com.susu.feature.mypage + +import androidx.lifecycle.viewModelScope +import com.kakao.sdk.user.UserApiClient +import com.susu.core.ui.base.BaseViewModel +import com.susu.domain.usecase.LogoutUseCase +import com.susu.domain.usecase.WithdrawUseCase +import dagger.hilt.android.lifecycle.HiltViewModel +import kotlinx.coroutines.launch +import javax.inject.Inject + +@HiltViewModel +class MyPageViewModel @Inject constructor( + private val logoutUseCase: LogoutUseCase, + private val withdrawUseCase: WithdrawUseCase, +) : BaseViewModel(MyPageContract.MyPageState) { + + fun logout() { + UserApiClient.instance.logout { error -> + if (error != null) { + postSideEffect(MyPageContract.MyPageEffect.ShowToast(error.message ?: "에러 발생했지만 토큰은 삭제됨")) + } else { + viewModelScope.launch { + logoutUseCase().onSuccess { + postSideEffect(MyPageContract.MyPageEffect.NavigateToLogin) + } + } + } + } + } + + fun withdraw() { + UserApiClient.instance.unlink { error -> + if (error != null) { + postSideEffect(MyPageContract.MyPageEffect.ShowToast(error.message ?: "에러 발생했지만 토큰은 삭제됨")) + } else { + viewModelScope.launch { + withdrawUseCase().onSuccess { + postSideEffect(MyPageContract.MyPageEffect.NavigateToLogin) + } + } + } + } + } +} diff --git a/feature/mypage/src/main/java/com/susu/feature/mypage/navigation/MyPageNavigation.kt b/feature/mypage/src/main/java/com/susu/feature/mypage/navigation/MyPageNavigation.kt index c5f5b0ca..4767c9f7 100644 --- a/feature/mypage/src/main/java/com/susu/feature/mypage/navigation/MyPageNavigation.kt +++ b/feature/mypage/src/main/java/com/susu/feature/mypage/navigation/MyPageNavigation.kt @@ -13,9 +13,10 @@ fun NavController.navigateMyPage(navOptions: NavOptions) { fun NavGraphBuilder.myPageNavGraph( padding: PaddingValues, + navigateToLogin: () -> Unit ) { composable(route = MyPageRoute.route) { - MyPageScreen(padding) + MyPageScreen(padding, navigateToLogin = navigateToLogin) } } diff --git a/feature/navigator/src/main/java/com/susu/feature/navigator/MainActivity.kt b/feature/navigator/src/main/java/com/susu/feature/navigator/MainActivity.kt index 0f1f079c..189f0e1a 100644 --- a/feature/navigator/src/main/java/com/susu/feature/navigator/MainActivity.kt +++ b/feature/navigator/src/main/java/com/susu/feature/navigator/MainActivity.kt @@ -64,8 +64,8 @@ class MainActivity : ComponentActivity() { ), ), startDestination = when (uiState.initialRoute) { - InitialRoute.SIGNUP_VOTE -> LoginSignupRoute.Parent.route - InitialRoute.LOGIN -> LoginSignupRoute.Parent.route + InitialRoute.SIGNUP_VOTE -> LoginSignupRoute.Parent.Vote.route + InitialRoute.LOGIN -> LoginSignupRoute.Parent.Login.route InitialRoute.RECEIVED -> ReceivedRoute.route InitialRoute.NONE -> LoginSignupRoute.Parent.route }, diff --git a/feature/navigator/src/main/java/com/susu/feature/navigator/MainScreen.kt b/feature/navigator/src/main/java/com/susu/feature/navigator/MainScreen.kt index 25c86334..e246635a 100644 --- a/feature/navigator/src/main/java/com/susu/feature/navigator/MainScreen.kt +++ b/feature/navigator/src/main/java/com/susu/feature/navigator/MainScreen.kt @@ -14,6 +14,7 @@ import androidx.navigation.compose.NavHost import com.susu.core.designsystem.component.navigation.SusuNavigationBar import com.susu.core.designsystem.component.navigation.SusuNavigationItem import com.susu.feature.community.navigation.communityNavGraph +import com.susu.feature.loginsignup.navigation.LoginSignupRoute import com.susu.feature.loginsignup.navigation.loginSignupNavGraph import com.susu.feature.mypage.navigation.myPageNavGraph import com.susu.feature.received.navigation.receivedNavGraph @@ -35,7 +36,14 @@ internal fun MainScreen( navController = navigator.navController, startDestination = startDestination, ) { - loginSignupNavGraph(navigator.navController) + loginSignupNavGraph( + navController = navigator.navController, + navigateToReceived = { + // TODO: 이쪽으로 수정 + // navigator.navController.navigateReceived(navOptions = NavOptions()) + navigator.navigate(MainNavigationTab.RECEIVED) + }, + ) sentNavGraph( padding = innerPadding, @@ -55,6 +63,7 @@ internal fun MainScreen( myPageNavGraph( padding = innerPadding, + navigateToLogin = { navigator.navController.navigate(LoginSignupRoute.Parent.Login.route) }, ) } },