Initial commit: Kecalek Android client
Complete Android client for encrypted chat platform. 78+ Kotlin files: crypto (X3DH, Double Ratchet, AES-GCM, Ed25519, X25519, RSA-PSS), network (TCP/TLS, 50 endpoints), Hilt DI, Room+SQLCipher DB, Jetpack Compose UI with Catppuccin Mocha theme. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
160
specs/agent-d-auth-screens.md
Normal file
160
specs/agent-d-auth-screens.md
Normal file
@@ -0,0 +1,160 @@
|
||||
# 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<AuthUiState> = _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)
|
||||
Reference in New Issue
Block a user