Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Flow.Launcher.Core/Plugin/PluginManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ public static void Save()
var savable = plugin.Plugin as ISavable;
savable?.Save();
}
API.SavePluginSettings();
}

public static async Task ReloadData()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

namespace Flow.Launcher.Infrastructure.Storage
{
public class FlowLauncherJsonStorage<T> : JsonStrorage<T> where T : new()
public class FlowLauncherJsonStorage<T> : JsonStorage<T> where T : new()
{
public FlowLauncherJsonStorage()
{
Expand Down
14 changes: 7 additions & 7 deletions Flow.Launcher.Infrastructure/Storage/JsonStorage.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ namespace Flow.Launcher.Infrastructure.Storage
/// <summary>
/// Serialize object using json format.
/// </summary>
public class JsonStrorage<T> where T : new()
public class JsonStorage<T> where T : new()
{
protected T _data;
// need a new directory name
Expand All @@ -23,10 +23,10 @@ public T Load()
{
if (File.Exists(FilePath))
{
var searlized = File.ReadAllText(FilePath);
if (!string.IsNullOrWhiteSpace(searlized))
var serialized = File.ReadAllText(FilePath);
if (!string.IsNullOrWhiteSpace(serialized))
{
Deserialize(searlized);
Deserialize(serialized);
}
else
{
Expand All @@ -40,16 +40,16 @@ public T Load()
return _data.NonNull();
}

private void Deserialize(string searlized)
private void Deserialize(string serialized)
{
try
{
_data = JsonSerializer.Deserialize<T>(searlized);
_data = JsonSerializer.Deserialize<T>(serialized);
}
catch (JsonException e)
{
LoadDefault();
Log.Exception($"|JsonStrorage.Deserialize|Deserialize error for json <{FilePath}>", e);
Log.Exception($"|JsonStorage.Deserialize|Deserialize error for json <{FilePath}>", e);
}

if (_data == null)
Expand Down
6 changes: 3 additions & 3 deletions Flow.Launcher.Infrastructure/Storage/PluginJsonStorage.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,13 @@

namespace Flow.Launcher.Infrastructure.Storage
{
public class PluginJsonStorage<T> :JsonStrorage<T> where T : new()
public class PluginJsonStorage<T> :JsonStorage<T> where T : new()
{
public PluginJsonStorage()
{
// C# releated, add python releated below
// C# related, add python related below
var dataType = typeof(T);
var assemblyName = typeof(T).Assembly.GetName().Name;
var assemblyName = dataType.Assembly.GetName().Name;
DirectoryPath = Path.Combine(DataLocation.DataDirectory(), DirectoryName, Constant.Plugins, assemblyName);
Helper.ValidateDirectory(DirectoryPath);

Expand Down
32 changes: 12 additions & 20 deletions Flow.Launcher.Plugin/IPublicAPI.cs
Original file line number Diff line number Diff line change
Expand Up @@ -30,10 +30,15 @@ public interface IPublicAPI
void RestartApp();

/// <summary>
/// Save all Flow Launcher settings
/// Save everything, all of Flow Launcher and plugins' data and settings
/// </summary>
void SaveAppAllSettings();

/// <summary>
/// Save all Flow's plugins settings
/// </summary>
void SavePluginSettings();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what's the difference between this method and SaveSettingJsonStorage()?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

SaveSettingJsonStorage is for a specific Type (or T as generic), but this is for all plugin.


/// <summary>
/// Reloads any Plugins that have the
/// IReloadable implemented. It refeshes
Expand Down Expand Up @@ -165,33 +170,20 @@ public interface IPublicAPI
void LogException(string className, string message, Exception e, [CallerMemberName] string methodName = "");

/// <summary>
/// Load JsonStorage for current plugin. This is the method used to load settings from json in Flow
/// Load JsonStorage for current plugin's setting. This is the method used to load settings from json in Flow.
/// When the file is not exist, it will create a new instance for the specific type.
/// </summary>
/// <typeparam name="T">Type for deserialization</typeparam>
/// <returns></returns>
T LoadJsonStorage<T>() where T : new();
T LoadSettingJsonStorage<T>() where T : new();

/// <summary>
/// Save JsonStorage for current plugin. This is the method used to save settings to json in Flow.Launcher
/// Save JsonStorage for current plugin's setting. This is the method used to save settings to json in Flow.Launcher
/// This method will save the original instance loaded with LoadJsonStorage.
/// This API call is for manually Save. Flow will automatically save all setting type that has called LoadSettingJsonStorage or SaveSettingJsonStorage previously.
/// </summary>
/// <typeparam name="T">Type for Serialization</typeparam>
/// <returns></returns>
void SaveJsonStorage<T>() where T : new();

/// <summary>
/// Save JsonStorage for current plugin. This is the method used to save settings to json in Flow.Launcher
/// This method will override the original class instance loaded from LoadJsonStorage
/// </summary>
/// <typeparam name="T">Type for Serialization</typeparam>
/// <returns></returns>
void SaveJsonStorage<T>(T settings) where T : new();

/// <summary>
/// Backup the JsonStorage you loaded from LoadJsonStorage
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="settings"></param>
void BackupJsonStorage<T>() where T : new();
void SaveSettingJsonStorage<T>() where T : new();
}
}
5 changes: 3 additions & 2 deletions Flow.Launcher.Plugin/Interfaces/ISavable.cs
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
namespace Flow.Launcher.Plugin
{
/// <summary>
/// Save plugin settings/cache,
/// todo should be merged into a abstract class intead of seperate interface
/// Save addtional plugin data. Inherit this interface if additional data e.g. cache needs to be saved,
/// Otherwise if LoadSettingJsonStorage or SaveSettingJsonStorage has been callded,
/// plugin settings will be automatically saved (see Flow.Launcher/PublicAPIInstance.SavePluginSettings) by Flow
/// </summary>
public interface ISavable
{
Expand Down
78 changes: 45 additions & 33 deletions Flow.Launcher/PublicAPIInstance.cs
Original file line number Diff line number Diff line change
Expand Up @@ -76,23 +76,25 @@ public void RestartApp()

public void SaveAppAllSettings()
{
SavePluginSettings();
_mainVM.Save();
_settingsVM.Save();
PluginManager.Save();
ImageLoader.Save();
}

public Task ReloadAllPluginData() => PluginManager.ReloadData();

public void ShowMsgError(string title, string subTitle = "") => ShowMsg(title, subTitle, Constant.ErrorIcon, true);
public void ShowMsgError(string title, string subTitle = "") =>
ShowMsg(title, subTitle, Constant.ErrorIcon, true);

public void ShowMsg(string title, string subTitle = "", string iconPath = "") => ShowMsg(title, subTitle, iconPath, true);
public void ShowMsg(string title, string subTitle = "", string iconPath = "") =>
ShowMsg(title, subTitle, iconPath, true);

public void ShowMsg(string title, string subTitle, string iconPath, bool useMainWindowAsOwner = true)
{
Application.Current.Dispatcher.Invoke(() =>
{
var msg = useMainWindowAsOwner ? new Msg { Owner = Application.Current.MainWindow } : new Msg();
var msg = useMainWindowAsOwner ? new Msg {Owner = Application.Current.MainWindow} : new Msg();
msg.Show(title, subTitle, iconPath);
});
}
Expand All @@ -113,61 +115,70 @@ public void OpenSettingDialog()

public List<PluginPair> GetAllPlugins() => PluginManager.AllPlugins.ToList();

public MatchResult FuzzySearch(string query, string stringToCompare) => StringMatcher.FuzzySearch(query, stringToCompare);
public MatchResult FuzzySearch(string query, string stringToCompare) =>
StringMatcher.FuzzySearch(query, stringToCompare);

public Task<string> HttpGetStringAsync(string url, CancellationToken token = default) => Http.GetAsync(url);

public Task<Stream> HttpGetStreamAsync(string url, CancellationToken token = default) => Http.GetStreamAsync(url);
public Task<Stream> HttpGetStreamAsync(string url, CancellationToken token = default) =>
Http.GetStreamAsync(url);

public Task HttpDownloadAsync([NotNull] string url, [NotNull] string filePath, CancellationToken token = default) => Http.DownloadAsync(url, filePath, token);
public Task HttpDownloadAsync([NotNull] string url, [NotNull] string filePath,
CancellationToken token = default) => Http.DownloadAsync(url, filePath, token);

public void AddActionKeyword(string pluginId, string newActionKeyword) => PluginManager.AddActionKeyword(pluginId, newActionKeyword);
public void AddActionKeyword(string pluginId, string newActionKeyword) =>
PluginManager.AddActionKeyword(pluginId, newActionKeyword);

public void RemoveActionKeyword(string pluginId, string oldActionKeyword) => PluginManager.RemoveActionKeyword(pluginId, oldActionKeyword);
public void RemoveActionKeyword(string pluginId, string oldActionKeyword) =>
PluginManager.RemoveActionKeyword(pluginId, oldActionKeyword);

public void LogDebug(string className, string message, [CallerMemberName] string methodName = "") => Log.Debug(className, message, methodName);
public void LogDebug(string className, string message, [CallerMemberName] string methodName = "") =>
Log.Debug(className, message, methodName);

public void LogInfo(string className, string message, [CallerMemberName] string methodName = "") => Log.Info(className, message, methodName);
public void LogInfo(string className, string message, [CallerMemberName] string methodName = "") =>
Log.Info(className, message, methodName);

public void LogWarn(string className, string message, [CallerMemberName] string methodName = "") => Log.Warn(className, message, methodName);
public void LogWarn(string className, string message, [CallerMemberName] string methodName = "") =>
Log.Warn(className, message, methodName);

public void LogException(string className, string message, Exception e, [CallerMemberName] string methodName = "") => Log.Exception(className, message, e, methodName);
public void LogException(string className, string message, Exception e,
[CallerMemberName] string methodName = "") => Log.Exception(className, message, e, methodName);

private readonly Dictionary<Type, dynamic> PluginJsonStorages = new Dictionary<Type, dynamic>();
private readonly Dictionary<Type, object> _pluginJsonStorages = new();

public T LoadJsonStorage<T>() where T : new()
public void SavePluginSettings()
{
var type = typeof(T);
if (!PluginJsonStorages.ContainsKey(type))
PluginJsonStorages[type] = new PluginJsonStorage<T>();

return PluginJsonStorages[type].Load();
foreach (var value in _pluginJsonStorages.Values)
{
var method = value.GetType().GetMethod("Save");
method?.Invoke(value, null);
}
}

public void SaveJsonStorage<T>() where T : new()
public T LoadSettingJsonStorage<T>() where T : new()
{
var type = typeof(T);
if (!PluginJsonStorages.ContainsKey(type))
PluginJsonStorages[type] = new PluginJsonStorage<T>();
if (!_pluginJsonStorages.ContainsKey(type))
_pluginJsonStorages[type] = new PluginJsonStorage<T>();

PluginJsonStorages[type].Save();
return ((PluginJsonStorage<T>) _pluginJsonStorages[type]).Load();
}

public void SaveJsonStorage<T>(T settings) where T : new()
public void SaveSettingJsonStorage<T>() where T : new()
{
var type = typeof(T);
PluginJsonStorages[type] = new PluginJsonStorage<T>(settings);
if (!_pluginJsonStorages.ContainsKey(type))
_pluginJsonStorages[type] = new PluginJsonStorage<T>();

PluginJsonStorages[type].Save();
((PluginJsonStorage<T>) _pluginJsonStorages[type]).Save();
}

public void BackupJsonStorage<T>() where T : new()
public void SaveJsonStorage<T>(T settings) where T : new()
{
var type = typeof(T);
if (!PluginJsonStorages.ContainsKey(type))
throw new InvalidOperationException("You haven't registered the JsonStorage for specific Type");
_pluginJsonStorages[type] = new PluginJsonStorage<T>(settings);

PluginJsonStorages[type].BackupOriginFile();
((PluginJsonStorage<T>) _pluginJsonStorages[type]).Save();
}

public event FlowLauncherGlobalKeyboardEventHandler GlobalKeyboardEvent;
Expand All @@ -180,11 +191,12 @@ private bool KListener_hookedKeyboardCallback(KeyEvent keyevent, int vkcode, Spe
{
if (GlobalKeyboardEvent != null)
{
return GlobalKeyboardEvent((int)keyevent, vkcode, state);
return GlobalKeyboardEvent((int) keyevent, vkcode, state);
}

return true;
}

#endregion
}
}
}
11 changes: 2 additions & 9 deletions Plugins/Flow.Launcher.Plugin.BrowserBookmark/Main.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,21 +12,19 @@

namespace Flow.Launcher.Plugin.BrowserBookmark
{
public class Main : ISettingProvider, IPlugin, IReloadable, IPluginI18n, ISavable, IContextMenu
public class Main : ISettingProvider, IPlugin, IReloadable, IPluginI18n, IContextMenu
{
private PluginInitContext context;

private List<Bookmark> cachedBookmarks = new List<Bookmark>();

private Settings _settings { get; set;}
private PluginJsonStorage<Settings> _storage { get; set;}

public void Init(PluginInitContext context)
{
this.context = context;

_storage = new PluginJsonStorage<Settings>();
_settings = _storage.Load();
_settings = context.API.LoadSettingJsonStorage<Settings>();

cachedBookmarks = Bookmarks.LoadAllBookmarks();
}
Expand Down Expand Up @@ -113,11 +111,6 @@ public Control CreateSettingPanel()
return new SettingsControl(_settings);
}

public void Save()
{
_storage.Save();
}

Comment on lines -116 to -120
Copy link
Member

@jjw24 jjw24 May 12, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why is this removed? settings still needs to be saved right?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I add a auto save for all registered jsonstorage, so that we don't need to configure isavable for setting, unless they are going to save something else.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

private void SaveAllJsonStorage()
{
foreach (var value in _pluginJsonStorages.Values)
{
var method = value.GetType().GetMethod("Save");
method?.Invoke(value, null);
}
}

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  1. would this not be a doubling up then, with PluginManager.Save() call?

  2. also you need to move this SaveAllJsonStorage() call to here right so when Flow's settings window closed you want to save all plugin settings:

    public void Save()
    {
    foreach (var vm in PluginViewModels)
    {
    var id = vm.PluginPair.Metadata.ID;
    Settings.PluginSettings.Plugins[id].Disabled = vm.PluginPair.Metadata.Disabled;
    Settings.PluginSettings.Plugins[id].Priority = vm.Priority;
    }
    PluginManager.Save();
    _storage.Save();
    }

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  1. do we want to remove ISavable?
  2. if it's auto saved, might want to document it somewhere right? for those that develop plugins

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this method is called in SaveAllJsonStorage, so it is impossible to directly call that method here, or else will become infinity recurse.
The call for

PluginManager.Save(); 
_storage.Save(); 

do save all plugin setting.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yeah i see. hmm how do save plugin settings when user closes settings window? PluginManager.Save() only saves plugin settings where the interface ISavable is applied and _storage.Save() saves Flow's own settings.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

instead of passing the api to the view, which is not even used, we can and should pass it to the viewmodel, this then allows you to call save plugin settings seperately from the view

public SettingWindow(IPublicAPI api, SettingWindowViewModel viewModel)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PluginManager.Save() only saves plugin settings where the interface ISavable is applied and _storage.Save() saves Flow's own settings.

I have modified PluginManager.Save() to include saving plugins settings.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

public static void Save()
        {
            foreach (var plugin in AllPlugins)
            {
                var savable = plugin.Plugin as ISavable;
                savable?.Save();
            }
            API.SavePluginSettings();
        }

public List<Result> LoadContextMenus(Result selectedResult)
{
return new List<Result>() {
Expand Down
2 changes: 1 addition & 1 deletion Plugins/Flow.Launcher.Plugin.BrowserBookmark/plugin.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
"Name": "Browser Bookmarks",
"Description": "Search your browser bookmarks",
"Author": "qianlifeng, Ioannis G.",
"Version": "1.4.3",
"Version": "1.4.4",
"Language": "csharp",
"Website": "https://github.com/Flow-Launcher/Flow.Launcher",
"ExecuteFileName": "Flow.Launcher.Plugin.BrowserBookmark.dll",
Expand Down
17 changes: 3 additions & 14 deletions Plugins/Flow.Launcher.Plugin.Calculator/Main.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@

namespace Flow.Launcher.Plugin.Caculator
{
public class Main : IPlugin, IPluginI18n, ISavable, ISettingProvider
public class Main : IPlugin, IPluginI18n, ISettingProvider
{
private static readonly Regex RegValidExpressChar = new Regex(
@"^(" +
Expand All @@ -30,17 +30,11 @@ public class Main : IPlugin, IPluginI18n, ISavable, ISettingProvider
private static Settings _settings;
private static SettingsViewModel _viewModel;

static Main()
{

}

public void Init(PluginInitContext context)
{
Context = context;

_viewModel = new SettingsViewModel();
_settings = _viewModel.Settings;
_settings = context.API.LoadSettingJsonStorage<Settings>();
_viewModel = new SettingsViewModel(_settings);

MagesEngine = new Engine(new Configuration
{
Expand Down Expand Up @@ -187,10 +181,5 @@ public Control CreateSettingPanel()
{
return new CalculatorSettings(_viewModel);
}

public void Save()
{
_viewModel.Save();
}
}
}
Loading