2022-08-09 00:35:38 +00:00
|
|
|
|
using System;
|
2014-01-04 12:26:13 +00:00
|
|
|
|
using System.Collections.Generic;
|
2015-10-31 18:06:57 +00:00
|
|
|
|
using System.Diagnostics;
|
2025-02-24 07:15:26 +00:00
|
|
|
|
using System.IO;
|
2014-01-04 12:26:13 +00:00
|
|
|
|
using System.Linq;
|
2021-01-02 09:58:30 +00:00
|
|
|
|
using System.Threading;
|
2016-11-30 01:07:48 +00:00
|
|
|
|
using System.Threading.Tasks;
|
2016-01-06 21:34:42 +00:00
|
|
|
|
using System.Windows.Controls;
|
2020-04-21 09:12:17 +00:00
|
|
|
|
using Flow.Launcher.Infrastructure.Logger;
|
2025-02-24 07:15:26 +00:00
|
|
|
|
using Flow.Launcher.Infrastructure.UserSettings;
|
2020-04-21 09:12:17 +00:00
|
|
|
|
using Flow.Launcher.Plugin.Program.Programs;
|
|
|
|
|
|
using Flow.Launcher.Plugin.Program.Views;
|
2022-10-20 08:36:58 +00:00
|
|
|
|
using Flow.Launcher.Plugin.Program.Views.Models;
|
2025-04-02 12:17:32 +00:00
|
|
|
|
using Flow.Launcher.Plugin.SharedCommands;
|
2021-05-27 11:28:17 +00:00
|
|
|
|
using Microsoft.Extensions.Caching.Memory;
|
2024-05-26 10:01:29 +00:00
|
|
|
|
using Path = System.IO.Path;
|
2020-04-21 09:12:17 +00:00
|
|
|
|
using Stopwatch = Flow.Launcher.Infrastructure.Stopwatch;
|
2014-01-04 12:26:13 +00:00
|
|
|
|
|
2020-04-21 09:12:17 +00:00
|
|
|
|
namespace Flow.Launcher.Plugin.Program
|
2014-01-04 12:26:13 +00:00
|
|
|
|
{
|
2025-04-01 06:21:29 +00:00
|
|
|
|
public class Main : ISettingProvider, IAsyncPlugin, IPluginI18n, IContextMenu, IAsyncReloadable, IDisposable
|
2014-01-04 12:26:13 +00:00
|
|
|
|
{
|
2025-04-01 06:21:29 +00:00
|
|
|
|
private const string Win32CacheName = "Win32";
|
|
|
|
|
|
private const string UwpCacheName = "UWP";
|
2016-04-22 22:03:32 +00:00
|
|
|
|
|
2025-04-01 06:21:29 +00:00
|
|
|
|
internal static List<Win32> _win32s { get; private set; }
|
|
|
|
|
|
internal static List<UWPApp> _uwps { get; private set; }
|
|
|
|
|
|
internal static Settings _settings { get; private set; }
|
2019-10-17 20:53:00 +00:00
|
|
|
|
|
2025-04-08 08:29:03 +00:00
|
|
|
|
internal static SemaphoreSlim _win32sLock = new(1, 1);
|
|
|
|
|
|
internal static SemaphoreSlim _uwpsLock = new(1, 1);
|
|
|
|
|
|
|
2021-11-06 06:10:29 +00:00
|
|
|
|
internal static PluginInitContext Context { get; private set; }
|
2016-04-21 00:53:21 +00:00
|
|
|
|
|
2021-05-24 02:21:39 +00:00
|
|
|
|
private static readonly List<Result> emptyResults = new();
|
|
|
|
|
|
|
2023-11-12 00:00:03 +00:00
|
|
|
|
private static readonly MemoryCacheOptions cacheOptions = new() { SizeLimit = 1560 };
|
2021-05-27 11:28:17 +00:00
|
|
|
|
private static MemoryCache cache = new(cacheOptions);
|
|
|
|
|
|
|
2024-05-26 10:01:29 +00:00
|
|
|
|
private static readonly string[] commonUninstallerNames =
|
|
|
|
|
|
{
|
|
|
|
|
|
"uninst.exe",
|
|
|
|
|
|
"unins000.exe",
|
|
|
|
|
|
"uninst000.exe",
|
|
|
|
|
|
"uninstall.exe"
|
|
|
|
|
|
};
|
2025-01-24 04:11:48 +00:00
|
|
|
|
private static readonly string[] commonUninstallerPrefixs =
|
|
|
|
|
|
{
|
2025-01-24 10:35:11 +00:00
|
|
|
|
"uninstall",//en
|
|
|
|
|
|
"卸载",//zh-cn
|
|
|
|
|
|
"卸載",//zh-tw
|
|
|
|
|
|
"видалити",//uk-UA
|
|
|
|
|
|
"удалить",//ru
|
|
|
|
|
|
"désinstaller",//fr
|
|
|
|
|
|
"アンインストール",//ja
|
|
|
|
|
|
"deïnstalleren",//nl
|
|
|
|
|
|
"odinstaluj",//pl
|
|
|
|
|
|
"afinstallere",//da
|
|
|
|
|
|
"deinstallieren",//de
|
|
|
|
|
|
"삭제",//ko
|
|
|
|
|
|
"деинсталирај",//sr
|
|
|
|
|
|
"desinstalar",//pt-pt
|
|
|
|
|
|
"desinstalar",//pt-br
|
|
|
|
|
|
"desinstalar",//es
|
|
|
|
|
|
"desinstalar",//es-419
|
|
|
|
|
|
"disinstallare",//it
|
|
|
|
|
|
"avinstallere",//nb-NO
|
|
|
|
|
|
"odinštalovať",//sk
|
|
|
|
|
|
"kaldır",//tr
|
|
|
|
|
|
"odinstalovat",//cs
|
|
|
|
|
|
"إلغاء التثبيت",//ar
|
|
|
|
|
|
"gỡ bỏ",//vi-vn
|
|
|
|
|
|
"הסרה"//he
|
2025-01-24 04:11:48 +00:00
|
|
|
|
};
|
|
|
|
|
|
private const string ExeUninstallerSuffix = ".exe";
|
|
|
|
|
|
private const string InkUninstallerSuffix = ".lnk";
|
2024-05-26 10:01:29 +00:00
|
|
|
|
|
2025-02-21 01:32:58 +00:00
|
|
|
|
private static readonly string WindowsAppPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles), "WindowsApps");
|
2025-02-20 06:59:16 +00:00
|
|
|
|
|
2021-01-02 09:58:30 +00:00
|
|
|
|
public async Task<List<Result>> QueryAsync(Query query, CancellationToken token)
|
2014-01-04 12:26:13 +00:00
|
|
|
|
{
|
2021-05-27 11:28:17 +00:00
|
|
|
|
var result = await cache.GetOrCreateAsync(query.Search, async entry =>
|
2022-02-06 23:34:50 +00:00
|
|
|
|
{
|
2025-04-08 08:29:03 +00:00
|
|
|
|
var resultList = await Task.Run(async () =>
|
2024-11-22 03:20:12 +00:00
|
|
|
|
{
|
2025-04-08 08:29:03 +00:00
|
|
|
|
await _win32sLock.WaitAsync(token);
|
|
|
|
|
|
await _uwpsLock.WaitAsync(token);
|
|
|
|
|
|
|
2024-11-22 03:20:12 +00:00
|
|
|
|
try
|
|
|
|
|
|
{
|
2025-02-20 06:59:16 +00:00
|
|
|
|
// Collect all UWP Windows app directories
|
2025-02-21 01:29:43 +00:00
|
|
|
|
var uwpsDirectories = _settings.HideDuplicatedWindowsApp ? _uwps
|
2025-02-20 06:59:16 +00:00
|
|
|
|
.Where(uwp => !string.IsNullOrEmpty(uwp.Location)) // Exclude invalid paths
|
|
|
|
|
|
.Where(uwp => uwp.Location.StartsWith(WindowsAppPath, StringComparison.OrdinalIgnoreCase)) // Keep system apps
|
|
|
|
|
|
.Select(uwp => uwp.Location.TrimEnd('\\')) // Remove trailing slash
|
|
|
|
|
|
.Distinct(StringComparer.OrdinalIgnoreCase)
|
|
|
|
|
|
.ToArray() : null;
|
|
|
|
|
|
|
2024-11-22 03:20:12 +00:00
|
|
|
|
return _win32s.Cast<IProgram>()
|
2025-04-08 09:20:57 +00:00
|
|
|
|
.Concat(_uwps)
|
|
|
|
|
|
.AsParallel()
|
|
|
|
|
|
.WithCancellation(token)
|
|
|
|
|
|
.Where(HideUninstallersFilter)
|
|
|
|
|
|
.Where(p => HideDuplicatedWindowsAppFilter(p, uwpsDirectories))
|
|
|
|
|
|
.Where(p => p.Enabled)
|
|
|
|
|
|
.Select(p => p.Result(query.Search, Context.API))
|
|
|
|
|
|
.Where(r => r?.Score > 0)
|
|
|
|
|
|
.ToList();
|
2024-11-22 03:20:12 +00:00
|
|
|
|
}
|
|
|
|
|
|
catch (OperationCanceledException)
|
|
|
|
|
|
{
|
2024-11-24 01:21:27 +00:00
|
|
|
|
Log.Debug("|Flow.Launcher.Plugin.Program.Main|Query operation cancelled");
|
2024-11-22 03:20:12 +00:00
|
|
|
|
return emptyResults;
|
|
|
|
|
|
}
|
2025-04-08 08:29:03 +00:00
|
|
|
|
finally
|
|
|
|
|
|
{
|
|
|
|
|
|
_uwpsLock.Release();
|
|
|
|
|
|
_win32sLock.Release();
|
|
|
|
|
|
}
|
2024-11-23 13:32:42 +00:00
|
|
|
|
}, token);
|
2022-02-06 23:34:50 +00:00
|
|
|
|
|
|
|
|
|
|
resultList = resultList.Any() ? resultList : emptyResults;
|
|
|
|
|
|
|
|
|
|
|
|
entry.SetSize(resultList.Count);
|
|
|
|
|
|
entry.SetSlidingExpiration(TimeSpan.FromHours(8));
|
|
|
|
|
|
|
|
|
|
|
|
return resultList;
|
|
|
|
|
|
});
|
2021-03-17 19:50:55 +00:00
|
|
|
|
|
|
|
|
|
|
return result;
|
2014-01-04 12:26:13 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
2024-05-26 10:01:29 +00:00
|
|
|
|
private bool HideUninstallersFilter(IProgram program)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (!_settings.HideUninstallers) return true;
|
|
|
|
|
|
if (program is not Win32 win32) return true;
|
2025-01-24 04:11:48 +00:00
|
|
|
|
|
|
|
|
|
|
// First check the executable path
|
2024-05-26 10:01:29 +00:00
|
|
|
|
var fileName = Path.GetFileName(win32.ExecutablePath);
|
2025-01-24 04:11:48 +00:00
|
|
|
|
// For cases when the uninstaller is named like "uninst.exe"
|
|
|
|
|
|
if (commonUninstallerNames.Contains(fileName, StringComparer.OrdinalIgnoreCase)) return false;
|
|
|
|
|
|
// For cases when the uninstaller is named like "Uninstall Program Name.exe"
|
|
|
|
|
|
foreach (var prefix in commonUninstallerPrefixs)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (fileName.StartsWith(prefix, StringComparison.OrdinalIgnoreCase) &&
|
|
|
|
|
|
fileName.EndsWith(ExeUninstallerSuffix, StringComparison.OrdinalIgnoreCase))
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-01-25 22:34:07 +00:00
|
|
|
|
// Second check the lnk path
|
2025-01-24 04:11:48 +00:00
|
|
|
|
if (!string.IsNullOrEmpty(win32.LnkResolvedPath))
|
|
|
|
|
|
{
|
|
|
|
|
|
var inkFileName = Path.GetFileName(win32.FullPath);
|
|
|
|
|
|
// For cases when the uninstaller is named like "Uninstall Program Name.ink"
|
|
|
|
|
|
foreach (var prefix in commonUninstallerPrefixs)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (inkFileName.StartsWith(prefix, StringComparison.OrdinalIgnoreCase) &&
|
|
|
|
|
|
inkFileName.EndsWith(InkUninstallerSuffix, StringComparison.OrdinalIgnoreCase))
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return true;
|
2024-05-26 10:01:29 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-02-21 01:29:43 +00:00
|
|
|
|
private static bool HideDuplicatedWindowsAppFilter(IProgram program, string[] uwpsDirectories)
|
2025-02-20 06:59:16 +00:00
|
|
|
|
{
|
|
|
|
|
|
if (uwpsDirectories == null || uwpsDirectories.Length == 0) return true;
|
|
|
|
|
|
if (program is UWPApp) return true;
|
|
|
|
|
|
|
|
|
|
|
|
var location = program.Location.TrimEnd('\\'); // Ensure trailing slash
|
|
|
|
|
|
if (string.IsNullOrEmpty(location))
|
|
|
|
|
|
return true; // Keep if location is invalid
|
|
|
|
|
|
|
|
|
|
|
|
if (!location.StartsWith(WindowsAppPath, StringComparison.OrdinalIgnoreCase))
|
|
|
|
|
|
return true; // Keep if not a Windows app
|
|
|
|
|
|
|
|
|
|
|
|
// Check if the any Win32 executable directory contains UWP Windows app location matches
|
|
|
|
|
|
return !uwpsDirectories.Any(uwpDirectory =>
|
|
|
|
|
|
location.StartsWith(uwpDirectory, StringComparison.OrdinalIgnoreCase));
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2021-01-02 09:58:30 +00:00
|
|
|
|
public async Task InitAsync(PluginInitContext context)
|
2014-01-04 12:26:13 +00:00
|
|
|
|
{
|
2021-11-06 18:58:28 +00:00
|
|
|
|
Context = context;
|
2021-01-02 09:58:30 +00:00
|
|
|
|
|
2021-05-13 11:29:21 +00:00
|
|
|
|
_settings = context.API.LoadSettingJsonStorage<Settings>();
|
2021-01-02 09:58:30 +00:00
|
|
|
|
|
2023-11-12 00:00:03 +00:00
|
|
|
|
await Stopwatch.NormalAsync("|Flow.Launcher.Plugin.Program.Main|Preload programs cost", async () =>
|
2021-03-08 08:16:54 +00:00
|
|
|
|
{
|
2025-04-01 06:21:29 +00:00
|
|
|
|
var pluginCachePath = Context.CurrentPluginMetadata.PluginCacheDirectoryPath;
|
2025-04-04 08:41:08 +00:00
|
|
|
|
FilesFolders.ValidateDirectory(pluginCachePath);
|
2025-02-24 07:15:26 +00:00
|
|
|
|
|
2025-02-24 08:11:49 +00:00
|
|
|
|
static void MoveFile(string sourcePath, string destinationPath)
|
2025-02-24 07:15:26 +00:00
|
|
|
|
{
|
|
|
|
|
|
if (!File.Exists(sourcePath))
|
|
|
|
|
|
{
|
2025-02-24 08:11:49 +00:00
|
|
|
|
return;
|
2025-02-24 07:15:26 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (File.Exists(destinationPath))
|
|
|
|
|
|
{
|
2025-02-24 08:11:49 +00:00
|
|
|
|
try
|
|
|
|
|
|
{
|
|
|
|
|
|
File.Delete(sourcePath);
|
|
|
|
|
|
}
|
|
|
|
|
|
catch (Exception)
|
|
|
|
|
|
{
|
|
|
|
|
|
// Ignore, we will handle next time we start the plugin
|
|
|
|
|
|
}
|
|
|
|
|
|
return;
|
2025-02-24 07:15:26 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
var destinationDirectory = Path.GetDirectoryName(destinationPath);
|
|
|
|
|
|
if (!Directory.Exists(destinationDirectory) && (!string.IsNullOrEmpty(destinationDirectory)))
|
|
|
|
|
|
{
|
2025-02-24 08:11:49 +00:00
|
|
|
|
try
|
|
|
|
|
|
{
|
|
|
|
|
|
Directory.CreateDirectory(destinationDirectory);
|
|
|
|
|
|
}
|
|
|
|
|
|
catch (Exception)
|
|
|
|
|
|
{
|
|
|
|
|
|
// Ignore, we will handle next time we start the plugin
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
try
|
|
|
|
|
|
{
|
|
|
|
|
|
File.Move(sourcePath, destinationPath);
|
|
|
|
|
|
}
|
|
|
|
|
|
catch (Exception)
|
|
|
|
|
|
{
|
|
|
|
|
|
// Ignore, we will handle next time we start the plugin
|
2025-02-24 07:15:26 +00:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Move old cache files to the new cache directory
|
2025-04-01 06:21:29 +00:00
|
|
|
|
var oldWin32CacheFile = Path.Combine(DataLocation.CacheDirectory, $"{Win32CacheName}.cache");
|
|
|
|
|
|
var newWin32CacheFile = Path.Combine(pluginCachePath, $"{Win32CacheName}.cache");
|
2025-02-24 07:15:26 +00:00
|
|
|
|
MoveFile(oldWin32CacheFile, newWin32CacheFile);
|
2025-04-01 06:21:29 +00:00
|
|
|
|
var oldUWPCacheFile = Path.Combine(DataLocation.CacheDirectory, $"{UwpCacheName}.cache");
|
|
|
|
|
|
var newUWPCacheFile = Path.Combine(pluginCachePath, $"{UwpCacheName}.cache");
|
2025-02-24 07:15:26 +00:00
|
|
|
|
MoveFile(oldUWPCacheFile, newUWPCacheFile);
|
|
|
|
|
|
|
2025-04-08 08:29:03 +00:00
|
|
|
|
await _win32sLock.WaitAsync();
|
2025-04-01 06:21:29 +00:00
|
|
|
|
_win32s = await context.API.LoadCacheBinaryStorageAsync(Win32CacheName, pluginCachePath, new List<Win32>());
|
2025-04-08 08:29:03 +00:00
|
|
|
|
_win32sLock.Release();
|
|
|
|
|
|
|
|
|
|
|
|
await _uwpsLock.WaitAsync();
|
2025-04-01 06:21:29 +00:00
|
|
|
|
_uwps = await context.API.LoadCacheBinaryStorageAsync(UwpCacheName, pluginCachePath, new List<UWPApp>());
|
2025-04-08 08:29:03 +00:00
|
|
|
|
_uwpsLock.Release();
|
2021-01-02 09:58:30 +00:00
|
|
|
|
});
|
2025-04-08 08:29:03 +00:00
|
|
|
|
await _win32sLock.WaitAsync();
|
|
|
|
|
|
await _uwpsLock.WaitAsync();
|
|
|
|
|
|
|
2025-04-01 06:21:29 +00:00
|
|
|
|
Log.Info($"|Flow.Launcher.Plugin.Program.Main|Number of preload win32 programs <{_win32s.Count}>");
|
|
|
|
|
|
Log.Info($"|Flow.Launcher.Plugin.Program.Main|Number of preload uwps <{_uwps.Count}>");
|
2021-03-08 08:16:54 +00:00
|
|
|
|
|
2024-03-31 12:07:18 +00:00
|
|
|
|
bool cacheEmpty = !_win32s.Any() || !_uwps.Any();
|
2021-01-02 09:58:30 +00:00
|
|
|
|
|
2025-04-08 08:29:03 +00:00
|
|
|
|
_win32sLock.Release();
|
|
|
|
|
|
_uwpsLock.Release();
|
|
|
|
|
|
|
2023-04-24 13:22:18 +00:00
|
|
|
|
if (cacheEmpty || _settings.LastIndexTime.AddHours(30) < DateTime.Now)
|
2021-01-02 09:58:30 +00:00
|
|
|
|
{
|
2023-04-24 13:22:18 +00:00
|
|
|
|
_ = Task.Run(async () =>
|
|
|
|
|
|
{
|
|
|
|
|
|
await IndexProgramsAsync().ConfigureAwait(false);
|
|
|
|
|
|
WatchProgramUpdate();
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
2021-01-02 09:58:30 +00:00
|
|
|
|
{
|
2023-04-24 13:22:18 +00:00
|
|
|
|
WatchProgramUpdate();
|
|
|
|
|
|
}
|
2021-05-24 02:21:39 +00:00
|
|
|
|
|
2023-04-24 13:22:18 +00:00
|
|
|
|
static void WatchProgramUpdate()
|
|
|
|
|
|
{
|
|
|
|
|
|
Win32.WatchProgramUpdate(_settings);
|
2023-11-12 00:00:03 +00:00
|
|
|
|
_ = UWPPackage.WatchPackageChange();
|
2023-04-24 13:22:18 +00:00
|
|
|
|
}
|
2014-08-10 14:22:54 +00:00
|
|
|
|
}
|
2014-03-20 19:53:18 +00:00
|
|
|
|
|
2025-04-01 06:21:29 +00:00
|
|
|
|
public static async Task IndexWin32ProgramsAsync()
|
2014-08-10 14:22:54 +00:00
|
|
|
|
{
|
2019-11-16 00:37:01 +00:00
|
|
|
|
var win32S = Win32.All(_settings);
|
2025-04-08 08:29:03 +00:00
|
|
|
|
await _win32sLock.WaitAsync();
|
2025-04-01 06:21:29 +00:00
|
|
|
|
_win32s.Clear();
|
|
|
|
|
|
foreach (var win32 in win32S)
|
|
|
|
|
|
{
|
|
|
|
|
|
_win32s.Add(win32);
|
|
|
|
|
|
}
|
2022-02-21 21:54:46 +00:00
|
|
|
|
ResetCache();
|
2025-04-01 06:21:29 +00:00
|
|
|
|
await Context.API.SaveCacheBinaryStorageAsync<List<Win32>>(Win32CacheName, Context.CurrentPluginMetadata.PluginCacheDirectoryPath);
|
2023-04-24 11:50:34 +00:00
|
|
|
|
_settings.LastIndexTime = DateTime.Now;
|
2025-04-08 09:20:57 +00:00
|
|
|
|
_win32sLock.Release();
|
2019-09-04 22:05:17 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-04-01 06:21:29 +00:00
|
|
|
|
public static async Task IndexUwpProgramsAsync()
|
2019-09-04 22:05:17 +00:00
|
|
|
|
{
|
2025-04-01 06:21:29 +00:00
|
|
|
|
var uwps = UWPPackage.All(_settings);
|
2025-04-08 08:29:03 +00:00
|
|
|
|
await _uwpsLock.WaitAsync();
|
2025-04-01 06:21:29 +00:00
|
|
|
|
_uwps.Clear();
|
|
|
|
|
|
foreach (var uwp in uwps)
|
|
|
|
|
|
{
|
|
|
|
|
|
_uwps.Add(uwp);
|
|
|
|
|
|
}
|
2022-02-21 21:54:46 +00:00
|
|
|
|
ResetCache();
|
2025-04-01 06:21:29 +00:00
|
|
|
|
await Context.API.SaveCacheBinaryStorageAsync<List<UWPApp>>(UwpCacheName, Context.CurrentPluginMetadata.PluginCacheDirectoryPath);
|
2023-04-24 11:50:34 +00:00
|
|
|
|
_settings.LastIndexTime = DateTime.Now;
|
2025-04-08 09:20:57 +00:00
|
|
|
|
_uwpsLock.Release();
|
2014-08-10 14:22:54 +00:00
|
|
|
|
}
|
2014-03-22 05:50:20 +00:00
|
|
|
|
|
2022-08-09 00:35:38 +00:00
|
|
|
|
public static async Task IndexProgramsAsync()
|
2019-09-04 22:05:17 +00:00
|
|
|
|
{
|
2025-04-01 06:21:29 +00:00
|
|
|
|
var win32Task = Task.Run(async () =>
|
2022-10-29 18:37:22 +00:00
|
|
|
|
{
|
2025-04-01 06:21:29 +00:00
|
|
|
|
await Stopwatch.NormalAsync("|Flow.Launcher.Plugin.Program.Main|Win32Program index cost", IndexWin32ProgramsAsync);
|
2022-10-29 18:37:22 +00:00
|
|
|
|
});
|
|
|
|
|
|
|
2025-04-01 06:21:29 +00:00
|
|
|
|
var uwpTask = Task.Run(async () =>
|
2022-10-29 18:37:22 +00:00
|
|
|
|
{
|
2025-04-01 06:21:29 +00:00
|
|
|
|
await Stopwatch.NormalAsync("|Flow.Launcher.Plugin.Program.Main|UWPProgram index cost", IndexUwpProgramsAsync);
|
2022-10-29 18:37:22 +00:00
|
|
|
|
});
|
2025-04-01 06:21:29 +00:00
|
|
|
|
|
|
|
|
|
|
await Task.WhenAll(win32Task, uwpTask).ConfigureAwait(false);
|
2021-11-30 00:31:48 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
internal static void ResetCache()
|
|
|
|
|
|
{
|
2021-05-27 11:28:17 +00:00
|
|
|
|
var oldCache = cache;
|
|
|
|
|
|
cache = new MemoryCache(cacheOptions);
|
|
|
|
|
|
oldCache.Dispose();
|
2019-11-28 23:38:50 +00:00
|
|
|
|
}
|
2019-09-07 05:58:13 +00:00
|
|
|
|
|
2016-01-06 21:34:42 +00:00
|
|
|
|
public Control CreateSettingPanel()
|
2014-03-29 07:52:57 +00:00
|
|
|
|
{
|
2025-04-01 06:21:29 +00:00
|
|
|
|
return new ProgramSetting(Context, _settings);
|
2014-03-29 07:52:57 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
2015-02-07 12:17:49 +00:00
|
|
|
|
public string GetTranslatedPluginTitle()
|
|
|
|
|
|
{
|
2021-11-06 18:58:28 +00:00
|
|
|
|
return Context.API.GetTranslation("flowlauncher_plugin_program_plugin_name");
|
2015-02-07 12:17:49 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public string GetTranslatedPluginDescription()
|
|
|
|
|
|
{
|
2021-11-06 18:58:28 +00:00
|
|
|
|
return Context.API.GetTranslation("flowlauncher_plugin_program_plugin_description");
|
2015-02-07 12:17:49 +00:00
|
|
|
|
}
|
2015-02-07 15:49:46 +00:00
|
|
|
|
|
|
|
|
|
|
public List<Result> LoadContextMenus(Result selectedResult)
|
|
|
|
|
|
{
|
2019-10-17 11:47:00 +00:00
|
|
|
|
var menuOptions = new List<Result>();
|
2016-08-22 01:21:22 +00:00
|
|
|
|
var program = selectedResult.ContextData as IProgram;
|
|
|
|
|
|
if (program != null)
|
2015-02-07 15:49:46 +00:00
|
|
|
|
{
|
2021-11-06 18:58:28 +00:00
|
|
|
|
menuOptions = program.ContextMenus(Context.API);
|
2016-08-18 00:16:40 +00:00
|
|
|
|
}
|
2019-10-17 11:47:00 +00:00
|
|
|
|
|
|
|
|
|
|
menuOptions.Add(
|
2021-01-02 09:58:30 +00:00
|
|
|
|
new Result
|
|
|
|
|
|
{
|
2021-11-06 18:58:28 +00:00
|
|
|
|
Title = Context.API.GetTranslation("flowlauncher_plugin_program_disable_program"),
|
2021-01-02 09:58:30 +00:00
|
|
|
|
Action = c =>
|
|
|
|
|
|
{
|
2025-04-08 08:59:27 +00:00
|
|
|
|
_ = DisableProgramAsync(program);
|
2021-11-06 18:58:28 +00:00
|
|
|
|
Context.API.ShowMsg(
|
|
|
|
|
|
Context.API.GetTranslation("flowlauncher_plugin_program_disable_dlgtitle_success"),
|
|
|
|
|
|
Context.API.GetTranslation(
|
2021-01-02 09:58:30 +00:00
|
|
|
|
"flowlauncher_plugin_program_disable_dlgtitle_success_message"));
|
2025-01-26 12:07:40 +00:00
|
|
|
|
Context.API.ReQuery();
|
2021-01-02 09:58:30 +00:00
|
|
|
|
return false;
|
|
|
|
|
|
},
|
2021-10-07 10:58:54 +00:00
|
|
|
|
IcoPath = "Images/disable.png",
|
|
|
|
|
|
Glyph = new GlyphInfo(FontFamily: "/Resources/#Segoe Fluent Icons", Glyph: "\xece4"),
|
2021-01-02 09:58:30 +00:00
|
|
|
|
}
|
|
|
|
|
|
);
|
2019-10-17 11:47:00 +00:00
|
|
|
|
|
|
|
|
|
|
return menuOptions;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-04-08 08:59:27 +00:00
|
|
|
|
private static async Task DisableProgramAsync(IProgram programToDelete)
|
2019-10-17 11:47:00 +00:00
|
|
|
|
{
|
2019-10-23 22:23:57 +00:00
|
|
|
|
if (_settings.DisabledProgramSources.Any(x => x.UniqueIdentifier == programToDelete.UniqueIdentifier))
|
|
|
|
|
|
return;
|
2019-10-17 11:47:00 +00:00
|
|
|
|
|
2025-04-08 08:29:03 +00:00
|
|
|
|
await _uwpsLock.WaitAsync();
|
2019-10-23 22:23:57 +00:00
|
|
|
|
if (_uwps.Any(x => x.UniqueIdentifier == programToDelete.UniqueIdentifier))
|
2022-10-18 13:30:55 +00:00
|
|
|
|
{
|
2022-10-28 10:06:44 +00:00
|
|
|
|
var program = _uwps.First(x => x.UniqueIdentifier == programToDelete.UniqueIdentifier);
|
|
|
|
|
|
program.Enabled = false;
|
|
|
|
|
|
_settings.DisabledProgramSources.Add(new ProgramSource(program));
|
2025-04-08 08:29:03 +00:00
|
|
|
|
_uwpsLock.Release();
|
|
|
|
|
|
|
|
|
|
|
|
// Reindex UWP programs
|
2022-10-28 08:44:44 +00:00
|
|
|
|
_ = Task.Run(() =>
|
2022-10-25 06:41:46 +00:00
|
|
|
|
{
|
2025-04-01 06:21:29 +00:00
|
|
|
|
_ = IndexUwpProgramsAsync();
|
2022-10-25 06:41:46 +00:00
|
|
|
|
});
|
2025-04-08 08:29:03 +00:00
|
|
|
|
return;
|
2022-10-18 13:30:55 +00:00
|
|
|
|
}
|
2025-04-08 08:59:27 +00:00
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
_uwpsLock.Release();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-04-08 08:29:03 +00:00
|
|
|
|
await _win32sLock.WaitAsync();
|
|
|
|
|
|
if (_win32s.Any(x => x.UniqueIdentifier == programToDelete.UniqueIdentifier))
|
2022-10-18 13:30:55 +00:00
|
|
|
|
{
|
2022-10-28 10:06:44 +00:00
|
|
|
|
var program = _win32s.First(x => x.UniqueIdentifier == programToDelete.UniqueIdentifier);
|
|
|
|
|
|
program.Enabled = false;
|
|
|
|
|
|
_settings.DisabledProgramSources.Add(new ProgramSource(program));
|
2025-04-08 08:29:03 +00:00
|
|
|
|
_win32sLock.Release();
|
|
|
|
|
|
|
|
|
|
|
|
// Reindex Win32 programs
|
2022-10-28 08:44:44 +00:00
|
|
|
|
_ = Task.Run(() =>
|
2022-10-25 06:41:46 +00:00
|
|
|
|
{
|
2025-04-01 06:21:29 +00:00
|
|
|
|
_ = IndexWin32ProgramsAsync();
|
2022-10-25 06:41:46 +00:00
|
|
|
|
});
|
2022-10-18 13:30:55 +00:00
|
|
|
|
}
|
2025-04-08 08:59:27 +00:00
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
_win32sLock.Release();
|
|
|
|
|
|
}
|
2015-02-07 15:49:46 +00:00
|
|
|
|
}
|
2016-03-27 01:49:05 +00:00
|
|
|
|
|
2019-12-16 10:01:45 +00:00
|
|
|
|
public static void StartProcess(Func<ProcessStartInfo, Process> runProcess, ProcessStartInfo info)
|
2016-03-27 01:49:05 +00:00
|
|
|
|
{
|
|
|
|
|
|
try
|
|
|
|
|
|
{
|
2019-12-10 11:01:12 +00:00
|
|
|
|
runProcess(info);
|
2016-03-27 01:49:05 +00:00
|
|
|
|
}
|
2016-08-22 01:21:22 +00:00
|
|
|
|
catch (Exception)
|
2016-03-27 01:49:05 +00:00
|
|
|
|
{
|
2022-11-29 10:13:55 +00:00
|
|
|
|
var title = Context.API.GetTranslation("flowlauncher_plugin_program_disable_dlgtitle_error");
|
2023-11-12 00:00:03 +00:00
|
|
|
|
var message = string.Format(Context.API.GetTranslation("flowlauncher_plugin_program_run_failed"),
|
|
|
|
|
|
info.FileName);
|
2022-11-29 10:13:55 +00:00
|
|
|
|
Context.API.ShowMsg(title, string.Format(message, info.FileName), string.Empty);
|
2016-03-27 01:49:05 +00:00
|
|
|
|
}
|
|
|
|
|
|
}
|
2019-10-06 02:15:06 +00:00
|
|
|
|
|
2021-01-02 09:58:30 +00:00
|
|
|
|
public async Task ReloadDataAsync()
|
2019-10-06 02:15:06 +00:00
|
|
|
|
{
|
2022-08-09 00:35:38 +00:00
|
|
|
|
await IndexProgramsAsync();
|
2019-10-06 02:15:06 +00:00
|
|
|
|
}
|
2022-10-21 10:39:03 +00:00
|
|
|
|
|
2022-01-08 21:50:27 +00:00
|
|
|
|
public void Dispose()
|
|
|
|
|
|
{
|
|
|
|
|
|
Win32.Dispose();
|
|
|
|
|
|
}
|
2014-01-04 12:26:13 +00:00
|
|
|
|
}
|
2022-08-09 00:35:38 +00:00
|
|
|
|
}
|