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 01/93] =?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 de7438791ce0374975444eb0adb7b646b908463f Mon Sep 17 00:00:00 2001 From: Jack251970 <1160210343@qq.com> Date: Sun, 25 May 2025 09:14:19 +0800 Subject: [PATCH 02/93] 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 03/93] 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 04/93] 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 05/93] 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 06/93] 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 489699ca89a86047509a1dc8a8dd180d986d22b1 Mon Sep 17 00:00:00 2001 From: Jeremy Wu Date: Tue, 27 May 2025 10:46:07 +0000 Subject: [PATCH 07/93] 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 08/93] 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 09/93] 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 10/93] 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 11/93] 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 12/93] 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 13/93] 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 14/93] 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 15/93] 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 16/93] 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 17/93] 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 18/93] 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"> -