ChecklistEditor: Improve focus handling

It's still a bit of a mess. I seem to be hitting this bug -
https://github.com/flutter/flutter/issues/20706 which others are also
hitting, but it seems to be closed despite a clearly reproduce test
case.
This commit is contained in:
Vishesh Handa
2020-05-02 02:28:30 +02:00
parent 441202af48
commit 793660e42f
2 changed files with 43 additions and 13 deletions

View File

@ -158,6 +158,7 @@ class Checklist {
var prevItem = items.last;
item.lineNo = prevItem.lineNo + 1;
items.add(item);
_lines.insert(item.lineNo, item.toString());
}
@ -183,6 +184,7 @@ class Checklist {
if (index == items.length) {
var prevItem = items.last;
item.lineNo = prevItem.lineNo + 1;
items.add(item);
_lines.insert(item.lineNo, item.toString());
return;
}

View File

@ -49,7 +49,9 @@ class ChecklistEditor extends StatefulWidget implements Editor {
class ChecklistEditorState extends State<ChecklistEditor>
implements EditorState {
Checklist checklist;
var focusNodes = <ChecklistItem, FocusScopeNode>{};
var focusNodes = <UniqueKey, FocusScopeNode>{};
var keys = <UniqueKey, ChecklistItem>{};
TextEditingController _titleTextController = TextEditingController();
bool _noteModified;
@ -67,9 +69,8 @@ class ChecklistEditorState extends State<ChecklistEditor>
var item = checklist.buildItem(false, "");
checklist.addItem(item);
}
for (var item in checklist.items) {
focusNodes[item] = FocusScopeNode();
keys[UniqueKey()] = item;
}
}
@ -79,6 +80,29 @@ class ChecklistEditorState extends State<ChecklistEditor>
super.dispose();
}
UniqueKey _getKey(ChecklistItem item) {
for (var e in keys.entries) {
if (e.value == item) {
return e.key;
}
}
var key = UniqueKey();
keys[key] = item;
return key;
}
FocusScopeNode _getFn(ChecklistItem item) {
var key = _getKey(item);
var fn = focusNodes[key];
if (fn == null) {
fn = FocusScopeNode();
focusNodes[key] = fn;
}
return fn;
}
@override
Widget build(BuildContext context) {
var itemTiles = <Widget>[];
@ -92,13 +116,14 @@ class ChecklistEditorState extends State<ChecklistEditor>
onPressed: () {
_noteTextChanged();
setState(() {
var fn = FocusScopeNode();
var item = checklist.buildItem(false, "");
var fn = _getFn(item);
checklist.addItem(item);
focusNodes[item] = fn;
// FIXME: Make this happen on the next build
Timer(const Duration(milliseconds: 50), () {
FocusScope.of(context).requestFocus();
FocusScope.of(context).requestFocus(fn);
});
});
@ -156,7 +181,7 @@ class ChecklistEditorState extends State<ChecklistEditor>
return ChecklistItemTile(
key: UniqueKey(),
item: item,
focusNode: focusNodes[item],
focusNode: _getFn(item),
isNewNote: autofocus,
statusChanged: (bool newVal) {
setState(() {
@ -181,16 +206,19 @@ class ChecklistEditorState extends State<ChecklistEditor>
FocusNode fn;
if (nextIndex >= 0) {
var nextItemForFocus = checklist.items[nextIndex];
fn = focusNodes[nextItemForFocus];
fn = _getFn(nextItemForFocus);
print("Giving focus to $nextItemForFocus");
}
focusNodes.remove(item);
var k = _getKey(item);
focusNodes.remove(k);
keys.remove(k);
checklist.removeItem(item);
// FIXME: Make this happen on the next build
Timer(const Duration(milliseconds: 300), () {
Timer(const Duration(milliseconds: 200), () {
if (fn != null) {
FocusScope.of(context).requestFocus();
FocusScope.of(context).requestFocus(fn);
}
});
@ -199,14 +227,14 @@ class ChecklistEditorState extends State<ChecklistEditor>
itemFinished: () {
_noteTextChanged();
setState(() {
var fn = FocusScopeNode();
var item = checklist.buildItem(false, "");
var fn = _getFn(item);
checklist.insertItem(index + 1, item);
focusNodes[item] = fn;
// FIXME: Make this happen on the next build
Timer(const Duration(milliseconds: 50), () {
print("Asking focus to ${index + 1}");
FocusScope.of(context).requestFocus();
FocusScope.of(context).requestFocus(fn);
});
});
@ -252,6 +280,7 @@ class _ChecklistItemTileState extends State<ChecklistItemTile> {
_textController.addListener(() {
widget.textChanged(_textController.value.text);
});
assert(widget.focusNode != null);
widget.focusNode.addListener(_onFocus);
}
@ -264,8 +293,7 @@ class _ChecklistItemTileState extends State<ChecklistItemTile> {
}
void _onFocus() {
setState(() {}); // rebuild to hide close button
SystemChannels.textInput.invokeMethod('TextInput.show');
setState(() {}); // rebuild to show/hide close button
}
@override