Skip to content

Avalonia migration#4214

Open
taooceros wants to merge 63 commits into
devfrom
avalonia_migration
Open

Avalonia migration#4214
taooceros wants to merge 63 commits into
devfrom
avalonia_migration

Conversation

@taooceros

@taooceros taooceros commented Jan 15, 2026

Copy link
Copy Markdown
Member

This PR introduces the experimental Avalonia UI host alongside the existing WPF host so the migration can continue incrementally while preserving side-by-side comparison.

The current migration tracker is AVALONIA_MIGRATION_CHECKLIST.md.

Summary

  • Adds Flow.Launcher.Avalonia, a .NET 9 Avalonia host with its own output directory at Output/Debug/Avalonia.
  • Reuses the existing shared projects: Flow.Launcher.Plugin, Flow.Launcher.Infrastructure, and Flow.Launcher.Core.
  • Keeps the WPF host intact while Avalonia parity is built out.
  • Uses CommunityToolkit.Mvvm patterns in the Avalonia host.
  • Current overall progress is approximately 70-75%.

What Works

  • Main window query flow with plugin-backed results.
  • Global hotkey show/hide support.
  • Result display, selection, activation, context menu, icons, and match highlighting.
  • Progressive/async plugin querying and image loading.
  • Settings shell and most migrated settings pages.
  • Plugin management and plugin store flows.
  • System tray, auto-start, portable mode wiring, message dialogs, report window, welcome/release-notes windows, and plugin update progress dialog.

Migration Checklist

Windows & Dialogs — 16/19 complete (84%)

  • Main window, settings window, result list, preview panel, welcome/report/release-notes dialogs.
  • Browser/file-manager selection windows, plugin update window, message/notification flows, progress dialog.
  • Remaining parity: custom hotkey/shortcut editor windows. Action keyword editing is handled by a dialog-based replacement.

Settings Pages

  • General settings — ~95% complete.
  • Proxy settings — 100% complete.
  • Plugin settings — ~90% complete.
  • Plugin store — ~95% complete.
  • About settings — ~90% complete.
  • Theme settings — ~75%; remaining gaps include window size slider, system backdrop parity, icon theme, and double-click icon action.
  • Hotkey settings — ~67%; add/edit custom query hotkey and shortcut dialogs still pending.

Core UX / ViewModels

  • Basic query, result display, keyboard navigation, activation, context menu, text highlighting, and history cycling.
  • Hide-on-focus-loss, topmost mode, window dragging, system tray, global hotkey, auto-start, portable mode.
  • Remaining MainViewModel parity: clipboard paste handling, auto-complete suggestions, text selection handling, preview toggle, dialog jump behavior, game mode detection, window position memory, and IME mode control.
  • Single-instance enforcement and multi-monitor position parity still need work.

Helpers, Converters, and Controls

  • Hotkey mapping/registration, image loading, font loading, text formatting, auto-start helper.
  • Card, ExCard, CardGroup, HotkeyControl, HotkeyRecorderDialog, and HotkeyDisplay controls.
  • Basic visibility, localization, and common converters.
  • Remaining helper parity: single instance, exception formatting, singleton window opener, wallpaper path retrieval, media preview helper, proxy-aware web requests, and syntax sugar helpers.
  • Remaining converter parity: query suggestions, text transforms, sizing/badge/icon/date/border/IME converters, and related WPF-specific visual helpers.

Theming and Polish

  • Light/dark/system mode, theme selection UI, live theme preview, font/size controls, animation speed setting, progress indicators.
  • Custom theme loading, full backdrop effects, icon themes, and most window/result/menu/settings transition animations.

Build & Run

dotnet build Flow.Launcher.Avalonia/Flow.Launcher.Avalonia.csproj
./Output/Debug/Avalonia/Flow.Launcher.Avalonia.exe

Notes for Reviewers

  • Treat AVALONIA_MIGRATION_CHECKLIST.md as the detailed source of truth for parity status and remaining gaps.
  • This PR is still a migration branch, not a claim that Avalonia has full WPF parity.

Create Flow.Launcher.Avalonia project as foundation for migrating from WPF to Avalonia UI framework.

Key components:
- MainWindow with query box and results list (matching WPF layout)
- ViewModels: MainViewModel, ResultsViewModel, ResultViewModel
- Themes/Base.axaml with converted styles from WPF
- FluentAvaloniaUI for Windows 11 styling
- References existing Core/Infrastructure/Plugin projects

The project builds and runs alongside the existing WPF application.
This is Phase 1 of the incremental migration approach.
- Load settings from disk via FlowLauncherJsonStorage
- Initialize PluginManager and query plugins on text change
- Add minimal AvaloniaPublicAPI implementing IPublicAPI
- Execute plugin results on Enter key
- Add WPF framework reference for IPublicAPI compatibility
…oading

- Use DynamicData SourceList with automatic sorting by score descending
- Add ReplaceResults() with EditDiff for minimal UI updates (reduces flickering)
- Keep previous results visible while typing until new results arrive
- Add ImageLoader with Windows Shell API (IShellItemImageFactory) for exe/ico icons
- Use AlphaFormat.Unpremul to correctly render transparent icons without white borders
- Query all plugins in parallel and merge/sort results globally
- Wrap each plugin query in Task.Run() to ensure synchronous plugin code
  doesn't block the UI thread
- Show results progressively as each plugin completes using ConcurrentBag
- Update UI after each plugin returns instead of waiting for all plugins
Copilot AI review requested due to automatic review settings January 15, 2026 08:31
@taooceros taooceros marked this pull request as draft January 15, 2026 08:31
@github-actions github-actions Bot added this to the 2.1.0 milestone Jan 15, 2026
@github-actions

This comment has been minimized.

@taooceros taooceros modified the milestones: 2.1.0, Future, 3.0.0 Jan 15, 2026
@prlabeler prlabeler Bot added bug Something isn't working enhancement New feature or request labels Jan 15, 2026

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

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 a new Avalonia UI frontend for Flow Launcher as an alternative to the existing WPF implementation. The migration adds a complete new project with UI components, ViewModels, and platform integration while maintaining compatibility with the existing plugin system.

Changes:

  • Adds new Flow.Launcher.Avalonia project with complete UI implementation including MainWindow, result list views, and styling
  • Implements Windows global hotkey support and image loading utilities with native Win32 interop
  • Adds console logging output to infrastructure logger for easier debugging

Reviewed changes

Copilot reviewed 22 out of 22 changed files in this pull request and generated 50 comments.

Show a summary per file
File Description
Flow.Launcher.sln Adds Flow.Launcher.Avalonia project to solution with build configurations
Flow.Launcher.Infrastructure/Logger/Log.cs Adds console output for log messages
Flow.Launcher.Avalonia/app.manifest Defines Windows compatibility and DPI awareness settings
Flow.Launcher.Avalonia/Views/ResultListBox.axaml XAML markup for search results list display
Flow.Launcher.Avalonia/Views/ResultListBox.axaml.cs Code-behind for result list interactions
Flow.Launcher.Avalonia/ViewModel/ResultsViewModel.cs ViewModel managing result collection with sorting and selection
Flow.Launcher.Avalonia/ViewModel/ResultViewModel.cs ViewModel for individual result items
Flow.Launcher.Avalonia/ViewModel/MainViewModel.cs Main application ViewModel coordinating queries and UI state
Flow.Launcher.Avalonia/Themes/Resources.axaml Color and resource definitions for UI theme
Flow.Launcher.Avalonia/Themes/Base.axaml Style definitions for UI components
Flow.Launcher.Avalonia/Program.cs Application entry point
Flow.Launcher.Avalonia/MainWindow.axaml Main window XAML markup
Flow.Launcher.Avalonia/MainWindow.axaml.cs Main window code-behind with event handling
Flow.Launcher.Avalonia/Helper/ImageLoader.cs Image loading utility with caching and Win32 shell integration
Flow.Launcher.Avalonia/Helper/HotKeyMapper.cs Global hotkey registration management
Flow.Launcher.Avalonia/Helper/GlobalHotkey.cs Win32-based global hotkey implementation
Flow.Launcher.Avalonia/Flow.Launcher.Avalonia.csproj Project configuration and dependencies
Flow.Launcher.Avalonia/Converters/CommonConverters.cs Value converters for data binding
Flow.Launcher.Avalonia/Converters/BoolToIsVisibleConverter.cs Boolean to visibility converter
Flow.Launcher.Avalonia/AvaloniaPublicAPI.cs IPublicAPI implementation for plugin compatibility
Flow.Launcher.Avalonia/App.axaml Application XAML with theme configuration
Flow.Launcher.Avalonia/App.axaml.cs Application code-behind with initialization logic

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread Flow.Launcher.Avalonia/app.manifest
Comment thread Flow.Launcher.Infrastructure/Logger/Log.cs
Comment thread Flow.Launcher.Avalonia/ViewModel/ResultsViewModel.cs
Comment thread Flow.Launcher.Avalonia/Helper/GlobalHotkey.cs
Comment thread Flow.Launcher.Avalonia/Helper/GlobalHotkey.cs
Comment thread Flow.Launcher.Avalonia/ViewModel/ResultViewModel.cs
Comment thread Flow.Launcher.Avalonia/ViewModel/ResultViewModel.cs
Comment thread Flow.Launcher.Avalonia/Views/ResultListBox.axaml.cs
Comment thread Flow.Launcher.Avalonia/ViewModel/ResultsViewModel.cs
Comment thread Flow.Launcher.Avalonia/ViewModel/MainViewModel.cs
- Add ActiveView enum to track Results vs ContextMenu view state
- Add ContextMenu ResultsViewModel and view switching logic
- Implement LoadContextMenuCommand using PluginManager.GetContextMenusForPlugin
- Add keyboard navigation: Shift+Enter/Right to open, Left/Escape to close
- Update SelectNextItem/SelectPrevItem to navigate appropriate list
- Update EscCommand to return from context menu before hiding
- Create Internationalization service that parses WPF XAML language files
- Load translations from main Languages/ folder and all plugin Languages/ folders
- Add LocalizeExtension markup extension and Translator helper for XAML/code
- Fix IPublicAPI.GetTranslation to use the i18n service for plugin context menus
- Update MainWindow to use localized placeholder text
@github-actions

This comment has been minimized.

- Internationalization.Initialize() called in constructor when DI creates it
- Remove InitializeInternationalization() method from App.axaml.cs
- Update AvaloniaPublicAPI and LocalizeExtension to use Ioc.Default.GetService
- Reorder ConfigureDI before i18n initialization
@github-actions

This comment has been minimized.

@TBM13

TBM13 commented Jan 16, 2026

Copy link
Copy Markdown
Contributor

Is there any actual benefit to switching to Avalonia or it's just for testing purposes?

@taooceros

Copy link
Copy Markdown
Member Author

Is there any actual benefit to switching to Avalonia or it's just for testing purposes?

There should be some performance improvement for animation. Besides, I also want to have the chance to make flow cross platform as I am gradually migrating my workflow to mac.

- MainWindowVisibility starts as false (window hidden)
- Window IsVisible bound to MainWindowVisibility
- Set MainWindowVisibility = true in OnPluginsReady() after plugins load
@github-actions

This comment has been minimized.

- Add Glyph and GlyphAvailable properties to ResultViewModel
- Set Glyph from plugin Result when creating result items
- Add resultGlyph style matching icon size (32x32)
- Update ResultListBox to show glyph or image icon based on ShowGlyph property
- ShowGlyph = true when UseGlyphIcons is enabled AND glyph is available
@jjw24 jjw24 modified the milestones: 3.0.0, Future Feb 22, 2026
@github-actions

Copy link
Copy Markdown

@check-spelling-bot Report

🔴 Please review

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

❌ Errors and Warnings Count
❌ check-file-path 199
❌ forbidden-pattern 1
⚠️ noisy-file 2
⚠️ non-alpha-in-dictionary 2

See ❌ Event descriptions for more information.

Forbidden patterns 🙅 (1)

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. preexisting

[Pp]re[- ]existing
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.

taooceros and others added 3 commits March 26, 2026 14:12
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
Split repository guidance by domain so contributors can find module-specific rules without duplicating repo-wide conventions.
@jjw24

jjw24 commented Apr 11, 2026

Copy link
Copy Markdown
Member

@taooceros could you list us what's left to do in this PR please.

@taooceros

Copy link
Copy Markdown
Member Author

I will get a summary soon.

taooceros and others added 12 commits April 19, 2026 15:04
Bring the Avalonia host closer to WPF parity by wiring the missing settings dialogs, selectors, and public API flows. Also fix the async JSON save path and settings DI so direct-launch validation can get past the earlier runtime failures.

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
Track the requested local agent metadata in the repo and add a minimal OpenCode project config for editor/schema support. Keep the old .gemini workspace out of the repository state.

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
Move the new WPF-inspired palette into shared Avalonia theme resources so the main shell can pull consistent brushes and borders from one place. This keeps later styling polish tied to a single resource layer instead of scattered hex values.

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
Apply the shared theme brushes to the live result list and the theme settings preview so the settings sample matches the actual search window. This makes the new palette visible in the places users judge the UI most quickly.

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
Replace the rigid footer button rows on the About page with flexible wrapping so longer labels do not clip or disappear. This keeps the action layout stable across different widths and localized text lengths.

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
Mark the completed dialogs, settings work, and runtime wiring so the migration plan matches the current Avalonia host state. This keeps the remaining work list focused on the gaps that still matter instead of already-finished items.

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
@taooceros taooceros marked this pull request as ready for review May 2, 2026 19:55

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

15 issues found across 291 files

Note: This PR contains a large number of files. cubic only reviews up to 75 files per PR, so some files may not have been reviewed. cubic prioritises the most important files to review.

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="Flow.Launcher.Avalonia/Views/SettingPages/ThemeSettingsPage.axaml">

<violation number="1" location="Flow.Launcher.Avalonia/Views/SettingPages/ThemeSettingsPage.axaml:13">
P3: Avoid hardcoding font sizes in XAML; rely on default or shared styles so theme/accessibility updates apply consistently.

(Based on your team's feedback about relying on default UI styles and font sizes.) [FEEDBACK_USED]</violation>
</file>

<file name="Flow.Launcher.Avalonia/Views/SettingPages/HotkeySettingsPage.axaml">

<violation number="1" location="Flow.Launcher.Avalonia/Views/SettingPages/HotkeySettingsPage.axaml:14">
P2: Avoid hardcoding FontSize in XAML; use the default/shared style so global theming and accessibility scaling stay consistent.

(Based on your team's feedback about relying on default UI styles and font sizes.) [FEEDBACK_USED]</violation>

<violation number="2" location="Flow.Launcher.Avalonia/Views/SettingPages/HotkeySettingsPage.axaml:24">
P3: Avoid hardcoding FontSize in XAML; use default/shared styles for consistent appearance across themes.

(Based on your team's feedback about relying on default UI styles and font sizes.) [FEEDBACK_USED]</violation>
</file>

<file name="Flow.Launcher.Avalonia/Views/Dialogs/ProgressBoxWindow.axaml">

<violation number="1" location="Flow.Launcher.Avalonia/Views/Dialogs/ProgressBoxWindow.axaml:17">
P3: Avoid hardcoded `FontSize` here and rely on default/shared text styles for consistent theming and accessibility.

(Based on your team's feedback about relying on default UI styles and avoiding hardcoded font sizes.) [FEEDBACK_USED]</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

Comment thread Flow.Launcher.Avalonia/Views/Controls/HotkeyControl.axaml.cs
Comment thread Flow.Launcher.Core/Flow.Launcher.Core.csproj
Comment thread Flow.Launcher.Avalonia/Views/Controls/HotkeyControl.axaml.cs
Comment thread .gitignore
Comment thread .github/workflows/dotnet.yml
Comment thread Flow.Launcher.Avalonia/Views/Dialogs/ReportWindow.axaml.cs
Comment thread Flow.Launcher.Avalonia/Views/Dialogs/ReportWindow.axaml.cs
Comment thread Flow.Launcher.Avalonia/Views/SettingPages/SettingsWindow.axaml
WindowStartupLocation="CenterScreen">

<Grid RowDefinitions="Auto,Auto,*,Auto" Margin="20">
<TextBlock FontSize="20"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P3: Avoid hardcoded FontSize here and rely on default/shared text styles for consistent theming and accessibility.

(Based on your team's feedback about relying on default UI styles and avoiding hardcoded font sizes.)

View Feedback

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At Flow.Launcher.Avalonia/Views/Dialogs/ProgressBoxWindow.axaml, line 17:

<comment>Avoid hardcoded `FontSize` here and rely on default/shared text styles for consistent theming and accessibility.

(Based on your team's feedback about relying on default UI styles and avoiding hardcoded font sizes.) </comment>

<file context>
@@ -0,0 +1,41 @@
+        WindowStartupLocation="CenterScreen">
+
+    <Grid RowDefinitions="Auto,Auto,*,Auto" Margin="20">
+        <TextBlock FontSize="20"
+                   FontWeight="SemiBold"
+                   Text="{Binding TitleText}" />
</file context>

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 19

Note

Due to the large number of review comments, Critical, Major severity comments were prioritized as inline comments.

♻️ Duplicate comments (2)
Flow.Launcher.Avalonia/App.axaml.cs (1)

142-150: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Attach storage to the fallback Settings instance too.

The failure path still creates _settings without SetStorage, so later saves run against an unconfigured settings object.

Suggested fix
         catch (Exception e)
         {
             Log.Exception(ClassName, "Settings load failed", e);
-            _settings = new Settings
+            var storage = new FlowLauncherJsonStorage<Settings>();
+            _settings = new Settings
             {
                 WindowSize = 580, WindowHeightSize = 42, QueryBoxFontSize = 24,
                 ItemHeightSize = 50, ResultItemFontSize = 14, ResultSubItemFontSize = 12, MaxResultsToShow = 6
             };
+            _settings.SetStorage(storage);
         }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@Flow.Launcher.Avalonia/App.axaml.cs` around lines 142 - 150, The fallback
Settings instance created in the catch block is missing its storage attachment,
so call SetStorage on the newly created _settings (the same storage used for the
normal settings path) before assigning/using it; update the catch to create the
Settings object and then invoke _settings.SetStorage(...) with the existing
settings storage instance (the same storage reference used elsewhere when
loading/saving settings), ensuring the fallback has storage configured.
Flow.Launcher.Avalonia/MainWindow.axaml (1)

68-75: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Make the search icon overlay non-hit-testable.

This overlay sits on top of the query box, so clicks on the icon area can stop focusing the TextBox.

Suggested fix
-                <Canvas Name="SearchIconCanvas" 
-                        Classes="searchIconPosition"
-                        HorizontalAlignment="Right">
+                <Canvas Name="SearchIconCanvas"
+                        Classes="searchIconPosition"
+                        HorizontalAlignment="Right"
+                        IsHitTestVisible="False">
In Avalonia UI, does an overlaid Canvas receive pointer events by default, and does setting `IsHitTestVisible="False"` allow clicks to pass through to the TextBox underneath?
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@Flow.Launcher.Avalonia/MainWindow.axaml` around lines 68 - 75, The overlaid
SearchIconCanvas is intercepting pointer events and preventing the underlying
TextBox from receiving focus; make the overlay non-hit-testable by setting
IsHitTestVisible="False" (on SearchIconCanvas or on the inner SearchIcon Path)
so pointer events pass through to the TextBox beneath, ensuring clicks still
focus the input while preserving the visual overlay.
🟡 Minor comments (22)
Flow.Launcher.Avalonia/Views/Dialogs/NotificationWindow.axaml.cs-87-94 (1)

87-94: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Handle icon-load failures explicitly to avoid silent task faults.

LoadIconAsync is fire-and-forget and currently has no local exception handling. A bad/corrupt image path can fault the task without structured logging.

Suggested fix
     private async System.Threading.Tasks.Task LoadIconAsync(string iconPath)
     {
-        var resolvedPath = File.Exists(iconPath)
-            ? iconPath
-            : Path.Combine(Constant.ProgramDirectory, "Images", "app.png");
-
-        NotificationIcon = await ImageLoader.LoadAsync(resolvedPath);
+        try
+        {
+            var resolvedPath = File.Exists(iconPath)
+                ? iconPath
+                : Path.Combine(Constant.ProgramDirectory, "Images", "app.png");
+
+            NotificationIcon = await ImageLoader.LoadAsync(resolvedPath);
+        }
+        catch (Exception ex)
+        {
+            Log.Exception(nameof(NotificationWindow), "Failed to load notification icon", ex);
+            NotificationIcon = null;
+        }
     }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@Flow.Launcher.Avalonia/Views/Dialogs/NotificationWindow.axaml.cs` around
lines 87 - 94, LoadIconAsync currently awaits ImageLoader.LoadAsync but has no
exception handling, causing silent task faults; wrap the
ImageLoader.LoadAsync(resolvedPath) call in a try/catch inside LoadIconAsync
(catch Exception) and on failure set a safe fallback for NotificationIcon and
log the exception (include resolvedPath and the exception) using the existing
logging mechanism so failures are visible and the UI remains stable.
AGENTS.md-5-16 (1)

5-16: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Root AGENTS table needs MD058 spacing fix.

Add blank lines around the WHERE TO LOOK table block.

Suggested patch
 ## WHERE TO LOOK
+
 | Task | Location | Notes |
 |------|----------|-------|
 | WPF app behavior | `Flow.Launcher/` | Main host, windows, settings shell, WPF-only UI rules |
 | Avalonia app behavior | `Flow.Launcher.Avalonia/` | Avalonia host, WPF compatibility shim, migrated settings pages |
 | Plugin lifecycle | `Flow.Launcher.Core/` | `PluginManager`, plugin loading, updates, manifest integration |
 | Shared infra | `Flow.Launcher.Infrastructure/` | settings, storage, hotkeys, logging, fuzzy matching |
 | Plugin SDK contract | `Flow.Launcher.Plugin/` | interfaces/models consumed by built-in and external plugins |
 | Built-in plugins | `Plugins/` | 12 plugin projects, shared `Main.cs` + `plugin.json` structure |
 | Test project | `Flow.Launcher.Test/` | NUnit 4 tests; some Explorer tests need Windows Search |
 | CI / release process | `.github/` | workflow automation, release PRs, plugin publishing, issue templates |
+
 ## CHILD AGENTS
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@AGENTS.md` around lines 5 - 16, The WHERE TO LOOK table in AGENTS.md violates
MD058 (missing blank lines around a block table); edit AGENTS.md and add a blank
line immediately before the "## WHERE TO LOOK" heading block and another blank
line immediately after the table (after the final | CI / release process |
`.github/` ... | row) so the table is separated from surrounding text, ensuring
proper Markdown spacing for the "WHERE TO LOOK" table block.
Flow.Launcher.Infrastructure/AGENTS.md-5-14 (1)

5-14: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Add blank lines around the table (MD058).

markdownlint expects a blank line before and after this table block.

Suggested patch
 ## WHERE TO LOOK
+
 | Task | Location | Notes |
 |------|----------|-------|
 | User settings | `UserSettings/` | `Settings`, `DataLocation`, app/user data roots |
 | Storage | `Storage/` | JSON/binary persistence, backup/atomic write behavior |
 | Search matching | `StringMatcher.cs`, related models | fuzzy/acronym/pinyin behavior |
 | Logging | `Logger/` | NLog wrapper and diagnostics |
 | Hotkeys | `Hotkey/` | low-level keyboard integration |
 | Windows helpers | helper/system wrappers | Win32 and shell integration |
+
 ## LOCAL RULES
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@Flow.Launcher.Infrastructure/AGENTS.md` around lines 5 - 14, The Markdown
table under the "## WHERE TO LOOK" heading needs blank lines before and after it
to satisfy markdownlint rule MD058; edit the AGENTS.md content so there is an
empty line between the "## WHERE TO LOOK" heading and the table start, and
another empty line after the table end (i.e., ensure a blank line before the
first | of the table and one after the final | row) to resolve the lint warning.
.github/AGENTS.md-5-15 (1)

5-15: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Lint fix needed: blank lines around table (MD058).

Please add a blank line before and after this table.

Suggested patch
 ## WHERE TO LOOK
+
 | Task | Location | Notes |
 |------|----------|-------|
 | CI build and artifacts | `.github/workflows/dotnet.yml` | build/test pipeline, WSearch service, artifact publishing |
 | Release deploy | `.github/workflows/release_deploy.yml` | website + Chocolatey dispatches, secret-driven |
 | Release PR body automation | `.github/workflows/release_pr.yml`, `.github/update_release_pr.py` | expects one open release PR and milestone grouping |
 | Built-in plugin publishing | `.github/workflows/default_plugins.yml` | publishes plugin repos, updates plugin metadata |
 | Issue/PR automation | `.github/workflows/pr_*.yml`, `stale.yml`, `spelling.yml` | author assignment, milestone, stale, spelling |
 | Dependency policy | `.github/dependabot.yml` | daily cadence, PR caps, ignored packages |
 | Intake rules | `.github/ISSUE_TEMPLATE/` | bug report required fields, feature request, code review template |
+
 ## LOCAL RULES
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.github/AGENTS.md around lines 5 - 15, Add a blank line before and after the
Markdown table under the "WHERE TO LOOK" heading so the table is separated from
surrounding text (fixes MD058); locate the "WHERE TO LOOK" header and the
following table block (the lines starting with "## WHERE TO LOOK" and the table
rows like "| Task | Location | Notes |") and insert one empty line immediately
above the "## WHERE TO LOOK" table block if not present and one empty line
immediately after the table end.
Plugins/AGENTS.md-11-18 (1)

11-18: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Resolve markdownlint MD058 for the WHERE TO LOOK table.

Insert blank lines around this table block.

Suggested patch
 ## WHERE TO LOOK
+
 | Task | Location | Notes |
 |------|----------|-------|
 | Entry/query logic | each plugin `Main.cs` | sync vs async behavior lives here |
 | Manifest | each plugin `plugin.json` | metadata, action keyword(s), icon, execute file |
 | Settings model | `Settings.cs` or equivalent | usually loaded through API storage helpers |
 | Plugin UI/settings | plugin views/viewmodels if present | some have WPF + Avalonia settings paths |
+
 ## LOCAL RULES
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@Plugins/AGENTS.md` around lines 11 - 18, The MD058 lint violation is caused
by the table not being separated by blank lines; update the Plugins/AGENTS.md by
adding a blank line after the "## WHERE TO LOOK" heading and another blank line
after the table block (the lines starting with "| Task | Location | Notes |"
through the table row with "Plugin UI/settings | plugin views/viewmodels if
present | ...") so the table is isolated with an empty line above and below to
satisfy markdownlint.
Flow.Launcher.Core/AGENTS.md-5-14 (1)

5-14: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Fix markdownlint MD058 around the table.

Add blank lines before/after the WHERE TO LOOK table to satisfy markdownlint.

Suggested patch
 ## WHERE TO LOOK
+
 | Task | Location | Notes |
 |------|----------|-------|
 | Plugin lifecycle | `Plugin/PluginManager.cs` | discovery, load, init, query fanout |
 | Plugin manifest parsing | `Plugin/PluginConfig.cs` | scans `plugin.json`, duplicate/version filtering |
 | Loader implementation | `Plugin/PluginsLoader.cs` | .NET + external plugin loading |
 | Community plugins | `ExternalPlugins/` | manifest/store integration |
 | Updates | updater-related files | Squirrel + release logic |
 | Resources/i18n | `Resource/`, related services | host/plugin resource merging |
+
 ## LOCAL RULES
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@Flow.Launcher.Core/AGENTS.md` around lines 5 - 14, Add a blank line
immediately before the "## WHERE TO LOOK" heading/table and another blank line
immediately after the table to satisfy markdownlint MD058; edit the AGENTS.md
section containing the table that lists Plugin/PluginManager.cs,
Plugin/PluginConfig.cs, Plugin/PluginsLoader.cs, ExternalPlugins/,
updater-related files, and Resource/ so the table is separated by empty lines
above and below.
Flow.Launcher.Plugin/AGENTS.md-5-12 (1)

5-12: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Table spacing violates MD058.

Please add blank lines before and after this table.

Suggested patch
 ## WHERE TO LOOK
+
 | Task | Location | Notes |
 |------|----------|-------|
 | Core plugin interfaces | `Interfaces/` | `IPlugin`, `IAsyncPlugin`, capability interfaces |
 | Public models | root models, `SharedModels/` | `Result`, `Query`, metadata, settings-facing types |
 | Shared commands/helpers | `SharedCommands/` | reusable SDK-side pieces |
 | Docs | `README.md` | package/plugin authoring baseline |
+
 ## LOCAL RULES
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@Flow.Launcher.Plugin/AGENTS.md` around lines 5 - 12, The Markdown table under
the "## WHERE TO LOOK" heading violates MD058 by lacking blank lines around the
table; fix it by inserting a single blank line immediately after the "## WHERE
TO LOOK" heading and another blank line immediately after the table block (the
pipe-delimited rows shown in the diff) so there is one empty line before and
after the table.
Flow.Launcher/AGENTS.md-5-13 (1)

5-13: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Surround the “WHERE TO LOOK” table with blank lines.

Line 6 currently triggers markdownlint MD058. Add a blank line before and after the table block.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@Flow.Launcher/AGENTS.md` around lines 5 - 13, The "WHERE TO LOOK" markdown
table in AGENTS.md triggers MD058 because it is not surrounded by blank lines;
update the file to insert a blank line immediately before the "## WHERE TO LOOK"
header/table block and another blank line immediately after the table so the
table is separated from surrounding content and satisfies markdownlint; target
the table block shown (the header "## WHERE TO LOOK" and its pipe-delimited
rows) when making the change.
Flow.Launcher.Avalonia/AGENTS.md-5-13 (1)

5-13: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Add blank lines around the table block.

Line 6 starts a table immediately after a heading, which triggers markdownlint (MD058). Add one blank line before and after this table for clean rendering/lint pass.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@Flow.Launcher.Avalonia/AGENTS.md` around lines 5 - 13, Add a blank line
before and a blank line after the markdown table that starts with the heading
"## WHERE TO LOOK" and the pipe-delimited table (the | Task | Location | Notes |
... block) so the table is separated from surrounding content and satisfies
MD058; edit the AGENTS.md section containing that table to insert one empty line
above the table and one empty line below it.
AVALONIA_MIGRATION_CHECKLIST.md-347-384 (1)

347-384: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Insert blank lines before table blocks in Core Features subsections.

At Line 348/362/372/381, tables start immediately after subsection titles and trigger MD058. Add a blank line before each table.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@AVALONIA_MIGRATION_CHECKLIST.md` around lines 347 - 384, The markdown linter
MD058 is triggered because tables in the "Search & Results", "Window
Management", and "System Integration" subsections start immediately after their
subsection titles; add a single blank line before each table to separate the
heading and the table (i.e., insert a blank line before the table that begins
under the "Search & Results" header, the table under "Window Management", and
the table under "System Integration") so each subsection title is followed by a
blank line then the table.
AVALONIA_MIGRATION_CHECKLIST.md-458-528 (1)

458-528: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Add language identifiers to fenced code blocks.

The blocks at Line 458 and Line 481 have no language (MD040). Use text (or bash where appropriate).

Suggested patch
-```
+```text
 Flow.Launcher/
 ...

- +text
Flow.Launcher.Avalonia/
...

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@AVALONIA_MIGRATION_CHECKLIST.md` around lines 458 - 528, Update the two
fenced code blocks that list the project trees so they include a language
identifier; specifically, change the triple-backtick fence before the block
starting with "Flow.Launcher/" and the one before the block starting with
"Flow.Launcher.Avalonia/" to use ```text (or ```bash for shell-style listing)
instead of bare ``` so the MD040 lint warning is resolved.
AVALONIA_MIGRATION_CHECKLIST.md-56-166 (1)

56-166: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Fix single-cell “section header” rows inside 3-column tables.

Rows like Line 58 (| **Startup Section** |) break table column count (MD056). Keep 3 cells for those separator rows.

Suggested patch pattern
-| **Startup Section** |
+| **Startup Section** |  |  |
...
-| **Behavior Section** |
+| **Behavior Section** |  |  |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@AVALONIA_MIGRATION_CHECKLIST.md` around lines 56 - 166, The table contains
single-cell section header rows (e.g., "**Startup Section**", "**Behavior
Section**", "**Position Section**", etc.) that break the 3-column table
structure and trigger MD056; update each of those separator rows so they contain
three pipe-separated cells (for example add two empty cells or placeholder text)
to maintain the "| col1 | col2 | col3 |" format throughout the file (search for
rows starting with "| **" and ensure they become three-cell rows).
Flow.Launcher.Avalonia/Views/SettingPages/CustomQueryHotkeyWindow.axaml.cs-81-118 (1)

81-118: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Localize the validation messages too.

This dialog already routes button text through Translate(...), but the error title/messages are still hard-coded English. That leaves part of the settings flow untranslated on non-English installs.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@Flow.Launcher.Avalonia/Views/SettingPages/CustomQueryHotkeyWindow.axaml.cs`
around lines 81 - 118, The validation dialog strings in OnDoneClick are
hard-coded; update the calls that pass "Custom Query Hotkey", "Both the hotkey
and query text are required.", and "That hotkey is already assigned to another
custom query." to use the app localization method (Translate) before calling
ShowMessageAsync, and modify ShowMessageAsync to accept already-localized
title/content or call Translate for any non-localized inputs; reference the
OnDoneClick method and ShowMessageAsync to locate and change the message
parameters so all dialog title and content use Translate(...) like the
CloseButtonText does.
Flow.Launcher.Avalonia/Views/Dialogs/PluginUpdateWindow.axaml-40-53 (1)

40-53: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Move the remaining labels through i18n resources.

Restart after updating plugins and Cancel are still hard-coded here, so this dialog won't fully localize with the rest of the Avalonia host.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@Flow.Launcher.Avalonia/Views/Dialogs/PluginUpdateWindow.axaml` around lines
40 - 53, Replace the two hard-coded UI strings with bindings to the i18n
resource keys so the dialog localizes; specifically change the CheckBox Content
("Restart after updating plugins") to use the localization resource (e.g., a
resource key like RestartAfterUpdatingPlugins) and change the Cancel Button
Content ("Cancel") to use the Cancel resource key, keeping the existing
bindings/properties (Restart, UpdateButtonText) and event handlers
(OnCancelClick, OnUpdateClick) intact so only the Content attributes are
switched to resource-based bindings or StaticResource/Loc markup extensions that
the project uses for localization.
Flow.Launcher.Avalonia/Views/SettingPages/CustomShortcutWindow.axaml.cs-80-100 (1)

80-100: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Trim the shortcut key before validating and saving it.

Right now "foo" and " foo " are treated as different values, so _doesShortcutExist(...) can be bypassed and the saved shortcut key may not expand the way the user expects.

Suggested change
 private async void OnDoneClick(object? sender, RoutedEventArgs e)
 {
-    if (string.IsNullOrWhiteSpace(ShortcutKey) || string.IsNullOrWhiteSpace(ShortcutValue))
+    var normalizedShortcutKey = ShortcutKey.Trim();
+
+    if (string.IsNullOrWhiteSpace(normalizedShortcutKey) || string.IsNullOrWhiteSpace(ShortcutValue))
     {
         await ShowMessageAsync("Custom Shortcut", "Both the shortcut and expansion text are required.");
         return;
     }
 
-    if (((_update && _originalShortcutKey != ShortcutKey) || !_update) && _doesShortcutExist(ShortcutKey))
+    if (((_update && _originalShortcutKey != normalizedShortcutKey) || !_update) &&
+        _doesShortcutExist(normalizedShortcutKey))
     {
         await ShowMessageAsync("Custom Shortcut", "That shortcut key already exists.");
         return;
     }
 
-    if (_update && _originalShortcutKey == ShortcutKey && _originalShortcutValue == ShortcutValue)
+    if (_update && _originalShortcutKey == normalizedShortcutKey && _originalShortcutValue == ShortcutValue)
     {
         Close(false);
         return;
     }
 
+    ShortcutKey = normalizedShortcutKey;
     Close(true);
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@Flow.Launcher.Avalonia/Views/SettingPages/CustomShortcutWindow.axaml.cs`
around lines 80 - 100, In OnDoneClick, normalize the ShortcutKey by trimming
whitespace before any validation, existence checks, or comparison with
_originalShortcutKey/_originalShortcutValue so leading/trailing spaces don't
bypass _doesShortcutExist or create mismatched saved keys; i.e., compute a
trimmedKey = ShortcutKey?.Trim(), use trimmedKey for the Null/WhiteSpace check,
pass trimmedKey into _doesShortcutExist(trimmedKey), compare trimmedKey to
_originalShortcutKey when determining no-op updates, and ensure the value used
when saving/closing is the trimmed key.
Flow.Launcher.Avalonia/ViewModel/MainViewModel.cs-290-295 (1)

290-295: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

LoadHistory() runs the same history query twice.

After QueryText = string.Empty;, OnQueryTextChanged() already invokes QueryAsync(). The extra _ = QueryAsync(); immediately below repeats the history load every time this view opens.

Suggested change
         if (ActiveView == ActiveView.Results)
         {
             _queryTextBeforeHistory = QueryText;
             ActiveView = ActiveView.History;
             QueryText = string.Empty;
-            _ = QueryAsync();
 
             if (HistoryView.Results.Count > 0)
             {
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@Flow.Launcher.Avalonia/ViewModel/MainViewModel.cs` around lines 290 - 295,
The history load is triggered twice because setting QueryText = string.Empty
fires OnQueryTextChanged which already calls QueryAsync(), so remove the
redundant explicit call to QueryAsync(); in the MainViewModel method that
switches views (the block referencing ActiveView, _queryTextBeforeHistory,
QueryText and calling QueryAsync()), delete the line "_ = QueryAsync();" so
QueryAsync is only invoked via OnQueryTextChanged when QueryText is set to
empty.
Flow.Launcher.Avalonia/Views/SettingPages/GeneralSettingsPage.axaml-80-100 (1)

80-100: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Move the new search-window labels into localization resources.

Custom screen, Custom position, and Set X and Y when alignment is Custom are user-facing English strings in an otherwise localized page. These should use i18n:Localize keys like the rest of the settings UI.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@Flow.Launcher.Avalonia/Views/SettingPages/GeneralSettingsPage.axaml` around
lines 80 - 100, Replace the hardcoded English strings in the
SettingsExpanderItem elements with i18n:Localize resource keys: change
Content="Custom screen" to Content="{i18n:Localize CustomScreen}" (or your
chosen key), Content="Custom position" to Content="{i18n:Localize
CustomPosition}", and Description="Set X and Y when alignment is Custom" to
Description="{i18n:Localize CustomPositionDescription}"; add corresponding keys
to the localization resource file so SearchWindowAlign and other localized
entries remain consistent and bind to UI:SettingsExpanderItem and its Footer
ComboBox elements unchanged.
Flow.Launcher.Avalonia/Views/SettingPages/AboutSettingsPage.axaml-44-46 (1)

44-46: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Localize the new section descriptions.

These descriptions are hardcoded English while the rest of the page is localized, so this page will regress into a mixed-language UI for non-English users. Please move them into the i18n resources as well.

Also applies to: 58-60, 72-74

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@Flow.Launcher.Avalonia/Views/SettingPages/AboutSettingsPage.axaml` around
lines 44 - 46, The Description attributes in AboutSettingsPage.axaml's
SettingsExpander elements (e.g., the one with Header="{i18n:Localize website}"
and IconSource="World") are hardcoded English; replace those literal Description
strings with i18n resource lookups (use i18n:Localize or the existing
localization markup) and add corresponding keys to the i18n resource files; do
the same for the other two expanders referenced (the elements around lines 58-60
and 72-74) so all Header and Description text is pulled from localization keys
rather than hardcoded English.
Flow.Launcher.Avalonia/Views/Dialogs/WelcomeWindow.axaml-50-53 (1)

50-53: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Swap these Page 3 labels or hotkeys.

HotkeyUpDownDesc is currently shown next to left/right arrows, and HotkeyLeftRightDesc is shown next to up/down arrows. The onboarding text is backwards.

Suggested fix
-                        <TextBlock Grid.Row="0" Margin="0,0,0,10" Text="{i18n:Localize HotkeyUpDownDesc}" />
+                        <TextBlock Grid.Row="0" Margin="0,0,0,10" Text="{i18n:Localize HotkeyLeftRightDesc}" />
                         <controls:HotkeyDisplay Grid.Row="0" Grid.Column="1" Keys="←+→" />
-                        <TextBlock Grid.Row="1" Margin="0,0,0,10" Text="{i18n:Localize HotkeyLeftRightDesc}" />
+                        <TextBlock Grid.Row="1" Margin="0,0,0,10" Text="{i18n:Localize HotkeyUpDownDesc}" />
                         <controls:HotkeyDisplay Grid.Row="1" Grid.Column="1" Keys="↑+↓" />
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@Flow.Launcher.Avalonia/Views/Dialogs/WelcomeWindow.axaml` around lines 50 -
53, The two Page 3 items are swapped: the TextBlock using i18n:Localize
HotkeyUpDownDesc is paired with Keys="←+→" and HotkeyLeftRightDesc is paired
with Keys="↑+↓"; swap them so HotkeyUpDownDesc is paired with Keys="↑+↓" and
HotkeyLeftRightDesc is paired with Keys="←+→". Locate the two controls: the
TextBlock elements referencing HotkeyUpDownDesc and HotkeyLeftRightDesc and the
adjacent controls:HotkeyDisplay elements with Keys="←+→" and Keys="↑+↓", and
swap the Keys values or swap the TextBlock positions so each description matches
the corresponding HotkeyDisplay.
Flow.Launcher.Avalonia/Views/SettingPages/HotkeySettingsPage.axaml-102-114 (1)

102-114: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Differentiate the fixed Shift+Enter row from the editable context-menu hotkey.

Both rows render the same label, so users can’t tell which one they can change and which one is hard-coded.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@Flow.Launcher.Avalonia/Views/SettingPages/HotkeySettingsPage.axaml` around
lines 102 - 114, The two SettingsExpanderItem rows use the same
Content/localization key so users can’t tell the editable hotkey (HotkeyControl
bound to OpenContextMenuHotkey) from the fixed one (HotkeyDisplay
Keys="Shift+Enter"); update the second SettingsExpanderItem to use a different
label (e.g., a new localization key like OpenContextMenuHotkey_Fixed or append
"(fixed)" to the content) or a distinct visual cue so the fixed Shift+Enter row
is clearly labeled as non-editable while leaving the HotkeyControl row
unchanged.
Flow.Launcher.Avalonia/Views/SettingPages/ThemeSettingsPage.axaml-28-40 (1)

28-40: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Localize the remaining hard-coded labels on this page.

This still exposes English-only UI (Hello there, Theme resources, Sizing and fonts, Theme Builder, Warning, etc.), so the page bypasses the app’s i18n path in visible settings content.

Also applies to: 88-93, 116-116, 201-205, 296-299

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@Flow.Launcher.Avalonia/Views/SettingPages/ThemeSettingsPage.axaml` around
lines 28 - 40, Replace all hard-coded TextBlock/Text content on
ThemeSettingsPage.axaml (e.g., the Text attributes "Hello there", "Sample result
title", "Sample result subtitle" and visible headings like "Theme resources",
"Sizing and fonts", "Theme Builder", "Warning") with localized resource lookups
or bindings to the app's i18n keys (use the same pattern used elsewhere in the
project such as StaticResource/x:Static or a LocalizationManager binding).
Create or use descriptive resource keys (e.g., ThemeSettings_Hello,
ThemeSettings_ResultTitle, ThemeSettings_ResultSubtitle,
ThemeSettings_ThemeResources, ThemeSettings_SizingAndFonts,
ThemeSettings_ThemeBuilder, ThemeSettings_Warning) and replace the literal
strings with those resource references so the page follows the app’s
localization path.
Flow.Launcher.Avalonia/ViewModel/SettingPages/GeneralSettingsViewModel.cs-75-86 (1)

75-86: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

History-style labels won't refresh after a language switch.

UpdateLabels() mutates HistoryStyleOption.Display, but HistoryStyleOption does not raise property changes and the view model never re-raises HistoryStyles/SelectedHistoryStyle. This dropdown will keep the old language until the page is recreated.

Also applies to: 407-423, 809-829

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@Flow.Launcher.Avalonia/ViewModel/SettingPages/GeneralSettingsViewModel.cs`
around lines 75 - 86, UpdateLabels currently mutates HistoryStyleOption.Display
but the UI doesn't refresh because HistoryStyleOption doesn't raise
PropertyChanged and the VM doesn't re-raise HistoryStyles/SelectedHistoryStyle;
fix by making HistoryStyleOption raise INotifyPropertyChanged for its Display
(implement PropertyChanged in UpdateLabel) and/or after calling
HistoryStyles.ForEach(x => x.UpdateLabel(_i18n)) call the view model's
RaisePropertyChanged(nameof(HistoryStyles)) and
RaisePropertyChanged(nameof(SelectedHistoryStyle)) so the dropdown updates when
UpdateLabels() runs.
🧹 Nitpick comments (4)
Flow.Launcher.Avalonia/Views/Dialogs/NotificationWindow.axaml.cs (1)

17-18: 🏗️ Heavy lift

Use CommunityToolkit MVVM primitives instead of manual code-behind state/handlers.

This dialog currently mixes manual INotifyPropertyChanged and click handlers in the view class; please move bindable state/commands to an ObservableObject view model and bind commands from AXAML.

As per coding guidelines: Flow.Launcher.Avalonia/**/*.cs: Avalonia UI code should use CommunityToolkit.Mvvm patterns such as ObservableObject, [ObservableProperty], [RelayCommand].

Also applies to: 48-57, 123-153

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@Flow.Launcher.Avalonia/Views/Dialogs/NotificationWindow.axaml.cs` around
lines 17 - 18, The NotificationWindow class currently implements
INotifyPropertyChanged and contains click handlers; create a
NotificationViewModel that inherits
CommunityToolkit.Mvvm.ComponentModel.ObservableObject, convert window state
fields to [ObservableProperty]s and handlers to [RelayCommand] methods, then set
NotificationWindow.DataContext to an instance of that view model and remove the
manual INotifyPropertyChanged implementation and code-behind click handlers from
NotificationWindow; update AXAML to bind buttons and properties to the view
model commands/properties instead of using code-behind.
Plugins/Flow.Launcher.Plugin.Explorer/Flow.Launcher.Plugin.Explorer.csproj (1)

68-68: Add explicit separator in OutputPath glob for consistency across all plugins.

While MSBuild's normalization makes the current pattern $(OutputPath)**\*.* work correctly and deterministically, adding an explicit backslash makes the glob pattern clearer: $(OutputPath)\**\*.*. Apply this consistently across all plugin projects where this pattern is used.

Files affected

All 12 plugin csproj files use this pattern:

  • Flow.Launcher.Plugin.Explorer (line 68)
  • Flow.Launcher.Plugin.WindowsSettings (line 78)
  • Flow.Launcher.Plugin.Sys (line 75)
  • Flow.Launcher.Plugin.Program (line 84)
  • Flow.Launcher.Plugin.ProcessKiller (line 78)
  • Flow.Launcher.Plugin.WebSearch (line 72)
  • Flow.Launcher.Plugin.Url (line 70)
  • Flow.Launcher.Plugin.PluginIndicator (line 69)
  • Flow.Launcher.Plugin.PluginsManager (line 51)
  • Flow.Launcher.Plugin.Shell (line 74)
  • Flow.Launcher.Plugin.BrowserBookmark (line 125)
  • Flow.Launcher.Plugin.Calculator (line 78)
Proposed fix
-      <PluginFiles Include="$(OutputPath)**\*.*" />
+      <PluginFiles Include="$(OutputPath)\**\*.*" />
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@Plugins/Flow.Launcher.Plugin.Explorer/Flow.Launcher.Plugin.Explorer.csproj`
at line 68, Update the PluginFiles Include pattern to explicitly add a directory
separator after $(OutputPath) so the glob is unambiguous: change the attribute
value from "$(OutputPath)**\*.*" to "$(OutputPath)\**\*.*" in this csproj (look
for the PluginFiles Include entry and the OutputPath pattern), and apply the
same edit to the other plugin csproj files listed to ensure consistency across
all plugins.
Flow.Launcher.Avalonia/Views/Dialogs/ProgressBoxWindow.axaml (1)

1-14: ⚡ Quick win

Reorder root AXAML attributes to match repo convention.

x:Class is currently placed after several xmlns/design attributes; please reorder the root attributes to follow the project’s prescribed order for consistent formatting.

As per coding guidelines: **/*.{xaml,axaml}: In XAML/AXAML attribute order: x:Class → xmlns → key/name → layout → size → margin/padding → rest.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@Flow.Launcher.Avalonia/Views/Dialogs/ProgressBoxWindow.axaml` around lines 1
- 14, Reorder the root Window attributes in ProgressBoxWindow.axaml so x:Class
is the first attribute
(x:Class="Flow.Launcher.Avalonia.Views.Dialogs.ProgressBoxWindow"), followed by
the xmlns declarations, then key/name attributes, layout attributes, size
attributes (Width/Height), margin/padding, and then the remaining attributes
(e.g., CanResize, WindowStartupLocation); update the Window tag for the
ProgressBoxWindow XAML to follow the project's prescribed attribute ordering
convention.
Flow.Launcher.Avalonia/Views/Dialogs/ProgressBoxWindow.axaml.cs (1)

11-25: 🏗️ Heavy lift

Align this dialog with the Avalonia MVVM pattern used in the host.

This window currently acts as its own view-model (INotifyPropertyChanged + code-behind click handlers). Please move state/commands into an ObservableObject view-model and bind commands from AXAML for consistency with the Avalonia migration pattern.

As per coding guidelines: Flow.Launcher.Avalonia/**/*.cs: Avalonia UI code should use CommunityToolkit.Mvvm patterns such as ObservableObject, [ObservableProperty], [RelayCommand].

Also applies to: 125-139

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@Flow.Launcher.Avalonia/Views/Dialogs/ProgressBoxWindow.axaml.cs` around lines
11 - 25, The ProgressBoxWindow class currently implements view-model
responsibilities (implements INotifyPropertyChanged, holds _isIndeterminate,
_progressValue, _progressText and click handlers) — refactor by extracting a new
ViewModel class that derives from
CommunityToolkit.Mvvm.ComponentModel.ObservableObject (e.g.,
ProgressBoxViewModel) and use [ObservableProperty] for IsIndeterminate,
ProgressValue, ProgressText and a [RelayCommand] for the cancel action that
invokes the existing _cancelProgress logic; update ProgressBoxWindow to set
DataContext = new ProgressBoxViewModel(TitleText, cancelAction) and remove
INotifyPropertyChanged implementation and backing fields from the code-behind,
then wire the AXAML to bind to the new ViewModel properties and command names
instead of relying on code-behind handlers (ensure ProgressBoxWindow constructor
still accepts caption and cancelAction and passes them into the ViewModel).

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: a0986ad8-fa43-42ba-912f-9c97ce418693

📥 Commits

Reviewing files that changed from the base of the PR and between 11eefa4 and 833672b.

📒 Files selected for processing (81)
  • .github/AGENTS.md
  • .github/workflows/dotnet.yml
  • .gitignore
  • .gsd/quick/1-a-review-about-whether-we-have-touched-a/1-SUMMARY.md
  • AGENTS.md
  • AVALONIA_MIGRATION_CHECKLIST.md
  • Flow.Launcher.Avalonia/.agent/README.md
  • Flow.Launcher.Avalonia/AGENTS.md
  • Flow.Launcher.Avalonia/App.axaml.cs
  • Flow.Launcher.Avalonia/AvaloniaPublicAPI.cs
  • Flow.Launcher.Avalonia/Flow.Launcher.Avalonia.csproj
  • Flow.Launcher.Avalonia/Helper/AutoStartup.cs
  • Flow.Launcher.Avalonia/Helper/HotKeyMapper.cs
  • Flow.Launcher.Avalonia/Helper/ResultHelper.cs
  • Flow.Launcher.Avalonia/MainWindow.axaml
  • Flow.Launcher.Avalonia/MainWindow.axaml.cs
  • Flow.Launcher.Avalonia/Storage/History.cs
  • Flow.Launcher.Avalonia/Themes/Base.axaml
  • Flow.Launcher.Avalonia/Themes/Resources.axaml
  • Flow.Launcher.Avalonia/ViewModel/MainViewModel.cs
  • Flow.Launcher.Avalonia/ViewModel/ResultViewModel.cs
  • Flow.Launcher.Avalonia/ViewModel/SettingPages/AboutSettingsViewModel.cs
  • Flow.Launcher.Avalonia/ViewModel/SettingPages/GeneralSettingsViewModel.cs
  • Flow.Launcher.Avalonia/ViewModel/SettingPages/HotkeySettingsViewModel.cs
  • Flow.Launcher.Avalonia/ViewModel/SettingPages/PluginStoreSettingsViewModel.cs
  • Flow.Launcher.Avalonia/ViewModel/SettingPages/ThemeSettingsViewModel.cs
  • Flow.Launcher.Avalonia/Views/Controls/HotkeyControl.axaml.cs
  • Flow.Launcher.Avalonia/Views/Controls/HotkeyDisplay.axaml
  • Flow.Launcher.Avalonia/Views/Controls/HotkeyDisplay.axaml.cs
  • Flow.Launcher.Avalonia/Views/Dialogs/NotificationWindow.axaml
  • Flow.Launcher.Avalonia/Views/Dialogs/NotificationWindow.axaml.cs
  • Flow.Launcher.Avalonia/Views/Dialogs/PluginUpdateWindow.axaml
  • Flow.Launcher.Avalonia/Views/Dialogs/PluginUpdateWindow.axaml.cs
  • Flow.Launcher.Avalonia/Views/Dialogs/ProgressBoxWindow.axaml
  • Flow.Launcher.Avalonia/Views/Dialogs/ProgressBoxWindow.axaml.cs
  • Flow.Launcher.Avalonia/Views/Dialogs/ReportWindow.axaml
  • Flow.Launcher.Avalonia/Views/Dialogs/ReportWindow.axaml.cs
  • Flow.Launcher.Avalonia/Views/Dialogs/WelcomeWindow.axaml
  • Flow.Launcher.Avalonia/Views/Dialogs/WelcomeWindow.axaml.cs
  • Flow.Launcher.Avalonia/Views/ResultListBox.axaml
  • Flow.Launcher.Avalonia/Views/SettingPages/AboutSettingsPage.axaml
  • Flow.Launcher.Avalonia/Views/SettingPages/CustomQueryHotkeyWindow.axaml
  • Flow.Launcher.Avalonia/Views/SettingPages/CustomQueryHotkeyWindow.axaml.cs
  • Flow.Launcher.Avalonia/Views/SettingPages/CustomShortcutWindow.axaml
  • Flow.Launcher.Avalonia/Views/SettingPages/CustomShortcutWindow.axaml.cs
  • Flow.Launcher.Avalonia/Views/SettingPages/GeneralSettingsPage.axaml
  • Flow.Launcher.Avalonia/Views/SettingPages/HotkeySettingsPage.axaml
  • Flow.Launcher.Avalonia/Views/SettingPages/ReleaseNotesWindow.axaml
  • Flow.Launcher.Avalonia/Views/SettingPages/ReleaseNotesWindow.axaml.cs
  • Flow.Launcher.Avalonia/Views/SettingPages/SelectBrowserWindow.axaml
  • Flow.Launcher.Avalonia/Views/SettingPages/SelectBrowserWindow.axaml.cs
  • Flow.Launcher.Avalonia/Views/SettingPages/SelectFileManagerWindow.axaml
  • Flow.Launcher.Avalonia/Views/SettingPages/SelectFileManagerWindow.axaml.cs
  • Flow.Launcher.Avalonia/Views/SettingPages/ThemeSettingsPage.axaml
  • Flow.Launcher.Core/AGENTS.md
  • Flow.Launcher.Core/packages.lock.json
  • Flow.Launcher.Infrastructure/AGENTS.md
  • Flow.Launcher.Infrastructure/Flow.Launcher.Infrastructure.csproj
  • Flow.Launcher.Infrastructure/Storage/JsonStorage.cs
  • Flow.Launcher.Infrastructure/packages.lock.json
  • Flow.Launcher.Plugin/AGENTS.md
  • Flow.Launcher.Plugin/Flow.Launcher.Plugin.csproj
  • Flow.Launcher.Plugin/packages.lock.json
  • Flow.Launcher.Test/Avalonia/ProgrammaticQueryFocusRequestTest.cs
  • Flow.Launcher.Test/Flow.Launcher.Test.csproj
  • Flow.Launcher/AGENTS.md
  • Flow.Launcher/Languages/en.xaml
  • Flow.Launcher/Storage/History.cs
  • Flow.Launcher/packages.lock.json
  • Plugins/AGENTS.md
  • Plugins/Flow.Launcher.Plugin.BrowserBookmark/Flow.Launcher.Plugin.BrowserBookmark.csproj
  • Plugins/Flow.Launcher.Plugin.Explorer/Flow.Launcher.Plugin.Explorer.csproj
  • Plugins/Flow.Launcher.Plugin.Explorer/Search/ResultManager.cs
  • Plugins/Flow.Launcher.Plugin.Explorer/ViewModels/SettingsViewModel.cs
  • Plugins/Flow.Launcher.Plugin.PluginsManager/Views/PluginsManagerSettings.xaml
  • Plugins/Flow.Launcher.Plugin.ProcessKiller/Flow.Launcher.Plugin.ProcessKiller.csproj
  • Plugins/Flow.Launcher.Plugin.ProcessKiller/Views/SettingsControl.xaml
  • Plugins/Flow.Launcher.Plugin.Program/Flow.Launcher.Plugin.Program.csproj
  • Plugins/Flow.Launcher.Plugin.Sys/Flow.Launcher.Plugin.Sys.csproj
  • Plugins/Flow.Launcher.Plugin.WebSearch/Flow.Launcher.Plugin.WebSearch.csproj
  • opencode.json
✅ Files skipped from review due to trivial changes (7)
  • Flow.Launcher.Infrastructure/Flow.Launcher.Infrastructure.csproj
  • Flow.Launcher.Avalonia/.agent/README.md
  • Flow.Launcher.Avalonia/Flow.Launcher.Avalonia.csproj
  • .gitignore
  • Flow.Launcher.Avalonia/Themes/Base.axaml
  • Flow.Launcher/Languages/en.xaml
  • Flow.Launcher.Plugin/packages.lock.json
🚧 Files skipped from review as they are similar to previous changes (7)
  • Flow.Launcher.Test/Flow.Launcher.Test.csproj
  • Flow.Launcher.Plugin/Flow.Launcher.Plugin.csproj
  • .github/workflows/dotnet.yml
  • Plugins/Flow.Launcher.Plugin.BrowserBookmark/Flow.Launcher.Plugin.BrowserBookmark.csproj
  • Flow.Launcher.Avalonia/ViewModel/SettingPages/HotkeySettingsViewModel.cs
  • Flow.Launcher.Avalonia/ViewModel/ResultViewModel.cs
  • Flow.Launcher.Avalonia/AvaloniaPublicAPI.cs

Comment thread Flow.Launcher.Avalonia/Helper/AutoStartup.cs
Comment thread Flow.Launcher.Avalonia/Helper/AutoStartup.cs
Comment thread Flow.Launcher.Avalonia/Helper/HotKeyMapper.cs
Comment thread Flow.Launcher.Avalonia/Storage/History.cs
Comment thread Flow.Launcher.Avalonia/ViewModel/MainViewModel.cs
Comment thread Flow.Launcher.Avalonia/Views/Dialogs/ReportWindow.axaml.cs
Comment thread Flow.Launcher.Avalonia/Views/Dialogs/ReportWindow.axaml.cs
Comment thread Flow.Launcher.Avalonia/Views/SettingPages/ThemeSettingsPage.axaml
@atticus-lv

Copy link
Copy Markdown

Amazing work. Always looking for a simple replacement for spotlight after switching from win to mac, since I use flow launcher for such a long time!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants