Skip to content

Conversation

@Renzo-Olivares
Copy link
Contributor

@Renzo-Olivares Renzo-Olivares commented Apr 13, 2023

Adds double click to select a word.
Adds double click + drag to select word by word.

Screen.Recording.2023-04-25.at.11.03.35.AM.mov

Partially fixes #104552

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 the framework flutter/packages/flutter repository. See also f: labels. label Apr 13, 2023
@Renzo-Olivares Renzo-Olivares force-pushed the selection-area-tapdrag branch 4 times, most recently from 8377b42 to 2d35b08 Compare April 18, 2023 18:18
@Renzo-Olivares Renzo-Olivares force-pushed the selection-area-tapdrag branch 2 times, most recently from 0bc6241 to 9ba1c10 Compare April 25, 2023 17:13
@Renzo-Olivares Renzo-Olivares changed the title [WIP] Add double tap + double tap and drag gestures to SelectionArea Add double tap + double tap and drag gestures to SelectionArea Apr 25, 2023
@flutter-dashboard flutter-dashboard bot added the f: material design flutter/packages/flutter/material repository. label Apr 25, 2023
@Renzo-Olivares Renzo-Olivares marked this pull request as ready for review April 25, 2023 17:59
@Renzo-Olivares Renzo-Olivares changed the title Add double tap + double tap and drag gestures to SelectionArea Add double click + double click and drag gestures to SelectionArea Apr 25, 2023
@Renzo-Olivares Renzo-Olivares changed the title Add double click + double click and drag gestures to SelectionArea Add double click and double click and drag gestures to SelectionArea Apr 25, 2023
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 with nits 👍

I'm always bummed that we don't get this kind of behavior for free shared between RenderEditable and RenderParagraph. But given that we can't do that yet, this is pretty clean, and I think TextGranularity makes it straightforward.

You have some test failures FYI.

Copy link
Contributor

Choose a reason for hiding this comment

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

Wow pattern matching 🤩

Comment on lines 391 to 392
Copy link
Contributor

Choose a reason for hiding this comment

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

Should these two names be the same? textGranularity and granularity.

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 point!

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 we have a method with the same name in text_selection.dart. Is it reasonable to share code here?

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 can re-visit this once I implement triple-click gestures. Right now there are some small nuances between how this effective consecutive tap count works on static vs editable text.

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.

Copy link
Contributor

Choose a reason for hiding this comment

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

No apostrophe here: "platform's" => "platforms"

Copy link
Contributor

Choose a reason for hiding this comment

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

Same for below.

Comment on lines 513 to 517
Copy link
Contributor

Choose a reason for hiding this comment

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

return isPositionAtOrBelowStartingBaseline;

Copy link
Contributor

Choose a reason for hiding this comment

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

Should there be spaces between the brackets and the text? I forget. Here and below, if I'm right.

Copy link
Contributor Author

@Renzo-Olivares Renzo-Olivares Apr 25, 2023

Choose a reason for hiding this comment

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

Looks like the other methods in this file with named parameters do not, so I just followed that. But I am also unsure what the preferred styling here is.

Copy link
Contributor

Choose a reason for hiding this comment

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

Sounds like it's not a big deal then, keeping it like this is fine 👍

Copy link
Contributor

Choose a reason for hiding this comment

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

It was probably my oversight.

Copy link
Contributor

Choose a reason for hiding this comment

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

Should textGranularity actually receive a default value 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: Maybe specify that the default is [TextGranularity.character] instead of saying "character by character".

Copy link
Contributor

Choose a reason for hiding this comment

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

Why is this needed now? (and in a few other places 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.

This is needed because of the switch to PanGestureRecognizer -> TapAndPanGestureRecognizer. PanGestureRecognizer calls onDown earlier than TapAndPanGestureRecognizer. PanGestureRecognizer calls it in addAllowedPointer, and TapAndPanGestureRecognizer waits for the recognizer to declare victory.

Copy link
Contributor

Choose a reason for hiding this comment

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

Thanks for the explanation!

Copy link
Contributor

Choose a reason for hiding this comment

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

Super nit: Maybe assign this offset to a variable so that it's clear where it's coming from?

@Renzo-Olivares Renzo-Olivares changed the title Add double click and double click and drag gestures to SelectionArea Add double click and double click + drag gestures to SelectionArea Apr 25, 2023
@Renzo-Olivares
Copy link
Contributor Author

Renzo-Olivares commented Apr 26, 2023

Looks like the failing tests are because getPositionForOffset returns a different value on web vs other platforms.

  Offset textOffsetToPosition(RenderParagraph paragraph, int offset) {
    const Rect caret = Rect.fromLTWH(0.0, 0.0, 2.0, 20.0);
    final Offset localOffset = paragraph.getOffsetForCaret(TextPosition(offset: offset), caret);
    return paragraph.localToGlobal(localOffset);
  }

  test('getWordBoundary control test failing', () {
    final RenderParagraph paragraph = RenderParagraph(
      const TextSpan(text: 'How are you?'),
      textDirection: TextDirection.ltr,
    );
    layout(paragraph);

    final Offset target4 = textOffsetToPosition(paragraph, 4);
    final TextPosition position4 = paragraph.getPositionForOffset(target4);
    final TextRange range4 = paragraph.getWordBoundary(position4);
    expect(range4.textInside('How are you?'), equals('are'));
  });

This fails with --platform=chrome because web getPositionForOffset returns TextPosition(4, upstream) and other platforms return TextPosition(4, downstream).

Looks like this test passes using --web-renderer=canvaskit but fails for skwasm and html.

Opened #125582 for further investigation.

@Renzo-Olivares Renzo-Olivares force-pushed the selection-area-tapdrag branch 2 times, most recently from cf86e53 to ffdaecd Compare April 27, 2023 09:26
@justinmc
Copy link
Contributor

Thanks for opening that issue!


final (TextPosition start, TextPosition end) wordBoundary = _getWordBoundaryAtPosition(position);
TextPosition targetPosition = isEnd ? wordBoundary.$2 : wordBoundary.$1;
if (!_rect.contains(localPosition)) {
Copy link
Contributor

Choose a reason for hiding this comment

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

I am not entirely sure what this is for can you explain?

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 found that since SelectionUtils.adjustDragOffset returns the top left of the rect for ltr if the drag is in Area1 of a Selectable it will return TextPosition(0). When using _getWordBoundaryAtPosition(position) that ends up selecting the first word of the selectable.

This is not desired since say we have a list of Selectables and our drag starts at the first one, dragging down to the second one moves the selection to the word on the second selectable, but then when dragging back up to the first selectable the second selectables first word is still selected because _getWordBoundaryAtPosition(TextPosition(0)) = first word.

This same logic is in _updateSelectionEdge but it works there because the edge will moved to TextPosition(0) and not the word at TextPosition(0).

This was my workaround for this issue.

Copy link
Contributor

Choose a reason for hiding this comment

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

Thanks for explanation. If this is the case, I think you can move this before the whole _getWordBoundaryAtPosition and short circuit it. Also would be good to add some comments about this

localPosition,
direction: paragraph.textDirection,
);
final TextPosition position = _clampTextPosition(paragraph.getPositionForOffset(adjustedOffset));
Copy link
Contributor

Choose a reason for hiding this comment

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

This probably should instead clamp after _getWordBoundaryAtPosition

it is fine if the position is outside of the text range of this selectablefragment, as long as the targetPosition is in the text range.

return SelectionResult.previous;
}

return SelectionUtils.getResultBasedOnRect(_rect, localPosition);
Copy link
Contributor

Choose a reason for hiding this comment

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

Can you also copy the todo over?

/// The [globalPosition] contains the new offset of the edge.
///
/// This event is dispatched when the framework detects [DragStartDetails] in
/// The [granularity] contains the granularity that the selection edge should move by.
Copy link
Contributor

Choose a reason for hiding this comment

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

should we document that only character and word is supported?

@flutter-dashboard flutter-dashboard bot added the f: scrolling Viewports, list views, slivers, etc. label Apr 29, 2023
@Renzo-Olivares Renzo-Olivares force-pushed the selection-area-tapdrag branch 3 times, most recently from 012396b to 83190e9 Compare May 4, 2023 03:55
Copy link
Contributor

Choose a reason for hiding this comment

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

why do you need to cache this value? is it possible to figure out whether the you need to move the start or end based on the current selection and the newly updated selection? for example, if current selection is (start: 3, end: 6) and you receive a end update, you will know you need to swap the start if new end position is < 3

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 hard to read the logic in these block. Can you add check isEnd in the condition? I think it would be noop in the set selection anyway

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 you don't need to cache the _originWordSelectionStart, you just need to find the wordboundary of _textSelectionEnd/Start and move them to the other side of the word.

Also the current logc assume _originWordSelectionStart and _originWordSelectionEnd are enclosing a word. is it possible it is not the case?

@Renzo-Olivares Renzo-Olivares force-pushed the selection-area-tapdrag branch 2 times, most recently from 1b1c1a8 to 52cb91b Compare May 9, 2023 21:51
engine-flutter-autoroll added a commit to engine-flutter-autoroll/packages that referenced this pull request Aug 13, 2023
engine-flutter-autoroll added a commit to engine-flutter-autoroll/packages that referenced this pull request Aug 14, 2023
engine-flutter-autoroll added a commit to engine-flutter-autoroll/packages that referenced this pull request Aug 14, 2023
engine-flutter-autoroll added a commit to engine-flutter-autoroll/packages that referenced this pull request Aug 14, 2023
engine-flutter-autoroll added a commit to engine-flutter-autoroll/packages that referenced this pull request Aug 14, 2023
engine-flutter-autoroll added a commit to engine-flutter-autoroll/packages that referenced this pull request Aug 14, 2023
engine-flutter-autoroll added a commit to engine-flutter-autoroll/packages that referenced this pull request Aug 14, 2023
engine-flutter-autoroll added a commit to engine-flutter-autoroll/packages that referenced this pull request Aug 14, 2023
engine-flutter-autoroll added a commit to engine-flutter-autoroll/packages that referenced this pull request Aug 14, 2023
engine-flutter-autoroll added a commit to engine-flutter-autoroll/packages that referenced this pull request Aug 15, 2023
engine-flutter-autoroll added a commit to engine-flutter-autoroll/packages that referenced this pull request Aug 15, 2023
engine-flutter-autoroll added a commit to engine-flutter-autoroll/packages that referenced this pull request Aug 15, 2023
engine-flutter-autoroll added a commit to engine-flutter-autoroll/packages that referenced this pull request Aug 15, 2023
engine-flutter-autoroll added a commit to engine-flutter-autoroll/packages that referenced this pull request Aug 15, 2023
engine-flutter-autoroll added a commit to engine-flutter-autoroll/packages that referenced this pull request Aug 15, 2023
engine-flutter-autoroll added a commit to engine-flutter-autoroll/packages that referenced this pull request Nov 15, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

autosubmit Merge PR when tree becomes green via auto submit App f: material design flutter/packages/flutter/material repository. f: scrolling Viewports, list views, slivers, etc. framework flutter/packages/flutter repository. See also f: labels.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

SelectionArea does not select the text when using double and triple tap

3 participants