From cc80221903577e21cc8123159d0f15ddde60a250 Mon Sep 17 00:00:00 2001 From: Jeremy Wu Date: Tue, 20 May 2025 20:00:13 +1000 Subject: [PATCH 01/53] Version bump for release --- appveyor.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/appveyor.yml b/appveyor.yml index 5902f09f1..fa0b5956b 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -1,4 +1,4 @@ -version: '1.19.5.{build}' +version: '1.20.0.{build}' init: - ps: | From 8aae92e61da289815da6d8f5291b5718c6741340 Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Thu, 22 May 2025 10:47:07 +0800 Subject: [PATCH 02/53] Fix main window null when checking exitting --- Flow.Launcher/App.xaml.cs | 2 +- Flow.Launcher/SettingWindow.xaml.cs | 2 +- Flow.Launcher/ViewModel/MainViewModel.cs | 2 +- Flow.Launcher/WelcomeWindow.xaml.cs | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Flow.Launcher/App.xaml.cs b/Flow.Launcher/App.xaml.cs index 969bb75bb..cedced181 100644 --- a/Flow.Launcher/App.xaml.cs +++ b/Flow.Launcher/App.xaml.cs @@ -32,7 +32,7 @@ namespace Flow.Launcher #region Public Properties public static IPublicAPI API { get; private set; } - public static bool Exiting => _mainWindow.CanClose; + public static bool LoadingOrExiting => _mainWindow == null || _mainWindow.CanClose; #endregion diff --git a/Flow.Launcher/SettingWindow.xaml.cs b/Flow.Launcher/SettingWindow.xaml.cs index c53a4ea80..c1c0f96a7 100644 --- a/Flow.Launcher/SettingWindow.xaml.cs +++ b/Flow.Launcher/SettingWindow.xaml.cs @@ -82,7 +82,7 @@ public partial class SettingWindow _viewModel.PropertyChanged -= ViewModel_PropertyChanged; // If app is exiting, settings save is not needed because main window closing event will handle this - if (App.Exiting) return; + if (App.LoadingOrExiting) return; // Save settings when window is closed _settings.Save(); App.API.SavePluginSettings(); diff --git a/Flow.Launcher/ViewModel/MainViewModel.cs b/Flow.Launcher/ViewModel/MainViewModel.cs index 807275fcb..c4da384f8 100644 --- a/Flow.Launcher/ViewModel/MainViewModel.cs +++ b/Flow.Launcher/ViewModel/MainViewModel.cs @@ -1729,7 +1729,7 @@ namespace Flow.Launcher.ViewModel public void Show() { // When application is exiting, we should not show the main window - if (App.Exiting) return; + if (App.LoadingOrExiting) return; // When application is exiting, the Application.Current will be null Application.Current?.Dispatcher.Invoke(() => diff --git a/Flow.Launcher/WelcomeWindow.xaml.cs b/Flow.Launcher/WelcomeWindow.xaml.cs index ef0706765..fe8a63e52 100644 --- a/Flow.Launcher/WelcomeWindow.xaml.cs +++ b/Flow.Launcher/WelcomeWindow.xaml.cs @@ -96,7 +96,7 @@ namespace Flow.Launcher private void Window_Closed(object sender, EventArgs e) { // If app is exiting, settings save is not needed because main window closing event will handle this - if (App.Exiting) return; + if (App.LoadingOrExiting) return; // Save settings when window is closed _settings.Save(); } From 90ad72ca30ca7e99e3e84c4cac4e507f91b47a4c Mon Sep 17 00:00:00 2001 From: 01Dri Date: Fri, 23 May 2025 16:33:47 -0300 Subject: [PATCH 03/53] Diff Time in Created At and LastModifiedAt --- .../Views/PreviewPanel.xaml.cs | 47 ++++++++++++++----- 1 file changed, 34 insertions(+), 13 deletions(-) diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Views/PreviewPanel.xaml.cs b/Plugins/Flow.Launcher.Plugin.Explorer/Views/PreviewPanel.xaml.cs index aaf1efdc1..1981a8b0e 100644 --- a/Plugins/Flow.Launcher.Plugin.Explorer/Views/PreviewPanel.xaml.cs +++ b/Plugins/Flow.Launcher.Plugin.Explorer/Views/PreviewPanel.xaml.cs @@ -1,4 +1,5 @@ -using System.ComponentModel; +using System; +using System.ComponentModel; using System.Globalization; using System.IO; using System.Runtime.CompilerServices; @@ -65,22 +66,22 @@ public partial class PreviewPanel : UserControl, INotifyPropertyChanged if (Settings.ShowCreatedDateInPreviewPanel) { - CreatedAt = File - .GetCreationTime(filePath) - .ToString( - $"{Settings.PreviewPanelDateFormat} {Settings.PreviewPanelTimeFormat}", - CultureInfo.CurrentCulture - ); + DateTime createdDate = File.GetCreationTime(filePath); + string formattedDate = createdDate.ToString( + $"{Settings.PreviewPanelDateFormat} {Settings.PreviewPanelTimeFormat}", + CultureInfo.CurrentCulture + ); + CreatedAt = $"{GetDiffTimeString(createdDate)} - {formattedDate}"; } if (Settings.ShowModifiedDateInPreviewPanel) { - LastModifiedAt = File - .GetLastWriteTime(filePath) - .ToString( - $"{Settings.PreviewPanelDateFormat} {Settings.PreviewPanelTimeFormat}", - CultureInfo.CurrentCulture - ); + DateTime lastModifiedDate = File.GetLastWriteTime(filePath); + string formattedDate = lastModifiedDate.ToString( + $"{Settings.PreviewPanelDateFormat} {Settings.PreviewPanelTimeFormat}", + CultureInfo.CurrentCulture + ); + LastModifiedAt = $"{GetDiffTimeString(lastModifiedDate)} - {formattedDate}"; } _ = LoadImageAsync(); @@ -90,7 +91,27 @@ public partial class PreviewPanel : UserControl, INotifyPropertyChanged { PreviewImage = await Main.Context.API.LoadImageAsync(FilePath, true).ConfigureAwait(false); } + + private string GetDiffTimeString(DateTime fileDateTime) + { + DateTime now = DateTime.Now; + TimeSpan difference = now - fileDateTime; + if (difference.TotalDays < 1) + return "Today"; + if (difference.TotalDays < 30) + return $"{(int)difference.TotalDays} days ago"; + + int monthsDiff = (now.Year - fileDateTime.Year) * 12 + now.Month - fileDateTime.Month; + if (monthsDiff < 12) + return monthsDiff == 1 ? "1 month ago" : $"{monthsDiff} months ago"; + + int yearsDiff = now.Year - fileDateTime.Year; + if (now.Month < fileDateTime.Month || (now.Month == fileDateTime.Month && now.Day < fileDateTime.Day)) + yearsDiff--; + + return yearsDiff == 1 ? "1 year ago" : $"{yearsDiff} years ago"; + } public event PropertyChangedEventHandler? PropertyChanged; protected virtual void OnPropertyChanged([CallerMemberName] string? propertyName = null) From 35e71c6f510256bdad0692919cdbfa1578d5ee87 Mon Sep 17 00:00:00 2001 From: 01Dri Date: Sat, 24 May 2025 00:12:56 -0300 Subject: [PATCH 04/53] Relative Date checkbox --- .../Flow.Launcher.Plugin.Explorer/Languages/en.xaml | 3 +++ .../Languages/pt-br.xaml | 5 +++-- Plugins/Flow.Launcher.Plugin.Explorer/Settings.cs | 3 +++ .../ViewModels/SettingsViewModel.cs | 12 ++++++++++++ .../Views/ExplorerSettings.xaml | 5 +++++ .../Views/PreviewPanel.xaml.cs | 11 ++++++++--- 6 files changed, 34 insertions(+), 5 deletions(-) diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Languages/en.xaml b/Plugins/Flow.Launcher.Plugin.Explorer/Languages/en.xaml index 79f8a5848..6680aacff 100644 --- a/Plugins/Flow.Launcher.Plugin.Explorer/Languages/en.xaml +++ b/Plugins/Flow.Launcher.Plugin.Explorer/Languages/en.xaml @@ -33,6 +33,7 @@ Size Date Created Date Modified + Relative Date Display File Info Date and time format Sort Option: @@ -125,6 +126,8 @@ Use '>' to search in this directory, '*' to search for file extensions or '>*' to combine both searches. + + Failed to load Everything SDK diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Languages/pt-br.xaml b/Plugins/Flow.Launcher.Plugin.Explorer/Languages/pt-br.xaml index 2754a5a99..59770a29d 100644 --- a/Plugins/Flow.Launcher.Plugin.Explorer/Languages/pt-br.xaml +++ b/Plugins/Flow.Launcher.Plugin.Explorer/Languages/pt-br.xaml @@ -29,8 +29,9 @@ Everything Setting Preview Panel Tamanho - Date Created - Date Modified + Data Criação + Data Modificação + Data Relativa Display File Info Date and time format Sort Option: diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Settings.cs b/Plugins/Flow.Launcher.Plugin.Explorer/Settings.cs index 3d30bcf29..0a91c024c 100644 --- a/Plugins/Flow.Launcher.Plugin.Explorer/Settings.cs +++ b/Plugins/Flow.Launcher.Plugin.Explorer/Settings.cs @@ -66,6 +66,9 @@ namespace Flow.Launcher.Plugin.Explorer public bool ShowCreatedDateInPreviewPanel { get; set; } = true; public bool ShowModifiedDateInPreviewPanel { get; set; } = true; + + public bool ShowRelativeDateInPreviewPanel { get; set; } = true; + public string PreviewPanelDateFormat { get; set; } = "yyyy-MM-dd"; diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/ViewModels/SettingsViewModel.cs b/Plugins/Flow.Launcher.Plugin.Explorer/ViewModels/SettingsViewModel.cs index cf9ebd33f..baa2c6c28 100644 --- a/Plugins/Flow.Launcher.Plugin.Explorer/ViewModels/SettingsViewModel.cs +++ b/Plugins/Flow.Launcher.Plugin.Explorer/ViewModels/SettingsViewModel.cs @@ -169,6 +169,18 @@ namespace Flow.Launcher.Plugin.Explorer.ViewModels } } + public bool ShowRelativeDateInPreviewPanel + { + get => Settings.ShowRelativeDateInPreviewPanel; + set + { + Settings.ShowRelativeDateInPreviewPanel = value; + OnPropertyChanged(); + OnPropertyChanged(nameof(ShowPreviewPanelDateTimeChoices)); + OnPropertyChanged(nameof(PreviewPanelDateTimeChoicesVisibility)); + } + } + public string PreviewPanelDateFormat { get => Settings.PreviewPanelDateFormat; diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Views/ExplorerSettings.xaml b/Plugins/Flow.Launcher.Plugin.Explorer/Views/ExplorerSettings.xaml index e5999da41..c16dc4f51 100644 --- a/Plugins/Flow.Launcher.Plugin.Explorer/Views/ExplorerSettings.xaml +++ b/Plugins/Flow.Launcher.Plugin.Explorer/Views/ExplorerSettings.xaml @@ -505,6 +505,11 @@ Margin="{StaticResource SettingPanelItemLeftTopBottomMargin}" Content="{DynamicResource plugin_explorer_previewpanel_display_file_modification_checkbox}" IsChecked="{Binding ShowModifiedDateInPreviewPanel}" /> + + diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Views/PreviewPanel.xaml.cs b/Plugins/Flow.Launcher.Plugin.Explorer/Views/PreviewPanel.xaml.cs index 1981a8b0e..aa5ba6cc7 100644 --- a/Plugins/Flow.Launcher.Plugin.Explorer/Views/PreviewPanel.xaml.cs +++ b/Plugins/Flow.Launcher.Plugin.Explorer/Views/PreviewPanel.xaml.cs @@ -71,7 +71,10 @@ public partial class PreviewPanel : UserControl, INotifyPropertyChanged $"{Settings.PreviewPanelDateFormat} {Settings.PreviewPanelTimeFormat}", CultureInfo.CurrentCulture ); - CreatedAt = $"{GetDiffTimeString(createdDate)} - {formattedDate}"; + + string result = formattedDate; + if (Settings.ShowRelativeDateInPreviewPanel) result = $"{GetFileAge(createdDate)} - {formattedDate}"; + CreatedAt = result; } if (Settings.ShowModifiedDateInPreviewPanel) @@ -81,7 +84,9 @@ public partial class PreviewPanel : UserControl, INotifyPropertyChanged $"{Settings.PreviewPanelDateFormat} {Settings.PreviewPanelTimeFormat}", CultureInfo.CurrentCulture ); - LastModifiedAt = $"{GetDiffTimeString(lastModifiedDate)} - {formattedDate}"; + string result = formattedDate; + if (Settings.ShowRelativeDateInPreviewPanel) result = $"{GetFileAge(lastModifiedDate)} - {formattedDate}"; + LastModifiedAt = result; } _ = LoadImageAsync(); @@ -92,7 +97,7 @@ public partial class PreviewPanel : UserControl, INotifyPropertyChanged PreviewImage = await Main.Context.API.LoadImageAsync(FilePath, true).ConfigureAwait(false); } - private string GetDiffTimeString(DateTime fileDateTime) + private string GetFileAge(DateTime fileDateTime) { DateTime now = DateTime.Now; TimeSpan difference = now - fileDateTime; From 02ddcaa0642a123ee1ac7caf747783651d4fc2f5 Mon Sep 17 00:00:00 2001 From: 01Dri Date: Sat, 24 May 2025 00:15:08 -0300 Subject: [PATCH 05/53] Function name changed to GetRelativeDate --- .../Views/PreviewPanel.xaml.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Views/PreviewPanel.xaml.cs b/Plugins/Flow.Launcher.Plugin.Explorer/Views/PreviewPanel.xaml.cs index aa5ba6cc7..05dfd66f3 100644 --- a/Plugins/Flow.Launcher.Plugin.Explorer/Views/PreviewPanel.xaml.cs +++ b/Plugins/Flow.Launcher.Plugin.Explorer/Views/PreviewPanel.xaml.cs @@ -73,7 +73,7 @@ public partial class PreviewPanel : UserControl, INotifyPropertyChanged ); string result = formattedDate; - if (Settings.ShowRelativeDateInPreviewPanel) result = $"{GetFileAge(createdDate)} - {formattedDate}"; + if (Settings.ShowRelativeDateInPreviewPanel) result = $"{GetRelativeDate(createdDate)} - {formattedDate}"; CreatedAt = result; } @@ -85,7 +85,7 @@ public partial class PreviewPanel : UserControl, INotifyPropertyChanged CultureInfo.CurrentCulture ); string result = formattedDate; - if (Settings.ShowRelativeDateInPreviewPanel) result = $"{GetFileAge(lastModifiedDate)} - {formattedDate}"; + if (Settings.ShowRelativeDateInPreviewPanel) result = $"{GetRelativeDate(lastModifiedDate)} - {formattedDate}"; LastModifiedAt = result; } @@ -97,7 +97,7 @@ public partial class PreviewPanel : UserControl, INotifyPropertyChanged PreviewImage = await Main.Context.API.LoadImageAsync(FilePath, true).ConfigureAwait(false); } - private string GetFileAge(DateTime fileDateTime) + private string GetRelativeDate(DateTime fileDateTime) { DateTime now = DateTime.Now; TimeSpan difference = now - fileDateTime; From a711ce4ec793158c6586ec70e5e0cd913c77319b Mon Sep 17 00:00:00 2001 From: 01Dri Date: Sat, 24 May 2025 01:10:12 -0300 Subject: [PATCH 06/53] Translate pt br --- Plugins/Flow.Launcher.Plugin.Explorer/Languages/pt-br.xaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Languages/pt-br.xaml b/Plugins/Flow.Launcher.Plugin.Explorer/Languages/pt-br.xaml index 59770a29d..3ab958506 100644 --- a/Plugins/Flow.Launcher.Plugin.Explorer/Languages/pt-br.xaml +++ b/Plugins/Flow.Launcher.Plugin.Explorer/Languages/pt-br.xaml @@ -29,8 +29,8 @@ Everything Setting Preview Panel Tamanho - Data Criação - Data Modificação + Data de Criação + Data de Modificação Data Relativa Display File Info Date and time format From b2f5713386d4a8a702c91b461f25de1598865776 Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Sat, 24 May 2025 13:10:25 +0800 Subject: [PATCH 07/53] =?UTF-8?q?Fix=20crash=20on=20=C3=9732=20devices?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../NativeMethods.txt | 2 +- .../PInvokeExtensions.cs | 26 ++++++++++++++++--- Flow.Launcher.Infrastructure/Win32Helper.cs | 6 ++--- 3 files changed, 27 insertions(+), 7 deletions(-) diff --git a/Flow.Launcher.Infrastructure/NativeMethods.txt b/Flow.Launcher.Infrastructure/NativeMethods.txt index 0e50420b0..c01532414 100644 --- a/Flow.Launcher.Infrastructure/NativeMethods.txt +++ b/Flow.Launcher.Infrastructure/NativeMethods.txt @@ -22,7 +22,7 @@ SystemParametersInfo SetForegroundWindow -GetWindowLong +WINDOW_LONG_PTR_INDEX GetForegroundWindow GetDesktopWindow GetShellWindow diff --git a/Flow.Launcher.Infrastructure/PInvokeExtensions.cs b/Flow.Launcher.Infrastructure/PInvokeExtensions.cs index 1a72ab7a6..18b992043 100644 --- a/Flow.Launcher.Infrastructure/PInvokeExtensions.cs +++ b/Flow.Launcher.Infrastructure/PInvokeExtensions.cs @@ -4,14 +4,16 @@ using Windows.Win32.UI.WindowsAndMessaging; namespace Windows.Win32; -// Edited from: https://github.com/files-community/Files internal static partial class PInvoke { + // SetWindowLong + // Edited from: https://github.com/files-community/Files + [DllImport("User32", EntryPoint = "SetWindowLongW", ExactSpelling = true)] - static extern int _SetWindowLong(HWND hWnd, int nIndex, int dwNewLong); + private static extern int _SetWindowLong(HWND hWnd, int nIndex, int dwNewLong); [DllImport("User32", EntryPoint = "SetWindowLongPtrW", ExactSpelling = true)] - static extern nint _SetWindowLongPtr(HWND hWnd, int nIndex, nint dwNewLong); + private static extern nint _SetWindowLongPtr(HWND hWnd, int nIndex, nint dwNewLong); // NOTE: // CsWin32 doesn't generate SetWindowLong on other than x86 and vice versa. @@ -22,4 +24,22 @@ internal static partial class PInvoke ? _SetWindowLong(hWnd, (int)nIndex, (int)dwNewLong) : _SetWindowLongPtr(hWnd, (int)nIndex, dwNewLong); } + + // GetWindowLong + + [DllImport("User32", EntryPoint = "GetWindowLongW", ExactSpelling = true)] + private static extern int _GetWindowLong(HWND hWnd, int nIndex); + + [DllImport("User32", EntryPoint = "GetWindowLongPtrW", ExactSpelling = true)] + private static extern nint _GetWindowLongPtr(HWND hWnd, int nIndex); + + // NOTE: + // CsWin32 doesn't generate GetWindowLong on other than x86 and vice versa. + // For more info, visit https://github.com/microsoft/CsWin32/issues/882 + public static unsafe nint GetWindowLongPtr(HWND hWnd, WINDOW_LONG_PTR_INDEX nIndex) + { + return sizeof(nint) is 4 + ? _GetWindowLong(hWnd, (int)nIndex) + : _GetWindowLongPtr(hWnd, (int)nIndex); + } } diff --git a/Flow.Launcher.Infrastructure/Win32Helper.cs b/Flow.Launcher.Infrastructure/Win32Helper.cs index 783ade14e..dad5f2f93 100644 --- a/Flow.Launcher.Infrastructure/Win32Helper.cs +++ b/Flow.Launcher.Infrastructure/Win32Helper.cs @@ -192,9 +192,9 @@ namespace Flow.Launcher.Infrastructure SetWindowStyle(hwnd, WINDOW_LONG_PTR_INDEX.GWL_STYLE, style); } - private static int GetWindowStyle(HWND hWnd, WINDOW_LONG_PTR_INDEX nIndex) + private static nint GetWindowStyle(HWND hWnd, WINDOW_LONG_PTR_INDEX nIndex) { - var style = PInvoke.GetWindowLong(hWnd, nIndex); + var style = PInvoke.GetWindowLongPtr(hWnd, nIndex); if (style == 0 && Marshal.GetLastPInvokeError() != 0) { throw new Win32Exception(Marshal.GetLastPInvokeError()); @@ -202,7 +202,7 @@ namespace Flow.Launcher.Infrastructure return style; } - private static nint SetWindowStyle(HWND hWnd, WINDOW_LONG_PTR_INDEX nIndex, int dwNewLong) + private static nint SetWindowStyle(HWND hWnd, WINDOW_LONG_PTR_INDEX nIndex, nint dwNewLong) { PInvoke.SetLastError(WIN32_ERROR.NO_ERROR); // Clear any existing error From f6103b1105d9c741c87ed0f954622c271a87620a Mon Sep 17 00:00:00 2001 From: 01Dri Date: Sat, 24 May 2025 03:16:03 -0300 Subject: [PATCH 08/53] Relative Date -> File Age --- Plugins/Flow.Launcher.Plugin.Explorer/Languages/en.xaml | 2 +- Plugins/Flow.Launcher.Plugin.Explorer/Languages/pt-br.xaml | 2 +- Plugins/Flow.Launcher.Plugin.Explorer/Settings.cs | 2 +- .../ViewModels/SettingsViewModel.cs | 6 +++--- .../Views/ExplorerSettings.xaml | 4 ++-- .../Views/PreviewPanel.xaml.cs | 4 ++-- 6 files changed, 10 insertions(+), 10 deletions(-) diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Languages/en.xaml b/Plugins/Flow.Launcher.Plugin.Explorer/Languages/en.xaml index 6680aacff..aa86d96cf 100644 --- a/Plugins/Flow.Launcher.Plugin.Explorer/Languages/en.xaml +++ b/Plugins/Flow.Launcher.Plugin.Explorer/Languages/en.xaml @@ -33,7 +33,7 @@ Size Date Created Date Modified - Relative Date + File Age Display File Info Date and time format Sort Option: diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Languages/pt-br.xaml b/Plugins/Flow.Launcher.Plugin.Explorer/Languages/pt-br.xaml index 3ab958506..ca7d9b48e 100644 --- a/Plugins/Flow.Launcher.Plugin.Explorer/Languages/pt-br.xaml +++ b/Plugins/Flow.Launcher.Plugin.Explorer/Languages/pt-br.xaml @@ -31,7 +31,7 @@ Tamanho Data de Criação Data de Modificação - Data Relativa + Idade do Arquivo Display File Info Date and time format Sort Option: diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Settings.cs b/Plugins/Flow.Launcher.Plugin.Explorer/Settings.cs index 0a91c024c..158cf0347 100644 --- a/Plugins/Flow.Launcher.Plugin.Explorer/Settings.cs +++ b/Plugins/Flow.Launcher.Plugin.Explorer/Settings.cs @@ -67,7 +67,7 @@ namespace Flow.Launcher.Plugin.Explorer public bool ShowModifiedDateInPreviewPanel { get; set; } = true; - public bool ShowRelativeDateInPreviewPanel { get; set; } = true; + public bool ShowFileAgeInPreviewPanel { get; set; } = true; public string PreviewPanelDateFormat { get; set; } = "yyyy-MM-dd"; diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/ViewModels/SettingsViewModel.cs b/Plugins/Flow.Launcher.Plugin.Explorer/ViewModels/SettingsViewModel.cs index baa2c6c28..fb33dacab 100644 --- a/Plugins/Flow.Launcher.Plugin.Explorer/ViewModels/SettingsViewModel.cs +++ b/Plugins/Flow.Launcher.Plugin.Explorer/ViewModels/SettingsViewModel.cs @@ -169,12 +169,12 @@ namespace Flow.Launcher.Plugin.Explorer.ViewModels } } - public bool ShowRelativeDateInPreviewPanel + public bool ShowFileAgeInPreviewPanel { - get => Settings.ShowRelativeDateInPreviewPanel; + get => Settings.ShowFileAgeInPreviewPanel; set { - Settings.ShowRelativeDateInPreviewPanel = value; + Settings.ShowFileAgeInPreviewPanel = value; OnPropertyChanged(); OnPropertyChanged(nameof(ShowPreviewPanelDateTimeChoices)); OnPropertyChanged(nameof(PreviewPanelDateTimeChoicesVisibility)); diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Views/ExplorerSettings.xaml b/Plugins/Flow.Launcher.Plugin.Explorer/Views/ExplorerSettings.xaml index c16dc4f51..4302e721a 100644 --- a/Plugins/Flow.Launcher.Plugin.Explorer/Views/ExplorerSettings.xaml +++ b/Plugins/Flow.Launcher.Plugin.Explorer/Views/ExplorerSettings.xaml @@ -508,8 +508,8 @@ + Content="{DynamicResource plugin_explorer_previewpanel_display_file_age_checkbox}" + IsChecked="{Binding ShowFileAgeInPreviewPanel}" /> diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Views/PreviewPanel.xaml.cs b/Plugins/Flow.Launcher.Plugin.Explorer/Views/PreviewPanel.xaml.cs index 05dfd66f3..801510eb7 100644 --- a/Plugins/Flow.Launcher.Plugin.Explorer/Views/PreviewPanel.xaml.cs +++ b/Plugins/Flow.Launcher.Plugin.Explorer/Views/PreviewPanel.xaml.cs @@ -73,7 +73,7 @@ public partial class PreviewPanel : UserControl, INotifyPropertyChanged ); string result = formattedDate; - if (Settings.ShowRelativeDateInPreviewPanel) result = $"{GetRelativeDate(createdDate)} - {formattedDate}"; + if (Settings.ShowFileAgeInPreviewPanel) result = $"{GetRelativeDate(createdDate)} - {formattedDate}"; CreatedAt = result; } @@ -85,7 +85,7 @@ public partial class PreviewPanel : UserControl, INotifyPropertyChanged CultureInfo.CurrentCulture ); string result = formattedDate; - if (Settings.ShowRelativeDateInPreviewPanel) result = $"{GetRelativeDate(lastModifiedDate)} - {formattedDate}"; + if (Settings.ShowFileAgeInPreviewPanel) result = $"{GetRelativeDate(lastModifiedDate)} - {formattedDate}"; LastModifiedAt = result; } From d726455b047c380179243ff85ee132e7d601ba0c Mon Sep 17 00:00:00 2001 From: 01Dri Date: Sat, 24 May 2025 03:16:51 -0300 Subject: [PATCH 09/53] Relative Date - FileAge --- .../Views/PreviewPanel.xaml.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Views/PreviewPanel.xaml.cs b/Plugins/Flow.Launcher.Plugin.Explorer/Views/PreviewPanel.xaml.cs index 801510eb7..28ceb5e96 100644 --- a/Plugins/Flow.Launcher.Plugin.Explorer/Views/PreviewPanel.xaml.cs +++ b/Plugins/Flow.Launcher.Plugin.Explorer/Views/PreviewPanel.xaml.cs @@ -73,7 +73,7 @@ public partial class PreviewPanel : UserControl, INotifyPropertyChanged ); string result = formattedDate; - if (Settings.ShowFileAgeInPreviewPanel) result = $"{GetRelativeDate(createdDate)} - {formattedDate}"; + if (Settings.ShowFileAgeInPreviewPanel) result = $"{GetFileAge(createdDate)} - {formattedDate}"; CreatedAt = result; } @@ -85,7 +85,7 @@ public partial class PreviewPanel : UserControl, INotifyPropertyChanged CultureInfo.CurrentCulture ); string result = formattedDate; - if (Settings.ShowFileAgeInPreviewPanel) result = $"{GetRelativeDate(lastModifiedDate)} - {formattedDate}"; + if (Settings.ShowFileAgeInPreviewPanel) result = $"{GetFileAge(lastModifiedDate)} - {formattedDate}"; LastModifiedAt = result; } @@ -97,7 +97,7 @@ public partial class PreviewPanel : UserControl, INotifyPropertyChanged PreviewImage = await Main.Context.API.LoadImageAsync(FilePath, true).ConfigureAwait(false); } - private string GetRelativeDate(DateTime fileDateTime) + private string GetFileAge(DateTime fileDateTime) { DateTime now = DateTime.Now; TimeSpan difference = now - fileDateTime; From 2ff0fc8a7d8de2306229f8439b530932974f4519 Mon Sep 17 00:00:00 2001 From: DB p Date: Sat, 24 May 2025 15:28:51 +0900 Subject: [PATCH 10/53] Disable ShowFileAgeInPreviewPanel by default --- Plugins/Flow.Launcher.Plugin.Explorer/Settings.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Settings.cs b/Plugins/Flow.Launcher.Plugin.Explorer/Settings.cs index 158cf0347..49ad2d358 100644 --- a/Plugins/Flow.Launcher.Plugin.Explorer/Settings.cs +++ b/Plugins/Flow.Launcher.Plugin.Explorer/Settings.cs @@ -67,7 +67,7 @@ namespace Flow.Launcher.Plugin.Explorer public bool ShowModifiedDateInPreviewPanel { get; set; } = true; - public bool ShowFileAgeInPreviewPanel { get; set; } = true; + public bool ShowFileAgeInPreviewPanel { get; set; } = false; public string PreviewPanelDateFormat { get; set; } = "yyyy-MM-dd"; From 03d3c9292dcfc3814a890b9e0806e975f3abff59 Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Sat, 24 May 2025 15:55:37 +0800 Subject: [PATCH 11/53] Fix blnak lie --- Plugins/Flow.Launcher.Plugin.Explorer/Languages/en.xaml | 2 -- Plugins/Flow.Launcher.Plugin.Explorer/Settings.cs | 1 - 2 files changed, 3 deletions(-) diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Languages/en.xaml b/Plugins/Flow.Launcher.Plugin.Explorer/Languages/en.xaml index aa86d96cf..ca994455a 100644 --- a/Plugins/Flow.Launcher.Plugin.Explorer/Languages/en.xaml +++ b/Plugins/Flow.Launcher.Plugin.Explorer/Languages/en.xaml @@ -126,8 +126,6 @@ Use '>' to search in this directory, '*' to search for file extensions or '>*' to combine both searches. - - Failed to load Everything SDK diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Settings.cs b/Plugins/Flow.Launcher.Plugin.Explorer/Settings.cs index 49ad2d358..4f83fc72e 100644 --- a/Plugins/Flow.Launcher.Plugin.Explorer/Settings.cs +++ b/Plugins/Flow.Launcher.Plugin.Explorer/Settings.cs @@ -27,7 +27,6 @@ namespace Flow.Launcher.Plugin.Explorer public string ExcludedFileTypes { get; set; } = ""; - public bool UseLocationAsWorkingDir { get; set; } = false; public bool ShowInlinedWindowsContextMenu { get; set; } = false; From 65e0a0220b07bf58ff6ffed2a796ea1094a66b5c Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Sat, 24 May 2025 15:56:02 +0800 Subject: [PATCH 12/53] Revert changes in pt-br.xaml --- Plugins/Flow.Launcher.Plugin.Explorer/Languages/pt-br.xaml | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Languages/pt-br.xaml b/Plugins/Flow.Launcher.Plugin.Explorer/Languages/pt-br.xaml index ca7d9b48e..2754a5a99 100644 --- a/Plugins/Flow.Launcher.Plugin.Explorer/Languages/pt-br.xaml +++ b/Plugins/Flow.Launcher.Plugin.Explorer/Languages/pt-br.xaml @@ -29,9 +29,8 @@ Everything Setting Preview Panel Tamanho - Data de Criação - Data de Modificação - Idade do Arquivo + Date Created + Date Modified Display File Info Date and time format Sort Option: From 0f718e5d920bab13a285f42b4fb9ac83c759a9af Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Sat, 24 May 2025 15:59:24 +0800 Subject: [PATCH 13/53] Code quality --- .../Views/PreviewPanel.xaml.cs | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Views/PreviewPanel.xaml.cs b/Plugins/Flow.Launcher.Plugin.Explorer/Views/PreviewPanel.xaml.cs index 28ceb5e96..eabe1ad41 100644 --- a/Plugins/Flow.Launcher.Plugin.Explorer/Views/PreviewPanel.xaml.cs +++ b/Plugins/Flow.Launcher.Plugin.Explorer/Views/PreviewPanel.xaml.cs @@ -97,26 +97,27 @@ public partial class PreviewPanel : UserControl, INotifyPropertyChanged PreviewImage = await Main.Context.API.LoadImageAsync(FilePath, true).ConfigureAwait(false); } - private string GetFileAge(DateTime fileDateTime) + private static string GetFileAge(DateTime fileDateTime) { - DateTime now = DateTime.Now; - TimeSpan difference = now - fileDateTime; + var now = DateTime.Now; + var difference = now - fileDateTime; if (difference.TotalDays < 1) return "Today"; if (difference.TotalDays < 30) return $"{(int)difference.TotalDays} days ago"; - int monthsDiff = (now.Year - fileDateTime.Year) * 12 + now.Month - fileDateTime.Month; + var monthsDiff = (now.Year - fileDateTime.Year) * 12 + now.Month - fileDateTime.Month; if (monthsDiff < 12) return monthsDiff == 1 ? "1 month ago" : $"{monthsDiff} months ago"; - int yearsDiff = now.Year - fileDateTime.Year; + var yearsDiff = now.Year - fileDateTime.Year; if (now.Month < fileDateTime.Month || (now.Month == fileDateTime.Month && now.Day < fileDateTime.Day)) yearsDiff--; return yearsDiff == 1 ? "1 year ago" : $"{yearsDiff} years ago"; } + public event PropertyChangedEventHandler? PropertyChanged; protected virtual void OnPropertyChanged([CallerMemberName] string? propertyName = null) From 62d7256db43d03eb56084fe82e21641ef8fa1ceb Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Sat, 24 May 2025 16:07:15 +0800 Subject: [PATCH 14/53] Support transaltion for preview information --- .../Flow.Launcher.Plugin.Explorer/Languages/en.xaml | 8 ++++++++ .../Views/PreviewPanel.xaml.cs | 11 +++++++---- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Languages/en.xaml b/Plugins/Flow.Launcher.Plugin.Explorer/Languages/en.xaml index ca994455a..eefd6f4eb 100644 --- a/Plugins/Flow.Launcher.Plugin.Explorer/Languages/en.xaml +++ b/Plugins/Flow.Launcher.Plugin.Explorer/Languages/en.xaml @@ -167,4 +167,12 @@ Display native context menu (experimental) Below you can specify items you want to include in the context menu, they can be partial (e.g. 'pen wit') or complete ('Open with'). Below you can specify items you want to exclude from context menu, they can be partial (e.g. 'pen wit') or complete ('Open with'). + + + Today + {0} days ago + 1 month ago + {0} months ago + 1 year ago + {0} years ago diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/Views/PreviewPanel.xaml.cs b/Plugins/Flow.Launcher.Plugin.Explorer/Views/PreviewPanel.xaml.cs index eabe1ad41..e1a957199 100644 --- a/Plugins/Flow.Launcher.Plugin.Explorer/Views/PreviewPanel.xaml.cs +++ b/Plugins/Flow.Launcher.Plugin.Explorer/Views/PreviewPanel.xaml.cs @@ -103,19 +103,22 @@ public partial class PreviewPanel : UserControl, INotifyPropertyChanged var difference = now - fileDateTime; if (difference.TotalDays < 1) - return "Today"; + return Main.Context.API.GetTranslation("Today"); if (difference.TotalDays < 30) - return $"{(int)difference.TotalDays} days ago"; + return string.Format(Main.Context.API.GetTranslation("DaysAgo"), (int)difference.TotalDays); var monthsDiff = (now.Year - fileDateTime.Year) * 12 + now.Month - fileDateTime.Month; + if (monthsDiff == 1) + return Main.Context.API.GetTranslation("OneMonthAgo"); if (monthsDiff < 12) - return monthsDiff == 1 ? "1 month ago" : $"{monthsDiff} months ago"; + return string.Format(Main.Context.API.GetTranslation("MonthsAgo"), monthsDiff); var yearsDiff = now.Year - fileDateTime.Year; if (now.Month < fileDateTime.Month || (now.Month == fileDateTime.Month && now.Day < fileDateTime.Day)) yearsDiff--; - return yearsDiff == 1 ? "1 year ago" : $"{yearsDiff} years ago"; + return yearsDiff == 1 ? Main.Context.API.GetTranslation("OneYearAgo") : + string.Format(Main.Context.API.GetTranslation("YearsAgo"), yearsDiff); } public event PropertyChangedEventHandler? PropertyChanged; From de7438791ce0374975444eb0adb7b646b908463f Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Sun, 25 May 2025 09:14:19 +0800 Subject: [PATCH 15/53] Fix argument null exception when updating plugin directories for errornous plugins --- Flow.Launcher.Core/Plugin/PluginManager.cs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/Flow.Launcher.Core/Plugin/PluginManager.cs b/Flow.Launcher.Core/Plugin/PluginManager.cs index aae8dd764..300603c69 100644 --- a/Flow.Launcher.Core/Plugin/PluginManager.cs +++ b/Flow.Launcher.Core/Plugin/PluginManager.cs @@ -187,11 +187,19 @@ namespace Flow.Launcher.Core.Plugin { if (AllowedLanguage.IsDotNet(metadata.Language)) { + if (string.IsNullOrEmpty(metadata.AssemblyName)) + { + continue; // Skip if AssemblyName is not set, which can happen for errornous plugins + } metadata.PluginSettingsDirectoryPath = Path.Combine(DataLocation.PluginSettingsDirectory, metadata.AssemblyName); metadata.PluginCacheDirectoryPath = Path.Combine(DataLocation.PluginCacheDirectory, metadata.AssemblyName); } else { + if (string.IsNullOrEmpty(metadata.Name)) + { + continue; // Skip if Name is not set, which can happen for errornous plugins + } metadata.PluginSettingsDirectoryPath = Path.Combine(DataLocation.PluginSettingsDirectory, metadata.Name); metadata.PluginCacheDirectoryPath = Path.Combine(DataLocation.PluginCacheDirectory, metadata.Name); } From 0d785d1c9ce819a0b0c7afe8f0110c947f727031 Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Sun, 25 May 2025 09:17:31 +0800 Subject: [PATCH 16/53] Fix typos --- Flow.Launcher.Core/Plugin/PluginManager.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Flow.Launcher.Core/Plugin/PluginManager.cs b/Flow.Launcher.Core/Plugin/PluginManager.cs index 300603c69..2689369f8 100644 --- a/Flow.Launcher.Core/Plugin/PluginManager.cs +++ b/Flow.Launcher.Core/Plugin/PluginManager.cs @@ -189,7 +189,7 @@ namespace Flow.Launcher.Core.Plugin { if (string.IsNullOrEmpty(metadata.AssemblyName)) { - continue; // Skip if AssemblyName is not set, which can happen for errornous plugins + continue; // Skip if AssemblyName is not set, which can happen for erroneous plugins } metadata.PluginSettingsDirectoryPath = Path.Combine(DataLocation.PluginSettingsDirectory, metadata.AssemblyName); metadata.PluginCacheDirectoryPath = Path.Combine(DataLocation.PluginCacheDirectory, metadata.AssemblyName); @@ -198,7 +198,7 @@ namespace Flow.Launcher.Core.Plugin { if (string.IsNullOrEmpty(metadata.Name)) { - continue; // Skip if Name is not set, which can happen for errornous plugins + continue; // Skip if Name is not set, which can happen for erroneous plugins } metadata.PluginSettingsDirectoryPath = Path.Combine(DataLocation.PluginSettingsDirectory, metadata.Name); metadata.PluginCacheDirectoryPath = Path.Combine(DataLocation.PluginCacheDirectory, metadata.Name); From 025895508326602066d1badf741182a91988ab26 Mon Sep 17 00:00:00 2001 From: Jack Ye <1160210343@qq.com> Date: Sun, 25 May 2025 09:19:41 +0800 Subject: [PATCH 17/53] Log a warning when encountering an empty Name Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- Flow.Launcher.Core/Plugin/PluginManager.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/Flow.Launcher.Core/Plugin/PluginManager.cs b/Flow.Launcher.Core/Plugin/PluginManager.cs index 2689369f8..54b74da39 100644 --- a/Flow.Launcher.Core/Plugin/PluginManager.cs +++ b/Flow.Launcher.Core/Plugin/PluginManager.cs @@ -198,6 +198,7 @@ namespace Flow.Launcher.Core.Plugin { if (string.IsNullOrEmpty(metadata.Name)) { + Log.Warn($"Plugin with empty Name encountered. Skipping plugin initialization. Metadata: {metadata}"); continue; // Skip if Name is not set, which can happen for erroneous plugins } metadata.PluginSettingsDirectoryPath = Path.Combine(DataLocation.PluginSettingsDirectory, metadata.Name); From 9e666f95ea6044b855f423c980f0db2090f6ff5f Mon Sep 17 00:00:00 2001 From: Jack Ye <1160210343@qq.com> Date: Sun, 25 May 2025 09:19:54 +0800 Subject: [PATCH 18/53] Log a warning when encountering an empty AssemblyName Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- Flow.Launcher.Core/Plugin/PluginManager.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/Flow.Launcher.Core/Plugin/PluginManager.cs b/Flow.Launcher.Core/Plugin/PluginManager.cs index 54b74da39..c4e505ad0 100644 --- a/Flow.Launcher.Core/Plugin/PluginManager.cs +++ b/Flow.Launcher.Core/Plugin/PluginManager.cs @@ -189,6 +189,7 @@ namespace Flow.Launcher.Core.Plugin { if (string.IsNullOrEmpty(metadata.AssemblyName)) { + Log.Warn($"Plugin skipped: AssemblyName is empty for plugin with metadata: {metadata.Name}", typeof(PluginManager)); continue; // Skip if AssemblyName is not set, which can happen for erroneous plugins } metadata.PluginSettingsDirectoryPath = Path.Combine(DataLocation.PluginSettingsDirectory, metadata.AssemblyName); From 50780db9f54c1b2eef27859a9583fd75d85ff626 Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Sun, 25 May 2025 09:20:57 +0800 Subject: [PATCH 19/53] Fix build issue --- Flow.Launcher.Core/Plugin/PluginManager.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Flow.Launcher.Core/Plugin/PluginManager.cs b/Flow.Launcher.Core/Plugin/PluginManager.cs index c4e505ad0..9b525f331 100644 --- a/Flow.Launcher.Core/Plugin/PluginManager.cs +++ b/Flow.Launcher.Core/Plugin/PluginManager.cs @@ -189,7 +189,7 @@ namespace Flow.Launcher.Core.Plugin { if (string.IsNullOrEmpty(metadata.AssemblyName)) { - Log.Warn($"Plugin skipped: AssemblyName is empty for plugin with metadata: {metadata.Name}", typeof(PluginManager)); + API.LogWarn(ClassName, $"AssemblyName is empty for plugin with metadata: {metadata.Name}"); continue; // Skip if AssemblyName is not set, which can happen for erroneous plugins } metadata.PluginSettingsDirectoryPath = Path.Combine(DataLocation.PluginSettingsDirectory, metadata.AssemblyName); @@ -199,7 +199,7 @@ namespace Flow.Launcher.Core.Plugin { if (string.IsNullOrEmpty(metadata.Name)) { - Log.Warn($"Plugin with empty Name encountered. Skipping plugin initialization. Metadata: {metadata}"); + API.LogWarn(ClassName, $"Name is empty for plugin with metadata: {metadata.Name}"); continue; // Skip if Name is not set, which can happen for erroneous plugins } metadata.PluginSettingsDirectoryPath = Path.Combine(DataLocation.PluginSettingsDirectory, metadata.Name); From 47878f3829a9cb10f87d5429d07fad097efec3dd Mon Sep 17 00:00:00 2001 From: DB p Date: Tue, 27 May 2025 14:08:32 +0900 Subject: [PATCH 20/53] Fix file explorer invocation to ensure correct file selection behavior --- Flow.Launcher/PublicAPIInstance.cs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Flow.Launcher/PublicAPIInstance.cs b/Flow.Launcher/PublicAPIInstance.cs index 66e11f881..93567288c 100644 --- a/Flow.Launcher/PublicAPIInstance.cs +++ b/Flow.Launcher/PublicAPIInstance.cs @@ -338,7 +338,10 @@ namespace Flow.Launcher // Windows File Manager explorer.StartInfo = new ProcessStartInfo { - FileName = targetPath, + FileName = "explorer.exe", + Arguments = FileNameOrFilePath is null + ? DirectoryPath // only open the directory + : $"/select,\"{targetPath}\"", // open the directory and select the file UseShellExecute = true }; } From 41c5b36fba5aa1a627c153db7fa9f7ffc525dd4b Mon Sep 17 00:00:00 2001 From: DB p Date: Tue, 27 May 2025 15:20:41 +0900 Subject: [PATCH 21/53] Enhance OpenDirectory method to support folder opening and file selection using SHOpenFolderAndSelectItems --- Flow.Launcher/PublicAPIInstance.cs | 99 +++++++++++++++++++++++------- 1 file changed, 76 insertions(+), 23 deletions(-) diff --git a/Flow.Launcher/PublicAPIInstance.cs b/Flow.Launcher/PublicAPIInstance.cs index 93567288c..58dbd3ff0 100644 --- a/Flow.Launcher/PublicAPIInstance.cs +++ b/Flow.Launcher/PublicAPIInstance.cs @@ -8,6 +8,7 @@ using System.IO; using System.Linq; using System.Net; using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; using System.Threading; using System.Threading.Tasks; using System.Windows; @@ -320,47 +321,98 @@ namespace Flow.Launcher ((PluginJsonStorage)_pluginJsonStorages[type]).Save(); } - public void OpenDirectory(string DirectoryPath, string FileNameOrFilePath = null) + [DllImport("shell32.dll", CharSet = CharSet.Unicode)] + private static extern int SHParseDisplayName( + [MarshalAs(UnmanagedType.LPWStr)] string name, + IntPtr bindingContext, + out IntPtr pidl, + uint sfgaoIn, + out uint psfgaoOut + ); + + [DllImport("shell32.dll")] + private static extern int SHOpenFolderAndSelectItems( + IntPtr pidlFolder, + uint cidl, + [MarshalAs(UnmanagedType.LPArray)] IntPtr[] apidl, + uint dwFlags + ); + + [DllImport("ole32.dll")] + private static extern void CoTaskMemFree(IntPtr pv); + + private void OpenFolderAndSelectItem(string filePath) + { + IntPtr pidlFolder = IntPtr.Zero; + IntPtr pidlFile = IntPtr.Zero; + uint attr; + + string folderPath = Path.GetDirectoryName(filePath); + + try + { + SHParseDisplayName(folderPath, IntPtr.Zero, out pidlFolder, 0, out attr); + SHParseDisplayName(filePath, IntPtr.Zero, out pidlFile, 0, out attr); + + if (pidlFolder != IntPtr.Zero && pidlFile != IntPtr.Zero) + { + SHOpenFolderAndSelectItems(pidlFolder, 1, new[] { pidlFile }, 0); + } + } + finally + { + if (pidlFile != IntPtr.Zero) + CoTaskMemFree(pidlFile); + if (pidlFolder != IntPtr.Zero) + CoTaskMemFree(pidlFolder); + } + } + + public void OpenDirectory(string directoryPath, string fileNameOrFilePath = null) { try { - using var explorer = new Process(); + string targetPath = fileNameOrFilePath is null + ? directoryPath + : Path.IsPathRooted(fileNameOrFilePath) + ? fileNameOrFilePath + : Path.Combine(directoryPath, fileNameOrFilePath); + var explorerInfo = _settings.CustomExplorer; var explorerPath = explorerInfo.Path.Trim().ToLowerInvariant(); - var targetPath = FileNameOrFilePath is null - ? DirectoryPath - : Path.IsPathRooted(FileNameOrFilePath) - ? FileNameOrFilePath - : Path.Combine(DirectoryPath, FileNameOrFilePath); if (Path.GetFileNameWithoutExtension(explorerPath) == "explorer") { - // Windows File Manager - explorer.StartInfo = new ProcessStartInfo + if (fileNameOrFilePath is null) { - FileName = "explorer.exe", - Arguments = FileNameOrFilePath is null - ? DirectoryPath // only open the directory - : $"/select,\"{targetPath}\"", // open the directory and select the file - UseShellExecute = true - }; + // 폴더만 열기 + Process.Start(new ProcessStartInfo + { + FileName = directoryPath, + UseShellExecute = true + })?.Dispose(); + } + else + { + // SHOpenFolderAndSelectItems 방식 + OpenFolderAndSelectItem(targetPath); + } } else { - // Custom File Manager - explorer.StartInfo = new ProcessStartInfo + // 커스텀 파일 관리자 + var shellProcess = new ProcessStartInfo { - FileName = explorerInfo.Path.Replace("%d", DirectoryPath), + FileName = explorerInfo.Path.Replace("%d", directoryPath), UseShellExecute = true, - Arguments = FileNameOrFilePath is null - ? explorerInfo.DirectoryArgument.Replace("%d", DirectoryPath) + Arguments = fileNameOrFilePath is null + ? explorerInfo.DirectoryArgument.Replace("%d", directoryPath) : explorerInfo.FileArgument - .Replace("%d", DirectoryPath) + .Replace("%d", directoryPath) .Replace("%f", targetPath) }; + Process.Start(shellProcess)?.Dispose(); } - - explorer.Start(); } catch (Win32Exception ex) when (ex.NativeErrorCode == 2) { @@ -384,6 +436,7 @@ namespace Flow.Launcher } } + private void OpenUri(Uri uri, bool? inPrivate = null) { if (uri.Scheme == Uri.UriSchemeHttp || uri.Scheme == Uri.UriSchemeHttps) From 086aeab6c05f4b2ab13e6d0a8239db7d83c588b1 Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Tue, 27 May 2025 14:36:09 +0800 Subject: [PATCH 22/53] Use PInvoke to improve code quality --- .../NativeMethods.txt | 4 + Flow.Launcher.Infrastructure/Win32Helper.cs | 31 ++++++++ Flow.Launcher/PublicAPIInstance.cs | 76 ++++--------------- 3 files changed, 50 insertions(+), 61 deletions(-) diff --git a/Flow.Launcher.Infrastructure/NativeMethods.txt b/Flow.Launcher.Infrastructure/NativeMethods.txt index 0e50420b0..2591506c8 100644 --- a/Flow.Launcher.Infrastructure/NativeMethods.txt +++ b/Flow.Launcher.Infrastructure/NativeMethods.txt @@ -57,3 +57,7 @@ LOCALE_TRANSIENT_KEYBOARD1 LOCALE_TRANSIENT_KEYBOARD2 LOCALE_TRANSIENT_KEYBOARD3 LOCALE_TRANSIENT_KEYBOARD4 + +SHParseDisplayName +SHOpenFolderAndSelectItems +CoTaskMemFree diff --git a/Flow.Launcher.Infrastructure/Win32Helper.cs b/Flow.Launcher.Infrastructure/Win32Helper.cs index 783ade14e..4952eec98 100644 --- a/Flow.Launcher.Infrastructure/Win32Helper.cs +++ b/Flow.Launcher.Infrastructure/Win32Helper.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.ComponentModel; using System.Diagnostics; using System.Globalization; +using System.IO; using System.Linq; using System.Runtime.InteropServices; using System.Threading; @@ -17,6 +18,7 @@ using Windows.Win32; using Windows.Win32.Foundation; using Windows.Win32.Graphics.Dwm; using Windows.Win32.UI.Input.KeyboardAndMouse; +using Windows.Win32.UI.Shell.Common; using Windows.Win32.UI.WindowsAndMessaging; using Point = System.Windows.Point; using SystemFonts = System.Windows.SystemFonts; @@ -753,5 +755,34 @@ namespace Flow.Launcher.Infrastructure } #endregion + + #region Explorer + + public static unsafe void OpenFolderAndSelectFile(string filePath) + { + ITEMIDLIST* pidlFolder = null; + ITEMIDLIST* pidlFile = null; + + var folderPath = Path.GetDirectoryName(filePath); + + try + { + var hrFolder = PInvoke.SHParseDisplayName(folderPath, null, out pidlFolder, 0, null); + if (hrFolder.Failed) throw new COMException("Failed to parse folder path", hrFolder); + + var hrFile = PInvoke.SHParseDisplayName(filePath, null, out pidlFile, 0, null); + if (hrFile.Failed) throw new COMException("Failed to parse file path", hrFile); + + var hrSelect = PInvoke.SHOpenFolderAndSelectItems(pidlFolder, 1, &pidlFile, 0); + if (hrSelect.Failed) throw new COMException("Failed to open folder and select item", hrSelect); + } + finally + { + if (pidlFile != null) PInvoke.CoTaskMemFree(pidlFile); + if (pidlFolder != null) PInvoke.CoTaskMemFree(pidlFolder); + } + } + + #endregion } } diff --git a/Flow.Launcher/PublicAPIInstance.cs b/Flow.Launcher/PublicAPIInstance.cs index 58dbd3ff0..c06c56039 100644 --- a/Flow.Launcher/PublicAPIInstance.cs +++ b/Flow.Launcher/PublicAPIInstance.cs @@ -8,11 +8,9 @@ using System.IO; using System.Linq; using System.Net; using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; using System.Threading; using System.Threading.Tasks; using System.Windows; -using System.Windows.Input; using System.Windows.Media; using CommunityToolkit.Mvvm.DependencyInjection; using Flow.Launcher.Core; @@ -320,88 +318,44 @@ namespace Flow.Launcher ((PluginJsonStorage)_pluginJsonStorages[type]).Save(); } - - [DllImport("shell32.dll", CharSet = CharSet.Unicode)] - private static extern int SHParseDisplayName( - [MarshalAs(UnmanagedType.LPWStr)] string name, - IntPtr bindingContext, - out IntPtr pidl, - uint sfgaoIn, - out uint psfgaoOut - ); - - [DllImport("shell32.dll")] - private static extern int SHOpenFolderAndSelectItems( - IntPtr pidlFolder, - uint cidl, - [MarshalAs(UnmanagedType.LPArray)] IntPtr[] apidl, - uint dwFlags - ); - - [DllImport("ole32.dll")] - private static extern void CoTaskMemFree(IntPtr pv); - - private void OpenFolderAndSelectItem(string filePath) - { - IntPtr pidlFolder = IntPtr.Zero; - IntPtr pidlFile = IntPtr.Zero; - uint attr; - - string folderPath = Path.GetDirectoryName(filePath); - - try - { - SHParseDisplayName(folderPath, IntPtr.Zero, out pidlFolder, 0, out attr); - SHParseDisplayName(filePath, IntPtr.Zero, out pidlFile, 0, out attr); - - if (pidlFolder != IntPtr.Zero && pidlFile != IntPtr.Zero) - { - SHOpenFolderAndSelectItems(pidlFolder, 1, new[] { pidlFile }, 0); - } - } - finally - { - if (pidlFile != IntPtr.Zero) - CoTaskMemFree(pidlFile); - if (pidlFolder != IntPtr.Zero) - CoTaskMemFree(pidlFolder); - } - } public void OpenDirectory(string directoryPath, string fileNameOrFilePath = null) { try { - string targetPath = fileNameOrFilePath is null + var explorerInfo = _settings.CustomExplorer; + var explorerPath = explorerInfo.Path.Trim().ToLowerInvariant(); + var targetPath = fileNameOrFilePath is null ? directoryPath : Path.IsPathRooted(fileNameOrFilePath) ? fileNameOrFilePath : Path.Combine(directoryPath, fileNameOrFilePath); - var explorerInfo = _settings.CustomExplorer; - var explorerPath = explorerInfo.Path.Trim().ToLowerInvariant(); - if (Path.GetFileNameWithoutExtension(explorerPath) == "explorer") { + // Windows File Manager if (fileNameOrFilePath is null) { - // 폴더만 열기 - Process.Start(new ProcessStartInfo + // Only Open the directory + using var explorer = new Process(); + explorer.StartInfo = new ProcessStartInfo { FileName = directoryPath, UseShellExecute = true - })?.Dispose(); + }; + explorer.Start(); } else { - // SHOpenFolderAndSelectItems 방식 - OpenFolderAndSelectItem(targetPath); + // Open the directory and select the file + Win32Helper.OpenFolderAndSelectFile(targetPath); } } else { - // 커스텀 파일 관리자 - var shellProcess = new ProcessStartInfo + // Custom File Manager + using var explorer = new Process(); + explorer.StartInfo = new ProcessStartInfo { FileName = explorerInfo.Path.Replace("%d", directoryPath), UseShellExecute = true, @@ -411,7 +365,7 @@ namespace Flow.Launcher .Replace("%d", directoryPath) .Replace("%f", targetPath) }; - Process.Start(shellProcess)?.Dispose(); + explorer.Start(); } } catch (Win32Exception ex) when (ex.NativeErrorCode == 2) From eb69ce919e65b7b35fe48722f7a7ba8e9aa49096 Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Tue, 27 May 2025 14:36:24 +0800 Subject: [PATCH 23/53] Add url comments --- Flow.Launcher.Infrastructure/Win32Helper.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Flow.Launcher.Infrastructure/Win32Helper.cs b/Flow.Launcher.Infrastructure/Win32Helper.cs index 4952eec98..96d8e925b 100644 --- a/Flow.Launcher.Infrastructure/Win32Helper.cs +++ b/Flow.Launcher.Infrastructure/Win32Helper.cs @@ -758,6 +758,8 @@ namespace Flow.Launcher.Infrastructure #region Explorer + // https://learn.microsoft.com/en-us/windows/win32/api/shlobj_core/nf-shlobj_core-shopenfolderandselectitems + public static unsafe void OpenFolderAndSelectFile(string filePath) { ITEMIDLIST* pidlFolder = null; From 489699ca89a86047509a1dc8a8dd180d986d22b1 Mon Sep 17 00:00:00 2001 From: Jeremy Wu Date: Tue, 27 May 2025 10:46:07 +0000 Subject: [PATCH 24/53] add update PR script --- .github/update_release_pr.py | 103 +++++++++++++++++++++++++++++++++++ 1 file changed, 103 insertions(+) create mode 100644 .github/update_release_pr.py diff --git a/.github/update_release_pr.py b/.github/update_release_pr.py new file mode 100644 index 000000000..a9d11651b --- /dev/null +++ b/.github/update_release_pr.py @@ -0,0 +1,103 @@ +import os +import requests + +def get_github_prs(token, owner, repo, milestone, label, state): + """ + Fetches pull requests from a GitHub repository that match a given milestone and label. + + Args: + token (str): GitHub token. + owner (str): The owner of the repository. + repo (str): The name of the repository. + milestone (str): The milestone title. + label (str): The label name. + state (str): State of PR, e.g. open + + Returns: + list: A list of dictionaries, where each dictionary represents a pull request. + Returns an empty list if no PRs are found or an error occurs. + """ + headers = { + "Authorization": f"token {token}", + "Accept": "application/vnd.github.v3+json", + } + + milestone_id = None + milestone_url = f"https://api.github.com/repos/{owner}/{repo}/milestones" + params = {"state": state} + + try: + response = requests.get(milestone_url, headers=headers, params=params) + response.raise_for_status() + milestones = response.json() + for ms in milestones: + if ms["title"] == milestone: + milestone_id = ms["number"] + break + + if not milestone_id: + print(f"Milestone '{milestone}' not found in repository '{owner}/{repo}'.") + return [] + + except requests.exceptions.RequestException as e: + print(f"Error fetching milestones: {e}") + return [] + + prs_url = f"https://api.github.com/repos/{owner}/{repo}/pulls" + params = { + "state": state, + "milestone": milestone_id, + "labels": label, + } + + all_prs = [] + page = 1 + while True: + try: + params["page"] = page + response = requests.get(prs_url, headers=headers, params=params) + response.raise_for_status() # Raise an exception for HTTP errors + prs = response.json() + + if not prs: + break # No more PRs to fetch + + all_prs.extend(prs) + page += 1 + + except requests.exceptions.RequestException as e: + print(f"Error fetching pull requests: {e}") + break + + return all_prs + +if __name__ == "__main__": + github_token = os.environ.get("GITHUB_TOKEN") + + if not github_token: + print("Error: GITHUB_TOKEN environment variable not set.") + exit(1) + + repository_owner = "flow-launcher" + repository_name = "flow.launcher" + target_milestone = "1.20.0" + target_label = "enhancement" + state = "closed" + + print(f"Fetching PRs for {repository_owner}/{repository_name} with milestone '{target_milestone}' and label '{target_label}'...") + + pull_requests = get_github_prs( + github_token, + repository_owner, + repository_name, + target_milestone, + target_label, + state + ) + + if pull_requests: + print(f"\nFound {len(pull_requests)} pull requests:") + for pr in pull_requests: + print(f"- {pr['state']} #{pr['number']}: {pr['title']} (URL: {pr['html_url']})") + else: + print("No matching pull requests found.") From f79a2d24674d7f6f208a6c09c8a60ba98618ea84 Mon Sep 17 00:00:00 2001 From: Jeremy Wu Date: Tue, 27 May 2025 11:36:38 +0000 Subject: [PATCH 25/53] change to issues endpoint --- .github/update_release_pr.py | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/.github/update_release_pr.py b/.github/update_release_pr.py index a9d11651b..b51620d73 100644 --- a/.github/update_release_pr.py +++ b/.github/update_release_pr.py @@ -24,7 +24,7 @@ def get_github_prs(token, owner, repo, milestone, label, state): milestone_id = None milestone_url = f"https://api.github.com/repos/{owner}/{repo}/milestones" - params = {"state": state} + params = {"state": open} try: response = requests.get(milestone_url, headers=headers, params=params) @@ -37,17 +37,19 @@ def get_github_prs(token, owner, repo, milestone, label, state): if not milestone_id: print(f"Milestone '{milestone}' not found in repository '{owner}/{repo}'.") - return [] + exit(1) except requests.exceptions.RequestException as e: print(f"Error fetching milestones: {e}") - return [] + exit(1) - prs_url = f"https://api.github.com/repos/{owner}/{repo}/pulls" + # This endpoint allows filtering by milestone and label. A PR in GH's perspective is a type of issue. + prs_url = f"https://api.github.com/repos/{owner}/{repo}/issues" params = { "state": state, "milestone": milestone_id, "labels": label, + "per_page": 100, } all_prs = [] @@ -61,18 +63,19 @@ def get_github_prs(token, owner, repo, milestone, label, state): if not prs: break # No more PRs to fetch - - all_prs.extend(prs) + + # Check for pr key since we are using issues endpoint instead. + all_prs.extend([item for item in prs if "pull_request" in item]) page += 1 except requests.exceptions.RequestException as e: print(f"Error fetching pull requests: {e}") - break + exit(1) return all_prs if __name__ == "__main__": - github_token = os.environ.get("GITHUB_TOKEN") + github_token = os.environ.get("GITHUB_TOKEN") if not github_token: print("Error: GITHUB_TOKEN environment variable not set.") From 55b69c601a12899f054cedab4956a2cb0dcf95e5 Mon Sep 17 00:00:00 2001 From: Jeremy Wu Date: Wed, 28 May 2025 11:20:39 +0000 Subject: [PATCH 26/53] get milestone dynamically --- .github/update_release_pr.py | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/.github/update_release_pr.py b/.github/update_release_pr.py index b51620d73..c00683439 100644 --- a/.github/update_release_pr.py +++ b/.github/update_release_pr.py @@ -1,7 +1,7 @@ import os import requests -def get_github_prs(token, owner, repo, milestone, label, state): +def get_github_prs(token, owner, repo, label, state): """ Fetches pull requests from a GitHub repository that match a given milestone and label. @@ -9,7 +9,6 @@ def get_github_prs(token, owner, repo, milestone, label, state): token (str): GitHub token. owner (str): The owner of the repository. repo (str): The name of the repository. - milestone (str): The milestone title. label (str): The label name. state (str): State of PR, e.g. open @@ -30,13 +29,19 @@ def get_github_prs(token, owner, repo, milestone, label, state): response = requests.get(milestone_url, headers=headers, params=params) response.raise_for_status() milestones = response.json() + + if len(milestones) > 2: + print("More than two milestones found, unable to determine the milestone required.") + + # milestones.pop() for ms in milestones: - if ms["title"] == milestone: + if ms["title"] != "Future": milestone_id = ms["number"] + print(f"Gathering PRs with milestone {ms['title']}..." ) break if not milestone_id: - print(f"Milestone '{milestone}' not found in repository '{owner}/{repo}'.") + print(f"No suitable milestone found in repository '{owner}/{repo}'.") exit(1) except requests.exceptions.RequestException as e: @@ -83,17 +88,15 @@ if __name__ == "__main__": repository_owner = "flow-launcher" repository_name = "flow.launcher" - target_milestone = "1.20.0" target_label = "enhancement" state = "closed" - print(f"Fetching PRs for {repository_owner}/{repository_name} with milestone '{target_milestone}' and label '{target_label}'...") + print(f"Fetching PRs for {repository_owner}/{repository_name} with label '{target_label}'...") pull_requests = get_github_prs( github_token, repository_owner, repository_name, - target_milestone, target_label, state ) From 0b616d8721d432fe940c2683c2edfb9695641bf3 Mon Sep 17 00:00:00 2001 From: Jeremy Wu Date: Wed, 28 May 2025 12:03:13 +0000 Subject: [PATCH 27/53] add pr update --- .github/update_release_pr.py | 84 +++++++++++++++++++++++++++++++++--- 1 file changed, 77 insertions(+), 7 deletions(-) diff --git a/.github/update_release_pr.py b/.github/update_release_pr.py index c00683439..b03b0c425 100644 --- a/.github/update_release_pr.py +++ b/.github/update_release_pr.py @@ -79,6 +79,53 @@ def get_github_prs(token, owner, repo, label, state): return all_prs +def update_pull_request_description(token, owner, repo, pr_number, new_description): + """ + Updates the description (body) of a GitHub Pull Request. + + Args: + token (str): Token. + owner (str): The owner of the repository. + repo (str): The name of the repository. + pr_number (int): The number of the pull request to update. + new_description (str): The new content for the PR's description. + + Returns: + dict or None: The updated PR object (as a dictionary) if successful, + None otherwise. + """ + headers = { + "Authorization": f"token {token}", + "Accept": "application/vnd.github.v3+json", + "Content-Type": "application/json" + } + + url = f"https://api.github.com/repos/{owner}/{repo}/pulls/{pr_number}" + + payload = { + "body": new_description + } + + print(f"Attempting to update PR #{pr_number} in {owner}/{repo}...") + print(f"URL: {url}") + # print(f"Payload: {payload}") # Uncomment for detailed payload debug + + try: + response = requests.patch(url, headers=headers, json=payload) + response.raise_for_status() + + updated_pr_data = response.json() + print(f"Successfully updated PR #{pr_number}.") + return updated_pr_data + + except requests.exceptions.RequestException as e: + print(f"Error updating pull request #{pr_number}: {e}") + if response is not None: + print(f"Response status code: {response.status_code}") + print(f"Response text: {response.text}") + return None + + if __name__ == "__main__": github_token = os.environ.get("GITHUB_TOKEN") @@ -92,7 +139,7 @@ if __name__ == "__main__": state = "closed" print(f"Fetching PRs for {repository_owner}/{repository_name} with label '{target_label}'...") - + pull_requests = get_github_prs( github_token, repository_owner, @@ -101,9 +148,32 @@ if __name__ == "__main__": state ) - if pull_requests: - print(f"\nFound {len(pull_requests)} pull requests:") - for pr in pull_requests: - print(f"- {pr['state']} #{pr['number']}: {pr['title']} (URL: {pr['html_url']})") - else: - print("No matching pull requests found.") + if not pull_requests: + print("No matching pull requests found") + exit(1) + + print(f"\nFound {len(pull_requests)} pull requests:") + + description_content = "" + for pr in pull_requests: + description_content+= f"- {pr['title']} #{pr['number']}\n" + + returned_pr = pull_requests = get_github_prs( + github_token, + repository_owner, + repository_name, + "release", + "open" + ) + + if len(returned_pr) != 1: + print(f"Unable to find the exact release PR. Returned result: {returned_pr}") + exit(1) + + release_pr = returned_pr[0] + + print(f"Found release PR: {release_pr['title']}") + + update_pull_request_description(github_token, repository_owner, repository_name, release_pr["number"], description_content) + + print(description_content) \ No newline at end of file From c33e9dedb85b8e11fdda534edef07875cd765879 Mon Sep 17 00:00:00 2001 From: DB P Date: Fri, 30 May 2025 13:20:16 +0900 Subject: [PATCH 28/53] Update delete confirmation message for folder link in context menu --- Plugins/Flow.Launcher.Plugin.Explorer/ContextMenu.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/ContextMenu.cs b/Plugins/Flow.Launcher.Plugin.Explorer/ContextMenu.cs index eabd118fb..db0128b3b 100644 --- a/Plugins/Flow.Launcher.Plugin.Explorer/ContextMenu.cs +++ b/Plugins/Flow.Launcher.Plugin.Explorer/ContextMenu.cs @@ -199,7 +199,7 @@ namespace Flow.Launcher.Plugin.Explorer { if (Context.API.ShowMsgBox( string.Format(Context.API.GetTranslation("plugin_explorer_delete_folder_link"), record.FullPath), - string.Empty, + Context.API.GetTranslation("plugin_explorer_deletefilefolder"), MessageBoxButton.YesNo, MessageBoxImage.Warning) == MessageBoxResult.No) From ebb74da8b39b92c7621d201a687bc3e5efd40928 Mon Sep 17 00:00:00 2001 From: DB P Date: Fri, 30 May 2025 13:37:50 +0900 Subject: [PATCH 29/53] Refactor key press handling in MessageBoxEx to improve result assignment logic --- Flow.Launcher/MessageBoxEx.xaml.cs | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/Flow.Launcher/MessageBoxEx.xaml.cs b/Flow.Launcher/MessageBoxEx.xaml.cs index c084b5149..510d14b89 100644 --- a/Flow.Launcher/MessageBoxEx.xaml.cs +++ b/Flow.Launcher/MessageBoxEx.xaml.cs @@ -159,12 +159,19 @@ namespace Flow.Launcher private void KeyEsc_OnPress(object sender, ExecutedRoutedEventArgs e) { - if (_button == MessageBoxButton.YesNo) - return; - else if (_button == MessageBoxButton.OK) - _result = MessageBoxResult.OK; - else - _result = MessageBoxResult.Cancel; + switch (_button) + { + case MessageBoxButton.OK: + _result = MessageBoxResult.None; + break; + case MessageBoxButton.OKCancel: + case MessageBoxButton.YesNoCancel: + _result = MessageBoxResult.Cancel; + break; + case MessageBoxButton.YesNo: + _result = MessageBoxResult.No; + break; + } DialogResult = false; Close(); } From 05486eae260622b35cb76b8dc421130144c057b6 Mon Sep 17 00:00:00 2001 From: DB P Date: Fri, 30 May 2025 14:45:19 +0900 Subject: [PATCH 30/53] Add OpenHistory hotkey functionality and binding --- Flow.Launcher.Infrastructure/UserSettings/Settings.cs | 4 +++- Flow.Launcher/HotkeyControl.xaml.cs | 5 +++++ Flow.Launcher/MainWindow.xaml | 8 ++++---- Flow.Launcher/SettingPages/Views/SettingsPaneHotkey.xaml | 5 ++++- Flow.Launcher/ViewModel/MainViewModel.cs | 4 ++++ 5 files changed, 20 insertions(+), 6 deletions(-) diff --git a/Flow.Launcher.Infrastructure/UserSettings/Settings.cs b/Flow.Launcher.Infrastructure/UserSettings/Settings.cs index f00f42ac0..892045994 100644 --- a/Flow.Launcher.Infrastructure/UserSettings/Settings.cs +++ b/Flow.Launcher.Infrastructure/UserSettings/Settings.cs @@ -50,6 +50,7 @@ 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 OpenHistoryHotkey { get; set; } = $"Ctrl+H"; public string CycleHistoryUpHotkey { get; set; } = $"{KeyConstant.Alt} + Up"; public string CycleHistoryDownHotkey { get; set; } = $"{KeyConstant.Alt} + Down"; @@ -426,6 +427,8 @@ namespace Flow.Launcher.Infrastructure.UserSettings list.Add(new(SelectPrevItemHotkey2, "SelectPrevItemHotkey", () => SelectPrevItemHotkey2 = "")); if (!string.IsNullOrEmpty(SettingWindowHotkey)) list.Add(new(SettingWindowHotkey, "SettingWindowHotkey", () => SettingWindowHotkey = "")); + if (!string.IsNullOrEmpty(OpenHistoryHotkey)) + list.Add(new(OpenHistoryHotkey, "OpenHistoryHotkey", () => OpenHistoryHotkey = "")); if (!string.IsNullOrEmpty(OpenContextMenuHotkey)) list.Add(new(OpenContextMenuHotkey, "OpenContextMenuHotkey", () => OpenContextMenuHotkey = "")); if (!string.IsNullOrEmpty(SelectNextPageHotkey)) @@ -461,7 +464,6 @@ namespace Flow.Launcher.Infrastructure.UserSettings 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"), diff --git a/Flow.Launcher/HotkeyControl.xaml.cs b/Flow.Launcher/HotkeyControl.xaml.cs index 262727127..e8961058c 100644 --- a/Flow.Launcher/HotkeyControl.xaml.cs +++ b/Flow.Launcher/HotkeyControl.xaml.cs @@ -100,6 +100,7 @@ namespace Flow.Launcher PreviewHotkey, OpenContextMenuHotkey, SettingWindowHotkey, + OpenHistoryHotkey, CycleHistoryUpHotkey, CycleHistoryDownHotkey, SelectPrevPageHotkey, @@ -130,6 +131,7 @@ namespace Flow.Launcher HotkeyType.PreviewHotkey => _settings.PreviewHotkey, HotkeyType.OpenContextMenuHotkey => _settings.OpenContextMenuHotkey, HotkeyType.SettingWindowHotkey => _settings.SettingWindowHotkey, + HotkeyType.OpenHistoryHotkey => _settings.OpenHistoryHotkey, HotkeyType.CycleHistoryUpHotkey => _settings.CycleHistoryUpHotkey, HotkeyType.CycleHistoryDownHotkey => _settings.CycleHistoryDownHotkey, HotkeyType.SelectPrevPageHotkey => _settings.SelectPrevPageHotkey, @@ -166,6 +168,9 @@ namespace Flow.Launcher case HotkeyType.SettingWindowHotkey: _settings.SettingWindowHotkey = value; break; + case HotkeyType.OpenHistoryHotkey: + _settings.OpenHistoryHotkey = value; + break; case HotkeyType.CycleHistoryUpHotkey: _settings.CycleHistoryUpHotkey = value; break; diff --git a/Flow.Launcher/MainWindow.xaml b/Flow.Launcher/MainWindow.xaml index 31bc2ba50..413315faf 100644 --- a/Flow.Launcher/MainWindow.xaml +++ b/Flow.Launcher/MainWindow.xaml @@ -64,10 +64,6 @@ Key="R" Command="{Binding ReQueryCommand}" Modifiers="Ctrl" /> - + - + VerifyOrSetDefaultHotkey(Settings.SelectPrevPageHotkey, ""); public string OpenContextMenuHotkey => VerifyOrSetDefaultHotkey(Settings.OpenContextMenuHotkey, "Ctrl+O"); public string SettingWindowHotkey => VerifyOrSetDefaultHotkey(Settings.SettingWindowHotkey, "Ctrl+I"); + public string OpenHistoryHotkey => VerifyOrSetDefaultHotkey(Settings.OpenHistoryHotkey, "Ctrl+H"); public string CycleHistoryUpHotkey => VerifyOrSetDefaultHotkey(Settings.CycleHistoryUpHotkey, "Alt+Up"); public string CycleHistoryDownHotkey => VerifyOrSetDefaultHotkey(Settings.CycleHistoryDownHotkey, "Alt+Down"); From e6eb8c01c05672e4908e04be52649b6c027314f1 Mon Sep 17 00:00:00 2001 From: DB P Date: Fri, 30 May 2025 14:48:25 +0900 Subject: [PATCH 31/53] Revert key press handling --- Flow.Launcher/MessageBoxEx.xaml.cs | 19 ++++++------------- 1 file changed, 6 insertions(+), 13 deletions(-) diff --git a/Flow.Launcher/MessageBoxEx.xaml.cs b/Flow.Launcher/MessageBoxEx.xaml.cs index 510d14b89..c084b5149 100644 --- a/Flow.Launcher/MessageBoxEx.xaml.cs +++ b/Flow.Launcher/MessageBoxEx.xaml.cs @@ -159,19 +159,12 @@ namespace Flow.Launcher private void KeyEsc_OnPress(object sender, ExecutedRoutedEventArgs e) { - switch (_button) - { - case MessageBoxButton.OK: - _result = MessageBoxResult.None; - break; - case MessageBoxButton.OKCancel: - case MessageBoxButton.YesNoCancel: - _result = MessageBoxResult.Cancel; - break; - case MessageBoxButton.YesNo: - _result = MessageBoxResult.No; - break; - } + if (_button == MessageBoxButton.YesNo) + return; + else if (_button == MessageBoxButton.OK) + _result = MessageBoxResult.OK; + else + _result = MessageBoxResult.Cancel; DialogResult = false; Close(); } From 7c718ce0614949ef2f56638efeca97e1af881909 Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Fri, 30 May 2025 15:28:39 +0800 Subject: [PATCH 32/53] Add code comments --- Flow.Launcher/MessageBoxEx.xaml.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Flow.Launcher/MessageBoxEx.xaml.cs b/Flow.Launcher/MessageBoxEx.xaml.cs index c084b5149..7296ff4ca 100644 --- a/Flow.Launcher/MessageBoxEx.xaml.cs +++ b/Flow.Launcher/MessageBoxEx.xaml.cs @@ -160,6 +160,7 @@ namespace Flow.Launcher private void KeyEsc_OnPress(object sender, ExecutedRoutedEventArgs e) { if (_button == MessageBoxButton.YesNo) + // Follow System.Windows.MessageBox behavior return; else if (_button == MessageBoxButton.OK) _result = MessageBoxResult.OK; @@ -188,6 +189,7 @@ namespace Flow.Launcher private void Button_Cancel(object sender, RoutedEventArgs e) { if (_button == MessageBoxButton.YesNo) + // Follow System.Windows.MessageBox behavior return; else if (_button == MessageBoxButton.OK) _result = MessageBoxResult.OK; From abef6177998bc6ab6d03ab19fcaf93548bbe59d1 Mon Sep 17 00:00:00 2001 From: DB P Date: Fri, 30 May 2025 17:35:24 +0900 Subject: [PATCH 33/53] Change delete confirmation dialog from Yes/No to OK/Cancel --- Plugins/Flow.Launcher.Plugin.Explorer/ContextMenu.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Plugins/Flow.Launcher.Plugin.Explorer/ContextMenu.cs b/Plugins/Flow.Launcher.Plugin.Explorer/ContextMenu.cs index db0128b3b..896fc9922 100644 --- a/Plugins/Flow.Launcher.Plugin.Explorer/ContextMenu.cs +++ b/Plugins/Flow.Launcher.Plugin.Explorer/ContextMenu.cs @@ -200,9 +200,9 @@ namespace Flow.Launcher.Plugin.Explorer if (Context.API.ShowMsgBox( string.Format(Context.API.GetTranslation("plugin_explorer_delete_folder_link"), record.FullPath), Context.API.GetTranslation("plugin_explorer_deletefilefolder"), - MessageBoxButton.YesNo, + MessageBoxButton.OKCancel, MessageBoxImage.Warning) - == MessageBoxResult.No) + == MessageBoxResult.Cancel) return false; if (isFile) From 70fcc848932e8f8f812896bc9b0a1acefc092c87 Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Sat, 31 May 2025 17:15:39 +0800 Subject: [PATCH 34/53] Use ResultContextMenu instead of ContextMenu --- Flow.Launcher/MainWindow.xaml | 6 +++--- Flow.Launcher/MainWindow.xaml.cs | 20 +++++++++---------- .../SettingPages/Views/SettingsPaneTheme.xaml | 2 +- Flow.Launcher/Themes/Base.xaml | 2 +- 4 files changed, 15 insertions(+), 15 deletions(-) diff --git a/Flow.Launcher/MainWindow.xaml b/Flow.Launcher/MainWindow.xaml index 413315faf..9ff38a564 100644 --- a/Flow.Launcher/MainWindow.xaml +++ b/Flow.Launcher/MainWindow.xaml @@ -359,7 +359,7 @@ - + @@ -373,7 +373,7 @@ - + @@ -419,7 +419,7 @@ diff --git a/Flow.Launcher/MainWindow.xaml.cs b/Flow.Launcher/MainWindow.xaml.cs index bb29d78e5..0048c8aa9 100644 --- a/Flow.Launcher/MainWindow.xaml.cs +++ b/Flow.Launcher/MainWindow.xaml.cs @@ -295,14 +295,14 @@ namespace Flow.Launcher // QueryTextBox.Text change detection (modified to only work when character count is 1 or higher) QueryTextBox.TextChanged += (s, e) => UpdateClockPanelVisibility(); - // Detecting ContextMenu.Visibility changes + // Detecting ResultContextMenu.Visibility changes DependencyPropertyDescriptor - .FromProperty(VisibilityProperty, typeof(ContextMenu)) - .AddValueChanged(ContextMenu, (s, e) => UpdateClockPanelVisibility()); + .FromProperty(VisibilityProperty, typeof(ResultListBox)) + .AddValueChanged(ResultContextMenu, (s, e) => UpdateClockPanelVisibility()); // Detect History.Visibility changes DependencyPropertyDescriptor - .FromProperty(VisibilityProperty, typeof(StackPanel)) + .FromProperty(VisibilityProperty, typeof(ResultListBox)) .AddValueChanged(History, (s, e) => UpdateClockPanelVisibility()); // Initialize query state @@ -1016,7 +1016,7 @@ namespace Flow.Launcher private void UpdateClockPanelVisibility() { - if (QueryTextBox == null || ContextMenu == null || History == null || ClockPanel == null) + if (QueryTextBox == null || ResultContextMenu == null || History == null || ClockPanel == null) { return; } @@ -1031,20 +1031,20 @@ namespace Flow.Launcher }; var animationDuration = TimeSpan.FromMilliseconds(animationLength * 2 / 3); - // ✅ Conditions for showing ClockPanel (No query input & ContextMenu, History are closed) + // ✅ Conditions for showing ClockPanel (No query input / ResultContextMenu & History are closed) var shouldShowClock = QueryTextBox.Text.Length == 0 && - ContextMenu.Visibility != Visibility.Visible && + ResultContextMenu.Visibility != Visibility.Visible && History.Visibility != Visibility.Visible; - // ✅ 1. When ContextMenu opens, immediately set Visibility.Hidden (force hide without animation) - if (ContextMenu.Visibility == Visibility.Visible) + // ✅ 1. When ResultContextMenu opens, immediately set Visibility.Hidden (force hide without animation) + if (ResultContextMenu.Visibility == Visibility.Visible) { _viewModel.ClockPanelVisibility = Visibility.Hidden; _viewModel.ClockPanelOpacity = 0.0; // Set to 0 in case Opacity animation affects it return; } - // ✅ 2. When ContextMenu is closed, keep it Hidden if there's text in the query (remember previous state) + // ✅ 2. When ResultContextMenu is closed, keep it Hidden if there's text in the query (remember previous state) else if (QueryTextBox.Text.Length > 0) { _viewModel.ClockPanelVisibility = Visibility.Hidden; diff --git a/Flow.Launcher/SettingPages/Views/SettingsPaneTheme.xaml b/Flow.Launcher/SettingPages/Views/SettingsPaneTheme.xaml index 700dc3a91..6e16012ac 100644 --- a/Flow.Launcher/SettingPages/Views/SettingsPaneTheme.xaml +++ b/Flow.Launcher/SettingPages/Views/SettingsPaneTheme.xaml @@ -374,7 +374,7 @@ IsHitTestVisible="False" Visibility="Visible" /> - + diff --git a/Flow.Launcher/Themes/Base.xaml b/Flow.Launcher/Themes/Base.xaml index 1844e25be..e531c17ad 100644 --- a/Flow.Launcher/Themes/Base.xaml +++ b/Flow.Launcher/Themes/Base.xaml @@ -479,7 +479,7 @@ + --> From 62359140a42b74048bf9a2d5e505ea0a7b16e541 Mon Sep 17 00:00:00 2001 From: DB P Date: Sun, 1 Jun 2025 19:34:49 +0900 Subject: [PATCH 35/53] Update Advanced title and reset button content to use dynamic resources --- Flow.Launcher/Languages/en.xaml | 1 + Flow.Launcher/SettingPages/Views/SettingsPaneAbout.xaml | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/Flow.Launcher/Languages/en.xaml b/Flow.Launcher/Languages/en.xaml index f233a30d5..28673c753 100644 --- a/Flow.Launcher/Languages/en.xaml +++ b/Flow.Launcher/Languages/en.xaml @@ -359,6 +359,7 @@ User Data Location User settings and installed plugins are saved in the user data folder. This location may vary depending on whether it's in portable mode or not. Open Folder + Advanced Log Level Debug Info diff --git a/Flow.Launcher/SettingPages/Views/SettingsPaneAbout.xaml b/Flow.Launcher/SettingPages/Views/SettingsPaneAbout.xaml index aa750cf86..65a470f4d 100644 --- a/Flow.Launcher/SettingPages/Views/SettingsPaneAbout.xaml +++ b/Flow.Launcher/SettingPages/Views/SettingsPaneAbout.xaml @@ -137,7 +137,7 @@ @@ -156,7 +156,7 @@ Icon="" Type="Inside"> -