Skip to content

Commit

Permalink
[SuperEditor] - Fix: When navigating from screen with keyboard open t…
Browse files Browse the repository at this point in the history
…o screen with no IME connection, KeyboardScaffoldSafeArea pushes the content up above the keyboard even though its closed. (Resolves #2419) (#2421)
  • Loading branch information
matthew-carroll authored and web-flow committed Nov 27, 2024
1 parent 8ba09ff commit 9c76c1e
Show file tree
Hide file tree
Showing 3 changed files with 243 additions and 28 deletions.
37 changes: 33 additions & 4 deletions super_editor/example/lib/main_super_editor_chat.dart
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,39 @@ void main() {

runApp(
MaterialApp(
home: Scaffold(
resizeToAvoidBottomInset: false,
body: MobileChatDemo(),
),
routes: {
"/": (context) => Scaffold(
appBar: AppBar(
actions: [
IconButton(
onPressed: () {
Navigator.of(context).pushNamed("/second");
},
icon: Icon(Icons.settings),
),
],
),
resizeToAvoidBottomInset: false,
body: MobileChatDemo(),
),
// We include a 2nd screen with navigation so that we can verify
// what happens to the keyboard safe area when navigating from an
// open editor to another screen with a safe area, but no keyboard
// scaffold. See issue #2419
"/second": (context) => Scaffold(
appBar: AppBar(),
resizeToAvoidBottomInset: false,
body: KeyboardScaffoldSafeArea(
child: ListView.builder(
itemBuilder: (context, index) {
return ListTile(
title: Text("Item $index"),
);
},
),
),
),
},
debugShowCheckedModeBanner: false,
),
);
Expand Down
44 changes: 39 additions & 5 deletions super_editor/lib/src/infrastructure/keyboard_panel_scaffold.dart
Original file line number Diff line number Diff line change
Expand Up @@ -707,6 +707,7 @@ class _KeyboardScaffoldSafeAreaState extends State<KeyboardScaffoldSafeArea>
KeyboardSafeAreaGeometry? _keyboardSafeAreaData;

KeyboardScaffoldSafeAreaMutator? _ancestorSafeArea;
bool _isSafeAreaFromMediaQuery = false;

@override
void didChangeDependencies() {
Expand All @@ -723,21 +724,54 @@ class _KeyboardScaffoldSafeAreaState extends State<KeyboardScaffoldSafeArea>
// of the editor, not a direct ancestor or descendant. So we need to be able to coordinate
// the safe area across independent trees by sharing an ancestor.
//
// If there's no existing ancestor KeyboardScaffoldSafeArea, then defer to whatever
// Example:
// KeyboardScaffoldSafeArea
// |- Stack
// |- KeyboardScaffoldSafeArea
// |- Content
// |- SuperEditor
//
// Second, if there's no existing ancestor KeyboardScaffoldSafeArea, then defer to whatever
// MediaQuery reports. We only do this for the very first frame because we don't yet
// know what our values should be (because that's reported by descendants in the tree).
_ancestorSafeArea = KeyboardScaffoldSafeArea.maybeOf(context);
_keyboardSafeAreaData ??= KeyboardSafeAreaGeometry(
bottomInsets: _ancestorSafeArea?.geometry.bottomInsets ?? MediaQuery.viewInsetsOf(context).bottom,
bottomPadding: _ancestorSafeArea?.geometry.bottomPadding ?? MediaQuery.paddingOf(context).bottom,
);

if (_keyboardSafeAreaData == null) {
// This is the first call to didChangeDependencies. Initialize our safe area.
_keyboardSafeAreaData = KeyboardSafeAreaGeometry(
bottomInsets: _ancestorSafeArea?.geometry.bottomInsets ?? MediaQuery.viewInsetsOf(context).bottom,
bottomPadding: _ancestorSafeArea?.geometry.bottomPadding ?? MediaQuery.paddingOf(context).bottom,
);

// We track whether our safe area is from MediaQuery (instead of an another KeyboardSafeAreaGeometry).
// We do this in case the MediaQuery value changes when we don't have any descendant
// KeyboardPanelScaffold.
//
// For example, you're on Screen 1 with the keyboard up. You navigate to Screen 2, which closes the keyboard. When
// Screen 2 first pumps, it sees that the keyboard is up, so it configures a keyboard safe area. But the keyboard
// immediately closes. Screen 2 is then stuck with a keyboard safe area that never goes away.
//
// By tracking when our safe area comes from MediaQuery, we can continue to honor changing
// MediaQuery values until a descendant explicitly sets our `geometry`.
_isSafeAreaFromMediaQuery = _ancestorSafeArea == null;
}

if (_isSafeAreaFromMediaQuery) {
// Our current safe area came from MediaQuery, not a descendant. Therefore,
// we want to continue blindly honoring the MediaQuery.
_keyboardSafeAreaData = KeyboardSafeAreaGeometry(
bottomInsets: MediaQuery.viewInsetsOf(context).bottom,
bottomPadding: MediaQuery.paddingOf(context).bottom,
);
}
}

@override
KeyboardSafeAreaGeometry get geometry => _keyboardSafeAreaData!;

@override
set geometry(KeyboardSafeAreaGeometry geometry) {
_isSafeAreaFromMediaQuery = false;
if (geometry == _keyboardSafeAreaData) {
return;
}
Expand Down
Loading

0 comments on commit 9c76c1e

Please sign in to comment.