Settings: Access it through the Provider

Make it a ChageNotifier and try to access it through the Provider
instead of like a global variable. This way, the state is better
managed and it'll be easier to split out Settings into smaller classes.
This commit is contained in:
Vishesh Handa
2020-08-09 01:29:22 +02:00
parent 9411a36f4a
commit 9d55b449d3
14 changed files with 136 additions and 106 deletions

View File

@ -46,10 +46,11 @@ class JournalApp extends StatefulWidget {
var appState = AppState(pref);
appState.dumpToLog();
Log.i("Setting ${Settings.instance.toLoggableMap()}");
var settings = Settings.instance;
Log.i("Setting ${settings.toLoggableMap()}");
if (Settings.instance.collectUsageStatistics) {
_enableAnalyticsIfPossible();
if (settings.collectUsageStatistics) {
_enableAnalyticsIfPossible(settings);
}
if (appState.gitBaseDirectory.isEmpty) {
@ -79,7 +80,9 @@ class JournalApp extends StatefulWidget {
appState.save(pref);
}
var app = ChangeNotifierProvider(
var app = ChangeNotifierProvider.value(
value: settings,
child: ChangeNotifierProvider(
create: (_) {
return StateContainer(appState);
},
@ -90,6 +93,7 @@ class JournalApp extends StatefulWidget {
return appState.notesFolder;
},
),
),
);
InAppPurchases.confirmProPurchaseBoot();
@ -105,7 +109,7 @@ class JournalApp extends StatefulWidget {
));
}
static void _enableAnalyticsIfPossible() async {
static void _enableAnalyticsIfPossible(Settings settings) async {
JournalApp.isInDebugMode = foundation.kDebugMode;
var isPhysicalDevice = true;
@ -136,7 +140,7 @@ class JournalApp extends StatefulWidget {
if (enabled) {
JournalApp.analytics.logEvent(
name: "settings",
parameters: Settings.instance.toLoggableMap(),
parameters: settings.toLoggableMap(),
);
}
}
@ -281,12 +285,13 @@ class _JournalAppState extends State<JournalApp> {
MaterialApp buildApp(BuildContext context, ThemeData themeData) {
var stateContainer = Provider.of<StateContainer>(context);
var settings = Provider.of<Settings>(context);
var initialRoute = '/';
if (!stateContainer.appState.onBoardingCompleted) {
initialRoute = '/onBoarding';
}
if (Settings.instance.homeScreen == SettingsHomeScreen.AllFolders) {
if (settings.homeScreen == SettingsHomeScreen.AllFolders) {
initialRoute = '/folders';
}

View File

@ -2,6 +2,8 @@ import 'dart:io';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:gitjournal/core/note.dart';
import 'package:gitjournal/editors/common.dart';
import 'package:gitjournal/editors/disposable_change_notifier.dart';
@ -129,7 +131,8 @@ class MarkdownEditorState extends State<MarkdownEditor>
Widget body = editingMode ? editor : NoteViewer(note: note);
if (Settings.instance.experimentalMarkdownToolbar && editingMode) {
var settings = Provider.of<Settings>(context);
if (settings.experimentalMarkdownToolbar && editingMode) {
body = Container(
height: 600,
child: Column(
@ -165,19 +168,19 @@ class MarkdownEditorState extends State<MarkdownEditor>
}
void _switchMode() {
var settings = Provider.of<Settings>(context);
setState(() {
editingMode = !editingMode;
switch (editingMode) {
case true:
Settings.instance.markdownLastUsedView =
SettingsMarkdownDefaultView.Edit;
settings.markdownLastUsedView = SettingsMarkdownDefaultView.Edit;
break;
case false:
Settings.instance.markdownLastUsedView =
SettingsMarkdownDefaultView.View;
settings.markdownLastUsedView = SettingsMarkdownDefaultView.View;
break;
}
Settings.instance.save();
settings.save();
_updateNote();
});
}

View File

@ -1,5 +1,7 @@
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:gitjournal/core/notes_folder_fs.dart';
import 'package:gitjournal/editors/common.dart';
import 'package:gitjournal/settings.dart';
@ -46,7 +48,9 @@ class _EditorScaffoldState extends State<EditorScaffold> {
}
void _editorChanged() {
if (Settings.instance.zenMode && !hideUIElements) {
var settings = Provider.of<Settings>(context);
if (settings.zenMode && !hideUIElements) {
setState(() {
hideUIElements = true;
});
@ -55,11 +59,13 @@ class _EditorScaffoldState extends State<EditorScaffold> {
@override
Widget build(BuildContext context) {
var settings = Provider.of<Settings>(context);
return Scaffold(
body: GestureDetector(
behavior: HitTestBehavior.translucent,
onTap: () {
if (Settings.instance.zenMode) {
if (settings.zenMode) {
setState(() {
hideUIElements = false;
});
@ -84,13 +90,13 @@ class _EditorScaffoldState extends State<EditorScaffold> {
editorState: widget.editorState,
parentFolder: widget.parentFolder,
allowEdits: widget.allowEdits,
zenMode: Settings.instance.zenMode,
zenMode: settings.zenMode,
onZenModeChanged: () {
setState(() {
Settings.instance.zenMode = !Settings.instance.zenMode;
Settings.instance.save();
settings.zenMode = !settings.zenMode;
settings.save();
if (Settings.instance.zenMode) {
if (settings.zenMode) {
hideUIElements = true;
}
});

View File

@ -1,6 +1,7 @@
import 'package:flutter/material.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:provider/provider.dart';
import 'package:gitjournal/settings.dart';
import 'package:gitjournal/utils/logger.dart';
@ -12,7 +13,6 @@ class DebugScreen extends StatefulWidget {
class _DebugScreenState extends State<DebugScreen> {
ScrollController _controller = ScrollController();
String filterLevel = Settings.instance.debugLogLevel;
List<LogMessage> _logs;
@ -79,6 +79,9 @@ class _DebugScreenState extends State<DebugScreen> {
}
bool _shouldDisplay(LogMessage msg) {
var settings = Provider.of<Settings>(context);
var filterLevel = settings.debugLogLevel;
if (filterLevel == null || filterLevel.isEmpty) {
return true;
}
@ -196,6 +199,9 @@ class _DebugScreenState extends State<DebugScreen> {
}
void _showFilterSelection() async {
var settings = Provider.of<Settings>(context);
var filterLevel = settings.debugLogLevel;
var dialog = AlertDialog(
title: Text(tr('settings.debug.levels')),
content: Column(
@ -211,12 +217,8 @@ class _DebugScreenState extends State<DebugScreen> {
);
var l = await showDialog(context: context, builder: (context) => dialog);
if (l != null) {
setState(() {
Settings.instance.debugLogLevel = l;
Settings.instance.save();
filterLevel = l;
});
settings.debugLogLevel = l;
settings.save();
}
}
}

View File

@ -1,6 +1,7 @@
import 'package:flutter/material.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:provider/provider.dart';
import 'package:gitjournal/core/notes_folder_fs.dart';
import 'package:gitjournal/screens/settings_screen.dart';
@ -18,9 +19,8 @@ class SettingsEditorsScreen extends StatefulWidget {
class SettingsEditorsScreenState extends State<SettingsEditorsScreen> {
@override
Widget build(BuildContext context) {
var settings = Settings.instance;
var defaultNewFolder =
Settings.instance.journalEditordefaultNewNoteFolderSpec;
var settings = Provider.of<Settings>(context);
var defaultNewFolder = settings.journalEditordefaultNewNoteFolderSpec;
if (defaultNewFolder.isEmpty) {
defaultNewFolder = tr("rootFolder");
} else {
@ -28,8 +28,8 @@ class SettingsEditorsScreenState extends State<SettingsEditorsScreen> {
setState(() {
defaultNewFolder = tr("rootFolder");
Settings.instance.journalEditordefaultNewNoteFolderSpec = "";
Settings.instance.save();
settings.journalEditordefaultNewNoteFolderSpec = "";
settings.save();
});
}
}
@ -42,8 +42,8 @@ class SettingsEditorsScreenState extends State<SettingsEditorsScreen> {
SettingsEditorType.options.map((f) => f.toPublicString()).toList(),
onChange: (String publicStr) {
var val = SettingsEditorType.fromPublicString(publicStr);
Settings.instance.defaultEditor = val;
Settings.instance.save();
settings.defaultEditor = val;
settings.save();
setState(() {});
},
),
@ -56,8 +56,8 @@ class SettingsEditorsScreenState extends State<SettingsEditorsScreen> {
.toList(),
onChange: (String publicStr) {
var val = SettingsMarkdownDefaultView.fromPublicString(publicStr);
Settings.instance.markdownDefaultView = val;
Settings.instance.save();
settings.markdownDefaultView = val;
settings.save();
setState(() {});
},
),
@ -72,9 +72,9 @@ class SettingsEditorsScreenState extends State<SettingsEditorsScreen> {
builder: (context) => FolderSelectionDialog(),
);
Settings.instance.journalEditordefaultNewNoteFolderSpec =
settings.journalEditordefaultNewNoteFolderSpec =
destFolder != null ? destFolder.pathSpec() : "";
Settings.instance.save();
settings.save();
setState(() {});
},
),

View File

@ -39,7 +39,7 @@ class _GitRemoteSettingsScreenState extends State<GitRemoteSettingsScreen> {
@override
Widget build(BuildContext context) {
var textTheme = Theme.of(context).textTheme;
var settings = Settings.instance;
var settings = Provider.of<Settings>(context);
var body = Column(
children: <Widget>[
@ -72,8 +72,8 @@ class _GitRemoteSettingsScreenState extends State<GitRemoteSettingsScreen> {
.toList(),
onChange: (String publicStr) {
var val = RemoteSyncFrequency.fromPublicString(publicStr);
Settings.instance.remoteSyncFrequency = val;
Settings.instance.save();
settings.remoteSyncFrequency = val;
settings.save();
setState(() {});
},
),

View File

@ -17,14 +17,14 @@ class SettingsImagesScreen extends StatefulWidget {
class SettingsImagesScreenState extends State<SettingsImagesScreen> {
@override
Widget build(BuildContext context) {
var settings = Settings.instance;
var settings = Provider.of<Settings>(context);
var folder = Provider.of<NotesFolderFS>(context)
.getFolderWithSpec(settings.imageLocationSpec);
// If the Custom Folder specified no longer exists
if (settings.imageLocationSpec != "." && folder == null) {
Settings.instance.imageLocationSpec = ".";
Settings.instance.save();
settings.imageLocationSpec = ".";
settings.save();
}
var sameFolder = tr("settings.images.currentFolder");
@ -38,11 +38,11 @@ class SettingsImagesScreenState extends State<SettingsImagesScreen> {
options: [sameFolder, customFolder],
onChange: (String publicStr) {
if (publicStr == sameFolder) {
Settings.instance.imageLocationSpec = ".";
settings.imageLocationSpec = ".";
} else {
Settings.instance.imageLocationSpec = "";
settings.imageLocationSpec = "";
}
Settings.instance.save();
settings.save();
setState(() {});
},
),
@ -56,9 +56,9 @@ class SettingsImagesScreenState extends State<SettingsImagesScreen> {
builder: (context) => FolderSelectionDialog(),
);
Settings.instance.imageLocationSpec =
settings.imageLocationSpec =
destFolder != null ? destFolder.pathSpec() : "";
Settings.instance.save();
settings.save();
setState(() {});
},
),

View File

@ -1,6 +1,7 @@
import 'package:flutter/material.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:provider/provider.dart';
import 'package:gitjournal/core/md_yaml_doc.dart';
import 'package:gitjournal/core/md_yaml_doc_codec.dart';
@ -23,6 +24,7 @@ class _NoteMetadataSettingsScreenState
@override
Widget build(BuildContext context) {
var textTheme = Theme.of(context).textTheme;
var settings = Provider.of<Settings>(context);
var note = Note(null, "fileName.md");
note.title = tr("settings.noteMetaData.exampleTitle");
@ -51,14 +53,14 @@ class _NoteMetadataSettingsScreenState
const Divider(),
SwitchListTile(
title: Text(tr("settings.noteMetaData.enableHeader")),
value: Settings.instance.yamlHeaderEnabled,
value: settings.yamlHeaderEnabled,
onChanged: (bool newVal) {
setState(() {
Settings.instance.yamlHeaderEnabled = newVal;
settings.yamlHeaderEnabled = newVal;
if (newVal == false) {
Settings.instance.saveTitleInH1 = true;
settings.saveTitleInH1 = true;
}
Settings.instance.save();
settings.save();
});
},
),
@ -71,14 +73,14 @@ class _NoteMetadataSettingsScreenState
"lastmodified",
"lastmod",
],
currentOption: Settings.instance.yamlModifiedKey,
currentOption: settings.yamlModifiedKey,
onChange: (String newVal) {
setState(() {
Settings.instance.yamlModifiedKey = newVal;
Settings.instance.save();
settings.yamlModifiedKey = newVal;
settings.save();
});
},
enabled: Settings.instance.yamlHeaderEnabled,
enabled: settings.yamlHeaderEnabled,
),
),
ProOverlay(
@ -88,14 +90,14 @@ class _NoteMetadataSettingsScreenState
"created",
"date",
],
currentOption: Settings.instance.yamlCreatedKey,
currentOption: settings.yamlCreatedKey,
onChange: (String newVal) {
setState(() {
Settings.instance.yamlCreatedKey = newVal;
Settings.instance.save();
settings.yamlCreatedKey = newVal;
settings.save();
});
},
enabled: Settings.instance.yamlHeaderEnabled,
enabled: settings.yamlHeaderEnabled,
),
),
ProOverlay(
@ -105,14 +107,14 @@ class _NoteMetadataSettingsScreenState
"tags",
"categories",
],
currentOption: Settings.instance.yamlTagsKey,
currentOption: settings.yamlTagsKey,
onChange: (String newVal) {
setState(() {
Settings.instance.yamlTagsKey = newVal;
Settings.instance.save();
settings.yamlTagsKey = newVal;
settings.save();
});
},
enabled: Settings.instance.yamlHeaderEnabled,
enabled: settings.yamlHeaderEnabled,
),
),
ProOverlay(
@ -120,17 +122,17 @@ class _NoteMetadataSettingsScreenState
title: tr("settings.noteMetaData.titleMetaData.title"),
options: [
tr("settings.noteMetaData.titleMetaData.fromH1"),
if (Settings.instance.yamlHeaderEnabled)
if (settings.yamlHeaderEnabled)
tr("settings.noteMetaData.titleMetaData.fromYaml"),
],
currentOption: Settings.instance.saveTitleInH1
currentOption: settings.saveTitleInH1
? tr("settings.noteMetaData.titleMetaData.fromH1")
: tr("settings.noteMetaData.titleMetaData.fromYaml"),
onChange: (String newVal) {
setState(() {
Settings.instance.saveTitleInH1 =
settings.saveTitleInH1 =
newVal == tr("settings.noteMetaData.titleMetaData.fromH1");
Settings.instance.save();
settings.save();
});
},
),

View File

@ -54,11 +54,11 @@ class SettingsListState extends State<SettingsList> {
var stateContainer = Provider.of<StateContainer>(context, listen: false);
var remoteGitConfigured = stateContainer.appState.remoteGitRepoConfigured;
var settings = Settings.instance;
var settings = Provider.of<Settings>(context);
var saveGitAuthor = (String gitAuthor) {
Settings.instance.gitAuthor = gitAuthor;
Settings.instance.save();
settings.gitAuthor = gitAuthor;
settings.save();
};
var gitAuthorForm = Form(
@ -80,7 +80,7 @@ class SettingsListState extends State<SettingsList> {
textInputAction: TextInputAction.done,
onFieldSubmitted: saveGitAuthor,
onSaved: saveGitAuthor,
initialValue: Settings.instance.gitAuthor,
initialValue: settings.gitAuthor,
),
onChanged: () {
if (!gitAuthorKey.currentState.validate()) return;
@ -90,8 +90,8 @@ class SettingsListState extends State<SettingsList> {
);
var saveGitAuthorEmail = (String gitAuthorEmail) {
Settings.instance.gitAuthorEmail = gitAuthorEmail;
Settings.instance.save();
settings.gitAuthorEmail = gitAuthorEmail;
settings.save();
};
var gitAuthorEmailForm = Form(
child: TextFormField(
@ -121,7 +121,7 @@ class SettingsListState extends State<SettingsList> {
textInputAction: TextInputAction.done,
onFieldSubmitted: saveGitAuthorEmail,
onSaved: saveGitAuthorEmail,
initialValue: Settings.instance.gitAuthorEmail,
initialValue: settings.gitAuthorEmail,
),
onChanged: () {
if (!gitAuthorEmailKey.currentState.validate()) return;
@ -131,7 +131,7 @@ class SettingsListState extends State<SettingsList> {
);
var brightness = DynamicTheme.of(context).brightness;
var defaultNewFolder = Settings.instance.defaultNewNoteFolderSpec;
var defaultNewFolder = settings.defaultNewNoteFolderSpec;
if (defaultNewFolder.isEmpty) {
defaultNewFolder = tr("rootFolder");
} else {
@ -139,8 +139,8 @@ class SettingsListState extends State<SettingsList> {
setState(() {
defaultNewFolder = tr("rootFolder");
Settings.instance.defaultNewNoteFolderSpec = "";
Settings.instance.save();
settings.defaultNewNoteFolderSpec = "";
settings.save();
});
}
}
@ -165,8 +165,8 @@ class SettingsListState extends State<SettingsList> {
.toList(),
onChange: (String publicStr) {
var s = SettingsHomeScreen.fromPublicString(publicStr);
Settings.instance.homeScreen = s;
Settings.instance.save();
settings.homeScreen = s;
settings.save();
setState(() {});
},
),
@ -181,8 +181,8 @@ class SettingsListState extends State<SettingsList> {
builder: (context) => FolderSelectionDialog(),
);
if (destFolder != null) {
Settings.instance.defaultNewNoteFolderSpec = destFolder.pathSpec();
Settings.instance.save();
settings.defaultNewNoteFolderSpec = destFolder.pathSpec();
settings.save();
setState(() {});
}
},
@ -222,8 +222,8 @@ class SettingsListState extends State<SettingsList> {
NoteFileNameFormat.options.map((f) => f.toPublicString()).toList(),
onChange: (String publicStr) {
var format = NoteFileNameFormat.fromPublicString(publicStr);
Settings.instance.noteFileNameFormat = format;
Settings.instance.save();
settings.noteFileNameFormat = format;
settings.save();
setState(() {});
},
),
@ -253,19 +253,19 @@ class SettingsListState extends State<SettingsList> {
SettingsHeader(tr('settings.analytics')),
SwitchListTile(
title: Text(tr('settings.usageStats')),
value: Settings.instance.collectUsageStatistics,
value: settings.collectUsageStatistics,
onChanged: (bool val) {
Settings.instance.collectUsageStatistics = val;
Settings.instance.save();
settings.collectUsageStatistics = val;
settings.save();
setState(() {});
},
),
SwitchListTile(
title: Text(tr('settings.crashReports')),
value: Settings.instance.collectCrashReports,
value: settings.collectCrashReports,
onChanged: (bool val) {
Settings.instance.collectCrashReports = val;
Settings.instance.save();
settings.collectCrashReports = val;
settings.save();
setState(() {});
},
),

View File

@ -1,3 +1,5 @@
import 'package:flutter/material.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:uuid/uuid.dart';
@ -5,7 +7,7 @@ import 'package:gitjournal/core/sorting_mode.dart';
import 'package:gitjournal/folder_views/common.dart';
import 'package:gitjournal/screens/note_editor.dart';
class Settings {
class Settings extends ChangeNotifier {
// singleton
static final Settings _singleton = Settings._internal();
factory Settings() => _singleton;
@ -203,6 +205,8 @@ class Settings {
_setBool(pref, "saveTitleInH1", saveTitleInH1, defaultSet.saveTitleInH1);
pref.setInt("settingsVersion", version);
notifyListeners();
}
Future<void> _setString(

View File

@ -514,10 +514,12 @@ class GitHostSetupScreenState extends State<GitHostSetupScreen> {
folderPath: repoPath,
);
await repo.add('.gitignore');
var settings = Provider.of<Settings>(context, listen: false);
await repo.commit(
message: "Add gitignore file",
authorEmail: Settings.instance.gitAuthorEmail,
authorName: Settings.instance.gitAuthor,
authorEmail: settings.gitAuthorEmail,
authorName: settings.gitAuthor,
);
}

View File

@ -43,6 +43,7 @@ class AppDrawer extends StatelessWidget {
}
var divider = Row(children: <Widget>[const Expanded(child: Divider())]);
var settings = Provider.of<Settings>(context);
return Drawer(
child: ListView(
@ -51,7 +52,7 @@ class AppDrawer extends StatelessWidget {
children: <Widget>[
_AppDrawerHeader(),
if (setupGitButton != null) ...[setupGitButton, divider],
if (!Settings.instance.proMode)
if (!settings.proMode)
_buildDrawerTile(
context,
icon: Icons.power,
@ -65,7 +66,7 @@ class AppDrawer extends StatelessWidget {
);
},
),
if (!Settings.instance.proMode) divider,
if (!settings.proMode) divider,
_buildDrawerTile(
context,
icon: Icons.note,
@ -80,7 +81,7 @@ class AppDrawer extends StatelessWidget {
onTap: () => _navTopLevel(context, '/folders'),
selected: currentRoute == "/folders",
),
if (Settings.instance.experimentalFs)
if (settings.experimentalFs)
_buildDrawerTile(
context,
icon: FontAwesomeIcons.solidFolderOpen,

View File

@ -1,6 +1,7 @@
import 'package:flutter/material.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:provider/provider.dart';
import 'package:gitjournal/settings.dart';
@ -11,9 +12,11 @@ class ProOverlay extends StatelessWidget {
@override
Widget build(BuildContext context) {
if (Settings.instance.proMode) {
var settings = Provider.of<Settings>(context);
if (settings.proMode) {
return child;
}
return GestureDetector(
behavior: HitTestBehavior.opaque,
child: Banner(

View File

@ -4,6 +4,7 @@ import 'dart:io';
import 'package:flutter/material.dart';
import 'package:in_app_purchase/in_app_purchase.dart';
import 'package:provider/provider.dart';
import 'package:gitjournal/analytics.dart';
import 'package:gitjournal/iap.dart';
@ -171,9 +172,10 @@ class _PurchaseWidgetState extends State<PurchaseWidget> {
}
void _deliverProduct(SubscriptionStatus status) {
Settings.instance.proMode = status.isPro;
Settings.instance.proExpirationDate = status.expiryDate.toIso8601String();
Settings.instance.save();
var settings = Provider.of<Settings>(context);
settings.proMode = status.isPro;
settings.proExpirationDate = status.expiryDate.toIso8601String();
settings.save();
getAnalytics().logEvent(
name: "purchase_screen_thank_you",