Fatima Jamal
Fatima Jamal

Reputation: 159

How to hide AlertDialog after leaving the Screen?

i have a SignUp page to store user data, i'm using HorizontalPager to view TextFields. At the last page when user click Submit if user didn't provide correct password and email, the AlertDialog pop up.

The bug is when i dismiss AlertDialog and navigate back from current page(last page in HorizontalPager) to first one, the AlertDialog show.

i have the SignupPage iniside a HorizontalPager along with a StartPage and LoginPage. to achieve Swappable effect between pages.

Also, when i go to LoginPage the AlertDialog pops up although i didn't press anything or entering anydata.

This is MyNavigation.kt

@Composable
fun MyAppNavigation(
    modifier: Modifier, authViewModel: AuthViewModel
) {
    val pages = registerInfoList.size
    val pagerState = rememberPagerState(pageCount = { pages })
    val scope = rememberCoroutineScope()

    Column(
        modifier = modifier.fillMaxSize()
    ) {
        HorizontalPager(
            state = pagerState, userScrollEnabled = false
        ) { page ->
            when (page) {
                0 -> StartPage(modifier = modifier,
                    toSignUp = {
                        scope.launch {
                            pagerState.animateScrollToPage(2)
                        }
                    }, toLogin = {
                        scope.launch {
                            pagerState.animateScrollToPage(1)
                        }
                    }, authViewModel = authViewModel
                )


                1 -> LoginPage(modifier = modifier,
                    toHome = {
                        scope.launch {
                            pagerState.animateScrollToPage(3)
                        }
                    }, toSignUp = {
                        scope.launch {
                            pagerState.animateScrollToPage(2)
                        }
                    },
                    toStart = {
                        scope.launch {
                            pagerState.animateScrollToPage(0)
                        }
                    }, authViewModel = authViewModel
                )


                2 -> SignupPage(
                    modifier = modifier,
                    toStart = {
                        scope.launch {
                            pagerState.animateScrollToPage(0)
                        }
                    },
                    toHome = {
                        scope.launch {
                            pagerState.animateScrollToPage(3)
                        }

                    },
                    authViewModel = authViewModel
                )

              ......
            }
        }
    }
}

LoginPage.kt

@OptIn(ExperimentalComposeUiApi::class, ExperimentalMaterial3Api::class)
@Composable
fun LoginPage(
    modifier: Modifier = Modifier,
    //navController: NavController,
    toSignUp: () -> Unit,
    toHome: () -> Unit,
    toStart: () -> Unit,
    authViewModel: AuthViewModel
) {
    val shouldShowDialog = remember {
        mutableStateOf(false)
    }
    var email by remember {
        mutableStateOf("")
    }


    var password by remember {
        mutableStateOf("")
    }
    var showPassword by remember {
        mutableStateOf(false)
    }

    val isFormValid = remember {
        derivedStateOf {
            email.isNotEmpty() && password.isNotEmpty()
        }
    }

    var errorMessage by remember {
        mutableStateOf("")
    }

    if (shouldShowDialog.value) {
        AlertDialog(shouldShowDialog = shouldShowDialog, message = errorMessage)
        
    }

    val authState = authViewModel.authState.observeAsState()

    LocalContext.current
    LaunchedEffect(authState.value) {
        when (authState.value) {
            is AuthState.Authenticated -> toHome()
            is AuthState.Error.InvalidCredentialsError -> {
                errorMessage = (authState.value as AuthState.Error.InvalidCredentialsError).message
                shouldShowDialog.value = true
            }

            is AuthState.Error.NetworkError -> {
                errorMessage = (authState.value as AuthState.Error.NetworkError).message
            }


            else -> Unit
        }
    }
    Scaffold(
        topBar = {
            CenterAlignedTopAppBar(
                title = {
                    Text(
                        "Log in",
                        fontWeight = FontWeight.Bold
                    )
                },
                navigationIcon = {
                    IconButton(onClick = {toStart()}) {
                        Icon(
                            imageVector = Icons.AutoMirrored.Filled.ArrowBack,
                            contentDescription = "Localized description"
                        )
                    }
                }, colors = TopAppBarColors(
                    containerColor = colorResource(id = R.color.black),
                    titleContentColor = Color.White,
                    actionIconContentColor = Color.White,
                    navigationIconContentColor = Color.White,
                    scrolledContainerColor = colorResource(id = R.color.black)
                )
            )
        },
    ) { innerPadding ->

        Column(
            modifier = modifier
                .fillMaxSize()
                .padding(innerPadding)
                .padding(16.dp)
                .background(MaterialTheme.colorScheme.background),
            verticalArrangement = Arrangement.Top,
            horizontalAlignment = Alignment.CenterHorizontally
        ) {
            Text(
                modifier = Modifier.fillMaxWidth(),
                textAlign = TextAlign.Start, // Aligns text to the left
                text = "Email or username",
                fontSize = 32.sp,
                fontWeight = FontWeight.Bold,
                color = Color.White
            )
            Spacer(modifier = Modifier.size(4.dp))
            TextField(......................
            )

            Spacer(modifier = Modifier.size(32.dp))
            Text(
                modifier = Modifier.fillMaxWidth(),
                textAlign = TextAlign.Start,
                text = "Password",
                fontSize = 32.sp,
                fontWeight = FontWeight.Bold,
                color = Color.White
            )
            Spacer(modifier = Modifier.size(4.dp))
            TextField(.................
            )
            Text(
                text = errorMessage,
                color = Color.White,
                fontSize = 13.sp,
                textAlign = TextAlign.Start
            )

            Spacer(modifier = Modifier.height(32.dp))
            var colorButton by remember { mutableStateOf(Color.White) }
            Button(..................., enabled = isFormValid.value, onClick = {
            }) {
                ................
            }
            Spacer(modifier = Modifier.height(8.dp))
            var color by remember { mutableStateOf(Color.White) }

            TextButton(modifier = Modifier
                .fillMaxWidth()
                .bounceClickEffect()
                .pointerInteropFilter {
                    when (it.action) {
                        MotionEvent.ACTION_DOWN -> {
                            color = Color.Gray
                        }

                        MotionEvent.ACTION_UP -> {
                            color = Color.White
                            toSignUp()
                        }
                    }
                    true
                },
                enabled = isFormValid.value,
                onClick = {

                }) {
                ..................
            }

        }
    }
}

SignupPage.kt

@OptIn(ExperimentalMaterial3Api::class, ExperimentalComposeUiApi::class)
@Composable
fun SignupPage(
    modifier: Modifier = Modifier,
    //navController: NavController,
    toStart: () -> Unit, toHome: () -> Unit, authViewModel: AuthViewModel
) {
    var email by remember {
        mutableStateOf("")
    }
    var password by remember { mutableStateOf("") }
    var dateOfBirth by remember { mutableStateOf("") }
    var gender by remember { mutableStateOf("") }
    var isExpanded by remember { mutableStateOf(false) }
    var userName by remember { mutableStateOf("") }
    var colorButton by remember { mutableStateOf(Color.White) }


    val pages = registerInfoList.size
    val pagerState = rememberPagerState(pageCount = { pages })
    val scope = rememberCoroutineScope()
    var showPassword by remember {
        mutableStateOf(false)
    }

    val authState = authViewModel.authState.observeAsState()


    // To handle whether we can move to the next page
    val isFormValid = remember {
        derivedStateOf {
            when (pagerState.currentPage) {
                0 -> {
                    email.isNotEmpty()
                }

                1 -> {
                    password.isNotEmpty()
                }

                2 -> {
                    dateOfBirth.isNotEmpty()
                }

                3 -> {
                    gender.isNotEmpty()
                }

                4 -> {
                    userName.isNotEmpty()
                }

                else -> {
                    false
                }
            }
        }
    }

    var errorMessage by remember {
        mutableStateOf("")
    }

    val shouldShowDialog = remember {
        mutableStateOf(false)
    }

    if (shouldShowDialog.value) {
        AlertDialog(shouldShowDialog = shouldShowDialog, message = errorMessage)
    }

  val keyboardController = LocalSoftwareKeyboardController.current
    val context = LocalContext.current
    LaunchedEffect(authState.value) {
        when (authState.value) {
            is AuthState.Authenticated -> {shouldShowDialog.value = false
                toHome()}
            is AuthState.Error.InvalidCredentialsError -> {
                errorMessage = (authState.value as AuthState.Error.InvalidCredentialsError).message
                shouldShowDialog.value = true
            }
            is AuthState.Error.NetworkError -> {
                errorMessage = (authState.value as AuthState.Error.NetworkError).message
            }

            else -> shouldShowDialog.value = false
        }
    }

    DisposableEffect(Unit) {
        onDispose {
            shouldShowDialog.value = false // Reset when leaving this screen
        }
    }



        LaunchedEffect(pagerState.currentPage) {//------> this where the crash happen
            when (pagerState.currentPage) {
                2 -> keyboardController?.hide()
                3 -> keyboardController?.hide()
            }
        }



    Scaffold(
        topBar = {
            CenterAlignedTopAppBar(title = {
                Text(
                    "Create account", fontWeight = FontWeight.Bold
                )
            }, navigationIcon = {
                IconButton(onClick = {
                    if (shouldShowDialog.value) {
                        shouldShowDialog.value = false // Close dialog if open
                    }
                    else {
                        if (pagerState.currentPage == 0) {
                            toStart()
                        } else {
                            scope.launch {
                                pagerState.animateScrollToPage(pagerState.currentPage - 1)
                            }
                        }
                    }
                }) {
                    Icon(
                        imageVector = Icons.AutoMirrored.Filled.ArrowBack,
                        contentDescription = "Localized description"
                    )
                }
            }
            )
            )
        },
    ) { innerPadding ->


        Column(
            modifier = modifier
                .fillMaxSize()
                .padding(innerPadding)
                .padding(8.dp),
            verticalArrangement = Arrangement.Top,
            horizontalAlignment = Alignment.CenterHorizontally
        ) {
            HorizontalPager(
                state = pagerState, userScrollEnabled = false
            ) { index ->
                Column(
                    modifier = Modifier
                        .padding(8.dp)
                        .wrapContentHeight()
                        .background(MaterialTheme.colorScheme.background),
                    horizontalAlignment = Alignment.CenterHorizontally
                ) {
                    Text(
                        modifier = Modifier.fillMaxWidth(),
                        textAlign = TextAlign.Start, // Aligns text to the left
                        text = registerInfoList[index].title,
                        fontSize = 20.sp,
                        fontWeight = FontWeight.Bold,
                        color = Color.White
                    )
                    Spacer(modifier = Modifier.size(4.dp))
                    when (index) {
                        0 -> // email and name

                            TextField(
                                modifier = Modifier
                                    .fillMaxWidth()
                                   // .focusRequester(emailFocusRequester),
                                ,value = email,
                                colors = TextFieldDefaults.colors(
                                    unfocusedContainerColor = colorResource(id = R.color.gray),
                                    cursorColor = colorResource(id = R.color.light_gray),
                                    focusedTextColor = Color.White,
                                    unfocusedTextColor = Color.White,
                                    focusedContainerColor = colorResource(id = R.color.moon_gray),
                                    disabledLabelColor = colorResource(id = R.color.moon_gray),
                                    focusedIndicatorColor = Color.Transparent,
                                    unfocusedIndicatorColor = Color.Transparent
                                ),
                                onValueChange = { newValue ->
                                    email = newValue
                                },
                                shape = RoundedCornerShape(8.dp),
                                singleLine = true,
                                keyboardOptions = KeyboardOptions(
                                    imeAction = ImeAction.Next
                                )
                            )

                        1 -> {
                            ...................
                        }

                        2 -> {

                            DatePicker { date ->
                                dateOfBirth = date.let {
                                    SimpleDateFormat("dd/MM/yyyy", Locale.getDefault()).format(it)
                                }
                            }
                        }

                        3 -> {..................
                        }

                        4 -> // email and name

                            TextField(...................
                    }

                    Spacer(modifier = Modifier.size(4.dp))
                    Text(
                        modifier = Modifier.fillMaxWidth(),
                        textAlign = TextAlign.Start, // Aligns text to the left
                        text = registerInfoList[index].message,
                        fontSize = 10.sp,
                        color = Color.White
                    )
                }
            }
            Spacer(modifier = Modifier.height(16.dp))
            Button(modifier = Modifier
                .bounceClickEffect()
                .pointerInteropFilter {
                    when (it.action) {
                        MotionEvent.ACTION_DOWN -> {
                            colorButton = Color.Gray
                        }

                        MotionEvent.ACTION_UP -> {
                            if (isFormValid.value) {
                                // Update page state first
                                scope.launch {
                                    pagerState.animateScrollToPage(pagerState.currentPage + 1)
                                }
                                // Then set color back to white for visual feedback
                                colorButton = Color.White

                                if (pagerState.currentPage == registerInfoList.size - 1) {
                                    authViewModel.signup(email, password)
                                }
                            }

                        }
                    }
                    true
                }, ..............
            ), enabled = isFormValid.value, onClick = {}) {
                Text(text = "Log in", fontSize = 16.sp)
            }
        }
    }
}

This AuthViewModel.kt

class AuthViewModel(
    private val networkConnectivityObserver: NetworkConnectivityObserver
) : ViewModel() {
    private val auth : FirebaseAuth = FirebaseAuth.getInstance()

    private val _authState = MutableLiveData<AuthState>()
    val authState : LiveData<AuthState> = _authState

    fun checkAuthStatus(){
        if(auth.currentUser==null){
            _authState.value = AuthState.Unauthenticated
        }else{
            _authState.value = AuthState.Authenticated
        }
    }

    fun login(email: String, password: String) {
        if (email.isEmpty() || password.isEmpty()) {
            _authState.value = AuthState.Error.InvalidCredentialsError("Email/Password can't be empty.")
            return
        }
        _authState.value = AuthState.Loading

        auth.signInWithEmailAndPassword(email, password)
            .addOnCompleteListener { task ->
                if (task.isSuccessful) {
                    _authState.value = AuthState.Authenticated
                } else {
                    // Handle login failure
                    val exception = task.exception
                    if (exception is FirebaseNetworkException) {
                        _authState.value =
                            AuthState.Error.NetworkError("You're offline. Check you connection and try again.")
                        // Network error occurred
                        // Show an error message to the user and suggest retrying
                    } else if (exception is FirebaseAuthException){
                        _authState.value =
                            AuthState.Error.InvalidCredentialsError("This email and password combination is incorrect.")
                    }
                }



        }
    }

    fun signup(email: String, password: String){
        if(email.isEmpty() || password.isEmpty() ){
            _authState.value = AuthState.Error.InvalidCredentialsError("Email/Password can't be empty.")
            return
        }
        _authState.value = AuthState.Loading

        auth.createUserWithEmailAndPassword(email,password)
            .addOnCompleteListener {task ->
                if(task.isSuccessful){
                    _authState.value = AuthState.Authenticated
                }else {
                    _authState.value = AuthState.Error.InvalidCredentialsError(task.exception?.message?:"Something went wrong")
                    Log.d("HEEEEEEEEEEEELLO",task.exception?.message?:"Something went wrong")
                }
            }
    }

    fun signout(){
        auth.signOut()
        _authState.value = AuthState.Unauthenticated
    }
}

sealed class AuthState{
    data object Authenticated : AuthState()
    data object Unauthenticated : AuthState()
    data object Loading : AuthState()
    sealed class Error : AuthState() {
        data class NetworkError(val message: String) : Error()
        data class InvalidCredentialsError(val message: String) : Error()
    }
}

This AlerDialog.kt

@Composable
fun AlertDialog(shouldShowDialog: MutableState<Boolean>, message: String) {
    if (shouldShowDialog.value) {
        Dialog(onDismissRequest = { shouldShowDialog.value = false
        Log.d("Bad",shouldShowDialog.value.toString() )}) {
            Card(
                modifier = Modifier
                    .fillMaxWidth()
                    .height(250.dp)
                    .padding(16.dp),
                shape = RoundedCornerShape(16.dp)
            ) {
                Column(
                    Modifier
                        .fillMaxSize()
                        .background(Color.White),
                    horizontalAlignment = Alignment.CenterHorizontally,
                    verticalArrangement = Arrangement.Center
                ) {
                    Text(
                        text = message, color = Color.Black,
                        textAlign = TextAlign.Center,
                        fontSize = 13.sp,
                        modifier = Modifier
                            .padding(16.dp)
                    )
                    Spacer(modifier = Modifier
                        .size(8.dp))
                    Button( onClick = { shouldShowDialog.value = false }) {
                        Text(text = "OK", color = Color.Black, fontSize = 16.sp, fontWeight = FontWeight.Bold,modifier = Modifier
                            .padding(4.dp))
                    }
                }
            }
        }
    }
}

Upvotes: 1

Views: 34

Answers (0)

Related Questions