mirror of
https://github.com/GitJournal/GitJournal.git
synced 2025-07-01 12:23:44 +08:00
Rename NotesFolder -> NotesFolderFS
And NotesFolderReadOnly to NotesFolder. It just makes more sense this way as we're now getting more and more different "types" of NotesFolders.
This commit is contained in:
@ -1,7 +1,7 @@
|
|||||||
import 'package:shared_preferences/shared_preferences.dart';
|
import 'package:shared_preferences/shared_preferences.dart';
|
||||||
import 'package:fimber/fimber.dart';
|
import 'package:fimber/fimber.dart';
|
||||||
|
|
||||||
import 'package:gitjournal/core/notes_folder.dart';
|
import 'package:gitjournal/core/notes_folder_fs.dart';
|
||||||
|
|
||||||
enum SyncStatus {
|
enum SyncStatus {
|
||||||
Unknown,
|
Unknown,
|
||||||
@ -35,7 +35,7 @@ class AppState {
|
|||||||
return notesFolder.hasNotes;
|
return notesFolder.hasNotes;
|
||||||
}
|
}
|
||||||
|
|
||||||
NotesFolder notesFolder;
|
NotesFolderFS notesFolder;
|
||||||
|
|
||||||
AppState(SharedPreferences pref) {
|
AppState(SharedPreferences pref) {
|
||||||
localGitRepoConfigured = pref.getBool("localGitRepoConfigured") ?? false;
|
localGitRepoConfigured = pref.getBool("localGitRepoConfigured") ?? false;
|
||||||
|
@ -2,21 +2,19 @@ import 'package:gitjournal/core/note.dart';
|
|||||||
import 'package:gitjournal/core/notes_folder.dart';
|
import 'package:gitjournal/core/notes_folder.dart';
|
||||||
import 'package:gitjournal/core/notes_folder_notifier.dart';
|
import 'package:gitjournal/core/notes_folder_notifier.dart';
|
||||||
|
|
||||||
class FlattenedNotesFolder
|
class FlattenedNotesFolder with NotesFolderNotifier implements NotesFolder {
|
||||||
with NotesFolderNotifier
|
|
||||||
implements NotesFolderReadOnly {
|
|
||||||
final NotesFolder _parentFolder;
|
final NotesFolder _parentFolder;
|
||||||
|
|
||||||
var _notes = <Note>[];
|
var _notes = <Note>[];
|
||||||
var _noteExtraInfo = <Note, int>{};
|
var _noteExtraInfo = <Note, int>{};
|
||||||
|
|
||||||
var _folders = <NotesFolderReadOnly>[];
|
var _folders = <NotesFolder>[];
|
||||||
|
|
||||||
FlattenedNotesFolder(this._parentFolder) {
|
FlattenedNotesFolder(this._parentFolder) {
|
||||||
_addFolder(_parentFolder);
|
_addFolder(_parentFolder);
|
||||||
}
|
}
|
||||||
|
|
||||||
void _addFolder(NotesFolderReadOnly folder) {
|
void _addFolder(NotesFolder folder) {
|
||||||
_folders.add(folder);
|
_folders.add(folder);
|
||||||
|
|
||||||
// Add Change notifiers
|
// Add Change notifiers
|
||||||
@ -102,4 +100,7 @@ class FlattenedNotesFolder
|
|||||||
NotesFolder get fsFolder {
|
NotesFolder get fsFolder {
|
||||||
return _parentFolder;
|
return _parentFolder;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get name => "All Notes";
|
||||||
}
|
}
|
||||||
|
@ -7,7 +7,7 @@ import 'package:fimber/fimber.dart';
|
|||||||
import 'package:git_bindings/git_bindings.dart';
|
import 'package:git_bindings/git_bindings.dart';
|
||||||
|
|
||||||
import 'package:gitjournal/core/note.dart';
|
import 'package:gitjournal/core/note.dart';
|
||||||
import 'package:gitjournal/core/notes_folder.dart';
|
import 'package:gitjournal/core/notes_folder_fs.dart';
|
||||||
import 'package:gitjournal/settings.dart';
|
import 'package:gitjournal/settings.dart';
|
||||||
|
|
||||||
class NoteRepoResult {
|
class NoteRepoResult {
|
||||||
@ -46,7 +46,7 @@ class GitNoteRepository {
|
|||||||
return NoteRepoResult(noteFilePath: note.filePath, error: false);
|
return NoteRepoResult(noteFilePath: note.filePath, error: false);
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<NoteRepoResult> addFolder(NotesFolder folder) async {
|
Future<NoteRepoResult> addFolder(NotesFolderFS folder) async {
|
||||||
await _gitRepo.add(".");
|
await _gitRepo.add(".");
|
||||||
await _gitRepo.commit(
|
await _gitRepo.commit(
|
||||||
message: "Created New Folder",
|
message: "Created New Folder",
|
||||||
|
@ -3,6 +3,7 @@ import 'dart:io';
|
|||||||
import 'package:fimber/fimber.dart';
|
import 'package:fimber/fimber.dart';
|
||||||
import 'package:gitjournal/core/md_yaml_doc_loader.dart';
|
import 'package:gitjournal/core/md_yaml_doc_loader.dart';
|
||||||
import 'package:gitjournal/core/note_notifier.dart';
|
import 'package:gitjournal/core/note_notifier.dart';
|
||||||
|
import 'package:gitjournal/core/notes_folder_fs.dart';
|
||||||
import 'package:gitjournal/settings.dart';
|
import 'package:gitjournal/settings.dart';
|
||||||
import 'package:gitjournal/utils/markdown.dart';
|
import 'package:gitjournal/utils/markdown.dart';
|
||||||
import 'package:path/path.dart' as p;
|
import 'package:path/path.dart' as p;
|
||||||
@ -11,7 +12,6 @@ import 'md_yaml_doc.dart';
|
|||||||
import 'md_yaml_doc_codec.dart';
|
import 'md_yaml_doc_codec.dart';
|
||||||
import 'note_fileName.dart';
|
import 'note_fileName.dart';
|
||||||
import 'note_serializer.dart';
|
import 'note_serializer.dart';
|
||||||
import 'notes_folder.dart';
|
|
||||||
|
|
||||||
enum NoteLoadState {
|
enum NoteLoadState {
|
||||||
None,
|
None,
|
||||||
@ -21,7 +21,7 @@ enum NoteLoadState {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class Note with NotesNotifier {
|
class Note with NotesNotifier {
|
||||||
NotesFolder parent;
|
NotesFolderFS parent;
|
||||||
String _filePath;
|
String _filePath;
|
||||||
|
|
||||||
String _title = "";
|
String _title = "";
|
||||||
@ -204,7 +204,7 @@ class Note with NotesNotifier {
|
|||||||
_notifyModified();
|
_notifyModified();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool move(NotesFolder destFolder) {
|
bool move(NotesFolderFS destFolder) {
|
||||||
var destPath = p.join(destFolder.folderPath, fileName);
|
var destPath = p.join(destFolder.folderPath, fileName);
|
||||||
if (File(destPath).existsSync()) {
|
if (File(destPath).existsSync()) {
|
||||||
return false;
|
return false;
|
||||||
|
@ -6,7 +6,7 @@ import 'package:path/path.dart' as p;
|
|||||||
import 'package:collection/collection.dart';
|
import 'package:collection/collection.dart';
|
||||||
|
|
||||||
import 'package:gitjournal/core/note.dart';
|
import 'package:gitjournal/core/note.dart';
|
||||||
import 'package:gitjournal/core/notes_folder.dart';
|
import 'package:gitjournal/core/notes_folder_fs.dart';
|
||||||
import 'package:gitjournal/core/sorting_mode.dart';
|
import 'package:gitjournal/core/sorting_mode.dart';
|
||||||
|
|
||||||
class NotesCache {
|
class NotesCache {
|
||||||
@ -16,7 +16,7 @@ class NotesCache {
|
|||||||
|
|
||||||
NotesCache({@required this.filePath, @required this.notesBasePath});
|
NotesCache({@required this.filePath, @required this.notesBasePath});
|
||||||
|
|
||||||
Future load(NotesFolder rootFolder) async {
|
Future load(NotesFolderFS rootFolder) async {
|
||||||
if (!enabled) return;
|
if (!enabled) return;
|
||||||
var fileList = await loadFromDisk();
|
var fileList = await loadFromDisk();
|
||||||
|
|
||||||
@ -37,14 +37,14 @@ class NotesCache {
|
|||||||
var c = components.sublist(0, i + 1);
|
var c = components.sublist(0, i + 1);
|
||||||
var folderPath = p.join(this.notesBasePath, c.join(sep));
|
var folderPath = p.join(this.notesBasePath, c.join(sep));
|
||||||
|
|
||||||
var folders = parent.subFolders;
|
var folders = parent.subFoldersFS;
|
||||||
var folderIndex = folders.indexWhere((f) => f.folderPath == folderPath);
|
var folderIndex = folders.indexWhere((f) => f.folderPath == folderPath);
|
||||||
if (folderIndex != -1) {
|
if (folderIndex != -1) {
|
||||||
parent = folders[folderIndex];
|
parent = folders[folderIndex];
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
var subFolder = NotesFolder(parent, folderPath);
|
var subFolder = NotesFolderFS(parent, folderPath);
|
||||||
parent.addFolder(subFolder);
|
parent.addFolder(subFolder);
|
||||||
parent = subFolder;
|
parent = subFolder;
|
||||||
}
|
}
|
||||||
@ -56,7 +56,7 @@ class NotesCache {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Future<void> buildCache(
|
Future<void> buildCache(
|
||||||
NotesFolder rootFolder,
|
NotesFolderFS rootFolder,
|
||||||
SortingMode sortingMode,
|
SortingMode sortingMode,
|
||||||
) async {
|
) async {
|
||||||
if (!enabled) return;
|
if (!enabled) return;
|
||||||
|
@ -1,344 +1,15 @@
|
|||||||
import 'dart:io';
|
|
||||||
|
|
||||||
import 'package:fimber/fimber.dart';
|
|
||||||
import 'package:path/path.dart' as p;
|
|
||||||
import 'package:path/path.dart';
|
|
||||||
|
|
||||||
import 'note.dart';
|
import 'note.dart';
|
||||||
import 'notes_folder_notifier.dart';
|
import 'notes_folder_notifier.dart';
|
||||||
|
|
||||||
abstract class NotesFolderReadOnly implements NotesFolderNotifier {
|
abstract class NotesFolder implements NotesFolderNotifier {
|
||||||
bool get isEmpty;
|
bool get isEmpty;
|
||||||
bool get hasNotes;
|
bool get hasNotes;
|
||||||
|
String get name;
|
||||||
|
|
||||||
List<Note> get notes;
|
List<Note> get notes;
|
||||||
List<NotesFolder> get subFolders;
|
List<NotesFolder> get subFolders;
|
||||||
NotesFolderReadOnly get parent;
|
NotesFolder get parent;
|
||||||
NotesFolder get fsFolder;
|
NotesFolder get fsFolder;
|
||||||
|
|
||||||
String pathSpec();
|
String pathSpec();
|
||||||
}
|
}
|
||||||
|
|
||||||
class NotesFolder
|
|
||||||
with NotesFolderNotifier
|
|
||||||
implements NotesFolderReadOnly, Comparable<NotesFolder> {
|
|
||||||
@override
|
|
||||||
final NotesFolder parent;
|
|
||||||
String _folderPath;
|
|
||||||
|
|
||||||
List<Note> _notes = [];
|
|
||||||
List<NotesFolder> _folders = [];
|
|
||||||
|
|
||||||
Map<String, dynamic> _entityMap = {};
|
|
||||||
|
|
||||||
NotesFolder(this.parent, this._folderPath);
|
|
||||||
|
|
||||||
@override
|
|
||||||
void dispose() {
|
|
||||||
_folders.forEach((f) => f.removeListener(_entityChanged));
|
|
||||||
_notes.forEach((f) => f.removeListener(_entityChanged));
|
|
||||||
|
|
||||||
super.dispose();
|
|
||||||
}
|
|
||||||
|
|
||||||
void _entityChanged() {
|
|
||||||
notifyListeners();
|
|
||||||
}
|
|
||||||
|
|
||||||
void _noteModified(Note note) {
|
|
||||||
notifyNoteModified(-1, note);
|
|
||||||
}
|
|
||||||
|
|
||||||
void reset(String folderPath) {
|
|
||||||
_folderPath = folderPath;
|
|
||||||
|
|
||||||
var notesCopy = List<Note>.from(_notes);
|
|
||||||
notesCopy.forEach(remove);
|
|
||||||
|
|
||||||
var foldersCopy = List<NotesFolder>.from(_folders);
|
|
||||||
foldersCopy.forEach(removeFolder);
|
|
||||||
|
|
||||||
assert(_notes.isEmpty);
|
|
||||||
assert(_folders.isEmpty);
|
|
||||||
|
|
||||||
notifyListeners();
|
|
||||||
}
|
|
||||||
|
|
||||||
String get folderPath => _folderPath;
|
|
||||||
|
|
||||||
@override
|
|
||||||
bool get isEmpty {
|
|
||||||
return _notes.isEmpty && _folders.isEmpty;
|
|
||||||
}
|
|
||||||
|
|
||||||
String get name {
|
|
||||||
return basename(folderPath);
|
|
||||||
}
|
|
||||||
|
|
||||||
String get fullName {
|
|
||||||
String n = name;
|
|
||||||
var par = parent;
|
|
||||||
while (par != null) {
|
|
||||||
n = p.join(par.name, n);
|
|
||||||
par = par.parent;
|
|
||||||
}
|
|
||||||
|
|
||||||
return n;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool get hasSubFolders {
|
|
||||||
return _folders.isNotEmpty;
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
bool get hasNotes {
|
|
||||||
return _notes.isNotEmpty;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool get hasNotesRecursive {
|
|
||||||
if (_notes.isNotEmpty) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (var folder in _folders) {
|
|
||||||
if (folder.hasNotesRecursive) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
int get numberOfNotes {
|
|
||||||
return _notes.length;
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
List<Note> get notes {
|
|
||||||
return _notes;
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
List<NotesFolder> get subFolders {
|
|
||||||
// FIXME: This is really not ideal
|
|
||||||
_folders.sort();
|
|
||||||
return _folders;
|
|
||||||
}
|
|
||||||
|
|
||||||
// FIXME: This asynchronously loads everything. Maybe it should just list them, and the individual _entities
|
|
||||||
// should be loaded as required?
|
|
||||||
Future<void> loadRecursively() async {
|
|
||||||
const maxParallel = 10;
|
|
||||||
var futures = <Future>[];
|
|
||||||
|
|
||||||
await load();
|
|
||||||
|
|
||||||
for (var note in _notes) {
|
|
||||||
// FIXME: Collected all the Errors, and report them back, along with "WHY", and the contents of the Note
|
|
||||||
// Each of these needs to be reported to crashlytics, as Note loading should never fail
|
|
||||||
var f = note.load();
|
|
||||||
futures.add(f);
|
|
||||||
|
|
||||||
if (futures.length >= maxParallel) {
|
|
||||||
await Future.wait(futures);
|
|
||||||
futures = <Future>[];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
await Future.wait(futures);
|
|
||||||
futures = <Future>[];
|
|
||||||
|
|
||||||
for (var folder in _folders) {
|
|
||||||
var f = folder.loadRecursively();
|
|
||||||
futures.add(f);
|
|
||||||
}
|
|
||||||
|
|
||||||
return Future.wait(futures);
|
|
||||||
}
|
|
||||||
|
|
||||||
// FIXME: This should not reconstruct the Notes or NotesFolders once constructed.
|
|
||||||
Future<void> load() async {
|
|
||||||
Set<String> pathsFound = {};
|
|
||||||
|
|
||||||
final dir = Directory(folderPath);
|
|
||||||
var lister = dir.list(recursive: false, followLinks: false);
|
|
||||||
await for (var fsEntity in lister) {
|
|
||||||
if (fsEntity is Link) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// If already seen before
|
|
||||||
var existingNoteFSEntity = _entityMap[fsEntity.path];
|
|
||||||
if (existingNoteFSEntity != null) {
|
|
||||||
pathsFound.add(fsEntity.path);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (fsEntity is Directory) {
|
|
||||||
Fimber.d("Found directory ${fsEntity.path}");
|
|
||||||
var subFolder = NotesFolder(this, fsEntity.path);
|
|
||||||
if (subFolder.name.startsWith('.')) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
subFolder.addListener(_entityChanged);
|
|
||||||
|
|
||||||
_folders.add(subFolder);
|
|
||||||
_entityMap[fsEntity.path] = subFolder;
|
|
||||||
|
|
||||||
pathsFound.add(fsEntity.path);
|
|
||||||
notifyFolderAdded(_folders.length - 1, subFolder);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
var note = Note(this, fsEntity.path);
|
|
||||||
if (!note.filePath.toLowerCase().endsWith('.md')) {
|
|
||||||
Fimber.d("Ignoring file ${fsEntity.path}");
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
Fimber.d("Found file ${fsEntity.path}");
|
|
||||||
note.addModifiedListener(_noteModified);
|
|
||||||
|
|
||||||
_notes.add(note);
|
|
||||||
_entityMap[fsEntity.path] = note;
|
|
||||||
|
|
||||||
pathsFound.add(fsEntity.path);
|
|
||||||
notifyNoteAdded(_notes.length - 1, note);
|
|
||||||
}
|
|
||||||
|
|
||||||
Set<String> pathsRemoved = _entityMap.keys.toSet().difference(pathsFound);
|
|
||||||
pathsRemoved.forEach((path) {
|
|
||||||
var e = _entityMap[path];
|
|
||||||
assert(e != null);
|
|
||||||
|
|
||||||
assert(e is NotesFolder || e is Note);
|
|
||||||
_entityMap.remove(path);
|
|
||||||
|
|
||||||
if (e is Note) {
|
|
||||||
Fimber.d("File $path was no longer found");
|
|
||||||
e.removeModifiedListener(_noteModified);
|
|
||||||
var i = _notes.indexWhere((n) => n.filePath == path);
|
|
||||||
assert(i != -1);
|
|
||||||
var note = _notes[i];
|
|
||||||
_notes.removeAt(i);
|
|
||||||
notifyNoteRemoved(i, note);
|
|
||||||
} else {
|
|
||||||
Fimber.d("Folder $path was no longer found");
|
|
||||||
e.removeListener(_entityChanged);
|
|
||||||
var i = _folders.indexWhere((f) => f.folderPath == path);
|
|
||||||
assert(i != -1);
|
|
||||||
var folder = _folders[i];
|
|
||||||
_folders.removeAt(i);
|
|
||||||
notifyFolderRemoved(i, folder);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
void add(Note note) {
|
|
||||||
assert(note.parent == this);
|
|
||||||
note.addModifiedListener(_noteModified);
|
|
||||||
|
|
||||||
_notes.add(note);
|
|
||||||
_entityMap[note.filePath] = note;
|
|
||||||
|
|
||||||
notifyNoteAdded(_notes.length - 1, note);
|
|
||||||
}
|
|
||||||
|
|
||||||
void insert(int index, Note note) {
|
|
||||||
assert(note.parent == this);
|
|
||||||
assert(index >= 0);
|
|
||||||
note.addModifiedListener(_noteModified);
|
|
||||||
|
|
||||||
_notes.insert(index, note);
|
|
||||||
_entityMap[note.filePath] = note;
|
|
||||||
|
|
||||||
notifyNoteAdded(index, note);
|
|
||||||
}
|
|
||||||
|
|
||||||
void remove(Note note) {
|
|
||||||
assert(note.parent == this);
|
|
||||||
note.removeModifiedListener(_noteModified);
|
|
||||||
|
|
||||||
assert(_notes.indexWhere((n) => n.filePath == note.filePath) != -1);
|
|
||||||
assert(_entityMap.containsKey(note.filePath));
|
|
||||||
|
|
||||||
var index = _notes.indexWhere((n) => n.filePath == note.filePath);
|
|
||||||
assert(index != -1);
|
|
||||||
_notes.removeAt(index);
|
|
||||||
_entityMap.remove(note.filePath);
|
|
||||||
|
|
||||||
notifyNoteRemoved(index, note);
|
|
||||||
}
|
|
||||||
|
|
||||||
void create() {
|
|
||||||
// Git doesn't track Directories, only files, so we create an empty .gitignore file
|
|
||||||
// in the directory instead.
|
|
||||||
var gitIgnoreFilePath = p.join(folderPath, ".gitignore");
|
|
||||||
var file = File(gitIgnoreFilePath);
|
|
||||||
if (!file.existsSync()) {
|
|
||||||
file.createSync(recursive: true);
|
|
||||||
}
|
|
||||||
notifyListeners();
|
|
||||||
}
|
|
||||||
|
|
||||||
void addFolder(NotesFolder folder) {
|
|
||||||
assert(folder.parent == this);
|
|
||||||
folder.addListener(_entityChanged);
|
|
||||||
|
|
||||||
_folders.add(folder);
|
|
||||||
_entityMap[folder.folderPath] = folder;
|
|
||||||
|
|
||||||
notifyFolderAdded(_folders.length - 1, folder);
|
|
||||||
}
|
|
||||||
|
|
||||||
void removeFolder(NotesFolder folder) {
|
|
||||||
folder.removeListener(_entityChanged);
|
|
||||||
|
|
||||||
assert(_folders.indexWhere((f) => f.folderPath == folder.folderPath) != -1);
|
|
||||||
assert(_entityMap.containsKey(folder.folderPath));
|
|
||||||
|
|
||||||
var index = _folders.indexWhere((f) => f.folderPath == folder.folderPath);
|
|
||||||
assert(index != -1);
|
|
||||||
_folders.removeAt(index);
|
|
||||||
_entityMap.remove(folder.folderPath);
|
|
||||||
|
|
||||||
notifyFolderRemoved(index, folder);
|
|
||||||
}
|
|
||||||
|
|
||||||
void rename(String newName) {
|
|
||||||
var dir = Directory(folderPath);
|
|
||||||
var parentDirName = dirname(folderPath);
|
|
||||||
dir.renameSync(folderPath);
|
|
||||||
_folderPath = p.join(parentDirName, newName);
|
|
||||||
|
|
||||||
notifyListeners();
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
String pathSpec() {
|
|
||||||
if (parent == null) {
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
return p.join(parent.pathSpec(), name);
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
int compareTo(NotesFolder other) {
|
|
||||||
return folderPath.compareTo(other.folderPath);
|
|
||||||
}
|
|
||||||
|
|
||||||
Iterable<Note> getAllNotes() sync* {
|
|
||||||
for (var note in _notes) {
|
|
||||||
yield note;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (var folder in _folders) {
|
|
||||||
var notes = folder.getAllNotes();
|
|
||||||
for (var note in notes) {
|
|
||||||
yield note;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
NotesFolder get fsFolder {
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
333
lib/core/notes_folder_fs.dart
Normal file
333
lib/core/notes_folder_fs.dart
Normal file
@ -0,0 +1,333 @@
|
|||||||
|
import 'dart:io';
|
||||||
|
|
||||||
|
import 'package:fimber/fimber.dart';
|
||||||
|
import 'package:path/path.dart' as p;
|
||||||
|
import 'package:path/path.dart';
|
||||||
|
|
||||||
|
import 'note.dart';
|
||||||
|
import 'notes_folder.dart';
|
||||||
|
import 'notes_folder_notifier.dart';
|
||||||
|
|
||||||
|
class NotesFolderFS with NotesFolderNotifier implements NotesFolder {
|
||||||
|
final NotesFolderFS _parent;
|
||||||
|
String _folderPath;
|
||||||
|
|
||||||
|
List<Note> _notes = [];
|
||||||
|
List<NotesFolderFS> _folders = [];
|
||||||
|
|
||||||
|
Map<String, dynamic> _entityMap = {};
|
||||||
|
|
||||||
|
NotesFolderFS(this._parent, this._folderPath);
|
||||||
|
|
||||||
|
@override
|
||||||
|
void dispose() {
|
||||||
|
_folders.forEach((f) => f.removeListener(_entityChanged));
|
||||||
|
_notes.forEach((f) => f.removeListener(_entityChanged));
|
||||||
|
|
||||||
|
super.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
NotesFolder get parent => _parent;
|
||||||
|
|
||||||
|
NotesFolderFS get parentFS => _parent;
|
||||||
|
|
||||||
|
void _entityChanged() {
|
||||||
|
notifyListeners();
|
||||||
|
}
|
||||||
|
|
||||||
|
void _noteModified(Note note) {
|
||||||
|
notifyNoteModified(-1, note);
|
||||||
|
}
|
||||||
|
|
||||||
|
void reset(String folderPath) {
|
||||||
|
_folderPath = folderPath;
|
||||||
|
|
||||||
|
var notesCopy = List<Note>.from(_notes);
|
||||||
|
notesCopy.forEach(remove);
|
||||||
|
|
||||||
|
var foldersCopy = List<NotesFolder>.from(_folders);
|
||||||
|
foldersCopy.forEach(removeFolder);
|
||||||
|
|
||||||
|
assert(_notes.isEmpty);
|
||||||
|
assert(_folders.isEmpty);
|
||||||
|
|
||||||
|
notifyListeners();
|
||||||
|
}
|
||||||
|
|
||||||
|
String get folderPath => _folderPath;
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool get isEmpty {
|
||||||
|
return _notes.isEmpty && _folders.isEmpty;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get name => basename(folderPath);
|
||||||
|
|
||||||
|
String get fullName {
|
||||||
|
String n = name;
|
||||||
|
var par = parent;
|
||||||
|
while (par != null) {
|
||||||
|
n = p.join(par.name, n);
|
||||||
|
par = par.parent;
|
||||||
|
}
|
||||||
|
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool get hasSubFolders {
|
||||||
|
return _folders.isNotEmpty;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool get hasNotes {
|
||||||
|
return _notes.isNotEmpty;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool get hasNotesRecursive {
|
||||||
|
if (_notes.isNotEmpty) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (var folder in _folders) {
|
||||||
|
if (folder.hasNotesRecursive) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
int get numberOfNotes {
|
||||||
|
return _notes.length;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
List<Note> get notes {
|
||||||
|
return _notes;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
List<NotesFolder> get subFolders => subFoldersFS;
|
||||||
|
|
||||||
|
List<NotesFolderFS> get subFoldersFS {
|
||||||
|
// FIXME: This is really not ideal
|
||||||
|
_folders.sort((NotesFolderFS a, NotesFolderFS b) =>
|
||||||
|
a.folderPath.compareTo(b.folderPath));
|
||||||
|
return _folders;
|
||||||
|
}
|
||||||
|
|
||||||
|
// FIXME: This asynchronously loads everything. Maybe it should just list them, and the individual _entities
|
||||||
|
// should be loaded as required?
|
||||||
|
Future<void> loadRecursively() async {
|
||||||
|
const maxParallel = 10;
|
||||||
|
var futures = <Future>[];
|
||||||
|
|
||||||
|
await load();
|
||||||
|
|
||||||
|
for (var note in _notes) {
|
||||||
|
// FIXME: Collected all the Errors, and report them back, along with "WHY", and the contents of the Note
|
||||||
|
// Each of these needs to be reported to crashlytics, as Note loading should never fail
|
||||||
|
var f = note.load();
|
||||||
|
futures.add(f);
|
||||||
|
|
||||||
|
if (futures.length >= maxParallel) {
|
||||||
|
await Future.wait(futures);
|
||||||
|
futures = <Future>[];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
await Future.wait(futures);
|
||||||
|
futures = <Future>[];
|
||||||
|
|
||||||
|
for (var folder in _folders) {
|
||||||
|
var f = folder.loadRecursively();
|
||||||
|
futures.add(f);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Future.wait(futures);
|
||||||
|
}
|
||||||
|
|
||||||
|
// FIXME: This should not reconstruct the Notes or NotesFolders once constructed.
|
||||||
|
Future<void> load() async {
|
||||||
|
Set<String> pathsFound = {};
|
||||||
|
|
||||||
|
final dir = Directory(folderPath);
|
||||||
|
var lister = dir.list(recursive: false, followLinks: false);
|
||||||
|
await for (var fsEntity in lister) {
|
||||||
|
if (fsEntity is Link) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If already seen before
|
||||||
|
var existingNoteFSEntity = _entityMap[fsEntity.path];
|
||||||
|
if (existingNoteFSEntity != null) {
|
||||||
|
pathsFound.add(fsEntity.path);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fsEntity is Directory) {
|
||||||
|
Fimber.d("Found directory ${fsEntity.path}");
|
||||||
|
var subFolder = NotesFolderFS(this, fsEntity.path);
|
||||||
|
if (subFolder.name.startsWith('.')) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
subFolder.addListener(_entityChanged);
|
||||||
|
|
||||||
|
_folders.add(subFolder);
|
||||||
|
_entityMap[fsEntity.path] = subFolder;
|
||||||
|
|
||||||
|
pathsFound.add(fsEntity.path);
|
||||||
|
notifyFolderAdded(_folders.length - 1, subFolder);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
var note = Note(this, fsEntity.path);
|
||||||
|
if (!note.filePath.toLowerCase().endsWith('.md')) {
|
||||||
|
Fimber.d("Ignoring file ${fsEntity.path}");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
Fimber.d("Found file ${fsEntity.path}");
|
||||||
|
note.addModifiedListener(_noteModified);
|
||||||
|
|
||||||
|
_notes.add(note);
|
||||||
|
_entityMap[fsEntity.path] = note;
|
||||||
|
|
||||||
|
pathsFound.add(fsEntity.path);
|
||||||
|
notifyNoteAdded(_notes.length - 1, note);
|
||||||
|
}
|
||||||
|
|
||||||
|
Set<String> pathsRemoved = _entityMap.keys.toSet().difference(pathsFound);
|
||||||
|
pathsRemoved.forEach((path) {
|
||||||
|
var e = _entityMap[path];
|
||||||
|
assert(e != null);
|
||||||
|
|
||||||
|
assert(e is NotesFolder || e is Note);
|
||||||
|
_entityMap.remove(path);
|
||||||
|
|
||||||
|
if (e is Note) {
|
||||||
|
Fimber.d("File $path was no longer found");
|
||||||
|
e.removeModifiedListener(_noteModified);
|
||||||
|
var i = _notes.indexWhere((n) => n.filePath == path);
|
||||||
|
assert(i != -1);
|
||||||
|
var note = _notes[i];
|
||||||
|
_notes.removeAt(i);
|
||||||
|
notifyNoteRemoved(i, note);
|
||||||
|
} else {
|
||||||
|
Fimber.d("Folder $path was no longer found");
|
||||||
|
e.removeListener(_entityChanged);
|
||||||
|
var i = _folders.indexWhere((f) => f.folderPath == path);
|
||||||
|
assert(i != -1);
|
||||||
|
var folder = _folders[i];
|
||||||
|
_folders.removeAt(i);
|
||||||
|
notifyFolderRemoved(i, folder);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void add(Note note) {
|
||||||
|
assert(note.parent == this);
|
||||||
|
note.addModifiedListener(_noteModified);
|
||||||
|
|
||||||
|
_notes.add(note);
|
||||||
|
_entityMap[note.filePath] = note;
|
||||||
|
|
||||||
|
notifyNoteAdded(_notes.length - 1, note);
|
||||||
|
}
|
||||||
|
|
||||||
|
void insert(int index, Note note) {
|
||||||
|
assert(note.parent == this);
|
||||||
|
assert(index >= 0);
|
||||||
|
note.addModifiedListener(_noteModified);
|
||||||
|
|
||||||
|
_notes.insert(index, note);
|
||||||
|
_entityMap[note.filePath] = note;
|
||||||
|
|
||||||
|
notifyNoteAdded(index, note);
|
||||||
|
}
|
||||||
|
|
||||||
|
void remove(Note note) {
|
||||||
|
assert(note.parent == this);
|
||||||
|
note.removeModifiedListener(_noteModified);
|
||||||
|
|
||||||
|
assert(_notes.indexWhere((n) => n.filePath == note.filePath) != -1);
|
||||||
|
assert(_entityMap.containsKey(note.filePath));
|
||||||
|
|
||||||
|
var index = _notes.indexWhere((n) => n.filePath == note.filePath);
|
||||||
|
assert(index != -1);
|
||||||
|
_notes.removeAt(index);
|
||||||
|
_entityMap.remove(note.filePath);
|
||||||
|
|
||||||
|
notifyNoteRemoved(index, note);
|
||||||
|
}
|
||||||
|
|
||||||
|
void create() {
|
||||||
|
// Git doesn't track Directories, only files, so we create an empty .gitignore file
|
||||||
|
// in the directory instead.
|
||||||
|
var gitIgnoreFilePath = p.join(folderPath, ".gitignore");
|
||||||
|
var file = File(gitIgnoreFilePath);
|
||||||
|
if (!file.existsSync()) {
|
||||||
|
file.createSync(recursive: true);
|
||||||
|
}
|
||||||
|
notifyListeners();
|
||||||
|
}
|
||||||
|
|
||||||
|
void addFolder(NotesFolderFS folder) {
|
||||||
|
assert(folder.parent == this);
|
||||||
|
folder.addListener(_entityChanged);
|
||||||
|
|
||||||
|
_folders.add(folder);
|
||||||
|
_entityMap[folder.folderPath] = folder;
|
||||||
|
|
||||||
|
notifyFolderAdded(_folders.length - 1, folder);
|
||||||
|
}
|
||||||
|
|
||||||
|
void removeFolder(NotesFolderFS folder) {
|
||||||
|
folder.removeListener(_entityChanged);
|
||||||
|
|
||||||
|
assert(_folders.indexWhere((f) => f.folderPath == folder.folderPath) != -1);
|
||||||
|
assert(_entityMap.containsKey(folder.folderPath));
|
||||||
|
|
||||||
|
var index = _folders.indexWhere((f) => f.folderPath == folder.folderPath);
|
||||||
|
assert(index != -1);
|
||||||
|
_folders.removeAt(index);
|
||||||
|
_entityMap.remove(folder.folderPath);
|
||||||
|
|
||||||
|
notifyFolderRemoved(index, folder);
|
||||||
|
}
|
||||||
|
|
||||||
|
void rename(String newName) {
|
||||||
|
var dir = Directory(folderPath);
|
||||||
|
var parentDirName = dirname(folderPath);
|
||||||
|
dir.renameSync(folderPath);
|
||||||
|
_folderPath = p.join(parentDirName, newName);
|
||||||
|
|
||||||
|
notifyListeners();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
String pathSpec() {
|
||||||
|
if (parent == null) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
return p.join(parent.pathSpec(), name);
|
||||||
|
}
|
||||||
|
|
||||||
|
Iterable<Note> getAllNotes() sync* {
|
||||||
|
for (var note in _notes) {
|
||||||
|
yield note;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (var folder in _folders) {
|
||||||
|
var notes = folder.getAllNotes();
|
||||||
|
for (var note in notes) {
|
||||||
|
yield note;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
NotesFolder get fsFolder {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
}
|
@ -6,10 +6,8 @@ import 'note.dart';
|
|||||||
import 'notes_folder.dart';
|
import 'notes_folder.dart';
|
||||||
import 'notes_folder_notifier.dart';
|
import 'notes_folder_notifier.dart';
|
||||||
|
|
||||||
class SortedNotesFolder
|
class SortedNotesFolder with NotesFolderNotifier implements NotesFolder {
|
||||||
with NotesFolderNotifier
|
final NotesFolder folder;
|
||||||
implements NotesFolderReadOnly {
|
|
||||||
final NotesFolderReadOnly folder;
|
|
||||||
|
|
||||||
SortingMode _sortingMode;
|
SortingMode _sortingMode;
|
||||||
NoteSortingFunction _sortFunc;
|
NoteSortingFunction _sortFunc;
|
||||||
@ -127,6 +125,9 @@ class SortedNotesFolder
|
|||||||
@override
|
@override
|
||||||
String pathSpec() => folder.pathSpec();
|
String pathSpec() => folder.pathSpec();
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get name => folder.name;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
NotesFolder get fsFolder {
|
NotesFolder get fsFolder {
|
||||||
return folder;
|
return folder;
|
||||||
|
@ -2,9 +2,7 @@ import 'note.dart';
|
|||||||
import 'notes_folder.dart';
|
import 'notes_folder.dart';
|
||||||
import 'notes_folder_notifier.dart';
|
import 'notes_folder_notifier.dart';
|
||||||
|
|
||||||
class VirtualNotesFolder
|
class VirtualNotesFolder with NotesFolderNotifier implements NotesFolder {
|
||||||
with NotesFolderNotifier
|
|
||||||
implements NotesFolderReadOnly {
|
|
||||||
final List<Note> _notes;
|
final List<Note> _notes;
|
||||||
|
|
||||||
VirtualNotesFolder(this._notes);
|
VirtualNotesFolder(this._notes);
|
||||||
@ -27,6 +25,9 @@ class VirtualNotesFolder
|
|||||||
@override
|
@override
|
||||||
String pathSpec() => "";
|
String pathSpec() => "";
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get name => "";
|
||||||
|
|
||||||
@override
|
@override
|
||||||
NotesFolder get fsFolder {
|
NotesFolder get fsFolder {
|
||||||
return null;
|
return null;
|
||||||
|
@ -8,7 +8,7 @@ typedef void NoteSelectedFunction(Note note);
|
|||||||
|
|
||||||
class CardView extends StatelessWidget {
|
class CardView extends StatelessWidget {
|
||||||
final NoteSelectedFunction noteSelectedFunction;
|
final NoteSelectedFunction noteSelectedFunction;
|
||||||
final NotesFolderReadOnly folder;
|
final NotesFolder folder;
|
||||||
final String emptyText;
|
final String emptyText;
|
||||||
|
|
||||||
CardView({
|
CardView({
|
||||||
|
@ -18,7 +18,7 @@ enum FolderViewType {
|
|||||||
Widget buildFolderView(
|
Widget buildFolderView(
|
||||||
BuildContext context,
|
BuildContext context,
|
||||||
FolderViewType viewType,
|
FolderViewType viewType,
|
||||||
NotesFolderReadOnly folder,
|
NotesFolder folder,
|
||||||
String emptyText,
|
String emptyText,
|
||||||
StandardViewHeader header,
|
StandardViewHeader header,
|
||||||
bool showSummary,
|
bool showSummary,
|
||||||
|
@ -11,7 +11,7 @@ import 'package:gitjournal/core/notes_folder.dart';
|
|||||||
|
|
||||||
class JournalView extends StatelessWidget {
|
class JournalView extends StatelessWidget {
|
||||||
final NoteSelectedFunction noteSelectedFunction;
|
final NoteSelectedFunction noteSelectedFunction;
|
||||||
final NotesFolderReadOnly folder;
|
final NotesFolder folder;
|
||||||
final String emptyText;
|
final String emptyText;
|
||||||
|
|
||||||
JournalView({
|
JournalView({
|
||||||
|
@ -15,7 +15,7 @@ typedef Widget NoteTileBuilder(BuildContext context, Note note);
|
|||||||
class FolderListView extends StatefulWidget {
|
class FolderListView extends StatefulWidget {
|
||||||
final NoteTileBuilder noteTileBuilder;
|
final NoteTileBuilder noteTileBuilder;
|
||||||
final NoteSelectedFunction noteSelectedFunction;
|
final NoteSelectedFunction noteSelectedFunction;
|
||||||
final NotesFolderReadOnly folder;
|
final NotesFolder folder;
|
||||||
final String emptyText;
|
final String emptyText;
|
||||||
|
|
||||||
FolderListView({
|
FolderListView({
|
||||||
|
@ -17,7 +17,7 @@ enum StandardViewHeader {
|
|||||||
|
|
||||||
class StandardView extends StatelessWidget {
|
class StandardView extends StatelessWidget {
|
||||||
final NoteSelectedFunction noteSelectedFunction;
|
final NoteSelectedFunction noteSelectedFunction;
|
||||||
final NotesFolderReadOnly folder;
|
final NotesFolder folder;
|
||||||
final String emptyText;
|
final String emptyText;
|
||||||
|
|
||||||
final StandardViewHeader headerType;
|
final StandardViewHeader headerType;
|
||||||
|
@ -6,7 +6,7 @@ import 'package:gitjournal/widgets/app_drawer.dart';
|
|||||||
import 'package:gitjournal/widgets/folder_tree_view.dart';
|
import 'package:gitjournal/widgets/folder_tree_view.dart';
|
||||||
import 'package:gitjournal/widgets/rename_dialog.dart';
|
import 'package:gitjournal/widgets/rename_dialog.dart';
|
||||||
import 'package:gitjournal/state_container.dart';
|
import 'package:gitjournal/state_container.dart';
|
||||||
import 'package:gitjournal/core/notes_folder.dart';
|
import 'package:gitjournal/core/notes_folder_fs.dart';
|
||||||
|
|
||||||
import 'folder_view.dart';
|
import 'folder_view.dart';
|
||||||
|
|
||||||
@ -17,16 +17,16 @@ class FolderListingScreen extends StatefulWidget {
|
|||||||
|
|
||||||
class _FolderListingScreenState extends State<FolderListingScreen> {
|
class _FolderListingScreenState extends State<FolderListingScreen> {
|
||||||
final _folderTreeViewKey = GlobalKey<FolderTreeViewState>();
|
final _folderTreeViewKey = GlobalKey<FolderTreeViewState>();
|
||||||
NotesFolder selectedFolder;
|
NotesFolderFS selectedFolder;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final notesFolder = Provider.of<NotesFolder>(context);
|
final notesFolder = Provider.of<NotesFolderFS>(context);
|
||||||
|
|
||||||
var treeView = FolderTreeView(
|
var treeView = FolderTreeView(
|
||||||
key: _folderTreeViewKey,
|
key: _folderTreeViewKey,
|
||||||
rootFolder: notesFolder,
|
rootFolder: notesFolder,
|
||||||
onFolderEntered: (NotesFolder folder) {
|
onFolderEntered: (NotesFolderFS folder) {
|
||||||
var route = MaterialPageRoute(
|
var route = MaterialPageRoute(
|
||||||
builder: (context) => FolderView(
|
builder: (context) => FolderView(
|
||||||
notesFolder: folder,
|
notesFolder: folder,
|
||||||
@ -147,7 +147,7 @@ class CreateFolderButton extends StatelessWidget {
|
|||||||
);
|
);
|
||||||
if (folderName is String) {
|
if (folderName is String) {
|
||||||
var container = Provider.of<StateContainer>(context, listen: false);
|
var container = Provider.of<StateContainer>(context, listen: false);
|
||||||
final notesFolder = Provider.of<NotesFolder>(context);
|
final notesFolder = Provider.of<NotesFolderFS>(context);
|
||||||
|
|
||||||
container.createFolder(notesFolder, folderName);
|
container.createFolder(notesFolder, folderName);
|
||||||
}
|
}
|
||||||
|
@ -23,7 +23,7 @@ enum DropDownChoices {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class FolderView extends StatefulWidget {
|
class FolderView extends StatefulWidget {
|
||||||
final NotesFolderReadOnly notesFolder;
|
final NotesFolder notesFolder;
|
||||||
|
|
||||||
FolderView({@required this.notesFolder});
|
FolderView({@required this.notesFolder});
|
||||||
|
|
||||||
|
@ -2,7 +2,7 @@ import 'package:flutter/material.dart';
|
|||||||
import 'package:gitjournal/core/flattened_notes_folder.dart';
|
import 'package:gitjournal/core/flattened_notes_folder.dart';
|
||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
|
|
||||||
import 'package:gitjournal/core/notes_folder.dart';
|
import 'package:gitjournal/core/notes_folder_fs.dart';
|
||||||
|
|
||||||
import 'folder_view.dart';
|
import 'folder_view.dart';
|
||||||
|
|
||||||
@ -18,7 +18,7 @@ class _HomeScreenState extends State<HomeScreen> {
|
|||||||
void initState() {
|
void initState() {
|
||||||
super.initState();
|
super.initState();
|
||||||
Future.delayed(Duration.zero, () {
|
Future.delayed(Duration.zero, () {
|
||||||
final rootFolder = Provider.of<NotesFolder>(context);
|
final rootFolder = Provider.of<NotesFolderFS>(context);
|
||||||
setState(() {
|
setState(() {
|
||||||
flattenedNotesFolder = FlattenedNotesFolder(rootFolder);
|
flattenedNotesFolder = FlattenedNotesFolder(rootFolder);
|
||||||
});
|
});
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:gitjournal/core/notes_folder.dart';
|
import 'package:gitjournal/core/notes_folder_fs.dart';
|
||||||
import 'package:gitjournal/settings.dart';
|
import 'package:gitjournal/settings.dart';
|
||||||
import 'package:gitjournal/state_container.dart';
|
import 'package:gitjournal/state_container.dart';
|
||||||
import 'package:gitjournal/utils.dart';
|
import 'package:gitjournal/utils.dart';
|
||||||
@ -142,7 +142,7 @@ class SettingsListState extends State<SettingsList> {
|
|||||||
subtitle: Text(Settings.instance.defaultNewNoteFolder
|
subtitle: Text(Settings.instance.defaultNewNoteFolder
|
||||||
.replaceFirst('journal', 'Notes')),
|
.replaceFirst('journal', 'Notes')),
|
||||||
onTap: () async {
|
onTap: () async {
|
||||||
var destFolder = await showDialog<NotesFolder>(
|
var destFolder = await showDialog<NotesFolderFS>(
|
||||||
context: context,
|
context: context,
|
||||||
builder: (context) => FolderSelectionDialog(),
|
builder: (context) => FolderSelectionDialog(),
|
||||||
);
|
);
|
||||||
|
@ -8,7 +8,7 @@ import 'package:gitjournal/apis/git_migration.dart';
|
|||||||
import 'package:gitjournal/appstate.dart';
|
import 'package:gitjournal/appstate.dart';
|
||||||
import 'package:gitjournal/core/note.dart';
|
import 'package:gitjournal/core/note.dart';
|
||||||
import 'package:gitjournal/core/notes_cache.dart';
|
import 'package:gitjournal/core/notes_cache.dart';
|
||||||
import 'package:gitjournal/core/notes_folder.dart';
|
import 'package:gitjournal/core/notes_folder_fs.dart';
|
||||||
import 'package:gitjournal/core/git_repo.dart';
|
import 'package:gitjournal/core/git_repo.dart';
|
||||||
import 'package:gitjournal/settings.dart';
|
import 'package:gitjournal/settings.dart';
|
||||||
import 'package:path/path.dart' as p;
|
import 'package:path/path.dart' as p;
|
||||||
@ -37,7 +37,7 @@ class StateContainer with ChangeNotifier {
|
|||||||
}
|
}
|
||||||
|
|
||||||
_gitRepo = GitNoteRepository(gitDirPath: repoPath);
|
_gitRepo = GitNoteRepository(gitDirPath: repoPath);
|
||||||
appState.notesFolder = NotesFolder(null, _gitRepo.gitDirPath);
|
appState.notesFolder = NotesFolderFS(null, _gitRepo.gitDirPath);
|
||||||
|
|
||||||
// Just a fail safe
|
// Just a fail safe
|
||||||
if (!appState.remoteGitRepoConfigured) {
|
if (!appState.remoteGitRepoConfigured) {
|
||||||
@ -117,9 +117,9 @@ class StateContainer with ChangeNotifier {
|
|||||||
return syncNotes(doNotThrow: true);
|
return syncNotes(doNotThrow: true);
|
||||||
}
|
}
|
||||||
|
|
||||||
void createFolder(NotesFolder parent, String folderName) async {
|
void createFolder(NotesFolderFS parent, String folderName) async {
|
||||||
var newFolderPath = p.join(parent.folderPath, folderName);
|
var newFolderPath = p.join(parent.folderPath, folderName);
|
||||||
var newFolder = NotesFolder(parent, newFolderPath);
|
var newFolder = NotesFolderFS(parent, newFolderPath);
|
||||||
newFolder.create();
|
newFolder.create();
|
||||||
|
|
||||||
Fimber.d("Created New Folder: " + newFolderPath);
|
Fimber.d("Created New Folder: " + newFolderPath);
|
||||||
@ -130,16 +130,16 @@ class StateContainer with ChangeNotifier {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void removeFolder(NotesFolder folder) {
|
void removeFolder(NotesFolderFS folder) {
|
||||||
Fimber.d("Removing Folder: " + folder.folderPath);
|
Fimber.d("Removing Folder: " + folder.folderPath);
|
||||||
|
|
||||||
folder.parent.removeFolder(folder);
|
folder.parentFS.removeFolder(folder);
|
||||||
_gitRepo.removeFolder(folder.folderPath).then((NoteRepoResult _) {
|
_gitRepo.removeFolder(folder.folderPath).then((NoteRepoResult _) {
|
||||||
_syncNotes();
|
_syncNotes();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void renameFolder(NotesFolder folder, String newFolderName) {
|
void renameFolder(NotesFolderFS folder, String newFolderName) {
|
||||||
var oldFolderPath = folder.folderPath;
|
var oldFolderPath = folder.folderPath;
|
||||||
folder.rename(newFolderName);
|
folder.rename(newFolderName);
|
||||||
|
|
||||||
@ -159,7 +159,7 @@ class StateContainer with ChangeNotifier {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void moveNote(Note note, NotesFolder destFolder) {
|
void moveNote(Note note, NotesFolderFS destFolder) {
|
||||||
if (destFolder.folderPath == note.parent.folderPath) {
|
if (destFolder.folderPath == note.parent.folderPath) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -1,19 +1,20 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:gitjournal/core/notes_folder.dart';
|
|
||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
|
|
||||||
typedef NoteFolderCallback = void Function(NotesFolder);
|
import 'package:gitjournal/core/notes_folder_fs.dart';
|
||||||
|
|
||||||
|
typedef NoteFolderCallback = void Function(NotesFolderFS);
|
||||||
|
|
||||||
class FolderSelectionDialog extends StatelessWidget {
|
class FolderSelectionDialog extends StatelessWidget {
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final notesFolder = Provider.of<NotesFolder>(context);
|
final notesFolder = Provider.of<NotesFolderFS>(context);
|
||||||
|
|
||||||
var body = Container(
|
var body = Container(
|
||||||
width: double.maxFinite,
|
width: double.maxFinite,
|
||||||
child: FolderTreeView(
|
child: FolderTreeView(
|
||||||
rootFolder: notesFolder,
|
rootFolder: notesFolder,
|
||||||
onFolderEntered: (NotesFolder destFolder) {
|
onFolderEntered: (NotesFolderFS destFolder) {
|
||||||
Navigator.of(context).pop(destFolder);
|
Navigator.of(context).pop(destFolder);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
@ -26,10 +27,10 @@ class FolderSelectionDialog extends StatelessWidget {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
typedef void FolderSelectedCallback(NotesFolder folder);
|
typedef void FolderSelectedCallback(NotesFolderFS folder);
|
||||||
|
|
||||||
class FolderTreeView extends StatelessWidget {
|
class FolderTreeView extends StatelessWidget {
|
||||||
final NotesFolder rootFolder;
|
final NotesFolderFS rootFolder;
|
||||||
final FolderSelectedCallback onFolderEntered;
|
final FolderSelectedCallback onFolderEntered;
|
||||||
|
|
||||||
FolderTreeView({
|
FolderTreeView({
|
||||||
@ -52,7 +53,7 @@ class FolderTreeView extends StatelessWidget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class FolderMiniTile extends StatefulWidget {
|
class FolderMiniTile extends StatefulWidget {
|
||||||
final NotesFolder folder;
|
final NotesFolderFS folder;
|
||||||
final FolderSelectedCallback onTap;
|
final FolderSelectedCallback onTap;
|
||||||
|
|
||||||
FolderMiniTile({
|
FolderMiniTile({
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
import 'package:gitjournal/core/notes_folder.dart';
|
import 'package:gitjournal/core/notes_folder_fs.dart';
|
||||||
|
|
||||||
typedef void FolderSelectedCallback(NotesFolder folder);
|
typedef void FolderSelectedCallback(NotesFolderFS folder);
|
||||||
|
|
||||||
class FolderTreeView extends StatefulWidget {
|
class FolderTreeView extends StatefulWidget {
|
||||||
final NotesFolder rootFolder;
|
final NotesFolderFS rootFolder;
|
||||||
|
|
||||||
final FolderSelectedCallback onFolderSelected;
|
final FolderSelectedCallback onFolderSelected;
|
||||||
final Function onFolderUnselected;
|
final Function onFolderUnselected;
|
||||||
@ -22,18 +22,18 @@ class FolderTreeView extends StatefulWidget {
|
|||||||
@override
|
@override
|
||||||
FolderTreeViewState createState() => FolderTreeViewState();
|
FolderTreeViewState createState() => FolderTreeViewState();
|
||||||
|
|
||||||
static void _doNothing(NotesFolder f) {}
|
static void _doNothing(NotesFolderFS f) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
class FolderTreeViewState extends State<FolderTreeView> {
|
class FolderTreeViewState extends State<FolderTreeView> {
|
||||||
bool inSelectionMode = false;
|
bool inSelectionMode = false;
|
||||||
NotesFolder selectedFolder;
|
NotesFolderFS selectedFolder;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
var tile = FolderTile(
|
var tile = FolderTile(
|
||||||
folder: widget.rootFolder,
|
folder: widget.rootFolder,
|
||||||
onTap: (NotesFolder folder) {
|
onTap: (NotesFolderFS folder) {
|
||||||
if (!inSelectionMode) {
|
if (!inSelectionMode) {
|
||||||
widget.onFolderEntered(folder);
|
widget.onFolderEntered(folder);
|
||||||
} else {
|
} else {
|
||||||
@ -68,10 +68,10 @@ class FolderTreeViewState extends State<FolderTreeView> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class FolderTile extends StatefulWidget {
|
class FolderTile extends StatefulWidget {
|
||||||
final NotesFolder folder;
|
final NotesFolderFS folder;
|
||||||
final FolderSelectedCallback onTap;
|
final FolderSelectedCallback onTap;
|
||||||
final FolderSelectedCallback onLongPress;
|
final FolderSelectedCallback onLongPress;
|
||||||
final NotesFolder selectedFolder;
|
final NotesFolderFS selectedFolder;
|
||||||
|
|
||||||
FolderTile({
|
FolderTile({
|
||||||
@required this.folder,
|
@required this.folder,
|
||||||
|
@ -2,7 +2,7 @@ import 'dart:io';
|
|||||||
|
|
||||||
import 'package:gitjournal/core/checklist.dart';
|
import 'package:gitjournal/core/checklist.dart';
|
||||||
import 'package:gitjournal/core/note.dart';
|
import 'package:gitjournal/core/note.dart';
|
||||||
import 'package:gitjournal/core/notes_folder.dart';
|
import 'package:gitjournal/core/notes_folder_fs.dart';
|
||||||
import 'package:path/path.dart' as p;
|
import 'package:path/path.dart' as p;
|
||||||
import 'package:test/test.dart';
|
import 'package:test/test.dart';
|
||||||
|
|
||||||
@ -39,7 +39,7 @@ Booga Wooga
|
|||||||
var notePath = p.join(tempDir.path, "note.md");
|
var notePath = p.join(tempDir.path, "note.md");
|
||||||
File(notePath).writeAsString(content);
|
File(notePath).writeAsString(content);
|
||||||
|
|
||||||
var parentFolder = NotesFolder(null, tempDir.path);
|
var parentFolder = NotesFolderFS(null, tempDir.path);
|
||||||
var note = Note(parentFolder, notePath);
|
var note = Note(parentFolder, notePath);
|
||||||
await note.load();
|
await note.load();
|
||||||
|
|
||||||
@ -114,7 +114,7 @@ Booga Wooga
|
|||||||
var notePath = p.join(tempDir.path, "note2.md");
|
var notePath = p.join(tempDir.path, "note2.md");
|
||||||
await File(notePath).writeAsString(content);
|
await File(notePath).writeAsString(content);
|
||||||
|
|
||||||
var parentFolder = NotesFolder(null, tempDir.path);
|
var parentFolder = NotesFolderFS(null, tempDir.path);
|
||||||
var note = Note(parentFolder, notePath);
|
var note = Note(parentFolder, notePath);
|
||||||
await note.load();
|
await note.load();
|
||||||
|
|
||||||
@ -136,7 +136,7 @@ Booga Wooga
|
|||||||
var notePath = p.join(tempDir.path, "note3.md");
|
var notePath = p.join(tempDir.path, "note3.md");
|
||||||
await File(notePath).writeAsString(content);
|
await File(notePath).writeAsString(content);
|
||||||
|
|
||||||
var parentFolder = NotesFolder(null, tempDir.path);
|
var parentFolder = NotesFolderFS(null, tempDir.path);
|
||||||
var note = Note(parentFolder, notePath);
|
var note = Note(parentFolder, notePath);
|
||||||
await note.load();
|
await note.load();
|
||||||
|
|
||||||
@ -156,7 +156,7 @@ Booga Wooga
|
|||||||
var notePath = p.join(tempDir.path, "note13.md");
|
var notePath = p.join(tempDir.path, "note13.md");
|
||||||
await File(notePath).writeAsString(content);
|
await File(notePath).writeAsString(content);
|
||||||
|
|
||||||
var parentFolder = NotesFolder(null, tempDir.path);
|
var parentFolder = NotesFolderFS(null, tempDir.path);
|
||||||
var note = Note(parentFolder, notePath);
|
var note = Note(parentFolder, notePath);
|
||||||
await note.load();
|
await note.load();
|
||||||
|
|
||||||
@ -176,7 +176,7 @@ Booga Wooga
|
|||||||
var notePath = p.join(tempDir.path, "note4.md");
|
var notePath = p.join(tempDir.path, "note4.md");
|
||||||
await File(notePath).writeAsString(content);
|
await File(notePath).writeAsString(content);
|
||||||
|
|
||||||
var parentFolder = NotesFolder(null, tempDir.path);
|
var parentFolder = NotesFolderFS(null, tempDir.path);
|
||||||
var note = Note(parentFolder, notePath);
|
var note = Note(parentFolder, notePath);
|
||||||
await note.load();
|
await note.load();
|
||||||
|
|
||||||
@ -196,7 +196,7 @@ Booga Wooga
|
|||||||
var notePath = p.join(tempDir.path, "note4.md");
|
var notePath = p.join(tempDir.path, "note4.md");
|
||||||
await File(notePath).writeAsString(content);
|
await File(notePath).writeAsString(content);
|
||||||
|
|
||||||
var parentFolder = NotesFolder(null, tempDir.path);
|
var parentFolder = NotesFolderFS(null, tempDir.path);
|
||||||
var note = Note(parentFolder, notePath);
|
var note = Note(parentFolder, notePath);
|
||||||
await note.load();
|
await note.load();
|
||||||
|
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import 'dart:io';
|
import 'dart:io';
|
||||||
|
|
||||||
import 'package:gitjournal/core/note.dart';
|
import 'package:gitjournal/core/note.dart';
|
||||||
import 'package:gitjournal/core/notes_folder.dart';
|
import 'package:gitjournal/core/notes_folder_fs.dart';
|
||||||
import 'package:path/path.dart' as p;
|
import 'package:path/path.dart' as p;
|
||||||
import 'package:test/test.dart';
|
import 'package:test/test.dart';
|
||||||
|
|
||||||
@ -28,7 +28,7 @@ Hello""";
|
|||||||
var notePath = p.join(tempDir.path, "note.md");
|
var notePath = p.join(tempDir.path, "note.md");
|
||||||
File(notePath).writeAsString(content);
|
File(notePath).writeAsString(content);
|
||||||
|
|
||||||
var parentFolder = NotesFolder(null, tempDir.path);
|
var parentFolder = NotesFolderFS(null, tempDir.path);
|
||||||
var note = Note(parentFolder, notePath);
|
var note = Note(parentFolder, notePath);
|
||||||
await note.load();
|
await note.load();
|
||||||
|
|
||||||
@ -58,7 +58,7 @@ Hello""";
|
|||||||
var notePath = p.join(tempDir.path, "note.md");
|
var notePath = p.join(tempDir.path, "note.md");
|
||||||
File(notePath).writeAsString(content);
|
File(notePath).writeAsString(content);
|
||||||
|
|
||||||
var parentFolder = NotesFolder(null, tempDir.path);
|
var parentFolder = NotesFolderFS(null, tempDir.path);
|
||||||
var note = Note(parentFolder, notePath);
|
var note = Note(parentFolder, notePath);
|
||||||
await note.load();
|
await note.load();
|
||||||
|
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import 'dart:io';
|
import 'dart:io';
|
||||||
|
|
||||||
import 'package:gitjournal/core/notes_cache.dart';
|
import 'package:gitjournal/core/notes_cache.dart';
|
||||||
import 'package:gitjournal/core/notes_folder.dart';
|
import 'package:gitjournal/core/notes_folder_fs.dart';
|
||||||
import 'package:path/path.dart' as p;
|
import 'package:path/path.dart' as p;
|
||||||
import 'package:test/test.dart';
|
import 'package:test/test.dart';
|
||||||
|
|
||||||
@ -39,7 +39,7 @@ void main() {
|
|||||||
|
|
||||||
test('Should create directory structure accurately', () async {
|
test('Should create directory structure accurately', () async {
|
||||||
await cache.saveToDisk(fileList);
|
await cache.saveToDisk(fileList);
|
||||||
var rootFolder = NotesFolder(null, '/base');
|
var rootFolder = NotesFolderFS(null, '/base');
|
||||||
await cache.load(rootFolder);
|
await cache.load(rootFolder);
|
||||||
|
|
||||||
expect(rootFolder.subFolders.length, 2);
|
expect(rootFolder.subFolders.length, 2);
|
||||||
|
@ -1,12 +1,12 @@
|
|||||||
import 'package:gitjournal/core/note.dart';
|
import 'package:gitjournal/core/note.dart';
|
||||||
import 'package:gitjournal/core/notes_folder.dart';
|
import 'package:gitjournal/core/notes_folder_fs.dart';
|
||||||
import 'package:gitjournal/core/sorting_mode.dart';
|
import 'package:gitjournal/core/sorting_mode.dart';
|
||||||
import 'package:test/test.dart';
|
import 'package:test/test.dart';
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
group('Sorting Mode', () {
|
group('Sorting Mode', () {
|
||||||
test('Created', () async {
|
test('Created', () async {
|
||||||
var folder = NotesFolder(null, '/tmp/');
|
var folder = NotesFolderFS(null, '/tmp/');
|
||||||
var n1 = Note(folder, '/tmp/1.md');
|
var n1 = Note(folder, '/tmp/1.md');
|
||||||
n1.created = DateTime(2020, 10, 01);
|
n1.created = DateTime(2020, 10, 01);
|
||||||
|
|
||||||
@ -30,7 +30,7 @@ void main() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('Modified', () async {
|
test('Modified', () async {
|
||||||
var folder = NotesFolder(null, '/tmp/');
|
var folder = NotesFolderFS(null, '/tmp/');
|
||||||
var n1 = Note(folder, '/tmp/1.md');
|
var n1 = Note(folder, '/tmp/1.md');
|
||||||
n1.modified = DateTime(2020, 10, 01);
|
n1.modified = DateTime(2020, 10, 01);
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user