# Agent D: Auth Screens ## Phase: 2 (UI Shells) ## Depends on: Agent A (project), Agent B (theme + navigation) ## Context You are building authentication screens for "Kecalek" encrypted chat app. The login uses RSA challenge-response (no password sent to server). Registration requires email verification code. Device pairing allows linking a new device to an existing account. ## Task Create Login, Register, Pairing screens and AuthViewModel skeleton. ## Files to Create ### 1. ui/auth/LoginScreen.kt Jetpack Compose screen with: - **App title** "Kecalek" at the top (headlineLarge) - **Subtitle** "Encrypted Messaging" (bodyMedium, Subtext1 color) - **Email/Username** text field (OutlinedTextField, Surface1 background) - **Password** text field (password visibility toggle icon) - **Login button** (filled, Lavender primary, full width) - **"Create Account"** text button below (navigates to Register) - **"Link Device"** text button below (navigates to Pairing) - **Server config section** (expandable/collapsible): - Host text field (default: "chat.ai-tech.news") - Port text field (default: "9999") - TLS toggle switch (default: off) - **Loading state**: CircularProgressIndicator replacing login button - **Error state**: Red error text below password field - **Biometric login button** (fingerprint icon, shown only if biometric available) **Layout**: Centered vertically, max width 400dp, padding 24dp. ### 2. ui/auth/RegisterScreen.kt Jetpack Compose screen with: - **Back arrow** in top bar (navigates back) - **Title** "Create Account" - **Username** text field - **Email** text field - **Password** text field (with visibility toggle) - **Confirm Password** text field - **Register button** (filled, Lavender, full width) - **Confirmation code section** (shown after successful registration): - Info text "Check your email for a verification code" - 6-digit code input field - Confirm button - **Loading state** + **Error state** (same pattern as Login) ### 3. ui/auth/PairingScreen.kt Jetpack Compose screen with: - **Back arrow** in top bar - **Title** "Link New Device" - **Info text** explaining pairing process - **8-digit pairing code** displayed prominently (headlineLarge, monospace, letter-spacing) - **Countdown timer** or progress indicator showing poll status - **"Waiting for authorization..."** text with animated dots - **Cancel button** (outlined) - **Status messages**: "Device authorized", "Pairing failed", etc. ### 4. ui/auth/AuthViewModel.kt ```kotlin package com.kecalek.chat.ui.auth import androidx.lifecycle.ViewModel import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.asStateFlow import javax.inject.Inject data class AuthUiState( val isLoading: Boolean = false, val error: String? = null, val isLoggedIn: Boolean = false, val isRegistered: Boolean = false, val needsConfirmation: Boolean = false, val pairingCode: String? = null, val isPairingWaiting: Boolean = false, val serverHost: String = "chat.ai-tech.news", val serverPort: Int = 9999, val useTls: Boolean = false, val biometricAvailable: Boolean = false, ) @HiltViewModel class AuthViewModel @Inject constructor( // TODO: Inject ChatClient, SessionManager ) : ViewModel() { private val _uiState = MutableStateFlow(AuthUiState()) val uiState: StateFlow = _uiState.asStateFlow() fun login(emailOrUsername: String, password: String) { // TODO: Implement RSA challenge-response login // 1. ChatClient.login(email, password) // 2. On success: navigate to ConversationList // 3. On failure: show error } fun register(username: String, email: String, password: String) { // TODO: Implement registration // 1. ChatClient.register(username, email, password) // 2. On success: show confirmation code input // 3. On failure: show error } fun confirmRegistration(email: String, code: String) { // TODO: Confirm with 6-digit code // 1. ChatClient.confirm_registration(email, code) // 2. On success: auto-login } fun startPairing() { // TODO: Start device pairing // 1. ChatClient.pairing_start() -> get 8-digit code // 2. Show code to user // 3. Start polling for authorization } fun loginWithBiometric() { // TODO: Biometric authentication } fun updateServerConfig(host: String, port: Int, useTls: Boolean) { _uiState.value = _uiState.value.copy( serverHost = host, serverPort = port, useTls = useTls, ) } fun clearError() { _uiState.value = _uiState.value.copy(error = null) } } ``` ## Reference: iOS LoginView behavior - Login/Register are modes of the same view (iOS uses toggle tabs) - Server configuration is expandable (collapsed by default) - Biometric login uses Face ID/Touch ID - Error messages appear below the form - Loading spinner replaces the action button ## Constraints - Use Material 3 components (OutlinedTextField, FilledTonalButton, etc.) - Use `CatppuccinMocha` colors from theme - Use `hiltViewModel()` for ViewModel injection - All screens receive `navController: NavHostController` parameter - Password fields must have visibility toggle - Support keyboard "Done" action to submit form - Use `rememberSaveable` for form state to survive config changes ## DO NOT - Implement actual login/register/pairing logic (just skeleton functions) - Handle cryptographic operations - Store credentials or keys - Modify navigation graph (screen placeholders already exist)