import 'dart:async'; import 'package:flutter/material.dart'; class SleepTimer { final VoidCallback onElapsed; final DateTime Function() now; late final ValueNotifier remaining = ValueNotifier(null); Timer? _timer; DateTime? _deadline; bool _firedThisSession = false; SleepTimer({ required this.onElapsed, DateTime Function()? now, }) : now = now ?? DateTime.now; void start(Duration duration) { if (duration <= Duration.zero) { cancel(); return; } cancel(); // Replace any running timer _firedThisSession = false; // ponytail: Wall-Clock-Deadline, selbstkorrigierend gegen OS-Throttling. // Nachteil: manuelle Systemuhr-Änderung feuert früh/spät — akzeptiert. _deadline = now().add(duration); _updateRemaining(); // Start periodic updates (1Hz for UI) _timer = Timer.periodic(const Duration(seconds: 1), (_) => tick()); } void tick() { _updateRemaining(); _checkElapsed(); } void _checkElapsed() { if (_deadline == null || _firedThisSession) return; if (!now().isBefore(_deadline!)) { _firedThisSession = true; _deadline = null; _timer?.cancel(); _timer = null; remaining.value = null; onElapsed(); } } void _updateRemaining() { if (_deadline == null) { remaining.value = null; return; } final diff = _deadline!.difference(now()); if (diff.isNegative) { remaining.value = null; } else { remaining.value = diff; } } void cancel() { _timer?.cancel(); _timer = null; _deadline = null; _firedThisSession = false; remaining.value = null; } }