A comprehensive analytics module that tracks app notification frequency, visualizes trends via heatmaps, and enables proactive digital well-being through integrated app limits.
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.
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.
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.
The NotificationsViewModel maintains two private for _selectedDate and _selectedPeriod. When these change, a combine block triggers a fresh data fetch:
Daily: Shows exact counts for the selected day.
Weekly/Monthly: Calculates a mathematical average (Total Notifications / Days in Period) to provide a “normalized” view of app noisiness.
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.
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:
Fetch: Pulls raw notification counts for the date range.
Filter: Removes system-level or non-user-facing apps using a launcher-intent heuristic in AppMetadataRepository.
Enrich: For every app, it checks if a LimitedApp entry exists in .
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.