-1

Here is my MainActivity.kt file

Surface(modifier = Modifier.fillMaxSize(), color = MaterialTheme.colorScheme.background) {
                    NavigationHoster()
                }

here is navhoster function

@Composable
fun NavigationHoster(){
    val navController = rememberNavController();
    
    NavHost(navController = navController, startDestination = "Home"){
        composable("Home"){ HomeScreen(navController = navController)}
        composable("Chat"){ ChatScreen()}
    }
}

here is HomeScreen Function

@OptIn(ExperimentalMaterial3Api::class)
//@Preview(showBackground = true, showSystemUi = true)
@Composable
fun HomeScreen(
    homeViewModel: HomeViewModel = viewModel(),
    navController: NavController
){
    val HomeViewState by homeViewModel.uiState.collectAsState()
    Scaffold (
        topBar = {
            TopAppBar(title = {
                Text(text = "Chat Wallet", style = MaterialTheme.typography.titleMedium)
            }, colors = TopAppBarDefaults.mediumTopAppBarColors(
                containerColor = MaterialTheme.colorScheme.primary,
                titleContentColor = MaterialTheme.colorScheme.background
            ))
        }
    ){
        paddingValues -> Box(modifier = Modifier.padding(paddingValues).fillMaxSize(), contentAlignment = Alignment.Center) {
            IconButton(onClick = { navController.navigate("Chat") }, colors = IconButtonDefaults.iconButtonColors(containerColor = MaterialTheme.colorScheme.primary)) {
                Icon(painter = painterResource(id = R.drawable.baseline_chat_24), contentDescription = null, tint = MaterialTheme.colorScheme.background)
            }

        }
    }
}

Here is my ViewModel

class HomeViewModel : ViewModel(){
    private var _uiState = MutableStateFlow(HomeData())
    var uiState : StateFlow<HomeData> = _uiState.asStateFlow()

    public fun ChangeName() {
        _uiState.value = HomeData(UserName = "hello there")
    }
}

These codes are works well and I tested. this viewmodel and screen file may be not linked.because I does different tests by changing it. can I know how to navigate to chat screen by calling changeName function from ui? I have no idea how to implement it

I didn't get any way to import navcontroller to viewmodel. so I stucked with that point. I thaught it have to import to viewmodel.

please give me simple example as well. thank you.

Gayantha
  • 92
  • 8

2 Answers2

1

You can create NavManager class that will have navigation functions in it and you can call them from ViewModel:

class NavManager(private val navController: NavController) {
    fun navigateToChatScreen() {
        navController.navigate("Chat")
    }
}

Now pass NavManager in HomeViewModel while navigating:

@Composable
fun NavigationHoster(){
    val navController = rememberNavController();
    val navManager = NavManager(navController)
    NavHost(navController = navController, startDestination = "Home"){
        composable("Home"){ 
             val viewModel = HomeViewModel(navManager)
             HomeScreen(viewModel)
        }
        composable("Chat"){ ChatScreen()}
    }
}

Now, HomeScreen should look like this:

@Composable
fun HomeScreen(
    homeViewModel: HomeViewModel
){
  ...
}

And HomeViewModel should look like this:

class HomeViewModel(private val navManager: NavManager) : ViewModel(){
    private var _uiState = MutableStateFlow(HomeData())
    var uiState : StateFlow<HomeData> = _uiState.asStateFlow()

    public fun ChangeName() {
        _uiState.value = HomeData(UserName = "hello there")
    }

    // Call this function from view whenever you want to navigate to chat screen
    fun navigateToChatScreen(){
        navManager.navigateToChatScreen()
    }
}

In another way, you can use hilt so that you don't have to pass navManager like this through navigation. Instead, you can just inject its dependency in HomeViewModel using constructor.

Megh
  • 831
  • 2
  • 12
1

You best approach would be to add a variable to the viewModel called navigateToChatScreen and then when this variable is true you can navigate in your composable like this:

    class HomeViewModel : ViewModel(){
    private var _uiState = MutableStateFlow(HomeData())
    var uiState : StateFlow<HomeData> = _uiState.asStateFlow()

private var _navigateToChatScreen = MutableStateFlow(false)
    var navigateToChatScreen : StateFlow<Boolean> = _navigateToChatScreen.asStateFlow()

    public fun ChangeName() {
        _uiState.value = HomeData(UserName = "hello there")
        _navigateToChatScreen.value = true
    }
}

Then you do it like this in your composable:

    @Composable
fun HomeScreen(
    homeViewModel: HomeViewModel = viewModel(),
    navController: NavController
){
    val HomeViewState by homeViewModel.uiState.collectAsState()

    val navigateToChatScreen by homeViewModel.navigateToChatScreen.collectAsState()

Launchedeffect(key= navigateToChatScreen){
  If(navigateToChatScreen){
     navController.navigate("chat")
  }
}
    Scaffold (
        topBar = {
            TopAppBar(title = {
                Text(text = "Chat Wallet", style = MaterialTheme.typography.titleMedium)
            }, colors = TopAppBarDefaults.mediumTopAppBarColors(
                containerColor = MaterialTheme.colorScheme.primary,
                titleContentColor = MaterialTheme.colorScheme.background
            ))
        }
    ){
        paddingValues -> Box(modifier = Modifier.padding(paddingValues).fillMaxSize(), contentAlignment = Alignment.Center) {
            IconButton(onClick = { homeViewModel.changeName()}, colors = IconButtonDefaults.iconButtonColors(containerColor = MaterialTheme.colorScheme.primary)) {
                Icon(painter = painterResource(id = R.drawable.baseline_chat_24), contentDescription = null, tint = MaterialTheme.colorScheme.background)
            }

        }
    }
}
Ayman Ait
  • 391
  • 2
  • 9