Skip to main content

Overview

The Notifications module serves as a “noise monitor” for the user’s device. It transforms raw system notification events into actionable insights, allowing users to identify which apps are most demanding of their attention. The feature provides a historical of notification activity, period-based filtering (Daily, Weekly, Monthly), and a direct path to “silence the noise” by setting usage limits on high-frequency apps.

Architecture & Data Flow

This module follows a strict pattern. The NotificationsViewModel acts as a central orchestrator, aggregating data from five distinct repositories to produce a single, immutable UI state.

Key Components

ComponentResponsibility
NotificationsViewModelOrchestrates the by combining historical counts with real-time limit data.
NotificationsScreenA complex that renders the heatmap, period selectors, and a grouped list of apps.
AppMetadataRepositoryManages a local cache of app icons and metadata, ensuring the UI remains performant without constant queries.
LimitViewModelDelegateA reusable interface that handles the logic for opening the “Set Limit” bottom sheet, shared across different dashboard modules.

Operational Logic

Initialization & Tutorial

Upon launch, the module queries the TutorialRepository. If the user hasn’t seen the notification dashboard before, a TutorialScaffold is triggered, highlighting key areas like the heatmap and the “Quick Limit” icons.

State Management & Periodicity

The NotificationsViewModel maintains two private for _selectedDate and _selectedPeriod. When these change, a combine block triggers a fresh data fetch:
  1. Daily: Shows exact counts for the selected day.
  2. Weekly/Monthly: Calculates a mathematical average (Total Notifications / Days in Period) to provide a “normalized” view of app noisiness.

Handling “Ghost” (Removed) Apps

A unique feature of this module is its handling of uninstalled apps. If an app sent notifications but was subsequently deleted, the AppMetadataRepository identifies it as !isInstalled. The ViewModel then aggregates these into a RemovedAppsData object, which is displayed as a single collapsed card to keep the UI clean while preserving historical accuracy.

Data Engineering & Transformation

The module performs significant data manipulation before the UI ever sees it:
  • Source Tables: Data is pulled from DailyAppUsageRecord (for counts), AppMetadata (for visibility), and LimitGroup (for constraints).
  • The Transformation Pipeline:
    1. Fetch: Pulls raw notification counts for the date range.
    2. Filter: Removes system-level or non-user-facing apps using a launcher-intent heuristic in AppMetadataRepository.
    3. Enrich: For every app, it checks if a LimitedApp entry exists in .
    4. Snapshot: If a limit exists, it calls the UsageRepository to calculate the live remaining time by subtracting current session usage from the stored DB limit.
  • Performance: Heavy operations, such as converting File paths to Drawable icons, are explicitly moved to Dispatchers.IO using to prevent UI jank.

Dependencies

  • Hilt: Used for of repositories and the IO Dispatcher.
  • Coil: Used for asynchronous loading of app icons from the internal storage cache.
  • Room (DAO): Provides the underlying reactive streams for notification summaries and app metadata.
  • UsageProjectionEngine: An external service used by UsageRepository to calculate real-time “time remaining” for apps currently in use.
Last modified on January 22, 2026