# Feature: Timer ## Behaviour - Only **one** active timer at a time. - Starting a new timer while one is running automatically stops the previous one and saves the completed `TimeEntry`. - Timer state persists across app restarts: on launch, read `time_entries` where `end_time IS NULL` — if found, restore the running timer. ## State Machine ``` IDLE ──start()──► RUNNING ──stop()──► IDLE │ discard() │ IDLE ``` ## TimerState (freezed union) ```dart @freezed class TimerState with _$TimerState { const factory TimerState.idle() = TimerIdle; const factory TimerState.running({ required int entryId, required DateTime startTime, required Project project, String? note, }) = TimerRunning; } ``` ## TimerNotifier responsibilities 1. `start(Project project)` — create TimeEntry (end_time = null), emit running 2. `stop()` — update TimeEntry (set end_time, compute duration_s), emit idle 3. `discard()` — delete the active TimeEntry, emit idle 4. `updateNote(String note)` — update note on active entry 5. `restoreFromDb()` — called on app init; check for open entry ## Elapsed Time Display - Use a `Timer.periodic(1 second)` inside the notifier while running. - Dispose the periodic timer on `stop()` / `discard()`. - Widget reads `DateTime.now().difference(startTime)` for display. ## No background service (v1) - Timer only ticks while app is in foreground. - If app is killed mid-session, the entry remains open (end_time = null). - On next launch, `restoreFromDb()` re-attaches to the open entry. - Future v2: consider `flutter_foreground_task` for background timer.