Skip to content

Conversation

@Renzo-Olivares
Copy link
Contributor

@Renzo-Olivares Renzo-Olivares commented Feb 9, 2022

Description

This change makes it so that the text selection toolbar hides when the text selection has moved outside of the view.

Android Cupertino
android-toolbar-hide cupertino-toolbar-hide

Related Issues

Fixes #77889

Tests

Pre-launch Checklist

  • I read the [Contributor Guide] and followed the process outlined there for submitting PRs.
  • I read the [Tree Hygiene] wiki page, which explains my responsibilities.
  • I read and followed the [Flutter Style Guide], including [Features we expect every widget to implement].
  • I signed the [CLA].
  • I listed at least one issue that this PR fixes in the description above.
  • I updated/added relevant documentation (doc comments with ///).
  • I added new tests to check the change I am making, or this PR is [test-exempt].
  • All existing and new tests are passing.

@flutter-dashboard flutter-dashboard bot added a: text input Entering text in a text field or keyboard related problems framework flutter/packages/flutter repository. See also f: labels. labels Feb 9, 2022
@Renzo-Olivares Renzo-Olivares marked this pull request as ready for review February 10, 2022 00:06
);
renderObject.selectionStartInViewport.addListener(_updateHandleVisibilities);
renderObject.selectionEndInViewport.addListener(_updateHandleVisibilities);
renderObject.selectionStartInViewport.addListener(_updateToolbarVisibility);
Copy link
Contributor

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() {
Copy link
Contributor

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

Copy link
Contributor

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);
Copy link
Contributor

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

Copy link
Contributor

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?

Copy link
Contributor Author

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?

Copy link
Contributor

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.

Copy link
Contributor

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.

Copy link
Contributor Author

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!

Copy link
Contributor

@justinmc justinmc left a 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.
Copy link
Contributor

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.

Copy link
Contributor Author

@Renzo-Olivares Renzo-Olivares Feb 14, 2022

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.

Copy link
Contributor

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);
Copy link
Contributor

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 {
Copy link
Contributor

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.

Copy link
Contributor

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...

Copy link
Contributor Author

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.

Copy link
Contributor

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));
Copy link
Contributor

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]
Copy link
Contributor

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?

Copy link
Contributor Author

@Renzo-Olivares Renzo-Olivares Feb 14, 2022

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
toolbar-vis-macos toolbar-no-vis-macos

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.

Copy link
Contributor

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.

Copy link
Contributor

@justinmc justinmc left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM 👍

Copy link
Contributor

@chunhtai chunhtai left a 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();
Copy link
Contributor

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.

Copy link
Contributor Author

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!

engine-flutter-autoroll added a commit to engine-flutter-autoroll/plugins that referenced this pull request Feb 15, 2022
clocksmith pushed a commit to clocksmith/flutter that referenced this pull request Mar 8, 2022
* 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]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

a: text input Entering text in a text field or keyboard related problems framework flutter/packages/flutter repository. See also f: labels.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Text selection controls appears above interface when scroll

3 participants