Skip to main content

Overview

The Today Summary module serves as the application’s “Home” screen. It is designed to provide immediate feedback on a user’s phone usage through a high-level dashboard. It aggregates complex data points—such as , scroll distance, and notification counts—into a cohesive, actionable interface. The module’s primary goal is to facilitate “mindful scrolling” by surfacing and providing quick access to app-specific limits.

Architecture & Data Flow

This feature follows a strict architecture. The AppScaffold acts as the global container, while the MainScreen serves as the primary entry point for the dashboard logic.

Key Components

ComponentResponsibility
AppScaffoldManages global UI elements like the and the centralized SnackbarHost.
TodaySummaryViewModelThe “Brain” of the module. It combines multiple from various repositories to build the dashboard state.
AppUiModelMapperA specialized utility that transforms database entities into UiItem models, handling icon loading and formatting logic.
CoachSuggestionManagerLogic engine that determines when to show “Smart Adaptation” cards to help users tighten or loosen their limits.
TipsCardStackA custom UI component that implements a “Tinder-style” swipeable stack for mental health and productivity tips.

Operational Logic

1. Initialization & Permission Handling

When the screen loads, the TodaySummaryViewModel triggers a data refresh. Because the app relies on sensitive Android permissions (Accessibility, Usage Stats), the module includes a PermissionsCard. This component dynamically appears if the detects missing requirements, ensuring the data shown is accurate.

2. State Management

The UI state is encapsulated in TodaySummaryUiState. It handles three distinct phases:
  • Loading: Displays a shimmer or progress indicator while data is being aggregated.
  • Refreshing: Triggered by a “Pull-to-Refresh” gesture, which forces the ScrollDataRepository to sync the latest usage stats.
  • Ready: The final state where usage metrics, comparisons, and coach suggestions are rendered.

3. Centralized Snackbar System

The module uses a Global Snackbar Architecture. Instead of every screen managing its own snackbar logic, they use a LocalSnackbarHostState provided via . This ensures that snackbars are positioned correctly above the navigation bar and don’t overlap with critical UI elements.

Data Engineering & Transformation

The dashboard doesn’t just display raw numbers; it performs significant data manipulation:
  • Aggregation: Usage records from the DailyAppUsageRecord table are grouped by package name and summed to provide total daily totals.
  • Comparison Logic: The system compares today’s metrics against yesterday’s (e.g., “15% less than yesterday”) using a StatComparison utility.
  • Unit Conversion: Raw scroll pixels are converted into human-readable meters or kilometers via the ConversionUtil.
  • Heuristics: The AppMetadataRepository uses heuristics (like checking for a launcher intent) to filter out system processes and only show “User-Visible” apps.

Dependencies

  • Hilt: Used for of repositories into the ViewModel.
  • Lottie: Powers the “Fitness-style” pull-to-refresh animations.
  • Jetpack Navigation: Manages transitions between the Dashboard, App Details, and Limit Configuration screens.
  • HapticsManager: Provides tactile feedback during “Coach Suggestion” swipes and refresh triggers.
// Example of the complex state combination in the ViewModel
val todaySummaryUiState: StateFlow<TodaySummaryUiState> = todayDataFlow.map { data ->
    TodaySummaryUiState(
        totalUsageTimeFormatted = dateUtil.formatDurationCompactSymbols(data.summary?.totalUsageTimeMillis ?: 0L),
        todaysAppUsageUiList = appUiModelMapper.mapToAppUsageUiItems(data.dailyAppUsage),
        scrollComparison = calculateComparison(data.currentScroll, data.yesterdayScroll),
        // ... other mappings
    )
}.stateIn(viewModelScope, SharingStarted.WhileSubscribed(5000L), InitialState)
Last modified on January 22, 2026