Improved settings

This commit is contained in:
Robert McRackan 2019-12-13 16:11:55 -05:00
parent 2fa5170f28
commit 95ae8335a1
36 changed files with 1755 additions and 805 deletions

View file

@ -4,6 +4,8 @@ using System.ComponentModel;
using System.IO;
using System.Linq;
using Dinah.Core;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
namespace FileManager
{
@ -31,12 +33,18 @@ namespace FileManager
*/
#endregion
private PersistentDictionary persistentDictionary { get; }
private PersistentDictionary persistentDictionary;
[Description("Location of the configuration file where these settings are saved. Please do not edit this file directly while Libation is running.")]
public string Filepath => Path.Combine(Path.GetDirectoryName(Exe.FileLocationOnDisk), "Settings.json");
public bool IsComplete
=> File.Exists(APPSETTINGS_JSON)
&& Directory.Exists(LibationFiles)
&& Directory.Exists(Books)
&& File.Exists(SettingsJsonPath)
&& !string.IsNullOrWhiteSpace(LocaleCountryCode)
&& !string.IsNullOrWhiteSpace(DownloadsInProgressEnum)
&& !string.IsNullOrWhiteSpace(DecryptInProgressEnum);
[Description("[Advanced. Leave alone in most cases.] Your user-specific key used to decrypt your audible files (*.aax) into audio files you can use anywhere (*.m4b)")]
[Description("Your user-specific key used to decrypt your audible files (*.aax) into audio files you can use anywhere (*.m4b). Leave alone in most cases")]
public string DecryptKey
{
get => persistentDictionary[nameof(DecryptKey)];
@ -50,17 +58,21 @@ namespace FileManager
set => persistentDictionary[nameof(Books)] = value;
}
public string WinTemp { get; } = Path.Combine(Path.GetTempPath(), "Libation");
public static string AppDir { get; } = Path.GetFullPath(Path.Combine(Path.GetDirectoryName(Exe.FileLocationOnDisk), LIBATION_FILES));
public static string MyDocs { get; } = Path.GetFullPath(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), LIBATION_FILES));
public static string WinTemp { get; } = Path.GetFullPath(Path.Combine(Path.GetTempPath(), "Libation"));
[Description("Location for storage of program-created files")]
public string LibationFiles
private Dictionary<string, string> wellKnownPaths { get; } = new Dictionary<string, string>
{
get => persistentDictionary[nameof(LibationFiles)];
set => persistentDictionary[nameof(LibationFiles)] = value;
}
["AppDir"] = AppDir,
["MyDocs"] = MyDocs,
["WinTemp"] = WinTemp
};
private Dictionary<string, string> cache { get; } = new Dictionary<string, string>();
// default setting and directory creation occur in class responsible for files.
// config class is only responsible for path. not responsible for setting defaults, dir validation, or dir creation
// exceptions: appsettings.json, LibationFiles dir, Settings.json
// temp/working dir(s) should be outside of dropbox
[Description("Temporary location of files while they're in process of being downloaded.\r\nWhen download is complete, the final file will be in [LibationFiles]\\DownloadsFinal")]
@ -78,49 +90,114 @@ namespace FileManager
set => persistentDictionary[nameof(DecryptInProgressEnum)] = value;
}
public string LocaleCountryCode
{
get => persistentDictionary[nameof(LocaleCountryCode)];
set => persistentDictionary[nameof(LocaleCountryCode)] = value;
}
public string LocaleCountryCode
{
get => persistentDictionary[nameof(LocaleCountryCode)];
set => persistentDictionary[nameof(LocaleCountryCode)] = value;
}
// note: any potential file manager static ctors can't compensate if storage dir is changed at run time via settings. this is partly bad architecture. but the side effect is desirable. if changing LibationFiles location: restart app
// singleton stuff
public static Configuration Instance { get; } = new Configuration();
private Configuration()
{
// load json values into memory
persistentDictionary = new PersistentDictionary(Filepath);
ensureDictionaryEntries();
private Configuration() { }
// don't create dir. dir creation is the responsibility of places that use the dir
if (string.IsNullOrWhiteSpace(LibationFiles))
LibationFiles = Path.Combine(Path.GetDirectoryName(Exe.FileLocationOnDisk), "Libation");
private const string APPSETTINGS_JSON = "appsettings.json";
private const string LIBATION_FILES = "LibationFiles";
[Description("Location for storage of program-created files")]
public string LibationFiles
=> cache.ContainsKey(LIBATION_FILES)
? cache[LIBATION_FILES]
: getLibationFiles();
private string getLibationFiles()
{
var value = getLiberationFilesSettingFromJson();
if (wellKnownPaths.ContainsKey(value))
value = wellKnownPaths[value];
// must write here before SettingsJsonPath in next step tries to read from dictionary
cache[LIBATION_FILES] = value;
// load json values into memory. create if not exists
persistentDictionary = new PersistentDictionary(SettingsJsonPath);
persistentDictionary.EnsureEntries<Configuration>();
return value;
}
private string getLiberationFilesSettingFromJson()
{
static string createSettingsJson()
{
var dir = "AppDir";
File.WriteAllText(APPSETTINGS_JSON, new JObject { { LIBATION_FILES, dir } }.ToString(Formatting.Indented));
return dir;
}
if (!File.Exists(APPSETTINGS_JSON))
return createSettingsJson();
var appSettingsContents = File.ReadAllText(APPSETTINGS_JSON);
JObject jObj;
try
{
jObj = JObject.Parse(appSettingsContents);
}
catch
{
return createSettingsJson();
}
if (!jObj.ContainsKey(LIBATION_FILES))
return createSettingsJson();
var value = jObj[LIBATION_FILES].Value<string>();
return value;
}
private string SettingsJsonPath => Path.Combine(LibationFiles, "Settings.json");
public static string GetDescription(string propertyName)
{
var attribute = typeof(Configuration)
.GetProperty(propertyName)
?.GetCustomAttributes(typeof(DescriptionAttribute), true)
.SingleOrDefault()
as DescriptionAttribute;
var attribute = typeof(Configuration)
.GetProperty(propertyName)
?.GetCustomAttributes(typeof(DescriptionAttribute), true)
.SingleOrDefault()
as DescriptionAttribute;
return attribute?.Description;
}
private void ensureDictionaryEntries()
{
var stringProperties = getDictionaryProperties().Select(p => p.Name).ToList();
var missingKeys = stringProperties.Except(persistentDictionary.Keys).ToArray();
persistentDictionary.AddKeys(missingKeys);
return attribute?.Description;
}
private IEnumerable<System.Reflection.PropertyInfo> dicPropertiesCache;
private IEnumerable<System.Reflection.PropertyInfo> getDictionaryProperties()
public bool TrySetLibationFiles(string directory)
{
if (dicPropertiesCache == null)
dicPropertiesCache = PersistentDictionary.GetPropertiesToPersist(this.GetType());
return dicPropertiesCache;
if (!Directory.Exists(directory) && !wellKnownPaths.ContainsKey(directory))
return false;
// if moving from default, delete old settings file and dir (if empty)
if (LibationFiles.EqualsInsensitive(AppDir))
{
File.Delete(SettingsJsonPath);
System.Threading.Thread.Sleep(100);
if (!Directory.EnumerateDirectories(AppDir).Any() && !Directory.EnumerateFiles(AppDir).Any())
Directory.Delete(AppDir);
}
cache.Remove(LIBATION_FILES);
var contents = File.ReadAllText(APPSETTINGS_JSON);
var jObj = JObject.Parse(contents);
jObj[LIBATION_FILES] = directory;
var output = JsonConvert.SerializeObject(jObj, Formatting.Indented);
File.WriteAllText(APPSETTINGS_JSON, output);
return true;
}
}
}