-
Notifications
You must be signed in to change notification settings - Fork 29.7k
Hide toolbar when selection is out of view #98152
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
Hide toolbar when selection is out of view #98152
Conversation
| ); | ||
| renderObject.selectionStartInViewport.addListener(_updateHandleVisibilities); | ||
| renderObject.selectionEndInViewport.addListener(_updateHandleVisibilities); | ||
| renderObject.selectionStartInViewport.addListener(_updateToolbarVisibility); |
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 would merge _updateHandleVisibilities and _updateToolbarVisibility into one callback, and rename the function to be more generic.
| } | ||
|
|
||
| /// Final cleanup. | ||
| void dispose() { |
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 i missed it in previous PR we should also dispose
_effectiveStartHandleVisibility
_effectiveEndHandleVisibility
as well as the new
_effectiveToolbarVisibility
in the dispose method
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.
they should be put after renderObject.selectionStartInViewport.removeListener
| @override | ||
| void didUpdateWidget(_SelectionToolbarOverlay oldWidget) { | ||
| super.didUpdateWidget(oldWidget); | ||
| oldWidget.visibility.removeListener(_toolbarVisibilityChanged); |
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.
we should check whether visibility change or not before remove/add listener, or simply assert they won't change if this widget would not be reused in the future
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.
True, it's possible that visibility is the same before and after right?
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.
For my understanding, why should we do this?
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 method will be called whenever _SelectionToolbarOverlay or its parents rebuilds regardless whether the visibility property changes or not.
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.
and based on the code, the visibility is passed in from the SelectionOverlay, and it should never change.
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.
Thank you that makes sense!
justinmc
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.
Sounds like this is on hold until some refactoring is done in text_selection.dart? Otherwise it looks fine to me besides a few small comments below.
| } | ||
| } | ||
|
|
||
| /// This widget represents a text selection toolbar. |
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.
Nit: No triple slash on a private class? Or maybe it doesn't matter.
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.
According to https://github.com/flutter/flutter/wiki/Style-guide-for-Flutter-repo#use--for-public-quality-private-documentation if we plan on making this public in the future it is fine (as long as the documentation is quality). I think this would still be flagged if we make it public because the class fields are not documented. I'm okay with either method.
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.
Ah I say keep it triple then. Thanks for looking that up, I never knew exactly what the policy was.
| @override | ||
| void didUpdateWidget(_SelectionToolbarOverlay oldWidget) { | ||
| super.didUpdateWidget(oldWidget); | ||
| oldWidget.visibility.removeListener(_toolbarVisibilityChanged); |
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.
True, it's possible that visibility is the same before and after right?
| } | ||
|
|
||
| /// This widget represents a text selection toolbar. | ||
| class _SelectionToolbarOverlay extends StatefulWidget { |
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.
Nit: Is there a better name for this class? Or maybe just describe what it does in the comment above in a bit more detail. I just wouldn't understand the difference between _SelectionToolbarOverlay and TextSelectionOverlay at a glance. And it doesn't seem to have to do with Overlay directly.
I really like the idea of splitting this out into its own class like this by the way, it seems cleaner to me.
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.
_SelectionToolbarPlacement? Something like that, naming is hard...
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.
For this I just followed the naming scheme of _SelectionHandleOverlay since this will be the widget created when we call
_toolbar = OverlayEntry(builder: _buildToolbar); , and _buildToolbar will return _SelectionToolbarOverlay.
to build the toolbar Overlay.
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.
Ah right, that makes sense 👍
| )); | ||
|
|
||
| final EditableTextState state = | ||
| tester.state<EditableTextState>(find.byType(EditableText)); |
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 this should be indented.
|
|
||
| // On web, we don't show the Flutter toolbar and instead rely on the browser | ||
| // toolbar. Until we change that, this test should remain skipped. | ||
| }, skip: kIsWeb); // [intended] |
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.
Does this apply in the same way to desktop?
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.
| MacOS With Hiding | MacOS Without Hiding |
|---|---|
![]() |
![]() |
The native behavior (MacOS) at least in the notes app, is to disable scrolling entirely while the selection menu is present.
Edit: Tested on Windows 11 in the notepad app and scrolling is also disabled while the selection menu is present. Also tested on Ubuntu 21.10 on the gedit app and can observe the same behavior (scrolling is disabled).
I think for now the hiding behavior would be preferred so the selection menu does not obscure any text. And when the native behavior of disabling scroll is implemented then this won't be an issue as scroll will be disabled.
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.
Sounds good. I'm working on the "context menu anywhere" stuff and I think it will work out that scrolling will be disabled while the menu is up.
justinmc
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 👍
chunhtai
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, just nit on the dispose order
| _effectiveToolbarVisibility.dispose(); | ||
| _effectiveStartHandleVisibility.dispose(); | ||
| _effectiveEndHandleVisibility.dispose(); | ||
| _selectionOverlay.dispose(); |
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.
It is more systematically correct to dispose _selectionOverlay first before cleaning up all the visibility objects since the selection overlay may be using the visibility objects. One patten I follow is the dispose order is usually the reverse of the initState order.
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. Thank you for the explanation!
* Hide toolbar when selection is out of view * properly dispose of toolbar visibility listener * Add test * rename toolbarvisibility * Make visibility for toolbar nullable * Properly dispose of toolbar visibility listener * Merge visibility methods into one * properly dispose of start selection view listener * Add some docs * remove unnecessary null check * more docs * Update dispose order Co-authored-by: Renzo Olivares <[email protected]>


Description
This change makes it so that the text selection toolbar hides when the text selection has moved outside of the view.
Related Issues
Fixes #77889
Tests
Pre-launch Checklist
///).