Skip to main content

Overview

The Onboarding module is the gateway to the application, designed to guide users through a complex configuration process. Given the app’s nature (likely a digital wellbeing or focus tool), it requires several “sensitive” Android permissions. This module transforms a tedious technical checklist into a premium user experience using:
  1. Educational Storytelling: Explaining the “Philosophy” before asking for data.
  2. Visual Feedback: Using to provide fluid, organic transitions.
  3. Reactive Validation: Real-time permission polling to allow the user to progress only when requirements are met.

Architecture & Data Flow

The module follows a strict pattern. The UI layer is entirely driven by the system’s permission state, which is polled and exposed by the ViewModel.

Key Components

1. SetupViewModel

The “Brain” of the module. It acts as a bridge between the and the Compose UI. It does not store data in a database; instead, it treats the Android OS as its “Source of Truth.”

2. SetupScreen (The Orchestrator)

Uses a HorizontalPager to manage the linear flow of onboarding. It implements custom graphicsLayer transformations to create a “fade and slide” transition between steps, ensuring the experience feels cohesive rather than fragmented.

3. PermissionIconCollage & SineWaveLine

Specialized UI components that provide “Ambient Delight.”
  • Collage: Uses to create abstract, animated backgrounds for permission icons.
  • SineWaveLine: A custom implementation that draws undulating waves to represent “thought flow” or “activity.”

Operational Logic

Permission Polling

Unlike standard apps that check permissions once, this module uses a LifecycleEventObserver. When the user returns from the System Settings (after granting a permission), the ON_RESUME event triggers viewModel.checkPermissions(context). This creates a seamless “Auto-advance” feel.

State-Driven Navigation

The “Next” button (implemented in SetupBottomBar) is context-aware. It morphs its shape based on the current page index:
  • Start: Circle
  • Middle: Flowers, Clovers, Gems (representing progress/growth)
  • End: A Checkmark (when all permissions are valid)
This is achieved by calculating a Morph progress between two RoundedPolygon objects based on the .

Data Engineering & Transformation

The “Data” in this module is the SetupUiState. The ViewModel performs a series of transformations to simplify the UI logic:
  • Source Mapping: It maps complex system checks (e.g., checking if an AccessibilityService is specifically enabled for this package) into simple Boolean flags.
  • Validation Logic: It computes a derived property allPermissionsGranted which the UI uses to enable/disable the final “Complete” action.
  • String Synthesis: The getMissingPermissionMessage() function acts as a small data transformer, joining a list of missing requirements into a human-readable string for the .

Dependencies

  • Hilt: Used for of the ViewModel.
  • AndroidX Graphics Shapes: Powers the complex polygon morphing.
  • Konfetti: Provides the celebration effect on the final “Features” page.
  • System Services:
    • AppOpsManager: For Usage Stats.
    • AccessibilityManager: For Accessibility Service status.
    • PowerManager: For Battery Optimization whitelisting.
    • Settings: For Overlay (Draw over apps) permissions.
// Example of the reactive transformation in the ViewModel
_uiState.update {
    it.copy(
        usageStatsPermissionGranted = checkUsageStats(context),
        overlayPermissionGranted = Settings.canDrawOverlays(context),
        // ... other mappings
    )
}
Last modified on January 22, 2026