Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[SuperEditor] - Fix: When navigating from screen with keyboard open to screen with no IME connection, KeyboardScaffoldSafeArea pushes the content up above the keyboard even though its closed. (Resolves #2419) #2421

Merged
merged 2 commits into from
Nov 27, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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 is from MediaQuery (instead of an another KeyboardSafeAreaGeometry).
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"We track whether our safe is" > "We track whether our safe area is" ?

// 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
Loading