Source Code added
This commit is contained in:
parent
800376eafd
commit
9efa9bc6dd
3912 changed files with 754770 additions and 2 deletions
95
mobile/lib/utils/debounce.dart
Normal file
95
mobile/lib/utils/debounce.dart
Normal file
|
|
@ -0,0 +1,95 @@
|
|||
import 'dart:async';
|
||||
|
||||
import 'package:flutter_hooks/flutter_hooks.dart';
|
||||
|
||||
/// Used to debounce function calls with the [interval] provided.
|
||||
/// If [maxWaitTime] is provided, the first [run] call as well as the next call since [maxWaitTime] has passed will be immediately executed, even if [interval] is not satisfied.
|
||||
class Debouncer {
|
||||
Debouncer({required this.interval, this.maxWaitTime});
|
||||
final Duration interval;
|
||||
final Duration? maxWaitTime;
|
||||
Timer? _timer;
|
||||
FutureOr<void> Function()? _lastAction;
|
||||
DateTime? _lastActionTime;
|
||||
Future<void>? _actionFuture;
|
||||
|
||||
void run(FutureOr<void> Function() action) {
|
||||
_lastAction = action;
|
||||
_timer?.cancel();
|
||||
|
||||
if (maxWaitTime != null &&
|
||||
// _actionFuture == null && // TODO: should this check be here?
|
||||
(_lastActionTime == null || DateTime.now().difference(_lastActionTime!) > maxWaitTime!)) {
|
||||
_callAndRest();
|
||||
return;
|
||||
}
|
||||
_timer = Timer(interval, _callAndRest);
|
||||
}
|
||||
|
||||
Future<void>? drain() {
|
||||
final timer = _timer;
|
||||
if (timer != null && timer.isActive) {
|
||||
timer.cancel();
|
||||
if (_lastAction != null) {
|
||||
_callAndRest();
|
||||
}
|
||||
}
|
||||
return _actionFuture;
|
||||
}
|
||||
|
||||
@pragma('vm:prefer-inline')
|
||||
void _callAndRest() {
|
||||
_lastActionTime = DateTime.now();
|
||||
final action = _lastAction;
|
||||
_lastAction = null;
|
||||
|
||||
final result = action!();
|
||||
if (result is Future) {
|
||||
_actionFuture = result.whenComplete(() {
|
||||
_actionFuture = null;
|
||||
});
|
||||
}
|
||||
_timer = null;
|
||||
}
|
||||
|
||||
void dispose() {
|
||||
_timer?.cancel();
|
||||
_timer = null;
|
||||
_lastAction = null;
|
||||
_lastActionTime = null;
|
||||
_actionFuture = null;
|
||||
}
|
||||
|
||||
bool get isActive => _actionFuture != null || (_timer != null && _timer!.isActive);
|
||||
}
|
||||
|
||||
/// Creates a [Debouncer] that will be disposed automatically. If no [interval] is provided, a
|
||||
/// default interval of 300ms is used to debounce the function calls
|
||||
Debouncer useDebouncer({
|
||||
Duration interval = const Duration(milliseconds: 300),
|
||||
Duration? maxWaitTime,
|
||||
List<Object?>? keys,
|
||||
}) => use(_DebouncerHook(interval: interval, maxWaitTime: maxWaitTime, keys: keys));
|
||||
|
||||
class _DebouncerHook extends Hook<Debouncer> {
|
||||
const _DebouncerHook({required this.interval, this.maxWaitTime, super.keys});
|
||||
|
||||
final Duration interval;
|
||||
final Duration? maxWaitTime;
|
||||
|
||||
@override
|
||||
HookState<Debouncer, Hook<Debouncer>> createState() => _DebouncerHookState();
|
||||
}
|
||||
|
||||
class _DebouncerHookState extends HookState<Debouncer, _DebouncerHook> {
|
||||
late final debouncer = Debouncer(interval: hook.interval, maxWaitTime: hook.maxWaitTime);
|
||||
|
||||
@override
|
||||
Debouncer build(_) => debouncer;
|
||||
|
||||
@override
|
||||
void dispose() => debouncer.dispose();
|
||||
|
||||
@override
|
||||
String get debugLabel => 'useDebouncer';
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue