Skip to main content

Data Strategy

The application employs a Local-First strategy for configuration. The for user preferences is the Android system. Data is exposed reactively using , ensuring that UI components and system services (like Haptics) automatically update when settings change without manual polling.

Key Repositories

  • SettingsRepository: The central mediator for all persistent app state, including theme, onboarding, and notification batching logic.
  • HapticsManager: A specialized service that consumes settings data to orchestrate across the device’s vibration hardware.

Schema & Performance (Data Engineering)

While not using a relational like , the SettingsRepository defines a strict key-value schema within ScrollTrackAppSettings.

Key Data Groups:

GroupKeysData Type
UI/UXselected_theme_palette, is_dark_mode, use_dynamic_colorString (Enum), Boolean
Hapticshaptics_enabledBoolean
Nudgesnudges_enabled, nudge_interval, nudges_respect_dndBoolean, Int
Notificationsnotification_batching_enabled, notification_batch_timesBoolean, Set<String>
Pledgepledge_signed, pledge_name, pledge_dateBoolean, String

Performance Optimization:

  • Reactive Updates: Uses OnSharedPreferenceChangeListener wrapped in a callbackFlow to prevent unnecessary disk reads.
  • Sanitization: The setNotificationBatchTimes function performs data cleaning (ensuring HH:mm format) before persistence.

Storage & Caching

  • Persistence Layer: Data is written to disk using SharedPreferences.edit { ... }.
  • Memory Cache: The HapticsManager maintains a local variable areHapticsEnabledApp which is kept in sync with the repository via a background collector, providing O(1) access time for time-sensitive vibration triggers.
  • Haptic Primitives: On Android 11 (API 30) and above, the system uses rich vibration primitives (like PRIMITIVE_CLICK or PRIMITIVE_SLOW_RISE) for high-fidelity feedback, falling back to simple waveforms on older hardware.

Threading & Concurrency

  • Non-Blocking Writes: All mutation functions (e.g., setSelectedTheme) are marked as , ensuring they are called from a coroutine context.
  • Main Thread Safety: The HapticsManager initializes its collector on Dispatchers.Main to ensure it can safely interact with UI-triggered events.
  • Thread-Safe Streams: The use of callbackFlow and awaitClose prevents when registering/unregistering listeners during configuration changes.
  • Dependency Injection: The HapticsManager is provided to the UI tree via a named LocalHaptics, ensuring a single instance is shared across the Compose hierarchy.
Last modified on January 22, 2026