From 2e8c91968f5f2fc4bc19c6a0d6912b88ae3109e2 Mon Sep 17 00:00:00 2001 From: Florian Grabmeier Date: Thu, 1 Feb 2024 16:38:44 +0100 Subject: [PATCH 01/14] Add local plugin installation Signed-off-by: Florian Grabmeier --- .../PluginsManager.cs | 59 +++++++++++++++++++ 1 file changed, 59 insertions(+) diff --git a/Plugins/Flow.Launcher.Plugin.PluginsManager/PluginsManager.cs b/Plugins/Flow.Launcher.Plugin.PluginsManager/PluginsManager.cs index 8cd58ac52..b9eaea2d4 100644 --- a/Plugins/Flow.Launcher.Plugin.PluginsManager/PluginsManager.cs +++ b/Plugins/Flow.Launcher.Plugin.PluginsManager/PluginsManager.cs @@ -14,6 +14,8 @@ using System.Net.Http; using System.Threading; using System.Threading.Tasks; using System.Windows; +using System.IO.Compression; +using Newtonsoft.Json; namespace Flow.Launcher.Plugin.PluginsManager { @@ -138,6 +140,12 @@ namespace Flow.Launcher.Plugin.PluginsManager MessageBoxButton.YesNo) == MessageBoxResult.No) return; + if (File.Exists(plugin.UrlDownload)) + { + Install(plugin, plugin.UrlDownload); + return; + } + // at minimum should provide a name, but handle plugin that is not downloaded from plugins manifest and is a url download var downloadFilename = string.IsNullOrEmpty(plugin.Version) ? $"{plugin.Name}-{Guid.NewGuid()}.zip" @@ -470,6 +478,54 @@ namespace Flow.Launcher.Plugin.PluginsManager return new List { result }; } + internal List InstallFromLocal(string path) + { + if (string.IsNullOrEmpty(path) || !File.Exists(path)) + { + return new List(); + } + + var plugin = null as UserPlugin; + + using (ZipArchive archive = ZipFile.OpenRead(path)) + { + var pluginJsonPath = archive.Entries.FirstOrDefault(x => x.Name == "plugin.json").ToString(); + ZipArchiveEntry pluginJsonEntry = archive.GetEntry(pluginJsonPath); + + if (pluginJsonEntry != null) + { + using (StreamReader reader = new StreamReader(pluginJsonEntry.Open())) + { + string pluginJsonContent = reader.ReadToEnd(); + plugin = JsonConvert.DeserializeObject(pluginJsonContent); + plugin.IcoPath = Path.Combine(path, pluginJsonEntry.FullName.Split('/')[0], plugin.IcoPath); + } + } + } + + if (plugin == null) + { + return new List(); + } + + plugin.UrlDownload = path; + + var result = new Result + { + Title = plugin.Name, + SubTitle = plugin.UrlDownload, + IcoPath = plugin.IcoPath, + Action = e => + { + Application.Current.MainWindow.Hide(); + _ = InstallOrUpdateAsync(plugin); + + return ShouldHideWindow; + } + }; + return new List { result }; + } + private bool InstallSourceKnown(string url) { var author = url.Split('/')[3]; @@ -489,6 +545,9 @@ namespace Flow.Launcher.Plugin.PluginsManager && search.Split('.').Last() == zip) return InstallFromWeb(search); + if (File.Exists(search) && search.Split('.').Last() == zip) + return InstallFromLocal(search); + var results = PluginsManifest .UserPlugins From 1dd526a2f984e1876f912a4d6a27f3f753f7a33e Mon Sep 17 00:00:00 2001 From: Florian Grabmeier Date: Sun, 4 Feb 2024 17:29:05 +0100 Subject: [PATCH 02/14] Add update from local file Signed-off-by: Florian Grabmeier --- .../Images/zipfolder.png | Bin 0 -> 2939 bytes .../PluginsManager.cs | 126 +++++++++++++++++- 2 files changed, 121 insertions(+), 5 deletions(-) create mode 100644 Plugins/Flow.Launcher.Plugin.PluginsManager/Images/zipfolder.png diff --git a/Plugins/Flow.Launcher.Plugin.PluginsManager/Images/zipfolder.png b/Plugins/Flow.Launcher.Plugin.PluginsManager/Images/zipfolder.png new file mode 100644 index 0000000000000000000000000000000000000000..5d3ed0ace3f8a26662b82611eccd95463f32f8c8 GIT binary patch literal 2939 zcmV->3xxEEP)i4qW7iveum z16oBzMNC8s@qNxuAq%F7b`~q@dk$jEvAH z1Q7W&9nVLj$jZPtuZ4~|T^x@3<`BCuQ~-sZYRY-Wmbr)^svJkF5U~?r91*aia=Wq4 zoxmb-Kpf)HOg|}ysYLFfhvI`65Th4{zPWJh4cTOUc|+2=gQ()fw(?9tRKEx=^__suGCbd{taS^cvz?pSRFQ0GsGTxDv_At|*8lUBqf*)B-Ih`BNl`@5os zK!OA~Dv;=x5?n2*v9qBiK-0)L_N(x5`v4ILeXL)NQgq|)?O0~K3=Bvrg*aZ_PD%tS zRmXvb1rRVo_(2gAoX!HqYm35^L_6i_KtL7sM+t_8!1_2{`C1P7qsu1B2sbK#QG)%W zc*ifK<15#bp1%r7chIW-<0x7!;_rQtp$%73-u5DHZx(F*@~JO?2*JQ8-U&TU&wY$9%JRe zJ^)YLOKZ^8C_=$F6jtWO{{@Be2n_F1%EL7gm?VH#fWGB|-aAhoWx8W#D{Q-$0!0h=w2-B z*%BR^h=SZUqMF~T53UrxE}EKKMhA>S@o*TWlrp8UIi zfUsJNr(?*}Ff_JQ%lNa;X5ce7APQ2)3#mYH-ual|eX=|M0@-*!V!W*bun?wt5FgxX zxq*H_Q7I5+l99iP|D3RZ*b1Vxe;T+UYAMATHf(x`zW_%$2@&9vLm4YZ3SsTun3Dhjhzc{`Na5FLTV4|&uKAUNBtQU(vb0`r1?)0t5&nEAz`5za_sIJU}ZmWz@70e*wY@WDRt!JoMbqlW<`Dp~us`;Cf(Vn2Mf4 z`~?Us=c&Ae~OhP2ml;5p6^@{O{0zh9j6`UmSCohnik?e z5_W*n_Ct@)y9Cb4KrjX;{P@uG0~?a?bO|ugbK(7$p!g~jrYw=4^S#60;~#*%k3u^B z4Ltr9IvEHQUcR*PdtUn)Q~)Rbi;CkffGQNSuzNGSysrNBZ~Ydw-2wRwtyIKxp$-%> zu=Qrx{AJkp7*Q1;$D#+Gg6F>muUrGU6qpoANXEs#4*;S){w}oTVBZr^IfsATaz2mr ze;d~oR(3zgWh?K5A)qY{l8WbotizBH0jN#F2;>XUS!Cyq9o%vIdO$hu8*d`#0by-_ zZi3$CksJZWQ3VTa?Va?V*hgRu$M?PivjH;-!!DGv;Ivx6j56N6&dQDQ`o1|l_~;63 z*|28G%cOH>(%{)}8)%}_Np>aY>Qe;0!WApQZVq$j>Ys3&5EXpRS-1VkD(G(r4T6R661a#DJ?(^ zR9$|uVm*pt(uQ5Te73%uCht`lEaiD^%K|!rkhy*RP{}p)s+c$+6JO%sn^)EaH#cb3W$Cn#fQ@kP}E(kCRV+E)< zU?LZUYRwG^p6j!>*v>7_oE2T;CSyV-IRaRLLbU0kG~`hYU0h=c)R1v~+OuOU>E6R7 zr*8z$LXZsanhYxe3MF3Ov54z8tYysRC=L!VuXB+8p;=sZ$`*d{ty{^CxugrjFj{+E zSgbuzL^4`{SV)K5^yInRv*lCiGUzUQIIHjW!~O1p93bty&D&D`{qToXG$!c z8?baCn832`jK`RN-0sK?#d|z(BWsFRB&QFs2C5lOTJR1h9S1MG)WL9hIrG{F*)`b5 z&Mhahb)b`-gR{Byhku5YpNNh){uYj-5`~s2z=@J?O6_|FR44}?jtQC5{z2{iJjrlF z$q^v!Q>}Wef9f;_CCdx%cF~g`Vc%$hRZDhq_NgzC3Ioo%-qZd(~I+)i(ypV#*t&(hvkxoGVs_y8DkVJtZ_VhM?Y0D+-Wo@(Hdas!M+ zBVa+XYNAA309YpxHGiCBv;Y+-dHnp$hsb*sMr@vKJ1noflcgZ$>6A~|PqAtHG6)Qq1nkZrDK2O-YN9tz)!a)pbm>l) z>FGK^cm4oZo%H~uEL74>Hnc7u=L;O-OaD+8Yd`lAzxwV*+_He@!$=|i{@)dW$x%?1 z#3ZmLV^v6*05=~*g+7{(ci{`s>b(KG2__5B7yglQ{MXS;#fTDECt9oPd(AedJ{1FP z_AX8ty9*`@u( x.Name == "plugin.json").ToString(); + ZipArchiveEntry pluginJsonEntry = archive.GetEntry(pluginJsonPath); + + if (pluginJsonEntry != null) + { + using (StreamReader reader = new StreamReader(pluginJsonEntry.Open())) + { + string pluginJsonContent = await reader.ReadToEndAsync(); + plugin = JsonConvert.DeserializeObject(pluginJsonContent); + plugin.IcoPath = "Images\\zipfolder.png"; + } + } + } + if (plugin == null) + { + return new List + { + new Result + { + Title = Context.API.GetTranslation("plugin_pluginsmanager_update_noresult_title"), + SubTitle = Context.API.GetTranslation("plugin_pluginsmanager_update_noresult_subtitle"), + IcoPath = icoPath + } + }; + } + + var pluginOld = Context.API.GetAllPlugins().FirstOrDefault(x => x.Metadata.ID == plugin.ID); + + return new List { + new Result + { + + Title = $"{plugin.Name} by {plugin.Author}", + SubTitle = $"Update from version {pluginOld.Metadata.Version} to {plugin.Version}", + IcoPath = pluginOld.Metadata.IcoPath, + Action = e => + { + string message; + if (Settings.AutoRestartAfterChanging) + { + message = string.Format( + Context.API.GetTranslation("plugin_pluginsmanager_update_prompt"), + plugin.Name, plugin.Author, + Environment.NewLine, Environment.NewLine); + } + else + { + message = string.Format( + Context.API.GetTranslation("plugin_pluginsmanager_update_prompt_no_restart"), + plugin.Name, plugin.Author, + Environment.NewLine); + } + + if (MessageBox.Show(message, + Context.API.GetTranslation("plugin_pluginsmanager_update_title"), + MessageBoxButton.YesNo) != MessageBoxResult.Yes) + { + return false; + } + + var downloadToFilePath = search; + + + PluginManager.UpdatePlugin(pluginOld.Metadata, plugin, + downloadToFilePath); + + if (Settings.AutoRestartAfterChanging) + { + Context.API.ShowMsg( + Context.API.GetTranslation("plugin_pluginsmanager_update_title"), + string.Format( + Context.API.GetTranslation( + "plugin_pluginsmanager_update_success_restart"), + plugin.Name)); + Context.API.RestartApp(); + } + else + { + Context.API.ShowMsg( + Context.API.GetTranslation("plugin_pluginsmanager_update_title"), + string.Format( + Context.API.GetTranslation( + "plugin_pluginsmanager_update_success_no_restart"), + plugin.Name)); + } + + return true; + + }, + ContextData = + new UserPlugin + { + Website = plugin.Website, + UrlSourceCode = plugin.UrlSourceCode + } + }}; + } + var resultsForUpdate = ( from existingPlugin in Context.API.GetAllPlugins() join pluginFromManifest in PluginsManifest.UserPlugins @@ -498,7 +610,7 @@ namespace Flow.Launcher.Plugin.PluginsManager { string pluginJsonContent = reader.ReadToEnd(); plugin = JsonConvert.DeserializeObject(pluginJsonContent); - plugin.IcoPath = Path.Combine(path, pluginJsonEntry.FullName.Split('/')[0], plugin.IcoPath); + plugin.IcoPath = "Images\\zipfolder.png"; } } } @@ -584,7 +696,11 @@ namespace Flow.Launcher.Plugin.PluginsManager try { PluginManager.InstallPlugin(plugin, downloadedFilePath); - File.Delete(downloadedFilePath); + if (downloadedFilePath.StartsWith(Path.GetTempPath())) + { + File.Delete(downloadedFilePath); + } + } catch (FileNotFoundException e) { From 3938858e33e4a5689a6919b69aae7420edcf52de Mon Sep 17 00:00:00 2001 From: DB p Date: Tue, 30 Apr 2024 02:23:16 +0900 Subject: [PATCH 03/14] Fix SettingWindow Position when first launch --- Flow.Launcher/SettingWindow.xaml.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Flow.Launcher/SettingWindow.xaml.cs b/Flow.Launcher/SettingWindow.xaml.cs index 8144c8ff8..bad15d2c9 100644 --- a/Flow.Launcher/SettingWindow.xaml.cs +++ b/Flow.Launcher/SettingWindow.xaml.cs @@ -446,7 +446,7 @@ namespace Flow.Launcher public void InitializePosition() { - if (settings.SettingWindowTop >= 0 && settings.SettingWindowLeft >= 0) + if (settings.SettingWindowTop == null) { Top = settings.SettingWindowTop; Left = settings.SettingWindowLeft; From c950a689d5b29c92f51743c03ff27d4d5fab156c Mon Sep 17 00:00:00 2001 From: DB p Date: Thu, 16 May 2024 01:11:27 +0900 Subject: [PATCH 04/14] - Convert Garulf's Query Cycle feature - Add Reset CycleIndex when close window --- .../UserSettings/Settings.cs | 6 ++ Flow.Launcher/MainWindow.xaml | 8 +++ Flow.Launcher/SettingWindow.xaml | 20 ++++++ Flow.Launcher/ViewModel/MainViewModel.cs | 68 ++++++++++++++++++- 4 files changed, 101 insertions(+), 1 deletion(-) diff --git a/Flow.Launcher.Infrastructure/UserSettings/Settings.cs b/Flow.Launcher.Infrastructure/UserSettings/Settings.cs index 7bb8fe200..3d4433493 100644 --- a/Flow.Launcher.Infrastructure/UserSettings/Settings.cs +++ b/Flow.Launcher.Infrastructure/UserSettings/Settings.cs @@ -31,6 +31,8 @@ namespace Flow.Launcher.Infrastructure.UserSettings public string SelectPrevPageHotkey { get; set; } = $"PageDown"; public string OpenContextMenuHotkey { get; set; } = $"Ctrl+O"; public string SettingWindowHotkey { get; set; } = $"Ctrl+I"; + public string CycleHistoryUpHotkey { get; set; } = $"{KeyConstant.Alt} + Up"; + public string CycleHistoryDownHotkey { get; set; } = $"{KeyConstant.Alt} + Down"; public string Language { @@ -340,6 +342,10 @@ namespace Flow.Launcher.Infrastructure.UserSettings list.Add(new(SelectNextPageHotkey, "SelectNextPageHotkey", () => SelectNextPageHotkey = "")); if(!string.IsNullOrEmpty(SelectPrevPageHotkey)) list.Add(new(SelectPrevPageHotkey, "SelectPrevPageHotkey", () => SelectPrevPageHotkey = "")); + if (!string.IsNullOrEmpty(CycleHistoryUpHotkey)) + list.Add(new(CycleHistoryUpHotkey, "CycleHistoryUpHotkey", () => CycleHistoryUpHotkey = "")); + if (!string.IsNullOrEmpty(CycleHistoryDownHotkey)) + list.Add(new(CycleHistoryDownHotkey, "CycleHistoryDownHotkey", () => CycleHistoryDownHotkey = "")); foreach (var customPluginHotkey in CustomPluginHotkeys) { diff --git a/Flow.Launcher/MainWindow.xaml b/Flow.Launcher/MainWindow.xaml index 2e6e973a7..da5ec63bf 100644 --- a/Flow.Launcher/MainWindow.xaml +++ b/Flow.Launcher/MainWindow.xaml @@ -197,6 +197,14 @@ Key="{Binding SelectPrevPageHotkey, Converter={StaticResource StringToKeyBindingConverter}, ConverterParameter='key'}" Command="{Binding SelectPrevPageCommand}" Modifiers="{Binding SelectPrevPageHotkey, Converter={StaticResource StringToKeyBindingConverter}, ConverterParameter='modifiers'}" /> + + diff --git a/Flow.Launcher/SettingWindow.xaml b/Flow.Launcher/SettingWindow.xaml index 119268d6b..4a563bc45 100644 --- a/Flow.Launcher/SettingWindow.xaml +++ b/Flow.Launcher/SettingWindow.xaml @@ -2810,6 +2810,26 @@ Type="Inside"> + + + + + + _userSelectedRecordStorage; private readonly FlowLauncherJsonStorage _topMostRecordStorage; private readonly History _history; + private int lasthistoryindex = 1; private readonly UserSelectedRecord _userSelectedRecord; private readonly TopMostRecord _topMostRecord; @@ -83,6 +84,12 @@ namespace Flow.Launcher.ViewModel case nameof(Settings.AutoCompleteHotkey): OnPropertyChanged(nameof(AutoCompleteHotkey)); break; + case nameof(Settings.CycleHistoryUpHotkey): + OnPropertyChanged(nameof(CycleHistoryUpHotkey)); + break; + case nameof(Settings.CycleHistoryDownHotkey): + OnPropertyChanged(nameof(CycleHistoryDownHotkey)); + break; case nameof(Settings.AutoCompleteHotkey2): OnPropertyChanged(nameof(AutoCompleteHotkey2)); break; @@ -256,6 +263,49 @@ namespace Flow.Launcher.ViewModel } } + [RelayCommand] + public void ReverseHistory() + { + if (_history.Items.Count > 0) + { + ChangeQueryText(_history.Items[_history.Items.Count - lasthistoryindex].Query.ToString()); + if (lasthistoryindex < _history.Items.Count) + { + lasthistoryindex++; + } + } + } + + [RelayCommand] + public void ForwardHistory() + { + if (_history.Items.Count > 0) + { + ChangeQueryText(_history.Items[_history.Items.Count - lasthistoryindex].Query.ToString()); + if (lasthistoryindex > 1) + { + lasthistoryindex--; + } + } + } + + [RelayCommand] + public void ReverseHistoryOnEmptyQuery() + { + var results = SelectedResults; + if (_history.Items.Count > 0 + && _queryText == String.Empty + && !HistorySelected() + && !ContextMenuSelected()) + { + ReverseHistory(); + } + else + { + SelectedResults.SelectPrevResult(); + } + } + [RelayCommand] private void LoadContextMenu() { @@ -394,7 +444,20 @@ namespace Flow.Launcher.ViewModel [RelayCommand] private void SelectPrevItem() { - SelectedResults.SelectPrevResult(); + var results = SelectedResults; + if (_history.Items.Count > 0 + && _queryText == String.Empty + && !HistorySelected() + && !ContextMenuSelected()) + { + lasthistoryindex = 1; + ReverseHistory(); + } + else + { + SelectedResults.SelectPrevResult(); + } + } [RelayCommand] @@ -690,6 +753,8 @@ namespace Flow.Launcher.ViewModel public string SelectPrevPageHotkey => VerifyOrSetDefaultHotkey(Settings.SelectPrevPageHotkey, ""); public string OpenContextMenuHotkey => VerifyOrSetDefaultHotkey(Settings.OpenContextMenuHotkey, "Ctrl+O"); public string SettingWindowHotkey => VerifyOrSetDefaultHotkey(Settings.SettingWindowHotkey, "Ctrl+I"); + public string CycleHistoryUpHotkey => VerifyOrSetDefaultHotkey(Settings.CycleHistoryUpHotkey, "Alt+Up"); + public string CycleHistoryDownHotkey => VerifyOrSetDefaultHotkey(Settings.CycleHistoryDownHotkey, "Alt+Down"); public string Image => Constant.QueryTextBoxIconImagePath; @@ -1116,6 +1181,7 @@ namespace Flow.Launcher.ViewModel public async void Hide() { + lasthistoryindex = 1; // Trick for no delay MainWindowOpacity = 0; lastContextMenuResult = new Result(); From 572e889c3449d604c7ad833cd8409f4bfb9da8ce Mon Sep 17 00:00:00 2001 From: DB p Date: Thu, 16 May 2024 01:44:00 +0900 Subject: [PATCH 05/14] Delete unused code --- Flow.Launcher/ViewModel/MainViewModel.cs | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/Flow.Launcher/ViewModel/MainViewModel.cs b/Flow.Launcher/ViewModel/MainViewModel.cs index ac5b980e0..2e52f92c1 100644 --- a/Flow.Launcher/ViewModel/MainViewModel.cs +++ b/Flow.Launcher/ViewModel/MainViewModel.cs @@ -289,23 +289,6 @@ namespace Flow.Launcher.ViewModel } } - [RelayCommand] - public void ReverseHistoryOnEmptyQuery() - { - var results = SelectedResults; - if (_history.Items.Count > 0 - && _queryText == String.Empty - && !HistorySelected() - && !ContextMenuSelected()) - { - ReverseHistory(); - } - else - { - SelectedResults.SelectPrevResult(); - } - } - [RelayCommand] private void LoadContextMenu() { From aa82d358d1e8642dee2ab93746e983401f10b48a Mon Sep 17 00:00:00 2001 From: DB p Date: Thu, 16 May 2024 15:16:52 +0900 Subject: [PATCH 06/14] Add Strings --- Flow.Launcher/Languages/en.xaml | 2 ++ Flow.Launcher/SettingWindow.xaml | 8 ++++---- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/Flow.Launcher/Languages/en.xaml b/Flow.Launcher/Languages/en.xaml index fd24f825e..9ab05555c 100644 --- a/Flow.Launcher/Languages/en.xaml +++ b/Flow.Launcher/Languages/en.xaml @@ -188,6 +188,8 @@ Select Previous Item Next Page Previous Page + Cycle Previous Query + Cycle Next Query Open Context Menu Open Setting Window Copy File Path diff --git a/Flow.Launcher/SettingWindow.xaml b/Flow.Launcher/SettingWindow.xaml index 4a563bc45..a8de26af7 100644 --- a/Flow.Launcher/SettingWindow.xaml +++ b/Flow.Launcher/SettingWindow.xaml @@ -2811,8 +2811,8 @@ Date: Thu, 16 May 2024 17:04:29 +0900 Subject: [PATCH 07/14] Block Mouse Hover --- Flow.Launcher/MainWindow.xaml | 1 + Flow.Launcher/MainWindow.xaml.cs | 23 ++++++++++++++++++++++- 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/Flow.Launcher/MainWindow.xaml b/Flow.Launcher/MainWindow.xaml index 2e6e973a7..34b6dfcdc 100644 --- a/Flow.Launcher/MainWindow.xaml +++ b/Flow.Launcher/MainWindow.xaml @@ -25,6 +25,7 @@ LocationChanged="OnLocationChanged" Opacity="{Binding MainWindowOpacity, Mode=OneWay, UpdateSourceTrigger=PropertyChanged}" PreviewKeyDown="OnKeyDown" + PreviewKeyUp="OnKeyUp" ResizeMode="NoResize" ShowInTaskbar="False" SizeToContent="Height" diff --git a/Flow.Launcher/MainWindow.xaml.cs b/Flow.Launcher/MainWindow.xaml.cs index 76e587cdc..9c5ed46c0 100644 --- a/Flow.Launcher/MainWindow.xaml.cs +++ b/Flow.Launcher/MainWindow.xaml.cs @@ -47,6 +47,7 @@ namespace Flow.Launcher private MainViewModel _viewModel; private bool _animating; MediaPlayer animationSound = new MediaPlayer(); + private bool isArrowKeyPressed = false; #endregion @@ -109,9 +110,11 @@ namespace Flow.Launcher private void OnInitialized(object sender, EventArgs e) { } - private void OnLoaded(object sender, RoutedEventArgs _) { + // MouseEventHandler + PreviewMouseMove += MainPreviewMouseMove; + CheckFirstLaunch(); HideStartup(); // show notify icon when flowlauncher is hidden @@ -406,6 +409,7 @@ namespace Flow.Launcher if (_animating) return; + isArrowKeyPressed = true; _animating = true; UpdatePosition(); @@ -494,6 +498,7 @@ namespace Flow.Launcher windowsb.Completed += (_, _) => _animating = false; _settings.WindowLeft = Left; _settings.WindowTop = Top; + isArrowKeyPressed = false; if (QueryTextBox.Text.Length == 0) { @@ -644,10 +649,12 @@ namespace Flow.Launcher switch (e.Key) { case Key.Down: + isArrowKeyPressed = true; _viewModel.SelectNextItemCommand.Execute(null); e.Handled = true; break; case Key.Up: + isArrowKeyPressed = true; _viewModel.SelectPrevItemCommand.Execute(null); e.Handled = true; break; @@ -698,7 +705,21 @@ namespace Flow.Launcher } } + private void OnKeyUp(object sender, KeyEventArgs e) + { + if (e.Key == Key.Up || e.Key == Key.Down) + { + isArrowKeyPressed = false; + } + } + private void MainPreviewMouseMove(object sender, System.Windows.Input.MouseEventArgs e) + { + if (isArrowKeyPressed) + { + e.Handled = true; // Ignore Mouse Hover when press Arrowkeys + } + } public void PreviewReset() { _viewModel.ResetPreview(); From 2606faae17b4b8ddddb182df85752efb282a4ac6 Mon Sep 17 00:00:00 2001 From: Jeremy Date: Thu, 16 May 2024 21:22:08 +1000 Subject: [PATCH 08/14] minor fixes & refactor --- .../ExternalPlugins/UserPlugin.cs | 4 +- Flow.Launcher.Core/Plugin/PluginManager.cs | 11 +- .../SharedCommands/FilesFolders.cs | 19 ++ Flow.Launcher.Test/Plugins/ExplorerTest.cs | 24 +- .../Languages/en.xaml | 1 - .../PluginsManager.cs | 269 ++++++------------ .../Utilities.cs | 30 +- 7 files changed, 152 insertions(+), 206 deletions(-) diff --git a/Flow.Launcher.Core/ExternalPlugins/UserPlugin.cs b/Flow.Launcher.Core/ExternalPlugins/UserPlugin.cs index bb1279b2c..5114c3ab4 100644 --- a/Flow.Launcher.Core/ExternalPlugins/UserPlugin.cs +++ b/Flow.Launcher.Core/ExternalPlugins/UserPlugin.cs @@ -1,4 +1,4 @@ -using System; +using System; namespace Flow.Launcher.Core.ExternalPlugins { @@ -13,9 +13,11 @@ namespace Flow.Launcher.Core.ExternalPlugins public string Website { get; set; } public string UrlDownload { get; set; } public string UrlSourceCode { get; set; } + public string LocalInstallPath { get; set; } public string IcoPath { get; set; } public DateTime LatestReleaseDate { get; set; } public DateTime DateAdded { get; set; } + public bool IsFromLocalInstallPath => !string.IsNullOrEmpty(LocalInstallPath); } } diff --git a/Flow.Launcher.Core/Plugin/PluginManager.cs b/Flow.Launcher.Core/Plugin/PluginManager.cs index 7f4d4ea35..e7dfb31c0 100644 --- a/Flow.Launcher.Core/Plugin/PluginManager.cs +++ b/Flow.Launcher.Core/Plugin/PluginManager.cs @@ -380,7 +380,8 @@ namespace Flow.Launcher.Core.Plugin /// - /// Update a plugin to new version, from a zip file. Will Delete zip after updating. + /// Update a plugin to new version, from a zip file. By default will remove the zip file if update is via url, + /// unless it's a local path installation /// public static void UpdatePlugin(PluginMetadata existingVersion, UserPlugin newVersion, string zipFilePath) { @@ -390,11 +391,11 @@ namespace Flow.Launcher.Core.Plugin } /// - /// Install a plugin. Will Delete zip after updating. + /// Install a plugin. By default will remove the zip file if installation is from url, unless it's a local path installation /// public static void InstallPlugin(UserPlugin plugin, string zipFilePath) { - InstallPlugin(plugin, zipFilePath, true); + InstallPlugin(plugin, zipFilePath, checkModified: true); } /// @@ -420,7 +421,9 @@ namespace Flow.Launcher.Core.Plugin // Unzip plugin files to temp folder var tempFolderPluginPath = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString()); System.IO.Compression.ZipFile.ExtractToDirectory(zipFilePath, tempFolderPluginPath); - File.Delete(zipFilePath); + + if(!plugin.IsFromLocalInstallPath) + File.Delete(zipFilePath); var pluginFolderPath = GetContainingFolderPathAfterUnzip(tempFolderPluginPath); diff --git a/Flow.Launcher.Plugin/SharedCommands/FilesFolders.cs b/Flow.Launcher.Plugin/SharedCommands/FilesFolders.cs index 4137ca8d0..dd8c4b112 100644 --- a/Flow.Launcher.Plugin/SharedCommands/FilesFolders.cs +++ b/Flow.Launcher.Plugin/SharedCommands/FilesFolders.cs @@ -1,6 +1,7 @@ using System; using System.Diagnostics; using System.IO; +using System.Linq; #pragma warning disable IDE0005 using System.Windows; #pragma warning restore IDE0005 @@ -200,6 +201,24 @@ namespace Flow.Launcher.Plugin.SharedCommands } } + /// + /// This checks whether a given string is a zip file path. + /// By default does not check if the zip file actually exist on disk, can do so by + /// setting checkFileExists = true. + /// + public static bool IsZipFilePath(string querySearchString, bool checkFileExists = false) + { + if (IsLocationPathString(querySearchString) && querySearchString.Split('.').Last() == "zip") + { + if (checkFileExists) + return FileExists(querySearchString); + + return true; + } + + return false; + } + /// /// This checks whether a given string is a directory path or network location string. /// It does not check if location actually exists. diff --git a/Flow.Launcher.Test/Plugins/ExplorerTest.cs b/Flow.Launcher.Test/Plugins/ExplorerTest.cs index e9d37433f..caa884b51 100644 --- a/Flow.Launcher.Test/Plugins/ExplorerTest.cs +++ b/Flow.Launcher.Test/Plugins/ExplorerTest.cs @@ -186,16 +186,20 @@ namespace Flow.Launcher.Test.Plugins $"Actual result was: {result}{Environment.NewLine}"); } - [TestCase(@"c:\\", false)] - [TestCase(@"i:\", true)] - [TestCase(@"\c:\", false)] - [TestCase(@"cc:\", false)] - [TestCase(@"\\\SomeNetworkLocation\", false)] - [TestCase("RandomFile", false)] - [TestCase(@"c:\>*", true)] - [TestCase(@"c:\>", true)] - [TestCase(@"c:\SomeLocation\SomeOtherLocation\>", true)] - [TestCase(@"c:\SomeLocation\SomeOtherLocation", true)] + //[TestCase(@"c:\\", false)] + //[TestCase(@"i:\", true)] + //[TestCase(@"\c:\", false)] + //[TestCase(@"cc:\", false)] + //[TestCase(@"\\\SomeNetworkLocation\", false)] + //[TestCase(@"\\SomeNetworkLocation\", true)] + //[TestCase("RandomFile", false)] + //[TestCase(@"c:\>*", true)] + //[TestCase(@"c:\>", true)] + //[TestCase(@"c:\SomeLocation\SomeOtherLocation\>", true)] + //[TestCase(@"c:\SomeLocation\SomeOtherLocation", true)] + //[TestCase(@"c:\SomeLocation\SomeOtherLocation\SomeFile.exe", true)] + [TestCase(@"\\SomeNetworkLocation\SomeFile.exe", true)] + public void WhenGivenQuerySearchString_ThenShouldIndicateIfIsLocationPathString(string querySearchString, bool expectedResult) { // When, Given diff --git a/Plugins/Flow.Launcher.Plugin.PluginsManager/Languages/en.xaml b/Plugins/Flow.Launcher.Plugin.PluginsManager/Languages/en.xaml index a89d9df21..de6a3a2fb 100644 --- a/Plugins/Flow.Launcher.Plugin.PluginsManager/Languages/en.xaml +++ b/Plugins/Flow.Launcher.Plugin.PluginsManager/Languages/en.xaml @@ -26,7 +26,6 @@ {0} by {1} {2}{3}Would you like to update this plugin? After the update Flow will automatically restart. {0} by {1} {2}{2}Would you like to update this plugin? Plugin Update - This plugin has an update, would you like to see it? This plugin is already installed Plugin Manifest Download Failed Please check if you can connect to github.com. This error means you may not be able to install or update plugins. diff --git a/Plugins/Flow.Launcher.Plugin.PluginsManager/PluginsManager.cs b/Plugins/Flow.Launcher.Plugin.PluginsManager/PluginsManager.cs index 69831d439..15cbda7f2 100644 --- a/Plugins/Flow.Launcher.Plugin.PluginsManager/PluginsManager.cs +++ b/Plugins/Flow.Launcher.Plugin.PluginsManager/PluginsManager.cs @@ -3,19 +3,15 @@ using Flow.Launcher.Core.Plugin; using Flow.Launcher.Infrastructure; using Flow.Launcher.Infrastructure.Http; using Flow.Launcher.Infrastructure.Logger; -using Flow.Launcher.Infrastructure.UserSettings; using Flow.Launcher.Plugin.SharedCommands; using System; using System.Collections.Generic; -using System.Diagnostics; using System.IO; using System.Linq; using System.Net.Http; using System.Threading; using System.Threading.Tasks; using System.Windows; -using System.IO.Compression; -using Newtonsoft.Json; namespace Flow.Launcher.Plugin.PluginsManager { @@ -101,21 +97,12 @@ namespace Flow.Launcher.Plugin.PluginsManager if (Context.API.GetAllPlugins() .Any(x => x.Metadata.ID == plugin.ID && x.Metadata.Version.CompareTo(plugin.Version) < 0)) { - if (MessageBox.Show(Context.API.GetTranslation("plugin_pluginsmanager_update_exists"), - Context.API.GetTranslation("plugin_pluginsmanager_update_title"), - MessageBoxButton.YesNo) == MessageBoxResult.Yes) - { - if (File.Exists(plugin.UrlDownload)) - { - Context.API.ChangeQuery( - $"{Context.CurrentPluginMetadata.ActionKeywords.FirstOrDefault()} {Settings.UpdateCommand} {plugin.UrlDownload}"); - } - else - { - Context.API.ChangeQuery( - $"{Context.CurrentPluginMetadata.ActionKeywords.FirstOrDefault()} {Settings.UpdateCommand} {plugin.Name}"); - } - } + var updateDetail = !plugin.IsFromLocalInstallPath ? plugin.Name : plugin.LocalInstallPath; + + Context + .API + .ChangeQuery( + $"{Context.CurrentPluginMetadata.ActionKeywords.FirstOrDefault()} {Settings.UpdateCommand} {updateDetail}"); var mainWindow = Application.Current.MainWindow; mainWindow.Show(); @@ -148,12 +135,6 @@ namespace Flow.Launcher.Plugin.PluginsManager MessageBoxButton.YesNo) == MessageBoxResult.No) return; - if (File.Exists(plugin.UrlDownload)) - { - Install(plugin, plugin.UrlDownload); - return; - } - // at minimum should provide a name, but handle plugin that is not downloaded from plugins manifest and is a url download var downloadFilename = string.IsNullOrEmpty(plugin.Version) ? $"{plugin.Name}-{Guid.NewGuid()}.zip" @@ -163,12 +144,17 @@ namespace Flow.Launcher.Plugin.PluginsManager try { - if (File.Exists(filePath)) + if (!plugin.IsFromLocalInstallPath) { - File.Delete(filePath); - } + if (File.Exists(filePath)) + File.Delete(filePath); - await Http.DownloadAsync(plugin.UrlDownload, filePath).ConfigureAwait(false); + await Http.DownloadAsync(plugin.UrlDownload, filePath).ConfigureAwait(false); + } + else + { + filePath = plugin.LocalInstallPath; + } Install(plugin, filePath); } @@ -209,128 +195,38 @@ namespace Flow.Launcher.Plugin.PluginsManager { await PluginsManifest.UpdateManifestAsync(token, usePrimaryUrlOnly); - if (File.Exists(search) && search.Split('.').Last() == zip) + var pluginFromLocalPath = null as UserPlugin; + var updateFromLocalPath = false; + + if (FilesFolders.IsZipFilePath(search, checkFileExists: true)) { - var plugin = null as UserPlugin; + pluginFromLocalPath = Utilities.GetPluginInfoFromZip(search); + pluginFromLocalPath.LocalInstallPath = search; + updateFromLocalPath = true; + } - using (ZipArchive archive = ZipFile.OpenRead(search)) - { - var pluginJsonPath = archive.Entries.FirstOrDefault(x => x.Name == "plugin.json").ToString(); - ZipArchiveEntry pluginJsonEntry = archive.GetEntry(pluginJsonPath); - - if (pluginJsonEntry != null) - { - using (StreamReader reader = new StreamReader(pluginJsonEntry.Open())) - { - string pluginJsonContent = await reader.ReadToEndAsync(); - plugin = JsonConvert.DeserializeObject(pluginJsonContent); - plugin.IcoPath = "Images\\zipfolder.png"; - } - } - } - if (plugin == null) - { - return new List - { - new Result - { - Title = Context.API.GetTranslation("plugin_pluginsmanager_update_noresult_title"), - SubTitle = Context.API.GetTranslation("plugin_pluginsmanager_update_noresult_subtitle"), - IcoPath = icoPath - } - }; - } - - var pluginOld = Context.API.GetAllPlugins().FirstOrDefault(x => x.Metadata.ID == plugin.ID); - - return new List { - new Result - { - - Title = $"{plugin.Name} by {plugin.Author}", - SubTitle = $"Update from version {pluginOld.Metadata.Version} to {plugin.Version}", - IcoPath = pluginOld.Metadata.IcoPath, - Action = e => - { - string message; - if (Settings.AutoRestartAfterChanging) - { - message = string.Format( - Context.API.GetTranslation("plugin_pluginsmanager_update_prompt"), - plugin.Name, plugin.Author, - Environment.NewLine, Environment.NewLine); - } - else - { - message = string.Format( - Context.API.GetTranslation("plugin_pluginsmanager_update_prompt_no_restart"), - plugin.Name, plugin.Author, - Environment.NewLine); - } - - if (MessageBox.Show(message, - Context.API.GetTranslation("plugin_pluginsmanager_update_title"), - MessageBoxButton.YesNo) != MessageBoxResult.Yes) - { - return false; - } - - var downloadToFilePath = search; - - - PluginManager.UpdatePlugin(pluginOld.Metadata, plugin, - downloadToFilePath); - - if (Settings.AutoRestartAfterChanging) - { - Context.API.ShowMsg( - Context.API.GetTranslation("plugin_pluginsmanager_update_title"), - string.Format( - Context.API.GetTranslation( - "plugin_pluginsmanager_update_success_restart"), - plugin.Name)); - Context.API.RestartApp(); - } - else - { - Context.API.ShowMsg( - Context.API.GetTranslation("plugin_pluginsmanager_update_title"), - string.Format( - Context.API.GetTranslation( - "plugin_pluginsmanager_update_success_no_restart"), - plugin.Name)); - } - - return true; - - }, - ContextData = - new UserPlugin - { - Website = plugin.Website, - UrlSourceCode = plugin.UrlSourceCode - } - }}; - } + var updateSource = !updateFromLocalPath + ? PluginsManifest.UserPlugins + : new List { pluginFromLocalPath }; var resultsForUpdate = ( from existingPlugin in Context.API.GetAllPlugins() - join pluginFromManifest in PluginsManifest.UserPlugins - on existingPlugin.Metadata.ID equals pluginFromManifest.ID - where String.Compare(existingPlugin.Metadata.Version, pluginFromManifest.Version, + join pluginUpdateSource in updateSource + on existingPlugin.Metadata.ID equals pluginUpdateSource.ID + where string.Compare(existingPlugin.Metadata.Version, pluginUpdateSource.Version, StringComparison.InvariantCulture) < - 0 // if current version precedes manifest version + 0 // if current version precedes version of the plugin from update source (e.g. PluginsManifest) && !PluginManager.PluginModified(existingPlugin.Metadata.ID) select new { - pluginFromManifest.Name, - pluginFromManifest.Author, + pluginUpdateSource.Name, + pluginUpdateSource.Author, CurrentVersion = existingPlugin.Metadata.Version, - NewVersion = pluginFromManifest.Version, + NewVersion = pluginUpdateSource.Version, existingPlugin.Metadata.IcoPath, PluginExistingMetadata = existingPlugin.Metadata, - PluginNewUserPlugin = pluginFromManifest + PluginNewUserPlugin = pluginUpdateSource }).ToList(); if (!resultsForUpdate.Any()) @@ -381,13 +277,21 @@ namespace Flow.Launcher.Plugin.PluginsManager _ = Task.Run(async delegate { - if (File.Exists(downloadToFilePath)) + if (!x.PluginNewUserPlugin.IsFromLocalInstallPath) { - File.Delete(downloadToFilePath); - } + if (File.Exists(downloadToFilePath)) + { + File.Delete(downloadToFilePath); + } - await Http.DownloadAsync(x.PluginNewUserPlugin.UrlDownload, downloadToFilePath) - .ConfigureAwait(false); + await Http.DownloadAsync(x.PluginNewUserPlugin.UrlDownload, downloadToFilePath) + .ConfigureAwait(false); + } + else + { + downloadToFilePath = x.PluginNewUserPlugin.LocalInstallPath; + } + PluginManager.UpdatePlugin(x.PluginExistingMetadata, x.PluginNewUserPlugin, downloadToFilePath); @@ -516,7 +420,7 @@ namespace Flow.Launcher.Plugin.PluginsManager results = results.Prepend(updateAllResult); } - return Search(results, search); + return !updateFromLocalPath ? Search(results, search) : results.ToList(); } internal bool PluginExists(string id) @@ -590,52 +494,40 @@ namespace Flow.Launcher.Plugin.PluginsManager return new List { result }; } - internal List InstallFromLocal(string path) + internal List InstallFromLocalPath(string localPath) { - if (string.IsNullOrEmpty(path) || !File.Exists(path)) + var plugin = Utilities.GetPluginInfoFromZip(localPath); + + plugin.LocalInstallPath = localPath; + + return new List { - return new List(); - } - - var plugin = null as UserPlugin; - - using (ZipArchive archive = ZipFile.OpenRead(path)) - { - var pluginJsonPath = archive.Entries.FirstOrDefault(x => x.Name == "plugin.json").ToString(); - ZipArchiveEntry pluginJsonEntry = archive.GetEntry(pluginJsonPath); - - if (pluginJsonEntry != null) + new Result { - using (StreamReader reader = new StreamReader(pluginJsonEntry.Open())) + Title = $"{plugin.Name} by {plugin.Author}", + SubTitle = plugin.Description, + IcoPath = plugin.IcoPath, + Action = e => { - string pluginJsonContent = reader.ReadToEnd(); - plugin = JsonConvert.DeserializeObject(pluginJsonContent); - plugin.IcoPath = "Images\\zipfolder.png"; + if (Settings.WarnFromUnknownSource) + { + if (!InstallSourceKnown(plugin.Website) + && MessageBox.Show(string.Format( + Context.API.GetTranslation("plugin_pluginsmanager_install_unknown_source_warning"), + Environment.NewLine), + Context.API.GetTranslation( + "plugin_pluginsmanager_install_unknown_source_warning_title"), + MessageBoxButton.YesNo) == MessageBoxResult.No) + return false; + } + + Application.Current.MainWindow.Hide(); + _ = InstallOrUpdateAsync(plugin); + + return ShouldHideWindow; } } - } - - if (plugin == null) - { - return new List(); - } - - plugin.UrlDownload = path; - - var result = new Result - { - Title = plugin.Name, - SubTitle = plugin.UrlDownload, - IcoPath = plugin.IcoPath, - Action = e => - { - Application.Current.MainWindow.Hide(); - _ = InstallOrUpdateAsync(plugin); - - return ShouldHideWindow; - } }; - return new List { result }; } private bool InstallSourceKnown(string url) @@ -657,8 +549,8 @@ namespace Flow.Launcher.Plugin.PluginsManager && search.Split('.').Last() == zip) return InstallFromWeb(search); - if (File.Exists(search) && search.Split('.').Last() == zip) - return InstallFromLocal(search); + if (FilesFolders.IsZipFilePath(search, checkFileExists: true)) + return InstallFromLocalPath(search); var results = PluginsManifest @@ -693,14 +585,13 @@ namespace Flow.Launcher.Plugin.PluginsManager if (!File.Exists(downloadedFilePath)) throw new FileNotFoundException($"Plugin {plugin.ID} zip file not found at {downloadedFilePath}", downloadedFilePath); + try { PluginManager.InstallPlugin(plugin, downloadedFilePath); - if (downloadedFilePath.StartsWith(Path.GetTempPath())) - { + + if (!plugin.IsFromLocalInstallPath) File.Delete(downloadedFilePath); - } - } catch (FileNotFoundException e) { diff --git a/Plugins/Flow.Launcher.Plugin.PluginsManager/Utilities.cs b/Plugins/Flow.Launcher.Plugin.PluginsManager/Utilities.cs index 792891ad1..9800fa020 100644 --- a/Plugins/Flow.Launcher.Plugin.PluginsManager/Utilities.cs +++ b/Plugins/Flow.Launcher.Plugin.PluginsManager/Utilities.cs @@ -1,5 +1,10 @@ -using ICSharpCode.SharpZipLib.Zip; +using Flow.Launcher.Core.ExternalPlugins; +using Flow.Launcher.Infrastructure.UserSettings; +using ICSharpCode.SharpZipLib.Zip; +using Newtonsoft.Json; using System.IO; +using System.IO.Compression; +using System.Linq; namespace Flow.Launcher.Plugin.PluginsManager { @@ -55,5 +60,28 @@ namespace Flow.Launcher.Plugin.PluginsManager return string.Empty; } + + internal static UserPlugin GetPluginInfoFromZip(string filePath) + { + var plugin = null as UserPlugin; + + using (ZipArchive archive = System.IO.Compression.ZipFile.OpenRead(filePath)) + { + var pluginJsonPath = archive.Entries.FirstOrDefault(x => x.Name == "plugin.json").ToString(); + ZipArchiveEntry pluginJsonEntry = archive.GetEntry(pluginJsonPath); + + if (pluginJsonEntry != null) + { + using (StreamReader reader = new StreamReader(pluginJsonEntry.Open())) + { + string pluginJsonContent = reader.ReadToEnd(); + plugin = JsonConvert.DeserializeObject(pluginJsonContent); + plugin.IcoPath = "Images\\zipfolder.png"; + } + } + } + + return plugin; + } } } From 986ec3691e4eb56270208fe7c5d72f6ac6ab692f Mon Sep 17 00:00:00 2001 From: Jeremy Date: Thu, 16 May 2024 21:24:20 +1000 Subject: [PATCH 09/14] fix typo --- Flow.Launcher.Test/Plugins/ExplorerTest.cs | 24 +++++++++++----------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/Flow.Launcher.Test/Plugins/ExplorerTest.cs b/Flow.Launcher.Test/Plugins/ExplorerTest.cs index caa884b51..80cb74729 100644 --- a/Flow.Launcher.Test/Plugins/ExplorerTest.cs +++ b/Flow.Launcher.Test/Plugins/ExplorerTest.cs @@ -186,18 +186,18 @@ namespace Flow.Launcher.Test.Plugins $"Actual result was: {result}{Environment.NewLine}"); } - //[TestCase(@"c:\\", false)] - //[TestCase(@"i:\", true)] - //[TestCase(@"\c:\", false)] - //[TestCase(@"cc:\", false)] - //[TestCase(@"\\\SomeNetworkLocation\", false)] - //[TestCase(@"\\SomeNetworkLocation\", true)] - //[TestCase("RandomFile", false)] - //[TestCase(@"c:\>*", true)] - //[TestCase(@"c:\>", true)] - //[TestCase(@"c:\SomeLocation\SomeOtherLocation\>", true)] - //[TestCase(@"c:\SomeLocation\SomeOtherLocation", true)] - //[TestCase(@"c:\SomeLocation\SomeOtherLocation\SomeFile.exe", true)] + [TestCase(@"c:\\", false)] + [TestCase(@"i:\", true)] + [TestCase(@"\c:\", false)] + [TestCase(@"cc:\", false)] + [TestCase(@"\\\SomeNetworkLocation\", false)] + [TestCase(@"\\SomeNetworkLocation\", true)] + [TestCase("RandomFile", false)] + [TestCase(@"c:\>*", true)] + [TestCase(@"c:\>", true)] + [TestCase(@"c:\SomeLocation\SomeOtherLocation\>", true)] + [TestCase(@"c:\SomeLocation\SomeOtherLocation", true)] + [TestCase(@"c:\SomeLocation\SomeOtherLocation\SomeFile.exe", true)] [TestCase(@"\\SomeNetworkLocation\SomeFile.exe", true)] public void WhenGivenQuerySearchString_ThenShouldIndicateIfIsLocationPathString(string querySearchString, bool expectedResult) From dcc48406b5996ac892aad33b4c0c828236e84882 Mon Sep 17 00:00:00 2001 From: VictoriousRaptor <10308169+VictoriousRaptor@users.noreply.github.com> Date: Sun, 19 May 2024 22:47:14 +0800 Subject: [PATCH 10/14] Extract fixed hotkeys --- .../UserSettings/Settings.cs | 77 ++++++++++--------- 1 file changed, 42 insertions(+), 35 deletions(-) diff --git a/Flow.Launcher.Infrastructure/UserSettings/Settings.cs b/Flow.Launcher.Infrastructure/UserSettings/Settings.cs index 3d4433493..61a9da400 100644 --- a/Flow.Launcher.Infrastructure/UserSettings/Settings.cs +++ b/Flow.Launcher.Infrastructure/UserSettings/Settings.cs @@ -282,42 +282,9 @@ namespace Flow.Launcher.Infrastructure.UserSettings { get { - var list = new List - { - new("Up", "HotkeyLeftRightDesc"), - new("Down", "HotkeyLeftRightDesc"), - new("Left", "HotkeyUpDownDesc"), - new("Right", "HotkeyUpDownDesc"), - new("Escape", "HotkeyESCDesc"), - new("F5", "ReloadPluginHotkey"), - new("Alt+Home", "HotkeySelectFirstResult"), - new("Alt+End", "HotkeySelectLastResult"), - new("Ctrl+R", "HotkeyRequery"), - new("Ctrl+H", "ToggleHistoryHotkey"), - new("Ctrl+OemCloseBrackets", "QuickWidthHotkey"), - new("Ctrl+OemOpenBrackets", "QuickWidthHotkey"), - new("Ctrl+OemPlus", "QuickHeightHotkey"), - new("Ctrl+OemMinus", "QuickHeightHotkey"), - new("Ctrl+Shift+Enter", "HotkeyCtrlShiftEnterDesc"), - new("Shift+Enter", "OpenContextMenuHotkey"), - new("Enter", "HotkeyRunDesc"), - new("Ctrl+Enter", "OpenContainFolderHotkey"), - new("Alt+Enter", "HotkeyOpenResult"), - new("Ctrl+F12", "ToggleGameModeHotkey"), - new("Ctrl+Shift+C", "CopyFilePathHotkey"), - - new($"{OpenResultModifiers}+D1", "HotkeyOpenResultN", 1), - new($"{OpenResultModifiers}+D2", "HotkeyOpenResultN", 2), - new($"{OpenResultModifiers}+D3", "HotkeyOpenResultN", 3), - new($"{OpenResultModifiers}+D4", "HotkeyOpenResultN", 4), - new($"{OpenResultModifiers}+D5", "HotkeyOpenResultN", 5), - new($"{OpenResultModifiers}+D6", "HotkeyOpenResultN", 6), - new($"{OpenResultModifiers}+D7", "HotkeyOpenResultN", 7), - new($"{OpenResultModifiers}+D8", "HotkeyOpenResultN", 8), - new($"{OpenResultModifiers}+D9", "HotkeyOpenResultN", 9), - new($"{OpenResultModifiers}+D0", "HotkeyOpenResultN", 10) - }; + var list = FixedHotkeys(); + // Customizeable hotkeys if(!string.IsNullOrEmpty(Hotkey)) list.Add(new(Hotkey, "flowlauncherHotkey", () => Hotkey = "")); if(!string.IsNullOrEmpty(PreviewHotkey)) @@ -347,6 +314,7 @@ namespace Flow.Launcher.Infrastructure.UserSettings if (!string.IsNullOrEmpty(CycleHistoryDownHotkey)) list.Add(new(CycleHistoryDownHotkey, "CycleHistoryDownHotkey", () => CycleHistoryDownHotkey = "")); + // Custom Query Hotkeys foreach (var customPluginHotkey in CustomPluginHotkeys) { if (!string.IsNullOrEmpty(customPluginHotkey.Hotkey)) @@ -356,6 +324,45 @@ namespace Flow.Launcher.Infrastructure.UserSettings return list; } } + + private List FixedHotkeys() + { + return new List + { + new("Up", "HotkeyLeftRightDesc"), + new("Down", "HotkeyLeftRightDesc"), + new("Left", "HotkeyUpDownDesc"), + new("Right", "HotkeyUpDownDesc"), + new("Escape", "HotkeyESCDesc"), + new("F5", "ReloadPluginHotkey"), + new("Alt+Home", "HotkeySelectFirstResult"), + new("Alt+End", "HotkeySelectLastResult"), + new("Ctrl+R", "HotkeyRequery"), + new("Ctrl+H", "ToggleHistoryHotkey"), + new("Ctrl+OemCloseBrackets", "QuickWidthHotkey"), + new("Ctrl+OemOpenBrackets", "QuickWidthHotkey"), + new("Ctrl+OemPlus", "QuickHeightHotkey"), + new("Ctrl+OemMinus", "QuickHeightHotkey"), + new("Ctrl+Shift+Enter", "HotkeyCtrlShiftEnterDesc"), + new("Shift+Enter", "OpenContextMenuHotkey"), + new("Enter", "HotkeyRunDesc"), + new("Ctrl+Enter", "OpenContainFolderHotkey"), + new("Alt+Enter", "HotkeyOpenResult"), + new("Ctrl+F12", "ToggleGameModeHotkey"), + new("Ctrl+Shift+C", "CopyFilePathHotkey"), + + new($"{OpenResultModifiers}+D1", "HotkeyOpenResultN", 1), + new($"{OpenResultModifiers}+D2", "HotkeyOpenResultN", 2), + new($"{OpenResultModifiers}+D3", "HotkeyOpenResultN", 3), + new($"{OpenResultModifiers}+D4", "HotkeyOpenResultN", 4), + new($"{OpenResultModifiers}+D5", "HotkeyOpenResultN", 5), + new($"{OpenResultModifiers}+D6", "HotkeyOpenResultN", 6), + new($"{OpenResultModifiers}+D7", "HotkeyOpenResultN", 7), + new($"{OpenResultModifiers}+D8", "HotkeyOpenResultN", 8), + new($"{OpenResultModifiers}+D9", "HotkeyOpenResultN", 9), + new($"{OpenResultModifiers}+D0", "HotkeyOpenResultN", 10) + }; + } } public enum LastQueryMode From 7924dcca0d83e69cb70a402881cf1cc8110ce120 Mon Sep 17 00:00:00 2001 From: VictoriousRaptor <10308169+VictoriousRaptor@users.noreply.github.com> Date: Sun, 19 May 2024 23:16:56 +0800 Subject: [PATCH 11/14] Rename to camel case --- Flow.Launcher/ViewModel/MainViewModel.cs | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/Flow.Launcher/ViewModel/MainViewModel.cs b/Flow.Launcher/ViewModel/MainViewModel.cs index 2e52f92c1..a134dbfa5 100644 --- a/Flow.Launcher/ViewModel/MainViewModel.cs +++ b/Flow.Launcher/ViewModel/MainViewModel.cs @@ -42,7 +42,7 @@ namespace Flow.Launcher.ViewModel private readonly FlowLauncherJsonStorage _userSelectedRecordStorage; private readonly FlowLauncherJsonStorage _topMostRecordStorage; private readonly History _history; - private int lasthistoryindex = 1; + private int lastHistoryIndex = 1; private readonly UserSelectedRecord _userSelectedRecord; private readonly TopMostRecord _topMostRecord; @@ -268,10 +268,10 @@ namespace Flow.Launcher.ViewModel { if (_history.Items.Count > 0) { - ChangeQueryText(_history.Items[_history.Items.Count - lasthistoryindex].Query.ToString()); - if (lasthistoryindex < _history.Items.Count) + ChangeQueryText(_history.Items[_history.Items.Count - lastHistoryIndex].Query.ToString()); + if (lastHistoryIndex < _history.Items.Count) { - lasthistoryindex++; + lastHistoryIndex++; } } } @@ -281,10 +281,10 @@ namespace Flow.Launcher.ViewModel { if (_history.Items.Count > 0) { - ChangeQueryText(_history.Items[_history.Items.Count - lasthistoryindex].Query.ToString()); - if (lasthistoryindex > 1) + ChangeQueryText(_history.Items[_history.Items.Count - lastHistoryIndex].Query.ToString()); + if (lastHistoryIndex > 1) { - lasthistoryindex--; + lastHistoryIndex--; } } } @@ -379,6 +379,7 @@ namespace Flow.Launcher.ViewModel { _userSelectedRecord.Add(result); _history.Add(result.OriginQuery.RawQuery); + } if (hideWindow) @@ -427,13 +428,12 @@ namespace Flow.Launcher.ViewModel [RelayCommand] private void SelectPrevItem() { - var results = SelectedResults; if (_history.Items.Count > 0 && _queryText == String.Empty && !HistorySelected() && !ContextMenuSelected()) { - lasthistoryindex = 1; + lastHistoryIndex = 1; ReverseHistory(); } else @@ -1164,7 +1164,7 @@ namespace Flow.Launcher.ViewModel public async void Hide() { - lasthistoryindex = 1; + lastHistoryIndex = 1; // Trick for no delay MainWindowOpacity = 0; lastContextMenuResult = new Result(); From 9ac92e293980ab1936eabba44f50c564e801fca3 Mon Sep 17 00:00:00 2001 From: VictoriousRaptor <10308169+VictoriousRaptor@users.noreply.github.com> Date: Sun, 19 May 2024 23:17:57 +0800 Subject: [PATCH 12/14] Reset lastHistoryIndex when opening result --- Flow.Launcher/ViewModel/MainViewModel.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Flow.Launcher/ViewModel/MainViewModel.cs b/Flow.Launcher/ViewModel/MainViewModel.cs index a134dbfa5..fbd35ed5b 100644 --- a/Flow.Launcher/ViewModel/MainViewModel.cs +++ b/Flow.Launcher/ViewModel/MainViewModel.cs @@ -379,7 +379,7 @@ namespace Flow.Launcher.ViewModel { _userSelectedRecord.Add(result); _history.Add(result.OriginQuery.RawQuery); - + lastHistoryIndex = 1; } if (hideWindow) From 3d6d79b6e4695959d428b328bea9a9dd2e164600 Mon Sep 17 00:00:00 2001 From: VictoriousRaptor <10308169+VictoriousRaptor@users.noreply.github.com> Date: Sun, 19 May 2024 23:27:24 +0800 Subject: [PATCH 13/14] Simplify conditions --- Flow.Launcher/ViewModel/MainViewModel.cs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/Flow.Launcher/ViewModel/MainViewModel.cs b/Flow.Launcher/ViewModel/MainViewModel.cs index fbd35ed5b..01dc67b98 100644 --- a/Flow.Launcher/ViewModel/MainViewModel.cs +++ b/Flow.Launcher/ViewModel/MainViewModel.cs @@ -429,9 +429,8 @@ namespace Flow.Launcher.ViewModel private void SelectPrevItem() { if (_history.Items.Count > 0 - && _queryText == String.Empty - && !HistorySelected() - && !ContextMenuSelected()) + && QueryText == string.Empty + && SelectedIsFromQueryResults()) { lastHistoryIndex = 1; ReverseHistory(); From e7abdcef1adec08d9b87e76d6f670497775cd777 Mon Sep 17 00:00:00 2001 From: DB p Date: Mon, 20 May 2024 17:46:01 +0900 Subject: [PATCH 14/14] Fix Logic --- Flow.Launcher/SettingWindow.xaml.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Flow.Launcher/SettingWindow.xaml.cs b/Flow.Launcher/SettingWindow.xaml.cs index bad15d2c9..1a75a853b 100644 --- a/Flow.Launcher/SettingWindow.xaml.cs +++ b/Flow.Launcher/SettingWindow.xaml.cs @@ -448,13 +448,13 @@ namespace Flow.Launcher { if (settings.SettingWindowTop == null) { - Top = settings.SettingWindowTop; - Left = settings.SettingWindowLeft; + Top = WindowTop(); + Left = WindowLeft(); } else { - Top = WindowTop(); - Left = WindowLeft(); + Top = settings.SettingWindowTop; + Left = settings.SettingWindowLeft; } WindowState = settings.SettingWindowState; }