Merge branch 'dev' into administrator_mode

This commit is contained in:
Jack Ye 2025-11-08 11:32:58 +08:00 committed by GitHub
commit 2c8df64559
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 98 additions and 30 deletions

View file

@ -54,28 +54,28 @@ jobs:
shell: powershell
run: .\Scripts\post_build.ps1
- name: Upload Plugin Nupkg
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v5
with:
name: Plugin nupkg
path: |
Output\Release\Flow.Launcher.Plugin.*.nupkg
compression-level: 0
- name: Upload Setup
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v5
with:
name: Flow Installer
path: |
Output\Packages\Flow-Launcher-*.exe
compression-level: 0
- name: Upload Portable Version
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v5
with:
name: Portable Version
path: |
Output\Packages\Flow-Launcher-Portable.zip
compression-level: 0
- name: Upload Full Nupkg
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v5
with:
name: Full nupkg
path: |
@ -83,7 +83,7 @@ jobs:
compression-level: 0
- name: Upload Release Information
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v5
with:
name: RELEASES
path: |

View file

@ -26,9 +26,11 @@ namespace Flow.Launcher.Core.ExternalPlugins
public static async Task<bool> UpdateManifestAsync(bool usePrimaryUrlOnly = false, CancellationToken token = default)
{
bool lockAcquired = false;
try
{
await manifestUpdateLock.WaitAsync(token).ConfigureAwait(false);
lockAcquired = true;
if (UserPlugins == null || usePrimaryUrlOnly || DateTime.Now.Subtract(lastFetchedAt) >= fetchTimeout)
{
@ -54,13 +56,18 @@ namespace Flow.Launcher.Core.ExternalPlugins
return true;
}
}
catch (OperationCanceledException)
{
// Ignored
}
catch (Exception e)
{
PublicApi.Instance.LogException(ClassName, "Http request failed", e);
}
finally
{
manifestUpdateLock.Release();
// Only release the lock if it was acquired
if (lockAcquired) manifestUpdateLock.Release();
}
return false;

View file

@ -454,7 +454,7 @@
<system:String x:Key="icons">Icons</system:String>
<system:String x:Key="about_activate_times">You have activated Flow Launcher {0} times</system:String>
<system:String x:Key="checkUpdates">Check for Updates</system:String>
<system:String x:Key="BecomeASponsor">Become A Sponsor</system:String>
<system:String x:Key="BecomeASponsor">Become a Sponsor</system:String>
<system:String x:Key="newVersionTips">New version {0} is available, would you like to restart Flow Launcher to use the update?</system:String>
<system:String x:Key="checkUpdatesFailed">Check updates failed, please check your connection and proxy settings to api.github.com.</system:String>
<system:String x:Key="downloadUpdatesFailed">

View file

@ -48,11 +48,18 @@ namespace Flow.Launcher.Plugin.Explorer.Search.Everything
public static async ValueTask<bool> IsEverythingRunningAsync(CancellationToken token = default)
{
await _semaphore.WaitAsync(token);
try
{
await _semaphore.WaitAsync(token);
}
catch (OperationCanceledException)
{
return false;
}
try
{
EverythingApiDllImport.Everything_GetMajorVersion();
_ = EverythingApiDllImport.Everything_GetMajorVersion();
var result = EverythingApiDllImport.Everything_GetLastError() != StateCode.IPCError;
return result;
}
@ -77,8 +84,14 @@ namespace Flow.Launcher.Plugin.Explorer.Search.Everything
if (option.MaxCount < 0)
throw new ArgumentOutOfRangeException(nameof(option.MaxCount), option.MaxCount, "MaxCount must be greater than or equal to 0");
await _semaphore.WaitAsync(token);
try
{
await _semaphore.WaitAsync(token);
}
catch (OperationCanceledException)
{
yield break;
}
try
{
@ -120,8 +133,6 @@ namespace Flow.Launcher.Plugin.Explorer.Search.Everything
EverythingApiDllImport.Everything_SetRequestFlags(EVERYTHING_REQUEST_FULL_PATH_AND_FILE_NAME);
}
if (token.IsCancellationRequested) yield break;
if (!EverythingApiDllImport.Everything_QueryW(true))

View file

@ -57,19 +57,16 @@ namespace Flow.Launcher.Plugin.Explorer.Search
{
if (string.IsNullOrEmpty(query.Search) && ActionKeywordMatch(query, Settings.ActionKeyword.QuickAccessActionKeyword))
return QuickAccess.AccessLinkListAll(query, Settings.QuickAccessLinks);
var quickAccessLinks = QuickAccess.AccessLinkListMatched(query, Settings.QuickAccessLinks);
results.UnionWith(quickAccessLinks);
}
else
{
// No action keyword matched- plugin should not handle this query, return empty results.
return new List<Result>();
}
IAsyncEnumerable<SearchResult> searchResults;
bool isPathSearch = query.Search.IsLocationPathString()
bool isPathSearch = query.Search.IsLocationPathString()
|| EnvironmentVariables.IsEnvironmentVariableSearch(query.Search)
|| EnvironmentVariables.HasEnvironmentVar(query.Search);
@ -103,10 +100,18 @@ namespace Flow.Launcher.Plugin.Explorer.Search
searchResults = Settings.IndexProvider.SearchAsync(query.Search, token);
engineName = Enum.GetName(Settings.IndexSearchEngine);
break;
case true or false
when ActionKeywordMatch(query, Settings.ActionKeyword.QuickAccessActionKeyword):
return QuickAccess.AccessLinkListMatched(query, Settings.QuickAccessLinks);
default:
return results.ToList();
}
// Merge Quick Access Link results for non-path searches.
results.UnionWith(QuickAccess.AccessLinkListMatched(query, Settings.QuickAccessLinks));
try
{
await foreach (var search in searchResults.WithCancellation(token).ConfigureAwait(false))

View file

@ -31,6 +31,8 @@ namespace Flow.Launcher.Plugin.Program
internal static PluginInitContext Context { get; private set; }
private static readonly Lock _lastIndexTimeLock = new();
private static readonly List<Result> emptyResults = [];
private static readonly MemoryCacheOptions cacheOptions = new() { SizeLimit = 1560 };
@ -82,8 +84,45 @@ namespace Flow.Launcher.Plugin.Program
{
var resultList = await Task.Run(async () =>
{
await _win32sLock.WaitAsync(token);
await _uwpsLock.WaitAsync(token);
// Preparing win32 programs
List<Win32> win32s;
bool win32LockAcquired = false;
try
{
await _win32sLock.WaitAsync(token);
win32LockAcquired = true;
win32s = [.. _win32s];
}
catch (OperationCanceledException)
{
return emptyResults;
}
finally
{
// Only release the lock if it was acquired
if (win32LockAcquired) _win32sLock.Release();
}
// Preparing UWP programs
List<UWPApp> uwps;
bool uwpsLockAcquired = false;
try
{
await _uwpsLock.WaitAsync(token);
uwpsLockAcquired = true;
uwps = [.. _uwps];
}
catch (OperationCanceledException)
{
return emptyResults;
}
finally
{
// Only release the lock if it was acquired
if (uwpsLockAcquired) _uwpsLock.Release();
}
// Start querying programs
try
{
// Collect all UWP Windows app directories
@ -94,8 +133,8 @@ namespace Flow.Launcher.Plugin.Program
.Distinct(StringComparer.OrdinalIgnoreCase)
.ToArray() : null;
return _win32s.Cast<IProgram>()
.Concat(_uwps)
return win32s.Cast<IProgram>()
.Concat(uwps)
.AsParallel()
.WithCancellation(token)
.Where(HideUninstallersFilter)
@ -109,11 +148,6 @@ namespace Flow.Launcher.Plugin.Program
{
return emptyResults;
}
finally
{
_uwpsLock.Release();
_win32sLock.Release();
}
}, token);
resultList = resultList.Count != 0 ? resultList : emptyResults;
@ -275,7 +309,12 @@ namespace Flow.Launcher.Plugin.Program
var cacheEmpty = _win32sCount == 0 || _uwpsCount == 0;
if (cacheEmpty || _settings.LastIndexTime.AddHours(30) < DateTime.Now)
bool needReindex;
lock (_lastIndexTimeLock)
{
needReindex = _settings.LastIndexTime.AddHours(30) < DateTime.Now;
}
if (cacheEmpty || needReindex)
{
_ = Task.Run(async () =>
{
@ -308,7 +347,10 @@ namespace Flow.Launcher.Plugin.Program
}
ResetCache();
await Context.API.SaveCacheBinaryStorageAsync<List<Win32>>(Win32CacheName, Context.CurrentPluginMetadata.PluginCacheDirectoryPath);
_settings.LastIndexTime = DateTime.Now;
lock (_lastIndexTimeLock)
{
_settings.LastIndexTime = DateTime.Now;
}
}
catch (Exception e)
{
@ -333,7 +375,10 @@ namespace Flow.Launcher.Plugin.Program
}
ResetCache();
await Context.API.SaveCacheBinaryStorageAsync<List<UWPApp>>(UwpCacheName, Context.CurrentPluginMetadata.PluginCacheDirectoryPath);
_settings.LastIndexTime = DateTime.Now;
lock (_lastIndexTimeLock)
{
_settings.LastIndexTime = DateTime.Now;
}
}
catch (Exception e)
{