From 43281bd2bb5e67560965ad44dcb08e228b805a6a Mon Sep 17 00:00:00 2001 From: Vishesh Handa Date: Wed, 29 Jan 2020 16:51:57 +0100 Subject: [PATCH] Add support for moving a Note to another folder The Folder selection dialog needs a lot of work, but it's a start. --- lib/core/git_repo.dart | 13 ++++++++++ lib/core/note.dart | 16 ++++++++++++ lib/editors/markdown_editor.dart | 21 +++++++++++++--- lib/editors/raw_editor.dart | 21 +++++++++++++--- lib/screens/note_editor.dart | 16 ++++++++++-- lib/state_container.dart | 13 ++++++++-- lib/widgets/folder_selection_dialog.dart | 31 ++++++++++++++++++++++++ lib/widgets/folder_tree_view.dart | 9 +++++-- 8 files changed, 128 insertions(+), 12 deletions(-) create mode 100644 lib/widgets/folder_selection_dialog.dart diff --git a/lib/core/git_repo.dart b/lib/core/git_repo.dart index 5ec12ccb..aa9c001b 100644 --- a/lib/core/git_repo.dart +++ b/lib/core/git_repo.dart @@ -81,6 +81,19 @@ class GitNoteRepository { return NoteRepoResult(noteFilePath: newFullPath, error: false); } + Future moveNote( + String oldFullPath, + String newFullPath, + ) async { + // FIXME: This is a hacky way of adding the changes, ideally we should be calling rm + add or something + await _gitRepo.add("."); + await _gitRepo.commit( + message: "Note Moved", + ); + + return NoteRepoResult(noteFilePath: newFullPath, error: false); + } + Future removeNote(String noteFilePath) async { var pathSpec = noteFilePath.replaceFirst(gitDirPath, "").substring(1); diff --git a/lib/core/note.dart b/lib/core/note.dart index a4d2f545..9ebae162 100644 --- a/lib/core/note.dart +++ b/lib/core/note.dart @@ -172,6 +172,22 @@ class Note with ChangeNotifier implements Comparable { notifyListeners(); } + bool move(NotesFolder destFolder) { + var destPath = p.join(destFolder.folderPath, fileName); + if (File(destPath).existsSync()) { + return false; + } + + File(filePath).renameSync(destPath); + + parent.remove(this); + parent = destFolder; + destFolder.add(this); + + notifyListeners(); + return true; + } + @override int get hashCode => _filePath.hashCode; diff --git a/lib/editors/markdown_editor.dart b/lib/editors/markdown_editor.dart index 3fe611b2..44b30ddf 100644 --- a/lib/editors/markdown_editor.dart +++ b/lib/editors/markdown_editor.dart @@ -4,7 +4,7 @@ import 'package:gitjournal/core/note.dart'; import 'package:gitjournal/widgets/note_viewer.dart'; typedef NoteCallback = void Function(Note); -enum DropDownChoices { Rename } +enum DropDownChoices { Rename, MoveToFolder } class MarkdownEditor extends StatefulWidget { final Note note; @@ -12,6 +12,7 @@ class MarkdownEditor extends StatefulWidget { final NoteCallback noteEditorChooserSelected; final NoteCallback exitEditorSelected; final NoteCallback renameNoteSelected; + final NoteCallback moveNoteToFolderSelected; final bool autofocusOnEditor; MarkdownEditor({ @@ -21,6 +22,7 @@ class MarkdownEditor extends StatefulWidget { @required this.noteEditorChooserSelected, @required this.exitEditorSelected, @required this.renameNoteSelected, + @required this.moveNoteToFolderSelected, this.autofocusOnEditor = false, }) : super(key: key); @@ -108,8 +110,17 @@ class MarkdownEditorState extends State { ), PopupMenuButton( onSelected: (DropDownChoices choice) { - _updateNote(); - widget.renameNoteSelected(note); + switch (choice) { + case DropDownChoices.Rename: + _updateNote(); + widget.renameNoteSelected(note); + return; + + case DropDownChoices.MoveToFolder: + _updateNote(); + widget.moveNoteToFolderSelected(note); + return; + } }, itemBuilder: (BuildContext context) => >[ @@ -117,6 +128,10 @@ class MarkdownEditorState extends State { value: DropDownChoices.Rename, child: Text('Edit File Name'), ), + const PopupMenuItem( + value: DropDownChoices.MoveToFolder, + child: Text('Move to Folder'), + ), ], ), ], diff --git a/lib/editors/raw_editor.dart b/lib/editors/raw_editor.dart index 1a780c28..91503f07 100644 --- a/lib/editors/raw_editor.dart +++ b/lib/editors/raw_editor.dart @@ -4,7 +4,7 @@ import 'package:gitjournal/core/note.dart'; import 'package:gitjournal/core/note_data_serializers.dart'; typedef NoteCallback = void Function(Note); -enum DropDownChoices { Rename } +enum DropDownChoices { Rename, MoveToFolder } class RawEditor extends StatefulWidget { final Note note; @@ -12,6 +12,7 @@ class RawEditor extends StatefulWidget { final NoteCallback noteEditorChooserSelected; final NoteCallback exitEditorSelected; final NoteCallback renameNoteSelected; + final NoteCallback moveNoteToFolderSelected; RawEditor({ Key key, @@ -20,6 +21,7 @@ class RawEditor extends StatefulWidget { @required this.noteEditorChooserSelected, @required this.exitEditorSelected, @required this.renameNoteSelected, + @required this.moveNoteToFolderSelected, }) : super(key: key); @override @@ -88,8 +90,17 @@ class RawEditorState extends State { ), PopupMenuButton( onSelected: (DropDownChoices choice) { - _updateNote(); - widget.renameNoteSelected(note); + switch (choice) { + case DropDownChoices.Rename: + _updateNote(); + widget.renameNoteSelected(note); + return; + + case DropDownChoices.MoveToFolder: + _updateNote(); + widget.moveNoteToFolderSelected(note); + return; + } }, itemBuilder: (BuildContext context) => >[ @@ -97,6 +108,10 @@ class RawEditorState extends State { value: DropDownChoices.Rename, child: Text('Edit File Name'), ), + const PopupMenuItem( + value: DropDownChoices.MoveToFolder, + child: Text('Move to Folder'), + ), ], ), ], diff --git a/lib/screens/note_editor.dart b/lib/screens/note_editor.dart index 0a5e5c07..3f5af7a3 100644 --- a/lib/screens/note_editor.dart +++ b/lib/screens/note_editor.dart @@ -8,10 +8,9 @@ import 'package:gitjournal/editors/raw_editor.dart'; import 'package:gitjournal/state_container.dart'; import 'package:gitjournal/core/note_data_serializers.dart'; import 'package:gitjournal/utils.dart'; +import 'package:gitjournal/widgets/folder_selection_dialog.dart'; import 'package:gitjournal/widgets/rename_dialog.dart'; -enum NoteEditorDropDownChoices { Discard, SwitchEditor } - class NoteEditor extends StatefulWidget { final Note note; final NotesFolder notesFolder; @@ -73,6 +72,7 @@ class NoteEditorState extends State { noteEditorChooserSelected: _noteEditorChooserSelected, exitEditorSelected: _exitEditorSelected, renameNoteSelected: _renameNoteSelected, + moveNoteToFolderSelected: _moveNoteToFolderSelected, autofocusOnEditor: _isNewNote, ); case EditorType.Raw: @@ -83,6 +83,7 @@ class NoteEditorState extends State { noteEditorChooserSelected: _noteEditorChooserSelected, exitEditorSelected: _exitEditorSelected, renameNoteSelected: _renameNoteSelected, + moveNoteToFolderSelected: _moveNoteToFolderSelected, ); } return null; @@ -227,4 +228,15 @@ class NoteEditorState extends State { } return null; } + + void _moveNoteToFolderSelected(Note note) async { + var destFolder = await showDialog( + context: context, + builder: (context) => FolderSelectionDialog(), + ); + if (destFolder != null) { + final stateContainer = StateContainer.of(context); + stateContainer.moveNote(note, destFolder); + } + } } diff --git a/lib/state_container.dart b/lib/state_container.dart index 5f799d9a..12dee38a 100644 --- a/lib/state_container.dart +++ b/lib/state_container.dart @@ -139,7 +139,7 @@ class StateContainerState extends State { }); } - void renameFolder(NotesFolder folder, String newFolderName) async { + void renameFolder(NotesFolder folder, String newFolderName) { var oldFolderPath = folder.folderPath; folder.rename(newFolderName); @@ -150,7 +150,7 @@ class StateContainerState extends State { }); } - void renameNote(Note note, String newFileName) async { + void renameNote(Note note, String newFileName) { var oldNotePath = note.filePath; note.rename(newFileName); @@ -159,6 +159,15 @@ class StateContainerState extends State { }); } + void moveNote(Note note, NotesFolder destFolder) { + var oldNotePath = note.filePath; + note.move(destFolder); + + _gitRepo.moveNote(oldNotePath, note.filePath).then((NoteRepoResult _) { + syncNotes(); + }); + } + void addNote(Note note) { insertNote(0, note); } diff --git a/lib/widgets/folder_selection_dialog.dart b/lib/widgets/folder_selection_dialog.dart new file mode 100644 index 00000000..a96add68 --- /dev/null +++ b/lib/widgets/folder_selection_dialog.dart @@ -0,0 +1,31 @@ +import 'package:flutter/material.dart'; +import 'package:gitjournal/core/notes_folder.dart'; +import 'package:gitjournal/widgets/folder_tree_view.dart'; +import 'package:provider/provider.dart'; + +typedef NoteFolderCallback = void Function(NotesFolder); + +class FolderSelectionDialog extends StatelessWidget { + @override + Widget build(BuildContext context) { + final notesFolder = Provider.of(context); + + var body = Container( + width: double.maxFinite, + child: FolderTreeView( + rootFolder: notesFolder, + onFolderEntered: (NotesFolder destFolder) { + Navigator.of(context).pop(destFolder); + }, + longPressAllowed: false, + ), + ); + + return AlertDialog( + title: const Text('Select a Folder'), + content: body, + ); + } +} + +// FIXME: Add the previously as a radio button selected Folder diff --git a/lib/widgets/folder_tree_view.dart b/lib/widgets/folder_tree_view.dart index 74233b03..6859061d 100644 --- a/lib/widgets/folder_tree_view.dart +++ b/lib/widgets/folder_tree_view.dart @@ -10,17 +10,21 @@ class FolderTreeView extends StatefulWidget { final FolderSelectedCallback onFolderSelected; final Function onFolderUnselected; final FolderSelectedCallback onFolderEntered; + final bool longPressAllowed; FolderTreeView({ Key key, @required this.rootFolder, - @required this.onFolderSelected, - @required this.onFolderUnselected, @required this.onFolderEntered, + this.onFolderSelected = _doNothing, + this.onFolderUnselected = _doNothing, + this.longPressAllowed = true, }) : super(key: key); @override FolderTreeViewState createState() => FolderTreeViewState(); + + static void _doNothing(NotesFolder f) {} } class FolderTreeViewState extends State { @@ -43,6 +47,7 @@ class FolderTreeViewState extends State { } }, onLongPress: (folder) { + if (!widget.longPressAllowed) return; setState(() { inSelectionMode = true; selectedFolder = folder;