mirror of
https://github.com/GitJournal/GitJournal.git
synced 2025-07-15 07:56:11 +08:00

For this journaling app, even though we are treating journal entries as notes, we don't really any 'id'. Just the filename is quite adequate. In the future, we can figure out this 'id' nonsense, and if it is even required given that we're always going to be built on top of a FS.
208 lines
5.2 KiB
Dart
208 lines
5.2 KiB
Dart
import 'dart:async';
|
|
import 'dart:io';
|
|
|
|
import 'package:flutter/foundation.dart';
|
|
import 'package:flutter/material.dart';
|
|
import 'package:path/path.dart' as p;
|
|
import 'package:shared_preferences/shared_preferences.dart';
|
|
|
|
import 'package:journal/appstate.dart';
|
|
import 'package:journal/note.dart';
|
|
import 'package:journal/storage/notes_repository.dart';
|
|
import 'package:journal/storage/git_storage.dart';
|
|
import 'package:journal/storage/git.dart';
|
|
import 'package:journal/datetime_utils.dart';
|
|
|
|
Future<Directory> getNotesDir() async {
|
|
var appDir = await getGitBaseDirectory();
|
|
var dir = new Directory(p.join(appDir.path, "journal"));
|
|
await dir.create();
|
|
|
|
return dir;
|
|
}
|
|
|
|
class StateContainer extends StatefulWidget {
|
|
final Widget child;
|
|
final bool onBoardingCompleted;
|
|
|
|
StateContainer({
|
|
@required this.onBoardingCompleted,
|
|
@required this.child,
|
|
});
|
|
|
|
static StateContainerState of(BuildContext context) {
|
|
return (context.inheritFromWidgetOfExactType(_InheritedStateContainer)
|
|
as _InheritedStateContainer)
|
|
.data;
|
|
}
|
|
|
|
@override
|
|
State<StatefulWidget> createState() {
|
|
return StateContainerState(this.onBoardingCompleted);
|
|
}
|
|
}
|
|
|
|
class StateContainerState extends State<StateContainer> {
|
|
AppState appState = AppState();
|
|
|
|
NoteRepository noteRepo = new GitNoteRepository(
|
|
getDirectory: getNotesDir,
|
|
dirName: "journal",
|
|
gitCloneUrl: "root@bcn.vhanda.in:git/test",
|
|
fileNameGenerator: (Note n) => toIso8601WithTimezone(n.created) + '.md',
|
|
);
|
|
|
|
StateContainerState(bool onBoardingCompleted) {
|
|
appState.onBoardingCompleted = onBoardingCompleted;
|
|
}
|
|
|
|
@override
|
|
void initState() {
|
|
super.initState();
|
|
|
|
if (appState.onBoardingCompleted) {
|
|
_loadNotesFromDisk();
|
|
_syncNotes();
|
|
} else {
|
|
removeExistingClone();
|
|
}
|
|
}
|
|
|
|
void removeExistingClone() async {
|
|
var baseDir = await getNotesDir();
|
|
var dotGitDir = new Directory(p.join(baseDir.path, ".git"));
|
|
bool exists = await dotGitDir.exists();
|
|
if (exists) {
|
|
await baseDir.delete(recursive: true);
|
|
await baseDir.create();
|
|
}
|
|
}
|
|
|
|
void _loadNotesFromDisk() {
|
|
print("Loading Notes From Disk");
|
|
appState.isLoadingFromDisk = true;
|
|
noteRepo.listNotes().then((loadedNotes) {
|
|
setState(() {
|
|
appState.isLoadingFromDisk = false;
|
|
appState.notes = loadedNotes;
|
|
});
|
|
}).catchError((err, stack) {
|
|
setState(() {
|
|
print("Load Notes From Disk Error: " + err.toString());
|
|
print(stack.toString());
|
|
appState.isLoadingFromDisk = false;
|
|
});
|
|
});
|
|
}
|
|
|
|
Future syncNotes() async {
|
|
try {
|
|
await noteRepo.sync();
|
|
} catch (err, stack) {
|
|
print("Notes Repo Sync Error: " + err.toString());
|
|
print(stack.toString());
|
|
return true;
|
|
}
|
|
|
|
try {
|
|
appState.isLoadingFromDisk = true;
|
|
var loadedNotes = await noteRepo.listNotes();
|
|
setState(() {
|
|
appState.isLoadingFromDisk = false;
|
|
appState.notes = loadedNotes;
|
|
});
|
|
} catch (err, stack) {
|
|
setState(() {
|
|
print("Load Notes From Disk Error: " + err.toString());
|
|
print(stack.toString());
|
|
appState.isLoadingFromDisk = false;
|
|
});
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
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).then((NoteRepoResult _) {
|
|
_syncNotes();
|
|
});
|
|
});
|
|
}
|
|
|
|
void insertNote(int index, Note note) {
|
|
setState(() {
|
|
if (note.id == null || note.id.isEmpty) {
|
|
note.id = toIso8601WithTimezone(note.created);
|
|
}
|
|
appState.notes.insert(index, note);
|
|
noteRepo.addNote(note).then((NoteRepoResult _) {
|
|
_syncNotes();
|
|
});
|
|
});
|
|
}
|
|
|
|
void updateNote(Note note) {
|
|
setState(() {
|
|
noteRepo.updateNote(note).then((NoteRepoResult _) {
|
|
_syncNotes();
|
|
});
|
|
});
|
|
}
|
|
|
|
void completeOnBoarding() {
|
|
setState(() {
|
|
this.appState.onBoardingCompleted = true;
|
|
|
|
_persistOnBoardingCompleted();
|
|
_loadNotesFromDisk();
|
|
_syncNotes();
|
|
});
|
|
}
|
|
|
|
void _persistOnBoardingCompleted() async {
|
|
var pref = await SharedPreferences.getInstance();
|
|
pref.setBool("onBoardingCompleted", true);
|
|
}
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
return _InheritedStateContainer(
|
|
data: this,
|
|
child: widget.child,
|
|
);
|
|
}
|
|
}
|
|
|
|
class _InheritedStateContainer extends InheritedWidget {
|
|
final StateContainerState data;
|
|
|
|
_InheritedStateContainer({
|
|
Key key,
|
|
@required this.data,
|
|
@required Widget child,
|
|
}) : super(key: key, child: child);
|
|
|
|
// Note: we could get fancy here and compare whether the old AppState is
|
|
// different than the current AppState. However, since we know this is the
|
|
// root Widget, when we make changes we also know we want to rebuild Widgets
|
|
// that depend on the StateContainer.
|
|
@override
|
|
bool updateShouldNotify(_InheritedStateContainer old) => true;
|
|
}
|