86 lines
1.9 KiB
Dart
86 lines
1.9 KiB
Dart
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;
|
|
}
|
|
}
|