Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Disable cursor opacity animation on macOS, make iOS cursor animation discrete #104335

Merged
merged 9 commits into from
Jun 22, 2022

Conversation

LongCatIsLooong
Copy link
Contributor

@LongCatIsLooong LongCatIsLooong commented May 21, 2022

  • Disable animated blinking cursor on macOS. The caret is an NSView that gets removed/added back periodically in AppKit text input views, its opacity doesn't change. This fixes Too much CPU usage with TextField caret on macOS #85781, CPU usage stays below/around 1% in my test app.
  • Make the iOS cursor blinking opacity animation discrete to match the native. This should also make the animation more energy efficient as we're no longer interpolating between the keyframes.
  • Disable "briefly show password" on iOS, since secured input fields don't seem to be doing that on iOS 15.4

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.

@flutter-dashboard flutter-dashboard bot added a: text input Entering text in a text field or keyboard related problems f: cupertino flutter/packages/flutter/cupertino repository f: material design flutter/packages/flutter/material repository. framework flutter/packages/flutter repository. See also f: labels. labels May 21, 2022
_DiscreteKeyFrameSimulation.iOSBlinkingCaret() : this._(_KeyFrame.iOSBlinkingCaretKeyFrames);
_DiscreteKeyFrameSimulation._(this._keyFrames)
: assert(_keyFrames.isNotEmpty),
assert(_keyFrames.last.time < maxDuration);
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 also make sure _keyFrames is sorted in an assert?


@override
double x(double time) {
time = time % maxDuration;
Copy link
Contributor

Choose a reason for hiding this comment

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

Reuse the time parameter is a little hard to comprehend. What does the new "time" mean? Maybe create a new variable with a different name to better describe what is time % maxDuration? Or maybe add a comment to explain. (I'd still have a new variable for it)

@@ -3489,7 +3543,7 @@ class EditableTextState extends State<EditableText> with AutomaticKeepAliveClien
text = widget.obscuringCharacter * text.length;
// Reveal the latest character in an obscured field only on mobile.
Copy link
Contributor

Choose a reason for hiding this comment

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

This comment has to be updated. Also a good place to explain why iOS is excluded, maybe add the issue link?

Copy link
Contributor

Choose a reason for hiding this comment

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

@LongCatIsLooong is this affected by your brieflyShowPassword thing, or was that Android only?

Copy link
Contributor

Choose a reason for hiding this comment

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

Oh I see you moved around a test related to this 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.

Yeah that was for Android only.

await verifyKeyFrame(opacity: 0.5, at: 925000);
await verifyKeyFrame(opacity: 0.75, at: 962500);
await verifyKeyFrame(opacity: 1.0, at: 1000000);
}, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS }));
Copy link
Contributor

Choose a reason for hiding this comment

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

Didn't we need to keep the macOS version of the test?

Copy link
Contributor Author

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

Changed the simulation to no longer wrap around when the input time becomes >= maxDuration. EditableTextState ends the animation anyways.

Copy link
Contributor

@cyanglaz cyanglaz 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

@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 👍

// A time-value pair that represents a key frame in an animation.
class _KeyFrame {
const _KeyFrame(this.time, this.value);
// Values extracted from iOS 15.4 UIKit.
Copy link
Contributor

Choose a reason for hiding this comment

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

How did you actually extract these values? Just out of my own curiosity.

}, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS, TargetPlatform.macOS }));

// Regression test for https://github.com/flutter/flutter/issues/78918.
// Regression test for https://github.com/flutter/flutter/issues/78918.
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 accidentally removed a space here if I'm reading the diff right.

@@ -3489,7 +3543,7 @@ class EditableTextState extends State<EditableText> with AutomaticKeepAliveClien
text = widget.obscuringCharacter * text.length;
// Reveal the latest character in an obscured field only on mobile.
Copy link
Contributor

Choose a reason for hiding this comment

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

@LongCatIsLooong is this affected by your brieflyShowPassword thing, or was that Android only?

Comment on lines +196 to +197
// verifies the opacity immediately *before* each key frame to avoid
// fp precision issues.
Copy link
Contributor

Choose a reason for hiding this comment

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

Nice 👍

lastVerifiedOpacity = opacity;
}

await verifyKeyFrame(opacity: 1.0, at: 500000);
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 it possible to reference the values in iOSBlinkingCaretKeyFrames instead of hardcoding them?

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'd prefer not to expose that animation, otherwise we would have to maintain that as a public API I think?

Copy link
Contributor

Choose a reason for hiding this comment

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

Oh right, I didn't realize it was in a private class. Sounds good as-is.

await tester.pump(const Duration(milliseconds: 100));
expect(tester.hasRunningAnimations, false);
}
}, variant: TargetPlatformVariant(TargetPlatform.values.toSet()..remove(TargetPlatform.iOS)));
Copy link
Contributor

Choose a reason for hiding this comment

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

Nice way to exclude a platform. See also #106216 CC @antholeole.

Copy link
Contributor

Choose a reason for hiding this comment

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

Almost exactly how 106216 is implemented! Depending on what gets in first, I’ll either change this to use the new API or this should use the new API.

Another good use case :).

@@ -956,4 +970,40 @@ void main() {
);
EditableText.debugDeterministicCursor = false;
}, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS, TargetPlatform.macOS }));

testWidgets('password briefly does not show last character on Android if turned off', (WidgetTester tester) async {
Copy link
Contributor

Choose a reason for hiding this comment

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

This mentions Android but it's run on the current platform? Shouldn't it fail on iOS?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Renamed the test

@@ -3489,7 +3543,7 @@ class EditableTextState extends State<EditableText> with AutomaticKeepAliveClien
text = widget.obscuringCharacter * text.length;
// Reveal the latest character in an obscured field only on mobile.
Copy link
Contributor

Choose a reason for hiding this comment

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

Oh I see you moved around a test related to this below.

@LongCatIsLooong LongCatIsLooong added the autosubmit Merge PR when tree becomes green via auto submit App label Jun 22, 2022
@auto-submit auto-submit bot merged commit 60f30e5 into flutter:master Jun 22, 2022
@LongCatIsLooong LongCatIsLooong deleted the ios-animated-cursor branch June 22, 2022 18:14
engine-flutter-autoroll added a commit to engine-flutter-autoroll/plugins that referenced this pull request Jun 22, 2022
engine-flutter-autoroll added a commit to engine-flutter-autoroll/packages that referenced this pull request Jun 23, 2022
engine-flutter-autoroll added a commit to engine-flutter-autoroll/packages that referenced this pull request Jun 23, 2022
LongCatIsLooong added a commit to LongCatIsLooong/flutter that referenced this pull request Jun 28, 2022
auto-submit bot pushed a commit that referenced this pull request Jun 28, 2022
XilaiZhang pushed a commit to XilaiZhang/flutter that referenced this pull request Jun 28, 2022
XilaiZhang added a commit that referenced this pull request Jun 28, 2022
…imation discrete (#104335)" (#106762) (#106766)

Co-authored-by: LongCatIsLooong <31859944+LongCatIsLooong@users.noreply.github.com>
LongCatIsLooong added a commit to LongCatIsLooong/flutter that referenced this pull request Jun 30, 2022
auto-submit bot pushed a commit that referenced this pull request Jul 8, 2022
camsim99 pushed a commit to camsim99/flutter that referenced this pull request Aug 10, 2022
camsim99 pushed a commit to camsim99/flutter that referenced this pull request Aug 10, 2022
camsim99 pushed a commit to camsim99/flutter that referenced this pull request Aug 10, 2022
engine-flutter-autoroll added a commit to engine-flutter-autoroll/packages that referenced this pull request Aug 30, 2022
engine-flutter-autoroll added a commit to engine-flutter-autoroll/plugins that referenced this pull request Aug 30, 2022
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.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Too much CPU usage with TextField caret on macOS
4 participants