mirror of
https://github.com/GitJournal/GitJournal.git
synced 2025-06-27 17:29:50 +08:00
Hookup the Journal app to git
Now notes are saved in the git repo, and immediately synced. This is not the best implementation, as the notes are being reloaded a lot, and the error handling is terrible (I miss golang). But it's the first working poc.
This commit is contained in:
@ -26,23 +26,37 @@ buildGitButtons() {
|
||||
),
|
||||
RaisedButton(
|
||||
child: Text("Git Clone"),
|
||||
onPressed: gitClone,
|
||||
onPressed: () async {
|
||||
gitClone("root@bcn.vhanda.in:git/test", "journal");
|
||||
},
|
||||
),
|
||||
RaisedButton(
|
||||
child: Text("Git Pull"),
|
||||
onPressed: gitPull,
|
||||
onPressed: () async {
|
||||
gitPull("journal");
|
||||
},
|
||||
),
|
||||
RaisedButton(
|
||||
child: Text("Git Add"),
|
||||
onPressed: gitAdd,
|
||||
onPressed: () async {
|
||||
await gitAdd("journal", "1");
|
||||
},
|
||||
),
|
||||
RaisedButton(
|
||||
child: Text("Git Push"),
|
||||
onPressed: gitPush,
|
||||
onPressed: () async {
|
||||
gitPush("journal");
|
||||
},
|
||||
),
|
||||
RaisedButton(
|
||||
child: Text("Git Commit"),
|
||||
onPressed: gitCommit,
|
||||
),
|
||||
child: Text("Git Commit"),
|
||||
onPressed: () async {
|
||||
gitCommit(
|
||||
gitFolder: "journal",
|
||||
authorEmail: "noemail@example.com",
|
||||
authorName: "Vishesh Handa",
|
||||
message: "Default message from GitJournal",
|
||||
);
|
||||
}),
|
||||
];
|
||||
}
|
||||
|
@ -5,24 +5,9 @@ import 'package:journal/app.dart';
|
||||
import 'package:journal/gitapp.dart';
|
||||
import 'package:journal/state_container.dart';
|
||||
|
||||
/*
|
||||
import 'note.dart';
|
||||
|
||||
Future<List<Note>> fetchNotes() async {
|
||||
final response = await http.get('http://192.168.1.132:8000/notes');
|
||||
final responseJson = json.decode(response.body);
|
||||
|
||||
var notes = <Note>[];
|
||||
for (var postJson in responseJson) {
|
||||
notes.add(new Note.fromJson(postJson));
|
||||
}
|
||||
|
||||
return notes;
|
||||
}
|
||||
*/
|
||||
|
||||
void main() {
|
||||
runApp(new StateContainer(
|
||||
child: GitApp(),
|
||||
child: JournalApp(),
|
||||
//child: GitApp(),
|
||||
));
|
||||
}
|
||||
|
@ -49,21 +49,34 @@ class Note implements Comparable {
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'Note{id: $id, body: $body, createdAt: $created}';
|
||||
return 'Note{id: $id, body: $body, created: $created}';
|
||||
}
|
||||
|
||||
@override
|
||||
int compareTo(other) => created.compareTo(other.created);
|
||||
int compareTo(other) {
|
||||
if (other == null) {
|
||||
return -1;
|
||||
}
|
||||
return created.compareTo(other.created);
|
||||
}
|
||||
}
|
||||
|
||||
class AppState {
|
||||
bool isLoading;
|
||||
bool isLoadingFromDisk;
|
||||
bool localStateModified;
|
||||
|
||||
bool isLoadingRemoteState;
|
||||
bool remoteStateModified;
|
||||
|
||||
List<Note> notes;
|
||||
|
||||
AppState({
|
||||
this.isLoading = false,
|
||||
this.isLoadingFromDisk = false,
|
||||
this.localStateModified = false,
|
||||
this.isLoadingRemoteState = false,
|
||||
this.remoteStateModified = false,
|
||||
this.notes = const [],
|
||||
});
|
||||
|
||||
factory AppState.loading() => AppState(isLoading: true);
|
||||
//factory AppState.loading() => AppState(isLoading: true);
|
||||
}
|
||||
|
@ -9,12 +9,12 @@ import 'package:uuid/uuid.dart';
|
||||
import 'package:journal/note.dart';
|
||||
import 'package:journal/storage/serializers.dart';
|
||||
import 'package:journal/storage/notes_repository.dart';
|
||||
import 'package:journal/storage/file_storage.dart';
|
||||
import 'package:journal/storage/git_storage.dart';
|
||||
import 'package:journal/storage/git.dart';
|
||||
|
||||
Future<Directory> getNotesDir() async {
|
||||
var appDir = await getGitBaseDirectory();
|
||||
var dir = new Directory(p.join(appDir.path, "notes"));
|
||||
var dir = new Directory(p.join(appDir.path, "journal"));
|
||||
await dir.create();
|
||||
|
||||
return dir;
|
||||
@ -40,56 +40,80 @@ class StateContainer extends StatefulWidget {
|
||||
}
|
||||
|
||||
class StateContainerState extends State<StateContainer> {
|
||||
AppState appState = AppState.loading();
|
||||
NoteRepository noteRepo = new FileStorage(
|
||||
AppState appState = AppState();
|
||||
|
||||
NoteRepository noteRepo = new GitNoteRepository(
|
||||
getDirectory: getNotesDir,
|
||||
noteSerializer: new MarkdownYAMLSerializer(),
|
||||
fileNameGenerator: (Note note) => note.id,
|
||||
dirName: "journal",
|
||||
gitCloneUrl: "root@bcn.vhanda.in:git/test",
|
||||
);
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
|
||||
_loadNotesFromDisk();
|
||||
_syncNotes();
|
||||
}
|
||||
|
||||
void _loadNotesFromDisk() {
|
||||
print("Loading Notes From Disk");
|
||||
appState.isLoadingFromDisk = true;
|
||||
noteRepo.listNotes().then((loadedNotes) {
|
||||
setState(() {
|
||||
appState = AppState(notes: loadedNotes);
|
||||
appState.isLoadingFromDisk = false;
|
||||
appState.notes = loadedNotes;
|
||||
});
|
||||
}).catchError((err) {
|
||||
}).catchError((err, stack) {
|
||||
setState(() {
|
||||
print("Load Notes Error:");
|
||||
print(err);
|
||||
appState.isLoading = false;
|
||||
print("Load Notes From Disk Error: " + err.toString());
|
||||
print(stack.toString());
|
||||
appState.isLoadingFromDisk = false;
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
void addNote(Note note) {
|
||||
setState(() {
|
||||
note.id = new Uuid().v4();
|
||||
appState.notes.insert(0, note);
|
||||
noteRepo.addNote(note);
|
||||
void _syncNotes() {
|
||||
print("Starting to syncNOtes");
|
||||
this.noteRepo.sync().then((loaded) {
|
||||
print("NotesRepo Synced: " + loaded.toString());
|
||||
_loadNotesFromDisk();
|
||||
}).catchError((err) {
|
||||
print("NotesRepo Sync: " + err.toString());
|
||||
});
|
||||
}
|
||||
|
||||
void addNote(Note note) {
|
||||
insertNote(0, note);
|
||||
}
|
||||
|
||||
void removeNote(Note note) {
|
||||
setState(() {
|
||||
appState.notes.remove(note);
|
||||
noteRepo.removeNote(note);
|
||||
noteRepo.removeNote(note).then((NoteRepoResult _) {
|
||||
_syncNotes();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
void insertNote(int index, Note note) {
|
||||
setState(() {
|
||||
print("insertNote: " + note.toString());
|
||||
if (note.id == null || note.id.isEmpty) {
|
||||
note.id = new Uuid().v4();
|
||||
}
|
||||
appState.notes.insert(index, note);
|
||||
noteRepo.addNote(note);
|
||||
noteRepo.addNote(note).then((NoteRepoResult _) {
|
||||
_syncNotes();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// FIXME: Implement this!
|
||||
void updateNote(Note note) {
|
||||
setState(() {
|
||||
noteRepo.updateNote(note);
|
||||
noteRepo.updateNote(note).then((NoteRepoResult _) {
|
||||
_syncNotes();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -29,6 +29,13 @@ class FileStorage implements NoteRepository {
|
||||
var lister = dir.list(recursive: false);
|
||||
await for (var fileEntity in lister) {
|
||||
Note note = await _loadNote(fileEntity);
|
||||
if (note == null) {
|
||||
continue;
|
||||
}
|
||||
if (note.id == null) {
|
||||
String filename = p.basename(fileEntity.path);
|
||||
note.id = filename;
|
||||
}
|
||||
notes.add(note);
|
||||
}
|
||||
|
||||
@ -47,30 +54,33 @@ class FileStorage implements NoteRepository {
|
||||
}
|
||||
|
||||
@override
|
||||
Future<bool> addNote(Note note) async {
|
||||
Future<NoteRepoResult> addNote(Note note) async {
|
||||
final dir = await getDirectory();
|
||||
var filePath = p.join(dir.path, fileNameGenerator(note));
|
||||
|
||||
var file = new File(filePath);
|
||||
if (file == null) {
|
||||
return NoteRepoResult(error: true);
|
||||
}
|
||||
var contents = noteSerializer.encode(note);
|
||||
await file.writeAsString(contents);
|
||||
|
||||
return true;
|
||||
return NoteRepoResult(noteFilePath: filePath, error: false);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<bool> removeNote(Note note) async {
|
||||
Future<NoteRepoResult> removeNote(Note note) async {
|
||||
final dir = await getDirectory();
|
||||
var filePath = p.join(dir.path, fileNameGenerator(note));
|
||||
|
||||
var file = new File(filePath);
|
||||
await file.delete();
|
||||
|
||||
return true;
|
||||
return NoteRepoResult(noteFilePath: filePath, error: false);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<bool> updateNote(Note note) async {
|
||||
Future<NoteRepoResult> updateNote(Note note) async {
|
||||
return addNote(note);
|
||||
}
|
||||
|
||||
@ -81,8 +91,8 @@ class FileStorage implements NoteRepository {
|
||||
|
||||
Future<Directory> saveNotes(List<Note> notes) async {
|
||||
final dir = await getDirectory();
|
||||
await dir.delete(recursive: true);
|
||||
await dir.create();
|
||||
// FIXME: Why do we need to delete everything?
|
||||
// await dir.delete(recursive: true);
|
||||
|
||||
for (var note in notes) {
|
||||
var filePath = p.join(dir.path, fileNameGenerator(note));
|
||||
|
@ -13,12 +13,12 @@ Future<Directory> getGitBaseDirectory() async {
|
||||
return new Directory(path);
|
||||
}
|
||||
|
||||
Future gitClone() async {
|
||||
Future gitClone(String cloneUrl, String folderName) async {
|
||||
print("Going to git clone");
|
||||
try {
|
||||
await _platform.invokeMethod('gitClone', {
|
||||
'cloneUrl': "root@bcn.vhanda.in:git/test",
|
||||
'folderName': "journal",
|
||||
'cloneUrl': cloneUrl,
|
||||
'folderName': folderName,
|
||||
});
|
||||
print("Done");
|
||||
} on PlatformException catch (e) {
|
||||
@ -36,11 +36,11 @@ Future generateSSHKeys() async {
|
||||
}
|
||||
}
|
||||
|
||||
Future gitPull() async {
|
||||
Future gitPull(String folderName) async {
|
||||
print("Going to git pull");
|
||||
try {
|
||||
await _platform.invokeMethod('gitPull', {
|
||||
'folderName': "journal",
|
||||
'folderName': folderName,
|
||||
});
|
||||
print("Done");
|
||||
} on PlatformException catch (e) {
|
||||
@ -48,12 +48,12 @@ Future gitPull() async {
|
||||
}
|
||||
}
|
||||
|
||||
Future gitAdd() async {
|
||||
print("Going to git add");
|
||||
Future gitAdd(String gitFolder, String filePattern) async {
|
||||
print("Going to git add: " + filePattern);
|
||||
try {
|
||||
await _platform.invokeMethod('gitAdd', {
|
||||
'folderName': "journal",
|
||||
'filePattern': ".",
|
||||
'folderName': gitFolder,
|
||||
'filePattern': filePattern,
|
||||
});
|
||||
print("Done");
|
||||
} on PlatformException catch (e) {
|
||||
@ -61,12 +61,12 @@ Future gitAdd() async {
|
||||
}
|
||||
}
|
||||
|
||||
Future gitRm() async {
|
||||
Future gitRm(String gitFolder, String filePattern) async {
|
||||
print("Going to git rm");
|
||||
try {
|
||||
await _platform.invokeMethod('gitRm', {
|
||||
'folderName': "journal",
|
||||
'filePattern': "1",
|
||||
'folderName': gitFolder,
|
||||
'filePattern': filePattern,
|
||||
});
|
||||
print("Done");
|
||||
} on PlatformException catch (e) {
|
||||
@ -74,11 +74,11 @@ Future gitRm() async {
|
||||
}
|
||||
}
|
||||
|
||||
Future gitPush() async {
|
||||
Future gitPush(String folderName) async {
|
||||
print("Going to git push");
|
||||
try {
|
||||
await _platform.invokeMethod('gitPush', {
|
||||
'folderName': "journal",
|
||||
'folderName': folderName,
|
||||
});
|
||||
print("Done");
|
||||
} on PlatformException catch (e) {
|
||||
@ -86,14 +86,19 @@ Future gitPush() async {
|
||||
}
|
||||
}
|
||||
|
||||
Future gitCommit() async {
|
||||
Future gitCommit({
|
||||
String gitFolder,
|
||||
String authorName,
|
||||
String authorEmail,
|
||||
String message,
|
||||
}) async {
|
||||
print("Going to git commit");
|
||||
try {
|
||||
await _platform.invokeMethod('gitCommit', {
|
||||
'folderName': "journal",
|
||||
'authorName': "Vishesh Handa",
|
||||
'authorEmail': "noemail@example.com",
|
||||
'message': "Default message from GitJournal",
|
||||
'folderName': gitFolder,
|
||||
'authorName': authorName,
|
||||
'authorEmail': authorEmail,
|
||||
'message': message,
|
||||
});
|
||||
print("Done");
|
||||
} on PlatformException catch (e) {
|
||||
|
108
lib/storage/git_storage.dart
Normal file
108
lib/storage/git_storage.dart
Normal file
@ -0,0 +1,108 @@
|
||||
import 'dart:async';
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:path/path.dart' as p;
|
||||
|
||||
import 'package:journal/note.dart';
|
||||
import 'package:journal/storage/git.dart';
|
||||
import 'package:journal/storage/serializers.dart';
|
||||
import 'package:journal/storage/file_storage.dart';
|
||||
import 'package:journal/storage/notes_repository.dart';
|
||||
|
||||
class GitNoteRepository implements NoteRepository {
|
||||
final FileStorage _fileStorage;
|
||||
final String gitCloneUrl;
|
||||
final String dirName;
|
||||
|
||||
bool cloned = false;
|
||||
bool checkForCloned = false;
|
||||
|
||||
final Future<Directory> Function() getDirectory;
|
||||
|
||||
GitNoteRepository({
|
||||
@required this.gitCloneUrl,
|
||||
@required this.dirName,
|
||||
@required this.getDirectory,
|
||||
}) : _fileStorage = FileStorage(
|
||||
noteSerializer: new MarkdownYAMLSerializer(),
|
||||
fileNameGenerator: (Note note) => note.id,
|
||||
getDirectory: getDirectory,
|
||||
) {
|
||||
// FIXME: This isn't correct. The gitUrl might not be cloned at this point!
|
||||
}
|
||||
|
||||
@override
|
||||
Future<NoteRepoResult> addNote(Note note) async {
|
||||
print("Calling gitStorage addNote");
|
||||
var result = await _fileStorage.addNote(note);
|
||||
if (result.error) {
|
||||
return result;
|
||||
}
|
||||
|
||||
var baseDir = await this.getDirectory();
|
||||
var filePath = result.noteFilePath.replaceFirst(baseDir.path + "/", "");
|
||||
|
||||
await gitAdd(this.dirName, filePath);
|
||||
await gitCommit(
|
||||
gitFolder: this.dirName,
|
||||
authorEmail: "noemail@example.com",
|
||||
authorName: "Vishesh Handa",
|
||||
message: "Added Journal entry",
|
||||
);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@override
|
||||
Future<NoteRepoResult> removeNote(Note note) async {
|
||||
var result = await _fileStorage.addNote(note);
|
||||
if (result.error) {
|
||||
return result;
|
||||
}
|
||||
|
||||
var baseDir = await this.getDirectory();
|
||||
var filePath = result.noteFilePath.replaceFirst(baseDir.path + "/", "");
|
||||
|
||||
await gitRm(this.dirName, filePath);
|
||||
await gitCommit(
|
||||
gitFolder: this.dirName,
|
||||
authorEmail: "noemail@example.com",
|
||||
authorName: "Vishesh Handa",
|
||||
message: "Added Journal entry",
|
||||
);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@override
|
||||
Future<NoteRepoResult> updateNote(Note note) async {
|
||||
return this.addNote(note);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<List<Note>> listNotes() {
|
||||
return _fileStorage.listNotes();
|
||||
}
|
||||
|
||||
@override
|
||||
Future<bool> sync() async {
|
||||
print("Starting Sync");
|
||||
if (!checkForCloned) {
|
||||
var baseDir = await this.getDirectory();
|
||||
var dotGitDir = new Directory(p.join(baseDir.path, ".git"));
|
||||
cloned = await dotGitDir.exists();
|
||||
checkForCloned = true;
|
||||
}
|
||||
if (!cloned) {
|
||||
await gitClone(this.gitCloneUrl, this.dirName);
|
||||
cloned = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
await gitPull(this.dirName);
|
||||
await gitPush(this.dirName);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
@ -1,13 +1,25 @@
|
||||
import 'dart:async';
|
||||
import 'package:flutter/foundation.dart';
|
||||
|
||||
import 'package:journal/note.dart';
|
||||
|
||||
class NoteRepoResult {
|
||||
bool error;
|
||||
String noteFilePath;
|
||||
|
||||
NoteRepoResult({
|
||||
@required this.error,
|
||||
this.noteFilePath,
|
||||
});
|
||||
}
|
||||
|
||||
abstract class NoteRepository {
|
||||
// TODO: Better error message!
|
||||
Future<bool> sync();
|
||||
|
||||
Future<bool> addNote(Note note);
|
||||
Future<bool> updateNote(Note note);
|
||||
Future<bool> removeNote(Note note);
|
||||
Future<NoteRepoResult> addNote(Note note);
|
||||
Future<NoteRepoResult> updateNote(Note note);
|
||||
Future<NoteRepoResult> removeNote(Note note);
|
||||
|
||||
Future<List<Note>> listNotes();
|
||||
}
|
||||
|
Reference in New Issue
Block a user