Skip to content

Conversation

@justinmc
Copy link
Contributor

@justinmc justinmc commented Jun 27, 2019

Description

There are various situations, described in the linked issues, where the text selection menu is not shown/hidden when it should be. This PR aims to get all cases right.

Related Issues

Closes #34215
Closes #33293
Probably should close #35837 too

@justinmc justinmc added a: text input Entering text in a text field or keyboard related problems framework flutter/packages/flutter repository. See also f: labels. work in progress; do not review labels Jun 27, 2019
@justinmc justinmc self-assigned this Jun 27, 2019
@HansMuller HansMuller added the f: material design flutter/packages/flutter/material repository. label Jun 28, 2019
@justinmc justinmc changed the title WIP Text selection menu show/hide cases Text selection menu show/hide cases Jul 1, 2019
@justinmc justinmc requested a review from HansMuller July 1, 2019 20:59
}
_requestKeyboard();
_confirmCurrentSplash();
_editableTextKey.currentState.hideToolbar();
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Fix 1/2: This fixes the problem where the selection menu could get stuck open. I had to add a check to hideToolbar to make sure that we're not hiding a toolbar that's already hidden, but it seems like that probably should have been there anyway.

Copy link
Contributor

Choose a reason for hiding this comment

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

It might be safer to turn it off at the start of the function? although I don't think we turn on toolbar in selectPosition

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I think I like putting it at the top more, I'll make that change. It seems to work fine.

if (!_value.selection.isValid) {
// Place cursor at the end if the selection is invalid when we receive focus.
widget.controller.selection = TextSelection.collapsed(offset: _value.text.length);
_handleSelectionChanged(TextSelection.collapsed(offset: _value.text.length), renderEditable, SelectionChangedCause.tap);
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Fix 2/2: This fixes the case where an autofocused field couldn't ever display its selection menu. The reason was that the menu was never created.

However, this had an implication in our tests. I had to wrap a bunch of pumped test widgets in MaterialApp, because otherwise I was getting an error that there was no parent Overlay widget when it tried to create the selection menu. See the changes below.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Also, I just remembered that I used SelectionChangedCause.tap and it felt a bit hacky. This isn't isn't caused by a tap. Really, it's called when the widget is rebuilt and is automatically focused. Should I add a new value to the SelectionChangedCause enum?

Copy link
Contributor

Choose a reason for hiding this comment

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

I feel a bit hacky too, but I can't think of a good cause either. I wonder if it make sense to leave it null?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Good idea. I thought it couldn't be null for some reason, but it seems to work fine.

if (!_value.selection.isValid) {
// Place cursor at the end if the selection is invalid when we receive focus.
widget.controller.selection = TextSelection.collapsed(offset: _value.text.length);
_handleSelectionChanged(TextSelection.collapsed(offset: _value.text.length), renderEditable, SelectionChangedCause.tap);
Copy link
Contributor

Choose a reason for hiding this comment

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

I feel a bit hacky too, but I can't think of a good cause either. I wonder if it make sense to leave it null?

}
_requestKeyboard();
_confirmCurrentSplash();
_editableTextKey.currentState.hideToolbar();
Copy link
Contributor

Choose a reason for hiding this comment

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

It might be safer to turn it off at the start of the function? although I don't think we turn on toolbar in selectPosition

@chunhtai
Copy link
Contributor

chunhtai commented Jul 3, 2019

Can you also add a regression test regarding #34215 ?

@justinmc
Copy link
Contributor Author

justinmc commented Jul 3, 2019

Good call, I totally forgot to test those cases. I will add a couple to make sure they're covered.

@justinmc
Copy link
Contributor Author

justinmc commented Jul 3, 2019

@chunhtai Updated with the tests.

@justinmc justinmc force-pushed the show-selection-menu branch from 4ed393d to 77e75ad Compare July 3, 2019 19:39
);
});

testWidgets(
Copy link
Contributor

Choose a reason for hiding this comment

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

This test is passing without the patch. Is the original issue already resolved?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

After looking into this, the "single tap hides" test was passing because of strangeness with the tap location. Using a direct longPress(textFieldFinder) made the test fail on master and pass in this branch.

For the other test, "long press on autofocused", I could not get it to fail on master no matter what I tried. However, trying a sample app, the behavior looked as if the test should definitely fail. I gave up trying to make it fail and instead wrote an integration test that fails on master and passes on this branch.

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 know what is going on.
When you use longPressAt(textOffsetToPosition(tester, 0)), it will tap at the start of the text which is also part of the selection handle. this will trigger _handleSelectionHandleTapped which toggle the toolbar off. That is why it still passing in master.

As for long press on autofocused, add an additional pump after the pump widget will fail the test as the on focus callback will update the selection from the default (-1, -1) to (0,0) but it take one frame to propagate down to renderEditable. While the long press started, the renderEditable is still has selection(-1,-1) which allow it to update its selection

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Brilliant, that did in fact make it fail on master. Thanks so much. I will make that change and then remove the e2e test (since it's much slower).

@justinmc
Copy link
Contributor Author

justinmc commented Jul 9, 2019

@chunhtai Updated with tests that fail on master.

@justinmc
Copy link
Contributor Author

justinmc commented Jul 9, 2019

@chunhtai Updated with your fix for the test that wasn't failing on master, thanks!

Copy link
Contributor

Choose a reason for hiding this comment

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

it requires a pump here

Copy link
Contributor

Choose a reason for hiding this comment

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

same here

@justinmc justinmc force-pushed the show-selection-menu branch from 0b208df to a22d636 Compare July 10, 2019 18:15
@justinmc
Copy link
Contributor Author

@chunhtai Whoops sorry, I think I lost the pumps I added when I was switching to master to try it out. Fixed.

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 with a minor suggestion

Copy link
Contributor

Choose a reason for hiding this comment

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

nit: It might be more clear to add a comment describe why we need a pump here

Copy link
Contributor

Choose a reason for hiding this comment

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

nit: same as below.

@justinmc justinmc force-pushed the show-selection-menu branch from a22d636 to 147ab98 Compare July 10, 2019 18:30
@justinmc justinmc merged commit ff53fbe into flutter:master Jul 10, 2019
@justinmc justinmc deleted the show-selection-menu branch July 10, 2019 21:08
AgentFabulous added a commit to AgentFabulous/flutter that referenced this pull request Jul 11, 2019
- flutter#35219 tried to resolve this and autofocus, but missed the usecase
  where the user may empty out the field and then try to long-press to
  paste something.
- When one taps on an empty text field, the long-press menu works,
  because:
    selection = TextSelection(
                    baseOffset: -1,
                    extentOffset: -1,
                    affinity: TextAffinity.downstream,
                    isDirectional: false,
                )

    nextSelection = TextSelection(
                        baseOffset: 0,
                        extentOffset: 0,
                        affinity: TextAffinity.downstream,
                        isDirectional: false,
                    )
- When one clears the text in a text field and then long-presses
  however, the menu doesn't appear because:
    selection = nextSelection = TextSelection(
                                    baseOffset: 0,
                                    extentOffset: 0,
                                    affinity: TextAffinity.downstream,
                                    isDirectional: false,
                                )
  and _handlePotentialSelectionChange() returns.
- Check if baseOffset and extentOffset of current and next are both 0,
  and set current to -1, to replicate working behaviour.
johnsonmh pushed a commit to johnsonmh/flutter that referenced this pull request Jul 30, 2019
Show and hide the text selection menu at the correct time with various gestures in the text field.
@github-actions github-actions bot locked as resolved and limited conversation to collaborators Aug 5, 2021
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

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

Projects

None yet

4 participants