Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Add useCarouselController #447

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -358,6 +358,7 @@ A series of hooks with no particular theme.
| [useExpansionTileController](https://api.flutter.dev/flutter/material/ExpansionTileController-class.html) | Creates a `ExpansionTileController`. |
| [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`. |

## Contributions

Expand Down
46 changes: 46 additions & 0 deletions packages/flutter_hooks/lib/src/carousel_controller.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
part of 'hooks.dart';

/// Creates a [CarouselController] that will be disposed automatically.
///
/// See also:
/// - [CarouselController]
CarouselController useCarouselController({
int initialItem = 0,
List<Object?>? keys,
}) {
return use(
_CarouselControllerHook(
initialItem: initialItem,
keys: keys,
),
);
}

class _CarouselControllerHook extends Hook<CarouselController> {
const _CarouselControllerHook({
required this.initialItem,
super.keys,
});

final int initialItem;

@override
HookState<CarouselController, Hook<CarouselController>> createState() =>
_CarouselControllerHookState();
}

class _CarouselControllerHookState
extends HookState<CarouselController, _CarouselControllerHook> {
late final controller = CarouselController(
initialItem: hook.initialItem,
);

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

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

@override
String get debugLabel => 'useCarouselController';
}
2 changes: 2 additions & 0 deletions packages/flutter_hooks/lib/src/hooks.dart
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart'
show
Brightness,
CarouselController,
DraggableScrollableController,
ExpansionTileController,
WidgetStatesController,
Expand All @@ -17,6 +18,7 @@ import 'framework.dart';

part 'animation.dart';
part 'async.dart';
part 'carousel_controller.dart';
part 'draggable_scrollable_controller.dart';
part 'expansion_tile_controller.dart';
part 'fixed_extent_scroll_controller.dart';
Expand Down
117 changes: 117 additions & 0 deletions packages/flutter_hooks/test/carousel_controller_test.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
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';
Comment on lines +1 to +7
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codebase verification

Remove unnecessary import of 'mock.dart'

The import of 'mock.dart' is not used in the file and can be safely removed.

🔗 Analysis chain

Verify the usage of 'mock.dart'

The file imports 'mock.dart', but it doesn't appear to be used in the visible code. Please ensure that this import is necessary for the tests.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check if 'mock.dart' is used in the file

# Test: Search for usage of any identifier from 'mock.dart'
rg --type dart -i '\bmock\b' packages/flutter_hooks/test/carousel_controller_test.dart

# If no results, the import might be unnecessary

Length of output: 108


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

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

expect(
element
.toDiagnosticsNode(style: DiagnosticsTreeStyle.offstage)
.toStringDeep(),
equalsIgnoringHashCodes(
'HookBuilder\n'
' │ useCarouselController: CarouselController#00000(no clients)\n'
' └SizedBox(renderObject: RenderConstrainedBox#00000)\n',
),
);
});

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

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

expect(controller.initialItem, controller2.initialItem);
expect(controller.initialScrollOffset, controller2.initialScrollOffset);
expect(controller.keepScrollOffset, controller2.keepScrollOffset);
expect(controller.onAttach, controller2.onAttach);
expect(controller.onDetach, controller2.onDetach);
});

testWidgets("returns a CarouselController that doesn't change",
(tester) async {
late CarouselController controller;
late CarouselController controller2;

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

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

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

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

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

await tester.pumpWidget(
HookBuilder(
builder: (context) {
controller = useCarouselController(
initialItem: 42,
);

return Container();
},
),
);

expect(controller.initialItem, 42);
});

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

await tester.pumpWidget(
HookBuilder(
builder: (context) {
controller = useCarouselController();
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'))),
);
});
});
}