1
0
mirror of https://github.com/GitJournal/GitJournal.git synced 2025-07-08 17:10:17 +08:00

Remove onboarding screen

For now just create a local git repo and commit all the changes over
there, we're going to allow the user to first see the app and use it
however they want, and later connect it to a remote git repo.

This commit breaks the app, as the on-boarding screen is no longer
connected so you cannot push to a remote app.
This commit is contained in:
Vishesh Handa
2019-01-21 13:43:33 +01:00
parent c915e58273
commit 519de8fcff
12 changed files with 239 additions and 76 deletions

@ -0,0 +1,55 @@
package io.gitjournal.gitjournal;
import android.os.AsyncTask;
import android.util.Log;
import org.eclipse.jgit.api.Git;
import org.eclipse.jgit.api.errors.GitAPIException;
import org.eclipse.jgit.api.CloneCommand;
import org.eclipse.jgit.api.TransportConfigCallback;
import org.eclipse.jgit.api.errors.TransportException;
import org.eclipse.jgit.transport.Transport;
import org.eclipse.jgit.transport.SshTransport;
import org.eclipse.jgit.lib.TextProgressMonitor;
import java.io.PrintWriter;
import java.io.File;
import io.flutter.plugin.common.MethodChannel.Result;
public class GitInitTask extends AsyncTask<String, Void, Void> {
private final static String TAG = "GitInit";
private Result result;
public GitInitTask(Result _result) {
result = _result;
}
protected Void doInBackground(String... params) {
String cloneDirPath = params[0];
File cloneDir = new File(cloneDirPath);
Log.d("GitInit Directory", cloneDirPath);
try {
Git.init().setDirectory(cloneDir).call();
} catch (TransportException e) {
Log.d(TAG, e.toString());
result.error("FAILED", e.getMessage(), null);
return null;
} catch (GitAPIException e) {
Log.d(TAG, e.toString());
result.error("FAILED", e.getMessage(), null);
return null;
} catch (Exception e) {
Log.d(TAG, e.toString());
result.error("FAILED", e.getMessage(), null);
return null;
}
result.success(null);
return null;
}
}

@ -146,6 +146,18 @@ public class MainActivity extends FlutterActivity {
new GitCommitTask(result).execute(cloneLocation, authorName, authorEmail, message);
return;
} else if (call.method.equals("gitInit")) {
String folderName = call.argument("folderName");
if (folderName == null || folderName.isEmpty()) {
result.error("Invalid Parameters", "folderName Invalid", null);
return;
}
String initLocation = filesDir + "/" + folderName;
new GitInitTask(result).execute(initLocation);
return;
} else if (call.method.equals("generateSSHKeys")) {
String comment = call.argument("comment");
if (comment == null || comment.isEmpty()) {

@ -1,7 +1,5 @@
import 'package:flutter/material.dart';
import 'package:journal/state_container.dart';
import 'package:journal/screens/home_screen.dart';
import 'package:journal/screens/onboarding_screens.dart';
import 'package:journal/screens/settings_screen.dart';
import 'package:firebase_analytics/firebase_analytics.dart';
@ -32,14 +30,7 @@ class JournalApp extends StatelessWidget {
navigatorObservers: <NavigatorObserver>[JournalApp.observer],
initialRoute: '/',
routes: {
'/': (context) {
final stateContainer = StateContainer.of(context);
var onBoardingDone = stateContainer.appState.onBoardingCompleted;
var home = onBoardingDone
? new HomeScreen()
: new OnBoardingScreen(stateContainer.completeOnBoarding);
return home;
},
'/': (context) => HomeScreen(),
'/settings': (context) => SettingsScreen(),
},
);

@ -1,12 +1,21 @@
import 'package:journal/note.dart';
class AppState {
bool onBoardingCompleted;
// FIXME: Make these 2 final
String localGitRepoPath = "";
bool localGitRepoConfigured = false;
// FIXME: Rename from 'path' to folderName
String remoteGitRepoPath = "";
bool remoteGitRepoConfigured = false;
// FIXME: Make final
String gitBaseDirectory = "";
bool isLoadingFromDisk;
List<Note> notes;
AppState({
this.onBoardingCompleted = false,
this.isLoadingFromDisk = false,
this.notes = const [],
});

@ -6,6 +6,7 @@ import 'package:flutter_crashlytics/flutter_crashlytics.dart';
import 'package:journal/app.dart';
import 'package:journal/state_container.dart';
import 'package:journal/storage/git.dart';
void main() async {
bool isInDebugMode = true;
@ -30,7 +31,11 @@ void main() async {
Future runJournalApp() async {
var pref = await SharedPreferences.getInstance();
var onBoardingCompleted = pref.getBool("onBoardingCompleted") ?? false;
var localGitRepoConfigured = pref.getBool("localGitRepoConfigured") ?? false;
var remoteGitRepoConfigured =
pref.getBool("remoteGitRepoConfigured") ?? false;
var localGitRepoPath = pref.getString("localGitRepoPath") ?? "";
var remoteGitRepoPath = pref.getString("remoteGitRepoPath") ?? "";
if (JournalApp.isInDebugMode) {
if (JournalApp.analytics.android != null) {
@ -38,8 +43,25 @@ Future runJournalApp() async {
}
}
if (localGitRepoConfigured == false) {
// FIXME: What about exceptions!
localGitRepoPath = "journal_local";
await gitInit(localGitRepoPath);
localGitRepoConfigured = true;
await pref.setBool("localGitRepoConfigured", localGitRepoConfigured);
await pref.setString("localGitRepoPath", localGitRepoPath);
}
var dir = await getGitBaseDirectory();
runApp(new StateContainer(
onBoardingCompleted: onBoardingCompleted,
localGitRepoConfigured: localGitRepoConfigured,
remoteGitRepoConfigured: remoteGitRepoConfigured,
localGitRepoPath: localGitRepoPath,
remoteGitRepoPath: remoteGitRepoPath,
gitBaseDirectory: dir.path,
child: JournalApp(),
));
}

@ -300,6 +300,8 @@ class OnBoardingScreenState extends State<OnBoardingScreen> {
}
Future _removeExistingClone() async {
// FIXME: Implement this
/*
var baseDir = await getNotesDir();
var dotGitDir = new Directory(p.join(baseDir.path, ".git"));
bool exists = await dotGitDir.exists();
@ -307,6 +309,7 @@ class OnBoardingScreenState extends State<OnBoardingScreen> {
await baseDir.delete(recursive: true);
await baseDir.create();
}
*/
}
}

@ -13,20 +13,20 @@ 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;
final bool localGitRepoConfigured;
final bool remoteGitRepoConfigured;
final String localGitRepoPath;
final String remoteGitRepoPath;
final String gitBaseDirectory;
StateContainer({
@required this.onBoardingCompleted,
@required this.localGitRepoConfigured,
@required this.remoteGitRepoConfigured,
@required this.localGitRepoPath,
@required this.remoteGitRepoPath,
@required this.gitBaseDirectory,
@required this.child,
});
@ -38,42 +38,56 @@ class StateContainer extends StatefulWidget {
@override
State<StatefulWidget> createState() {
return StateContainerState(this.onBoardingCompleted);
var st = StateContainerState();
st.appState.localGitRepoConfigured = localGitRepoConfigured;
st.appState.remoteGitRepoConfigured = remoteGitRepoConfigured;
st.appState.localGitRepoPath = localGitRepoPath;
st.appState.remoteGitRepoPath = remoteGitRepoPath;
st.appState.gitBaseDirectory = gitBaseDirectory;
return st;
}
}
class StateContainerState extends State<StateContainer> {
AppState appState = AppState();
NoteRepository noteRepo = new GitNoteRepository(
getDirectory: getNotesDir,
dirName: "journal",
gitCloneUrl: "root@bcn.vhanda.in:git/test",
);
StateContainerState(bool onBoardingCompleted) {
appState.onBoardingCompleted = onBoardingCompleted;
}
NoteRepository noteRepo;
@override
void initState() {
super.initState();
if (appState.onBoardingCompleted) {
_loadNotesFromDisk();
_syncNotes();
} else {
removeExistingClone();
assert(appState.localGitRepoConfigured);
if (appState.remoteGitRepoConfigured) {
noteRepo = new GitNoteRepository(
baseDirectory: appState.gitBaseDirectory,
dirName: appState.remoteGitRepoPath,
);
} else if (appState.localGitRepoConfigured) {
noteRepo = new GitNoteRepository(
baseDirectory: appState.gitBaseDirectory,
dirName: appState.localGitRepoPath,
);
}
// Just a fail safe
if (!appState.remoteGitRepoConfigured) {
removeExistingRemoteClone();
}
_loadNotesFromDisk();
_syncNotes();
}
void removeExistingClone() async {
var baseDir = await getNotesDir();
var dotGitDir = new Directory(p.join(baseDir.path, ".git"));
void removeExistingRemoteClone() async {
var remoteGitDir = new Directory(
p.join(appState.gitBaseDirectory, appState.remoteGitRepoPath));
var dotGitDir = new Directory(p.join(remoteGitDir.path, ".git"));
bool exists = await dotGitDir.exists();
if (exists) {
await baseDir.delete(recursive: true);
await baseDir.create();
await remoteGitDir.delete(recursive: true);
}
}
@ -95,6 +109,11 @@ class StateContainerState extends State<StateContainer> {
}
Future syncNotes() async {
if (!appState.remoteGitRepoConfigured) {
print("Not syncing because RemoteRepo not configured");
return true;
}
await noteRepo.sync();
try {
@ -116,7 +135,12 @@ class StateContainerState extends State<StateContainer> {
}
void _syncNotes() {
print("Starting to syncNOtes");
if (!appState.remoteGitRepoConfigured) {
print("Not syncing because RemoteRepo not configured");
return;
}
print("Starting to syncNotes");
this.noteRepo.sync().then((loaded) {
print("NotesRepo Synced: " + loaded.toString());
_loadNotesFromDisk();
@ -162,7 +186,7 @@ class StateContainerState extends State<StateContainer> {
void completeOnBoarding() {
setState(() {
this.appState.onBoardingCompleted = true;
//this.appState.onBoardingCompleted = true;
_persistOnBoardingCompleted();
_loadNotesFromDisk();
@ -175,6 +199,13 @@ class StateContainerState extends State<StateContainer> {
pref.setBool("onBoardingCompleted", true);
}
Future _persistConfig() async {
var pref = await SharedPreferences.getInstance();
await pref.setBool(
"remoteGitRepoConfigured", appState.remoteGitRepoConfigured);
await pref.setString("remoteGitRepoPath", appState.remoteGitRepoPath);
}
@override
Widget build(BuildContext context) {
return _InheritedStateContainer(

@ -12,17 +12,21 @@ typedef String NoteFileNameGenerator(Note note);
/// Each Note is saved in a different file
/// Each note must have a fileName which ends in a .md
class FileStorage implements NoteRepository {
final Future<Directory> Function() getDirectory;
final String baseDirectory;
final NoteSerializer noteSerializer;
const FileStorage({
@required this.getDirectory,
FileStorage({
@required this.baseDirectory,
@required this.noteSerializer,
});
}) {
assert(this.baseDirectory != null);
assert(this.baseDirectory.isNotEmpty);
print("FileStorage Directory: " + this.baseDirectory);
}
@override
Future<List<Note>> listNotes() async {
final dir = await getDirectory();
final dir = new Directory(baseDirectory);
var notes = new List<Note>();
var lister = dir.list(recursive: false);
@ -56,8 +60,8 @@ class FileStorage implements NoteRepository {
@override
Future<NoteRepoResult> addNote(Note note) async {
final dir = await getDirectory();
var filePath = p.join(dir.path, note.fileName);
var filePath = p.join(baseDirectory, note.fileName);
print("FileStorage: Adding note in " + filePath);
var file = new File(filePath);
if (file == null) {
@ -71,8 +75,7 @@ class FileStorage implements NoteRepository {
@override
Future<NoteRepoResult> removeNote(Note note) async {
final dir = await getDirectory();
var filePath = p.join(dir.path, note.fileName);
var filePath = p.join(baseDirectory, note.fileName);
var file = new File(filePath);
await file.delete();
@ -91,7 +94,7 @@ class FileStorage implements NoteRepository {
}
Future<Directory> saveNotes(List<Note> notes) async {
final dir = await getDirectory();
final dir = new Directory(baseDirectory);
for (var note in notes) {
var filePath = p.join(dir.path, note.fileName);

@ -147,3 +147,16 @@ Future gitCommit({
print("gitCommit Failed: '${e.message}'.");
}
}
Future gitInit(String folderName) async {
print("Going to git init");
try {
await _platform.invokeMethod('gitInit', {
'folderName': folderName,
});
print("Done");
} on PlatformException catch (e) {
print("gitInit Failed: '${e.message}'.");
throw createGitException(e.message);
}
}

@ -12,21 +12,18 @@ import 'package:journal/storage/notes_repository.dart';
class GitNoteRepository implements NoteRepository {
final FileStorage _fileStorage;
final String gitCloneUrl;
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,
@required String baseDirectory,
}) : _fileStorage = FileStorage(
noteSerializer: new MarkdownYAMLSerializer(),
getDirectory: getDirectory,
baseDirectory: p.join(baseDirectory, dirName),
);
@override
@ -40,8 +37,8 @@ class GitNoteRepository implements NoteRepository {
return result;
}
var baseDir = await this.getDirectory();
var filePath = result.noteFilePath.replaceFirst(baseDir.path + "/", "");
var baseDir = _fileStorage.baseDirectory;
var filePath = result.noteFilePath.replaceFirst(baseDir + "/", "");
await gitAdd(this.dirName, filePath);
await gitCommit(
@ -61,8 +58,9 @@ class GitNoteRepository implements NoteRepository {
return result;
}
var baseDir = await this.getDirectory();
var filePath = result.noteFilePath.replaceFirst(baseDir.path + "/", "");
// FIXME: '/' is not valid on all platforms
var baseDir = _fileStorage.baseDirectory;
var filePath = result.noteFilePath.replaceFirst(baseDir + "/", "");
await gitRm(this.dirName, filePath);
await gitCommit(
@ -87,13 +85,19 @@ class GitNoteRepository implements NoteRepository {
@override
Future<bool> sync() async {
print("Starting Sync");
if (gitCloneUrl == null || gitCloneUrl.isEmpty) {
print("Cannot sync because of lack of clone url");
return false;
}
if (!checkForCloned) {
var baseDir = await this.getDirectory();
var baseDir = new Directory(_fileStorage.baseDirectory);
var dotGitDir = new Directory(p.join(baseDir.path, ".git"));
cloned = await dotGitDir.exists();
checkForCloned = true;
}
// FIXME: If we are calling sync, it should always be cloned!
assert(cloned == true);
if (!cloned) {
await gitClone(this.gitCloneUrl, this.dirName);
cloned = true;

@ -1,8 +1,23 @@
import 'package:flutter/material.dart';
import 'package:journal/state_container.dart';
class AppDrawer extends StatelessWidget {
@override
Widget build(BuildContext context) {
Widget setupGitButton = new Container();
var appState = StateContainer.of(context).appState;
if (!appState.remoteGitRepoConfigured) {
setupGitButton = ListTile(
title: new Text('Setup Git Sync'),
onTap: () {
Navigator.pop(context);
// Update the state of the app
// ...
},
);
}
return new Drawer(
child: new ListView(
// Important: Remove any padding from the ListView.
@ -23,6 +38,7 @@ class AppDrawer extends StatelessWidget {
),
),
),
setupGitButton,
new ListTile(
title: new Text('Share App'),
onTap: () {

@ -19,15 +19,19 @@ main() {
Note(fileName: "2.md", body: "test2", created: nowWithoutMicro()),
];
final directory = Directory.systemTemp.createTemp('__storage_test__');
final storage = FileStorage(
getDirectory: () => directory,
noteSerializer: new JsonNoteSerializer(),
);
Directory tempDir;
FileStorage storage;
setUpAll(() async {
tempDir = await Directory.systemTemp.createTemp('__storage_test__');
storage = FileStorage(
baseDirectory: tempDir.path,
noteSerializer: new JsonNoteSerializer(),
);
});
tearDownAll(() async {
final tempDirectory = await directory;
tempDirectory.deleteSync(recursive: true);
tempDir.deleteSync(recursive: true);
});
test('Should persist Notes to disk', () async {