Skip to main content

Overview

The Nudges module is a core behavioral intervention component of the application. It provides users with real-time awareness of their app usage by “nudging” them at specific intervals (e.g., every 20 minutes) or when specific problematic patterns (Insights) are detected. To the user, this manifests as a non-intrusive floating chip or a notification showing the time spent in the current app, accompanied by a motivational follow-up.

Architecture & Data Flow

The feature follows a pattern for the UI, while utilizing a background “Monitor” service to handle real-time app tracking and intervention logic.

Key Components

ComponentResponsibility
NudgesViewModelOrchestrates UI state by combining app metadata with user-specific nudge statistics.
NudgeMonitorThe “Engine.” It listens for foreground app changes and schedules the next nudge based on usage thresholds.
NudgesRepositoryManages persistence for DailyAppNudgeStats (e.g., whether nudges are enabled for a specific app).
SettingsRepositoryStores global preferences like the nudge interval, DND (Do Not Disturb) respect, and master toggles.
InsightNudgesDetailSheetAn interactive UI component using a swipeable card stack to educate users on different nudge types.

Operational Logic

1. Initialization & State Management

When the user opens the Nudges screen, the NudgesViewModel uses a combine operator. It merges the list of installed apps from AppMetadataRepository with the current day’s nudge settings from NudgesRepository. This ensures that if an app is uninstalled or a setting is changed elsewhere, the UI updates reactively.

2. The Monitoring Loop

The NudgeMonitor is the most critical part of the system. It operates outside the UI lifecycle:
  1. App Change: When onForegroundAppChanged is called, it cancels any pending nudges.
  2. Eligibility Check: It verifies if the app is a system app, a launcher, or the “Scrollless” app itself (which are excluded).
  3. Threshold Calculation: It fetches the baselineUsageMs (total time spent in the app today) and calculates the nextThreshold (e.g., if usage is 17m and interval is 10m, the next nudge is at 20m).
  4. Scheduling: It uses a with a delay to wait until the threshold is reached.

3. Intervention Delivery

When a threshold is hit, the system attempts to show a Floating Chip via NudgeOverlayManager. If overlay permissions are missing, it falls back to a Low-Priority Notification via NudgesNotifier.

Data Engineering & Transformation

The module performs significant data synthesis to provide a smooth user experience:
  • Source Tables:
    • DailyAppNudgeStats: Tracks isEnabled and nudgesShownToday per package.
    • AppMetadata: Provides app names and cached icon paths.
  • Transformation Logic: In NudgesViewModel, the app list is filtered and sorted:
    apps.filter { it.packageName != AppConstants.OWN_PACKAGE_NAME }
        .sortedBy { it.appName.lowercase() }
        .map { meta -> 
            // Map metadata + stats into a UI-ready AppNudgeItem
        }
    
  • Performance: Heavy operations like fetching app icons or querying the are performed on Dispatchers.IO to prevent UI stuttering.

Insight Nudges

Beyond simple intervals, the module includes “Insight Nudges” which are pattern-based interventions:
  • Bounce Loop: Detecting rapid switching between two apps.
  • Late-Night Session: Alerting the user when they start scrolling after a certain hour.
  • Doomscrolling: A high-intensity nudge triggered when a single session exceeds 40 minutes.

Dependencies

  • Hilt: Used for across the ViewModel and Monitor.
  • Coil: Used for asynchronous loading of app icons from the internal cache.
  • Material 3: The UI utilizes LargeTopAppBar, ModalBottomSheet, and FilterChip for a modern Android experience.
  • SharedPreferences: Used via SettingsRepository for high-frequency, low-latency preference lookups.
Last modified on January 22, 2026