diff --git a/Flow.Launcher.Test/Plugins/ProgramTest.cs b/Flow.Launcher.Test/Plugins/ProgramTest.cs
index a0d2243ce75..e3a05f484f0 100644
--- a/Flow.Launcher.Test/Plugins/ProgramTest.cs
+++ b/Flow.Launcher.Test/Plugins/ProgramTest.cs
@@ -19,7 +19,7 @@ public void WhenGivenPriReferenceValueShouldReturnCorrectFormat(string packageNa
var app = new UWP.Application();
// Act
- var result = app.FormattedPriReferenceValue(packageName, rawPriReferenceValue);
+ var result = UWP.Application.FormattedPriReferenceValue(packageName, rawPriReferenceValue);
// Assert
Assert.IsTrue(result == expectedFormat,
diff --git a/Plugins/Flow.Launcher.Plugin.Program/AddProgramSource.xaml b/Plugins/Flow.Launcher.Plugin.Program/AddProgramSource.xaml
index 9230eb06254..39d5f8a4e19 100644
--- a/Plugins/Flow.Launcher.Plugin.Program/AddProgramSource.xaml
+++ b/Plugins/Flow.Launcher.Plugin.Program/AddProgramSource.xaml
@@ -5,12 +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="400"
+ Width="530"
Background="{DynamicResource PopuBGColor}"
Foreground="{DynamicResource PopupTextColor}"
+ ResizeMode="NoResize"
SizeToContent="Height"
- WindowStartupLocation="CenterScreen"
- mc:Ignorable="d">
+ WindowStartupLocation="CenterScreen">
@@ -19,7 +19,6 @@
-
@@ -53,33 +52,78 @@
-
-
+
+
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -87,19 +131,17 @@
-
-
-
+
\ No newline at end of file
diff --git a/Plugins/Flow.Launcher.Plugin.Program/AddProgramSource.xaml.cs b/Plugins/Flow.Launcher.Plugin.Program/AddProgramSource.xaml.cs
index 045d363b3fe..e88c9b988d1 100644
--- a/Plugins/Flow.Launcher.Plugin.Program/AddProgramSource.xaml.cs
+++ b/Plugins/Flow.Launcher.Plugin.Program/AddProgramSource.xaml.cs
@@ -9,11 +9,12 @@ namespace Flow.Launcher.Plugin.Program
///
/// Interaction logic for AddProgramSource.xaml
///
- public partial class AddProgramSource
+ public partial class AddProgramSource : Window
{
private PluginInitContext _context;
- private Settings.ProgramSource _editing;
+ private ProgramSource _editing;
private Settings _settings;
+ private bool update;
public AddProgramSource(PluginInitContext context, Settings settings)
{
@@ -21,14 +22,19 @@ public AddProgramSource(PluginInitContext context, Settings settings)
_context = context;
_settings = settings;
Directory.Focus();
+ Chkbox.IsChecked = true;
+ update = false;
+ btnAdd.Content = _context.API.GetTranslation("flowlauncher_plugin_program_add");
}
- public AddProgramSource(Settings.ProgramSource edit, Settings settings)
+ public AddProgramSource(PluginInitContext context, Settings settings, ProgramSource source)
{
- _editing = edit;
- _settings = settings;
-
InitializeComponent();
+ _context = context;
+ _editing = source;
+ _settings = settings;
+ update = true;
+ Chkbox.IsChecked = _editing.Enabled;
Directory.Text = _editing.Location;
}
@@ -47,34 +53,54 @@ private void BtnCancel_OnClick(object sender, RoutedEventArgs e)
Close();
}
- private void ButtonAdd_OnClick(object sender, RoutedEventArgs e)
+ private void BtnAdd_OnClick(object sender, RoutedEventArgs e)
{
- string s = Directory.Text;
- if (!System.IO.Directory.Exists(s))
+ string path = Directory.Text;
+ bool modified = false;
+ if (!System.IO.Directory.Exists(path))
{
System.Windows.MessageBox.Show(_context.API.GetTranslation("flowlauncher_plugin_program_invalid_path"));
return;
}
- if (_editing == null)
+ if (!update)
{
- if (!ProgramSetting.ProgramSettingDisplayList.Any(x => x.UniqueIdentifier == Directory.Text))
+ if (!ProgramSetting.ProgramSettingDisplayList.Any(x => x.UniqueIdentifier.Equals(path, System.StringComparison.OrdinalIgnoreCase)))
{
- var source = new ProgramSource
- {
- Location = Directory.Text,
- UniqueIdentifier = Directory.Text
- };
-
+ var source = new ProgramSource(path);
+ modified = true;
_settings.ProgramSources.Insert(0, source);
ProgramSetting.ProgramSettingDisplayList.Add(source);
}
+ else
+ {
+ System.Windows.MessageBox.Show(_context.API.GetTranslation("flowlauncher_plugin_program_duplicate_program_source"));
+ return;
+ }
}
else
{
- _editing.Location = Directory.Text;
+ // Separate checks to avoid changing UniqueIdentifier of UWP
+ if (!_editing.Location.Equals(path, System.StringComparison.OrdinalIgnoreCase))
+ {
+ if (ProgramSetting.ProgramSettingDisplayList
+ .Any(x => x.UniqueIdentifier.Equals(path, System.StringComparison.OrdinalIgnoreCase)))
+ {
+ // Check if the new location is used
+ // No need to check win32 or uwp, just override them
+ System.Windows.MessageBox.Show(_context.API.GetTranslation("flowlauncher_plugin_program_duplicate_program_source"));
+ return;
+ }
+ modified = true;
+ _editing.Location = path; // Changes UniqueIdentifier internally
+ }
+ if (_editing.Enabled != Chkbox.IsChecked)
+ {
+ modified = true;
+ _editing.Enabled = Chkbox.IsChecked ?? true;
+ }
}
- DialogResult = true;
+ DialogResult = modified;
Close();
}
}
diff --git a/Plugins/Flow.Launcher.Plugin.Program/FileChangeWatcher.cs b/Plugins/Flow.Launcher.Plugin.Program/FileChangeWatcher.cs
deleted file mode 100644
index 4ede37dec5d..00000000000
--- a/Plugins/Flow.Launcher.Plugin.Program/FileChangeWatcher.cs
+++ /dev/null
@@ -1,58 +0,0 @@
-using System.Collections.Generic;
-using System.IO;
-using System.Threading.Tasks;
-using Flow.Launcher.Infrastructure.Logger;
-using Flow.Launcher.Plugin.Program.Programs;
-
-namespace Flow.Launcher.Plugin.Program
-{
- //internal static class FileChangeWatcher
- //{
- // private static readonly List WatchedPath = new List();
- // // todo remove previous watcher events
- // public static void AddAll(List sources, string[] suffixes)
- // {
- // foreach (var s in sources)
- // {
- // if (Directory.Exists(s.Location))
- // {
- // AddWatch(s.Location, suffixes);
- // }
- // }
- // }
-
- // public static void AddWatch(string path, string[] programSuffixes, bool includingSubDirectory = true)
- // {
- // if (WatchedPath.Contains(path)) return;
- // if (!Directory.Exists(path))
- // {
- // Log.Warn($"|FileChangeWatcher|{path} doesn't exist");
- // return;
- // }
-
- // WatchedPath.Add(path);
- // foreach (string fileType in programSuffixes)
- // {
- // FileSystemWatcher watcher = new FileSystemWatcher
- // {
- // Path = path,
- // IncludeSubdirectories = includingSubDirectory,
- // Filter = $"*.{fileType}",
- // EnableRaisingEvents = true
- // };
- // watcher.Changed += FileChanged;
- // watcher.Created += FileChanged;
- // watcher.Deleted += FileChanged;
- // watcher.Renamed += FileChanged;
- // }
- // }
-
- // private static void FileChanged(object source, FileSystemEventArgs e)
- // {
- // Task.Run(() =>
- // {
- // Main.IndexPrograms();
- // });
- // }
- //}
-}
diff --git a/Plugins/Flow.Launcher.Plugin.Program/Languages/en.xaml b/Plugins/Flow.Launcher.Plugin.Program/Languages/en.xaml
index eba3c2f7956..1c6c97792a9 100644
--- a/Plugins/Flow.Launcher.Plugin.Program/Languages/en.xaml
+++ b/Plugins/Flow.Launcher.Plugin.Program/Languages/en.xaml
@@ -10,6 +10,7 @@
Add
Name
Enable
+ Enabled
Disable
Location
All Programs
@@ -38,8 +39,12 @@
Please select a program source
Are you sure you want to delete the selected program sources?
+ Another program source with the same location alreaday exists.
- OK
+ Program Source
+ Edit directory and status of this program source.
+
+ Update
Program Plugin will only index files with selected suffixes and .url files with selected protocols.
Successfully updated file suffixes
File suffixes can't be empty
diff --git a/Plugins/Flow.Launcher.Plugin.Program/Logger/ProgramLogger.cs b/Plugins/Flow.Launcher.Plugin.Program/Logger/ProgramLogger.cs
index cbf4960a33e..1ae6d8a29b2 100644
--- a/Plugins/Flow.Launcher.Plugin.Program/Logger/ProgramLogger.cs
+++ b/Plugins/Flow.Launcher.Plugin.Program/Logger/ProgramLogger.cs
@@ -1,13 +1,8 @@
using NLog;
-using NLog.Config;
-using NLog.Targets;
using System;
-using System.Diagnostics;
using System.IO;
using System.Runtime.CompilerServices;
using System.Security;
-using Flow.Launcher.Infrastructure;
-using Flow.Launcher.Infrastructure.UserSettings;
namespace Flow.Launcher.Plugin.Program.Logger
{
diff --git a/Plugins/Flow.Launcher.Plugin.Program/Main.cs b/Plugins/Flow.Launcher.Plugin.Program/Main.cs
index 2178c8ef5cd..c212bf8f446 100644
--- a/Plugins/Flow.Launcher.Plugin.Program/Main.cs
+++ b/Plugins/Flow.Launcher.Plugin.Program/Main.cs
@@ -1,7 +1,5 @@
using System;
-using System.Collections.Concurrent;
using System.Collections.Generic;
-using System.Collections.Specialized;
using System.Diagnostics;
using System.Linq;
using System.Threading;
@@ -11,9 +9,8 @@
using Flow.Launcher.Infrastructure.Storage;
using Flow.Launcher.Plugin.Program.Programs;
using Flow.Launcher.Plugin.Program.Views;
+using Flow.Launcher.Plugin.Program.Views.Models;
using Microsoft.Extensions.Caching.Memory;
-using Microsoft.Extensions.Configuration;
-using Microsoft.Extensions.Primitives;
using Stopwatch = Flow.Launcher.Infrastructure.Stopwatch;
namespace Flow.Launcher.Plugin.Program
@@ -82,13 +79,9 @@ public async Task InitAsync(PluginInitContext context)
Stopwatch.Normal("|Flow.Launcher.Plugin.Program.Main|Preload programs cost", () =>
{
_win32Storage = new BinaryStorage("Win32");
- _win32s = _win32Storage.TryLoad(new Win32[]
- {
- });
+ _win32s = _win32Storage.TryLoad(Array.Empty());
_uwpStorage = new BinaryStorage("UWP");
- _uwps = _uwpStorage.TryLoad(new UWP.Application[]
- {
- });
+ _uwps = _uwpStorage.TryLoad(Array.Empty());
});
Log.Info($"|Flow.Launcher.Plugin.Program.Main|Number of preload win32 programs <{_win32s.Length}>");
Log.Info($"|Flow.Launcher.Plugin.Program.Main|Number of preload uwps <{_uwps.Length}>");
@@ -123,18 +116,23 @@ public static void IndexUwpPrograms()
{
var windows10 = new Version(10, 0);
var support = Environment.OSVersion.Version.Major >= windows10.Major;
- var applications = support ? UWP.All() : new UWP.Application[]
- {
- };
+ var applications = support ? UWP.All() : Array.Empty();
_uwps = applications;
ResetCache();
}
public static async Task IndexProgramsAsync()
{
- var t1 = Task.Run(IndexWin32Programs);
- var t2 = Task.Run(IndexUwpPrograms);
- await Task.WhenAll(t1, t2).ConfigureAwait(false);
+ var a = Task.Run(() =>
+ {
+ Stopwatch.Normal("|Flow.Launcher.Plugin.Program.Main|Win32Program index cost", IndexWin32Programs);
+ });
+
+ var b = Task.Run(() =>
+ {
+ Stopwatch.Normal("|Flow.Launcher.Plugin.Program.Main|UWPProgram index cost", IndexUwpPrograms);
+ });
+ await Task.WhenAll(a, b).ConfigureAwait(false);
_settings.LastIndexTime = DateTime.Today;
}
@@ -190,29 +188,33 @@ public List LoadContextMenus(Result selectedResult)
return menuOptions;
}
- private void DisableProgram(IProgram programToDelete)
+ private static void DisableProgram(IProgram programToDelete)
{
if (_settings.DisabledProgramSources.Any(x => x.UniqueIdentifier == programToDelete.UniqueIdentifier))
return;
if (_uwps.Any(x => x.UniqueIdentifier == programToDelete.UniqueIdentifier))
- _uwps.FirstOrDefault(x => x.UniqueIdentifier == programToDelete.UniqueIdentifier)
- .Enabled = false;
-
- if (_win32s.Any(x => x.UniqueIdentifier == programToDelete.UniqueIdentifier))
- _win32s.FirstOrDefault(x => x.UniqueIdentifier == programToDelete.UniqueIdentifier)
- .Enabled = false;
-
- _settings.DisabledProgramSources
- .Add(
- new Settings.DisabledProgramSource
- {
- Name = programToDelete.Name,
- Location = programToDelete.Location,
- UniqueIdentifier = programToDelete.UniqueIdentifier,
- Enabled = false
- }
- );
+ {
+ var program = _uwps.First(x => x.UniqueIdentifier == programToDelete.UniqueIdentifier);
+ program.Enabled = false;
+ _settings.DisabledProgramSources.Add(new ProgramSource(program));
+ _ = Task.Run(() =>
+ {
+ IndexUwpPrograms();
+ _settings.LastIndexTime = DateTime.Today;
+ });
+ }
+ else if (_win32s.Any(x => x.UniqueIdentifier == programToDelete.UniqueIdentifier))
+ {
+ var program = _win32s.First(x => x.UniqueIdentifier == programToDelete.UniqueIdentifier);
+ program.Enabled = false;
+ _settings.DisabledProgramSources.Add(new ProgramSource(program));
+ _ = Task.Run(() =>
+ {
+ IndexWin32Programs();
+ _settings.LastIndexTime = DateTime.Today;
+ });
+ }
}
public static void StartProcess(Func runProcess, ProcessStartInfo info)
@@ -233,6 +235,7 @@ public async Task ReloadDataAsync()
{
await IndexProgramsAsync();
}
+
public void Dispose()
{
Win32.Dispose();
diff --git a/Plugins/Flow.Launcher.Plugin.Program/Programs/ApplicationActivationHelper.cs b/Plugins/Flow.Launcher.Plugin.Program/Programs/ApplicationActivationHelper.cs
index 4b8423ed6fe..790a70392e6 100644
--- a/Plugins/Flow.Launcher.Plugin.Program/Programs/ApplicationActivationHelper.cs
+++ b/Plugins/Flow.Launcher.Plugin.Program/Programs/ApplicationActivationHelper.cs
@@ -1,8 +1,6 @@
using System;
-using System.Diagnostics;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
-using System.Text.RegularExpressions;
namespace Flow.Launcher.Plugin.Program.Programs
{
diff --git a/Plugins/Flow.Launcher.Plugin.Program/Programs/AppxPackageHelper.cs b/Plugins/Flow.Launcher.Plugin.Program/Programs/AppxPackageHelper.cs
index e48f30757be..62416609e9c 100644
--- a/Plugins/Flow.Launcher.Plugin.Program/Programs/AppxPackageHelper.cs
+++ b/Plugins/Flow.Launcher.Plugin.Program/Programs/AppxPackageHelper.cs
@@ -1,20 +1,18 @@
using System;
using System.Collections.Generic;
-using System.Text;
using System.Runtime.InteropServices;
using System.Runtime.InteropServices.ComTypes;
-using Windows.Storage;
namespace Flow.Launcher.Plugin.Program.Programs
{
public class AppxPackageHelper
{
// This function returns a list of attributes of applications
- public List getAppsFromManifest(IStream stream)
+ public static List GetAppsFromManifest(IStream stream)
{
+ IAppxFactory appxFactory = (IAppxFactory)new AppxFactory();
List apps = new List();
- var appxFactory = new AppxFactory();
- var reader = ((IAppxFactory)appxFactory).CreateManifestReader(stream);
+ var reader = appxFactory.CreateManifestReader(stream);
var manifestApps = reader.GetApplications();
while (manifestApps.GetHasCurrent())
{
diff --git a/Plugins/Flow.Launcher.Plugin.Program/Programs/ShellLinkHelper.cs b/Plugins/Flow.Launcher.Plugin.Program/Programs/ShellLinkHelper.cs
index d17048dcbd8..72b7b0a91cb 100644
--- a/Plugins/Flow.Launcher.Plugin.Program/Programs/ShellLinkHelper.cs
+++ b/Plugins/Flow.Launcher.Plugin.Program/Programs/ShellLinkHelper.cs
@@ -1,11 +1,8 @@
using System;
-using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;
-using System.IO;
using Accessibility;
using System.Runtime.InteropServices.ComTypes;
-using System.Security.Policy;
namespace Flow.Launcher.Plugin.Program.Programs
{
diff --git a/Plugins/Flow.Launcher.Plugin.Program/Programs/UWP.cs b/Plugins/Flow.Launcher.Plugin.Program/Programs/UWP.cs
index 316aaaac301..84aa93664ef 100644
--- a/Plugins/Flow.Launcher.Plugin.Program/Programs/UWP.cs
+++ b/Plugins/Flow.Launcher.Plugin.Program/Programs/UWP.cs
@@ -18,7 +18,6 @@
using Rect = System.Windows.Rect;
using Flow.Launcher.Plugin.SharedModels;
using Flow.Launcher.Infrastructure.Logger;
-using System.Runtime.Versioning;
using System.Threading.Channels;
namespace Flow.Launcher.Plugin.Program.Programs
@@ -42,39 +41,27 @@ public UWP(Package package)
FullName = package.Id.FullName;
FamilyName = package.Id.FamilyName;
InitializeAppInfo();
- Apps = Apps.Where(a =>
- {
- var valid =
- !string.IsNullOrEmpty(a.UserModelId) &&
- !string.IsNullOrEmpty(a.DisplayName);
- return valid;
- }).ToArray();
}
private void InitializeAppInfo()
{
- AppxPackageHelper _helper = new AppxPackageHelper();
var path = Path.Combine(Location, "AppxManifest.xml");
var namespaces = XmlNamespaces(path);
InitPackageVersion(namespaces);
const uint noAttribute = 0x80;
- const Stgm exclusiveRead = Stgm.Read | Stgm.ShareExclusive;
- var hResult = SHCreateStreamOnFileEx(path, exclusiveRead, noAttribute, false, null, out IStream stream);
+ const Stgm nonExclusiveRead = Stgm.Read | Stgm.ShareDenyNone;
+ var hResult = SHCreateStreamOnFileEx(path, nonExclusiveRead, noAttribute, false, null, out IStream stream);
if (hResult == Hresult.Ok)
{
- var apps = new List();
-
- List _apps = _helper.getAppsFromManifest(stream);
- foreach (var _app in _apps)
- {
- var app = new Application(_app, this);
- apps.Add(app);
- }
+ List _apps = AppxPackageHelper.GetAppsFromManifest(stream);
- Apps = apps.Where(a => a.AppListEntry != "none").ToArray();
+ Apps = _apps.Select(x => new Application(x, this))
+ .Where(a => !string.IsNullOrEmpty(a.UserModelId)
+ && !string.IsNullOrEmpty(a.DisplayName))
+ .ToArray();
}
else
{
@@ -82,17 +69,17 @@ private void InitializeAppInfo()
ProgramLogger.LogException($"|UWP|InitializeAppInfo|{path}" +
"|Error caused while trying to get the details of the UWP program", e);
- Apps = new List().ToArray();
+ Apps = Array.Empty();
}
- if (Marshal.ReleaseComObject(stream) > 0)
+ if (stream != null && Marshal.ReleaseComObject(stream) > 0)
{
Log.Error("Flow.Launcher.Plugin.Program.Programs.UWP", "AppxManifest.xml was leaked");
}
}
/// http://www.hanselman.com/blog/GetNamespacesFromAnXMLDocumentWithXPathDocumentAndLINQToXML.aspx
- private string[] XmlNamespaces(string path)
+ private static string[] XmlNamespaces(string path)
{
XDocument z = XDocument.Load(path);
if (z.Root != null)
@@ -110,9 +97,7 @@ private string[] XmlNamespaces(string path)
ProgramLogger.LogException($"|UWP|XmlNamespaces|{path}" +
$"|Error occured while trying to get the XML from {path}", new ArgumentNullException());
- return new string[]
- {
- };
+ return Array.Empty();
}
}
@@ -178,16 +163,13 @@ public static Application[] All()
var updatedListWithoutDisabledApps = applications
.Where(t1 => !Main._settings.DisabledProgramSources
- .Any(x => x.UniqueIdentifier == t1.UniqueIdentifier))
- .Select(x => x);
+ .Any(x => x.UniqueIdentifier == t1.UniqueIdentifier));
return updatedListWithoutDisabledApps.ToArray();
}
else
{
- return new Application[]
- {
- };
+ return Array.Empty();
}
}
@@ -233,9 +215,7 @@ private static IEnumerable CurrentUserPackages()
}
else
{
- return new Package[]
- {
- };
+ return Array.Empty();
}
}
@@ -297,7 +277,6 @@ public override int GetHashCode()
[Serializable]
public class Application : IProgram
{
- public string AppListEntry { get; set; }
public string UniqueIdentifier { get; set; }
public string DisplayName { get; set; }
public string Description { get; set; }
@@ -317,7 +296,6 @@ public class Application : IProgram
public Application() { }
-
public Result Result(string query, IPublicAPI api)
{
string title;
@@ -544,7 +522,7 @@ internal string ResourceFromPri(string packageFullName, string packageName, stri
}
}
- public string FormattedPriReferenceValue(string packageName, string rawPriReferenceValue)
+ public static string FormattedPriReferenceValue(string packageName, string rawPriReferenceValue)
{
const string prefix = "ms-resource:";
@@ -701,9 +679,15 @@ public ImageSource Logo()
private BitmapImage ImageFromPath(string path)
{
+ // TODO: Consider using infrastructure.image.imageloader?
if (File.Exists(path))
{
- var image = new BitmapImage(new Uri(path));
+ var image = new BitmapImage();
+ image.BeginInit();
+ image.UriSource = new Uri(path);
+ image.CacheOption = BitmapCacheOption.OnLoad;
+ image.EndInit();
+ image.Freeze();
return image;
}
else
@@ -775,6 +759,23 @@ public override string ToString()
{
return $"{DisplayName}: {Description}";
}
+
+ public override bool Equals(object obj)
+ {
+ if (obj is Application other)
+ {
+ return UniqueIdentifier == other.UniqueIdentifier;
+ }
+ else
+ {
+ return false;
+ }
+ }
+
+ public override int GetHashCode()
+ {
+ return UniqueIdentifier.GetHashCode();
+ }
}
public enum PackageVersion
@@ -790,6 +791,7 @@ private enum Stgm : uint
{
Read = 0x0,
ShareExclusive = 0x10,
+ ShareDenyNone = 0x40
}
private enum Hresult : uint
diff --git a/Plugins/Flow.Launcher.Plugin.Program/Programs/Win32.cs b/Plugins/Flow.Launcher.Plugin.Program/Programs/Win32.cs
index f927d60cd28..c13b32e80fc 100644
--- a/Plugins/Flow.Launcher.Plugin.Program/Programs/Win32.cs
+++ b/Plugins/Flow.Launcher.Plugin.Program/Programs/Win32.cs
@@ -13,9 +13,8 @@
using Flow.Launcher.Plugin.SharedModels;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
-using System.Text.RegularExpressions;
using System.Threading.Channels;
-using Flow.Launcher.Infrastructure.Image;
+using Flow.Launcher.Plugin.Program.Views.Models;
using IniParser;
namespace Flow.Launcher.Plugin.Program.Programs
@@ -24,7 +23,7 @@ namespace Flow.Launcher.Plugin.Program.Programs
public class Win32 : IProgram, IEquatable
{
public string Name { get; set; }
- public string UniqueIdentifier { get; set; }
+ public string UniqueIdentifier { get => _uid; set => _uid = value.ToLowerInvariant(); } // For path comparison
public string IcoPath { get; set; }
public string FullPath { get; set; }
public string LnkResolvedPath { get; set; }
@@ -38,6 +37,7 @@ public class Win32 : IProgram, IEquatable
private const string ShortcutExtension = "lnk";
private const string UrlExtension = "url";
private const string ExeExtension = "exe";
+ private string _uid = string.Empty;
private static readonly Win32 Default = new Win32()
{
@@ -222,10 +222,7 @@ private static Win32 Win32Program(string path)
ProgramLogger.LogException($"|Win32|Win32Program|{path}" +
$"|Permission denied when trying to load the program from {path}", e);
- return new Win32()
- {
- Valid = false, Enabled = false
- };
+ return Default;
}
}
@@ -245,7 +242,7 @@ private static Win32 LnkProgram(string path)
if (extension == ExeExtension && File.Exists(target))
{
program.LnkResolvedPath = program.FullPath;
- program.FullPath = Path.GetFullPath(target).ToLower();
+ program.FullPath = Path.GetFullPath(target).ToLowerInvariant();
program.ExecutableName = Path.GetFileName(target);
var description = _helper.description;
@@ -296,7 +293,7 @@ private static Win32 LnkProgram(string path)
#endif
}
- private static Win32 UrlProgram(string path)
+ private static Win32 UrlProgram(string path, string[] protocols)
{
var program = Win32Program(path);
program.Valid = false;
@@ -311,9 +308,9 @@ private static Win32 UrlProgram(string path)
{
return program;
}
- foreach(var protocol in Main._settings.GetProtocols())
+ foreach (var protocol in protocols)
{
- if(url.StartsWith(protocol))
+ if (url.StartsWith(protocol))
{
program.LnkResolvedPath = url;
program.Valid = true;
@@ -350,10 +347,7 @@ private static Win32 ExeProgram(string path)
ProgramLogger.LogException($"|Win32|ExeProgram|{path}" +
$"|Permission denied when trying to load the program from {path}", e);
- return new Win32()
- {
- Valid = false, Enabled = false
- };
+ return Default;
}
}
@@ -364,16 +358,17 @@ private static IEnumerable ProgramPaths(string directory, string[] suffi
return Directory.EnumerateFiles(directory, "*", new EnumerationOptions
{
- IgnoreInaccessible = true, RecurseSubdirectories = recursive
+ IgnoreInaccessible = true,
+ RecurseSubdirectories = recursive
}).Where(x => suffixes.Contains(Extension(x)));
}
private static string Extension(string path)
{
- var extension = Path.GetExtension(path)?.ToLower();
+ var extension = Path.GetExtension(path)?.ToLowerInvariant();
if (!string.IsNullOrEmpty(extension))
{
- return extension.Substring(1);
+ return extension.Substring(1); // remove dot
}
else
{
@@ -381,26 +376,20 @@ private static string Extension(string path)
}
}
- private static IEnumerable UnregisteredPrograms(List sources, string[] suffixes)
+ private static IEnumerable UnregisteredPrograms(List sources, string[] suffixes, string[] protocols)
{
+ // Disabled custom sources are not in DisabledProgramSources
var paths = ExceptDisabledSource(sources.Where(s => Directory.Exists(s.Location) && s.Enabled)
- .SelectMany(s => ProgramPaths(s.Location, suffixes)), x => x)
- .Distinct();
-
- var programs = paths.Select(x => Extension(x) switch
- {
- ExeExtension => ExeProgram(x),
- ShortcutExtension => LnkProgram(x),
- UrlExtension => UrlProgram(x),
- _ => Win32Program(x)
- });
+ .AsParallel()
+ .SelectMany(s => ProgramPaths(s.Location, suffixes)))
+ .Distinct();
+ var programs = paths.Select(x => GetProgramFromPath(x, protocols));
return programs;
}
- private static IEnumerable StartMenuPrograms(string[] suffixes)
+ private static IEnumerable StartMenuPrograms(string[] suffixes, string[] protocols)
{
-
var directory1 = Environment.GetFolderPath(Environment.SpecialFolder.Programs);
var directory2 = Environment.GetFolderPath(Environment.SpecialFolder.CommonPrograms);
var paths1 = ProgramPaths(directory1, suffixes);
@@ -409,16 +398,11 @@ private static IEnumerable StartMenuPrograms(string[] suffixes)
var toFilter = paths1.Concat(paths2);
var programs = ExceptDisabledSource(toFilter.Distinct())
- .Select(x => Extension(x) switch
- {
- ShortcutExtension => LnkProgram(x),
- UrlExtension => UrlProgram(x),
- _ => Win32Program(x)
- });
+ .Select(x => GetProgramFromPath(x, protocols));
return programs;
}
- private static IEnumerable PATHPrograms(string[] suffixes)
+ private static IEnumerable PATHPrograms(string[] suffixes, string[] protocols)
{
var pathEnv = Environment.GetEnvironmentVariable("Path");
if (String.IsNullOrEmpty(pathEnv))
@@ -434,14 +418,14 @@ private static IEnumerable PATHPrograms(string[] suffixes)
.Select(x => Extension(x) switch
{
ShortcutExtension => LnkProgram(x),
- UrlExtension => UrlProgram(x),
+ UrlExtension => UrlProgram(x, protocols),
ExeExtension => ExeProgram(x),
_ => Win32Program(x)
});
return programs;
}
- private static IEnumerable AppPathsPrograms(string[] suffixes)
+ private static IEnumerable AppPathsPrograms(string[] suffixes, string[] protocols)
{
// https://msdn.microsoft.com/en-us/library/windows/desktop/ee872121
const string appPaths = @"SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths";
@@ -461,12 +445,11 @@ private static IEnumerable AppPathsPrograms(string[] suffixes)
toFilter = toFilter.Concat(GetPathFromRegistry(rootUser));
}
-
toFilter = toFilter.Distinct().Where(p => suffixes.Contains(Extension(p)));
- var filtered = ExceptDisabledSource(toFilter);
-
- return filtered.Select(GetProgramFromPath).ToList(); // ToList due to disposing issue
+ var programs = ExceptDisabledSource(toFilter)
+ .Select(x => GetProgramFromPath(x, protocols)).Where(x => x.Valid).ToList(); // ToList due to disposing issue
+ return programs;
}
private static IEnumerable GetPathFromRegistry(RegistryKey root)
@@ -506,7 +489,7 @@ private static string GetProgramPathFromRegistrySubKeys(RegistryKey root, string
}
}
- private static Win32 GetProgramFromPath(string path)
+ private static Win32 GetProgramFromPath(string path, string[] protocols)
{
if (string.IsNullOrEmpty(path))
return Default;
@@ -516,14 +499,18 @@ private static Win32 GetProgramFromPath(string path)
if (!File.Exists(path))
return Default;
- var entry = Win32Program(path);
-
- return entry;
+ return Extension(path) switch
+ {
+ ShortcutExtension => LnkProgram(path),
+ ExeExtension => ExeProgram(path),
+ UrlExtension => UrlProgram(path, protocols),
+ _ => Win32Program(path)
+ }; ;
}
- public static IEnumerable ExceptDisabledSource(IEnumerable sources)
+ public static IEnumerable ExceptDisabledSource(IEnumerable paths)
{
- return ExceptDisabledSource(sources, x => x);
+ return ExceptDisabledSource(paths, x => x.ToLowerInvariant());
}
public static IEnumerable ExceptDisabledSource(IEnumerable sources,
@@ -558,7 +545,8 @@ public static IEnumerable DistinctBy(IEnumerable source, Func
private static IEnumerable ProgramsHasher(IEnumerable programs)
{
- return programs.GroupBy(p => p.FullPath.ToLower())
+ return programs.GroupBy(p => p.FullPath.ToLowerInvariant())
+ .AsParallel()
.SelectMany(g =>
{
var temp = g.Where(g => !string.IsNullOrEmpty(g.Description)).ToList();
@@ -574,8 +562,10 @@ public static Win32[] All(Settings settings)
try
{
var programs = Enumerable.Empty();
+ var suffixes = settings.GetSuffixes();
+ var protocols = settings.GetProtocols();
- var unregistered = UnregisteredPrograms(settings.ProgramSources, settings.GetSuffixes());
+ var unregistered = UnregisteredPrograms(settings.ProgramSources, suffixes, protocols);
programs = programs.Concat(unregistered);
@@ -583,19 +573,19 @@ public static Win32[] All(Settings settings)
if (settings.EnableRegistrySource)
{
- var appPaths = AppPathsPrograms(settings.GetSuffixes());
+ var appPaths = AppPathsPrograms(suffixes, protocols);
autoIndexPrograms = autoIndexPrograms.Concat(appPaths);
}
if (settings.EnableStartMenuSource)
{
- var startMenu = StartMenuPrograms(settings.GetSuffixes());
+ var startMenu = StartMenuPrograms(suffixes, protocols);
autoIndexPrograms = autoIndexPrograms.Concat(startMenu);
}
if (settings.EnablePATHSource)
{
- var path = PATHPrograms(settings.GetSuffixes());
+ var path = PATHPrograms(settings.GetSuffixes(), protocols);
autoIndexPrograms = autoIndexPrograms.Concat(path);
}
@@ -633,6 +623,18 @@ public bool Equals([AllowNull] Win32 other)
return UniqueIdentifier == other.UniqueIdentifier;
}
+ public override bool Equals(object obj)
+ {
+ if (obj is Win32 other)
+ {
+ return UniqueIdentifier == other.UniqueIdentifier;
+ }
+ else
+ {
+ return false;
+ }
+ }
+
private static IEnumerable GetStartMenuPaths()
{
var directory1 = Environment.GetFolderPath(Environment.SpecialFolder.Programs);
@@ -673,7 +675,7 @@ public static async Task MonitorDirectoryChangeAsync()
await Task.Run(Main.IndexWin32Programs);
}
}
-
+
public static void WatchDirectory(string directory)
{
if (!Directory.Exists(directory))
@@ -686,7 +688,7 @@ public static void WatchDirectory(string directory)
watcher.Deleted += static (_, _) => indexQueue.Writer.TryWrite(default);
watcher.EnableRaisingEvents = true;
watcher.IncludeSubdirectories = true;
-
+
Watchers.Add(watcher);
}
diff --git a/Plugins/Flow.Launcher.Plugin.Program/Settings.cs b/Plugins/Flow.Launcher.Plugin.Program/Settings.cs
index 4929d4b09e3..e3e8b99b9b2 100644
--- a/Plugins/Flow.Launcher.Plugin.Program/Settings.cs
+++ b/Plugins/Flow.Launcher.Plugin.Program/Settings.cs
@@ -1,18 +1,24 @@
using System;
using System.Collections.Generic;
-using System.IO;
using System.Linq;
using System.Text.Json.Serialization;
-using PropertyChanged;
-using Windows.Foundation.Metadata;
+using Flow.Launcher.Plugin.Program.Views.Models;
namespace Flow.Launcher.Plugin.Program
{
public class Settings
{
public DateTime LastIndexTime { get; set; }
+
+ ///
+ /// User-added program sources' directories
+ ///
public List ProgramSources { get; set; } = new List();
- public List DisabledProgramSources { get; set; } = new List();
+
+ ///
+ /// Disabled single programs, not including User-added directories
+ ///
+ public List DisabledProgramSources { get; set; } = new List();
[Obsolete("Should use GetSuffixes() instead."), JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
public string[] ProgramSuffixes { get; set; } = null;
@@ -122,25 +128,5 @@ private void RemoveRedundantSuffixes()
internal const string Explorer = "explorer";
internal const string ExplorerArgs = "%s";
-
- ///
- /// Contains user added folder location contents as well as all user disabled applications
- ///
- ///
- /// Win32 class applications set UniqueIdentifier using their full file path
- /// UWP class applications set UniqueIdentifier using their Application User Model ID
- /// Custom user added program sources set UniqueIdentifier using their location
- ///
- public class ProgramSource
- {
- private string name;
-
- public string Location { get; set; }
- public string Name { get => name ?? new DirectoryInfo(Location).Name; set => name = value; }
- public bool Enabled { get; set; } = true;
- public string UniqueIdentifier { get; set; }
- }
-
- public class DisabledProgramSource : ProgramSource { }
}
}
diff --git a/Plugins/Flow.Launcher.Plugin.Program/Views/Commands/ProgramSettingDisplay.cs b/Plugins/Flow.Launcher.Plugin.Program/Views/Commands/ProgramSettingDisplay.cs
index 3129b2b996e..e4d7c323a5f 100644
--- a/Plugins/Flow.Launcher.Plugin.Program/Views/Commands/ProgramSettingDisplay.cs
+++ b/Plugins/Flow.Launcher.Plugin.Program/Views/Commands/ProgramSettingDisplay.cs
@@ -1,146 +1,88 @@
-using System;
-using System.Collections.Generic;
+using System.Collections.Generic;
using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
using Flow.Launcher.Plugin.Program.Views.Models;
namespace Flow.Launcher.Plugin.Program.Views.Commands
{
internal static class ProgramSettingDisplay
{
- internal static List LoadProgramSources(this List programSources)
+ internal static List LoadProgramSources()
{
- var list = new List();
-
- programSources.ForEach(x => list
- .Add(
- new ProgramSource
- {
- Enabled = x.Enabled,
- Location = x.Location,
- Name = x.Name,
- UniqueIdentifier = x.UniqueIdentifier
- }
- ));
-
// Even though these are disabled, we still want to display them so users can enable later on
- Main._settings
- .DisabledProgramSources
- .Where(t1 => !Main._settings
- .ProgramSources // program sourcces added above already, so exlcude
- .Any(x => t1.UniqueIdentifier == x.UniqueIdentifier))
- .Select(x => x)
- .ToList()
- .ForEach(x => list
- .Add(
- new ProgramSource
- {
- Enabled = x.Enabled,
- Location = x.Location,
- Name = x.Name,
- UniqueIdentifier = x.UniqueIdentifier
- }
- ));
-
- return list;
+ return Main._settings
+ .DisabledProgramSources
+ .Union(Main._settings.ProgramSources)
+ .ToList();
}
- internal static void LoadAllApplications(this List list)
+ internal static void DisplayAllPrograms()
{
- Main._win32s
- .Where(t1 => !ProgramSetting.ProgramSettingDisplayList.Any(x => x.UniqueIdentifier == t1.UniqueIdentifier))
- .ToList()
- .ForEach(t1 => ProgramSetting.ProgramSettingDisplayList
- .Add(
- new ProgramSource
- {
- Name = t1.Name,
- Location = t1.ParentDirectory,
- UniqueIdentifier = t1.UniqueIdentifier,
- Enabled = t1.Enabled
- }
- ));
+ var win32 = Main._win32s
+ .Where(t1 => !ProgramSetting.ProgramSettingDisplayList.Any(x => x.UniqueIdentifier == t1.UniqueIdentifier))
+ .Select(x => new ProgramSource(x));
- Main._uwps
- .Where(t1 => !ProgramSetting.ProgramSettingDisplayList.Any(x => x.UniqueIdentifier == t1.UniqueIdentifier))
- .ToList()
- .ForEach(t1 => ProgramSetting.ProgramSettingDisplayList
- .Add(
- new ProgramSource
- {
- Name = t1.DisplayName,
- Location = t1.Package.Location,
- UniqueIdentifier = t1.UniqueIdentifier,
- Enabled = t1.Enabled
- }
- ));
+ var uwp = Main._uwps
+ .Where(t1 => !ProgramSetting.ProgramSettingDisplayList.Any(x => x.UniqueIdentifier == t1.UniqueIdentifier))
+ .Select(x => new ProgramSource(x));
+
+ ProgramSetting.ProgramSettingDisplayList.AddRange(win32);
+ ProgramSetting.ProgramSettingDisplayList.AddRange(uwp);
}
- internal static void SetProgramSourcesStatus(this List list, List selectedProgramSourcesToDisable, bool status)
+ internal static void SetProgramSourcesStatus(List selectedProgramSourcesToDisable, bool status)
{
- ProgramSetting.ProgramSettingDisplayList
- .Where(t1 => selectedProgramSourcesToDisable.Any(x => x.UniqueIdentifier == t1.UniqueIdentifier && t1.Enabled != status))
- .ToList()
- .ForEach(t1 => t1.Enabled = status);
-
- Main._win32s
- .Where(t1 => selectedProgramSourcesToDisable.Any(x => x.UniqueIdentifier == t1.UniqueIdentifier && t1.Enabled != status))
- .ToList()
- .ForEach(t1 => t1.Enabled = status);
-
- Main._uwps
- .Where(t1 => selectedProgramSourcesToDisable.Any(x => x.UniqueIdentifier == t1.UniqueIdentifier && t1.Enabled != status))
- .ToList()
- .ForEach(t1 => t1.Enabled = status);
+ foreach(var program in ProgramSetting.ProgramSettingDisplayList)
+ {
+ if (selectedProgramSourcesToDisable.Any(x => x.UniqueIdentifier == program.UniqueIdentifier && program.Enabled != status))
+ {
+ program.Enabled = status;
+ }
+ }
+
+ foreach(var program in Main._win32s)
+ {
+ if (selectedProgramSourcesToDisable.Any(x => x.UniqueIdentifier == program.UniqueIdentifier && program.Enabled != status))
+ {
+ program.Enabled = status;
+ }
+ }
+
+ foreach (var program in Main._uwps)
+ {
+ if (selectedProgramSourcesToDisable.Any(x => x.UniqueIdentifier == program.UniqueIdentifier && program.Enabled != status))
+ {
+ program.Enabled = status;
+ }
+ }
}
- internal static void StoreDisabledInSettings(this List list)
+ internal static void StoreDisabledInSettings()
{
- Main._settings.ProgramSources
- .Where(t1 => ProgramSetting.ProgramSettingDisplayList.Any(x => x.UniqueIdentifier == t1.UniqueIdentifier && !x.Enabled))
- .ToList()
- .ForEach(t1 => t1.Enabled = false);
-
- ProgramSetting.ProgramSettingDisplayList
+ // Disabled, not in DisabledProgramSources or ProgramSources
+ var tmp = ProgramSetting.ProgramSettingDisplayList
.Where(t1 => !t1.Enabled
- && !Main._settings.DisabledProgramSources.Any(x => x.UniqueIdentifier == t1.UniqueIdentifier))
- .ToList()
- .ForEach(x => Main._settings.DisabledProgramSources
- .Add(
- new Settings.DisabledProgramSource
- {
- Name = x.Name,
- Location = x.Location,
- UniqueIdentifier = x.UniqueIdentifier,
- Enabled = false
- }
- ));
+ && !Main._settings.DisabledProgramSources.Any(x => x.UniqueIdentifier == t1.UniqueIdentifier)
+ && !Main._settings.ProgramSources.Any(x => x.UniqueIdentifier == t1.UniqueIdentifier));
+
+ Main._settings.DisabledProgramSources.AddRange(tmp);
}
- internal static void RemoveDisabledFromSettings(this List list)
+ internal static void RemoveDisabledFromSettings()
{
- Main._settings.ProgramSources
- .Where(t1 => ProgramSetting.ProgramSettingDisplayList.Any(x => x.UniqueIdentifier == t1.UniqueIdentifier && x.Enabled))
- .ToList()
- .ForEach(t1 => t1.Enabled = true);
-
- Main._settings.DisabledProgramSources
- .Where(t1 => ProgramSetting.ProgramSettingDisplayList.Any(x => x.UniqueIdentifier == t1.UniqueIdentifier && x.Enabled))
- .ToList()
- .ForEach(x => Main._settings.DisabledProgramSources.Remove(x));
+ Main._settings.DisabledProgramSources.RemoveAll(t1 => t1.Enabled);
}
internal static bool IsReindexRequired(this List selectedItems)
{
- if (selectedItems.Where(t1 => t1.Enabled && !Main._uwps.Any(x => t1.UniqueIdentifier == x.UniqueIdentifier)).Count() > 0
- && selectedItems.Where(t1 => t1.Enabled && !Main._win32s.Any(x => t1.UniqueIdentifier == x.UniqueIdentifier)).Count() > 0)
+ // Not in cache
+ if (selectedItems.Any(t1 => t1.Enabled && !Main._uwps.Any(x => t1.UniqueIdentifier == x.UniqueIdentifier))
+ && selectedItems.Any(t1 => t1.Enabled && !Main._win32s.Any(x => t1.UniqueIdentifier == x.UniqueIdentifier)))
return true;
// ProgramSources holds list of user added directories,
// so when we enable/disable we need to reindex to show/not show the programs
// that are found in those directories.
- if (selectedItems.Where(t1 => Main._settings.ProgramSources.Any(x => t1.UniqueIdentifier == x.UniqueIdentifier)).Count() > 0)
+ if (selectedItems.Any(t1 => Main._settings.ProgramSources.Any(x => t1.UniqueIdentifier == x.UniqueIdentifier)))
return true;
return false;
diff --git a/Plugins/Flow.Launcher.Plugin.Program/Views/Models/ProgramSource.cs b/Plugins/Flow.Launcher.Plugin.Program/Views/Models/ProgramSource.cs
index 8e3184ff7fb..fb32fb892a7 100644
--- a/Plugins/Flow.Launcher.Plugin.Program/Views/Models/ProgramSource.cs
+++ b/Plugins/Flow.Launcher.Plugin.Program/Views/Models/ProgramSource.cs
@@ -1,5 +1,86 @@
-
+using System;
+using System.IO;
+using System.Text.Json.Serialization;
+using Flow.Launcher.Plugin.Program.Programs;
+
namespace Flow.Launcher.Plugin.Program.Views.Models
{
- public class ProgramSource : Settings.ProgramSource { }
+ ///
+ /// Contains user added folder location contents as well as all user disabled applications
+ ///
+ ///
+ /// Win32 class applications set UniqueIdentifier using their full file path
+ /// UWP class applications set UniqueIdentifier using their Application User Model ID
+ /// Custom user added program sources set UniqueIdentifier using their location
+ ///
+ public class ProgramSource
+ {
+ private string name;
+
+ private string loc;
+ public string Location
+ {
+ get => loc;
+ set
+ {
+ loc = value;
+ UniqueIdentifier = value.ToLowerInvariant();
+ }
+ }
+ public string Name { get => name ?? new DirectoryInfo(Location).Name; set => name = value; }
+ public bool Enabled { get; set; } = true;
+
+ public string UniqueIdentifier { get; private set; }
+
+ [JsonConstructor]
+ public ProgramSource(string name, string location, bool enabled, string uniqueIdentifier)
+ {
+ loc = location;
+ this.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
+ }
+ }
+
+ ///
+ /// Add source by location
+ ///
+ /// location of program source
+ /// enabled
+ public ProgramSource(string location, bool enabled = true)
+ {
+ loc = location;
+ Enabled = enabled;
+ UniqueIdentifier = location.ToLowerInvariant(); // For path comparison
+ }
+
+ public ProgramSource(IProgram source)
+ {
+ loc = source.Location;
+ Name = source.Name;
+ Enabled = source.Enabled;
+ UniqueIdentifier = source.UniqueIdentifier;
+ }
+
+ public override bool Equals(object obj)
+ {
+ return obj is ProgramSource other && other.UniqueIdentifier == this.UniqueIdentifier;
+ }
+
+ public bool Equals(IProgram program)
+ {
+ return program != null && program.UniqueIdentifier == this.UniqueIdentifier;
+ }
+
+ public override int GetHashCode()
+ {
+ return HashCode.Combine(UniqueIdentifier);
+ }
+ }
}
diff --git a/Plugins/Flow.Launcher.Plugin.Program/Views/ProgramSetting.xaml b/Plugins/Flow.Launcher.Plugin.Program/Views/ProgramSetting.xaml
index 4d6db38fdb1..227c23ebc62 100644
--- a/Plugins/Flow.Launcher.Plugin.Program/Views/ProgramSetting.xaml
+++ b/Plugins/Flow.Launcher.Plugin.Program/Views/ProgramSetting.xaml
@@ -146,6 +146,8 @@
Drop="programSourceView_Drop"
GridViewColumnHeader.Click="GridViewColumnHeaderClickedHandler"
PreviewMouseRightButtonUp="ProgramSourceView_PreviewMouseRightButtonUp"
+ MouseDoubleClick="programSourceView_MouseDoubleClick"
+ SelectionChanged="programSourceView_SelectionChanged"
SelectionMode="Extended">
@@ -156,7 +158,7 @@
-
+
_settings.HideAppsPath;
@@ -98,7 +98,7 @@ public ProgramSetting(PluginInitContext context, Settings settings, Win32[] win3
private void Setting_Loaded(object sender, RoutedEventArgs e)
{
- ProgramSettingDisplayList = _settings.ProgramSources.LoadProgramSources();
+ ProgramSettingDisplayList = ProgramSettingDisplay.LoadProgramSources();
programSourceView.ItemsSource = ProgramSettingDisplayList;
ViewRefresh();
@@ -157,20 +157,35 @@ private void DeleteProgramSources(List itemsToDelete)
private void btnEditProgramSource_OnClick(object sender, RoutedEventArgs e)
{
- var selectedProgramSource = programSourceView.SelectedItem as Settings.ProgramSource;
- if (selectedProgramSource != null)
+ var selectedProgramSource = programSourceView.SelectedItem as ProgramSource;
+ EditProgramSource(selectedProgramSource);
+ }
+
+ private void EditProgramSource(ProgramSource selectedProgramSource)
+ {
+ if (selectedProgramSource == null)
{
- var add = new AddProgramSource(selectedProgramSource, _settings);
+ string msg = context.API.GetTranslation("flowlauncher_plugin_program_pls_select_program_source");
+ MessageBox.Show(msg);
+ }
+ else
+ {
+ var add = new AddProgramSource(context, _settings, selectedProgramSource);
if (add.ShowDialog() ?? false)
{
+ if (selectedProgramSource.Enabled)
+ {
+ ProgramSettingDisplay.SetProgramSourcesStatus(new List { selectedProgramSource }, true); // sync status in win32, uwp and disabled
+ ProgramSettingDisplay.RemoveDisabledFromSettings();
+ }
+ else
+ {
+ ProgramSettingDisplay.SetProgramSourcesStatus(new List { selectedProgramSource }, false);
+ ProgramSettingDisplay.StoreDisabledInSettings();
+ }
ReIndexing();
}
}
- else
- {
- string msg = context.API.GetTranslation("flowlauncher_plugin_program_pls_select_program_source");
- MessageBox.Show(msg);
- }
}
private void btnReindex_Click(object sender, RoutedEventArgs e)
@@ -209,19 +224,16 @@ private void programSourceView_Drop(object sender, DragEventArgs e)
{
foreach (string directory in directories)
{
- if (Directory.Exists(directory) && !ProgramSettingDisplayList.Any(x => x.UniqueIdentifier == directory))
+ if (Directory.Exists(directory)
+ && !ProgramSettingDisplayList.Any(x => x.UniqueIdentifier.Equals(directory, System.StringComparison.OrdinalIgnoreCase)))
{
- var source = new ProgramSource
- {
- Location = directory,
- UniqueIdentifier = directory
- };
+ var source = new ProgramSource(directory);
directoriesToAdd.Add(source);
}
}
- if (directoriesToAdd.Count() > 0)
+ if (directoriesToAdd.Count > 0)
{
directoriesToAdd.ForEach(x => _settings.ProgramSources.Add(x));
directoriesToAdd.ForEach(x => ProgramSettingDisplayList.Add(x));
@@ -234,7 +246,7 @@ private void programSourceView_Drop(object sender, DragEventArgs e)
private void btnLoadAllProgramSource_OnClick(object sender, RoutedEventArgs e)
{
- ProgramSettingDisplayList.LoadAllApplications();
+ ProgramSettingDisplay.DisplayAllPrograms();
ViewRefresh();
}
@@ -245,18 +257,14 @@ private void btnProgramSourceStatus_OnClick(object sender, RoutedEventArgs e)
.SelectedItems.Cast()
.ToList();
- if (selectedItems.Count() == 0)
+ if (selectedItems.Count == 0)
{
string msg = context.API.GetTranslation("flowlauncher_plugin_program_pls_select_program_source");
MessageBox.Show(msg);
return;
}
- if (selectedItems
- .Where(t1 => !_settings
- .ProgramSources
- .Any(x => t1.UniqueIdentifier == x.UniqueIdentifier))
- .Count() == 0)
+ if (IsAllItemsUserAdded(selectedItems))
{
var msg = string.Format(context.API.GetTranslation("flowlauncher_plugin_program_delete_program_source"));
@@ -267,17 +275,17 @@ private void btnProgramSourceStatus_OnClick(object sender, RoutedEventArgs e)
DeleteProgramSources(selectedItems);
}
- else if (IsSelectedRowStatusEnabledMoreOrEqualThanDisabled(selectedItems))
+ else if (HasMoreOrEqualEnabledItems(selectedItems))
{
- ProgramSettingDisplayList.SetProgramSourcesStatus(selectedItems, false);
+ ProgramSettingDisplay.SetProgramSourcesStatus(selectedItems, false);
- ProgramSettingDisplayList.StoreDisabledInSettings();
+ ProgramSettingDisplay.StoreDisabledInSettings();
}
else
{
- ProgramSettingDisplayList.SetProgramSourcesStatus(selectedItems, true);
+ ProgramSettingDisplay.SetProgramSourcesStatus(selectedItems, true);
- ProgramSettingDisplayList.RemoveDisabledFromSettings();
+ ProgramSettingDisplay.RemoveDisabledFromSettings();
}
if (selectedItems.IsReindexRequired())
@@ -339,35 +347,41 @@ private void Sort(string sortBy, ListSortDirection direction)
dataView.Refresh();
}
- private bool IsSelectedRowStatusEnabledMoreOrEqualThanDisabled(List selectedItems)
+ private static bool HasMoreOrEqualEnabledItems(List items)
{
- return selectedItems.Where(x => x.Enabled).Count() >= selectedItems.Where(x => !x.Enabled).Count();
+ var enableCount = items.Where(x => x.Enabled).Count();
+ return enableCount >= items.Count - enableCount;
}
- private void Row_OnClick(object sender, RoutedEventArgs e)
+ private void programSourceView_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
var selectedItems = programSourceView
- .SelectedItems.Cast()
- .ToList();
-
- if (selectedItems
- .Where(t1 => !_settings
- .ProgramSources
- .Any(x => t1.UniqueIdentifier == x.UniqueIdentifier))
- .Count() == 0)
+ .SelectedItems.Cast()
+ .ToList();
+
+ if (IsAllItemsUserAdded(selectedItems))
{
btnProgramSourceStatus.Content = context.API.GetTranslation("flowlauncher_plugin_program_delete");
- return;
}
-
- if (IsSelectedRowStatusEnabledMoreOrEqualThanDisabled(selectedItems))
+ else if (HasMoreOrEqualEnabledItems(selectedItems))
{
- btnProgramSourceStatus.Content = "Disable";
+ btnProgramSourceStatus.Content = context.API.GetTranslation("flowlauncher_plugin_program_disable");
}
else
{
- btnProgramSourceStatus.Content = "Enable";
+ btnProgramSourceStatus.Content = context.API.GetTranslation("flowlauncher_plugin_program_enable");
}
}
+
+ private void programSourceView_MouseDoubleClick(object sender, MouseButtonEventArgs e)
+ {
+ var selectedProgramSource = programSourceView.SelectedItem as ProgramSource;
+ EditProgramSource(selectedProgramSource);
+ }
+
+ private bool IsAllItemsUserAdded(List items)
+ {
+ return items.All(x => _settings.ProgramSources.Any(y => y.UniqueIdentifier == x.UniqueIdentifier));
+ }
}
}