Skip to content

4. add counter (recitation) mode as a separate meditation mode

status: accepted

deciders: phase 6 implementation

date: 2026-01-11

context

phase 6 adds a "recitation mode" to the existing timer-based meditation engine. meditations now fall into one of two runtime behaviors:

  • timer: the existing time-based player with segment durations.
  • counter (recitation): a count-up player where the user repeats an action (tapping a button or pressing hardware keys) until a target count is reached.

this required changes to the database schema, the domain model, the player, stat aggregation, and the editor.

superseded terminology: the runtime values described here are now MeditationMode.meditation (was timer) and MeditationMode.recitation (was counter); TimerSegment is now Segment and EditorScreen is MeditationEditorScreen. the stored values timer/counter are unchanged — see docs/dev-guide/terminology.md.

decision

we decided to model recitation mode as a first-class mode field on Meditation rather than a separate Recitation entity.

  • MeditationsTable has a mode column (timer or counter).
  • TimerSegment is reused with a new target_count column; duration_seconds is still present but set to zero for counter segments.
  • RecitationPlayerScreen is a separate screen for the counter runtime, launched when meditation.mode == MeditationMode.counter.
  • RecitationInputService abstracts all input sources (on-screen buttons, keyboard, and Android hardware keys) so the player only sees increment/decrement events.

consequences

positive:

  • editor, library, stats, and easy mode can all work with both modes with minimal conditional logic.
  • stats aggregation naturally mixes timer and counter sessions; SessionStats now has parallel time and recitation metrics.
  • counter meditations can use the same bell/background/prompt infrastructure as timer meditations.

negative:

  • TimerSegment now has two mutually exclusive fields (duration_seconds and target_count). validation in EditorScreen and MeditationsRepository must ensure a segment is meaningful for the meditation's mode.
  • the migration to schema version 14 adds a mode column to an existing table, which required idempotent migration helpers (_addColumnIfMissing) to keep v9→v10 and v13→v14 paths safe.