Unverified Commit 212d0a64 authored by LongCatIsLooong's avatar LongCatIsLooong Committed by GitHub

Allow selection in composing region (#140516)

Fixes https://github.com/flutter/flutter/issues/68547 for macOS. Needs https://github.com/flutter/engine/pull/49314
parent 9775877d
...@@ -218,9 +218,9 @@ class TextEditingController extends ValueNotifier<TextEditingValue> { ...@@ -218,9 +218,9 @@ class TextEditingController extends ValueNotifier<TextEditingValue> {
/// actions, not during the build, layout, or paint phases. /// actions, not during the build, layout, or paint phases.
/// ///
/// This property can be set from a listener added to this /// This property can be set from a listener added to this
/// [TextEditingController]; however, one should not also set [selection] /// [TextEditingController]; **however, one should not also set [selection]
/// in a separate statement. To change both the [text] and the [selection] /// in a separate statement. To change both the [text] and the [selection]
/// change the controller's [value]. /// change the controller's [value].**
set text(String newText) { set text(String newText) {
value = value.copyWith( value = value.copyWith(
text: newText, text: newText,
...@@ -285,16 +285,13 @@ class TextEditingController extends ValueNotifier<TextEditingValue> { ...@@ -285,16 +285,13 @@ class TextEditingController extends ValueNotifier<TextEditingValue> {
/// in a separate statement. To change both the [text] and the [selection] /// in a separate statement. To change both the [text] and the [selection]
/// change the controller's [value]. /// change the controller's [value].
/// ///
/// If the new selection is of non-zero length, or is outside the composing /// If the new selection is outside the composing range, the composing range is
/// range, the composing range is cleared. /// cleared.
set selection(TextSelection newSelection) { set selection(TextSelection newSelection) {
if (!isSelectionWithinTextBounds(newSelection)) { if (!_isSelectionWithinTextBounds(newSelection)) {
throw FlutterError('invalid text selection: $newSelection'); throw FlutterError('invalid text selection: $newSelection');
} }
final TextRange newComposing = final TextRange newComposing = _isSelectionWithinComposingRange(newSelection) ? value.composing : TextRange.empty;
newSelection.isCollapsed && _isSelectionWithinComposingRange(newSelection)
? value.composing
: TextRange.empty;
value = value.copyWith(selection: newSelection, composing: newComposing); value = value.copyWith(selection: newSelection, composing: newComposing);
} }
...@@ -326,7 +323,7 @@ class TextEditingController extends ValueNotifier<TextEditingValue> { ...@@ -326,7 +323,7 @@ class TextEditingController extends ValueNotifier<TextEditingValue> {
} }
/// Check that the [selection] is inside of the bounds of [text]. /// Check that the [selection] is inside of the bounds of [text].
bool isSelectionWithinTextBounds(TextSelection selection) { bool _isSelectionWithinTextBounds(TextSelection selection) {
return selection.start <= text.length && selection.end <= text.length; return selection.start <= text.length && selection.end <= text.length;
} }
...@@ -3650,7 +3647,7 @@ class EditableTextState extends State<EditableText> with AutomaticKeepAliveClien ...@@ -3650,7 +3647,7 @@ class EditableTextState extends State<EditableText> with AutomaticKeepAliveClien
// We return early if the selection is not valid. This can happen when the // We return early if the selection is not valid. This can happen when the
// text of [EditableText] is updated at the same time as the selection is // text of [EditableText] is updated at the same time as the selection is
// changed by a gesture event. // changed by a gesture event.
if (!widget.controller.isSelectionWithinTextBounds(selection)) { if (!widget.controller._isSelectionWithinTextBounds(selection)) {
return; return;
} }
......
...@@ -11185,14 +11185,15 @@ void main() { ...@@ -11185,14 +11185,15 @@ void main() {
)); ));
expect(state.currentTextEditingValue.composing, const TextRange(start: 4, end: 12)); expect(state.currentTextEditingValue.composing, const TextRange(start: 4, end: 12));
// Setting a selection within the composing range clears the composing range. // Setting a selection within the composing range doesn't clear the composing range.
state.updateEditingValue(const TextEditingValue( state.updateEditingValue(const TextEditingValue(
text: 'foo composing bar', text: 'foo composing bar',
selection: TextSelection.collapsed(offset: 4), selection: TextSelection.collapsed(offset: 4),
composing: TextRange(start: 4, end: 12), composing: TextRange(start: 4, end: 12),
)); ));
controller.selection = const TextSelection(baseOffset: 5, extentOffset: 7); controller.selection = const TextSelection(baseOffset: 5, extentOffset: 7);
expect(state.currentTextEditingValue.composing, TextRange.empty); expect(state.currentTextEditingValue.composing, const TextRange(start: 4, end: 12));
expect(state.currentTextEditingValue.selection, const TextSelection(baseOffset: 5, extentOffset: 7));
// Reset the composing range. // Reset the composing range.
state.updateEditingValue(const TextEditingValue( state.updateEditingValue(const TextEditingValue(
......
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