Skip to content

Commit 3e2199b

Browse files
authored
Merge branch 'dev' into feature/pinned-results
2 parents 599a944 + 7fdf3a2 commit 3e2199b

File tree

9 files changed

+257
-83
lines changed

9 files changed

+257
-83
lines changed

.github/actions/spelling/expect.txt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,3 +108,7 @@ Msix
108108
dummyprofile
109109
browserbookmark
110110
copyurl
111+
uninstaller
112+
taskbar
113+
taskbars
114+
ikw

.github/workflows/spelling.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ jobs:
7272
steps:
7373
- name: check-spelling
7474
id: spelling
75-
uses: check-spelling/check-spelling@v0.0.25
75+
uses: check-spelling/check-spelling@v0.0.26
7676
with:
7777
suppress_push_for_open_pull_request: 1
7878
checkout: true
@@ -128,7 +128,7 @@ jobs:
128128
if: (success() || failure()) && needs.spelling.outputs.followup && contains(github.event_name, 'pull_request')
129129
steps:
130130
- name: comment
131-
uses: check-spelling/check-spelling@v0.0.25
131+
uses: check-spelling/check-spelling@v0.0.26
132132
with:
133133
checkout: true
134134
spell_check_this: check-spelling/spell-check-this@main

Flow.Launcher.Core/ExternalPlugins/Environments/AbstractPluginEnvironment.cs

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,12 @@ internal AbstractPluginEnvironment(List<PluginMetadata> pluginMetadataList, Plug
4040
PluginSettings = pluginSettings;
4141
}
4242

43+
/// <summary>
44+
/// Resolves the configured runtime executable path to an absolute path.
45+
/// Supports both absolute paths and relative paths (relative to ProgramDirectory).
46+
/// </summary>
47+
private string ResolvedPluginsSettingsFilePath => FilesFolders.ResolveAbsolutePath(PluginsSettingsFilePath);
48+
4349
internal IEnumerable<PluginPair> Setup()
4450
{
4551
// If no plugin is using the language, return empty list
@@ -48,13 +54,16 @@ internal IEnumerable<PluginPair> Setup()
4854
return new List<PluginPair>();
4955
}
5056

51-
if (!string.IsNullOrEmpty(PluginsSettingsFilePath) && FilesFolders.FileExists(PluginsSettingsFilePath))
57+
var resolvedPath = ResolvedPluginsSettingsFilePath;
58+
if (!string.IsNullOrEmpty(resolvedPath) && FilesFolders.FileExists(resolvedPath))
5259
{
5360
// Ensure latest only if user is using Flow's environment setup.
54-
if (PluginsSettingsFilePath.StartsWith(EnvPath, StringComparison.OrdinalIgnoreCase))
55-
EnsureLatestInstalled(ExecutablePath, PluginsSettingsFilePath, EnvPath);
61+
if (resolvedPath.StartsWith(EnvPath, StringComparison.OrdinalIgnoreCase))
62+
EnsureLatestInstalled(ExecutablePath, resolvedPath, EnvPath);
5663

57-
return SetPathForPluginPairs(PluginsSettingsFilePath, Language);
64+
// Ensure the path is updated in settings in case environment was updated
65+
resolvedPath = ResolvedPluginsSettingsFilePath;
66+
return SetPathForPluginPairs(resolvedPath, Language);
5867
}
5968

6069
var noRuntimeMessage = Localize.runtimePluginInstalledChooseRuntimePrompt(Language, EnvName, Environment.NewLine);
@@ -103,9 +112,11 @@ internal IEnumerable<PluginPair> Setup()
103112
InstallEnvironment();
104113
}
105114

106-
if (FilesFolders.FileExists(PluginsSettingsFilePath))
115+
// Ensure the path is updated when user has chosen to install or select environment executable
116+
resolvedPath = ResolvedPluginsSettingsFilePath;
117+
if (FilesFolders.FileExists(resolvedPath))
107118
{
108-
return SetPathForPluginPairs(PluginsSettingsFilePath, Language);
119+
return SetPathForPluginPairs(resolvedPath, Language);
109120
}
110121
else
111122
{

Flow.Launcher.Plugin/SharedCommands/FilesFolders.cs

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22
using System.Diagnostics;
33
using System.IO;
44
using System.Linq;
5+
using System.Reflection;
6+
57
#pragma warning disable IDE0005
68
using System.Windows;
79
#pragma warning restore IDE0005
@@ -487,5 +489,34 @@ public static void ValidateDataDirectory(string bundledDataDirectory, string dat
487489
}
488490
}
489491
}
492+
493+
/// <summary>
494+
/// Resolves a path that may be relative to an absolute path.
495+
/// If the path is already absolute, returns it as-is.
496+
/// If the path is not rooted (as determined by <see cref="Path.IsPathRooted(string)"/>), resolves it relative to ProgramDirectory.
497+
/// </summary>
498+
/// <param name="path">The path to resolve</param>
499+
/// <returns>An absolute path</returns>
500+
public static string ResolveAbsolutePath(string path)
501+
{
502+
if (string.IsNullOrEmpty(path))
503+
return path;
504+
505+
// If already absolute, return as-is
506+
if (Path.IsPathFullyQualified(path))
507+
return path;
508+
509+
// Resolve relative to ProgramDirectory, handling invalid path formats gracefully
510+
try
511+
{
512+
return Path.GetFullPath(Path.Combine(Directory.GetParent(Assembly.GetExecutingAssembly().Location).ToString(), path));
513+
}
514+
catch (Exception)
515+
{
516+
// If the path cannot be resolved (invalid characters, format, or too long),
517+
// return the original path to avoid crashing the application.
518+
return path;
519+
}
520+
}
490521
}
491522
}

Flow.Launcher/Languages/en.xaml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -253,6 +253,11 @@
253253
<system:String x:Key="pluginStore_RecentlyUpdated">Recently Updated</system:String>
254254
<system:String x:Key="pluginStore_None">Plugins</system:String>
255255
<system:String x:Key="pluginStore_Installed">Installed</system:String>
256+
<system:String x:Key="PluginStoreSortModeDefault">Default</system:String>
257+
<system:String x:Key="PluginStoreSortModeName">Name</system:String>
258+
<system:String x:Key="PluginStoreSortModeReleaseDate">Release Date</system:String>
259+
<system:String x:Key="PluginStoreSortModeUpdatedDate">Updated Date</system:String>
260+
<system:String x:Key="PluginStoreSortingModeComboboxLabel">Sorting Mode:</system:String>
256261
<system:String x:Key="refresh">Refresh</system:String>
257262
<system:String x:Key="installbtn">Install</system:String>
258263
<system:String x:Key="uninstallbtn">Uninstall</system:String>

Flow.Launcher/SettingPages/ViewModels/SettingsPanePluginStoreViewModel.cs

Lines changed: 71 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,31 @@ namespace Flow.Launcher.SettingPages.ViewModels;
1212

1313
public partial class SettingsPanePluginStoreViewModel : BaseModel
1414
{
15+
public class SortModeData : DropdownDataGeneric<PluginStoreSortMode> { }
16+
17+
public List<SortModeData> SortModes { get; } =
18+
DropdownDataGeneric<PluginStoreSortMode>.GetValues<SortModeData>("PluginStoreSortMode");
19+
20+
public SettingsPanePluginStoreViewModel()
21+
{
22+
UpdateEnumDropdownLocalizations();
23+
}
24+
25+
private PluginStoreSortMode _selectedSortMode = PluginStoreSortMode.Default;
26+
public PluginStoreSortMode SelectedSortMode
27+
{
28+
get => _selectedSortMode;
29+
set
30+
{
31+
if (_selectedSortMode != value)
32+
{
33+
_selectedSortMode = value;
34+
OnPropertyChanged();
35+
OnPropertyChanged(nameof(ExternalPlugins));
36+
}
37+
}
38+
}
39+
1540
private string filterText = string.Empty;
1641
public string FilterText
1742
{
@@ -82,13 +107,8 @@ public bool ShowExecutable
82107
}
83108
}
84109

85-
public IList<PluginStoreItemViewModel> ExternalPlugins => App.API.GetPluginManifest()
86-
.Select(p => new PluginStoreItemViewModel(p))
87-
.OrderByDescending(p => p.Category == PluginStoreItemViewModel.NewRelease)
88-
.ThenByDescending(p => p.Category == PluginStoreItemViewModel.RecentlyUpdated)
89-
.ThenByDescending(p => p.Category == PluginStoreItemViewModel.None)
90-
.ThenByDescending(p => p.Category == PluginStoreItemViewModel.Installed)
91-
.ToList();
110+
public IList<PluginStoreItemViewModel> ExternalPlugins => GetSortedPlugins(
111+
App.API.GetPluginManifest().Select(p => new PluginStoreItemViewModel(p)));
92112

93113
[RelayCommand]
94114
private async Task RefreshExternalPluginsAsync()
@@ -168,4 +188,48 @@ public bool SatisfiesFilter(PluginStoreItemViewModel plugin)
168188
App.API.FuzzySearch(FilterText, plugin.Name).IsSearchPrecisionScoreMet() ||
169189
App.API.FuzzySearch(FilterText, plugin.Description).IsSearchPrecisionScoreMet();
170190
}
191+
192+
private void UpdateEnumDropdownLocalizations()
193+
{
194+
DropdownDataGeneric<PluginStoreSortMode>.UpdateLabels(SortModes);
195+
}
196+
197+
private IList<PluginStoreItemViewModel> GetSortedPlugins(IEnumerable<PluginStoreItemViewModel> plugins)
198+
{
199+
return SelectedSortMode switch
200+
{
201+
PluginStoreSortMode.Name => plugins
202+
.OrderBy(p => p.LabelInstalled)
203+
.ThenBy(p => p.Name)
204+
.ToList(),
205+
206+
PluginStoreSortMode.ReleaseDate => plugins
207+
.OrderBy(p => p.LabelInstalled)
208+
.ThenByDescending(p => p.DateAdded.HasValue)
209+
.ThenByDescending(p => p.DateAdded)
210+
.ToList(),
211+
212+
PluginStoreSortMode.UpdatedDate => plugins
213+
.OrderBy(p => p.LabelInstalled)
214+
.ThenByDescending(p => p.UpdatedDate.HasValue)
215+
.ThenByDescending(p => p.UpdatedDate)
216+
.ToList(),
217+
218+
_ => plugins
219+
.OrderByDescending(p => p.DefaultCategory == PluginStoreItemViewModel.NewRelease)
220+
.ThenByDescending(p => p.DefaultCategory == PluginStoreItemViewModel.RecentlyUpdated)
221+
.ThenByDescending(p => p.DefaultCategory == PluginStoreItemViewModel.None)
222+
.ThenByDescending(p => p.DefaultCategory == PluginStoreItemViewModel.Installed)
223+
.ToList(),
224+
};
225+
}
226+
227+
}
228+
229+
public enum PluginStoreSortMode
230+
{
231+
Default,
232+
Name,
233+
ReleaseDate,
234+
UpdatedDate
171235
}

0 commit comments

Comments
 (0)