Cardinal Maps is an Android mapping application built with a focus on usability. Material 3 and Material 3 Expressive components are used throughout. The app is based on a model-view-viewmodel architecture (MVVM) and is designed with the principle of separation of concerns in mind to ensure code quality and testability. Hilt is used for dependency injection, Room is used for data persistence. Robolectric, JUnit and mockk are the technologies we use for testing.
## Project Structure
```
cardinal-android/ - Main Android application with Kotlin/Compose
├── app/ - Android app module with UI and business logic
├── context/ - Shared context module
└── gradle/ - Build configuration
cardinal-geocoder/ - Rust-based geocoding engine with UniFFI bindings
-**Material 3 & Material 3 Expressive**: Design system
-**Hilt**: Dependency injection
-**Room**: Database persistence
-**MapLibre GL Native**: Map rendering
-**Rust**: High-performance geocoding engine
### External Services
-**Valhalla**: Open-source routing engine
-**Ferrostar**: Navigation framework
-**Pelias**: Geocoding service (configurable)
### Build Tools
-**Gradle (Kotlin DSL)**: Build system
-**Cargo NDK**: Rust compilation for Android
-**UniFFI**: Rust-Kotlin bindings
-**KSP**: Kotlin Symbol Processing
## Development Setup
### Prerequisites
- Android Studio (latest version)
- JDK 8 or later
- Rust (for building geocoding component)
- Android SDK and NDK
### Building the Project
1. Clone the repository
2. Run `./gradlew build` to build the Android application
3. The Rust geocoding component will be automatically compiled
### Running the Application
- Debug build: `./gradlew installDebug`
- Release build: `./gradlew assembleRelease`
### Debugging Tips
- Use Android Studio's debugger for Kotlin code
- Logcat for runtime logs
- Rust debugger for geocoding component issues
- Chrome DevTools for web-based components
## Development Tips
* Maps applications are inherently complex, and despite our best efforts, some of the logic is very tricky. When writing tests, write only one test at a time, then run it with `./gradlew test` to ensure it passes before moving on.
* The Android ecosystem moves fast, and some of the patterns, components and libraries we use may be from after your knowledge cutoff date. Fortunately, this is not a green-field project. Use the surrounding context to see how things work.
* Run `./gradlew check` regularly.
* We have a comprehensive linting and CI process, so don't concern yourself with unused imports or other trivial tasks.
## Testing
### Test Structure
-**Unit Tests**: Located in `src/test/` for business logic
-**Integration Tests**: Located in `src/androidTest/` for UI components
-**Robolectric**: For testing Android components without device
-**Mockk**: For mocking dependencies in tests
### Running Tests
- Run all tests: `./gradlew test`
- Run specific test: `./gradlew test`
- Run integration tests: `./gradlew connectedAndroidTest`