Skip to main content

Overview

The Old Onboarding module serves as the first touchpoint for new users. It is designed as a narrative journey that transitions from high-level value propositions (mindful usage) to technical setup (permissions). The module uses a to create a guided, step-by-step experience. The feature’s primary goals are:
  1. Education: Explaining the difference between “mindless scrolling” and “intentional usage.”
  2. Trust Building: Using premium animations (Pixel Grids, Typewriter effects) to establish app quality.
  3. System Integration: Guiding the user through complex Android required for the app’s core tracking functionality.

Architecture & Data Flow

The module follows a strict pattern. The OnboardingScreen acts as the state consumer, while the SettingsViewModel orchestrates logic across multiple repositories.

Key Components

ComponentResponsibility
OnboardingScreenManages the HorizontalPager and renders specific pages (Hero, Insight, Permissions, etc.).
SettingsViewModelThe central that tracks permission status and handles the transition to the Dashboard.
PermissionManagerA utility class that abstracts the complexity of requesting system-level intents for Accessibility and Usage Stats.
LocalHapticsA provider that allows UI components to trigger tactile feedback during interactions.

Operational Logic

1. Permission-Gated Navigation

The onboarding flow is not strictly linear. The pageCount is dynamically calculated based on the mandatoryPermissionsGranted state.
  • Gating: If mandatory permissions (Usage Stats, Accessibility, Notification Listener) are not granted, the user is blocked from reaching the “Final Page.”
  • Lifecycle Awareness: The UI uses a LifecycleEventObserver to trigger viewModel.refreshPermissionStatus() every time the user returns to the app from the System Settings screens.

2. The “Hold to Start” Interaction

The final step uses a HoldToStartButton instead of a simple click. This requires a loop that:
  1. Tracks a LongPress gesture.
  2. Increments a progress float over 1500ms.
  3. Triggers “Tick” to create a sense of physical tension/momentum.
  4. Navigates to the Dashboard only upon 100% completion.

Data Engineering & Transformation

The module performs several critical data operations during the transition from onboarding to active usage:
  • State Mapping: The SettingsViewModel transforms raw repository flows into UI-ready states using the stateIn operator. For example, calibrationStatusText is derived by mapping the screenDpi flow to a human-readable string.
  • Historical Backfilling: When the Usage Stats permission is granted, the system detects a KEY_FORWARD_FILL_PENDING flag in SharedPreferences. It then triggers scrollDataRepository.backfillHistoricalAppUsageData(7), which pulls the last 7 days of usage data into the local database.
  • Reactive Cleanup: Upon completion, setOnboardingCompleted(true) is called, which persists the state in the SettingsRepository (likely backed by DataStore), ensuring the user never sees the onboarding flow again.

Performance & UI Polish

  • Animation Optimization: The PixelGridAnimation uses a custom Canvas implementation with a time-based infiniteTransition. It calculates dot positions and “Matrix-style” rain patterns using math functions (sin, cos) rather than heavy object allocation to maintain 60FPS.
  • Haptic Feedback: The module utilizes a centralized HapticsManager to perform different types of feedback (Confirm, Tick, Heavy) depending on the importance of the user action.
  • Memory Management: The KonfettiView on the final page is only active when the page is visible, preventing unnecessary CPU usage on background pages.

Dependencies

  • Hilt: Used for of repositories and managers.
  • Navigation Compose: Handles the transition from the Onboarding graph to the Main Dashboard graph.
  • Konfetti: A lightweight particle system for the “Success” state on the final page.
Last modified on January 22, 2026