mirror of
https://github.com/Flow-Launcher/Flow.Launcher.git
synced 2026-03-11 08:54:32 +00:00
Merge branch 'dev' into FixPluginListFreezing
This commit is contained in:
commit
b1e1f71c10
10 changed files with 197 additions and 95 deletions
|
|
@ -89,7 +89,7 @@
|
|||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="InputSimulator" Version="1.0.4" />
|
||||
<PackageReference Include="Microsoft.Toolkit.Uwp.Notifications" Version="7.1.2" />
|
||||
<PackageReference Include="Microsoft.Toolkit.Uwp.Notifications" Version="7.1.3" />
|
||||
<PackageReference Include="ModernWpfUI" Version="0.9.4" />
|
||||
<PackageReference Include="NHotkey.Wpf" Version="2.1.0" />
|
||||
<PackageReference Include="NuGet.CommandLine" Version="5.7.2">
|
||||
|
|
|
|||
|
|
@ -92,6 +92,7 @@
|
|||
<system:String x:Key="plugin_query_time">Query time:</system:String>
|
||||
<system:String x:Key="plugin_query_version">| Version</system:String>
|
||||
<system:String x:Key="plugin_query_web">Website</system:String>
|
||||
<system:String x:Key="plugin_uninstall">Uninstall</system:String>
|
||||
|
||||
|
||||
<!-- Setting Plugin Store -->
|
||||
|
|
|
|||
|
|
@ -3,7 +3,6 @@
|
|||
<PropertyGroup>
|
||||
<OutputType>Library</OutputType>
|
||||
<TargetFramework>net6.0-windows</TargetFramework>
|
||||
<RuntimeIdentifier>win-x64</RuntimeIdentifier>
|
||||
<UseWPF>true</UseWPF>
|
||||
<ProjectGuid>{9B130CC5-14FB-41FF-B310-0A95B6894C37}</ProjectGuid>
|
||||
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||
|
|
@ -65,4 +64,19 @@
|
|||
<Compile Remove="Bookmark.cs" />
|
||||
</ItemGroup>
|
||||
|
||||
<Target Name="CopyDLLs" AfterTargets="Build">
|
||||
<Message Text="Executing CopyDLLs task" Importance="High" />
|
||||
<Copy
|
||||
SourceFiles="$(TargetDir)\runtimes\win-x64\native\SQLite.Interop.dll"
|
||||
DestinationFolder="$(TargetDir)\x64" />
|
||||
<Copy
|
||||
SourceFiles="$(TargetDir)\runtimes\win-x86\native\SQLite.Interop.dll"
|
||||
DestinationFolder="$(TargetDir)\x86" />
|
||||
</Target>
|
||||
|
||||
<Target Name="DeleteRuntimesFolder" AfterTargets="CopyDLLs">
|
||||
<Message Text="Deleting runtimes folder" Importance="High" />
|
||||
<RemoveDir Directories="$(TargetDir)\runtimes" />
|
||||
</Target>
|
||||
|
||||
</Project>
|
||||
|
|
@ -5,11 +5,12 @@
|
|||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
Title="{DynamicResource flowlauncher_plugin_program_directory}"
|
||||
Width="530"
|
||||
Width="Auto"
|
||||
Height="276"
|
||||
Background="{DynamicResource PopuBGColor}"
|
||||
Foreground="{DynamicResource PopupTextColor}"
|
||||
ResizeMode="NoResize"
|
||||
SizeToContent="Height"
|
||||
SizeToContent="Width"
|
||||
WindowStartupLocation="CenterScreen">
|
||||
<WindowChrome.WindowChrome>
|
||||
<WindowChrome CaptionHeight="32" ResizeBorderThickness="{x:Static SystemParameters.WindowResizeBorderThickness}" />
|
||||
|
|
@ -69,9 +70,9 @@
|
|||
TextAlignment="Left"
|
||||
TextWrapping="WrapWithOverflow" />
|
||||
</StackPanel>
|
||||
|
||||
<StackPanel Margin="0,10,0,0" Orientation="Horizontal">
|
||||
<Grid Width="470">
|
||||
|
||||
<StackPanel Margin="0,10,10,0" Orientation="Horizontal">
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition />
|
||||
<RowDefinition />
|
||||
|
|
@ -88,21 +89,22 @@
|
|||
VerticalAlignment="Center"
|
||||
FontSize="14"
|
||||
Text="{DynamicResource flowlauncher_plugin_program_directory}" />
|
||||
<DockPanel
|
||||
Grid.Row="0"
|
||||
Grid.Column="1"
|
||||
<DockPanel
|
||||
Grid.Row="0"
|
||||
Grid.Column="1"
|
||||
LastChildFill="True">
|
||||
<Button
|
||||
Width="70"
|
||||
HorizontalAlignment="Right"
|
||||
MinWidth="70"
|
||||
HorizontalAlignment="Stretch"
|
||||
Click="BrowseButton_Click"
|
||||
DockPanel.Dock="Right"
|
||||
Content="{DynamicResource flowlauncher_plugin_program_browse}" />
|
||||
Content="{DynamicResource flowlauncher_plugin_program_browse}"
|
||||
DockPanel.Dock="Right" />
|
||||
<TextBox
|
||||
Name="Directory"
|
||||
MinWidth="300"
|
||||
Margin="10"
|
||||
VerticalAlignment="Center"
|
||||
HorizontalAlignment="Stretch" />
|
||||
HorizontalAlignment="Stretch"
|
||||
VerticalAlignment="Center" />
|
||||
</DockPanel>
|
||||
<TextBlock
|
||||
Grid.Row="1"
|
||||
|
|
@ -112,7 +114,8 @@
|
|||
VerticalAlignment="Center"
|
||||
FontSize="14"
|
||||
Text="{DynamicResource flowlauncher_plugin_program_enabled}" />
|
||||
<CheckBox x:Name="Chkbox"
|
||||
<CheckBox
|
||||
x:Name="Chkbox"
|
||||
Grid.Row="1"
|
||||
Grid.Column="1"
|
||||
Margin="10,0"
|
||||
|
|
|
|||
|
|
@ -61,7 +61,7 @@
|
|||
Insert file suffixes you want to index. Suffixes should be separated by ';'. (ex>bat;py)
|
||||
</system:String>
|
||||
<system:String x:Key="flowlauncher_plugin_program_protocol_tooltip">
|
||||
Insert protocols of .url files you want to index. Protocols should be separated by ';'. (ex>ftp;netflix)
|
||||
Insert protocols of .url files you want to index. Protocols should be separated by ';', and should end with "://". (ex>ftp://;mailto://)
|
||||
</system:String>
|
||||
|
||||
<system:String x:Key="flowlauncher_plugin_program_run_as_different_user">Run As Different User</system:String>
|
||||
|
|
|
|||
|
|
@ -102,7 +102,7 @@ namespace Flow.Launcher.Plugin.Program
|
|||
await Task.WhenAll(a, b);
|
||||
|
||||
Win32.WatchProgramUpdate(_settings);
|
||||
UWP.WatchPackageChange();
|
||||
_ = UWP.WatchPackageChange();
|
||||
}
|
||||
|
||||
public static void IndexWin32Programs()
|
||||
|
|
|
|||
|
|
@ -277,7 +277,8 @@ namespace Flow.Launcher.Plugin.Program.Programs
|
|||
[Serializable]
|
||||
public class Application : IProgram
|
||||
{
|
||||
public string UniqueIdentifier { get; set; }
|
||||
private string _uid = string.Empty;
|
||||
public string UniqueIdentifier { get => _uid; set => _uid = value == null ? string.Empty : value.ToLowerInvariant(); }
|
||||
public string DisplayName { get; set; }
|
||||
public string Description { get; set; }
|
||||
public string UserModelId { get; set; }
|
||||
|
|
|
|||
|
|
@ -23,10 +23,21 @@ namespace Flow.Launcher.Plugin.Program.Programs
|
|||
public class Win32 : IProgram, IEquatable<Win32>
|
||||
{
|
||||
public string Name { get; set; }
|
||||
public string UniqueIdentifier { get => _uid; set => _uid = value.ToLowerInvariant(); } // For path comparison
|
||||
public string UniqueIdentifier { get => _uid; set => _uid = value == null ? string.Empty : value.ToLowerInvariant(); } // For path comparison
|
||||
public string IcoPath { get; set; }
|
||||
/// <summary>
|
||||
/// Path of the file. It's the path of .lnk or .url for .lnk and .url.
|
||||
/// </summary>
|
||||
public string FullPath { get; set; }
|
||||
/// <summary>
|
||||
/// Path of the excutable for .lnk, or the URL for .url.
|
||||
/// </summary>
|
||||
public string LnkResolvedPath { get; set; }
|
||||
/// <summary>
|
||||
/// Path of the actual executable file.
|
||||
/// </summary>
|
||||
public string ExecutablePath => LnkResolvedPath ?? FullPath;
|
||||
public string WorkingDir => Directory.GetParent(ExecutablePath)?.FullName ?? string.Empty;
|
||||
public string ParentDirectory { get; set; }
|
||||
public string ExecutableName { get; set; }
|
||||
public string Description { get; set; }
|
||||
|
|
@ -97,10 +108,23 @@ namespace Flow.Launcher.Plugin.Program.Programs
|
|||
matchResult.MatchData = new List<int>();
|
||||
}
|
||||
|
||||
string subtitle = string.Empty;
|
||||
if (!Main._settings.HideAppsPath)
|
||||
{
|
||||
if (Extension(FullPath) == UrlExtension)
|
||||
{
|
||||
subtitle = LnkResolvedPath;
|
||||
}
|
||||
else
|
||||
{
|
||||
subtitle = FullPath;
|
||||
}
|
||||
}
|
||||
|
||||
var result = new Result
|
||||
{
|
||||
Title = title,
|
||||
SubTitle = Main._settings.HideAppsPath ? string.Empty : LnkResolvedPath ?? FullPath,
|
||||
SubTitle = subtitle,
|
||||
IcoPath = IcoPath,
|
||||
Score = matchResult.Score,
|
||||
TitleHighlightData = matchResult.MatchData,
|
||||
|
|
@ -116,8 +140,8 @@ namespace Flow.Launcher.Plugin.Program.Programs
|
|||
|
||||
var info = new ProcessStartInfo
|
||||
{
|
||||
FileName = LnkResolvedPath ?? FullPath,
|
||||
WorkingDirectory = ParentDirectory,
|
||||
FileName = ExecutablePath,
|
||||
WorkingDirectory = WorkingDir,
|
||||
UseShellExecute = true,
|
||||
Verb = runAsAdmin ? "runas" : null
|
||||
};
|
||||
|
|
@ -143,8 +167,8 @@ namespace Flow.Launcher.Plugin.Program.Programs
|
|||
{
|
||||
var info = new ProcessStartInfo
|
||||
{
|
||||
FileName = FullPath,
|
||||
WorkingDirectory = ParentDirectory,
|
||||
FileName = ExecutablePath,
|
||||
WorkingDirectory = WorkingDir,
|
||||
UseShellExecute = true
|
||||
};
|
||||
|
||||
|
|
@ -162,8 +186,8 @@ namespace Flow.Launcher.Plugin.Program.Programs
|
|||
{
|
||||
var info = new ProcessStartInfo
|
||||
{
|
||||
FileName = FullPath,
|
||||
WorkingDirectory = ParentDirectory,
|
||||
FileName = ExecutablePath,
|
||||
WorkingDirectory = WorkingDir,
|
||||
Verb = "runas",
|
||||
UseShellExecute = true
|
||||
};
|
||||
|
|
@ -224,6 +248,15 @@ namespace Flow.Launcher.Plugin.Program.Programs
|
|||
|
||||
return Default;
|
||||
}
|
||||
#if !DEBUG
|
||||
catch (Exception e)
|
||||
{
|
||||
ProgramLogger.LogException($"|Win32|Win32Program|{path}" +
|
||||
"|An unexpected error occurred in the calling method Win32Program", e);
|
||||
|
||||
return Default;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
private static Win32 LnkProgram(string path)
|
||||
|
|
@ -241,8 +274,7 @@ namespace Flow.Launcher.Plugin.Program.Programs
|
|||
var extension = Extension(target);
|
||||
if (extension == ExeExtension && File.Exists(target))
|
||||
{
|
||||
program.LnkResolvedPath = program.FullPath;
|
||||
program.FullPath = Path.GetFullPath(target).ToLowerInvariant();
|
||||
program.LnkResolvedPath = Path.GetFullPath(target);
|
||||
program.ExecutableName = Path.GetFileName(target);
|
||||
|
||||
var description = _helper.description;
|
||||
|
|
@ -270,16 +302,14 @@ namespace Flow.Launcher.Plugin.Program.Programs
|
|||
"|Error caused likely due to trying to get the description of the program",
|
||||
e);
|
||||
|
||||
program.Valid = false;
|
||||
return program;
|
||||
return Default;
|
||||
}
|
||||
catch (FileNotFoundException e)
|
||||
{
|
||||
ProgramLogger.LogException($"|Win32|LnkProgram|{path}" +
|
||||
"|An unexpected error occurred in the calling method LnkProgram", e);
|
||||
|
||||
program.Valid = false;
|
||||
return program;
|
||||
return Default;
|
||||
}
|
||||
#if !DEBUG //Only do a catch all in production. This is so make developer aware of any unhandled exception and add the exception handling in.
|
||||
catch (Exception e)
|
||||
|
|
@ -287,8 +317,7 @@ namespace Flow.Launcher.Plugin.Program.Programs
|
|||
ProgramLogger.LogException($"|Win32|LnkProgram|{path}" +
|
||||
"|An unexpected error occurred in the calling method LnkProgram", e);
|
||||
|
||||
program.Valid = false;
|
||||
return program;
|
||||
return Default;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
|
@ -342,6 +371,13 @@ namespace Flow.Launcher.Plugin.Program.Programs
|
|||
program.Description = info.FileDescription;
|
||||
return program;
|
||||
}
|
||||
catch (FileNotFoundException e)
|
||||
{
|
||||
ProgramLogger.LogException($"|Win32|ExeProgram|{path}" +
|
||||
$"|File not found when trying to load the program from {path}", e);
|
||||
|
||||
return Default;
|
||||
}
|
||||
catch (Exception e) when (e is SecurityException || e is UnauthorizedAccessException)
|
||||
{
|
||||
ProgramLogger.LogException($"|Win32|ExeProgram|{path}" +
|
||||
|
|
@ -351,7 +387,7 @@ namespace Flow.Launcher.Plugin.Program.Programs
|
|||
}
|
||||
}
|
||||
|
||||
private static IEnumerable<string> ProgramPaths(string directory, string[] suffixes, bool recursive = true)
|
||||
private static IEnumerable<string> EnumerateProgramsInDir(string directory, string[] suffixes, bool recursive = true)
|
||||
{
|
||||
if (!Directory.Exists(directory))
|
||||
return Enumerable.Empty<string>();
|
||||
|
|
@ -376,15 +412,14 @@ namespace Flow.Launcher.Plugin.Program.Programs
|
|||
}
|
||||
}
|
||||
|
||||
private static IEnumerable<Win32> UnregisteredPrograms(List<ProgramSource> sources, string[] suffixes, string[] protocols)
|
||||
private static IEnumerable<Win32> UnregisteredPrograms(List<string> directories, string[] suffixes, string[] protocols)
|
||||
{
|
||||
// Disabled custom sources are not in DisabledProgramSources
|
||||
var paths = ExceptDisabledSource(sources.Where(s => Directory.Exists(s.Location) && s.Enabled)
|
||||
.AsParallel()
|
||||
.SelectMany(s => ProgramPaths(s.Location, suffixes)))
|
||||
.Distinct();
|
||||
var paths = directories.AsParallel()
|
||||
.SelectMany(s => EnumerateProgramsInDir(s, suffixes));
|
||||
|
||||
var programs = paths.Select(x => GetProgramFromPath(x, protocols));
|
||||
// Remove disabled programs in DisabledProgramSources
|
||||
var programs = ExceptDisabledSource(paths).Select(x => GetProgramFromPath(x, protocols));
|
||||
return programs;
|
||||
}
|
||||
|
||||
|
|
@ -392,8 +427,8 @@ namespace Flow.Launcher.Plugin.Program.Programs
|
|||
{
|
||||
var directory1 = Environment.GetFolderPath(Environment.SpecialFolder.Programs);
|
||||
var directory2 = Environment.GetFolderPath(Environment.SpecialFolder.CommonPrograms);
|
||||
var paths1 = ProgramPaths(directory1, suffixes);
|
||||
var paths2 = ProgramPaths(directory2, suffixes);
|
||||
var paths1 = EnumerateProgramsInDir(directory1, suffixes);
|
||||
var paths2 = EnumerateProgramsInDir(directory2, suffixes);
|
||||
|
||||
var toFilter = paths1.Concat(paths2);
|
||||
|
||||
|
|
@ -402,26 +437,22 @@ namespace Flow.Launcher.Plugin.Program.Programs
|
|||
return programs;
|
||||
}
|
||||
|
||||
private static IEnumerable<Win32> PATHPrograms(string[] suffixes, string[] protocols)
|
||||
private static IEnumerable<Win32> PATHPrograms(string[] suffixes, string[] protocols, List<string> commonParents)
|
||||
{
|
||||
var pathEnv = Environment.GetEnvironmentVariable("Path");
|
||||
if (String.IsNullOrEmpty(pathEnv))
|
||||
{
|
||||
return Array.Empty<Win32>();
|
||||
if (String.IsNullOrEmpty(pathEnv))
|
||||
{
|
||||
return Array.Empty<Win32>();
|
||||
}
|
||||
|
||||
var paths = pathEnv.Split(";", StringSplitOptions.RemoveEmptyEntries).DistinctBy(p => p.ToLowerInvariant());
|
||||
|
||||
var toFilter = paths.AsParallel().SelectMany(p => ProgramPaths(p, suffixes, recursive: false));
|
||||
paths = paths.Where(x => commonParents.All(parent => !x.StartsWith(parent, StringComparison.OrdinalIgnoreCase)));
|
||||
|
||||
var toFilter = paths.AsParallel().SelectMany(p => EnumerateProgramsInDir(p, suffixes, recursive: false));
|
||||
|
||||
var programs = ExceptDisabledSource(toFilter.Distinct())
|
||||
.Select(x => Extension(x) switch
|
||||
{
|
||||
ShortcutExtension => LnkProgram(x),
|
||||
UrlExtension => UrlProgram(x, protocols),
|
||||
ExeExtension => ExeProgram(x),
|
||||
_ => Win32Program(x)
|
||||
});
|
||||
.Select(x => GetProgramFromPath(x, protocols));
|
||||
return programs;
|
||||
}
|
||||
|
||||
|
|
@ -496,9 +527,6 @@ namespace Flow.Launcher.Plugin.Program.Programs
|
|||
|
||||
path = Environment.ExpandEnvironmentVariables(path);
|
||||
|
||||
if (!File.Exists(path))
|
||||
return Default;
|
||||
|
||||
return Extension(path) switch
|
||||
{
|
||||
ShortcutExtension => LnkProgram(path),
|
||||
|
|
@ -545,7 +573,7 @@ namespace Flow.Launcher.Plugin.Program.Programs
|
|||
|
||||
private static IEnumerable<Win32> ProgramsHasher(IEnumerable<Win32> programs)
|
||||
{
|
||||
return programs.GroupBy(p => p.FullPath.ToLowerInvariant())
|
||||
return programs.GroupBy(p => p.ExecutablePath.ToLowerInvariant())
|
||||
.AsParallel()
|
||||
.SelectMany(g =>
|
||||
{
|
||||
|
|
@ -553,7 +581,7 @@ namespace Flow.Launcher.Plugin.Program.Programs
|
|||
if (temp.Any())
|
||||
return DistinctBy(temp, x => x.Description);
|
||||
return g.Take(1);
|
||||
}).ToArray();
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -565,11 +593,15 @@ namespace Flow.Launcher.Plugin.Program.Programs
|
|||
var suffixes = settings.GetSuffixes();
|
||||
var protocols = settings.GetProtocols();
|
||||
|
||||
var unregistered = UnregisteredPrograms(settings.ProgramSources, suffixes, protocols);
|
||||
// Disabled custom sources are not in DisabledProgramSources
|
||||
var sources = settings.ProgramSources.Where(s => Directory.Exists(s.Location) && s.Enabled).Distinct();
|
||||
var commonParents = GetCommonParents(sources);
|
||||
|
||||
var unregistered = UnregisteredPrograms(commonParents, suffixes, protocols);
|
||||
|
||||
programs = programs.Concat(unregistered);
|
||||
|
||||
var autoIndexPrograms = Enumerable.Empty<Win32>();
|
||||
var autoIndexPrograms = Enumerable.Empty<Win32>(); // for single programs, not folders
|
||||
|
||||
if (settings.EnableRegistrySource)
|
||||
{
|
||||
|
|
@ -585,11 +617,11 @@ namespace Flow.Launcher.Plugin.Program.Programs
|
|||
|
||||
if (settings.EnablePATHSource)
|
||||
{
|
||||
var path = PATHPrograms(settings.GetSuffixes(), protocols);
|
||||
autoIndexPrograms = autoIndexPrograms.Concat(path);
|
||||
var path = PATHPrograms(settings.GetSuffixes(), protocols, commonParents);
|
||||
programs = programs.Concat(path);
|
||||
}
|
||||
|
||||
autoIndexPrograms = ProgramsHasher(autoIndexPrograms);
|
||||
autoIndexPrograms = ProgramsHasher(autoIndexPrograms).ToArray();
|
||||
|
||||
return programs.Concat(autoIndexPrograms).Where(x => x.Valid).Distinct().ToArray();
|
||||
}
|
||||
|
|
@ -651,11 +683,13 @@ namespace Flow.Launcher.Plugin.Program.Programs
|
|||
if (settings.EnableStartMenuSource)
|
||||
paths.AddRange(GetStartMenuPaths());
|
||||
|
||||
paths.AddRange(from source in settings.ProgramSources where source.Enabled select source.Location);
|
||||
var customSources = GetCommonParents(settings.ProgramSources);
|
||||
paths.AddRange(customSources);
|
||||
|
||||
var fileExtensionToWatch = settings.GetSuffixes();
|
||||
foreach (var directory in from path in paths where Directory.Exists(path) select path)
|
||||
{
|
||||
WatchDirectory(directory);
|
||||
WatchDirectory(directory, fileExtensionToWatch);
|
||||
}
|
||||
|
||||
_ = Task.Run(MonitorDirectoryChangeAsync);
|
||||
|
|
@ -676,7 +710,7 @@ namespace Flow.Launcher.Plugin.Program.Programs
|
|||
}
|
||||
}
|
||||
|
||||
public static void WatchDirectory(string directory)
|
||||
public static void WatchDirectory(string directory, string[] extensions)
|
||||
{
|
||||
if (!Directory.Exists(directory))
|
||||
{
|
||||
|
|
@ -688,6 +722,10 @@ namespace Flow.Launcher.Plugin.Program.Programs
|
|||
watcher.Deleted += static (_, _) => indexQueue.Writer.TryWrite(default);
|
||||
watcher.EnableRaisingEvents = true;
|
||||
watcher.IncludeSubdirectories = true;
|
||||
foreach (var extension in extensions)
|
||||
{
|
||||
watcher.Filters.Add($"*.{extension}");
|
||||
}
|
||||
|
||||
Watchers.Add(watcher);
|
||||
}
|
||||
|
|
@ -699,5 +737,38 @@ namespace Flow.Launcher.Plugin.Program.Programs
|
|||
fileSystemWatcher.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
// https://stackoverflow.com/a/66877016
|
||||
private static bool IsSubPathOf(string subPath, string basePath)
|
||||
{
|
||||
var rel = Path.GetRelativePath(basePath, subPath);
|
||||
return rel != "."
|
||||
&& rel != ".."
|
||||
&& !rel.StartsWith("../")
|
||||
&& !rel.StartsWith(@"..\")
|
||||
&& !Path.IsPathRooted(rel);
|
||||
}
|
||||
|
||||
private static List<string> GetCommonParents(IEnumerable<ProgramSource> programSources)
|
||||
{
|
||||
// To avoid unnecessary io
|
||||
// like c:\windows and c:\windows\system32
|
||||
var grouped = programSources.GroupBy(p => p.Location.ToLowerInvariant()[0]); // group by disk
|
||||
List<string> result = new();
|
||||
foreach (var group in grouped)
|
||||
{
|
||||
HashSet<ProgramSource> parents = group.ToHashSet();
|
||||
foreach (var source in group)
|
||||
{
|
||||
if (parents.Any(p => IsSubPathOf(source.Location, p.Location) &&
|
||||
source != p))
|
||||
{
|
||||
parents.Remove(source);
|
||||
}
|
||||
}
|
||||
result.AddRange(parents.Select(x => x.Location));
|
||||
}
|
||||
return result.DistinctBy(x => x.ToLowerInvariant()).ToList();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,37 +15,39 @@ namespace Flow.Launcher.Plugin.Program.Views.Models
|
|||
/// </remarks>
|
||||
public class ProgramSource
|
||||
{
|
||||
private string name;
|
||||
private string name = string.Empty;
|
||||
private string loc = string.Empty;
|
||||
private string uniqueIdentifier = string.Empty;
|
||||
|
||||
private string loc;
|
||||
public string Location
|
||||
{
|
||||
get => loc;
|
||||
set
|
||||
{
|
||||
loc = value;
|
||||
UniqueIdentifier = value.ToLowerInvariant();
|
||||
loc = value ?? string.Empty;
|
||||
UniqueIdentifier = value;
|
||||
}
|
||||
}
|
||||
public string Name { get => name ?? new DirectoryInfo(Location).Name; set => name = value; }
|
||||
|
||||
public string Name { get => name; set => name = value ?? string.Empty; }
|
||||
public bool Enabled { get; set; } = true;
|
||||
|
||||
public string UniqueIdentifier { get; private set; }
|
||||
public string UniqueIdentifier
|
||||
{
|
||||
get => uniqueIdentifier;
|
||||
private set
|
||||
{
|
||||
uniqueIdentifier = value == null ? string.Empty : value.ToLowerInvariant();
|
||||
}
|
||||
}
|
||||
|
||||
[JsonConstructor]
|
||||
public ProgramSource(string name, string location, bool enabled, string uniqueIdentifier)
|
||||
{
|
||||
loc = location;
|
||||
this.name = name;
|
||||
loc = location ?? string.Empty;
|
||||
Name = name;
|
||||
Enabled = enabled;
|
||||
if (location.Equals(uniqueIdentifier, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
UniqueIdentifier = location.ToLowerInvariant(); // To make sure old config can be reset to case-insensitive
|
||||
}
|
||||
else
|
||||
{
|
||||
UniqueIdentifier = uniqueIdentifier; // For uwp apps
|
||||
}
|
||||
UniqueIdentifier = uniqueIdentifier;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
@ -55,14 +57,15 @@ namespace Flow.Launcher.Plugin.Program.Views.Models
|
|||
/// <param name="enabled">enabled</param>
|
||||
public ProgramSource(string location, bool enabled = true)
|
||||
{
|
||||
loc = location;
|
||||
loc = location ?? string.Empty;
|
||||
Enabled = enabled;
|
||||
UniqueIdentifier = location.ToLowerInvariant(); // For path comparison
|
||||
UniqueIdentifier = location; // For path comparison
|
||||
Name = new DirectoryInfo(Location).Name;
|
||||
}
|
||||
|
||||
public ProgramSource(IProgram source)
|
||||
{
|
||||
loc = source.Location;
|
||||
loc = source.Location ?? string.Empty;
|
||||
Name = source.Name;
|
||||
Enabled = source.Enabled;
|
||||
UniqueIdentifier = source.UniqueIdentifier;
|
||||
|
|
|
|||
21
appveyor.yml
21
appveyor.yml
|
|
@ -4,6 +4,10 @@ init:
|
|||
- ps: |
|
||||
$version = new-object System.Version $env:APPVEYOR_BUILD_VERSION
|
||||
$env:flowVersion = "{0}.{1}.{2}" -f $version.Major, $version.Minor, $version.Build
|
||||
if ($env:APPVEYOR_REPO_BRANCH -eq "dev")
|
||||
{
|
||||
$env:prereleaseTag = "{0}.{1}.{2}.{3}" -f $version.Major, $version.Minor, $version.Build, $version.Revision
|
||||
}
|
||||
- sc config WSearch start= auto # Starts Windows Search service- Needed for running ExplorerTest
|
||||
- net start WSearch
|
||||
|
||||
|
|
@ -18,12 +22,6 @@ assembly_info:
|
|||
assembly_file_version: $(flowVersion)
|
||||
assembly_informational_version: $(flowVersion)
|
||||
|
||||
skip_branch_with_pr: true
|
||||
|
||||
skip_commits:
|
||||
files:
|
||||
- '*.md'
|
||||
|
||||
image: Visual Studio 2022
|
||||
platform: Any CPU
|
||||
configuration: Release
|
||||
|
|
@ -57,6 +55,17 @@ deploy:
|
|||
on:
|
||||
APPVEYOR_REPO_TAG: true
|
||||
|
||||
- provider: GitHub
|
||||
repository: Flow-Launcher/Prereleases
|
||||
release: v$(prereleaseTag)
|
||||
description: 'This is the early access build of our upcoming release. All changes contained here are reviewed, tested and stable to use.\n\nSee our [release](https://github.com/Flow-Launcher/Flow.Launcher/pulls?q=is%3Aopen+is%3Apr+label%3Arelease) Pull Request for details.\n\nFor latest production release visit [here](https://github.com/Flow-Launcher/Flow.Launcher/releases/latest)\n\nPlease report any bugs or issues over at the [main repository](https://github.com/Flow-Launcher/Flow.Launcher/issues)'
|
||||
auth_token:
|
||||
secure: ij4UeXUYQBDJxn2YRAAhUOjklOGVKDB87Hn5J8tKIzj13yatoI7sLM666QDQFEgv
|
||||
artifact: Squirrel Installer, Portable Version, Squirrel nupkg, Squirrel RELEASES
|
||||
force_update: true
|
||||
on:
|
||||
branch: dev
|
||||
|
||||
- provider: GitHub
|
||||
release: v$(flowVersion)
|
||||
auth_token:
|
||||
|
|
|
|||
Loading…
Reference in a new issue