BIT-144: Setup root level app navigation (#8)

This commit is contained in:
Andrew Haisting
2023-08-25 08:54:18 -05:00
committed by Álison Fernandes
parent cd204b9b11
commit 116d48d8ac
9 changed files with 266 additions and 20 deletions

View File

@@ -3,13 +3,7 @@ package com.x8bit.bitwarden
import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import com.x8bit.bitwarden.ui.theme.BitwardenTheme
import com.x8bit.bitwarden.ui.feature.rootnav.RootNavScreen
import dagger.hilt.android.AndroidEntryPoint
/**
@@ -19,17 +13,6 @@ import dagger.hilt.android.AndroidEntryPoint
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
BitwardenTheme {
Surface(
modifier = Modifier.fillMaxSize(),
color = MaterialTheme.colorScheme.background,
) {
Text(
text = stringResource(id = R.string.app_name),
)
}
}
}
setContent { RootNavScreen() }
}
}

View File

@@ -0,0 +1,27 @@
package com.x8bit.bitwarden.ui.components
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
/**
* Temporary composable that can be used as a navigation placeholder.
*/
@Composable
fun PlaceholderComposable(
text: String = "Placeholder Composable"
) {
Box(
modifier = Modifier
.fillMaxSize()
.background(Color.White),
contentAlignment = Alignment.Center,
) {
Text(text = text)
}
}

View File

@@ -0,0 +1,110 @@
package com.x8bit.bitwarden.ui.feature.rootnav
import androidx.compose.animation.EnterTransition
import androidx.compose.animation.ExitTransition
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import androidx.lifecycle.viewmodel.compose.viewModel
import androidx.navigation.NavController
import androidx.navigation.NavGraphBuilder
import androidx.navigation.compose.NavHost
import androidx.navigation.compose.composable
import androidx.navigation.compose.rememberNavController
import com.x8bit.bitwarden.ui.components.PlaceholderComposable
/**
* Controls root level [NavHost] for the app.
*/
@Composable
fun RootNavScreen(
viewModel: RootNavViewModel = viewModel()
) {
val navController = rememberNavController()
val state by viewModel.state.collectAsStateWithLifecycle()
NavHost(
navController = navController,
startDestination = SplashRoute,
enterTransition = { EnterTransition.None },
exitTransition = { ExitTransition.None },
) {
splashDestinations()
loginDestinations()
}
// When state changes, navigate to different root navigation state
when (state) {
RootNavState.Login -> navController.navigateToLoginAsRoot()
RootNavState.Splash -> navController.navigateToSplashAsRoot()
}
}
/**
* The functions below should be moved to their respective feature packages once they exist.
*
* For an example of how to setup these nav extensions, see NIA project.
*/
/**
* TODO: move to splash package (BIT-147)
*/
private const val SplashRoute = "splash"
/**
* Add splash destinations to the nav graph.
*
* TODO: move to splash package (BIT-147)
*/
private fun NavGraphBuilder.splashDestinations() {
composable(SplashRoute) {
PlaceholderComposable(text = "Splash")
}
}
/**
* Navigate to the splash screen. Note this will only work if splash destination was added
* via [splashDestinations].
*
* TODO: move to splash package (BIT-147)
*
*/
private fun NavController.navigateToSplashAsRoot() {
navigate(SplashRoute) {
// When changing root navigation state, pop everything else off the back stack:
popUpTo(graph.id) {
inclusive = true
}
}
}
/**
* TODO move to login package(BIT-146)
*/
private val LoginRoute = "login"
/**
* Add login destinations to the nav graph.
*
* TODO: move to login package (BIT-146)
*/
private fun NavGraphBuilder.loginDestinations() {
composable(LoginRoute) {
PlaceholderComposable(text = "Login")
}
}
/**
* Navigate to the splash screen. Note this will only work if login destination was added
* via [loginDestinations].
*
* TODO: move to login package (BIT-146)
*/
private fun NavController.navigateToLoginAsRoot() {
navigate(LoginRoute) {
// When changing root navigation state, pop everything else off the back stack:
popUpTo(graph.id) {
inclusive = true
}
}
}

View File

@@ -0,0 +1,44 @@
package com.x8bit.bitwarden.ui.feature.rootnav
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.launch
import javax.inject.Inject
/**
* Manages root level navigation state of the application.
*/
@HiltViewModel
class RootNavViewModel @Inject constructor() : ViewModel() {
private val _state = MutableStateFlow<RootNavState>(RootNavState.Splash)
val state: StateFlow<RootNavState> = _state.asStateFlow()
init {
viewModelScope.launch {
delay(1000)
_state.value = RootNavState.Login
}
}
}
/**
* Models state of the root level navigation of the app.
*/
sealed class RootNavState {
/**
* Show the login screen.
*/
data object Login : RootNavState()
/**
* Show the splash screen.
*/
data object Splash : RootNavState()
}