I am trying to send the Id of one of my object from one screen to other but I don't know why it is not getting the correct Id. When I seperately try to understand the navigation concept and made a small app it was working . That small app was like this
@Composable
fun ScreenOne(onClick : (Int) -> Unit){
val number = 34
Column(
modifier = Modifier.fillMaxSize(),
verticalArrangement = Arrangement.Center,
horizontalAlignment = Alignment.CenterHorizontally
) {
Button(onClick = { onClick(number) }) {
Text(text = "Navigate")
}
}
}
@Composable
fun ScreenTwo(number:Int){
Column(
modifier = Modifier.fillMaxSize(),
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.Center
) {
Text(text = "Got number : $number")
}
}
@Composable
fun MyApp(modifier: Modifier = Modifier){
val navController = rememberNavController()
NavHost(navController = navController, startDestination = "a"){
composable("a") {
ScreenOne {
num->
navController.navigate("b/${num}")
}
}
composable("b/{num}") {
navBackStackEntry ->
val number = navBackStackEntry.arguments?.getString("num")?.toIntOrNull() ?: 0
ScreenTwo(number = number)
}
}
}
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
enableEdgeToEdge()
setContent {
PracticingNavigationTheme {
Scaffold(modifier = Modifier.fillMaxSize()) { innerPadding ->
MyApp(Modifier.padding(innerPadding))
}
}
}
}
}
But I don't know why this same logic is not working in my main project.
I will share my main project code files
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun ProfileScreen(
onFabClicked : () -> Unit,
onMailClicked: (Int) -> Unit,
profileScreenViewModel: ProfileScreenViewModel
) {
val TAG = "ProfileScreen"
val mailList by profileScreenViewModel.mailLayoutList.observeAsState(emptyList())
Log.d(TAG,"Size is : ${mailList.size}")
val drawerState = rememberDrawerState(initialValue = DrawerValue.Closed)
val scope = rememberCoroutineScope()
val bottomSheetState = rememberModalBottomSheetState(
skipPartiallyExpanded = false
)
var showSheet by remember {
mutableStateOf(false)
}
//Track if FAB is extended
var isExtended by remember {
mutableStateOf(false)
}
Box (
modifier = Modifier
.fillMaxSize()
.pointerInput(Unit) {
detectVerticalDragGestures { _, dragAmount ->
//Detect swipe up or down
if (dragAmount < 0) {
//Swiped Up
isExtended = true
} else if (dragAmount > 0) {
// Swiped down
isExtended = false
}
}
}
) {
ModalNavigationDrawer(
drawerState = drawerState, // Use ModalDrawer's state
drawerContent = {
DrawerItemUiLayout() // Drawer content
},
gesturesEnabled = true, // Allow gestures to open/close the drawer
scrimColor = Color.Black.copy(alpha = 0.32f) // Scrim with dimming effect
) {
Scaffold(
modifier = Modifier.windowInsetsPadding(WindowInsets.systemBars),
topBar = {
TopBarOne(
openDrawer = {
scope.launch {
drawerState.open() // Open drawer with built-in animation
}
},
openProfile = {
showSheet = true
}
)
},
bottomBar = {
BottomBarLayout()
},
floatingActionButton = {
if (isExtended) {
Log.d("FAB","value is : $isExtended")
ExtendedFloatingActionButton(
onClick = { onFabClicked() },
modifier = Modifier.background(Color.Cyan)
) {
Icon(imageVector = Icons.Default.Create, contentDescription = null)
Text(text = "Compose")
}
} else {
Log.d("FAB","value is : $isExtended")
FloatingActionButton(onClick = { onFabClicked() }) {
Icon(imageVector = Icons.Default.Create, contentDescription = null)
}
}
}
) { innerPadding ->
if (showSheet){
ModalBottomSheet(
modifier = Modifier.fillMaxHeight(),
sheetState = bottomSheetState,
onDismissRequest = { showSheet = false }
) {
Text(
"Swipe up to open sheet. Swipe down to dismiss.",
modifier = Modifier.padding(16.dp)
)
}
}
LazyColumn(
modifier = Modifier
.fillMaxSize()
.padding(innerPadding)
) {
// Main content here
items(mailList){
mails ->
MailLayout(
mailLayoutItem = mails,
onMailClicked = {
onMailClicked(it)
Log.d(TAG, "Navigating to ShowMailScreen with id: ${it}")
},
profileScreenViewModel = profileScreenViewModel
)
}
}
}
}
}
}
@OptIn(ExperimentalFoundationApi::class)
@Composable
fun ShowMailScreen(
onBackButtonClicked: () -> Unit,
onUnreadMailClicked: () -> Unit,
profileScreenViewModel: ProfileScreenViewModel,
mailId: Int
) {
val TAG = "SHOW_MAIL_SCREEN"
Log.d(TAG, "Got mail with id: ${mailId}")
var mail : MailLayoutItem = MailLayoutItem(
icon = 0,
sender = "null",
receiver = "null",
subject = "null",
content = "null",
time = "00:00",
isFavoriteClicked = false
)
LaunchedEffect(mailId) {
mail = profileScreenViewModel.findAParticularMail(mailId)
}
var isStarClicked by remember { mutableStateOf(mail.isFavoriteClicked) }
val example = listOf("1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1", "1")
Scaffold(
topBar = {
TopBarThree(
onBackButtonClicked = { onBackButtonClicked() },
onMoreButtonClicked = { /*TODO*/ },
onArchiveClicked = { /*TODO*/ },
onDeleteClicked = { /*TODO*/ },
onUnreadMailClicked = { onUnreadMailClicked() }
)
},
bottomBar = { BottomBarLayout()}
) { innerPadding ->
Column(
modifier = Modifier
.fillMaxSize()
.padding(innerPadding)
) {
// LazyColumn taking 3/4th of the screen
LazyColumn(
modifier = Modifier
.fillMaxWidth()
.weight(3f)
) {
item {
Text(text = "GOt mail with name ${mail.subject}")
}
item {
Row (
modifier = Modifier
.fillMaxWidth()
.padding(16.dp),
horizontalArrangement = Arrangement.SpaceBetween
){
Text(text = "Your ebook bargains for Tuesday.", fontSize = 26.sp, modifier = Modifier.weight(3f))
IconButton(onClick = {
profileScreenViewModel.ToggleFavorite(mailId = mail.id)
isStarClicked = !isStarClicked
}) {
if (isStarClicked){
Icon(
imageVector = Icons.Filled.Star,
contentDescription = null,
tint = Color.Blue
)
}else{
Icon(painter = painterResource(id = R.drawable.baseline_star_border_24) , contentDescription = null )
}
}
}
}
items(example) { item: String ->
Text(text = item)
}
stickyHeader {
Text(text = "This is the second part", fontWeight = FontWeight.Bold)
}
}
ReplyRowLayout()
}
}
}
@RequiresApi(Build.VERSION_CODES.O)
@Composable
fun AppNavigation(profileScreenViewModel: ProfileScreenViewModel = viewModel(
)){
val navController = rememberNavController()
NavHost(navController = navController, startDestination = Screens.PrimaryScreen.route){
composable(route = Screens.PrimaryScreen.route){
ProfileScreen(
onFabClicked = { navController.navigate(Screens.ComposeScreen.route) },
onMailClicked = {
mailId->
navController.navigate("${Screens.ShowMailScreen.route}/{mailId}")
},
profileScreenViewModel = profileScreenViewModel
)
}
composable(route = Screens.ComposeScreen.route) {
ComposeScreen(
onBackButtonClicked = {navController.navigateUp()},
onSendButtonClicked = {navController.navigateUp()},
profileScreenViewModel = profileScreenViewModel
)
}
composable(
route = "${Screens.ShowMailScreen.route}/{mailId}"
) {navBackStackEntry->
val mailId = navBackStackEntry.arguments?.getString("mailId")?.toIntOrNull() ?: 0
ShowMailScreen(
onBackButtonClicked = {navController.navigateUp()},
onUnreadMailClicked = {navController.navigateUp()},
profileScreenViewModel = profileScreenViewModel,
mailId = mailId
)
}
}
}
class ProfileScreenViewModel(
private val allMailsRepository: MailItemRepository = MailItemGraph.allMailsRepository
) : ViewModel() {
private val TAG = "ProfileScreenViewModel"
private val getDateAndTime = GetDateAndTime()
private val _mailLayoutList = MutableLiveData<List<MailLayoutItem>>(
emptyList()
)
val mailLayoutList: LiveData<List<MailLayoutItem>> get() = _mailLayoutList
init {
viewModelScope.launch {
allMailsRepository.getAllMails().collect { mails ->
_mailLayoutList.value = mails.sortedByDescending { it.id }
}
}
}
//Selecting favorite or not Favorite
fun ToggleFavorite(mailId: Int) {
_mailLayoutList.value = _mailLayoutList.value?.map { mailLayoutItem: MailLayoutItem ->
if (mailLayoutItem.id == mailId) {
val updatedMailLayoutItem = mailLayoutItem.copy(
isFavoriteClicked = !mailLayoutItem.isFavoriteClicked
)
viewModelScope.launch {
try {
allMailsRepository.insertMail(updatedMailLayoutItem)
} catch (e: Exception) {
Log.d(TAG, "Can't update the mail : ${e.message}")
}
}
updatedMailLayoutItem
} else {
mailLayoutItem
}
}
}
//Sending the clicked mail to other screen to view full mail
fun findAParticularMail(mailId: Int): MailLayoutItem {
var foundMail: MailLayoutItem = MailLayoutItem(
icon = 0,
sender = "null",
receiver = "null",
subject = "null",
content = "null",
time = "00:00",
isFavoriteClicked = false
)
viewModelScope.launch {
try {
allMailsRepository.getSpecificMail(mailId).collect {
foundMail = it
}
} catch (e: Exception) {
Log.d(TAG, "Specific mail can't be found with error : ${e.message}")
}
}
// val mail = _mailLayoutList.value?.find {
// foundMail->
// foundMail.id == mailId
// }
return foundMail
}
//Adding new mail in list
@RequiresApi(Build.VERSION_CODES.O)
fun addNewMail(mailLayoutItem: MailLayoutItem) {
val currentDateAndTime = LocalDateTime.now(ZoneId.of("Asia/Kolkata"))
val formattedTimeOrDate = getDateAndTime.getFormatedTimeOrDate(currentDateAndTime)
val newMailLayoutItem = mailLayoutItem.copy(time = formattedTimeOrDate)
viewModelScope.launch {
try {
allMailsRepository.insertMail(newMailLayoutItem)
} catch (e: Exception) {
Log.d(TAG, "Error occurred while inserting the mail: ${e.message}")
}
}
}
}
@Composable
fun MailLayout(
mailLayoutItem: MailLayoutItem,
onMailClicked: (Int) -> Unit,
profileScreenViewModel: ProfileScreenViewModel
){
val TAG = "MAIL_LAYOUT_SCREEN"
fun truncateString(input:String, maxLength:Int):String{
if (input.length > maxLength){
return input.take(maxLength) + "..."
}else{
return input
}
}
val mailImageBitmap = ImageBitmap.imageResource(id = mailLayoutItem.icon)
Row (
modifier = Modifier
.fillMaxWidth()
.padding(8.dp)
.clickable {
onMailClicked(
mailLayoutItem.id
)
Log.d(TAG, "Navigating to ShowMailScreen with id: ${mailLayoutItem.id}")
},
horizontalArrangement = Arrangement.Start,
verticalAlignment = Alignment.CenterVertically
){
Box(modifier = Modifier
.size(60.dp)
.clip(CircleShape)
){
Image(bitmap = mailImageBitmap, contentDescription = null, contentScale = ContentScale.Fit)
}
Column(
modifier = Modifier.fillMaxHeight().padding(horizontal = 8.dp).weight(5f),
) {
Text(text = truncateString(mailLayoutItem.sender, 25), fontWeight = FontWeight.Bold)
Text(text = truncateString(mailLayoutItem.subject, 50), fontSize = 12.sp, fontWeight = FontWeight.Bold)
Text(text = truncateString(mailLayoutItem.content, 40), fontSize = 12.sp)
}
Column(
modifier = Modifier.fillMaxHeight(),
verticalArrangement = Arrangement.SpaceBetween
) {
Text(text = mailLayoutItem.time, fontSize = 10.sp, fontWeight = FontWeight.ExtraBold)
IconButton(onClick = {
profileScreenViewModel.ToggleFavorite(mailId = mailLayoutItem.id)
}) {
if (mailLayoutItem.isFavoriteClicked){
Icon(imageVector = Icons.Filled.Star, contentDescription = null, tint = Color.Blue)
}else{
Icon(painter = painterResource(id = R.drawable.baseline_star_border_24), contentDescription = null)
}
}
}
}
}
@Entity
data class MailLayoutItem(
@PrimaryKey(autoGenerate = true)
val id : Int = 0,
val icon : Int,
val sender : String,
val receiver : String,
val subject : String,
val content : String,
val time : String,
val isFavoriteClicked : Boolean
)
I used some logging, so I am sharing some important log entries regarding this issue "
2024-09-22 11:11:57.657 12290-12290 ProfileScreen com.example.gmailappclone D Navigating to ShowMailScreen with id: 2
2024-09-22 11:11:57.658 12290-12290 MAIL_LAYOUT_SCREEN com.example.gmailappclone D Navigating to ShowMailScreen with id: 2
2024-09-22 11:11:57.703 12290-12290 SHOW_MAIL_SCREEN com.example.gmailappclone D Got mail with id: 0
"
I humbly request you to please help me regarding why the navigation logic is not working in my project.
It seems that you forgot the dollar sign in front of mailId
here, so you are not passing the actual mailId
to the destination:
onMailClicked = { mailId->
navController.navigate("${Screens.ShowMailScreen.route}/{mailId}")
}