diff --git a/Flow.Launcher.Infrastructure/UserSettings/Settings.cs b/Flow.Launcher.Infrastructure/UserSettings/Settings.cs
index 2dbdf0bf8..cd74178df 100644
--- a/Flow.Launcher.Infrastructure/UserSettings/Settings.cs
+++ b/Flow.Launcher.Infrastructure/UserSettings/Settings.cs
@@ -58,6 +58,7 @@ 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
@@ -472,13 +473,14 @@ 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.Plugin/Interfaces/IPublicAPI.cs b/Flow.Launcher.Plugin/Interfaces/IPublicAPI.cs
index f47ee5e11..9905d156d 100644
--- a/Flow.Launcher.Plugin/Interfaces/IPublicAPI.cs
+++ b/Flow.Launcher.Plugin/Interfaces/IPublicAPI.cs
@@ -226,8 +226,25 @@ namespace Flow.Launcher.Plugin
/// Query string
/// The string that will be compared against the query
/// Match results
+
MatchResult FuzzySearch(string query, string stringToCompare);
+ ///
+ /// Returns if the given name is valid file name even if it doesn't exist
+ ///
+ /// the name to check
+ public bool IsValidFileName(string name);
+ ///
+ /// Returns if the given name is valid directory name even if it doesn't exist
+ ///
+ /// the name to check
+ public bool IsValidDirectoryName(string name);
+ ///
+ /// Open A dialog to rename the given file or folder
+ ///
+ /// The directory or file info for the thing to rename. You must check if it actually exists or this will throw an exception
+
+
///
/// Http download the spefic url and return as string
///
diff --git a/Flow.Launcher/HotkeyControl.xaml.cs b/Flow.Launcher/HotkeyControl.xaml.cs
index e8961058c..073880343 100644
--- a/Flow.Launcher/HotkeyControl.xaml.cs
+++ b/Flow.Launcher/HotkeyControl.xaml.cs
@@ -1,4 +1,5 @@
using System.Collections.ObjectModel;
+using System.IO;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Input;
@@ -110,7 +111,9 @@ namespace Flow.Launcher
SelectPrevItemHotkey,
SelectPrevItemHotkey2,
SelectNextItemHotkey,
- SelectNextItemHotkey2
+ SelectNextItemHotkey2,
+ RenameFileHotkey
+
}
// We can initialize settings in static field because it has been constructed in App constuctor
@@ -142,6 +145,8 @@ 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")
};
}
@@ -201,6 +206,9 @@ 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");
}
@@ -231,7 +239,7 @@ namespace Flow.Launcher
public string EmptyHotkey => App.API.GetTranslation("none");
- public ObservableCollection KeysToDisplay { get; set; } = new();
+ public ObservableCollection KeysToDisplay { get; set; } = new ObservableCollection();
public HotkeyModel CurrentHotkey { get; private set; } = new(false, false, false, false, Key.None);
@@ -308,6 +316,7 @@ namespace Flow.Launcher
private void SetKeysToDisplay(HotkeyModel? hotkey)
{
+
KeysToDisplay.Clear();
if (hotkey == null || hotkey == default(HotkeyModel))
@@ -318,8 +327,11 @@ namespace Flow.Launcher
foreach (var key in hotkey.Value.EnumerateDisplayKeys()!)
{
+
KeysToDisplay.Add(key);
}
+
+
}
public void SetHotkey(string? keyStr, bool triggerValidate = true)
diff --git a/Flow.Launcher/HotkeyControlDialog.xaml.cs b/Flow.Launcher/HotkeyControlDialog.xaml.cs
index c7af8c5b8..9d6c8a4c3 100644
--- a/Flow.Launcher/HotkeyControlDialog.xaml.cs
+++ b/Flow.Launcher/HotkeyControlDialog.xaml.cs
@@ -135,10 +135,12 @@ public partial class HotkeyControlDialog : ContentDialog
}
if (tbMsg == null)
+
return;
if (_hotkeySettings.RegisteredHotkeys.FirstOrDefault(v => v.Hotkey == hotkey) is { } registeredHotkeyData)
{
+
var description = string.Format(
App.API.GetTranslation(registeredHotkeyData.DescriptionResourceKey),
registeredHotkeyData.DescriptionFormatVariables
@@ -146,6 +148,7 @@ public partial class HotkeyControlDialog : ContentDialog
Alert.Visibility = Visibility.Visible;
if (registeredHotkeyData.RemoveHotkey is not null)
{
+
tbMsg.Text = string.Format(
App.API.GetTranslation("hotkeyUnavailableEditable"),
description
@@ -158,6 +161,7 @@ public partial class HotkeyControlDialog : ContentDialog
}
else
{
+
tbMsg.Text = string.Format(
App.API.GetTranslation("hotkeyUnavailableUneditable"),
description
@@ -175,6 +179,7 @@ public partial class HotkeyControlDialog : ContentDialog
if (!CheckHotkeyAvailability(hotkey.Value, true))
{
+
tbMsg.Text = App.API.GetTranslation("hotkeyUnavailable");
Alert.Visibility = Visibility.Visible;
SaveBtn.IsEnabled = false;
@@ -182,10 +187,12 @@ public partial class HotkeyControlDialog : ContentDialog
}
else
{
+
Alert.Visibility = Visibility.Collapsed;
SaveBtn.IsEnabled = true;
SaveBtn.Visibility = Visibility.Visible;
}
+
}
private static bool CheckHotkeyAvailability(HotkeyModel hotkey, bool validateKeyGesture)
diff --git a/Flow.Launcher/Languages/en.xaml b/Flow.Launcher/Languages/en.xaml
index bd4cbd282..29ab40076 100644
--- a/Flow.Launcher/Languages/en.xaml
+++ b/Flow.Launcher/Languages/en.xaml
@@ -555,4 +555,7 @@
File Size
Created
Last Modified
+
+
+ dcdc
diff --git a/Flow.Launcher/MainWindow.xaml b/Flow.Launcher/MainWindow.xaml
index 9ff38a564..8ea2351de 100644
--- a/Flow.Launcher/MainWindow.xaml
+++ b/Flow.Launcher/MainWindow.xaml
@@ -211,6 +211,10 @@
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 6e82032ff..382cfee0a 100644
--- a/Flow.Launcher/PublicAPIInstance.cs
+++ b/Flow.Launcher/PublicAPIInstance.cs
@@ -33,6 +33,7 @@ using Flow.Launcher.ViewModel;
using JetBrains.Annotations;
using Squirrel;
using Stopwatch = Flow.Launcher.Infrastructure.Stopwatch;
+using Windows.Foundation.Metadata;
namespace Flow.Launcher
{
@@ -222,7 +223,26 @@ namespace Flow.Launcher
}
}
}
-
+ public bool IsValidFileName(string name)
+ {
+ if (name.IndexOfAny(Path.GetInvalidFileNameChars()) >= 0 || name.Trim() == "")
+ {
+ return false;
+ }
+ return true;
+ }
+ public bool IsValidDirectoryName(string name)
+ {
+ List invalidChars = Path.GetInvalidPathChars().ToList();
+ invalidChars.Add('/');
+ invalidChars.Add('\\');
+ if (name.IndexOfAny(invalidChars.ToArray()) >= 0 || name.Trim() == "")
+ {
+ return false;
+ }
+ return true;
+ }
+
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 89eb2dccd..4fb15492f 100644
--- a/Flow.Launcher/SettingPages/Views/SettingsPaneHotkey.xaml
+++ b/Flow.Launcher/SettingPages/Views/SettingsPaneHotkey.xaml
@@ -204,6 +204,15 @@
+
+
+
diff --git a/Flow.Launcher/ViewModel/MainViewModel.cs b/Flow.Launcher/ViewModel/MainViewModel.cs
index 64a39fa62..6355b61a1 100644
--- a/Flow.Launcher/ViewModel/MainViewModel.cs
+++ b/Flow.Launcher/ViewModel/MainViewModel.cs
@@ -2,6 +2,7 @@
using System.Collections.Generic;
using System.ComponentModel;
using System.Globalization;
+using System.IO;
using System.Linq;
using System.Text;
using System.Threading;
@@ -22,6 +23,7 @@ using Flow.Launcher.Plugin;
using Flow.Launcher.Plugin.SharedCommands;
using Flow.Launcher.Storage;
using Microsoft.VisualStudio.Threading;
+using Svg;
namespace Flow.Launcher.ViewModel
{
@@ -60,6 +62,8 @@ namespace Flow.Launcher.ViewModel
#endregion
+
+
#region Constructor
public MainViewModel()
@@ -140,6 +144,9 @@ namespace Flow.Launcher.ViewModel
case nameof(Settings.OpenHistoryHotkey):
OnPropertyChanged(nameof(OpenHistoryHotkey));
break;
+ case nameof(Settings.RenameFileHotkey):
+ OnPropertyChanged(nameof(Settings.RenameFileHotkey));
+ break;
}
};
@@ -596,6 +603,7 @@ namespace Flow.Launcher.ViewModel
#endregion
#region ViewModel Properties
+
public Settings Settings { get; }
public string ClockText { get; private set; }
@@ -913,9 +921,53 @@ 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()
+ {
+ const string explorerPluginID = "572be03c74c642baae319fc283e561a8";
+ // check if explorer plugin is enabled
+ var explorerPluginMatches = App.API.GetAllPlugins().Where(plugin => plugin.Metadata.ID == "572be03c74c642baae319fc283e561a8");
+
+ if (!explorerPluginMatches.Any())
+ {
+ timesTriedToRenameFileWithExplorerDisabled++;
+ return;
+ }
+ else if (!explorerPluginMatches.Any() && timesTriedToRenameFileWithExplorerDisabled > 3)
+ {
+ App.API.ShowMsg("Are you trying to rename a file?", "The explorer plugin needs to be enabled for the hotkey to rename files to work.");
+ timesTriedToRenameFileWithExplorerDisabled = 0;
+ }
+ else
+ {
+ dynamic explorerPlugin = explorerPluginMatches.First();
+ string path = SelectedResults.SelectedItem.Result.SubTitle;
+ if (File.Exists(path) || Directory.Exists(path))
+ {
+ explorerPlugin.Plugin.RenameDialog(new FileInfo(path), App.API ); // this feels kinda hacky
+ return;
+ }
+ else if (new DirectoryInfo(path).Parent == null) // check if isn't a root directory like C:\
+ {
+ App.API.ShowMsgError("Cannot rename this.");
+ return;
+ }
+
+
+
+
+ }
+ }
+ #endregion
+
#endregion
#region Preview
@@ -1011,6 +1063,7 @@ namespace Flow.Launcher.ViewModel
_ = ShowPreviewAsync();
}
}
+
private async Task OpenExternalPreviewAsync(string path, bool sendFailToast = true)
{
diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Helper/RenameThing.cs b/Plugins/Flow.Launcher.Plugin.Explorer/Helper/RenameThing.cs
index a337b2dfb..e963b5b4b 100644
--- a/Plugins/Flow.Launcher.Plugin.Explorer/Helper/RenameThing.cs
+++ b/Plugins/Flow.Launcher.Plugin.Explorer/Helper/RenameThing.cs
@@ -9,11 +9,11 @@ namespace Flow.Launcher.Plugin.Explorer.Helper
{
public static class RenameThing
{
- public static void Rename(this FileSystemInfo info, string newName)
+ public static void Rename(this FileSystemInfo info, string newName, IPublicAPI api)
{
if (info is FileInfo)
{
- if (newName.IndexOfAny(Path.GetInvalidFileNameChars()) >= 0)
+ if (!api.IsValidFileName(newName))
{
throw new InvalidNameException();
}
@@ -30,10 +30,10 @@ namespace Flow.Launcher.Plugin.Explorer.Helper
}
else if (info is DirectoryInfo)
{
- List invalidChars = Path.GetInvalidPathChars().ToList();
- invalidChars.Add('/');
- invalidChars.Add('\\');
- if (newName.IndexOfAny(invalidChars.ToArray()) >= 0)
+
+
+
+ if (!api.IsValidDirectoryName(newName))
{
throw new InvalidNameException();
}
@@ -47,12 +47,13 @@ namespace Flow.Launcher.Plugin.Explorer.Helper
}
Directory.Move(info.FullName, Path.Join(parent.FullName, newName));
- }
- else
+ }else
{
throw new ArgumentException($"{nameof(info)} must be either, {nameof(FileInfo)} or {nameof(DirectoryInfo)}");
}
}
+
+ }
}
internal class NotANewNameException : IOException
@@ -85,5 +86,5 @@ namespace Flow.Launcher.Plugin.Explorer.Helper
}
-}
+
diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Main.cs b/Plugins/Flow.Launcher.Plugin.Explorer/Main.cs
index 283820204..1225711fb 100644
--- a/Plugins/Flow.Launcher.Plugin.Explorer/Main.cs
+++ b/Plugins/Flow.Launcher.Plugin.Explorer/Main.cs
@@ -10,6 +10,8 @@ using System.Threading;
using System.Threading.Tasks;
using System.Windows.Controls;
using Flow.Launcher.Plugin.Explorer.Exceptions;
+using System.Xml;
+using System.CodeDom;
namespace Flow.Launcher.Plugin.Explorer
{
@@ -42,11 +44,12 @@ namespace Flow.Launcher.Plugin.Explorer
contextMenu = new ContextMenu(Context, Settings, viewModel);
searchManager = new SearchManager(Settings, Context);
ResultManager.Init(Context, Settings);
-
+
SortOptionTranslationHelper.API = context.API;
EverythingApiDllImport.Load(Path.Combine(Context.CurrentPluginMetadata.PluginDirectory, "EverythingSDK",
Environment.Is64BitProcess ? "x64" : "x86"));
+
return Task.CompletedTask;
}
@@ -55,8 +58,10 @@ namespace Flow.Launcher.Plugin.Explorer
return contextMenu.LoadContextMenus(selectedResult);
}
+
public async Task> QueryAsync(Query query, CancellationToken token)
{
+
try
{
return await searchManager.SearchAsync(query, token);
@@ -96,7 +101,10 @@ namespace Flow.Launcher.Plugin.Explorer
{
return Context.API.GetTranslation("plugin_explorer_plugin_description");
}
-
+ public void RenameDialog(FileSystemInfo info, IPublicAPI api)
+ {
+ new RenameFile(api, info).Show();
+ }
private void FillQuickAccessLinkNames()
{
// Legacy version does not have names for quick access links, so we fill them with the path name.
@@ -108,5 +116,6 @@ namespace Flow.Launcher.Plugin.Explorer
}
}
}
+
}
}
diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Search/SearchManager.cs b/Plugins/Flow.Launcher.Plugin.Explorer/Search/SearchManager.cs
index 28609c86d..12df6c145 100644
--- a/Plugins/Flow.Launcher.Plugin.Explorer/Search/SearchManager.cs
+++ b/Plugins/Flow.Launcher.Plugin.Explorer/Search/SearchManager.cs
@@ -47,16 +47,6 @@ namespace Flow.Launcher.Plugin.Explorer.Search
internal async Task> SearchAsync(Query query, CancellationToken token)
{
var results = new HashSet(PathEqualityComparator.Instance);
- if (ActionKeywordMatch(query, Settings.ActionKeyword.RenameActionKeyword))
- {
- return new List()
- {
- new Result(){
- Title = "Done",
- AutoCompleteText = "test"
- }
- };
- }
// This allows the user to type the below action keywords and see/search the list of quick folder links
if (ActionKeywordMatch(query, Settings.ActionKeyword.SearchActionKeyword)
@@ -161,7 +151,6 @@ namespace Flow.Launcher.Plugin.Explorer.Search
keyword == Settings.IndexSearchActionKeyword,
Settings.ActionKeyword.QuickAccessActionKeyword => Settings.QuickAccessKeywordEnabled &&
keyword == Settings.QuickAccessActionKeyword,
- Settings.ActionKeyword.RenameActionKeyword => Settings.RenameActionKeywordEnabled && keyword == Settings.RenameActionKeyword,
_ => throw new ArgumentOutOfRangeException(nameof(allowedActionKeyword), allowedActionKeyword, "actionKeyword out of range")
};
}
diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Views/RenameFile.xaml.cs b/Plugins/Flow.Launcher.Plugin.Explorer/Views/RenameFile.xaml.cs
index 068015844..d27ef0e29 100644
--- a/Plugins/Flow.Launcher.Plugin.Explorer/Views/RenameFile.xaml.cs
+++ b/Plugins/Flow.Launcher.Plugin.Explorer/Views/RenameFile.xaml.cs
@@ -11,11 +11,11 @@ using Microsoft.VisualBasic.Logging;
namespace Flow.Launcher.Plugin.Explorer.Views
{
-
+
[INotifyPropertyChanged]
- public partial class RenameFile : Window
+ public partial class RenameFile : Window
{
-
+
public string NewFileName
{
@@ -28,7 +28,7 @@ namespace Flow.Launcher.Plugin.Explorer.Views
private string _newFileName;
-
+
private readonly IPublicAPI _api;
private readonly string _oldFilePath;
@@ -47,27 +47,28 @@ namespace Flow.Launcher.Plugin.Explorer.Views
RenameTb.SelectAll();
+
_info = info;
_oldFilePath = _info.FullName;
NewFileName = _info.Name;
-
-
+
+
}
private void OnDoneButtonClick(object sender, RoutedEventArgs e)
{
// if it's just whitespace and nothing else
- _api.LogInfo(nameof(RenameFile),$"THIS IS NEW FILE NAME: {NewFileName}");
+ _api.LogInfo(nameof(RenameFile), $"THIS IS NEW FILE NAME: {NewFileName}");
if (NewFileName.Trim() == "" || NewFileName == "")
{
_api.ShowMsgError(string.Format(_api.GetTranslation("plugin_explorer_field_may_not_be_empty"), "New file name"));
return;
}
-
+
try
{
- _info.Rename(NewFileName);
+ _info.Rename(NewFileName, _api);
}
catch (Exception exception)
{
@@ -100,14 +101,14 @@ namespace Flow.Launcher.Plugin.Explorer.Views
}
}
Close();
-
+
}
private void BtnCancel(object sender, RoutedEventArgs e)
{
Close();
}
-
+
private void RenameTb_OnKeyDown(object sender, KeyEventArgs e)
{
if (e.Key == Key.Enter)
@@ -115,9 +116,10 @@ namespace Flow.Launcher.Plugin.Explorer.Views
btnDone.Focus();
OnDoneButtonClick(sender, e);
e.Handled = true;
+ }
+
+
+
}
-
-
-
}
}