From 7319133ae8b9f0f8f7e88cd0712f6bb8c7123ef5 Mon Sep 17 00:00:00 2001 From: Jeremy Wu Date: Mon, 21 Jun 2021 12:34:07 +1000 Subject: [PATCH 1/4] add backwards compatibility with Everything plugin --- Flow.Launcher.Core/Plugin/PluginManager.cs | 7 +- .../Storage/ISavable.cs | 11 +++ .../Storage/JsonStorage.cs | 90 +++++++++++++++++++ .../Storage/PluginJsonStorage.cs | 22 ++++- .../{ISavable.cs => ISettingsSavable.cs} | 2 +- Flow.Launcher/PublicAPIInstance.cs | 2 +- Flow.Launcher/ViewModel/MainViewModel.cs | 2 +- Plugins/Flow.Launcher.Plugin.Program/Main.cs | 2 +- 8 files changed, 130 insertions(+), 8 deletions(-) create mode 100644 Flow.Launcher.Infrastructure/Storage/ISavable.cs rename Flow.Launcher.Plugin/Interfaces/{ISavable.cs => ISettingsSavable.cs} (91%) diff --git a/Flow.Launcher.Core/Plugin/PluginManager.cs b/Flow.Launcher.Core/Plugin/PluginManager.cs index 8d2c6df2426..06f8cca19d3 100644 --- a/Flow.Launcher.Core/Plugin/PluginManager.cs +++ b/Flow.Launcher.Core/Plugin/PluginManager.cs @@ -48,9 +48,14 @@ public static void Save() { foreach (var plugin in AllPlugins) { - var savable = plugin.Plugin as ISavable; + var savable = plugin.Plugin as ISettingsSavable; savable?.Save(); } + + // Everything plugin + var savableEverything = AllPlugins.FirstOrDefault(x => x.Metadata.ID == "D2D2C23B084D411DB66FE0C79D6C2A6E")?.Plugin as ISavable; + savableEverything?.Save(); + API.SavePluginSettings(); } diff --git a/Flow.Launcher.Infrastructure/Storage/ISavable.cs b/Flow.Launcher.Infrastructure/Storage/ISavable.cs new file mode 100644 index 00000000000..155f1af61fa --- /dev/null +++ b/Flow.Launcher.Infrastructure/Storage/ISavable.cs @@ -0,0 +1,11 @@ +namespace Flow.Launcher.Infrastructure.Storage +{ + /// + /// Save plugin settings/cache, + /// todo should be merged into a abstract class intead of seperate interface + /// + public interface ISavable + { + void Save(); + } +} \ No newline at end of file diff --git a/Flow.Launcher.Infrastructure/Storage/JsonStorage.cs b/Flow.Launcher.Infrastructure/Storage/JsonStorage.cs index 43d19bea865..6863b2b5734 100644 --- a/Flow.Launcher.Infrastructure/Storage/JsonStorage.cs +++ b/Flow.Launcher.Infrastructure/Storage/JsonStorage.cs @@ -87,4 +87,94 @@ public void Save() File.WriteAllText(FilePath, serialized); } } + + public class JsonStrorage where T : new() + { + private readonly JsonSerializerOptions _serializerSettings; + private T _data; + // need a new directory name + public const string DirectoryName = "Settings"; + public const string FileSuffix = ".json"; + public string FilePath { get; set; } + public string DirectoryPath { get; set; } + + + internal JsonStrorage() + { + // use property initialization instead of DefaultValueAttribute + // easier and flexible for default value of object + _serializerSettings = new JsonSerializerOptions + { + IgnoreNullValues = false + }; + } + + public T Load() + { + if (File.Exists(FilePath)) + { + var searlized = File.ReadAllText(FilePath); + if (!string.IsNullOrWhiteSpace(searlized)) + { + Deserialize(searlized); + } + else + { + LoadDefault(); + } + } + else + { + LoadDefault(); + } + return _data.NonNull(); + } + + private void Deserialize(string searlized) + { + try + { + _data = JsonSerializer.Deserialize(searlized, _serializerSettings); + } + catch (JsonException e) + { + LoadDefault(); + Log.Exception($"|JsonStrorage.Deserialize|Deserialize error for json <{FilePath}>", e); + } + + if (_data == null) + { + LoadDefault(); + } + } + + private void LoadDefault() + { + if (File.Exists(FilePath)) + { + BackupOriginFile(); + } + + _data = new T(); + Save(); + } + + private void BackupOriginFile() + { + var timestamp = DateTime.Now.ToString("yyyy-MM-dd-HH-mm-ss-fffffff", CultureInfo.CurrentUICulture); + var directory = Path.GetDirectoryName(FilePath).NonNull(); + var originName = Path.GetFileNameWithoutExtension(FilePath); + var backupName = $"{originName}-{timestamp}{FileSuffix}"; + var backupPath = Path.Combine(directory, backupName); + File.Copy(FilePath, backupPath, true); + // todo give user notification for the backup process + } + + public void Save() + { + string serialized = JsonSerializer.Serialize(_data, new JsonSerializerOptions() { WriteIndented = true }); + + File.WriteAllText(FilePath, serialized); + } + } } diff --git a/Flow.Launcher.Infrastructure/Storage/PluginJsonStorage.cs b/Flow.Launcher.Infrastructure/Storage/PluginJsonStorage.cs index c26aef95dfc..585770e0fab 100644 --- a/Flow.Launcher.Infrastructure/Storage/PluginJsonStorage.cs +++ b/Flow.Launcher.Infrastructure/Storage/PluginJsonStorage.cs @@ -3,9 +3,9 @@ namespace Flow.Launcher.Infrastructure.Storage { - public class PluginJsonStorage :JsonStorage where T : new() + public class PluginJsonSettingStorage :JsonStorage where T : new() { - public PluginJsonStorage() + public PluginJsonSettingStorage() { // C# related, add python related below var dataType = typeof(T); @@ -16,9 +16,25 @@ public PluginJsonStorage() FilePath = Path.Combine(DirectoryPath, $"{dataType.Name}{FileSuffix}"); } - public PluginJsonStorage(T data) : this() + public PluginJsonSettingStorage(T data) : this() { _data = data; } } + + public class PluginJsonStorage : JsonStrorage where T : new() + { + public PluginJsonStorage() + { + // C# releated, add python releated below + var dataType = typeof(T); + var assemblyName = typeof(T).Assembly.GetName().Name; + DirectoryPath = Path.Combine(DataLocation.DataDirectory(), DirectoryName, Constant.Plugins, assemblyName); + Helper.ValidateDirectory(DirectoryPath); + + FilePath = Path.Combine(DirectoryPath, $"{dataType.Name}{FileSuffix}"); + } + } + } + diff --git a/Flow.Launcher.Plugin/Interfaces/ISavable.cs b/Flow.Launcher.Plugin/Interfaces/ISettingsSavable.cs similarity index 91% rename from Flow.Launcher.Plugin/Interfaces/ISavable.cs rename to Flow.Launcher.Plugin/Interfaces/ISettingsSavable.cs index 6f408dc2ee9..120a18adc7a 100644 --- a/Flow.Launcher.Plugin/Interfaces/ISavable.cs +++ b/Flow.Launcher.Plugin/Interfaces/ISettingsSavable.cs @@ -5,7 +5,7 @@ /// Otherwise if LoadSettingJsonStorage or SaveSettingJsonStorage has been callded, /// plugin settings will be automatically saved (see Flow.Launcher/PublicAPIInstance.SavePluginSettings) by Flow /// - public interface ISavable + public interface ISettingsSavable { void Save(); } diff --git a/Flow.Launcher/PublicAPIInstance.cs b/Flow.Launcher/PublicAPIInstance.cs index f3403696e05..6502e735a59 100644 --- a/Flow.Launcher/PublicAPIInstance.cs +++ b/Flow.Launcher/PublicAPIInstance.cs @@ -177,7 +177,7 @@ public void SavePluginSettings() public void SaveJsonStorage(T settings) where T : new() { var type = typeof(T); - _pluginJsonStorages[type] = new PluginJsonStorage(settings); + _pluginJsonStorages[type] = new PluginJsonSettingStorage(settings); ((PluginJsonStorage) _pluginJsonStorages[type]).Save(); } diff --git a/Flow.Launcher/ViewModel/MainViewModel.cs b/Flow.Launcher/ViewModel/MainViewModel.cs index 4ee15b46d4d..469be42c1a0 100644 --- a/Flow.Launcher/ViewModel/MainViewModel.cs +++ b/Flow.Launcher/ViewModel/MainViewModel.cs @@ -23,7 +23,7 @@ namespace Flow.Launcher.ViewModel { - public class MainViewModel : BaseModel, ISavable + public class MainViewModel : BaseModel, ISettingsSavable { #region Private Fields diff --git a/Plugins/Flow.Launcher.Plugin.Program/Main.cs b/Plugins/Flow.Launcher.Plugin.Program/Main.cs index 5175970fd41..59bd4809dbf 100644 --- a/Plugins/Flow.Launcher.Plugin.Program/Main.cs +++ b/Plugins/Flow.Launcher.Plugin.Program/Main.cs @@ -13,7 +13,7 @@ namespace Flow.Launcher.Plugin.Program { - public class Main : ISettingProvider, IAsyncPlugin, IPluginI18n, IContextMenu, ISavable, IAsyncReloadable + public class Main : ISettingProvider, IAsyncPlugin, IPluginI18n, IContextMenu, ISettingsSavable, IAsyncReloadable { internal static Win32[] _win32s { get; set; } internal static UWP.Application[] _uwps { get; set; } From 6ec151a8ab4f4ab93fdddf576c802da85995af20 Mon Sep 17 00:00:00 2001 From: Jeremy Wu Date: Mon, 21 Jun 2021 21:04:19 +1000 Subject: [PATCH 2/4] use inheritance for ISavable and JsonStrorage --- Flow.Launcher.Core/Plugin/PluginManager.cs | 4 - .../Storage/ISavable.cs | 9 +- .../Storage/JsonStorage.cs | 90 +------------------ 3 files changed, 5 insertions(+), 98 deletions(-) diff --git a/Flow.Launcher.Core/Plugin/PluginManager.cs b/Flow.Launcher.Core/Plugin/PluginManager.cs index 06f8cca19d3..b3a4ad0e193 100644 --- a/Flow.Launcher.Core/Plugin/PluginManager.cs +++ b/Flow.Launcher.Core/Plugin/PluginManager.cs @@ -52,10 +52,6 @@ public static void Save() savable?.Save(); } - // Everything plugin - var savableEverything = AllPlugins.FirstOrDefault(x => x.Metadata.ID == "D2D2C23B084D411DB66FE0C79D6C2A6E")?.Plugin as ISavable; - savableEverything?.Save(); - API.SavePluginSettings(); } diff --git a/Flow.Launcher.Infrastructure/Storage/ISavable.cs b/Flow.Launcher.Infrastructure/Storage/ISavable.cs index 155f1af61fa..2fc577e8680 100644 --- a/Flow.Launcher.Infrastructure/Storage/ISavable.cs +++ b/Flow.Launcher.Infrastructure/Storage/ISavable.cs @@ -1,11 +1,10 @@ -namespace Flow.Launcher.Infrastructure.Storage +using Flow.Launcher.Plugin; + +namespace Flow.Launcher.Infrastructure.Storage { /// /// Save plugin settings/cache, /// todo should be merged into a abstract class intead of seperate interface /// - public interface ISavable - { - void Save(); - } + public interface ISavable : ISettingsSavable { } } \ No newline at end of file diff --git a/Flow.Launcher.Infrastructure/Storage/JsonStorage.cs b/Flow.Launcher.Infrastructure/Storage/JsonStorage.cs index 6863b2b5734..9a863f9fa9e 100644 --- a/Flow.Launcher.Infrastructure/Storage/JsonStorage.cs +++ b/Flow.Launcher.Infrastructure/Storage/JsonStorage.cs @@ -88,93 +88,5 @@ public void Save() } } - public class JsonStrorage where T : new() - { - private readonly JsonSerializerOptions _serializerSettings; - private T _data; - // need a new directory name - public const string DirectoryName = "Settings"; - public const string FileSuffix = ".json"; - public string FilePath { get; set; } - public string DirectoryPath { get; set; } - - - internal JsonStrorage() - { - // use property initialization instead of DefaultValueAttribute - // easier and flexible for default value of object - _serializerSettings = new JsonSerializerOptions - { - IgnoreNullValues = false - }; - } - - public T Load() - { - if (File.Exists(FilePath)) - { - var searlized = File.ReadAllText(FilePath); - if (!string.IsNullOrWhiteSpace(searlized)) - { - Deserialize(searlized); - } - else - { - LoadDefault(); - } - } - else - { - LoadDefault(); - } - return _data.NonNull(); - } - - private void Deserialize(string searlized) - { - try - { - _data = JsonSerializer.Deserialize(searlized, _serializerSettings); - } - catch (JsonException e) - { - LoadDefault(); - Log.Exception($"|JsonStrorage.Deserialize|Deserialize error for json <{FilePath}>", e); - } - - if (_data == null) - { - LoadDefault(); - } - } - - private void LoadDefault() - { - if (File.Exists(FilePath)) - { - BackupOriginFile(); - } - - _data = new T(); - Save(); - } - - private void BackupOriginFile() - { - var timestamp = DateTime.Now.ToString("yyyy-MM-dd-HH-mm-ss-fffffff", CultureInfo.CurrentUICulture); - var directory = Path.GetDirectoryName(FilePath).NonNull(); - var originName = Path.GetFileNameWithoutExtension(FilePath); - var backupName = $"{originName}-{timestamp}{FileSuffix}"; - var backupPath = Path.Combine(directory, backupName); - File.Copy(FilePath, backupPath, true); - // todo give user notification for the backup process - } - - public void Save() - { - string serialized = JsonSerializer.Serialize(_data, new JsonSerializerOptions() { WriteIndented = true }); - - File.WriteAllText(FilePath, serialized); - } - } + public class JsonStrorage : JsonStorage where T : new() { } } From 0387bfbb64cf206616f28d3f3dfb87154d9ff5b9 Mon Sep 17 00:00:00 2001 From: Jeremy Wu Date: Mon, 21 Jun 2021 21:31:07 +1000 Subject: [PATCH 3/4] update class name --- .../Storage/PluginJsonStorage.cs | 21 +++---------------- Flow.Launcher/PublicAPIInstance.cs | 2 +- 2 files changed, 4 insertions(+), 19 deletions(-) diff --git a/Flow.Launcher.Infrastructure/Storage/PluginJsonStorage.cs b/Flow.Launcher.Infrastructure/Storage/PluginJsonStorage.cs index 585770e0fab..923a1a6b56f 100644 --- a/Flow.Launcher.Infrastructure/Storage/PluginJsonStorage.cs +++ b/Flow.Launcher.Infrastructure/Storage/PluginJsonStorage.cs @@ -3,9 +3,9 @@ namespace Flow.Launcher.Infrastructure.Storage { - public class PluginJsonSettingStorage :JsonStorage where T : new() + public class PluginJsonStorage :JsonStorage where T : new() { - public PluginJsonSettingStorage() + public PluginJsonStorage() { // C# related, add python related below var dataType = typeof(T); @@ -16,25 +16,10 @@ public PluginJsonSettingStorage() FilePath = Path.Combine(DirectoryPath, $"{dataType.Name}{FileSuffix}"); } - public PluginJsonSettingStorage(T data) : this() + public PluginJsonStorage(T data) : this() { _data = data; } } - - public class PluginJsonStorage : JsonStrorage where T : new() - { - public PluginJsonStorage() - { - // C# releated, add python releated below - var dataType = typeof(T); - var assemblyName = typeof(T).Assembly.GetName().Name; - DirectoryPath = Path.Combine(DataLocation.DataDirectory(), DirectoryName, Constant.Plugins, assemblyName); - Helper.ValidateDirectory(DirectoryPath); - - FilePath = Path.Combine(DirectoryPath, $"{dataType.Name}{FileSuffix}"); - } - } - } diff --git a/Flow.Launcher/PublicAPIInstance.cs b/Flow.Launcher/PublicAPIInstance.cs index 6502e735a59..f3403696e05 100644 --- a/Flow.Launcher/PublicAPIInstance.cs +++ b/Flow.Launcher/PublicAPIInstance.cs @@ -177,7 +177,7 @@ public void SavePluginSettings() public void SaveJsonStorage(T settings) where T : new() { var type = typeof(T); - _pluginJsonStorages[type] = new PluginJsonSettingStorage(settings); + _pluginJsonStorages[type] = new PluginJsonStorage(settings); ((PluginJsonStorage) _pluginJsonStorages[type]).Save(); } From 644be7977cfcd89e8fc4fa2dfa1cc5bcbf4afacd Mon Sep 17 00:00:00 2001 From: Jeremy Wu Date: Mon, 21 Jun 2021 21:56:20 +1000 Subject: [PATCH 4/4] use ISavable and add obsolete message --- Flow.Launcher.Core/Plugin/PluginManager.cs | 4 ++-- Flow.Launcher.Infrastructure/Storage/ISavable.cs | 10 ++++------ Flow.Launcher.Infrastructure/Storage/JsonStorage.cs | 2 ++ .../Interfaces/{ISettingsSavable.cs => ISavable.cs} | 2 +- Flow.Launcher/ViewModel/MainViewModel.cs | 3 ++- Plugins/Flow.Launcher.Plugin.Program/Main.cs | 2 +- 6 files changed, 12 insertions(+), 11 deletions(-) rename Flow.Launcher.Plugin/Interfaces/{ISettingsSavable.cs => ISavable.cs} (91%) diff --git a/Flow.Launcher.Core/Plugin/PluginManager.cs b/Flow.Launcher.Core/Plugin/PluginManager.cs index b3a4ad0e193..59f34de742e 100644 --- a/Flow.Launcher.Core/Plugin/PluginManager.cs +++ b/Flow.Launcher.Core/Plugin/PluginManager.cs @@ -7,9 +7,9 @@ using System.Threading.Tasks; using Flow.Launcher.Infrastructure; using Flow.Launcher.Infrastructure.Logger; -using Flow.Launcher.Infrastructure.Storage; using Flow.Launcher.Infrastructure.UserSettings; using Flow.Launcher.Plugin; +using ISavable = Flow.Launcher.Plugin.ISavable; namespace Flow.Launcher.Core.Plugin { @@ -48,7 +48,7 @@ public static void Save() { foreach (var plugin in AllPlugins) { - var savable = plugin.Plugin as ISettingsSavable; + var savable = plugin.Plugin as ISavable; savable?.Save(); } diff --git a/Flow.Launcher.Infrastructure/Storage/ISavable.cs b/Flow.Launcher.Infrastructure/Storage/ISavable.cs index 2fc577e8680..ba2b58c6a18 100644 --- a/Flow.Launcher.Infrastructure/Storage/ISavable.cs +++ b/Flow.Launcher.Infrastructure/Storage/ISavable.cs @@ -1,10 +1,8 @@ -using Flow.Launcher.Plugin; +using System; namespace Flow.Launcher.Infrastructure.Storage { - /// - /// Save plugin settings/cache, - /// todo should be merged into a abstract class intead of seperate interface - /// - public interface ISavable : ISettingsSavable { } + [Obsolete("Deprecated as of Flow Launcher v1.8.0, on 2021.06.21. " + + "This is used only for Everything plugin v1.4.9 or below backwards compatibility")] + public interface ISavable : Plugin.ISavable { } } \ No newline at end of file diff --git a/Flow.Launcher.Infrastructure/Storage/JsonStorage.cs b/Flow.Launcher.Infrastructure/Storage/JsonStorage.cs index 9a863f9fa9e..0083ccb87b0 100644 --- a/Flow.Launcher.Infrastructure/Storage/JsonStorage.cs +++ b/Flow.Launcher.Infrastructure/Storage/JsonStorage.cs @@ -88,5 +88,7 @@ public void Save() } } + [Obsolete("Deprecated as of Flow Launcher v1.8.0, on 2021.06.21. " + + "This is used only for Everything plugin v1.4.9 or below backwards compatibility")] public class JsonStrorage : JsonStorage where T : new() { } } diff --git a/Flow.Launcher.Plugin/Interfaces/ISettingsSavable.cs b/Flow.Launcher.Plugin/Interfaces/ISavable.cs similarity index 91% rename from Flow.Launcher.Plugin/Interfaces/ISettingsSavable.cs rename to Flow.Launcher.Plugin/Interfaces/ISavable.cs index 120a18adc7a..6f408dc2ee9 100644 --- a/Flow.Launcher.Plugin/Interfaces/ISettingsSavable.cs +++ b/Flow.Launcher.Plugin/Interfaces/ISavable.cs @@ -5,7 +5,7 @@ /// Otherwise if LoadSettingJsonStorage or SaveSettingJsonStorage has been callded, /// plugin settings will be automatically saved (see Flow.Launcher/PublicAPIInstance.SavePluginSettings) by Flow /// - public interface ISettingsSavable + public interface ISavable { void Save(); } diff --git a/Flow.Launcher/ViewModel/MainViewModel.cs b/Flow.Launcher/ViewModel/MainViewModel.cs index 469be42c1a0..4f6d3be84d3 100644 --- a/Flow.Launcher/ViewModel/MainViewModel.cs +++ b/Flow.Launcher/ViewModel/MainViewModel.cs @@ -20,10 +20,11 @@ using Flow.Launcher.Storage; using Flow.Launcher.Infrastructure.Logger; using System.Threading.Channels; +using ISavable = Flow.Launcher.Plugin.ISavable; namespace Flow.Launcher.ViewModel { - public class MainViewModel : BaseModel, ISettingsSavable + public class MainViewModel : BaseModel, ISavable { #region Private Fields diff --git a/Plugins/Flow.Launcher.Plugin.Program/Main.cs b/Plugins/Flow.Launcher.Plugin.Program/Main.cs index 59bd4809dbf..5175970fd41 100644 --- a/Plugins/Flow.Launcher.Plugin.Program/Main.cs +++ b/Plugins/Flow.Launcher.Plugin.Program/Main.cs @@ -13,7 +13,7 @@ namespace Flow.Launcher.Plugin.Program { - public class Main : ISettingProvider, IAsyncPlugin, IPluginI18n, IContextMenu, ISettingsSavable, IAsyncReloadable + public class Main : ISettingProvider, IAsyncPlugin, IPluginI18n, IContextMenu, ISavable, IAsyncReloadable { internal static Win32[] _win32s { get; set; } internal static UWP.Application[] _uwps { get; set; }