Skip to main content

Overview

The Unlocks module provides users with a deep dive into their “digital checking” habits. Instead of focusing on time spent (duration), this module focuses on frequency—how many times an app was opened. It helps users identify compulsive behaviors by visualizing launch patterns through heatmaps and providing quick actions to set directly from the usage list.

Architecture & Data Flow

The module follows a strict architecture. The UnlocksViewModel acts as the central orchestrator, reactive to changes in the underlying database via .

Key Components

1. UI Components

  • UnlocksScreen: The primary entry point. It coordinates the display of the metric header, the interactive heatmap, and the scrollable list of app usage.
  • DashboardHeatmap: A visual representation of historical unlock counts, allowing users to select specific dates to filter the list.
  • AppOpenRow: A specialized list item that displays the app’s icon, name, open count, and a .
  • RemovedAppsCard: A specialized UI element that aggregates data for apps that have been uninstalled but still have historical usage data.

2. Logic & State

  • UnlocksViewModel: Manages the UnlocksUiState. It combines streams from four different repositories to create a cohesive view of the user’s data.
  • AppUiModelMapper: A specialized utility that converts raw database entities (DailyAppUsageRecord) into UI-ready models (AppOpenUiItem), handling the heavy lifting of merging icon files and limit information.
  • LimitViewModelDelegate: Encapsulates the logic for opening the “Set Limit” bottom sheet, ensuring that limit-setting logic is reusable across different dashboard screens.

Operational Logic

Initialization & State Management

When the screen loads, the UnlocksViewModel initializes a complex combine block. It observes:
  1. Selected Date: Defaults to today.
  2. Unlock Period: (Daily, Weekly, or Monthly).
  3. Device Summaries: Used to populate the heatmap.
  4. Limits Snapshot: A combination of custom and “quick” limits.
As any of these change, the ViewModel triggers a recalculation. If the period is “Weekly,” it calculates the average opens across a 7-day range.

Tutorial System

The module features an integrated onboarding experience using TutorialScaffold. It checks the TutorialRepository to see if the user has completed the “dashboard_unlocks” tutorial. If not, it highlights key UI elements like the heatmap and the limit icons using a spotlight effect.

Handling Uninstalled Apps

A unique feature of this module is its “Data Engineering” approach to uninstalled apps. When an app is removed from the device:
  1. AppMetadataRepository marks it as isInstalled = false.
  2. The ViewModel filters these into a removedAppsData object.
  3. The UI groups these into a single “Removed Apps” card to keep the main list clean while preserving historical accuracy.

Data Engineering & Transformation

Source Tables

The module queries several tables:
  • daily_device_summary: For the high-level heatmap data.
  • daily_app_usage_record: For specific app open counts.
  • app_metadata: For app names and cached icon paths.
  • limit_groups & limited_apps: To determine if an app has an active restriction.

Transformation Pipeline

The ViewModel performs significant data manipulation:
  • Aggregation: Summing appOpenCount across date ranges for Weekly/Monthly views.
  • Averaging: Calculating the mean opens per day when viewing extended periods.
  • Merging: Using withContext(Dispatchers.Default) and async/awaitAll to concurrently map raw records to UI items, ensuring the remains responsive.
  • Sorting: Dynamically re-sorting the list based on the calculated metric (open count) while keeping “Show All” and “Removed Apps” logic intact.

Dependencies

  • ScrollDataRepository: Provides the raw usage and unlock telemetry.
  • LimitsRepository: Manages the lifecycle of app restrictions.
  • AppMetadataRepository: Handles the mapping of package names to human-readable names and manages the local file cache for app icons.
  • Hilt: Used for across all components.
  • Coil: Used for asynchronous loading of app icons from the internal file system.
Last modified on January 22, 2026