Repository navigation
Text selection handle color respects Theme.textSelectionHandleColor - #36313
LongCatIsLooong wants to merge 5 commits into
Conversation
justinmc
left a comment
There was a problem hiding this comment.
I called out a bunch of places that contain breaking changes just as a heads up. I think we have to announce those if they go into the final version of this PR.
See my question about the original approach to handle color in material though. I need some help understanding how you were able to solve the problem.
| bool showCursor, | ||
| this.showSelectionHandles = false, | ||
| this.selectionColor, | ||
| @required this.textSelectionHandleColor, |
There was a problem hiding this comment.
This is a breaking change
| import 'package:flutter/widgets.dart'; | ||
| import 'package:flutter_test/flutter_test.dart'; | ||
| import 'package:mockito/mockito.dart'; | ||
| import 'package:flutter/foundation.dart'; |
There was a problem hiding this comment.
Thanks for alphabetizing 👍
| class _TextSelectionHandlePainter extends CustomPainter { | ||
| const _TextSelectionHandlePainter(); | ||
| const _TextSelectionHandlePainter(this.color); | ||
| final Color color; |
There was a problem hiding this comment.
This parameter in material's _TextSelectionHandlePainter is a named parameter, so probably make this one named too for consistency.
Also, maybe they should both be required and non-null? I'm not sure why the material one isn't like that already, but maybe there's a reason I'm not seeing.
| /// The top left corner of this widget is positioned at the bottom of the | ||
| /// selection position. | ||
| Widget buildHandle(BuildContext context, TextSelectionHandleType type, double textLineHeight); | ||
| Widget buildHandle(BuildContext context, TextSelectionHandleType type, Color color, double textLineHeight); |
There was a problem hiding this comment.
This is also a breaking change.
| @required this.endHandleLayerLink, | ||
| @required this.renderObject, | ||
| this.selectionControls, | ||
| @required this.textSelectionHandleColor, |
| height: _kHandleSize, | ||
| child: CustomPaint( | ||
| painter: _TextSelectionHandlePainter( | ||
| color: Theme.of(context).textSelectionHandleColor |
There was a problem hiding this comment.
Was something about this original approach causing the color to not change when the theme was updated? I'm trying to understand the cause of the problem and why the breaking changes are needed. Like the parameter in EditableText. Does passing it through there somehow make the handles rebuild when they weren't with this original code?
There was a problem hiding this comment.
The problem is text selection handles are inserted onto an Overlay as OverlayEntrys:
flutter/packages/flutter/lib/src/widgets/text_selection.dart
Lines 404 to 409 in 93a3ce7
So calling
Theme.of(context) returns the closest ThemeData above the Overlay, which might be different from the ThemeData that sits above the EditableText, e.g.:
/ TextSelectionHandle
Theme0 - Overlay <
\ Theme1 - TextField - EditableText
Instead of Theme1, currently Theme0 is inherited by TextSelectionHandle.
The easy fix is to let EditableText take in textSelectionHandleColor as a parameter, and let TextField inherits from Theme (which it already does) to get the correct ThemeData.textSelectionHandleColor to build the text selection handles.
The fix doesn't solve the problem entirely as one of the tests demonstrated, because selection handles don't listen to Theme directly ("listen to" as in an inheritor listens to an InheritedWidget, not sure what the correct term is).
There was a problem hiding this comment.
Oh I see, thanks for the clear explanation!
Would it be possible to make the handles use Theme1? Like what if you passed this.context from TextSelectionOverlay into _buildHandle instead of the given context and let the handles use that? Is that a major sin in Flutter?
There was a problem hiding this comment.
Haven't tried it but I think that probably won't work. An InheritedWidget's inheritors have to be its descendant widgets, but Theme1 and TextSelectionHandle are sibling nodes. Moreover if the BuildContext (i.e. Element) we passed to the handle is unmounted (e.g., replaced by a new Element node) at some point, the app may crash.
There was a problem hiding this comment.
Good point... What if you wrap the handles built in showHandles with a Theme widget? I guess that wouldn't update the handle color when Theme1 changes either, so that's not really a complete solution.
Just trying to brainstorm ways to solve this problem with our existing theme infrastructure to avoid having a redundant textSelectionHandleColor parameter.
Codecov Report
@@ Coverage Diff @@
## master #36313 +/- ##
==========================================
+ Coverage 53.69% 54.83% +1.14%
==========================================
Files 187 187
Lines 17248 17237 -11
==========================================
+ Hits 9261 9452 +191
+ Misses 7987 7785 -202
Continue to review full report at Codecov.
|
c2b33b4 to
bac4c1c
Compare
|
Since the PR introduces multiple breaking changes, I'm going to close it in favor of the attempt to resolve #36220. |
Description
Added a new parameter to
EditableText's constructor, as well asTextSelectionControls.buildHandle.Note that even with this fix, if the selection handles are currently visible,
ThemeData.textSelectionHandleColorchange won't immediately affect the color of the handles, until the handles are rebuilt. This is because selection handles might be higher up in the tree than theThemeit is depending on (which happens toselectionColoras well). See #36220.Related Issues
Fixes #34640
Tests
I added the following tests:
Checklist
Before you create this PR confirm that it meets all requirements listed below by checking the relevant checkboxes (
[x]). This will ensure a smooth and quick review process.///).flutter analyze --flutter-repo) does not report any problems on my PR.Breaking Change
Does your PR require Flutter developers to manually update their apps to accommodate your change?