-
Notifications
You must be signed in to change notification settings - Fork 29.7k
iOS TextSelectionToolbar fidelity #127757
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
|
It looks like this pull request may not have tests. Please make sure to add tests before merging. If you need an exemption to this rule, contact Hixie on the #hackers channel in Chat (don't just cc him here, he won't see it! He's on Discord!). If you are not sure if you need tests, consider this rule of thumb: the purpose of a test is to make sure someone doesn't accidentally revert the fix. Ask yourself, is there anything in your PR that you feel it is important we not accidentally revert back to how it was before your fix? Reviewers: Read the Tree Hygiene page and make sure this patch meets those guidelines before LGTMing. |
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 is an awesome PR, the menu looks so much better from your videos. I think there's one architectural problem to solve (_CupertinoTextSelectionToolbarItemsController) but otherwise the approach looks good.
Is the point of that controller to be able to pass information up the class hierarchy from _RenderCupertinoTextSelectionToolbarItems to _CupertinoTextSelectionToolbarContentState? I think we need to find a better way to do that other than a shared mutable class.
Fortunately it seems like you only need that information in a callback (_handleNext/PreviousPage) so we can probably look it up without having to worry about layout order. Could you pass a key to _CupertinoTextSelectionToolbarItems and then look up the information using GlobalKey.currentWidget? Something like that should be doable...
| // accommodate the back button. | ||
| } | ||
|
|
||
| // Update the controller values so that we can check in the horizontal |
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.
I think the Flutter style guide recommends not using "we" etc., so maybe say "...so that it's possible to check them in the horizontal..."
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.
Reminder on this one.
|
Thank you! 😁 About the controller, yes, I only use it to know if it's possible to navigate to previous/next page when dragging, basically. But I don't understand how a GlobalKey would solve this problem. The only way to know if there is a previous/next button (as far as I can tell) is in flutter/packages/flutter/lib/src/cupertino/text_selection_toolbar.dart Lines 946 to 947 in 6762521
So we need to set the variables in this method. From what I understood of your suggestion, a GlobalKey should be used instead of the "controller", like globalKey.currentWidget.hasNextPage = page != currentPage;
globalKey.currentWidget.hasPreviousPage = page > 0; But how would I set variables using Probably I'm missing something here, but I couldn't come up with a solution that doesn't involve a shared mutable class. 😅 |
| // correctly shows/hides the previous/next buttons automatically, but now the | ||
| // horizontal drag gesture callback has to check whether it's possible to | ||
| // navigate or not, making this necessary. | ||
| class _CupertinoTextSelectionToolbarItemsController { |
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.
I think controller classes are normally used in APIs for others widgets to change the state of a stateful widget. Here we're operating on a render object so this should probably be done using individual fields e.g.
void updateRenderObject(BuildContext context, _RenderCupertinoTextSelectionToolbarItems renderObject) {
renderObject
..page = page
..hasPreviousPage = hasPreviousPage
..hasNextPage = hasNextPage
..dividerColor = dividerColor
Then in the RenderBox class you'd have a setter and a getter just like with dividerColor.
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 problem with this approach is that, as far as I understand it, I wouldn't be able to update hasNextPage and hasPreviousPage in _RenderCupertinoTextSelectionToolbarItems, and have it available in its parent (_CupertinoTextSelectionToolbarContentState) when the user does a horizontal drag gesture on the whole toolbar.
This is where I update the values:
flutter/packages/flutter/lib/src/cupertino/text_selection_toolbar.dart
Lines 944 to 947 in 6762521
| // Update the controller values so that we can check in the horizontal | |
| // drag gesture callback when it's possible to navigate. | |
| controller?.hasNextPage = page != currentPage; | |
| controller?.hasPreviousPage = page > 0; |
And this is where I use them:
flutter/packages/flutter/lib/src/cupertino/text_selection_toolbar.dart
Lines 461 to 475 in 6762521
| void _handleNextPage() { | |
| if (_toolbarItemsController.hasNextPage) { | |
| _controller.reverse(); | |
| _controller.addStatusListener(_statusListener); | |
| _nextPage = _page + 1; | |
| } | |
| } | |
| void _handlePreviousPage() { | |
| if (_toolbarItemsController.hasPreviousPage) { | |
| _controller.reverse(); | |
| _controller.addStatusListener(_statusListener); | |
| _nextPage = _page - 1; | |
| } | |
| } |
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 the hasPreviousPage / hasNextPage fields are only updated by _RenderCupertinoTextSelectionToolbarItems (which makes sense given this will depend on the incoming constraints for the RenderBox), perhaps one approach would be to:
- keep them as
boolvalues without getter/setter - from the widget state, in the gesture handler, do something like:
final RenderBox? renderBox = context.findRenderObject() as RenderBox?;
if (renderBox is _RenderCupertinoTextSelectionToolbarItems && renderBox.hasPreviousPage) {
[...]
Perhaps there will be a bit extra complexity if you insert another widget inbetween like AnimatedSize: if this is the case and context.findRenderObject() returns another box, you could pass a global key to the _CupertinoTextSelectionToolbarItems widget you're looking for and do:
renderBox = _toolbarItemsKey.currentContext?.findRenderObject()
This is commonly done across the framework so you can search for findRenderObject().
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.
+1 that's what I was thinking!
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.
That makes sense and it's way cleaner, thank you! I will see if I can remove the controller until this weekend.
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.
Just fixed this and all tests passed, should be OK now 😁
|
@tgucio Can you give the final approval here? |
|
LGTM - thanks again for the PR! |
Roll Flutter from 96a2c05 to 51bef1b (37 revisions) flutter/flutter@96a2c05...51bef1b 2023-06-28 [email protected] Roll Flutter Engine from e8a1c23d66ba to 241ca5c1d6be (1 revision) (flutter/flutter#129725) 2023-06-28 [email protected] Update analysis, linter, and repo links in analysis options (flutter/flutter#129686) 2023-06-28 [email protected] Roll Flutter Engine from be1073aa352f to e8a1c23d66ba (1 revision) (flutter/flutter#129723) 2023-06-28 [email protected] Dev, examples/api, etc updated for Material 3 by default (flutter/flutter#129683) 2023-06-28 [email protected] Add `DatePickerTheme.inputDecorationTheme` for the DatePicker with input mode. (flutter/flutter#128950) 2023-06-28 [email protected] [framework] ensure flexible space bar fades when scrolling. (flutter/flutter#129527) 2023-06-28 [email protected] Add InputDecorator.error to allow error message customization (flutter/flutter#129275) 2023-06-28 [email protected] Roll Flutter Engine from b388e852be44 to be1073aa352f (1 revision) (flutter/flutter#129712) 2023-06-28 [email protected] Roll Flutter Engine from 17173994a8c2 to b388e852be44 (1 revision) (flutter/flutter#129708) 2023-06-28 [email protected] [flutter roll] Revert "Fix `AnimatedList` & `AnimatedGrid` doesn't apply `MediaQuery` padding" (flutter/flutter#129645) 2023-06-28 [email protected] Roll Flutter Engine from 2f4fc4872699 to 17173994a8c2 (1 revision) (flutter/flutter#129694) 2023-06-28 [email protected] Roll Flutter Engine from a6d9d12c440f to 2f4fc4872699 (1 revision) (flutter/flutter#129691) 2023-06-28 [email protected] Roll Flutter Engine from 25a5850f8b5b to a6d9d12c440f (4 revisions) (flutter/flutter#129687) 2023-06-28 [email protected] Roll Flutter Engine from 7c7c45d53bec to 25a5850f8b5b (1 revision) (flutter/flutter#129682) 2023-06-27 [email protected] Roll Flutter Engine from f320b8c36fee to 7c7c45d53bec (14 revisions) (flutter/flutter#129678) 2023-06-27 [email protected] Update labeler yaml (flutter/flutter#129676) 2023-06-27 [email protected] Revert "Fix the matcher condition where multiple matchers are found" (flutter/flutter#129675) 2023-06-27 [email protected] Revert "Labeler format to remove extra single quote" (flutter/flutter#129674) 2023-06-27 [email protected] Revert "Update labeler.yml to v5.0.0-beta.1" (flutter/flutter#129673) 2023-06-27 [email protected] Labeler format to remove extra single quote (flutter/flutter#129672) 2023-06-27 [email protected] Fix the matcher condition where multiple matchers are found (flutter/flutter#129670) 2023-06-27 [email protected] Automatically migrate ClipboardData.text to non-null (flutter/flutter#129567) 2023-06-27 [email protected] Remove Editable.onCaretChanged callback (flutter/flutter#109114) 2023-06-27 [email protected] Reland "Fix issue where DevTools would not be immediately available when using --start-paused (#126698)" (flutter/flutter#129368) 2023-06-27 [email protected] Update Xcode to 14.3.1 (flutter/flutter#129024) 2023-06-27 [email protected] Adds `dart_fix` support to `integration_test` (flutter/flutter#129579) 2023-06-27 [email protected] Update labeler.yml to v5.0.0-beta.1 (flutter/flutter#129617) 2023-06-27 [email protected] iOS TextSelectionToolbar fidelity (flutter/flutter#127757) 2023-06-27 [email protected] Make a paragraph test involving Chinese characters work with inconsistent host system fonts (flutter/flutter#129628) 2023-06-27 [email protected] Roll Packages from 6b70804 to f89ce02 (7 revisions) (flutter/flutter#129630) 2023-06-27 [email protected] Roll Flutter Engine from 715eff211a42 to f320b8c36fee (6 revisions) (flutter/flutter#129599) 2023-06-27 [email protected] Fix chinese text is not selected by long press (flutter/flutter#129320) 2023-06-26 [email protected] Roll Flutter Engine from 0da06de991a9 to 715eff211a42 (4 revisions) (flutter/flutter#129593) 2023-06-26 [email protected] Fix syntax error in no-response (flutter/flutter#129588) 2023-06-26 [email protected] Roll Flutter Engine from f2d70cc809cd to 0da06de991a9 (3 revisions) (flutter/flutter#129582) 2023-06-26 [email protected] Updated chip_test.dart tests for M3 (flutter/flutter#129570) 2023-06-26 [email protected] Roll Flutter Engine from 4032a9bc964e to f2d70cc809cd (4 revisions) (flutter/flutter#129574) 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 Please CC [email protected],[email protected],[email protected] on the revert to ensure that a human is aware of the problem. To file a bug in Packages: https://github.com/flutter/flutter/issues/new/choose ...
CupertinoTextSelectionToolbar is different from the native one, with some UI and UX issues. More details on the linked issue.
#127756
Currently the only problem that I listed on the linked issue that I couldn't fix was the horizontal scrolling, but to workaround this I added a GestureDetector to change pages when swiping the toolbar. It's not exactly the same as native as there is no scroll animation, but it works.
I'm creating this PR a little early to have some feedback as these changes were more complex than the ones in my last PR. Probably best if @justinmc is involved 😅
old.mov
new.mov
native.mov
Pre-launch Checklist
///).