mirror of
https://github.com/GitJournal/GitJournal.git
synced 2025-06-28 01:45:55 +08:00
Add support for moving a Note to another folder
The Folder selection dialog needs a lot of work, but it's a start.
This commit is contained in:
@ -81,6 +81,19 @@ class GitNoteRepository {
|
|||||||
return NoteRepoResult(noteFilePath: newFullPath, error: false);
|
return NoteRepoResult(noteFilePath: newFullPath, error: false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<NoteRepoResult> 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<NoteRepoResult> removeNote(String noteFilePath) async {
|
Future<NoteRepoResult> removeNote(String noteFilePath) async {
|
||||||
var pathSpec = noteFilePath.replaceFirst(gitDirPath, "").substring(1);
|
var pathSpec = noteFilePath.replaceFirst(gitDirPath, "").substring(1);
|
||||||
|
|
||||||
|
@ -172,6 +172,22 @@ class Note with ChangeNotifier implements Comparable<Note> {
|
|||||||
notifyListeners();
|
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
|
@override
|
||||||
int get hashCode => _filePath.hashCode;
|
int get hashCode => _filePath.hashCode;
|
||||||
|
|
||||||
|
@ -4,7 +4,7 @@ import 'package:gitjournal/core/note.dart';
|
|||||||
import 'package:gitjournal/widgets/note_viewer.dart';
|
import 'package:gitjournal/widgets/note_viewer.dart';
|
||||||
|
|
||||||
typedef NoteCallback = void Function(Note);
|
typedef NoteCallback = void Function(Note);
|
||||||
enum DropDownChoices { Rename }
|
enum DropDownChoices { Rename, MoveToFolder }
|
||||||
|
|
||||||
class MarkdownEditor extends StatefulWidget {
|
class MarkdownEditor extends StatefulWidget {
|
||||||
final Note note;
|
final Note note;
|
||||||
@ -12,6 +12,7 @@ class MarkdownEditor extends StatefulWidget {
|
|||||||
final NoteCallback noteEditorChooserSelected;
|
final NoteCallback noteEditorChooserSelected;
|
||||||
final NoteCallback exitEditorSelected;
|
final NoteCallback exitEditorSelected;
|
||||||
final NoteCallback renameNoteSelected;
|
final NoteCallback renameNoteSelected;
|
||||||
|
final NoteCallback moveNoteToFolderSelected;
|
||||||
final bool autofocusOnEditor;
|
final bool autofocusOnEditor;
|
||||||
|
|
||||||
MarkdownEditor({
|
MarkdownEditor({
|
||||||
@ -21,6 +22,7 @@ class MarkdownEditor extends StatefulWidget {
|
|||||||
@required this.noteEditorChooserSelected,
|
@required this.noteEditorChooserSelected,
|
||||||
@required this.exitEditorSelected,
|
@required this.exitEditorSelected,
|
||||||
@required this.renameNoteSelected,
|
@required this.renameNoteSelected,
|
||||||
|
@required this.moveNoteToFolderSelected,
|
||||||
this.autofocusOnEditor = false,
|
this.autofocusOnEditor = false,
|
||||||
}) : super(key: key);
|
}) : super(key: key);
|
||||||
|
|
||||||
@ -108,8 +110,17 @@ class MarkdownEditorState extends State<MarkdownEditor> {
|
|||||||
),
|
),
|
||||||
PopupMenuButton<DropDownChoices>(
|
PopupMenuButton<DropDownChoices>(
|
||||||
onSelected: (DropDownChoices choice) {
|
onSelected: (DropDownChoices choice) {
|
||||||
_updateNote();
|
switch (choice) {
|
||||||
widget.renameNoteSelected(note);
|
case DropDownChoices.Rename:
|
||||||
|
_updateNote();
|
||||||
|
widget.renameNoteSelected(note);
|
||||||
|
return;
|
||||||
|
|
||||||
|
case DropDownChoices.MoveToFolder:
|
||||||
|
_updateNote();
|
||||||
|
widget.moveNoteToFolderSelected(note);
|
||||||
|
return;
|
||||||
|
}
|
||||||
},
|
},
|
||||||
itemBuilder: (BuildContext context) =>
|
itemBuilder: (BuildContext context) =>
|
||||||
<PopupMenuEntry<DropDownChoices>>[
|
<PopupMenuEntry<DropDownChoices>>[
|
||||||
@ -117,6 +128,10 @@ class MarkdownEditorState extends State<MarkdownEditor> {
|
|||||||
value: DropDownChoices.Rename,
|
value: DropDownChoices.Rename,
|
||||||
child: Text('Edit File Name'),
|
child: Text('Edit File Name'),
|
||||||
),
|
),
|
||||||
|
const PopupMenuItem<DropDownChoices>(
|
||||||
|
value: DropDownChoices.MoveToFolder,
|
||||||
|
child: Text('Move to Folder'),
|
||||||
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
@ -4,7 +4,7 @@ import 'package:gitjournal/core/note.dart';
|
|||||||
import 'package:gitjournal/core/note_data_serializers.dart';
|
import 'package:gitjournal/core/note_data_serializers.dart';
|
||||||
|
|
||||||
typedef NoteCallback = void Function(Note);
|
typedef NoteCallback = void Function(Note);
|
||||||
enum DropDownChoices { Rename }
|
enum DropDownChoices { Rename, MoveToFolder }
|
||||||
|
|
||||||
class RawEditor extends StatefulWidget {
|
class RawEditor extends StatefulWidget {
|
||||||
final Note note;
|
final Note note;
|
||||||
@ -12,6 +12,7 @@ class RawEditor extends StatefulWidget {
|
|||||||
final NoteCallback noteEditorChooserSelected;
|
final NoteCallback noteEditorChooserSelected;
|
||||||
final NoteCallback exitEditorSelected;
|
final NoteCallback exitEditorSelected;
|
||||||
final NoteCallback renameNoteSelected;
|
final NoteCallback renameNoteSelected;
|
||||||
|
final NoteCallback moveNoteToFolderSelected;
|
||||||
|
|
||||||
RawEditor({
|
RawEditor({
|
||||||
Key key,
|
Key key,
|
||||||
@ -20,6 +21,7 @@ class RawEditor extends StatefulWidget {
|
|||||||
@required this.noteEditorChooserSelected,
|
@required this.noteEditorChooserSelected,
|
||||||
@required this.exitEditorSelected,
|
@required this.exitEditorSelected,
|
||||||
@required this.renameNoteSelected,
|
@required this.renameNoteSelected,
|
||||||
|
@required this.moveNoteToFolderSelected,
|
||||||
}) : super(key: key);
|
}) : super(key: key);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@ -88,8 +90,17 @@ class RawEditorState extends State<RawEditor> {
|
|||||||
),
|
),
|
||||||
PopupMenuButton<DropDownChoices>(
|
PopupMenuButton<DropDownChoices>(
|
||||||
onSelected: (DropDownChoices choice) {
|
onSelected: (DropDownChoices choice) {
|
||||||
_updateNote();
|
switch (choice) {
|
||||||
widget.renameNoteSelected(note);
|
case DropDownChoices.Rename:
|
||||||
|
_updateNote();
|
||||||
|
widget.renameNoteSelected(note);
|
||||||
|
return;
|
||||||
|
|
||||||
|
case DropDownChoices.MoveToFolder:
|
||||||
|
_updateNote();
|
||||||
|
widget.moveNoteToFolderSelected(note);
|
||||||
|
return;
|
||||||
|
}
|
||||||
},
|
},
|
||||||
itemBuilder: (BuildContext context) =>
|
itemBuilder: (BuildContext context) =>
|
||||||
<PopupMenuEntry<DropDownChoices>>[
|
<PopupMenuEntry<DropDownChoices>>[
|
||||||
@ -97,6 +108,10 @@ class RawEditorState extends State<RawEditor> {
|
|||||||
value: DropDownChoices.Rename,
|
value: DropDownChoices.Rename,
|
||||||
child: Text('Edit File Name'),
|
child: Text('Edit File Name'),
|
||||||
),
|
),
|
||||||
|
const PopupMenuItem<DropDownChoices>(
|
||||||
|
value: DropDownChoices.MoveToFolder,
|
||||||
|
child: Text('Move to Folder'),
|
||||||
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
@ -8,10 +8,9 @@ import 'package:gitjournal/editors/raw_editor.dart';
|
|||||||
import 'package:gitjournal/state_container.dart';
|
import 'package:gitjournal/state_container.dart';
|
||||||
import 'package:gitjournal/core/note_data_serializers.dart';
|
import 'package:gitjournal/core/note_data_serializers.dart';
|
||||||
import 'package:gitjournal/utils.dart';
|
import 'package:gitjournal/utils.dart';
|
||||||
|
import 'package:gitjournal/widgets/folder_selection_dialog.dart';
|
||||||
import 'package:gitjournal/widgets/rename_dialog.dart';
|
import 'package:gitjournal/widgets/rename_dialog.dart';
|
||||||
|
|
||||||
enum NoteEditorDropDownChoices { Discard, SwitchEditor }
|
|
||||||
|
|
||||||
class NoteEditor extends StatefulWidget {
|
class NoteEditor extends StatefulWidget {
|
||||||
final Note note;
|
final Note note;
|
||||||
final NotesFolder notesFolder;
|
final NotesFolder notesFolder;
|
||||||
@ -73,6 +72,7 @@ class NoteEditorState extends State<NoteEditor> {
|
|||||||
noteEditorChooserSelected: _noteEditorChooserSelected,
|
noteEditorChooserSelected: _noteEditorChooserSelected,
|
||||||
exitEditorSelected: _exitEditorSelected,
|
exitEditorSelected: _exitEditorSelected,
|
||||||
renameNoteSelected: _renameNoteSelected,
|
renameNoteSelected: _renameNoteSelected,
|
||||||
|
moveNoteToFolderSelected: _moveNoteToFolderSelected,
|
||||||
autofocusOnEditor: _isNewNote,
|
autofocusOnEditor: _isNewNote,
|
||||||
);
|
);
|
||||||
case EditorType.Raw:
|
case EditorType.Raw:
|
||||||
@ -83,6 +83,7 @@ class NoteEditorState extends State<NoteEditor> {
|
|||||||
noteEditorChooserSelected: _noteEditorChooserSelected,
|
noteEditorChooserSelected: _noteEditorChooserSelected,
|
||||||
exitEditorSelected: _exitEditorSelected,
|
exitEditorSelected: _exitEditorSelected,
|
||||||
renameNoteSelected: _renameNoteSelected,
|
renameNoteSelected: _renameNoteSelected,
|
||||||
|
moveNoteToFolderSelected: _moveNoteToFolderSelected,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
@ -227,4 +228,15 @@ class NoteEditorState extends State<NoteEditor> {
|
|||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void _moveNoteToFolderSelected(Note note) async {
|
||||||
|
var destFolder = await showDialog<NotesFolder>(
|
||||||
|
context: context,
|
||||||
|
builder: (context) => FolderSelectionDialog(),
|
||||||
|
);
|
||||||
|
if (destFolder != null) {
|
||||||
|
final stateContainer = StateContainer.of(context);
|
||||||
|
stateContainer.moveNote(note, destFolder);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -139,7 +139,7 @@ class StateContainerState extends State<StateContainer> {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void renameFolder(NotesFolder folder, String newFolderName) async {
|
void renameFolder(NotesFolder folder, String newFolderName) {
|
||||||
var oldFolderPath = folder.folderPath;
|
var oldFolderPath = folder.folderPath;
|
||||||
folder.rename(newFolderName);
|
folder.rename(newFolderName);
|
||||||
|
|
||||||
@ -150,7 +150,7 @@ class StateContainerState extends State<StateContainer> {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void renameNote(Note note, String newFileName) async {
|
void renameNote(Note note, String newFileName) {
|
||||||
var oldNotePath = note.filePath;
|
var oldNotePath = note.filePath;
|
||||||
note.rename(newFileName);
|
note.rename(newFileName);
|
||||||
|
|
||||||
@ -159,6 +159,15 @@ class StateContainerState extends State<StateContainer> {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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) {
|
void addNote(Note note) {
|
||||||
insertNote(0, note);
|
insertNote(0, note);
|
||||||
}
|
}
|
||||||
|
31
lib/widgets/folder_selection_dialog.dart
Normal file
31
lib/widgets/folder_selection_dialog.dart
Normal file
@ -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<NotesFolder>(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
|
@ -10,17 +10,21 @@ class FolderTreeView extends StatefulWidget {
|
|||||||
final FolderSelectedCallback onFolderSelected;
|
final FolderSelectedCallback onFolderSelected;
|
||||||
final Function onFolderUnselected;
|
final Function onFolderUnselected;
|
||||||
final FolderSelectedCallback onFolderEntered;
|
final FolderSelectedCallback onFolderEntered;
|
||||||
|
final bool longPressAllowed;
|
||||||
|
|
||||||
FolderTreeView({
|
FolderTreeView({
|
||||||
Key key,
|
Key key,
|
||||||
@required this.rootFolder,
|
@required this.rootFolder,
|
||||||
@required this.onFolderSelected,
|
|
||||||
@required this.onFolderUnselected,
|
|
||||||
@required this.onFolderEntered,
|
@required this.onFolderEntered,
|
||||||
|
this.onFolderSelected = _doNothing,
|
||||||
|
this.onFolderUnselected = _doNothing,
|
||||||
|
this.longPressAllowed = true,
|
||||||
}) : super(key: key);
|
}) : super(key: key);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
FolderTreeViewState createState() => FolderTreeViewState();
|
FolderTreeViewState createState() => FolderTreeViewState();
|
||||||
|
|
||||||
|
static void _doNothing(NotesFolder f) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
class FolderTreeViewState extends State<FolderTreeView> {
|
class FolderTreeViewState extends State<FolderTreeView> {
|
||||||
@ -43,6 +47,7 @@ class FolderTreeViewState extends State<FolderTreeView> {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
onLongPress: (folder) {
|
onLongPress: (folder) {
|
||||||
|
if (!widget.longPressAllowed) return;
|
||||||
setState(() {
|
setState(() {
|
||||||
inSelectionMode = true;
|
inSelectionMode = true;
|
||||||
selectedFolder = folder;
|
selectedFolder = folder;
|
||||||
|
Reference in New Issue
Block a user