Thread
#compose
    Samir Basnet

    Samir Basnet

    1 year ago
    If anyone have implemented a login api in compose screen with viewModel can you please share a gist. I am a little confused about how to do it properly
    message has been deleted
    @HiltViewModel
    class UserViewModel @Inject constructor(
        private val userRepository: UserRepository
    ) : ViewModel() {
    
        var login = mutableStateOf("")
        var password = mutableStateOf("")
    
        val loginState: MutableState<ApiState<LoginResponse>> = mutableStateOf(ApiState.Empty)
    
        fun onLoginChange(login: String) {
            this.login.value = login
        }
    
        fun onPasswordChange(password: String) {
            this.password.value = password
        }
    
    
        fun resetLogin(){
            this.login.value = ""
            this.password.value = ""
            this.loginState.value = ApiState.Empty
        }
    
    
        fun loginUser() {
            viewModelScope.launch {
                loginState.value = ApiState.Loading
                loginState.value = userRepository.callLoginApi(LoginParams(login.value, password.value))
            }
        }
    }
    
    @ExperimentalComposeUiApi
    @ExperimentalAnimationApi
    @Composable
    fun LoginScreen(navController: NavController, viewModel: UserViewModel) {
        val loginState = viewModel.loginState.value
        var startAnimation by remember { mutableStateOf(false) }
    
        LaunchedEffect(Unit) {
            delay(5)
            if (!startAnimation)
                startAnimation = true
        }
    
        Box(
            modifier = Modifier.fillMaxSize(),
            contentAlignment = Alignment.Center
        ) {
    
            Image(
                modifier = Modifier.fillMaxSize(),
                contentScale = ContentScale.Crop,
                painter = painterResource(id = R.drawable.gradient_background),
                contentDescription = null,
            )
            AnimatedVisibility(
                visible = startAnimation,
                enter = slideInVertically(animationSpec = TweenSpec(durationMillis = 900))
            ) {
                Card(
                    modifier = Modifier
                        .padding(horizontal = 15.dp, vertical = 20.dp)
                        .fillMaxWidth()
                        .wrapContentHeight(),
                ) {
                    Column(
                        modifier = Modifier.verticalScroll(rememberScrollState()),
                        horizontalAlignment = Alignment.CenterHorizontally
                    ) {
                        MahalSectionHeader(
                            modifier = Modifier
                                .padding(top = 20.dp, start = 15.dp)
                                .align(Alignment.Start), label = "LOGIN"
                        )
                        LoginFields(viewModel)
    
                        ForgotAndLoginButtons(
                            modifier = Modifier
                                .align(Alignment.End)
                                .padding(end = 15.dp),
                            loginState,
                            viewModel
                        )
    
                        NoAccountSection(
                            modifier = Modifier.align(Alignment.CenterHorizontally),
                            navController = navController
                        )
    
                        SocialLoginSection(navController)
                        Spacer(modifier = Modifier.padding(bottom = 20.dp))
                    }
    
    
                }
            }
    
            MahalErrorSnackBar(apiState = loginState, modifier = Modifier.align(Alignment.TopCenter))
            if (loginState is ApiState.Success) {
                viewModel.resetLogin()
                navController.navigate("home")
            }
    
    
        }
    }
    @ExperimentalAnimationApi
    @Composable
    private fun ForgotAndLoginButtons(
        modifier: Modifier,
        loginState: ApiState<LoginResponse>,
        viewModel: UserViewModel,
    ) {
        MahalTextButton(
            modifier = modifier,
            label = "Forgot password?",
            performAction = { })
        MahalSolidButton(label = "Login", apiState = loginState) {
            viewModel.loginUser()
        }
    
    
    }
    
    @ExperimentalComposeUiApi
    @Composable
    private fun LoginFields(viewModel: UserViewModel) {
        val passwordFocusRequester = remember { FocusRequester() }
        val focusManager = LocalFocusManager.current
        val autofill = LocalAutofill.current
        var numberMode by remember { mutableStateOf(false) }
    
        MahalFirstTextField(
            input = viewModel.login,
            label = if (numberMode) "Mobile Number" else "Email",
            keyboardType = if (numberMode) KeyboardType.Phone else KeyboardType.Email,
            leadingIcon = if (numberMode) Icons.Filled.Phone else Icons.Filled.Email,
            nextFocusRequester = passwordFocusRequester,
            autofill = autofill,
        ) {
            if (it == "4321")
                numberMode = !numberMode
    
            viewModel.onLoginChange(it)
        }
    
        MahalPasswordField(
            label = "Password",
            imeAction = ImeAction.Done,
            focusRequester = passwordFocusRequester,
            focusManager = focusManager,
            autofill = autofill
        ) {
            viewModel.onPasswordChange(it)
        }
    }
    For now just consider when i press back i come back to LoginScreen with a reset. Above is how i have done. Please guide me what can be improved