Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
  • Loading branch information
rrousselGit committed Oct 10, 2023
2 parents 9982bd3 + 74f356a commit 5558b3b
Show file tree
Hide file tree
Showing 4 changed files with 183 additions and 18 deletions.
35 changes: 18 additions & 17 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -338,23 +338,24 @@ They will take care of creating/updating/disposing an object.

A series of hooks with no particular theme.

| Name | Description |
|--------------------------------------------------------------------------------------------------------------------------------------|-----------------------------------------------------------------------------|
| [useReducer](https://pub.dev/documentation/flutter_hooks/latest/flutter_hooks/useReducer.html) | An alternative to `useState` for more complex states. |
| [usePrevious](https://pub.dev/documentation/flutter_hooks/latest/flutter_hooks/usePrevious.html) | Returns the previous argument called to [usePrevious]. |
| [useTextEditingController](https://pub.dev/documentation/flutter_hooks/latest/flutter_hooks/useTextEditingController-constant.html) | Creates a `TextEditingController`. |
| [useFocusNode](https://pub.dev/documentation/flutter_hooks/latest/flutter_hooks/useFocusNode.html) | Creates a `FocusNode`. |
| [useTabController](https://pub.dev/documentation/flutter_hooks/latest/flutter_hooks/useTabController.html) | Creates and disposes a `TabController`. |
| [useScrollController](https://pub.dev/documentation/flutter_hooks/latest/flutter_hooks/useScrollController.html) | Creates and disposes a `ScrollController`. |
| [usePageController](https://pub.dev/documentation/flutter_hooks/latest/flutter_hooks/usePageController.html) | Creates and disposes a `PageController`. |
| [useAppLifecycleState](https://pub.dev/documentation/flutter_hooks/latest/flutter_hooks/useAppLifecycleState.html) | Returns the current `AppLifecycleState` and rebuilds the widget on change. |
| [useOnAppLifecycleStateChange](https://pub.dev/documentation/flutter_hooks/latest/flutter_hooks/useOnAppLifecycleStateChange.html) | Listens to `AppLifecycleState` changes and triggers a callback on change. |
| [useTransformationController](https://pub.dev/documentation/flutter_hooks/latest/flutter_hooks/useTransformationController.html) | Creates and disposes a `TransformationController`. |
| [useIsMounted](https://pub.dev/documentation/flutter_hooks/latest/flutter_hooks/useIsMounted.html) | An equivalent to `State.mounted` for hooks. |
| [useAutomaticKeepAlive](https://pub.dev/documentation/flutter_hooks/latest/flutter_hooks/useAutomaticKeepAlive.html) | An equivalent to the `AutomaticKeepAlive` widget for hooks. |
| [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`. |
| [useExpansionTileController](https://api.flutter.dev/flutter/material/ExpansionTileController-class.html) | Creates a `ExpansionTileController`. |
| Name | Description |
| ------------------------------------------------------------------------------------------------------------------------------------ | -------------------------------------------------------------------------- |
| [useReducer](https://pub.dev/documentation/flutter_hooks/latest/flutter_hooks/useReducer.html) | An alternative to `useState` for more complex states. |
| [usePrevious](https://pub.dev/documentation/flutter_hooks/latest/flutter_hooks/usePrevious.html) | Returns the previous argument called to [usePrevious]. |
| [useTextEditingController](https://pub.dev/documentation/flutter_hooks/latest/flutter_hooks/useTextEditingController-constant.html) | Creates a `TextEditingController`. |
| [useFocusNode](https://pub.dev/documentation/flutter_hooks/latest/flutter_hooks/useFocusNode.html) | Creates a `FocusNode`. |
| [useTabController](https://pub.dev/documentation/flutter_hooks/latest/flutter_hooks/useTabController.html) | Creates and disposes a `TabController`. |
| [useScrollController](https://pub.dev/documentation/flutter_hooks/latest/flutter_hooks/useScrollController.html) | Creates and disposes a `ScrollController`. |
| [usePageController](https://pub.dev/documentation/flutter_hooks/latest/flutter_hooks/usePageController.html) | Creates and disposes a `PageController`. |
| [useAppLifecycleState](https://pub.dev/documentation/flutter_hooks/latest/flutter_hooks/useAppLifecycleState.html) | Returns the current `AppLifecycleState` and rebuilds the widget on change. |
| [useOnAppLifecycleStateChange](https://pub.dev/documentation/flutter_hooks/latest/flutter_hooks/useOnAppLifecycleStateChange.html) | Listens to `AppLifecycleState` changes and triggers a callback on change. |
| [useTransformationController](https://pub.dev/documentation/flutter_hooks/latest/flutter_hooks/useTransformationController.html) | Creates and disposes a `TransformationController`. |
| [useIsMounted](https://pub.dev/documentation/flutter_hooks/latest/flutter_hooks/useIsMounted.html) | An equivalent to `State.mounted` for hooks. |
| [useAutomaticKeepAlive](https://pub.dev/documentation/flutter_hooks/latest/flutter_hooks/useAutomaticKeepAlive.html) | An equivalent to the `AutomaticKeepAlive` widget for hooks. |
| [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`. |
| [useMaterialStatesController](https://pub.dev/documentation/flutter_hooks/latest/flutter_hooks/useMaterialStatesController.html) | Creates and disposes a `MaterialStatesController`. |
| [useExpansionTileController](https://api.flutter.dev/flutter/material/ExpansionTileController-class.html) | Creates a `ExpansionTileController`. |

## Contributions

Expand Down
9 changes: 8 additions & 1 deletion packages/flutter_hooks/lib/src/hooks.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,13 @@ import 'dart:async';

import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart'
show Brightness, ExpansionTileController, SearchController, TabController;
show
Brightness,
ExpansionTileController,
MaterialState,
MaterialStatesController,
SearchController,
TabController;
import 'package:flutter/scheduler.dart';
import 'package:flutter/widgets.dart';

Expand All @@ -26,3 +32,4 @@ part 'tab_controller.dart';
part 'text_controller.dart';
part 'transformation_controller.dart';
part 'widgets_binding_observer.dart';
part 'material_states_controller.dart';
44 changes: 44 additions & 0 deletions packages/flutter_hooks/lib/src/material_states_controller.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
part of 'hooks.dart';

/// Creates a [MaterialStatesController] that will be disposed automatically.
///
/// See also:
/// - [MaterialStatesController]
MaterialStatesController useMaterialStatesController({
Set<MaterialState>? values,
List<Object?>? keys,
}) {
return use(
_MaterialStatesControllerHook(
values: values,
keys: keys,
),
);
}

class _MaterialStatesControllerHook extends Hook<MaterialStatesController> {
const _MaterialStatesControllerHook({
required this.values,
super.keys,
});

final Set<MaterialState>? values;

@override
HookState<MaterialStatesController, Hook<MaterialStatesController>>
createState() => _MaterialStateControllerHookState();
}

class _MaterialStateControllerHookState
extends HookState<MaterialStatesController, _MaterialStatesControllerHook> {
late final controller = MaterialStatesController(hook.values);

@override
MaterialStatesController build(BuildContext context) => controller;

@override
void dispose() => controller.dispose();

@override
String get debugLabel => 'useMaterialStatesController';
}
113 changes: 113 additions & 0 deletions packages/flutter_hooks/test/use_material_states_controller_test.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter_hooks/src/framework.dart';
import 'package:flutter_hooks/src/hooks.dart';
import 'package:flutter_test/flutter_test.dart';

import 'mock.dart';

void main() {
testWidgets('debugFillProperties', (tester) async {
await tester.pumpWidget(
HookBuilder(builder: (context) {
useMaterialStatesController();
return const SizedBox();
}),
);

final element = tester.element(find.byType(HookBuilder));

expect(
element
.toDiagnosticsNode(style: DiagnosticsTreeStyle.offstage)
.toStringDeep(),
equalsIgnoringHashCodes(
'HookBuilder\n'
' │ useMaterialStatesController: MaterialStatesController#00000({})\n'
' └SizedBox(renderObject: RenderConstrainedBox#00000)\n',
),
);
});

group('useMaterialStatesController', () {
testWidgets('initial values matches with real constructor', (tester) async {
late MaterialStatesController controller;
late MaterialStatesController controller2;

await tester.pumpWidget(
HookBuilder(builder: (context) {
controller2 = MaterialStatesController();
controller = useMaterialStatesController();
return Container();
}),
);

expect(controller.value, controller2.value);
});
testWidgets("returns a MaterialStatesController that doesn't change",
(tester) async {
late MaterialStatesController controller;
late MaterialStatesController controller2;

await tester.pumpWidget(
HookBuilder(builder: (context) {
controller = useMaterialStatesController();
return Container();
}),
);

expect(controller, isA<MaterialStatesController>());

await tester.pumpWidget(
HookBuilder(builder: (context) {
controller2 = useMaterialStatesController();
return Container();
}),
);

expect(identical(controller, controller2), isTrue);
});

testWidgets('passes hook parameters to the MaterialStatesController',
(tester) async {
late MaterialStatesController controller;

await tester.pumpWidget(
HookBuilder(
builder: (context) {
controller = useMaterialStatesController(
values: {MaterialState.selected},
);

return Container();
},
),
);

expect(controller.value, {MaterialState.selected});
});

testWidgets('disposes the MaterialStatesController on unmount',
(tester) async {
late MaterialStatesController controller;

await tester.pumpWidget(
HookBuilder(
builder: (context) {
controller = useMaterialStatesController();
return Container();
},
),
);

// pump another widget so that the old one gets disposed
await tester.pumpWidget(Container());

expect(
() => controller.addListener(() {}),
throwsA(isFlutterError.having(
(e) => e.message, 'message', contains('disposed'))),
);
});
});
}

0 comments on commit 5558b3b

Please sign in to comment.