import 'dart:async'; class CooldownController { CooldownController({void Function()? onTick}) : _onTick = onTick; final void Function()? _onTick; Timer? _timer; DateTime? _until; int _remainingSeconds = 0; int get remainingSeconds => _remainingSeconds; bool get isActive => _remainingSeconds > 0; DateTime? get until => _until; void start(Duration duration) { startUntil(DateTime.now().add(duration)); } void startUntil(DateTime until) { _until = until; _restartTimer(); _syncRemaining(notify: true); } void syncUntil(DateTime? until, {bool notify = true}) { if (until == null) { stop(notify: notify); return; } _until = until; _restartTimer(); _syncRemaining(notify: notify); } void stop({bool notify = false}) { _timer?.cancel(); _timer = null; _until = null; final hadRemaining = _remainingSeconds != 0; _remainingSeconds = 0; if (notify && hadRemaining) { _onTick?.call(); } } void dispose() { _timer?.cancel(); _timer = null; } void _restartTimer() { _timer?.cancel(); _timer = null; if (_remaining() <= 0) return; _timer = Timer.periodic(const Duration(seconds: 1), (_) { final nextRemaining = _remaining(); if (nextRemaining <= 0) { stop(notify: true); return; } if (nextRemaining != _remainingSeconds) { _remainingSeconds = nextRemaining; _onTick?.call(); } }); } void _syncRemaining({required bool notify}) { final nextRemaining = _remaining(); if (nextRemaining == _remainingSeconds) return; _remainingSeconds = nextRemaining; if (notify) { _onTick?.call(); } } int _remaining() { final until = _until; if (until == null) return 0; final remaining = until.difference(DateTime.now()).inSeconds; return remaining < 0 ? 0 : remaining; } }