Skip to content

Conversation

yiiim
Copy link
Member

@yiiim yiiim commented Nov 15, 2023

This PR changes the regular cursor to a floating cursor when a long press occurs.

This is a new feature. Fixes #89228

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.

If you need help, consider asking for advice on the #hackers-new channel on Discord.

@github-actions github-actions bot added a: text input Entering text in a text field or keyboard related problems framework flutter/packages/flutter repository. See also f: labels. f: material design flutter/packages/flutter/material repository. f: cupertino flutter/packages/flutter/cupertino repository labels Nov 15, 2023
@yiiim yiiim changed the title Fix 132825 Changes the regular cursor to a floating cursor when a long press occurs. Nov 15, 2023
@flutter-dashboard
Copy link

Golden file changes have been found for this pull request. Click here to view and triage (e.g. because this is an intentional change).

If you are still iterating on this change and are not ready to resolve the images on the Flutter Gold dashboard, consider marking this PR as a draft pull request above. You will still be able to view image results on the dashboard, commenting will be silenced, and the check will not try to resolve itself until marked ready for review.

For more guidance, visit Writing a golden file test for package:flutter.

Reviewers: Read the Tree Hygiene page and make sure this patch meets those guidelines before LGTMing.

Changes reported for pull request #138479 at sha 03efdc22f780d3b9b66832332a1d7064d3a621b3

@flutter-dashboard flutter-dashboard bot added the will affect goldens Changes to golden files label Nov 15, 2023
Copy link
Contributor

@LongCatIsLooong LongCatIsLooong left a comment

Choose a reason for hiding this comment

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

This looks like a new feature to me. Could you add a bit more detail wrt how this fixes the flickering in #132825 ?

Copy link
Contributor

Choose a reason for hiding this comment

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

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 add a bit more context about the behavior? Something like in UITextField when floating cursor is activated the regular cursor won't be visible unless it's too far away from the regular one?

Copy link
Contributor

Choose a reason for hiding this comment

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

nit: use ?? over if statements?

Copy link
Contributor

Choose a reason for hiding this comment

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

can this be incorporated into the base class instead of a separate mixin?

Copy link
Member Author

Choose a reason for hiding this comment

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

Yes, I found that it doesn't affect SelectableText, so we can incorporate into the base class.

Copy link
Contributor

@LongCatIsLooong LongCatIsLooong Nov 15, 2023

Choose a reason for hiding this comment

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

Ideally we should avoid using the selection value from the controller. The value from the controller is potentially one frame ahead of the currently rendered selection range (and the selection range reported to the iOS text input plugin).

Copy link
Member Author

Choose a reason for hiding this comment

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

Then we have to update the floating cursor after the frame

@yiiim
Copy link
Member Author

yiiim commented Nov 16, 2023

This looks like a new feature to me. Could you add a bit more detail wrt how this fixes the flickering in #132825 ?

Sorry, I seem to have had some misunderstandings. This cannot be fixed #132825. I will change the description.

Copy link
Contributor

Choose a reason for hiding this comment

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

Why does the code need to be scheduled to run as a post-frame callback?

Copy link
Member Author

Choose a reason for hiding this comment

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

editable_text.dart#L3135C7-L3135C7 Need to get the correct selection after the frame.

Copy link
Contributor

Choose a reason for hiding this comment

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

Shouldn't this go to line 2417? The floating cursor is iOS only right? And it only happens when you long press and drag the blinking cursor?

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 the update/end events)

Copy link
Member Author

Choose a reason for hiding this comment

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

A long press displays a floating cursor that does not require dragging. A long press may be further away from the regular cursor. For example, long press at the end of the text far away from the text

Copy link
Contributor

@LongCatIsLooong LongCatIsLooong Dec 7, 2023

Choose a reason for hiding this comment

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

Ah I see thanks for pointing this out. I tried this in a UITextView, my observations so far:

  1. When the text selection is collapsed, long press drag initiates floating cursor and when it ends the selection remains collapsed.
  2. When there is pre-selected text, long press drag does the same, but only when the initial long press starts outside of the selected text. And when it ends the selection becomes collapsed.
  3. When there is pre-selected text, and the initial long press starts inside of the selected text, the behavior has been somewhat inconsistent for me. Most of the time it enters "text drag and drop" mode, but sometimes one of the selection handlers enters the floating cursor mode and I was able to adjust the text selection in that mode.
  4. When the field doesn't have focus you can still long press to focus the field and start floating cursor.

Copy link
Member Author

@yiiim yiiim Dec 7, 2023

Choose a reason for hiding this comment

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

I guess I should only need to show the floating cursor when the selection is collapsed. Do we have any plans regarding "text drag and drop" mode? I'd like to contribute to this.

Copy link
Contributor

Choose a reason for hiding this comment

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

One existing issue I found: #128388. @Renzo-Olivares have you looked into this?

@LongCatIsLooong
Copy link
Contributor

I'd like to verify some floating cursor interactions in a UIKit app tomorrow and get back to this PR. Sorry for the delay!

@yiiim
Copy link
Member Author

yiiim commented Nov 28, 2023

I also found that the cursor will be reset to the blinking state shortly after long pressing. This may also be incorrect behavior. I will look for this issue later and fix it as another PR.

@LongCatIsLooong LongCatIsLooong self-requested a review November 29, 2023 18:43
@yiiim
Copy link
Member Author

yiiim commented Dec 6, 2023

Are you still continuing the review? @LongCatIsLooong

Copy link
Contributor

@LongCatIsLooong LongCatIsLooong left a comment

Choose a reason for hiding this comment

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

Sorry for the delay.

Copy link
Contributor

Choose a reason for hiding this comment

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

Shouldn't this go to line 2417? The floating cursor is iOS only right? And it only happens when you long press and drag the blinking cursor?

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 the update/end events)

Copy link
Contributor

@LongCatIsLooong LongCatIsLooong Dec 7, 2023

Choose a reason for hiding this comment

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

It will probably be easier if we update the logic in RenderEditable.updateFloatingCursor to update the selection immediately on FloatingCursorDragState.Start (as all types of floating cursors seem to relocate the caret to where the floating cursor is on start?), so we don't have to do this? And we should be able to avoid the post frame callback with that.

Copy link
Contributor

Choose a reason for hiding this comment

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

Also when I tried long pressing on ios/macos, whether the field was initially focused didn't seem to make any difference. cc @Renzo-Olivares.

Copy link
Member Author

Choose a reason for hiding this comment

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

If we update the selection within updateFloatingCursor, we would also need to bring SelectionChangedCause.longPress into updateFloatingCursor. This could potentially complicate things further.

Copy link
Contributor

Choose a reason for hiding this comment

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

Good point. Then does it make sense to add the new text selection to the RawFloatingCursorPoint class?

class RawFloatingCursorPoint {
  // (local offset, new caret location)
  //  Only non-null when starting a floating cursor via long press.
  final (Offset, TextPositon)? startLocation;
}

Then in editable_text.dart we can use that information in the FloatingCursorDragState.Start clause if non-null. It's error-prone to use addPostframeCallback in general since you don't know what is going to happen in that frame (the render object can be disposed, for example).

Copy link
Member Author

Choose a reason for hiding this comment

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

Coooooool, we can avoid using the addPostframeCallback method now. 🎉🎉🎉

Copy link
Contributor

@LongCatIsLooong LongCatIsLooong left a comment

Choose a reason for hiding this comment

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

Could you add a few tests to verify the new feature works?

Copy link
Contributor

Choose a reason for hiding this comment

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

remove late?

Copy link
Contributor

Choose a reason for hiding this comment

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

nit: I think it probably makes more sense to keep this in the switch statement? If the render editable isn't focused, instead of selecting the word, we want to select the position and start the floating cursor right?

@yiiim
Copy link
Member Author

yiiim commented Dec 11, 2023

@LongCatIsLooong Hello, I noticed some issues when moving outside of the textfield, which have now been fixed. Please continue with the review. Additionally, I moved the code into a switch statement. I found that macOS does not trigger the long press gesture, so I didn't make any additional judgments. Finally, I added a golden file test. This is my first time using a golden file test, and I hope everything goes smoothly.

@flutter-dashboard
Copy link

Golden file changes are available for triage from new commit, Click here to view.

For more guidance, visit Writing a golden file test for package:flutter.

Reviewers: Read the Tree Hygiene page and make sure this patch meets those guidelines before LGTMing.

Changes reported for pull request #138479 at sha ca6474ccef9ee2c31445db077a4f40d4b89af83a

Copy link
Contributor

Choose a reason for hiding this comment

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

Can this just be an Offset and we can get the current value from within updateFloatingCursor?

Copy link
Member Author

Choose a reason for hiding this comment

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

I had a discussion with LongCatIsLooong, and because renderEditable.selection updates one frame late, we can't use renderEditable.selection for calculation.

Copy link
Contributor

Choose a reason for hiding this comment

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

Since this is public API documentation, could you update it to make it more formal / descriptive?

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 this empty line needed?

Copy link
Contributor

Choose a reason for hiding this comment

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

nit: add a period at the end of this comment.

Copy link
Contributor

Choose a reason for hiding this comment

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

nit: add a period at the end of this comment.

Copy link
Contributor

Choose a reason for hiding this comment

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

nit: Wait for autofocus.

Copy link
Contributor

Choose a reason for hiding this comment

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

nit: consider changing to Wait for autofocus.

Copy link
Contributor

Choose a reason for hiding this comment

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

nit: Add a period at the end of this comment.

@yiiim
Copy link
Member Author

yiiim commented Dec 13, 2023

All nits have been fixed.

@flutter-dashboard
Copy link

Golden file changes are available for triage from new commit, Click here to view.

For more guidance, visit Writing a golden file test for package:flutter.

Reviewers: Read the Tree Hygiene page and make sure this patch meets those guidelines before LGTMing.

Changes reported for pull request #138479 at sha 05a3344cf8252ba33120f6ff85c1801fe64a289e

@flutter-dashboard
Copy link

Golden file changes are available for triage from new commit, Click here to view.

For more guidance, visit Writing a golden file test for package:flutter.

Reviewers: Read the Tree Hygiene page and make sure this patch meets those guidelines before LGTMing.

Changes reported for pull request #138479 at sha 5bf4b9f

final EdgeInsets boundingRect = _calculateFloatingCursorBounds();

if (shouldResetOrigin != null) {
_shouldResetOrigin = shouldResetOrigin;
Copy link
Contributor

Choose a reason for hiding this comment

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

nit: ??=

Copy link
Member Author

Choose a reason for hiding this comment

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

We can't use ??= here. When shouldResetOrigin is not null, the variable that needs to be assigned is _shouldResetOrigin, they are not the same.

/// Returns the position within the text field closest to the raw cursor offset.
Offset calculateBoundedFloatingCursorOffset(Offset rawCursorOffset, {bool? shouldResetOrigin}) {
Offset deltaPosition = Offset.zero;
final EdgeInsets boundingRect = _calculateFloatingCursorBounds();
Copy link
Contributor

Choose a reason for hiding this comment

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

nit: inline the implementation?

also consider using clampDouble.

Copy link
Contributor

Choose a reason for hiding this comment

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

also nit: bounding rects are typically Rects.

Copy link
Member Author

Choose a reason for hiding this comment

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

Fixed.

Copy link
Contributor

Choose a reason for hiding this comment

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

nit: use Rect instead of EdgeInsets.

}

if (!_shouldResetOrigin) {
return _calculateAdjustedCursorOffset(rawCursorOffset, boundingRect);
Copy link
Contributor

Choose a reason for hiding this comment

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

If you adjust the cursor offset to be within boundingRect, does a multiline text field still scroll down if you drag the cursor to the bottom of the text field?

Copy link
Member Author

Choose a reason for hiding this comment

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

I see that they are working properly.

@flutter-dashboard
Copy link

Golden file changes are available for triage from new commit, Click here to view.

For more guidance, visit Writing a golden file test for package:flutter.

Reviewers: Read the Tree Hygiene page and make sure this patch meets those guidelines before LGTMing.

Changes reported for pull request #138479 at sha 53b7bcf

@yiiim yiiim requested a review from LongCatIsLooong January 2, 2024 16:23
@flutter-dashboard
Copy link

Golden file changes are available for triage from new commit, Click here to view.

For more guidance, visit Writing a golden file test for package:flutter.

Reviewers: Read the Tree Hygiene page and make sure this patch meets those guidelines before LGTMing.

Changes reported for pull request #138479 at sha 8838224

Copy link
Contributor

@LongCatIsLooong LongCatIsLooong left a comment

Choose a reason for hiding this comment

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

LGTM modulo nits. Thank you for contributing! The floating cursor seems to work pretty well when I tried out this patch.

/// Returns the position within the text field closest to the raw cursor offset.
Offset calculateBoundedFloatingCursorOffset(Offset rawCursorOffset, {bool? shouldResetOrigin}) {
Offset deltaPosition = Offset.zero;
final EdgeInsets boundingRect = _calculateFloatingCursorBounds();
Copy link
Contributor

Choose a reason for hiding this comment

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

nit: use Rect instead of EdgeInsets.

return EdgeInsets.fromLTRB(leftBound, topBound, rightBound, bottomBound);
}

Offset _calculateAdjustedCursorOffset(Offset offset, EdgeInsets boundingRect) {
Copy link
Contributor

Choose a reason for hiding this comment

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

nit: make this static?

Copy link
Contributor

Choose a reason for hiding this comment

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

Since this is public API documentation, could you update it to make it more formal / descriptive?

from: details.globalPosition,
cause: SelectionChangedCause.longPress,
);
// Show the floating cursor
Copy link
Contributor

Choose a reason for hiding this comment

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

nit: period at the end of sentence.

Copy link
Contributor

@Renzo-Olivares Renzo-Olivares left a comment

Choose a reason for hiding this comment

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

LGTM w/ small nit.

@flutter-dashboard
Copy link

Golden file changes are available for triage from new commit, Click here to view.

For more guidance, visit Writing a golden file test for package:flutter.

Reviewers: Read the Tree Hygiene page and make sure this patch meets those guidelines before LGTMing.

Changes reported for pull request #138479 at sha aa4e580

@yiiim
Copy link
Member Author

yiiim commented Jan 3, 2024

The nits have been fixed, I believe it's ready for merge.

@LongCatIsLooong LongCatIsLooong added the autosubmit Merge PR when tree becomes green via auto submit App label Jan 3, 2024
@auto-submit auto-submit bot merged commit 0d4eb5e into flutter:master Jan 3, 2024
engine-flutter-autoroll added a commit to engine-flutter-autoroll/packages that referenced this pull request Jan 3, 2024
engine-flutter-autoroll added a commit to engine-flutter-autoroll/packages that referenced this pull request Jan 5, 2024
tarrinneal added a commit to flutter/packages that referenced this pull request Jan 5, 2024
Manual roll Flutter from 11def8e to cc40425 (118 revisions)

Manual roll requested by [email protected]

flutter/flutter@11def8e...cc40425

2024-01-05 [email protected] Roll Flutter Engine from
0bbb4d61ce82 to f60d9a9a3395 (1 revision) (flutter/flutter#140993)
2024-01-04 [email protected] Roll Flutter Engine from
b2a9ce88a19e to 0bbb4d61ce82 (3 revisions) (flutter/flutter#140990)
2024-01-04 [email protected] [web] Fix and unskip a few more CanvasKit
tests (flutter/flutter#140821)
2024-01-04 [email protected] Roll Flutter Engine from
bd175aa5e0b6 to b2a9ce88a19e (1 revision) (flutter/flutter#140986)
2024-01-04 [email protected] Pin package:vm_service
(flutter/flutter#140972)
2024-01-04 [email protected] Add scrollbar
for menus (flutter/flutter#140941)
2024-01-04 [email protected] manual pub roll to pick up dds
fixes (flutter/flutter#140979)
2024-01-04 [email protected] Roll Flutter Engine from
b81023eb71c9 to bd175aa5e0b6 (2 revisions) (flutter/flutter#140980)
2024-01-04 [email protected] Temporarily remove env variable for leak
tracking bots. (flutter/flutter#140978)
2024-01-04 [email protected] Add Flutter CI status to README
(flutter/flutter#140513)
2024-01-04 [email protected] Reland "integrate testWidgets with leak
tracking" (#140521) (flutter/flutter#140928)
2024-01-04 [email protected] Run half of iOS
devicelab tests with Xcode 15 (flutter/flutter#140927)
2024-01-04 [email protected] Fix
`SegmentedButton` states update logic (flutter/flutter#140772)
2024-01-04 [email protected] Roll Flutter Engine from
f539acfb8c5a to b81023eb71c9 (1 revision) (flutter/flutter#140973)
2024-01-04 [email protected] [Fix] Consistency in
ButtonStyleButton related Tests (flutter/flutter#140610)
2024-01-04 [email protected] Roll Packages from
bbb4134 to 31fc7b5 (6 revisions) (flutter/flutter#140967)
2024-01-04 [email protected] Fix local engine use in macOS plugins
(flutter/flutter#140222)
2024-01-04 [email protected] Roll Flutter Engine from
7d5a120a601b to f539acfb8c5a (2 revisions) (flutter/flutter#140959)
2024-01-04 [email protected] Roll Flutter Engine from
1ff3cb885842 to 7d5a120a601b (1 revision) (flutter/flutter#140946)
2024-01-04 [email protected] Roll Flutter Engine from
c8bf51f0d4cd to 1ff3cb885842 (1 revision) (flutter/flutter#140943)
2024-01-04 [email protected] Roll Flutter Engine from
bfd2d8a100ec to c8bf51f0d4cd (2 revisions) (flutter/flutter#140939)
2024-01-04 [email protected] Roll Flutter Engine from
28ae9e35c331 to bfd2d8a100ec (1 revision) (flutter/flutter#140937)
2024-01-04 [email protected] Roll Flutter Engine from
ab4098c742f8 to 28ae9e35c331 (1 revision) (flutter/flutter#140936)
2024-01-04 [email protected] Roll Flutter Engine from
e169f3677008 to ab4098c742f8 (2 revisions) (flutter/flutter#140933)
2024-01-03 [email protected] Roll Flutter Engine from
7c2adb811059 to e169f3677008 (1 revision) (flutter/flutter#140929)
2024-01-03 [email protected] Remove deprecated bitcode stripping from
tooling (flutter/flutter#140903)
2024-01-03 [email protected] Add Windows leak
tracking targets (flutter/flutter#140423)
2024-01-03 [email protected] [github actions] refactor and fix
cherry pick actions (flutter/flutter#140499)
2024-01-03 [email protected] Migrate Xcode projects last version checks
to Xcode 15.1 (flutter/flutter#140256)
2024-01-03 [email protected] Roll Flutter Engine from
bf232c4da241 to 7c2adb811059 (3 revisions) (flutter/flutter#140920)
2024-01-03 [email protected] fix typo and reflow
(flutter/flutter#140925)
2024-01-03 98614782+auto-submit[bot]@users.noreply.github.com Reverts
"Re-land integrate testWidgets with leak tracking."
(flutter/flutter#140926)
2024-01-03 [email protected] Roll Flutter Engine from
bf979d220283 to bf232c4da241 (1 revision) (flutter/flutter#140915)
2024-01-03 [email protected] Changes the regular cursor to a
floating cursor when a long press occurs. (flutter/flutter#138479)
2024-01-03 [email protected] Add
`SegmentedButton.styleFrom` (flutter/flutter#137542)
2024-01-03 [email protected] Roll Flutter Engine from
c62bcff5b809 to bf979d220283 (1 revision) (flutter/flutter#140910)
2024-01-03 [email protected] Re-land integrate testWidgets with leak
tracking. (flutter/flutter#140521)
2024-01-03 [email protected] Roll Flutter Engine from
98b72c7ffe71 to c62bcff5b809 (2 revisions) (flutter/flutter#140905)
2024-01-03 [email protected] [flutter_tools] add support for
--enable-impeller to test device. (flutter/flutter#140899)
2024-01-03 [email protected] Roll Flutter Engine from
cf7536964a2f to 98b72c7ffe71 (1 revision) (flutter/flutter#140897)
2024-01-03 [email protected] Handle
KEYCODE_DPAD_CENTER and KEYCODE_ENTER (flutter/flutter#140808)
2024-01-03 [email protected] Add Lucas Saudon to AUTHORS
(flutter/flutter#139965)
2024-01-03 [email protected] Link to wiki page
about updating dependencies in each `pubspec.yaml` file
(flutter/flutter#140826)
2024-01-03 [email protected] Marks Linux_pixel_7pro
native_assets_android to be unflaky (flutter/flutter#140866)
...

---------

Co-authored-by: Tarrin Neal <[email protected]>
engine-flutter-autoroll added a commit to engine-flutter-autoroll/packages that referenced this pull request Feb 16, 2024
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 autosubmit Merge PR when tree becomes green via auto submit App f: cupertino flutter/packages/flutter/cupertino repository f: material design flutter/packages/flutter/material repository. framework flutter/packages/flutter repository. See also f: labels. will affect goldens Changes to golden files

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Double cursor using iOS floating cursor (keyboard cursor move with spacebar)

3 participants