Commit 470db7d9 authored by Adam Barth's avatar Adam Barth Committed by GitHub

TextField should update IME when controller changes (#9261)

Fixes #9246
parent 249bbac3
......@@ -239,9 +239,8 @@ class EditableTextState extends State<EditableText> implements TextInputClient {
if (config.controller != oldConfig.controller) {
oldConfig.controller.removeListener(_didChangeTextEditingValue);
config.controller.addListener(_didChangeTextEditingValue);
if (_hasInputConnection && config.controller.value != oldConfig.controller.value)
_textInputConnection.setEditingState(config.controller.value);
}
_updateRemoteEditingValueIfNeeded();
}
if (config.focusNode != oldConfig.focusNode) {
oldConfig.focusNode.removeListener(_handleFocusChanged);
config.focusNode.addListener(_handleFocusChanged);
......@@ -263,10 +262,13 @@ class EditableTextState extends State<EditableText> implements TextInputClient {
// TextInputClient implementation:
TextEditingValue _lastKnownRemoteTextEditingValue;
@override
void updateEditingValue(TextEditingValue value) {
if (value.text != _value.text)
_hideSelectionOverlayIfNeeded();
_lastKnownRemoteTextEditingValue = value;
_value = value;
if (config.onChanged != null)
config.onChanged(value.text);
......@@ -280,6 +282,16 @@ class EditableTextState extends State<EditableText> implements TextInputClient {
config.onSubmitted(_value.text);
}
void _updateRemoteEditingValueIfNeeded() {
if (!_hasInputConnection)
return;
final TextEditingValue localValue = _value;
if (localValue == _lastKnownRemoteTextEditingValue)
return;
_lastKnownRemoteTextEditingValue = localValue;
_textInputConnection.setEditingState(localValue);
}
TextEditingValue get _value => config.controller.value;
set _value(TextEditingValue value) {
config.controller.value = value;
......@@ -306,8 +318,10 @@ class EditableTextState extends State<EditableText> implements TextInputClient {
void _openInputConnectionIfNeeded() {
if (!_hasInputConnection) {
final TextEditingValue localValue = _value;
_lastKnownRemoteTextEditingValue = localValue;
_textInputConnection = TextInput.attach(this, new TextInputConfiguration(inputType: config.keyboardType))
..setEditingState(_value)
..setEditingState(localValue)
..show();
}
}
......@@ -316,6 +330,7 @@ class EditableTextState extends State<EditableText> implements TextInputClient {
if (_hasInputConnection) {
_textInputConnection.close();
_textInputConnection = null;
_lastKnownRemoteTextEditingValue = null;
}
}
......@@ -429,6 +444,7 @@ class EditableTextState extends State<EditableText> implements TextInputClient {
}
void _didChangeTextEditingValue() {
_updateRemoteEditingValueIfNeeded();
_startOrStopCursorTimerIfNeeded();
_updateOrDisposeSelectionOverlayIfNeeded();
// TODO(abarth): Teach RenderEditable about ValueNotifier<TextEditingValue>
......
......@@ -886,4 +886,59 @@ void main() {
expect(topLeft.x, equals(399.0));
});
testWidgets('Controller can update server', (WidgetTester tester) async {
final TextEditingController controller = new TextEditingController(
text: 'Initial Text',
);
final TextEditingController controller2 = new TextEditingController(
text: 'More Text',
);
TextEditingController currentController = controller;
StateSetter setState;
await tester.pumpWidget(
overlay(new Center(
child: new Material(
child: new StatefulBuilder(
builder: (BuildContext context, StateSetter setter) {
setState = setter;
return new TextField(controller: currentController);
}
),
),
),
));
expect(tester.testTextInput.editingState['text'], isEmpty);
await tester.tap(find.byType(TextField));
await tester.pump();
expect(tester.testTextInput.editingState['text'], equals('Initial Text'));
controller.text = 'Updated Text';
await tester.idle();
expect(tester.testTextInput.editingState['text'], equals('Updated Text'));
setState(() {
currentController = controller2;
});
await tester.pump();
expect(tester.testTextInput.editingState['text'], equals('More Text'));
controller.text = 'Ignored Text';
await tester.idle();
expect(tester.testTextInput.editingState['text'], equals('More Text'));
controller2.text = 'Final Text';
await tester.idle();
expect(tester.testTextInput.editingState['text'], equals('Final Text'));
});
}
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