Skip to content

Commit 7329bdf

Browse files
authored
Merge pull request #243 from Flow-Launcher/pluginsmanager_update
Update plugins via Pluginsmanager
2 parents 829fccf + 5ab021f commit 7329bdf

File tree

6 files changed

+178
-64
lines changed

6 files changed

+178
-64
lines changed

Plugins/Flow.Launcher.Plugin.PluginsManager/Languages/en.xaml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,13 @@
1111
<system:String x:Key="plugin_pluginsmanager_install_title">Plugin Install</system:String>
1212
<system:String x:Key="plugin_pluginsmanager_uninstall_title">Plugin Uninstall</system:String>
1313
<system:String x:Key="plugin_pluginsmanager_install_errormetadatafile">Install failed: unable to find the plugin.json metadata file from the new plugin</system:String>
14+
<system:String x:Key="plugin_pluginsmanager_update_noresult_title">No update available</system:String>
15+
<system:String x:Key="plugin_pluginsmanager_update_noresult_subtitle">All plugins are up to date</system:String>
16+
<system:String x:Key="plugin_pluginsmanager_update_prompt">{0} by {1} {2}{3}Would you like to update this plugin? After the update Flow will automatically restart.</system:String>
17+
<system:String x:Key="plugin_pluginsmanager_update_title">Plugin Update</system:String>
18+
<system:String x:Key="plugin_pluginsmanager_update_exists">This plugin has an update, would you like to see it?</system:String>
19+
<system:String x:Key="plugin_pluginsmanager_update_alreadyexists">This plugin is already installed</system:String>
20+
1421
<!--Controls-->
1522

1623
<!--Plugin Infos-->

Plugins/Flow.Launcher.Plugin.PluginsManager/Main.cs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,9 +42,13 @@ public List<Result> Query(Query query)
4242
var pluginManager = new PluginsManager(Context, Settings);
4343

4444
if (!string.IsNullOrEmpty(search)
45-
&& ($"{Settings.UninstallHotkey} ".StartsWith(search) || search.StartsWith($"{Settings.UninstallHotkey} ")))
45+
&& ($"{Settings.HotkeyUninstall} ".StartsWith(search) || search.StartsWith($"{Settings.HotkeyUninstall} ")))
4646
return pluginManager.RequestUninstall(search);
47-
47+
48+
if (!string.IsNullOrEmpty(search)
49+
&& ($"{Settings.HotkeyUpdate} ".StartsWith(search) || search.StartsWith($"{Settings.HotkeyUpdate} ")))
50+
return pluginManager.RequestUpdate(search);
51+
4852
return pluginManager.RequestInstallOrUpdate(search);
4953
}
5054

Plugins/Flow.Launcher.Plugin.PluginsManager/Models/UserPlugin.cs

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,4 @@
1-
using System;
2-
using System.Collections.Generic;
3-
using System.Text;
4-
1+

52
namespace Flow.Launcher.Plugin.PluginsManager.Models
63
{
74
public class UserPlugin

Plugins/Flow.Launcher.Plugin.PluginsManager/PluginsManager.cs

Lines changed: 160 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,21 @@ internal class PluginsManager
1919

2020
private Settings Settings { get; set; }
2121

22+
private bool shouldHideWindow = true;
23+
private bool ShouldHideWindow
24+
{
25+
set { shouldHideWindow = value; }
26+
get
27+
{
28+
var setValue = shouldHideWindow;
29+
// Default value for hide main window is true. Revert after get call.
30+
// This ensures when set by another method to false, it is only used once.
31+
shouldHideWindow = true;
32+
33+
return setValue;
34+
}
35+
}
36+
2237
private readonly string icoPath = "Images\\pluginsmanager.png";
2338

2439
internal PluginsManager(PluginInitContext context, Settings settings)
@@ -31,7 +46,22 @@ internal void InstallOrUpdate(UserPlugin plugin)
3146
{
3247
if (PluginExists(plugin.ID))
3348
{
34-
Context.API.ShowMsg("Plugin already installed");
49+
if (Context.API.GetAllPlugins().Any(x => x.Metadata.ID == plugin.ID && x.Metadata.Version != plugin.Version))
50+
{
51+
if (MessageBox.Show(Context.API.GetTranslation("plugin_pluginsmanager_update_exists"),
52+
Context.API.GetTranslation("plugin_pluginsmanager_update_title"),
53+
MessageBoxButton.YesNo) == MessageBoxResult.Yes)
54+
Context
55+
.API
56+
.ChangeQuery($"{Context.CurrentPluginMetadata.ActionKeywords.FirstOrDefault()} {Settings.HotkeyUpdate} {plugin.Name}");
57+
58+
Application.Current.MainWindow.Show();
59+
shouldHideWindow = false;
60+
61+
return;
62+
}
63+
64+
Context.API.ShowMsg(Context.API.GetTranslation("plugin_pluginsmanager_update_alreadyexists"));
3565
return;
3666
}
3767

@@ -42,7 +72,7 @@ internal void InstallOrUpdate(UserPlugin plugin)
4272
if (MessageBox.Show(message, Context.API.GetTranslation("plugin_pluginsmanager_install_title"), MessageBoxButton.YesNo) == MessageBoxResult.No)
4373
return;
4474

45-
var filePath = Path.Combine(DataLocation.PluginsDirectory, $"{plugin.Name}{plugin.ID}.zip");
75+
var filePath = Path.Combine(DataLocation.PluginsDirectory, $"{plugin.Name}-{plugin.Version}.zip");
4676

4777
try
4878
{
@@ -62,29 +92,92 @@ internal void InstallOrUpdate(UserPlugin plugin)
6292
Log.Exception("PluginsManager", "An error occured while downloading plugin", e, "PluginDownload");
6393
}
6494

65-
Application.Current.Dispatcher.Invoke(() => Install(plugin, filePath));
95+
Application.Current.Dispatcher.Invoke(() => { Install(plugin, filePath); Context.API.RestartApp(); });
6696
}
6797

68-
internal void Update()
98+
internal List<Result> RequestUpdate(string search)
6999
{
70-
throw new NotImplementedException();
100+
var autocompletedResults = AutoCompleteReturnAllResults(search,
101+
Settings.HotkeyUpdate,
102+
"Update",
103+
"Select a plugin to update");
104+
105+
if (autocompletedResults.Any())
106+
return autocompletedResults;
107+
108+
var uninstallSearch = search.Replace(Settings.HotkeyUpdate, string.Empty).TrimStart();
109+
110+
111+
var resultsForUpdate =
112+
from existingPlugin in Context.API.GetAllPlugins()
113+
join pluginFromManifest in pluginsManifest.UserPlugins
114+
on existingPlugin.Metadata.ID equals pluginFromManifest.ID
115+
where existingPlugin.Metadata.Version != pluginFromManifest.Version
116+
select
117+
new
118+
{
119+
pluginFromManifest.Name,
120+
pluginFromManifest.Author,
121+
CurrentVersion = existingPlugin.Metadata.Version,
122+
NewVersion = pluginFromManifest.Version,
123+
existingPlugin.Metadata.IcoPath,
124+
PluginExistingMetadata = existingPlugin.Metadata,
125+
PluginNewUserPlugin = pluginFromManifest
126+
};
127+
128+
if (!resultsForUpdate.Any())
129+
return new List<Result> {
130+
new Result
131+
{
132+
Title = Context.API.GetTranslation("plugin_pluginsmanager_update_noresult_title"),
133+
SubTitle = Context.API.GetTranslation("plugin_pluginsmanager_update_noresult_subtitle"),
134+
IcoPath = icoPath
135+
}};
136+
137+
138+
var results = resultsForUpdate
139+
.Select(x =>
140+
new Result
141+
{
142+
Title = $"{x.Name} by {x.Author}",
143+
SubTitle = $"Update from version {x.CurrentVersion} to {x.NewVersion}",
144+
IcoPath = x.IcoPath,
145+
Action = e =>
146+
{
147+
string message = string.Format(Context.API.GetTranslation("plugin_pluginsmanager_update_prompt"),
148+
x.Name, x.Author,
149+
Environment.NewLine, Environment.NewLine);
150+
151+
if (MessageBox.Show(message, Context.API.GetTranslation("plugin_pluginsmanager_update_title"),
152+
MessageBoxButton.YesNo) == MessageBoxResult.Yes)
153+
{
154+
Uninstall(x.PluginExistingMetadata);
155+
156+
var downloadToFilePath = Path.Combine(DataLocation.PluginsDirectory, $"{x.Name}-{x.NewVersion}.zip");
157+
Http.Download(x.PluginNewUserPlugin.UrlDownload, downloadToFilePath);
158+
Install(x.PluginNewUserPlugin, downloadToFilePath);
159+
160+
Context.API.RestartApp();
161+
162+
return true;
163+
}
164+
165+
return false;
166+
}
167+
});
168+
169+
return Search(results, uninstallSearch);
71170
}
72171

73172
internal bool PluginExists(string id)
74173
{
75174
return Context.API.GetAllPlugins().Any(x => x.Metadata.ID == id);
76175
}
77176

78-
internal void PluginsManifestSiteOpen()
79-
{
80-
//Open from context menu https://git.vcmq.workers.dev/Flow-Launcher/Flow.Launcher.PluginsManifest
81-
throw new NotImplementedException();
82-
}
83-
84-
internal List<Result> Search(List<Result> results, string searchName)
177+
internal List<Result> Search(IEnumerable<Result> results, string searchName)
85178
{
86179
if (string.IsNullOrEmpty(searchName))
87-
return results;
180+
return results.ToList();
88181

89182
return results
90183
.Where(x =>
@@ -114,11 +207,10 @@ internal List<Result> RequestInstallOrUpdate(string searchName)
114207
Application.Current.MainWindow.Hide();
115208
InstallOrUpdate(x);
116209

117-
return true;
210+
return ShouldHideWindow;
118211
},
119212
ContextData = x
120-
})
121-
.ToList();
213+
});
122214

123215
return Search(results, searchName);
124216
}
@@ -154,42 +246,24 @@ private void Install(UserPlugin plugin, string downloadedFilePath)
154246
return;
155247
}
156248

157-
string newPluginPath = Path.Combine(DataLocation.PluginsDirectory, $"{plugin.Name}{plugin.ID}");
249+
string newPluginPath = Path.Combine(DataLocation.PluginsDirectory, $"{plugin.Name}-{plugin.Version}");
158250

159251
Directory.Move(pluginFolderPath, newPluginPath);
160-
161-
Context.API.RestartApp();
162252
}
163253

164254
internal List<Result> RequestUninstall(string search)
165255
{
166-
if (!string.IsNullOrEmpty(search)
167-
&& Settings.UninstallHotkey.StartsWith(search)
168-
&& (Settings.UninstallHotkey != search || !search.StartsWith(Settings.UninstallHotkey)))
169-
{
170-
return
171-
new List<Result>
172-
{
173-
new Result
174-
{
175-
Title = "Uninstall",
176-
IcoPath = icoPath,
177-
SubTitle = "Select a plugin to uninstall",
178-
Action = e =>
179-
{
180-
Context
181-
.API
182-
.ChangeQuery($"{Context.CurrentPluginMetadata.ActionKeywords.FirstOrDefault()} {Settings.UninstallHotkey} ");
256+
var autocompletedResults = AutoCompleteReturnAllResults(search,
257+
Settings.HotkeyUninstall,
258+
"Uninstall",
259+
"Select a plugin to uninstall");
183260

184-
return false;
185-
}
186-
}
187-
};
188-
}
261+
if (autocompletedResults.Any())
262+
return autocompletedResults;
189263

190-
var uninstallSearch = search.Replace(Settings.UninstallHotkey, string.Empty).TrimStart();
264+
var uninstallSearch = search.Replace(Settings.HotkeyUninstall, string.Empty).TrimStart();
191265

192-
var results= Context.API
266+
var results = Context.API
193267
.GetAllPlugins()
194268
.Select(x =>
195269
new Result
@@ -199,30 +273,60 @@ internal List<Result> RequestUninstall(string search)
199273
IcoPath = x.Metadata.IcoPath,
200274
Action = e =>
201275
{
202-
Application.Current.MainWindow.Hide();
203-
Uninstall(x.Metadata);
276+
string message = string.Format(Context.API.GetTranslation("plugin_pluginsmanager_uninstall_prompt"),
277+
x.Metadata.Name, x.Metadata.Author,
278+
Environment.NewLine, Environment.NewLine);
204279

205-
return true;
280+
if (MessageBox.Show(message, Context.API.GetTranslation("plugin_pluginsmanager_uninstall_title"),
281+
MessageBoxButton.YesNo) == MessageBoxResult.Yes)
282+
{
283+
Application.Current.MainWindow.Hide();
284+
Uninstall(x.Metadata);
285+
Context.API.RestartApp();
286+
287+
return true;
288+
}
289+
290+
return false;
206291
}
207-
})
208-
.ToList();
292+
});
209293

210294
return Search(results, uninstallSearch);
211295
}
212296

213297
private void Uninstall(PluginMetadata plugin)
214298
{
215-
string message = string.Format(Context.API.GetTranslation("plugin_pluginsmanager_uninstall_prompt"),
216-
plugin.Name, plugin.Author,
217-
Environment.NewLine, Environment.NewLine);
299+
// Marked for deletion. Will be deleted on next start up
300+
using var _ = File.CreateText(Path.Combine(plugin.PluginDirectory, "NeedDelete.txt"));
301+
}
218302

219-
if (MessageBox.Show(message, Context.API.GetTranslation("plugin_pluginsmanager_uninstall_title"),
220-
MessageBoxButton.YesNo) == MessageBoxResult.Yes)
303+
private List<Result> AutoCompleteReturnAllResults(string search, string hotkey, string title, string subtitle)
304+
{
305+
if (!string.IsNullOrEmpty(search)
306+
&& hotkey.StartsWith(search)
307+
&& (hotkey != search || !search.StartsWith(hotkey)))
221308
{
222-
using var _ = File.CreateText(Path.Combine(plugin.PluginDirectory, "NeedDelete.txt"));
223-
224-
Context.API.RestartApp();
309+
return
310+
new List<Result>
311+
{
312+
new Result
313+
{
314+
Title = title,
315+
IcoPath = icoPath,
316+
SubTitle = subtitle,
317+
Action = e =>
318+
{
319+
Context
320+
.API
321+
.ChangeQuery($"{Context.CurrentPluginMetadata.ActionKeywords.FirstOrDefault()} {hotkey} ");
322+
323+
return false;
324+
}
325+
}
326+
};
225327
}
328+
329+
return new List<Result>();
226330
}
227331
}
228332
}

Plugins/Flow.Launcher.Plugin.PluginsManager/Settings.cs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ namespace Flow.Launcher.Plugin.PluginsManager
66
{
77
internal class Settings
88
{
9-
internal string UninstallHotkey { get; set; } = "uninstall";
9+
internal string HotkeyUninstall { get; set; } = "uninstall";
10+
11+
internal string HotkeyUpdate { get; set; } = "update";
1012
}
1113
}

Plugins/Flow.Launcher.Plugin.PluginsManager/plugin.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
"Name": "Plugins Manager",
77
"Description": "Management of installing, uninstalling or updating Flow Launcher plugins",
88
"Author": "Jeremy Wu",
9-
"Version": "1.2.0",
9+
"Version": "1.3.0",
1010
"Language": "csharp",
1111
"Website": "https://github.com/Flow-Launcher/Flow.Launcher",
1212
"ExecuteFileName": "Flow.Launcher.Plugin.PluginsManager.dll",

0 commit comments

Comments
 (0)