Skip to content

Commit

Permalink
Fix selection not deselected when TextField loses focus (#103424)
Browse files Browse the repository at this point in the history
  • Loading branch information
Renzo-Olivares authored May 11, 2022
1 parent 594d524 commit c411065
Show file tree
Hide file tree
Showing 5 changed files with 126 additions and 6 deletions.
4 changes: 1 addition & 3 deletions packages/flutter/lib/src/widgets/editable_text.dart
Original file line number Diff line number Diff line change
Expand Up @@ -3253,8 +3253,6 @@ class EditableTextState extends State<EditableText> with AutomaticKeepAliveClien
assert(debugCheckHasMediaQuery(context));
super.build(context); // See AutomaticKeepAliveClientMixin.

final Color? effectiveSelectionColor = widget.selectionColor ?? DefaultSelectionStyle.of(context).selectionColor;

final TextSelectionControls? controls = widget.selectionControls;
return MouseRegion(
cursor: widget.mouseCursor ?? SystemMouseCursors.text,
Expand Down Expand Up @@ -3316,7 +3314,7 @@ class EditableTextState extends State<EditableText> with AutomaticKeepAliveClien
minLines: widget.minLines,
expands: widget.expands,
strutStyle: widget.strutStyle,
selectionColor: effectiveSelectionColor,
selectionColor: widget.selectionColor,
textScaleFactor: widget.textScaleFactor ?? MediaQuery.textScaleFactorOf(context),
textAlign: widget.textAlign,
textDirection: _textDirection,
Expand Down
57 changes: 57 additions & 0 deletions packages/flutter/test/cupertino/text_field_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -433,6 +433,63 @@ void main() {
},
);

testWidgets('Text field drops selection color when losing focus', (WidgetTester tester) async {
// Regression test for https://github.com/flutter/flutter/issues/103341.
final Key key1 = UniqueKey();
final Key key2 = UniqueKey();
final TextEditingController controller1 = TextEditingController();
const Color selectionColor = Colors.orange;
const Color cursorColor = Colors.red;

await tester.pumpWidget(
CupertinoApp(
home: Center(
child: DefaultSelectionStyle(
selectionColor: selectionColor,
cursorColor: cursorColor,
child: Column(
children: <Widget>[
CupertinoTextField(
key: key1,
controller: controller1,
),
CupertinoTextField(key: key2),
],
),
),
),
),
);

const TextSelection selection = TextSelection(baseOffset: 0, extentOffset: 4);
final EditableTextState state1 = tester.state<EditableTextState>(find.byType(EditableText).first);
final EditableTextState state2 = tester.state<EditableTextState>(find.byType(EditableText).last);

await tester.tap(find.byKey(key1));
await tester.enterText(find.byKey(key1), 'abcd');
await tester.pump();

await tester.tap(find.byKey(key2));
await tester.enterText(find.byKey(key2), 'dcba');
await tester.pump();

// Focus and selection is active on first TextField, so the second TextFields
// selectionColor should be dropped.
await tester.tap(find.byKey(key1));
controller1.selection = const TextSelection(baseOffset: 0, extentOffset: 4);
await tester.pump();
expect(controller1.selection, selection);
expect(state1.widget.selectionColor, selectionColor);
expect(state2.widget.selectionColor, null);

// Focus and selection is active on second TextField, so the first TextFields
// selectionColor should be dropped.
await tester.tap(find.byKey(key2));
await tester.pump();
expect(state1.widget.selectionColor, null);
expect(state2.widget.selectionColor, selectionColor);
});

testWidgets(
'multi-lined text fields are intrinsically taller no-strut',
(WidgetTester tester) async {
Expand Down
55 changes: 55 additions & 0 deletions packages/flutter/test/material/text_field_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -4198,6 +4198,61 @@ void main() {
feedback.dispose();
});

testWidgets('Text field drops selection color when losing focus', (WidgetTester tester) async {
// Regression test for https://github.com/flutter/flutter/issues/103341.
final Key key1 = UniqueKey();
final Key key2 = UniqueKey();
final TextEditingController controller1 = TextEditingController();
const Color selectionColor = Colors.orange;
const Color cursorColor = Colors.red;

await tester.pumpWidget(
overlay(
child: DefaultSelectionStyle(
selectionColor: selectionColor,
cursorColor: cursorColor,
child: Column(
children: <Widget>[
TextField(
key: key1,
controller: controller1,
),
TextField(key: key2),
],
),
),
),
);

const TextSelection selection = TextSelection(baseOffset: 0, extentOffset: 4);
final EditableTextState state1 = tester.state<EditableTextState>(find.byType(EditableText).first);
final EditableTextState state2 = tester.state<EditableTextState>(find.byType(EditableText).last);

await tester.tap(find.byKey(key1));
await tester.enterText(find.byKey(key1), 'abcd');
await tester.pump();

await tester.tap(find.byKey(key2));
await tester.enterText(find.byKey(key2), 'dcba');
await tester.pump();

// Focus and selection is active on first TextField, so the second TextFields
// selectionColor should be dropped.
await tester.tap(find.byKey(key1));
controller1.selection = const TextSelection(baseOffset: 0, extentOffset: 4);
await tester.pump();
expect(controller1.selection, selection);
expect(state1.widget.selectionColor, selectionColor);
expect(state2.widget.selectionColor, null);

// Focus and selection is active on second TextField, so the first TextFields
// selectionColor should be dropped.
await tester.tap(find.byKey(key2));
await tester.pump();
expect(state1.widget.selectionColor, null);
expect(state2.widget.selectionColor, selectionColor);
});

testWidgets('Selection is consistent with text length', (WidgetTester tester) async {
final TextEditingController controller = TextEditingController();

Expand Down
11 changes: 10 additions & 1 deletion packages/flutter/test/material/theme_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ void main() {
});

testWidgets('Theme overrides selection style', (WidgetTester tester) async {
final Key key = UniqueKey();
const Color defaultSelectionColor = Color(0x11111111);
const Color defaultCursorColor = Color(0x22222222);
const Color themeSelectionColor = Color(0x33333333);
Expand All @@ -66,7 +67,9 @@ void main() {
cursorColor: themeCursorColor,
),
),
child: const TextField(),
child: TextField(
key: key,
),
)
),
),
Expand All @@ -83,6 +86,12 @@ void main() {
child.visitChildren(recursiveFinder);
}
root.visitChildren(recursiveFinder);

// Focus text field so it has a selection color. The selection color is null
// on an unfocused text field.
await tester.tap(find.byKey(key));
await tester.pump();

expect(renderEditable.selectionColor, themeSelectionColor);
expect(tester.widget<EditableText>(find.byType(EditableText)).cursorColor, themeCursorColor);
});
Expand Down
5 changes: 3 additions & 2 deletions packages/flutter/test/widgets/editable_text_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -660,7 +660,8 @@ void main() {
expect(focusNode.hasFocus, isFalse);
});

testWidgets('use DefaultSelectionStyle for selection color', (WidgetTester tester) async {
testWidgets('EditableText does not derive selection color from DefaultSelectionStyle', (WidgetTester tester) async {
// Regression test for https://github.com/flutter/flutter/issues/103341.
const TextEditingValue value = TextEditingValue(
text: 'test test',
selection: TextSelection(affinity: TextAffinity.upstream, baseOffset: 5, extentOffset: 7),
Expand All @@ -687,7 +688,7 @@ void main() {
),
);
final EditableTextState state = tester.state<EditableTextState>(find.byType(EditableText));
expect(state.renderEditable.selectionColor, selectionColor);
expect(state.renderEditable.selectionColor, null);
});

testWidgets('visiblePassword keyboard is requested when set explicitly', (WidgetTester tester) async {
Expand Down

0 comments on commit c411065

Please sign in to comment.