Editors: Do not use BottomAppBar in the scaffold property

The BottomAppBar when given in the Scaffold gets hidden when the
keyboard is visible. We had hacked around that by translating its
position, however that resulted in the cursor at the bottom being hidden
when we were typing a long note.

It is not just part of the body of the scaffold.

Also converted many functions into widgets.
This commit is contained in:
Vishesh Handa
2020-05-06 15:14:41 +02:00
parent 81eb605e98
commit 62b5761ec4
5 changed files with 190 additions and 132 deletions

View File

@ -152,18 +152,17 @@ class ChecklistEditorState extends State<ChecklistEditor>
child: NoteTitleEditor(_titleTextController, _noteTextChanged), child: NoteTitleEditor(_titleTextController, _noteTextChanged),
); );
return Scaffold( return EditorScaffold(
appBar: buildEditorAppBar(widget, this, noteModified: _noteModified), editor: widget,
editorState: this,
noteModified: _noteModified,
parentFolder: widget.note.parent,
body: Column( body: Column(
children: <Widget>[ children: <Widget>[
if (widget.note.canHaveMetadata) titleEditor, if (widget.note.canHaveMetadata) titleEditor,
Expanded(child: FocusScope(child: checklistWidget)), Expanded(child: FocusScope(child: checklistWidget)),
], ],
), ),
bottomNavigationBar: Builder(
builder: (context) =>
buildEditorBottonBar(context, widget, this, widget.note.parent),
),
); );
} }

View File

@ -26,104 +26,134 @@ abstract class EditorState {
enum DropDownChoices { Rename, DiscardChanges, Share } enum DropDownChoices { Rename, DiscardChanges, Share }
AppBar buildEditorAppBar( class EditorAppBar extends StatelessWidget implements PreferredSizeWidget {
Editor editor, final Editor editor;
EditorState editorState, { final EditorState editorState;
@required bool noteModified, final bool noteModified;
List<IconButton> extraButtons, final IconButton extraButton;
}) {
return AppBar(
leading: IconButton(
key: const ValueKey("NewEntry"),
icon: Icon(noteModified ? Icons.check : Icons.close),
onPressed: () {
editor.exitEditorSelected(editorState.getNote());
},
),
actions: <Widget>[
...?extraButtons,
IconButton(
key: const ValueKey("EditorSelector"),
icon: const Icon(Icons.library_books),
onPressed: () {
var note = editorState.getNote();
editor.noteEditorChooserSelected(note);
},
),
IconButton(
icon: const Icon(Icons.delete),
onPressed: () {
var note = editorState.getNote();
editor.noteDeletionSelected(note);
},
),
PopupMenuButton<DropDownChoices>(
onSelected: (DropDownChoices choice) {
switch (choice) {
case DropDownChoices.Rename:
var note = editorState.getNote();
editor.renameNoteSelected(note);
return;
case DropDownChoices.DiscardChanges: EditorAppBar({
var note = editorState.getNote(); Key key,
editor.discardChangesSelected(note); @required this.editor,
return; @required this.editorState,
@required this.noteModified,
this.extraButton,
}) : preferredSize = Size.fromHeight(kToolbarHeight),
super(key: key);
case DropDownChoices.Share: @override
var note = editorState.getNote(); final Size preferredSize;
Share.share(note.body);
return; @override
} Widget build(BuildContext context) {
return AppBar(
leading: IconButton(
key: const ValueKey("NewEntry"),
icon: Icon(noteModified ? Icons.check : Icons.close),
onPressed: () {
editor.exitEditorSelected(editorState.getNote());
}, },
itemBuilder: (BuildContext context) =>
<PopupMenuEntry<DropDownChoices>>[
const PopupMenuItem<DropDownChoices>(
value: DropDownChoices.Rename,
child: Text('Edit File Name'),
),
const PopupMenuItem<DropDownChoices>(
value: DropDownChoices.DiscardChanges,
child: Text('Discard Changes'),
),
const PopupMenuItem<DropDownChoices>(
value: DropDownChoices.Share,
child: Text('Share Note'),
),
],
), ),
], actions: <Widget>[
); if (extraButton != null) extraButton,
IconButton(
key: const ValueKey("EditorSelector"),
icon: const Icon(Icons.library_books),
onPressed: () {
var note = editorState.getNote();
editor.noteEditorChooserSelected(note);
},
),
IconButton(
icon: const Icon(Icons.delete),
onPressed: () {
var note = editorState.getNote();
editor.noteDeletionSelected(note);
},
),
PopupMenuButton<DropDownChoices>(
onSelected: (DropDownChoices choice) {
switch (choice) {
case DropDownChoices.Rename:
var note = editorState.getNote();
editor.renameNoteSelected(note);
return;
case DropDownChoices.DiscardChanges:
var note = editorState.getNote();
editor.discardChangesSelected(note);
return;
case DropDownChoices.Share:
var note = editorState.getNote();
Share.share(note.body);
return;
}
},
itemBuilder: (BuildContext context) =>
<PopupMenuEntry<DropDownChoices>>[
const PopupMenuItem<DropDownChoices>(
value: DropDownChoices.Rename,
child: Text('Edit File Name'),
),
const PopupMenuItem<DropDownChoices>(
value: DropDownChoices.DiscardChanges,
child: Text('Discard Changes'),
),
const PopupMenuItem<DropDownChoices>(
value: DropDownChoices.Share,
child: Text('Share Note'),
),
],
),
],
);
}
} }
Widget buildEditorBottonBar( class EditorBottomBar extends StatelessWidget {
BuildContext context, final Editor editor;
Editor editor, final EditorState editorState;
EditorState editorState, final NotesFolderFS parentFolder;
NotesFolderFS parentFolder, final bool allowEdits;
) {
var folderName = parentFolder.pathSpec();
if (folderName.isEmpty) {
folderName = "Root Folder";
}
var s = Scaffold.of(context); EditorBottomBar({
print("s $s"); @required this.editor,
return StickyBottomAppBar( @required this.editorState,
child: BottomAppBar( @required this.parentFolder,
@required this.allowEdits,
});
@override
Widget build(BuildContext context) {
var folderName = parentFolder.pathSpec();
if (folderName.isEmpty) {
folderName = "Root Folder";
}
var addIcon = IconButton(
icon: Icon(Icons.add),
onPressed: () {
showModalBottomSheet(
context: context,
builder: (c) => _buildAddBottomSheet(c, editor, editorState),
elevation: 0,
);
},
);
return BottomAppBar(
elevation: 0.0, elevation: 0.0,
color: Theme.of(context).scaffoldBackgroundColor, color: Theme.of(context).scaffoldBackgroundColor,
child: Row( child: Row(
children: <Widget>[ children: <Widget>[
IconButton( Visibility(
icon: Icon(Icons.add), child: addIcon,
onPressed: () { visible: allowEdits,
showModalBottomSheet( maintainSize: true,
context: context, maintainAnimation: true,
builder: (c) => _buildAddBottomSheet(c, editor, editorState), maintainState: true,
elevation: 0, maintainInteractivity: false,
);
},
), ),
Expanded( Expanded(
child: FlatButton.icon( child: FlatButton.icon(
@ -135,26 +165,18 @@ Widget buildEditorBottonBar(
}, },
), ),
), ),
const SizedBox( // Just so there is equal padding on the right side
height: 32.0, Visibility(
width: 32.0, child: addIcon,
visible: false,
maintainSize: true,
maintainAnimation: true,
maintainState: true,
maintainInteractivity: false,
), ),
], ],
mainAxisAlignment: MainAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center,
), ),
),
);
}
class StickyBottomAppBar extends StatelessWidget {
final BottomAppBar child;
StickyBottomAppBar({@required this.child});
@override
Widget build(BuildContext context) {
return Transform.translate(
offset: Offset(0.0, -1 * MediaQuery.of(context).viewInsets.bottom),
child: child,
); );
} }
} }
@ -208,3 +230,46 @@ Widget _buildAddBottomSheet(
), ),
); );
} }
class EditorScaffold extends StatelessWidget {
final Editor editor;
final EditorState editorState;
final bool noteModified;
final IconButton extraButton;
final Widget body;
final NotesFolderFS parentFolder;
final bool allowEdits;
EditorScaffold({
@required this.editor,
@required this.editorState,
@required this.noteModified,
@required this.body,
@required this.parentFolder,
this.extraButton,
this.allowEdits = true,
});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: EditorAppBar(
editor: editor,
editorState: editorState,
noteModified: noteModified,
extraButton: extraButton,
),
body: Column(
children: <Widget>[
Expanded(child: body),
EditorBottomBar(
editor: editor,
editorState: editorState,
parentFolder: parentFolder,
allowEdits: allowEdits,
),
],
),
);
}
}

View File

@ -80,13 +80,12 @@ class JournalEditorState extends State<JournalEditor> implements EditorState {
), ),
); );
return Scaffold( return EditorScaffold(
appBar: buildEditorAppBar(widget, this, noteModified: _noteModified), editor: widget,
editorState: this,
noteModified: _noteModified,
parentFolder: note.parent,
body: editor, body: editor,
bottomNavigationBar: Builder(
builder: (context) =>
buildEditorBottonBar(context, widget, this, note.parent),
),
); );
} }

View File

@ -106,18 +106,14 @@ class MarkdownEditorState extends State<MarkdownEditor> implements EditorState {
onPressed: _switchMode, onPressed: _switchMode,
); );
return Scaffold( return EditorScaffold(
appBar: buildEditorAppBar( editor: widget,
widget, editorState: this,
this, extraButton: extraButton,
noteModified: _noteModified, noteModified: _noteModified,
extraButtons: [extraButton], parentFolder: note.parent,
), allowEdits: editingMode,
body: body, body: body,
bottomNavigationBar: Builder(
builder: (context) =>
buildEditorBottonBar(context, widget, this, note.parent),
),
); );
} }

View File

@ -77,13 +77,12 @@ class RawEditorState extends State<RawEditor> implements EditorState {
), ),
); );
return Scaffold( return EditorScaffold(
appBar: buildEditorAppBar(widget, this, noteModified: _noteModified), editor: widget,
editorState: this,
noteModified: _noteModified,
parentFolder: note.parent,
body: editor, body: editor,
bottomNavigationBar: Builder(
builder: (context) =>
buildEditorBottonBar(context, widget, this, note.parent),
),
); );
} }