An Android currency conversion app built with Jetpack Compose and Material Design 3. Converts currencies in real-time using the ExchangeRate-API. Contains features such as
- currency search, selection, and conversion
- adaptive layouts for portrait and landscape
- light and dark themes
- success, loading, and error states when fetching data
- a custom numeric keypad for a sleek feel
- emoji country flag display
Three-layer clean architecture:
| Layer | Responsibility | Technology |
|---|---|---|
| Presentation | UI screens, ViewModels, Compose components | Jetpack Compose, M3, Navigation Compose |
| Domain | Business models, use cases, repository interfaces | Pure Kotlin |
| Service | Remote data, API, DTOs, dependency injection | Retrofit, OkHttp, Koin |
com.example.currencyconverter/
├── domain/
│ ├── model/ # CurrencyCode, Currency, ConversionQuote, CurrencyResult, DomainError
│ ├── repository/ # ExchangeRatesRepository interface
│ ├── usecase/ # ConvertCurrencyUseCase, GetSupportedCurrenciesUseCase
│ └── util/ # CurrencyFlagProvider (emoji flag mapping)
├── presentation/
│ ├── components/ # Shared UI: CurrencyKeypad, CurrencySelector, AdaptiveLayout, etc.
│ ├── currencyconversion/ # Conversion result screen + ViewModel
│ ├── currencyinput/ # Currency selection + amount input screen + ViewModel
│ ├── currencyselection/ # Currency picker bottom sheet + ViewModel
│ ├── navigation/ # Navigation graph
│ └── theme/ # Material 3 theme with dynamic colors
└── service/
├── di/ # Koin modules
├── dto/ # API response DTOs (kotlinx.serialization)
├── mapper/ # DTO → Domain model mappers
├── remote/ # Retrofit API interface
└── repository/ # RemoteExchangeRatesRepository implementation
- Get a free API key from ExchangeRate-API
- Add the key to
local.properties:
EXCHANGE_RATE_API_KEY=your_api_key_here- Rebuild the project.
# Assemble debug APK
./gradlew :app:assembleDebug
# Run unit tests
./gradlew :app:testDebugUnitTest
# Run instrumented (UI) tests (requires connected device/emulator)
./gradlew :app:connectedDebugAndroidTest- 63 unit tests covering domain models, utilities, repository (with MockWebServer), and all three ViewModels
- Compose UI tests for CurrencyInputScreen and CurrencyConversionScreen (in
app/src/androidTest/) - Uses
FakeExchangeRatesRepositoryfor ViewModel tests — no real network calls - Uses
kotlinx-coroutines-testwithStandardTestDispatcherfor deterministic coroutine testing
9 hours total across 2 days.
- Spent 2 hours writing and refining main AI prompt with assistance from GPT-5.6 Sol, describing all specifications. You can find the prompt here.
- Spent 1 hour running prompt with Deepseek v4 Pro (these model choices are not personal preference, they were picked experimentally).
- Spent 2 hours validating prompt results, fixing issues, and steering the model to strictly follow the specifications.
- Spent 4 hours polishing design, refactoring code, fixing edge cases, and manually testing.
Additionally, after the deadline, some tests were not updated after a final refactoring, so some time was spent fixing those tests in a separate branch called feature/test-coverage-report. More tests were also written, doubling the number of total tests.