Skip to content

Commit 67027eb

Browse files
committed
Allow JsonRPCPlugin.cs to have setting control
1 parent 8ae13a5 commit 67027eb

File tree

3 files changed

+128
-11
lines changed

3 files changed

+128
-11
lines changed

Flow.Launcher.Core/Plugin/JsonPRCModel.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ public class JsonRPCQueryResponseModel : JsonRPCResponseModel
4545

4646
public string DebugMessage { get; set; }
4747
}
48-
48+
4949
public class JsonRPCRequestModel
5050
{
5151
public string Method { get; set; }

Flow.Launcher.Core/Plugin/JsonRPCPlugin.cs

Lines changed: 125 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
1-
using Flow.Launcher.Core.Resource;
1+
using Accessibility;
2+
using Flow.Launcher.Core.Resource;
3+
using Flow.Launcher.Infrastructure;
24
using System;
35
using System.Collections.Generic;
46
using System.Diagnostics;
@@ -8,20 +10,30 @@
810
using System.Text.Json;
911
using System.Threading;
1012
using System.Threading.Tasks;
11-
using System.Windows.Forms;
1213
using Flow.Launcher.Infrastructure.Logger;
14+
using Flow.Launcher.Infrastructure.UserSettings;
1315
using Flow.Launcher.Plugin;
1416
using ICSharpCode.SharpZipLib.Zip;
1517
using JetBrains.Annotations;
1618
using Microsoft.IO;
19+
using System.Text.Json.Serialization;
20+
using System.Windows;
21+
using System.Windows.Controls;
22+
using System.Windows.Forms;
23+
using CheckBox = System.Windows.Controls.CheckBox;
24+
using Control = System.Windows.Controls.Control;
25+
using Label = System.Windows.Controls.Label;
26+
using Orientation = System.Windows.Controls.Orientation;
27+
using TextBox = System.Windows.Controls.TextBox;
28+
using UserControl = System.Windows.Controls.UserControl;
1729

1830
namespace Flow.Launcher.Core.Plugin
1931
{
2032
/// <summary>
2133
/// Represent the plugin that using JsonPRC
2234
/// every JsonRPC plugin should has its own plugin instance
2335
/// </summary>
24-
internal abstract class JsonRPCPlugin : IAsyncPlugin, IContextMenu
36+
internal abstract class JsonRPCPlugin : IAsyncPlugin, IContextMenu, ISettingProvider, ISavable
2537
{
2638
protected PluginInitContext context;
2739
public const string JsonRPC = "JsonRPC";
@@ -35,6 +47,8 @@ internal abstract class JsonRPCPlugin : IAsyncPlugin, IContextMenu
3547

3648
private static readonly RecyclableMemoryStreamManager BufferManager = new();
3749

50+
private string SettingPath => Path.Combine(DataLocation.PluginSettingsDirectory, context.CurrentPluginMetadata.Name, "Setting.json");
51+
3852
public List<Result> LoadContextMenus(Result selectedResult)
3953
{
4054
var request = new JsonRPCRequestModel
@@ -58,6 +72,7 @@ public List<Result> LoadContextMenus(Result selectedResult)
5872
new JsonObjectConverter()
5973
}
6074
};
75+
private Dictionary<string, object> Settings { get; set; }
6176

6277
private async Task<List<Result>> DeserializedResultAsync(Stream output)
6378
{
@@ -292,10 +307,115 @@ public async Task<List<Result>> QueryAsync(Query query, CancellationToken token)
292307
return await DeserializedResultAsync(output);
293308
}
294309

295-
public virtual Task InitAsync(PluginInitContext context)
310+
public async Task InitSettingAsync()
311+
{
312+
if (File.Exists(SettingPath))
313+
Settings = await JsonSerializer.DeserializeAsync<Dictionary<string, object>>(File.OpenRead(SettingPath), options);
314+
315+
var request = new JsonRPCRequestModel()
316+
{
317+
Method = "get_setting_template"
318+
};
319+
await using var result = await RequestAsync(request);
320+
if (result.Length == 0)
321+
return;
322+
var settingsTemplate = await JsonSerializer.DeserializeAsync<Dictionary<string, JsonElement>>(result, options) ??
323+
new();
324+
325+
Settings ??= new();
326+
327+
foreach (var (key, element) in settingsTemplate)
328+
{
329+
if (!Settings.ContainsKey(key))
330+
{
331+
Settings[key] = element.ValueKind switch
332+
{
333+
JsonValueKind.True or JsonValueKind.False => element.GetBoolean(),
334+
JsonValueKind.String or JsonValueKind.Number => element.GetString(),
335+
JsonValueKind.Null => throw new ArgumentNullException(),
336+
_ => throw new ArgumentOutOfRangeException()
337+
};
338+
}
339+
}
340+
}
341+
342+
public virtual async Task InitAsync(PluginInitContext context)
296343
{
297344
this.context = context;
298-
return Task.CompletedTask;
345+
await InitSettingAsync();
346+
}
347+
private static Thickness settingControlMargin = new(10);
348+
public Control CreateSettingPanel()
349+
{
350+
if (Settings == null)
351+
return new();
352+
var settingWindow = new UserControl();
353+
var mainPanel = new StackPanel
354+
{
355+
Margin = settingControlMargin,
356+
Orientation = Orientation.Vertical
357+
};
358+
settingWindow.Content = mainPanel;
359+
foreach (var (key, value) in Settings)
360+
{
361+
var panel = new StackPanel
362+
{
363+
Orientation = Orientation.Horizontal,
364+
Margin = settingControlMargin
365+
};
366+
var name = new Label
367+
{
368+
Content = key,
369+
VerticalAlignment = VerticalAlignment.Center
370+
};
371+
UIElement content = null;
372+
switch (value)
373+
{
374+
case int i:
375+
case double d:
376+
throw new TypeAccessException();
377+
case string s:
378+
var textBox = new TextBox
379+
{
380+
Text = s,
381+
Margin = settingControlMargin,
382+
VerticalAlignment = VerticalAlignment.Center
383+
};
384+
textBox.TextChanged += (_, _) =>
385+
{
386+
Settings[key] = textBox.Text;
387+
};
388+
content = textBox;
389+
break;
390+
case bool b:
391+
var checkBox = new CheckBox
392+
{
393+
IsChecked = b,
394+
Margin = settingControlMargin,
395+
VerticalAlignment = VerticalAlignment.Center
396+
};
397+
checkBox.Click += (_, _) =>
398+
{
399+
Settings[key] = checkBox.IsChecked;
400+
};
401+
content = checkBox;
402+
break;
403+
default:
404+
throw new ArgumentOutOfRangeException();
405+
}
406+
panel.Children.Add(name);
407+
panel.Children.Add(content);
408+
mainPanel.Children.Add(panel);
409+
}
410+
return settingWindow;
411+
}
412+
public void Save()
413+
{
414+
if (Settings != null)
415+
{
416+
Helper.ValidateDirectory(Path.Combine(DataLocation.PluginSettingsDirectory, context.CurrentPluginMetadata.Name));
417+
File.WriteAllText(SettingPath, JsonSerializer.Serialize(Settings));
418+
}
299419
}
300420
}
301421
}

Flow.Launcher.Core/Plugin/PythonPlugin.cs

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -46,15 +46,12 @@ protected override string Request(JsonRPCRequestModel rpcRequest, CancellationTo
4646
// TODO: Async Action
4747
return Execute(_startInfo);
4848
}
49-
public override Task InitAsync(PluginInitContext context)
49+
public override async Task InitAsync(PluginInitContext context)
5050
{
51-
this.context = context;
5251
_startInfo.ArgumentList.Add(context.CurrentPluginMetadata.ExecuteFilePath);
5352
_startInfo.ArgumentList.Add("");
54-
53+
await base.InitAsync(context);
5554
_startInfo.WorkingDirectory = context.CurrentPluginMetadata.PluginDirectory;
56-
57-
return Task.CompletedTask;
5855
}
5956
}
6057
}

0 commit comments

Comments
 (0)