Unverified Commit 39becb77 authored by Justin McCandless's avatar Justin McCandless Committed by GitHub

iOS spell check cursor placement (#124875)

Fixes the cursor location after selecting a spell check result on iOS.
parent f7245b64
...@@ -98,9 +98,15 @@ class CupertinoSpellCheckSuggestionsToolbar extends StatelessWidget { ...@@ -98,9 +98,15 @@ class CupertinoSpellCheckSuggestionsToolbar extends StatelessWidget {
// Replacement cannot be performed if the text is read only or obscured. // Replacement cannot be performed if the text is read only or obscured.
assert(!editableTextState.widget.readOnly && !editableTextState.widget.obscureText); assert(!editableTextState.widget.readOnly && !editableTextState.widget.obscureText);
final TextEditingValue newValue = editableTextState.textEditingValue.replaced( final TextEditingValue newValue = editableTextState.textEditingValue
.replaced(
replacementRange, replacementRange,
text, text,
)
.copyWith(
selection: TextSelection.collapsed(
offset: replacementRange.start + text.length,
),
); );
editableTextState.userUpdateTextEditingValue(newValue,SelectionChangedCause.toolbar); editableTextState.userUpdateTextEditingValue(newValue,SelectionChangedCause.toolbar);
...@@ -111,7 +117,6 @@ class CupertinoSpellCheckSuggestionsToolbar extends StatelessWidget { ...@@ -111,7 +117,6 @@ class CupertinoSpellCheckSuggestionsToolbar extends StatelessWidget {
} }
}); });
editableTextState.hideToolbar(); editableTextState.hideToolbar();
editableTextState.renderEditable.selectWordEdge(cause: SelectionChangedCause.toolbar);
} }
/// Builds the toolbar buttons based on the [buttonItems]. /// Builds the toolbar buttons based on the [buttonItems].
......
...@@ -15294,6 +15294,118 @@ testWidgets('Floating cursor ending with selection', (WidgetTester tester) async ...@@ -15294,6 +15294,118 @@ testWidgets('Floating cursor ending with selection', (WidgetTester tester) async
expect(state.currentTextEditingValue.selection.baseOffset, equals(0)); expect(state.currentTextEditingValue.selection.baseOffset, equals(0));
} }
}); });
testWidgets('replacing puts cursor at the end of the word', (WidgetTester tester) async {
tester.binding.platformDispatcher.nativeSpellCheckServiceDefinedTestValue =
true;
controller.value = const TextEditingValue(
// All misspellings of "test". One the same length, one shorter, and one
// longer.
text: 'tset tst testt',
selection: TextSelection(affinity: TextAffinity.upstream, baseOffset: 0, extentOffset: 4),
);
await tester.pumpWidget(
CupertinoApp(
home: EditableText(
backgroundCursorColor: Colors.grey,
controller: controller,
focusNode: focusNode,
style: textStyle,
cursorColor: cursorColor,
selectionControls: materialTextSelectionControls,
spellCheckConfiguration:
const SpellCheckConfiguration(
misspelledTextStyle: CupertinoTextField.cupertinoMisspelledTextStyle,
spellCheckSuggestionsToolbarBuilder: CupertinoTextField.defaultSpellCheckSuggestionsToolbarBuilder,
),
),
),
);
final EditableTextState state =
tester.state<EditableTextState>(find.byType(EditableText));
state.spellCheckResults = SpellCheckResults(
controller.value.text,
const <SuggestionSpan>[
SuggestionSpan(TextRange(start: 0, end: 4), <String>['test']),
SuggestionSpan(TextRange(start: 5, end: 8), <String>['test']),
SuggestionSpan(TextRange(start: 9, end: 13), <String>['test']),
]);
await tester.tapAt(textOffsetToPosition(tester, 0));
await tester.pumpAndSettle();
expect(state.showSpellCheckSuggestionsToolbar(), isTrue);
await tester.pumpAndSettle();
expect(find.text('test'), findsOneWidget);
// Replacing a word of the same length as the replacement puts the cursor
// at the end of the new word.
await tester.tap(find.text('test'));
await tester.pumpAndSettle();
expect(
controller.value,
equals(const TextEditingValue(
text: 'test tst testt',
selection: TextSelection.collapsed(
offset: 4,
),
)),
);
state.spellCheckResults = SpellCheckResults(
controller.value.text,
const <SuggestionSpan>[
SuggestionSpan(TextRange(start: 5, end: 8), <String>['test']),
SuggestionSpan(TextRange(start: 9, end: 13), <String>['test']),
]);
await tester.tapAt(textOffsetToPosition(tester, 5));
await tester.pumpAndSettle();
expect(state.showSpellCheckSuggestionsToolbar(), isTrue);
await tester.pumpAndSettle();
expect(find.text('test'), findsOneWidget);
// Replacing a word of less length as the replacement puts the cursor at
// the end of the new word.
await tester.tap(find.text('test'));
await tester.pumpAndSettle();
expect(
controller.value,
equals(const TextEditingValue(
text: 'test test testt',
selection: TextSelection.collapsed(
offset: 9,
),
)),
);
state.spellCheckResults = SpellCheckResults(
controller.value.text,
const <SuggestionSpan>[
SuggestionSpan(TextRange(start: 10, end: 15), <String>['test']),
]);
await tester.tapAt(textOffsetToPosition(tester, 10));
await tester.pumpAndSettle();
expect(state.showSpellCheckSuggestionsToolbar(), isTrue);
await tester.pumpAndSettle();
expect(find.text('test'), findsOneWidget);
// Replacing a word of greater length as the replacement puts the cursor
// at the end of the new word.
await tester.tap(find.text('test'));
await tester.pumpAndSettle();
expect(
controller.value,
equals(const TextEditingValue(
text: 'test test test',
selection: TextSelection.collapsed(
offset: 14,
),
)),
);
},
variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS, TargetPlatform.android }),
skip: kIsWeb, // [intended]
);
}); });
group('magnifier', () { group('magnifier', () {
......
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