From 4c56ddc4dfa9a8c76ee50e7da7c59999515857fd Mon Sep 17 00:00:00 2001 From: Vishesh Handa Date: Wed, 20 May 2020 00:25:20 +0200 Subject: [PATCH] Allow the default Image location to be configured Fixes #10 --- assets/langs/en.yaml | 6 +++ lib/core/note.dart | 47 +++++++++++++++--- lib/core/notes_folder_fs.dart | 8 +++ lib/screens/settings_images.dart | 84 ++++++++++++++++++++++++++++++++ lib/screens/settings_screen.dart | 11 +++++ lib/settings.dart | 8 +++ 6 files changed, 156 insertions(+), 8 deletions(-) create mode 100644 lib/screens/settings_images.dart diff --git a/assets/langs/en.yaml b/assets/langs/en.yaml index 327e905e..f37a212a 100644 --- a/assets/langs/en.yaml +++ b/assets/langs/en.yaml @@ -21,6 +21,12 @@ settings: usageStats: Collect Anonymous Usage Statistics debug: Debug App debugLog: Look under the hood + images: + title: Image Settings + subtitle: Configure how Images are stored + imageLocation: Image Location + currentFolder: Same Folder as Note + customFolder: Custom Folder editors: checklist: add: Add Item diff --git a/lib/core/note.dart b/lib/core/note.dart index c61fb416..c9f5b90b 100644 --- a/lib/core/note.dart +++ b/lib/core/note.dart @@ -270,19 +270,50 @@ class Note with NotesNotifier { } Future addImage(File file) async { - var imageFileName = p.basename(file.path); - var imagePath = p.join(parent.folderPath, imageFileName); - await file.copy(imagePath); + var absImagePath = _buildImagePath(file); + await file.copy(absImagePath); - body = "$body\n ![Image](./$imageFileName)\n"; + var relativeImagePath = p.relative(absImagePath, from: parent.folderPath); + if (!relativeImagePath.startsWith('.')) { + relativeImagePath = './$relativeImagePath'; + } + var imageMarkdown = "![Image]($relativeImagePath)\n"; + if (body.isEmpty) { + body = imageMarkdown; + } else { + body = "$body\n$imageMarkdown"; + } } Future addImageSync(File file) async { - var imageFileName = p.basename(file.path); - var imagePath = p.join(parent.folderPath, imageFileName); - file.copySync(imagePath); + var absImagePath = _buildImagePath(file); + file.copySync(absImagePath); - body = "$body\n ![Image](./$imageFileName)\n"; + var relativeImagePath = p.relative(absImagePath, from: parent.folderPath); + if (!relativeImagePath.startsWith('.')) { + relativeImagePath = './$relativeImagePath'; + } + var imageMarkdown = "![Image]($relativeImagePath)\n"; + if (body.isEmpty) { + body = imageMarkdown; + } else { + body = "$body\n$imageMarkdown"; + } + } + + String _buildImagePath(File file) { + String baseFolder; + + var imageSpec = Settings.instance.imageLocationSpec; + if (imageSpec == '.') { + baseFolder = parent.folderPath; + } else { + baseFolder = parent.rootFolder.getFolderWithSpec(imageSpec).folderPath; + baseFolder ??= parent.folderPath; + } + + var imageFileName = p.basename(file.path); + return p.join(baseFolder, imageFileName); } @override diff --git a/lib/core/notes_folder_fs.dart b/lib/core/notes_folder_fs.dart index 8d86c58d..63f86fd3 100644 --- a/lib/core/notes_folder_fs.dart +++ b/lib/core/notes_folder_fs.dart @@ -399,6 +399,14 @@ class NotesFolderFS with NotesFolderNotifier implements NotesFolder { return null; } + NotesFolderFS get rootFolder { + var folder = this; + while (folder.parent != null) { + folder = folder.parent; + } + return folder; + } + Note getNoteWithSpec(String spec) { var parts = spec.split(p.separator); var folder = this; diff --git a/lib/screens/settings_images.dart b/lib/screens/settings_images.dart new file mode 100644 index 00000000..3a8bc0ba --- /dev/null +++ b/lib/screens/settings_images.dart @@ -0,0 +1,84 @@ +import 'package:easy_localization/easy_localization.dart'; +import 'package:flutter/material.dart'; +import 'package:gitjournal/settings.dart'; +import 'package:gitjournal/screens/settings_widgets.dart'; +import 'package:gitjournal/core/notes_folder_fs.dart'; +import 'package:gitjournal/widgets/folder_selection_dialog.dart'; +import 'package:gitjournal/widgets/pro_overlay.dart'; +import 'package:provider/provider.dart'; + +class SettingsImagesScreen extends StatefulWidget { + @override + SettingsImagesScreenState createState() => SettingsImagesScreenState(); +} + +class SettingsImagesScreenState extends State { + @override + Widget build(BuildContext context) { + var settings = Settings.instance; + var folder = Provider.of(context) + .getFolderWithSpec(settings.imageLocationSpec); + + var sameFolder = tr("settings.images.currentFolder"); + var customFolder = tr("settings.images.customFolder"); + + var body = ListView(children: [ + ListPreference( + title: tr("settings.images.imageLocation"), + currentOption: + settings.imageLocationSpec == '.' ? sameFolder : customFolder, + options: [sameFolder, customFolder], + onChange: (String publicStr) { + if (publicStr == sameFolder) { + Settings.instance.imageLocationSpec = "."; + } else { + Settings.instance.imageLocationSpec = ""; + } + Settings.instance.save(); + setState(() {}); + }, + ), + if (settings.imageLocationSpec != '.') + ListTile( + title: Text(customFolder), + subtitle: Text(folder != null ? folder.publicName : "/"), + onTap: () async { + var destFolder = await showDialog( + context: context, + builder: (context) => FolderSelectionDialog(), + ); + + Settings.instance.imageLocationSpec = + destFolder != null ? destFolder.pathSpec() : ""; + Settings.instance.save(); + setState(() {}); + }, + ), + ]); + + return Scaffold( + appBar: AppBar( + title: Text(tr('settings.images.title')), + leading: IconButton( + icon: const Icon(Icons.arrow_back), + onPressed: () { + Navigator.of(context).pop(); + }, + ), + ), + body: ProOverlay(child: body), + ); + } +} + +// +// Options to expose +// - Image Location +// - Note Directory +// - Custom Directory +// Bool use relative path if possible +// - Image FileName +// - Original Name +// - Note FileName + _num +// - Custom Name +// diff --git a/lib/screens/settings_screen.dart b/lib/screens/settings_screen.dart index 8b240c8a..852dc243 100644 --- a/lib/screens/settings_screen.dart +++ b/lib/screens/settings_screen.dart @@ -4,6 +4,7 @@ import 'package:easy_localization/easy_localization.dart'; import 'package:gitjournal/core/notes_folder_fs.dart'; import 'package:gitjournal/screens/debug_screen.dart'; import 'package:gitjournal/screens/settings_editors.dart'; +import 'package:gitjournal/screens/settings_images.dart'; import 'package:gitjournal/settings.dart'; import 'package:gitjournal/state_container.dart'; import 'package:gitjournal/utils.dart'; @@ -222,6 +223,16 @@ class SettingsListState extends State { Navigator.of(context).push(route); }, ), + ListTile( + title: Text(tr('settings.images.title')), + subtitle: Text(tr('settings.images.subtitle')), + onTap: () { + var route = MaterialPageRoute( + builder: (context) => SettingsImagesScreen(), + ); + Navigator.of(context).push(route); + }, + ), const SizedBox(height: 16.0), SettingsHeader(tr('settings.analytics')), SwitchListTile( diff --git a/lib/settings.dart b/lib/settings.dart index 6e051f39..2d0d9c02 100644 --- a/lib/settings.dart +++ b/lib/settings.dart @@ -46,6 +46,8 @@ class Settings { SettingsMarkdownDefaultView markdownDefaultView = SettingsMarkdownDefaultView.Default; + String imageLocationSpec = "."; // . means the same folder + void load(SharedPreferences pref) { gitAuthor = pref.getString("gitAuthor") ?? gitAuthor; gitAuthorEmail = pref.getString("gitAuthorEmail") ?? gitAuthorEmail; @@ -94,6 +96,9 @@ class Settings { homeScreen = SettingsHomeScreen.fromInternalString(pref.getString("homeScreen")); + + imageLocationSpec = + pref.getString("imageLocationSpec") ?? imageLocationSpec; } Future save() async { @@ -148,6 +153,8 @@ class Settings { _setBool(pref, "proMode", proMode, defaultSet.proMode); _setString(pref, "homeScreen", homeScreen.toInternalString(), defaultSet.homeScreen.toInternalString()); + _setString(pref, "imageLocationSpec", imageLocationSpec, + defaultSet.imageLocationSpec); pref.setInt("settingsVersion", version); @@ -206,6 +213,7 @@ class Settings { 'pseudoId': pseudoId, 'markdownDefaultView': markdownDefaultView.toInternalString(), 'homeScreen': homeScreen.toInternalString(), + 'imageLocationSpec': imageLocationSpec, }; }