Skip to content

Commit 9506ee7

Browse files
authored
Merge pull request #464 from benthillerkus/use-snapshot-controller
Add Hook for managing SnapshotController instances
2 parents e802dd3 + dfad115 commit 9506ee7

File tree

4 files changed

+140
-1
lines changed

4 files changed

+140
-1
lines changed

README.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -355,12 +355,13 @@ A series of hooks with no particular theme.
355355
| [useOnPlatformBrightnessChange](https://pub.dev/documentation/flutter_hooks/latest/flutter_hooks/useOnPlatformBrightnessChange.html) | Listens to platform `Brightness` changes and triggers a callback on change. |
356356
| [useSearchController](https://pub.dev/documentation/flutter_hooks/latest/flutter_hooks/useSearchController.html) | Creates and disposes a `SearchController`. |
357357
| [useWidgetStatesController](https://pub.dev/documentation/flutter_hooks/latest/flutter_hooks/useWidgetStatesController.html) | Creates and disposes a `WidgetStatesController`. |
358-
| [useExpansibleController](https://pub.dev/documentation/flutter_hooks/latest/flutter_hooks/useExpansibleController.html) | Creates a `ExpansibleController`. |
358+
| [useExpansibleController](https://pub.dev/documentation/flutter_hooks/latest/flutter_hooks/useExpansibleController.html) | Creates a `ExpansibleController`. |
359359
| [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 |
360360
| [useDraggableScrollableController](https://api.flutter.dev/flutter/widgets/DraggableScrollableController-class.html) | Creates a `DraggableScrollableController`. |
361361
| [useCarouselController](https://pub.dev/documentation/flutter_hooks/latest/flutter_hooks/useCarouselController.html) | Creates and disposes a **`CarouselController`**. |
362362
| [useTreeSliverController](https://pub.dev/documentation/flutter_hooks/latest/flutter_hooks/useTreeSliverController.html) | Creates a `TreeSliverController`. |
363363
| [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. |
364+
| [useSnapshotController](https://api.flutter.dev/flutter/widgets/SnapshotController-class.html) | Creates and manages a `SnapshotController` |
364365

365366
## Contributions
366367

packages/flutter_hooks/lib/src/hooks.dart

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,3 +42,4 @@ part 'transformation_controller.dart';
4242
part 'tree_sliver_controller.dart';
4343
part 'widget_states_controller.dart';
4444
part 'widgets_binding_observer.dart';
45+
part 'snapshot_controller.dart';
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
part of 'hooks.dart';
2+
3+
/// Creates and disposes a [SnapshotController].
4+
///
5+
/// Note that [allowSnapshotting] must be set to `true`
6+
/// in order for this controller to actually do anything.
7+
/// This is consistent with [SnapshotController.new].
8+
///
9+
/// If [allowSnapshotting] changes on subsequent calls to [useSnapshotController],
10+
/// [SnapshotController.allowSnapshotting] will be called to update accordingly.
11+
///
12+
/// ```dart
13+
/// final controller = useSnapshotController(allowSnapshotting: true);
14+
/// // is equivalent to
15+
/// final controller = useSnapshotController();
16+
/// controller.allowSnapshotting = true;
17+
/// ```
18+
///
19+
/// See also:
20+
/// - [SnapshotController]
21+
SnapshotController useSnapshotController({
22+
bool allowSnapshotting = false,
23+
}) {
24+
return use(
25+
_SnapshotControllerHook(
26+
allowSnapshotting: allowSnapshotting,
27+
),
28+
);
29+
}
30+
31+
class _SnapshotControllerHook extends Hook<SnapshotController> {
32+
const _SnapshotControllerHook({
33+
required this.allowSnapshotting,
34+
});
35+
36+
final bool allowSnapshotting;
37+
38+
@override
39+
HookState<SnapshotController, Hook<SnapshotController>> createState() =>
40+
_SnapshotControllerHookState();
41+
}
42+
43+
class _SnapshotControllerHookState
44+
extends HookState<SnapshotController, _SnapshotControllerHook> {
45+
late final controller =
46+
SnapshotController(allowSnapshotting: hook.allowSnapshotting);
47+
48+
@override
49+
void didUpdateHook(_SnapshotControllerHook oldHook) {
50+
super.didUpdateHook(oldHook);
51+
controller.allowSnapshotting = hook.allowSnapshotting;
52+
}
53+
54+
@override
55+
SnapshotController build(BuildContext context) => controller;
56+
57+
@override
58+
void dispose() => controller.dispose();
59+
60+
@override
61+
String get debugLabel => 'useSnapshotController';
62+
}
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
import 'package:flutter/foundation.dart';
2+
import 'package:flutter/widgets.dart';
3+
import 'package:flutter_hooks/src/framework.dart';
4+
import 'package:flutter_hooks/src/hooks.dart';
5+
6+
import 'mock.dart';
7+
8+
void main() {
9+
testWidgets('debugFillProperties', (tester) async {
10+
await tester.pumpWidget(
11+
HookBuilder(builder: (context) {
12+
useSnapshotController();
13+
return const SizedBox();
14+
}),
15+
);
16+
17+
await tester.pump();
18+
19+
final element = tester.element(find.byType(HookBuilder));
20+
21+
expect(
22+
element
23+
.toDiagnosticsNode(style: DiagnosticsTreeStyle.offstage)
24+
.toStringDeep(),
25+
equalsIgnoringHashCodes(
26+
'HookBuilder\n'
27+
" │ useSnapshotController: Instance of 'SnapshotController'\n"
28+
' └SizedBox(renderObject: RenderConstrainedBox#00000)\n',
29+
),
30+
);
31+
});
32+
33+
group('useSnapshotController', () {
34+
testWidgets('initial values matches with real constructor', (tester) async {
35+
late SnapshotController controller;
36+
late SnapshotController controller2;
37+
38+
await tester.pumpWidget(
39+
HookBuilder(builder: (context) {
40+
controller2 = SnapshotController();
41+
controller = useSnapshotController();
42+
return Container();
43+
}),
44+
);
45+
46+
expect(controller.allowSnapshotting, controller2.allowSnapshotting);
47+
});
48+
49+
testWidgets('passes hook parameters to the SnapshotController',
50+
(tester) async {
51+
late SnapshotController controller;
52+
53+
await tester.pumpWidget(
54+
HookBuilder(builder: (context) {
55+
controller = useSnapshotController(allowSnapshotting: true);
56+
return const SizedBox();
57+
}),
58+
);
59+
60+
expect(controller.allowSnapshotting, true);
61+
62+
late SnapshotController retrievedController;
63+
await tester.pumpWidget(
64+
HookBuilder(builder: (context) {
65+
// ignore: avoid_redundant_argument_values
66+
retrievedController = useSnapshotController(allowSnapshotting: false);
67+
return const SizedBox();
68+
}),
69+
);
70+
71+
expect(retrievedController, same(controller));
72+
expect(retrievedController.allowSnapshotting, false);
73+
});
74+
});
75+
}

0 commit comments

Comments
 (0)