# 34. Android App — Jetpack Compose Foundation, Navigation, and Shared Theme meta: id: kordant-unified-restructure-34 feature: kordant-unified-restructure priority: P1 depends_on: [kordant-unified-restructure-01, kordant-unified-restructure-02] tags: [android, jetpack-compose, foundation, navigation, mobile] objective: - Establish the Android app foundation in `android/`: a Jetpack Compose project with app entry point, navigation architecture, and a shared theme system that mirrors the web app's Kordant brand palette with Material3 and dynamic dark mode support. deliverables: - `android/` directory with complete Android project: - `app/build.gradle.kts` — App module configuration - `app/src/main/AndroidManifest.xml` — App manifest with permissions - `app/src/main/java/com/kordant/android/MainActivity.kt` — Entry point with `setContent` - `app/src/main/java/com/kordant/android/KordantApp.kt` — Application class - `android/app/src/main/java/com/kordant/android/ui/theme/` — Theme system: - `Color.kt` — All brand color tokens as `Color` constants: - `BrandPrimary`, `BrandPrimaryLight`, `BrandPrimaryDark` - `BrandAccent`, `BrandAccentLight`, `BrandAccentDark` - `BgPrimary`, `BgSecondary`, `BgTertiary` (light and dark variants) - `TextPrimary`, `TextSecondary`, `TextTertiary` - `Success`, `Warning`, `Error`, `Info` - `Type.kt` — Typography scale using Material3 `Typography` - `Shape.kt` — Corner radius shapes (small, medium, large) - `Theme.kt` — `KordantTheme` composable: - `lightColorScheme()` and `darkColorScheme()` using Material3 - `dynamicColor` support for Android 12+ (optional) - Manual theme override state - `android/app/src/main/java/com/kordant/android/navigation/` — Navigation: - `AppNavigation.kt` — Navigation host with all routes - `Screen.kt` — Sealed class of all destinations with arguments - `BottomNavBar.kt` — Bottom navigation with 5 items: Dashboard, Services, Alerts, Settings, Account - `NavGraph.kt` — Compose Navigation graph definition - `android/app/src/main/res/` — Resources: - `mipmap-xxxhdpi/` — App icons for all densities - `values/themes.xml` — Base theme definitions - `drawable/` — Vector icons and logos - Project configuration: - `build.gradle.kts` (project level) with Kotlin 2.0, Compose BOM - `settings.gradle.kts` including app module - Min SDK: 26 (Android 8.0), Target SDK: 35, Compile SDK: 35 - Kotlin version: 2.0.0 - Compose BOM: 2024.05.00 or latest stable steps: 1. Create `android/` directory with standard Android project structure. 2. Set up Gradle files: - Root `build.gradle.kts`: plugins block with `com.android.application`, `org.jetbrains.kotlin.android` - `gradle/libs.versions.toml` for version catalog (recommended) - App `build.gradle.kts`: ```kotlin android { compileSdk = 35 defaultConfig { minSdk = 26 targetSdk = 35 applicationId = "com.kordant.android" } buildFeatures { compose = true } composeOptions { kotlinCompilerExtensionVersion = "1.5.14" } } dependencies { implementation(platform("androidx.compose:compose-bom:2024.05.00")) implementation("androidx.compose.ui:ui") implementation("androidx.compose.material3:material3") implementation("androidx.navigation:navigation-compose:2.7.7") // ... other deps } ``` 3. Create theme system: - `Color.kt`: Define all colors as `val BrandPrimary = Color(0xFF4F46E5)` etc. - `Type.kt`: Create `Typography` with Inter font (download and add to `res/font/`) - `Shape.kt`: `Shapes` with `small = RoundedCornerShape(8.dp)`, `medium = 12.dp`, `large = 16.dp` - `Theme.kt`: ```kotlin @Composable fun KordantTheme( darkTheme: Boolean = isSystemInDarkTheme(), dynamicColor: Boolean = false, // disable for brand consistency content: @Composable () -> Unit ) { val colorScheme = when { dynamicColor && Build.VERSION.SDK_INT >= 31 -> { if (darkTheme) dynamicDarkColorScheme(LocalContext.current) else dynamicLightColorScheme(LocalContext.current) } darkTheme -> DarkColorScheme else -> LightColorScheme } MaterialTheme(colorScheme = colorScheme, typography = Typography, shapes = Shapes, content = content) } ``` 4. Create navigation: - `Screen` sealed class: `Dashboard`, `Services`, `Alerts`, `Settings`, `Account`, `Login`, `Signup`, `Onboarding`, `ServiceDetail(val service: String)` - `AppNavigation.kt`: `NavHost` with `rememberNavController()` - `BottomNavBar.kt`: `NavigationBar` with 5 items, each with icon and label - Handle auth state: if unauthenticated, show Login as start destination 5. Create `MainActivity.kt`: - `setContent { KordantTheme { AppNavigation() } }` - Handle window insets for edge-to-edge display 6. Create `KordantApp.kt`: - Application class for initialization (dependency injection setup, if used) 7. Add app icons: - Convert Kordant logo SVG to vector drawable (`res/drawable/ic_logo.xml`) - Generate mipmap icons using Android Studio's Image Asset Studio 8. Build and run on Android Emulator to verify app launches. steps: - Unit: Theme switches correctly between light and dark modes - Unit: Navigation graph contains all expected destinations - Visual: App launches with correct bottom navigation and branding - Visual: Theme colors match web app palette in both modes acceptance_criteria: - [ ] Android app builds and launches without crashes - [ ] Bottom navigation has 5 tabs with correct icons and labels - [ ] Theme colors match web app palette in both light and dark modes - [ ] Navigation between screens works with native Android transitions - [ ] App icon displays correctly on launcher - [ ] Theme supports manual override (light/dark/system) - [ ] Project uses modern Android stack: Kotlin 2.0, Compose, Material3 validation: - Build app in Android Studio and run on Pixel 7 emulator (API 34) - Toggle device dark mode and verify all colors shift - Navigate through all bottom tabs and verify transitions - Verify app icon on emulator home screen - Run `./gradlew test` for unit tests notes: - The Android app should feel native to Android, not like an iOS port. Use Material3 components, bottom sheets, floating action buttons, and Android-specific patterns. - Dynamic colors (Material You) are disabled by default to maintain brand consistency. Can be enabled as a user preference later. - Use Jetpack Compose Navigation with type-safe navigation arguments (Kotlin DSL or Navigation Compose 2.8+ typed navigation). - Consider using Hilt for dependency injection, but keep it simple for the initial setup. - The `android/` directory is not part of the pnpm workspace. It is a standalone Gradle project. - For font loading, add Inter font files to `res/font/` and reference them in `Type.kt`.