I'm having an issue with ModalNavigationDrawer. It is supposed to navigate to another screen after clicking an item in the ModalDrawerSheet, but it does nothing. Here are my files:
TaskListEvent.kt
sealed class TaskListEvent {
data class OnDeleteTask(val task: Task) : TaskListEvent()
object OnUndoDeleteTask : TaskListEvent()
data class OnEditClick(val task: Task) : TaskListEvent()
object OnAddTask : TaskListEvent()
class OnDrawerNavigationClick(val navigationItem: NavigationItem) : TaskListEvent()
}
Routes.kt:
sealed class Routes(val route: String) {
object TASKSLIST : Routes(route = "tasks_list")
object ADDEDITTASK : Routes(route = "add_edit_task")
}
Navigation.kt:
@RequiresApi(Build.VERSION_CODES.TIRAMISU)
@Composable
fun Navigation(navController: NavHostController) {
NavHost(navController = navController, startDestination = Routes.TASKSLIST.route) {
composable(
Routes.TASKSLIST.route
) {
TasksListScreen(onNavigate = {
navController.navigate(it.route)
})
}
composable(
route = Routes.ADDEDITTASK.route + "?taskId={taskId}",
arguments = listOf(navArgument(name = "taskId") {
type = NavType.IntType
defaultValue = -1
})
) {
AddEditScreen(
onPopBackStack = {
navController.popBackStack()
})
}
}
}
NavigationItem.kt:
data class NavigationItem(
val title: String,
val selectedIcon: ImageVector,
val unselectedIcon: ImageVector,
val route: String
)
val items = listOf(
NavigationItem(
title = "Planner",
selectedIcon = Icons.Default.Done,
unselectedIcon = Icons.Default.Done,
route = Routes.TASKSLIST.route
),
NavigationItem(
title = "Library",
selectedIcon = Icons.Default.Email,
unselectedIcon = Icons.Default.Email,
route = Routes.ADDEDITTASK.route
)
)
TaskListViewModel.kt:
@HiltViewModel
class TaskListViewModel @Inject constructor(private val repository: TaskRepositoryImplementation) :
ViewModel() { [...]
is TaskListEvent.OnDrawerNavigationClick -> {
sendUiEvent(UiEvent.Navigate(event.navigationItem.route))
}
}
}
private fun sendUiEvent(event: UiEvent) {
viewModelScope.launch(Dispatchers.IO) {
_uiEvent.send(event)
}
}
}
TasksList.kt:
@RequiresApi(Build.VERSION_CODES.TIRAMISU)
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun TasksListScreen(
modifier: Modifier = Modifier,
onNavigate: (UiEvent.Navigate) -> Unit,
viewModel: TaskListViewModel = hiltViewModel()
) {
val tasks = viewModel.tasks.collectAsState(initial = emptyList())
val snackbarHostState = remember { SnackbarHostState() }
val coroutineScope = rememberCoroutineScope()
val snackBarController = SnackBarController(coroutineScope)
LaunchedEffect(key1 = true) {
viewModel.uiEvent.collectLatest { event ->
when (event) {
[...]
is UiEvent.Navigate -> {
onNavigate(event)
}
else -> Unit
}
}
}
val drawerState = rememberDrawerState(initialValue = DrawerValue.Closed)
var selectedItemIndex by rememberSaveable {
mutableIntStateOf(0)
}
ModalNavigationDrawer(drawerContent = {
ModalDrawerSheet {
items.forEachIndexed { index, item ->
Spacer(modifier = Modifier.height(12.dp))
NavigationDrawerItem(
label = { Text(item.title) },
selected = index == selectedItemIndex,
onClick = {
TaskListEvent.OnDrawerNavigationClick(item)
selectedItemIndex = index
coroutineScope.launch {
drawerState.close()
}
},
icon = {
Icon(
imageVector = if (index == selectedItemIndex) {
item.selectedIcon
} else item.unselectedIcon, contentDescription = item.title
)
},
modifier = Modifier.padding(NavigationDrawerItemDefaults.ItemPadding))
}
}
}, drawerState = drawerState) { [...] }
I have tried to change the route type from "string" to actual "route" type in NavigationItem.kt and make the needed changes in the TaskListViewModel.kt:
replaced sendUiEvent(UiEvent.Navigate(event.navigationItem.route))
with sendUiEvent(UiEvent.Navigate(event.navigationItem.route.toString()))
but nothing seemed to work anyway. Do you have any ideas on how to make it work?
When you write TaskListEvent.OnDrawerNavigationClick(item)
, you're creating an event, but you're not actually doing anything with that event - it never makes it to your viewModel.uiEvent
flow to actually get processed. You'll need to connect these two pieces together if you want to process the event from the click.