Skip to main content

Summary

The data layer serves as the single source of truth for the application. It acts as a bridge between the raw Android system data (like screen time and app installs) and the user interface. Its primary job is to fetch raw data from the device, process it into meaningful statistics, store it locally for offline access, and synchronize app categories with a remote server.

Data Flow

The application follows a “Sync and Store” pattern. It pulls raw data from the Android system, processes it, and saves it to a local database. The UI only reads from this local database to ensure the app remains fast and responsive.
1

Ingestion

Repositories request raw data from Android system services (like UsageStatsManager for screen time or PackageManager for installed apps).
2

Processing & Storage

The data is cleaned, aggregated (e.g., summing up daily usage), and stored in the local . Icons are cached as files.
3

Presentation

The UI observes the local database. When the repositories update the database with new system data, the UI updates automatically.

Repositories

Repositories are the managers of data. They decide whether to fetch new data from the system/network or return existing data from the database.

ScrollDataRepository

What it manages: The core usage statistics of the app. Role: This is the heaviest repository. It syncs with the Android UsageStatsManager to retrieve raw app usage events. It processes these raw events into daily summaries, scroll sessions, and unlock counts. It also handles privacy redaction for notifications.

AppMetadataRepository

What it manages: Information about installed applications. Role: It detects when apps are installed or uninstalled using the system PackageManager. It caches app names, version numbers, and saves app icons to the local file system so they load quickly.

AppCategoryRepository

What it manages: Categorization of apps (e.g., “Social”, “Productivity”). Role: It checks the local database for uncategorized apps. If found, it batches them and queries a Remote API. It handles offline scenarios by queuing sync jobs via WorkManager.

LimitsRepository

What it manages: User-defined usage limits. Role: Allows the user to create groups of apps (e.g., “Social Media”) and set time limits. It manages the creation, updating, and deletion of these rules in the local database.

UsageRepository

What it manages: Real-time usage calculation against limits. Role: A wrapper that combines historical data from the database with a live “in-memory” buffer to tell the UI exactly how much time is left for a specific app limit right now.

JourneysRepository

What it manages: The “Timeline” or “Journey” view. Role: It aggregates disparate data points—unlocks, app usage, and notifications—into a linear timeline. It contains logic to merge rapid app switches into single cohesive “sessions” to reduce noise in the UI.

BackupRepository

What it manages: Data export and import. Role: Reads all tables from the database, compresses them into a GZIP JSON file for backup, and handles the restoration process by clearing tables and re-inserting data transactionally.

SettingsRepository

What it manages: User preferences. Role: A wrapper around SharedPreferences for simple flags like Theme (Dark/Light), Onboarding status, and Developer Mode toggles.

Data Sources

The primary storage for the app. All UI data comes from here.
TableContent
daily_app_usageAggregated time spent per app, per day
raw_app_eventsRaw system events (screen on/off, app open)
app_metadataNames, versions, and install status of apps
limit_groupsUser-defined rules for limiting app usage
notificationsLog of received notifications (for analysis)

Caching Strategy

The app employs a robust offline-first strategy.
StrategyDescription
System MirroringThe app does not query the Android System for every UI update. Instead, it periodically “syncs” system data into the local database. The UI only reads the local database.
Icon CachingApp icons are extracted once upon install and saved as PNG files. The app loads these files instead of querying the system repeatedly, improving scroll performance.
Stale-while-revalidateFor app categories, the app displays existing local data immediately. If an app is “Uncategorized”, it schedules a background worker to fetch the category from the API without blocking the user.
In-Memory ProjectionFor real-time limits, the app combines the “stale” database numbers with a live in-memory buffer of the current session to provide instant feedback without constant database writes.
Last modified on January 25, 2026