Skip to content

Commit a203adf

Browse files
authored
Merge pull request #450 from offich:feat/use-overlay-portal-controller
Add useOverlayPortalController
2 parents c3c3d24 + 16a0b79 commit a203adf

File tree

4 files changed

+145
-23
lines changed

4 files changed

+145
-23
lines changed

README.md

Lines changed: 24 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -337,29 +337,30 @@ They will take care of creating/updating/disposing an object.
337337

338338
A series of hooks with no particular theme.
339339

340-
| Name | Description |
341-
| -------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------- |
342-
| [useReducer](https://pub.dev/documentation/flutter_hooks/latest/flutter_hooks/useReducer.html) | An alternative to `useState` for more complex states. |
343-
| [usePrevious](https://pub.dev/documentation/flutter_hooks/latest/flutter_hooks/usePrevious.html) | Returns the previous argument called to [usePrevious]. |
344-
| [useTextEditingController](https://pub.dev/documentation/flutter_hooks/latest/flutter_hooks/useTextEditingController-constant.html) | Creates a `TextEditingController`. |
345-
| [useFocusNode](https://pub.dev/documentation/flutter_hooks/latest/flutter_hooks/useFocusNode.html) | Creates a `FocusNode`. |
346-
| [useTabController](https://pub.dev/documentation/flutter_hooks/latest/flutter_hooks/useTabController.html) | Creates and disposes a `TabController`. |
347-
| [useScrollController](https://pub.dev/documentation/flutter_hooks/latest/flutter_hooks/useScrollController.html) | Creates and disposes a `ScrollController`. |
348-
| [usePageController](https://pub.dev/documentation/flutter_hooks/latest/flutter_hooks/usePageController.html) | Creates and disposes a `PageController`. |
349-
| [useFixedExtentScrollController](https://pub.dev/documentation/flutter_hooks/latest/flutter_hooks/useFixedExtentScrollController.html) | Creates and disposes a `FixedExtentScrollController`. |
350-
| [useAppLifecycleState](https://pub.dev/documentation/flutter_hooks/latest/flutter_hooks/useAppLifecycleState.html) | Returns the current `AppLifecycleState` and rebuilds the widget on change. |
351-
| [useOnAppLifecycleStateChange](https://pub.dev/documentation/flutter_hooks/latest/flutter_hooks/useOnAppLifecycleStateChange.html) | Listens to `AppLifecycleState` changes and triggers a callback on change. |
352-
| [useTransformationController](https://pub.dev/documentation/flutter_hooks/latest/flutter_hooks/useTransformationController.html) | Creates and disposes a `TransformationController`. |
353-
| [useIsMounted](https://pub.dev/documentation/flutter_hooks/latest/flutter_hooks/useIsMounted.html) | An equivalent to `State.mounted` for hooks. |
354-
| [useAutomaticKeepAlive](https://pub.dev/documentation/flutter_hooks/latest/flutter_hooks/useAutomaticKeepAlive.html) | An equivalent to the `AutomaticKeepAlive` widget for hooks. |
355-
| [useOnPlatformBrightnessChange](https://pub.dev/documentation/flutter_hooks/latest/flutter_hooks/useOnPlatformBrightnessChange.html) | Listens to platform `Brightness` changes and triggers a callback on change. |
356-
| [useSearchController](https://pub.dev/documentation/flutter_hooks/latest/flutter_hooks/useSearchController.html) | Creates and disposes a `SearchController`. |
357-
| [useWidgetStatesController](https://pub.dev/documentation/flutter_hooks/latest/flutter_hooks/useWidgetStatesController.html) | Creates and disposes a `WidgetStatesController`. |
358-
| [useExpansionTileController](https://api.flutter.dev/flutter/material/ExpansionTileController-class.html) | Creates a `ExpansionTileController`. |
359-
| [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 |
360-
| [useDraggableScrollableController](https://api.flutter.dev/flutter/widgets/DraggableScrollableController-class.html) | Creates a `DraggableScrollableController`. |
361-
| [useCarouselController](https://pub.dev/documentation/flutter_hooks/latest/flutter_hooks/useCarouselController.html) | Creates and disposes a `CarouselController`. |
362-
| [useTreeSliverController](https://pub.dev/documentation/flutter_hooks/latest/flutter_hooks/useTreeSliverController.html) | Creates a `TreeSliverController`. |
340+
| Name | Description |
341+
| -------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
342+
| [useReducer](https://pub.dev/documentation/flutter_hooks/latest/flutter_hooks/useReducer.html) | An alternative to `useState` for more complex states. |
343+
| [usePrevious](https://pub.dev/documentation/flutter_hooks/latest/flutter_hooks/usePrevious.html) | Returns the previous argument called to [usePrevious]. |
344+
| [useTextEditingController](https://pub.dev/documentation/flutter_hooks/latest/flutter_hooks/useTextEditingController-constant.html) | Creates a `TextEditingController`. |
345+
| [useFocusNode](https://pub.dev/documentation/flutter_hooks/latest/flutter_hooks/useFocusNode.html) | Creates a `FocusNode`. |
346+
| [useTabController](https://pub.dev/documentation/flutter_hooks/latest/flutter_hooks/useTabController.html) | Creates and disposes a `TabController`. |
347+
| [useScrollController](https://pub.dev/documentation/flutter_hooks/latest/flutter_hooks/useScrollController.html) | Creates and disposes a `ScrollController`. |
348+
| [usePageController](https://pub.dev/documentation/flutter_hooks/latest/flutter_hooks/usePageController.html) | Creates and disposes a `PageController`. |
349+
| [useFixedExtentScrollController](https://pub.dev/documentation/flutter_hooks/latest/flutter_hooks/useFixedExtentScrollController.html) | Creates and disposes a `FixedExtentScrollController`. |
350+
| [useAppLifecycleState](https://pub.dev/documentation/flutter_hooks/latest/flutter_hooks/useAppLifecycleState.html) | Returns the current `AppLifecycleState` and rebuilds the widget on change. |
351+
| [useOnAppLifecycleStateChange](https://pub.dev/documentation/flutter_hooks/latest/flutter_hooks/useOnAppLifecycleStateChange.html) | Listens to `AppLifecycleState` changes and triggers a callback on change. |
352+
| [useTransformationController](https://pub.dev/documentation/flutter_hooks/latest/flutter_hooks/useTransformationController.html) | Creates and disposes a `TransformationController`. |
353+
| [useIsMounted](https://pub.dev/documentation/flutter_hooks/latest/flutter_hooks/useIsMounted.html) | An equivalent to `State.mounted` for hooks. |
354+
| [useAutomaticKeepAlive](https://pub.dev/documentation/flutter_hooks/latest/flutter_hooks/useAutomaticKeepAlive.html) | An equivalent to the `AutomaticKeepAlive` widget for hooks. |
355+
| [useOnPlatformBrightnessChange](https://pub.dev/documentation/flutter_hooks/latest/flutter_hooks/useOnPlatformBrightnessChange.html) | Listens to platform `Brightness` changes and triggers a callback on change. |
356+
| [useSearchController](https://pub.dev/documentation/flutter_hooks/latest/flutter_hooks/useSearchController.html) | Creates and disposes a `SearchController`. |
357+
| [useWidgetStatesController](https://pub.dev/documentation/flutter_hooks/latest/flutter_hooks/useWidgetStatesController.html) | Creates and disposes a `WidgetStatesController`. |
358+
| [useExpansionTileController](https://api.flutter.dev/flutter/material/ExpansionTileController-class.html) | Creates a `ExpansionTileController`. |
359+
| [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 |
360+
| [useDraggableScrollableController](https://api.flutter.dev/flutter/widgets/DraggableScrollableController-class.html) | Creates a `DraggableScrollableController`. |
361+
| [useCarouselController](https://pub.dev/documentation/flutter_hooks/latest/flutter_hooks/useCarouselController.html) | Creates and disposes a **`CarouselController`**. |
362+
| [useTreeSliverController](https://pub.dev/documentation/flutter_hooks/latest/flutter_hooks/useTreeSliverController.html) | Creates a `TreeSliverController`. |
363+
| [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. |
363364

364365
## Contributions
365366

packages/flutter_hooks/CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
- Add `useCarouselController` (thanks to @riscait)
44
- Add `useTreeSliverController` (thanks to @benthillerkus)
5+
- Added `useOverlayPortalController` (thanks to @offich)
56

67
## 0.21.1-pre.4 - 2024-08-01
78

packages/flutter_hooks/lib/src/misc.dart

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -229,3 +229,32 @@ class _IsMountedHookState extends HookState<IsMounted, _IsMountedHook> {
229229
"Use BuildContext.mounted instead if you're on Flutter 3.7.0 or greater",
230230
)
231231
typedef IsMounted = bool Function();
232+
233+
/// Creates a [OverlayPortalController] that will be disposed automatically.
234+
///
235+
/// See also:
236+
/// - [OverlayPortalController]
237+
OverlayPortalController useOverlayPortalController({
238+
List<Object?>? keys,
239+
}) {
240+
return use(_OverlayPortalControllerHook(keys: keys));
241+
}
242+
243+
class _OverlayPortalControllerHook extends Hook<OverlayPortalController> {
244+
const _OverlayPortalControllerHook({List<Object?>? keys}) : super(keys: keys);
245+
246+
@override
247+
HookState<OverlayPortalController, Hook<OverlayPortalController>>
248+
createState() => _OverlayPortalControllerHookState();
249+
}
250+
251+
class _OverlayPortalControllerHookState
252+
extends HookState<OverlayPortalController, _OverlayPortalControllerHook> {
253+
final controller = OverlayPortalController();
254+
255+
@override
256+
OverlayPortalController build(BuildContext context) => controller;
257+
258+
@override
259+
String get debugLabel => 'useOverlayPortalController';
260+
}
Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
import 'package:flutter/foundation.dart';
2+
import 'package:flutter/material.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+
useOverlayPortalController();
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+
' │ useOverlayPortalController: OverlayPortalController DETACHED\n'
28+
' └SizedBox(renderObject: RenderConstrainedBox#00000)\n',
29+
),
30+
);
31+
});
32+
33+
group('useOverlayPortalController', () {
34+
testWidgets('initial values matches with real constructor', (tester) async {
35+
late OverlayPortalController controller;
36+
final controller2 = OverlayPortalController();
37+
38+
await tester.pumpWidget(MaterialApp(
39+
home: Scaffold(
40+
body: HookBuilder(builder: (context) {
41+
controller = useOverlayPortalController();
42+
return Column(
43+
children: [
44+
OverlayPortal(
45+
controller: controller,
46+
overlayChildBuilder: (context) =>
47+
const Text('Overlay Portal'),
48+
),
49+
OverlayPortal(
50+
controller: controller2,
51+
overlayChildBuilder: (context) =>
52+
const Text('Overlay Portal 2'),
53+
),
54+
],
55+
);
56+
}),
57+
),
58+
));
59+
expect(controller, isA<OverlayPortalController>());
60+
expect(controller.isShowing, controller2.isShowing);
61+
});
62+
63+
testWidgets('check show/hide of overlay portal', (tester) async {
64+
late OverlayPortalController controller;
65+
await tester.pumpWidget(MaterialApp(
66+
home: Scaffold(
67+
body: HookBuilder(builder: (context) {
68+
controller = useOverlayPortalController();
69+
return OverlayPortal(
70+
controller: controller,
71+
overlayChildBuilder: (context) => const Text('Overlay Content'),
72+
);
73+
}),
74+
),
75+
));
76+
77+
expect(controller.isShowing, false);
78+
expect(find.text('Overlay Content'), findsNothing);
79+
80+
controller.show();
81+
await tester.pump();
82+
expect(controller.isShowing, true);
83+
expect(find.text('Overlay Content'), findsOneWidget);
84+
85+
controller.hide();
86+
await tester.pump();
87+
expect(controller.isShowing, false);
88+
expect(find.text('Overlay Content'), findsNothing);
89+
});
90+
});
91+
}

0 commit comments

Comments
 (0)