Note: Replace 'id' with 'fileName'

It all just makes far more since when each Note has a fileName.

Though we don't save the fileName in the YAML header. It seems quite
redundant to do that.

Another advantage of this is that if we can read any file ending with a
'.md' in a git repo. It doesn't need to be named exactly how we want it,
and we will still save the details correctly.
This commit is contained in:
Vishesh Handa
2019-01-18 16:00:44 +01:00
parent 99392955c9
commit c99fe854a1
8 changed files with 37 additions and 51 deletions

View File

@ -5,23 +5,23 @@ typedef NoteRemover(Note note);
typedef NoteUpdator(Note note); typedef NoteUpdator(Note note);
class Note implements Comparable { class Note implements Comparable {
String id; String fileName;
DateTime created; DateTime created;
String body; String body;
Map<String, dynamic> extraProperties = new Map<String, dynamic>(); Map<String, dynamic> extraProperties = new Map<String, dynamic>();
Note({this.created, this.body, this.id, this.extraProperties}) { Note({this.created, this.body, this.fileName, this.extraProperties}) {
if (extraProperties == null) { if (extraProperties == null) {
extraProperties = new Map<String, dynamic>(); extraProperties = new Map<String, dynamic>();
} }
} }
factory Note.fromJson(Map<String, dynamic> json) { factory Note.fromJson(Map<String, dynamic> json) {
String id; String fileName = "";
if (json.containsKey("id")) { if (json.containsKey("fileName")) {
id = json["id"].toString(); fileName = json["fileName"].toString();
json.remove("id"); json.remove("fileName");
} }
DateTime created; DateTime created;
@ -50,10 +50,6 @@ class Note implements Comparable {
json.remove("created"); json.remove("created");
} }
if (id == null && created != null) {
id = toIso8601WithTimezone(created);
}
String body = ""; String body = "";
if (json.containsKey("body")) { if (json.containsKey("body")) {
body = json['body']; body = json['body'];
@ -61,7 +57,7 @@ class Note implements Comparable {
} }
return new Note( return new Note(
id: id, fileName: fileName,
created: created, created: created,
body: body, body: body,
extraProperties: json, extraProperties: json,
@ -72,21 +68,24 @@ class Note implements Comparable {
var json = Map<String, dynamic>.from(extraProperties); var json = Map<String, dynamic>.from(extraProperties);
json['created'] = toIso8601WithTimezone(created); json['created'] = toIso8601WithTimezone(created);
json['body'] = body; json['body'] = body;
json['id'] = id; json['fileName'] = fileName;
return json; return json;
} }
@override @override
int get hashCode => int get hashCode =>
id.hashCode ^ created.hashCode ^ body.hashCode ^ extraProperties.hashCode; fileName.hashCode ^
created.hashCode ^
body.hashCode ^
extraProperties.hashCode;
@override @override
bool operator ==(Object other) => bool operator ==(Object other) =>
identical(this, other) || identical(this, other) ||
other is Note && other is Note &&
runtimeType == other.runtimeType && runtimeType == other.runtimeType &&
id == other.id && fileName == other.fileName &&
body == other.body && body == other.body &&
created == other.created && created == other.created &&
_equalMaps(extraProperties, other.extraProperties); _equalMaps(extraProperties, other.extraProperties);
@ -98,7 +97,7 @@ class Note implements Comparable {
@override @override
String toString() { String toString() {
return 'Note{id: $id, body: $body, created: $created, extraProperties: $extraProperties}'; return 'Note{fileName: $fileName, body: $body, created: $created, extraProperties: $extraProperties}';
} }
@override @override

View File

@ -49,7 +49,6 @@ class StateContainerState extends State<StateContainer> {
getDirectory: getNotesDir, getDirectory: getNotesDir,
dirName: "journal", dirName: "journal",
gitCloneUrl: "root@bcn.vhanda.in:git/test", gitCloneUrl: "root@bcn.vhanda.in:git/test",
fileNameGenerator: (Note n) => toIso8601WithTimezone(n.created) + '.md',
); );
StateContainerState(bool onBoardingCompleted) { StateContainerState(bool onBoardingCompleted) {
@ -140,9 +139,10 @@ class StateContainerState extends State<StateContainer> {
} }
void insertNote(int index, Note note) { void insertNote(int index, Note note) {
print("State Container insertNote");
setState(() { setState(() {
if (note.id == null || note.id.isEmpty) { if (note.fileName == null || note.fileName.isEmpty) {
note.id = toIso8601WithTimezone(note.created); note.fileName = toIso8601WithTimezone(note.created) + '.md';
} }
appState.notes.insert(index, note); appState.notes.insert(index, note);
noteRepo.addNote(note).then((NoteRepoResult _) { noteRepo.addNote(note).then((NoteRepoResult _) {
@ -152,6 +152,7 @@ class StateContainerState extends State<StateContainer> {
} }
void updateNote(Note note) { void updateNote(Note note) {
print("State Container updateNote");
setState(() { setState(() {
noteRepo.updateNote(note).then((NoteRepoResult _) { noteRepo.updateNote(note).then((NoteRepoResult _) {
_syncNotes(); _syncNotes();

View File

@ -10,15 +10,14 @@ import 'package:path/path.dart' as p;
typedef String NoteFileNameGenerator(Note note); typedef String NoteFileNameGenerator(Note note);
/// Each Note is saved in a different file /// Each Note is saved in a different file
/// Each note must have a fileName which ends in a .md
class FileStorage implements NoteRepository { class FileStorage implements NoteRepository {
final Future<Directory> Function() getDirectory; final Future<Directory> Function() getDirectory;
final NoteSerializer noteSerializer; final NoteSerializer noteSerializer;
final NoteFileNameGenerator fileNameGenerator;
const FileStorage({ const FileStorage({
@required this.getDirectory, @required this.getDirectory,
@required this.noteSerializer, @required this.noteSerializer,
@required this.fileNameGenerator,
}); });
@override @override
@ -32,14 +31,9 @@ class FileStorage implements NoteRepository {
if (note == null) { if (note == null) {
continue; continue;
} }
if (!fileEntity.path.endsWith('.md') && if (!note.fileName.toLowerCase().endsWith('.md')) {
!fileEntity.path.endsWith('.MD')) {
continue; continue;
} }
if (note.id == null) {
String filename = p.basename(fileEntity.path);
note.id = filename;
}
notes.add(note); notes.add(note);
} }
@ -54,13 +48,16 @@ class FileStorage implements NoteRepository {
} }
var file = entity as File; var file = entity as File;
final string = await file.readAsString(); final string = await file.readAsString();
return noteSerializer.decode(string);
var note = noteSerializer.decode(string);
note.fileName = p.basename(entity.path);
return note;
} }
@override @override
Future<NoteRepoResult> addNote(Note note) async { Future<NoteRepoResult> addNote(Note note) async {
final dir = await getDirectory(); final dir = await getDirectory();
var filePath = p.join(dir.path, fileNameGenerator(note)); var filePath = p.join(dir.path, note.fileName);
var file = new File(filePath); var file = new File(filePath);
if (file == null) { if (file == null) {
@ -75,7 +72,7 @@ class FileStorage implements NoteRepository {
@override @override
Future<NoteRepoResult> removeNote(Note note) async { Future<NoteRepoResult> removeNote(Note note) async {
final dir = await getDirectory(); final dir = await getDirectory();
var filePath = p.join(dir.path, fileNameGenerator(note)); var filePath = p.join(dir.path, note.fileName);
var file = new File(filePath); var file = new File(filePath);
await file.delete(); await file.delete();
@ -95,11 +92,9 @@ class FileStorage implements NoteRepository {
Future<Directory> saveNotes(List<Note> notes) async { Future<Directory> saveNotes(List<Note> notes) async {
final dir = await getDirectory(); final dir = await getDirectory();
// FIXME: Why do we need to delete everything?
// await dir.delete(recursive: true);
for (var note in notes) { for (var note in notes) {
var filePath = p.join(dir.path, fileNameGenerator(note)); var filePath = p.join(dir.path, note.fileName);
var file = new File(filePath); var file = new File(filePath);
var contents = noteSerializer.encode(note); var contents = noteSerializer.encode(note);

View File

@ -24,14 +24,10 @@ class GitNoteRepository implements NoteRepository {
@required this.gitCloneUrl, @required this.gitCloneUrl,
@required this.dirName, @required this.dirName,
@required this.getDirectory, @required this.getDirectory,
@required fileNameGenerator,
}) : _fileStorage = FileStorage( }) : _fileStorage = FileStorage(
noteSerializer: new MarkdownYAMLSerializer(), noteSerializer: new MarkdownYAMLSerializer(),
fileNameGenerator: fileNameGenerator,
getDirectory: getDirectory, getDirectory: getDirectory,
) { ) {}
// FIXME: This isn't correct. The gitUrl might not be cloned at this point!
}
@override @override
Future<NoteRepoResult> addNote(Note note) async { Future<NoteRepoResult> addNote(Note note) async {
@ -39,7 +35,6 @@ class GitNoteRepository implements NoteRepository {
} }
Future<NoteRepoResult> _addNote(Note note, String commitMessage) async { Future<NoteRepoResult> _addNote(Note note, String commitMessage) async {
print("Calling gitStorage addNote");
var result = await _fileStorage.addNote(note); var result = await _fileStorage.addNote(note);
if (result.error) { if (result.error) {
return result; return result;

View File

@ -48,13 +48,7 @@ class MarkdownYAMLSerializer implements NoteSerializer {
var metadata = note.toJson(); var metadata = note.toJson();
metadata.remove('body'); metadata.remove('body');
metadata.remove('fileName');
// Do not save the 'id' if it is just the 'created' file like default
if (metadata.containsKey('id') && metadata.containsKey('created')) {
if (metadata['id'] == metadata['created']) {
metadata.remove('id');
}
}
str += toYAML(metadata); str += toYAML(metadata);
str += serparator; str += serparator;

View File

@ -29,7 +29,7 @@ class JournalList extends StatelessWidget {
var note = notes[i]; var note = notes[i];
return new Dismissible( return new Dismissible(
key: new Key(note.id), key: new Key(note.fileName),
child: _buildRow(context, note, i), child: _buildRow(context, note, i),
background: new Container(color: Theme.of(context).accentColor), background: new Container(color: Theme.of(context).accentColor),
onDismissed: (direction) { onDismissed: (direction) {

View File

@ -15,15 +15,14 @@ DateTime nowWithoutMicro() {
main() { main() {
group('FileStorage', () { group('FileStorage', () {
var notes = [ var notes = [
Note(id: "1", body: "test", created: nowWithoutMicro()), Note(fileName: "1.md", body: "test", created: nowWithoutMicro()),
Note(id: "2", body: "test2", created: nowWithoutMicro()), Note(fileName: "2.md", body: "test2", created: nowWithoutMicro()),
]; ];
final directory = Directory.systemTemp.createTemp('__storage_test__'); final directory = Directory.systemTemp.createTemp('__storage_test__');
final storage = FileStorage( final storage = FileStorage(
getDirectory: () => directory, getDirectory: () => directory,
noteSerializer: new JsonNoteSerializer(), noteSerializer: new JsonNoteSerializer(),
fileNameGenerator: (Note note) => note.id + '.md',
); );
tearDownAll(() async { tearDownAll(() async {

View File

@ -10,8 +10,8 @@ DateTime nowWithoutMicro() {
main() { main() {
group('Serializers', () { group('Serializers', () {
var note = var note = Note(
Note(id: "2", body: "This is the body", created: nowWithoutMicro()); fileName: "2", body: "This is the body", created: nowWithoutMicro());
test('JSON Serializer', () { test('JSON Serializer', () {
var serializer = new JsonNoteSerializer(); var serializer = new JsonNoteSerializer();
@ -26,6 +26,9 @@ main() {
var str = serializer.encode(note); var str = serializer.encode(note);
var note2 = serializer.decode(str); var note2 = serializer.decode(str);
// The YAML seriazlier loses the fileName by design
note2.fileName = note.fileName;
expect(note2, note); expect(note2, note);
}); });
}); });