Skip to content

omsharma0401/mf-explorer

Repository files navigation

Mutual Fund Explorer – Technical Documentation

Mutual Fund Explorer is an offline-first Android application designed to discover, search, and track mutual funds. It focuses on local caching, pagination, background synchronization, and a strict Single Source of Truth architecture

1. System Architecture

The application implements the Model-View-ViewModel (MVVM) architecture with Clean Architecture principles.

  • Data Layer: Handles all data operations, including API requests via Retrofit and local caching via Room. Repositories act as mediators.
  • UI Layer: Implemented entirely in Jetpack Compose. Screens observe state exclusively through StateFlow exposed by ViewModels.
  • Single Source of Truth: The UI strictly observes the local Room database to render arrays and states. The network layer merely acts as a synchronization mechanism responsible for populating the cache rather than pushing to the view.

2. Offline-First & Local Caching (Room DB)

The application guarantees offline functionality by persisting all critical data locally.

Database Schema

Room is used as the underlying SQLite wrapper. Three separate DAOs manage the structural entities:

  • ExploreCacheDao: Caches categorized funds (Index, Bluechip, ELSS, Large Cap) required for the main dashboard.
  • FundDetailCacheDao: Caches historical NAV data paths (1M, 3M, 6M, 1Y) mapped to specific scheme schemas.
  • WatchlistDao: Stores user-created watchlists and implements relation mapping matching scheme codes into custom collections.

Sync & Stale Data Mechanics

When a user navigates to a screen, data is emitted instantly from the Room cache, whilst a network routine is executed concurrently.

  • If the network request resolves, the Room cache is overwritten, natively propagating the updated StateFlow tree to the UI.
  • If the network fails, the user interacts seamlessly with the existing cached memory. A non-obtrusive "Stale Data" state logic is logged and handled quietly at the UI layer.

3. Pagination (Paging 3)

Handling thousands of mutual fund payloads is managed via Jetpack Paging 3 to restrict excessive memory buffer consumption and huge unpaginated network requests.

  • Search Screen & View All: The API provides paginated constraints (limit and offset).
  • MFFundsPagingSource and SearchFundsPagingSource manage sequential network offsets natively.
  • The UI maps a single Flow<PagingData<MutualFund>> integrating instantly into Compose LazyColumns. As the user reaches pre-defined threshold bounds in the layout list, consecutive request offsets resolve lazily.

4. Background Synchronization (WorkManager)

The platform evaluates metrics via deferred background task synchronization managed by WorkManager.

  • WatchlistSyncWorker: Because NAV metrics fluctuate, funds actively added to a user's local watchlist are periodically re-synced against remote values.
  • The underlying worker activates, queries the WatchlistDao sequentially for all tracked scheme constraints, fetches the latest mapped NAV array from the API, and persists updates securely back to Room-executing independently of the application process.

5. Dependency Injection (Dagger Hilt)

Dagger Hilt resolves dependencies globally reducing boilerplate code allocation.

  • Singleton Scope: Room database implementations, Retrofit configurations, and Repository objects are initiated safely and provided globally across execution graphs.
  • ViewModel Components: Hilt natively constructs interface variables (MFRepo, ThemeRepo) parsing them into designated ViewModels (e.g., MFViewModel).
  • WorkManager resolution uses Hilt-Work extensions (@HiltWorker), permitting DAOs and Repositories to inject cleanly into background synchronizer classes mapping strict modular bounds.

6. Networking & API Configuration (Retrofit)

Data fetching boundaries are structured inside MFApiService.

  • Retrofit & GSON: Raw JSON network paths convert symmetrically to domain-level Kotlin structures (e.g., FundDetail, MutualFund).
  • OkHttp Configurations: Includes raw Request/Response logging interceptor debugging parameters.
  • Static Endpoints: Base environment URL configuration is strictly segmented securely to standard configuration rules via local.properties:
BASE_URL="[API_ENDPOINT]"

Which is then globally exposed into build.gradle.kts via a property helper and registered as a compilation constant:

buildConfigField("String", "BASE_URL", getBaseUrl())

7. Preferences Storage (DataStore)

Standard SharedPreferences mapping mechanics are abandoned for native Jetpack DataStore processing parameters.

  • Utilized exclusively internally inside ThemeRepo components.
  • Actions execute asynchronously binding to Kotlin Coroutines to avoid main thread synchronous parsing blockades.
  • Provides immediate Flow array streams forcing native configuration refreshes across Theme states (Dark, Light, System, Dynamic Monet config boundaries) implicitly.

8. Charts

To display historical NAV performance trends, dynamic data visualization was required on the Product Details screen.

Initially, the Vico charting library was integrated to handle the line graphs. However, upon evaluation, the visual output and strict styling constraints of Vico did not align with the premium, polished aesthetic targeted for this application.

Consequently, a custom declarative charting solution was implemented natively using Jetpack Compose Canvas. Building a bespoke Canvas solution provided absolute, granular control over path drawing, smooth gradient fills beneath the data lines, and fluid performance, avoiding the overhead of a heavy third-party graphing dependency while achieving a significantly better look and feel.

9. Folder Structure

The package components enforce modular separation.

app/src/main/java/com/omsharma/mfexplorer/
├── data/
│   ├── local/      # Room Database generation, Schema configurations, and DAOs
│   ├── remote/     # Retrofit Interface bindings and DTO response entities
│   ├── repo/       # Aggregation bindings mapping Network constraints securely to Local Database schemas
│   ├── sync/       # Background routine tasks allocated via WorkManager execution arrays
│   └── model/      # Core data configurations and serializable payloads
├── di/             # Dagger Hilt Injectable Component arrays
├── navigation/     # Compose Route controllers orchestrating screen destinations
├── state/          # UI state variables mapping network results (Success/Error/Loading/Stale)
├── ui/
│   ├── screens/    # Concrete layout paths routing visual implementations natively mapped to ViewModels
│   ├── components/ # Granular reusable visual widget configurations
│   └── theme/      # Compose native Matrix/Dynamic palette implementations
└── viewmodel/      # Architecture states evaluating formatting functions formatting outputs explicitly to Compose States

Run Instructions & Build Deploy

Prerequisites

  • Android Studio
  • Android SDK 34 minimum mapped inside Gradle rules.

Running the Environment Directly

  1. Initialize a clone instance of the repository root framework.
  2. In the local.properties file located at the structural root constraint, insert your Mock OR Live HTTP API string parameter:
BASE_URL="https://api.mfapi.in/"
  1. Trigger Gradle Sync natively to fetch missing dependencies.
  2. Issue the standard Android Studio Run execution protocol attached to an emulator instance or physical debug unit.

Building the Direct Application Package (APK)

To manually generate a standalone deployable Android Package (APK):

  1. Navigate directly to the embedded terminal view inside Android Studio (or host shell mapped to project root).
  2. Execute the Gradle build wrapper instruction natively:
./gradlew assembleDebug
  1. Upon task completion, the executable package will compile directly at: app/build/outputs/apk/debug/app-debug.apk

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages