68 lines
1.7 KiB
Dart
68 lines
1.7 KiB
Dart
import 'dart:async';
|
|
|
|
typedef _Debounceable<S, T> = Future<S?> Function(T parameter);
|
|
|
|
class Debouncer {
|
|
Debouncer(this._duration, this._callback);
|
|
|
|
final Duration _duration;
|
|
final dynamic _callback;
|
|
late final _Debounceable<dynamic, String> _debouncedSearch = _debounce<dynamic, String>(_callback);
|
|
|
|
/// Returns a new function that is a debounced version of the given function.
|
|
///
|
|
/// This means that the original function will be called only after no calls
|
|
/// have been made for the given Duration.
|
|
_Debounceable<S, T> _debounce<S, T>(_Debounceable<S?, T> function) {
|
|
_DebounceTimer? debounceTimer;
|
|
|
|
return (T parameter) async {
|
|
if (debounceTimer != null && !debounceTimer!.isCompleted) {
|
|
debounceTimer!.cancel();
|
|
}
|
|
debounceTimer = _DebounceTimer(_duration);
|
|
try {
|
|
await debounceTimer!.future;
|
|
} on _CancelException {
|
|
return null;
|
|
}
|
|
return function(parameter);
|
|
};
|
|
}
|
|
|
|
process(data) {
|
|
return _debouncedSearch(data);
|
|
}
|
|
}
|
|
|
|
// A wrapper around Timer used for debouncing.
|
|
class _DebounceTimer {
|
|
final Duration debounceDuration;
|
|
|
|
_DebounceTimer(
|
|
this.debounceDuration
|
|
) {
|
|
_timer = Timer(debounceDuration, _onComplete);
|
|
}
|
|
|
|
late final Timer _timer;
|
|
final Completer<void> _completer = Completer<void>();
|
|
|
|
void _onComplete() {
|
|
_completer.complete();
|
|
}
|
|
|
|
Future<void> get future => _completer.future;
|
|
|
|
bool get isCompleted => _completer.isCompleted;
|
|
|
|
void cancel() {
|
|
_timer.cancel();
|
|
_completer.completeError(const _CancelException());
|
|
}
|
|
}
|
|
|
|
// An exception indicating that the timer was canceled.
|
|
class _CancelException implements Exception {
|
|
const _CancelException();
|
|
} |