From 925fa9331675a6dd4c92d39ff1381427c5976394 Mon Sep 17 00:00:00 2001 From: yeongun130 Date: Mon, 15 Jul 2024 13:14:15 +0900 Subject: [PATCH 1/5] =?UTF-8?q?:sparkles:=20::=20logout=20=EA=B8=B0?= =?UTF-8?q?=EB=8A=A5=20=EA=B5=AC=ED=98=84=20=EB=B0=8F=20=EA=B8=B0=EB=8A=A5?= =?UTF-8?q?=20=EC=97=B0=EA=B2=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/kdn/stack_knowledge/MainActivity.kt | 15 +++++++++- .../navigation/StackKnowledgeNavHost.kt | 2 ++ .../stack_knowledge/ui/StackKnowledgeApp.kt | 4 ++- .../repository/auth/AuthRepository.kt | 2 ++ .../repository/auth/AuthRepositoryImpl.kt | 7 +++++ .../stackknowledge/util/AuthInterceptor.kt | 12 ++++++-- .../login/viewmodel/AuthViewModel.kt | 6 ++++ .../com/stackknowledge/main/MainPageScreen.kt | 30 +++++++++++++++++-- .../main/navigation/MainNavigation.kt | 2 ++ .../main/viewModel/MainViewModel.kt | 22 ++++++++++++++ 10 files changed, 95 insertions(+), 7 deletions(-) diff --git a/app/src/main/java/com/kdn/stack_knowledge/MainActivity.kt b/app/src/main/java/com/kdn/stack_knowledge/MainActivity.kt index 7633a287..637484aa 100644 --- a/app/src/main/java/com/kdn/stack_knowledge/MainActivity.kt +++ b/app/src/main/java/com/kdn/stack_knowledge/MainActivity.kt @@ -1,5 +1,6 @@ package com.kdn.stack_knowledge +import android.content.Intent import android.os.Bundle import android.util.Log import android.widget.Toast @@ -25,6 +26,7 @@ import com.stackknowledge.login.viewmodel.AuthViewModel import com.kdn.stack_knowledge.ui.StackKnowledgeApp import com.stackknowledge.user.R import dagger.hilt.android.AndroidEntryPoint +import kotlinx.coroutines.runBlocking import remote.request.auth.LoginRequestModel import javax.inject.Inject import javax.inject.Named @@ -72,7 +74,8 @@ class MainActivity : ComponentActivity() { windowSizeClass = calculateWindowSizeClass(this@MainActivity), onLoginButtonClick = { googleSocialLogin() - } + }, + onLogout = { logout() } ) } } @@ -118,4 +121,14 @@ class MainActivity : ComponentActivity() { } } } + + private fun logout() { + runBlocking { + viewModel.deleteToken() + } + finish() + + val intent = Intent(this, MainActivity::class.java) + startActivity(intent) + } } \ No newline at end of file diff --git a/app/src/main/java/com/kdn/stack_knowledge/navigation/StackKnowledgeNavHost.kt b/app/src/main/java/com/kdn/stack_knowledge/navigation/StackKnowledgeNavHost.kt index 85ef2c28..3e25f743 100644 --- a/app/src/main/java/com/kdn/stack_knowledge/navigation/StackKnowledgeNavHost.kt +++ b/app/src/main/java/com/kdn/stack_knowledge/navigation/StackKnowledgeNavHost.kt @@ -37,6 +37,7 @@ fun StackKnowledgeNavHost( startDestination: String = roleCheckRoute, modifier: Modifier = Modifier, onLoginButtonClick: () -> Unit = {}, + onLogout: () -> Unit, ) { val navController = appState.navController @@ -64,6 +65,7 @@ fun StackKnowledgeNavHost( } } else bottomNavigationNavigate(role, navController, navType) }, + logoutSuccess = onLogout ) createMissionScreen( onNavigate = { role, navType -> bottomNavigationNavigate(role, navController, navType) }, diff --git a/app/src/main/java/com/kdn/stack_knowledge/ui/StackKnowledgeApp.kt b/app/src/main/java/com/kdn/stack_knowledge/ui/StackKnowledgeApp.kt index ee988f04..4d83c85a 100644 --- a/app/src/main/java/com/kdn/stack_knowledge/ui/StackKnowledgeApp.kt +++ b/app/src/main/java/com/kdn/stack_knowledge/ui/StackKnowledgeApp.kt @@ -12,11 +12,13 @@ fun StackKnowledgeApp( windowSizeClass = windowSizeClass ), onLoginButtonClick: () -> Unit = {}, + onLogout: () -> Unit, ) { StackKnowledgeAndroidTheme { _, _ -> StackKnowledgeNavHost( appState = appState, - onLoginButtonClick = onLoginButtonClick + onLoginButtonClick = onLoginButtonClick, + onLogout = onLogout ) } } \ No newline at end of file diff --git a/core/data/src/main/kotlin/com/stackknowledge/repository/auth/AuthRepository.kt b/core/data/src/main/kotlin/com/stackknowledge/repository/auth/AuthRepository.kt index 760c3c03..d8b7aa29 100644 --- a/core/data/src/main/kotlin/com/stackknowledge/repository/auth/AuthRepository.kt +++ b/core/data/src/main/kotlin/com/stackknowledge/repository/auth/AuthRepository.kt @@ -11,6 +11,8 @@ interface AuthRepository { suspend fun saveToken(token: LoginResponseModel) + suspend fun deleteToken() + fun getRole(): Flow fun logout(): Flow diff --git a/core/data/src/main/kotlin/com/stackknowledge/repository/auth/AuthRepositoryImpl.kt b/core/data/src/main/kotlin/com/stackknowledge/repository/auth/AuthRepositoryImpl.kt index c83cd5a0..edf856f8 100644 --- a/core/data/src/main/kotlin/com/stackknowledge/repository/auth/AuthRepositoryImpl.kt +++ b/core/data/src/main/kotlin/com/stackknowledge/repository/auth/AuthRepositoryImpl.kt @@ -32,6 +32,13 @@ class AuthRepositoryImpl @Inject constructor( } } + override suspend fun deleteToken() { + localDataSource.removeAccessToken() + localDataSource.removeRefreshToken() + localDataSource.removeAccessTime() + localDataSource.removeRefreshTime() + } + override fun getRole(): Flow { return localDataSource.getAuthorityInfo() } diff --git a/core/network/src/main/kotlin/com/stackknowledge/util/AuthInterceptor.kt b/core/network/src/main/kotlin/com/stackknowledge/util/AuthInterceptor.kt index 0911f817..547a10de 100644 --- a/core/network/src/main/kotlin/com/stackknowledge/util/AuthInterceptor.kt +++ b/core/network/src/main/kotlin/com/stackknowledge/util/AuthInterceptor.kt @@ -45,6 +45,8 @@ class AuthInterceptor @Inject constructor( runBlocking { val refreshTime = dataSource.getRefreshTime().first().replace("\"", "") val accessTime = dataSource.getAccessTime().first().replace("\"", "") + val refreshToken = dataSource.getRefreshToken().first().replace("\"", "") + val accessToken = dataSource.getAccessToken().first().replace("\"", "") if (refreshTime == "") { return@runBlocking @@ -82,9 +84,15 @@ class AuthInterceptor @Inject constructor( } else throw NeedLoginException() } } - val accessToken = dataSource.getAccessToken().first().replace("\"", "") + if (method == "DELETE") { + builder.addHeader("RefreshToken", refreshToken) + } builder.addHeader("Authorization", "Bearer $accessToken") } - return chain.proceed(builder.build()) + val response = chain.proceed(builder.build()) + return when (response.code) { + 204 -> response.newBuilder().code(200).build() + else -> response + } } } diff --git a/feature/login/src/main/java/com/stackknowledge/login/viewmodel/AuthViewModel.kt b/feature/login/src/main/java/com/stackknowledge/login/viewmodel/AuthViewModel.kt index dc86fa6e..275e0350 100644 --- a/feature/login/src/main/java/com/stackknowledge/login/viewmodel/AuthViewModel.kt +++ b/feature/login/src/main/java/com/stackknowledge/login/viewmodel/AuthViewModel.kt @@ -8,6 +8,7 @@ import com.example.common.result.asResult import com.example.common.util.Event import com.example.common.util.errorHandling import com.stackknowledge.login.viewmodel.uistate.LoginUiState +import com.stackknowledge.repository.auth.AuthRepository import com.stackknowledge.usecase.auth.SaveTokenUseCase import com.stackknowledge.usecase.auth.LoginStudentUseCase import com.stackknowledge.usecase.auth.LoginTeacherUseCase @@ -25,6 +26,7 @@ class AuthViewModel @Inject constructor( private val loginStudentUseCase: LoginStudentUseCase, private val loginTeacherUseCase: LoginTeacherUseCase, private val saveTokenUseCase: SaveTokenUseCase, + private val authRepository: AuthRepository, ) : ViewModel() { private val _saveTokenRequest = MutableStateFlow>(Event.Loading) internal val saveTokenRequest = _saveTokenRequest.asStateFlow() @@ -72,4 +74,8 @@ class AuthViewModel @Inject constructor( _saveTokenRequest.value = it.errorHandling() } } + + fun deleteToken() = viewModelScope.launch{ + authRepository.deleteToken() + } } \ No newline at end of file diff --git a/feature/main/src/main/java/com/stackknowledge/main/MainPageScreen.kt b/feature/main/src/main/java/com/stackknowledge/main/MainPageScreen.kt index 90c211d8..32137661 100644 --- a/feature/main/src/main/java/com/stackknowledge/main/MainPageScreen.kt +++ b/feature/main/src/main/java/com/stackknowledge/main/MainPageScreen.kt @@ -1,7 +1,6 @@ package com.stackknowledge.main import androidx.compose.foundation.background -import androidx.compose.foundation.gestures.scrollable import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Spacer @@ -18,9 +17,12 @@ import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.unit.dp import androidx.hilt.navigation.compose.hiltViewModel import androidx.lifecycle.compose.collectAsStateWithLifecycle +import com.example.common.toast.makeToast +import com.example.common.util.Event import com.minstone.ui.navigation.NavigateType import com.minstone.ui.navigation.StackKnowledgeBottomNavigation import com.stackknowledge.design_system.component.dialog.JoinWaitingDialog @@ -39,23 +41,28 @@ import enumdata.Authority @Composable internal fun MainPageRoute( onNavigate: (Authority, String, Int?) -> Unit, + logoutSuccess: () -> Unit, viewModel: MainViewModel = hiltViewModel() ) { val role by viewModel.role.collectAsStateWithLifecycle(initialValue = "") val getMissionUiState by viewModel.getMissionUiState.collectAsStateWithLifecycle() val getRankingUiState by viewModel.getRankingUiState.collectAsStateWithLifecycle() + val logoutRequest by viewModel.logoutRequest.collectAsStateWithLifecycle() MainPageScreen( role = if (role.isNotBlank()) Authority.valueOf(role) else Authority.ROLE_TEACHER, getMissionUiState = getMissionUiState, getRankingUiState = getRankingUiState, + logoutRequest = logoutRequest, onNavigate = { navType, index -> onNavigate(Authority.valueOf(role), navType, index) }, initMain = { with(viewModel) { getMission() getRanking() } - } + }, + logout = viewModel::logout, + onSuccess = logoutSuccess ) } @@ -65,10 +72,14 @@ private fun MainPageScreen( role: Authority, getMissionUiState: GetMissionUiState, getRankingUiState: GetRankingUiState, + logoutRequest: Event, onNavigate: (String, Int?) -> Unit, initMain: () -> Unit, + logout: () -> Unit, + onSuccess: () -> Unit, ) { val scrollState = rememberScrollState() + val context = LocalContext.current var openDialog by remember { mutableStateOf(false) } var openLogoutDialog by remember { mutableStateOf(false) } @@ -122,7 +133,10 @@ private fun MainPageScreen( if (openLogoutDialog) { StackKnowledgeDialog( content = "로그아웃 하시겠습니까?", - onConfirm = { openLogoutDialog = false }, + onConfirm = { + openLogoutDialog = false + logout() + }, onDismiss = { openLogoutDialog = false }, onStateChange = { openLogoutDialog = it }, openDialog = openLogoutDialog, @@ -136,5 +150,15 @@ private fun MainPageScreen( onRefuse = {} ) } + + when (logoutRequest) { + is Event.Loading -> Unit + is Event.Success -> { + onSuccess() + } + else -> { + makeToast(context = context, message = "로그아웃이 실패했습니다.") + } + } } } \ No newline at end of file diff --git a/feature/main/src/main/java/com/stackknowledge/main/navigation/MainNavigation.kt b/feature/main/src/main/java/com/stackknowledge/main/navigation/MainNavigation.kt index 53326e28..d93ed4ac 100644 --- a/feature/main/src/main/java/com/stackknowledge/main/navigation/MainNavigation.kt +++ b/feature/main/src/main/java/com/stackknowledge/main/navigation/MainNavigation.kt @@ -15,10 +15,12 @@ fun NavController.navigateToMain(navOptions: NavOptions? = null) { fun NavGraphBuilder.mainScreen( onNavigate: (Authority, String, Int?) -> Unit, + logoutSuccess: () -> Unit, ) { composable(route = mainPageRoute) { MainPageRoute( onNavigate = onNavigate, + logoutSuccess = logoutSuccess, ) } } \ No newline at end of file diff --git a/feature/main/src/main/java/com/stackknowledge/main/viewModel/MainViewModel.kt b/feature/main/src/main/java/com/stackknowledge/main/viewModel/MainViewModel.kt index 7647409d..77db1559 100644 --- a/feature/main/src/main/java/com/stackknowledge/main/viewModel/MainViewModel.kt +++ b/feature/main/src/main/java/com/stackknowledge/main/viewModel/MainViewModel.kt @@ -5,14 +5,18 @@ import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import com.example.common.result.Result import com.example.common.result.asResult +import com.example.common.util.Event +import com.example.common.util.errorHandling import com.stackknowledge.main.viewModel.uistate.GetMissionUiState import com.stackknowledge.main.viewModel.uistate.GetRankingUiState import com.stackknowledge.repository.auth.AuthRepository +import com.stackknowledge.usecase.auth.LogoutUseCase import com.stackknowledge.usecase.mission.GetMissionUseCase import com.stackknowledge.usecase.student.GetStudentPointRankingUseCase import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.asStateFlow +import kotlinx.coroutines.flow.catch import kotlinx.coroutines.flow.collectLatest import kotlinx.coroutines.launch import javax.inject.Inject @@ -21,6 +25,7 @@ import javax.inject.Inject class MainViewModel @Inject constructor( private val getMissionUseCase: GetMissionUseCase, private val getStudentPointRankingUseCase: GetStudentPointRankingUseCase, + private val logoutUseCase: LogoutUseCase, private val authRepository: AuthRepository ): ViewModel() { private val _getMissionUiState = MutableStateFlow(GetMissionUiState.Loading) @@ -29,6 +34,9 @@ class MainViewModel @Inject constructor( private val _getRankingUiState = MutableStateFlow(GetRankingUiState.Loading) internal val getRankingUiState = _getRankingUiState.asStateFlow() + private val _logoutRequest = MutableStateFlow>(Event.Loading) + internal val logoutRequest = _logoutRequest.asStateFlow() + internal val role = authRepository.getRole() internal fun getMission() = viewModelScope.launch { getMissionUseCase() @@ -53,4 +61,18 @@ class MainViewModel @Inject constructor( } } } + + internal fun logout() = viewModelScope.launch { + logoutUseCase() + .onSuccess { + it.catch { remoteError -> + _logoutRequest.value = remoteError.errorHandling() + }.collect { + _logoutRequest.value = Event.Success() + } + } + .onFailure { + _logoutRequest.value = it.errorHandling() + } + } } \ No newline at end of file From eed880cc0cc7a558df50342d3f9e593cbf9f2ed0 Mon Sep 17 00:00:00 2001 From: yeongun130 Date: Mon, 15 Jul 2024 15:13:07 +0900 Subject: [PATCH 2/5] =?UTF-8?q?:sparkles:=20::=20logout=20=EA=B8=B0?= =?UTF-8?q?=EB=8A=A5=20=EA=B5=AC=ED=98=84=20=EB=B0=8F=20=EA=B8=B0=EB=8A=A5?= =?UTF-8?q?=20=EC=97=B0=EA=B2=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../navigation/StackKnowledgeNavHost.kt | 9 ++++++++- .../repository/auth/AuthRepositoryImpl.kt | 1 + .../stackknowledge/datastore/LocalAuthDataSource.kt | 2 ++ .../datastore/LocalAuthDataSourceImpl.kt | 6 ++++++ core/design-system/src/main/res/values/strings.xml | 2 ++ .../java/com/stackknowledge/main/MainPageScreen.kt | 11 +++++++++-- .../stackknowledge/main/navigation/MainNavigation.kt | 2 ++ 7 files changed, 30 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/com/kdn/stack_knowledge/navigation/StackKnowledgeNavHost.kt b/app/src/main/java/com/kdn/stack_knowledge/navigation/StackKnowledgeNavHost.kt index 3e25f743..e4f7ce5e 100644 --- a/app/src/main/java/com/kdn/stack_knowledge/navigation/StackKnowledgeNavHost.kt +++ b/app/src/main/java/com/kdn/stack_knowledge/navigation/StackKnowledgeNavHost.kt @@ -65,7 +65,14 @@ fun StackKnowledgeNavHost( } } else bottomNavigationNavigate(role, navController, navType) }, - logoutSuccess = onLogout + logoutSuccess = onLogout, + onDeleteBackStack = { + navController.navigate(roleCheckRoute) { + popUpTo(navController.graph.id) { + inclusive = true + } + } + } ) createMissionScreen( onNavigate = { role, navType -> bottomNavigationNavigate(role, navController, navType) }, diff --git a/core/data/src/main/kotlin/com/stackknowledge/repository/auth/AuthRepositoryImpl.kt b/core/data/src/main/kotlin/com/stackknowledge/repository/auth/AuthRepositoryImpl.kt index edf856f8..2aa377b2 100644 --- a/core/data/src/main/kotlin/com/stackknowledge/repository/auth/AuthRepositoryImpl.kt +++ b/core/data/src/main/kotlin/com/stackknowledge/repository/auth/AuthRepositoryImpl.kt @@ -37,6 +37,7 @@ class AuthRepositoryImpl @Inject constructor( localDataSource.removeRefreshToken() localDataSource.removeAccessTime() localDataSource.removeRefreshTime() + localDataSource.removeAuthorityInfo() } override fun getRole(): Flow { diff --git a/core/datastore/src/main/java/com/stackknowledge/datastore/LocalAuthDataSource.kt b/core/datastore/src/main/java/com/stackknowledge/datastore/LocalAuthDataSource.kt index 457a5147..f6f5b016 100644 --- a/core/datastore/src/main/java/com/stackknowledge/datastore/LocalAuthDataSource.kt +++ b/core/datastore/src/main/java/com/stackknowledge/datastore/LocalAuthDataSource.kt @@ -35,4 +35,6 @@ interface LocalAuthDataSource { suspend fun setAuthorityInfo(authority: String) fun getAuthorityInfo(): Flow + + suspend fun removeAuthorityInfo() } \ No newline at end of file diff --git a/core/datastore/src/main/java/com/stackknowledge/datastore/LocalAuthDataSourceImpl.kt b/core/datastore/src/main/java/com/stackknowledge/datastore/LocalAuthDataSourceImpl.kt index 86922801..a63db5f1 100644 --- a/core/datastore/src/main/java/com/stackknowledge/datastore/LocalAuthDataSourceImpl.kt +++ b/core/datastore/src/main/java/com/stackknowledge/datastore/LocalAuthDataSourceImpl.kt @@ -84,4 +84,10 @@ class LocalAuthDataSourceImpl @Inject constructor( it[AuthPreferenceKey.AUTHORITY] = authority } } + + override suspend fun removeAuthorityInfo() { + dataStore.edit { + it.remove(AuthPreferenceKey.AUTHORITY) + } + } } \ No newline at end of file diff --git a/core/design-system/src/main/res/values/strings.xml b/core/design-system/src/main/res/values/strings.xml index 93721909..f50157d6 100644 --- a/core/design-system/src/main/res/values/strings.xml +++ b/core/design-system/src/main/res/values/strings.xml @@ -45,4 +45,6 @@ 문제 채점이 끝나셨습니까? 문제 채점이 완료되었습니다! 상품을 차감하시겠습니까? + 로그아웃이 완료되었습니다. + 로그아웃이 실패했습니다. \ No newline at end of file diff --git a/feature/main/src/main/java/com/stackknowledge/main/MainPageScreen.kt b/feature/main/src/main/java/com/stackknowledge/main/MainPageScreen.kt index 32137661..758bb9ff 100644 --- a/feature/main/src/main/java/com/stackknowledge/main/MainPageScreen.kt +++ b/feature/main/src/main/java/com/stackknowledge/main/MainPageScreen.kt @@ -18,6 +18,7 @@ import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.res.stringResource import androidx.compose.ui.unit.dp import androidx.hilt.navigation.compose.hiltViewModel import androidx.lifecycle.compose.collectAsStateWithLifecycle @@ -37,11 +38,13 @@ import com.stackknowledge.main.viewModel.MainViewModel import com.stackknowledge.main.viewModel.uistate.GetMissionUiState import com.stackknowledge.main.viewModel.uistate.GetRankingUiState import enumdata.Authority +import com.stackknowledge.design_system.R @Composable internal fun MainPageRoute( onNavigate: (Authority, String, Int?) -> Unit, logoutSuccess: () -> Unit, + onDeleteBackStack: () -> Unit, viewModel: MainViewModel = hiltViewModel() ) { val role by viewModel.role.collectAsStateWithLifecycle(initialValue = "") @@ -62,7 +65,8 @@ internal fun MainPageRoute( } }, logout = viewModel::logout, - onSuccess = logoutSuccess + onSuccess = logoutSuccess, + onDeleteBackStack = onDeleteBackStack, ) } @@ -77,6 +81,7 @@ private fun MainPageScreen( initMain: () -> Unit, logout: () -> Unit, onSuccess: () -> Unit, + onDeleteBackStack: () -> Unit ) { val scrollState = rememberScrollState() val context = LocalContext.current @@ -155,9 +160,11 @@ private fun MainPageScreen( is Event.Loading -> Unit is Event.Success -> { onSuccess() + makeToast(context = context, message = stringResource(id = R.string.success_logout)) + onDeleteBackStack() } else -> { - makeToast(context = context, message = "로그아웃이 실패했습니다.") + makeToast(context = context, message = stringResource(id = R.string.failure_logout)) } } } diff --git a/feature/main/src/main/java/com/stackknowledge/main/navigation/MainNavigation.kt b/feature/main/src/main/java/com/stackknowledge/main/navigation/MainNavigation.kt index d93ed4ac..16a84d51 100644 --- a/feature/main/src/main/java/com/stackknowledge/main/navigation/MainNavigation.kt +++ b/feature/main/src/main/java/com/stackknowledge/main/navigation/MainNavigation.kt @@ -16,11 +16,13 @@ fun NavController.navigateToMain(navOptions: NavOptions? = null) { fun NavGraphBuilder.mainScreen( onNavigate: (Authority, String, Int?) -> Unit, logoutSuccess: () -> Unit, + onDeleteBackStack: () -> Unit, ) { composable(route = mainPageRoute) { MainPageRoute( onNavigate = onNavigate, logoutSuccess = logoutSuccess, + onDeleteBackStack = onDeleteBackStack, ) } } \ No newline at end of file From 20068cd966cde96f171e1567850ebd74927ea8e1 Mon Sep 17 00:00:00 2001 From: yeongun130 Date: Mon, 15 Jul 2024 16:05:42 +0900 Subject: [PATCH 3/5] :sparkles: :: Back Button Click -> MainPage --- .../navigation/StackKnowledgeNavHost.kt | 10 +++++++++- .../main/java/com/stackknowledge/login/LoginScreen.kt | 9 +++++++-- .../stackknowledge/login/navigation/LoginNavigation.kt | 4 +++- 3 files changed, 19 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/com/kdn/stack_knowledge/navigation/StackKnowledgeNavHost.kt b/app/src/main/java/com/kdn/stack_knowledge/navigation/StackKnowledgeNavHost.kt index e4f7ce5e..28155593 100644 --- a/app/src/main/java/com/kdn/stack_knowledge/navigation/StackKnowledgeNavHost.kt +++ b/app/src/main/java/com/kdn/stack_knowledge/navigation/StackKnowledgeNavHost.kt @@ -24,6 +24,7 @@ import com.stackknowledge.shop.navigation.shopScreen import com.stackknowledge.shop.navigation.teacherShopRoute import com.stackknowledge.shop.navigation.teacherShopScreen import com.kdn.stack_knowledge.ui.StackKnowledgeAppState +import com.stackknowledge.main.navigation.mainPageRoute import com.stackkowledge.mission.navigation.createMissionScreen import com.stackkowledge.mission.navigation.entireMissionScreen import com.stackkowledge.mission.navigation.navigateToEntireMission @@ -48,7 +49,14 @@ fun StackKnowledgeNavHost( ) { loginScreen( onSuccess = navController::navigateToMain, - onLoginButtonClick = onLoginButtonClick + onLoginButtonClick = onLoginButtonClick, + onDeleteBackStack = { + navController.navigate(mainPageRoute) { + popUpTo(roleCheckRoute) { + inclusive = true + } + } + } ) roleCheckScreen( onRoleButtonClick = navController::navigateToLogin diff --git a/feature/login/src/main/java/com/stackknowledge/login/LoginScreen.kt b/feature/login/src/main/java/com/stackknowledge/login/LoginScreen.kt index 6e18116d..b2627f0f 100644 --- a/feature/login/src/main/java/com/stackknowledge/login/LoginScreen.kt +++ b/feature/login/src/main/java/com/stackknowledge/login/LoginScreen.kt @@ -35,6 +35,7 @@ import com.stackknowledge.login.viewmodel.uistate.LoginUiState internal fun LoginRoute( onSuccess: () -> Unit, onGoogleLoginButtonClicked: () -> Unit, + onDeleteBackStack: () -> Unit, viewModel: AuthViewModel = hiltViewModel(LocalContext.current as ComponentActivity), ) { val loginUiState by viewModel.loginUiState.collectAsStateWithLifecycle() @@ -43,7 +44,8 @@ internal fun LoginRoute( onGoogleLoginButtonClicked = onGoogleLoginButtonClicked, loginUiState = loginUiState, viewModel = viewModel, - onLoginSuccess = onSuccess + onLoginSuccess = onSuccess, + onDeleteBackStack = onDeleteBackStack, ) } @@ -54,6 +56,7 @@ private fun LoginScreen( onGoogleLoginButtonClicked: () -> Unit = {}, loginUiState: LoginUiState, onLoginSuccess: () -> Unit = {}, + onDeleteBackStack: () -> Unit, ) { StackKnowledgeAndroidTheme { colors, typography -> Surface { @@ -108,6 +111,7 @@ private fun LoginScreen( viewModel.saveToken(tokenResponse) onLoginSuccess() + onDeleteBackStack() } is LoginUiState.Error -> { // Login 실패 처리 (임의) @@ -129,6 +133,7 @@ private fun LoginScreen( fun LoginScreenPre() { LoginScreen( onGoogleLoginButtonClicked = {}, - loginUiState = LoginUiState.Loading + loginUiState = LoginUiState.Loading, + onDeleteBackStack = {} ) } \ No newline at end of file diff --git a/feature/login/src/main/java/com/stackknowledge/login/navigation/LoginNavigation.kt b/feature/login/src/main/java/com/stackknowledge/login/navigation/LoginNavigation.kt index 6e1ece0c..18bbf1c8 100644 --- a/feature/login/src/main/java/com/stackknowledge/login/navigation/LoginNavigation.kt +++ b/feature/login/src/main/java/com/stackknowledge/login/navigation/LoginNavigation.kt @@ -17,11 +17,13 @@ fun NavController.navigateToLogin(navOptions: NavOptions? = null) { fun NavGraphBuilder.loginScreen( onSuccess: () -> Unit = {}, onLoginButtonClick: () -> Unit = {}, + onDeleteBackStack: () -> Unit, ) { composable(route = loginRoute) { LoginRoute( onSuccess = onSuccess, - onGoogleLoginButtonClicked = onLoginButtonClick + onGoogleLoginButtonClicked = onLoginButtonClick, + onDeleteBackStack = onDeleteBackStack, ) } } From 5816e3464a261abb11eba376e828b4b29b4b86ef Mon Sep 17 00:00:00 2001 From: yeongun130 Date: Mon, 15 Jul 2024 16:06:05 +0900 Subject: [PATCH 4/5] =?UTF-8?q?:sparkles:=20::=20=EB=A1=9C=EA=B7=B8?= =?UTF-8?q?=EC=95=84=EC=9B=83=20=EC=9D=B4=ED=9B=84=20=ED=99=94=EB=A9=B4?= =?UTF-8?q?=EC=9D=B4=202=EB=B2=88=20=ED=98=B8=EC=B6=9C=20=EB=90=98?= =?UTF-8?q?=EB=8A=94=20=EB=AC=B8=EC=A0=9C=20=ED=95=B4=EA=B2=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../kdn/stack_knowledge/navigation/StackKnowledgeNavHost.kt | 6 ++---- .../src/main/java/com/stackknowledge/main/MainPageScreen.kt | 2 +- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/app/src/main/java/com/kdn/stack_knowledge/navigation/StackKnowledgeNavHost.kt b/app/src/main/java/com/kdn/stack_knowledge/navigation/StackKnowledgeNavHost.kt index 28155593..24d83f80 100644 --- a/app/src/main/java/com/kdn/stack_knowledge/navigation/StackKnowledgeNavHost.kt +++ b/app/src/main/java/com/kdn/stack_knowledge/navigation/StackKnowledgeNavHost.kt @@ -75,10 +75,8 @@ fun StackKnowledgeNavHost( }, logoutSuccess = onLogout, onDeleteBackStack = { - navController.navigate(roleCheckRoute) { - popUpTo(navController.graph.id) { - inclusive = true - } + navController.navigate(mainPageRoute) { + popUpTo(roleCheckRoute) } } ) diff --git a/feature/main/src/main/java/com/stackknowledge/main/MainPageScreen.kt b/feature/main/src/main/java/com/stackknowledge/main/MainPageScreen.kt index 758bb9ff..e24a5371 100644 --- a/feature/main/src/main/java/com/stackknowledge/main/MainPageScreen.kt +++ b/feature/main/src/main/java/com/stackknowledge/main/MainPageScreen.kt @@ -81,7 +81,7 @@ private fun MainPageScreen( initMain: () -> Unit, logout: () -> Unit, onSuccess: () -> Unit, - onDeleteBackStack: () -> Unit + onDeleteBackStack: () -> Unit, ) { val scrollState = rememberScrollState() val context = LocalContext.current From a9639952d562408b87d4a9060ba143713902a555 Mon Sep 17 00:00:00 2001 From: yeongun130 Date: Mon, 15 Jul 2024 16:45:04 +0900 Subject: [PATCH 5/5] :sparkles: :: modify navigate --- .../navigation/StackKnowledgeNavHost.kt | 61 +++++++++++++------ .../navigation/TopLevelDestination.kt | 1 + .../util/BottomNavigationNavigate.kt | 3 +- .../ui/StackKnowledgeAppState.kt | 21 +++++++ .../repository/auth/AuthRepositoryImpl.kt | 24 +++++--- .../com/stackknowledge/login/LoginScreen.kt | 5 -- .../login/navigation/LoginNavigation.kt | 2 - .../com/stackknowledge/main/MainPageScreen.kt | 4 -- .../main/navigation/MainNavigation.kt | 2 - 9 files changed, 80 insertions(+), 43 deletions(-) diff --git a/app/src/main/java/com/kdn/stack_knowledge/navigation/StackKnowledgeNavHost.kt b/app/src/main/java/com/kdn/stack_knowledge/navigation/StackKnowledgeNavHost.kt index 24d83f80..52dc6827 100644 --- a/app/src/main/java/com/kdn/stack_knowledge/navigation/StackKnowledgeNavHost.kt +++ b/app/src/main/java/com/kdn/stack_knowledge/navigation/StackKnowledgeNavHost.kt @@ -48,15 +48,10 @@ fun StackKnowledgeNavHost( modifier = modifier ) { loginScreen( - onSuccess = navController::navigateToMain, + onSuccess = { + appState.navigateToTopLevelDestination(TopLevelDestination.MAIN) + }, onLoginButtonClick = onLoginButtonClick, - onDeleteBackStack = { - navController.navigate(mainPageRoute) { - popUpTo(roleCheckRoute) { - inclusive = true - } - } - } ) roleCheckScreen( onRoleButtonClick = navController::navigateToLogin @@ -73,19 +68,29 @@ fun StackKnowledgeNavHost( } } else bottomNavigationNavigate(role, navController, navType) }, - logoutSuccess = onLogout, - onDeleteBackStack = { - navController.navigate(mainPageRoute) { - popUpTo(roleCheckRoute) - } - } + logoutSuccess = { + onLogout() + appState.navigateToTopLevelDestination(TopLevelDestination.ROLE_CHECK) + }, ) createMissionScreen( - onNavigate = { role, navType -> bottomNavigationNavigate(role, navController, navType) }, + onNavigate = { role, navType -> + bottomNavigationNavigate( + role, + navController, + navType + ) + }, createMissionSuccess = navController::navigateToMain ) entireMissionScreen( - onNavigate = { role, navType -> bottomNavigationNavigate(role, navController, navType) }, + onNavigate = { role, navType -> + bottomNavigationNavigate( + role, + navController, + navType + ) + }, onItemClick = navController::navigateToResolveMission ) rankingScreen( @@ -95,16 +100,34 @@ fun StackKnowledgeNavHost( onNavigate = { role, navType -> bottomNavigationNavigate(role, navController, navType) } ) resolveMissionScreen( - onNavigate = { role, navType -> bottomNavigationNavigate(role, navController, navType) }, + onNavigate = { role, navType -> + bottomNavigationNavigate( + role, + navController, + navType + ) + }, onBackClick = navController::popBackStack, solveMissionSuccess = navController::navigateToMain, ) gradingAnswerScreen( - onNavigate = { role, navType -> bottomNavigationNavigate(role, navController, navType) }, + onNavigate = { role, navType -> + bottomNavigationNavigate( + role, + navController, + navType + ) + }, scoreMissionSuccess = navController::navigateToMain, ) solvedMissionScreen( - onNavigate = { role, navType -> bottomNavigationNavigate(role, navController, navType) }, + onNavigate = { role, navType -> + bottomNavigationNavigate( + role, + navController, + navType + ) + }, onItemClick = navController::navigateToGradingAnswer ) shopScreen( diff --git a/app/src/main/java/com/kdn/stack_knowledge/navigation/TopLevelDestination.kt b/app/src/main/java/com/kdn/stack_knowledge/navigation/TopLevelDestination.kt index 03b87dc0..2bfd5245 100644 --- a/app/src/main/java/com/kdn/stack_knowledge/navigation/TopLevelDestination.kt +++ b/app/src/main/java/com/kdn/stack_knowledge/navigation/TopLevelDestination.kt @@ -2,4 +2,5 @@ package com.kdn.stack_knowledge.navigation enum class TopLevelDestination { ROLE_CHECK, + MAIN } \ No newline at end of file diff --git a/app/src/main/java/com/kdn/stack_knowledge/navigation/util/BottomNavigationNavigate.kt b/app/src/main/java/com/kdn/stack_knowledge/navigation/util/BottomNavigationNavigate.kt index cf47d712..95f6f87d 100644 --- a/app/src/main/java/com/kdn/stack_knowledge/navigation/util/BottomNavigationNavigate.kt +++ b/app/src/main/java/com/kdn/stack_knowledge/navigation/util/BottomNavigationNavigate.kt @@ -4,6 +4,7 @@ import androidx.navigation.NavController import androidx.navigation.NavGraph.Companion.findStartDestination import androidx.navigation.navOptions import com.minstone.ui.navigation.NavigateType +import com.stackknowledge.main.navigation.mainPageRoute import com.stackknowledge.main.navigation.navigateToMain import com.stackknowledge.ranking.navigation.navigateToRanking import com.stackknowledge.ranking.navigation.navigateToTeacherRanking @@ -20,7 +21,7 @@ fun bottomNavigationNavigate( navType: String ) { val topLevelNavOptions = navOptions { - popUpTo(navController.graph.findStartDestination().id) { + popUpTo(mainPageRoute) { inclusive = false } launchSingleTop = true diff --git a/app/src/main/java/com/kdn/stack_knowledge/ui/StackKnowledgeAppState.kt b/app/src/main/java/com/kdn/stack_knowledge/ui/StackKnowledgeAppState.kt index 59fe2488..f115348e 100644 --- a/app/src/main/java/com/kdn/stack_knowledge/ui/StackKnowledgeAppState.kt +++ b/app/src/main/java/com/kdn/stack_knowledge/ui/StackKnowledgeAppState.kt @@ -6,12 +6,18 @@ import androidx.compose.runtime.Composable import androidx.compose.runtime.Stable import androidx.compose.runtime.remember import androidx.compose.runtime.rememberCoroutineScope +import androidx.compose.ui.util.trace import androidx.navigation.NavDestination +import androidx.navigation.NavGraph.Companion.findStartDestination import androidx.navigation.NavHostController import androidx.navigation.compose.currentBackStackEntryAsState import androidx.navigation.compose.rememberNavController +import androidx.navigation.navOptions import com.kdn.stack_knowledge.navigation.TopLevelDestination +import com.stackknowledge.login.navigation.navigateToLogin +import com.stackknowledge.login.navigation.navigateToRoleCheck import com.stackknowledge.login.navigation.roleCheckRoute +import com.stackknowledge.main.navigation.navigateToMain import kotlinx.coroutines.CoroutineScope @Composable @@ -53,4 +59,19 @@ class StackKnowledgeAppState( get() = windowSizeClass.widthSizeClass == WindowWidthSizeClass.Compact val topLevelDestinations: List = TopLevelDestination.values().asList() + + fun navigateToTopLevelDestination(topLevelDestination: TopLevelDestination) { + trace("Navigation: ${topLevelDestination.name}") { + val topLevelNavOptions = navOptions { + popUpTo(navController.graph.findStartDestination().id) { + inclusive = true + } + } + + when (topLevelDestination) { + TopLevelDestination.ROLE_CHECK -> navController.navigateToRoleCheck(topLevelNavOptions) + TopLevelDestination.MAIN -> navController.navigateToMain(topLevelNavOptions) + } + } + } } \ No newline at end of file diff --git a/core/data/src/main/kotlin/com/stackknowledge/repository/auth/AuthRepositoryImpl.kt b/core/data/src/main/kotlin/com/stackknowledge/repository/auth/AuthRepositoryImpl.kt index 2aa377b2..27743e88 100644 --- a/core/data/src/main/kotlin/com/stackknowledge/repository/auth/AuthRepositoryImpl.kt +++ b/core/data/src/main/kotlin/com/stackknowledge/repository/auth/AuthRepositoryImpl.kt @@ -24,20 +24,24 @@ class AuthRepositoryImpl @Inject constructor( override suspend fun saveToken(token: LoginResponseModel) { token.let { - localDataSource.setAccessToken(it.accessToken) - localDataSource.setAccessTime(it.expiredAt) - localDataSource.setRefreshToken(it.refreshToken) - localDataSource.setRefreshTime(it.expiredAt) - localDataSource.setAuthorityInfo(it.authority.toString()) + with(localDataSource) { + setAccessToken(it.accessToken) + setAccessTime(it.expiredAt) + setRefreshToken(it.refreshToken) + setRefreshTime(it.expiredAt) + setAuthorityInfo(it.authority.toString()) + } } } override suspend fun deleteToken() { - localDataSource.removeAccessToken() - localDataSource.removeRefreshToken() - localDataSource.removeAccessTime() - localDataSource.removeRefreshTime() - localDataSource.removeAuthorityInfo() + with(localDataSource) { + removeAccessToken() + removeRefreshToken() + removeAccessTime() + removeRefreshTime() + removeAuthorityInfo() + } } override fun getRole(): Flow { diff --git a/feature/login/src/main/java/com/stackknowledge/login/LoginScreen.kt b/feature/login/src/main/java/com/stackknowledge/login/LoginScreen.kt index b2627f0f..e888a30f 100644 --- a/feature/login/src/main/java/com/stackknowledge/login/LoginScreen.kt +++ b/feature/login/src/main/java/com/stackknowledge/login/LoginScreen.kt @@ -35,7 +35,6 @@ import com.stackknowledge.login.viewmodel.uistate.LoginUiState internal fun LoginRoute( onSuccess: () -> Unit, onGoogleLoginButtonClicked: () -> Unit, - onDeleteBackStack: () -> Unit, viewModel: AuthViewModel = hiltViewModel(LocalContext.current as ComponentActivity), ) { val loginUiState by viewModel.loginUiState.collectAsStateWithLifecycle() @@ -45,7 +44,6 @@ internal fun LoginRoute( loginUiState = loginUiState, viewModel = viewModel, onLoginSuccess = onSuccess, - onDeleteBackStack = onDeleteBackStack, ) } @@ -56,7 +54,6 @@ private fun LoginScreen( onGoogleLoginButtonClicked: () -> Unit = {}, loginUiState: LoginUiState, onLoginSuccess: () -> Unit = {}, - onDeleteBackStack: () -> Unit, ) { StackKnowledgeAndroidTheme { colors, typography -> Surface { @@ -111,7 +108,6 @@ private fun LoginScreen( viewModel.saveToken(tokenResponse) onLoginSuccess() - onDeleteBackStack() } is LoginUiState.Error -> { // Login 실패 처리 (임의) @@ -134,6 +130,5 @@ fun LoginScreenPre() { LoginScreen( onGoogleLoginButtonClicked = {}, loginUiState = LoginUiState.Loading, - onDeleteBackStack = {} ) } \ No newline at end of file diff --git a/feature/login/src/main/java/com/stackknowledge/login/navigation/LoginNavigation.kt b/feature/login/src/main/java/com/stackknowledge/login/navigation/LoginNavigation.kt index 18bbf1c8..a9e35a25 100644 --- a/feature/login/src/main/java/com/stackknowledge/login/navigation/LoginNavigation.kt +++ b/feature/login/src/main/java/com/stackknowledge/login/navigation/LoginNavigation.kt @@ -17,13 +17,11 @@ fun NavController.navigateToLogin(navOptions: NavOptions? = null) { fun NavGraphBuilder.loginScreen( onSuccess: () -> Unit = {}, onLoginButtonClick: () -> Unit = {}, - onDeleteBackStack: () -> Unit, ) { composable(route = loginRoute) { LoginRoute( onSuccess = onSuccess, onGoogleLoginButtonClicked = onLoginButtonClick, - onDeleteBackStack = onDeleteBackStack, ) } } diff --git a/feature/main/src/main/java/com/stackknowledge/main/MainPageScreen.kt b/feature/main/src/main/java/com/stackknowledge/main/MainPageScreen.kt index e24a5371..1d038302 100644 --- a/feature/main/src/main/java/com/stackknowledge/main/MainPageScreen.kt +++ b/feature/main/src/main/java/com/stackknowledge/main/MainPageScreen.kt @@ -44,7 +44,6 @@ import com.stackknowledge.design_system.R internal fun MainPageRoute( onNavigate: (Authority, String, Int?) -> Unit, logoutSuccess: () -> Unit, - onDeleteBackStack: () -> Unit, viewModel: MainViewModel = hiltViewModel() ) { val role by viewModel.role.collectAsStateWithLifecycle(initialValue = "") @@ -66,7 +65,6 @@ internal fun MainPageRoute( }, logout = viewModel::logout, onSuccess = logoutSuccess, - onDeleteBackStack = onDeleteBackStack, ) } @@ -81,7 +79,6 @@ private fun MainPageScreen( initMain: () -> Unit, logout: () -> Unit, onSuccess: () -> Unit, - onDeleteBackStack: () -> Unit, ) { val scrollState = rememberScrollState() val context = LocalContext.current @@ -161,7 +158,6 @@ private fun MainPageScreen( is Event.Success -> { onSuccess() makeToast(context = context, message = stringResource(id = R.string.success_logout)) - onDeleteBackStack() } else -> { makeToast(context = context, message = stringResource(id = R.string.failure_logout)) diff --git a/feature/main/src/main/java/com/stackknowledge/main/navigation/MainNavigation.kt b/feature/main/src/main/java/com/stackknowledge/main/navigation/MainNavigation.kt index 16a84d51..d93ed4ac 100644 --- a/feature/main/src/main/java/com/stackknowledge/main/navigation/MainNavigation.kt +++ b/feature/main/src/main/java/com/stackknowledge/main/navigation/MainNavigation.kt @@ -16,13 +16,11 @@ fun NavController.navigateToMain(navOptions: NavOptions? = null) { fun NavGraphBuilder.mainScreen( onNavigate: (Authority, String, Int?) -> Unit, logoutSuccess: () -> Unit, - onDeleteBackStack: () -> Unit, ) { composable(route = mainPageRoute) { MainPageRoute( onNavigate = onNavigate, logoutSuccess = logoutSuccess, - onDeleteBackStack = onDeleteBackStack, ) } } \ No newline at end of file