Line data Source code
1 : import 'package:flutter/widgets.dart';
2 : import 'debouncer.dart';
3 : import 'debouncer_config.dart';
4 : import 'strategy/debounce_strategy.dart';
5 : import 'strategy/trailing_edge_strategy.dart';
6 : import 'utils/debouncer_logger.dart';
7 : import 'utils/lifecycle_hooks.dart';
8 :
9 : /// A mixin for [State] subclasses that manages a [Debouncer] automatically.
10 : ///
11 : /// The debouncer is created lazily on first use and disposed alongside
12 : /// the widget — you never need to manually call [Debouncer.dispose].
13 : ///
14 : /// ## Basic usage
15 : /// ```dart
16 : /// class _SearchBarState extends State<SearchBar> with DebouncerMixin {
17 : /// void _onChanged(String query) {
18 : /// debounce(() => _search(query));
19 : /// }
20 : /// }
21 : /// ```
22 : ///
23 : /// ## Custom delay
24 : /// ```dart
25 : /// @override
26 : /// Duration get debounceDuration => const Duration(milliseconds: 500);
27 : /// ```
28 : ///
29 : /// ## Custom strategy
30 : /// ```dart
31 : /// @override
32 : /// DebouncerStrategy get debouncerStrategy => const LeadingEdgeStrategy();
33 : /// ```
34 : mixin DebouncerMixin<T extends StatefulWidget> on State<T> {
35 : Debouncer? _mixinDebouncer;
36 :
37 : /// How long to wait after the last call before firing. Default: 300 ms.
38 0 : Duration get debounceDuration => const Duration(milliseconds: 300);
39 :
40 : /// Which [DebouncerStrategy] to use. Default: [TrailingEdgeStrategy].
41 1 : DebouncerStrategy get debouncerStrategy => const TrailingEdgeStrategy();
42 :
43 : /// Optional [DebouncerLogger]. Override to enable logging.
44 1 : DebouncerLogger? get debouncerLogger => null;
45 :
46 : /// Optional [LifecycleHooks]. Override to receive fire/cancel callbacks.
47 1 : LifecycleHooks? get debouncerHooks => null;
48 :
49 3 : Debouncer get _debouncerInstance => _mixinDebouncer ??= Debouncer.fromConfig(
50 1 : DebouncerConfig(
51 1 : delay: debounceDuration,
52 2 : debugLabel: runtimeType.toString(),
53 : ),
54 1 : strategy: debouncerStrategy,
55 1 : logger: debouncerLogger,
56 1 : hooks: debouncerHooks,
57 : );
58 :
59 : /// Schedules [action] through the widget-scoped debouncer.
60 3 : void debounce(VoidCallback action) => _debouncerInstance.run(action);
61 :
62 : /// Cancels any currently-pending debounced action.
63 0 : void cancelDebounce() => _mixinDebouncer?.cancel();
64 :
65 : /// `true` if a debounced call is currently waiting to fire.
66 0 : bool get hasPendingDebounce => _mixinDebouncer?.isPending ?? false;
67 :
68 1 : @override
69 : void dispose() {
70 2 : _mixinDebouncer?.dispose();
71 1 : _mixinDebouncer = null;
72 1 : super.dispose();
73 : }
74 : }
|