-
Notifications
You must be signed in to change notification settings - Fork 29.2k
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...
@@ -903,6 +940,11 @@ class _RenderCupertinoTextSelectionToolbarItems extends RenderBox with Container | |||
// already been taken care of when laying out the children to | |||
// 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
bool
values 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 engine-flutter-autoroll@skia.org Roll Flutter Engine from e8a1c23d66ba to 241ca5c1d6be (1 revision) (flutter/flutter#129725) 2023-06-28 parlough@gmail.com Update analysis, linter, and repo links in analysis options (flutter/flutter#129686) 2023-06-28 engine-flutter-autoroll@skia.org Roll Flutter Engine from be1073aa352f to e8a1c23d66ba (1 revision) (flutter/flutter#129723) 2023-06-28 hans.muller@gmail.com Dev, examples/api, etc updated for Material 3 by default (flutter/flutter#129683) 2023-06-28 tessertaha@gmail.com Add `DatePickerTheme.inputDecorationTheme` for the DatePicker with input mode. (flutter/flutter#128950) 2023-06-28 jonahwilliams@google.com [framework] ensure flexible space bar fades when scrolling. (flutter/flutter#129527) 2023-06-28 leroux_bruno@yahoo.fr Add InputDecorator.error to allow error message customization (flutter/flutter#129275) 2023-06-28 engine-flutter-autoroll@skia.org Roll Flutter Engine from b388e852be44 to be1073aa352f (1 revision) (flutter/flutter#129712) 2023-06-28 engine-flutter-autoroll@skia.org Roll Flutter Engine from 17173994a8c2 to b388e852be44 (1 revision) (flutter/flutter#129708) 2023-06-28 xilaizhang@google.com [flutter roll] Revert "Fix `AnimatedList` & `AnimatedGrid` doesn't apply `MediaQuery` padding" (flutter/flutter#129645) 2023-06-28 engine-flutter-autoroll@skia.org Roll Flutter Engine from 2f4fc4872699 to 17173994a8c2 (1 revision) (flutter/flutter#129694) 2023-06-28 engine-flutter-autoroll@skia.org Roll Flutter Engine from a6d9d12c440f to 2f4fc4872699 (1 revision) (flutter/flutter#129691) 2023-06-28 engine-flutter-autoroll@skia.org Roll Flutter Engine from 25a5850f8b5b to a6d9d12c440f (4 revisions) (flutter/flutter#129687) 2023-06-28 engine-flutter-autoroll@skia.org Roll Flutter Engine from 7c7c45d53bec to 25a5850f8b5b (1 revision) (flutter/flutter#129682) 2023-06-27 engine-flutter-autoroll@skia.org Roll Flutter Engine from f320b8c36fee to 7c7c45d53bec (14 revisions) (flutter/flutter#129678) 2023-06-27 32242716+ricardoamador@users.noreply.github.com Update labeler yaml (flutter/flutter#129676) 2023-06-27 32242716+ricardoamador@users.noreply.github.com Revert "Fix the matcher condition where multiple matchers are found" (flutter/flutter#129675) 2023-06-27 32242716+ricardoamador@users.noreply.github.com Revert "Labeler format to remove extra single quote" (flutter/flutter#129674) 2023-06-27 32242716+ricardoamador@users.noreply.github.com Revert "Update labeler.yml to v5.0.0-beta.1" (flutter/flutter#129673) 2023-06-27 32242716+ricardoamador@users.noreply.github.com Labeler format to remove extra single quote (flutter/flutter#129672) 2023-06-27 32242716+ricardoamador@users.noreply.github.com Fix the matcher condition where multiple matchers are found (flutter/flutter#129670) 2023-06-27 737941+loic-sharma@users.noreply.github.com Automatically migrate ClipboardData.text to non-null (flutter/flutter#129567) 2023-06-27 72562119+tgucio@users.noreply.github.com Remove Editable.onCaretChanged callback (flutter/flutter#109114) 2023-06-27 bkonyi@google.com Reland "Fix issue where DevTools would not be immediately available when using --start-paused (#126698)" (flutter/flutter#129368) 2023-06-27 15619084+vashworth@users.noreply.github.com Update Xcode to 14.3.1 (flutter/flutter#129024) 2023-06-27 109253501+pdblasi-google@users.noreply.github.com Adds `dart_fix` support to `integration_test` (flutter/flutter#129579) 2023-06-27 chillers@google.com Update labeler.yml to v5.0.0-beta.1 (flutter/flutter#129617) 2023-06-27 luccas.clezar@gmail.com iOS TextSelectionToolbar fidelity (flutter/flutter#127757) 2023-06-27 jason-simmons@users.noreply.github.com Make a paragraph test involving Chinese characters work with inconsistent host system fonts (flutter/flutter#129628) 2023-06-27 engine-flutter-autoroll@skia.org Roll Packages from 6b70804 to f89ce02 (7 revisions) (flutter/flutter#129630) 2023-06-27 engine-flutter-autoroll@skia.org Roll Flutter Engine from 715eff211a42 to f320b8c36fee (6 revisions) (flutter/flutter#129599) 2023-06-27 jhy03261997@gmail.com Fix chinese text is not selected by long press (flutter/flutter#129320) 2023-06-26 engine-flutter-autoroll@skia.org Roll Flutter Engine from 0da06de991a9 to 715eff211a42 (4 revisions) (flutter/flutter#129593) 2023-06-26 godofredoc@google.com Fix syntax error in no-response (flutter/flutter#129588) 2023-06-26 engine-flutter-autoroll@skia.org Roll Flutter Engine from f2d70cc809cd to 0da06de991a9 (3 revisions) (flutter/flutter#129582) 2023-06-26 hans.muller@gmail.com Updated chip_test.dart tests for M3 (flutter/flutter#129570) 2023-06-26 engine-flutter-autoroll@skia.org 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 camillesimon@google.com,rmistry@google.com,stuartmorgan@google.com 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
///
).