Skip to content

Add long-press-drag cursor move support for text fields - #26001

Merged
xster merged 18 commits into
flutter:masterfrom
xster:long-press-drag
Feb 12, 2019
Merged

xster merged 18 commits into
flutter:masterfrom
xster:long-press-drag

Conversation

@xster

@xster xster commented Jan 3, 2019 •

Copy link
Copy Markdown
Member

Add long press drag recognizer as a separate recognizer to the normal long press which gets canceled if moved.

Use on iOS to move cursor.

Long press drag on Android, which moves word selections rather than a collapsed cursor, will be a different PR.

Fixes #20693.

Is API breaking since it adds a new GestureRecognizerState enum though I doubt anyone uses it.

Left #26394 for Android

@xster
xster requested review from HansMuller and jslavitz January 3, 2019 07:15
@zoechi zoechi added a: text input Entering text in a text field or keyboard related problems framework flutter/packages/flutter repository. See also f: labels. p: material_ui material_ui package in flutter/packages p: cupertino_ui cupertino_ui package in flutter/packages labels Jan 3, 2019

@jslavitz jslavitz left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Looks good, mostly just comments.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Is there a need for a sourceTimeStamp in this gesture detector?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Not right now but I feel like our gesture classes are a bit relatively under-engineered for a low level API. I'm keeping it mostly consistent with the drag details which this is comparable to.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Comment thread packages/flutter/lib/src/gestures/long_press.dart Outdated
Comment thread packages/flutter/lib/src/gestures/long_press.dart Outdated
Comment thread packages/flutter/lib/src/gestures/long_press.dart Outdated
Comment thread packages/flutter/lib/src/gestures/long_press.dart Outdated

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

If the touch was canceled, do you need to call onLongPressUp here?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

I don't think we're still calling 'onLongPressUp' still. Which line were you referring to?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Would it make sense to also include the touch delta in this class?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Did you mean something similar to DragUpdateDetails? Chatted with Hans a bit and I feel like providing absolute values is better than providing relative to relative values. It's a lot easier to go from one way to the other than the reverse.

Comment thread packages/flutter/lib/src/gestures/long_press.dart Outdated
Comment thread packages/flutter/lib/src/gestures/long_press.dart Outdated
Comment thread packages/flutter/lib/src/gestures/long_press.dart Outdated
@xster
xster force-pushed the long-press-drag branch 2 times, most recently from f4575ee to 3953929 Compare January 15, 2019 09:52

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

I think these lack of new lines in the test data are bugs

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Did the tests start failing?

I don't think this should be changed. It looks like tests that used kThreeLines set the font size to 34, which would cause the text field to insert soft breaks at the ends of the lines.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

No but rather the test has always been passing by pure coincidence where we weren't actually dragging the handle in some parts of the test that tried to exercise it. Though the outcome was the same when the drag was done on the textfield behind it which scrolled nevertheless.

Looking at the existing usages of kThreeLines and kMoreThanFourLines also seem to expect that the beginning of lines match the beginnings of each test lines.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

triggered from => triggered by?

Not sure what this is referring to exactly. Maybe a "See also" that sheds some light on "proxied events"?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

ah good point. Linked

Comment thread packages/flutter/lib/src/gestures/long_press.dart Outdated
Comment thread packages/flutter/lib/src/gestures/long_press.dart Outdated

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Recognizes a long press followed by a drag, followed by an up event.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

It doesn't have to be dragged around

Comment thread packages/flutter/lib/src/gestures/long_press.dart Outdated
Comment thread packages/flutter/lib/src/widgets/text_selection.dart Outdated
Comment thread packages/flutter/test/gestures/long_press_test.dart Outdated

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Did the tests start failing?

I don't think this should be changed. It looks like tests that used kThreeLines set the font size to 34, which would cause the text field to insert soft breaks at the ends of the lines.

Comment thread packages/flutter/test/material/text_field_test.dart Outdated
Comment thread packages/flutter/test/material/text_field_test.dart Outdated
@xster

xster commented Jan 16, 2019

Copy link
Copy Markdown
Member Author

GitHub notifications is pretty wonky. @HansMuller ready for another look.

@xster

xster commented Feb 7, 2019

Copy link
Copy Markdown
Member Author

@HansMuller this is ready for another look.
@goderbauer I didn't merge the 2 long press recognizers as we talked about. Unfortunately, the existing long press recognizer's callback signature is too spartan to make use of them. Rather than breaking that API, which would be a bit more significant, I just left the newly created one.

Comment thread packages/flutter/lib/src/gestures/recognizer.dart Outdated
Comment thread packages/flutter/lib/src/gestures/recognizer.dart Outdated
Comment thread packages/flutter/lib/src/gestures/recognizer.dart Outdated
&& _getDistance(event) > postAcceptSlopTolerance;

if (event is PointerMoveEvent && (isPreAcceptSlopPastTolerance || isPostAcceptSlopPastTolerance)) {
resolve(GestureDisposition.rejected);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I don't understand. If isPostAcceptSlopPastTolerance is true, then we know we've already been accepted, so what does it mean to reject it?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

I don't have a strong opinion about this. I'm mostly leaning towards not introducing more API breaks in this PR since it was the existing behaviour (whether the gesture was accepted or not). Rejecting an accepted gesture makes future events not go through, such as the up event.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I don't understand how your comment corresponds to my question.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

If isPostAcceptSlopPastTolerance is true, then we know we've already been accepted

Yes

so what does it mean to reject it?

In the existing implementation,

if (event is PointerMoveEvent && _getDistance(event) > kTouchSlop) {
  resolve(GestureDisposition.rejected);

causes the recognizer to stop emitting post-accept events such as the up event. I leaned towards not altering that behavior and left it in this PR though we can make that change if we feel that we have a strong reason to.

///
/// * [LongPressGestureRecognizer], which cancels its gesture if a drag event
/// occurs at any point during the long-press.
class LongPressDragGestureRecognizer extends PrimaryPointerGestureRecognizer {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

shouldn't this be a DragGestureRecognizer subclass?

@xster xster Feb 7, 2019 •

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

The DragGestureRecognizer is unconcerned with the time dimension which is important here. Perhaps both PrimaryPointerGestureRecognizer and/or DragGestureRecognizer can be refactored to be mixins, though that would break more APIs

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Presumably adding the time dimension would be what you would do in the DragGestureRecognizer subclass.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

We could add a time component to DragGestureRecognizer or a move component to PrimaryPointerGestureRecognizer. I don't feel strongly either way. We can modify DragGestureRecognizer and have this subclass it instead if you prefer.

Ideally, the time and position components would both come in via mixins. We can also just not change either subclasses and do it here directly but we'd have to repeat that work for some of the other gestures that are coming up such as double tap drag.

@HansMuller HansMuller left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

LGTM

Looks like there's still feedback from Ian to deal with.

@xster

xster commented Feb 8, 2019

Copy link
Copy Markdown
Member Author

@Hixie can you see if you have additional comments?

@xster

xster commented Feb 12, 2019

Copy link
Copy Markdown
Member Author

I'm landing this to unblock follow up PRs. Let me know if you have additional comments @Hixie and I'll address them.

@xster
xster merged commit 892c891 into flutter:master Feb 12, 2019
@xster
xster deleted the long-press-drag branch February 12, 2019 23:10
@xster xster changed the title Add long-press-drag cursor move support on iOS Add long-press-drag cursor move support for text fields Feb 13, 2019
void rejectGesture(int pointer) {
void acceptGesture(int pointer) {
// Ignore state 'ready' here because that would happen if this recognizer
// won by a sweep.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

this comment doesn't make much sense to me

void rejectGesture(int pointer) {
if (pointer == primaryPointer
&& (state == GestureRecognizerState.possible ||
state == GestureRecognizerState.accepted)) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

i think we should assert that we're not accepted here. it doesn't make sense to reject when you're accepted.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

It's the existing behavior since there are no knowledge of acceptance in this class yet. We're moving a step closer in this PR but I haven't changed this behavior.

possible,

/// The gesture has been definitively accepted by the recognizer.
accepted,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

i am not convinced about adding this. I don't really understand what it gives us.

@Hixie

Hixie commented Feb 15, 2019

Copy link
Copy Markdown
Contributor

Sorry about not getting back promptly. In general, please don't land things until you get a clear indication from everyone who has left comments that they are happy.

@xster

xster commented Feb 16, 2019 •

Copy link
Copy Markdown
Member Author

#28032 to revert for more discussions.

@xster

xster commented Feb 20, 2019

Copy link
Copy Markdown
Member Author

Some notes from offline chat:

  • Change the various name references to not conflate with anything from the gesture arena ("accept" and "reject") since in the gesture arena sense, the arena is done once someone accepts.
  • Rename to not have the word 'drag' in the recognizer since it's not a conventional drag gesture.
  • Consider adding new callbacks to the non-drag long press to get around not breaking APIs with existing callback signatures that don't have enough data to work with.

@xster xster mentioned this pull request Feb 21, 2019
9 of 10 tasks
xster added a commit to xster/flutter that referenced this pull request Feb 21, 2019
mdebbar pushed a commit to mdebbar/flutter that referenced this pull request Feb 21, 2019
@github-actions github-actions Bot locked as resolved and limited conversation to collaborators Aug 7, 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 c: API break Backwards-incompatible API changes framework flutter/packages/flutter repository. See also f: labels. p: cupertino_ui cupertino_ui package in flutter/packages p: material_ui material_ui package in flutter/packages

Projects

None yet

Development

Successfully merging this pull request may close these issues.

It's not possible to move the cursor in a text field by dragging

6 participants