Skip to main content

Overview

The Journeys module is the diagnostic heart of the application. Instead of showing abstract totals (e.g., “3 hours of screen time”), it visualizes the user’s day as a vertical timeline. It maps exactly when the phone was unlocked, which apps were used in succession, how much scrolling occurred, and—crucially—what triggered the session (e.g., a notification). To the user, this looks like a “travel log” of their digital life, highlighting both active usage and the “gaps” where they successfully stayed off their device.

Architecture & Data Flow

The module follows a strict pattern. It relies on a heavy data aggregation layer that synthesizes multiple raw data sources into a single “Journey” table.

Key Components

ComponentResponsibility
JourneysScreenRenders the timeline using a and custom Canvas drawing for the timeline “track”.
JourneysViewModelManages the selectedDate state and orchestrates the refresh logic when the user switches days.
JourneysRepositoryImplThe “Brain” of the module. It performs complex from five different database tables.
UserJourneyDaoProvides a reactive of the processed timeline events.
TimelineUiItemA used to differentiate between “Sessions” (active use) and “Gaps” (idle time) in the UI.

Operational Logic

1. The “Sync” Lifecycle

When the user opens the screen or changes the date:
  1. The ViewModel updates the selectedDate .
  2. A flatMapLatest operator triggers a refreshJourney call in the repository.
  3. The Repository fetches raw data for that 24-hour window and runs the Reconstruction Algorithm (see Data Engineering below).
  4. The results are saved to the user_journey table.
  5. The UI, which is observing that table, automatically updates with the new data.

2. Timeline Visualization

The UI uses a custom-drawn “Track” system:
  • Solid Lines: Represent active phone sessions.
  • Dotted Lines: Represent “Gaps” (time spent off the phone).
  • Anchor Dots: Placed at the start of every unlock event.
  • Intrinsic Measurements: The module uses IntrinsicSize.Min to ensure the vertical timeline line perfectly matches the height of the content cards, regardless of how many apps were used in that session.

Data Engineering & Transformation

The repository acts as a Data Engineer, transforming noisy system logs into clean user stories.

Source Tables

The system queries:
  • unlock_sessions: To define the start and end of a physical interaction.
  • raw_app_events: To see which apps moved to the foreground.
  • notifications: To check if a specific notification arrived just before an unlock.
  • scroll_sessions: To attach “meters scrolled” to specific app usage segments.

The Reconstruction Algorithm

The consolidateEvents function performs several critical transformations:
  1. Debouncing: If a user switches between apps in less than 2 seconds (e.g., checking a 2FA code), the segments are merged or treated as a single flow to reduce noise.
  2. Noise Filtering: System apps (launchers, settings, system UI) are stripped out to focus on “intentional” app usage.
  3. Trigger Attribution: The algorithm looks back 15 seconds from an unlock. If a notification arrived in that window, it marks the session as “Notification Triggered.”
  4. Duration Calculation: It calculates the delta between app switches to determine exactly how long each app was used.

Dependencies

  • Room DB: The source of all raw logs and the destination for processed journeys.
  • Hilt: Used for of the repository and dispatchers.
  • Coil: Used to asynchronously load app icons into the timeline.
  • Material 3 Expressive: Utilizes the latest M3 shapes for the “Back” button and “ButtonGroup” components for the date selector.
  • DateUtil: A custom utility used to handle UTC-to-Local conversions, ensuring the timeline matches the user’s actual wall-clock time.
Last modified on January 22, 2026