mirror of
https://github.com/GitJournal/GitJournal.git
synced 2025-07-20 04:42:59 +08:00
Reduce code duplication between Editors
It also makes it so much easier to implement a new editor.
This commit is contained in:
86
lib/editors/common.dart
Normal file
86
lib/editors/common.dart
Normal file
@ -0,0 +1,86 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:gitjournal/core/note.dart';
|
||||
|
||||
typedef NoteCallback = void Function(Note);
|
||||
|
||||
abstract class Editor {
|
||||
NoteCallback get noteDeletionSelected;
|
||||
NoteCallback get noteEditorChooserSelected;
|
||||
NoteCallback get exitEditorSelected;
|
||||
NoteCallback get renameNoteSelected;
|
||||
NoteCallback get moveNoteToFolderSelected;
|
||||
}
|
||||
|
||||
abstract class EditorState {
|
||||
Note getNote();
|
||||
}
|
||||
|
||||
enum DropDownChoices { Rename, MoveToFolder }
|
||||
|
||||
AppBar buildEditorAppBar(
|
||||
Editor editor,
|
||||
EditorState editorState, {
|
||||
List<IconButton> extraButtons,
|
||||
}) {
|
||||
return AppBar(
|
||||
leading: IconButton(
|
||||
key: const ValueKey("NewEntry"),
|
||||
icon: const Icon(Icons.check),
|
||||
onPressed: () {
|
||||
editor.exitEditorSelected(editorState.getNote());
|
||||
},
|
||||
),
|
||||
actions: <Widget>[
|
||||
...?extraButtons,
|
||||
IconButton(
|
||||
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.MoveToFolder:
|
||||
var note = editorState.getNote();
|
||||
editor.moveNoteToFolderSelected(note);
|
||||
return;
|
||||
}
|
||||
},
|
||||
itemBuilder: (BuildContext context) =>
|
||||
<PopupMenuEntry<DropDownChoices>>[
|
||||
const PopupMenuItem<DropDownChoices>(
|
||||
value: DropDownChoices.Rename,
|
||||
child: Text('Edit File Name'),
|
||||
),
|
||||
const PopupMenuItem<DropDownChoices>(
|
||||
value: DropDownChoices.MoveToFolder,
|
||||
child: Text('Move to Folder'),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
FloatingActionButton buildFAB(Editor editor, EditorState editorState) {
|
||||
return FloatingActionButton(
|
||||
child: const Icon(Icons.check),
|
||||
onPressed: () {
|
||||
editor.exitEditorSelected(editorState.getNote());
|
||||
},
|
||||
);
|
||||
}
|
@ -1,18 +1,23 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import 'package:gitjournal/core/note.dart';
|
||||
import 'package:gitjournal/editors/common.dart';
|
||||
import 'package:gitjournal/widgets/note_viewer.dart';
|
||||
|
||||
typedef NoteCallback = void Function(Note);
|
||||
enum DropDownChoices { Rename, MoveToFolder }
|
||||
|
||||
class MarkdownEditor extends StatefulWidget {
|
||||
class MarkdownEditor extends StatefulWidget implements Editor {
|
||||
final Note note;
|
||||
|
||||
@override
|
||||
final NoteCallback noteDeletionSelected;
|
||||
@override
|
||||
final NoteCallback noteEditorChooserSelected;
|
||||
@override
|
||||
final NoteCallback exitEditorSelected;
|
||||
@override
|
||||
final NoteCallback renameNoteSelected;
|
||||
@override
|
||||
final NoteCallback moveNoteToFolderSelected;
|
||||
|
||||
final bool autofocusOnEditor;
|
||||
|
||||
MarkdownEditor({
|
||||
@ -32,7 +37,7 @@ class MarkdownEditor extends StatefulWidget {
|
||||
}
|
||||
}
|
||||
|
||||
class MarkdownEditorState extends State<MarkdownEditor> {
|
||||
class MarkdownEditorState extends State<MarkdownEditor> implements EditorState {
|
||||
Note note;
|
||||
TextEditingController _textController = TextEditingController();
|
||||
TextEditingController _titleTextController = TextEditingController();
|
||||
@ -69,75 +74,18 @@ class MarkdownEditorState extends State<MarkdownEditor> {
|
||||
);
|
||||
|
||||
Widget body = editingMode ? editor : NoteViewer(note: note);
|
||||
var fab = FloatingActionButton(
|
||||
child: const Icon(Icons.check),
|
||||
onPressed: () {
|
||||
_updateNote();
|
||||
widget.exitEditorSelected(note);
|
||||
},
|
||||
|
||||
var extraButton = IconButton(
|
||||
icon: editingMode
|
||||
? const Icon(Icons.remove_red_eye)
|
||||
: const Icon(Icons.edit),
|
||||
onPressed: _switchMode,
|
||||
);
|
||||
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
leading: IconButton(
|
||||
key: const ValueKey("NewEntry"),
|
||||
icon: const Icon(Icons.check),
|
||||
onPressed: () {
|
||||
_updateNote();
|
||||
widget.exitEditorSelected(note);
|
||||
},
|
||||
),
|
||||
actions: <Widget>[
|
||||
IconButton(
|
||||
icon: editingMode
|
||||
? const Icon(Icons.remove_red_eye)
|
||||
: const Icon(Icons.edit),
|
||||
onPressed: _switchMode,
|
||||
),
|
||||
IconButton(
|
||||
icon: const Icon(Icons.library_books),
|
||||
onPressed: () {
|
||||
_updateNote();
|
||||
widget.noteEditorChooserSelected(note);
|
||||
},
|
||||
),
|
||||
IconButton(
|
||||
icon: const Icon(Icons.delete),
|
||||
onPressed: () {
|
||||
_updateNote();
|
||||
widget.noteDeletionSelected(note);
|
||||
},
|
||||
),
|
||||
PopupMenuButton<DropDownChoices>(
|
||||
onSelected: (DropDownChoices choice) {
|
||||
switch (choice) {
|
||||
case DropDownChoices.Rename:
|
||||
_updateNote();
|
||||
widget.renameNoteSelected(note);
|
||||
return;
|
||||
|
||||
case DropDownChoices.MoveToFolder:
|
||||
_updateNote();
|
||||
widget.moveNoteToFolderSelected(note);
|
||||
return;
|
||||
}
|
||||
},
|
||||
itemBuilder: (BuildContext context) =>
|
||||
<PopupMenuEntry<DropDownChoices>>[
|
||||
const PopupMenuItem<DropDownChoices>(
|
||||
value: DropDownChoices.Rename,
|
||||
child: Text('Edit File Name'),
|
||||
),
|
||||
const PopupMenuItem<DropDownChoices>(
|
||||
value: DropDownChoices.MoveToFolder,
|
||||
child: Text('Move to Folder'),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
appBar: buildEditorAppBar(widget, this, extraButtons: [extraButton]),
|
||||
floatingActionButton: buildFAB(widget, this),
|
||||
body: body,
|
||||
floatingActionButton: fab,
|
||||
);
|
||||
}
|
||||
|
||||
@ -153,6 +101,7 @@ class MarkdownEditorState extends State<MarkdownEditor> {
|
||||
note.body = _textController.text.trim();
|
||||
}
|
||||
|
||||
@override
|
||||
Note getNote() {
|
||||
_updateNote();
|
||||
return note;
|
||||
|
@ -2,16 +2,20 @@ import 'package:flutter/material.dart';
|
||||
|
||||
import 'package:gitjournal/core/note.dart';
|
||||
import 'package:gitjournal/core/note_data_serializers.dart';
|
||||
import 'package:gitjournal/editors/common.dart';
|
||||
|
||||
typedef NoteCallback = void Function(Note);
|
||||
enum DropDownChoices { Rename, MoveToFolder }
|
||||
|
||||
class RawEditor extends StatefulWidget {
|
||||
class RawEditor extends StatefulWidget implements Editor {
|
||||
final Note note;
|
||||
|
||||
@override
|
||||
final NoteCallback noteDeletionSelected;
|
||||
@override
|
||||
final NoteCallback noteEditorChooserSelected;
|
||||
@override
|
||||
final NoteCallback exitEditorSelected;
|
||||
@override
|
||||
final NoteCallback renameNoteSelected;
|
||||
@override
|
||||
final NoteCallback moveNoteToFolderSelected;
|
||||
|
||||
RawEditor({
|
||||
@ -30,7 +34,7 @@ class RawEditor extends StatefulWidget {
|
||||
}
|
||||
}
|
||||
|
||||
class RawEditorState extends State<RawEditor> {
|
||||
class RawEditorState extends State<RawEditor> implements EditorState {
|
||||
Note note;
|
||||
TextEditingController _textController = TextEditingController();
|
||||
|
||||
@ -55,78 +59,16 @@ class RawEditorState extends State<RawEditor> {
|
||||
),
|
||||
);
|
||||
|
||||
var fab = FloatingActionButton(
|
||||
child: const Icon(Icons.check),
|
||||
onPressed: () {
|
||||
_updateNote();
|
||||
widget.exitEditorSelected(note);
|
||||
},
|
||||
);
|
||||
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
leading: IconButton(
|
||||
key: const ValueKey("NewEntry"),
|
||||
icon: const Icon(Icons.check),
|
||||
onPressed: () {
|
||||
_updateNote();
|
||||
widget.exitEditorSelected(note);
|
||||
},
|
||||
),
|
||||
actions: <Widget>[
|
||||
IconButton(
|
||||
icon: const Icon(Icons.library_books),
|
||||
onPressed: () {
|
||||
_updateNote();
|
||||
widget.noteEditorChooserSelected(note);
|
||||
},
|
||||
),
|
||||
IconButton(
|
||||
icon: const Icon(Icons.delete),
|
||||
onPressed: () {
|
||||
_updateNote();
|
||||
widget.noteDeletionSelected(note);
|
||||
},
|
||||
),
|
||||
PopupMenuButton<DropDownChoices>(
|
||||
onSelected: (DropDownChoices choice) {
|
||||
switch (choice) {
|
||||
case DropDownChoices.Rename:
|
||||
_updateNote();
|
||||
widget.renameNoteSelected(note);
|
||||
return;
|
||||
|
||||
case DropDownChoices.MoveToFolder:
|
||||
_updateNote();
|
||||
widget.moveNoteToFolderSelected(note);
|
||||
return;
|
||||
}
|
||||
},
|
||||
itemBuilder: (BuildContext context) =>
|
||||
<PopupMenuEntry<DropDownChoices>>[
|
||||
const PopupMenuItem<DropDownChoices>(
|
||||
value: DropDownChoices.Rename,
|
||||
child: Text('Edit File Name'),
|
||||
),
|
||||
const PopupMenuItem<DropDownChoices>(
|
||||
value: DropDownChoices.MoveToFolder,
|
||||
child: Text('Move to Folder'),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
appBar: buildEditorAppBar(widget, this),
|
||||
floatingActionButton: buildFAB(widget, this),
|
||||
body: editor,
|
||||
floatingActionButton: fab,
|
||||
);
|
||||
}
|
||||
|
||||
void _updateNote() {
|
||||
note.data = serializer.decode(_textController.text);
|
||||
}
|
||||
|
||||
@override
|
||||
Note getNote() {
|
||||
_updateNote();
|
||||
note.data = serializer.decode(_textController.text);
|
||||
return note;
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user