timetracker/.ai/features/timer.md
2026-08-03 21:51:48 +02:00

49 lines
1.7 KiB
Markdown

# 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.