# 38. Android App — Dashboard and Service Screens meta: id: kordant-unified-restructure-38 feature: kordant-unified-restructure priority: P1 depends_on: [kordant-unified-restructure-34, kordant-unified-restructure-35, kordant-unified-restructure-36, kordant-unified-restructure-37] tags: [android, jetpack-compose, dashboard, services, mobile] objective: - Build the main dashboard and all service-specific screens for the Android app. These should mirror the web app's functionality while using native Android UI patterns (lists, cards, bottom sheets, charts). deliverables: - `android/app/src/main/java/com/kordant/android/ui/screens/dashboard/` — Dashboard: - `DashboardScreen.kt` — Main dashboard with scrollable content: - Threat score circular gauge (custom Canvas composable) - Recent alerts list (top 5) - Service summary cards in horizontal scroll or grid - Quick action FABs or chips - Pull-to-refresh with `PullRefreshIndicator` - `AlertDetailScreen.kt` — Alert detail with correlated alerts - `android/app/src/main/java/com/kordant/android/ui/screens/services/` — Service screens: - `DarkWatchScreen.kt` — Watchlist and exposures - `VoicePrintScreen.kt` — Enrollments and analysis history - `SpamShieldScreen.kt` — Stats, rules, number check - `HomeTitleScreen.kt` — Properties, map, changes - `RemoveBrokersScreen.kt` — Broker registry, requests - `android/app/src/main/java/com/kordant/android/ui/screens/settings/` — Settings: - `SettingsScreen.kt` — Account, preferences, family, logout - `android/app/src/main/java/com/kordant/android/viewmodel/` — ViewModels: - `DashboardViewModel.kt`, `DarkWatchViewModel.kt`, `VoicePrintViewModel.kt`, etc. - Each exposes `StateFlow` with Loading, Success, Error states steps: 1. Create screen directories: `dashboard/`, `services/`, `settings/`. 2. **DashboardScreen**: - `LazyColumn` for scrollable content - Threat score: custom `Canvas` composable drawing circular arc with gradient - Alerts section: `LazyRow` or vertical list of `ShieldCard` items - Service cards: `LazyHorizontalGrid` or `Row` of compact cards - Quick actions: `FloatingActionButton` or `Row` of icon buttons - `PullRefreshIndicator` with `rememberPullRefreshState` 3. **AlertDetailScreen**: - `Column` with sections - Severity `ShieldBadge` at top - Description and metadata - Correlated alerts in nested list - Action buttons: "Mark Resolved", "False Positive" 4. **DarkWatchScreen**: - `LazyColumn` with sticky headers for sections - Watchlist items: swipe-to-delete with `SwipeToDismissBox` - Add button → bottom sheet with form - Exposures: tap to navigate to detail 5. **VoicePrintScreen**: - Enrollments section with audio playback (ExoPlayer or MediaPlayer) - "Enroll" FAB → bottom sheet with recording UI - Analysis list with verdict color coding - Recording UI: real-time waveform using `Canvas` + `AudioRecord` 6. **SpamShieldScreen**: - Stats cards at top in `Row` - Rules list with toggle switches - Number check: `ShieldTextField` + check button → result card - "Report spam" FAB 7. **HomeTitleScreen**: - Properties list with addresses - Add property: address search with geocoding - Property detail: Google Maps Compose or static map image - Snapshot history and changes list 8. **RemoveBrokersScreen**: - Broker registry with search and category chips - Request list with status badges and progress bars - Start removal: bottom sheet with broker selection and form 9. **SettingsScreen**: - `LazyColumn` with sections using `ListItem` or custom rows - Account info with avatar - Subscription card with upgrade button - Notification toggles - Theme selection dropdown - Biometric auth toggle - Family group management - Logout button with confirmation dialog 10. **ViewModels**: - Each screen has a `ViewModel` with `StateFlow` - `UiState` sealed class: `Loading`, `Success(data)`, `Error(message)` - Call repository methods, handle errors, expose state - Use `viewModelScope.launch` for coroutines 11. Wire navigation in `AppNavigation.kt`: - Bottom nav routes to dashboard and services - Settings accessible from bottom nav or profile menu - Service screens accessible from dashboard or bottom nav submenu steps: - Unit: Each ViewModel emits correct states for loading/success/error - Unit: DashboardViewModel aggregates data from multiple repositories - Visual: All screens use theme tokens and adapt to dark mode - E2E: Navigate through all service screens and verify data loads - E2E: Perform CRUD operations (add watchlist item, delete enrollment, create rule) acceptance_criteria: - [x] Dashboard displays threat score, alerts, service summaries, and quick actions - [x] All 5 service screens (DarkWatch, VoicePrint, SpamShield, HomeTitle, RemoveBrokers) load and display data - [x] Each service screen supports core CRUD operations - [x] Alert detail shows full information and correlation group - [x] Settings screen allows managing account, preferences, and family - [x] Pull-to-refresh updates dashboard data - [x] All screens show loading skeletons and empty states appropriately - [x] Navigation between screens works with native Android transitions validation: - Launch app, login, and verify dashboard renders with real data - Tap each service tab and verify screen loads - Add a watchlist item in DarkWatch and verify it appears in list - Delete a voice enrollment and verify it disappears - Create a spam rule and verify it applies - Toggle settings and verify preferences persist - Run `./gradlew test` for unit tests notes: - Use native Android patterns: `LazyColumn`/`LazyRow` for lists, `BottomSheet` for modals, `FloatingActionButton` for primary actions, `Chip` for filters. - For the threat score gauge, draw an arc on `Canvas` using `drawArc` with a `SweepGradient` brush. - The map in HomeTitle can use Google Maps Compose (`com.google.maps.android:maps-compose`) or OpenStreetMap. - Voice recording requires microphone permission. Add `RECORD_AUDIO` permission to manifest and request at runtime. - Keep ViewModels separate from UI for testability. ViewModels should own the state and business logic. - Consider using `Paging 3` (`androidx.paging:paging-compose`) for large lists (e.g., alert history, exposure list). - For image loading in lists, use Coil (`io.coil-kt:coil-compose`).