Sunday, 23 April 2023

stuck navigation in Jetpack Compose

I have a Jetpack Compose project and I am making API call to send OTP and Verify the OTP on a second screen. My Problem now is when the OTP request is sent, and the request is successful I expect to navigate to the screen to verify the OTP which works but if I try to navigate back to the initial screen where my phone was verified, the back button never seem to work.

Here is my code.

@Composable
fun ContinueWithPhoneView(
    navController: NavController,
    authenticationDataViewModel: AuthenticationDataViewModel
) {
    val viewModel = hiltViewModel<ContinueWithPhoneViewModel>()
    val event by viewModel.events.observeAsState(null)
    val phoneNumber = remember { mutableStateOf("") }
    val errorMessage = remember { mutableStateOf("") }
    val (gesturesEnabled, toggleGesturesEnabled) = remember { mutableStateOf(false) }
    val scope = rememberCoroutineScope()
    val isLoading = remember { mutableStateOf(false) }
    val drawerState = rememberBottomDrawerState(BottomDrawerValue.Closed)
    Surface(
        modifier = Modifier.fillMaxSize(),
        ) {
        BottomDrawer(
            gesturesEnabled = gesturesEnabled,
            drawerState = drawerState,
            drawerShape = BottomSheetShape,
            drawerElevation = 8.dp,
            drawerContent = {
                ErrorBottomView(message = errorMessage.value) {
                    scope.launch { drawerState.close() }
                }
            },
            content = {
                Column(
                    horizontalAlignment = Alignment.CenterHorizontally,
                ) {
                    Column {
                        NavigationBar(topAppBarText = "Continue With Phone") {
                            navController.popBackStack()
                        }
                    }
                    Spacer(modifier = Modifier
                        .weight(1f))

                    Column(
                        modifier = Modifier
                            .fillMaxWidth()
                            .padding(start = 16.dp, end = 16.dp),
                    ) {
                        OutlinedTextField(
                            keyboardOptions = KeyboardOptions(
                                capitalization = KeyboardCapitalization.None,
                                autoCorrect = false,
                                keyboardType = KeyboardType.Phone,
                            ),
                            modifier = Modifier
                                .navigationBarsWithImePadding()
                                .fillMaxWidth(),
                            value = phoneNumber.value,
                            onValueChange = { phoneNumber.value = it },
                            label = {
                                Text(
                                    text = "Phone Number"
                                )
                            },
                            colors = TextFieldDefaults.outlinedTextFieldColors(
                                focusedBorderColor = MaterialTheme.colors.onSecondary, // Set the focused border color here
                                focusedLabelColor = MaterialTheme.colors.onSecondary
                            )
                        )
                        Spacer(modifier = Modifier.padding(8.dp))
                        Text(modifier = Modifier, style = MaterialTheme.typography.caption, text = "By continuing, you agree to get SMS messages, WhatsApp, Telegram or calls, including automated means, from Dispatch and its affiliates to the number provided")
                    }
                    Spacer(modifier = Modifier
                        .weight(1f))
                    Column(
                        modifier = Modifier
                            .fillMaxWidth()
                            .padding(start = 16.dp, end = 16.dp),
                    ) {
                        NavigationButton(buttonText = "Continue with Phone", isLoading = isLoading.value, onBackPressed = {
                            navController.popBackStack()
                        }) {
                            viewModel.sendOtp(phoneNumber = phoneNumber.value)
                        }
                    }

                    Spacer(modifier = Modifier.padding(6.dp))
                }
            }
        )
        LaunchedEffect(event) {
            when (event) {
                is Result.Loading -> {
                    isLoading.value = true
                }
                is Result.Error -> {
                    val exception = (event as Result.Error).exception
                    scope.launch {
                        errorMessage.value = exception
                        isLoading.value = false
                        drawerState.open()
                    }
                }
                is Result.Success -> {
                    val logInRequest = LogInRequest(phoneNumber = phoneNumber.value, password = "")
                    isLoading.value = false
                    navController.currentBackStackEntry?.arguments?.putParcelable("logInRequest", logInRequest)
                    navController.navigate(Screen.VerifyPhone.route)
                }
                else -> {}
            }
        }
    }
}

My ViewModel

@HiltViewModel
class ContinueWithPhoneViewModel @Inject constructor(
    private val repository: AccountRepositoryProviding,
    @DefaultDispatcher private val defaultDispatcher: CoroutineDispatcher,
): ViewModel() {
    private val _events = MutableLiveData<Result<Boolean>>()
    val events: LiveData<Result<Boolean>> = _events

    private var job: Job? = null

    fun sendOtp(phoneNumber: String) {
        job?.cancel()
//        Timber.tag(javaClass.name)
//            .d("inputted phone number %s", phoneNumber)
        _events.value = Result.Loading

        val handler = CoroutineExceptionHandler { _, throwable ->
            val message = when (throwable) {
                is HttpException -> throwable.toErrorMessage()
                else -> "An Error Occurred."
            }
            Log.d("ContinueWithPhoneViewModel", "ERR :: ${throwable} \n")
//            Timber.tag(javaClass.name)
//                .e(throwable)
            _events.value = Result.Error(message)
        }
        job = viewModelScope.launch(handler) {
            val resp = repository.sendOtp(phoneNumber = phoneNumber)
            Timber.tag(javaClass.name)
                .d("Response ::: %s", resp)
            _events.value = Result.Success(resp.data ?: false)
        }
    }
}

my app navigation

@Composable
fun AppNavigation() {
    val navController = rememberNavController()
    val authenticationDataViewModel: AuthenticationDataViewModel = viewModel()
    NavHost(
        navController = navController,
        startDestination = Screen.Landing.route
    ) {

        composable(Screen.Landing.route) {
            LandingPageView(navController = navController)
        }

        composable(Screen.ContinueWithPhone.route) {
            ContinueWithPhoneView(navController = navController, authenticationDataViewModel = authenticationDataViewModel)
        }

        composable(route = Screen.VerifyPhone.route) {
            navController.previousBackStackEntry?.arguments?.getParcelable<LogInRequest>("logInRequest")?.let { request -> VerifyPhoneView(navController, request) }
        }

        composable(route = Screen.Base.route) {
            TabBarView()
        }
    }
}

Any help is appreciated.



from stuck navigation in Jetpack Compose

No comments:

Post a Comment