In my app I want to send info to server and after receiving successful response I want to pass info to current screen to navigate to another screen.
Here's the flow:
From UI I call viewModel
to send request to server. In ViewModel
I have a callback:
@HiltViewModel
class CreateAccountViewModel @Inject constructor(
private val cs: CS
) : ViewModel() {
private val _screen = mutableStateOf("")
val screen: State<String> = _screen
fun setScreen(screen: Screen) {
_screen.value = screen.route
}
private val signUpCallback = object : SignUpHandler {
override fun onSuccess(user: User?, signUpResult: SignUpResult?) {
setScreen(Screen.VerifyAccountScreen)
Log.i(Constants.TAG, "sign up success")
}
override fun onFailure(exception: Exception?) {
Log.i(Constants.TAG, "sign up failure ")
}
}
}
As you can see I have also State
responsible for Screen so when response is successful I want to update the state so UI layer (Screen) knows that it should navigate to another screen. My question is: how can I observer State in
@Composable
fun CreateAccountScreen(
navController: NavController,
viewModel: CreateAccountViewModel = hiltViewModel()
) {
}
Or is there a better way to achieve that?
CodePudding user response:
I think your view model should know nothing about navigation routes. Simple verificationNeeded
flag will be enough in this case:
var verificationNeeded by mutableStateOf(false)
private set
private val signUpCallback = object : SignUpHandler {
override fun onSuccess(user: User?, signUpResult: SignUpResult?) {
verificationNeeded = true
Log.i(Constants.TAG, "sign up success")
}
override fun onFailure(exception: Exception?) {
Log.i(Constants.TAG, "sign up failure ")
}
}
The best practice is not sharing navController
outside of the view managing the NavHost
, and only pass even handlers. It may be useful when you need to test or preview your screen.
Here's how you can navigate when this flag is changed:
@Composable
fun CreateAccountScreen(
onRequestVerification: () -> Unit,
viewModel: CreateAccountViewModel = hiltViewModel(),
) {
if (viewModel.verificationNeeded) {
LaunchedEffect(Unit) {
onRequestVerification()
}
}
}
in your navigation managing view:
val navController = rememberNavController()
NavHost(
navController = navController,
startDestination = Screen.CreateAccount
) {
composable(Screen.CreateAccount) {
CreateAccountScreen(
onRequestVerification = {
navController.navigate(Screen.VerifyAccountScreen)
}
)
}
}