A modern Android application built with Jetpack Compose that displays real-time price updates for 25 stock symbols using WebSocket communication. The app connects to a WebSocket echo server, sends mock price updates every 2 seconds, and displays live data in a clean, scrollable interface.
Live demo showing real-time price updates, theme switching, and connection management
| Dark theme (Disconnected) | Light theme | Dark theme with live updates |
Key UI Features Shown:
- π¨ Dual Theme Support: Seamless light/dark mode with moon/sun toggle
- π΄π’ Connection Status: Visual indicator (red = disconnected, green = connected)
- π Real-time Updates: Price changes with β²/βΌ indicators and percentage changes
- π― Clean Design: Material 3 with rounded cards and company logos
- π± Sorted List: Automatically sorted by price (highest to lowest)
- Real-time Price Tracking: Monitor 25 major stock symbols (AAPL, GOOG, TSLA, NVDA, etc.)
- Live WebSocket Connection: Connects to
wss://ws.postman-echo.com/rawfor real-time data exchange - Visual Price Indicators: Green β for price increases, Red β for decreases
- Price Flash Animation: Visual feedback with 1-second color flash on price changes
- Dynamic Sorting: Automatically sorts stocks by price (highest to top)
- Connection Management: Start/Stop button with connection status indicator
- Theme Support: Light and Dark theme with system default option
- Clean Architecture: Multi-module structure with clear separation of concerns
- Comprehensive Testing: Unit tests for business logic and UI tests for all Compose components
All optional bonus requirements from the challenge have been implemented:
- β Price Flash Animation: Prices flash green for 1 second on increase, red on decrease
- β Comprehensive Testing: Full test coverage including Compose UI tests for all components and screens
- β Theme Support: Complete light/dark theme implementation with system default option
This project follows Clean Architecture with MVVM (Model-View-ViewModel) pattern in a multi-module structure:
βββββββββββββββββββββββββββββββββββββββββββββββ
β App (Presentation) β
β β’ Jetpack Compose UI β
β β’ ViewModels + StateFlow β
β β’ Immutable UI State β
ββββββββββββββββ¬βββββββββββββββββββββββββββββββ
β
ββββββββββββββββΌβββββββββββββββββββββββββββββββ
β Domain (Business Logic) β
β β’ Use Cases (Single Responsibility) β
β β’ Repository Interfaces β
β β’ Domain Models β
ββββββββββββββββ¬βββββββββββββββββββββββββββββββ
β
ββββββββββββββββΌβββββββββββββββββββββββββββββββ
β Data (Data Layer) β
β β’ Repository Implementations β
β β’ WebSocket Manager (OkHttp) β
β β’ DataStore (Theme Persistence) β
βββββββββββββββββββββββββββββββββββββββββββββββ
π Detailed Architecture Breakdown
App Module (Presentation Layer)
TrackerScreen&StockListItem: Compose UI componentsTrackerViewModel&MainViewModel: State management with StateFlow- Observes domain use cases and exposes immutable UI state
Domain Module (Pure Kotlin)
- Use Cases:
ObserveStockPricesUseCase,StartConnectionUseCase,StopConnectionUseCase, etc. - Repository Interfaces: Define contracts for data operations
- Models: Domain entities (Stock, ConnectionState)
- Completely independent of Android framework
Data Module
- Repositories:
StockRepositoryImpl,ConnectionRepositoryImpl,ThemeRepositoryImpl - WebSocketManager: Handles real-time connection with OkHttp
- StockPriceCoordinator: Generates mock price updates every 2 seconds
- StockDataSource: 25 stock symbols with metadata
View (Compose) βββΊ ViewModel βββΊ Use Case βββΊ Repository Interface
β β
StateFlow ββββββββββββββββββββββββββββ
β
Repository Impl βββΊ WebSocket/DataStore
Key Benefits: Separation of concerns β’ Testability β’ Scalability β’ Maintainability
Dependency Injection: Hilt with @HiltViewModel and @Singleton scopes
State Management: StateFlow for reactive UI β’ Immutable state β’ Unidirectional data flow
- Android Studio: Ladybug | 2024.2.1 or newer
- JDK: Java 17 (included in Android Studio)
- Minimum SDK: API 24 (Android 7.0)
- Target SDK: API 36 (Android 15)
-
Clone the repository:
git clone <repository-url> cd TrackerApp
-
Open in Android Studio:
- Launch Android Studio
- Select "Open an existing project"
- Navigate to the
TrackerAppdirectory and select it
-
Sync Gradle:
- Android Studio should automatically trigger a Gradle sync
- If not, click "File" β "Sync Project with Gradle Files"
- Wait for dependencies to download (first sync may take a few minutes)
-
Run on Emulator or Device:
- Emulator: Create an AVD (Android Virtual Device) via "Device Manager"
- Recommended: Pixel 5 or newer with API 34+
- Physical Device: Enable USB debugging in Developer Options
- Click the green "Run" button (
βΆοΈ ) or pressShift + F10
- Emulator: Create an AVD (Android Virtual Device) via "Device Manager"
-
Verify the App:
- The app should launch with 25 stock symbols displayed
- Tap the "Start" button in the top bar to begin real-time updates
- Observe prices updating every 2 seconds with animations
- Check the connection indicator (β) showing Connected/Disconnected status
# Build debug APK
./gradlew assembleDebug
# Install on connected device
./gradlew installDebug
# Run all tests
./gradlew test
# Run connected tests (requires device/emulator)
./gradlew connectedAndroidTest- Build fails: Ensure you have Java 17 configured in Android Studio settings
- Dependencies not downloading: Check your internet connection and proxy settings
- WebSocket not connecting: Verify network permissions and internet access
- App crashes on start: Check Logcat for stack traces; ensure minimum SDK 24
Comprehensive test coverage at all layers with JUnit 4, MockK, Turbine, and Compose Testing.
# Run all tests
./gradlew test # Unit tests
./gradlew connectedAndroidTest # UI tests (requires device/emulator)Coverage Summary:
- β Unit Tests: ViewModels β’ Repositories β’ Business Logic β’ UI State
- β UI Tests: Screen interactions β’ Component rendering β’ Animations β’ State changes
π Detailed Test Coverage
- ViewModels:
TrackerViewModelTest,MainViewModelTest - Repositories:
StockRepositoryImplTest,ConnectionRepositoryImplTest,ThemeRepositoryImplTest - Business Logic:
StockPriceCoordinatorTest,WebSocketManagerTest - UI State:
TrackerUIStateTest
- Screens:
TrackerScreenTest- Full screen interaction and state verification - Components:
StockListItemTest,TopBarTest,ConnectionStatusIndicatorTest
- JUnit 4 + MockK for mocking β’ Turbine for Flow testing
- Coroutines Test for suspend functions β’ Compose Testing with semantic matchers
- Test Tags for reliable UI element identification
π Key Assumptions
- Mock Data: Random price generation ($50-$500 range, Β±5% changes) for demo purposes
- Echo Server: Using Postman Echo Server; production would use real stock API
- Stock List: Fixed 25 major tech/financial stocks (extensible in future)
- Connectivity: Requires internet; basic error handling, no offline mode
- Persistence: Only theme preference saved; prices reset on restart (intentional)
βοΈ Architecture Trade-offs
| Decision | Benefits β | Costs β | Rationale |
|---|---|---|---|
| Multi-module Architecture | Clean separation, maintainable, scalable | More boilerplate, setup time | Production-ready structure |
| WebSocket vs Polling | Real-time, low latency, less bandwidth | Complex management, battery | Required by challenge, better UX |
| Single StateFlow | Atomic updates, simpler testing | Potential recomposition overhead | @Immutable enables smart recomposition |
| Price Gen in Data Layer | Pure domain, easy API swap | Slightly impure data layer | Demo-appropriate, swappable |
| Coordinator Pattern | Centralized timing control | Couples generation + network | Cleaner lifecycle management |
| No Caching/Room | Simpler, always fresh data | No offline support | Sufficient for demo scope |
| Hilt DI | Type-safe, less boilerplate | Longer build times | Industry standard |
| StateFlow over LiveData | Compose-friendly, coroutine integration | Less mature ecosystem | Modern approach |
| Comprehensive Testing | High confidence, early bug detection | Time investment, build overhead | Quality assurance priority |
| Simple Error Handling | Focused on core functionality | Limited user feedback | Demo scope, extensible |
| Category | Technology |
|---|---|
| Language | Kotlin 2.2.21 |
| UI Framework | Jetpack Compose (BOM 2025.11.01) |
| Architecture | MVVM + Clean Architecture |
| Dependency Injection | Hilt 2.57.2 |
| Async | Kotlin Coroutines 1.10.2 |
| Networking | OkHttp 5.3.2 (WebSocket) |
| JSON | Gson 2.13.2 |
| Storage | DataStore Preferences 1.1.1 |
| Image Loading | Coil (if logos are displayed) |
| Testing | JUnit 4, MockK 1.14.6, Turbine 1.2.1 |
| Build System | Gradle 8.13.1 with Kotlin DSL |
TrackerApp/
βββ app/ # UI Layer (Compose, ViewModels, 3 unit tests, 4 UI tests)
βββ domain/ # Business Logic (Use Cases, Repository Interfaces)
βββ data/ # Data Layer (Repositories, WebSocket, DataStore, 5 tests)
π Detailed File Structure
app/
βββ src/main/java/com/tracker/app/
β βββ TrackerApplication.kt # Hilt application
β βββ base/BaseViewModel.kt
β βββ ui/
β β βββ MainActivity.kt # Entry point
β β βββ MainViewModel.kt # Theme management
β β βββ components/ # StockListItem, TopBar, etc.
β β βββ screen/ # TrackerScreen + ViewModel + UIState
β β βββ theme/ # Compose theme
β β βββ model/ # UI models
β βββ tools/PriceFlashAnimation.kt
βββ src/test/ # 3 unit tests
βββ src/androidTest/ # 4 UI tests
domain/src/main/java/com/tracker/domain/
βββ base/ # BaseUseCase, BaseFlowUseCase
βββ connection/ # 3 use cases + ConnectionState model
βββ stock/ # ObserveStockPricesUseCase + Stock model
βββ theme/ # 2 theme use cases
βββ error/ # ErrorConverter
βββ di/DomainModule.kt
data/
βββ src/main/java/com/tracker/data/
β βββ connection/ # WebSocketManager + ConnectionRepositoryImpl
β βββ stock/ # StockDataSource + Coordinator + RepositoryImpl
β βββ theme/ # ThemeRepositoryImpl (DataStore)
β βββ di/DataModule.kt
βββ src/test/ # 5 unit tests