How to pass Arguments between Nested Navigation Graph Jet Compose - android

I want to pass {id} from ListScreen to DetailScreen. In ListScreen, when a click event is occured, I start navigate to DetailScreen like this.
navController.navigate(
route = AppDestination.UserProfile.passId(
friendId = it.friendId
)
)
In DetailScreen, I get that friendId through constructor like this.
#Composable
fun UserProfileScreen(
navController: NavController,
friendId: Long,
) {
UserProfileView(
navController = navController,
friendId = friendId
)
}
In my app, I just manage navigation flow with 3 graphs. Like RootGraph, AuthGraph and HomeGraph. Following is the navigation codes.
object Routes {
const val AUTH_ROUTE = "auth"
const val HOME_ROUTE = "home"
const val ROOT_ROUTE = "root"
}
object ArgsConstants{
const val USER_PROFILE_KEY = "id"
}
sealed class AppDestination(val route: String) {
//user
object UserProfile : AppDestination(route = "user_profile_screen/{${ArgsConstants.USER_PROFILE_KEY}}"){
fun passId(friendId : Long): String{
return this.route.replace(
oldValue = "{${ArgsConstants.USER_PROFILE_KEY}}",
newValue = friendId.toString()
)
}
}
}
This is my RootGraph.
#Composable
fun RootNavGraph(
navController: NavHostController
) {
NavHost(
navController = navController,
startDestination = AppDestination.Branding.route,
route = Routes.ROOT_ROUTE
) {
composable(route = AppDestination.Branding.route) {
BrandingScreen(navController = navController)
}
authNavGraph(navController = navController)
homeNavGraph(navController = navController)
}
}
This is my AuthGraph.
fun NavGraphBuilder.authNavGraph(
navController: NavHostController
) {
navigation(
startDestination = AppDestination.Language.route,
route = Routes.AUTH_ROUTE
) {
composable(route = AppDestination.Language.route) {
val parentEntry = remember {
navController.getBackStackEntry(Routes.AUTH_ROUTE)
}
val authViewModel = hiltViewModel<AuthViewModel>(parentEntry)
LanguageScreen(navController = navController, vm = authViewModel)
}
composable(route = AppDestination.Login.route) {
val parentEntry = remember {
navController.getBackStackEntry(Routes.AUTH_ROUTE)
}
val authViewModel = hiltViewModel<AuthViewModel>(parentEntry)
LoginScreen(navController = navController, vm = authViewModel)
}
composable(route = AppDestination.Signup.route) {
val parentEntry = remember {
navController.getBackStackEntry(Routes.AUTH_ROUTE)
}
val authViewModel = hiltViewModel<AuthViewModel>(parentEntry)
SignupScreen(navController = navController, vm = authViewModel)
}
composable(route = AppDestination.VerifiedAccount.route) {
val parentEntry = remember {
navController.getBackStackEntry(Routes.AUTH_ROUTE)
}
val authViewModel = hiltViewModel<AuthViewModel>(parentEntry)
VerifiedAccountScreen(navController = navController, vm = authViewModel)
}
composable(route = AppDestination.NoAccount.route) {
val parentEntry = remember {
navController.getBackStackEntry(Routes.AUTH_ROUTE)
}
val authViewModel = hiltViewModel<AuthViewModel>(parentEntry)
NoAccountScreen(navController = navController, vm = authViewModel)
}
composable(route = AppDestination.VerifiedMethod.route) {
val parentEntry = remember {
navController.getBackStackEntry(Routes.AUTH_ROUTE)
}
val authViewModel = hiltViewModel<AuthViewModel>(parentEntry)
VerifiedMethodScreen(navController = navController, vm = authViewModel)
}
composable(route = AppDestination.VerifiedOtp.route) {
val parentEntry = remember {
navController.getBackStackEntry(Routes.AUTH_ROUTE)
}
val authViewModel = hiltViewModel<AuthViewModel>(parentEntry)
VerifiedOtpScreen(navController = navController, vm = authViewModel)
}
composable(route = AppDestination.VerifiedQuestion.route) {
val parentEntry = remember {
navController.getBackStackEntry(Routes.AUTH_ROUTE)
}
val authViewModel = hiltViewModel<AuthViewModel>(parentEntry)
VerifiedQuestionScreen(navController = navController, vm = authViewModel)
}
composable(route = AppDestination.TwoFactor.route) {
val parentEntry = remember {
navController.getBackStackEntry(Routes.AUTH_ROUTE)
}
val authViewModel = hiltViewModel<AuthViewModel>(parentEntry)
TwoFactorScreen(navController = navController, vm = authViewModel)
}
composable(route = AppDestination.PasswordReset.route) {
val parentEntry = remember {
navController.getBackStackEntry(Routes.AUTH_ROUTE)
}
val authViewModel = hiltViewModel<AuthViewModel>(parentEntry)
PasswordResetScreen(navController = navController, vm = authViewModel)
}
composable(route = AppDestination.SuccessReset.route) {
val parentEntry = remember {
navController.getBackStackEntry(Routes.AUTH_ROUTE)
}
val authViewModel = hiltViewModel<AuthViewModel>(parentEntry)
SuccessResetScreen(navController = navController, vm = authViewModel)
}
}
}
This is my HomeGraph.
fun NavGraphBuilder.homeNavGraph(
navController: NavHostController
) {
navigation(
startDestination = AppDestination.Home.route,
route = Routes.HOME_ROUTE
) {
//user
composable(route = AppDestination.UserProfile.route + "/{${ArgsConstants.USER_PROFILE_KEY}}",
arguments = listOf(
navArgument(
name = ArgsConstants.USER_PROFILE_KEY,
) {
type = NavType.LongType
}
)) {
Timber.tag("ahahah").d(it.arguments?.getLong(ArgsConstants.USER_PROFILE_KEY).toString())
UserProfileScreen(
navController = navController,
friendId = it.arguments?.getLong(ArgsConstants.USER_PROFILE_KEY) ?: -1L
)
}
}
}
This is my error when navigate route is launch.
java.lang.IllegalArgumentException: Navigation destination that matches request NavDeepLinkRequest{ uri=android-app://androidx.navigation/user_profile_screen/1084 } cannot be found in the navigation graph NavGraph(0x78dcd1ef) route=root startDestination={Destination(0xf2da2703) route=branding_screen}
I have implemented navigation arguments in other projects but in this project, I manage 3 graphs. I think my failure is because of this. I tried other ways like shared with saveStateHandle in ViewModel. and also fail. Please help me. I stuck in this a week.

Related

how to Update my UI using android jetpack compose and retrofit with a new request data from retrofit

I have created an app using kotlin and android jetpack compose and dependency injection for creating my
retrofit and room datebase the problem is that I'm getting some data using retrofit from internet and showing them in my ui but when I want to send a request for the second time I get the information but
I don't know how to put them insted of existing list that I have .
It's like a movie app that I want to go to next page or load more data when the list ends
interface AppGameApi {
#GET("farsroid")
suspend fun getAppGameFromPage(
#Query("token") token: String = Constants.TOKEN,
#Query("action") action: String,
#Query("page") page: String
): AppGame
#GET("farsroid")
suspend fun getAppGameFromSearch(
#Query("token") token: String = Constants.TOKEN,
#Query("action") action: String = "search",
#Query("q") q: String = ""
): AppGame
#GET("farsroid")
suspend fun getAppGameFromDownload(
#Query("token") token: String = Constants.TOKEN,
#Query("action") action: String = "download",
#Query("link") link: String = ""
): AppGameDownload
}
class AppGameRetrofitRepository #Inject constructor(private val api: AppGameApi) {
private val appGames = DataOrException<AppGame,Boolean,Exception>()
private val appGamesSearch = DataOrException<AppGame,Boolean,Exception>()
private val appGamesDownload = DataOrException<AppGameDownload,Boolean,Exception>()
suspend fun getAllAppGames(page:String,action:String):DataOrException<AppGame,Boolean,java.lang.Exception>{
try {
appGames.isLoading = true
appGames.data = api.getAppGameFromPage(page = page, action = action)
if (appGames.data!!.status == 200) appGames.isLoading = false
Log.d("Mr", "getAllAppGames: ${appGames.data!!.result[0]}")
}catch (exception:Exception){
appGames.e = exception
}
return appGames
}
suspend fun getAllAppGamesSearch(q:String):DataOrException<AppGame,Boolean,java.lang.Exception>{
try {
appGamesSearch.isLoading = true
appGamesSearch.data = api.getAppGameFromSearch(q = q)
if (appGamesSearch.data!!.status == 200) appGamesSearch.isLoading = false
}catch (exception:Exception){
appGamesSearch.e = exception
Log.d("Error", "getAllAppGames: ${appGamesSearch.e!!.localizedMessage} ")
}
return appGamesSearch
}
suspend fun getAllAppGamesDownload(link:String):DataOrException<AppGameDownload,Boolean,java.lang.Exception>{
try {
appGamesDownload.isLoading = true
appGamesDownload.data = api.getAppGameFromDownload(link = link)
if (appGamesDownload.data!!.status == 200) appGamesDownload.isLoading = false
}catch (exception:Exception){
appGamesDownload.e = exception
Log.d("Error", "getAllAppGames: ${appGamesDownload.e!!.localizedMessage} ")
}
return appGamesDownload
}
}
#HiltViewModel
class AppGameRetrofitViewModel #Inject constructor(private val repository: AppGameRetrofitRepository) :
ViewModel() {
var appGame: MutableState<DataOrException<AppGame, Boolean, Exception>> =
mutableStateOf(DataOrException(null, true, Exception("")))
private val appGameSearch: MutableState<DataOrException<AppGame, Boolean, Exception>> =
mutableStateOf(DataOrException(null, true, Exception("")))
private val appGameDownload: MutableState<DataOrException<AppGameDownload, Boolean, Exception>> =
mutableStateOf(DataOrException(null, true, Exception("")))
init {
getAllAppGames("1","app")
}
fun getAllAppGames(
page: String,
action: String
): DataOrException<AppGame, Boolean, Exception> {
viewModelScope.launch {
appGame.value.isLoading = true
appGame.value = repository.getAllAppGames(page = page, action = action)
if (appGame.value.data!!.status == 200) appGame.value.isLoading = false
}
return appGame.value
}
private fun getAllAppGamesSearch(q: String = "") {
viewModelScope.launch {
appGameSearch.value.isLoading = true
appGameSearch.value = repository.getAllAppGamesSearch(q = q)
if (appGameSearch.value.data!!.status == 200) appGameSearch.value.isLoading = false
}
}
private fun getAllAppGamesDownload(link: String = "") {
viewModelScope.launch {
appGameDownload.value.isLoading = true
appGameDownload.value = repository.getAllAppGamesDownload(link = link)
if (appGameDownload.value.data!!.status == 200) appGameDownload.value.isLoading = false
}
}
}
I have tried these and my mainActivity looks like this
#AndroidEntryPoint
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
Android_Complete_TemplateTheme {
val appGameViewModelRoomDatabase by viewModels<RoomDatabaseViewModel>()
val appGameViewModelRetrofit by viewModels<AppGameRetrofitViewModel>()
val navController = rememberNavController()
val pageCounter = remember {
mutableStateOf("1")
}
val pageAction = remember {
mutableStateOf("game")
}
FarsroidNavigationSystem(
roomDatabaseViewModel = appGameViewModelRoomDatabase,
appGameRetrofitViewModel = appGameViewModelRetrofit,
navController = navController,
) {
if (appGameViewModelRetrofit.appGame.value.isLoading == true) {
AppGame(
status = 200,
result = listOf()
)
} else {
appGameViewModelRetrofit.getAllAppGames(
pageCounter.value,
pageAction.value
).data!!
}
}
pageCounter.value= pageCounter.value+1
}
}
}
}
#Composable
fun FarsroidNavigationSystem(
roomDatabaseViewModel: RoomDatabaseViewModel,
appGameRetrofitViewModel: AppGameRetrofitViewModel,
navController: NavHostController,
onClicked: () -> AppGame
) {
NavHost(
navController = navController,
startDestination = Screens.HomeScreen.name
) {
composable(route = Screens.HomeScreen.name) {
HomeScreen(
retrofitViewModel = appGameRetrofitViewModel,
navController = navController
){
onClicked()
}
}
composable(route = Screens.DetailScreen.name) {
DetailScreen(
roomDatabaseViewModel = roomDatabaseViewModel,
navController = navController
)
}
}
}
#Composable
fun HomeScreen(
retrofitViewModel: AppGameRetrofitViewModel,
navController: NavHostController,
onClicked: () -> AppGame
) {
Scaffold(
modifier = Modifier
.fillMaxSize(),
backgroundColor = Color.White,
contentColor = Color.DarkGray
) { paddingValues ->
Spacer(modifier = Modifier.padding(paddingValues))
if (onClicked().status != 200)
CircularProgressIndicator(modifier = Modifier.fillMaxSize(), color = Color.Red)
else
LazyColumn {
items(onClicked().result) {
ItemCard(resultAppGame = it)
}
}
Button(onClick = {
onClicked()
}) {
Text("LoadMore")
}
}
}
#Composable
fun ItemCard(
resultAppGame: ResultAppGame,
) {
Card(
modifier = Modifier
.fillMaxWidth()
.padding(10.dp),
shape = CutCornerShape(10.dp),
backgroundColor = Color.White,
contentColor = Color.DarkGray,
elevation = 10.dp
) {
Column(
modifier = Modifier.padding(10.dp),
verticalArrangement = Arrangement.Top,
horizontalAlignment = Alignment.CenterHorizontally
) {
Card(
modifier = Modifier
.size(150.dp)
.padding(20.dp),
elevation = 10.dp,
shape = CircleShape,
backgroundColor = Color.White,
border = BorderStroke(width = 0.5.dp, Color.LightGray)
) {
Image(
painter = rememberAsyncImagePainter(
model = resultAppGame.pic),
contentDescription = resultAppGame.pic,
contentScale = ContentScale.Fit
)
}
Divider(thickness = 1.dp, color = Color.Gray)
Text(text = resultAppGame.title, textAlign = TextAlign.Right)
Divider(thickness = 1.dp, color = Color.Gray)
Text(text = resultAppGame.description, textAlign = TextAlign.Right)
Divider(thickness = 1.dp, color = Color.Gray)
Text(text = resultAppGame.link)
}
}
}

Why my viewModel function won't load data from JSON using retrofit?

In my application i'm using Navigation Compose. After implementing it, my viewModel's function getExercises() won't fetch the data. Why is that?
MainActivity:
class MainActivity : ComponentActivity() {
lateinit var navController: NavHostController
lateinit var viewModel: ExerciseViewModel
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
GymEncV2Theme {
// A surface container using the 'background' color from the theme
navController = rememberNavController()
viewModel = ExerciseViewModel()
Surface(
modifier = Modifier.fillMaxSize(),
color = MaterialTheme.colors.background
) {
SetupNavGraph(navController = navController, viewModel = viewModel)
}
}
}
}
}
NavGraph:
#Composable
fun SetupNavGraph(navController: NavHostController, viewModel: ExerciseViewModel) {
NavHost(navController = navController, startDestination = Screen.Home.route) {
composable(
route = Screen.Home.route
) {
HomeScreen(navController = navController)
}
composable(
route = Screen.SampleExercise.route,
arguments = listOf(navArgument(SAMPLE_EXERCISE_SCREEN_KEY) {
type = NavType.StringType
})
) {
SampleExerciseScreen(navController = navController, viewModel = viewModel, muscleGroup = it.arguments?.getString(
SAMPLE_EXERCISE_SCREEN_KEY).toString())
}
}
}
ExerciseApi built with Retrofit:
interface ExerciseApi {
#GET("GymEnc_v2.JSON")
suspend fun getExercises() : List<Exercise>
companion object {
private var exerciseApi: ExerciseApi? = null
fun getInstance() : ExerciseApi {
if (exerciseApi == null) {
exerciseApi = Retrofit.Builder()
.baseUrl(Constants.BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.build()
.create(ExerciseApi::class.java)
}
return exerciseApi!!
}
}
}
Repository Implementation:
class ExerciseRepositoryImpl : ExerciseRepository {
private val api = ExerciseApi.getInstance()
override suspend fun getExercises(): List<Exercise> {
return api.getExercises()
}
}
And finally the viewModel:
class ExerciseViewModel : ViewModel() {
private val repository = ExerciseRepositoryImpl()
var exerciseListResponse : List<Exercise> by mutableStateOf(arrayListOf())
var errorMessage: String by mutableStateOf("")
fun getExercises(): List<Exercise>{
viewModelScope.launch {
try {
val exerciseList = repository.getExercises()
exerciseListResponse = exerciseList
} catch (e: Exception) {
errorMessage = e.message.toString()
}
}
return exerciseListResponse
}
}
SampleExercisesScreen:
#Composable
fun SampleExerciseScreen(navController: NavController, muscleGroup: String, viewModel: ExerciseViewModel) {
val exerciseList = viewModel.getExercises().filter { it.muscle == muscleGroup }
Surface(modifier = Modifier.fillMaxSize(),
color = AppColors.mBackground) {
Column {
MyTopBar(navController = navController)
Text(text = muscleGroup,
style = MaterialTheme.typography.h3,
color = AppColors.mDetails,
fontWeight = FontWeight.Bold,
textAlign = TextAlign.Center)
UserExercisesButton()
}
}
}
After using viewModel.getExercises() in SampleExercisesScreen, they simply won't load, leaving me with an empty list.

PagingData<T> is empty briefly in Compose UI

I have a LazyColumn that collects a Flow<PagingData<ShoppingListItem>>? from the ViewModel, but the itemCount property of the collected state reports an empty list with 0 items at first briefly before it reports the actual number of items in the database. How can I fix this?
Logcat Output
2022-11-17 06:41:06.187 I/##successItemsCount: 0
2022-11-17 06:41:06.447 I/##successItemsCount: 0
2022-11-17 06:41:06.501 I/##successItemsCount: 11
Sealed Class
sealed class ListItemsState {
object Loading : ListItemsState()
object Error : ListItemsState()
data class Success(val allItems: Flow<PagingData<ShoppingListItem>>?) : ListItemsState()
}
ViewModel
#HiltViewModel
class ShoppingListScreenViewModel #Inject constructor(
private val getAllShoppingListItemsUseCase: GetAllShoppingListItemsUseCase
) {
private val _shoppingListItemsState = mutableStateOf<Flow<PagingData<ShoppingListItem>>?>(null)
private val _listItemsLoadingState = MutableStateFlow<ListItemsState>(ListItemsState.Loading)
val listItemsLoadingState = _listItemsLoadingState.asStateFlow()
init {
getAllShoppingListItemsFromDb()
}
private fun getAllShoppingListItemsFromDb() {
viewModelScope.launch {
_shoppingListItemsState.value = getAllShoppingListItemsUseCase().distinctUntilChanged()
_listItemsLoadingState.value = ListItemsState.Success(_shoppingListItemsState.value)
}
}
}
ShoppingListScreen Composable
#Composable
fun ShoppingListScreen(
navController: NavHostController,
shoppingListScreenViewModel: ShoppingListScreenViewModel,
sharedViewModel: SharedViewModel
) {
val screenHeight = LocalConfiguration.current.screenHeightDp.dp
val allItemsState = shoppingListScreenViewModel.listItemsLoadingState.collectAsState().value
Scaffold(
topBar = {
CustomAppBar(
title = "Shopping List",
titleFontSize = 20.sp,
appBarElevation = 4.dp,
navController = navController
)
},
floatingActionButton = {
FloatingActionButton(
onClick = {
shoppingListScreenViewModel.setStateValue(SHOW_ADD_ITEM_DIALOG_STR, true)
},
backgroundColor = Color.Blue,
contentColor = Color.White
) {
Icon(Icons.Filled.Add, "")
}
},
backgroundColor = Color.White,
// Defaults to false
isFloatingActionButtonDocked = false,
bottomBar = { BottomNavigationBar(navController = navController) }
) {
Box {
when (allItemsState) {
is ListItemsState.Loading -> ConditionalCircularProgressBar(isDisplayed = true)
is ListItemsState.Error -> Text("Error!")
is ListItemsState.Success -> {
ConditionalCircularProgressBar(isDisplayed = false)
val successItems = allItemsState.allItems?.collectAsLazyPagingItems()
Log.i("##successItemsCount", successItems.itemCount.toString())
LazyColumn(
modifier = Modifier
.fillMaxWidth()
.height(screenHeight)
) {
items(
items = successItems!!,
key = { item ->
item.id
}
) { item ->
ShoppingListScreenItem(
navController = navController,
item = item,
sharedViewModel = sharedViewModel
) { isChecked ->
scope.launch {
shoppingListScreenViewModel.changeItemChecked(item!!, isChecked)
}
}
}
item { Spacer(modifier = Modifier.padding(screenHeight - (screenHeight - 70.dp))) }
}
}
else -> {}
}
}
}
}

IllegalStateException with snapshots when using Dispatchers.IO and Dispatchers.Main in ViewModel

I want to show a spinning progress bar while shopping list items are being retrieved from the database in the ViewModel and then hide it when the data has been loaded, but the code below throws the following IllegalStateException. How can I fix it?:
java.lang.IllegalStateException: Reading a state that was created after the snapshot was taken or in a snapshot that has not yet been applied
Composable
#Composable
fun ShoppingListScreen(
navController: NavHostController,
shoppingListScreenViewModel: ShoppingListScreenViewModel,
sharedViewModel: SharedViewModel
) {
val screenHeight = LocalConfiguration.current.screenHeightDp.dp
val allItems = shoppingListScreenViewModel.shoppingListItemsState.value?.collectAsLazyPagingItems()
val showProgressBar = shoppingListScreenViewModel.loading.value
...
Box {
LazyColumn(
modifier = Modifier
.fillMaxWidth()
.height(screenHeight)
) {
if (allItems?.itemCount == 0) {
item { Text("You don't have any items in this shopping list.") }
}
items(
items = allItems!!,
key = { item ->
item.id
}
) { item ->
ShoppingListScreenItem(
navController = navController,
item = item,
sharedViewModel = sharedViewModel
) { isChecked ->
scope.launch {
shoppingListScreenViewModel.changeItemChecked(item!!, isChecked)
}
}
}
item { Spacer(modifier = Modifier.padding(screenHeight - (screenHeight - 70.dp))) }
}
ConditionalCircularProgressBar(isDisplayed = showProgressBar)
}
...
}
ViewModel
#HiltViewModel
class ShoppingListScreenViewModel #Inject constructor(
private val getAllShoppingListItemsUseCase: GetAllShoppingListItemsUseCase
) : ViewModel() {
private val _shoppingListItemsState = mutableStateOf<Flow<PagingData<ShoppingListItem>>?>(null)
val shoppingListItemsState: State<Flow<PagingData<ShoppingListItem>>?> get() = _shoppingListItemsState
val loading = mutableStateOf(false)
init {
loading.value = true
getAllShoppingListItemsFromDb()
}
private fun getAllShoppingListItemsFromDb() {
viewModelScope.launch(Dispatchers.IO){
_shoppingListItemsState.value = getAllShoppingListItemsUseCase().distinctUntilChanged()
withContext(Dispatchers.Main) {
loading.value = false
}
}
}

Why the navigation component has crashed when I want to navigate from two screen to same screen

I have three screens: CategoryScreen, CompanyScreen, and ProductsScreen.
I want to navigate from CategoryScreen and CompanyScreen to ProductsScreen.(ProductsScreen is a Common destination).
When I navigate from CompanyScreen everything is correct but when I want to navigate from CategoryScreen, the app is crashed.
My NavHost:
NavHost(
navController = navController,
startDestination = startDestination,
modifier = modifier,
) {
homeGraph(
windowSizeClass = windowSizeClass,
navigateToSubCategories = { navController.navigate(route = "${SubCategoryDestination.destination}/$this") },
navigateToAllCategories = { navController.navigate(route = AllCategoriesDestination.destination) },
nestedGraphs = {
allCategoriesGraph(windowSizeClass = windowSizeClass,
onBackClick = { navController.popBackStack() },
navigateToProducts = {
navController.navigate(route = "${AllProductsDestination.destination}/$this/${ProductsType.CATEGORY.type}")
},
nestedGraphs = {
allProductsGraph(windowSizeClass = windowSizeClass,
onBackClick = {},
navigateToProductDetail = {
navController.navigate(ProductDetailDestination.route)
},
nestedGraphs = {
productDetailGraph()
})
})
}
)
allCompaniesGraph(
windowSizeClass = windowSizeClass,
navigateToProducts = { navController.navigate( route = "${AllProductsDestination.destination}/$this/${ProductsType.COMPANY.type}") },
nestedGraphs = {
allProductsGraph(windowSizeClass = windowSizeClass,
onBackClick = {},
navigateToProductDetail = {
navController.navigate(ProductDetailDestination.route)
},
nestedGraphs = {
productDetailGraph()
})
}
)
}
CompanyNavigation file:
object AllCompaniesDestination : IFishoppingNavigationDestination {
override val route: String
get() = "all_companies_route"
override val destination: String
get() = "all_companies_destination"
}
#ExperimentalFoundationApi
#ExperimentalAnimationApi
#ExperimentalMaterial3Api
fun NavGraphBuilder.allCompaniesGraph(
windowSizeClass: WindowSizeClass,
navigateToProducts: String.() -> Unit,
nestedGraphs: NavGraphBuilder.() -> Unit,
) {
navigation(route = AllCompaniesDestination.route,
startDestination = AllCompaniesDestination.destination) {
composable(route = AllCompaniesDestination.destination) {
CompaniesScreen(windowSizeClass = windowSizeClass,
navigateToProducts = navigateToProducts)
}
nestedGraphs()
}
}
CategoryNavigation fule:
object AllCategoriesDestination : IFishoppingNavigationDestination {
override val route: String
get() = "all_categories_route"
override val destination: String
get() = "all_categories_destination"
}
#ExperimentalAnimationApi
#ExperimentalLayoutApi
#ExperimentalMaterial3Api
fun NavGraphBuilder.allCategoriesGraph(
windowSizeClass: WindowSizeClass,
onBackClick: () -> Unit,
navigateToProducts: String.() -> Unit,
nestedGraphs: NavGraphBuilder.() -> Unit,
) {
navigation(
route = AllCategoriesDestination.route,
startDestination = AllCategoriesDestination.destination
) {
composable(route = AllCategoriesDestination.destination) {
AllCategoriesScreen(windowSizeClass = windowSizeClass,
onBackClick = {},
navigateToProducts = { navigateToProducts() })
}
nestedGraphs()
}
}
ProductNavigation file (common destination):
object AllProductsDestination : IFishoppingNavigationDestination {
override val route: String
get() = "all_products_route"
override val destination: String
get() = "all_products_destination"
const val allProductsArg = "allProductsParam"
const val allProductsRequestTypeArg = "allProductsRequestTypeParam"
}
#ExperimentalLayoutApi
#ExperimentalMaterial3Api
fun NavGraphBuilder.allProductsGraph(
windowSizeClass: WindowSizeClass,
onBackClick: () -> Unit,
navigateToProductDetail: String.() -> Unit,
nestedGraphs: NavGraphBuilder.() -> Unit,
) {
navigation(route = AllProductsDestination.route,
startDestination = AllProductsDestination.destination)
{
composable(route = AllProductsDestination.destination
.plus("/{${AllProductsDestination.allProductsArg}}")
.plus("/{${AllProductsDestination.allProductsRequestTypeArg}}"),
arguments = listOf(
navArgument(AllProductsDestination.allProductsArg) {
type = NavType.StringType
},
navArgument(AllProductsDestination.allProductsRequestTypeArg) {
type = NavType.StringType
}
)) {
ProductsScreen(windowSizeClass = windowSizeClass, onBackClick = onBackClick)
}
nestedGraphs()
}
}
You are trying to navigate to a destination that’s not part of the nested graph

Categories

Resources