@@ -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}
0 commit comments