Skip to main content

Overview

The Signup Screen provides a user registration interface for creating new accounts in the NASA Explorer application. It features email and password validation, Firebase authentication integration, and comprehensive error handling for duplicate accounts.

Key Features

Account Creation

Creates new user accounts using Firebase Authentication

Duplicate Detection

Detects and prevents registration with existing email addresses

Input Validation

Validates email format and password strength requirements

Loading States

Shows progress indicators during registration process

Screen Components

Main UI Elements

The signup screen consists of:
  • Title: “Registro nuevo usuario” header text in white
  • Email TextField: Outlined input field for email address
  • Password TextField: Outlined secure input field for password
  • Register Button: Full-width button at the bottom to submit registration
  • Progress Indicator: Circular loading indicator during registration
The screen uses a black background with white text styling for consistency with the app theme.

Architecture

SignUpScreen Composable

@Composable
fun SignUpScreen(
    signUpViewModel: SignUpViewModel = hiltViewModel(),
    onNavigateToHome: () -> Unit
) {
    val isLoading by signUpViewModel.isLoading.collectAsState()
    val errorMessage by signUpViewModel.errorMessage.collectAsState()

    if (errorMessage.isNotEmpty()) {
        Toast.makeText(LocalContext.current, errorMessage, Toast.LENGTH_LONG).show()
        signUpViewModel.resetErrorMessage()
    }

    Box(
        modifier = Modifier
            .fillMaxSize()
            .background(Color.Black)
    ) {
        // UI components
    }
}

Layout Structure

The screen uses a Box layout with centered column content:
Column(
    Modifier
        .fillMaxWidth()
        .align(Alignment.Center),
    horizontalAlignment = Alignment.CenterHorizontally
) {
    Text(text = "Registro nuevo usuario", style = TextStyle(color = Color.White))
    // Email and password fields
}

Button(
    onClick = { /* Registration logic */ },
    modifier = Modifier
        .fillMaxWidth()
        .align(Alignment.BottomCenter)
        .padding(26.dp)
) {
    Text(text = "Registrarse")
}

ViewModel Implementation

SignUpViewModel

Manages registration state and Firebase authentication:
@HiltViewModel
class SignUpViewModel @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 register(email: String, password: String, onNavigateToHome: () -> Unit) {
        // Registration logic
    }
}

Registration Flow

Validation Steps

1

Empty Field Validation

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

Email Format Validation

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

Password Length Validation

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

Firebase Registration

Creates user account via AuthService
val result = withContext(Dispatchers.IO) {
    authService.register(email = email, password = password)
}

Complete Registration Function

fun register(email: String, password: String, onNavigateToHome: () -> Unit) {
    viewModelScope.launch {
        _isLoading.value = true

        try {
            val result = withContext(Dispatchers.IO) {
                authService.register(email = email, password = password)
            }
            
            if (result != null) {
                onNavigateToHome()
            } else {
                _errorMessage.value = "Error de autenticación.Revisa tus credenciales."
            }
        } catch (e: FirebaseAuthUserCollisionException) {
            _errorMessage.value = "El correo ya está en uso."
        } catch (e: Exception) {
            _errorMessage.value = "Se produjo un error durante el registro"
        } finally {
            _isLoading.value = false
        }
    }
}
Registration operations use Dispatchers.IO to avoid blocking the main thread during network calls.

Error Handling

Firebase-Specific Errors

The screen handles Firebase authentication exceptions:
Error: Account already existsMessage: “El correo ya está en uso.”Triggered when attempting to register with an email that already has an account.
catch (e: FirebaseAuthUserCollisionException) {
    _errorMessage.value = "El correo ya está en uso."
}
Error: Unknown registration failureMessage: “Se produjo un error durante el registro”Catches all other exceptions during registration process.
catch (e: Exception) {
    _errorMessage.value = "Se produjo un error durante el registro"
}

Validation Errors

Error TypeMessageTrigger Condition
Empty Fields”Los campos no pueden estar vacios”Email or password is blank
Invalid Email”El correo no es válido”Email format doesn’t match pattern
Short Password”La contraseña debe tener al menos 6 caracteres”Password length < 6

State Management

Observable State

The screen observes two state flows:
val isLoading by signUpViewModel.isLoading.collectAsState()
val errorMessage by signUpViewModel.errorMessage.collectAsState()

Loading State UI

Conditionally displays progress indicator:
if (isLoading) {
    CircularProgressIndicator(modifier = Modifier.padding(top = 56.dp))
}

Success Navigation

After successful registration, users are automatically navigated to the home screen:
if (result != null) {
    onNavigateToHome()
}

Input Fields

Email TextField

OutlinedTextField(
    value = email,
    onValueChange = { email = it },
    modifier = Modifier.padding(24.dp),
    label = { Text(text = "Correo", color = Color.White) },
    textStyle = TextStyle(Color.White)
)

Password TextField

OutlinedTextField(
    value = password,
    onValueChange = { password = it },
    modifier = Modifier.padding(top = 24.dp),
    label = { Text(text = "Contraseña", color = Color.White) },
    textStyle = TextStyle(Color.White)
)
Both text fields use remember state for local value management:
var email by remember { mutableStateOf("") }
var password by remember { mutableStateOf("") }

Register Button

The registration button is positioned at the bottom of the screen:
Button(
    onClick = {
        signUpViewModel.register(
            email = email,
            password = password,
            onNavigateToHome = onNavigateToHome
        )
    },
    modifier = Modifier
        .fillMaxWidth()
        .align(Alignment.BottomCenter)
        .padding(26.dp)
) {
    Text(text = "Registrarse")
}

Dependencies

Firebase Authentication

import com.google.firebase.auth.FirebaseAuthUserCollisionException

Hilt Dependency Injection

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

Coroutines

import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext

File Location

app/src/main/java/com/ccandeladev/nasaexplorer/ui/signupscreen/
├── SignupScreen.kt
└── SignUpViewModel.kt
Security: Password validation and Firebase authentication ensure secure account creation.

Build docs developers (and LLMs) love