Skip to content

Quick Switch #1018

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 244 commits into
base: dev
Choose a base branch
from
Open

Quick Switch #1018

wants to merge 244 commits into from

Conversation

taooceros
Copy link
Member

@taooceros taooceros commented Feb 10, 2022

Important

Auto quick switch is an experimental feature and it can cause some possible issues, so it is marked as experimental.

Nothing more than quickswitch. We may integrate flow's path system to this feature instead of relying explorer.

Setup Quick Switch

  1. Quick switch key: Alt+G by default
  2. Quick switch automatically
  3. Quick switch window

Use Quick Switch

  1. Open explorer -> Open file dialog -> Use hotkey to navigate to that path.

  2. Open file dialog -> Query window (quick switch window) fixed under file dialog -> Click results to navigate to the selected path

Quick Switch API

Implement new api interfaces to develop third party explorers & dialogs which are for dotnet plugins only.

public interface IAsyncQuickSwitch
{
    /// <summary>
    /// Asynchronous querying for quick switch window
    /// </summary>
    Task<List<QuickSwitchResult>> QueryQuickSwitchAsync(Query query, CancellationToken token);
}
public interface IQuickSwitch : IAsyncQuickSwitch
{
    /// <summary>
    /// Querying for quick switch window
    /// </summary>
    List<QuickSwitchResult> QueryQuickSwitch(Query query);

    Task<List<QuickSwitchResult>> IAsyncQuickSwitch.QueryQuickSwitchAsync(Query query, CancellationToken token) => Task.Run(() => QueryQuickSwitch(query));
}
/// <summary>
/// Describes a result of a <see cref="Query"/> executed by a plugin in quick switch window
/// </summary>
public class QuickSwitchResult : Result
{
    /// <summary>
    /// This holds the path which can be provided by plugin to be navigated to the
    /// file dialog when records in quick switch window is right clicked on a result.
    /// </summary>
    public required string QuickSwitchPath { get; init; }

    // ...
}

Additionally, Explorer plugin already supports quick switch.

Test

  • Quick switch hotkey can change and apply.
  • Automatically quick switch can work under most cases (since it is an experimental feature)
  • Show quick switch window
  • Quick switch window position can change properly.
  • Quick switch window action can change properly.

Todos

  • https://github.com/listary/Listary.FileAppPlugin/blob/master/docs%2FGetting%20Started.md
  • Support opening file path.
  • Quick switch automatically issue for save as file dialog from @onesounds: For the Open dialog, the path changes correctly at the time the dialog is opened, even without switching focus to File Explorer.
    However, for the Save As dialog, the path does not apply immediately when the dialog is opened. It only works after switching focus to File Explorer and then returning.
  • Third party explorer.
  • Third party dialog.
  • In auto mode, the target program still closes when using "Open." (Previously reported issue) on some devices & apps from @onesounds.
  • Dialogs pop up on many other dialog windows.
  • When the bottom bar mode is active, if a dialog is closed and Flow is exited without being reopened, the window position is saved based on the bottom bar mode location. On the next launch, Flow opens at the last position used by the bottom bar mode.
  • In the "Save As" dialog, Flow automatically inputs the entire file name, which causes unintended saving.
  • Check if plugin is modified before querying (Check if plugin is modified before querying #3791)

@taooceros
Copy link
Member Author

Some threading issues seem appearing. Not sure the detailed reason.

@stefnotch
Copy link
Contributor

Okay, my main questions would be

  • What's the intended use-case for this? As in, when does a Flow plugin need to navigate in the actual file explorer, instead of opening a new one with the correct path.
  • Would opening a new file explorer window with the desired path, and closing the old one work? Or does that not handle certain cases? (e.g. the file browser/chooser )

@taooceros
Copy link
Member Author

Okay, my main questions would be

* What's the intended use-case for this? As in, when does a Flow plugin need to navigate in the actual file explorer, instead of opening a new one with the correct path.

I think the major use case is to sync the path of an opened explorer to a open file dialog to select a file easily.

Would opening a new file explorer window with the desired path, and closing the old one work? Or does that not handle certain cases? (e.g. the file browser/chooser )

Sry I don't get the idea.

@stefnotch
Copy link
Contributor

Okay, I understand what this is used for now. I'd have to dig a lot deeper into what the IUIAutomation can do to be able to improve this.

I think the rule of thumb is to avoid sending keyboard events, and instead always use an API if one exists. Keyboard events can be delayed and whatnot.

@taooceros
Copy link
Member Author

Okay, I understand what this is used for now. I'd have to dig a lot deeper into what the IUIAutomation can do to be able to improve this.

I think the rule of thumb is to avoid sending keyboard events, and instead always use an API if one exists. Keyboard events can be delayed and whatnot.

Yeah that's what I would like to see. It is possible to use PInvoke directly without IUIAutomation though, so it will be cool if you are familiar with that as well.

Another thing is the original listary seems implement this feature without changing the textbox and sending an enter signal, so I wonder whether you may have some clues about that.

@stefnotch
Copy link
Contributor

I tried searching for what I could, but that's apparently quite tricky to hook into. So I don't really have a better solution at the moment.

@taooceros
Copy link
Member Author

I tried searching for what I could, but that's apparently quite tricky to hook into. So I don't really have a better solution at the moment.

okay thanks🤣

@stefnotch
Copy link
Contributor

stefnotch commented Aug 17, 2022

There might be a alternate design:

So the file manager has the "quick access" sidebar. Flow could add its own entry there, and that entry always redirects to the currently open folder. An additional advantage might be that it's easier to discover this, compared to a keyboard shortcut.

Screenshot for context:

image

(Note: I have no idea how hard that would be to efficiently pull that off.)

@taooceros
Copy link
Member Author

So you mean to add a entry that redirect to the most recent opened explorer path?🤔Interesting

@stefnotch
Copy link
Contributor

Yep, spot-on.

@taooceros
Copy link
Member Author

Yep, spot-on.

If that's the case, we may be able to create a plugin for it.

@taooceros
Copy link
Member Author

Do you have any docs for that?

@stefnotch
Copy link
Contributor

stefnotch commented Aug 17, 2022

@taooceros I haven't looked into this all that much (just a few cursory google searches)

Programmatic access

Apparently there's a way of programmatically adding folders to the quick access area.

https://stackoverflow.com/questions/30051634/is-it-possible-programmatically-add-folders-to-the-windows-10-quick-access-panel

Special Links folder

https://blogs.msmvps.com/kenlin/2017/06/14/537/

Steps:

  1. Enable a special, built-in folder by setting a value in the system registry. Anything in this folder will land in the "quick access".
  2. Put a shortcut in that folder. (A .lnk shortcut)
  3. And then always update the shortcut's path to point at the currently open file explorer.

Symbolic links or Hardlink

I bet there's some trickery that could be done with those

Extra harddrive

We could add an in-memory harddrive, mount it and provide a single shortcut in there.
This might be a tad tricky though, depending on whether there's an easy API/wrapper or not...

@mcthesw
Copy link

mcthesw commented Oct 15, 2022

Could this be done? I really love this feature.

@VictoriousRaptor VictoriousRaptor linked an issue Nov 2, 2022 that may be closed by this pull request
@VictoriousRaptor VictoriousRaptor linked an issue Nov 27, 2022 that may be closed by this pull request
@stefnotch
Copy link
Contributor

Yet another option would be to add a "switch to" context menu entry

Sort of like how 7zip has a dynamic context menu, except that we'd populate it with the titles of other explorer windows.
image

@stefnotch
Copy link
Contributor

stefnotch commented Jan 8, 2023

Apparently Windows 11 can add files to quick access. That might let us pin a program to quick access

Such a program could then update the list of files in the quick access window.

This comment has been minimized.

This comment has been minimized.

This comment has been minimized.

@Jack251970 Jack251970 requested a review from Copilot June 28, 2025 05:53
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

♻️ Duplicate comments (9)
Flow.Launcher.Infrastructure/QuickSwitch/QuickSwitch.cs (9)

543-546: Add logging for exception handling.

catch (System.Exception ex)
{
-   // Ignored
+   Log.Debug(ClassName, $"Error checking explorer window: {ex.Message}");
}

898-900: Clear auto-switched dialogs collection in Dispose.

The Dispose method should also clear the _autoSwitchedDialogs collection to ensure complete cleanup.

// Dispose locks
+lock (_autoSwitchedDialogsLock)
+{
+    _autoSwitchedDialogs.Clear();
+}
_foregroundChangeLock.Dispose();
_navigationLock.Dispose();

411-414: Add exception handling to prevent hotkey failures.

The hotkey handler doesn't catch exceptions, which could lead to hotkey failures if the navigation logic throws exceptions.

public static void OnToggleHotkey(object sender, HotkeyEventArgs args)
{
-   _ = Task.Run(() => NavigateDialogPathAsync(PInvoke.GetForegroundWindow()));
+   try
+   {
+       _ = Task.Run(async () => 
+       {
+           try 
+           {
+               await NavigateDialogPathAsync(PInvoke.GetForegroundWindow());
+           }
+           catch (Exception ex)
+           {
+               Log.Exception(ClassName, "Error in NavigateDialogPathAsync from hotkey", ex);
+           }
+       });
+   }
+   catch (Exception ex)
+   {
+       Log.Exception(ClassName, "Error processing quickswitch hotkey", ex);
+   }
}

476-479: Use correct lock object for thread safety.

The code uses _dialogWindowHandleLock instead of _autoSwitchedDialogsLock when accessing _autoSwitchedDialogs, which could lead to race conditions.

bool alreadySwitched;
-lock (_dialogWindowHandleLock)
+lock (_autoSwitchedDialogsLock)
{
    alreadySwitched = _autoSwitchedDialogs.Contains(hwnd);
}

644-657: Add path existence validation.

The method should validate if the path exists before attempting to jump to it.

public static async Task<bool> JumpToPathAsync(nint hwnd, string path)
{
    // Check handle
    if (hwnd == nint.Zero) return false;
+   
+   // Validate path
+   if (string.IsNullOrEmpty(path)) 
+   {
+       Log.Error(ClassName, "Path is null or empty");
+       return false;
+   }
+   
+   if (!Path.IsPathRooted(path))
+   {
+       Log.Error(ClassName, $"Path is not rooted: {path}");
+       return false;
+   }

    // Check path
    if (!CheckPath(path, out var isFile)) return false;

749-751: Fix logic error in dialog window search.

The method returns the first dialog window found instead of continuing the search for a matching one.

// Update dialog window if found
if (dialogWindow != null)
{
    _quickSwitchDialogs[dialog] = dialogWindow;
    return dialogWindow;
}
-
-return dialogWindow;

783-783: Add null check for Path.GetDirectoryName result.

Path.GetDirectoryName() can return null for root paths or invalid paths.

case QuickSwitchFileResultBehaviours.Directory:
    Log.Debug(ClassName, $"File Jump Directory (Auto: {auto}): {path}");
-   result = DirJump(Path.GetDirectoryName(path), dialog, auto);
+   var dirPath = Path.GetDirectoryName(path);
+   if (string.IsNullOrEmpty(dirPath))
+   {
+       Log.Error(ClassName, $"Could not get directory for file: {path}");
+       return false;
+   }
+   result = DirJump(dirPath, dialog, auto);
    break;

84-84: Replace List<HWND> with HashSet<HWND> for better performance.

Since you're frequently checking if dialogs are already switched using Contains(), a HashSet<HWND> would provide O(1) lookup performance instead of O(n).

-private static readonly List<HWND> _autoSwitchedDialogs = new();
+private static readonly HashSet<HWND> _autoSwitchedDialogs = new();

372-375: Add error handling for delegate invocation.

The method invokes external code but doesn't include error handling, which could lead to unhandled exceptions.

private static void InvokeUpdateQuickSwitchWindow()
{
-   UpdateQuickSwitchWindow?.Invoke();
+   try
+   {
+       UpdateQuickSwitchWindow?.Invoke();
+   }
+   catch (Exception ex)
+   {
+       Log.Exception(ClassName, "Error updating QuickSwitch window", ex);
+   }
}
🧹 Nitpick comments (2)
Flow.Launcher.Infrastructure/QuickSwitch/QuickSwitch.cs (2)

143-147: Add logging for caught exceptions.

The catch block swallows exceptions without logging them, which can make debugging difficult.

catch (System.Exception ex)
{
-   // Ignored
+   Log.Debug(ClassName, $"Error refreshing last explorer: {ex.Message}");
}

621-621: Fix typo in log message.

-Log.Debug(ClassName, $"Destory dialog: {hwnd}");
+Log.Debug(ClassName, $"Destroy dialog: {hwnd}");
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between b75f237 and 3808418.

📒 Files selected for processing (1)
  • Flow.Launcher.Infrastructure/QuickSwitch/QuickSwitch.cs (1 hunks)
🧰 Additional context used
🧠 Learnings (2)
📓 Common learnings
Learnt from: Yusyuriv
PR: Flow-Launcher/Flow.Launcher#3057
File: Flow.Launcher.Core/Plugin/JsonRPCPluginSettings.cs:0-0
Timestamp: 2024-11-03T07:40:11.014Z
Learning: In Flow Launcher, when using Windows Forms dialogs (e.g., in `JsonRPCPluginSettings.cs`), path validation is enabled by default in `OpenFileDialog` and `FolderBrowserDialog`, preventing users from selecting invalid paths, but it's possible to opt out of this validation on individual dialogs.
Flow.Launcher.Infrastructure/QuickSwitch/QuickSwitch.cs (5)
Learnt from: Yusyuriv
PR: Flow-Launcher/Flow.Launcher#3057
File: Flow.Launcher.Core/Plugin/JsonRPCPluginSettings.cs:0-0
Timestamp: 2024-11-03T07:40:11.014Z
Learning: In Flow Launcher, when using Windows Forms dialogs (e.g., in `JsonRPCPluginSettings.cs`), path validation is enabled by default in `OpenFileDialog` and `FolderBrowserDialog`, preventing users from selecting invalid paths, but it's possible to opt out of this validation on individual dialogs.
Learnt from: Jack251970
PR: Flow-Launcher/Flow.Launcher#3672
File: Flow.Launcher/MainWindow.xaml.cs:244-247
Timestamp: 2025-06-08T14:12:21.348Z
Learning: In Flow.Launcher, App.NotifyIcon is created before MainWindow creation, so null checks for App.NotifyIcon are not necessary when accessing it from MainWindow code.
Learnt from: Yusyuriv
PR: Flow-Launcher/Flow.Launcher#3057
File: Flow.Launcher.Core/Plugin/JsonRPCPluginSettings.cs:0-0
Timestamp: 2024-11-03T07:34:24.926Z
Learning: In Windows Forms dialogs, Windows handles invalid paths and prevents the user from clicking "Ok" if the path is incorrect, so additional path validation is unnecessary.
Learnt from: Jack251970
PR: Flow-Launcher/Flow.Launcher#3672
File: Flow.Launcher/MainWindow.xaml.cs:318-318
Timestamp: 2025-06-08T14:12:12.842Z
Learning: In Flow.Launcher, the App.NotifyIcon static property is initialized in the App class before MainWindow creation, so null checks are not needed when accessing App.NotifyIcon in MainWindow lifecycle methods.
Learnt from: onesounds
PR: Flow-Launcher/Flow.Launcher#3394
File: Flow.Launcher/Themes/Darker Glass.xaml:134-141
Timestamp: 2025-03-28T21:12:13.386Z
Learning: In Flow.Launcher, hotkey styling is implemented with a two-component structure: a Border element with style `ItemHotkeyBGStyle` that provides background and border styling, containing a TextBlock with style `ItemHotkeyStyle` that handles the text styling.
🪛 GitHub Actions: Check Spelling
Flow.Launcher.Infrastructure/QuickSwitch/QuickSwitch.cs

[warning] 12-621: Unrecognized spelling: 'NHotkey', 'VSTHRD', 'Destory', 'Ioc', 'Wnd'.

⏰ Context from checks skipped due to timeout of 90000ms (1)
  • GitHub Check: build

Copy link
Contributor

@Copilot Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

This PR introduces an experimental “Quick Switch” feature that lets users automatically or manually navigate file dialogs to the current file-manager path.

  • Defined new Quick Switch interfaces, result model, and core logic in Infrastructure/QuickSwitch
  • Integrated Quick Switch into the main app, ViewModel, and explorer plugin
  • Added UI settings and a default hotkey (Alt+G) for Quick Switch; updated project references

Reviewed Changes

Copilot reviewed 28 out of 28 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
Plugins/Flow.Launcher.Plugin.Explorer/Search/ResultManager.cs Use directory var for subtitles and working dir
Plugins/Flow.Launcher.Plugin.Explorer/Main.cs Implement IAsyncQuickSwitch and query adapter
Flow.Launcher/ViewModel/MainViewModel.cs Added Quick Switch state, cloning, and query logic
Flow.Launcher/SettingPages/Views/SettingsPaneHotkey.xaml Added hotkey control card for Quick Switch
Flow.Launcher/SettingPages/Views/SettingsPaneGeneral.xaml Added Quick Switch settings cards
Flow.Launcher/SettingPages/ViewModels/SettingsPaneHotkeyViewModel.cs Bound Quick Switch hotkey command
Flow.Launcher/SettingPages/ViewModels/SettingsPaneGeneralViewModel.cs Exposed EnableQuickSwitch and dropdown data
Flow.Launcher/MainWindow.xaml.cs Hooked Quick Switch events and position logic
Flow.Launcher/Languages/en.xaml Added Quick Switch UI strings
Flow.Launcher/HotkeyControl.xaml.cs Added QuickSwitchHotkey enum and settings
Flow.Launcher/Helper/HotKeyMapper.cs Register Quick Switch toggle hotkey
Flow.Launcher/Flow.Launcher.csproj Removed obsolete package refs
Flow.Launcher/App.xaml.cs Initialized Quick Switch on startup
Flow.Launcher.Plugin/Result.cs Minor formatting change
Flow.Launcher.Plugin/QuickSwitchResult.cs New QuickSwitchResult model with clone and factory
Flow.Launcher.Plugin/Interfaces/IQuickSwitchExplorer.cs Defined explorer plugin interface
Flow.Launcher.Plugin/Interfaces/IQuickSwitchDialog.cs Defined dialog plugin interface
Flow.Launcher.Plugin/Interfaces/IQuickSwitch.cs Defined sync Quick Switch interface
Flow.Launcher.Plugin/Interfaces/IAsyncQuickSwitch.cs Defined async Quick Switch interface
Flow.Launcher.Infrastructure/Win32Helper.cs Added window-rect and foreground helpers
Flow.Launcher.Infrastructure/UserSettings/Settings.cs Added Quick Switch settings and enums
Flow.Launcher.Infrastructure/QuickSwitch/QuickSwitchPair.cs Pair types for explorers and dialogs
Flow.Launcher.Infrastructure/QuickSwitch/QuickSwitch.cs Core Quick Switch implementation
Flow.Launcher.Infrastructure/QuickSwitch/Models/WindowsExplorer.cs Windows Explorer adapter
Flow.Launcher.Infrastructure/QuickSwitch/Models/WindowsDialog.cs Windows File Dialog adapter
Flow.Launcher.Infrastructure/QuickSwitch/NativeMethods.txt Added Win32 event constants
Flow.Launcher.Infrastructure/Flow.Launcher.Infrastructure.csproj Added InputSimulator and NHotkey.Wpf refs
Flow.Launcher.Core/Plugin/PluginManager.cs Registered Quick Switch plugins
Comments suppressed due to low confidence (2)

Flow.Launcher.Infrastructure/QuickSwitch/QuickSwitch.cs:1

  • The new QuickSwitch core logic is large and complex but has no associated unit tests. Consider adding tests for path navigation, event hooks, and cancellation behavior.
using System;

Flow.Launcher/ViewModel/MainViewModel.cs:2076

  • You removed the null-conditional operator on _lastQuery, introducing a possible NullReferenceException if _lastQuery is null. Consider restoring ? or adding an explicit null check.
                        var newQuery = _lastQuery.ActionKeyword;

This comment has been minimized.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

♻️ Duplicate comments (7)
Flow.Launcher.Infrastructure/QuickSwitch/QuickSwitch.cs (7)

411-414: Add exception handling to prevent hotkey failures.

The hotkey handler doesn't catch exceptions, which could lead to hotkey failures if the navigation logic throws.

 public static void OnToggleHotkey(object sender, HotkeyEventArgs args)
 {
-    _ = Task.Run(() => NavigateDialogPathAsync(PInvoke.GetForegroundWindow()));
+    try
+    {
+        _ = Task.Run(async () => 
+        {
+            try 
+            {
+                await NavigateDialogPathAsync(PInvoke.GetForegroundWindow());
+            }
+            catch (Exception ex)
+            {
+                Log.Exception(ClassName, "Error in NavigateDialogPathAsync from hotkey", ex);
+            }
+        });
+    }
+    catch (Exception ex)
+    {
+        Log.Exception(ClassName, "Error processing quickswitch hotkey", ex);
+    }
 }

476-479: Incorrect lock object used for thread safety.

The code uses _dialogWindowHandleLock which doesn't exist in the class. Should use _autoSwitchedDialogsLock.

 // Check if we have already switched for this dialog
 bool alreadySwitched;
-lock (_dialogWindowHandleLock)
+lock (_autoSwitchedDialogsLock)
 {
     alreadySwitched = _autoSwitchedDialogs.Contains(hwnd);
 }

593-601: Timer operations called from non-UI thread may throw exceptions.

MoveSizeCallBack runs on the WinEvent hook thread, but DispatcherTimer.Start/Stop must be called on the UI thread.

 switch (eventType)
 {
     case PInvoke.EVENT_SYSTEM_MOVESIZESTART:
-        _dragMoveTimer.Start(); // Start dragging position
+        _dragMoveTimer.Dispatcher.BeginInvoke(() => _dragMoveTimer.Start());
         break;
     case PInvoke.EVENT_SYSTEM_MOVESIZEEND:
-        _dragMoveTimer.Stop(); // Stop dragging
+        _dragMoveTimer.Dispatcher.BeginInvoke(() => _dragMoveTimer.Stop());
         break;
 }

740-748: Fix logic error in dialog window search.

The method returns the first dialog window found instead of only returning when it matches the target HWND.

The current logic will return any dialog window found, not necessarily the one matching hwnd. Only return when a match is found:

 dialogWindow = dialog.Plugin.CheckDialogWindow(hwnd);
-}
 
-// Update dialog window if found
-if (dialogWindow != null)
-{
-    _quickSwitchDialogs[dialog] = dialogWindow;
-    return dialogWindow;
+    // Update dialog window if found
+    if (dialogWindow != null)
+    {
+        _quickSwitchDialogs[dialog] = dialogWindow;
+        return dialogWindow;
+    }
 }

781-781: Add null check for Path.GetDirectoryName result.

Path.GetDirectoryName() can return null for root paths, which would cause issues.

 case QuickSwitchFileResultBehaviours.Directory:
     Log.Debug(ClassName, $"File Jump Directory (Auto: {auto}): {path}");
-    result = DirJump(Path.GetDirectoryName(path), dialog, auto);
+    var dirPath = Path.GetDirectoryName(path);
+    if (string.IsNullOrEmpty(dirPath))
+    {
+        Log.Error(ClassName, $"Could not get directory for file: {path}");
+        return false;
+    }
+    result = DirJump(dirPath, dialog, auto);
     break;

754-812: Method always returns true regardless of actual result.

The result variable is computed but the method always returns true, preventing callers from detecting failures.

Move the result declaration outside the try block and return it:

 private static async Task<bool> JumpToPathAsync(IQuickSwitchDialogWindowTab dialog, string path, bool isFile, bool auto = false)
 {
     // Jump after flow launcher window vanished...
     var dialogHandle = dialog.Handle;
     var timeOut = !SpinWait.SpinUntil(() => Win32Helper.IsForegroundWindow(dialogHandle), 1000);
     if (timeOut) return false;
 
+    bool result = false;
     // Assume that the dialog is in the foreground now
     await _navigationLock.WaitAsync();
     try
     {
-        bool result;
         if (isFile)
         {
             // ... existing switch logic ...
         }
         // ... rest of try block ...
     }
     catch (System.Exception e)
     {
         Log.Exception(ClassName, "Failed to jump to path", e);
-        return false;
     }
     finally
     {
         _navigationLock.Release();
     }
-    return true;
+    return result;
 }

846-906: Complete resource cleanup in Dispose method.

The Dispose method is missing several cleanup steps that could cause issues.

Add the missing cleanup:

 // Dispose locks
 _foregroundChangeLock.Dispose();
-_navigationLock.Dispose();
+_navigationLock.Dispose();
+
+// Clear auto-switched dialogs
+lock (_autoSwitchedDialogsLock)
+{
+    _autoSwitchedDialogs.Clear();
+}
 
 // Stop drag move timer
 if (_dragMoveTimer != null)
 {
     _dragMoveTimer.Stop();
     _dragMoveTimer = null;
 }
+
+// Uninitialize COM (if it was initialized)
+if (_enabled)
+{
+    try
+    {
+        PInvoke.CoUninitialize();
+    }
+    catch (Exception ex)
+    {
+        Log.Debug(ClassName, $"Error uninitializing COM: {ex.Message}");
+    }
+}
🧹 Nitpick comments (2)
Flow.Launcher.Infrastructure/QuickSwitch/QuickSwitch.cs (2)

83-86: Replace List<HWND> with HashSet<HWND> for better performance.

The Contains operation on List<T> has O(n) time complexity. Since this is checked in the foreground change callback which fires frequently, use HashSet<HWND> for O(1) lookups.

-// A list of all file dialog windows that are auto switched already
-private static readonly List<HWND> _autoSwitchedDialogs = new();
+// A set of all file dialog windows that are auto switched already
+private static readonly HashSet<HWND> _autoSwitchedDialogs = new();
 private static readonly object _autoSwitchedDialogsLock = new();

621-621: Fix typo in log message.

"Destory" should be "Destroy".

-Log.Debug(ClassName, $"Destory dialog: {hwnd}");
+Log.Debug(ClassName, $"Destroy dialog: {hwnd}");
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 3808418 and 8ef4684.

📒 Files selected for processing (1)
  • Flow.Launcher.Infrastructure/QuickSwitch/QuickSwitch.cs (1 hunks)
🧰 Additional context used
🧠 Learnings (2)
📓 Common learnings
Learnt from: Yusyuriv
PR: Flow-Launcher/Flow.Launcher#3057
File: Flow.Launcher.Core/Plugin/JsonRPCPluginSettings.cs:0-0
Timestamp: 2024-11-03T07:40:11.014Z
Learning: In Flow Launcher, when using Windows Forms dialogs (e.g., in `JsonRPCPluginSettings.cs`), path validation is enabled by default in `OpenFileDialog` and `FolderBrowserDialog`, preventing users from selecting invalid paths, but it's possible to opt out of this validation on individual dialogs.
Flow.Launcher.Infrastructure/QuickSwitch/QuickSwitch.cs (5)
Learnt from: Yusyuriv
PR: Flow-Launcher/Flow.Launcher#3057
File: Flow.Launcher.Core/Plugin/JsonRPCPluginSettings.cs:0-0
Timestamp: 2024-11-03T07:40:11.014Z
Learning: In Flow Launcher, when using Windows Forms dialogs (e.g., in `JsonRPCPluginSettings.cs`), path validation is enabled by default in `OpenFileDialog` and `FolderBrowserDialog`, preventing users from selecting invalid paths, but it's possible to opt out of this validation on individual dialogs.
Learnt from: Jack251970
PR: Flow-Launcher/Flow.Launcher#3672
File: Flow.Launcher/MainWindow.xaml.cs:244-247
Timestamp: 2025-06-08T14:12:21.348Z
Learning: In Flow.Launcher, App.NotifyIcon is created before MainWindow creation, so null checks for App.NotifyIcon are not necessary when accessing it from MainWindow code.
Learnt from: Yusyuriv
PR: Flow-Launcher/Flow.Launcher#3057
File: Flow.Launcher.Core/Plugin/JsonRPCPluginSettings.cs:0-0
Timestamp: 2024-11-03T07:34:24.926Z
Learning: In Windows Forms dialogs, Windows handles invalid paths and prevents the user from clicking "Ok" if the path is incorrect, so additional path validation is unnecessary.
Learnt from: Jack251970
PR: Flow-Launcher/Flow.Launcher#3672
File: Flow.Launcher/MainWindow.xaml.cs:318-318
Timestamp: 2025-06-08T14:12:12.842Z
Learning: In Flow.Launcher, the App.NotifyIcon static property is initialized in the App class before MainWindow creation, so null checks are not needed when accessing App.NotifyIcon in MainWindow lifecycle methods.
Learnt from: onesounds
PR: Flow-Launcher/Flow.Launcher#3394
File: Flow.Launcher/Themes/Darker Glass.xaml:134-141
Timestamp: 2025-03-28T21:12:13.386Z
Learning: In Flow.Launcher, hotkey styling is implemented with a two-component structure: a Border element with style `ItemHotkeyBGStyle` that provides background and border styling, containing a TextBlock with style `ItemHotkeyStyle` that handles the text styling.
⏰ Context from checks skipped due to timeout of 90000ms (1)
  • GitHub Check: build

This comment has been minimized.

This comment has been minimized.

This comment has been minimized.

This comment has been minimized.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

♻️ Duplicate comments (3)
Flow.Launcher/MainWindow.xaml.cs (1)

816-828: Fix the spelling and forbidden pattern issue.

The positioning logic correctly branches between Quick Switch and normal modes, and making the method public is appropriate for external Quick Switch integration. However, there's a spelling error and forbidden pattern issue in the comment that needs to be addressed.

Apply this diff to fix the issues:

-            // Initialize call twice to work around multi-display alignment issue- https://github.com/Flow-Launcher/Flow.Launcher/issues/2910
+            // Initialize call twice to resolve multi-display alignment issue- https://github.com/Flow-Launcher/Flow.Launcher/issues/2910
Flow.Launcher/ViewModel/MainViewModel.cs (2)

508-508: Add type checking before casting to QuickSwitchResult

Similar to the LoadContextMenu method, this direct cast could throw an InvalidCastException.

-                    if (result is QuickSwitchResult quickSwitchResult)
+                    if (result is QuickSwitchResult quickSwitchResult)
                     {
                         Win32Helper.SetForegroundWindow(DialogWindowHandle);
                         _ = Task.Run(() => QuickSwitch.JumpToPathAsync(DialogWindowHandle, quickSwitchResult.QuickSwitchPath));
                     }

1829-1829: Thread safety concerns for DialogWindowHandle

The DialogWindowHandle property lacks thread synchronization mechanisms for safe access from multiple threads.

🧹 Nitpick comments (1)
Flow.Launcher/ViewModel/MainViewModel.cs (1)

1924-1924: Fix duplicate word in comment

The comment contains a duplicate word "the the" that should be corrected.

-                            // Bring focus back to the the dialog
+                            // Bring focus back to the dialog
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 4716605 and cad2737.

📒 Files selected for processing (2)
  • Flow.Launcher/MainWindow.xaml.cs (11 hunks)
  • Flow.Launcher/ViewModel/MainViewModel.cs (15 hunks)
🧰 Additional context used
🧠 Learnings (3)
📓 Common learnings
Learnt from: Yusyuriv
PR: Flow-Launcher/Flow.Launcher#3057
File: Flow.Launcher.Core/Plugin/JsonRPCPluginSettings.cs:0-0
Timestamp: 2024-11-03T07:40:11.014Z
Learning: In Flow Launcher, when using Windows Forms dialogs (e.g., in `JsonRPCPluginSettings.cs`), path validation is enabled by default in `OpenFileDialog` and `FolderBrowserDialog`, preventing users from selecting invalid paths, but it's possible to opt out of this validation on individual dialogs.
Flow.Launcher/ViewModel/MainViewModel.cs (9)
Learnt from: Yusyuriv
PR: Flow-Launcher/Flow.Launcher#3118
File: Flow.Launcher/ViewModel/MainViewModel.cs:1404-1413
Timestamp: 2024-12-08T21:12:12.060Z
Learning: In the `MainViewModel` class, the `_lastQuery` field is initialized in the constructor and is never null.
Learnt from: Jack251970
PR: Flow-Launcher/Flow.Launcher#3791
File: Flow.Launcher.Core/Plugin/PluginManager.cs:293-295
Timestamp: 2025-07-01T05:46:13.251Z
Learning: In Flow.Launcher.Core/Plugin/PluginManager.cs, when checking if a plugin is modified within the PluginManager class itself, prefer using the internal static PluginModified(string id) method directly rather than going through API.PluginModified() for better performance and architectural design.
Learnt from: Yusyuriv
PR: Flow-Launcher/Flow.Launcher#3057
File: Flow.Launcher.Core/Plugin/JsonRPCPluginSettings.cs:0-0
Timestamp: 2024-11-03T07:40:11.014Z
Learning: In Flow Launcher, when using Windows Forms dialogs (e.g., in `JsonRPCPluginSettings.cs`), path validation is enabled by default in `OpenFileDialog` and `FolderBrowserDialog`, preventing users from selecting invalid paths, but it's possible to opt out of this validation on individual dialogs.
Learnt from: Yusyuriv
PR: Flow-Launcher/Flow.Launcher#3057
File: Flow.Launcher.Core/Plugin/JsonRPCPluginSettings.cs:0-0
Timestamp: 2024-11-03T07:34:24.926Z
Learning: In Windows Forms dialogs, Windows handles invalid paths and prevents the user from clicking "Ok" if the path is incorrect, so additional path validation is unnecessary.
Learnt from: Jack251970
PR: Flow-Launcher/Flow.Launcher#3672
File: Flow.Launcher/MainWindow.xaml.cs:244-247
Timestamp: 2025-06-08T14:12:21.348Z
Learning: In Flow.Launcher, App.NotifyIcon is created before MainWindow creation, so null checks for App.NotifyIcon are not necessary when accessing it from MainWindow code.
Learnt from: Jack251970
PR: Flow-Launcher/Flow.Launcher#3672
File: Flow.Launcher/MainWindow.xaml.cs:318-318
Timestamp: 2025-06-08T14:12:12.842Z
Learning: In Flow.Launcher, the App.NotifyIcon static property is initialized in the App class before MainWindow creation, so null checks are not needed when accessing App.NotifyIcon in MainWindow lifecycle methods.
Learnt from: taooceros
PR: Flow-Launcher/Flow.Launcher#3112
File: Flow.Launcher/ViewModel/ResultsViewModel.cs:231-239
Timestamp: 2024-12-07T18:48:14.625Z
Learning: Optimizing the LINQ operations in the method `NewResults` in `ResultsViewModel.cs` did not improve performance.
Learnt from: onesounds
PR: Flow-Launcher/Flow.Launcher#3394
File: Flow.Launcher/Themes/Darker Glass.xaml:134-141
Timestamp: 2025-03-28T21:12:13.386Z
Learning: In Flow.Launcher, hotkey styling is implemented with a two-component structure: a Border element with style `ItemHotkeyBGStyle` that provides background and border styling, containing a TextBlock with style `ItemHotkeyStyle` that handles the text styling.
Learnt from: jjw24
PR: Flow-Launcher/Flow.Launcher#2448
File: Plugins/Flow.Launcher.Plugin.Sys/ThemeSelector.cs:16-20
Timestamp: 2025-01-18T10:10:18.414Z
Learning: In Flow Launcher's plugin system, the PluginInitContext parameter passed to plugin constructors is guaranteed to be non-null by the plugin initialization system, making null checks unnecessary.
Flow.Launcher/MainWindow.xaml.cs (13)
Learnt from: Jack251970
PR: Flow-Launcher/Flow.Launcher#3672
File: Flow.Launcher/MainWindow.xaml.cs:244-247
Timestamp: 2025-06-08T14:12:21.348Z
Learning: In Flow.Launcher, App.NotifyIcon is created before MainWindow creation, so null checks for App.NotifyIcon are not necessary when accessing it from MainWindow code.
Learnt from: Jack251970
PR: Flow-Launcher/Flow.Launcher#3672
File: Flow.Launcher/MainWindow.xaml.cs:318-318
Timestamp: 2025-06-08T14:12:12.842Z
Learning: In Flow.Launcher, the App.NotifyIcon static property is initialized in the App class before MainWindow creation, so null checks are not needed when accessing App.NotifyIcon in MainWindow lifecycle methods.
Learnt from: onesounds
PR: Flow-Launcher/Flow.Launcher#3394
File: Flow.Launcher/Themes/Darker Glass.xaml:134-141
Timestamp: 2025-03-28T21:12:13.386Z
Learning: In Flow.Launcher, hotkey styling is implemented with a two-component structure: a Border element with style `ItemHotkeyBGStyle` that provides background and border styling, containing a TextBlock with style `ItemHotkeyStyle` that handles the text styling.
Learnt from: Jack251970
PR: Flow-Launcher/Flow.Launcher#3791
File: Flow.Launcher.Core/Plugin/PluginManager.cs:293-295
Timestamp: 2025-07-01T05:46:13.251Z
Learning: In Flow.Launcher.Core/Plugin/PluginManager.cs, when checking if a plugin is modified within the PluginManager class itself, prefer using the internal static PluginModified(string id) method directly rather than going through API.PluginModified() for better performance and architectural design.
Learnt from: taooceros
PR: Flow-Launcher/Flow.Launcher#2616
File: Flow.Launcher/Flow.Launcher.csproj:7-7
Timestamp: 2024-10-08T15:52:58.573Z
Learning: In the Flow Launcher project, the version number in the `Flow.Launcher.csproj` file is dynamically updated during the CI/CD process.
Learnt from: Yusyuriv
PR: Flow-Launcher/Flow.Launcher#3057
File: Flow.Launcher.Core/Plugin/JsonRPCPluginSettings.cs:0-0
Timestamp: 2024-11-03T07:40:11.014Z
Learning: In Flow Launcher, when using Windows Forms dialogs (e.g., in `JsonRPCPluginSettings.cs`), path validation is enabled by default in `OpenFileDialog` and `FolderBrowserDialog`, preventing users from selecting invalid paths, but it's possible to opt out of this validation on individual dialogs.
Learnt from: onesounds
PR: Flow-Launcher/Flow.Launcher#3394
File: Flow.Launcher/Themes/Darker Glass.xaml:134-141
Timestamp: 2025-03-28T21:20:54.978Z
Learning: In WPF applications like Flow.Launcher, Border elements cannot directly display text content and require a child element like TextBlock to handle text rendering. This separation of concerns (Border for visual container styling, TextBlock for text display) follows WPF best practices and provides greater styling flexibility.
Learnt from: onesounds
PR: Flow-Launcher/Flow.Launcher#3394
File: Flow.Launcher/Themes/Darker Glass.xaml:134-141
Timestamp: 2025-03-28T21:20:54.978Z
Learning: In WPF applications like Flow.Launcher, Border elements cannot directly display text content and require a child element like TextBlock to handle text rendering. This separation of concerns (Border for visual container styling, TextBlock for text display) follows WPF best practices and provides greater styling flexibility.
Learnt from: taooceros
PR: Flow-Launcher/Flow.Launcher#2983
File: Flow.Launcher/MainWindow.xaml.cs:191-191
Timestamp: 2024-09-21T17:57:31.445Z
Learning: Calling `InitializePosition()` multiple times is intentional to prevent DPI issues across multiple displays.
Learnt from: taooceros
PR: Flow-Launcher/Flow.Launcher#2983
File: Flow.Launcher/MainWindow.xaml.cs:191-191
Timestamp: 2024-10-08T15:52:58.573Z
Learning: Calling `InitializePosition()` multiple times is intentional to prevent DPI issues across multiple displays.
Learnt from: jjw24
PR: Flow-Launcher/Flow.Launcher#2448
File: Plugins/Flow.Launcher.Plugin.Sys/ThemeSelector.cs:16-20
Timestamp: 2025-01-18T10:10:18.414Z
Learning: In Flow Launcher's plugin system, the PluginInitContext parameter passed to plugin constructors is guaranteed to be non-null by the plugin initialization system, making null checks unnecessary.
Learnt from: Jack251970
PR: Flow-Launcher/Flow.Launcher#3279
File: Flow.Launcher/Helper/WallpaperPathRetrieval.cs:44-46
Timestamp: 2025-02-28T07:47:24.148Z
Learning: In Flow.Launcher's WallpaperPathRetrieval class, using a `using` statement with MemoryStream when loading images with BitmapImage does not work properly, even when using BitmapCacheOption.OnLoad. The stream needs to remain open while the bitmap is in use.
Learnt from: Yusyuriv
PR: Flow-Launcher/Flow.Launcher#3118
File: Flow.Launcher/ViewModel/MainViewModel.cs:1404-1413
Timestamp: 2024-12-08T21:12:12.060Z
Learning: In the `MainViewModel` class, the `_lastQuery` field is initialized in the constructor and is never null.
🧬 Code Graph Analysis (1)
Flow.Launcher/MainWindow.xaml.cs (3)
Flow.Launcher.Infrastructure/QuickSwitch/QuickSwitch.cs (2)
  • QuickSwitch (19-909)
  • InitializeQuickSwitch (100-128)
Flow.Launcher/ViewModel/MainViewModel.cs (5)
  • InitializeVisibilityStatus (1837-1840)
  • Show (2022-2064)
  • IsQuickSwitchWindowUnderDialog (1842-1845)
  • ResetQuickSwitch (1937-1977)
  • HideQuickSwitch (1981-1996)
Flow.Launcher.Infrastructure/Win32Helper.cs (2)
  • Win32Helper (30-870)
  • GetWindowRect (783-801)
🪛 GitHub Check: Check Spelling
Flow.Launcher/ViewModel/MainViewModel.cs

[failure] 1924-1924:
the the matches a line_forbidden.patterns entry: \s([A-Z]{3,}|[A-Z][a-z]{2,}|[a-z]{3,})\s\g{-1}\s. (forbidden-pattern)

Flow.Launcher/MainWindow.xaml.cs

[failure] 818-818:
work around matches a line_forbidden.patterns entry: \bwork[- ]arounds?\b. (forbidden-pattern)

⏰ Context from checks skipped due to timeout of 90000ms (2)
  • GitHub Check: Report (PR)
  • GitHub Check: build
🔇 Additional comments (16)
Flow.Launcher/MainWindow.xaml.cs (7)

22-22: LGTM!

The import statement correctly adds the necessary namespace for Quick Switch functionality.


120-120: Verify the async to sync method signature change.

The method signature changed from async void to void. Ensure that no important async operations were removed that could affect the window initialization process.


169-169: LGTM!

The visibility status initialization calls correctly set the initial state based on the startup behavior, which is essential for Quick Switch functionality.

Also applies to: 174-174


217-218: LGTM!

The Quick Switch initialization is properly placed in the window loading sequence and will set up the necessary event handlers.


232-232: LGTM!

The conditional logic appropriately disables sound effects and animations when in Quick Switch mode under a dialog, preventing interference with the Quick Switch user experience.

Also applies to: 255-255


381-384: LGTM!

The early return statements correctly prevent normal window behavior when in Quick Switch mode under a dialog, ensuring the Quick Switch positioning and interaction model works as intended.

Also applies to: 395-398, 589-593, 601-604


1379-1417: LGTM!

The Quick Switch region is well-implemented with:

  • Proper delegate setup linking MainWindow to QuickSwitch infrastructure
  • Robust positioning logic with appropriate null checks and error handling
  • Helper methods that follow the same pattern as existing positioning methods
  • Clean separation of Quick Switch-specific functionality

The implementation correctly handles window positioning relative to dialog windows and integrates seamlessly with the existing codebase architecture.

Flow.Launcher/ViewModel/MainViewModel.cs (9)

19-19: LGTM - Clean import addition

The using directive is correctly added for the Quick Switch infrastructure.


56-56: LGTM - Consistent empty result pattern

The empty QuickSwitchResult collection follows the same pattern as the existing _emptyResult field for consistent handling.


291-300: LGTM - Clean refactoring to use shared cloning method

The refactoring to use DeepCloneResults with the isQuickSwitch parameter correctly set to false maintains existing functionality while enabling Quick Switch support.


1876-1876: LGTM - Safe navigation pattern

The use of optional chaining with the MainWindow cast provides safe navigation and null handling.


1998-2014: LGTM - Well-structured cleanup method

The ResetWindowAsync method properly handles the cleanup operations for Quick Switch window reset with appropriate async/await usage and state management.


2037-2037: LGTM - Appropriate Quick Switch animation handling

The conditional opacity logic properly disables animations during Quick Switch mode for improved user experience.


2066-2066: LGTM - Backward-compatible API enhancement

The optional reset parameter with default value maintains backward compatibility while providing necessary control for Quick Switch scenarios.


2254-2254: LGTM - Proper resource disposal

The addition of _quickSwitchSource?.Dispose() follows the established pattern and ensures proper cleanup of cancellation token sources.


414-414: Add type checking before casting to QuickSwitchResult

The direct cast to QuickSwitchResult could throw an InvalidCastException if the result is not of the expected type.

-                    if (result is QuickSwitchResult quickSwitchResult)
+                    if (result is QuickSwitchResult quickSwitchResult)
                     {
-                        var result = SelectedResults.SelectedItem.Result;
-                        if (result is QuickSwitchResult quickSwitchResult)
+                        Win32Helper.SetForegroundWindow(DialogWindowHandle);
+                        _ = Task.Run(() => QuickSwitch.JumpToPathAsync(DialogWindowHandle, quickSwitchResult.QuickSwitchPath));
+                    }

Likely an incorrect or invalid review comment.

This comment has been minimized.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

♻️ Duplicate comments (7)
Flow.Launcher/ViewModel/MainViewModel.cs (7)

408-421: Unhandled exceptions in Quick Switch navigation task.

The Task.Run operation for Quick Switch path navigation lacks exception handling, which could lead to unobserved exceptions if navigation fails.


501-514: Unhandled exceptions in Quick Switch navigation task.

Similar to the right-click mode, this Task.Run operation for Quick Switch path navigation lacks exception handling.


538-564: Type safety issue in result casting.

The cast to QuickSwitchResult could throw InvalidCastException if the assumption about result types is incorrect.


1828-1846: Thread safety concerns with Quick Switch state.

The DialogWindowHandle and _isQuickSwitch fields are accessed from multiple threads without synchronization, which could lead to race conditions.


1902-1932: Cancellation token capture race condition.

The cancellation token is captured after the CancellationTokenSource assignment, which could lead to race conditions if multiple dialogs appear before the task executes.


1937-1937: Async void method should return Task.

The ResetQuickSwitch method uses async void which prevents proper exception handling and makes testing difficult.


1981-1996: Window handle validity check needed.

The method assumes that a non-zero DialogWindowHandle is still valid, but Windows handles can be reused or invalidated.

🧹 Nitpick comments (2)
Flow.Launcher.Infrastructure/Win32Helper.cs (1)

807-836: Consider the hardcoded buffer size limit.

The implementation correctly uses SafeProcessHandle for resource management and appropriate error handling. However, the hardcoded buffer size of 2000 characters could potentially be insufficient for very long paths (though this is rare in practice).

Consider using a more robust approach or documenting the limitation:

-                uint capacity = 2000;
+                uint capacity = 2000; // Should be sufficient for most paths; Windows max path ~32k chars

Alternatively, you could use a larger buffer or implement retry logic with increasing buffer sizes if needed.

Flow.Launcher/ViewModel/MainViewModel.cs (1)

1924-1924: Fix the typo in the comment.

There's a duplicated word "the" in the comment.

-                            // Bring focus back to the the dialog
+                            // Bring focus back to the dialog
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between cad2737 and a493ed6.

📒 Files selected for processing (7)
  • Flow.Launcher.Core/Plugin/PluginManager.cs (6 hunks)
  • Flow.Launcher.Infrastructure/UserSettings/Settings.cs (5 hunks)
  • Flow.Launcher.Infrastructure/Win32Helper.cs (4 hunks)
  • Flow.Launcher/App.xaml.cs (3 hunks)
  • Flow.Launcher/Languages/en.xaml (1 hunks)
  • Flow.Launcher/SettingPages/Views/SettingsPaneGeneral.xaml (1 hunks)
  • Flow.Launcher/ViewModel/MainViewModel.cs (15 hunks)
✅ Files skipped from review due to trivial changes (1)
  • Flow.Launcher/Languages/en.xaml
🚧 Files skipped from review as they are similar to previous changes (4)
  • Flow.Launcher/App.xaml.cs
  • Flow.Launcher/SettingPages/Views/SettingsPaneGeneral.xaml
  • Flow.Launcher.Core/Plugin/PluginManager.cs
  • Flow.Launcher.Infrastructure/UserSettings/Settings.cs
🧰 Additional context used
🧠 Learnings (3)
📓 Common learnings
Learnt from: Yusyuriv
PR: Flow-Launcher/Flow.Launcher#3057
File: Flow.Launcher.Core/Plugin/JsonRPCPluginSettings.cs:0-0
Timestamp: 2024-11-03T07:40:11.014Z
Learning: In Flow Launcher, when using Windows Forms dialogs (e.g., in `JsonRPCPluginSettings.cs`), path validation is enabled by default in `OpenFileDialog` and `FolderBrowserDialog`, preventing users from selecting invalid paths, but it's possible to opt out of this validation on individual dialogs.
Flow.Launcher.Infrastructure/Win32Helper.cs (11)
Learnt from: Jack251970
PR: Flow-Launcher/Flow.Launcher#3672
File: Flow.Launcher/MainWindow.xaml.cs:244-247
Timestamp: 2025-06-08T14:12:21.348Z
Learning: In Flow.Launcher, App.NotifyIcon is created before MainWindow creation, so null checks for App.NotifyIcon are not necessary when accessing it from MainWindow code.
Learnt from: Jack251970
PR: Flow-Launcher/Flow.Launcher#3672
File: Flow.Launcher/MainWindow.xaml.cs:318-318
Timestamp: 2025-06-08T14:12:12.842Z
Learning: In Flow.Launcher, the App.NotifyIcon static property is initialized in the App class before MainWindow creation, so null checks are not needed when accessing App.NotifyIcon in MainWindow lifecycle methods.
Learnt from: Jack251970
PR: Flow-Launcher/Flow.Launcher#3572
File: Flow.Launcher/App.xaml.cs:214-216
Timestamp: 2025-07-06T12:21:37.927Z
Learning: In Flow Launcher, the UpdatePluginManifestAsync method in PluginsManifest.cs already has comprehensive internal try-catch handling that logs exceptions and returns false on failure rather than throwing, making external try-catch wrappers unnecessary.
Learnt from: Jack251970
PR: Flow-Launcher/Flow.Launcher#3791
File: Flow.Launcher.Core/Plugin/PluginManager.cs:293-295
Timestamp: 2025-07-01T05:46:13.251Z
Learning: In Flow.Launcher.Core/Plugin/PluginManager.cs, when checking if a plugin is modified within the PluginManager class itself, prefer using the internal static PluginModified(string id) method directly rather than going through API.PluginModified() for better performance and architectural design.
Learnt from: onesounds
PR: Flow-Launcher/Flow.Launcher#0
File: :0-0
Timestamp: 2025-04-23T15:14:49.986Z
Learning: In WPF applications like Flow.Launcher, font styling should be applied using implicit styles instead of setting the FontFamily property on individual controls. Define implicit styles in a ResourceDictionary using <Style TargetType="{x:Type Button}"> format and merge it into App.xaml, which automatically applies the font to all instances of the control type while still allowing explicit overrides where needed.
Learnt from: Yusyuriv
PR: Flow-Launcher/Flow.Launcher#3057
File: Flow.Launcher.Core/Plugin/JsonRPCPluginSettings.cs:0-0
Timestamp: 2024-11-03T07:40:11.014Z
Learning: In Flow Launcher, when using Windows Forms dialogs (e.g., in `JsonRPCPluginSettings.cs`), path validation is enabled by default in `OpenFileDialog` and `FolderBrowserDialog`, preventing users from selecting invalid paths, but it's possible to opt out of this validation on individual dialogs.
Learnt from: Jack251970
PR: Flow-Launcher/Flow.Launcher#3279
File: Flow.Launcher/Helper/WallpaperPathRetrieval.cs:44-46
Timestamp: 2025-02-28T07:47:24.148Z
Learning: In Flow.Launcher's WallpaperPathRetrieval class, using a `using` statement with MemoryStream when loading images with BitmapImage does not work properly, even when using BitmapCacheOption.OnLoad. The stream needs to remain open while the bitmap is in use.
Learnt from: onesounds
PR: Flow-Launcher/Flow.Launcher#3394
File: Flow.Launcher/Themes/Darker Glass.xaml:134-141
Timestamp: 2025-03-28T21:20:54.978Z
Learning: In WPF applications like Flow.Launcher, Border elements cannot directly display text content and require a child element like TextBlock to handle text rendering. This separation of concerns (Border for visual container styling, TextBlock for text display) follows WPF best practices and provides greater styling flexibility.
Learnt from: onesounds
PR: Flow-Launcher/Flow.Launcher#3394
File: Flow.Launcher/Themes/Darker Glass.xaml:134-141
Timestamp: 2025-03-28T21:20:54.978Z
Learning: In WPF applications like Flow.Launcher, Border elements cannot directly display text content and require a child element like TextBlock to handle text rendering. This separation of concerns (Border for visual container styling, TextBlock for text display) follows WPF best practices and provides greater styling flexibility.
Learnt from: onesounds
PR: Flow-Launcher/Flow.Launcher#3394
File: Flow.Launcher/Themes/Darker Glass.xaml:134-141
Timestamp: 2025-03-28T21:12:13.386Z
Learning: In Flow.Launcher, hotkey styling is implemented with a two-component structure: a Border element with style `ItemHotkeyBGStyle` that provides background and border styling, containing a TextBlock with style `ItemHotkeyStyle` that handles the text styling.
Learnt from: Jack251970
PR: Flow-Launcher/Flow.Launcher#3573
File: Plugins/Flow.Launcher.Plugin.Explorer/ViewModels/SettingsViewModel.cs:491-493
Timestamp: 2025-06-18T13:55:09.190Z
Learning: When opening Windows settings (like indexing options), de-elevation is not needed since these operations cannot bring security risks, even when Flow Launcher is running as administrator.
Flow.Launcher/ViewModel/MainViewModel.cs (10)
Learnt from: Jack251970
PR: Flow-Launcher/Flow.Launcher#3791
File: Flow.Launcher.Core/Plugin/PluginManager.cs:293-295
Timestamp: 2025-07-01T05:46:13.251Z
Learning: In Flow.Launcher.Core/Plugin/PluginManager.cs, when checking if a plugin is modified within the PluginManager class itself, prefer using the internal static PluginModified(string id) method directly rather than going through API.PluginModified() for better performance and architectural design.
Learnt from: Yusyuriv
PR: Flow-Launcher/Flow.Launcher#3118
File: Flow.Launcher/ViewModel/MainViewModel.cs:1404-1413
Timestamp: 2024-12-08T21:12:12.060Z
Learning: In the `MainViewModel` class, the `_lastQuery` field is initialized in the constructor and is never null.
Learnt from: Yusyuriv
PR: Flow-Launcher/Flow.Launcher#3057
File: Flow.Launcher.Core/Plugin/JsonRPCPluginSettings.cs:0-0
Timestamp: 2024-11-03T07:40:11.014Z
Learning: In Flow Launcher, when using Windows Forms dialogs (e.g., in `JsonRPCPluginSettings.cs`), path validation is enabled by default in `OpenFileDialog` and `FolderBrowserDialog`, preventing users from selecting invalid paths, but it's possible to opt out of this validation on individual dialogs.
Learnt from: Jack251970
PR: Flow-Launcher/Flow.Launcher#3572
File: Flow.Launcher/App.xaml.cs:214-216
Timestamp: 2025-07-06T12:21:37.927Z
Learning: In Flow Launcher, the UpdatePluginManifestAsync method in PluginsManifest.cs already has comprehensive internal try-catch handling that logs exceptions and returns false on failure rather than throwing, making external try-catch wrappers unnecessary.
Learnt from: Yusyuriv
PR: Flow-Launcher/Flow.Launcher#3057
File: Flow.Launcher.Core/Plugin/JsonRPCPluginSettings.cs:0-0
Timestamp: 2024-11-03T07:34:24.926Z
Learning: In Windows Forms dialogs, Windows handles invalid paths and prevents the user from clicking "Ok" if the path is incorrect, so additional path validation is unnecessary.
Learnt from: Jack251970
PR: Flow-Launcher/Flow.Launcher#3672
File: Flow.Launcher/MainWindow.xaml.cs:244-247
Timestamp: 2025-06-08T14:12:21.348Z
Learning: In Flow.Launcher, App.NotifyIcon is created before MainWindow creation, so null checks for App.NotifyIcon are not necessary when accessing it from MainWindow code.
Learnt from: Jack251970
PR: Flow-Launcher/Flow.Launcher#3672
File: Flow.Launcher/MainWindow.xaml.cs:318-318
Timestamp: 2025-06-08T14:12:12.842Z
Learning: In Flow.Launcher, the App.NotifyIcon static property is initialized in the App class before MainWindow creation, so null checks are not needed when accessing App.NotifyIcon in MainWindow lifecycle methods.
Learnt from: taooceros
PR: Flow-Launcher/Flow.Launcher#3112
File: Flow.Launcher/ViewModel/ResultsViewModel.cs:231-239
Timestamp: 2024-12-07T18:48:14.625Z
Learning: Optimizing the LINQ operations in the method `NewResults` in `ResultsViewModel.cs` did not improve performance.
Learnt from: onesounds
PR: Flow-Launcher/Flow.Launcher#3394
File: Flow.Launcher/Themes/Darker Glass.xaml:134-141
Timestamp: 2025-03-28T21:12:13.386Z
Learning: In Flow.Launcher, hotkey styling is implemented with a two-component structure: a Border element with style `ItemHotkeyBGStyle` that provides background and border styling, containing a TextBlock with style `ItemHotkeyStyle` that handles the text styling.
Learnt from: jjw24
PR: Flow-Launcher/Flow.Launcher#2448
File: Plugins/Flow.Launcher.Plugin.Sys/ThemeSelector.cs:16-20
Timestamp: 2025-01-18T10:10:18.414Z
Learning: In Flow Launcher's plugin system, the PluginInitContext parameter passed to plugin constructors is guaranteed to be non-null by the plugin initialization system, making null checks unnecessary.
🪛 GitHub Actions: Check Spelling
Flow.Launcher.Infrastructure/Win32Helper.cs

[warning] 20-20: Spell check warning: Dwm is not a recognized word.


[warning] 45-45: Spell check warning: Dwm is not a recognized word.


[warning] 56-56: Spell check warning: SYSTEMBACKDROP is not a recognized word.


[warning] 57-57: Spell check warning: DWMSBT and SYSTEMBACKDROP are not recognized words.


[warning] 58-58: Spell check warning: DWMSBT and SYSTEMBACKDROP are not recognized words.


[warning] 59-59: Spell check warning: DWMSBT and SYSTEMBACKDROP are not recognized words.


[warning] 62-62: Spell check warning: Dwm is not a recognized word.


[warning] 64-64: Spell check warning: DWMWA and DWMWINDOWATTRIBUTE are not recognized words.


[warning] 73-73: Spell check warning: Dwm is not a recognized word.


[warning] 75-75: Spell check warning: DWMWA and DWMWINDOWATTRIBUTE are not recognized words.


[warning] 91-93: Spell check warning: DWMWCP is not a recognized word.


[warning] 99-99: Spell check warning: DWMWA and DWMWINDOWATTRIBUTE are not recognized words.


[warning] 165-186: Spell check warning: GWL is not a recognized word.


[warning] 204-204: Spell check warning: Wnd is not a recognized word.


[warning] 271-271: Spell check warning: WINTAB is not a recognized word.


[warning] 284-285: Spell check warning: Progman and WORKERW are not recognized words.


[warning] 540-546: Spell check warning: hkl is not a recognized word.


[warning] 572-572: Spell check warning: nqo is not a recognized word.


[warning] 645-669: Spell check warning: tsf and Tsf are not recognized words.


[warning] 705-708: Spell check warning: Noto is not a recognized word.


[warning] 749-754: Spell check warning: noto is not a recognized word.


[warning] 774-774: Spell check warning: noto is not a recognized word.


[warning] 47-47: Spell check warning: DWMWINDOWATTRIBUTE and DWMWA are not recognized words.


[warning] 56-58: Spell check warning: DWMSBT, TRANSIENTWINDOW, MAINWINDOW, and TABBEDWINDOW are not recognized words.


[warning] 90-92: Spell check warning: DWMWCP, DONOTROUND, and ROUNDSMALL are not recognized words.


[warning] 190-190: Spell check warning: toolbar is not a recognized word.


[warning] 232-234: Spell check warning: WINTAB, Progman, and WORKERW are not recognized words.


[warning] 287-287: Spell check warning: SHELLDLL is not a recognized word.


[warning] 537-537: Spell check warning: hkl is not a recognized word.


[warning] 570-571: Spell check warning: LCIDTo and nqo are not recognized words.


[warning] 574-574: Spell check warning: workaround is not a recognized word.


[warning] 654-654: Spell check warning: DWord is not a recognized word.


[warning] 691-691: Spell check warning: regionlanguage is not a recognized word.


[warning] 703-703: Spell check warning: Noto is not a recognized word.


[warning] 749-749: Spell check warning: noto is not a recognized word.


[warning] 877-877: Spell check warning: uxtheme is not a recognized word.

🪛 GitHub Check: Check Spelling
Flow.Launcher/ViewModel/MainViewModel.cs

[failure] 1924-1924:
the the matches a line_forbidden.patterns entry: \s([A-Z]{3,}|[A-Z][a-z]{2,}|[a-z]{3,})\s\g{-1}\s. (forbidden-pattern)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: gitStream.cm
  • GitHub Check: build
🔇 Additional comments (4)
Flow.Launcher.Infrastructure/Win32Helper.cs (4)

17-17: LGTM: Required imports for new functionality.

The new using statements are necessary for the SafeProcessHandle and process access rights used in the new methods.

Also applies to: 21-21


143-146: LGTM: Consistent API design.

The public overload follows the established pattern of providing both Window and nint handle variants for window operations, maintaining consistency with other methods in the class.


354-362: LGTM: Proper null checking for application lifecycle.

The null check for Application.Current properly handles the case when the application is exiting, which is crucial for avoiding exceptions during shutdown.


783-801: LGTM: Proper error handling and type conversion.

The method correctly handles API failures by returning false and provides proper conversion from native RECT to WPF Rect. The unsafe code usage is appropriate for the PInvoke call.

This comment has been minimized.

Copy link

github-actions bot commented Jul 7, 2025

@check-spelling-bot Report

🔴 Please review

See the 📂 files view, the 📜action log, or 📝 job summary for details.

❌ Errors and Warnings Count
❌ forbidden-pattern 4
⚠️ non-alpha-in-dictionary 2

See ❌ Event descriptions for more information.

Forbidden patterns 🙅 (2)

In order to address this, you could change the content to not match the forbidden patterns (comments before forbidden patterns may help explain why they're forbidden), add patterns for acceptable instances, or adjust the forbidden patterns themselves.

These forbidden patterns matched content:

s.b. workaround(s)

\bwork[- ]arounds?\b

Reject duplicate words

\s([A-Z]{3,}|[A-Z][a-z]{2,}|[a-z]{3,})\s\g{-1}\s
If the flagged items are 🤯 false positives

If items relate to a ...

  • binary file (or some other file you wouldn't want to check at all).

    Please add a file path to the excludes.txt file matching the containing file.

    File paths are Perl 5 Regular Expressions - you can test yours before committing to verify it will match your files.

    ^ refers to the file's path from the root of the repository, so ^README\.md$ would exclude README.md (on whichever branch you're using).

  • well-formed pattern.

    If you can write a pattern that would match it,
    try adding it to the patterns.txt file.

    Patterns are Perl 5 Regular Expressions - you can test yours before committing to verify it will match your lines.

    Note that patterns can't match multiline strings.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

♻️ Duplicate comments (5)
Flow.Launcher.Infrastructure/QuickSwitch/QuickSwitch.cs (5)

598-610: Fix cross-thread timer access.

MoveSizeCallBack is executed on the WinEvent hook thread, not the WPF UI thread where _dragMoveTimer was created. Calling Start()/Stop() directly can raise an InvalidOperationException.

case PInvoke.EVENT_SYSTEM_MOVESIZESTART:
-   _dragMoveTimer.Start();
+   _dragMoveTimer.Dispatcher.BeginInvoke(() => _dragMoveTimer.Start());
    break;
case PInvoke.EVENT_SYSTEM_MOVESIZEEND:
-   _dragMoveTimer.Stop();
+   _dragMoveTimer.Dispatcher.BeginInvoke(() => _dragMoveTimer.Stop());
    break;

416-419: Add exception handling to prevent hotkey failures.

The hotkey handler doesn't catch exceptions, which could lead to hotkey failures if the navigation logic throws exceptions, potentially disrupting the application's functionality.

public static void OnToggleHotkey(object sender, HotkeyEventArgs args)
{
-   _ = Task.Run(() => NavigateDialogPathAsync(PInvoke.GetForegroundWindow()));
+   try
+   {
+       _ = Task.Run(async () => 
+       {
+           try 
+           {
+               await NavigateDialogPathAsync(PInvoke.GetForegroundWindow());
+           }
+           catch (Exception ex)
+           {
+               Log.Exception(ClassName, "Error in NavigateDialogPathAsync from hotkey", ex);
+           }
+       });
+   }
+   catch (Exception ex)
+   {
+       Log.Exception(ClassName, "Error processing quickswitch hotkey", ex);
+   }
}

791-794: Add null check for Path.GetDirectoryName result.

Path.GetDirectoryName() can return null for root paths or invalid paths, which would cause issues in the DirJump method.

case QuickSwitchFileResultBehaviours.Directory:
    Log.Debug(ClassName, $"File Jump Directory (Auto: {auto}): {path}");
-   result = DirJump(Path.GetDirectoryName(path), dialog, auto);
+   var dirPath = Path.GetDirectoryName(path);
+   if (string.IsNullOrEmpty(dirPath))
+   {
+       Log.Error(ClassName, $"Could not get directory for file: {path}");
+       return false;
+   }
+   result = DirJump(dirPath, dialog, auto);
    break;

425-560: Add exception handling to async void method.

The ForegroundChangeCallback is marked with SuppressMessage for async void, but lacks comprehensive exception handling. Any unhandled exceptions could terminate the application.

[System.Diagnostics.CodeAnalysis.SuppressMessage("Usage", "VSTHRD100:Avoid async void methods", Justification = "<Pending>")]
private static async void ForegroundChangeCallback(
    // parameters...
)
{
+   try 
+   {
        await _foregroundChangeLock.WaitAsync();
        try
        {
            // existing implementation...
        }
        finally
        {
            _foregroundChangeLock.Release();
        }
+   }
+   catch (Exception ex)
+   {
+       Log.Exception(ClassName, "Unhandled exception in ForegroundChangeCallback", ex);
+   }
}

134-203: Initialize COM before using shell APIs.

The SetupQuickSwitch method uses Windows shell APIs through RefreshLastExplorer() but never initializes COM. This could cause failures on some systems where COM hasn't been initialized.

if (enabled)
{
+   // Initialize COM for this thread
+   var hr = PInvoke.CoInitializeEx(null, COINIT.COINIT_APARTMENTTHREADED);
+   if (hr.Failed)
+   {
+       Log.Error(ClassName, $"Failed to initialize COM: {hr}");
+       return;
+   }
+
    // Check if there are explorer windows and get the topmost one

Remember to balance this with CoUninitialize() in the Dispose() method.

🧹 Nitpick comments (2)
Flow.Launcher.Infrastructure/QuickSwitch/QuickSwitch.cs (2)

87-90: Optimize data structure for better performance.

Using List<HWND> for _autoSwitchedDialogs results in O(n) performance for Contains, Add, and Remove operations. Since these operations occur in foreground-change callbacks, consider using HashSet<HWND> for O(1) performance and automatic duplicate prevention.

-private static readonly List<HWND> _autoSwitchedDialogs = new();
+private static readonly HashSet<HWND> _autoSwitchedDialogs = new();

628-628: Fix typo in log message.

There's a spelling error in the log message.

-Log.Debug(ClassName, $"Destory dialog: {hwnd}");
+Log.Debug(ClassName, $"Destroy dialog: {hwnd}");
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between b6be321 and cf66077.

📒 Files selected for processing (1)
  • Flow.Launcher.Infrastructure/QuickSwitch/QuickSwitch.cs (1 hunks)
🧰 Additional context used
🧠 Learnings (2)
📓 Common learnings
Learnt from: Yusyuriv
PR: Flow-Launcher/Flow.Launcher#3057
File: Flow.Launcher.Core/Plugin/JsonRPCPluginSettings.cs:0-0
Timestamp: 2024-11-03T07:40:11.014Z
Learning: In Flow Launcher, when using Windows Forms dialogs (e.g., in `JsonRPCPluginSettings.cs`), path validation is enabled by default in `OpenFileDialog` and `FolderBrowserDialog`, preventing users from selecting invalid paths, but it's possible to opt out of this validation on individual dialogs.
Flow.Launcher.Infrastructure/QuickSwitch/QuickSwitch.cs (7)
Learnt from: Yusyuriv
PR: Flow-Launcher/Flow.Launcher#3057
File: Flow.Launcher.Core/Plugin/JsonRPCPluginSettings.cs:0-0
Timestamp: 2024-11-03T07:40:11.014Z
Learning: In Flow Launcher, when using Windows Forms dialogs (e.g., in `JsonRPCPluginSettings.cs`), path validation is enabled by default in `OpenFileDialog` and `FolderBrowserDialog`, preventing users from selecting invalid paths, but it's possible to opt out of this validation on individual dialogs.
Learnt from: Jack251970
PR: Flow-Launcher/Flow.Launcher#3791
File: Flow.Launcher.Core/Plugin/PluginManager.cs:293-295
Timestamp: 2025-07-01T05:46:13.251Z
Learning: In Flow.Launcher.Core/Plugin/PluginManager.cs, when checking if a plugin is modified within the PluginManager class itself, prefer using the internal static PluginModified(string id) method directly rather than going through API.PluginModified() for better performance and architectural design.
Learnt from: Jack251970
PR: Flow-Launcher/Flow.Launcher#3672
File: Flow.Launcher/MainWindow.xaml.cs:244-247
Timestamp: 2025-06-08T14:12:21.348Z
Learning: In Flow.Launcher, App.NotifyIcon is created before MainWindow creation, so null checks for App.NotifyIcon are not necessary when accessing it from MainWindow code.
Learnt from: Yusyuriv
PR: Flow-Launcher/Flow.Launcher#3057
File: Flow.Launcher.Core/Plugin/JsonRPCPluginSettings.cs:0-0
Timestamp: 2024-11-03T07:34:24.926Z
Learning: In Windows Forms dialogs, Windows handles invalid paths and prevents the user from clicking "Ok" if the path is incorrect, so additional path validation is unnecessary.
Learnt from: Jack251970
PR: Flow-Launcher/Flow.Launcher#3572
File: Flow.Launcher/App.xaml.cs:214-216
Timestamp: 2025-07-06T12:21:37.927Z
Learning: In Flow Launcher, the UpdatePluginManifestAsync method in PluginsManifest.cs already has comprehensive internal try-catch handling that logs exceptions and returns false on failure rather than throwing, making external try-catch wrappers unnecessary.
Learnt from: Jack251970
PR: Flow-Launcher/Flow.Launcher#3672
File: Flow.Launcher/MainWindow.xaml.cs:318-318
Timestamp: 2025-06-08T14:12:12.842Z
Learning: In Flow.Launcher, the App.NotifyIcon static property is initialized in the App class before MainWindow creation, so null checks are not needed when accessing App.NotifyIcon in MainWindow lifecycle methods.
Learnt from: onesounds
PR: Flow-Launcher/Flow.Launcher#3394
File: Flow.Launcher/Themes/Darker Glass.xaml:134-141
Timestamp: 2025-03-28T21:12:13.386Z
Learning: In Flow.Launcher, hotkey styling is implemented with a two-component structure: a Border element with style `ItemHotkeyBGStyle` that provides background and border styling, containing a TextBlock with style `ItemHotkeyStyle` that handles the text styling.
🪛 GitHub Actions: Check Spelling
Flow.Launcher.Infrastructure/QuickSwitch/QuickSwitch.cs

[warning] 272-42: Spell check warning: 'Wnd' is not a recognized word.


[warning] 279-86: Spell check warning: 'Wnd' is not a recognized word.


[warning] 12-14: Spell check warning: 'NHotkey' is not a recognized word.


[warning] 628-51: Spell check warning: 'Destory' is not a recognized word.

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: gitStream.cm
  • GitHub Check: build
🔇 Additional comments (1)
Flow.Launcher.Infrastructure/QuickSwitch/QuickSwitch.cs (1)

713-764: Fix logic error in dialog window search.

The method has flawed logic - it may return the wrong dialog window because it doesn't properly validate the HWND match before returning. Additionally, the cache isn't updated when a dialog window is found.

// Finally search for the dialog window again
foreach (var dialog in _quickSwitchDialogs.Keys)
{
    if (API.PluginModified(dialog.Metadata.ID) || // Plugin is modified
        dialog.Metadata.Disabled) continue; // Plugin is disabled

    IQuickSwitchDialogWindow dialogWindow;
    var existingDialogWindow = _quickSwitchDialogs[dialog];
    if (existingDialogWindow != null && existingDialogWindow.Handle == hwnd)
    {
        // If the dialog window is already in the list, no need to check again
        dialogWindow = existingDialogWindow;
    }
    else
    {
        dialogWindow = dialog.Plugin.CheckDialogWindow(hwnd);
    }

    // Update dialog window if found
    if (dialogWindow != null)
    {
        _quickSwitchDialogs[dialog] = dialogWindow;
-       return dialogWindow;
+       // Only return if this dialog window matches the target HWND
+       if (dialogWindow.Handle == hwnd)
+       {
+           return dialogWindow;
+       }
    }
}

return null;
⛔ Skipped due to learnings
Learnt from: Jack251970
PR: Flow-Launcher/Flow.Launcher#3791
File: Flow.Launcher.Core/Plugin/PluginManager.cs:293-295
Timestamp: 2025-07-01T05:46:13.251Z
Learning: In Flow.Launcher.Core/Plugin/PluginManager.cs, when checking if a plugin is modified within the PluginManager class itself, prefer using the internal static PluginModified(string id) method directly rather than going through API.PluginModified() for better performance and architectural design.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
20 min review bug Something isn't working enhancement New feature or request kind/ux related to user experience listary from listary review in progress Indicates that a review is in progress for this PR
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Quick Switch like Listary output search result to file selection dialog?
7 participants