Skip to content

Commit

Permalink
[SuperTextField] Fix setState called during build phase (Resolves #1980
Browse files Browse the repository at this point in the history
…) (#1981)
  • Loading branch information
angelosilvestre authored and web-flow committed May 6, 2024
1 parent 68dada6 commit 570385f
Show file tree
Hide file tree
Showing 2 changed files with 70 additions and 54 deletions.
62 changes: 35 additions & 27 deletions super_editor/lib/src/super_textfield/android/android_textfield.dart
Original file line number Diff line number Diff line change
Expand Up @@ -382,36 +382,44 @@ class SuperAndroidTextFieldState extends State<SuperAndroidTextField>
bool get _isMultiline => (widget.minLines ?? 1) != 1 || widget.maxLines != 1;

void _updateSelectionAndImeConnectionOnFocusChange() {
if (_focusNode.hasFocus) {
if (!_textEditingController.isAttachedToIme) {
_log.info('Attaching TextInputClient to TextInput');
// The focus change callback might be invoked in the build phase, usually when used inside
// an OverlayPortal. If that's the case, defer the setState call until the end of the frame.
WidgetsBinding.instance.runAsSoonAsPossible(() {
if (!mounted) {
return;
}

if (_focusNode.hasFocus) {
if (!_textEditingController.isAttachedToIme) {
_log.info('Attaching TextInputClient to TextInput');
setState(() {
if (!_textEditingController.selection.isValid) {
_textEditingController.selection = TextSelection.collapsed(offset: _textEditingController.text.length);
}

if (widget.imeConfiguration != null) {
_textEditingController.attachToImeWithConfig(widget.imeConfiguration!);
} else {
_textEditingController.attachToIme(
textInputAction: widget.textInputAction ?? TextInputAction.done,
textInputType: _isMultiline ? TextInputType.multiline : TextInputType.text,
);
}

_autoScrollToKeepTextFieldVisible();
_showEditingControlsOverlay();
});
}
} else {
_log.info('Lost focus. Detaching TextInputClient from TextInput.');
setState(() {
if (!_textEditingController.selection.isValid) {
_textEditingController.selection = TextSelection.collapsed(offset: _textEditingController.text.length);
}

if (widget.imeConfiguration != null) {
_textEditingController.attachToImeWithConfig(widget.imeConfiguration!);
} else {
_textEditingController.attachToIme(
textInputAction: widget.textInputAction ?? TextInputAction.done,
textInputType: _isMultiline ? TextInputType.multiline : TextInputType.text,
);
}

_autoScrollToKeepTextFieldVisible();
_showEditingControlsOverlay();
_textEditingController.detachFromIme();
_textEditingController.selection = const TextSelection.collapsed(offset: -1);
_textEditingController.composingRegion = TextRange.empty;
_removeEditingOverlayControls();
});
}
} else {
_log.info('Lost focus. Detaching TextInputClient from TextInput.');
setState(() {
_textEditingController.detachFromIme();
_textEditingController.selection = const TextSelection.collapsed(offset: -1);
_textEditingController.composingRegion = TextRange.empty;
_removeEditingOverlayControls();
});
}
});
}

void _onTextOrSelectionChange() {
Expand Down
62 changes: 35 additions & 27 deletions super_editor/lib/src/super_textfield/ios/ios_textfield.dart
Original file line number Diff line number Diff line change
Expand Up @@ -399,36 +399,44 @@ class SuperIOSTextFieldState extends State<SuperIOSTextField>
DeltaTextInputClient get imeClient => _textEditingController;

void _updateSelectionAndImeConnectionOnFocusChange() {
if (_focusNode.hasFocus) {
if (!_textEditingController.isAttachedToIme) {
_log.info('Attaching TextInputClient to TextInput');
// The focus change callback might be invoked in the build phase, usually when used inside
// an OverlayPortal. If that's the case, defer the setState call until the end of the frame.
WidgetsBinding.instance.runAsSoonAsPossible(() {
if (!mounted) {
return;
}

if (_focusNode.hasFocus) {
if (!_textEditingController.isAttachedToIme) {
_log.info('Attaching TextInputClient to TextInput');
setState(() {
if (!_textEditingController.selection.isValid) {
_textEditingController.selection = TextSelection.collapsed(offset: _textEditingController.text.length);
}

if (widget.imeConfiguration != null) {
_textEditingController.attachToImeWithConfig(widget.imeConfiguration!);
} else {
_textEditingController.attachToIme(
textInputAction: widget.textInputAction ?? TextInputAction.done,
textInputType: _isMultiline ? TextInputType.multiline : TextInputType.text,
);
}

_autoScrollToKeepTextFieldVisible();
_showHandles();
});
}
} else {
_log.info('Lost focus. Detaching TextInputClient from TextInput.');
setState(() {
if (!_textEditingController.selection.isValid) {
_textEditingController.selection = TextSelection.collapsed(offset: _textEditingController.text.length);
}

if (widget.imeConfiguration != null) {
_textEditingController.attachToImeWithConfig(widget.imeConfiguration!);
} else {
_textEditingController.attachToIme(
textInputAction: widget.textInputAction ?? TextInputAction.done,
textInputType: _isMultiline ? TextInputType.multiline : TextInputType.text,
);
}

_autoScrollToKeepTextFieldVisible();
_showHandles();
_textEditingController.detachFromIme();
_textEditingController.selection = const TextSelection.collapsed(offset: -1);
_textEditingController.composingRegion = TextRange.empty;
_removeEditingOverlayControls();
});
}
} else {
_log.info('Lost focus. Detaching TextInputClient from TextInput.');
setState(() {
_textEditingController.detachFromIme();
_textEditingController.selection = const TextSelection.collapsed(offset: -1);
_textEditingController.composingRegion = TextRange.empty;
_removeEditingOverlayControls();
});
}
});
}

void _onTextOrSelectionChange() {
Expand Down

0 comments on commit 570385f

Please sign in to comment.