Unverified Commit 81241910 authored by LongCatIsLooong's avatar LongCatIsLooong Committed by GitHub

Revert "Disable cursor opacity animation on macOS, make iOS cursor animation...

Revert "Disable cursor opacity animation on macOS, make iOS cursor animation discrete (#104335)" (#106762)
parent 6fbd6ea0
......@@ -1168,7 +1168,7 @@ class _TextFieldState extends State<TextField> with RestorationMixin implements
forcePressEnabled = false;
textSelectionControls ??= cupertinoDesktopTextSelectionControls;
paintCursorAboveText = true;
cursorOpacityAnimates = false;
cursorOpacityAnimates = true;
cursorColor = widget.cursorColor ?? selectionStyle.cursorColor ?? cupertinoTheme.primaryColor;
selectionColor = selectionStyle.selectionColor ?? cupertinoTheme.primaryColor.withOpacity(0.40);
cursorRadius ??= const Radius.circular(2.0);
......
......@@ -702,6 +702,40 @@ void main() {
expect(editableText.cursorOffset, const Offset(-2.0 / 3.0, 0));
});
testWidgets('Cursor animates', (WidgetTester tester) async {
await tester.pumpWidget(
const CupertinoApp(
home: CupertinoTextField(),
),
);
final Finder textFinder = find.byType(CupertinoTextField);
await tester.tap(textFinder);
await tester.pump();
final EditableTextState editableTextState = tester.firstState(find.byType(EditableText));
final RenderEditable renderEditable = editableTextState.renderEditable;
expect(renderEditable.cursorColor!.alpha, 255);
await tester.pump(const Duration(milliseconds: 100));
await tester.pump(const Duration(milliseconds: 400));
expect(renderEditable.cursorColor!.alpha, 255);
await tester.pump(const Duration(milliseconds: 200));
await tester.pump(const Duration(milliseconds: 100));
expect(renderEditable.cursorColor!.alpha, 110);
await tester.pump(const Duration(milliseconds: 100));
expect(renderEditable.cursorColor!.alpha, 16);
await tester.pump(const Duration(milliseconds: 50));
expect(renderEditable.cursorColor!.alpha, 0);
}, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS, TargetPlatform.macOS }));
testWidgets('Cursor radius is 2.0', (WidgetTester tester) async {
await tester.pumpWidget(
const CupertinoApp(
......
......@@ -609,6 +609,42 @@ void main() {
await checkCursorToggle();
});
testWidgets('Cursor animates', (WidgetTester tester) async {
await tester.pumpWidget(
const MaterialApp(
home: Material(
child: TextField(),
),
),
);
final Finder textFinder = find.byType(TextField);
await tester.tap(textFinder);
await tester.pump();
final EditableTextState editableTextState = tester.firstState(find.byType(EditableText));
final RenderEditable renderEditable = editableTextState.renderEditable;
expect(renderEditable.cursorColor!.alpha, 255);
await tester.pump(const Duration(milliseconds: 100));
await tester.pump(const Duration(milliseconds: 400));
expect(renderEditable.cursorColor!.alpha, 255);
await tester.pump(const Duration(milliseconds: 200));
await tester.pump(const Duration(milliseconds: 100));
expect(renderEditable.cursorColor!.alpha, 110);
await tester.pump(const Duration(milliseconds: 100));
expect(renderEditable.cursorColor!.alpha, 16);
await tester.pump(const Duration(milliseconds: 50));
expect(renderEditable.cursorColor!.alpha, 0);
}, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS, TargetPlatform.macOS }));
// Regression test for https://github.com/flutter/flutter/issues/78918.
testWidgets('RenderEditable sets correct text editing value', (WidgetTester tester) async {
final TextEditingController controller = TextEditingController(text: 'how are you');
......@@ -1292,7 +1328,7 @@ void main() {
editText = (findRenderEditable(tester).text! as TextSpan).text!;
expect(editText.substring(editText.length - 1), '\u2022');
}, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.android }));
}, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS, TargetPlatform.android }));
testWidgets('desktop obscureText control test', (WidgetTester tester) async {
await tester.pumpWidget(
......
......@@ -166,75 +166,61 @@ void main() {
);
});
testWidgets('Cursor animates on iOS', (WidgetTester tester) async {
await tester.pumpWidget(
const MaterialApp(
testWidgets('Cursor animates', (WidgetTester tester) async {
const Widget widget = MaterialApp(
home: Material(
child: TextField(),
child: TextField(
maxLines: 3,
),
),
);
await tester.pumpWidget(widget);
final Finder textFinder = find.byType(TextField);
await tester.tap(textFinder);
await tester.tap(find.byType(TextField));
await tester.pump();
final EditableTextState editableTextState = tester.firstState(find.byType(EditableText));
final RenderEditable renderEditable = editableTextState.renderEditable;
expect(renderEditable.cursorColor!.opacity, 1.0);
expect(renderEditable.cursorColor!.alpha, 255);
int walltimeMicrosecond = 0;
double lastVerifiedOpacity = 1.0;
// Trigger initial timer. When focusing the first time, the cursor shows
// for slightly longer than the average on time.
await tester.pump();
await tester.pump(const Duration(milliseconds: 200));
// Start timing standard cursor show period.
expect(renderEditable.cursorColor!.alpha, 255);
expect(renderEditable, paints..rrect(color: const Color(0xff2196f3)));
Future<void> verifyKeyFrame({ required double opacity, required int at }) async {
const int delta = 1;
assert(at - delta > walltimeMicrosecond);
await tester.pump(Duration(microseconds: at - delta - walltimeMicrosecond));
await tester.pump(const Duration(milliseconds: 500));
// Start to animate the cursor away.
expect(renderEditable.cursorColor!.alpha, 255);
expect(renderEditable, paints..rrect(color: const Color(0xff2196f3)));
// Instead of verifying the opacity at each key frame, this function
// verifies the opacity immediately *before* each key frame to avoid
// fp precision issues.
expect(
renderEditable.cursorColor!.opacity,
closeTo(lastVerifiedOpacity, 0.01),
reason: 'opacity at ${at-delta} microseconds',
);
await tester.pump(const Duration(milliseconds: 100));
expect(renderEditable.cursorColor!.alpha, 110);
expect(renderEditable, paints..rrect(color: const Color(0x6e2196f3)));
walltimeMicrosecond = at - delta;
lastVerifiedOpacity = opacity;
}
await tester.pump(const Duration(milliseconds: 100));
expect(renderEditable.cursorColor!.alpha, 16);
expect(renderEditable, paints..rrect(color: const Color(0x102196f3)));
await verifyKeyFrame(opacity: 1.0, at: 500000);
await verifyKeyFrame(opacity: 0.75, at: 537500);
await verifyKeyFrame(opacity: 0.5, at: 575000);
await verifyKeyFrame(opacity: 0.25, at: 612500);
await verifyKeyFrame(opacity: 0.0, at: 650000);
await verifyKeyFrame(opacity: 0.0, at: 850000);
await verifyKeyFrame(opacity: 0.25, at: 887500);
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 }));
testWidgets('Cursor does not animate on non-iOS platforms', (WidgetTester tester) async {
await tester.pumpWidget(
const MaterialApp(
home: Material(child: TextField(maxLines: 3)),
),
);
await tester.pump(const Duration(milliseconds: 100));
expect(renderEditable.cursorColor!.alpha, 0);
// Don't try to draw the cursor.
expect(renderEditable, paintsExactlyCountTimes(#drawRRect, 0));
await tester.tap(find.byType(TextField));
await tester.pump();
// Wait for the current animation to finish. If the cursor never stops its
// blinking animation the test will timeout.
await tester.pumpAndSettle();
// Wait some more while the cursor is gone. It'll trigger the cursor to
// start animating in again.
await tester.pump(const Duration(milliseconds: 300));
expect(renderEditable.cursorColor!.alpha, 0);
expect(renderEditable, paintsExactlyCountTimes(#drawRRect, 0));
for (int i = 0; i < 40; i += 1) {
await tester.pump(const Duration(milliseconds: 100));
expect(tester.hasRunningAnimations, false);
}
}, variant: TargetPlatformVariant.all(excluding: <TargetPlatform>{ TargetPlatform.iOS }));
await tester.pump(const Duration(milliseconds: 50));
// Cursor starts coming back.
expect(renderEditable.cursorColor!.alpha, 79);
expect(renderEditable, paints..rrect(color: const Color(0x4f2196f3)));
}, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS, TargetPlatform.macOS }));
testWidgets('Cursor does not animate on Android', (WidgetTester tester) async {
final Color defaultCursorColor = Color(ThemeData.fallback().colorScheme.primary.value);
......@@ -970,40 +956,4 @@ void main() {
);
EditableText.debugDeterministicCursor = false;
}, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS, TargetPlatform.macOS }));
testWidgets('password briefly does not show last character when disabled by system', (WidgetTester tester) async {
final bool debugDeterministicCursor = EditableText.debugDeterministicCursor;
EditableText.debugDeterministicCursor = false;
addTearDown(() {
EditableText.debugDeterministicCursor = debugDeterministicCursor;
});
await tester.pumpWidget(MaterialApp(
home: EditableText(
backgroundCursorColor: Colors.grey,
controller: controller,
obscureText: true,
focusNode: focusNode,
style: textStyle,
cursorColor: cursorColor,
),
));
await tester.enterText(find.byType(EditableText), 'AA');
await tester.pump();
await tester.enterText(find.byType(EditableText), 'AAA');
await tester.pump();
tester.binding.platformDispatcher.brieflyShowPasswordTestValue = false;
addTearDown(() {
tester.binding.platformDispatcher.brieflyShowPasswordTestValue = true;
});
expect((findRenderEditable(tester).text! as TextSpan).text, '••A');
await tester.pump(const Duration(milliseconds: 500));
expect((findRenderEditable(tester).text! as TextSpan).text, '•••');
await tester.pump(const Duration(milliseconds: 500));
await tester.pump(const Duration(milliseconds: 500));
await tester.pump(const Duration(milliseconds: 500));
expect((findRenderEditable(tester).text! as TextSpan).text, '•••');
});
}
......@@ -3943,6 +3943,42 @@ void main() {
expect((findRenderEditable(tester).text! as TextSpan).text, '•••');
});
testWidgets('password briefly does not show last character on Android if turned off', (WidgetTester tester) async {
final bool debugDeterministicCursor = EditableText.debugDeterministicCursor;
EditableText.debugDeterministicCursor = false;
addTearDown(() {
EditableText.debugDeterministicCursor = debugDeterministicCursor;
});
await tester.pumpWidget(MaterialApp(
home: EditableText(
backgroundCursorColor: Colors.grey,
controller: controller,
obscureText: true,
focusNode: focusNode,
style: textStyle,
cursorColor: cursorColor,
),
));
await tester.enterText(find.byType(EditableText), 'AA');
await tester.pump();
await tester.enterText(find.byType(EditableText), 'AAA');
await tester.pump();
tester.binding.platformDispatcher.brieflyShowPasswordTestValue = false;
addTearDown(() {
tester.binding.platformDispatcher.brieflyShowPasswordTestValue = true;
});
expect((findRenderEditable(tester).text! as TextSpan).text, '••A');
await tester.pump(const Duration(milliseconds: 500));
expect((findRenderEditable(tester).text! as TextSpan).text, '•••');
await tester.pump(const Duration(milliseconds: 500));
await tester.pump(const Duration(milliseconds: 500));
await tester.pump(const Duration(milliseconds: 500));
expect((findRenderEditable(tester).text! as TextSpan).text, '•••');
});
group('a11y copy/cut/paste', () {
Future<void> buildApp(MockTextSelectionControls controls, WidgetTester tester) {
return tester.pumpWidget(MaterialApp(
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment