Skip to main content

Overview

The Login Screen provides a secure authentication interface for users to access the NASA Explorer application. It features email and password input fields with comprehensive validation, loading states, and error handling.

Key Features

Email Validation

Validates email format using Android’s EMAIL_ADDRESS pattern matcher

Password Security

Enforces minimum 6-character password requirement

Loading States

Displays circular progress indicator during authentication

Error Handling

Shows toast messages for validation and authentication errors

Screen Components

Main UI Elements

The login screen consists of the following visual components:
  • Logo Image: Planet icon (250x250dp) with rounded corners and white tint
  • Email TextField: Outlined text field for email input
  • Password TextField: Outlined text field for password input with secure entry
  • Sign Up Link: Clickable text to navigate to registration screen
  • Login Button: Full-width button at the bottom to submit credentials
  • Progress Indicator: Circular loading indicator shown during authentication
All text fields use white color styling to contrast against the black background theme.

Architecture

LoginScreen Composable

The main composable function that renders the login interface:
@Composable
fun LoginScreen(
    loginScreenViewModel: LoginScreenViewModel = hiltViewModel(),
    onNavigationToHome: () -> Unit,
    onNavigationToSignUp: () -> Unit
) {
    val isLoading by loginScreenViewModel.isLoading.collectAsState()
    val errorMessage by loginScreenViewModel.errorMessage.collectAsState()

    // Error message handling
    if (errorMessage.isNotEmpty()) {
        Toast.makeText(LocalContext.current, errorMessage, Toast.LENGTH_LONG).show()
        loginScreenViewModel.resetErrorMessage()
    }

    Column(
        modifier = Modifier
            .fillMaxSize()
            .background(Color.Black),
        Arrangement.Top,
        horizontalAlignment = Alignment.CenterHorizontally
    ) {
        // UI components
    }
}

ViewModel State Management

The LoginScreenViewModel manages authentication state and business logic:
@HiltViewModel
class LoginScreenViewModel @Inject constructor(
    private val authService: AuthService
) : ViewModel() {

    private var _isLoading = MutableStateFlow<Boolean>(false)
    val isLoading: StateFlow<Boolean> = _isLoading

    private var _errorMessage = MutableStateFlow<String>("")
    val errorMessage: StateFlow<String> = _errorMessage

    fun login(email: String, password: String, onNavigateToHome: () -> Unit) {
        // Validation and authentication logic
    }
}

Validation Logic

Input Validation

The screen performs comprehensive validation before attempting authentication:
1

Empty Field Check

Verifies that both email and password fields are not blank
if (email.isBlank() || password.isBlank()) {
    _errorMessage.value = "Los campos no pueden estar vacios"
    return
}
2

Email Format Validation

Validates email format using Android’s pattern matcher
private fun isValidEmail(email: String): Boolean {
    return android.util.Patterns.EMAIL_ADDRESS.matcher(email).matches()
}
3

Password Length Check

Ensures password meets minimum length requirement
if (password.length < 6) {
    _errorMessage.value = "La contraseña debe tener al menos 6 caracteres"
    return
}

Authentication Flow

Login Process

The authentication flow uses Kotlin coroutines for asynchronous operations:
fun login(email: String, password: String, onNavigateToHome: () -> Unit) {
    viewModelScope.launch {
        _isLoading.value = true

        try {
            val result = withContext(Dispatchers.IO) {
                authService.login(email = email, password = password)
            }
            
            if (result != null) {
                onNavigateToHome()
            } else {
                _errorMessage.value = "Error de autenticación.Por favor, revisa tus credenciales."
            }
        } catch (e: Exception) {
            _errorMessage.value = "Correo o contraseña no válidos."
        } finally {
            _isLoading.value = false
        }
    }
}
Authentication operations run on Dispatchers.IO to prevent blocking the main UI thread.

State Management

StateFlow Properties

The screen observes the following state flows:
StateTypePurpose
isLoadingStateFlow<Boolean>Controls progress indicator visibility
errorMessageStateFlow<String>Stores validation or authentication error messages

State Collection

State is collected using Compose’s collectAsState() extension:
val isLoading by loginScreenViewModel.isLoading.collectAsState()
val errorMessage by loginScreenViewModel.errorMessage.collectAsState()
The screen supports two navigation callbacks:
// Called after successful authentication
onNavigationToHome: () -> Unit
Text(
    text = "Registrarse",
    modifier = Modifier
        .clickable { onNavigationToSignUp() }
        .align(Alignment.End)
        .padding(end = 56.dp, top = 8.dp),
    color = Color.White
)

Error Handling

Error Message Display

Errors are displayed using Android Toast messages:
if (errorMessage.isNotEmpty()) {
    Toast.makeText(LocalContext.current, errorMessage, Toast.LENGTH_LONG).show()
    loginScreenViewModel.resetErrorMessage()
}

Error Types

Message: “Los campos no pueden estar vacios”Triggered when either email or password field is blank.
Message: “El correo no es válido”Triggered when email format doesn’t match standard pattern.
Message: “La contraseña debe tener al menos 6 caracteres”Triggered when password is shorter than 6 characters.
Message: “Correo o contraseña no válidos”Triggered when authentication fails with invalid credentials.

Dependencies

Injection & State

import androidx.hilt.navigation.compose.hiltViewModel
import androidx.compose.runtime.collectAsState
import dagger.hilt.android.lifecycle.HiltViewModel
import javax.inject.Inject

Compose UI

import androidx.compose.material3.OutlinedTextField
import androidx.compose.material3.Button
import androidx.compose.material3.CircularProgressIndicator
import androidx.compose.foundation.layout.*

File Location

app/src/main/java/com/ccandeladev/nasaexplorer/ui/loginscreen/
├── LoginScreen.kt
└── LoginScreenViewModel.kt
Best Practice: The screen follows MVVM architecture with clear separation between UI (LoginScreen.kt) and business logic (LoginScreenViewModel.kt).

Build docs developers (and LLMs) love