mirror of
				https://github.com/immich-app/immich.git
				synced 2025-11-03 19:17:11 -05:00 
			
		
		
		
	* chore: bump dart sdk to 3.8 * chore: make build * make pigeon * chore: format files --------- Co-authored-by: shenlong-tanwen <139912620+shalong-tanwen@users.noreply.github.com>
		
			
				
	
	
		
			95 lines
		
	
	
		
			2.6 KiB
		
	
	
	
		
			Dart
		
	
	
	
	
	
			
		
		
	
	
			95 lines
		
	
	
		
			2.6 KiB
		
	
	
	
		
			Dart
		
	
	
	
	
	
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() {
 | 
						|
    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';
 | 
						|
}
 |