6.9 KiB
6.9 KiB
34. Android App — Jetpack Compose Foundation, Navigation, and Shared Theme
meta: id: shieldai-unified-restructure-34 feature: shieldai-unified-restructure priority: P1 depends_on: [shieldai-unified-restructure-01, shieldai-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 ShieldAI brand palette with Material3 and dynamic dark mode support.
deliverables:
android/directory with complete Android project:app/build.gradle.kts— App module configurationapp/src/main/AndroidManifest.xml— App manifest with permissionsapp/src/main/java/com/shieldai/android/MainActivity.kt— Entry point withsetContentapp/src/main/java/com/shieldai/android/ShieldAIApp.kt— Application class
android/app/src/main/java/com/shieldai/android/ui/theme/— Theme system:Color.kt— All brand color tokens asColorconstants:BrandPrimary,BrandPrimaryLight,BrandPrimaryDarkBrandAccent,BrandAccentLight,BrandAccentDarkBgPrimary,BgSecondary,BgTertiary(light and dark variants)TextPrimary,TextSecondary,TextTertiarySuccess,Warning,Error,Info
Type.kt— Typography scale using Material3TypographyShape.kt— Corner radius shapes (small, medium, large)Theme.kt—ShieldAIThemecomposable:lightColorScheme()anddarkColorScheme()using Material3dynamicColorsupport for Android 12+ (optional)- Manual theme override state
android/app/src/main/java/com/shieldai/android/navigation/— Navigation:AppNavigation.kt— Navigation host with all routesScreen.kt— Sealed class of all destinations with argumentsBottomNavBar.kt— Bottom navigation with 5 items: Dashboard, Services, Alerts, Settings, AccountNavGraph.kt— Compose Navigation graph definition
android/app/src/main/res/— Resources:mipmap-xxxhdpi/— App icons for all densitiesvalues/themes.xml— Base theme definitionsdrawable/— Vector icons and logos
- Project configuration:
build.gradle.kts(project level) with Kotlin 2.0, Compose BOMsettings.gradle.ktsincluding 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:
- Create
android/directory with standard Android project structure. - Set up Gradle files:
- Root
build.gradle.kts: plugins block withcom.android.application,org.jetbrains.kotlin.android gradle/libs.versions.tomlfor version catalog (recommended)- App
build.gradle.kts:android { compileSdk = 35 defaultConfig { minSdk = 26 targetSdk = 35 applicationId = "com.shieldai.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 }
- Root
- Create theme system:
Color.kt: Define all colors asval BrandPrimary = Color(0xFF4F46E5)etc.Type.kt: CreateTypographywith Inter font (download and add tores/font/)Shape.kt:Shapeswithsmall = RoundedCornerShape(8.dp),medium = 12.dp,large = 16.dpTheme.kt:@Composable fun ShieldAITheme( 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) }
- Create navigation:
Screensealed class:Dashboard,Services,Alerts,Settings,Account,Login,Signup,Onboarding,ServiceDetail(val service: String)AppNavigation.kt:NavHostwithrememberNavController()BottomNavBar.kt:NavigationBarwith 5 items, each with icon and label- Handle auth state: if unauthenticated, show Login as start destination
- Create
MainActivity.kt:setContent { ShieldAITheme { AppNavigation() } }- Handle window insets for edge-to-edge display
- Create
ShieldAIApp.kt:- Application class for initialization (dependency injection setup, if used)
- Add app icons:
- Convert ShieldAI logo SVG to vector drawable (
res/drawable/ic_logo.xml) - Generate mipmap icons using Android Studio's Image Asset Studio
- Convert ShieldAI logo SVG to vector drawable (
- 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 testfor 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 inType.kt.