-
Notifications
You must be signed in to change notification settings - Fork 3.6k
[rfw] Add Flexible widget support to core widgets #9750
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
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Code Review
This pull request adds support for the Flexible widget to Remote Flutter Widgets, which is a great addition for creating more complex layouts. The implementation in core_widgets.dart is clean and follows the existing patterns. The accompanying tests in core_widgets_test.dart are comprehensive and cover various use cases. I have one suggestion to improve the maintainability of the new test suite by reducing code repetition. Overall, this is a solid contribution.
| testWidgets('Flexible widget', (WidgetTester tester) async { | ||
| final Runtime runtime = Runtime() | ||
| ..update(const LibraryName(<String>['core']), createCoreWidgets()); | ||
| addTearDown(runtime.dispose); | ||
| final DynamicContent data = DynamicContent(); | ||
|
|
||
| // Test Flexible with default values | ||
| runtime.update(const LibraryName(<String>['test']), parseLibraryFile(''' | ||
| import core; | ||
| widget root = Directionality( | ||
| textDirection: "ltr", | ||
| child: Column( | ||
| children: [ | ||
| Flexible( | ||
| child: Text(text: "Default flexible"), | ||
| ), | ||
| ], | ||
| ), | ||
| ); | ||
| ''')); | ||
|
|
||
| await tester.pumpWidget( | ||
| RemoteWidget( | ||
| runtime: runtime, | ||
| data: data, | ||
| widget: const FullyQualifiedWidgetName(LibraryName(<String>['test']), 'root'), | ||
| ), | ||
| ); | ||
| await tester.pump(); | ||
| expect(find.byType(Flexible), findsOneWidget); | ||
| final Flexible defaultFlexible = tester.widget<Flexible>(find.byType(Flexible)); | ||
| expect(defaultFlexible.flex, equals(1)); | ||
| expect(defaultFlexible.fit, equals(FlexFit.loose)); | ||
|
|
||
| // Test Flexible with custom flex value | ||
| runtime.update(const LibraryName(<String>['test']), parseLibraryFile(''' | ||
| import core; | ||
| widget root = Directionality( | ||
| textDirection: "ltr", | ||
| child: Column( | ||
| children: [ | ||
| Flexible( | ||
| flex: 3, | ||
| child: Text(text: "Custom flex"), | ||
| ), | ||
| ], | ||
| ), | ||
| ); | ||
| ''')); | ||
| await tester.pumpAndSettle(); | ||
| final Flexible customFlexFlexible = tester.widget<Flexible>(find.byType(Flexible)); | ||
| expect(customFlexFlexible.flex, equals(3)); | ||
| expect(customFlexFlexible.fit, equals(FlexFit.loose)); | ||
|
|
||
| // Test Flexible with fit: "tight" | ||
| runtime.update(const LibraryName(<String>['test']), parseLibraryFile(''' | ||
| import core; | ||
| widget root = Directionality( | ||
| textDirection: "ltr", | ||
| child: Column( | ||
| children: [ | ||
| Flexible( | ||
| flex: 2, | ||
| fit: "tight", | ||
| child: Text(text: "Tight fit"), | ||
| ), | ||
| ], | ||
| ), | ||
| ); | ||
| ''')); | ||
| await tester.pumpAndSettle(); | ||
| final Flexible tightFlexible = tester.widget<Flexible>(find.byType(Flexible)); | ||
| expect(tightFlexible.flex, equals(2)); | ||
| expect(tightFlexible.fit, equals(FlexFit.tight)); | ||
|
|
||
| // Test Flexible with fit: "loose" | ||
| runtime.update(const LibraryName(<String>['test']), parseLibraryFile(''' | ||
| import core; | ||
| widget root = Directionality( | ||
| textDirection: "ltr", | ||
| child: Column( | ||
| children: [ | ||
| Flexible( | ||
| flex: 4, | ||
| fit: "loose", | ||
| child: Text(text: "Loose fit"), | ||
| ), | ||
| ], | ||
| ), | ||
| ); | ||
| ''')); | ||
| await tester.pumpAndSettle(); | ||
| final Flexible looseFlexible = tester.widget<Flexible>(find.byType(Flexible)); | ||
| expect(looseFlexible.flex, equals(4)); | ||
| expect(looseFlexible.fit, equals(FlexFit.loose)); | ||
|
|
||
| // Test multiple Flexible widgets in a Column | ||
| runtime.update(const LibraryName(<String>['test']), parseLibraryFile(''' | ||
| import core; | ||
| widget root = Directionality( | ||
| textDirection: "ltr", | ||
| child: Column( | ||
| children: [ | ||
| Flexible( | ||
| flex: 1, | ||
| fit: "loose", | ||
| child: Text(text: "First"), | ||
| ), | ||
| Flexible( | ||
| flex: 2, | ||
| fit: "tight", | ||
| child: Text(text: "Second"), | ||
| ), | ||
| Flexible( | ||
| flex: 1, | ||
| child: Text(text: "Third"), | ||
| ), | ||
| ], | ||
| ), | ||
| ); | ||
| ''')); | ||
| await tester.pumpAndSettle(); | ||
| expect(find.byType(Flexible), findsNWidgets(3)); | ||
|
|
||
| final List<Flexible> flexibleWidgets = tester.widgetList<Flexible>(find.byType(Flexible)).toList(); | ||
| expect(flexibleWidgets[0].flex, equals(1)); | ||
| expect(flexibleWidgets[0].fit, equals(FlexFit.loose)); | ||
| expect(flexibleWidgets[1].flex, equals(2)); | ||
| expect(flexibleWidgets[1].fit, equals(FlexFit.tight)); | ||
| expect(flexibleWidgets[2].flex, equals(1)); | ||
| expect(flexibleWidgets[2].fit, equals(FlexFit.loose)); | ||
| }); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The test cases for the Flexible widget are comprehensive, but the implementation is quite repetitive. Each scenario re-defines the entire widget root and has similar boilerplate code.
To improve readability and maintainability, you could refactor this by extracting the common test logic into a helper function. This would make the test suite more concise and easier to extend in the future.
Here's an example of what a helper function could look like:
Future<void> _testFlexible(
WidgetTester tester,
Runtime runtime, {
required String rfwSnippet,
required void Function(Flexible flexible) verifier,
}) async {
runtime.update(const LibraryName(<String>['test']), parseLibraryFile('''
import core;
widget root = Directionality(
textDirection: "ltr",
child: Column(
children: [
$rfwSnippet
],
),
);
'''));
await tester.pumpAndSettle();
verifier(tester.widget(find.byType(Flexible)));
}Each test case would then become a much simpler call to this helper.
|
Thanks for the contribution! You’ve checked boxes in the PR checklist above that are not reflected in this PR, so I’m assuming this is a work in progress and am marking it as a Draft. Please review the checklist, updating the PR as appropriate, and when the state of the PR as posted reflects the checklist please feel free to mark it as ready for review.
Please read the documentation linked from the entry you checked here.
Please read the exemption documention linked from the entries you checked here. |
81fe452 to
80a77cf
Compare
@stuartmorgan-g ✅ Issues Resolved:1. Issue Linking Fixed
2. Version Management Corrected
3. Checklist Accuracy Verified
🔧 Additional Improvements Made:
📋 Current PR State:
I apologize for the initial checklist inconsistencies and appreciate your patience in helping me understand Flutter's Thank you for the guidance! |
|
From triage: @Hixie it looks like this should be ready for review. |
|
From triage: this is on the backlog for review; there's limited bandwidth for |
Hixie
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
stuartmorgan-g
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This PR has an analysis failure that will need to be fixed, in addition to the comments below.
packages/rfw/pubspec.yaml
Outdated
| repository: https://github.com/flutter/packages/tree/main/packages/rfw | ||
| issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+rfw%22 | ||
| version: 1.0.31 | ||
| version: 1.0.32 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
New public API is a minor version in semver, not a bugfix version.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done. Updated to 1.1.0 (minor version bump for new API).
| expect(defaultFlexible.flex, equals(1)); | ||
| expect(defaultFlexible.fit, equals(FlexFit.loose)); | ||
|
|
||
| // Test Flexible with custom flex value |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If there are a bunch of conceptually distinct cases being tested, then each one should be its own test.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done. Split into 5 separate tests:
- Flexible widget with default values
- Flexible widget with custom flex value
- Flexible widget with fit tight
- Flexible widget with fit loose
- Multiple Flexible widgets in Column
- Fix semver: bump version to 1.1.0 (new API = minor, not patch) - Merge NEXT section entries into version 1.1.0 in CHANGELOG - Split Flexible widget test into 5 separate test functions - Remove stray test_refactor_suggestion.dart causing analysis failures
stuartmorgan-g
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
|
autosubmit label was removed for flutter/packages/9750, because - The status or check suite Linux analyze_downgraded stable has failed. Please fix the issues identified (or deflake) before re-applying this label. |
|
Ah, this will need to be updated (via |
@stuartmorgan-g |
|
Apologies, I forgot that this package is opted out of autoformat enforcement, which is why this made so many changes. That commit will need to be reverted, and redone with just the |
|
@stuartmorgan-g |
flutter/packages@338ecd3...74a5a53 2025-12-10 [email protected] [ci] Rewrites branch exists without external dependencies (flutter/packages#10594) 2025-12-10 [email protected] [rfw] Add Flexible widget support to core widgets (flutter/packages#9750) 2025-12-09 [email protected] Redistribute package ownership among Android team (flutter/packages#10569) 2025-12-09 [email protected] [camera_android_camerax] Updates pigeon generation to prevent crash when objects call to Dart after a hot restart (flutter/packages#10571) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-packages-flutter-autoroll Please CC [email protected] on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://issues.skia.org/issues/new?component=1389291&template=1850622 Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md
[rfw] Add Flexible widget support
This PR adds support for the
Flexiblewidget to Remote Flutter Widgets (RFW), allowing developers to create flexible layouts with both loose and tight fitting behavior.Fixes #173313
The
Flexiblewidget provides more granular control over flex layouts compared to the existingExpandedwidget:Implementation:
Flexiblewidget tolib/src/flutter/core_widgets.dartflex(default: 1) andfitparameters (loose/tight, default: loose)ArgumentDecoders.enumValuepattern for FlexFit parsingtest/core_widgets_test.dartUsage Example:
API Compatibility:
Follows Flutter's
Flexiblewidget API exactly:flex: int(default: 1)fit: FlexFit(loose/tight, default: loose)child: Widget(required)Pre-Review Checklist
[rfw]pubspec.yamlwith an appropriate new version according to the pub versioning philosophy.CHANGELOG.mdto add a description of the change, following repository CHANGELOG style.///).If you need help, consider asking for advice on the #hackers-new channel on Discord.