Editor: Show ✕ or ✓ in AppBar depending on if the note has been modified

Fixes 
This commit is contained in:
Vishesh Handa
2020-05-01 10:14:18 +02:00
parent 4e593d6c2f
commit 9ee16ebe50
7 changed files with 104 additions and 14 deletions

@ -10,6 +10,7 @@ import 'package:gitjournal/editors/note_title_editor.dart';
class ChecklistEditor extends StatefulWidget implements Editor {
final Note note;
final bool noteModified;
@override
final NoteCallback noteDeletionSelected;
@ -29,6 +30,7 @@ class ChecklistEditor extends StatefulWidget implements Editor {
ChecklistEditor({
Key key,
@required this.note,
@required this.noteModified,
@required this.noteDeletionSelected,
@required this.noteEditorChooserSelected,
@required this.exitEditorSelected,
@ -49,6 +51,7 @@ class ChecklistEditorState extends State<ChecklistEditor>
Checklist checklist;
var focusNodes = <ChecklistItem, FocusScopeNode>{};
TextEditingController _titleTextController = TextEditingController();
bool _noteModified;
ChecklistEditorState(Note note) {
_titleTextController = TextEditingController(text: note.title);
@ -58,6 +61,8 @@ class ChecklistEditorState extends State<ChecklistEditor>
@override
void initState() {
super.initState();
_noteModified = widget.noteModified;
if (checklist.items.isEmpty) {
var item = checklist.buildItem(false, "");
checklist.addItem(item);
@ -85,6 +90,7 @@ class ChecklistEditorState extends State<ChecklistEditor>
itemTiles.add(AddItemButton(
key: UniqueKey(),
onPressed: () {
_noteTextChanged();
setState(() {
var fn = FocusScopeNode();
var item = checklist.buildItem(false, "");
@ -102,6 +108,7 @@ class ChecklistEditorState extends State<ChecklistEditor>
Widget checklistWidget = ReorderableListView(
children: itemTiles,
onReorder: (int oldIndex, int newIndex) {
_noteTextChanged();
setState(() {
var item = checklist.removeAt(oldIndex);
@ -116,11 +123,11 @@ class ChecklistEditorState extends State<ChecklistEditor>
var titleEditor = Padding(
padding: const EdgeInsets.fromLTRB(16.0, 16.0, 16.0, 0.0),
child: NoteTitleEditor(_titleTextController),
child: NoteTitleEditor(_titleTextController, _noteTextChanged),
);
return Scaffold(
appBar: buildEditorAppBar(widget, this),
appBar: buildEditorAppBar(widget, this, noteModified: _noteModified),
body: Column(
children: <Widget>[
if (widget.note.canHaveMetadata) titleEditor,
@ -138,6 +145,13 @@ class ChecklistEditorState extends State<ChecklistEditor>
return note;
}
void _noteTextChanged() {
if (_noteModified) return;
setState(() {
_noteModified = true;
});
}
ChecklistItemTile _buildTile(ChecklistItem item, int index, bool autofocus) {
return ChecklistItemTile(
key: UniqueKey(),
@ -148,11 +162,14 @@ class ChecklistEditorState extends State<ChecklistEditor>
setState(() {
item.checked = newVal;
});
_noteTextChanged();
},
textChanged: (String newVal) {
item.text = newVal;
_noteTextChanged();
},
itemRemoved: () {
_noteTextChanged();
setState(() {
// Give next item the focus
var nextIndex = index + 1;
@ -180,6 +197,7 @@ class ChecklistEditorState extends State<ChecklistEditor>
});
},
itemFinished: () {
_noteTextChanged();
setState(() {
var fn = FocusScopeNode();
var item = checklist.buildItem(false, "");

@ -21,12 +21,13 @@ enum DropDownChoices { Rename, MoveToFolder, DiscardChanges }
AppBar buildEditorAppBar(
Editor editor,
EditorState editorState, {
@required bool noteModified,
List<IconButton> extraButtons,
}) {
return AppBar(
leading: IconButton(
key: const ValueKey("NewEntry"),
icon: const Icon(Icons.check),
icon: Icon(noteModified ? Icons.check : Icons.close),
onPressed: () {
editor.exitEditorSelected(editorState.getNote());
},

@ -6,6 +6,7 @@ import 'package:gitjournal/widgets/journal_editor_header.dart';
class JournalEditor extends StatefulWidget implements Editor {
final Note note;
final bool noteModified;
@override
final NoteCallback noteDeletionSelected;
@ -25,6 +26,7 @@ class JournalEditor extends StatefulWidget implements Editor {
JournalEditor({
Key key,
@required this.note,
@required this.noteModified,
@required this.noteDeletionSelected,
@required this.noteEditorChooserSelected,
@required this.exitEditorSelected,
@ -43,11 +45,18 @@ class JournalEditor extends StatefulWidget implements Editor {
class JournalEditorState extends State<JournalEditor> implements EditorState {
Note note;
TextEditingController _textController = TextEditingController();
bool _noteModified;
JournalEditorState(this.note) {
_textController = TextEditingController(text: note.body);
}
@override
void initState() {
super.initState();
_noteModified = widget.noteModified;
}
@override
void dispose() {
_textController.dispose();
@ -63,8 +72,9 @@ class JournalEditorState extends State<JournalEditor> implements EditorState {
children: <Widget>[
JournalEditorHeader(note),
_NoteBodyEditor(
_textController,
textController: _textController,
autofocus: widget.isNewNote,
onChanged: _noteTextChanged,
),
],
),
@ -72,7 +82,7 @@ class JournalEditorState extends State<JournalEditor> implements EditorState {
);
return Scaffold(
appBar: buildEditorAppBar(widget, this),
appBar: buildEditorAppBar(widget, this, noteModified: _noteModified),
body: editor,
);
}
@ -83,13 +93,21 @@ class JournalEditorState extends State<JournalEditor> implements EditorState {
note.type = NoteType.Journal;
return note;
}
void _noteTextChanged() {
if (_noteModified) return;
setState(() {
_noteModified = true;
});
}
}
class _NoteBodyEditor extends StatelessWidget {
final TextEditingController textController;
final bool autofocus;
final Function onChanged;
_NoteBodyEditor(this.textController, {this.autofocus = false});
_NoteBodyEditor({this.textController, this.autofocus, this.onChanged});
@override
Widget build(BuildContext context) {
@ -108,6 +126,7 @@ class _NoteBodyEditor extends StatelessWidget {
controller: textController,
textCapitalization: TextCapitalization.sentences,
scrollPadding: const EdgeInsets.all(0.0),
onChanged: (_) => onChanged(),
);
}
}

@ -8,6 +8,7 @@ import 'package:gitjournal/widgets/note_viewer.dart';
class MarkdownEditor extends StatefulWidget implements Editor {
final Note note;
final bool noteModified;
@override
final NoteCallback noteDeletionSelected;
@ -27,6 +28,7 @@ class MarkdownEditor extends StatefulWidget implements Editor {
MarkdownEditor({
Key key,
@required this.note,
@required this.noteModified,
@required this.noteDeletionSelected,
@required this.noteEditorChooserSelected,
@required this.exitEditorSelected,
@ -48,6 +50,7 @@ class MarkdownEditorState extends State<MarkdownEditor> implements EditorState {
TextEditingController _titleTextController = TextEditingController();
bool editingMode = true;
bool _noteModified;
MarkdownEditorState(this.note) {
_textController = TextEditingController(text: note.body);
@ -60,6 +63,7 @@ class MarkdownEditorState extends State<MarkdownEditor> implements EditorState {
@override
void initState() {
super.initState();
_noteModified = widget.noteModified;
if (widget.isNewNote) {
editingMode = true;
}
@ -79,10 +83,15 @@ class MarkdownEditorState extends State<MarkdownEditor> implements EditorState {
child: SingleChildScrollView(
child: Column(
children: <Widget>[
if (note.canHaveMetadata) NoteTitleEditor(_titleTextController),
if (note.canHaveMetadata)
NoteTitleEditor(
_titleTextController,
_noteTextChanged,
),
_NoteBodyEditor(
_textController,
textController: _textController,
autofocus: widget.isNewNote,
onChanged: _noteTextChanged,
),
],
),
@ -99,7 +108,12 @@ class MarkdownEditorState extends State<MarkdownEditor> implements EditorState {
);
return Scaffold(
appBar: buildEditorAppBar(widget, this, extraButtons: [extraButton]),
appBar: buildEditorAppBar(
widget,
this,
noteModified: _noteModified,
extraButtons: [extraButton],
),
body: body,
);
}
@ -122,13 +136,25 @@ class MarkdownEditorState extends State<MarkdownEditor> implements EditorState {
_updateNote();
return note;
}
void _noteTextChanged() {
if (_noteModified) return;
setState(() {
_noteModified = true;
});
}
}
class _NoteBodyEditor extends StatelessWidget {
final TextEditingController textController;
final bool autofocus;
final Function onChanged;
_NoteBodyEditor(this.textController, {this.autofocus = false});
_NoteBodyEditor({
@required this.textController,
@required this.autofocus,
@required this.onChanged,
});
@override
Widget build(BuildContext context) {
@ -147,6 +173,7 @@ class _NoteBodyEditor extends StatelessWidget {
controller: textController,
textCapitalization: TextCapitalization.sentences,
scrollPadding: const EdgeInsets.all(0.0),
onChanged: (_) => onChanged(),
);
}
}

@ -2,8 +2,9 @@ import 'package:flutter/material.dart';
class NoteTitleEditor extends StatelessWidget {
final TextEditingController textController;
final Function onChanged;
NoteTitleEditor(this.textController);
NoteTitleEditor(this.textController, this.onChanged);
@override
Widget build(BuildContext context) {
@ -20,6 +21,7 @@ class NoteTitleEditor extends StatelessWidget {
controller: textController,
textCapitalization: TextCapitalization.sentences,
maxLines: null,
onChanged: (_) => onChanged(),
);
}
}

@ -6,6 +6,7 @@ import 'package:gitjournal/editors/common.dart';
class RawEditor extends StatefulWidget implements Editor {
final Note note;
final bool noteModified;
@override
final NoteCallback noteDeletionSelected;
@ -25,6 +26,7 @@ class RawEditor extends StatefulWidget implements Editor {
RawEditor({
Key key,
@required this.note,
@required this.noteModified,
@required this.noteDeletionSelected,
@required this.noteEditorChooserSelected,
@required this.exitEditorSelected,
@ -42,6 +44,7 @@ class RawEditor extends StatefulWidget implements Editor {
class RawEditorState extends State<RawEditor> implements EditorState {
Note note;
bool _noteModified;
TextEditingController _textController = TextEditingController();
final serializer = MarkdownYAMLCodec();
@ -50,6 +53,12 @@ class RawEditorState extends State<RawEditor> implements EditorState {
_textController = TextEditingController(text: serializer.encode(note.data));
}
@override
void initState() {
super.initState();
_noteModified = widget.noteModified;
}
@override
void dispose() {
_textController.dispose();
@ -62,14 +71,15 @@ class RawEditorState extends State<RawEditor> implements EditorState {
padding: const EdgeInsets.all(16.0),
child: SingleChildScrollView(
child: _NoteEditor(
_textController,
textController: _textController,
autofocus: widget.isNewNote,
onChanged: _noteTextChanged,
),
),
);
return Scaffold(
appBar: buildEditorAppBar(widget, this),
appBar: buildEditorAppBar(widget, this, noteModified: _noteModified),
body: editor,
);
}
@ -79,13 +89,21 @@ class RawEditorState extends State<RawEditor> implements EditorState {
note.data = serializer.decode(_textController.text);
return note;
}
void _noteTextChanged() {
if (_noteModified) return;
setState(() {
_noteModified = true;
});
}
}
class _NoteEditor extends StatelessWidget {
final TextEditingController textController;
final bool autofocus;
final Function onChanged;
_NoteEditor(this.textController, {this.autofocus = false});
_NoteEditor({this.textController, this.autofocus, this.onChanged});
@override
Widget build(BuildContext context) {
@ -105,6 +123,7 @@ class _NoteEditor extends StatelessWidget {
controller: textController,
textCapitalization: TextCapitalization.sentences,
scrollPadding: const EdgeInsets.all(0.0),
onChanged: (_) => onChanged(),
);
}
}

@ -96,6 +96,7 @@ class NoteEditorState extends State<NoteEditor> {
return MarkdownEditor(
key: _markdownEditorKey,
note: note,
noteModified: _noteModified(note),
noteDeletionSelected: _noteDeletionSelected,
noteEditorChooserSelected: _noteEditorChooserSelected,
exitEditorSelected: _exitEditorSelected,
@ -108,6 +109,7 @@ class NoteEditorState extends State<NoteEditor> {
return RawEditor(
key: _rawEditorKey,
note: note,
noteModified: _noteModified(note),
noteDeletionSelected: _noteDeletionSelected,
noteEditorChooserSelected: _noteEditorChooserSelected,
exitEditorSelected: _exitEditorSelected,
@ -120,6 +122,7 @@ class NoteEditorState extends State<NoteEditor> {
return ChecklistEditor(
key: _checklistEditorKey,
note: note,
noteModified: _noteModified(note),
noteDeletionSelected: _noteDeletionSelected,
noteEditorChooserSelected: _noteEditorChooserSelected,
exitEditorSelected: _exitEditorSelected,
@ -132,6 +135,7 @@ class NoteEditorState extends State<NoteEditor> {
return JournalEditor(
key: _journalEditorKey,
note: note,
noteModified: _noteModified(note),
noteDeletionSelected: _noteDeletionSelected,
noteEditorChooserSelected: _noteEditorChooserSelected,
exitEditorSelected: _exitEditorSelected,