Compare commits

...

586 commits
v2.1.1 ... dev

Author SHA1 Message Date
Jack Ye
e8353f7648
Merge pull request #4339 from Flow-Launcher/copilot/fix-folder-search-action
Some checks failed
Build / build (push) Has been cancelled
Fix ArgumentException when editing a disabled Explorer action keyword
2026-03-10 23:29:51 +08:00
VictoriousRaptor
8d042d2134
Fix settings window is minimized when re-opened. (#4341)
* Fix settings window is minimized when re-opened

* Don't save minimized state
2026-03-10 22:50:40 +08:00
Jack Ye
a406eb83e1
Fix ReportWindow crash when log directory is empty or missing (#4338)
* Initial plan

* Fix ReportWindow crash when log directory is empty or doesn't exist

Co-authored-by: Jack251970 <53996452+Jack251970@users.noreply.github.com>

* Improve code comments

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2026-03-10 20:29:09 +08:00
copilot-swe-agent[bot]
531b45210a Fix exception when setting Folder Search action keyword in Explorer plugin
- Fix (false, false) case in EditActionKeyword to break gracefully instead
  of throwing ArgumentException. This handles the valid scenario where the
  user changes a disabled keyword's text but keeps it disabled.
- Fix GetActiveActionKeywords to return an empty dictionary instead of null
  when actionKeywordStr is null/empty, preventing NullReferenceException.
- Fix ActionKeyword setter to only auto-enable when the value actually
  changes, preventing unintended side-effects during construction.
- Initialize ActionKeywordSetting backing fields directly in constructor to
  avoid the auto-enable triggering during initialization.
- Change TextBox binding to UpdateSourceTrigger=PropertyChanged so the
  checkbox auto-enables as the user types (before they click the checkbox),
  fixing the checkbox toggle issue caused by LostFocus timing.

Co-authored-by: Jack251970 <53996452+Jack251970@users.noreply.github.com>
2026-03-10 05:40:25 +00:00
copilot-swe-agent[bot]
319db64393 Initial plan 2026-03-10 05:19:00 +00:00
Jack Ye
24f6c90f72
Merge pull request #4333 from Flow-Launcher/dependabot/nuget/Plugins/Flow.Launcher.Plugin.BrowserBookmark/Svg.Skia-3.5.0
Some checks are pending
Build / build (push) Waiting to run
Bump Svg.Skia from 3.4.1 to 3.5.0
2026-03-10 11:52:19 +08:00
dependabot[bot]
3e493263c3
Bump Svg.Skia from 3.4.1 to 3.5.0
---
updated-dependencies:
- dependency-name: Svg.Skia
  dependency-version: 3.5.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-03-09 23:05:08 +00:00
Jack Ye
916b4ff091
Merge pull request #4312 from Flow-Launcher/Theme_Enhancement
Some checks are pending
Build / build (push) Waiting to run
Improve code quality
2026-03-09 15:15:41 +08:00
Jack Ye
dad8f3e695
Merge branch 'dev' into Theme_Enhancement 2026-03-09 12:05:48 +08:00
Jeremy Wu
7a46fac41a
Merge pull request #4329 from Flow-Launcher/merge_back_2_1_1
Merge v2.1.1 back to dev
2026-03-09 15:00:27 +11:00
Jeremy
79f3bfab96 merge back v2.1.1 from master to dev 2026-03-09 14:50:29 +11:00
Jack Ye
0ddcc5c1c6
Merge pull request #4319 from Flow-Launcher/FreezeResources1
Freeze SolidColorBrush to improve performance
2026-03-09 11:11:59 +08:00
Jeremy Wu
5ef6a2b688
New Crowdin updates (#4293) 2026-03-09 04:44:49 +02:00
Jack251970
7766d7053d Rename GetFreezeSolidColorBrush to GetFrozenSolidColorBrush
Renamed the method GetFreezeSolidColorBrush to GetFrozenSolidColorBrush in ThemeHelper.cs for improved naming consistency. Updated all references in Theme.cs accordingly. No changes to functionality.
2026-03-08 23:49:09 +08:00
Jack251970
36e15d3809 Refactor: move CopyStyle to ThemeHelper class
Moved the CopyStyle method from Theme to a new static ThemeHelper class for better code organization and reusability. Updated all references in Theme to use ThemeHelper.CopyStyle. Added ThemeHelper.cs and necessary using directives.
2026-03-08 23:48:10 +08:00
Jack251970
ed14c45fd2 Refactor brush creation with ThemeHelper utility
Introduce ThemeHelper.GetFreezeSolidColorBrush to centralize and reuse SolidColorBrush creation and freezing logic. Refactor Theme.cs to use this helper, improving code clarity and maintainability. Also, use Brushes.Transparent directly where appropriate.
2026-03-08 23:46:08 +08:00
Jeremy Wu
12c4b4d711
Merge pull request #4313 from Flow-Launcher/InitProgressbarAnimation_Null
Some checks are pending
Build / build (push) Waiting to run
Move progress bar animation init to Loaded event to fix possible null exception of ProgressBar
2026-03-08 21:30:02 +11:00
Jack Ye
1bdc1164f8
Merge pull request #4322 from Flow-Launcher/FixSelectionBrush
Use DynamicResource for TextBox SelectionBrush
2026-03-08 17:56:16 +08:00
Jack251970
71944ab6cd Use DynamicResource for TextBox SelectionBrush
Changed SelectionBrush in TextBox style from StaticResource to DynamicResource for SystemAccentColorLight1Brush. This enables automatic updates to the selection color when the resource changes at runtime, improving theme responsiveness.
2026-03-04 18:42:19 +08:00
Jack Ye
984b3dabdc
Fix Explorer plugin Quick Access items missing from general search results (#4294)
Some checks failed
Build / build (push) Has been cancelled
2026-03-04 21:25:25 +11:00
Jack251970
9abf136ea2 Improve SolidColorBrush usage and property checks in Theme
Refactor background brush creation to assign, freeze, and reuse
SolidColorBrush instances for better WPF performance. Replace
string-based property checks with type-safe Control.BackgroundProperty
comparisons for improved robustness.
2026-03-04 12:48:48 +08:00
Jack251970
a2f224225e Move progress bar animation init to Loaded event
InitProgressbarAnimation is now triggered by the progress bar's Loaded event instead of during main window initialization. This ensures the animation starts only after the progress bar is fully loaded, improving reliability and preventing potential UI timing issues.
2026-03-02 18:20:09 +08:00
Jack251970
6566871b15 Refactor theme blur and dark mode handling logic
Refactored Theme.cs to improve theme blur and dark mode handling:
- Replaced static IsBlurTheme() with IsThemeBlurEnabled(dict) for per-theme blur detection.
- Updated all blur checks to use the new method.
- Improved code style, readability, and comments.
- Moved system dark mode registry check to only run when needed.
- Ensured blur and dark mode are applied based on theme and user/system preferences.
2026-03-02 18:03:24 +08:00
Jack Ye
dda900041a
Merge pull request #4299 from Flow-Launcher/IsMinimumAppVersionSatisfied
Some checks failed
Build / build (push) Has been cancelled
Add MinimumAppVersion support for plugin.json
2026-03-01 11:15:01 +08:00
Jack251970
cce80ac5aa Ensure temporary folder deletion 2026-02-27 19:14:03 +08:00
Jack251970
036a3761ea Remove log for plugin version mismatch in PluginManager
Logging when a plugin's minimum Flow Launcher version is not met
has been removed. The method now returns false without logging
any informational message.
2026-02-27 19:05:25 +08:00
Jack251970
48878d2d8c Make log message context-neutral 2026-02-27 19:04:30 +08:00
Jack Ye
dca90916fe
Fix translations
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2026-02-27 19:02:50 +08:00
Jack251970
ba1908d605 Update plugin min version warning message formatting
Improved the message shown when a plugin requires a newer Flow Launcher version by adding line breaks for clarity and updating the title wording. Adjusted code to pass Environment.NewLine and modified resource strings in en.xaml to support the new format.
2026-02-27 18:54:13 +08:00
Jack251970
590bf20204 Add null check for plugin metadata deserialization
Throw a JsonException if deserializing plugin metadata from JSON returns null. This prevents null metadata from being used and improves error handling for invalid or corrupted plugin.json files.
2026-02-27 18:53:30 +08:00
Jack251970
b02a5a265d Refactor plugin min version check and improve logging
Refactored the plugin minimum app version check to use Version.TryParse instead of try-catch with Version.Parse, preventing exceptions on invalid input. Improved error handling by logging parse failures as errors and version mismatches as info, making the logic clearer and more robust.
2026-02-27 18:48:59 +08:00
Jack251970
b1b18ee215 Improve error handling for invalid plugin.json files
Previously, installing a plugin with an invalid or corrupted plugin.json would cause an unhandled exception. Now, deserialization errors are caught, a user-friendly error message is shown, and the exception is logged. Added a new localized error message for this scenario in en.xaml.
2026-02-27 18:42:07 +08:00
Jack Ye
8e4f7258ff
Improve translations
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2026-02-27 18:36:54 +08:00
Jack251970
2e0db3b90f Add MinimumAppVersion support for plugins
Introduced MinimumAppVersion property to PluginMetadata, enabling plugins to specify required Flow Launcher version. Plugin installation now checks this requirement and prompts users if unsatisfied. Minimum app version logic moved to PluginManager and applied to manifest updates. Added localized strings for user prompts. Refactored SameOrLesserPluginVersionExists to accept PluginMetadata.
2026-02-27 18:30:29 +08:00
Jack Ye
54dc790cb6
Merge pull request #4297 from Flow-Launcher/dependabot/github_actions/actions/upload-artifact-7
Some checks failed
Build / build (push) Has been cancelled
Bump actions/upload-artifact from 6 to 7
2026-02-27 12:08:19 +08:00
dependabot[bot]
ed6fe34192
Bump actions/upload-artifact from 6 to 7
Bumps [actions/upload-artifact](https://github.com/actions/upload-artifact) from 6 to 7.
- [Release notes](https://github.com/actions/upload-artifact/releases)
- [Commits](https://github.com/actions/upload-artifact/compare/v6...v7)

---
updated-dependencies:
- dependency-name: actions/upload-artifact
  dependency-version: '7'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-02-26 22:42:54 +00:00
Jeremy Wu
10fcbb9990
Merge pull request #4292 from Flow-Launcher/merge_2_1_0
Some checks failed
Build / build (push) Has been cancelled
Merge v2.1.0 back to dev
2026-02-25 22:54:55 +11:00
Jeremy Wu
980c1a1060
Merge branch 'dev' into merge_2_1_0 2026-02-25 22:45:03 +11:00
Jack Ye
3b3a59fd62
Fix process priority for logon startup task set to BelowNormal by default (#4283)
Some checks are pending
Build / build (push) Waiting to run
2026-02-24 21:17:22 +11:00
Jack Ye
73f657f84e
Merge pull request #4279 from Flow-Launcher/websearch_ui
Some checks are pending
Build / build (push) Waiting to run
Enable TwoWay binding for MaxSuggestions NumberBox
2026-02-24 14:25:10 +08:00
Jack Ye
c9baab7ac9
Merge branch 'dev' into websearch_ui 2026-02-24 00:08:25 +08:00
Jack251970
72269db8e6 Enable TwoWay binding for MaxSuggestions NumberBox
Changed NumberBox binding for Settings.MaxSuggestions from OneWay to TwoWay, allowing user input in the UI to update the underlying setting. This ensures changes made by users are saved back to the settings model.
2026-02-24 00:07:36 +08:00
Jack Ye
ffa974b4e5
Merge pull request #4277 from Flow-Launcher/websearch_ui
Some checks are pending
Build / build (push) Waiting to run
Downgrade iNKORE.UI.WPF.Modern to 0.10.1 for WebSearch Plugin
2026-02-23 17:09:43 +08:00
Jack Ye
727aac4b82
Merge pull request #4278 from Flow-Launcher/SkiaSharp_runtimes
Some checks are pending
Build / build (push) Waiting to run
Remove Skia sharp unnecessary runtimes from packages
2026-02-23 17:01:00 +08:00
Jack251970
9e66f71774 Revert version bump of SkiaSharp package 2026-02-23 16:36:08 +08:00
Jack Ye
d511872c00
Ensure runtimes folder
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2026-02-22 21:29:01 +08:00
Jack251970
c46a52d1ca Remove SkiaSharp .pdb files after build and publish
Added MSBuild targets to delete unnecessary SkiaSharp .pdb files from output and publish directories after build and publish steps, reducing artifact size.
2026-02-22 21:22:17 +08:00
Jack251970
c04da3ab83 Add RISC-V 64-bit runtime support to project config
Included linux-musl-riscv64 and linux-riscv64 in both OutputPath and PublishDir of Flow.Launcher.Plugin.BrowserBookmark.csproj to ensure runtime files for RISC-V 64-bit architectures are available during build and publish.
2026-02-22 21:13:38 +08:00
Jack251970
cb60492657 Downgrade iNKORE.UI.WPF.Modern to 0.10.1
The package reference for iNKORE.UI.WPF.Modern in Flow.Launcher.Plugin.WebSearch.csproj was changed from version 0.10.2.1 to 0.10.1.
2026-02-22 12:38:17 +08:00
Jack Ye
118d6e2a73
Fix incomplete plugin directory deletion on uninstall (#4250)
Some checks failed
Build / build (push) Has been cancelled
2026-02-21 22:34:53 +11:00
Jeremy Wu
918eb0f4a9
New Crowdin updates (#4181) 2026-02-21 12:51:21 +02:00
DB P
11e0f8c3a4
Merge pull request #4273 from onesounds/20250220_SkipConfirm
Some checks are pending
Build / build (push) Waiting to run
Add option to skip confirmation for power actions (Sys Plugin)
2026-02-21 16:01:06 +09:00
Jack251970
a99b8399fe Improve code quality 2026-02-21 14:51:20 +08:00
DB P
7e9a626891 style: fix indentation and tab spacing 2026-02-20 17:40:27 +09:00
DB P
cecd90e675 Refactor: Improve power action logic and property setter
- Add braces for better readability in shutdown/reboot logic (Main.cs).
- Prevent redundant OnPropertyChanged calls in _skipPowerActionConfirmation setter (Settings.cs).
2026-02-20 17:34:37 +09:00
DB P
2d7d025682 Add Skip logic in command 2026-02-20 17:18:21 +09:00
DB P
12fc597b56 Add Checkbox for Skip Confirm 2026-02-20 17:06:31 +09:00
Jack Ye
886cd75ad2
Merge pull request #4272 from umutKaracelebi/fix/readme-drag-drop-typo
Some checks are pending
Build / build (push) Waiting to run
Fix/readme drag drop typo
2026-02-20 12:32:40 +08:00
Jack251970
2b50c4faae README Polish: fixed Flow 2026-02-20 12:22:44 +08:00
umutKaracelebi
9c3dfcd09f README Polish: fixed grammar, consistency, and phrasing 2026-02-19 21:50:29 +03:00
umutKaracelebi
cb52fa6ab7 Fix typo: 'can be change' -> 'can be changed' in Drag & Drop section 2026-02-19 21:29:39 +03:00
Jack Ye
faeba8119a
Merge pull request #4263 from Flow-Launcher/dependabot/nuget/Plugins/Flow.Launcher.Plugin.BrowserBookmark/Microsoft.Data.Sqlite-10.0.3
Some checks failed
Build / build (push) Has been cancelled
Bump Microsoft.Data.Sqlite from 10.0.2 to 10.0.3
2026-02-11 10:07:49 +08:00
Jack Ye
89b338fb86
Merge pull request #4264 from Flow-Launcher/dependabot/nuget/Flow.Launcher.Plugin/Microsoft.SourceLink.GitHub-10.0.103
Bump Microsoft.SourceLink.GitHub from 10.0.102 to 10.0.103
2026-02-11 10:07:35 +08:00
dependabot[bot]
60ef8e648c
Bump Microsoft.SourceLink.GitHub from 10.0.102 to 10.0.103
---
updated-dependencies:
- dependency-name: Microsoft.SourceLink.GitHub
  dependency-version: 10.0.103
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-02-10 22:45:26 +00:00
dependabot[bot]
498913e71d
Bump Microsoft.Data.Sqlite from 10.0.2 to 10.0.3
---
updated-dependencies:
- dependency-name: Microsoft.Data.Sqlite
  dependency-version: 10.0.3
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-02-10 22:45:10 +00:00
Jack Ye
6c1f7fade8
Merge pull request #4260 from Flow-Launcher/dependabot/nuget/Plugins/Flow.Launcher.Plugin.BrowserBookmark/SkiaSharp-3.119.2
Some checks are pending
Build / build (push) Waiting to run
Bump SkiaSharp from 3.119.1 to 3.119.2
2026-02-10 11:44:48 +08:00
dependabot[bot]
0f829d0b91
Bump SkiaSharp from 3.119.1 to 3.119.2
---
updated-dependencies:
- dependency-name: SkiaSharp
  dependency-version: 3.119.2
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-02-10 01:07:13 +00:00
Jack Ye
0717933459
Fix progress query management and thread safety (#4135)
Some checks failed
Build / build (push) Has been cancelled
2026-02-08 12:49:12 +11:00
Jack Ye
516059e390
Merge pull request #4252 from Flow-Launcher/dependabot/nuget/Flow.Launcher.Plugin/multi-5d8c206339
Some checks failed
Build / build (push) Has been cancelled
Bump Microsoft.Windows.CsWin32 from 0.3.205 to 0.3.269
2026-02-06 14:06:23 +08:00
Jack251970
d4f472a64e Update AdjustTokenPrivileges PInvoke usage
Refactored the AdjustTokenPrivileges call to use null for the previous state and an out variable for the return length, improving compatibility with the PInvoke signature and aligning with recommended usage.
2026-02-05 20:28:37 +08:00
dependabot[bot]
97d7eab1a7
Bump Microsoft.Windows.CsWin32 from 0.3.205 to 0.3.269
---
updated-dependencies:
- dependency-name: Microsoft.Windows.CsWin32
  dependency-version: 0.3.269
  dependency-type: direct:production
  update-type: version-update:semver-patch
- dependency-name: Microsoft.Windows.CsWin32
  dependency-version: 0.3.269
  dependency-type: direct:production
  update-type: version-update:semver-patch
- dependency-name: Microsoft.Windows.CsWin32
  dependency-version: 0.3.269
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-02-04 22:46:23 +00:00
Jeremy Wu
6c8add051f
Merge pull request #4057 from Flow-Launcher/last_history_show_result_icon
Some checks failed
Build / build (push) Has been cancelled
History results display actual result icon for Last Opened history style
2026-01-26 17:50:55 +11:00
Jeremy
248da93d05 fix preview when toggle history mode via Ctrl + H 2026-01-26 16:57:47 +11:00
Jack Ye
e9dcd8b7ba
Fix code comments
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
2026-01-23 16:15:25 +08:00
Jack251970
935d41dc26 Ensure combability of glyph setter 2026-01-23 16:10:01 +08:00
Jack251970
0f0ee9ffde Revert "Try to fix combability issue"
This reverts commit b703bcdd52.
2026-01-23 16:05:03 +08:00
Jack251970
b703bcdd52 Try to fix combability issue 2026-01-23 15:51:24 +08:00
Jack251970
8e127d0339 Code cleanup 2026-01-21 18:13:27 +08:00
Jack Ye
add111fe3f
Merge pull request #4212 from Flow-Launcher/dependabot/nuget/Flow.Launcher.Plugin/Microsoft.SourceLink.GitHub-10.0.102
Bump Microsoft.SourceLink.GitHub from 8.0.0 to 10.0.102
2026-01-21 18:08:03 +08:00
Jeremy
bf44637400 revert context menu early exit when history result 2026-01-20 23:18:00 +11:00
Jeremy
657e6ae7d3 add null-safe comparison for glyph 2026-01-20 22:55:04 +11:00
Jeremy
4ddb164bbd adjusted context menu call to exit early when history result selected 2026-01-20 22:48:11 +11:00
Jeremy
5c241d7491 fix to respect max history result shown setting 2026-01-20 21:47:38 +11:00
Jeremy
90360022a4 update glyph when history result exists 2026-01-20 21:26:04 +11:00
Jack Ye
ca5f5cf0e3
Merge pull request #4206 from Flow-Launcher/copilot/fix-calculator-thousands-separator
Add setting to disable thousands separator in Calculator plugin
2026-01-17 20:17:41 +08:00
VictoriousRaptor
befcc9b37c
Update Plugins/Flow.Launcher.Plugin.Calculator/Languages/en.xaml 2026-01-17 19:59:47 +08:00
Jack Ye
a46350c76a
Merge pull request #4211 from Flow-Launcher/dependabot/nuget/Plugins/Flow.Launcher.Plugin.BrowserBookmark/Microsoft.Data.Sqlite-10.0.2
Bump Microsoft.Data.Sqlite from 10.0.1 to 10.0.2
2026-01-14 21:53:22 +08:00
Jack Ye
d72a15937d
Merge branch 'dev' into dependabot/nuget/Plugins/Flow.Launcher.Plugin.BrowserBookmark/Microsoft.Data.Sqlite-10.0.2 2026-01-14 21:17:51 +08:00
Jack Ye
56c1b92316
Merge pull request #4210 from Flow-Launcher/dependabot/nuget/Plugins/Flow.Launcher.Plugin.BrowserBookmark/Svg.Skia-3.4.1
Bump Svg.Skia from 3.4.0 to 3.4.1
2026-01-14 21:17:13 +08:00
dependabot[bot]
91cd27298d
Bump Microsoft.SourceLink.GitHub from 8.0.0 to 10.0.102
---
updated-dependencies:
- dependency-name: Microsoft.SourceLink.GitHub
  dependency-version: 10.0.102
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-01-13 22:45:22 +00:00
dependabot[bot]
98bb98c265
Bump Microsoft.Data.Sqlite from 10.0.1 to 10.0.2
---
updated-dependencies:
- dependency-name: Microsoft.Data.Sqlite
  dependency-version: 10.0.2
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-01-13 22:45:07 +00:00
Jeremy
e970bb4d4e fix icon & glyph display based on selected history style results 2026-01-13 23:32:13 +11:00
dependabot[bot]
ed83da5669
Bump Svg.Skia from 3.4.0 to 3.4.1
---
updated-dependencies:
- dependency-name: Svg.Skia
  dependency-version: 3.4.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-01-13 03:05:02 +00:00
Jack Ye
7e7f85352b
Fix potential locale-dependent test failure
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
2026-01-12 14:13:01 +08:00
Jack251970
013622a2a7 Restore to default in calculator tests 2026-01-12 11:37:47 +08:00
Jack251970
fb4da697a2 Improve calculator thousands separator test 2026-01-12 11:37:06 +08:00
Jack Ye
4e56cb4e74
Merge pull request #4203 from Flow-Launcher/shell_path
Fix ShellPath directory for shell path selection
2026-01-11 21:07:39 +08:00
copilot-swe-agent[bot]
649b142b46 Add UseThousandsSeparator setting to Calculator plugin
Co-authored-by: Jack251970 <53996452+Jack251970@users.noreply.github.com>
2026-01-10 06:30:57 +00:00
copilot-swe-agent[bot]
34257cad60 Initial plan 2026-01-10 06:27:26 +00:00
Jack251970
382a77d2c5 Fix ShellPath directory for shell path selection
Updated OpenShellPath to use Settings.ShellPath directory when prompting for a file path, ensuring the dialog opens in the relevant location instead of the editor path directory.
2026-01-07 13:40:13 +08:00
Jack251970
3745c44455 Revert Update the result when executing history item 2026-01-06 20:11:36 +08:00
Jack251970
9d9ab1ffd2 Do not allow context menu for history items 2026-01-06 18:35:53 +08:00
Jack251970
938a87ceca Fix preview panel blank issue 2026-01-06 18:31:15 +08:00
Jack251970
583bf74724 Update code comments 2026-01-06 15:46:08 +08:00
Jack251970
26e4529f27 Update the result when executing history item 2026-01-06 15:45:49 +08:00
Jack251970
e404d02965 Update the result when executing history item 2026-01-06 15:13:37 +08:00
Jack251970
c610100c13 Use QueryManager function 2026-01-06 15:07:00 +08:00
Jack Ye
8d4e03bdb8
Merge pull request #4202 from Flow-Launcher/dependabot/nuget/Plugins/Flow.Launcher.Plugin.BrowserBookmark/Svg.Skia-3.4.0
Bump Svg.Skia from 3.2.1 to 3.4.0
2026-01-06 10:40:22 +08:00
dependabot[bot]
77b631be87
Bump Svg.Skia from 3.2.1 to 3.4.0
---
updated-dependencies:
- dependency-name: Svg.Skia
  dependency-version: 3.4.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-01-05 22:08:44 +00:00
Jack251970
e403c41530 Change copied icon logic as origin 2026-01-05 22:55:09 +08:00
Jack251970
5b2fb1fb38 Revert "Ensure history items have valid icons in QueryHistory"
This reverts commit e6a91a9959.
2026-01-05 22:26:39 +08:00
Jack251970
cf4268d1c3 Fix preview panel blank issue 2026-01-05 21:30:06 +08:00
Jack251970
e6a91a9959 Ensure history items have valid icons in QueryHistory
Added CheckIcoPathValidity to QueryHistory to set default icons for history items missing IcoPath, addressing legacy data issues. Integrated this check into MainViewModel's RefreshLastOpenedHistoryResults to guarantee icon validity before updating absolute paths.
2026-01-05 20:17:12 +08:00
Jack251970
f22b6449d4 Fix issue when querying history items in home page 2026-01-05 19:18:47 +08:00
Jeremy
58d910dc57 fix deep copy Glyph on LastOpenHistoryResult 2026-01-05 19:37:05 +11:00
Jeremy
11645fdc9a ensure history results ordered by ExecutedDateTime 2026-01-05 19:27:11 +11:00
Jack251970
177e60739c Add code comments 2026-01-05 14:34:57 +08:00
Jack251970
5f992352ee Code cleanup 2026-01-05 13:48:58 +08:00
Jack251970
216b6f536f Code cleanup 2026-01-05 13:07:02 +08:00
Jack Ye
1e176151a0
Merge pull request #4201 from Flow-Launcher/revert-4118-UI.WPF.Modern
Revert "Upgrade iNKORE.UI.WPF.Modern and refactor scroll logic"
2026-01-05 07:38:31 +08:00
Jack Ye
604fd2be44
Merge branch 'dev' into revert-4118-UI.WPF.Modern 2026-01-04 23:59:04 +08:00
Jack Ye
27c4d35a9b
Merge pull request #4198 from nilvanlopes/feature/websearch-max-suggestions
Add max suggestions limit for web search plugin
2026-01-04 23:58:43 +08:00
Jack Ye
a9e6a68369
Revert "Upgrade iNKORE.UI.WPF.Modern and refactor scroll logic" 2026-01-04 23:47:42 +08:00
Jack251970
6c1c9fe600 Use wrap panel 2026-01-04 23:45:13 +08:00
Jack251970
af9050c34b Test no PrivateAssets 2026-01-04 23:19:41 +08:00
Jack251970
4c46e16160 Fix possible convert issue 2026-01-04 23:19:12 +08:00
Jack251970
590b4c82d2 Try NumberBox 2026-01-04 23:00:24 +08:00
Jeremy
19fa107fea minor fixes and adjustments for code quality 2026-01-04 22:05:39 +11:00
Jeremy
ea7a2d271d mark PopulateHistoryFromLegacyHistory obsolete 2026-01-04 21:37:39 +11:00
Jeremy
55673cdb4b add method comments 2026-01-04 21:16:13 +11:00
Jeremy
25037e3f5f update IcoPath if existing is different to the selected 2026-01-04 20:51:25 +11:00
Jeremy
94ebbab68a update legacy item to show Query style title 2026-01-04 19:54:16 +11:00
Jeremy
4174b5e1e4 fix title when query history style used 2026-01-04 17:41:52 +11:00
Jeremy
101e5e6ff1 fix Glyph optional null when copying 2026-01-04 16:39:33 +11:00
Nilvan Lopes
669f3ef404
Update Plugins/Flow.Launcher.Plugin.WebSearch/Languages/en.xaml
Co-authored-by: VictoriousRaptor <10308169+VictoriousRaptor@users.noreply.github.com>
2026-01-03 11:14:20 -03:00
Nilvan Lopes
4c7cbadc2f remove the language files other than the en.xaml 2026-01-02 23:07:29 -03:00
Nilvan Lopes
2176553b26 Add max suggestions setting for web search plugins
Introduced a MaxSuggestions property (min 1, max 10) to control the number of autocomplete suggestions shown in web search plugins. Updated the UI to allow user configuration and added localized labels for the new setting in all supported languages. Suggestions in results are now limited according to this setting.
2026-01-02 14:32:44 -03:00
Jeremy
024eeaf6bf changed LastOpenHistoryResult's Copy to DeepCopy to clarify intent 2026-01-02 22:30:09 +11:00
Jack Ye
83883c4b05
Merge pull request #4195 from Flow-Launcher/fix-localized-name
Fix localized name search for Program plugin
2026-01-02 19:20:56 +08:00
VictoriousRaptor
b062fc056f Catch exceptions and release com objects 2026-01-02 12:23:05 +08:00
VictoriousRaptor
3e32fca356 Fix localized name get failure 2026-01-02 01:47:44 +08:00
Jeremy
9c2f2398f1 add method comments for LastOpenedHistoryResult 2026-01-01 23:11:28 +11:00
Jeremy
6d6003fd80 switch to using TrimmedQuery 2026-01-01 22:45:52 +11:00
Jeremy
f9df44a2cd rename to IcoPathAbsolute 2026-01-01 22:32:39 +11:00
Jeremy
7c670de7c2 fix history result highlight and scroll when history mode activated 2026-01-01 18:23:12 +11:00
Jeremy
20854ba5d7 formatting 2026-01-01 18:20:29 +11:00
Jeremy
2e8bb357fc Merge branch 'dev' into last_history_show_result_icon 2026-01-01 17:01:17 +11:00
Jeremy
810725cc6b add explicit JsonInclude for PluginID internal set 2026-01-01 15:43:23 +11:00
Jeremy
8d7fa1d397 revert QueryHistoryItems property 2026-01-01 15:14:05 +11:00
Jeremy
6b6a9a9935 simplify GetHistoryItems 2026-01-01 14:30:28 +11:00
VictoriousRaptor
8e80c3bde6
Add option to show taskbar when Flow Launcher is opend (#4177)
* Add option to show taskbar when Flow Launcher is invoked

Co-authored-by: VictoriousRaptor <10308169+VictoriousRaptor@users.noreply.github.com>

* Fix: Use ABM_ACTIVATE instead of ABM_SETSTATE for temporary taskbar showing

Co-authored-by: VictoriousRaptor <10308169+VictoriousRaptor@users.noreply.github.com>

* Remove unnecessary unsafe keyword from ShowTaskbar method

Co-authored-by: VictoriousRaptor <10308169+VictoriousRaptor@users.noreply.github.com>

* Fix missing closing braces in Win32Helper.cs

Co-authored-by: VictoriousRaptor <10308169+VictoriousRaptor@users.noreply.github.com>

* Change wording from 'invoked' to 'opened' in localization strings

Co-authored-by: VictoriousRaptor <10308169+VictoriousRaptor@users.noreply.github.com>

* Show/hide tasking when showing/hiding Flow

* Remove unused APPBARDATA

* Guard HideTaskbar() with state so show/hide stay balanced

* Improve taskbar visibility management in MainViewModel

Moved taskbar show logic to after keyboard layout switch in Show().Ensures consistent taskbar state when invoking or hiding the app.

* Clean code

* Clean code

* Remove blank line

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: Jack Ye <jack1160210343@gmail.com>
Co-authored-by: Jack251970 <1160210343@qq.com>
2025-12-31 18:05:53 +08:00
Jeremy
de0d022268 rename last opened class; use inheritance; initialise at startup 2025-12-31 12:14:07 +11:00
Jack Ye
8092a440f4
Merge pull request #4182 from Flow-Launcher/custom_query_hotkey
Fix an issue that custom query hotkey cannot work with context menu page
2025-12-27 23:34:04 +08:00
Jeremy
d78d313372 update to use IcoAbsoluteLocalPath 2025-12-26 21:37:30 +11:00
Jack Ye
1a7957bee6
Merge pull request #4183 from Flow-Launcher/dependabot/github_actions/toshimaru/auto-author-assign-3.0.1
Bump toshimaru/auto-author-assign from 3.0.0 to 3.0.1
2025-12-26 13:33:53 +08:00
dependabot[bot]
23caeb477c
Bump toshimaru/auto-author-assign from 3.0.0 to 3.0.1
Bumps [toshimaru/auto-author-assign](https://github.com/toshimaru/auto-author-assign) from 3.0.0 to 3.0.1.
- [Release notes](https://github.com/toshimaru/auto-author-assign/releases)
- [Changelog](https://github.com/toshimaru/auto-author-assign/blob/main/CHANGELOG.md)
- [Commits](https://github.com/toshimaru/auto-author-assign/compare/v3.0.0...v3.0.1)

---
updated-dependencies:
- dependency-name: toshimaru/auto-author-assign
  dependency-version: 3.0.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-12-25 22:03:58 +00:00
Jack251970
2856803371 Ensure hotkey actions return to query results page first
Added a call to App.API.BackToQueryResults() after showing the main window when a hotkey is triggered. This prevents issues that can occur if the current page is a context menu before changing the query.
2025-12-25 21:14:11 +08:00
Jeremy Wu
ffb37d3e12
New Crowdin updates (#4127) 2025-12-25 17:06:56 +08:00
Jack Ye
bb1dfcde9b
Fix hide item option not working in Program plugin (#4141) 2025-12-25 07:01:47 +02:00
Jack Ye
1594683191
Merge pull request #4178 from Flow-Launcher/dependabot/github_actions/toshimaru/auto-author-assign-3.0.0
Bump toshimaru/auto-author-assign from 2.1.2 to 3.0.0
2025-12-24 12:02:34 +08:00
dependabot[bot]
0d4775bb7d
Bump toshimaru/auto-author-assign from 2.1.2 to 3.0.0
Bumps [toshimaru/auto-author-assign](https://github.com/toshimaru/auto-author-assign) from 2.1.2 to 3.0.0.
- [Release notes](https://github.com/toshimaru/auto-author-assign/releases)
- [Changelog](https://github.com/toshimaru/auto-author-assign/blob/main/CHANGELOG.md)
- [Commits](https://github.com/toshimaru/auto-author-assign/compare/v2.1.2...v3.0.0)

---
updated-dependencies:
- dependency-name: toshimaru/auto-author-assign
  dependency-version: 3.0.0
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-12-22 22:04:55 +00:00
Jeremy Wu
a08a45640d
Merge pull request #4170 from Flow-Launcher/VictoriousRaptor-patch-1
Replace old clipboard plugin with a new one in README
2025-12-22 09:44:54 +11:00
VictoriousRaptor
d1518a490f
Replace old clipboard plugin with a new one in README 2025-12-22 00:02:47 +08:00
VictoriousRaptor
f95d41e093
Merge pull request #4167 from Heck-R/dev
Fix: Result.Preview.Description Does not Display in Preview Panel
2025-12-19 20:33:22 +08:00
Jack251970
a07af87cb1 Update name 2025-12-19 15:56:58 +08:00
Jack Ye
e634e2cbff
Merge branch 'dev' into dev 2025-12-19 15:51:06 +08:00
Jack Ye
c8cebc2b18
Merge pull request #4166 from Flow-Launcher/dependabot/nuget/Plugins/Flow.Launcher.Plugin.BrowserBookmark/Microsoft.Data.Sqlite-10.0.1
Bump Microsoft.Data.Sqlite from 10.0.0 to 10.0.1
2025-12-19 14:07:54 +08:00
Heck-R
e01869afda Fix: Result.Preview.Description is not ignored anymore 2025-12-17 23:37:43 +01:00
dependabot[bot]
b4ec480405
Bump Microsoft.Data.Sqlite from 10.0.0 to 10.0.1
---
updated-dependencies:
- dependency-name: Microsoft.Data.Sqlite
  dependency-version: 10.0.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-12-17 22:07:00 +00:00
Jack Ye
12ab11a4e4
Merge pull request #4165 from Flow-Launcher/dependabot/github_actions/toshimaru/auto-author-assign-2.1.2
Bump toshimaru/auto-author-assign from 2.1.1 to 2.1.2
2025-12-17 10:24:42 +08:00
dependabot[bot]
bb3c8fbe0c
Bump toshimaru/auto-author-assign from 2.1.1 to 2.1.2
Bumps [toshimaru/auto-author-assign](https://github.com/toshimaru/auto-author-assign) from 2.1.1 to 2.1.2.
- [Release notes](https://github.com/toshimaru/auto-author-assign/releases)
- [Changelog](https://github.com/toshimaru/auto-author-assign/blob/main/CHANGELOG.md)
- [Commits](https://github.com/toshimaru/auto-author-assign/compare/v2.1.1...v2.1.2)

---
updated-dependencies:
- dependency-name: toshimaru/auto-author-assign
  dependency-version: 2.1.2
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-12-16 22:04:28 +00:00
Jack Ye
20930617bb
Merge pull request #4118 from Flow-Launcher/UI.WPF.Modern
Upgrade iNKORE.UI.WPF.Modern and refactor scroll logic
2025-12-16 22:54:53 +08:00
Jeremy Wu
0f34829dab
Merge pull request #4160 from Flow-Launcher/add_sponsor
Add sponsor to README
2025-12-16 02:25:06 +11:00
Jack Ye
4221797569
Merge pull request #4125 from Flow-Launcher/dialog_jump_ignore_null_handler
Add null checks and improve dialog window handling
2025-12-15 19:51:32 +08:00
Jeremy Wu
437b7da0f7
formatting 2025-12-15 21:24:14 +11:00
Jeremy Wu
31f5698437
update readme 2025-12-15 21:20:35 +11:00
Jeremy Wu
666d525243
Add sponsor to README
Added sponsor to the README.
2025-12-15 20:59:18 +11:00
Diego Henrique
9066913710
[FEATURE] Folder and File Action Keywords (#4093) 2025-12-14 12:18:21 +02:00
Jack Ye
ebc1a85190
Merge pull request #4155 from Flow-Launcher/dependabot/github_actions/actions/upload-artifact-6
Bump actions/upload-artifact from 5 to 6
2025-12-13 15:39:03 +08:00
dependabot[bot]
4c44877af4
Bump actions/upload-artifact from 5 to 6
Bumps [actions/upload-artifact](https://github.com/actions/upload-artifact) from 5 to 6.
- [Release notes](https://github.com/actions/upload-artifact/releases)
- [Commits](https://github.com/actions/upload-artifact/compare/v5...v6)

---
updated-dependencies:
- dependency-name: actions/upload-artifact
  dependency-version: '6'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-12-12 22:04:55 +00:00
VictoriousRaptor
c03c778efb
Merge pull request #4151 from Flow-Launcher/fix3965
Fix incorrect text highlighting when using pinyin queries
2025-12-09 08:35:53 +08:00
VictoriousRaptor
b6339d38fa
Fix compile error introduced by coderabbit 2025-12-08 13:06:14 +08:00
VictoriousRaptor
42e04d459b
Cover all positions in unit test
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
2025-12-08 00:41:08 +08:00
VictoriousRaptor
769179d04b
Fix test case
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-12-07 19:28:17 +08:00
VictoriousRaptor
a7c67bbb35
Fix incorrect index marker
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-12-07 19:18:49 +08:00
VictoriousRaptor
b869eb8d1d Avoid adding unnecessary space and improve unit test 2025-12-07 18:50:54 +08:00
VictoriousRaptor
7d9de4b0d2 Fix index lookup for boundary 2025-12-07 18:16:09 +08:00
Jack Ye
a49eb464c8
Merge pull request #4129 from Flow-Launcher/dependabot/nuget/Plugins/Flow.Launcher.Plugin.Calculator/Mages-3.0.1
Bump Mages from 3.0.0 to 3.0.1
2025-11-26 18:33:53 +08:00
Jack Ye
48f67b1886
Improve and fix query result update logic issue & provide access to exact query typed by user (#3502) 2025-11-26 21:15:12 +11:00
dependabot[bot]
ce4a37b292
Bump Mages from 3.0.0 to 3.0.1
---
updated-dependencies:
- dependency-name: Mages
  dependency-version: 3.0.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-11-25 22:35:13 +00:00
Jack251970
5623bf253b Add null checks and improve dialog window handling
Added early null checks for `hwnd` to prevent invalid processing.
Enhanced thread safety by locking `_dialogWindow` updates.
Documented dialog window state handling with comments for clarity.
Handled scenarios for dialog window movement, resizing, hiding,
destruction, and termination. Improved robustness and maintainability.
2025-11-23 18:05:12 +08:00
Jack Ye
38c0fae064
Merge pull request #4124 from Flow-Launcher/dependabot/github_actions/actions/checkout-6
Bump actions/checkout from 5 to 6
2025-11-21 17:43:17 +08:00
dependabot[bot]
28065f7231
Bump actions/checkout from 5 to 6
Bumps [actions/checkout](https://github.com/actions/checkout) from 5 to 6.
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](https://github.com/actions/checkout/compare/v5...v6)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-version: '6'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-11-20 22:05:52 +00:00
Jeremy Wu
bb841fcc3b
Merge pull request #4122 from Flow-Launcher/merge_2_0_3
Merge v2.0.3 back to dev
2025-11-20 23:33:34 +11:00
Jeremy
1c29fb2db3 merge back v2.0.3 from master to dev 2025-11-20 23:12:58 +11:00
Jeremy Wu
533a58d083
New Crowdin updates (#4051) 2025-11-20 18:26:31 +08:00
Jeremy
7958b17968 wip show result icon 2025-11-20 21:02:19 +11:00
Jack Ye
a773b51ada
Handle recoverable DWM composition exceptions gracefully (#4113) 2025-11-19 22:16:09 +02:00
Jack251970
05f15d9831 Upgrade iNKORE.UI.WPF.Modern and refactor scroll logic
Upgraded `iNKORE.UI.WPF.Modern` to version `0.10.2.1` and
replaced the custom `CustomScrollViewerEx` implementation with
the built-in `ScrollViewerEx` for simplified scrolling behavior.
Updated `Flow.Launcher.Plugin` to version `5.1.0` for compatibility.
Removed unused namespaces and adjusted styles in `Base.xaml`
to align with the new `ScrollViewerEx` usage.
2025-11-18 22:19:02 +08:00
Jeremy Wu
c6c413202c
Merge pull request #4108 from Flow-Launcher/add_sponsor
Add new sponsor to README
2025-11-14 18:11:59 +09:00
Jeremy Wu
f1b80ab90f
Add new sponsor to README 2025-11-14 17:54:45 +09:00
Jack Ye
558240279f
Merge pull request #4103 from Flow-Launcher/dependabot/nuget/Plugins/Flow.Launcher.Plugin.BrowserBookmark/Microsoft.Data.Sqlite-10.0.0
Bump Microsoft.Data.Sqlite from 9.0.10 to 10.0.0
2025-11-13 10:26:05 +08:00
dependabot[bot]
3492aac2c0
Bump Microsoft.Data.Sqlite from 9.0.10 to 10.0.0
---
updated-dependencies:
- dependency-name: Microsoft.Data.Sqlite
  dependency-version: 10.0.0
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-11-11 22:07:56 +00:00
Jack Ye
fc93d0904e
Merge pull request #4072 from Flow-Launcher/program_plugin_index_issue
Fix Possible OperationCancelException for WaitAsync Operations
2025-11-08 11:28:58 +08:00
Jack251970
2adbc334a2 Improve semaphore lock handling and code robustness
Added `lockAcquired` flags in `PluginsManifest.cs` and `Main.cs`
to ensure semaphore locks are only released if successfully
acquired, preventing potential runtime errors. Updated `finally`
blocks to conditionally release locks based on these flags.

Removed redundant cancellation check in `EverythingAPI.cs` to
simplify code, assuming cancellation is handled elsewhere. These
changes enhance reliability and maintainability of the codebase.
2025-11-07 15:30:07 +08:00
Jack251970
05c8dd2fe1 Remove unnecessary debug information 2025-11-06 20:48:41 +08:00
Jack251970
88fd1e56d0 Handle OperationCanceledException gracefully
Added a `catch` block for `OperationCanceledException` in
`PluginsManifest.cs` to ignore canceled operations. Updated
`EverythingAPI.cs` to use cancellation tokens with `_semaphore.WaitAsync`
and handle cancellations by exiting the method cleanly with `yield break`.
2025-11-06 20:47:54 +08:00
Jack251970
49f89e33b5 Make locking operations cancelable with tokens
Updated `_semaphore.WaitAsync` in `EverythingAPI.cs` to accept a `CancellationToken` and handle `OperationCanceledException` gracefully, returning `false` instead of propagating the exception.

Refactored locking mechanisms in `Main.cs` to use `CancellationToken` for `_win32sLock` and `_uwpsLock`. Added `try-catch` blocks to handle `OperationCanceledException` and ensure proper lock release. Methods now return `emptyResults` when operations are canceled.
2025-11-06 20:46:29 +08:00
Jack251970
d0a47c84b9 Clarify CancellationToken handling in comments
Updated comments to explain the rationale for not directly passing
CancellationToken to methods and instead checking
IsCancellationRequested within locks. This prevents unexpected
OperationCanceledException. Changes made in EverythingAPI.cs
(IsEverythingRunningAsync) and Main.cs (Win32 and UWP program
preparation). No functional changes to the code.
2025-11-06 15:39:19 +08:00
Jack251970
bfaff5cca5 Improve semaphore usage and logging clarity
Added comments in `EverythingAPI.cs` and `Main.cs` to explain
why `CancellationToken` is not directly passed to semaphore
locks, preventing unexpected `OperationCanceledException`.

Updated debug log messages in `Main.cs` for better clarity,
including changing "Start handling programs" to "Start querying
programs". Removed redundant log messages to improve logging
consistency.
2025-11-06 15:32:08 +08:00
Jack251970
30d7f67d42 Refactor token cancellation check for readability
Simplified the `if` statement that checks for token cancellation
by condensing it into a single line. This improves code readability
and eliminates unnecessary line breaks.
2025-11-06 15:30:32 +08:00
Jack251970
7e332fa615 Refactor caching and indexing logic
Added `ResetCache` calls after clearing `_win32s` and `_uwps` lists to ensure proper cache reset during indexing. Updated logic to return `resultList` after setting cache size and expiration for improved clarity. Removed `await Task.WhenAll` to adjust asynchronous flow in the indexing process.
2025-11-06 15:29:38 +08:00
Jack251970
3d8fd1d352 Improve cancellation, locking, and logging mechanisms
Enhanced cancellation handling by adding `token.IsCancellationRequested` checks to improve responsiveness. Refactored locking mechanisms for `_win32sLock` and `_uwpsLock` using `try-finally` blocks to ensure proper acquisition and release, improving thread safety and preventing deadlocks.

Reorganized Win32 and UWP program querying logic for better modularity and readability. Replaced shared collection access with local variables to improve clarity and maintain thread safety. Simplified empty result handling by directly returning `emptyResults` when canceled.

Removed redundant debug log statements to reduce verbosity and updated remaining logs for clarity. Suppressed unused result warnings by replacing direct calls to `EverythingApiDllImport.Everything_GetMajorVersion()` with null-coalescing assignments.
2025-11-06 15:28:13 +08:00
Jack251970
db0c86d50c Remove CancellationToken from semaphore WaitAsync calls
Removed the `CancellationToken` parameter from `WaitAsync` calls
on semaphores in `EverythingAPI.cs` and `Main.cs`. This change
eliminates cancellation support for semaphore waits, likely due
to a design decision prioritizing simplicity or avoiding issues
with cancellation handling.

In `EverythingAPI.cs`, `WaitAsync(token)` was replaced with
`WaitAsync()` in two methods. Similarly, in `Main.cs`, the
`WaitAsync` calls for `_win32sLock` and `_uwpsLock` were updated
to remove the `token` parameter.

Note: This change may impact the ability to gracefully handle
cancellation during semaphore waits.
2025-11-04 14:25:55 +08:00
Jack251970
6e17d5d756 Improve logging for Win32 program lock acquisition
Added a debug log statement to indicate when the lock for
querying Win32 programs is being acquired. This enhances
granularity in logging, making it easier to distinguish
between the acquisition of locks for Win32 and UWP programs.
Improves traceability and debugging of the program's
execution flow.
2025-11-04 12:27:59 +08:00
Jack Ye
e2ac32139c
Merge pull request #4084 from 90gq29/patch-1
Update en.xaml - Typo fix
2025-11-02 11:39:45 +08:00
90gq29
348a83a1d9
Update en.xaml
In standard title case (used for buttons and such), articles or short function words like "a" or "for" shouldn't be capitalized. 

Doesn't seem to be capitalized for stylistic reasons either as "Check for Updates" is capitalized in standard title case.
2025-11-01 15:29:06 +01:00
Jack251970
4cf942ac3a Add detailed debug logging for query execution process
Enhanced logging to provide better traceability and insights:
- Added debug logs for query reception, cache misses, and lock acquisition.
- Logged query cancellation and completion with result counts.
- Added logs for caching results, including item counts and query details.
- Improved logging for filtering and program selection processes.
- Ensured no functional changes to existing query and filtering logic.
2025-10-26 21:01:07 +08:00
Jack251970
f632a4b773 Add caching to QueryAsync and integrate cache reset logic
Introduced a MemoryCache to improve QueryAsync performance by
caching query results, reducing redundant computations. Added
a ResetCache method to reinitialize the cache when settings
are updated. Integrated cache reset calls into settings
property setters to ensure consistency.

Refactored query logic to leverage MemoryCache.GetOrCreateAsync
for streamlined caching. Removed redundant code and debug
logging for improved readability and maintainability. Ensured
thread safety with proper locking mechanisms. Simplified and
consolidated caching logic for better maintainability.
2025-10-26 20:59:29 +08:00
Jack251970
e2fa122362 Improve program indexing with logging and thread safety
Added detailed debug logging to `IndexWin32ProgramsAsync` and
`IndexUwpProgramsAsync` to track the indexing process, including
preparation, start, retrieval, caching, and completion.

Replaced direct updates to `_settings.LastIndexTime` with a
thread-safe lock to prevent race conditions.

Enhanced `IndexProgramsAsync` with a debug log to indicate the
start of indexing for better traceability.

Updated program retrieval logic to process Win32 and UWP programs
in parallel with cancellation support and applied the
`HideUninstallersFilter` for cleaner results.
2025-10-26 20:56:08 +08:00
Jack251970
6a65f8090f Enhance thread safety and refactor reindexing logic
Introduced `_lastIndexTimeLock` to ensure thread-safe access
and updates to `_settings.LastIndexTime`, preventing race
conditions. Refactored reindexing logic to use a `lock` block
for evaluating and updating the reindexing condition.

Added `emptyResults` as a static readonly placeholder list.
Improved code clarity and maintainability without altering
existing functionality.
2025-10-26 20:51:08 +08:00
Jack251970
637d926f7a Remove caching logic and initialize emptyResults list
The caching-related code, including `cacheOptions` and `cache`, has been removed from `Main.cs`, indicating that the caching mechanism is no longer in use or has been refactored elsewhere. Additionally, the `emptyResults` list is now explicitly initialized as an empty list (`[]`). No changes were made to the `Context` property or the `commonUninstallerNames` array.
2025-10-26 20:41:06 +08:00
Jack251970
7f5efc5ca1 Refactor caching and improve QueryAsync method
Removed the `ResetCache` method and its associated calls to streamline caching management and improve performance. Refactored the `QueryAsync` method for better thread safety, synchronization, and exception handling. Simplified UWP and Win32 program filtering logic and removed redundant code. Eliminated manual cache disposal and reset logic, favoring a more efficient and automated caching mechanism. These changes enhance maintainability, responsiveness, and overall plugin performance.
2025-10-26 20:40:37 +08:00
Jack Ye
1885a48241
Merge pull request #4070 from Flow-Launcher/dependabot/github_actions/actions/upload-artifact-5
Bump actions/upload-artifact from 4 to 5
2025-10-25 14:33:11 +08:00
dependabot[bot]
f0584ac853
Bump actions/upload-artifact from 4 to 5
Bumps [actions/upload-artifact](https://github.com/actions/upload-artifact) from 4 to 5.
- [Release notes](https://github.com/actions/upload-artifact/releases)
- [Commits](https://github.com/actions/upload-artifact/compare/v4...v5)

---
updated-dependencies:
- dependency-name: actions/upload-artifact
  dependency-version: '5'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-10-24 22:05:42 +00:00
Jeremy
0f269455b1 remove duplicate history item sort call 2025-10-21 22:18:29 +11:00
Jeremy
25aa5bf2af show history result sorted descending by execution time 2025-10-21 21:54:38 +11:00
Jeremy
92551c58a5 show distinct records when history style is last opened 2025-10-21 21:53:32 +11:00
Diego Henrique
1bfd147421
BUG: Explorer plugin navigate path should only show results in current path (#4053) 2025-10-21 12:12:45 +11:00
Jeremy
26ad473592 change getting last history item to get the same result if exists 2025-10-19 21:46:02 +11:00
Jeremy
10d3ba268d update history result icon display logic & remove badge icon logic 2025-10-19 20:22:03 +11:00
Jeremy
7883e7a0a9 add result IcoPath & Glyph + handling show badge switching 2025-10-18 10:35:23 +11:00
Jeremy Wu
da4b961686
Merge pull request #3854 from Flow-Launcher/plugin_initialization
Asynchronous Loading & Initialization Plugin Model to Improve Window Startup Speed
2025-10-16 22:08:42 +11:00
Jack Ye
fb84cb03f3
Improve code comments
Co-authored-by: Jeremy Wu <jeremy24wu@gmail.com>
2025-10-16 18:48:17 +08:00
Jack Ye
c9e3c628e8
Improve code comments
Co-authored-by: Jeremy Wu <jeremy24wu@gmail.com>
2025-10-16 18:48:07 +08:00
Jack251970
fbeaafa8d3 Remove Score = -100 from result objects in PluginManager
Removed the `Score = -100` property from multiple result objects
in `PluginManager.cs` to simplify the code and improve clarity.
Adjusted the formatting and structure to ensure proper syntax
and maintain code consistency. This includes changes to result
objects that handle re-querying and exception handling.
2025-10-16 18:47:15 +08:00
Jack251970
68454a8a6e Change log level for plugin constructor timing message
Updated the log level for the plugin constructor cost message
from `LogInfo` to `LogDebug` to reduce verbosity in production
logs and make this information available primarily during
debugging sessions.
2025-10-16 18:43:19 +08:00
Jeremy Wu
bd880d304e
update wording 2025-10-16 20:46:35 +11:00
Jeremy Wu
386737acac
update method parameter style 2025-10-16 20:20:51 +11:00
Jack Ye
3690042d2c
Fix DialogJump UriFormatException when navigating to root directories (#4052) 2025-10-15 20:12:51 +11:00
Jack251970
c00d804073 Resolve conflicts 2025-10-15 13:07:43 +08:00
Jack Ye
e2abc1b265
Merge branch 'dev' into plugin_initialization 2025-10-15 13:06:14 +08:00
Jack Ye
3d9ef2c63f
Merge pull request #4042 from 01Dri/feature/history_mode
Add "Last opened" history mode & Fix non-result history item save issue
2025-10-15 12:47:45 +08:00
Jack251970
b13c29ab91 Record user selection after successful execution 2025-10-15 12:40:00 +08:00
Jack251970
df4f08b071 Add exception logging to ResultHelper catch block
Updated the `catch` block in the `ResultHelper` class to explicitly catch `System.Exception` and log the error using `App.API.LogException`. The log includes the class name, a failure message for querying results, and the exception details. This improves error visibility and debugging.
2025-10-15 12:35:53 +08:00
Jack Ye
83cab764a1
Fix typos
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-10-15 12:30:59 +08:00
Jack251970
b784a14aee Update tooltip text for historyStyleTooltip
The tooltip text for the key `historyStyleTooltip` was updated to improve capitalization and consistency. "History" and "Home Page" were capitalized to align with the formatting of other keys in the file.
2025-10-15 12:28:54 +08:00
Jack251970
629c2eb4c6 Record user-selected results for ranking
Moved `_userSelectedRecord.Add(result)` outside the `if (queryResultsSelected)` block to ensure all user-selected results are recorded, regardless of their source (query results, context menu, or history). Added a comment to clarify that only query results are added to history.
2025-10-15 12:26:21 +08:00
Jack251970
c73689fbc3 Fix spelling 2025-10-15 12:24:36 +08:00
Jack251970
1298b76b77 Track user-selected results for ranking purposes
Added logic to record user-selected results in `_userSelectedRecord`
before executing both synchronous and asynchronous actions. This
enables tracking of user interactions for result ranking or analytics.
Comments were added to clarify the purpose of the new logic.
2025-10-15 12:23:52 +08:00
Jack251970
4b6ee4ea98 Improve code quality 2025-10-15 12:23:00 +08:00
01Dri
10d353defe Returning actions 2025-10-15 00:34:38 -03:00
01Dri
9ca7c8431b Revert modifications and returning actions 2025-10-15 00:34:16 -03:00
01Dri
a8d3cdf62c SubTitle equals 2025-10-14 23:26:32 -03:00
01Dri
764c674350 code quality 2025-10-14 23:15:14 -03:00
01Dri
f31abe83b0 PopulateHistoryFromLegacyHistory with HistoryStyle 2025-10-14 23:12:25 -03:00
Jack Ye
4fe3b55720
Merge pull request #4049 from Flow-Launcher/dependabot/nuget/Plugins/Flow.Launcher.Plugin.BrowserBookmark/Microsoft.Data.Sqlite-9.0.10
Bump Microsoft.Data.Sqlite from 9.0.9 to 9.0.10
2025-10-15 10:08:39 +08:00
01Dri
8e96d1a461 HistoryStyle enum values 2025-10-14 22:51:28 -03:00
01Dri
9f652c33b4 History items filtered based on HistoryStyle. 2025-10-14 22:51:09 -03:00
01Dri
d5a2695766 Update the history item if it equals the last added item or already exists in the list. 2025-10-14 22:50:29 -03:00
01Dri
ced824d791 is equals 2025-10-14 22:49:03 -03:00
01Dri
0131b92c7a The HistoryStyle property is used to distinguish history items 2025-10-14 22:47:58 -03:00
dependabot[bot]
a3d1c43580
Bump Microsoft.Data.Sqlite from 9.0.9 to 9.0.10
---
updated-dependencies:
- dependency-name: Microsoft.Data.Sqlite
  dependency-version: 9.0.10
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-10-14 22:07:02 +00:00
Jack251970
66fe0b8245 Adjust design-time height in SettingsPaneGeneral.xaml 2025-10-14 23:23:52 +08:00
Jack Ye
adfd5425f0
Merge branch 'dev' into plugin_initialization 2025-10-14 21:53:43 +08:00
Jeremy Wu
8fde82a0eb
Merge pull request #4047 from Flow-Launcher/merge_back_2_0_2
Merge v2.0.2 back to dev
2025-10-15 00:49:27 +11:00
Jack251970
787ccad384 Refactor history handling with async ResultHelper
Replaced `HistoryHelper` with a new `ResultHelper` class to handle plugin result population asynchronously, improving performance and maintainability. Removed `ExecuteAction` and `QueryAction` properties from `LastOpenedHistoryItem` and updated `QueryHistory` and `MainViewModel` to use `LastOpenedHistoryItems` directly.

Refactored history result generation to support `AsyncAction` in `Result` objects, replacing synchronous plugin queries. Simplified legacy history migration and enhanced support for `HistoryStyle`. Improved error handling, code readability, and UI-related logic for history navigation.
2025-10-14 21:29:22 +08:00
Jack251970
693bae7631 Optimize query result selection handling
Refactored `QueryResultsSelected()` usage by introducing a local
variable `queryResultsSelected` to avoid redundant method calls,
improving efficiency and readability. Added a comment to clarify
the purpose of the variable. Updated conditional logic to use
the new variable instead of directly invoking the method.
2025-10-14 20:47:57 +08:00
Jack251970
f6d5a27e0b Refactor and enhance history management system
Refactored the `History` class to separate query and last opened history into distinct models, introducing `LastOpenedHistoryItem` and deprecating `HistoryItem`. Added a `HistoryStyle` enum and property to allow users to toggle between "Query History" and "Last Opened History." Simplified history display logic and updated the UI with a dropdown for history style selection.

Improved history item display with dynamic action population and relative timestamps. Enhanced performance by optimizing history storage with a maximum limit and streamlined logic for adding/retrieving items. Ensured backward compatibility by migrating legacy history data to the new format.

Updated localization strings, removed deprecated properties, and cleaned up redundant code. Fixed bugs related to inconsistent history actions and edge cases with legacy data.
2025-10-14 20:28:39 +08:00
Jack Ye
592440f2b1
Merge pull request #3982 from Flow-Launcher/squirrel_upgrade
Upgrade Nuget Packages
2025-10-14 19:54:21 +08:00
Jack251970
b84ca9b283 Improve code quality 2025-10-14 19:39:33 +08:00
Jeremy
7445d54d22 merge back v2.0.2 from master to dev 2025-10-14 22:35:06 +11:00
Jeremy Wu
02a29c6af4
New Crowdin updates (#4002) 2025-10-14 12:14:37 +03:00
Jack251970
7fa78f0304 Code cleanup 2025-10-13 15:30:38 +08:00
Jack251970
e3527f47ea Add RecordKey for precise history matching and refactor
Added a `RecordKey` property to `HistoryItem` for unique identification of history records, enabling more accurate matching during queries and executions. Updated `HistoryHelper` methods to utilize `RecordKey` for matching, with fallback to `Title` and `SubTitle`. Enhanced `GetExecuteAction` with error handling, nullable reference types, and improved matching logic. Included `RecordKey` in `History` object creation. Enabled nullable reference types in `HistoryHelper.cs` for better code safety. Refactored code for clarity and maintainability.
2025-10-13 15:27:06 +08:00
Jack Ye
e6c4cc25e5
Merge pull request #4037 from AWAS666/httpspref
Prefer https over http setting for url
2025-10-12 13:41:29 +08:00
Jack251970
1e3306ef28 Remove unused file 2025-10-12 13:33:20 +08:00
Jack251970
6f17aa21c2 Resolve conflicts 2025-10-12 13:31:24 +08:00
Jack Ye
b8acead444
Merge branch 'dev' into httpspref 2025-10-12 13:24:11 +08:00
Jack Ye
eb261f503b
Merge pull request #3944 from Flow-Launcher/url_open_enhancement
Enhancement: Support Custom Browser Path & Open in window / tab & In private for URL Plugin
2025-10-12 12:22:36 +08:00
Diego Henrique
cc397d45a9
Merge branch 'dev' into feature/history_mode 2025-10-11 15:43:05 -03:00
Jack Ye
01bbb54054
Merge pull request #4038 from AWAS666/dragdropwebsearch
Enable reordering of websearches with drap and drop
2025-10-11 20:49:17 +08:00
01Dri
2b7c2048ef up 2025-10-11 05:26:28 -03:00
Jack Ye
b297f3d3a3
Fix ArgumentOutOfRangeException in WebSearch Plugin (#4041) 2025-10-11 18:34:05 +11:00
01Dri
a3b7c6808b up 2025-10-11 04:29:33 -03:00
01Dri
a1f82e1652 refactor: using count for better performance 2025-10-11 03:47:04 -03:00
01Dri
690d33ece3 up 2025-10-11 03:43:06 -03:00
01Dri
d7579cce9e fix erros 2025-10-11 03:23:14 -03:00
01Dri
e468c48da4 feat: fix erros 2025-10-11 03:15:10 -03:00
01Dri
e6cae1a79b feat: helper 2025-10-11 03:08:23 -03:00
01Dri
95122e91f5 feat: code quality 2025-10-11 02:56:49 -03:00
01Dri
bf2acfec38 feat: code quality 2025-10-11 02:54:29 -03:00
01Dri
9e1b8c1a72 feat: Populate new history system with legacy query history 2025-10-11 02:43:27 -03:00
AWAS666
d7dd89d719 change from remove/insert to move 2025-10-10 11:40:06 +02:00
AWAS666
20a865f012 missing nullchecks and casts 2025-10-10 10:06:54 +02:00
AWAS666
87676d2994 fix: error when dragging downwards 2025-10-10 10:06:42 +02:00
AWAS666
001dad9a79 revert manual translation 2025-10-10 10:03:16 +02:00
Jack Ye
a412c7978a
Fix format
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-10-10 12:23:41 +08:00
01Dri
8e8e9d35ac code quality 2025-10-10 00:08:27 -03:00
01Dri
545c4208d9 code quality 2025-10-10 00:07:24 -03:00
01Dri
50f5e850dd feat: code quality 2025-10-09 23:47:59 -03:00
AWAS666
b9a43147dc enable reordering with drap and drop on websearches 2025-10-09 12:35:04 +02:00
AWAS666
ae3559ca74 fix: explicit scheme 2025-10-09 10:48:58 +02:00
AWAS666
1a373e1c40 prefer https over http setting 2025-10-09 10:36:42 +02:00
01Dri
d122276e71 feat: clean imports 2025-10-08 22:09:09 -03:00
01Dri
156cb3055c merge 2025-10-08 22:06:39 -03:00
01Dri
6aa35d592e merge dev 2025-10-08 21:38:10 -03:00
01Dri
b290055e83 feat: up 2025-10-08 21:25:13 -03:00
01Dri
c051c5cd50 feat: new history logic in MainViewModel 2025-10-08 21:15:10 -03:00
01Dri
06711d3b8b feat: Saving actions for history 2025-10-08 21:12:36 -03:00
01Dri
4f2db28196 faet: query action save 2025-10-08 21:12:14 -03:00
01Dri
3681340587 feat: toggle history 2025-10-08 21:11:27 -03:00
01Dri
9e182a2e47 feat: base history model in MainView and refactoring code to replace action between query result or last opened 2025-10-07 00:35:34 -03:00
01Dri
e5736567f6 feat: created a base History model 2025-10-07 00:33:16 -03:00
Jack Ye
a2d12eb225
Merge branch 'dev' into plugin_initialization 2025-10-05 19:25:01 +08:00
Jack Ye
5ae159de5b
Move to iNKORE.UI.WPF.Modern UI Framework (#3593) 2025-10-05 13:44:40 +03:00
Jack Ye
8c98aedac2
Merge pull request #4025 from Flow-Launcher/hide_window_before_sleep
Save settings before shutdown/restart to prevent data loss
2025-10-04 19:52:26 +08:00
01Dri
7ba4f8de4a feat: last opened history 2025-10-04 02:19:57 -03:00
Jack251970
6f6292494c Use ContainsKey(id) for O(1) lookup instead of O(n) iteration 2025-10-03 16:13:24 +08:00
Jack251970
793476432b Show setting panel for initializing or initialization failed plugins 2025-10-03 16:06:22 +08:00
Jack251970
9d7ac851bd Show setting panel for initializing or init failed plugins 2025-10-03 16:04:26 +08:00
Jack251970
54e693d0e2 Add functions in Check Initializing & Init Failed region 2025-10-03 16:03:54 +08:00
Jack251970
969b3ccbcd Revert CancelAsync to Cancel 2025-10-03 15:58:48 +08:00
Jack251970
8a2edf274a Add AutoCompleteText property for results 2025-10-03 15:36:32 +08:00
Jack251970
171eb2dd8b Data race on _allLoadedPlugins (List) across threads 2025-10-03 15:28:11 +08:00
Jack251970
76cc22d5af Use TryRemove and discard out var to clean up action keywords 2025-10-03 15:21:11 +08:00
Jack251970
2be10eb4ca Add translation for plugin failed to respond & Improve translations for plugin stil initializing 2025-10-02 22:26:28 +08:00
Jack251970
297cb5c3ef Return results to tell users that this plugin is still initializing 2025-10-02 22:23:07 +08:00
Jack251970
9a20b0e0de Expose initialized plugins via PublicAPI 2025-10-02 21:59:05 +08:00
Jack251970
66fb1d7c60 Register plugin action keywords when plugins are loaded 2025-10-02 21:52:31 +08:00
Jack251970
5ed94c8abc Resolve conflicts 2025-10-02 20:25:45 +08:00
Jack Ye
6213193cda
Merge branch 'dev' into plugin_initialization 2025-10-02 20:22:20 +08:00
Jack Ye
5b0a30774e
Fix code comment typo
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-10-02 19:45:08 +08:00
Jack251970
d08ee30a7a Refactor plugin actions to simplify logic
Removed logoff operation logic and associated return statement.
Eliminated return statement after recycle bin error handling.
Removed async plugin data reload and success message logic.
Simplified theme selector query handling by removing `return false`.
These changes streamline the code and improve maintainability.
2025-10-02 19:43:31 +08:00
Jack251970
167570559f Move settings save to post-confirmation for actions
Previously, `Context.API.SaveAppAllSettings()` was called unconditionally before user confirmation for shutdown, restart, and advanced restart actions. This change ensures settings are only saved if the user confirms the action by clicking "Yes" in the confirmation dialog.

For all three functionalities:
- Moved the settings save call inside the `if (result == MessageBoxResult.Yes)` block.
- Retained the existing logic for executing the respective system commands, with checks for `EnableShutdownPrivilege()` to determine whether to use `PInvoke.ExitWindowsEx` or the `shutdown` command.

This change prevents unnecessary settings saves when the user cancels the action.
2025-10-02 19:42:24 +08:00
Jack251970
e376da4482 Save settings before shutdown/restart to prevent data loss
Added a call to `Context.API.SaveAppAllSettings()` before executing system shutdown, restart, or advanced restart operations. This ensures that any unsaved settings are persisted, reducing the risk of data loss during these actions.
2025-10-02 19:29:46 +08:00
Jack Ye
1b7a475631
Merge pull request #4024 from Flow-Launcher/power_enhancement
Use sleep mode listener to fix modern standby sleep mode issue
2025-10-02 19:19:01 +08:00
01Dri
5fcd01224c feat: text 2025-10-02 00:19:40 -03:00
01Dri
bc1f9d3734 refactor: renaming executed history to last opened history 2025-10-02 00:09:28 -03:00
01Dri
c0369e6e76 feat: radio button with history query option or history executed option 2025-10-02 00:03:48 -03:00
01Dri
3cc4f13f4d feat: New option to show executed results in settings 2025-10-01 23:05:41 -03:00
Jack251970
c27817eaf0 Fix possible null exception 2025-09-30 21:20:00 +08:00
Jack251970
f239866c68 Use sleep mode listener to fix modern standby sleep mode issue 2025-09-30 21:11:03 +08:00
Jack Ye
7f0851bcb1
Merge pull request #4023 from Flow-Launcher/shell_setting_panel_enhancement
Refactor ShellSettings with Binding & Fix IsEnabled logic
2025-09-30 20:50:16 +08:00
Jeremy Wu
652ec40d82
add removal todo comment 2025-09-30 22:28:41 +10:00
Jack251970
d56d85b702 Add lock for sound & Rename variable 2025-09-30 19:41:27 +08:00
Jack251970
9be546d6c7 Fix ShowOnlyMostUsedCMDsNumber default value 2025-09-30 09:50:29 +08:00
Jack Ye
aab213a6b9
Add default value for ShowOnlyMostUsedCMDsNumber
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
2025-09-30 09:38:18 +08:00
Jack Ye
89505fce30
Remove unnecessary DataContext
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-09-30 09:37:48 +08:00
Jack251970
d106c5144b Fix IsEnabled logic 2025-09-29 23:12:02 +08:00
Jack251970
175571a130 Refactor ShellSettings with Binding logic 2025-09-29 23:00:32 +08:00
Jack251970
d363cf8137 Add property change for settings class & Add localize support for enum 2025-09-29 10:42:19 +08:00
Jack251970
ec41ec2377 Improve code quality 2025-09-28 12:04:32 +08:00
Jack251970
64e9150f11 Fix build issue 2025-09-28 12:03:49 +08:00
Jack Ye
08bf147559
Merge branch 'dev' into url_open_enhancement 2025-09-28 12:02:24 +08:00
Jack251970
ca94ef58e8 Fix build issue 2025-09-28 11:46:55 +08:00
Jack Ye
b34851bd12
Merge branch 'dev' into squirrel_upgrade 2025-09-28 11:37:18 +08:00
Jack Ye
5b6ea73513
Code cleanup & Use Flow.Launcher.Localization to improve code quality (#4009)
* Use Flow.Launcher.Localization to improve code quality

* Code cleanup

* Improve code quality

* Improve code quality

* Use internal static Context & Improve code quality

* Use Flow.Launcher.Localization to improve code quality

* Code cleanup

* Use Flow.Launcher.Localization to improve code quality

* Improve code quality

* Improve code quality

* Use Flow.Launcher.Localization to improve code quality

* Fix logic issue

* Fix the variable name typo

* Fix redundant boolean cast and ensure consistent default value handling

* Use Flow.Launcher.Localization to improve code quality

* Revert namespace styles

* Fix indent format

* Revert namespace style

* Fix indent format

* Fix namespace style

* Fix indent format

* Fix indent format
2025-09-27 19:18:33 +03:00
Jack Ye
2d00ab1d3e
Merge pull request #4011 from Flow-Launcher/flow_launcher_localization1
Use Flow.Launcher.Localization to improve code quality
2025-09-28 00:04:14 +08:00
Jack Ye
e068104253
Merge pull request #3995 from Flow-Launcher/dependabot/nuget/Plugins/Flow.Launcher.Plugin.BrowserBookmark/Svg.Skia-3.2.1
Bump Svg.Skia from 3.0.6 to 3.2.1
2025-09-25 13:06:11 +08:00
Jack Ye
5e2536c129
Merge branch 'dev' into dependabot/nuget/Plugins/Flow.Launcher.Plugin.BrowserBookmark/Svg.Skia-3.2.1 2025-09-25 12:41:14 +08:00
Jack Ye
f72e4692e4
Merge pull request #4012 from Flow-Launcher/dependabot/nuget/Plugins/Flow.Launcher.Plugin.BrowserBookmark/SkiaSharp-3.119.1
Bump SkiaSharp from 3.119.0 to 3.119.1
2025-09-25 12:40:28 +08:00
dependabot[bot]
a76e2fea7f
Bump SkiaSharp from 3.119.0 to 3.119.1
---
updated-dependencies:
- dependency-name: SkiaSharp
  dependency-version: 3.119.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-09-23 22:06:58 +00:00
Jack Ye
09425e1c43
Merge pull request #4006 from sstream17/dev
Support .url Internet Shortcut File Icons
2025-09-23 21:48:22 +08:00
Jack251970
ba7de5d33d Add documents 2025-09-23 21:39:42 +08:00
Jack251970
2770dfde56 Merge branch 'dev' of https://github.com/sstream17/Flow.Launcher into dev 2025-09-23 20:50:45 +08:00
Jack251970
9b2d36b78a Revert "Catch exception"
This reverts commit 49d5cd36df.
2025-09-23 20:48:41 +08:00
Spencer Stream
3bd6906c80 Validate iconPath exists 2025-09-23 07:19:39 -05:00
Jack251970
ac62ebadf0 Add space for code quality 2025-09-23 18:07:15 +08:00
Jack251970
54622d6759 Fix Flow.Launcher.Localization contentHash issue 2025-09-23 17:53:04 +08:00
Jack251970
0a7ed3b52f Add AbstractPluginEnvironment.API back 2025-09-23 17:52:49 +08:00
Jack251970
0e366a6269 Use PublicApi.Instance instead of private one 2025-09-23 17:40:54 +08:00
Jack251970
7350c1d4d5 Use Flow.Launcher.Localization to improve code quality 2025-09-23 17:14:30 +08:00
Jack251970
d87650de08 Use Flow.Launcher.Localization to improve code quality 2025-09-23 16:21:09 +08:00
Jack251970
4865224458 Fix format 2025-09-23 14:09:21 +08:00
Jack251970
49d5cd36df Catch exception 2025-09-23 12:24:44 +08:00
Jack Ye
130033cf4b
Apply suggestion from @Copilot
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-09-23 12:22:46 +08:00
Spencer Stream
c293a273ca Fix nitpick on extension string comparison 2025-09-22 21:53:54 -05:00
Spencer Stream
90c73e5e3d Support .url file icons 2025-09-22 19:42:49 -05:00
Spencer Stream
fbc88bb4cd Add ini-parser package to Infrastructure project 2025-09-22 19:42:49 -05:00
Jack Ye
1e8819af0c
Merge pull request #4004 from dcog989/404-local-file-crash
Crash when opening non-existent local file
2025-09-22 21:09:29 +08:00
Jack251970
763fee0c14 Add new helper method & Improve code quality 2025-09-22 20:58:22 +08:00
Jack251970
71b8144c3c Add translations & Improve code quality 2025-09-22 20:55:36 +08:00
dcog989
bfd10f6903 Crash when opening non-existent file 2025-09-22 13:37:22 +01:00
Jack Ye
10c79da35c
Merge branch 'dev' into plugin_initialization 2025-09-21 21:37:18 +08:00
Jack Ye
d7d88a9ebb
Merge branch 'dev' into url_open_enhancement 2025-09-21 21:37:14 +08:00
Jack Ye
a32b9ca8c0
Merge branch 'dev' into squirrel_upgrade 2025-09-21 21:37:09 +08:00
Jeremy Wu
7de420e32b
Merge pull request #4001 from Flow-Launcher/merge_back_v2_0_1
Merge v2.0.1 back into dev
2025-09-21 23:32:09 +10:00
Jeremy
dc1f0f1095 merge back v2.0.1 from master into dev 2025-09-21 23:15:34 +10:00
Jack Ye
18a3ae7bff
Merge branch 'dev' into squirrel_upgrade 2025-09-21 20:28:01 +08:00
Jack Ye
35867a0a00
Merge pull request #3999 from Flow-Launcher/portable_mode_fix
Fix PortableMode Check Issue
2025-09-21 20:23:39 +08:00
Jack251970
6fca1c919e Fix issue in PortableDataLocationInUse 2025-09-21 20:07:18 +08:00
Jeremy Wu
d7e1ad73cc
New Crowdin updates (#3948) 2025-09-21 14:36:35 +03:00
Jack251970
7e56c8a011 Revert changes 2025-09-21 16:48:00 +08:00
Jack251970
d6bc053950 Revert changes 2025-09-21 16:46:43 +08:00
Jack251970
813be4af2b Merge branch 'squirrel_upgrade' of https://github.com/Flow-Launcher/Flow.Launcher into squirrel_upgrade 2025-09-21 16:45:37 +08:00
Jack251970
df1a272090 Fix argument null exception 2025-09-21 16:45:25 +08:00
Jack Ye
f1ae421853
Update code comments
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-09-21 16:25:24 +08:00
Jack251970
99b7bdab27 Fix build issue 2025-09-21 16:21:38 +08:00
Jack251970
fbb9e09237 Improve code quality 2025-09-21 16:19:13 +08:00
Jack251970
21a6fdd100 Fix issue in PortableDataLocationInUse 2025-09-21 16:17:41 +08:00
Jack251970
2f52c1aa1b Improve code quality 2025-09-21 16:17:31 +08:00
Jack251970
56d6234f1c Initialize logger after data path initialization during portable clean up 2025-09-21 15:17:18 +08:00
Jack251970
81dcadb959 Use getter to fix data location issue 2025-09-21 14:57:50 +08:00
Jack251970
89d726de2a Use getter to fix data location issue 2025-09-21 14:03:43 +08:00
Jack Ye
9211fe476d
Merge branch 'dev' into squirrel_upgrade 2025-09-21 13:42:37 +08:00
Jack Ye
3116f3d363
Merge branch 'dev' into plugin_initialization 2025-09-21 13:22:31 +08:00
dependabot[bot]
846cc65d8e
Bump Svg.Skia from 3.0.6 to 3.2.1
---
updated-dependencies:
- dependency-name: Svg.Skia
  dependency-version: 3.2.1
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-09-21 04:49:51 +00:00
Jack Ye
7a7760c3dd
Merge pull request #3997 from Flow-Launcher/flow_launcher_localization
Use Flow.Launcher.Localization to improve code quality
2025-09-21 12:47:34 +08:00
Jack251970
78e5bf2a60 Use Flow.Launcher.Localization to improve code quality 2025-09-21 11:50:51 +08:00
Jack Ye
a2c11af82b
Merge pull request #3980 from Flow-Launcher/try_create_setting_panel
Catch exception when creating setting panel
2025-09-20 07:53:22 +08:00
Jack Ye
89fca85ca8
Merge pull request #3993 from Flow-Launcher/improve_log
Use Debug instead of Info
2025-09-19 13:27:40 +08:00
Jack Ye
536f1a392e
Merge pull request #3986 from Flow-Launcher/wallpaper_lock
Fix Wallpaper File Lock
2025-09-19 13:27:18 +08:00
Jack Ye
5d843ecae8
Merge pull request #3990 from Flow-Launcher/internalization_memory_leak
Remove old dictionaries references to fix possible memory leak
2025-09-19 12:41:43 +08:00
Jack251970
bbc12ec041 Revert "Disable cache feature"
This reverts commit 9a597f2b4d.
2025-09-18 21:45:24 +08:00
Jack251970
72dae631fe Use TextBox.ForegroundProperty 2025-09-18 21:19:49 +08:00
Jack251970
245c492906 Improve code quality 2025-09-18 21:13:12 +08:00
Jeremy Wu
3a8c64b02d
update wording 2025-09-18 23:08:02 +10:00
Jack251970
7a5e55e5f0 Use Debug instead of Info 2025-09-18 21:06:18 +08:00
Jack Ye
16895716e9
Merge pull request #3978 from Flow-Launcher/program_locks
Fix program lock waiting issue
2025-09-18 20:38:15 +08:00
Jack Ye
9030bffdbd
Merge pull request #3992 from Flow-Launcher/clear_cache_twice
Fix DirectoryNotFoundException when deleting cache twice
2025-09-18 19:59:34 +08:00
Jeremy Wu
4bea4101a1
add comment for cache folder size refresh event 2025-09-18 21:40:37 +10:00
Jack251970
ec182ade39 Fix property changed event 2025-09-18 19:18:11 +08:00
Jack251970
35a5e27e2d Fix DirectoryNotFoundException when deleting cache twice 2025-09-18 19:15:22 +08:00
Jack251970
9a597f2b4d Disable cache feature 2025-09-18 18:32:13 +08:00
Jack251970
fc2e3fec63 Improve ImageLoader performance 2025-09-18 18:29:45 +08:00
Jack251970
0f6245a072 Handle exceptions inside ChangeLanguageAsync to avoid unobserved task crashes 2025-09-18 18:18:02 +08:00
Jack251970
86581e6a00 Add disposable for internalization 2025-09-18 18:17:27 +08:00
Jack251970
330e6c09e7 Add language change lock 2025-09-18 18:07:18 +08:00
Jack251970
6c695f09e7 Use clear function 2025-09-18 17:55:06 +08:00
Jack251970
b05c2c1e1a Remove old dictionaries references to fix possible memory leak 2025-09-18 16:25:21 +08:00
Jack Ye
820304ce19
Merge pull request #3988 from Flow-Launcher/default_browser_explorer_translation
Add Default Browser & File Explorer & New Profile Translation & Ignore index change for -1
2025-09-18 12:58:04 +08:00
Jack251970
1017501153 Fix namespace issue 2025-09-18 12:36:40 +08:00
Jack251970
256ae5c4b0 Fill missing translation 2025-09-18 12:15:33 +08:00
Jack251970
a03f62832a Ignore index change for -1 2025-09-18 12:08:49 +08:00
Jack251970
dd07baff59 Add SelectFile helper method & Improve code quality 2025-09-18 11:58:38 +08:00
Jack251970
647c55eaf7 Add property changed check 2025-09-18 11:47:18 +08:00
Jack251970
1fea8edb74 Add translation for default items & new profile item for explorer & browser window 2025-09-18 11:46:09 +08:00
Jack Ye
2dd416028d
Merge pull request #3950 from Flow-Launcher/FileExplorerHelper_enhancement
Use DialogJump to get explorer path
2025-09-18 09:17:47 +08:00
Jack Ye
3f0f118c8b
Merge pull request #3985 from Flow-Launcher/everything_sort_option
Fix AllEverythingSortOptions issue
2025-09-18 09:07:19 +08:00
Jack Ye
e50a2772f8
Update code comments
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-09-17 19:33:46 +08:00
Jack251970
354b04bea4 Add code comments 2025-09-17 19:29:36 +08:00
Jack251970
60ec9b5c49 Use OnLoaded to ensure the wallpaper file is not locked 2025-09-17 19:24:32 +08:00
Jack251970
83f02f5c91 Use log error & Improve returned color 2025-09-17 19:16:58 +08:00
Jack251970
5c16b86edf Fix file lock during file stream 2025-09-17 19:16:09 +08:00
Jack251970
80c283a370 Improve code quality 2025-09-17 19:15:46 +08:00
Jack251970
23d0b73e20 Fix AllEverythingSortOptions issue 2025-09-17 17:30:03 +08:00
Jack Ye
8bac530504
Merge pull request #3971 from dcog989/calculator-min-fix
Backout 'smart' digit separation & Fix Mages functions for Calculator plugin
2025-09-16 21:13:40 +08:00
Jack251970
8321e400c1 Fix test setting & Add instances to private fields 2025-09-16 21:04:56 +08:00
Jack251970
552b6547db Fix unit test result issue 2025-09-16 16:40:36 +08:00
Jack251970
e10b9254ed Add workaround for log & ln function 2025-09-16 16:31:06 +08:00
Jack251970
6841ad5410 Add calculator unit testing 2025-09-16 16:08:17 +08:00
Jack251970
f7b3a7c812 Fix Squirrel.exe path 2025-09-16 12:12:35 +08:00
Jack251970
3596f59430 Upgrade squirrel package version 2025-09-16 12:03:15 +08:00
Jack Ye
43e3376d2e
Merge pull request #3979 from Flow-Launcher/json_plugin_setting
Improve JsonRPC Plugin Setting Panel
2025-09-16 08:04:57 +08:00
Jack251970
18c8a04cbc Log exception 2025-09-15 21:46:03 +08:00
Jack251970
0355993b00 Use translation 2025-09-15 21:38:53 +08:00
Jack251970
e204daa844 Catch exception when creating setting panel 2025-09-15 21:33:21 +08:00
Jack251970
55f9857dec Remove SystemParameters.VerticalScrollBarWidth 2025-09-15 18:59:01 +08:00
Jack251970
e571204a84 No need to initialize max width 2025-09-15 18:48:09 +08:00
Jack251970
988db485a2 Merge branch 'json_plugin_setting' of https://github.com/Flow-Launcher/Flow.Launcher into json_plugin_setting 2025-09-15 18:46:53 +08:00
Jack251970
f3cb85ea59 Remove unnecessary check 2025-09-15 18:46:47 +08:00
Jack Ye
5695200940
Fix typos
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-09-15 18:46:05 +08:00
Jack251970
44ca9c3480 Use wrap text warpping & set max width of all children 2025-09-15 18:40:16 +08:00
Jack251970
b5c860db1d Add max width constrain 2025-09-15 18:27:19 +08:00
Jack251970
ef69e329fc Fix release 2025-09-15 15:50:22 +08:00
Jack251970
9321a7df14 Fix program lock issue 2025-09-15 15:40:49 +08:00
Jack251970
684fafdfdd Improve code quality 2025-09-15 15:18:42 +08:00
Jack251970
c2e797615d Improve code quality 2025-09-15 15:18:23 +08:00
Jack251970
f9facda521 Improve code quality 2025-09-15 13:02:42 +08:00
Jack251970
1906d68541 Add ShowErrorMessage setting 2025-09-15 12:57:25 +08:00
Jack251970
cea1402dde Improve code quality 2025-09-15 12:53:17 +08:00
Jack251970
b07420a193 Use EmptyResults to improve code quality 2025-09-15 12:51:31 +08:00
dcog989
9be8b71f09 review feedback, CultureInvariant, mild refactor 2025-09-14 22:28:37 +01:00
dcog989
edc76faeb4 Review feedback, case insensitive, consistent separators 2025-09-14 21:51:47 +01:00
dcog989
e990e0ff5b Handle misplaced separators, Mages edge cases
Allow for e.g. `25,00` when `,` used as digit grouping.
Exclude Mages function from the above relaxed logic.
2025-09-14 19:39:06 +01:00
dcog989
336e51d104 IcoPath to const string 2025-09-14 17:08:37 +01:00
dcog989
c79e4831e1
Merge branch 'Flow-Launcher:dev' into calculator-min-fix 2025-09-14 14:54:28 +01:00
Jack251970
daf35a4972 Do not check bracket complete 2025-09-14 15:54:35 +08:00
Jack251970
495ace1246 Improve plugin description 2025-09-14 12:39:11 +08:00
Jack Ye
51df66e362
Merge pull request #3976 from dcog989/logging-enhanced
Enhanced logging
2025-09-14 12:34:32 +08:00
Jack251970
11f5ea5074 Improve code quality 2025-09-14 12:33:46 +08:00
Jack251970
c2fcf648e0 Improve log file format 2025-09-14 12:25:54 +08:00
Jack251970
2ae57ae34c Format & Improve string resources & Rename enums 2025-09-14 12:20:00 +08:00
Jack Ye
0e0ef0e5a2
Merge pull request #3975 from dcog989/CommunityPluginSource-logging-refined
Catch scary exception, print friendly log
2025-09-14 12:05:19 +08:00
dcog989
d4a757be49 Enhanced logging
User can now choose None, Error, Info, or Debug.
2025-09-13 19:57:54 +01:00
dcog989
08a571f076 Merge branch 'CommunityPluginSource-logging-refined' of https://github.com/dcog989/Flow.Launcher into CommunityPluginSource-logging-refined 2025-09-13 17:06:21 +01:00
dcog989
f3998a190c explicit exception logging 2025-09-13 17:04:32 +01:00
dcog989
6eeef62568
Merge branch 'dev' into CommunityPluginSource-logging-refined 2025-09-13 16:33:49 +01:00
dcog989
e63c4f3b6e Catch scary exception, print friendly log
Rather than showing the user `EXCEPTION OCCURS: System.Threading.Tasks.TaskCanceledException...`, print not scary log msg
2025-09-13 16:30:13 +01:00
dcog989
6462023d58
Merge branch 'dev' into calculator-min-fix 2025-09-13 13:17:40 +01:00
dcog989
110f571b40 Rework solution for nested Mages
Previous solution missed e.g. `pow(min(2,3), 4)`
2025-09-13 13:17:08 +01:00
Jeremy Wu
eaa90b31d8
Merge pull request #3906 from Flow-Launcher/nuget_package_upgrade
Upgrade Nuget packages & Update lock files
2025-09-13 17:36:20 +10:00
Jack251970
29b675b26a Upgrade nuget packages 2025-09-13 14:14:59 +08:00
Jack Ye
889ed58f0c
Merge pull request #3973 from dcog989/bookmark-quick-fix
Bookmark plugin - catch an exception for empty / broken favicons
2025-09-13 14:13:06 +08:00
Jack Ye
7fc30aea93
Merge branch 'dev' into nuget_package_upgrade 2025-09-13 14:06:16 +08:00
Jack Ye
45275f0a2c
Merge pull request #3964 from Flow-Launcher/dependabot/nuget/Plugins/Flow.Launcher.Plugin.BrowserBookmark/Microsoft.Data.Sqlite-9.0.9
Bump Microsoft.Data.Sqlite from 9.0.8 to 9.0.9
2025-09-13 14:05:36 +08:00
dcog989
15f31a1698 Bookmark plugin quick fix
Catch an exception for empty / corrupted favicons.
2025-09-12 22:34:03 +01:00
dcog989
bd186e7fe1 correct + extend description 2025-09-12 20:02:34 +01:00
dcog989
190e0e179f Fix 'German' number formatting 2025-09-12 20:01:55 +01:00
dcog989
103d3832a0 dead code, improve messages, group separator fix? 2025-09-12 19:30:07 +01:00
dcog989
e1079396c3 backout 'smart' digit grouping, mages fixes + workaround
Mages did not like the previous change to smart thousands / decimal so backed that out.

Workaround for https://github.com/FlorianRappl/Mages/issues/132
2025-09-12 19:20:19 +01:00
dependabot[bot]
ca164b37db
Bump Microsoft.Data.Sqlite from 9.0.8 to 9.0.9
---
updated-dependencies:
- dependency-name: Microsoft.Data.Sqlite
  dependency-version: 9.0.9
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-09-09 22:07:50 +00:00
Jack251970
f40255bc8a Use DialogJump to get explorer path 2025-09-06 15:52:57 +08:00
Jack251970
8e837b8e56 Avoid clobbering inherited NoWarn; append instead. 2025-09-06 13:37:27 +08:00
Jack Ye
2d8c7a39ca
Merge branch 'dev' into plugin_initialization 2025-09-06 13:31:29 +08:00
Jack Ye
8bc60e55e0
Merge branch 'dev' into nuget_package_upgrade 2025-09-06 13:31:24 +08:00
Jack Ye
45bb6e94fc
Merge branch 'dev' into url_open_enhancement 2025-09-06 13:31:19 +08:00
Jack Ye
cf8096f276
Merge branch 'dev' into plugin_initialization 2025-09-05 20:35:05 +08:00
Jack251970
b501e52f5d Upgrade nuget packages 2025-09-05 19:49:21 +08:00
Jack251970
3f6bebd540 Keep default value same as origin 2025-09-05 19:04:46 +08:00
Jack251970
96d7d18f6d Change string resource names & Redesign setting panel 2025-09-05 19:02:49 +08:00
Jack251970
4f49077bee Add & Use BoolToVisibilityConverter 2025-09-05 19:02:29 +08:00
Jack251970
33aef7eb54 Add convert back implementation for InverseBoolConverter 2025-09-05 19:02:11 +08:00
Jack251970
cdf3905a51 Use InverseBoolConverter 2025-09-05 18:40:50 +08:00
Jack251970
c17db8c9b4 Use using statements 2025-09-05 18:40:28 +08:00
Jack251970
34a58bc5da Add InverseBoolConverter 2025-09-05 18:39:31 +08:00
Jack251970
7ca37697d4 Use PrivateModeArgument & Implement new logic for browser openning 2025-09-05 18:39:22 +08:00
Jack251970
978b18570a Add PrivateModeArgument & Add IPropertyChanged interface for some properties 2025-09-05 18:39:02 +08:00
Jack251970
1303ae5682 Update string resource 2025-09-05 16:07:26 +08:00
Jack251970
33a9654fe0 Add settings control 2025-09-04 22:06:02 +08:00
Jack251970
1dc1643071 Change language strings 2025-09-04 21:46:55 +08:00
Jack251970
48e845c0b1 Change language strings 2025-09-04 21:45:20 +08:00
Jack251970
5976ddeb72 Add more strings 2025-09-04 17:54:03 +08:00
Jack251970
2d5626b0cd Use more settings 2025-09-04 17:30:20 +08:00
Jack251970
c9ca9ad4ba Add more settings 2025-09-04 17:30:08 +08:00
Jack251970
f848d1b7b2 Improve code quality 2025-09-04 17:26:19 +08:00
Jack251970
56bdfa72d1 Improve code quality 2025-09-04 17:24:59 +08:00
Jack251970
6e873abc7b Upgrade nuget package & Fix lock file issue 2025-08-30 16:34:34 +08:00
Jack Ye
528687cf63
Merge branch 'dev' into nuget_package_upgrade 2025-08-30 16:27:15 +08:00
Jack251970
6b60373886 Upgrade nuget packages 2025-08-25 18:50:02 +08:00
Jack251970
b07763ad05 Suppress FLSG0007 2025-08-19 14:27:45 +08:00
Jack251970
922c3d5611 Upgrade nuget packages & Update lock files 2025-08-17 16:54:41 +08:00
Jack251970
fb8daa4ed9 Potential race condition in action keyword management 2025-08-12 18:12:15 +08:00
Jack Ye
04bd9ddc2c
Verify File.Delete exception handling
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
2025-08-12 18:09:59 +08:00
Jack251970
9221435bad Remove plugin from _allLoadedPlugins when one plugin is uninstalled 2025-08-12 18:07:10 +08:00
Jack251970
31c8e850cd Improve code quality 2025-08-12 18:03:23 +08:00
Jack251970
f08466245a Set GetAllInitializedPlugins to private 2025-08-12 17:53:53 +08:00
Jack251970
93af079316 Improve code quality 2025-08-12 17:49:22 +08:00
Jack Ye
97fb8d680f
Merge branch 'dev' into plugin_initialization 2025-07-24 11:54:19 +01:00
Jack251970
3221f930c4 Add info log message for plugin constructors 2025-07-21 21:17:30 +08:00
Jack251970
e0240784b5 Improve code quality 2025-07-21 21:11:48 +08:00
Jack251970
0f8553b45d Refresh home page after plugins are initialized 2025-07-21 19:39:42 +08:00
Jack251970
269d21a4c0 Change plugin modified logic 2025-07-21 18:11:16 +08:00
Jack251970
566bd04e3f Support two types in one class 2025-07-21 18:06:05 +08:00
Jack251970
bef1feea0a Fix plugin page logic 2025-07-21 18:05:22 +08:00
Jack251970
f808469285 Fix logic & Improve code quality 2025-07-21 17:59:28 +08:00
Jack251970
63f86613c3 Use internal PluginModified method instead of API.PluginModified 2025-07-21 17:55:06 +08:00
Jack251970
067a51775e Fix null exception 2025-07-21 17:54:20 +08:00
Jack251970
d9cc67ce6d Merge branch 'plugin_initialization' of https://github.com/Flow-Launcher/Flow.Launcher into plugin_initialization 2025-07-21 17:49:31 +08:00
Jack251970
59e4fb82b9 Fix logic & Add code comments 2025-07-21 17:49:24 +08:00
Jack Ye
a9a705f118
Fix logic
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-07-21 17:48:17 +08:00
Jack251970
6409c193c4 Add code comments 2025-07-21 17:47:19 +08:00
Jack251970
950a4a00a6 Code quality 2025-07-21 17:45:46 +08:00
Jack251970
67c940f3a8 Do not show setting panel for init failed plugins 2025-07-21 17:45:01 +08:00
Jack251970
324b3eb081 Do not call interface methods for init failed plugins 2025-07-21 17:33:47 +08:00
Jack251970
d4a1953747 Add init failed plugins 2025-07-21 17:28:20 +08:00
Jack251970
b348debc72 Code quality 2025-07-21 17:27:37 +08:00
Jack251970
fc01ddbb1c Save init failed plugins 2025-07-21 17:27:21 +08:00
Jack251970
7f797b1039 Add code comments 2025-07-21 17:22:17 +08:00
Jack251970
3bd76b2dfd Rename variable 2025-07-21 17:17:49 +08:00
Jack251970
8d03fcee2e Remove error codes 2025-07-21 17:17:11 +08:00
Jack251970
9149e3f201 Mark initializing plugins as modified 2025-07-21 17:16:36 +08:00
Jack251970
6d99416641 Search in loaded plugins 2025-07-21 17:14:03 +08:00
Jack251970
6e0f2fc4ce Return loaded plugins 2025-07-21 17:03:21 +08:00
Jack251970
fe3339f645 Get initialized plugins for plugin page 2025-07-21 17:02:19 +08:00
Jack251970
11e05f73d9 Add all loaded plugins 2025-07-21 17:00:19 +08:00
Jack251970
566572b013 Use api function & rename function 2025-07-21 16:57:35 +08:00
Jack251970
8b60d26f5e Fix build issue 2025-07-21 16:56:14 +08:00
Jack251970
50924e4189 Improve code quality 2025-07-21 16:45:34 +08:00
Jack251970
cc68183940 Change variable name 2025-07-21 16:30:39 +08:00
Jack251970
55164ef60f Improve code quality 2025-07-21 16:29:01 +08:00
Jack251970
de568140d2 Improve code quality 2025-07-21 16:27:11 +08:00
Jack251970
445a14278b Add code comments 2025-07-21 16:25:26 +08:00
Jack251970
1d3ab39dca Use () => instead of delegate 2025-07-21 16:24:23 +08:00
Jack251970
35c8e39beb Improve code comments 2025-07-21 16:23:40 +08:00
Jack251970
c3a598464f Fix code comments 2025-07-21 16:20:09 +08:00
Jack251970
0a01d85f40 Improve code quality 2025-07-21 16:16:21 +08:00
Jack251970
52bb909f0b Add plugin to all plugin list later 2025-07-21 16:00:42 +08:00
Jack251970
59a7a2c807 Improve code quality 2025-07-21 15:59:27 +08:00
Jack251970
6beeecb0f7 Use async load & initialization model 2025-07-21 14:26:24 +08:00
Jack251970
c2157e2df1 Add support for concurrent operation of explorers & dialogs adding 2025-07-21 14:03:45 +08:00
Jack251970
d4e672d630 Add support to update translation for one plugin 2025-07-21 13:55:47 +08:00
Jack251970
f5f256809c Add IResultUpdateRegister interface 2025-07-21 13:52:11 +08:00
Jack251970
aee46e8640 Initialize quick jump earlier 2025-07-21 12:10:06 +08:00
Jack251970
9ce911771e Improve code quality 2025-07-21 11:31:54 +08:00
28 changed files with 769 additions and 270 deletions

View file

@ -1,7 +1,7 @@
<Project> <Project>
<PropertyGroup> <PropertyGroup>
<AccelerateBuildsInVisualStudio>true</AccelerateBuildsInVisualStudio> <AccelerateBuildsInVisualStudio>true</AccelerateBuildsInVisualStudio>
<!-- Work around https://github.com/dotnet/runtime/issues/109682 --> <!-- Workaround https://github.com/dotnet/runtime/issues/109682 -->
<CETCompat>false</CETCompat> <CETCompat>false</CETCompat>
</PropertyGroup> </PropertyGroup>
</Project> </Project>

View file

@ -3,7 +3,7 @@ using System.Collections.Generic;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using Flow.Launcher.Plugin; using Flow.Launcher.Plugin;
using Flow.Launcher.Infrastructure; using Flow.Launcher.Core.Plugin;
namespace Flow.Launcher.Core.ExternalPlugins namespace Flow.Launcher.Core.ExternalPlugins
{ {
@ -41,11 +41,10 @@ namespace Flow.Launcher.Core.ExternalPlugins
return false; return false;
var updatedPluginResults = new List<UserPlugin>(); var updatedPluginResults = new List<UserPlugin>();
var appVersion = SemanticVersioning.Version.Parse(Constant.Version);
for (int i = 0; i < results.Count; i++) for (int i = 0; i < results.Count; i++)
{ {
if (IsMinimumAppVersionSatisfied(results[i], appVersion)) if (PluginManager.IsMinimumAppVersionSatisfied(results[i].Name, results[i].MinimumAppVersion))
updatedPluginResults.Add(results[i]); updatedPluginResults.Add(results[i]);
} }
@ -72,28 +71,5 @@ namespace Flow.Launcher.Core.ExternalPlugins
return false; return false;
} }
private static bool IsMinimumAppVersionSatisfied(UserPlugin plugin, SemanticVersioning.Version appVersion)
{
if (string.IsNullOrEmpty(plugin.MinimumAppVersion))
return true;
try
{
if (appVersion >= SemanticVersioning.Version.Parse(plugin.MinimumAppVersion))
return true;
}
catch (Exception e)
{
PublicApi.Instance.LogException(ClassName, $"Failed to parse the minimum app version {plugin.MinimumAppVersion} for plugin {plugin.Name}. "
+ "Plugin excluded from manifest", e);
return false;
}
PublicApi.Instance.LogInfo(ClassName, $"Plugin {plugin.Name} requires minimum Flow Launcher version {plugin.MinimumAppVersion}, "
+ $"but current version is {Constant.Version}. Plugin excluded from manifest.");
return false;
}
} }
} }

View file

@ -6,6 +6,7 @@ using System.Linq;
using System.Text.Json; using System.Text.Json;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using System.Windows;
using Flow.Launcher.Core.ExternalPlugins; using Flow.Launcher.Core.ExternalPlugins;
using Flow.Launcher.Core.Resource; using Flow.Launcher.Core.Resource;
using Flow.Launcher.Infrastructure; using Flow.Launcher.Infrastructure;
@ -813,15 +814,13 @@ namespace Flow.Launcher.Core.Plugin
return string.Empty; return string.Empty;
} }
private static bool SameOrLesserPluginVersionExists(string metadataPath) private static bool SameOrLesserPluginVersionExists(PluginMetadata metadata)
{ {
var newMetadata = JsonSerializer.Deserialize<PluginMetadata>(File.ReadAllText(metadataPath)); if (!Version.TryParse(metadata.Version, out var newVersion))
if (!Version.TryParse(newMetadata.Version, out var newVersion))
return true; // If version is not valid, we assume it is lesser than any existing version return true; // If version is not valid, we assume it is lesser than any existing version
// Get all plugins even if initialization failed so that we can check if the plugin with the same ID exists // Get all plugins even if initialization failed so that we can check if the plugin with the same ID exists
return GetAllInitializedPlugins(includeFailed: true).Any(x => x.Metadata.ID == newMetadata.ID return GetAllInitializedPlugins(includeFailed: true).Any(x => x.Metadata.ID == metadata.ID
&& Version.TryParse(x.Metadata.Version, out var version) && Version.TryParse(x.Metadata.Version, out var version)
&& newVersion <= version); && newVersion <= version);
} }
@ -881,7 +880,9 @@ namespace Flow.Launcher.Core.Plugin
var tempFolderPluginPath = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString()); var tempFolderPluginPath = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString());
System.IO.Compression.ZipFile.ExtractToDirectory(zipFilePath, tempFolderPluginPath); System.IO.Compression.ZipFile.ExtractToDirectory(zipFilePath, tempFolderPluginPath);
if(!plugin.IsFromLocalInstallPath) try
{
if (!plugin.IsFromLocalInstallPath)
File.Delete(zipFilePath); File.Delete(zipFilePath);
var pluginFolderPath = GetContainingFolderPathAfterUnzip(tempFolderPluginPath); var pluginFolderPath = GetContainingFolderPathAfterUnzip(tempFolderPluginPath);
@ -897,13 +898,40 @@ namespace Flow.Launcher.Core.Plugin
return false; return false;
} }
if (SameOrLesserPluginVersionExists(metadataJsonFilePath)) PluginMetadata newMetadata;
try
{
newMetadata = JsonSerializer.Deserialize<PluginMetadata>(File.ReadAllText(metadataJsonFilePath)) ??
throw new JsonException("Deserialized metadata is null");
}
catch (Exception ex)
{
PublicApi.Instance.ShowMsgError(Localize.failedToInstallPluginTitle(plugin.Name),
Localize.pluginJsonInvalidOrCorrupted());
PublicApi.Instance.LogException(ClassName,
$"Failed to deserialize plugin metadata for plugin {plugin.Name} from file {metadataJsonFilePath}", ex);
return false;
}
if (SameOrLesserPluginVersionExists(newMetadata))
{ {
PublicApi.Instance.ShowMsgError(Localize.failedToInstallPluginTitle(plugin.Name), PublicApi.Instance.ShowMsgError(Localize.failedToInstallPluginTitle(plugin.Name),
Localize.pluginExistAlreadyMessage()); Localize.pluginExistAlreadyMessage());
return false; return false;
} }
if (!IsMinimumAppVersionSatisfied(newMetadata.Name, newMetadata.MinimumAppVersion))
{
// Ask users if they want to install the plugin that doesn't satisfy the minimum app version requirement
if (PublicApi.Instance.ShowMsgBox(
Localize.pluginMinimumAppVersionUnsatisfiedMessage(newMetadata.Name, Environment.NewLine),
Localize.pluginMinimumAppVersionUnsatisfiedTitle(newMetadata.Name, newMetadata.MinimumAppVersion),
MessageBoxButton.YesNo) == MessageBoxResult.No)
{
return false;
}
}
var folderName = string.IsNullOrEmpty(plugin.Version) ? $"{plugin.Name}-{Guid.NewGuid()}" : $"{plugin.Name}-{plugin.Version}"; var folderName = string.IsNullOrEmpty(plugin.Version) ? $"{plugin.Name}-{Guid.NewGuid()}" : $"{plugin.Name}-{plugin.Version}";
var defaultPluginIDs = new List<string> var defaultPluginIDs = new List<string>
@ -943,6 +971,15 @@ namespace Flow.Launcher.Core.Plugin
PublicApi.Instance.LogException(ClassName, $"Failed to delete plugin marker file in {newPluginPath}", e); PublicApi.Instance.LogException(ClassName, $"Failed to delete plugin marker file in {newPluginPath}", e);
} }
if (checkModified)
{
ModifiedPlugins.Add(plugin.ID);
}
return true;
}
finally
{
try try
{ {
if (Directory.Exists(tempFolderPluginPath)) if (Directory.Exists(tempFolderPluginPath))
@ -952,13 +989,7 @@ namespace Flow.Launcher.Core.Plugin
{ {
PublicApi.Instance.LogException(ClassName, $"Failed to delete temp folder {tempFolderPluginPath}", e); PublicApi.Instance.LogException(ClassName, $"Failed to delete temp folder {tempFolderPluginPath}", e);
} }
if (checkModified)
{
ModifiedPlugins.Add(plugin.ID);
} }
return true;
} }
internal static async Task<bool> UninstallPluginAsync(PluginMetadata plugin, bool removePluginFromSettings, bool removePluginSettings, bool checkModified) internal static async Task<bool> UninstallPluginAsync(PluginMetadata plugin, bool removePluginFromSettings, bool removePluginSettings, bool checkModified)
@ -1050,6 +1081,27 @@ namespace Flow.Launcher.Core.Plugin
return true; return true;
} }
internal static bool IsMinimumAppVersionSatisfied(string pluginName, string minimumAppVersion)
{
// If the minimum app version is not specified in plugin.json, this plugin is compatible with all app versions
if (string.IsNullOrEmpty(minimumAppVersion))
return true;
var appVersion = Version.Parse(Constant.Version);
if (!Version.TryParse(minimumAppVersion, out var minimumVersion))
{
PublicApi.Instance.LogError(ClassName,
$"Failed to parse the minimum app version {minimumAppVersion} for plugin {pluginName}.");
return false; // If the minimum app version specified in plugin.json is invalid, we assume it is not satisfied
}
if (appVersion >= minimumVersion)
return true;
return false;
}
#endregion #endregion
#endregion #endregion

View file

@ -124,8 +124,8 @@ namespace Flow.Launcher.Core.Resource
try try
{ {
// Load a ResourceDictionary for the specified theme. // Load a ResourceDictionary for the specified theme.
var themeName = _settings.Theme; var theme = _settings.Theme;
var dict = GetThemeResourceDictionary(themeName); var dict = GetThemeResourceDictionary(theme);
// Apply font settings to the theme resource. // Apply font settings to the theme resource.
ApplyFontSettings(dict); ApplyFontSettings(dict);
@ -292,10 +292,10 @@ namespace Flow.Launcher.Core.Resource
dict["ItemHotkeyStyle"] is Style resultHotkeyItemStyle && dict["ItemHotkeyStyle"] is Style resultHotkeyItemStyle &&
dict["ItemHotkeySelectedStyle"] is Style resultHotkeyItemSelectedStyle) dict["ItemHotkeySelectedStyle"] is Style resultHotkeyItemSelectedStyle)
{ {
Setter fontFamily = new Setter(TextBlock.FontFamilyProperty, new FontFamily(_settings.ResultFont)); var fontFamily = new Setter(TextBlock.FontFamilyProperty, new FontFamily(_settings.ResultFont));
Setter fontStyle = new Setter(TextBlock.FontStyleProperty, FontHelper.GetFontStyleFromInvariantStringOrNormal(_settings.ResultFontStyle)); var fontStyle = new Setter(TextBlock.FontStyleProperty, FontHelper.GetFontStyleFromInvariantStringOrNormal(_settings.ResultFontStyle));
Setter fontWeight = new Setter(TextBlock.FontWeightProperty, FontHelper.GetFontWeightFromInvariantStringOrNormal(_settings.ResultFontWeight)); var fontWeight = new Setter(TextBlock.FontWeightProperty, FontHelper.GetFontWeightFromInvariantStringOrNormal(_settings.ResultFontWeight));
Setter fontStretch = new Setter(TextBlock.FontStretchProperty, FontHelper.GetFontStretchFromInvariantStringOrNormal(_settings.ResultFontStretch)); var fontStretch = new Setter(TextBlock.FontStretchProperty, FontHelper.GetFontStretchFromInvariantStringOrNormal(_settings.ResultFontStretch));
Setter[] setters = { fontFamily, fontStyle, fontWeight, fontStretch }; Setter[] setters = { fontFamily, fontStyle, fontWeight, fontStretch };
Array.ForEach( Array.ForEach(
@ -307,10 +307,10 @@ namespace Flow.Launcher.Core.Resource
dict["ItemSubTitleStyle"] is Style resultSubItemStyle && dict["ItemSubTitleStyle"] is Style resultSubItemStyle &&
dict["ItemSubTitleSelectedStyle"] is Style resultSubItemSelectedStyle) dict["ItemSubTitleSelectedStyle"] is Style resultSubItemSelectedStyle)
{ {
Setter fontFamily = new Setter(TextBlock.FontFamilyProperty, new FontFamily(_settings.ResultSubFont)); var fontFamily = new Setter(TextBlock.FontFamilyProperty, new FontFamily(_settings.ResultSubFont));
Setter fontStyle = new Setter(TextBlock.FontStyleProperty, FontHelper.GetFontStyleFromInvariantStringOrNormal(_settings.ResultSubFontStyle)); var fontStyle = new Setter(TextBlock.FontStyleProperty, FontHelper.GetFontStyleFromInvariantStringOrNormal(_settings.ResultSubFontStyle));
Setter fontWeight = new Setter(TextBlock.FontWeightProperty, FontHelper.GetFontWeightFromInvariantStringOrNormal(_settings.ResultSubFontWeight)); var fontWeight = new Setter(TextBlock.FontWeightProperty, FontHelper.GetFontWeightFromInvariantStringOrNormal(_settings.ResultSubFontWeight));
Setter fontStretch = new Setter(TextBlock.FontStretchProperty, FontHelper.GetFontStretchFromInvariantStringOrNormal(_settings.ResultSubFontStretch)); var fontStretch = new Setter(TextBlock.FontStretchProperty, FontHelper.GetFontStretchFromInvariantStringOrNormal(_settings.ResultSubFontStretch));
Setter[] setters = { fontFamily, fontStyle, fontWeight, fontStretch }; Setter[] setters = { fontFamily, fontStyle, fontWeight, fontStretch };
Array.ForEach( Array.ForEach(
@ -395,7 +395,7 @@ namespace Flow.Launcher.Core.Resource
public List<ThemeData> GetAvailableThemes() public List<ThemeData> GetAvailableThemes()
{ {
List<ThemeData> themes = new List<ThemeData>(); var themes = new List<ThemeData>();
foreach (var themeDirectory in _themeDirectories) foreach (var themeDirectory in _themeDirectories)
{ {
var filePaths = Directory var filePaths = Directory
@ -410,8 +410,7 @@ namespace Flow.Launcher.Core.Resource
public bool ChangeTheme(string theme = null) public bool ChangeTheme(string theme = null)
{ {
if (string.IsNullOrEmpty(theme)) if (string.IsNullOrEmpty(theme)) theme = _settings.Theme;
theme = _settings.Theme;
string path = GetThemePath(theme); string path = GetThemePath(theme);
try try
@ -426,13 +425,14 @@ namespace Flow.Launcher.Core.Resource
_settings.Theme = theme; _settings.Theme = theme;
//always allow re-loading default theme, in case of failure of switching to a new theme from default theme // Always allow re-loading default theme, in case of failure of switching to a new theme from default theme
if (_oldTheme != theme || theme == Constant.DefaultTheme) if (_oldTheme != theme || theme == Constant.DefaultTheme)
{ {
_oldTheme = Path.GetFileNameWithoutExtension(_oldResource.Source.AbsolutePath); _oldTheme = Path.GetFileNameWithoutExtension(_oldResource.Source.AbsolutePath);
} }
BlurEnabled = IsBlurTheme(); // Check if blur is enabled
BlurEnabled = Win32Helper.IsBackdropSupported() && IsThemeBlurEnabled(resourceDict);
// Apply blur and drop shadow effect so that we do not need to call it again // Apply blur and drop shadow effect so that we do not need to call it again
_ = RefreshFrameAsync(); _ = RefreshFrameAsync();
@ -667,19 +667,19 @@ namespace Flow.Launcher.Core.Resource
if (mainWindow == null) return; if (mainWindow == null) return;
// Check if the theme supports blur // Check if the theme supports blur
bool hasBlur = dict.Contains("ThemeBlurEnabled") && dict["ThemeBlurEnabled"] is bool b && b; var hasBlur = IsThemeBlurEnabled(dict);
if (BlurEnabled && hasBlur && Win32Helper.IsBackdropSupported()) if (BlurEnabled && hasBlur && Win32Helper.IsBackdropSupported())
{ {
// If the BackdropType is Mica or MicaAlt, set the windowborderstyle's background to transparent // If the BackdropType is Mica or MicaAlt, set the windowborderstyle's background to transparent
if (backdropType == BackdropTypes.Mica || backdropType == BackdropTypes.MicaAlt) if (backdropType is BackdropTypes.Mica or BackdropTypes.MicaAlt)
{ {
windowBorderStyle.Setters.Remove(windowBorderStyle.Setters.OfType<Setter>().FirstOrDefault(x => x.Property.Name == "Background")); windowBorderStyle.Setters.Remove(windowBorderStyle.Setters.OfType<Setter>().FirstOrDefault(x => x.Property == Control.BackgroundProperty));
windowBorderStyle.Setters.Add(new Setter(Border.BackgroundProperty, new SolidColorBrush(Color.FromArgb(1, 0, 0, 0)))); windowBorderStyle.Setters.Add(new Setter(Border.BackgroundProperty, ThemeHelper.GetFrozenSolidColorBrush(Color.FromArgb(1, 0, 0, 0))));
} }
else if (backdropType == BackdropTypes.Acrylic) else if (backdropType == BackdropTypes.Acrylic)
{ {
windowBorderStyle.Setters.Remove(windowBorderStyle.Setters.OfType<Setter>().FirstOrDefault(x => x.Property.Name == "Background")); windowBorderStyle.Setters.Remove(windowBorderStyle.Setters.OfType<Setter>().FirstOrDefault(x => x.Property == Control.BackgroundProperty));
windowBorderStyle.Setters.Add(new Setter(Border.BackgroundProperty, new SolidColorBrush(Colors.Transparent))); windowBorderStyle.Setters.Add(new Setter(Border.BackgroundProperty, Brushes.Transparent));
} }
// For themes with blur enabled, the window border is rendered by the system, so it's treated as a simple rectangle regardless of thickness. // For themes with blur enabled, the window border is rendered by the system, so it's treated as a simple rectangle regardless of thickness.
@ -798,12 +798,12 @@ namespace Flow.Launcher.Core.Resource
Application.Current.Resources["WindowBorderStyle"] is Style originalStyle) Application.Current.Resources["WindowBorderStyle"] is Style originalStyle)
{ {
// Copy the original style, including the base style if it exists // Copy the original style, including the base style if it exists
CopyStyle(originalStyle, previewStyle); ThemeHelper.CopyStyle(originalStyle, previewStyle);
} }
// Apply background color (remove transparency in color) // Apply background color (remove transparency in color)
Color backgroundColor = Color.FromRgb(bgColor.Value.R, bgColor.Value.G, bgColor.Value.B); var backgroundColor = Color.FromRgb(bgColor.Value.R, bgColor.Value.G, bgColor.Value.B);
previewStyle.Setters.Add(new Setter(Border.BackgroundProperty, new SolidColorBrush(backgroundColor))); previewStyle.Setters.Add(new Setter(Border.BackgroundProperty, ThemeHelper.GetFrozenSolidColorBrush(backgroundColor)));
// The blur theme keeps the corner round fixed (applying DWM code to modify it causes rendering issues). // The blur theme keeps the corner round fixed (applying DWM code to modify it causes rendering issues).
// The non-blur theme retains the previously set WindowBorderStyle. // The non-blur theme retains the previously set WindowBorderStyle.
@ -817,21 +817,6 @@ namespace Flow.Launcher.Core.Resource
Application.Current.Resources["PreviewWindowBorderStyle"] = previewStyle; Application.Current.Resources["PreviewWindowBorderStyle"] = previewStyle;
} }
private void CopyStyle(Style originalStyle, Style targetStyle)
{
// If the style is based on another style, copy the base style first
if (originalStyle.BasedOn != null)
{
CopyStyle(originalStyle.BasedOn, targetStyle);
}
// Copy the setters from the original style
foreach (var setter in originalStyle.Setters.OfType<Setter>())
{
targetStyle.Setters.Add(new Setter(setter.Property, setter.Value));
}
}
private void ColorizeWindow(string theme, BackdropTypes backdropType) private void ColorizeWindow(string theme, BackdropTypes backdropType)
{ {
var dict = GetThemeResourceDictionary(theme); var dict = GetThemeResourceDictionary(theme);
@ -841,20 +826,16 @@ namespace Flow.Launcher.Core.Resource
if (mainWindow == null) return; if (mainWindow == null) return;
// Check if the theme supports blur // Check if the theme supports blur
bool hasBlur = dict.Contains("ThemeBlurEnabled") && dict["ThemeBlurEnabled"] is bool b && b; var hasBlur = IsThemeBlurEnabled(dict);
// SystemBG value check (Auto, Light, Dark) // SystemBG value check (Auto, Light, Dark)
string systemBG = dict.Contains("SystemBG") ? dict["SystemBG"] as string : "Auto"; // 기본값 Auto var systemBG = dict.Contains("SystemBG") ? dict["SystemBG"] as string : "Auto"; // 기본값 Auto
// Check the user's ColorScheme setting // Check the user's ColorScheme setting
string colorScheme = _settings.ColorScheme; var colorScheme = _settings.ColorScheme;
// Check system dark mode setting (read AppsUseLightTheme value)
int themeValue = (int)Registry.GetValue(@"HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Themes\Personalize", "AppsUseLightTheme", 1);
bool isSystemDark = themeValue == 0;
// Final decision on whether to use dark mode // Final decision on whether to use dark mode
bool useDarkMode = false; var useDarkMode = false;
// If systemBG is not "Auto", prioritize it over ColorScheme and set the mode based on systemBG value // If systemBG is not "Auto", prioritize it over ColorScheme and set the mode based on systemBG value
if (systemBG == "Dark") if (systemBG == "Dark")
@ -869,12 +850,21 @@ namespace Flow.Launcher.Core.Resource
{ {
// If systemBG is "Auto", decide based on ColorScheme // If systemBG is "Auto", decide based on ColorScheme
if (colorScheme == "Dark") if (colorScheme == "Dark")
{
useDarkMode = true; useDarkMode = true;
}
else if (colorScheme == "Light") else if (colorScheme == "Light")
{
useDarkMode = false; useDarkMode = false;
}
else else
{
// Check system dark mode setting (read AppsUseLightTheme value)
var themeValue = (int)Registry.GetValue(@"HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Themes\Personalize", "AppsUseLightTheme", 1);
var isSystemDark = themeValue == 0;
useDarkMode = isSystemDark; // Auto (based on system setting) useDarkMode = isSystemDark; // Auto (based on system setting)
} }
}
// Apply DWM Dark Mode // Apply DWM Dark Mode
Win32Helper.DWMSetDarkModeForWindow(mainWindow, useDarkMode); Win32Helper.DWMSetDarkModeForWindow(mainWindow, useDarkMode);
@ -915,25 +905,20 @@ namespace Flow.Launcher.Core.Resource
else else
{ {
// Only set the background to transparent if the theme supports blur // Only set the background to transparent if the theme supports blur
if (backdropType == BackdropTypes.Mica || backdropType == BackdropTypes.MicaAlt) if (backdropType is BackdropTypes.Mica or BackdropTypes.MicaAlt)
{ {
mainWindow.Background = new SolidColorBrush(Color.FromArgb(1, 0, 0, 0)); mainWindow.Background = ThemeHelper.GetFrozenSolidColorBrush(Color.FromArgb(1, 0, 0, 0));
} }
else else
{ {
mainWindow.Background = new SolidColorBrush(selectedBG); mainWindow.Background = ThemeHelper.GetFrozenSolidColorBrush(selectedBG);
} }
} }
} }
private static bool IsBlurTheme() private static bool IsThemeBlurEnabled(ResourceDictionary dict)
{ {
if (!Win32Helper.IsBackdropSupported()) // Windows 11 미만이면 무조건 false return dict.Contains("ThemeBlurEnabled") && dict["ThemeBlurEnabled"] is bool enabled && enabled;
return false;
var resource = Application.Current.TryFindResource("ThemeBlurEnabled");
return resource is bool b && b;
} }
#endregion #endregion

View file

@ -0,0 +1,30 @@
using System.Linq;
using System.Windows;
using System.Windows.Media;
namespace Flow.Launcher.Core.Resource;
public static class ThemeHelper
{
public static void CopyStyle(Style originalStyle, Style targetStyle)
{
// If the style is based on another style, copy the base style first
if (originalStyle.BasedOn != null)
{
CopyStyle(originalStyle.BasedOn, targetStyle);
}
// Copy the setters from the original style
foreach (var setter in originalStyle.Setters.OfType<Setter>())
{
targetStyle.Setters.Add(new Setter(setter.Property, setter.Value));
}
}
public static SolidColorBrush GetFrozenSolidColorBrush(Color color)
{
var brush = new SolidColorBrush(color);
brush.Freeze();
return brush;
}
}

View file

@ -7,6 +7,7 @@ using CommunityToolkit.Mvvm.DependencyInjection;
using Flow.Launcher.Infrastructure.Hotkey; using Flow.Launcher.Infrastructure.Hotkey;
using Flow.Launcher.Infrastructure.Logger; using Flow.Launcher.Infrastructure.Logger;
using Flow.Launcher.Infrastructure.Storage; using Flow.Launcher.Infrastructure.Storage;
using Flow.Launcher.Localization.Attributes;
using Flow.Launcher.Plugin; using Flow.Launcher.Plugin;
using Flow.Launcher.Plugin.SharedModels; using Flow.Launcher.Plugin.SharedModels;
@ -514,6 +515,21 @@ namespace Flow.Launcher.Infrastructure.UserSettings
[JsonConverter(typeof(JsonStringEnumConverter))] [JsonConverter(typeof(JsonStringEnumConverter))]
public LastQueryMode LastQueryMode { get; set; } = LastQueryMode.Selected; public LastQueryMode LastQueryMode { get; set; } = LastQueryMode.Selected;
private HistoryStyle _historyStyle = HistoryStyle.Query;
[JsonConverter(typeof(JsonStringEnumConverter))]
public HistoryStyle HistoryStyle
{
get => _historyStyle;
set
{
if (_historyStyle != value)
{
_historyStyle = value;
OnPropertyChanged();
}
}
}
[JsonConverter(typeof(JsonStringEnumConverter))] [JsonConverter(typeof(JsonStringEnumConverter))]
public AnimationSpeeds AnimationSpeed { get; set; } = AnimationSpeeds.Medium; public AnimationSpeeds AnimationSpeed { get; set; } = AnimationSpeeds.Medium;
public int CustomAnimationLength { get; set; } = 360; public int CustomAnimationLength { get; set; } = 360;
@ -696,4 +712,14 @@ namespace Flow.Launcher.Infrastructure.UserSettings
FullPathOpen, FullPathOpen,
Directory Directory
} }
[EnumLocalize]
public enum HistoryStyle
{
[EnumLocalizeKey(nameof(Localize.queryHistory))]
Query,
[EnumLocalizeKey(nameof(Localize.executedHistory))]
LastOpened
}
} }

View file

@ -137,6 +137,11 @@ namespace Flow.Launcher.Plugin
[JsonIgnore] [JsonIgnore]
public int QueryCount { get; set; } public int QueryCount { get; set; }
/// <summary>
/// The minimum Flow Launcher version required for this plugin. Default is "".
/// </summary>
public string MinimumAppVersion { get; set; } = string.Empty;
/// <summary> /// <summary>
/// The path to the plugin settings directory which is not validated. /// The path to the plugin settings directory which is not validated.
/// It is used to store plugin settings files and data files. /// It is used to store plugin settings files and data files.

View file

@ -4,11 +4,13 @@ using System.IO;
using System.Threading.Tasks; using System.Threading.Tasks;
using System.Windows.Controls; using System.Windows.Controls;
using System.Windows.Media; using System.Windows.Media;
using System.Text.Json.Serialization;
namespace Flow.Launcher.Plugin namespace Flow.Launcher.Plugin
{ {
/// <summary> /// <summary>
/// Describes a result of a <see cref="Query"/> executed by a plugin /// Describes a result of a <see cref="Query"/> executed by a plugin.
/// This or its child classes is serializable.
/// </summary> /// </summary>
public class Result public class Result
{ {
@ -21,6 +23,8 @@ namespace Flow.Launcher.Plugin
private string _icoPath; private string _icoPath;
private string _icoPathAbsolute;
private string _copyText = string.Empty; private string _copyText = string.Empty;
private string _badgeIcoPath; private string _badgeIcoPath;
@ -64,15 +68,27 @@ namespace Flow.Launcher.Plugin
public string AutoCompleteText { get; set; } public string AutoCompleteText { get; set; }
/// <summary> /// <summary>
/// The image to be displayed for the result. /// Path or URI to the icon image for this result.
/// Updates <see cref="IcoPathAbsolute"/> appropriately when set.
/// </summary> /// </summary>
/// <value>Can be a local file path or a URL.</value> /// <remarks>
/// <remarks>GlyphInfo is prioritized if not null</remarks> /// Preferred usage: provide a path relative to the plugin directory (for example: "Images\icon.png").
/// Because <see cref="IcoPath"/> is serialized, using relative paths keeps the icon reference portable
/// when Flow is moved.
///
/// Accepted formats:
/// - Relative file paths (resolved against <see cref="PluginDirectory"/> into <see cref="IcoPathAbsolute"/>)
/// - Absolute file paths (left as-is)
/// - HTTP/HTTPS URLs (left as-is)
/// - Data URIs (left as-is)
/// </remarks>
public string IcoPath public string IcoPath
{ {
get => _icoPath; get => _icoPath;
set set
{ {
_icoPath = value;
// As a standard this property will handle prepping and converting to absolute local path for icon image processing // As a standard this property will handle prepping and converting to absolute local path for icon image processing
if (!string.IsNullOrEmpty(value) if (!string.IsNullOrEmpty(value)
&& !string.IsNullOrEmpty(PluginDirectory) && !string.IsNullOrEmpty(PluginDirectory)
@ -81,15 +97,23 @@ namespace Flow.Launcher.Plugin
&& !value.StartsWith("https://", StringComparison.OrdinalIgnoreCase) && !value.StartsWith("https://", StringComparison.OrdinalIgnoreCase)
&& !value.StartsWith("data:image", StringComparison.OrdinalIgnoreCase)) && !value.StartsWith("data:image", StringComparison.OrdinalIgnoreCase))
{ {
_icoPath = Path.Combine(PluginDirectory, value); _icoPathAbsolute = Path.Combine(PluginDirectory, value);
} }
else else
{ {
_icoPath = value; _icoPathAbsolute = value;
} }
} }
} }
/// <summary>
/// Absolute path or URI which is used to load and display the result icon for Flow.
/// This is populated by the <see cref="IcoPath"/> setter.
/// If a relative path was provided to <see cref="IcoPath"/>, this property will contain the resolved
/// absolute local path after combining with <see cref="PluginDirectory"/>.
/// </summary>
public string IcoPathAbsolute => _icoPathAbsolute;
/// <summary> /// <summary>
/// The image to be displayed for the badge of the result. /// The image to be displayed for the badge of the result.
/// </summary> /// </summary>
@ -131,17 +155,34 @@ namespace Flow.Launcher.Plugin
/// <summary> /// <summary>
/// Delegate to load an icon for this result. /// Delegate to load an icon for this result.
/// </summary> /// </summary>
[JsonIgnore]
public IconDelegate Icon = null; public IconDelegate Icon = null;
/// <summary> /// <summary>
/// Delegate to load an icon for the badge of this result. /// Delegate to load an icon for the badge of this result.
/// </summary> /// </summary>
[JsonIgnore]
public IconDelegate BadgeIcon = null; public IconDelegate BadgeIcon = null;
private GlyphInfo _glyph;
/// <summary> /// <summary>
/// Information for Glyph Icon (Prioritized than IcoPath/Icon if user enable Glyph Icons) /// Information for Glyph Icon (Prioritized than IcoPath/Icon if user enable Glyph Icons)
/// </summary> /// </summary>
public GlyphInfo Glyph { get; init; } public GlyphInfo Glyph
{
get => _glyph;
init => _glyph = value;
}
/// <summary>
/// Set the Glyph Icon after initialization
/// </summary>
/// <param name="glyph"></param>
public void SetGlyph(GlyphInfo glyph)
{
_glyph = glyph;
}
/// <summary> /// <summary>
/// An action to take in the form of a function call when the result has been selected. /// An action to take in the form of a function call when the result has been selected.
@ -151,6 +192,7 @@ namespace Flow.Launcher.Plugin
/// Its result determines what happens to Flow Launcher's query form: /// Its result determines what happens to Flow Launcher's query form:
/// when true, the form will be hidden; when false, it will stay in focus. /// when true, the form will be hidden; when false, it will stay in focus.
/// </remarks> /// </remarks>
[JsonIgnore]
public Func<ActionContext, bool> Action { get; set; } public Func<ActionContext, bool> Action { get; set; }
/// <summary> /// <summary>
@ -161,6 +203,7 @@ namespace Flow.Launcher.Plugin
/// Its result determines what happens to Flow Launcher's query form: /// Its result determines what happens to Flow Launcher's query form:
/// when true, the form will be hidden; when false, it will stay in focus. /// when true, the form will be hidden; when false, it will stay in focus.
/// </remarks> /// </remarks>
[JsonIgnore]
public Func<ActionContext, ValueTask<bool>> AsyncAction { get; set; } public Func<ActionContext, ValueTask<bool>> AsyncAction { get; set; }
/// <summary> /// <summary>
@ -203,11 +246,13 @@ namespace Flow.Launcher.Plugin
/// <example> /// <example>
/// As external information for ContextMenu /// As external information for ContextMenu
/// </example> /// </example>
[JsonIgnore]
public object ContextData { get; set; } public object ContextData { get; set; }
/// <summary> /// <summary>
/// Plugin ID that generated this result /// Plugin ID that generated this result
/// </summary> /// </summary>
[JsonInclude]
public string PluginID { get; internal set; } public string PluginID { get; internal set; }
/// <summary> /// <summary>
@ -223,6 +268,7 @@ namespace Flow.Launcher.Plugin
/// <summary> /// <summary>
/// Customized Preview Panel /// Customized Preview Panel
/// </summary> /// </summary>
[JsonIgnore]
public Lazy<UserControl> PreviewPanel { get; set; } public Lazy<UserControl> PreviewPanel { get; set; }
/// <summary> /// <summary>
@ -352,6 +398,7 @@ namespace Flow.Launcher.Plugin
/// <summary> /// <summary>
/// Delegate to get the preview panel's image /// Delegate to get the preview panel's image
/// </summary> /// </summary>
[JsonIgnore]
public IconDelegate PreviewDelegate { get; set; } = null; public IconDelegate PreviewDelegate { get; set; } = null;
/// <summary> /// <summary>

View file

@ -259,6 +259,9 @@ namespace Flow.Launcher
await PluginManager.InitializePluginsAsync(_mainVM); await PluginManager.InitializePluginsAsync(_mainVM);
// Refresh the history results after plugins are initialized so that we can parse the absolute icon paths
_mainVM.RefreshLastOpenedHistoryResults();
// Refresh home page after plugins are initialized because users may open main window during plugin initialization // Refresh home page after plugins are initialized because users may open main window during plugin initialization
// And home page is created without full plugin list // And home page is created without full plugin list
if (_settings.ShowHomePage && _mainVM.QueryResultsSelected() && string.IsNullOrEmpty(_mainVM.QueryText)) if (_settings.ShowHomePage && _mainVM.QueryResultsSelected() && string.IsNullOrEmpty(_mainVM.QueryText))

View file

@ -185,7 +185,7 @@
</Target> </Target>
<Target Name="RemoveDuplicateAnalyzers" BeforeTargets="CoreCompile"> <Target Name="RemoveDuplicateAnalyzers" BeforeTargets="CoreCompile">
<!-- Work around https://github.com/dotnet/wpf/issues/6792 --> <!-- Workaround https://github.com/dotnet/wpf/issues/6792 -->
<ItemGroup> <ItemGroup>
<FilteredAnalyzer Include="@(Analyzer-&gt;Distinct())" /> <FilteredAnalyzer Include="@(Analyzer-&gt;Distinct())" />
<Analyzer Remove="@(Analyzer)" /> <Analyzer Remove="@(Analyzer)" />

View file

@ -0,0 +1,45 @@
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Flow.Launcher.Core.Plugin;
using Flow.Launcher.Plugin;
using Flow.Launcher.Storage;
namespace Flow.Launcher.Helper;
#nullable enable
public static class ResultHelper
{
public static async Task<Result?> PopulateResultsAsync(LastOpenedHistoryResult item)
{
return await PopulateResultsAsync(item.PluginID, item.Query, item.Title, item.SubTitle, item.RecordKey);
}
public static async Task<Result?> PopulateResultsAsync(string pluginId, string trimmedQuery, string title, string subTitle, string recordKey)
{
var plugin = PluginManager.GetPluginForId(pluginId);
if (plugin == null) return null;
var query = QueryBuilder.Build(trimmedQuery, trimmedQuery, PluginManager.GetNonGlobalPlugins());
if (query == null) return null;
try
{
var freshResults = await PluginManager.QueryForPluginAsync(plugin, query, CancellationToken.None);
// Try to match by record key first if it is valid, otherwise fall back to title + subtitle match
if (string.IsNullOrEmpty(recordKey))
{
return freshResults?.FirstOrDefault(r => r.Title == title && r.SubTitle == subTitle);
}
else
{
return freshResults?.FirstOrDefault(r => r.RecordKey == recordKey) ??
freshResults?.FirstOrDefault(r => r.Title == title && r.SubTitle == subTitle);
}
}
catch (System.Exception e)
{
App.API.LogException(nameof(ResultHelper), $"Failed to query results for {plugin.Metadata.Name}", e);
return null;
}
}
}

View file

@ -172,6 +172,10 @@
<system:String x:Key="homePageToolTip">Show home page results when query text is empty.</system:String> <system:String x:Key="homePageToolTip">Show home page results when query text is empty.</system:String>
<system:String x:Key="historyResultsForHomePage">Show History Results in Home Page</system:String> <system:String x:Key="historyResultsForHomePage">Show History Results in Home Page</system:String>
<system:String x:Key="historyResultsCountForHomePage">Maximum History Results Shown in Home Page</system:String> <system:String x:Key="historyResultsCountForHomePage">Maximum History Results Shown in Home Page</system:String>
<system:String x:Key="historyStyle">History Style</system:String>
<system:String x:Key="historyStyleTooltip">Choose the type of history to show in the History and Home Page</system:String>
<system:String x:Key="queryHistory">Query history</system:String>
<system:String x:Key="executedHistory">Last opened history</system:String>
<system:String x:Key="homeToggleBoxToolTip">This can only be edited if plugin supports Home feature and Home Page is enabled.</system:String> <system:String x:Key="homeToggleBoxToolTip">This can only be edited if plugin supports Home feature and Home Page is enabled.</system:String>
<system:String x:Key="showAtTopmost">Show Search Window at Foremost</system:String> <system:String x:Key="showAtTopmost">Show Search Window at Foremost</system:String>
<system:String x:Key="showAtTopmostToolTip">Overrides other programs' 'Always on Top' setting and displays Flow in the foremost position.</system:String> <system:String x:Key="showAtTopmostToolTip">Overrides other programs' 'Always on Top' setting and displays Flow in the foremost position.</system:String>
@ -228,6 +232,9 @@
<system:String x:Key="fileNotFoundMessage">Unable to find plugin.json from the extracted zip file, or this path {0} does not exist</system:String> <system:String x:Key="fileNotFoundMessage">Unable to find plugin.json from the extracted zip file, or this path {0} does not exist</system:String>
<system:String x:Key="pluginExistAlreadyMessage">A plugin with the same ID and version already exists, or the version is greater than this downloaded plugin</system:String> <system:String x:Key="pluginExistAlreadyMessage">A plugin with the same ID and version already exists, or the version is greater than this downloaded plugin</system:String>
<system:String x:Key="errorCreatingSettingPanel">Error creating setting panel for plugin {0}:{1}{2}</system:String> <system:String x:Key="errorCreatingSettingPanel">Error creating setting panel for plugin {0}:{1}{2}</system:String>
<system:String x:Key="pluginMinimumAppVersionUnsatisfiedTitle">{0} requires Flow version {1} to run</system:String>
<system:String x:Key="pluginMinimumAppVersionUnsatisfiedMessage">Flow does not meet the minimum version requirements for {0} to run. Do you want to continue installing it?{1}{1}We recommend updating Flow to the latest version to ensure that {0} works without issues.</system:String>
<system:String x:Key="pluginJsonInvalidOrCorrupted">Failed to install plugin because plugin.json is invalid or corrupted</system:String>
<!-- Setting Plugin Store --> <!-- Setting Plugin Store -->
<system:String x:Key="pluginStore">Plugin Store</system:String> <system:String x:Key="pluginStore">Plugin Store</system:String>

View file

@ -319,6 +319,7 @@ namespace Flow.Launcher
break; break;
case nameof(Settings.ShowHomePage): case nameof(Settings.ShowHomePage):
case nameof(Settings.ShowHistoryResultsForHomePage): case nameof(Settings.ShowHistoryResultsForHomePage):
case nameof(Settings.HistoryStyle):
if (_viewModel.QueryResultsSelected() && string.IsNullOrEmpty(_viewModel.QueryText)) if (_viewModel.QueryResultsSelected() && string.IsNullOrEmpty(_viewModel.QueryText))
{ {
_viewModel.QueryResults(); _viewModel.QueryResults();
@ -861,7 +862,7 @@ namespace Flow.Launcher
public void UpdatePosition() public void UpdatePosition()
{ {
// Initialize call twice to work around multi-display alignment issue- https://github.com/Flow-Launcher/Flow.Launcher/issues/2910 // Initialize call twice to workaround multi-display alignment issue- https://github.com/Flow-Launcher/Flow.Launcher/issues/2910
if (_viewModel.IsDialogJumpWindowUnderDialog()) if (_viewModel.IsDialogJumpWindowUnderDialog())
{ {
InitializeDialogJumpPosition(); InitializeDialogJumpPosition();
@ -885,7 +886,7 @@ namespace Flow.Launcher
private void InitializePosition() private void InitializePosition()
{ {
// Initialize call twice to work around multi-display alignment issue- https://github.com/Flow-Launcher/Flow.Launcher/issues/2910 // Initialize call twice to workaround multi-display alignment issue- https://github.com/Flow-Launcher/Flow.Launcher/issues/2910
InitializePositionInner(); InitializePositionInner();
InitializePositionInner(); InitializePositionInner();
return; return;

View file

@ -37,10 +37,21 @@ namespace Flow.Launcher
} }
private void SetException(Exception exception) private void SetException(Exception exception)
{
FileInfo log = null;
try
{ {
var path = DataLocation.VersionLogDirectory; var path = DataLocation.VersionLogDirectory;
var directory = new DirectoryInfo(path); var directory = new DirectoryInfo(path);
var log = directory.GetFiles().OrderByDescending(f => f.LastWriteTime).First(); if (directory.Exists)
{
log = directory.GetFiles().OrderByDescending(f => f.LastWriteTime).FirstOrDefault();
}
}
catch (Exception)
{
// Intentionally ignore all errors when trying to find the log file to avoid secondary crashes
}
var websiteUrl = exception switch var websiteUrl = exception switch
{ {
@ -49,8 +60,11 @@ namespace Flow.Launcher
}; };
var paragraph = Hyperlink(Localize.reportWindow_please_open_issue(), websiteUrl); var paragraph = Hyperlink(Localize.reportWindow_please_open_issue(), websiteUrl);
if (log is not null)
{
paragraph.Inlines.Add(Localize.reportWindow_upload_log(log.FullName)); paragraph.Inlines.Add(Localize.reportWindow_upload_log(log.FullName));
paragraph.Inlines.Add("\n"); paragraph.Inlines.Add("\n");
}
paragraph.Inlines.Add(Localize.reportWindow_copy_below()); paragraph.Inlines.Add(Localize.reportWindow_copy_below());
ErrorTextbox.Document.Blocks.Add(paragraph); ErrorTextbox.Document.Blocks.Add(paragraph);

View file

@ -147,6 +147,8 @@ public partial class SettingsPaneGeneralViewModel : BaseModel
public List<LastQueryModeData> LastQueryModes { get; } = public List<LastQueryModeData> LastQueryModes { get; } =
DropdownDataGeneric<LastQueryMode>.GetValues<LastQueryModeData>("LastQuery"); DropdownDataGeneric<LastQueryMode>.GetValues<LastQueryModeData>("LastQuery");
public List<HistoryStyleLocalized> HistoryStyles { get; } = HistoryStyleLocalized.GetValues();
public bool EnableDialogJump public bool EnableDialogJump
{ {
get => Settings.EnableDialogJump; get => Settings.EnableDialogJump;
@ -213,6 +215,7 @@ public partial class SettingsPaneGeneralViewModel : BaseModel
DropdownDataGeneric<SearchWindowAligns>.UpdateLabels(SearchWindowAligns); DropdownDataGeneric<SearchWindowAligns>.UpdateLabels(SearchWindowAligns);
DropdownDataGeneric<SearchPrecisionScore>.UpdateLabels(SearchPrecisionScores); DropdownDataGeneric<SearchPrecisionScore>.UpdateLabels(SearchPrecisionScores);
DropdownDataGeneric<LastQueryMode>.UpdateLabels(LastQueryModes); DropdownDataGeneric<LastQueryMode>.UpdateLabels(LastQueryModes);
HistoryStyleLocalized.UpdateLabels(HistoryStyles);
DropdownDataGeneric<DoublePinyinSchemas>.UpdateLabels(DoublePinyinSchemas); DropdownDataGeneric<DoublePinyinSchemas>.UpdateLabels(DoublePinyinSchemas);
DropdownDataGeneric<DialogJumpWindowPositions>.UpdateLabels(DialogJumpWindowPositions); DropdownDataGeneric<DialogJumpWindowPositions>.UpdateLabels(DialogJumpWindowPositions);
DropdownDataGeneric<DialogJumpResultBehaviours>.UpdateLabels(DialogJumpResultBehaviours); DropdownDataGeneric<DialogJumpResultBehaviours>.UpdateLabels(DialogJumpResultBehaviours);

View file

@ -255,6 +255,22 @@
SelectedValuePath="Value" /> SelectedValuePath="Value" />
</ui:SettingsCard> </ui:SettingsCard>
<ui:SettingsCard
Margin="0 14 0 0"
Description="{DynamicResource historyStyleTooltip}"
Header="{DynamicResource historyStyle}">
<ui:SettingsCard.HeaderIcon>
<ui:FontIcon Glyph="&#xE81C;" />
</ui:SettingsCard.HeaderIcon>
<ComboBox
MaxWidth="200"
DisplayMemberPath="Display"
ItemsSource="{Binding HistoryStyles}"
SelectedValue="{Binding Settings.HistoryStyle}"
SelectedValuePath="Value" />
</ui:SettingsCard>
<ui:SettingsCard <ui:SettingsCard
Margin="0 14 0 0" Margin="0 14 0 0"
Description="{DynamicResource autoRestartAfterChangingToolTip}" Description="{DynamicResource autoRestartAfterChangingToolTip}"

View file

@ -333,7 +333,7 @@
Margin="18 24 0 0" Margin="18 24 0 0"
HorizontalAlignment="Left" HorizontalAlignment="Left"
RenderOptions.BitmapScalingMode="Fant" RenderOptions.BitmapScalingMode="Fant"
Source="{Binding IcoPath, IsAsync=True}" /> Source="{Binding IcoPathAbsolute, IsAsync=True}" />
<Border <Border
x:Name="LabelUpdate" x:Name="LabelUpdate"
Height="12" Height="12"

View file

@ -96,7 +96,7 @@ public partial class SettingWindow
private void Window_StateChanged(object sender, EventArgs e) private void Window_StateChanged(object sender, EventArgs e)
{ {
RefreshMaximizeRestoreButton(); RefreshMaximizeRestoreButton();
if (IsLoaded) if (IsLoaded && WindowState != WindowState.Minimized)
{ {
_settings.SettingWindowState = WindowState; _settings.SettingWindowState = WindowState;
} }
@ -169,7 +169,9 @@ public partial class SettingWindow
SetWindowPosition(top, left); SetWindowPosition(top, left);
} }
WindowState = _settings.SettingWindowState; WindowState = _settings.SettingWindowState == WindowState.Minimized
? WindowState.Normal
: _settings.SettingWindowState;
} }
private void SetWindowPosition(double top, double left) private void SetWindowPosition(double top, double left)

View file

@ -1,7 +1,8 @@
using System; using System;
namespace Flow.Launcher.Storage namespace Flow.Launcher.Storage
{ {
[Obsolete("Use LastOpenedHistoryResult instead. This class will be removed in future versions.")]
public class HistoryItem public class HistoryItem
{ {
public string Query { get; set; } public string Query { get; set; }

View file

@ -0,0 +1,146 @@
using System;
using Flow.Launcher.Infrastructure;
using Flow.Launcher.Plugin;
namespace Flow.Launcher.Storage;
/// <summary>
/// A serializable result used to record the last opened history for reopening results.
/// Inherits common result fields from <see cref="Result"/> and adds the original query and execution time.
/// </summary>
public class LastOpenedHistoryResult : Result
{
/// <summary>
/// The query string from Query.TrimmedQuery property, it is stored as a string instead of the entire Query class <see cref="Result"/>.
/// This is used so results can be reopened or re-run using the serialized query string.
/// </summary>
public string Query { get; set; } = string.Empty;
/// <summary>
/// The local date and time when this result was executed/opened.
/// </summary>
public DateTime ExecutedDateTime { get; set; }
/// <summary>
/// Initializes a new instance of <see cref="LastOpenedHistoryResult"/>.
/// </summary>
public LastOpenedHistoryResult()
{
}
/// <summary>
/// Creates a <see cref="LastOpenedHistoryResult"/> from an existing <see cref="Result"/>.
/// Copies required fields and sets up default reopening actions.
/// </summary>
/// <param name="result">The original result to create history from.</param>
public LastOpenedHistoryResult(Result result)
{
Title = result.Title;
SubTitle = result.SubTitle;
PluginID = result.PluginID;
Query = result.OriginQuery.TrimmedQuery;
OriginQuery = result.OriginQuery;
RecordKey = result.RecordKey;
IcoPath = result.IcoPath;
PluginDirectory = result.PluginDirectory;
Glyph = result.Glyph;
ExecutedDateTime = DateTime.Now;
// Used for Query History style reopening
Action = _ =>
{
App.API.BackToQueryResults();
App.API.ChangeQuery(result.OriginQuery.TrimmedQuery);
return false;
};
// Used for Last Opened History style reopening, currently need to be assigned at MainViewModel.cs
AsyncAction = null;
}
/// <summary>
/// Selectively creates a deep copy of the required properties for <see cref="LastOpenedHistoryResult"/>
/// based on the style of history- Last Opened or Query.
/// This copy should be independent of original and full isolated.
/// </summary>
/// <returns>A new <see cref="LastOpenedHistoryResult"/> containing the same required data.</returns>
public LastOpenedHistoryResult DeepCopyForHistoryStyle(bool isHistoryStyleLastOpened)
{
// queryValue and glyphValue are captured to ensure they are correctly referenced in the Action delegate.
var queryValue = Query;
var glyphValue = Glyph;
var title = string.Empty;
var showBadge = false;
var badgeIcoPath = string.Empty;
var icoPath = string.Empty;
var glyph = null as GlyphInfo;
if (isHistoryStyleLastOpened)
{
title = Title;
icoPath = IcoPath;
glyph = glyphValue != null
? new GlyphInfo(glyphValue.FontFamily, glyphValue.Glyph)
: null;
showBadge = true;
badgeIcoPath = Constant.HistoryIcon;
}
else
{
title = Localize.executeQuery(Query);
icoPath = Constant.HistoryIcon;
glyph = new GlyphInfo(FontFamily: "/Resources/#Segoe Fluent Icons", Glyph: "\uE81C");
showBadge = false;
}
return new LastOpenedHistoryResult
{
Title = title,
// Subtitle has datetime which can cause duplicates when saving.
SubTitle = Localize.lastExecuteTime(ExecutedDateTime),
// Empty PluginID so the source of last opened history results won't be updated, this copy is meant to be temporary.
PluginID = string.Empty,
Query = Query,
OriginQuery = new Query { TrimmedQuery = Query },
RecordKey = RecordKey,
IcoPath = icoPath,
ShowBadge = showBadge,
BadgeIcoPath = badgeIcoPath,
PluginDirectory = PluginDirectory,
// Used for Query History style reopening
Action = _ =>
{
App.API.BackToQueryResults();
App.API.ChangeQuery(queryValue);
return false;
},
// Used for Last Opened History style reopening, currently need to be assigned at MainViewModel.cs
AsyncAction = null,
Glyph = glyph,
ExecutedDateTime = ExecutedDateTime
// Note: Other properties are left as default — copy if needed.
};
}
/// <summary>
/// Determines whether the specified <see cref="Result"/> is equivalent to this history result.
/// Comparison uses <see cref="Result.RecordKey"/> when available; otherwise falls back to title/subtitle/plugin id and query.
/// </summary>
/// <param name="r">The result to compare to.</param>
/// <returns><c>true</c> if the results are considered equal; otherwise <c>false</c>.</returns>
public bool Equals(Result r)
{
if (string.IsNullOrEmpty(RecordKey) || string.IsNullOrEmpty(r.RecordKey))
{
return Title == r.Title
&& SubTitle == r.SubTitle
&& PluginID == r.PluginID
&& Query == r.OriginQuery.TrimmedQuery;
}
else
{
return RecordKey == r.RecordKey
&& PluginID == r.PluginID
&& Query == r.OriginQuery.TrimmedQuery;
}
}
}

View file

@ -2,35 +2,118 @@ using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text.Json.Serialization; using System.Text.Json.Serialization;
using Flow.Launcher.Core.Plugin;
using Flow.Launcher.Plugin;
namespace Flow.Launcher.Storage namespace Flow.Launcher.Storage
{ {
public class History public class History
{ {
[JsonInclude] [JsonInclude]
public List<HistoryItem> Items { get; private set; } = new List<HistoryItem>(); #pragma warning disable CS0618 // Type or member is obsolete
public List<HistoryItem> Items { get; private set; } = [];
#pragma warning restore CS0618 // Type or member is obsolete
private int _maxHistory = 300; [JsonInclude]
public List<LastOpenedHistoryResult> LastOpenedHistoryItems { get; private set; } = [];
public void Add(string query) private readonly int _maxHistory = 300;
/// <summary>
/// Migrate legacy history data (stored in <see cref="Items"/>) into the new
/// <see cref="LastOpenedHistoryResult"/> format and append them to
/// <see cref="LastOpenedHistoryItems"/>.
/// </summary>
[Obsolete("For backwards compatibility. Remove after release v2.3.0")]
public void PopulateHistoryFromLegacyHistory()
{ {
if (string.IsNullOrEmpty(query)) return; if (Items.Count == 0) return;
if (Items.Count > _maxHistory) // Migrate old history items to new LastOpenedHistoryItems
foreach (var item in Items)
{ {
Items.RemoveAt(0); LastOpenedHistoryItems.Add(new LastOpenedHistoryResult
{
Title = Localize.executeQuery(item.Query),
OriginQuery = new Query { TrimmedQuery = item.Query },
Query = item.Query,
Action = _ =>
{
App.API.BackToQueryResults();
App.API.ChangeQuery(item.Query);
return false;
},
ExecutedDateTime = item.ExecutedDateTime
});
}
Items.Clear();
} }
if (Items.Count > 0 && Items.Last().Query == query) /// <summary>
/// Records a result into the last-opened history list (<see cref="LastOpenedHistoryItems"/>).
/// This will also update the IcoPath if existing history item has one that is different.
/// </summary>
/// <param name="result">The result to add to history. Must have a non-empty <see cref="Result.OriginQuery"/>.<see cref="Query.TrimmedQuery"/>.</param>
public void Add(Result result)
{ {
Items.Last().ExecutedDateTime = DateTime.Now; if (string.IsNullOrEmpty(result.OriginQuery.TrimmedQuery)) return;
// History results triggered from homepage do not contain PluginID,
// these are intentionally not saved otherwise cause duplicates due to subtitle
// containing datetime string.
if (string.IsNullOrEmpty(result.PluginID)) return;
// Maintain the max history limit
if (LastOpenedHistoryItems.Count > _maxHistory)
{
LastOpenedHistoryItems.RemoveAt(0);
}
// If the last item is the same as the current result, just update the timestamp and the icon path
if (LastOpenedHistoryItems.Count > 0 &&
TryGetLastOpenedHistoryResult(result, out var existingHistoryItem))
{
existingHistoryItem.ExecutedDateTime = DateTime.Now;
if (existingHistoryItem.IcoPath != result.IcoPath)
existingHistoryItem.IcoPath = result.IcoPath;
if (existingHistoryItem.Glyph?.Glyph != result.Glyph?.Glyph
|| existingHistoryItem.Glyph?.FontFamily != result.Glyph?.FontFamily)
existingHistoryItem.SetGlyph(result.Glyph);
} }
else else
{ {
Items.Add(new HistoryItem LastOpenedHistoryItems.Add(new LastOpenedHistoryResult(result));
}
}
/// <summary>
/// Attempts to find an existing <see cref="LastOpenedHistoryResult"/> in <see cref="LastOpenedHistoryItems"/>
/// that is considered equal to the supplied <paramref name="result"/>.
/// </summary>
private bool TryGetLastOpenedHistoryResult(Result result, out LastOpenedHistoryResult historyItem)
{ {
Query = query, historyItem = LastOpenedHistoryItems.FirstOrDefault(x => x.Equals(result));
ExecutedDateTime = DateTime.Now return historyItem is not null;
}); }
/// <summary>
/// Flow uses IcoPathAbsolute property to display result the icons. This refreshes the IcoPathAbsolute
/// property using current plugin metadata by updating the PluginDirectory property, which in turn also
/// updates IcoPath. This keeps the saved icon paths of results updated correctly if flow is moved around.
/// </summary>
/// <remarks> Call this after plugins are loaded/initialized.</remarks>
public void UpdateIcoPathAbsolute()
{
if (LastOpenedHistoryItems.Count == 0) return;
foreach (var item in LastOpenedHistoryItems)
{
if (string.IsNullOrEmpty(item.PluginID)) continue;
var pluginPair = PluginManager.GetPluginForId(item.PluginID);
if (pluginPair == null) continue;
item.PluginDirectory = pluginPair.Metadata.PluginDirectory;
} }
} }
} }

View file

@ -1,4 +1,4 @@
using System; using System;
using System.Collections.Concurrent; using System.Collections.Concurrent;
using System.Collections.Generic; using System.Collections.Generic;
using System.ComponentModel; using System.ComponentModel;
@ -9,16 +9,17 @@ using System.Threading;
using System.Threading.Channels; using System.Threading.Channels;
using System.Threading.Tasks; using System.Threading.Tasks;
using System.Windows; using System.Windows;
using System.Windows.Input;
using System.Windows.Controls; using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media; using System.Windows.Media;
using System.Windows.Threading; using System.Windows.Threading;
using CommunityToolkit.Mvvm.DependencyInjection; using CommunityToolkit.Mvvm.DependencyInjection;
using CommunityToolkit.Mvvm.Input; using CommunityToolkit.Mvvm.Input;
using Flow.Launcher.Core.Plugin; using Flow.Launcher.Core.Plugin;
using Flow.Launcher.Helper;
using Flow.Launcher.Infrastructure; using Flow.Launcher.Infrastructure;
using Flow.Launcher.Infrastructure.Hotkey;
using Flow.Launcher.Infrastructure.DialogJump; using Flow.Launcher.Infrastructure.DialogJump;
using Flow.Launcher.Infrastructure.Hotkey;
using Flow.Launcher.Infrastructure.Storage; using Flow.Launcher.Infrastructure.Storage;
using Flow.Launcher.Infrastructure.UserSettings; using Flow.Launcher.Infrastructure.UserSettings;
using Flow.Launcher.Plugin; using Flow.Launcher.Plugin;
@ -43,10 +44,10 @@ namespace Flow.Launcher.ViewModel
private string _ignoredQueryText; // Used to ignore query text change when switching between context menu and query results private string _ignoredQueryText; // Used to ignore query text change when switching between context menu and query results
private readonly FlowLauncherJsonStorage<History> _historyItemsStorage; private readonly FlowLauncherJsonStorage<History> _historyItemsStorage;
private readonly FlowLauncherJsonStorage<UserSelectedRecord> _userSelectedRecordStorage;
private readonly FlowLauncherJsonStorageTopMostRecord _topMostRecord;
private readonly History _history; private readonly History _history;
private int lastHistoryIndex = 1; private int lastHistoryIndex = 1;
private readonly FlowLauncherJsonStorage<UserSelectedRecord> _userSelectedRecordStorage;
private readonly FlowLauncherJsonStorageTopMostRecord _topMostRecord;
private readonly UserSelectedRecord _userSelectedRecord; private readonly UserSelectedRecord _userSelectedRecord;
private CancellationTokenSource _updateSource; // Used to cancel old query flows private CancellationTokenSource _updateSource; // Used to cancel old query flows
@ -152,10 +153,10 @@ namespace Flow.Launcher.ViewModel
}; };
_historyItemsStorage = new FlowLauncherJsonStorage<History>(); _historyItemsStorage = new FlowLauncherJsonStorage<History>();
_userSelectedRecordStorage = new FlowLauncherJsonStorage<UserSelectedRecord>();
_topMostRecord = new FlowLauncherJsonStorageTopMostRecord();
_history = _historyItemsStorage.Load(); _history = _historyItemsStorage.Load();
_userSelectedRecordStorage = new FlowLauncherJsonStorage<UserSelectedRecord>();
_userSelectedRecord = _userSelectedRecordStorage.Load(); _userSelectedRecord = _userSelectedRecordStorage.Load();
_topMostRecord = new FlowLauncherJsonStorageTopMostRecord();
ContextMenu = new ResultsViewModel(Settings, this) ContextMenu = new ResultsViewModel(Settings, this)
{ {
@ -354,11 +355,17 @@ namespace Flow.Launcher.ViewModel
if (QueryResultsSelected()) if (QueryResultsSelected())
{ {
SelectedResults = History; SelectedResults = History;
History.SelectedIndex = _history.Items.Count - 1; if (History.Results.Count > 0)
{
SelectedResults.SelectedIndex = 0;
SelectedResults.SelectedItem = History.Results[0];
}
} }
else else
{ {
SelectedResults = Results; SelectedResults = Results;
PreviewSelectedItem = Results.SelectedItem;
_ = UpdatePreviewAsync();
} }
} }
@ -382,10 +389,11 @@ namespace Flow.Launcher.ViewModel
[RelayCommand] [RelayCommand]
public void ReverseHistory() public void ReverseHistory()
{ {
if (_history.Items.Count > 0) var historyItems = _history.LastOpenedHistoryItems;
if (historyItems.Count > 0)
{ {
ChangeQueryText(_history.Items[^lastHistoryIndex].Query); ChangeQueryText(historyItems[^lastHistoryIndex].Query);
if (lastHistoryIndex < _history.Items.Count) if (lastHistoryIndex < historyItems.Count)
{ {
lastHistoryIndex++; lastHistoryIndex++;
} }
@ -395,9 +403,10 @@ namespace Flow.Launcher.ViewModel
[RelayCommand] [RelayCommand]
public void ForwardHistory() public void ForwardHistory()
{ {
if (_history.Items.Count > 0) var historyItems = _history.LastOpenedHistoryItems;
if (historyItems.Count > 0)
{ {
ChangeQueryText(_history.Items[^lastHistoryIndex].Query); ChangeQueryText(historyItems[^lastHistoryIndex].Query);
if (lastHistoryIndex > 1) if (lastHistoryIndex > 1)
{ {
lastHistoryIndex--; lastHistoryIndex--;
@ -428,7 +437,8 @@ namespace Flow.Launcher.ViewModel
{ {
// When switch to ContextMenu from QueryResults, but no item being chosen, should do nothing // When switch to ContextMenu from QueryResults, but no item being chosen, should do nothing
// i.e. Shift+Enter/Ctrl+O right after Alt + Space should do nothing // i.e. Shift+Enter/Ctrl+O right after Alt + Space should do nothing
if (SelectedResults.SelectedItem != null) if (SelectedResults.SelectedItem?.Result != null &&
!string.IsNullOrEmpty(SelectedResults.SelectedItem.Result.PluginID)) // Do not show context menu for history results
{ {
SelectedResults = ContextMenu; SelectedResults = ContextMenu;
} }
@ -436,6 +446,8 @@ namespace Flow.Launcher.ViewModel
else else
{ {
SelectedResults = Results; SelectedResults = Results;
PreviewSelectedItem = Results.SelectedItem;
_ = UpdatePreviewAsync();
} }
} }
@ -489,6 +501,8 @@ namespace Flow.Launcher.ViewModel
[RelayCommand] [RelayCommand]
private async Task OpenResultAsync(string index) private async Task OpenResultAsync(string index)
{ {
// Must check query results selected before executing the action
var queryResultsSelected = QueryResultsSelected();
var results = SelectedResults; var results = SelectedResults;
if (index is not null) if (index is not null)
{ {
@ -529,10 +543,12 @@ namespace Flow.Launcher.ViewModel
} }
} }
if (QueryResultsSelected()) // Record user selected result for result ranking
{
_userSelectedRecord.Add(result); _userSelectedRecord.Add(result);
_history.Add(result.OriginQuery.RawQuery); // Add item to history only if it is from results but not context menu or history
if (queryResultsSelected)
{
_history.Add(result);
lastHistoryIndex = 1; lastHistoryIndex = 1;
} }
} }
@ -608,10 +624,11 @@ namespace Flow.Launcher.ViewModel
[RelayCommand] [RelayCommand]
private void SelectPrevItem() private void SelectPrevItem()
{ {
var historyItems = _history.LastOpenedHistoryItems;
if (QueryResultsSelected() // Results selected if (QueryResultsSelected() // Results selected
&& string.IsNullOrEmpty(QueryText) // No input && string.IsNullOrEmpty(QueryText) // No input
&& Results.Visibility != Visibility.Visible // No items in result list, e.g. when home page is off and no query text is entered, therefore the view is collapsed. && Results.Visibility != Visibility.Visible // No items in result list, e.g. when home page is off and no query text is entered, therefore the view is collapsed.
&& _history.Items.Count > 0) // Have history items && historyItems.Count > 0) // Have history items
{ {
lastHistoryIndex = 1; lastHistoryIndex = 1;
ReverseHistory(); ReverseHistory();
@ -634,6 +651,8 @@ namespace Flow.Launcher.ViewModel
if (!QueryResultsSelected()) if (!QueryResultsSelected())
{ {
SelectedResults = Results; SelectedResults = Results;
PreviewSelectedItem = Results.SelectedItem;
_ = UpdatePreviewAsync();
} }
else else
{ {
@ -910,7 +929,7 @@ namespace Flow.Launcher.ViewModel
private string _placeholderText; private string _placeholderText;
public string PlaceholderText public string PlaceholderText
{ {
get => string.IsNullOrEmpty(_placeholderText) ? Localize.queryTextBoxPlaceholder(): _placeholderText; get => string.IsNullOrEmpty(_placeholderText) ? Localize.queryTextBoxPlaceholder() : _placeholderText;
set set
{ {
_placeholderText = value; _placeholderText = value;
@ -1152,6 +1171,7 @@ namespace Flow.Launcher.ViewModel
HideInternalPreview(); HideInternalPreview();
_ = OpenExternalPreviewAsync(path); _ = OpenExternalPreviewAsync(path);
} }
break; break;
case true case true
when !CanExternalPreviewSelectedResult(out var _): when !CanExternalPreviewSelectedResult(out var _):
@ -1243,22 +1263,12 @@ namespace Flow.Launcher.ViewModel
var selected = Results.SelectedItem?.Result; var selected = Results.SelectedItem?.Result;
if (selected != null) // SelectedItem returns null if selection is empty. if (selected != null && // SelectedItem returns null if selection is empty.
!string.IsNullOrEmpty(selected.PluginID)) // SelectedItem must have a valid PluginID, history results do not.
{ {
List<Result> results; List<Result> results = PluginManager.GetContextMenusForPlugin(selected);
if (selected.PluginID == null) // SelectedItem from history in home page.
{
results = new()
{
ContextMenuTopMost(selected)
};
}
else
{
results = PluginManager.GetContextMenusForPlugin(selected);
results.Add(ContextMenuTopMost(selected)); results.Add(ContextMenuTopMost(selected));
results.Add(ContextMenuPluginInfo(selected)); results.Add(ContextMenuPluginInfo(selected));
}
if (!string.IsNullOrEmpty(query)) if (!string.IsNullOrEmpty(query))
{ {
@ -1292,7 +1302,7 @@ namespace Flow.Launcher.ViewModel
var query = QueryText.ToLower().Trim(); var query = QueryText.ToLower().Trim();
History.Clear(); History.Clear();
var results = GetHistoryItems(_history.Items); var results = GetHistoryItems(_history.LastOpenedHistoryItems);
if (!string.IsNullOrEmpty(query)) if (!string.IsNullOrEmpty(query))
{ {
@ -1309,30 +1319,77 @@ namespace Flow.Launcher.ViewModel
} }
} }
private static List<Result> GetHistoryItems(IEnumerable<HistoryItem> historyItems) private List<Result> GetHistoryItems(IEnumerable<LastOpenedHistoryResult> historyItems, int? maxResult = null)
{ {
var results = new List<Result>(); var results = new List<Result>();
foreach (var h in historyItems)
// Order by executed time descending: Latest -> Oldest
historyItems = historyItems.OrderByDescending(x => x.ExecutedDateTime);
if (Settings.HistoryStyle == HistoryStyle.LastOpened)
{ {
var result = new Result // Items saved to disk are differentiated by Query also, but LastOpened style only cares about unique results
{ historyItems = historyItems
Title = Localize.executeQuery(h.Query), .GroupBy(r => new { r.Title, r.SubTitle, r.PluginID, r.RecordKey })
SubTitle = Localize.lastExecuteTime(h.ExecutedDateTime), .Select(g => g.First());
IcoPath = Constant.HistoryIcon,
OriginQuery = new Query { RawQuery = h.Query },
Action = _ =>
{
App.API.BackToQueryResults();
App.API.ChangeQuery(h.Query);
return false;
},
Glyph = new GlyphInfo(FontFamily: "/Resources/#Segoe Fluent Icons", Glyph: "\uE81C")
};
results.Add(result);
} }
// Max history results to return for display
if (maxResult.HasValue)
{
historyItems = historyItems.Take(maxResult.Value);
}
foreach (var item in historyItems)
{
var copiedItem = item.DeepCopyForHistoryStyle(Settings.HistoryStyle == HistoryStyle.LastOpened);
if (Settings.HistoryStyle == HistoryStyle.LastOpened)
{
copiedItem.AsyncAction = async c =>
{
// Use original history item to reflect correct result because properties like subtitle have been modified in copiedItem
var reflectResult = await ResultHelper.PopulateResultsAsync(item);
if (reflectResult != null)
{
// Since some actions may need to hide the Flow window to execute
// So let us populate the results of them
return await reflectResult.ExecuteAsync(c);
}
// If we cannot get the result, fallback to re-query
App.API.BackToQueryResults();
App.API.ChangeQuery(copiedItem.Query);
return false;
};
}
results.Add(copiedItem);
}
return results; return results;
} }
/// <summary>
/// Refreshes the last-opened history storage by migrating legacy entries and
/// updating stored icon paths to their resolved (absolute) locations.
/// </summary>
/// <remarks>
/// Calls <see cref="History.UpdateIcoPathAbsolute"/> to refresh absolute icon
/// paths on the migrated/saved history entries by updating each item's
/// <c>PluginDirectory</c> (which in turn resolves <c>IcoPathAbsolute</c>).
///
/// Important:
/// - Plugins must be initialized (their metadata and <c>PluginDirectory</c> set)
/// before calling this method; otherwise icon resolution cannot be performed.
/// </remarks>
internal void RefreshLastOpenedHistoryResults()
{
_history.PopulateHistoryFromLegacyHistory();
_history.UpdateIcoPathAbsolute();
}
private async Task QueryResultsAsync(bool searchDelay, bool isReQuery = false, bool reSelect = true) private async Task QueryResultsAsync(bool searchDelay, bool isReQuery = false, bool reSelect = true)
{ {
_updateSource?.Cancel(); _updateSource?.Cancel();
@ -1574,10 +1631,8 @@ namespace Flow.Launcher.ViewModel
void QueryHistoryTask(CancellationToken token) void QueryHistoryTask(CancellationToken token)
{ {
// Select last history results and revert its order to make sure last history results are on top // Select last history results
var historyItems = _history.Items.TakeLast(Settings.MaxHistoryResultsToShowForHomePage).Reverse(); var results = GetHistoryItems(_history.LastOpenedHistoryItems, Settings.MaxHistoryResultsToShowForHomePage);
var results = GetHistoryItems(historyItems);
if (token.IsCancellationRequested) return; if (token.IsCancellationRequested) return;

View file

@ -141,7 +141,7 @@ namespace Flow.Launcher.ViewModel
private bool GlyphAvailable => Glyph is not null; private bool GlyphAvailable => Glyph is not null;
private bool ImgIconAvailable => !string.IsNullOrEmpty(Result.IcoPath) || Result.Icon is not null; private bool ImgIconAvailable => !string.IsNullOrEmpty(Result.IcoPathAbsolute) || Result.Icon is not null;
private bool BadgeIconAvailable => !string.IsNullOrEmpty(Result.BadgeIcoPath) || Result.BadgeIcon is not null; private bool BadgeIconAvailable => !string.IsNullOrEmpty(Result.BadgeIcoPath) || Result.BadgeIcon is not null;
@ -236,7 +236,7 @@ namespace Flow.Launcher.ViewModel
private async Task LoadImageAsync() private async Task LoadImageAsync()
{ {
var imagePath = Result.IcoPath; var imagePath = Result.IcoPathAbsolute;
var iconDelegate = Result.Icon; var iconDelegate = Result.Icon;
if (ImageLoader.TryGetValue(imagePath, false, out var img)) if (ImageLoader.TryGetValue(imagePath, false, out var img))
{ {
@ -266,7 +266,7 @@ namespace Flow.Launcher.ViewModel
private async Task LoadPreviewImageAsync() private async Task LoadPreviewImageAsync()
{ {
var imagePath = Result.Preview.PreviewImagePath ?? Result.IcoPath; var imagePath = Result.Preview.PreviewImagePath ?? Result.IcoPathAbsolute;
var iconDelegate = Result.Preview.PreviewDelegate ?? Result.Icon; var iconDelegate = Result.Preview.PreviewDelegate ?? Result.Icon;
if (ImageLoader.TryGetValue(imagePath, true, out var img)) if (ImageLoader.TryGetValue(imagePath, true, out var img))
{ {

View file

@ -110,7 +110,7 @@
<PackageReference Include="CommunityToolkit.Mvvm" Version="8.4.0" /> <PackageReference Include="CommunityToolkit.Mvvm" Version="8.4.0" />
<PackageReference Include="Flow.Launcher.Localization" Version="0.0.6" /> <PackageReference Include="Flow.Launcher.Localization" Version="0.0.6" />
<PackageReference Include="Microsoft.Data.Sqlite" Version="10.0.3" /> <PackageReference Include="Microsoft.Data.Sqlite" Version="10.0.3" />
<PackageReference Include="Svg.Skia" Version="3.4.1" /> <PackageReference Include="Svg.Skia" Version="3.5.0" />
<PackageReference Include="SkiaSharp" Version="3.119.1" /> <PackageReference Include="SkiaSharp" Version="3.119.1" />
</ItemGroup> </ItemGroup>

View file

@ -230,7 +230,7 @@ namespace Flow.Launcher.Plugin.Explorer
internal Dictionary<ActionKeyword, string> GetActiveActionKeywords(string actionKeywordStr) internal Dictionary<ActionKeyword, string> GetActiveActionKeywords(string actionKeywordStr)
{ {
var result = new Dictionary<ActionKeyword, string>(); var result = new Dictionary<ActionKeyword, string>();
if (string.IsNullOrEmpty(actionKeywordStr)) return null; if (string.IsNullOrEmpty(actionKeywordStr)) return result;
foreach (var action in Enum.GetValues<ActionKeyword>()) foreach (var action in Enum.GetValues<ActionKeyword>())
{ {
var keywordStr = GetActionKeyword(action); var keywordStr = GetActionKeyword(action);

View file

@ -321,8 +321,9 @@ namespace Flow.Launcher.Plugin.Explorer.ViewModels
Context.API.AddActionKeyword(Context.CurrentPluginMetadata.ID, actionKeywordWindow.ActionKeyword); Context.API.AddActionKeyword(Context.CurrentPluginMetadata.ID, actionKeywordWindow.ActionKeyword);
break; break;
case (false, false): case (false, false):
throw new ArgumentException( // Keyword was disabled and remains disabled, but the keyword text was changed.
$"Both false in {nameof(actionKeyword)}.{nameof(actionKeyword.Enabled)} and {nameof(actionKeywordWindow)}.{nameof(actionKeywordWindow.KeywordEnabled)} should suggest that the ShowDialog() result is false"); // No action keyword registration changes needed; the model will be updated below.
break;
} }
(actionKeyword.Keyword, actionKeyword.Enabled) = (actionKeywordWindow.ActionKeyword, actionKeywordWindow.KeywordEnabled); (actionKeyword.Keyword, actionKeyword.Enabled) = (actionKeywordWindow.ActionKeyword, actionKeywordWindow.KeywordEnabled);

View file

@ -82,7 +82,7 @@
VerticalAlignment="Center" VerticalAlignment="Center"
DataObject.Pasting="TextBox_Pasting" DataObject.Pasting="TextBox_Pasting"
PreviewKeyDown="TxtCurrentActionKeyword_OnKeyDown" PreviewKeyDown="TxtCurrentActionKeyword_OnKeyDown"
Text="{Binding ActionKeyword}" /> Text="{Binding ActionKeyword, UpdateSourceTrigger=PropertyChanged}" />
</StackPanel> </StackPanel>
<StackPanel Margin="0 10 0 15" Orientation="Horizontal"> <StackPanel Margin="0 10 0 15" Orientation="Horizontal">
<TextBlock <TextBlock

View file

@ -16,9 +16,9 @@ namespace Flow.Launcher.Plugin.Explorer.Views
get => actionKeyword; get => actionKeyword;
set set
{ {
// Set Enable to be true if user change ActionKeyword // Set Enable to be true only when the ActionKeyword value actually changes
if (SetProperty(ref actionKeyword, value))
KeywordEnabled = true; KeywordEnabled = true;
_ = SetProperty(ref actionKeyword, value);
} }
} }
@ -34,8 +34,9 @@ namespace Flow.Launcher.Plugin.Explorer.Views
public ActionKeywordSetting(ActionKeywordModel selectedActionKeyword) public ActionKeywordSetting(ActionKeywordModel selectedActionKeyword)
{ {
CurrentActionKeyword = selectedActionKeyword; CurrentActionKeyword = selectedActionKeyword;
ActionKeyword = selectedActionKeyword.Keyword; // Initialize backing fields directly to avoid triggering the auto-enable side-effect
KeywordEnabled = selectedActionKeyword.Enabled; actionKeyword = selectedActionKeyword.Keyword;
_keywordEnabled = selectedActionKeyword.Enabled;
InitializeComponent(); InitializeComponent();