Move all persistent state from AppState to Settings

This way all the persistant state of the app is managed from the same
place. It makes everything much easier. Also, it's required for when
GitJournal supports multiple repositories.
This commit is contained in:
Vishesh Handa
2020-09-24 23:44:32 +02:00
parent 1f32a3c10e
commit f30c52f595
11 changed files with 79 additions and 108 deletions

View File

@ -15,7 +15,6 @@ import 'package:path_provider/path_provider.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:quick_actions/quick_actions.dart'; import 'package:quick_actions/quick_actions.dart';
import 'package:receive_sharing_intent/receive_sharing_intent.dart'; import 'package:receive_sharing_intent/receive_sharing_intent.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:gitjournal/analytics.dart'; import 'package:gitjournal/analytics.dart';
import 'package:gitjournal/appstate.dart'; import 'package:gitjournal/appstate.dart';
@ -41,12 +40,10 @@ import 'setup/screens.dart';
class JournalApp extends StatefulWidget { class JournalApp extends StatefulWidget {
final AppState appState; final AppState appState;
static Future main(SharedPreferences pref) async { static Future main() async {
await Log.init(); await Log.init();
var appState = AppState(pref); var appState = AppState();
appState.dumpToLog();
var settings = Settings.instance; var settings = Settings.instance;
Log.i("Setting ${settings.toLoggableMap()}"); Log.i("Setting ${settings.toLoggableMap()}");
@ -54,38 +51,38 @@ class JournalApp extends StatefulWidget {
_enableAnalyticsIfPossible(settings); _enableAnalyticsIfPossible(settings);
} }
if (appState.gitBaseDirectory.isEmpty) { if (settings.gitBaseDirectory.isEmpty) {
var dir = await getApplicationDocumentsDirectory(); var dir = await getApplicationDocumentsDirectory();
appState.gitBaseDirectory = dir.path; settings.gitBaseDirectory = dir.path;
appState.save(pref); settings.save();
} }
if (!Directory(appState.gitBaseDirectory).existsSync()) { if (!Directory(settings.gitBaseDirectory).existsSync()) {
Log.w("Applications Documents Directory no longer exists"); Log.w("Applications Documents Directory no longer exists");
var dir = await getApplicationDocumentsDirectory(); var dir = await getApplicationDocumentsDirectory();
appState.gitBaseDirectory = dir.path; settings.gitBaseDirectory = dir.path;
appState.save(pref); settings.save();
Log.i("New Documents Directory Path ${dir.path}"); Log.i("New Documents Directory Path ${dir.path}");
} }
if (appState.localGitRepoConfigured == false) { if (settings.localGitRepoConfigured == false) {
// FIXME: What about exceptions! // FIXME: What about exceptions!
appState.localGitRepoFolderName = "journal_local"; settings.localGitRepoFolderName = "journal_local";
var repoPath = p.join( var repoPath = p.join(
appState.gitBaseDirectory, settings.gitBaseDirectory,
appState.localGitRepoFolderName, settings.localGitRepoFolderName,
); );
await GitRepository.init(repoPath); await GitRepository.init(repoPath);
appState.localGitRepoConfigured = true; settings.localGitRepoConfigured = true;
appState.save(pref); settings.save();
} }
var app = ChangeNotifierProvider.value( var app = ChangeNotifierProvider.value(
value: settings, value: settings,
child: ChangeNotifierProvider( child: ChangeNotifierProvider(
create: (_) { create: (_) {
return StateContainer(appState); return StateContainer(appState, settings);
}, },
child: ChangeNotifierProvider( child: ChangeNotifierProvider(
child: JournalApp(appState), child: JournalApp(appState),

View File

@ -1,7 +1,4 @@
import 'package:shared_preferences/shared_preferences.dart';
import 'package:gitjournal/core/notes_folder_fs.dart'; import 'package:gitjournal/core/notes_folder_fs.dart';
import 'package:gitjournal/utils/logger.dart';
enum SyncStatus { enum SyncStatus {
Unknown, Unknown,
@ -12,54 +9,12 @@ enum SyncStatus {
} }
class AppState { class AppState {
//
// Saved on Disk
//
// FIXME: These should be figured out by querying the 'git remotes'
String localGitRepoFolderName = "";
bool localGitRepoConfigured = false;
String remoteGitRepoFolderName = "";
bool remoteGitRepoConfigured = false;
SyncStatus syncStatus = SyncStatus.Unknown; SyncStatus syncStatus = SyncStatus.Unknown;
int numChanges = 0; int numChanges = 0;
//
// Temporary
//
/// This is the directory where all the git repos are stored
String gitBaseDirectory = "";
bool get hasJournalEntries { bool get hasJournalEntries {
return notesFolder.hasNotes; return notesFolder.hasNotes;
} }
NotesFolderFS notesFolder; NotesFolderFS notesFolder;
AppState(SharedPreferences pref) {
localGitRepoConfigured = pref.getBool("localGitRepoConfigured") ?? false;
remoteGitRepoConfigured = pref.getBool("remoteGitRepoConfigured") ?? false;
localGitRepoFolderName = pref.getString("localGitRepoPath") ?? "";
remoteGitRepoFolderName = pref.getString("remoteGitRepoPath") ?? "";
gitBaseDirectory = pref.getString("gitBaseDirectory") ?? "";
}
void dumpToLog() {
Log.i(" ---- Settings ---- ");
Log.i("localGitRepoConfigured: $localGitRepoConfigured");
Log.i("remoteGitRepoConfigured: $remoteGitRepoConfigured");
Log.i("localGitRepoFolderName: $localGitRepoFolderName");
Log.i("remoteGitRepoFolderName: $remoteGitRepoFolderName");
Log.i("gitBaseDirectory: $gitBaseDirectory");
Log.i(" ------------------ ");
}
Future save(SharedPreferences pref) async {
await pref.setBool("localGitRepoConfigured", localGitRepoConfigured);
await pref.setBool("remoteGitRepoConfigured", remoteGitRepoConfigured);
await pref.setString("localGitRepoPath", localGitRepoFolderName);
await pref.setString("remoteGitRepoPath", remoteGitRepoFolderName);
await pref.setString("gitBaseDirectory", gitBaseDirectory);
}
} }

View File

@ -29,6 +29,6 @@ void main() async {
}).sendPort); }).sendPort);
runZonedGuarded(() async { runZonedGuarded(() async {
await JournalApp.main(pref); await JournalApp.main();
}, reportError); }, reportError);
} }

View File

@ -372,7 +372,7 @@ class _FolderViewState extends State<FolderView> {
} }
List<Widget> _buildNoteActions() { List<Widget> _buildNoteActions() {
final appState = Provider.of<StateContainer>(context).appState; final settings = Provider.of<Settings>(context);
var extraActions = PopupMenuButton<DropDownChoices>( var extraActions = PopupMenuButton<DropDownChoices>(
onSelected: (DropDownChoices choice) { onSelected: (DropDownChoices choice) {
@ -405,7 +405,7 @@ class _FolderViewState extends State<FolderView> {
onPressed: _folderViewChooserSelected, onPressed: _folderViewChooserSelected,
key: const ValueKey("FolderViewSelector"), key: const ValueKey("FolderViewSelector"),
), ),
if (appState.remoteGitRepoConfigured) SyncButton(), if (settings.remoteGitRepoConfigured) SyncButton(),
IconButton( IconButton(
icon: const Icon(Icons.search), icon: const Icon(Icons.search),
onPressed: () { onPressed: () {

View File

@ -132,7 +132,8 @@ class _GitRemoteSettingsScreenState extends State<GitRemoteSettingsScreen> {
} }
var stateContainer = Provider.of<StateContainer>(context); var stateContainer = Provider.of<StateContainer>(context);
var gitDir = stateContainer.appState.gitBaseDirectory; final settings = Provider.of<Settings>(context);
var gitDir = settings.gitBaseDirectory;
// Figure out the next available folder // Figure out the next available folder
String repoFolderName = "journal_"; String repoFolderName = "journal_";

View File

@ -18,7 +18,6 @@ import 'package:gitjournal/screens/settings_note_metadata.dart';
import 'package:gitjournal/screens/settings_tags.dart'; import 'package:gitjournal/screens/settings_tags.dart';
import 'package:gitjournal/screens/settings_widgets.dart'; import 'package:gitjournal/screens/settings_widgets.dart';
import 'package:gitjournal/settings.dart'; import 'package:gitjournal/settings.dart';
import 'package:gitjournal/state_container.dart';
import 'package:gitjournal/utils.dart'; import 'package:gitjournal/utils.dart';
import 'package:gitjournal/widgets/folder_selection_dialog.dart'; import 'package:gitjournal/widgets/folder_selection_dialog.dart';
import 'package:gitjournal/widgets/pro_overlay.dart'; import 'package:gitjournal/widgets/pro_overlay.dart';
@ -55,10 +54,8 @@ class SettingsListState extends State<SettingsList> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
var stateContainer = Provider.of<StateContainer>(context, listen: false);
var remoteGitConfigured = stateContainer.appState.remoteGitRepoConfigured;
var settings = Provider.of<Settings>(context); var settings = Provider.of<Settings>(context);
var remoteGitConfigured = settings.remoteGitRepoConfigured;
var saveGitAuthor = (String gitAuthor) { var saveGitAuthor = (String gitAuthor) {
settings.gitAuthor = gitAuthor; settings.gitAuthor = gitAuthor;

View File

@ -75,6 +75,15 @@ class Settings extends ChangeNotifier {
Set<String> inlineTagPrefixes = {'#'}; Set<String> inlineTagPrefixes = {'#'};
// From AppState
String localGitRepoFolderName = "";
bool localGitRepoConfigured = false;
String remoteGitRepoFolderName = "";
bool remoteGitRepoConfigured = false;
String gitBaseDirectory = "";
void load(SharedPreferences pref) { void load(SharedPreferences pref) {
onBoardingCompleted = pref.getBool("onBoardingCompleted") ?? false; onBoardingCompleted = pref.getBool("onBoardingCompleted") ?? false;
@ -158,6 +167,13 @@ class Settings extends ChangeNotifier {
inlineTagPrefixes = inlineTagPrefixes =
pref.getStringList("inlineTagPrefixes")?.toSet() ?? inlineTagPrefixes; pref.getStringList("inlineTagPrefixes")?.toSet() ?? inlineTagPrefixes;
// From AppState
localGitRepoConfigured = pref.getBool("localGitRepoConfigured") ?? false;
remoteGitRepoConfigured = pref.getBool("remoteGitRepoConfigured") ?? false;
localGitRepoFolderName = pref.getString("localGitRepoPath") ?? "";
remoteGitRepoFolderName = pref.getString("remoteGitRepoPath") ?? "";
gitBaseDirectory = pref.getString("gitBaseDirectory") ?? "";
} }
Future save() async { Future save() async {
@ -245,6 +261,12 @@ class Settings extends ChangeNotifier {
pref.setInt("settingsVersion", version); pref.setInt("settingsVersion", version);
pref.setBool("localGitRepoConfigured", localGitRepoConfigured);
pref.setBool("remoteGitRepoConfigured", remoteGitRepoConfigured);
pref.setString("localGitRepoPath", localGitRepoFolderName);
pref.setString("remoteGitRepoPath", remoteGitRepoFolderName);
pref.setString("gitBaseDirectory", gitBaseDirectory);
notifyListeners(); notifyListeners();
} }
@ -330,6 +352,11 @@ class Settings extends ChangeNotifier {
'swipeToDelete': swipeToDelete.toString(), 'swipeToDelete': swipeToDelete.toString(),
'inlineTagPrefixes': inlineTagPrefixes.join(' '), 'inlineTagPrefixes': inlineTagPrefixes.join(' '),
'emojiParser': emojiParser.toString(), 'emojiParser': emojiParser.toString(),
'localGitRepoConfigured': localGitRepoConfigured.toString(),
'remoteGitRepoConfigured': remoteGitRepoConfigured.toString(),
'localGitRepoFolderName': localGitRepoFolderName.toString(),
'remoteGitRepoFolderName': remoteGitRepoFolderName.toString(),
'gitBaseDirectory': gitBaseDirectory.toString(),
}; };
} }

View File

@ -21,7 +21,6 @@ import 'package:gitjournal/setup/clone_url.dart';
import 'package:gitjournal/setup/loading_error.dart'; import 'package:gitjournal/setup/loading_error.dart';
import 'package:gitjournal/setup/repo_selector.dart'; import 'package:gitjournal/setup/repo_selector.dart';
import 'package:gitjournal/setup/sshkey.dart'; import 'package:gitjournal/setup/sshkey.dart';
import 'package:gitjournal/state_container.dart';
import 'package:gitjournal/utils.dart'; import 'package:gitjournal/utils.dart';
import 'package:gitjournal/utils/logger.dart'; import 'package:gitjournal/utils/logger.dart';
@ -468,9 +467,8 @@ class GitHostSetupScreenState extends State<GitHostSetupScreen> {
gitCloneErrorMessage = ""; gitCloneErrorMessage = "";
}); });
var stateContainer = Provider.of<StateContainer>(context); final settings = Provider.of<Settings>(context);
var appState = stateContainer.appState; var basePath = settings.gitBaseDirectory;
var basePath = appState.gitBaseDirectory;
// Just in case it was half cloned because of an error // Just in case it was half cloned because of an error
String repoPath = p.join(basePath, widget.repoFolderName); String repoPath = p.join(basePath, widget.repoFolderName);

View File

@ -5,7 +5,6 @@ import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:path/path.dart' as p; import 'package:path/path.dart' as p;
import 'package:shared_preferences/shared_preferences.dart';
import 'package:synchronized/synchronized.dart'; import 'package:synchronized/synchronized.dart';
import 'package:gitjournal/analytics.dart'; import 'package:gitjournal/analytics.dart';
@ -23,6 +22,7 @@ import 'package:gitjournal/utils/logger.dart';
class StateContainer with ChangeNotifier { class StateContainer with ChangeNotifier {
final AppState appState; final AppState appState;
final Settings settings;
final _opLock = Lock(); final _opLock = Lock();
final _loadLock = Lock(); final _loadLock = Lock();
@ -33,33 +33,33 @@ class StateContainer with ChangeNotifier {
GitNoteRepository _gitRepo; GitNoteRepository _gitRepo;
NotesCache _notesCache; NotesCache _notesCache;
StateContainer(this.appState) { StateContainer(this.appState, this.settings) {
assert(appState.localGitRepoConfigured); assert(settings.localGitRepoConfigured);
String repoPath; String repoPath;
if (appState.remoteGitRepoConfigured) { if (settings.remoteGitRepoConfigured) {
repoPath = repoPath =
p.join(appState.gitBaseDirectory, appState.remoteGitRepoFolderName); p.join(settings.gitBaseDirectory, settings.remoteGitRepoFolderName);
} else if (appState.localGitRepoConfigured) { } else if (settings.localGitRepoConfigured) {
repoPath = repoPath =
p.join(appState.gitBaseDirectory, appState.localGitRepoFolderName); p.join(settings.gitBaseDirectory, settings.localGitRepoFolderName);
} }
_gitRepo = GitNoteRepository(gitDirPath: repoPath); _gitRepo = GitNoteRepository(gitDirPath: repoPath);
appState.notesFolder = NotesFolderFS(null, _gitRepo.gitDirPath); appState.notesFolder = NotesFolderFS(null, _gitRepo.gitDirPath);
// Just a fail safe // Just a fail safe
if (!appState.remoteGitRepoConfigured) { if (!settings.remoteGitRepoConfigured) {
removeExistingRemoteClone(); removeExistingRemoteClone();
} }
// Makes it easier to filter the analytics // Makes it easier to filter the analytics
getAnalytics().firebase.setUserProperty( getAnalytics().firebase.setUserProperty(
name: 'onboarded', name: 'onboarded',
value: appState.remoteGitRepoConfigured.toString(), value: settings.remoteGitRepoConfigured.toString(),
); );
var cachePath = p.join(appState.gitBaseDirectory, "cache.json"); var cachePath = p.join(settings.gitBaseDirectory, "cache.json");
_notesCache = NotesCache( _notesCache = NotesCache(
filePath: cachePath, filePath: cachePath,
notesBasePath: _gitRepo.gitDirPath, notesBasePath: _gitRepo.gitDirPath,
@ -79,7 +79,7 @@ class StateContainer with ChangeNotifier {
void removeExistingRemoteClone() async { void removeExistingRemoteClone() async {
var remoteGitDir = Directory( var remoteGitDir = Directory(
p.join(appState.gitBaseDirectory, appState.remoteGitRepoFolderName)); p.join(settings.gitBaseDirectory, settings.remoteGitRepoFolderName));
var dotGitDir = Directory(p.join(remoteGitDir.path, ".git")); var dotGitDir = Directory(p.join(remoteGitDir.path, ".git"));
bool exists = dotGitDir.existsSync(); bool exists = dotGitDir.existsSync();
@ -100,7 +100,7 @@ class StateContainer with ChangeNotifier {
} }
Future<void> syncNotes({bool doNotThrow = false}) async { Future<void> syncNotes({bool doNotThrow = false}) async {
if (!appState.remoteGitRepoConfigured) { if (!settings.remoteGitRepoConfigured) {
Log.d("Not syncing because RemoteRepo not configured"); Log.d("Not syncing because RemoteRepo not configured");
return true; return true;
} }
@ -348,21 +348,21 @@ class StateContainer with ChangeNotifier {
void completeGitHostSetup(String repoFolderName) { void completeGitHostSetup(String repoFolderName) {
() async { () async {
var reconfiguringRemote = appState.remoteGitRepoConfigured; var reconfiguringRemote = settings.remoteGitRepoConfigured;
appState.remoteGitRepoConfigured = true; settings.remoteGitRepoConfigured = true;
appState.remoteGitRepoFolderName = repoFolderName; settings.remoteGitRepoFolderName = repoFolderName;
if (!reconfiguringRemote) { if (!reconfiguringRemote) {
await migrateGitRepo( await migrateGitRepo(
fromGitBasePath: appState.localGitRepoFolderName, fromGitBasePath: settings.localGitRepoFolderName,
toGitBaseFolder: appState.remoteGitRepoFolderName, toGitBaseFolder: settings.remoteGitRepoFolderName,
gitBasePath: appState.gitBaseDirectory, gitBasePath: settings.gitBaseDirectory,
); );
} }
var repoPath = var repoPath =
p.join(appState.gitBaseDirectory, appState.remoteGitRepoFolderName); p.join(settings.gitBaseDirectory, settings.remoteGitRepoFolderName);
_gitRepo = GitNoteRepository(gitDirPath: repoPath); _gitRepo = GitNoteRepository(gitDirPath: repoPath);
appState.notesFolder.reset(_gitRepo.gitDirPath); appState.notesFolder.reset(_gitRepo.gitDirPath);
@ -376,7 +376,6 @@ class StateContainer with ChangeNotifier {
} }
Future _persistConfig() async { Future _persistConfig() async {
var pref = await SharedPreferences.getInstance(); await settings.save();
await appState.save(pref);
} }
} }

View File

@ -13,7 +13,6 @@ import 'package:url_launcher/url_launcher.dart';
import 'package:gitjournal/analytics.dart'; import 'package:gitjournal/analytics.dart';
import 'package:gitjournal/settings.dart'; import 'package:gitjournal/settings.dart';
import 'package:gitjournal/state_container.dart';
import 'package:gitjournal/utils.dart'; import 'package:gitjournal/utils.dart';
import 'package:gitjournal/utils/logger.dart'; import 'package:gitjournal/utils/logger.dart';
@ -21,11 +20,11 @@ class AppDrawer extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
Widget setupGitButton; Widget setupGitButton;
var appState = Provider.of<StateContainer>(context).appState; var settings = Provider.of<Settings>(context);
var textStyle = Theme.of(context).textTheme.bodyText1; var textStyle = Theme.of(context).textTheme.bodyText1;
var currentRoute = ModalRoute.of(context).settings.name; var currentRoute = ModalRoute.of(context).settings.name;
if (!appState.remoteGitRepoConfigured) { if (!settings.remoteGitRepoConfigured) {
setupGitButton = ListTile( setupGitButton = ListTile(
leading: Icon(Icons.sync, color: textStyle.color), leading: Icon(Icons.sync, color: textStyle.color),
title: Text(tr('drawer.setup'), style: textStyle), title: Text(tr('drawer.setup'), style: textStyle),
@ -43,7 +42,6 @@ class AppDrawer extends StatelessWidget {
} }
var divider = Row(children: <Widget>[const Expanded(child: Divider())]); var divider = Row(children: <Widget>[const Expanded(child: Divider())]);
var settings = Provider.of<Settings>(context);
return Drawer( return Drawer(
child: ListView( child: ListView(

View File

@ -4,7 +4,6 @@ import 'package:flutter_driver/driver_extension.dart';
import 'package:path_provider/path_provider.dart'; import 'package:path_provider/path_provider.dart';
import 'package:gitjournal/app.dart'; import 'package:gitjournal/app.dart';
import 'package:gitjournal/appstate.dart';
import 'package:gitjournal/settings.dart'; import 'package:gitjournal/settings.dart';
import 'package:gitjournal/utils/datetime.dart'; import 'package:gitjournal/utils/datetime.dart';
@ -19,20 +18,20 @@ void main() async {
Settings.instance.load(pref); Settings.instance.load(pref);
await populateWithData(pref); await populateWithData(pref);
await JournalApp.main(pref); await JournalApp.main();
} }
// Generate lots of notes and folders better screenshots // Generate lots of notes and folders better screenshots
Future<void> populateWithData(SharedPreferences pref) async { Future<void> populateWithData(SharedPreferences pref) async {
var dir = await getApplicationDocumentsDirectory(); var dir = await getApplicationDocumentsDirectory();
var appState = AppState(pref); var settings = Settings.instance;
appState.gitBaseDirectory = dir.path; settings.gitBaseDirectory = dir.path;
appState.localGitRepoConfigured = true; settings.localGitRepoConfigured = true;
appState.localGitRepoFolderName = "journal_local"; settings.localGitRepoFolderName = "journal_local";
appState.save(pref); settings.save();
var repoPath = p.join(dir.path, appState.localGitRepoFolderName); var repoPath = p.join(dir.path, settings.localGitRepoFolderName);
await GitRepository.init(repoPath); await GitRepository.init(repoPath);
print("Filling fake data in $repoPath"); print("Filling fake data in $repoPath");