mirror of
https://github.com/Flow-Launcher/Flow.Launcher.git
synced 2026-03-11 08:54:32 +00:00
Merge Dev
This commit is contained in:
commit
c7eb4e213c
22 changed files with 586 additions and 552 deletions
|
|
@ -58,7 +58,7 @@
|
||||||
<PackageReference Include="NLog.Schema" Version="4.7.10" />
|
<PackageReference Include="NLog.Schema" Version="4.7.10" />
|
||||||
<PackageReference Include="NLog.Web.AspNetCore" Version="4.13.0" />
|
<PackageReference Include="NLog.Web.AspNetCore" Version="4.13.0" />
|
||||||
<PackageReference Include="PropertyChanged.Fody" Version="3.4.0" />
|
<PackageReference Include="PropertyChanged.Fody" Version="3.4.0" />
|
||||||
<PackageReference Include="System.Drawing.Common" Version="5.0.2" />
|
<PackageReference Include="System.Drawing.Common" Version="5.0.3" />
|
||||||
<!--ToolGood.Words.Pinyin v3.0.2.6 results in high memory usage when search with pinyin is enabled-->
|
<!--ToolGood.Words.Pinyin v3.0.2.6 results in high memory usage when search with pinyin is enabled-->
|
||||||
<!--Bumping to it or higher needs to test and ensure this is no longer a problem-->
|
<!--Bumping to it or higher needs to test and ensure this is no longer a problem-->
|
||||||
<PackageReference Include="ToolGood.Words.Pinyin" Version="3.0.1.4" />
|
<PackageReference Include="ToolGood.Words.Pinyin" Version="3.0.1.4" />
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,7 @@ namespace Flow.Launcher.Test.Plugins
|
||||||
var app = new UWP.Application();
|
var app = new UWP.Application();
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
var result = app.FormattedPriReferenceValue(packageName, rawPriReferenceValue);
|
var result = UWP.Application.FormattedPriReferenceValue(packageName, rawPriReferenceValue);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
Assert.IsTrue(result == expectedFormat,
|
Assert.IsTrue(result == expectedFormat,
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
using Flow.Launcher.Plugin.BrowserBookmark.Models;
|
using Flow.Launcher.Plugin.BrowserBookmark.Models;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Data.SQLite;
|
using System.Data.SQLite;
|
||||||
|
|
@ -130,4 +130,4 @@ namespace Flow.Launcher.Plugin.BrowserBookmark
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,8 @@
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<OutputType>Library</OutputType>
|
<OutputType>Library</OutputType>
|
||||||
<TargetFramework>net6.0-windows</TargetFramework>
|
<TargetFramework>net6.0-windows</TargetFramework>
|
||||||
<UseWPF>true</UseWPF>
|
<RuntimeIdentifier>win-x64</RuntimeIdentifier>
|
||||||
|
<UseWPF>true</UseWPF>
|
||||||
<ProjectGuid>{9B130CC5-14FB-41FF-B310-0A95B6894C37}</ProjectGuid>
|
<ProjectGuid>{9B130CC5-14FB-41FF-B310-0A95B6894C37}</ProjectGuid>
|
||||||
<AppDesignerFolder>Properties</AppDesignerFolder>
|
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||||
<RootNamespace>Flow.Launcher.Plugin.BrowserBookmark</RootNamespace>
|
<RootNamespace>Flow.Launcher.Plugin.BrowserBookmark</RootNamespace>
|
||||||
|
|
@ -23,7 +24,7 @@
|
||||||
<WarningLevel>4</WarningLevel>
|
<WarningLevel>4</WarningLevel>
|
||||||
<Prefer32Bit>false</Prefer32Bit>
|
<Prefer32Bit>false</Prefer32Bit>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||||
<DebugType>pdbonly</DebugType>
|
<DebugType>pdbonly</DebugType>
|
||||||
<Optimize>true</Optimize>
|
<Optimize>true</Optimize>
|
||||||
|
|
@ -39,15 +40,6 @@
|
||||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
</None>
|
</None>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
|
||||||
<Content Include="x64\SQLite.Interop.dll">
|
|
||||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
|
||||||
</Content>
|
|
||||||
<Content Include="x86\SQLite.Interop.dll">
|
|
||||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
|
||||||
</Content>
|
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\..\Flow.Launcher.Infrastructure\Flow.Launcher.Infrastructure.csproj" />
|
<ProjectReference Include="..\..\Flow.Launcher.Infrastructure\Flow.Launcher.Infrastructure.csproj" />
|
||||||
|
|
@ -64,8 +56,8 @@
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="System.Data.SQLite" Version="1.0.114.4" />
|
<PackageReference Include="System.Data.SQLite" Version="1.0.116" />
|
||||||
<PackageReference Include="System.Data.SQLite.Core" Version="1.0.114.3" />
|
<PackageReference Include="System.Data.SQLite.Core" Version="1.0.116" />
|
||||||
<PackageReference Include="UnidecodeSharp" Version="1.0.0" />
|
<PackageReference Include="UnidecodeSharp" Version="1.0.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
|
|
||||||
Binary file not shown.
Binary file not shown.
|
|
@ -10,8 +10,7 @@
|
||||||
Foreground="{DynamicResource PopupTextColor}"
|
Foreground="{DynamicResource PopupTextColor}"
|
||||||
ResizeMode="NoResize"
|
ResizeMode="NoResize"
|
||||||
SizeToContent="WidthAndHeight"
|
SizeToContent="WidthAndHeight"
|
||||||
WindowStartupLocation="CenterScreen"
|
WindowStartupLocation="CenterScreen">
|
||||||
mc:Ignorable="d">
|
|
||||||
<WindowChrome.WindowChrome>
|
<WindowChrome.WindowChrome>
|
||||||
<WindowChrome CaptionHeight="32" ResizeBorderThickness="{x:Static SystemParameters.WindowResizeBorderThickness}" />
|
<WindowChrome CaptionHeight="32" ResizeBorderThickness="{x:Static SystemParameters.WindowResizeBorderThickness}" />
|
||||||
</WindowChrome.WindowChrome>
|
</WindowChrome.WindowChrome>
|
||||||
|
|
@ -20,7 +19,6 @@
|
||||||
<RowDefinition />
|
<RowDefinition />
|
||||||
<RowDefinition Height="80" />
|
<RowDefinition Height="80" />
|
||||||
</Grid.RowDefinitions>
|
</Grid.RowDefinitions>
|
||||||
|
|
||||||
<StackPanel Grid.Row="0">
|
<StackPanel Grid.Row="0">
|
||||||
<StackPanel>
|
<StackPanel>
|
||||||
<Grid>
|
<Grid>
|
||||||
|
|
@ -54,42 +52,78 @@
|
||||||
</Button>
|
</Button>
|
||||||
</Grid>
|
</Grid>
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
<StackPanel Margin="26,12,26,0">
|
<StackPanel Margin="26,0,26,0">
|
||||||
<StackPanel Margin="0,0,0,12">
|
<StackPanel Grid.Row="0" Margin="0,0,0,12">
|
||||||
<TextBlock
|
<TextBlock
|
||||||
Grid.Column="0"
|
Grid.Column="0"
|
||||||
Margin="0,0,0,0"
|
Margin="0,0,0,0"
|
||||||
FontSize="20"
|
FontSize="20"
|
||||||
FontWeight="SemiBold"
|
FontWeight="SemiBold"
|
||||||
Text="{DynamicResource flowlauncher_plugin_program_directory}"
|
Text="{DynamicResource flowlauncher_plugin_program_edit_program_source_title}"
|
||||||
TextAlignment="Left" />
|
TextAlignment="Left" />
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
<StackPanel Margin="0,0,0,10" Orientation="Horizontal">
|
<StackPanel>
|
||||||
<Grid>
|
<TextBlock
|
||||||
|
FontSize="14"
|
||||||
|
Text="{DynamicResource flowlauncher_plugin_program_edit_program_source_tips}"
|
||||||
|
TextAlignment="Left"
|
||||||
|
TextWrapping="WrapWithOverflow" />
|
||||||
|
</StackPanel>
|
||||||
|
|
||||||
|
<StackPanel Margin="0,10,0,0" Orientation="Horizontal">
|
||||||
|
<Grid Width="470">
|
||||||
|
<Grid.RowDefinitions>
|
||||||
|
<RowDefinition />
|
||||||
|
<RowDefinition />
|
||||||
|
</Grid.RowDefinitions>
|
||||||
<Grid.ColumnDefinitions>
|
<Grid.ColumnDefinitions>
|
||||||
<ColumnDefinition Width="*" />
|
|
||||||
<ColumnDefinition Width="Auto" />
|
<ColumnDefinition Width="Auto" />
|
||||||
|
<ColumnDefinition Width="*" />
|
||||||
</Grid.ColumnDefinitions>
|
</Grid.ColumnDefinitions>
|
||||||
<TextBox
|
<TextBlock
|
||||||
Name="Directory"
|
Grid.Row="0"
|
||||||
Grid.Column="0"
|
Grid.Column="0"
|
||||||
MinWidth="248"
|
Margin="10"
|
||||||
Margin="0,7"
|
HorizontalAlignment="Left"
|
||||||
VerticalAlignment="Center" />
|
VerticalAlignment="Center"
|
||||||
<Button
|
FontSize="14"
|
||||||
|
Text="{DynamicResource flowlauncher_plugin_program_directory}" />
|
||||||
|
<DockPanel
|
||||||
|
Grid.Row="0"
|
||||||
|
Grid.Column="1"
|
||||||
|
LastChildFill="True">
|
||||||
|
<Button
|
||||||
|
Width="70"
|
||||||
|
HorizontalAlignment="Right"
|
||||||
|
Click="BrowseButton_Click"
|
||||||
|
DockPanel.Dock="Right"
|
||||||
|
Content="{DynamicResource flowlauncher_plugin_program_browse}" />
|
||||||
|
<TextBox
|
||||||
|
Name="Directory"
|
||||||
|
Margin="10"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
HorizontalAlignment="Stretch" />
|
||||||
|
</DockPanel>
|
||||||
|
<TextBlock
|
||||||
|
Grid.Row="1"
|
||||||
|
Grid.Column="0"
|
||||||
|
Margin="10"
|
||||||
|
HorizontalAlignment="Left"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
FontSize="14"
|
||||||
|
Text="{DynamicResource flowlauncher_plugin_program_enabled}" />
|
||||||
|
<CheckBox x:Name="Chkbox"
|
||||||
|
Grid.Row="1"
|
||||||
Grid.Column="1"
|
Grid.Column="1"
|
||||||
MinWidth="80"
|
Margin="10,0"
|
||||||
Margin="10,10,0,10"
|
VerticalAlignment="Center" />
|
||||||
Padding="14,6,14,6"
|
|
||||||
HorizontalAlignment="Right"
|
|
||||||
Click="BrowseButton_Click"
|
|
||||||
Content="{DynamicResource flowlauncher_plugin_program_browse}" />
|
|
||||||
</Grid>
|
</Grid>
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
<Border
|
<Border
|
||||||
Grid.Row="1"
|
Grid.Row="1"
|
||||||
|
Margin="0,14,0,0"
|
||||||
Background="{DynamicResource PopupButtonAreaBGColor}"
|
Background="{DynamicResource PopupButtonAreaBGColor}"
|
||||||
BorderBrush="{DynamicResource PopupButtonAreaBorderColor}"
|
BorderBrush="{DynamicResource PopupButtonAreaBorderColor}"
|
||||||
BorderThickness="0,1,0,0">
|
BorderThickness="0,1,0,0">
|
||||||
|
|
@ -97,19 +131,17 @@
|
||||||
<Button
|
<Button
|
||||||
x:Name="btnCancel"
|
x:Name="btnCancel"
|
||||||
MinWidth="140"
|
MinWidth="140"
|
||||||
Margin="0,0,5,0"
|
Margin="10,0,5,0"
|
||||||
Click="BtnCancel_OnClick"
|
Click="BtnCancel_OnClick"
|
||||||
Content="{DynamicResource cancel}" />
|
Content="{DynamicResource cancel}" />
|
||||||
|
|
||||||
<Button
|
<Button
|
||||||
|
x:Name="btnAdd"
|
||||||
MinWidth="140"
|
MinWidth="140"
|
||||||
Margin="5,0,0,0"
|
Margin="5,0,10,0"
|
||||||
HorizontalAlignment="Right"
|
Click="BtnAdd_OnClick"
|
||||||
Click="ButtonAdd_OnClick"
|
|
||||||
Content="{DynamicResource flowlauncher_plugin_program_update}"
|
Content="{DynamicResource flowlauncher_plugin_program_update}"
|
||||||
Style="{DynamicResource AccentButtonStyle}" />
|
Style="{DynamicResource AccentButtonStyle}" />
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
</Border>
|
</Border>
|
||||||
</Grid>
|
</Grid>
|
||||||
|
</Window>
|
||||||
</Window>
|
|
||||||
|
|
@ -9,11 +9,12 @@ namespace Flow.Launcher.Plugin.Program
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Interaction logic for AddProgramSource.xaml
|
/// Interaction logic for AddProgramSource.xaml
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public partial class AddProgramSource
|
public partial class AddProgramSource : Window
|
||||||
{
|
{
|
||||||
private PluginInitContext _context;
|
private PluginInitContext _context;
|
||||||
private Settings.ProgramSource _editing;
|
private ProgramSource _editing;
|
||||||
private Settings _settings;
|
private Settings _settings;
|
||||||
|
private bool update;
|
||||||
|
|
||||||
public AddProgramSource(PluginInitContext context, Settings settings)
|
public AddProgramSource(PluginInitContext context, Settings settings)
|
||||||
{
|
{
|
||||||
|
|
@ -21,14 +22,19 @@ namespace Flow.Launcher.Plugin.Program
|
||||||
_context = context;
|
_context = context;
|
||||||
_settings = settings;
|
_settings = settings;
|
||||||
Directory.Focus();
|
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();
|
InitializeComponent();
|
||||||
|
_context = context;
|
||||||
|
_editing = source;
|
||||||
|
_settings = settings;
|
||||||
|
update = true;
|
||||||
|
Chkbox.IsChecked = _editing.Enabled;
|
||||||
Directory.Text = _editing.Location;
|
Directory.Text = _editing.Location;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -47,34 +53,54 @@ namespace Flow.Launcher.Plugin.Program
|
||||||
Close();
|
Close();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ButtonAdd_OnClick(object sender, RoutedEventArgs e)
|
private void BtnAdd_OnClick(object sender, RoutedEventArgs e)
|
||||||
{
|
{
|
||||||
string s = Directory.Text;
|
string path = Directory.Text;
|
||||||
if (!System.IO.Directory.Exists(s))
|
bool modified = false;
|
||||||
|
if (!System.IO.Directory.Exists(path))
|
||||||
{
|
{
|
||||||
System.Windows.MessageBox.Show(_context.API.GetTranslation("flowlauncher_plugin_program_invalid_path"));
|
System.Windows.MessageBox.Show(_context.API.GetTranslation("flowlauncher_plugin_program_invalid_path"));
|
||||||
return;
|
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
|
var source = new ProgramSource(path);
|
||||||
{
|
modified = true;
|
||||||
Location = Directory.Text,
|
|
||||||
UniqueIdentifier = Directory.Text
|
|
||||||
};
|
|
||||||
|
|
||||||
_settings.ProgramSources.Insert(0, source);
|
_settings.ProgramSources.Insert(0, source);
|
||||||
ProgramSetting.ProgramSettingDisplayList.Add(source);
|
ProgramSetting.ProgramSettingDisplayList.Add(source);
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
System.Windows.MessageBox.Show(_context.API.GetTranslation("flowlauncher_plugin_program_duplicate_program_source"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
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();
|
Close();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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<string> WatchedPath = new List<string>();
|
|
||||||
// // todo remove previous watcher events
|
|
||||||
// public static void AddAll(List<UnregisteredPrograms> 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();
|
|
||||||
// });
|
|
||||||
// }
|
|
||||||
//}
|
|
||||||
}
|
|
||||||
|
|
@ -10,16 +10,21 @@
|
||||||
<system:String x:Key="flowlauncher_plugin_program_add">Add</system:String>
|
<system:String x:Key="flowlauncher_plugin_program_add">Add</system:String>
|
||||||
<system:String x:Key="flowlauncher_plugin_program_name">Name</system:String>
|
<system:String x:Key="flowlauncher_plugin_program_name">Name</system:String>
|
||||||
<system:String x:Key="flowlauncher_plugin_program_enable">Enable</system:String>
|
<system:String x:Key="flowlauncher_plugin_program_enable">Enable</system:String>
|
||||||
|
<system:String x:Key="flowlauncher_plugin_program_enabled">Enabled</system:String>
|
||||||
<system:String x:Key="flowlauncher_plugin_program_disable">Disable</system:String>
|
<system:String x:Key="flowlauncher_plugin_program_disable">Disable</system:String>
|
||||||
<system:String x:Key="flowlauncher_plugin_program_location">Location</system:String>
|
<system:String x:Key="flowlauncher_plugin_program_location">Location</system:String>
|
||||||
<system:String x:Key="flowlauncher_plugin_program_all_programs">All Programs</system:String>
|
<system:String x:Key="flowlauncher_plugin_program_all_programs">All Programs</system:String>
|
||||||
<system:String x:Key="flowlauncher_plugin_program_suffixes">File Type</system:String>
|
<system:String x:Key="flowlauncher_plugin_program_suffixes">File Type</system:String>
|
||||||
<system:String x:Key="flowlauncher_plugin_program_reindex">Reindex</system:String>
|
<system:String x:Key="flowlauncher_plugin_program_reindex">Reindex</system:String>
|
||||||
<system:String x:Key="flowlauncher_plugin_program_indexing">Indexing</system:String>
|
<system:String x:Key="flowlauncher_plugin_program_indexing">Indexing</system:String>
|
||||||
<system:String x:Key="flowlauncher_plugin_program_index_start">Index Start Menu</system:String>
|
<system:String x:Key="flowlauncher_plugin_program_index_source">Index Sources</system:String>
|
||||||
|
<system:String x:Key="flowlauncher_plugin_program_index_option">Options</system:String>
|
||||||
|
<system:String x:Key="flowlauncher_plugin_program_index_start">Start Menu</system:String>
|
||||||
<system:String x:Key="flowlauncher_plugin_program_index_start_tooltip">When enabled, Flow will load programs from the start menu</system:String>
|
<system:String x:Key="flowlauncher_plugin_program_index_start_tooltip">When enabled, Flow will load programs from the start menu</system:String>
|
||||||
<system:String x:Key="flowlauncher_plugin_program_index_registry">Index Registry</system:String>
|
<system:String x:Key="flowlauncher_plugin_program_index_registry">Registry</system:String>
|
||||||
<system:String x:Key="flowlauncher_plugin_program_index_registry_tooltip">When enabled, Flow will load programs from the registry</system:String>
|
<system:String x:Key="flowlauncher_plugin_program_index_registry_tooltip">When enabled, Flow will load programs from the registry</system:String>
|
||||||
|
<system:String x:Key="flowlauncher_plugin_program_index_PATH">PATH</system:String>
|
||||||
|
<system:String x:Key="flowlauncher_plugin_program_index_PATH_tooltip">When enabled, Flow will load programs from the PATH environment variable</system:String>
|
||||||
<system:String x:Key="flowlauncher_plugin_program_enable_hidelnkpath">Hide app path</system:String>
|
<system:String x:Key="flowlauncher_plugin_program_enable_hidelnkpath">Hide app path</system:String>
|
||||||
<system:String x:Key="flowlauncher_plugin_program_enable_hidelnkpath_tooltip">For executable files such as UWP or lnk, hide the file path from being visible</system:String>
|
<system:String x:Key="flowlauncher_plugin_program_enable_hidelnkpath_tooltip">For executable files such as UWP or lnk, hide the file path from being visible</system:String>
|
||||||
<system:String x:Key="flowlauncher_plugin_program_enable_description">Search in Program Description</system:String>
|
<system:String x:Key="flowlauncher_plugin_program_enable_description">Search in Program Description</system:String>
|
||||||
|
|
@ -34,8 +39,12 @@
|
||||||
|
|
||||||
<system:String x:Key="flowlauncher_plugin_program_pls_select_program_source">Please select a program source</system:String>
|
<system:String x:Key="flowlauncher_plugin_program_pls_select_program_source">Please select a program source</system:String>
|
||||||
<system:String x:Key="flowlauncher_plugin_program_delete_program_source">Are you sure you want to delete the selected program sources?</system:String>
|
<system:String x:Key="flowlauncher_plugin_program_delete_program_source">Are you sure you want to delete the selected program sources?</system:String>
|
||||||
|
<system:String x:Key="flowlauncher_plugin_program_duplicate_program_source">Another program source with the same location alreaday exists.</system:String>
|
||||||
|
|
||||||
<system:String x:Key="flowlauncher_plugin_program_update">OK</system:String>
|
<system:String x:Key="flowlauncher_plugin_program_edit_program_source_title">Program Source</system:String>
|
||||||
|
<system:String x:Key="flowlauncher_plugin_program_edit_program_source_tips">Edit directory and status of this program source.</system:String>
|
||||||
|
|
||||||
|
<system:String x:Key="flowlauncher_plugin_program_update">Update</system:String>
|
||||||
<system:String x:Key="flowlauncher_plugin_program_only_index_tip">Program Plugin will only index files with selected suffixes and .url files with selected protocols.</system:String>
|
<system:String x:Key="flowlauncher_plugin_program_only_index_tip">Program Plugin will only index files with selected suffixes and .url files with selected protocols.</system:String>
|
||||||
<system:String x:Key="flowlauncher_plugin_program_update_file_suffixes">Successfully updated file suffixes</system:String>
|
<system:String x:Key="flowlauncher_plugin_program_update_file_suffixes">Successfully updated file suffixes</system:String>
|
||||||
<system:String x:Key="flowlauncher_plugin_program_suffixes_cannot_empty">File suffixes can't be empty</system:String>
|
<system:String x:Key="flowlauncher_plugin_program_suffixes_cannot_empty">File suffixes can't be empty</system:String>
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,8 @@
|
||||||
using NLog;
|
using NLog;
|
||||||
using NLog.Config;
|
|
||||||
using NLog.Targets;
|
|
||||||
using System;
|
using System;
|
||||||
using System.Diagnostics;
|
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
using System.Security;
|
using System.Security;
|
||||||
using Flow.Launcher.Infrastructure;
|
|
||||||
using Flow.Launcher.Infrastructure.UserSettings;
|
|
||||||
|
|
||||||
namespace Flow.Launcher.Plugin.Program.Logger
|
namespace Flow.Launcher.Plugin.Program.Logger
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,5 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Concurrent;
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Collections.Specialized;
|
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
|
|
@ -11,9 +9,8 @@ using Flow.Launcher.Infrastructure.Logger;
|
||||||
using Flow.Launcher.Infrastructure.Storage;
|
using Flow.Launcher.Infrastructure.Storage;
|
||||||
using Flow.Launcher.Plugin.Program.Programs;
|
using Flow.Launcher.Plugin.Program.Programs;
|
||||||
using Flow.Launcher.Plugin.Program.Views;
|
using Flow.Launcher.Plugin.Program.Views;
|
||||||
|
using Flow.Launcher.Plugin.Program.Views.Models;
|
||||||
using Microsoft.Extensions.Caching.Memory;
|
using Microsoft.Extensions.Caching.Memory;
|
||||||
using Microsoft.Extensions.Configuration;
|
|
||||||
using Microsoft.Extensions.Primitives;
|
|
||||||
using Stopwatch = Flow.Launcher.Infrastructure.Stopwatch;
|
using Stopwatch = Flow.Launcher.Infrastructure.Stopwatch;
|
||||||
|
|
||||||
namespace Flow.Launcher.Plugin.Program
|
namespace Flow.Launcher.Plugin.Program
|
||||||
|
|
@ -82,13 +79,9 @@ namespace Flow.Launcher.Plugin.Program
|
||||||
Stopwatch.Normal("|Flow.Launcher.Plugin.Program.Main|Preload programs cost", () =>
|
Stopwatch.Normal("|Flow.Launcher.Plugin.Program.Main|Preload programs cost", () =>
|
||||||
{
|
{
|
||||||
_win32Storage = new BinaryStorage<Win32[]>("Win32");
|
_win32Storage = new BinaryStorage<Win32[]>("Win32");
|
||||||
_win32s = _win32Storage.TryLoad(new Win32[]
|
_win32s = _win32Storage.TryLoad(Array.Empty<Win32>());
|
||||||
{
|
|
||||||
});
|
|
||||||
_uwpStorage = new BinaryStorage<UWP.Application[]>("UWP");
|
_uwpStorage = new BinaryStorage<UWP.Application[]>("UWP");
|
||||||
_uwps = _uwpStorage.TryLoad(new UWP.Application[]
|
_uwps = _uwpStorage.TryLoad(Array.Empty<UWP.Application>());
|
||||||
{
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
Log.Info($"|Flow.Launcher.Plugin.Program.Main|Number of preload win32 programs <{_win32s.Length}>");
|
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}>");
|
Log.Info($"|Flow.Launcher.Plugin.Program.Main|Number of preload uwps <{_uwps.Length}>");
|
||||||
|
|
@ -102,7 +95,7 @@ namespace Flow.Launcher.Plugin.Program
|
||||||
|
|
||||||
var b = Task.Run(() =>
|
var b = Task.Run(() =>
|
||||||
{
|
{
|
||||||
Stopwatch.Normal("|Flow.Launcher.Plugin.Program.Main|Win32Program index cost", IndexUwpPrograms);
|
Stopwatch.Normal("|Flow.Launcher.Plugin.Program.Main|UWPPRogram index cost", IndexUwpPrograms);
|
||||||
});
|
});
|
||||||
|
|
||||||
if (cacheEmpty)
|
if (cacheEmpty)
|
||||||
|
|
@ -123,18 +116,23 @@ namespace Flow.Launcher.Plugin.Program
|
||||||
{
|
{
|
||||||
var windows10 = new Version(10, 0);
|
var windows10 = new Version(10, 0);
|
||||||
var support = Environment.OSVersion.Version.Major >= windows10.Major;
|
var support = Environment.OSVersion.Version.Major >= windows10.Major;
|
||||||
var applications = support ? UWP.All() : new UWP.Application[]
|
var applications = support ? UWP.All() : Array.Empty<UWP.Application>();
|
||||||
{
|
|
||||||
};
|
|
||||||
_uwps = applications;
|
_uwps = applications;
|
||||||
ResetCache();
|
ResetCache();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static async Task IndexProgramsAsync()
|
public static async Task IndexProgramsAsync()
|
||||||
{
|
{
|
||||||
var t1 = Task.Run(IndexWin32Programs);
|
var a = Task.Run(() =>
|
||||||
var t2 = Task.Run(IndexUwpPrograms);
|
{
|
||||||
await Task.WhenAll(t1, t2).ConfigureAwait(false);
|
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;
|
_settings.LastIndexTime = DateTime.Today;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -190,29 +188,33 @@ namespace Flow.Launcher.Plugin.Program
|
||||||
return menuOptions;
|
return menuOptions;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void DisableProgram(IProgram programToDelete)
|
private static void DisableProgram(IProgram programToDelete)
|
||||||
{
|
{
|
||||||
if (_settings.DisabledProgramSources.Any(x => x.UniqueIdentifier == programToDelete.UniqueIdentifier))
|
if (_settings.DisabledProgramSources.Any(x => x.UniqueIdentifier == programToDelete.UniqueIdentifier))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (_uwps.Any(x => x.UniqueIdentifier == programToDelete.UniqueIdentifier))
|
if (_uwps.Any(x => x.UniqueIdentifier == programToDelete.UniqueIdentifier))
|
||||||
_uwps.FirstOrDefault(x => x.UniqueIdentifier == programToDelete.UniqueIdentifier)
|
{
|
||||||
.Enabled = false;
|
var program = _uwps.First(x => x.UniqueIdentifier == programToDelete.UniqueIdentifier);
|
||||||
|
program.Enabled = false;
|
||||||
if (_win32s.Any(x => x.UniqueIdentifier == programToDelete.UniqueIdentifier))
|
_settings.DisabledProgramSources.Add(new ProgramSource(program));
|
||||||
_win32s.FirstOrDefault(x => x.UniqueIdentifier == programToDelete.UniqueIdentifier)
|
_ = Task.Run(() =>
|
||||||
.Enabled = false;
|
{
|
||||||
|
IndexUwpPrograms();
|
||||||
_settings.DisabledProgramSources
|
_settings.LastIndexTime = DateTime.Today;
|
||||||
.Add(
|
});
|
||||||
new Settings.DisabledProgramSource
|
}
|
||||||
{
|
else if (_win32s.Any(x => x.UniqueIdentifier == programToDelete.UniqueIdentifier))
|
||||||
Name = programToDelete.Name,
|
{
|
||||||
Location = programToDelete.Location,
|
var program = _win32s.First(x => x.UniqueIdentifier == programToDelete.UniqueIdentifier);
|
||||||
UniqueIdentifier = programToDelete.UniqueIdentifier,
|
program.Enabled = false;
|
||||||
Enabled = false
|
_settings.DisabledProgramSources.Add(new ProgramSource(program));
|
||||||
}
|
_ = Task.Run(() =>
|
||||||
);
|
{
|
||||||
|
IndexWin32Programs();
|
||||||
|
_settings.LastIndexTime = DateTime.Today;
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void StartProcess(Func<ProcessStartInfo, Process> runProcess, ProcessStartInfo info)
|
public static void StartProcess(Func<ProcessStartInfo, Process> runProcess, ProcessStartInfo info)
|
||||||
|
|
@ -233,6 +235,7 @@ namespace Flow.Launcher.Plugin.Program
|
||||||
{
|
{
|
||||||
await IndexProgramsAsync();
|
await IndexProgramsAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
{
|
{
|
||||||
Win32.Dispose();
|
Win32.Dispose();
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,6 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Diagnostics;
|
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
using System.Text.RegularExpressions;
|
|
||||||
|
|
||||||
namespace Flow.Launcher.Plugin.Program.Programs
|
namespace Flow.Launcher.Plugin.Program.Programs
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -1,20 +1,18 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Text;
|
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
using System.Runtime.InteropServices.ComTypes;
|
using System.Runtime.InteropServices.ComTypes;
|
||||||
using Windows.Storage;
|
|
||||||
|
|
||||||
namespace Flow.Launcher.Plugin.Program.Programs
|
namespace Flow.Launcher.Plugin.Program.Programs
|
||||||
{
|
{
|
||||||
public class AppxPackageHelper
|
public class AppxPackageHelper
|
||||||
{
|
{
|
||||||
// This function returns a list of attributes of applications
|
// This function returns a list of attributes of applications
|
||||||
public List<IAppxManifestApplication> getAppsFromManifest(IStream stream)
|
public static List<IAppxManifestApplication> GetAppsFromManifest(IStream stream)
|
||||||
{
|
{
|
||||||
|
IAppxFactory appxFactory = (IAppxFactory)new AppxFactory();
|
||||||
List<IAppxManifestApplication> apps = new List<IAppxManifestApplication>();
|
List<IAppxManifestApplication> apps = new List<IAppxManifestApplication>();
|
||||||
var appxFactory = new AppxFactory();
|
var reader = appxFactory.CreateManifestReader(stream);
|
||||||
var reader = ((IAppxFactory)appxFactory).CreateManifestReader(stream);
|
|
||||||
var manifestApps = reader.GetApplications();
|
var manifestApps = reader.GetApplications();
|
||||||
while (manifestApps.GetHasCurrent())
|
while (manifestApps.GetHasCurrent())
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,8 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
using System.IO;
|
|
||||||
using Accessibility;
|
using Accessibility;
|
||||||
using System.Runtime.InteropServices.ComTypes;
|
using System.Runtime.InteropServices.ComTypes;
|
||||||
using System.Security.Policy;
|
|
||||||
|
|
||||||
namespace Flow.Launcher.Plugin.Program.Programs
|
namespace Flow.Launcher.Plugin.Program.Programs
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,6 @@ using Flow.Launcher.Plugin.Program.Logger;
|
||||||
using Rect = System.Windows.Rect;
|
using Rect = System.Windows.Rect;
|
||||||
using Flow.Launcher.Plugin.SharedModels;
|
using Flow.Launcher.Plugin.SharedModels;
|
||||||
using Flow.Launcher.Infrastructure.Logger;
|
using Flow.Launcher.Infrastructure.Logger;
|
||||||
using System.Runtime.Versioning;
|
|
||||||
using System.Threading.Channels;
|
using System.Threading.Channels;
|
||||||
|
|
||||||
namespace Flow.Launcher.Plugin.Program.Programs
|
namespace Flow.Launcher.Plugin.Program.Programs
|
||||||
|
|
@ -42,39 +41,27 @@ namespace Flow.Launcher.Plugin.Program.Programs
|
||||||
FullName = package.Id.FullName;
|
FullName = package.Id.FullName;
|
||||||
FamilyName = package.Id.FamilyName;
|
FamilyName = package.Id.FamilyName;
|
||||||
InitializeAppInfo();
|
InitializeAppInfo();
|
||||||
Apps = Apps.Where(a =>
|
|
||||||
{
|
|
||||||
var valid =
|
|
||||||
!string.IsNullOrEmpty(a.UserModelId) &&
|
|
||||||
!string.IsNullOrEmpty(a.DisplayName);
|
|
||||||
return valid;
|
|
||||||
}).ToArray();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void InitializeAppInfo()
|
private void InitializeAppInfo()
|
||||||
{
|
{
|
||||||
AppxPackageHelper _helper = new AppxPackageHelper();
|
|
||||||
var path = Path.Combine(Location, "AppxManifest.xml");
|
var path = Path.Combine(Location, "AppxManifest.xml");
|
||||||
|
|
||||||
var namespaces = XmlNamespaces(path);
|
var namespaces = XmlNamespaces(path);
|
||||||
InitPackageVersion(namespaces);
|
InitPackageVersion(namespaces);
|
||||||
|
|
||||||
const uint noAttribute = 0x80;
|
const uint noAttribute = 0x80;
|
||||||
const Stgm exclusiveRead = Stgm.Read | Stgm.ShareExclusive;
|
const Stgm nonExclusiveRead = Stgm.Read | Stgm.ShareDenyNone;
|
||||||
var hResult = SHCreateStreamOnFileEx(path, exclusiveRead, noAttribute, false, null, out IStream stream);
|
var hResult = SHCreateStreamOnFileEx(path, nonExclusiveRead, noAttribute, false, null, out IStream stream);
|
||||||
|
|
||||||
if (hResult == Hresult.Ok)
|
if (hResult == Hresult.Ok)
|
||||||
{
|
{
|
||||||
var apps = new List<Application>();
|
List<AppxPackageHelper.IAppxManifestApplication> _apps = AppxPackageHelper.GetAppsFromManifest(stream);
|
||||||
|
|
||||||
List<AppxPackageHelper.IAppxManifestApplication> _apps = _helper.getAppsFromManifest(stream);
|
Apps = _apps.Select(x => new Application(x, this))
|
||||||
foreach (var _app in _apps)
|
.Where(a => !string.IsNullOrEmpty(a.UserModelId)
|
||||||
{
|
&& !string.IsNullOrEmpty(a.DisplayName))
|
||||||
var app = new Application(_app, this);
|
.ToArray();
|
||||||
apps.Add(app);
|
|
||||||
}
|
|
||||||
|
|
||||||
Apps = apps.Where(a => a.AppListEntry != "none").ToArray();
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
@ -82,17 +69,17 @@ namespace Flow.Launcher.Plugin.Program.Programs
|
||||||
ProgramLogger.LogException($"|UWP|InitializeAppInfo|{path}" +
|
ProgramLogger.LogException($"|UWP|InitializeAppInfo|{path}" +
|
||||||
"|Error caused while trying to get the details of the UWP program", e);
|
"|Error caused while trying to get the details of the UWP program", e);
|
||||||
|
|
||||||
Apps = new List<Application>().ToArray();
|
Apps = Array.Empty<Application>();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Marshal.ReleaseComObject(stream) > 0)
|
if (stream != null && Marshal.ReleaseComObject(stream) > 0)
|
||||||
{
|
{
|
||||||
Log.Error("Flow.Launcher.Plugin.Program.Programs.UWP", "AppxManifest.xml was leaked");
|
Log.Error("Flow.Launcher.Plugin.Program.Programs.UWP", "AppxManifest.xml was leaked");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// http://www.hanselman.com/blog/GetNamespacesFromAnXMLDocumentWithXPathDocumentAndLINQToXML.aspx
|
/// http://www.hanselman.com/blog/GetNamespacesFromAnXMLDocumentWithXPathDocumentAndLINQToXML.aspx
|
||||||
private string[] XmlNamespaces(string path)
|
private static string[] XmlNamespaces(string path)
|
||||||
{
|
{
|
||||||
XDocument z = XDocument.Load(path);
|
XDocument z = XDocument.Load(path);
|
||||||
if (z.Root != null)
|
if (z.Root != null)
|
||||||
|
|
@ -110,9 +97,7 @@ namespace Flow.Launcher.Plugin.Program.Programs
|
||||||
ProgramLogger.LogException($"|UWP|XmlNamespaces|{path}" +
|
ProgramLogger.LogException($"|UWP|XmlNamespaces|{path}" +
|
||||||
$"|Error occured while trying to get the XML from {path}", new ArgumentNullException());
|
$"|Error occured while trying to get the XML from {path}", new ArgumentNullException());
|
||||||
|
|
||||||
return new string[]
|
return Array.Empty<string>();
|
||||||
{
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -178,16 +163,13 @@ namespace Flow.Launcher.Plugin.Program.Programs
|
||||||
|
|
||||||
var updatedListWithoutDisabledApps = applications
|
var updatedListWithoutDisabledApps = applications
|
||||||
.Where(t1 => !Main._settings.DisabledProgramSources
|
.Where(t1 => !Main._settings.DisabledProgramSources
|
||||||
.Any(x => x.UniqueIdentifier == t1.UniqueIdentifier))
|
.Any(x => x.UniqueIdentifier == t1.UniqueIdentifier));
|
||||||
.Select(x => x);
|
|
||||||
|
|
||||||
return updatedListWithoutDisabledApps.ToArray();
|
return updatedListWithoutDisabledApps.ToArray();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
return new Application[]
|
return Array.Empty<Application>();
|
||||||
{
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -233,9 +215,7 @@ namespace Flow.Launcher.Plugin.Program.Programs
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
return new Package[]
|
return Array.Empty<Package>();
|
||||||
{
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -297,7 +277,6 @@ namespace Flow.Launcher.Plugin.Program.Programs
|
||||||
[Serializable]
|
[Serializable]
|
||||||
public class Application : IProgram
|
public class Application : IProgram
|
||||||
{
|
{
|
||||||
public string AppListEntry { get; set; }
|
|
||||||
public string UniqueIdentifier { get; set; }
|
public string UniqueIdentifier { get; set; }
|
||||||
public string DisplayName { get; set; }
|
public string DisplayName { get; set; }
|
||||||
public string Description { get; set; }
|
public string Description { get; set; }
|
||||||
|
|
@ -317,7 +296,6 @@ namespace Flow.Launcher.Plugin.Program.Programs
|
||||||
|
|
||||||
public Application() { }
|
public Application() { }
|
||||||
|
|
||||||
|
|
||||||
public Result Result(string query, IPublicAPI api)
|
public Result Result(string query, IPublicAPI api)
|
||||||
{
|
{
|
||||||
string title;
|
string title;
|
||||||
|
|
@ -544,7 +522,7 @@ namespace Flow.Launcher.Plugin.Program.Programs
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public string FormattedPriReferenceValue(string packageName, string rawPriReferenceValue)
|
public static string FormattedPriReferenceValue(string packageName, string rawPriReferenceValue)
|
||||||
{
|
{
|
||||||
const string prefix = "ms-resource:";
|
const string prefix = "ms-resource:";
|
||||||
|
|
||||||
|
|
@ -701,9 +679,15 @@ namespace Flow.Launcher.Plugin.Program.Programs
|
||||||
|
|
||||||
private BitmapImage ImageFromPath(string path)
|
private BitmapImage ImageFromPath(string path)
|
||||||
{
|
{
|
||||||
|
// TODO: Consider using infrastructure.image.imageloader?
|
||||||
if (File.Exists(path))
|
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;
|
return image;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|
@ -775,6 +759,23 @@ namespace Flow.Launcher.Plugin.Program.Programs
|
||||||
{
|
{
|
||||||
return $"{DisplayName}: {Description}";
|
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
|
public enum PackageVersion
|
||||||
|
|
@ -790,6 +791,7 @@ namespace Flow.Launcher.Plugin.Program.Programs
|
||||||
{
|
{
|
||||||
Read = 0x0,
|
Read = 0x0,
|
||||||
ShareExclusive = 0x10,
|
ShareExclusive = 0x10,
|
||||||
|
ShareDenyNone = 0x40
|
||||||
}
|
}
|
||||||
|
|
||||||
private enum Hresult : uint
|
private enum Hresult : uint
|
||||||
|
|
|
||||||
|
|
@ -11,14 +11,10 @@ using Flow.Launcher.Infrastructure;
|
||||||
using Flow.Launcher.Plugin.Program.Logger;
|
using Flow.Launcher.Plugin.Program.Logger;
|
||||||
using Flow.Launcher.Plugin.SharedCommands;
|
using Flow.Launcher.Plugin.SharedCommands;
|
||||||
using Flow.Launcher.Plugin.SharedModels;
|
using Flow.Launcher.Plugin.SharedModels;
|
||||||
using Flow.Launcher.Infrastructure.Logger;
|
|
||||||
using System.Collections;
|
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using Stopwatch = Flow.Launcher.Infrastructure.Stopwatch;
|
|
||||||
using System.Diagnostics.CodeAnalysis;
|
using System.Diagnostics.CodeAnalysis;
|
||||||
using System.Text.RegularExpressions;
|
|
||||||
using System.Threading.Channels;
|
using System.Threading.Channels;
|
||||||
using Flow.Launcher.Infrastructure.Image;
|
using Flow.Launcher.Plugin.Program.Views.Models;
|
||||||
using IniParser;
|
using IniParser;
|
||||||
|
|
||||||
namespace Flow.Launcher.Plugin.Program.Programs
|
namespace Flow.Launcher.Plugin.Program.Programs
|
||||||
|
|
@ -27,7 +23,7 @@ namespace Flow.Launcher.Plugin.Program.Programs
|
||||||
public class Win32 : IProgram, IEquatable<Win32>
|
public class Win32 : IProgram, IEquatable<Win32>
|
||||||
{
|
{
|
||||||
public string Name { get; set; }
|
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 IcoPath { get; set; }
|
||||||
public string FullPath { get; set; }
|
public string FullPath { get; set; }
|
||||||
public string LnkResolvedPath { get; set; }
|
public string LnkResolvedPath { get; set; }
|
||||||
|
|
@ -41,6 +37,7 @@ namespace Flow.Launcher.Plugin.Program.Programs
|
||||||
private const string ShortcutExtension = "lnk";
|
private const string ShortcutExtension = "lnk";
|
||||||
private const string UrlExtension = "url";
|
private const string UrlExtension = "url";
|
||||||
private const string ExeExtension = "exe";
|
private const string ExeExtension = "exe";
|
||||||
|
private string _uid = string.Empty;
|
||||||
|
|
||||||
private static readonly Win32 Default = new Win32()
|
private static readonly Win32 Default = new Win32()
|
||||||
{
|
{
|
||||||
|
|
@ -225,10 +222,7 @@ namespace Flow.Launcher.Plugin.Program.Programs
|
||||||
ProgramLogger.LogException($"|Win32|Win32Program|{path}" +
|
ProgramLogger.LogException($"|Win32|Win32Program|{path}" +
|
||||||
$"|Permission denied when trying to load the program from {path}", e);
|
$"|Permission denied when trying to load the program from {path}", e);
|
||||||
|
|
||||||
return new Win32()
|
return Default;
|
||||||
{
|
|
||||||
Valid = false, Enabled = false
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -248,7 +242,7 @@ namespace Flow.Launcher.Plugin.Program.Programs
|
||||||
if (extension == ExeExtension && File.Exists(target))
|
if (extension == ExeExtension && File.Exists(target))
|
||||||
{
|
{
|
||||||
program.LnkResolvedPath = program.FullPath;
|
program.LnkResolvedPath = program.FullPath;
|
||||||
program.FullPath = Path.GetFullPath(target).ToLower();
|
program.FullPath = Path.GetFullPath(target).ToLowerInvariant();
|
||||||
program.ExecutableName = Path.GetFileName(target);
|
program.ExecutableName = Path.GetFileName(target);
|
||||||
|
|
||||||
var description = _helper.description;
|
var description = _helper.description;
|
||||||
|
|
@ -279,6 +273,14 @@ namespace Flow.Launcher.Plugin.Program.Programs
|
||||||
program.Valid = false;
|
program.Valid = false;
|
||||||
return program;
|
return program;
|
||||||
}
|
}
|
||||||
|
catch (FileNotFoundException e)
|
||||||
|
{
|
||||||
|
ProgramLogger.LogException($"|Win32|LnkProgram|{path}" +
|
||||||
|
"|An unexpected error occurred in the calling method LnkProgram", e);
|
||||||
|
|
||||||
|
program.Valid = false;
|
||||||
|
return program;
|
||||||
|
}
|
||||||
#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.
|
#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)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
|
|
@ -291,7 +293,7 @@ namespace Flow.Launcher.Plugin.Program.Programs
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Win32 UrlProgram(string path)
|
private static Win32 UrlProgram(string path, string[] protocols)
|
||||||
{
|
{
|
||||||
var program = Win32Program(path);
|
var program = Win32Program(path);
|
||||||
program.Valid = false;
|
program.Valid = false;
|
||||||
|
|
@ -306,9 +308,9 @@ namespace Flow.Launcher.Plugin.Program.Programs
|
||||||
{
|
{
|
||||||
return program;
|
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.LnkResolvedPath = url;
|
||||||
program.Valid = true;
|
program.Valid = true;
|
||||||
|
|
@ -345,30 +347,28 @@ namespace Flow.Launcher.Plugin.Program.Programs
|
||||||
ProgramLogger.LogException($"|Win32|ExeProgram|{path}" +
|
ProgramLogger.LogException($"|Win32|ExeProgram|{path}" +
|
||||||
$"|Permission denied when trying to load the program from {path}", e);
|
$"|Permission denied when trying to load the program from {path}", e);
|
||||||
|
|
||||||
return new Win32()
|
return Default;
|
||||||
{
|
|
||||||
Valid = false, Enabled = false
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static IEnumerable<string> ProgramPaths(string directory, string[] suffixes)
|
private static IEnumerable<string> ProgramPaths(string directory, string[] suffixes, bool recursive = true)
|
||||||
{
|
{
|
||||||
if (!Directory.Exists(directory))
|
if (!Directory.Exists(directory))
|
||||||
return Enumerable.Empty<string>();
|
return Enumerable.Empty<string>();
|
||||||
|
|
||||||
return Directory.EnumerateFiles(directory, "*", new EnumerationOptions
|
return Directory.EnumerateFiles(directory, "*", new EnumerationOptions
|
||||||
{
|
{
|
||||||
IgnoreInaccessible = true, RecurseSubdirectories = true
|
IgnoreInaccessible = true,
|
||||||
|
RecurseSubdirectories = recursive
|
||||||
}).Where(x => suffixes.Contains(Extension(x)));
|
}).Where(x => suffixes.Contains(Extension(x)));
|
||||||
}
|
}
|
||||||
|
|
||||||
private static string Extension(string path)
|
private static string Extension(string path)
|
||||||
{
|
{
|
||||||
var extension = Path.GetExtension(path)?.ToLower();
|
var extension = Path.GetExtension(path)?.ToLowerInvariant();
|
||||||
if (!string.IsNullOrEmpty(extension))
|
if (!string.IsNullOrEmpty(extension))
|
||||||
{
|
{
|
||||||
return extension.Substring(1);
|
return extension.Substring(1); // remove dot
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
@ -376,27 +376,20 @@ namespace Flow.Launcher.Plugin.Program.Programs
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static IEnumerable<Win32> UnregisteredPrograms(List<Settings.ProgramSource> sources, string[] suffixes)
|
private static IEnumerable<Win32> UnregisteredPrograms(List<ProgramSource> sources, string[] suffixes, string[] protocols)
|
||||||
{
|
{
|
||||||
|
// Disabled custom sources are not in DisabledProgramSources
|
||||||
var paths = ExceptDisabledSource(sources.Where(s => Directory.Exists(s.Location) && s.Enabled)
|
var paths = ExceptDisabledSource(sources.Where(s => Directory.Exists(s.Location) && s.Enabled)
|
||||||
.SelectMany(s => ProgramPaths(s.Location, suffixes)), x => x)
|
.AsParallel()
|
||||||
.Distinct();
|
.SelectMany(s => ProgramPaths(s.Location, suffixes)))
|
||||||
|
.Distinct();
|
||||||
var programs = paths.Select(x => Extension(x) switch
|
|
||||||
{
|
|
||||||
ExeExtension => ExeProgram(x),
|
|
||||||
ShortcutExtension => LnkProgram(x),
|
|
||||||
UrlExtension => UrlProgram(x),
|
|
||||||
_ => Win32Program(x)
|
|
||||||
});
|
|
||||||
|
|
||||||
|
var programs = paths.Select(x => GetProgramFromPath(x, protocols));
|
||||||
return programs;
|
return programs;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static IEnumerable<Win32> StartMenuPrograms(string[] suffixes)
|
private static IEnumerable<Win32> StartMenuPrograms(string[] suffixes, string[] protocols)
|
||||||
{
|
{
|
||||||
var disabledProgramsList = Main._settings.DisabledProgramSources;
|
|
||||||
|
|
||||||
var directory1 = Environment.GetFolderPath(Environment.SpecialFolder.Programs);
|
var directory1 = Environment.GetFolderPath(Environment.SpecialFolder.Programs);
|
||||||
var directory2 = Environment.GetFolderPath(Environment.SpecialFolder.CommonPrograms);
|
var directory2 = Environment.GetFolderPath(Environment.SpecialFolder.CommonPrograms);
|
||||||
var paths1 = ProgramPaths(directory1, suffixes);
|
var paths1 = ProgramPaths(directory1, suffixes);
|
||||||
|
|
@ -404,17 +397,35 @@ namespace Flow.Launcher.Plugin.Program.Programs
|
||||||
|
|
||||||
var toFilter = paths1.Concat(paths2);
|
var toFilter = paths1.Concat(paths2);
|
||||||
|
|
||||||
|
var programs = ExceptDisabledSource(toFilter.Distinct())
|
||||||
|
.Select(x => GetProgramFromPath(x, protocols));
|
||||||
|
return programs;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static IEnumerable<Win32> PATHPrograms(string[] suffixes, string[] protocols)
|
||||||
|
{
|
||||||
|
var pathEnv = Environment.GetEnvironmentVariable("Path");
|
||||||
|
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));
|
||||||
|
|
||||||
var programs = ExceptDisabledSource(toFilter.Distinct())
|
var programs = ExceptDisabledSource(toFilter.Distinct())
|
||||||
.Select(x => Extension(x) switch
|
.Select(x => Extension(x) switch
|
||||||
{
|
{
|
||||||
ShortcutExtension => LnkProgram(x),
|
ShortcutExtension => LnkProgram(x),
|
||||||
UrlExtension => UrlProgram(x),
|
UrlExtension => UrlProgram(x, protocols),
|
||||||
|
ExeExtension => ExeProgram(x),
|
||||||
_ => Win32Program(x)
|
_ => Win32Program(x)
|
||||||
});
|
});
|
||||||
return programs;
|
return programs;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static IEnumerable<Win32> AppPathsPrograms(string[] suffixes)
|
private static IEnumerable<Win32> AppPathsPrograms(string[] suffixes, string[] protocols)
|
||||||
{
|
{
|
||||||
// https://msdn.microsoft.com/en-us/library/windows/desktop/ee872121
|
// https://msdn.microsoft.com/en-us/library/windows/desktop/ee872121
|
||||||
const string appPaths = @"SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths";
|
const string appPaths = @"SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths";
|
||||||
|
|
@ -434,12 +445,11 @@ namespace Flow.Launcher.Plugin.Program.Programs
|
||||||
toFilter = toFilter.Concat(GetPathFromRegistry(rootUser));
|
toFilter = toFilter.Concat(GetPathFromRegistry(rootUser));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
toFilter = toFilter.Distinct().Where(p => suffixes.Contains(Extension(p)));
|
toFilter = toFilter.Distinct().Where(p => suffixes.Contains(Extension(p)));
|
||||||
|
|
||||||
var filtered = ExceptDisabledSource(toFilter);
|
var programs = ExceptDisabledSource(toFilter)
|
||||||
|
.Select(x => GetProgramFromPath(x, protocols)).Where(x => x.Valid).ToList(); // ToList due to disposing issue
|
||||||
return filtered.Select(GetProgramFromPath).ToList(); // ToList due to disposing issue
|
return programs;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static IEnumerable<string> GetPathFromRegistry(RegistryKey root)
|
private static IEnumerable<string> GetPathFromRegistry(RegistryKey root)
|
||||||
|
|
@ -479,7 +489,7 @@ namespace Flow.Launcher.Plugin.Program.Programs
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Win32 GetProgramFromPath(string path)
|
private static Win32 GetProgramFromPath(string path, string[] protocols)
|
||||||
{
|
{
|
||||||
if (string.IsNullOrEmpty(path))
|
if (string.IsNullOrEmpty(path))
|
||||||
return Default;
|
return Default;
|
||||||
|
|
@ -489,14 +499,18 @@ namespace Flow.Launcher.Plugin.Program.Programs
|
||||||
if (!File.Exists(path))
|
if (!File.Exists(path))
|
||||||
return Default;
|
return Default;
|
||||||
|
|
||||||
var entry = Win32Program(path);
|
return Extension(path) switch
|
||||||
|
{
|
||||||
return entry;
|
ShortcutExtension => LnkProgram(path),
|
||||||
|
ExeExtension => ExeProgram(path),
|
||||||
|
UrlExtension => UrlProgram(path, protocols),
|
||||||
|
_ => Win32Program(path)
|
||||||
|
}; ;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static IEnumerable<string> ExceptDisabledSource(IEnumerable<string> sources)
|
public static IEnumerable<string> ExceptDisabledSource(IEnumerable<string> paths)
|
||||||
{
|
{
|
||||||
return ExceptDisabledSource(sources, x => x);
|
return ExceptDisabledSource(paths, x => x.ToLowerInvariant());
|
||||||
}
|
}
|
||||||
|
|
||||||
public static IEnumerable<TSource> ExceptDisabledSource<TSource>(IEnumerable<TSource> sources,
|
public static IEnumerable<TSource> ExceptDisabledSource<TSource>(IEnumerable<TSource> sources,
|
||||||
|
|
@ -531,7 +545,8 @@ namespace Flow.Launcher.Plugin.Program.Programs
|
||||||
|
|
||||||
private static IEnumerable<Win32> ProgramsHasher(IEnumerable<Win32> programs)
|
private static IEnumerable<Win32> ProgramsHasher(IEnumerable<Win32> programs)
|
||||||
{
|
{
|
||||||
return programs.GroupBy(p => p.FullPath.ToLower())
|
return programs.GroupBy(p => p.FullPath.ToLowerInvariant())
|
||||||
|
.AsParallel()
|
||||||
.SelectMany(g =>
|
.SelectMany(g =>
|
||||||
{
|
{
|
||||||
var temp = g.Where(g => !string.IsNullOrEmpty(g.Description)).ToList();
|
var temp = g.Where(g => !string.IsNullOrEmpty(g.Description)).ToList();
|
||||||
|
|
@ -547,8 +562,10 @@ namespace Flow.Launcher.Plugin.Program.Programs
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var programs = Enumerable.Empty<Win32>();
|
var programs = Enumerable.Empty<Win32>();
|
||||||
|
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);
|
programs = programs.Concat(unregistered);
|
||||||
|
|
||||||
|
|
@ -556,16 +573,22 @@ namespace Flow.Launcher.Plugin.Program.Programs
|
||||||
|
|
||||||
if (settings.EnableRegistrySource)
|
if (settings.EnableRegistrySource)
|
||||||
{
|
{
|
||||||
var appPaths = AppPathsPrograms(settings.GetSuffixes());
|
var appPaths = AppPathsPrograms(suffixes, protocols);
|
||||||
autoIndexPrograms = autoIndexPrograms.Concat(appPaths);
|
autoIndexPrograms = autoIndexPrograms.Concat(appPaths);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (settings.EnableStartMenuSource)
|
if (settings.EnableStartMenuSource)
|
||||||
{
|
{
|
||||||
var startMenu = StartMenuPrograms(settings.GetSuffixes());
|
var startMenu = StartMenuPrograms(suffixes, protocols);
|
||||||
autoIndexPrograms = autoIndexPrograms.Concat(startMenu);
|
autoIndexPrograms = autoIndexPrograms.Concat(startMenu);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (settings.EnablePATHSource)
|
||||||
|
{
|
||||||
|
var path = PATHPrograms(settings.GetSuffixes(), protocols);
|
||||||
|
autoIndexPrograms = autoIndexPrograms.Concat(path);
|
||||||
|
}
|
||||||
|
|
||||||
autoIndexPrograms = ProgramsHasher(autoIndexPrograms);
|
autoIndexPrograms = ProgramsHasher(autoIndexPrograms);
|
||||||
|
|
||||||
return programs.Concat(autoIndexPrograms).Where(x => x.Valid).Distinct().ToArray();
|
return programs.Concat(autoIndexPrograms).Where(x => x.Valid).Distinct().ToArray();
|
||||||
|
|
@ -600,6 +623,18 @@ namespace Flow.Launcher.Plugin.Program.Programs
|
||||||
return UniqueIdentifier == other.UniqueIdentifier;
|
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<string> GetStartMenuPaths()
|
private static IEnumerable<string> GetStartMenuPaths()
|
||||||
{
|
{
|
||||||
var directory1 = Environment.GetFolderPath(Environment.SpecialFolder.Programs);
|
var directory1 = Environment.GetFolderPath(Environment.SpecialFolder.Programs);
|
||||||
|
|
@ -640,7 +675,7 @@ namespace Flow.Launcher.Plugin.Program.Programs
|
||||||
await Task.Run(Main.IndexWin32Programs);
|
await Task.Run(Main.IndexWin32Programs);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void WatchDirectory(string directory)
|
public static void WatchDirectory(string directory)
|
||||||
{
|
{
|
||||||
if (!Directory.Exists(directory))
|
if (!Directory.Exists(directory))
|
||||||
|
|
@ -653,7 +688,7 @@ namespace Flow.Launcher.Plugin.Program.Programs
|
||||||
watcher.Deleted += static (_, _) => indexQueue.Writer.TryWrite(default);
|
watcher.Deleted += static (_, _) => indexQueue.Writer.TryWrite(default);
|
||||||
watcher.EnableRaisingEvents = true;
|
watcher.EnableRaisingEvents = true;
|
||||||
watcher.IncludeSubdirectories = true;
|
watcher.IncludeSubdirectories = true;
|
||||||
|
|
||||||
Watchers.Add(watcher);
|
Watchers.Add(watcher);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,19 +1,26 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text.Json.Serialization;
|
using System.Text.Json.Serialization;
|
||||||
using Windows.Foundation.Metadata;
|
using Flow.Launcher.Plugin.Program.Views.Models;
|
||||||
|
|
||||||
namespace Flow.Launcher.Plugin.Program
|
namespace Flow.Launcher.Plugin.Program
|
||||||
{
|
{
|
||||||
public class Settings
|
public class Settings
|
||||||
{
|
{
|
||||||
public DateTime LastIndexTime { get; set; }
|
public DateTime LastIndexTime { get; set; }
|
||||||
public List<ProgramSource> ProgramSources { get; set; } = new List<ProgramSource>();
|
|
||||||
public List<DisabledProgramSource> DisabledProgramSources { get; set; } = new List<DisabledProgramSource>();
|
|
||||||
|
|
||||||
[Obsolete, JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
|
/// <summary>
|
||||||
|
/// User-added program sources' directories
|
||||||
|
/// </summary>
|
||||||
|
public List<ProgramSource> ProgramSources { get; set; } = new List<ProgramSource>();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Disabled single programs, not including User-added directories
|
||||||
|
/// </summary>
|
||||||
|
public List<ProgramSource> DisabledProgramSources { get; set; } = new List<ProgramSource>();
|
||||||
|
|
||||||
|
[Obsolete("Should use GetSuffixes() instead."), JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)]
|
||||||
public string[] ProgramSuffixes { get; set; } = null;
|
public string[] ProgramSuffixes { get; set; } = null;
|
||||||
public string[] CustomSuffixes { get; set; } = Array.Empty<string>(); // Custom suffixes only
|
public string[] CustomSuffixes { get; set; } = Array.Empty<string>(); // Custom suffixes only
|
||||||
public string[] CustomProtocols { get; set; } = Array.Empty<string>();
|
public string[] CustomProtocols { get; set; } = Array.Empty<string>();
|
||||||
|
|
@ -111,6 +118,8 @@ namespace Flow.Launcher.Plugin.Program
|
||||||
public bool EnableDescription { get; set; } = false;
|
public bool EnableDescription { get; set; } = false;
|
||||||
public bool HideAppsPath { get; set; } = true;
|
public bool HideAppsPath { get; set; } = true;
|
||||||
public bool EnableRegistrySource { get; set; } = true;
|
public bool EnableRegistrySource { get; set; } = true;
|
||||||
|
public bool EnablePATHSource { get; set; } = true;
|
||||||
|
|
||||||
public string CustomizedExplorer { get; set; } = Explorer;
|
public string CustomizedExplorer { get; set; } = Explorer;
|
||||||
public string CustomizedArgs { get; set; } = ExplorerArgs;
|
public string CustomizedArgs { get; set; } = ExplorerArgs;
|
||||||
|
|
||||||
|
|
@ -119,25 +128,5 @@ namespace Flow.Launcher.Plugin.Program
|
||||||
internal const string Explorer = "explorer";
|
internal const string Explorer = "explorer";
|
||||||
|
|
||||||
internal const string ExplorerArgs = "%s";
|
internal const string ExplorerArgs = "%s";
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Contains user added folder location contents as well as all user disabled applications
|
|
||||||
/// </summary>
|
|
||||||
/// <remarks>
|
|
||||||
/// <para>Win32 class applications set UniqueIdentifier using their full file path</para>
|
|
||||||
/// <para>UWP class applications set UniqueIdentifier using their Application User Model ID</para>
|
|
||||||
/// <para>Custom user added program sources set UniqueIdentifier using their location</para>
|
|
||||||
/// </remarks>
|
|
||||||
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 { }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,146 +1,88 @@
|
||||||
using System;
|
using System.Collections.Generic;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using Flow.Launcher.Plugin.Program.Views.Models;
|
using Flow.Launcher.Plugin.Program.Views.Models;
|
||||||
|
|
||||||
namespace Flow.Launcher.Plugin.Program.Views.Commands
|
namespace Flow.Launcher.Plugin.Program.Views.Commands
|
||||||
{
|
{
|
||||||
internal static class ProgramSettingDisplay
|
internal static class ProgramSettingDisplay
|
||||||
{
|
{
|
||||||
internal static List<ProgramSource> LoadProgramSources(this List<Settings.ProgramSource> programSources)
|
internal static List<ProgramSource> LoadProgramSources()
|
||||||
{
|
{
|
||||||
var list = new List<ProgramSource>();
|
|
||||||
|
|
||||||
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
|
// Even though these are disabled, we still want to display them so users can enable later on
|
||||||
Main._settings
|
return Main._settings
|
||||||
.DisabledProgramSources
|
.DisabledProgramSources
|
||||||
.Where(t1 => !Main._settings
|
.Union(Main._settings.ProgramSources)
|
||||||
.ProgramSources // program sourcces added above already, so exlcude
|
.ToList();
|
||||||
.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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static void LoadAllApplications(this List<ProgramSource> list)
|
internal static void DisplayAllPrograms()
|
||||||
{
|
{
|
||||||
Main._win32s
|
var win32 = Main._win32s
|
||||||
.Where(t1 => !ProgramSetting.ProgramSettingDisplayList.Any(x => x.UniqueIdentifier == t1.UniqueIdentifier))
|
.Where(t1 => !ProgramSetting.ProgramSettingDisplayList.Any(x => x.UniqueIdentifier == t1.UniqueIdentifier))
|
||||||
.ToList()
|
.Select(x => new ProgramSource(x));
|
||||||
.ForEach(t1 => ProgramSetting.ProgramSettingDisplayList
|
|
||||||
.Add(
|
|
||||||
new ProgramSource
|
|
||||||
{
|
|
||||||
Name = t1.Name,
|
|
||||||
Location = t1.ParentDirectory,
|
|
||||||
UniqueIdentifier = t1.UniqueIdentifier,
|
|
||||||
Enabled = t1.Enabled
|
|
||||||
}
|
|
||||||
));
|
|
||||||
|
|
||||||
Main._uwps
|
var uwp = Main._uwps
|
||||||
.Where(t1 => !ProgramSetting.ProgramSettingDisplayList.Any(x => x.UniqueIdentifier == t1.UniqueIdentifier))
|
.Where(t1 => !ProgramSetting.ProgramSettingDisplayList.Any(x => x.UniqueIdentifier == t1.UniqueIdentifier))
|
||||||
.ToList()
|
.Select(x => new ProgramSource(x));
|
||||||
.ForEach(t1 => ProgramSetting.ProgramSettingDisplayList
|
|
||||||
.Add(
|
ProgramSetting.ProgramSettingDisplayList.AddRange(win32);
|
||||||
new ProgramSource
|
ProgramSetting.ProgramSettingDisplayList.AddRange(uwp);
|
||||||
{
|
|
||||||
Name = t1.DisplayName,
|
|
||||||
Location = t1.Package.Location,
|
|
||||||
UniqueIdentifier = t1.UniqueIdentifier,
|
|
||||||
Enabled = t1.Enabled
|
|
||||||
}
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static void SetProgramSourcesStatus(this List<ProgramSource> list, List<ProgramSource> selectedProgramSourcesToDisable, bool status)
|
internal static void SetProgramSourcesStatus(List<ProgramSource> selectedProgramSourcesToDisable, bool status)
|
||||||
{
|
{
|
||||||
ProgramSetting.ProgramSettingDisplayList
|
foreach(var program in ProgramSetting.ProgramSettingDisplayList)
|
||||||
.Where(t1 => selectedProgramSourcesToDisable.Any(x => x.UniqueIdentifier == t1.UniqueIdentifier && t1.Enabled != status))
|
{
|
||||||
.ToList()
|
if (selectedProgramSourcesToDisable.Any(x => x.UniqueIdentifier == program.UniqueIdentifier && program.Enabled != status))
|
||||||
.ForEach(t1 => t1.Enabled = status);
|
{
|
||||||
|
program.Enabled = status;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Main._win32s
|
foreach(var program in Main._win32s)
|
||||||
.Where(t1 => selectedProgramSourcesToDisable.Any(x => x.UniqueIdentifier == t1.UniqueIdentifier && t1.Enabled != status))
|
{
|
||||||
.ToList()
|
if (selectedProgramSourcesToDisable.Any(x => x.UniqueIdentifier == program.UniqueIdentifier && program.Enabled != status))
|
||||||
.ForEach(t1 => t1.Enabled = status);
|
{
|
||||||
|
program.Enabled = status;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Main._uwps
|
foreach (var program in Main._uwps)
|
||||||
.Where(t1 => selectedProgramSourcesToDisable.Any(x => x.UniqueIdentifier == t1.UniqueIdentifier && t1.Enabled != status))
|
{
|
||||||
.ToList()
|
if (selectedProgramSourcesToDisable.Any(x => x.UniqueIdentifier == program.UniqueIdentifier && program.Enabled != status))
|
||||||
.ForEach(t1 => t1.Enabled = status);
|
{
|
||||||
|
program.Enabled = status;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static void StoreDisabledInSettings(this List<ProgramSource> list)
|
internal static void StoreDisabledInSettings()
|
||||||
{
|
{
|
||||||
Main._settings.ProgramSources
|
// Disabled, not in DisabledProgramSources or ProgramSources
|
||||||
.Where(t1 => ProgramSetting.ProgramSettingDisplayList.Any(x => x.UniqueIdentifier == t1.UniqueIdentifier && !x.Enabled))
|
var tmp = ProgramSetting.ProgramSettingDisplayList
|
||||||
.ToList()
|
|
||||||
.ForEach(t1 => t1.Enabled = false);
|
|
||||||
|
|
||||||
ProgramSetting.ProgramSettingDisplayList
|
|
||||||
.Where(t1 => !t1.Enabled
|
.Where(t1 => !t1.Enabled
|
||||||
&& !Main._settings.DisabledProgramSources.Any(x => x.UniqueIdentifier == t1.UniqueIdentifier))
|
&& !Main._settings.DisabledProgramSources.Any(x => x.UniqueIdentifier == t1.UniqueIdentifier)
|
||||||
.ToList()
|
&& !Main._settings.ProgramSources.Any(x => x.UniqueIdentifier == t1.UniqueIdentifier));
|
||||||
.ForEach(x => Main._settings.DisabledProgramSources
|
|
||||||
.Add(
|
Main._settings.DisabledProgramSources.AddRange(tmp);
|
||||||
new Settings.DisabledProgramSource
|
|
||||||
{
|
|
||||||
Name = x.Name,
|
|
||||||
Location = x.Location,
|
|
||||||
UniqueIdentifier = x.UniqueIdentifier,
|
|
||||||
Enabled = false
|
|
||||||
}
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static void RemoveDisabledFromSettings(this List<ProgramSource> list)
|
internal static void RemoveDisabledFromSettings()
|
||||||
{
|
{
|
||||||
Main._settings.ProgramSources
|
Main._settings.DisabledProgramSources.RemoveAll(t1 => t1.Enabled);
|
||||||
.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));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static bool IsReindexRequired(this List<ProgramSource> selectedItems)
|
internal static bool IsReindexRequired(this List<ProgramSource> selectedItems)
|
||||||
{
|
{
|
||||||
if (selectedItems.Where(t1 => t1.Enabled && !Main._uwps.Any(x => t1.UniqueIdentifier == x.UniqueIdentifier)).Count() > 0
|
// Not in cache
|
||||||
&& selectedItems.Where(t1 => t1.Enabled && !Main._win32s.Any(x => t1.UniqueIdentifier == x.UniqueIdentifier)).Count() > 0)
|
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;
|
return true;
|
||||||
|
|
||||||
// ProgramSources holds list of user added directories,
|
// ProgramSources holds list of user added directories,
|
||||||
// so when we enable/disable we need to reindex to show/not show the programs
|
// so when we enable/disable we need to reindex to show/not show the programs
|
||||||
// that are found in those directories.
|
// 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 true;
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
|
|
|
||||||
|
|
@ -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
|
namespace Flow.Launcher.Plugin.Program.Views.Models
|
||||||
{
|
{
|
||||||
public class ProgramSource : Settings.ProgramSource { }
|
/// <summary>
|
||||||
|
/// Contains user added folder location contents as well as all user disabled applications
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// <para>Win32 class applications set UniqueIdentifier using their full file path</para>
|
||||||
|
/// <para>UWP class applications set UniqueIdentifier using their Application User Model ID</para>
|
||||||
|
/// <para>Custom user added program sources set UniqueIdentifier using their location</para>
|
||||||
|
/// </remarks>
|
||||||
|
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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Add source by location
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="location">location of program source</param>
|
||||||
|
/// <param name="enabled">enabled</param>
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -10,58 +10,88 @@
|
||||||
mc:Ignorable="d">
|
mc:Ignorable="d">
|
||||||
<Grid Margin="0">
|
<Grid Margin="0">
|
||||||
<Grid.RowDefinitions>
|
<Grid.RowDefinitions>
|
||||||
<RowDefinition Height="170" />
|
<RowDefinition Height="Auto" />
|
||||||
|
<RowDefinition Height="Auto" />
|
||||||
<RowDefinition Height="*" />
|
<RowDefinition Height="*" />
|
||||||
<RowDefinition Height="60" />
|
<RowDefinition Height="60" />
|
||||||
</Grid.RowDefinitions>
|
</Grid.RowDefinitions>
|
||||||
|
<DockPanel
|
||||||
|
Margin="70,10,0,8"
|
||||||
|
HorizontalAlignment="Stretch"
|
||||||
|
LastChildFill="True">
|
||||||
|
<TextBlock
|
||||||
|
MinWidth="120"
|
||||||
|
Margin="0,5,10,0"
|
||||||
|
Text="{DynamicResource flowlauncher_plugin_program_index_source}" />
|
||||||
|
<WrapPanel
|
||||||
|
Width="Auto"
|
||||||
|
Margin="0,0,14,0"
|
||||||
|
HorizontalAlignment="Right"
|
||||||
|
DockPanel.Dock="Right">
|
||||||
|
<CheckBox
|
||||||
|
Name="StartMenuEnabled"
|
||||||
|
Margin="12,0,12,0"
|
||||||
|
Content="{DynamicResource flowlauncher_plugin_program_index_start}"
|
||||||
|
IsChecked="{Binding EnableStartMenuSource}"
|
||||||
|
ToolTip="{DynamicResource flowlauncher_plugin_program_index_start_tooltip}" />
|
||||||
|
<CheckBox
|
||||||
|
Name="RegistryEnabled"
|
||||||
|
Margin="12,0,12,0"
|
||||||
|
Content="{DynamicResource flowlauncher_plugin_program_index_registry}"
|
||||||
|
IsChecked="{Binding EnableRegistrySource}"
|
||||||
|
ToolTip="{DynamicResource flowlauncher_plugin_program_index_registry_tooltip}" />
|
||||||
|
|
||||||
|
<CheckBox
|
||||||
|
Name="PATHEnabled"
|
||||||
|
Margin="12,0,12,0"
|
||||||
|
Content="{DynamicResource flowlauncher_plugin_program_index_PATH}"
|
||||||
|
IsChecked="{Binding EnablePATHSource}"
|
||||||
|
ToolTip="{DynamicResource flowlauncher_plugin_program_index_PATH_tooltip}" />
|
||||||
|
</WrapPanel>
|
||||||
|
</DockPanel>
|
||||||
|
|
||||||
<StackPanel
|
<StackPanel
|
||||||
Grid.Row="0"
|
Grid.Row="1"
|
||||||
HorizontalAlignment="Stretch"
|
HorizontalAlignment="Stretch"
|
||||||
Orientation="Vertical">
|
Orientation="Vertical">
|
||||||
<StackPanel Width="Auto" Orientation="Vertical">
|
<Separator
|
||||||
<StackPanel Width="Auto" Orientation="Horizontal">
|
Height="1"
|
||||||
<CheckBox
|
BorderBrush="{DynamicResource Color03B}"
|
||||||
Name="StartMenuEnabled"
|
BorderThickness="1" />
|
||||||
Width="220"
|
<DockPanel
|
||||||
Margin="70,8,10,8"
|
Margin="70,10,0,8"
|
||||||
Content="{DynamicResource flowlauncher_plugin_program_index_start}"
|
HorizontalAlignment="Stretch"
|
||||||
IsChecked="{Binding EnableStartMenuSource}"
|
LastChildFill="True">
|
||||||
ToolTip="{DynamicResource flowlauncher_plugin_program_index_start_tooltip}" />
|
<TextBlock
|
||||||
<CheckBox
|
MinWidth="120"
|
||||||
Name="RegistryEnabled"
|
Margin="0,5,10,0"
|
||||||
Margin="70,8,10,8"
|
Text="{DynamicResource flowlauncher_plugin_program_index_option}" />
|
||||||
Content="{DynamicResource flowlauncher_plugin_program_index_registry}"
|
<WrapPanel
|
||||||
IsChecked="{Binding EnableRegistrySource}"
|
Width="Auto"
|
||||||
ToolTip="{DynamicResource flowlauncher_plugin_program_index_registry_tooltip}" />
|
Margin="0,0,14,0"
|
||||||
</StackPanel>
|
HorizontalAlignment="Right"
|
||||||
|
DockPanel.Dock="Right">
|
||||||
<Separator
|
|
||||||
Height="1"
|
|
||||||
BorderBrush="{DynamicResource Color03B}"
|
|
||||||
BorderThickness="1" />
|
|
||||||
<StackPanel Width="Auto" Orientation="Horizontal">
|
|
||||||
<CheckBox
|
<CheckBox
|
||||||
Name="HideLnkEnabled"
|
Name="HideLnkEnabled"
|
||||||
Width="220"
|
Margin="12,0,12,0"
|
||||||
Margin="70,8,10,8"
|
|
||||||
Content="{DynamicResource flowlauncher_plugin_program_enable_hidelnkpath}"
|
Content="{DynamicResource flowlauncher_plugin_program_enable_hidelnkpath}"
|
||||||
IsChecked="{Binding HideAppsPath}"
|
IsChecked="{Binding HideAppsPath}"
|
||||||
ToolTip="{DynamicResource flowlauncher_plugin_program_enable_hidelnkpath_tooltip}" />
|
ToolTip="{DynamicResource flowlauncher_plugin_program_enable_hidelnkpath_tooltip}" />
|
||||||
<CheckBox
|
<CheckBox
|
||||||
Name="DescriptionEnabled"
|
Name="DescriptionEnabled"
|
||||||
Margin="70,8,10,8"
|
Margin="12,0,12,0"
|
||||||
Content="{DynamicResource flowlauncher_plugin_program_enable_description}"
|
Content="{DynamicResource flowlauncher_plugin_program_enable_description}"
|
||||||
IsChecked="{Binding EnableDescription}"
|
IsChecked="{Binding EnableDescription}"
|
||||||
ToolTip="{DynamicResource flowlauncher_plugin_program_enable_description_tooltip}" />
|
ToolTip="{DynamicResource flowlauncher_plugin_program_enable_description_tooltip}" />
|
||||||
</StackPanel>
|
</WrapPanel>
|
||||||
<Separator
|
</DockPanel>
|
||||||
Height="1"
|
<Separator
|
||||||
BorderBrush="{DynamicResource Color03B}"
|
Height="1"
|
||||||
BorderThickness="1" />
|
BorderBrush="{DynamicResource Color03B}"
|
||||||
</StackPanel>
|
BorderThickness="1" />
|
||||||
<StackPanel
|
<StackPanel
|
||||||
Width="Auto"
|
Width="Auto"
|
||||||
Margin="10,6,0,0"
|
Margin="60,6,0,0"
|
||||||
HorizontalAlignment="Left"
|
HorizontalAlignment="Left"
|
||||||
Orientation="Horizontal">
|
Orientation="Horizontal">
|
||||||
<Button
|
<Button
|
||||||
|
|
@ -107,8 +137,8 @@
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
<ListView
|
<ListView
|
||||||
x:Name="programSourceView"
|
x:Name="programSourceView"
|
||||||
Grid.Row="1"
|
Grid.Row="2"
|
||||||
Margin="20,0,20,0"
|
Margin="70,0,20,0"
|
||||||
AllowDrop="True"
|
AllowDrop="True"
|
||||||
BorderBrush="DarkGray"
|
BorderBrush="DarkGray"
|
||||||
BorderThickness="1"
|
BorderThickness="1"
|
||||||
|
|
@ -116,6 +146,8 @@
|
||||||
Drop="programSourceView_Drop"
|
Drop="programSourceView_Drop"
|
||||||
GridViewColumnHeader.Click="GridViewColumnHeaderClickedHandler"
|
GridViewColumnHeader.Click="GridViewColumnHeaderClickedHandler"
|
||||||
PreviewMouseRightButtonUp="ProgramSourceView_PreviewMouseRightButtonUp"
|
PreviewMouseRightButtonUp="ProgramSourceView_PreviewMouseRightButtonUp"
|
||||||
|
MouseDoubleClick="programSourceView_MouseDoubleClick"
|
||||||
|
SelectionChanged="programSourceView_SelectionChanged"
|
||||||
SelectionMode="Extended">
|
SelectionMode="Extended">
|
||||||
<ListView.View>
|
<ListView.View>
|
||||||
<GridView>
|
<GridView>
|
||||||
|
|
@ -126,7 +158,7 @@
|
||||||
</DataTemplate>
|
</DataTemplate>
|
||||||
</GridViewColumn.CellTemplate>
|
</GridViewColumn.CellTemplate>
|
||||||
</GridViewColumn>
|
</GridViewColumn>
|
||||||
<GridViewColumn Header="{DynamicResource flowlauncher_plugin_program_enable}">
|
<GridViewColumn Header="{DynamicResource flowlauncher_plugin_program_enabled}">
|
||||||
<GridViewColumn.CellTemplate>
|
<GridViewColumn.CellTemplate>
|
||||||
<DataTemplate>
|
<DataTemplate>
|
||||||
<TextBlock
|
<TextBlock
|
||||||
|
|
@ -147,7 +179,7 @@
|
||||||
</ListView.View>
|
</ListView.View>
|
||||||
</ListView>
|
</ListView>
|
||||||
<DockPanel
|
<DockPanel
|
||||||
Grid.Row="2"
|
Grid.Row="3"
|
||||||
Grid.RowSpan="1"
|
Grid.RowSpan="1"
|
||||||
Margin="0,0,20,10">
|
Margin="0,0,20,10">
|
||||||
<StackPanel HorizontalAlignment="Right" Orientation="Horizontal">
|
<StackPanel HorizontalAlignment="Right" Orientation="Horizontal">
|
||||||
|
|
@ -173,66 +205,3 @@
|
||||||
</DockPanel>
|
</DockPanel>
|
||||||
</Grid>
|
</Grid>
|
||||||
</UserControl>
|
</UserControl>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,6 @@
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading.Tasks;
|
|
||||||
using System.Windows;
|
using System.Windows;
|
||||||
using System.Windows.Controls;
|
using System.Windows.Controls;
|
||||||
using System.Windows.Input;
|
using System.Windows.Input;
|
||||||
|
|
@ -36,6 +35,7 @@ namespace Flow.Launcher.Plugin.Program.Views
|
||||||
_settings.EnableDescription = value;
|
_settings.EnableDescription = value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool HideAppsPath
|
public bool HideAppsPath
|
||||||
{
|
{
|
||||||
get => _settings.HideAppsPath;
|
get => _settings.HideAppsPath;
|
||||||
|
|
@ -66,6 +66,16 @@ namespace Flow.Launcher.Plugin.Program.Views
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public bool EnablePATHSource
|
||||||
|
{
|
||||||
|
get => _settings.EnablePATHSource;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
_settings.EnablePATHSource = value;
|
||||||
|
ReIndexing();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public string CustomizedExplorerPath
|
public string CustomizedExplorerPath
|
||||||
{
|
{
|
||||||
get => _settings.CustomizedExplorer;
|
get => _settings.CustomizedExplorer;
|
||||||
|
|
@ -88,7 +98,7 @@ namespace Flow.Launcher.Plugin.Program.Views
|
||||||
|
|
||||||
private void Setting_Loaded(object sender, RoutedEventArgs e)
|
private void Setting_Loaded(object sender, RoutedEventArgs e)
|
||||||
{
|
{
|
||||||
ProgramSettingDisplayList = _settings.ProgramSources.LoadProgramSources();
|
ProgramSettingDisplayList = ProgramSettingDisplay.LoadProgramSources();
|
||||||
programSourceView.ItemsSource = ProgramSettingDisplayList;
|
programSourceView.ItemsSource = ProgramSettingDisplayList;
|
||||||
|
|
||||||
ViewRefresh();
|
ViewRefresh();
|
||||||
|
|
@ -147,20 +157,35 @@ namespace Flow.Launcher.Plugin.Program.Views
|
||||||
|
|
||||||
private void btnEditProgramSource_OnClick(object sender, RoutedEventArgs e)
|
private void btnEditProgramSource_OnClick(object sender, RoutedEventArgs e)
|
||||||
{
|
{
|
||||||
var selectedProgramSource = programSourceView.SelectedItem as Settings.ProgramSource;
|
var selectedProgramSource = programSourceView.SelectedItem as ProgramSource;
|
||||||
if (selectedProgramSource != null)
|
EditProgramSource(selectedProgramSource);
|
||||||
{
|
}
|
||||||
var add = new AddProgramSource(selectedProgramSource, _settings);
|
|
||||||
if (add.ShowDialog() ?? false)
|
private void EditProgramSource(ProgramSource selectedProgramSource)
|
||||||
{
|
{
|
||||||
ReIndexing();
|
if (selectedProgramSource == null)
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
{
|
||||||
string msg = context.API.GetTranslation("flowlauncher_plugin_program_pls_select_program_source");
|
string msg = context.API.GetTranslation("flowlauncher_plugin_program_pls_select_program_source");
|
||||||
MessageBox.Show(msg);
|
MessageBox.Show(msg);
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var add = new AddProgramSource(context, _settings, selectedProgramSource);
|
||||||
|
if (add.ShowDialog() ?? false)
|
||||||
|
{
|
||||||
|
if (selectedProgramSource.Enabled)
|
||||||
|
{
|
||||||
|
ProgramSettingDisplay.SetProgramSourcesStatus(new List<ProgramSource> { selectedProgramSource }, true); // sync status in win32, uwp and disabled
|
||||||
|
ProgramSettingDisplay.RemoveDisabledFromSettings();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ProgramSettingDisplay.SetProgramSourcesStatus(new List<ProgramSource> { selectedProgramSource }, false);
|
||||||
|
ProgramSettingDisplay.StoreDisabledInSettings();
|
||||||
|
}
|
||||||
|
ReIndexing();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void btnReindex_Click(object sender, RoutedEventArgs e)
|
private void btnReindex_Click(object sender, RoutedEventArgs e)
|
||||||
|
|
@ -199,19 +224,16 @@ namespace Flow.Launcher.Plugin.Program.Views
|
||||||
{
|
{
|
||||||
foreach (string directory in directories)
|
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
|
var source = new ProgramSource(directory);
|
||||||
{
|
|
||||||
Location = directory,
|
|
||||||
UniqueIdentifier = directory
|
|
||||||
};
|
|
||||||
|
|
||||||
directoriesToAdd.Add(source);
|
directoriesToAdd.Add(source);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (directoriesToAdd.Count() > 0)
|
if (directoriesToAdd.Count > 0)
|
||||||
{
|
{
|
||||||
directoriesToAdd.ForEach(x => _settings.ProgramSources.Add(x));
|
directoriesToAdd.ForEach(x => _settings.ProgramSources.Add(x));
|
||||||
directoriesToAdd.ForEach(x => ProgramSettingDisplayList.Add(x));
|
directoriesToAdd.ForEach(x => ProgramSettingDisplayList.Add(x));
|
||||||
|
|
@ -224,7 +246,7 @@ namespace Flow.Launcher.Plugin.Program.Views
|
||||||
|
|
||||||
private void btnLoadAllProgramSource_OnClick(object sender, RoutedEventArgs e)
|
private void btnLoadAllProgramSource_OnClick(object sender, RoutedEventArgs e)
|
||||||
{
|
{
|
||||||
ProgramSettingDisplayList.LoadAllApplications();
|
ProgramSettingDisplay.DisplayAllPrograms();
|
||||||
|
|
||||||
ViewRefresh();
|
ViewRefresh();
|
||||||
}
|
}
|
||||||
|
|
@ -235,18 +257,14 @@ namespace Flow.Launcher.Plugin.Program.Views
|
||||||
.SelectedItems.Cast<ProgramSource>()
|
.SelectedItems.Cast<ProgramSource>()
|
||||||
.ToList();
|
.ToList();
|
||||||
|
|
||||||
if (selectedItems.Count() == 0)
|
if (selectedItems.Count == 0)
|
||||||
{
|
{
|
||||||
string msg = context.API.GetTranslation("flowlauncher_plugin_program_pls_select_program_source");
|
string msg = context.API.GetTranslation("flowlauncher_plugin_program_pls_select_program_source");
|
||||||
MessageBox.Show(msg);
|
MessageBox.Show(msg);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (selectedItems
|
if (IsAllItemsUserAdded(selectedItems))
|
||||||
.Where(t1 => !_settings
|
|
||||||
.ProgramSources
|
|
||||||
.Any(x => t1.UniqueIdentifier == x.UniqueIdentifier))
|
|
||||||
.Count() == 0)
|
|
||||||
{
|
{
|
||||||
var msg = string.Format(context.API.GetTranslation("flowlauncher_plugin_program_delete_program_source"));
|
var msg = string.Format(context.API.GetTranslation("flowlauncher_plugin_program_delete_program_source"));
|
||||||
|
|
||||||
|
|
@ -257,17 +275,17 @@ namespace Flow.Launcher.Plugin.Program.Views
|
||||||
|
|
||||||
DeleteProgramSources(selectedItems);
|
DeleteProgramSources(selectedItems);
|
||||||
}
|
}
|
||||||
else if (IsSelectedRowStatusEnabledMoreOrEqualThanDisabled(selectedItems))
|
else if (HasMoreOrEqualEnabledItems(selectedItems))
|
||||||
{
|
{
|
||||||
ProgramSettingDisplayList.SetProgramSourcesStatus(selectedItems, false);
|
ProgramSettingDisplay.SetProgramSourcesStatus(selectedItems, false);
|
||||||
|
|
||||||
ProgramSettingDisplayList.StoreDisabledInSettings();
|
ProgramSettingDisplay.StoreDisabledInSettings();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
ProgramSettingDisplayList.SetProgramSourcesStatus(selectedItems, true);
|
ProgramSettingDisplay.SetProgramSourcesStatus(selectedItems, true);
|
||||||
|
|
||||||
ProgramSettingDisplayList.RemoveDisabledFromSettings();
|
ProgramSettingDisplay.RemoveDisabledFromSettings();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (selectedItems.IsReindexRequired())
|
if (selectedItems.IsReindexRequired())
|
||||||
|
|
@ -329,35 +347,41 @@ namespace Flow.Launcher.Plugin.Program.Views
|
||||||
dataView.Refresh();
|
dataView.Refresh();
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool IsSelectedRowStatusEnabledMoreOrEqualThanDisabled(List<ProgramSource> selectedItems)
|
private static bool HasMoreOrEqualEnabledItems(List<ProgramSource> 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
|
var selectedItems = programSourceView
|
||||||
.SelectedItems.Cast<ProgramSource>()
|
.SelectedItems.Cast<ProgramSource>()
|
||||||
.ToList();
|
.ToList();
|
||||||
|
|
||||||
if (selectedItems
|
if (IsAllItemsUserAdded(selectedItems))
|
||||||
.Where(t1 => !_settings
|
|
||||||
.ProgramSources
|
|
||||||
.Any(x => t1.UniqueIdentifier == x.UniqueIdentifier))
|
|
||||||
.Count() == 0)
|
|
||||||
{
|
{
|
||||||
btnProgramSourceStatus.Content = context.API.GetTranslation("flowlauncher_plugin_program_delete");
|
btnProgramSourceStatus.Content = context.API.GetTranslation("flowlauncher_plugin_program_delete");
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
else if (HasMoreOrEqualEnabledItems(selectedItems))
|
||||||
if (IsSelectedRowStatusEnabledMoreOrEqualThanDisabled(selectedItems))
|
|
||||||
{
|
{
|
||||||
btnProgramSourceStatus.Content = "Disable";
|
btnProgramSourceStatus.Content = context.API.GetTranslation("flowlauncher_plugin_program_disable");
|
||||||
}
|
}
|
||||||
else
|
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<ProgramSource> items)
|
||||||
|
{
|
||||||
|
return items.All(x => _settings.ProgramSources.Any(y => y.UniqueIdentifier == x.UniqueIdentifier));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue