From cf06c674030d13077a35049608b8ffa15b35368a Mon Sep 17 00:00:00 2001 From: Bent Hillerkus <29630575+benthillerkus@users.noreply.github.com> Date: Sat, 22 Mar 2025 00:53:32 +0100 Subject: [PATCH 1/3] feat: add Hook for managing SnapshotController instances --- packages/flutter_hooks/lib/src/hooks.dart | 1 + .../lib/src/snapshot_controller.dart | 61 +++++++++++++++ .../test/use_snapshot_controller_test.dart | 75 +++++++++++++++++++ 3 files changed, 137 insertions(+) create mode 100644 packages/flutter_hooks/lib/src/snapshot_controller.dart create mode 100644 packages/flutter_hooks/test/use_snapshot_controller_test.dart diff --git a/packages/flutter_hooks/lib/src/hooks.dart b/packages/flutter_hooks/lib/src/hooks.dart index d1e4664a..b5e1d562 100644 --- a/packages/flutter_hooks/lib/src/hooks.dart +++ b/packages/flutter_hooks/lib/src/hooks.dart @@ -41,3 +41,4 @@ part 'transformation_controller.dart'; part 'tree_sliver_controller.dart'; part 'widget_states_controller.dart'; part 'widgets_binding_observer.dart'; +part 'snapshot_controller.dart'; \ No newline at end of file diff --git a/packages/flutter_hooks/lib/src/snapshot_controller.dart b/packages/flutter_hooks/lib/src/snapshot_controller.dart new file mode 100644 index 00000000..9fcf70ab --- /dev/null +++ b/packages/flutter_hooks/lib/src/snapshot_controller.dart @@ -0,0 +1,61 @@ +part of 'hooks.dart'; + +/// Creates and disposes a [SnapshotController]. +/// +/// Note that [allowSnapshotting] must be set to `true` +/// in order for this controller to actually do anything. +/// This is consistent with [SnapshotController.new]. +/// +/// If [allowSnapshotting] changes on subsequent calls to [useSnapshotController], +/// [SnapshotController.allowSnapshotting] will be called to update accordingly. +/// +/// ```dart +/// final controller = useSnapshotController(allowSnapshotting: true); +/// // is equivalent to +/// final controller = useSnapshotController(); +/// controller.allowSnapshotting = true; +/// ``` +/// +/// See also: +/// - [SnapshotController] +SnapshotController useSnapshotController({ + bool allowSnapshotting = false, +}) { + return use( + _SnapshotControllerHook( + allowSnapshotting: allowSnapshotting, + ), + ); +} + +class _SnapshotControllerHook extends Hook { + const _SnapshotControllerHook({ + required this.allowSnapshotting, + }); + + final bool allowSnapshotting; + + @override + HookState> + createState() => _SnapshotControllerHookState(); +} + +class _SnapshotControllerHookState + extends HookState { + late final controller = SnapshotController(allowSnapshotting: hook.allowSnapshotting); + + @override + void didUpdateHook(_SnapshotControllerHook oldHook) { + super.didUpdateHook(oldHook); + controller.allowSnapshotting = hook.allowSnapshotting; + } + + @override + SnapshotController build(BuildContext context) => controller; + + @override + void dispose() => controller.dispose(); + + @override + String get debugLabel => 'useSnapshotController'; +} diff --git a/packages/flutter_hooks/test/use_snapshot_controller_test.dart b/packages/flutter_hooks/test/use_snapshot_controller_test.dart new file mode 100644 index 00000000..842691d4 --- /dev/null +++ b/packages/flutter_hooks/test/use_snapshot_controller_test.dart @@ -0,0 +1,75 @@ +import 'package:flutter/foundation.dart'; +import 'package:flutter/widgets.dart'; +import 'package:flutter_hooks/src/framework.dart'; +import 'package:flutter_hooks/src/hooks.dart'; + +import 'mock.dart'; + +void main() { + testWidgets('debugFillProperties', (tester) async { + await tester.pumpWidget( + HookBuilder(builder: (context) { + useSnapshotController(); + return const SizedBox(); + }), + ); + + await tester.pump(); + + final element = tester.element(find.byType(HookBuilder)); + + expect( + element + .toDiagnosticsNode(style: DiagnosticsTreeStyle.offstage) + .toStringDeep(), + equalsIgnoringHashCodes( + 'HookBuilder\n' + " │ useSnapshotController: Instance of 'SnapshotController'\n" + ' └SizedBox(renderObject: RenderConstrainedBox#00000)\n', + ), + ); + }); + + group('useSnapshotController', () { + testWidgets('initial values matches with real constructor', (tester) async { + late SnapshotController controller; + late SnapshotController controller2; + + await tester.pumpWidget( + HookBuilder(builder: (context) { + controller2 = SnapshotController(); + controller = useSnapshotController(); + return Container(); + }), + ); + + expect(controller.allowSnapshotting, controller2.allowSnapshotting); + }); + + testWidgets('passes hook parameters to the SnapshotController', + (tester) async { + late SnapshotController controller; + + await tester.pumpWidget( + HookBuilder(builder: (context) { + controller = useSnapshotController(allowSnapshotting: true); + return const SizedBox(); + }), + ); + + expect(controller.allowSnapshotting, true); + + late SnapshotController retrievedController; + await tester.pumpWidget( + HookBuilder(builder: (context) { + // ignore: avoid_redundant_argument_values + retrievedController = useSnapshotController(allowSnapshotting: false); + return const SizedBox(); + }), + ); + + expect(retrievedController, same(controller)); + expect(retrievedController.allowSnapshotting, false); + }); + }); +} From 846bc3a69982a84bad7a26f0ea11f3792868b919 Mon Sep 17 00:00:00 2001 From: Bent Hillerkus <29630575+benthillerkus@users.noreply.github.com> Date: Sat, 22 Mar 2025 01:16:13 +0100 Subject: [PATCH 2/3] chore: autoformat --- packages/flutter_hooks/lib/src/hooks.dart | 2 +- .../flutter_hooks/lib/src/snapshot_controller.dart | 13 +++++++------ 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/packages/flutter_hooks/lib/src/hooks.dart b/packages/flutter_hooks/lib/src/hooks.dart index b5e1d562..2ad681b1 100644 --- a/packages/flutter_hooks/lib/src/hooks.dart +++ b/packages/flutter_hooks/lib/src/hooks.dart @@ -41,4 +41,4 @@ part 'transformation_controller.dart'; part 'tree_sliver_controller.dart'; part 'widget_states_controller.dart'; part 'widgets_binding_observer.dart'; -part 'snapshot_controller.dart'; \ No newline at end of file +part 'snapshot_controller.dart'; diff --git a/packages/flutter_hooks/lib/src/snapshot_controller.dart b/packages/flutter_hooks/lib/src/snapshot_controller.dart index 9fcf70ab..d5b69ec7 100644 --- a/packages/flutter_hooks/lib/src/snapshot_controller.dart +++ b/packages/flutter_hooks/lib/src/snapshot_controller.dart @@ -1,14 +1,14 @@ part of 'hooks.dart'; /// Creates and disposes a [SnapshotController]. -/// +/// /// Note that [allowSnapshotting] must be set to `true` /// in order for this controller to actually do anything. /// This is consistent with [SnapshotController.new]. -/// +/// /// If [allowSnapshotting] changes on subsequent calls to [useSnapshotController], /// [SnapshotController.allowSnapshotting] will be called to update accordingly. -/// +/// /// ```dart /// final controller = useSnapshotController(allowSnapshotting: true); /// // is equivalent to @@ -36,13 +36,14 @@ class _SnapshotControllerHook extends Hook { final bool allowSnapshotting; @override - HookState> - createState() => _SnapshotControllerHookState(); + HookState> createState() => + _SnapshotControllerHookState(); } class _SnapshotControllerHookState extends HookState { - late final controller = SnapshotController(allowSnapshotting: hook.allowSnapshotting); + late final controller = + SnapshotController(allowSnapshotting: hook.allowSnapshotting); @override void didUpdateHook(_SnapshotControllerHook oldHook) { From dfad11587b227602188ddd421722b10fa9e9688b Mon Sep 17 00:00:00 2001 From: Remi Rousselet Date: Tue, 12 Aug 2025 18:20:05 +0200 Subject: [PATCH 3/3] Docs --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index fcb293cd..4f014f86 100644 --- a/README.md +++ b/README.md @@ -355,12 +355,13 @@ A series of hooks with no particular theme. | [useOnPlatformBrightnessChange](https://pub.dev/documentation/flutter_hooks/latest/flutter_hooks/useOnPlatformBrightnessChange.html) | Listens to platform `Brightness` changes and triggers a callback on change. | | [useSearchController](https://pub.dev/documentation/flutter_hooks/latest/flutter_hooks/useSearchController.html) | Creates and disposes a `SearchController`. | | [useWidgetStatesController](https://pub.dev/documentation/flutter_hooks/latest/flutter_hooks/useWidgetStatesController.html) | Creates and disposes a `WidgetStatesController`. | -| [useExpansibleController](https://pub.dev/documentation/flutter_hooks/latest/flutter_hooks/useExpansibleController.html) | Creates a `ExpansibleController`. | +| [useExpansibleController](https://pub.dev/documentation/flutter_hooks/latest/flutter_hooks/useExpansibleController.html) | Creates a `ExpansibleController`. | | [useDebounced](https://pub.dev/documentation/flutter_hooks/latest/flutter_hooks/useDebounced.html) | Returns a debounced version of the provided value, triggering widget updates accordingly after a specified timeout duration | | [useDraggableScrollableController](https://api.flutter.dev/flutter/widgets/DraggableScrollableController-class.html) | Creates a `DraggableScrollableController`. | | [useCarouselController](https://pub.dev/documentation/flutter_hooks/latest/flutter_hooks/useCarouselController.html) | Creates and disposes a **`CarouselController`**. | | [useTreeSliverController](https://pub.dev/documentation/flutter_hooks/latest/flutter_hooks/useTreeSliverController.html) | Creates a `TreeSliverController`. | | [useOverlayPortalController](https://api.flutter.dev/flutter/widgets/OverlayPortalController-class.html) | Creates and manages an `OverlayPortalController` for controlling the visibility of overlay content. The controller will be automatically disposed when no longer needed. | +| [useSnapshotController](https://api.flutter.dev/flutter/widgets/SnapshotController-class.html) | Creates and manages a `SnapshotController` | ## Contributions