Skip to main content

Summary

The application follows a modern MVVM (Model-View-ViewModel) architecture with a strong emphasis on Offline-First data persistence. It is structured to separate the user interface from the business logic and data handling. The app relies heavily on background services and workers to track usage data reliably, even when the app is closed. Dependency Injection (Hilt) is used throughout to wire these components together efficiently.

Architecture Diagram

This diagram illustrates how data flows from the system and user inputs through the app layers to the database and UI.

Layers

UI Layer

What it does: Displays data to the user and captures interactions. Key Parts:
  • Screens: Built with Jetpack Compose (implied).
  • ViewModels: Holds the state for the screens. They survive configuration changes (like screen rotation) and act as the bridge between the UI and the Data Layer.

Data Layer

What it does: Acts as the “Single Source of Truth.” It handles where data comes from (local database vs. network) and how it is stored. Key Parts:
  • Repositories: The main entry point for data. ViewModels ask Repositories for data, and Repositories decide whether to fetch it from the API or the Database.
  • Room Database: A robust local SQL database that stores usage stats, limits, and app metadata.
  • Remote API: Used primarily for syncing app categories and metadata.

Background Layer

What it does: Performs heavy lifting without blocking the user interface, ensuring data tracking continues even when the app is in the background. Key Parts:
  • WorkManager: Handles scheduled tasks like daily processing, database cleanup, and syncing.
  • Foreground Services: Runs persistent processes (like AppTrackerService) to monitor app usage in real-time.

Key Patterns

MVVM

separates the UI code from the logic. The ViewModel prepares data for the UI, keeping the screens “dumb” and focused only on drawing.

Repository Pattern

Repositories abstract the data sources. The rest of the app doesn’t know (or care) if data comes from the network or a local database.

Dependency Injection

Using , the app automatically provides necessary objects (like the Database or Network Client) to classes, making the code modular and testable.

Offline-First

The app prioritizes the local database. Network calls (like syncing categories) happen in the background to update the local data, ensuring the app works perfectly without internet.

Technology Stack

CategoryTechnologyPurpose
LanguageKotlinPrimary programming language.
DIHilt (Dagger)Managing dependencies and scoping.
DatabaseRoomLocal SQLite abstraction with complex migrations.
NetworkRetrofit + OkHttpCommunicating with backend APIs.
ConcurrencyCoroutines + FlowAsynchronous programming and reactive data streams.
BackgroundWorkManagerReliable scheduled tasks (e.g., daily summaries).

Dependency Injection Structure

The app uses Hilt to manage the object graph.
  • Singleton Component (AppSingletonProvides): Objects that live as long as the app runs.
    • Database: Created once with extensive migration logic.
    • Network: Retrofit and OkHttp clients.
    • Dispatchers: Threading contexts (IO, Main).
  • ViewModel Component (ViewModelModules): Objects that live as long as a specific screen.
    • Delegates: Helper logic specific to UI flows.

Database Management

The AppDatabase is a critical component, featuring a robust migration strategy (currently tracking versions v28 through v44). This ensures that as the app evolves and data structures change, user data is preserved and upgraded safely without crashes or data loss.
Last modified on January 25, 2026