mirror of
https://github.com/GitJournal/GitJournal.git
synced 2025-07-10 04:04:42 +08:00
Editor: Show ✕ or ✓ in AppBar depending on if the note has been modified
Fixes #123
This commit is contained in:
@ -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,
|
||||
|
Reference in New Issue
Block a user