# QuranApp Repository Structure: MVVM Architecture and Android Implementation Guide

> Explore the alfaazplus/quranapp repository structure. Learn about its MVVM architecture, Jetpack Compose UI, ViewModel state, domain use cases, and data layer using DataStore and SQLite.

- Repository: [AlfaazPlus/quranapp](https://github.com/alfaazplus/quranapp)
- Tags: architecture
- Published: 2026-02-24

---

**The alfaazplus/quranapp repository is structured around a clean MVVM architecture that separates Jetpack Compose UI components from business logic through ViewModel state management, Domain layer use-cases, and Data layer persistence using DataStore and SQLite.**

The alfaazplus/quranapp repository delivers an ad-free, privacy-focused Qur'an reader for Android built entirely in Kotlin. Understanding the repository structure requires mapping how the Presentation, ViewModel, Domain, and Data layers interact to handle everything from UI rendering to offline tafsir downloads. This guide walks through each architectural component with direct source links to the master branch.

## Architecture Breakdown

The codebase organizes functionality into five distinct layers, each with specific responsibilities and entry points:

**Presentation Layer**
- **Responsibility**: Rendering UI through Jetpack Compose and custom Android Views
- **Key Files**: 
  - [[`PeaceRadioGroup.kt`](https://github.com/alfaazplus/quranapp/blob/main/PeaceRadioGroup.kt)](https://github.com/alfaazplus/quranapp/blob/master/app/src/main/java/com/quranapp/android/widgets/PeaceRadioGroup.kt) – Custom widget for grouped selection controls
  - [[`FragMain.kt`](https://github.com/alfaazplus/quranapp/blob/main/FragMain.kt)](https://github.com/alfaazplus/quranapp/blob/master/app/src/main/java/com/quranapp/android/frags/FragMain.kt) – Primary navigation fragment hosting the main drawer

**ViewModel Layer**
- **Responsibility**: Holding UI state, processing user events, and mediating between UI and data operations
- **Key Files**: 
  - [[`TafsirViewModel.kt`](https://github.com/alfaazplus/quranapp/blob/main/TafsirViewModel.kt)](https://github.com/alfaazplus/quranapp/blob/master/app/src/main/java/com/quranapp/android/viewmodels/TafsirViewModel.kt) – Manages tafsir selection, download states, and initialization flows

**Domain Layer**
- **Responsibility**: Encapsulating business logic for resource fetching and download orchestration
- **Key Files**: 
  - [[`TafsirManager.kt`](https://github.com/alfaazplus/quranapp/blob/main/TafsirManager.kt)](https://github.com/alfaazplus/quranapp/blob/master/app/src/main/java/com/quranapp/android/utils/reader/tafsir/TafsirManager.kt) – Parses and caches tafsir JSON data
  - [[`TafsirDownloadManager.kt`](https://github.com/alfaazplus/quranapp/blob/main/TafsirDownloadManager.kt)](https://github.com/alfaazplus/quranapp/blob/master/app/src/main/java/com/quranapp/android/utils/managers/TafsirDownloadManager.kt) – Orchestrates background downloads via WorkManager

**Data Layer**
- **Responsibility**: Local persistence and preference storage
- **Key Files**: 
  - [[`QuranTafsirDBHelper.kt`](https://github.com/alfaazplus/quranapp/blob/main/QuranTafsirDBHelper.kt)](https://github.com/alfaazplus/quranapp/blob/master/app/src/main/java/com/quranapp/android/utils/reader/tafsir/QuranTafsirDBHelper.kt) – SQLite helper for offline tafsir storage
  - [[`DataStoreManager.kt`](https://github.com/alfaazplus/quranapp/blob/main/DataStoreManager.kt)](https://github.com/alfaazplus/quranapp/blob/master/app/src/main/java/com/quranapp/android/utils/prefs/DataStoreManager.kt) – Wrapper around Jetpack DataStore for type-safe preferences

**Network Layer**
- **Responsibility**: Remote API communication using Retrofit and Kotlinx Serialization
- **Key Files**: 
  - [[`AlfaazPlusApi.kt`](https://github.com/alfaazplus/quranapp/blob/main/AlfaazPlusApi.kt)](https://github.com/alfaazplus/quranapp/blob/master/app/src/main/java/com/quranapp/android/api/AlfaazPlusApi.kt) – Central Retrofit interface defining API endpoints
  - [`app/build.gradle.kts`](https://github.com/alfaazplus/quranapp/blob/master/app/build.gradle.kts) – Declares `retrofit` and `kotlinx-serialization` dependencies

**Build Configuration**
- **Responsibility**: Module configuration and dependency versioning
- **Key Files**: 
  - [`settings.gradle.kts`](https://github.com/alfaazplus/quranapp/blob/master/settings.gradle.kts) – Root project settings
  - [[`gradle/libs.versions.toml`](https://github.com/alfaazplus/quranapp/blob/main/gradle/libs.versions.toml)](https://github.com/alfaazplus/quranapp/blob/master/gradle/libs.versions.toml) – Centralized version catalog for all third-party libraries

## Component Interaction Flow

The architecture enforces unidirectional data flow from UI to Data and back. Here is how a typical tafsir download operation traverses the layers:

1. **Initialization**: `TafsirViewModel` initializes in [[`TafsirViewModel.kt`](https://github.com/alfaazplus/quranapp/blob/main/TafsirViewModel.kt)](https://github.com/alfaazplus/quranapp/blob/master/app/src/main/java/com/quranapp/android/viewmodels/TafsirViewModel.kt) by reading the saved tafsir key from `DataStoreManager`, calling `TafsirDownloadManager.initialize(context)`, and loading cached keys from `QuranTafsirDBHelper`.

2. **State Observation**: The UI layer collects `StateFlow<TafsirUiState>` from the ViewModel. When `observeDownloadStates()` detects progress updates from the download manager, it maps them to `TafsirDownloadState` objects and emits new states, triggering automatic UI recomposition.

3. **User Action**: When a user triggers a download, the UI calls `viewModel.onEvent(TafsirEvent.DownloadTafsir(key))`, which delegates to `TafsirDownloadManager.startDownload()`.

4. **Background Processing**: The download manager verifies network connectivity via `NetworkStateReceiver`, then launches a WorkManager task. Progress updates flow back to the ViewModel through callback observers.

5. **Persistence**: Upon completion, `QuranTafsirDBHelper` writes the tafsir data to SQLite, and the ViewModel updates `downloadedTafsirKeys` in the UI state, immediately reflecting the new available resource in the interface.

## Code Examples

### Observing ViewModel State in Compose

The UI layer consumes state through Kotlin Coroutines `collectAsState()`, ensuring the interface reacts to data changes without manual callback wiring:

```kotlin
@Composable
fun TafsirScreen(viewModel: TafsirViewModel = viewModel()) {
    val uiState by viewModel.uiState.collectAsState()

    when {
        uiState.isLoading -> CircularProgressIndicator()
        uiState.error != null -> Text(uiState.error?.message ?: "Error")
        else -> TafsirList(
            state = uiState,
            onEvent = viewModel::onEvent
        )
    }
}

```

### Initiating a Download from UI

User interactions are encapsulated as sealed class events, maintaining type-safe communication between UI and ViewModel:

```kotlin
Button(
    onClick = { 
        viewModel.onEvent(TafsirEvent.DownloadTafsir(tafsirKey)) 
    }
) {
    Text("Download Tafsir")
}

```

### Reading Saved Preferences via DataStore

The repository uses Jetpack DataStore instead of SharedPreferences for asynchronous, type-safe storage operations:

```kotlin
object SPReader {
    private val Context.dataStore by preferencesDataStore(name = "quranapp_prefs")
    private val SAVED_TAFSIR_KEY = stringPreferencesKey("saved_tafsir_key")

    suspend fun getSavedTafsirKey(context: Context): String? =
        context.dataStore.data
            .map { it[SAVED_TAFSIR_KEY] }
            .firstOrNull()
}

```

## Key Files Reference

Navigate the repository efficiently using these direct links to critical implementation files:

- [[`README.md`](https://github.com/alfaazplus/quranapp/blob/main/README.md)](https://github.com/alfaazplus/quranapp/blob/master/README.md) – Project overview and contribution guidelines
- [`LICENSE`](https://github.com/alfaazplus/quranapp/blob/master/LICENSE) – GPL-v3 license terms
- [`app/build.gradle.kts`](https://github.com/alfaazplus/quranapp/blob/master/app/build.gradle.kts) – Module-level build configuration enabling Compose and ViewBinding
- [[`TafsirViewModel.kt`](https://github.com/alfaazplus/quranapp/blob/main/TafsirViewModel.kt)](https://github.com/alfaazplus/quranapp/blob/master/app/src/main/java/com/quranapp/android/viewmodels/TafsirViewModel.kt) – Primary ViewModel implementation for tafsir management
- [[`AlfaazPlusApi.kt`](https://github.com/alfaazplus/quranapp/blob/main/AlfaazPlusApi.kt)](https://github.com/alfaazplus/quranapp/blob/master/app/src/main/java/com/quranapp/android/api/AlfaazPlusApi.kt) – REST API interface definitions
- [[`QuranTafsirDBHelper.kt`](https://github.com/alfaazplus/quranapp/blob/main/QuranTafsirDBHelper.kt)](https://github.com/alfaazplus/quranapp/blob/master/app/src/main/java/com/quranapp/android/utils/reader/tafsir/QuranTafsirDBHelper.kt) – SQLite database helper for offline storage
- [[`DataStoreManager.kt`](https://github.com/alfaazplus/quranapp/blob/main/DataStoreManager.kt)](https://github.com/alfaazplus/quranapp/blob/master/app/src/main/java/com/quranapp/android/utils/prefs/DataStoreManager.kt) – DataStore preferences wrapper
- [[`PeaceRadioGroup.kt`](https://github.com/alfaazplus/quranapp/blob/main/PeaceRadioGroup.kt)](https://github.com/alfaazplus/quranapp/blob/master/app/src/main/java/com/quranapp/android/widgets/PeaceRadioGroup.kt) – Example custom UI component
- [[`FragMain.kt`](https://github.com/alfaazplus/quranapp/blob/main/FragMain.kt)](https://github.com/alfaazplus/quranapp/blob/master/app/src/main/java/com/quranapp/android/frags/FragMain.kt) – Main activity fragment container

## Summary

- **MVVM Architecture**: The repository strictly separates Presentation, ViewModel, Domain, and Data layers to ensure testability and maintainability.
- **State Management**: UI states flow through `StateFlow` objects in ViewModels, consumed by Jetpack Compose screens for reactive updates.
- **Offline-First Design**: Tafsir content persists in SQLite via `QuranTafsirDBHelper`, with DataStore managing user preferences asynchronously.
- **Modular UI**: Custom widgets like `PeaceRadioGroup` reside in the `widgets` package, while navigation logic lives in the `frags` package.
- **Dependency Versioning**: The [`gradle/libs.versions.toml`](https://github.com/alfaazplus/quranapp/blob/main/gradle/libs.versions.toml) file centralizes library versions across the multi-module project including the `peacedesign` UI library.

## Frequently Asked Questions

### What architecture pattern does QuranApp use?

The repository implements the **Model-View-ViewModel (MVVM)** pattern with unidirectional data flow. Activities and Fragments host Jetpack Compose UI elements that observe immutable state objects from ViewModels, while business logic remains isolated in domain managers and data repositories.

### How are UI components organized in the repository?

UI components follow a hierarchical structure: custom Android Views and Compose wrappers reside in [`app/src/main/java/com/quranapp/android/widgets/`](https://github.com/alfaazplus/quranapp/blob/master/app/src/main/java/com/quranapp/android/widgets/), while screen-level containers and navigation logic are located in the [`frags`](https://github.com/alfaazplus/quranapp/blob/master/app/src/main/java/com/quranapp/android/frags/) directory. Shared theming components live in the separate `peacedesign` module.

### Where is dependency injection handled?

The project does not use a DI framework like Hilt or Dagger. Instead, it employs manual singleton initialization through static `initialize(context)` methods, as seen in [[`TafsirViewModel.kt`](https://github.com/alfaazplus/quranapp/blob/main/TafsirViewModel.kt)](https://github.com/alfaazplus/quranapp/blob/master/app/src/main/java/com/quranapp/android/viewmodels/TafsirViewModel.kt) where `TafsirDownloadManager` is initialized with an application context.

### How does the app manage offline tafsir data?

Offline storage combines **SQLite** for content persistence and **DataStore** for metadata. When a user downloads a tafsir, `TafsirDownloadManager` streams the data to `QuranTafsirDBHelper`, which writes to a local SQLite database. The ViewModel then queries this database via `loadDownloadedTafsirKeys()` to display available offline content without network calls.