diff --git a/presentation/src/main/kotlin/ac/dnd/bookkeeping/android/presentation/ui/main/MainScreen.kt b/presentation/src/main/kotlin/ac/dnd/bookkeeping/android/presentation/ui/main/MainScreen.kt index 9cbaafac..33d8e270 100644 --- a/presentation/src/main/kotlin/ac/dnd/bookkeeping/android/presentation/ui/main/MainScreen.kt +++ b/presentation/src/main/kotlin/ac/dnd/bookkeeping/android/presentation/ui/main/MainScreen.kt @@ -6,11 +6,7 @@ import ac.dnd.bookkeeping.android.presentation.ui.main.home.homeDestination import ac.dnd.bookkeeping.android.presentation.ui.main.login.loginNavGraph import ac.dnd.bookkeeping.android.presentation.ui.main.splash.SplashConstant import ac.dnd.bookkeeping.android.presentation.ui.main.splash.splashDestination -import androidx.compose.foundation.layout.fillMaxSize -import androidx.compose.material.MaterialTheme -import androidx.compose.material.Surface import androidx.compose.runtime.Composable -import androidx.compose.ui.Modifier import androidx.compose.ui.tooling.preview.Preview import androidx.hilt.navigation.compose.hiltViewModel import androidx.navigation.compose.NavHost @@ -20,24 +16,19 @@ fun MainScreen( viewModel: MainViewModel = hiltViewModel() ) { BookkeepingTheme { - Surface( - modifier = Modifier.fillMaxSize(), - color = MaterialTheme.colors.background - ) { - val appState = rememberApplicationState() - ManageSystemUiState(appState = appState) + val appState = rememberApplicationState() + ManageSystemUiState(appState = appState) - NavHost( - navController = appState.navController, - startDestination = makeRoute( - SplashConstant.ROUTE, - listOf(SplashConstant.ROUTE_ARGUMENT_ENTRY_POINT_MAIN to SplashConstant.ROUTE_ARGUMENT_ENTRY_POINT_MAIN) - ) - ) { - loginNavGraph(appState = appState) - homeDestination(appState = appState) - splashDestination(appState = appState) - } + NavHost( + navController = appState.navController, + startDestination = makeRoute( + SplashConstant.ROUTE, + listOf(SplashConstant.ROUTE_ARGUMENT_ENTRY_POINT_MAIN to SplashConstant.ROUTE_ARGUMENT_ENTRY_POINT_MAIN) + ) + ) { + loginNavGraph(appState = appState) + homeDestination(appState = appState) + splashDestination(appState = appState) } } } diff --git a/presentation/src/main/kotlin/ac/dnd/bookkeeping/android/presentation/ui/main/login/LoginConstant.kt b/presentation/src/main/kotlin/ac/dnd/bookkeeping/android/presentation/ui/main/login/LoginConstant.kt index 844d9387..53f2e0d6 100644 --- a/presentation/src/main/kotlin/ac/dnd/bookkeeping/android/presentation/ui/main/login/LoginConstant.kt +++ b/presentation/src/main/kotlin/ac/dnd/bookkeeping/android/presentation/ui/main/login/LoginConstant.kt @@ -2,7 +2,4 @@ package ac.dnd.bookkeeping.android.presentation.ui.main.login object LoginConstant { const val ROUTE = "/login" - - const val ROUTE_STEP_1 = "$ROUTE/step1" - const val ROUTE_STEP_2 = "$ROUTE/step2" } diff --git a/presentation/src/main/kotlin/ac/dnd/bookkeeping/android/presentation/ui/main/login/LoginNavGraph.kt b/presentation/src/main/kotlin/ac/dnd/bookkeeping/android/presentation/ui/main/login/LoginNavGraph.kt index ef0161e3..b87d7f2e 100644 --- a/presentation/src/main/kotlin/ac/dnd/bookkeeping/android/presentation/ui/main/login/LoginNavGraph.kt +++ b/presentation/src/main/kotlin/ac/dnd/bookkeeping/android/presentation/ui/main/login/LoginNavGraph.kt @@ -1,39 +1,18 @@ package ac.dnd.bookkeeping.android.presentation.ui.main.login import ac.dnd.bookkeeping.android.presentation.ui.main.ApplicationState -import androidx.compose.runtime.remember -import androidx.hilt.navigation.compose.hiltViewModel +import ac.dnd.bookkeeping.android.presentation.ui.main.login.main.LoginMainConstant +import ac.dnd.bookkeeping.android.presentation.ui.main.login.main.loginMainDestination import androidx.navigation.NavGraphBuilder -import androidx.navigation.compose.composable import androidx.navigation.navigation fun NavGraphBuilder.loginNavGraph( appState: ApplicationState ) { navigation( - startDestination = LoginConstant.ROUTE_STEP_1, + startDestination = LoginMainConstant.ROUTE, route = LoginConstant.ROUTE ) { - // TODO : 분리 - composable( - route = LoginConstant.ROUTE_STEP_1 - ) { - val backStackEntry = remember(it) { - appState.navController.getBackStackEntry(LoginConstant.ROUTE_STEP_1) - } - val loginViewModel: LoginViewModel = hiltViewModel(backStackEntry) - LoginScreen(appState = appState, viewModel = loginViewModel) - } - - // TODO : 분리 - composable( - route = LoginConstant.ROUTE_STEP_2 - ) { - val backStackEntry = remember(it) { - appState.navController.getBackStackEntry(LoginConstant.ROUTE) - } - val loginViewModel: LoginViewModel = hiltViewModel(backStackEntry) - OnBoardScreen(appState = appState, viewModel = loginViewModel) - } + loginMainDestination(appState = appState) } } diff --git a/presentation/src/main/kotlin/ac/dnd/bookkeeping/android/presentation/ui/main/login/OnBoardScreen.kt b/presentation/src/main/kotlin/ac/dnd/bookkeeping/android/presentation/ui/main/login/OnBoardScreen.kt deleted file mode 100644 index 225bc9c2..00000000 --- a/presentation/src/main/kotlin/ac/dnd/bookkeeping/android/presentation/ui/main/login/OnBoardScreen.kt +++ /dev/null @@ -1,72 +0,0 @@ -package ac.dnd.bookkeeping.android.presentation.ui.main.login - -import ac.dnd.bookkeeping.android.presentation.ui.main.ApplicationState -import ac.dnd.bookkeeping.android.presentation.ui.main.home.HomeConstant -import androidx.compose.foundation.background -import androidx.compose.foundation.clickable -import androidx.compose.foundation.layout.Box -import androidx.compose.foundation.layout.fillMaxSize -import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.shape.RoundedCornerShape -import androidx.compose.material.Surface -import androidx.compose.material.Text -import androidx.compose.runtime.Composable -import androidx.compose.runtime.mutableStateOf -import androidx.compose.runtime.remember -import androidx.compose.ui.Alignment -import androidx.compose.ui.Modifier -import androidx.compose.ui.graphics.Color -import androidx.compose.ui.text.style.TextAlign -import androidx.compose.ui.unit.dp -import androidx.compose.ui.unit.sp -import androidx.hilt.navigation.compose.hiltViewModel - -@Composable -fun OnBoardScreen( - appState: ApplicationState, - viewModel: LoginViewModel = hiltViewModel() -) { - val nextStageState = remember { mutableStateOf(false) } - if (nextStageState.value) { - appState.navController.navigate(HomeConstant.ROUTE) { - popUpTo(LoginConstant.ROUTE_STEP_2) { - inclusive = true - } - } - nextStageState.value = false - } - - Box( - modifier = Modifier - .fillMaxSize() - .background(color = Color.Black), - ) { - Text( - text = "OnBoard Screen", - fontSize = 20.sp, - color = Color.White, - modifier = Modifier.align(Alignment.Center) - ) - - Surface( - modifier = Modifier - .align(Alignment.BottomCenter) - .padding(30.dp) - .fillMaxWidth() - .clickable { - nextStageState.value = true - }, - shape = RoundedCornerShape(10.dp), - color = Color.White - ) { - Text( - text = "next", - fontSize = 20.sp, - color = Color.Black, - textAlign = TextAlign.Center, - modifier = Modifier.padding(5.dp) - ) - } - } -} diff --git a/presentation/src/main/kotlin/ac/dnd/bookkeeping/android/presentation/ui/main/login/main/LoginMainConstant.kt b/presentation/src/main/kotlin/ac/dnd/bookkeeping/android/presentation/ui/main/login/main/LoginMainConstant.kt new file mode 100644 index 00000000..0ce3f8ba --- /dev/null +++ b/presentation/src/main/kotlin/ac/dnd/bookkeeping/android/presentation/ui/main/login/main/LoginMainConstant.kt @@ -0,0 +1,7 @@ +package ac.dnd.bookkeeping.android.presentation.ui.main.login.main + +import ac.dnd.bookkeeping.android.presentation.ui.main.login.LoginConstant + +object LoginMainConstant { + const val ROUTE: String = "${LoginConstant.ROUTE}/main" +} diff --git a/presentation/src/main/kotlin/ac/dnd/bookkeeping/android/presentation/ui/main/login/main/LoginMainDestination.kt b/presentation/src/main/kotlin/ac/dnd/bookkeeping/android/presentation/ui/main/login/main/LoginMainDestination.kt new file mode 100644 index 00000000..534d3e06 --- /dev/null +++ b/presentation/src/main/kotlin/ac/dnd/bookkeeping/android/presentation/ui/main/login/main/LoginMainDestination.kt @@ -0,0 +1,17 @@ +package ac.dnd.bookkeeping.android.presentation.ui.main.login.main + +import ac.dnd.bookkeeping.android.presentation.ui.main.ApplicationState +import androidx.navigation.NavGraphBuilder +import androidx.navigation.compose.composable + +fun NavGraphBuilder.loginMainDestination( + appState: ApplicationState +) { + composable( + route = LoginMainConstant.ROUTE + ) { + LoginMainScreen( + appState = appState + ) + } +} diff --git a/presentation/src/main/kotlin/ac/dnd/bookkeeping/android/presentation/ui/main/login/main/LoginMainEvent.kt b/presentation/src/main/kotlin/ac/dnd/bookkeeping/android/presentation/ui/main/login/main/LoginMainEvent.kt new file mode 100644 index 00000000..f6f947e0 --- /dev/null +++ b/presentation/src/main/kotlin/ac/dnd/bookkeeping/android/presentation/ui/main/login/main/LoginMainEvent.kt @@ -0,0 +1,11 @@ +package ac.dnd.bookkeeping.android.presentation.ui.main.login.main + +import ac.dnd.bookkeeping.android.domain.model.error.ServerException + +sealed interface LoginMainEvent { + sealed interface Login : LoginMainEvent { + data object Success : Login + data class Failure(val exception: ServerException) : Login + data class Error(val exception: Throwable) : Login + } +} diff --git a/presentation/src/main/kotlin/ac/dnd/bookkeeping/android/presentation/ui/main/login/LoginScreen.kt b/presentation/src/main/kotlin/ac/dnd/bookkeeping/android/presentation/ui/main/login/main/LoginMainScreen.kt similarity index 52% rename from presentation/src/main/kotlin/ac/dnd/bookkeeping/android/presentation/ui/main/login/LoginScreen.kt rename to presentation/src/main/kotlin/ac/dnd/bookkeeping/android/presentation/ui/main/login/main/LoginMainScreen.kt index 6498de6a..f6cbc95a 100644 --- a/presentation/src/main/kotlin/ac/dnd/bookkeeping/android/presentation/ui/main/login/LoginScreen.kt +++ b/presentation/src/main/kotlin/ac/dnd/bookkeeping/android/presentation/ui/main/login/main/LoginMainScreen.kt @@ -1,7 +1,11 @@ -package ac.dnd.bookkeeping.android.presentation.ui.main.login +package ac.dnd.bookkeeping.android.presentation.ui.main.login.main import ac.dnd.bookkeeping.android.presentation.common.util.ErrorObserver +import ac.dnd.bookkeeping.android.presentation.common.util.LaunchedEffectWithLifecycle +import ac.dnd.bookkeeping.android.presentation.common.util.coroutine.event.eventObserve import ac.dnd.bookkeeping.android.presentation.ui.main.ApplicationState +import ac.dnd.bookkeeping.android.presentation.ui.main.home.HomeConstant +import ac.dnd.bookkeeping.android.presentation.ui.main.login.LoginConstant import androidx.compose.foundation.background import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Box @@ -12,8 +16,7 @@ import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material.Surface import androidx.compose.material.Text import androidx.compose.runtime.Composable -import androidx.compose.runtime.mutableStateOf -import androidx.compose.runtime.remember +import androidx.compose.runtime.getValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color @@ -21,22 +24,37 @@ import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import androidx.hilt.navigation.compose.hiltViewModel +import androidx.lifecycle.compose.collectAsStateWithLifecycle @Composable -fun LoginScreen( +fun LoginMainScreen( appState: ApplicationState, - viewModel: LoginViewModel = hiltViewModel() + viewModel: LoginMainViewModel = hiltViewModel() ) { - Observer( appState = appState, viewModel = viewModel ) - val nextStageState = remember { mutableStateOf(false) } - if (nextStageState.value) { - appState.navController.navigate(LoginConstant.ROUTE_STEP_2) - nextStageState.value = false + Screen( + appState = appState, + viewModel = viewModel + ) +} + +@Composable +private fun Screen( + appState: ApplicationState, + viewModel: LoginMainViewModel +) { + val state by viewModel.state.collectAsStateWithLifecycle() + + fun navigateToLogin() { + appState.navController.navigate(HomeConstant.ROUTE) { + popUpTo(LoginConstant.ROUTE) { + inclusive = true + } + } } Box( @@ -45,7 +63,7 @@ fun LoginScreen( .background(color = Color.Black), ) { Text( - text = "Login Screen", + text = "OnBoard Screen", fontSize = 20.sp, color = Color.White, modifier = Modifier.align(Alignment.Center) @@ -57,7 +75,7 @@ fun LoginScreen( .padding(30.dp) .fillMaxWidth() .clickable { - nextStageState.value = true + navigateToLogin() }, shape = RoundedCornerShape(10.dp), color = Color.White @@ -76,7 +94,31 @@ fun LoginScreen( @Composable private fun Observer( appState: ApplicationState, - viewModel: LoginViewModel + viewModel: LoginMainViewModel ) { ErrorObserver(viewModel) + + fun login(event: LoginMainEvent.Login) { + when (event) { + LoginMainEvent.Login.Success -> { + // TODO : Implement Success Case + } + + is LoginMainEvent.Login.Error -> { + // TODO : Implement Request Error Case + } + + is LoginMainEvent.Login.Failure -> { + // TODO : Implement Internal Server Error Case + } + } + } + + LaunchedEffectWithLifecycle(viewModel.event, viewModel.handler) { + viewModel.event.eventObserve { event -> + when (event) { + is LoginMainEvent.Login -> login(event) + } + } + } } diff --git a/presentation/src/main/kotlin/ac/dnd/bookkeeping/android/presentation/ui/main/login/main/LoginMainState.kt b/presentation/src/main/kotlin/ac/dnd/bookkeeping/android/presentation/ui/main/login/main/LoginMainState.kt new file mode 100644 index 00000000..f1c446f1 --- /dev/null +++ b/presentation/src/main/kotlin/ac/dnd/bookkeeping/android/presentation/ui/main/login/main/LoginMainState.kt @@ -0,0 +1,5 @@ +package ac.dnd.bookkeeping.android.presentation.ui.main.login.main + +sealed interface LoginMainState { + data object Init : LoginMainState +} diff --git a/presentation/src/main/kotlin/ac/dnd/bookkeeping/android/presentation/ui/main/login/main/LoginMainViewModel.kt b/presentation/src/main/kotlin/ac/dnd/bookkeeping/android/presentation/ui/main/login/main/LoginMainViewModel.kt new file mode 100644 index 00000000..393692ac --- /dev/null +++ b/presentation/src/main/kotlin/ac/dnd/bookkeeping/android/presentation/ui/main/login/main/LoginMainViewModel.kt @@ -0,0 +1,24 @@ +package ac.dnd.bookkeeping.android.presentation.ui.main.login.main + +import ac.dnd.bookkeeping.android.presentation.common.base.BaseViewModel +import ac.dnd.bookkeeping.android.presentation.common.util.coroutine.event.EventFlow +import ac.dnd.bookkeeping.android.presentation.common.util.coroutine.event.MutableEventFlow +import ac.dnd.bookkeeping.android.presentation.common.util.coroutine.event.asEventFlow +import androidx.lifecycle.SavedStateHandle +import dagger.hilt.android.lifecycle.HiltViewModel +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.asStateFlow +import javax.inject.Inject + +@HiltViewModel +class LoginMainViewModel @Inject constructor( + private val savedStateHandle: SavedStateHandle, +) : BaseViewModel() { + + private val _state: MutableStateFlow = MutableStateFlow(LoginMainState.Init) + val state: StateFlow = _state.asStateFlow() + + private val _event: MutableEventFlow = MutableEventFlow() + val event: EventFlow = _event.asEventFlow() +}