diff --git a/Flow.Launcher.Infrastructure/UserSettings/Settings.cs b/Flow.Launcher.Infrastructure/UserSettings/Settings.cs index cd74178df..2dbdf0bf8 100644 --- a/Flow.Launcher.Infrastructure/UserSettings/Settings.cs +++ b/Flow.Launcher.Infrastructure/UserSettings/Settings.cs @@ -58,7 +58,6 @@ namespace Flow.Launcher.Infrastructure.UserSettings public string OpenHistoryHotkey { get; set; } = $"Ctrl+H"; public string CycleHistoryUpHotkey { get; set; } = $"{KeyConstant.Alt} + Up"; public string CycleHistoryDownHotkey { get; set; } = $"{KeyConstant.Alt} + Down"; - public string RenameFileHotkey { get; set; } = $"F2"; private string _language = Constant.SystemLanguageCode; public string Language @@ -473,14 +472,13 @@ namespace Flow.Launcher.Infrastructure.UserSettings list.Add(new(CycleHistoryUpHotkey, "CycleHistoryUpHotkey", () => CycleHistoryUpHotkey = "")); if (!string.IsNullOrEmpty(CycleHistoryDownHotkey)) list.Add(new(CycleHistoryDownHotkey, "CycleHistoryDownHotkey", () => CycleHistoryDownHotkey = "")); - if (!string.IsNullOrEmpty(RenameFileHotkey)) - list.Add(new RegisteredHotkeyData(RenameFileHotkey, "RenameFileHotkey", () => RenameFileHotkey = "")); + // Custom Query Hotkeys - foreach (var customPluginHotkey in CustomPluginHotkeys) - { - if (!string.IsNullOrEmpty(customPluginHotkey.Hotkey)) - list.Add(new(customPluginHotkey.Hotkey, "customQueryHotkey", () => customPluginHotkey.Hotkey = "")); - } + foreach (var customPluginHotkey in CustomPluginHotkeys) + { + if (!string.IsNullOrEmpty(customPluginHotkey.Hotkey)) + list.Add(new(customPluginHotkey.Hotkey, "customQueryHotkey", () => customPluginHotkey.Hotkey = "")); + } return list; } diff --git a/Flow.Launcher/HotkeyControl.xaml.cs b/Flow.Launcher/HotkeyControl.xaml.cs index 073880343..33316938c 100644 --- a/Flow.Launcher/HotkeyControl.xaml.cs +++ b/Flow.Launcher/HotkeyControl.xaml.cs @@ -111,9 +111,7 @@ namespace Flow.Launcher SelectPrevItemHotkey, SelectPrevItemHotkey2, SelectNextItemHotkey, - SelectNextItemHotkey2, - RenameFileHotkey - + SelectNextItemHotkey2 } // We can initialize settings in static field because it has been constructed in App constuctor @@ -145,8 +143,6 @@ namespace Flow.Launcher HotkeyType.SelectPrevItemHotkey2 => _settings.SelectPrevItemHotkey2, HotkeyType.SelectNextItemHotkey => _settings.SelectNextItemHotkey, HotkeyType.SelectNextItemHotkey2 => _settings.SelectNextItemHotkey2, - HotkeyType.RenameFileHotkey => _settings.RenameFileHotkey, - _ => throw new System.NotImplementedException("Hotkey type not set") }; } @@ -206,9 +202,6 @@ namespace Flow.Launcher case HotkeyType.SelectNextItemHotkey2: _settings.SelectNextItemHotkey2 = value; break; - case HotkeyType.RenameFileHotkey: - _settings.RenameFileHotkey = value; - break; default: throw new System.NotImplementedException("Hotkey type not set"); } @@ -239,7 +232,7 @@ namespace Flow.Launcher public string EmptyHotkey => App.API.GetTranslation("none"); - public ObservableCollection KeysToDisplay { get; set; } = new ObservableCollection(); + public ObservableCollection KeysToDisplay { get; set; } = new(); public HotkeyModel CurrentHotkey { get; private set; } = new(false, false, false, false, Key.None); @@ -316,7 +309,6 @@ namespace Flow.Launcher private void SetKeysToDisplay(HotkeyModel? hotkey) { - KeysToDisplay.Clear(); if (hotkey == null || hotkey == default(HotkeyModel)) @@ -330,8 +322,6 @@ namespace Flow.Launcher KeysToDisplay.Add(key); } - - } public void SetHotkey(string? keyStr, bool triggerValidate = true) diff --git a/Flow.Launcher/Languages/en.xaml b/Flow.Launcher/Languages/en.xaml index 365215307..55bbed7e0 100644 --- a/Flow.Launcher/Languages/en.xaml +++ b/Flow.Launcher/Languages/en.xaml @@ -557,9 +557,4 @@ File Size Created Last Modified - - - Rename a file/directory - Are you trying to rename a file? - The explorer plugin needs to be enabled for the hotkey to rename files to work. diff --git a/Flow.Launcher/MainWindow.xaml b/Flow.Launcher/MainWindow.xaml index 8ea2351de..9ff38a564 100644 --- a/Flow.Launcher/MainWindow.xaml +++ b/Flow.Launcher/MainWindow.xaml @@ -211,10 +211,6 @@ Key="{Binding CycleHistoryDownHotkey, Converter={StaticResource StringToKeyBindingConverter}, ConverterParameter='key'}" Command="{Binding ForwardHistoryCommand}" Modifiers="{Binding CycleHistoryDownHotkey, Converter={StaticResource StringToKeyBindingConverter}, ConverterParameter='modifiers'}" /> - diff --git a/Flow.Launcher/PublicAPIInstance.cs b/Flow.Launcher/PublicAPIInstance.cs index 875a54f80..6e82032ff 100644 --- a/Flow.Launcher/PublicAPIInstance.cs +++ b/Flow.Launcher/PublicAPIInstance.cs @@ -222,7 +222,7 @@ namespace Flow.Launcher } } } - + private static async Task RetryActionOnSTAThreadAsync(Action action, int retryCount = 6, int retryDelay = 150) { for (var i = 0; i < retryCount; i++) diff --git a/Flow.Launcher/SettingPages/Views/SettingsPaneHotkey.xaml b/Flow.Launcher/SettingPages/Views/SettingsPaneHotkey.xaml index c145d16a1..fd3d415cc 100644 --- a/Flow.Launcher/SettingPages/Views/SettingsPaneHotkey.xaml +++ b/Flow.Launcher/SettingPages/Views/SettingsPaneHotkey.xaml @@ -204,15 +204,6 @@ - - - diff --git a/Flow.Launcher/ViewModel/MainViewModel.cs b/Flow.Launcher/ViewModel/MainViewModel.cs index ff596352a..64a39fa62 100644 --- a/Flow.Launcher/ViewModel/MainViewModel.cs +++ b/Flow.Launcher/ViewModel/MainViewModel.cs @@ -2,7 +2,6 @@ using System.Collections.Generic; using System.ComponentModel; using System.Globalization; -using System.IO; using System.Linq; using System.Text; using System.Threading; @@ -24,7 +23,6 @@ using Flow.Launcher.Plugin.SharedCommands; using Flow.Launcher.Storage; using Microsoft.VisualStudio.Threading; - namespace Flow.Launcher.ViewModel { public partial class MainViewModel : BaseModel, ISavable, IDisposable @@ -62,8 +60,6 @@ namespace Flow.Launcher.ViewModel #endregion - - #region Constructor public MainViewModel() @@ -144,9 +140,6 @@ namespace Flow.Launcher.ViewModel case nameof(Settings.OpenHistoryHotkey): OnPropertyChanged(nameof(OpenHistoryHotkey)); break; - case nameof(Settings.RenameFileHotkey): - OnPropertyChanged(nameof(RenameFileHotkey)); - break; } }; @@ -603,7 +596,6 @@ namespace Flow.Launcher.ViewModel #endregion #region ViewModel Properties - public Settings Settings { get; } public string ClockText { get; private set; } @@ -921,76 +913,9 @@ namespace Flow.Launcher.ViewModel public string OpenHistoryHotkey => VerifyOrSetDefaultHotkey(Settings.OpenHistoryHotkey, "Ctrl+H"); public string CycleHistoryUpHotkey => VerifyOrSetDefaultHotkey(Settings.CycleHistoryUpHotkey, "Alt+Up"); public string CycleHistoryDownHotkey => VerifyOrSetDefaultHotkey(Settings.CycleHistoryDownHotkey, "Alt+Down"); - public string RenameFileHotkey => VerifyOrSetDefaultHotkey(Settings.RenameFileHotkey, "F2"); - public bool StartWithEnglishMode => Settings.AlwaysStartEn; - #region renamingFiles - private int timesTriedToRenameFileWithExplorerDisabled = 0; - - [RelayCommand] - private void RenameFile() - { - // at runtime this is an instance the Flow.Launcher.Plugin.Explorer.Main - var explorerPlugin = GetExplorerPlugin(); - - if (!(explorerPlugin != null)) - { - timesTriedToRenameFileWithExplorerDisabled++; - if (timesTriedToRenameFileWithExplorerDisabled > 3) - { - App.API.ShowMsg(App.API.GetTranslation("AreTryingToRenameFile"), App.API.GetTranslation("ExplorerNeedsEnabledForRenameFile")); - timesTriedToRenameFileWithExplorerDisabled = 0; - } - return; - - } - else - { - string path = SelectedResults?.SelectedItem?.Result.SubTitle ?? ""; - string name = SelectedResults?.SelectedItem?.Result.Title ?? ""; - if (string.IsNullOrWhiteSpace(path) || string.IsNullOrWhiteSpace(name)) return; - ShowRenamingDialog(explorerPlugin, path, name); - } - } - /// - /// Get an instance of the explorer plugin if it's loaded - /// - /// Returns an instance of Flow.Launcher.Plugin.Explorer.Main, if it's not loaded this returns null. - private IAsyncPlugin GetExplorerPlugin() - { - const string explorerPluginID = "572be03c74c642baae319fc283e561a8"; - IEnumerable explorerPluginMatches = App.API.GetAllPlugins().Where( - plugin => plugin.Metadata.ID == explorerPluginID && plugin.Metadata.Disabled != true) ; - if (explorerPluginMatches.Any()) - { - // assuming it's the first plugin as no 2 plugins can be loaded with the same ID - return explorerPluginMatches.First().Plugin; - } - return null; - } - /// - /// Shows the dialog to rename a file system element. - /// - /// An instance of the Flow.Launcher.Plugin.Explorer.Main, which is invisible in the current namespace - /// The path of the element - /// The new name - private void ShowRenamingDialog(dynamic explorerPlugin, string path, string name) - { - if (File.Exists(Path.Join(path, name))) - { - explorerPlugin.RenameDialog(new FileInfo(Path.Join(path, name)), App.API); - return; - } - if (Directory.Exists(path)) - { - explorerPlugin.RenameDialog(new DirectoryInfo(path), App.API); - return; - } - } - #endregion - #endregion #region Preview @@ -1086,7 +1011,6 @@ namespace Flow.Launcher.ViewModel _ = ShowPreviewAsync(); } } - private async Task OpenExternalPreviewAsync(string path, bool sendFailToast = true) { diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Languages/en.xaml b/Plugins/Flow.Launcher.Plugin.Explorer/Languages/en.xaml index 95b250797..64ced20a9 100644 --- a/Plugins/Flow.Launcher.Plugin.Explorer/Languages/en.xaml +++ b/Plugins/Flow.Launcher.Plugin.Explorer/Languages/en.xaml @@ -130,6 +130,7 @@ Show Windows Context Menu Open With Select a program to open with + Run As Administrator {0} free of {1} diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Main.cs b/Plugins/Flow.Launcher.Plugin.Explorer/Main.cs index afd42c8d7..6f230edab 100644 --- a/Plugins/Flow.Launcher.Plugin.Explorer/Main.cs +++ b/Plugins/Flow.Launcher.Plugin.Explorer/Main.cs @@ -1,24 +1,26 @@ -using Flow.Launcher.Plugin.Explorer.Helper; -using Flow.Launcher.Plugin.Explorer.Search; -using Flow.Launcher.Plugin.Explorer.Search.Everything; -using Flow.Launcher.Plugin.Explorer.ViewModels; -using Flow.Launcher.Plugin.Explorer.Views; -using System; +using System; using System.Collections.Generic; using System.IO; using System.Threading; using System.Threading.Tasks; using System.Windows.Controls; using Flow.Launcher.Plugin.Explorer.Exceptions; +using Flow.Launcher.Plugin.Explorer.Helper; +using Flow.Launcher.Plugin.Explorer.Search; +using Flow.Launcher.Plugin.Explorer.Search.Everything; +using Flow.Launcher.Plugin.Explorer.ViewModels; +using Flow.Launcher.Plugin.Explorer.Views; namespace Flow.Launcher.Plugin.Explorer { - public class Main : ISettingProvider, IAsyncPlugin, IContextMenu, IPluginI18n + public class Main : ISettingProvider, IAsyncPlugin, IContextMenu, IPluginI18n, IPluginHotkey { internal static PluginInitContext Context { get; set; } internal Settings Settings; + private static readonly string ClassName = nameof(Main); + private SettingsViewModel viewModel; private IContextMenu contextMenu; @@ -56,10 +58,8 @@ namespace Flow.Launcher.Plugin.Explorer return contextMenu.LoadContextMenus(selectedResult); } - public async Task> QueryAsync(Query query, CancellationToken token) { - try { return await searchManager.SearchAsync(query, token); @@ -99,21 +99,7 @@ namespace Flow.Launcher.Plugin.Explorer { return Context.API.GetTranslation("plugin_explorer_plugin_description"); } - public void RenameDialog(FileSystemInfo info, IPublicAPI api) - { - if (info == null) throw new ArgumentNullException(nameof(info)); - if (api == null) throw new ArgumentNullException(nameof(api)); - try - { - new RenameFile(api, info).ShowDialog(); - } - catch (Exception ex) - { - api.ShowMsgError(api.GetTranslation("errorTitle"), api.GetTranslation("plugin_explorer_failed_to_open_rename_dialog")); - api.LogException(nameof(Main), $"Failed to open rename dialog: {ex.Message}", ex, nameof(RenameDialog)); - } - } private void FillQuickAccessLinkNames() { // Legacy version does not have names for quick access links, so we fill them with the path name. @@ -125,6 +111,144 @@ namespace Flow.Launcher.Plugin.Explorer } } } - + + public List GetPuginHotkeys() + { + return new List + { + new SearchWindowPluginHotkey() + { + Id = 0, + Name = Context.API.GetTranslation("plugin_explorer_opencontainingfolder"), + Description = Context.API.GetTranslation("plugin_explorer_opencontainingfolder_subtitle"), + Glyph = new GlyphInfo(FontFamily: "/Resources/#Segoe Fluent Icons", Glyph: "\ue838"), + DefaultHotkey = "Ctrl+Enter", + Editable = false, + Action = (r) => + { + if (r.ContextData is SearchResult record) + { + if (record.Type is ResultType.File) + { + ResultManager.OpenFolder(record.FullPath, record.FullPath); + } + else + { + try + { + Context.API.OpenDirectory(Path.GetDirectoryName(record.FullPath), record.FullPath); + } + catch (Exception e) + { + var message = $"Fail to open file at {record.FullPath}"; + Context.API.LogException(ClassName, message, e); + Context.API.ShowMsgBox(e.Message, Context.API.GetTranslation("plugin_explorer_opendir_error")); + return false; + } + + return true; + } + } + + return false; + } + }, + new SearchWindowPluginHotkey() + { + Id = 1, + Name = Context.API.GetTranslation("plugin_explorer_show_contextmenu_title"), + Glyph = new GlyphInfo(FontFamily: "/Resources/#Segoe Fluent Icons", Glyph: "\ue700"), + DefaultHotkey = "Alt+Enter", + Editable = false, + Action = (r) => + { + if (r.ContextData is SearchResult record && record.Type is not ResultType.Volume) + { + try + { + ResultManager.ShowNativeContextMenu(record.FullPath, record.Type); + } + catch (Exception e) + { + var message = $"Fail to show context menu for {record.FullPath}"; + Context.API.LogException(ClassName, message, e); + } + } + + return false; + } + }, + new SearchWindowPluginHotkey() + { + Id = 2, + Name = Context.API.GetTranslation("plugin_explorer_run_as_administrator"), + Glyph = new GlyphInfo(FontFamily: "/Resources/#Segoe Fluent Icons", Glyph: "\uE7EF"), + DefaultHotkey = "Ctrl+Shift+Enter", + Editable = false, + Action = (r) => + { + if (r.ContextData is SearchResult record) + { + if (record.Type is ResultType.File) + { + var filePath = record.FullPath; + ResultManager.OpenFile(filePath, Settings.UseLocationAsWorkingDir ? Path.GetDirectoryName(filePath) : string.Empty, true); + } + else + { + try + { + ResultManager.OpenFolder(record.FullPath); + return true; + } + catch (Exception ex) + { + var message = $"Fail to open file at {record.FullPath}"; + Context.API.LogException(ClassName, message, ex); + Context.API.ShowMsgBox(ex.Message, Context.API.GetTranslation("plugin_explorer_opendir_error")); + return false; + } + } + return true; + } + + return false; + } + }, + new SearchWindowPluginHotkey() + { + Id = 3, + Name = Context.API.GetTranslation("plugin_explorer_rename_a_file"), + Description = Context.API.GetTranslation("plugin_explorer_rename_subtitle"), + Glyph = new GlyphInfo(FontFamily: "/Resources/#Segoe Fluent Icons", Glyph: "\ue8ac"), + DefaultHotkey = "F2", + Editable = true, + Action = (r) => + { + if (r.ContextData is SearchResult record) + { + RenameFile window; + switch (record.Type) + { + case ResultType.Folder: + window = new RenameFile(Context.API, new DirectoryInfo(record.FullPath)); + break; + case ResultType.File: + window = new RenameFile(Context.API, new FileInfo(record.FullPath)); + break; + default: + Context.API.ShowMsgError(Context.API.GetTranslation("plugin_explorer_cannot_rename")); + return false; + } + window.ShowDialog(); + + return false; + } + + return false; + } + } + }; + } } } diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Search/ResultManager.cs b/Plugins/Flow.Launcher.Plugin.Explorer/Search/ResultManager.cs index e87d2df97..83195a47f 100644 --- a/Plugins/Flow.Launcher.Plugin.Explorer/Search/ResultManager.cs +++ b/Plugins/Flow.Launcher.Plugin.Explorer/Search/ResultManager.cs @@ -108,40 +108,6 @@ namespace Flow.Launcher.Plugin.Explorer.Search PreviewPanel = new Lazy(() => new PreviewPanel(Settings, path, ResultType.Folder)), Action = c => { - if (c.SpecialKeyState.ToModifierKeys() == ModifierKeys.Alt) - { - ShowNativeContextMenu(path, ResultType.Folder); - return false; - } - // open folder - if (c.SpecialKeyState.ToModifierKeys() == (ModifierKeys.Control | ModifierKeys.Shift)) - { - try - { - OpenFolder(path); - return true; - } - catch (Exception ex) - { - Context.API.ShowMsgBox(ex.Message, Context.API.GetTranslation("plugin_explorer_opendir_error")); - return false; - } - } - // Open containing folder - if (c.SpecialKeyState.ToModifierKeys() == ModifierKeys.Control) - { - try - { - Context.API.OpenDirectory(Path.GetDirectoryName(path), path); - return true; - } - catch (Exception ex) - { - Context.API.ShowMsgBox(ex.Message, Context.API.GetTranslation("plugin_explorer_opendir_error")); - return false; - } - } - // If path search is disabled just open it in file manager if (Settings.DefaultOpenFolderInFileManager || (!Settings.PathSearchKeywordEnabled && !Settings.SearchActionKeywordEnabled)) { @@ -259,11 +225,6 @@ namespace Flow.Launcher.Plugin.Explorer.Search CopyText = folderPath, Action = c => { - if (c.SpecialKeyState.ToModifierKeys() == ModifierKeys.Alt) - { - ShowNativeContextMenu(folderPath, ResultType.Folder); - return false; - } OpenFolder(folderPath); return true; }, @@ -296,25 +257,9 @@ namespace Flow.Launcher.Plugin.Explorer.Search PreviewPanel = new Lazy(() => new PreviewPanel(Settings, filePath, ResultType.File)), Action = c => { - if (c.SpecialKeyState.ToModifierKeys() == ModifierKeys.Alt) - { - ShowNativeContextMenu(filePath, ResultType.File); - return false; - } try { - if (c.SpecialKeyState.ToModifierKeys() == (ModifierKeys.Control | ModifierKeys.Shift)) - { - OpenFile(filePath, Settings.UseLocationAsWorkingDir ? Path.GetDirectoryName(filePath) : string.Empty, true); - } - else if (c.SpecialKeyState.ToModifierKeys() == ModifierKeys.Control) - { - OpenFolder(filePath, filePath); - } - else - { - OpenFile(filePath, Settings.UseLocationAsWorkingDir ? Path.GetDirectoryName(filePath) : string.Empty); - } + OpenFile(filePath, Settings.UseLocationAsWorkingDir ? Path.GetDirectoryName(filePath) : string.Empty); } catch (Exception ex) { @@ -337,13 +282,13 @@ namespace Flow.Launcher.Plugin.Explorer.Search return MediaExtensions.Contains(extension.ToLowerInvariant()); } - private static void OpenFile(string filePath, string workingDir = "", bool asAdmin = false) + public static void OpenFile(string filePath, string workingDir = "", bool asAdmin = false) { IncrementEverythingRunCounterIfNeeded(filePath); FilesFolders.OpenFile(filePath, workingDir, asAdmin, (string str) => Context.API.ShowMsgBox(str)); } - private static void OpenFolder(string folderPath, string fileNameOrFilePath = null) + public static void OpenFolder(string folderPath, string fileNameOrFilePath = null) { IncrementEverythingRunCounterIfNeeded(folderPath); Context.API.OpenDirectory(folderPath, fileNameOrFilePath);