Skip to content

[SuperEditor][IME] - Make IME connection global to avoid losing it on rebuilds #2807

@matthew-carroll

Description

@matthew-carroll

SuperEditor internally contains a widget called SuperEditorImeInteractor. This interactor holds the current IME connection in a State property:

final _imeConnection = ValueNotifier<TextInputConnection?>(null);

As a result, if this part of the widget tree is recreated, we lose the existing text input connection and then create a new one.

Why would this widget be recreated?
Any ancestor widget that's added or removed in the tree will result in a full subtree recreation, including this widget.

Can we avoid subtree recreation?
Carefully placed GlobalKeys can prevent subtree recreation, however, it's not clear where exactly those GlobalKeys need to be placed. It will be easy to get that wrong and end up with unexpected keyboard behaviors. It would be better to interact with the IME in a way that's not susceptible to widget recreation.

Why does recreation matter?
There might be any number of unexpected behaviors, but here's one that's happening for sure:

  1. Deploy a bottom mounted chat experience
  2. Tap the editor to give focus and open the keyboard
  3. Open a panel that replaces the keyboard
  4. In the IDE, add or remove any ancestor widget above the editor and run hot reload
  5. The panel stays open, but the keyboard pops back up, seemingly for no reason, on top of the panel.

The cause of this issue is that the interactor widget with the original IME connection is disposed, at which point it not only loses the IME connection property, but even tells the IME connection to close. The new IME interactor widget that's replacing the old one has an addPostFrameCallback in its initState, which then opens a new IME connection because the SoftwareKeyboardController still exists and it says we want an open IME connection.

How do we solve this?
If we're not going to rely on GlobalKeys to keep the interactor widget around across rebuilds then I see two options:

  1. Require a ValueNotifier<IMEConnection> or a similar controller to be passed into every SuperEditor widget. We can't allow it to be created inside SuperEditor because then we suffer the same fate when SuperEditor is recreated.
  2. Create a global shared IME connection that's never created or destroyed via widget rebuilds. SuperEditor and its internal widgets would need to know when and how to take ownership of this shared connection, including when one SuperEditor is being initialized, to replaced another SuperEditor that's being disposed.

Metadata

Metadata

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions