This file aggregates all Markdown documents in a single place for easy consumption.
Table of Contents
-
- Architecture
-
- Modules
-
- Build and Run
-
- Navigation
-
- Data and Persistence
-
- DI and Configuration
-
- Code Style and Conventions
-
- Contributing
-
- Troubleshooting
-
- FAQ
ETFlux is a modular Android application built with Kotlin and Jetpack Compose that provides market data browsing, watchlist management, and ticker insights. The project demonstrates a clean modular architecture, dependency injection with Koin, persistence with Room, and navigation with the Jetpack Compose Navigation component.
This README provides a quick overview. Extensive documentation is available in the docs/ directory:
- docs/Architecture.md
- docs/Modules.md
- docs/BuildAndRun.md
- docs/Navigation.md
- docs/DataAndPersistence.md
- docs/DIAndConfiguration.md
- docs/CodeStyleAndConventions.md
- docs/Contributing.md
- docs/Troubleshooting.md
- docs/FAQ.md
- Requirements: Android Studio Iguana or newer, JDK 17, Android SDK 24+.
- Clone the repository and open it in Android Studio.
- Build and run the app on a device or emulator. See docs/BuildAndRun.md for details.
Images:
Video:
- App Demo (MP4): View in docs/AppDemo.mp4
+------------------------+ +------------------------+
| app | | shared |
| - Application, DI boot |<----->| UI components, domain |
| - Compose Nav host | | models, networking |
+-----------^------------+ +-----------^------------+
| |
| |
+------+------+ +------+------+
| home | | watchlist |
| Feature: | | Feature: |
| Home, charts| | Watchlists |
+------^------+ +------+-----+
| |
+---------------------+--------------+
|
+-----v------+
| core |
| Room DB, |
| utils, DI |
+------------+
See docs/Architecture.md for details.
- Kotlin, Jetpack Compose, Compose Navigation
- Koin for dependency injection
- Room (SQLite) for local persistence
- Coroutines and Flow for async + reactive state
Add your license information here.
[Source: docs/Architecture.md]
This document explains the architecture of ETFlux and how the modules interact.
ETFlux is organized into multiple Gradle modules with clear responsibilities:
- app: Application entry point, DI bootstrap (Koin), Compose Navigation host, and overall wiring.
- core: Core services such as Room database, entities, DAOs, utilities, and core DI module.
- home: Feature module implementing the Home screens, networking for home data, ViewModels, and state.
- watchlist: Feature module implementing Watchlist screens, repository, ViewModel, and state.
- shared: Shared UI elements (Compose components), common networking interfaces, shared domain models, and DI wiring.
The app follows a layered approach within features:
- data: networking/DAO access
- domain: domain models and repositories
- presentation: Jetpack Compose UI + ViewModels + UI state classes
- app depends on: core, home, watchlist, shared
- home depends on: core, shared
- watchlist depends on: core, shared
- shared may depend on: core (for some utilities) where needed
- core is independent (no feature depends cycles)
Koin DI modules wire dependencies at runtime. See DIAndConfiguration.md for details.
- UI (Compose) interacts with ViewModels (presentation layer)
- ViewModels call Repositories (domain layer)
- Repositories orchestrate data from Network (shared/home) and Room (core) via DAOs
- Data returned as Kotlin Flows or suspend functions
- Coroutines for background tasks
- StateFlows and immutable UI state classes (e.g., HomeScreenDataState, TickerDataState, WatchListDataState)
- Compose observes state via collectAsState
- Repository returns Results/Resource wrappers (see shared/domain/Resources.kt)
- UI reacts to Loading/Success/Error
Navigation is centralized in app module:
- EtFluxApplication initializes Koin
- Navigation.kt defines type-safe routes using Kotlin serialization for complex arguments (e.g., TickerInfoRoute with JSON-encoded Data).
- Feature screens (HomeScreen, GainerScreen, etc.) are registered as composable destinations.
See Navigation.md for examples and route classes.
- Room database defined in core/db/AppDataBase with entities:
- ImageDataEntity, GainersEntity, LosersEntity, TickerInfoEntity, MonthlyStockEntity, WatchlistEntity, BookmarkEntity
- DAOs provide queries for each entity
- Version = 5; schemas are exported under core/schemas for migration tracking
See DataAndPersistence.md for more details.
[Source: docs/Modules.md]
This document lists each Gradle module and its responsibilities.
- EtFluxApplication bootstraps Koin (see app/src/main/java/org/soumen/etflux/EtFluxApplication.kt)
- DI initialization in di/InitKoin.kt aggregates modules: mainModule (app), HomeModule (home), sharedModule (shared), coreModule (core), watchlistModule (watchlist)
- Navigation host in presentation/presentation/Navigation.kt defines routes and destinations.
- Room database (core/src/main/java/org/soumen/core/db/AppDataBase.kt)
- Entities in core/db/entities and DAOs in core/db/dao
- Core DI module (core/src/main/java/org/soumen/core/di/Module.kt)
- Utilities (e.g., status bar helpers)
- Networking: data/networking/api/HomeScreenApiService.kt and response models
- Domain models under domain/dataModels
- Repository interface/implementation under domain/repository
- UI: presentation/screens (HomeScreen, GainerScreen, etc.), state classes, and HomeViewModel
- DI module (home/src/main/java/org/soumen/home/di/Module.kt)
- Domain models under domain/datamodules
- Repository (watchlist/domain/WatchlistRepository.kt)
- UI: WatchlistScreen, WatchListItemsScreen, states, and WatchlistViewModel
- DI module (watchlist/src/main/java/org/soumen/watchlist/di/Module.kt)
- Shared UI components: presentation/bottomBar (Bottom bar items and components)
- Shared networking services (e.g., ImageApiService, TickerInfoApiService)
- Shared domain Resource wrapper (shared/src/main/java/org/soumen/shared/domain/Resources.kt)
- DI module (shared/src/main/java/org/soumen/shared/di/Module.kt)
[Source: docs/BuildAndRun.md]
Add the following entries to your local.properties (do not commit this file):
apikey=Q1888W3LTE7H3P5N
baseApi=www.alphavantage.co/query
baseImageApi=api.api-ninjas.com/v1/logo
imageApiKey=8NGwfRX4yrde9RLammaw5w==dGmi306WIkg7raA2
clearbitApiKey=pk_cW4oyjgyR0Sj0WIxpBfKfA
Note: local.properties is machine-specific and should not be committed. Ensure gradle sync picks up these properties via your module Gradle files or BuildConfig usage.
- Android Studio Iguana or newer
- JDK 17
- Android SDK 24+
- Kotlin 1.9+ (managed by Gradle)
- git clone
- Open the project in Android Studio
- Let Gradle sync finish
- Select the
appconfiguration and click Run. - Minimum supported device API is 24.
- ./gradlew assembleDebug
- ./gradlew :app:installDebug
- ./gradlew testDebugUnitTest
- ./gradlew connectedDebugAndroidTest
If flavors are defined (e.g., development/release), select them in Build Variants. The project includes generated buildConfig for development; adjust as needed.
- API keys or endpoints should be configured in
coreorsharedconfigs (e.g., ApiConfigs). Avoid committing secrets. - Use local.properties or Gradle properties for local overrides.
[Source: docs/Navigation.md]
Navigation is implemented using Jetpack Compose Navigation in the app module.
- The
Navigationcomposable in app/src/main/java/org/soumen/etflux/presentation/presentation/Navigation.kt hosts all routes. - It sets up bottom bar destinations and feature screens.
- TickerInfoRoute: uses Kotlin serialization to pass a
Dataobject as JSON. - IndividualWatchlistScreenRoute: passes a
watchlistID: Longas an argument.
Example route definitions (see actual code for details):
@Serializable
class TickerInfoRoute(val tickerJson: String)
class IndividualWatchlistScreenRoute(val watchlistID: Long)- Uses fade and slide animations (tween) for enter/exit transitions.
- Complex objects are serialized to JSON with kotlinx.serialization Json.
- Primitive args (Long, String) are part of the type-safe route.
- Screen-level ViewModels are provided by Koin and passed or retrieved in composables.
- Keep arguments small; prefer IDs and load details in destination when possible.
- Ensure types are serializable if passing as JSON.
[Source: docs/DataAndPersistence.md]
This project uses Room for local data persistence and Retrofit/HTTP clients for remote data (in feature/shared modules).
- Database: core/src/main/java/org/soumen/core/db/AppDataBase.kt
- Version: 5
- Entities:
- ImageDataEntity
- GainersEntity
- LosersEntity
- TickerInfoEntity
- MonthlyStockEntity
- WatchlistEntity
- BookmarkEntity
- DAOs:
- ImageEntityDao, GainersLosersEntityDao, TickerEntityDao, MonthlyStockEntityDao, WatchlistEntityDao, BookmarkEntityDao
- Singleton access: AppDataBase.getDatabase(context) is provided for non-DI scenarios; the app uses DI (Koin) to provide the database/DAOs via
coreModule.
- Room schemas are exported under core/schemas/org.soumen.core.db.AppDataBase/ for historical versions.
- When changing entities, bump version and add a proper migration.
- Home and Watchlist modules include repositories that mediate between DAOs and network services.
- Repositories return Resource/Result wrappers (see shared/domain/Resources.kt) to represent loading, success, and error states.
- Keep DAO methods small and specific.
- Use Flow for observing tables that change.
- For large objects, store only necessary fields.
[Source: docs/DIAndConfiguration.md]
Koin is used for dependency injection and module wiring.
- EtFluxApplication.onCreate calls
initKoin { androidContext(appContext) }. initKoin(app/di/InitKoin.kt) callsstartKoin { modules(...) }and aggregates:- mainModule (app)
- HomeModule (home)
- sharedModule (shared)
- coreModule (core)
- watchlistModule (watchlist)
val watchlistModule = module {
single { WatchlistRepository(get(), get()) }
viewModel { WatchlistViewModel(watchlistRepository = get()) }
}- Repositories receive dependencies via
get()(e.g., DAOs, network services provided by core/shared modules). - ViewModels are declared with
viewModel { ... }and can be retrieved in Compose via koin or passed down.
- Decide the owning module (feature/core/shared).
- Create a Koin module provider there.
- Expose required classes via
single,factory, orviewModel. - Add the module to
initKoinif it is a new module.
- Use Gradle properties and BuildConfig fields as needed per module.
- Avoid hardcoding secrets; prefer local.properties or environment variables.
[Source: docs/CodeStyleAndConventions.md]
- Use Kotlin official coding conventions.
- Prefer immutable data classes for UI state.
- Use explicit visibility modifiers where helpful.
- Use viewModelScope in ViewModels.
- Expose StateFlow for UI states.
- Keep composables small and stateless where possible; hoist state to ViewModel.
- Follow Material 3 theming via app/ui/theme.
- Preview composables with @Preview for fast iteration.
- Place feature-specific code in feature modules; avoid cross-feature imports not via shared/core.
- Keep public APIs of modules minimal.
- Unit tests under src/test; instrumented tests under src/androidTest.
- Suffix DAO with Dao, Entity with Entity, ViewModels with ViewModel, etc.
- Update docs/ when adding modules or changing architecture.
[Source: docs/Contributing.md]
Thanks for considering contributing to ETFlux!
- Fork the repo and create a feature branch.
- Follow the existing module boundaries and code conventions.
- Add/update tests where applicable.
- Update documentation under docs/ when making architectural changes.
- Open a pull request with a clear description.
- Use concise, descriptive messages. Prefix with module if useful (e.g., "watchlist: fix delete flow").
- Keep PRs focused and under ~300 lines when possible.
- Provide context and screenshots/gifs for UI changes.
- Include steps to reproduce, expected vs actual, logs if available, and device/environment details.
[Source: docs/Troubleshooting.md]
- Invalidate caches/restart Android Studio.
- Ensure JDK 17 is configured.
- Check gradle.properties and wrapper versions.
- Ensure schema version in AppDataBase matches exported schema changes.
- Provide proper Migration objects if altering tables.
- Verify EtFluxApplication is registered in AndroidManifest.xml.
- Ensure initKoin is called and all modules are included.
- Confirm API keys/endpoints and internet permission in AndroidManifest.
- Use @Preview and provide mock ViewModel/state.
- Update Android Studio to latest Canary/Stable version if needed.
[Source: docs/FAQ.md]
A modular Android app demonstrating market data browsing, watchlists, and charts using Kotlin and Compose.
Koin.
API 24.
Locally with Room (SQLite). Remote data via networking in feature/shared modules.
- app module: EtFluxApplication and Navigation.kt
- home and watchlist modules for feature logic
- core for database and utilities
- shared for common components and services
- Create a new Gradle module.
- Add your DI module and include it in initKoin.
- Expose your navigation destinations and integrate with NavHost.





