mirror of
https://github.com/microsoft/PowerToys.git
synced 2026-01-15 08:46:37 +01:00
Add a new icon for run (#574)
Couple other hotfixes: * We broke FastUpToDate in #559. `PreserveNewest` fixes this * Winget would fetch ALL the details before displaying the list. Big yikes. Lazy load that! * We needed to better handle the case where we fetched items in response to a `ItemsChanged`, Loading is set to false, && there's an EmptyContent - we shouldn't flash the empty state before displaying the results * Details had itsy-bitsy text (regressed in #482)
This commit is contained in:
@@ -3,11 +3,11 @@
|
||||
<ManagePackageVersionsCentrally>true</ManagePackageVersionsCentrally>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<PackageVersion Include="Microsoft.CommandPalette.Extensions" Version="0.0.9" />
|
||||
<PackageVersion Include="Microsoft.CommandPalette.Extensions" Version="0.1.0" />
|
||||
<PackageVersion Include="Microsoft.CodeAnalysis.NetAnalyzers" Version="9.0.0-preview.24508.2" />
|
||||
<PackageVersion Include="Microsoft.Web.WebView2" Version="1.0.2903.40" />
|
||||
<PackageVersion Include="Microsoft.Windows.CsWin32" Version="0.2.46-beta" />
|
||||
<PackageVersion Include="Microsoft.Windows.CsWinRT" Version="2.1.5" />
|
||||
<PackageVersion Include="Microsoft.Windows.CsWinRT" Version="2.2.0" />
|
||||
<PackageVersion Include="Microsoft.Windows.SDK.BuildTools" Version="10.0.22621.2428" />
|
||||
<PackageVersion Include="Microsoft.WindowsAppSDK" Version="1.6.250205002" />
|
||||
<PackageVersion Include="StyleCop.Analyzers" Version="1.2.0-beta.556" />
|
||||
|
||||
@@ -7,10 +7,6 @@
|
||||
<AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
|
||||
<AppendRuntimeIdentifierToOutputPath>false</AppendRuntimeIdentifierToOutputPath>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<None Remove="Assets\AllApps.png" />
|
||||
<None Remove="Assets\AllApps.svg" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="System.IO.Abstractions" />
|
||||
@@ -34,12 +30,16 @@
|
||||
</Compile>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Remove="Assets\AllApps.png" />
|
||||
<None Remove="Assets\AllApps.svg" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Content Update="Assets\AllApps.png">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Update="Assets\AllApps.svg">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
</ItemGroup>
|
||||
|
||||
|
||||
@@ -8,9 +8,6 @@
|
||||
<!-- MRT from windows app sdk will search for a pri file with the same name of the module before defaulting to resources.pri -->
|
||||
<ProjectPriFileName>Microsoft.CmdPal.Ext.Calc.pri</ProjectPriFileName>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<None Remove="Assets\Calculator.svg" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\extensionsdk\Microsoft.CommandPalette.Extensions.Toolkit\Microsoft.CommandPalette.Extensions.Toolkit.csproj" />
|
||||
</ItemGroup>
|
||||
@@ -23,12 +20,15 @@
|
||||
</Compile>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Remove="Assets\Calculator.svg" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Content Update="Assets\Calculator.png">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Update="Assets\Calculator.svg">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
|
||||
@@ -8,9 +8,6 @@
|
||||
<AppendRuntimeIdentifierToOutputPath>false</AppendRuntimeIdentifierToOutputPath>
|
||||
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<None Remove="Assets\FileExplorer.svg" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.Windows.CsWin32">
|
||||
@@ -30,12 +27,15 @@
|
||||
</Compile>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Remove="Assets\FileExplorer.svg" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Content Update="Assets\FileExplorer.png">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Update="Assets\FileExplorer.svg">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
</ItemGroup>
|
||||
|
||||
|
||||
@@ -8,9 +8,6 @@
|
||||
<!-- MRT from windows app sdk will search for a pri file with the same name of the module before defaulting to resources.pri -->
|
||||
<ProjectPriFileName>Microsoft.CmdPal.Ext.Registry.pri</ProjectPriFileName>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<None Remove="Assets\Registry.svg" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="System.ServiceProcess.ServiceController" />
|
||||
</ItemGroup>
|
||||
@@ -24,12 +21,16 @@
|
||||
<DependentUpon>Resources.resx</DependentUpon>
|
||||
</Compile>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Remove="Assets\Registry.svg" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Content Update="Assets\Registry.png">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Update="Assets\Registry.svg">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
</ItemGroup>
|
||||
|
||||
|
||||
@@ -23,4 +23,11 @@
|
||||
<Generator>PublicResXFileCodeGenerator</Generator>
|
||||
</EmbeddedResource>
|
||||
</ItemGroup>
|
||||
|
||||
|
||||
<ItemGroup>
|
||||
<Content Update="Assets\Run@2x.svg">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
||||
@@ -20,14 +20,14 @@ public partial class ShellCommandsProvider : CommandProvider
|
||||
{
|
||||
Id = "Run";
|
||||
DisplayName = Resources.cmd_plugin_name;
|
||||
Icon = new IconInfo("\uE756");
|
||||
Icon = Icons.RunV2;
|
||||
Settings = _settingsManager.Settings;
|
||||
|
||||
_fallbackItem = new FallbackExecuteItem(_settingsManager);
|
||||
|
||||
_shellPageItem = new CommandItem(new ShellListPage(_settingsManager))
|
||||
{
|
||||
Icon = new IconInfo("\uE756"),
|
||||
Icon = Icons.RunV2,
|
||||
Title = Resources.shell_command_name,
|
||||
Subtitle = Resources.cmd_plugin_description,
|
||||
MoreCommands = [
|
||||
|
||||
@@ -8,9 +8,6 @@
|
||||
<!-- MRT from windows app sdk will search for a pri file with the same name of the module before defaulting to resources.pri -->
|
||||
<ProjectPriFileName>Microsoft.CmdPal.Ext.TimeDate.pri</ProjectPriFileName>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<None Include="Assets\TimeDate.png" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<EmbeddedResource Update="Properties\Resources.resx">
|
||||
@@ -32,12 +29,15 @@
|
||||
</Compile>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Include="Assets\TimeDate.png" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Content Update="Assets\TimeDate.png">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Update="Assets\TimeDate.svg">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
@@ -7,17 +7,7 @@
|
||||
<AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
|
||||
<AppendRuntimeIdentifierToOutputPath>false</AppendRuntimeIdentifierToOutputPath>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Compile Remove="Images\**" />
|
||||
<Content Remove="Images\**" />
|
||||
<EmbeddedResource Remove="Images\**" />
|
||||
<None Remove="Images\**" />
|
||||
<Page Remove="Images\**" />
|
||||
<PRIResource Remove="Images\**" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Remove="Assets\WebSearch.svg" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\extensionsdk\Microsoft.CommandPalette.Extensions.Toolkit\Microsoft.CommandPalette.Extensions.Toolkit.csproj" />
|
||||
</ItemGroup>
|
||||
@@ -38,11 +28,18 @@
|
||||
</Compile>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Remove="Assets\WebSearch.svg" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Content Update="Assets\WebSearch.png">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Update="Assets\WebSearch.svg">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<EmbeddedResource Update="Properties\Resources.resx">
|
||||
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
|
||||
@@ -50,8 +47,5 @@
|
||||
</EmbeddedResource>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Content Update="Assets\WebSearch.svg">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</Content>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
||||
@@ -30,10 +30,10 @@
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Content Update="Assets\WindowsSettings.png">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Update="Assets\WindowsSettings.svg">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
|
||||
@@ -9,12 +9,6 @@
|
||||
<!-- MRT from windows app sdk will search for a pri file with the same name of the module before defaulting to resources.pri -->
|
||||
<ProjectPriFileName>Microsoft.CmdPal.Ext.WindowsTerminal.pri</ProjectPriFileName>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Content Remove="Assets\WindowsTerminal.dark.png" />
|
||||
<Content Remove="Assets\WindowsTerminal.dark.png" />
|
||||
<Content Remove="Assets\WindowsTerminal.light.png" />
|
||||
<Content Remove="Assets\WindowsTerminal.light.png" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Remove="Assets\WindowsTerminal.svg" />
|
||||
</ItemGroup>
|
||||
@@ -28,14 +22,22 @@
|
||||
<AutoGen>True</AutoGen>
|
||||
</Compile>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Content Remove="Assets\WindowsTerminal.dark.png" />
|
||||
<Content Remove="Assets\WindowsTerminal.dark.png" />
|
||||
<Content Remove="Assets\WindowsTerminal.light.png" />
|
||||
<Content Remove="Assets\WindowsTerminal.light.png" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Content Update="Assets\WindowsTerminal.png">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Update="Assets\WindowsTerminal.svg">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<EmbeddedResource Update="Properties\Resources.resx">
|
||||
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
|
||||
|
||||
Binary file not shown.
@@ -28,13 +28,13 @@ internal sealed partial class CreatedExtensionForm : NewExtensionFormBase
|
||||
|
||||
public override ICommandResult SubmitForm(string inputs, string data)
|
||||
{
|
||||
var dataInput = JsonNode.Parse(data)?.AsObject();
|
||||
JsonObject? dataInput = JsonNode.Parse(data)?.AsObject();
|
||||
if (dataInput == null)
|
||||
{
|
||||
return CommandResult.KeepOpen();
|
||||
}
|
||||
|
||||
var verb = dataInput["x"]?.AsValue()?.ToString() ?? string.Empty;
|
||||
string verb = dataInput["x"]?.AsValue()?.ToString() ?? string.Empty;
|
||||
return verb switch
|
||||
{
|
||||
"sln" => OpenSolution(),
|
||||
@@ -47,17 +47,17 @@ internal sealed partial class CreatedExtensionForm : NewExtensionFormBase
|
||||
private ICommandResult OpenSolution()
|
||||
{
|
||||
string[] parts = [_path, _name, $"{_name}.sln"];
|
||||
var pathToSolution = Path.Combine(parts);
|
||||
string pathToSolution = Path.Combine(parts);
|
||||
ShellHelpers.OpenInShell(pathToSolution);
|
||||
return CommandResult.GoHome();
|
||||
return CommandResult.Hide();
|
||||
}
|
||||
|
||||
private ICommandResult OpenDirectory()
|
||||
{
|
||||
string[] parts = [_path, _name];
|
||||
var pathToDir = Path.Combine(parts);
|
||||
string pathToDir = Path.Combine(parts);
|
||||
ShellHelpers.OpenInShell(pathToDir);
|
||||
return CommandResult.GoHome();
|
||||
return CommandResult.Hide();
|
||||
}
|
||||
|
||||
private ICommandResult CreateNew()
|
||||
|
||||
@@ -32,12 +32,14 @@ public partial class ListViewModel : PageViewModel, IDisposable
|
||||
private readonly Lock _listLock = new();
|
||||
|
||||
private bool _isLoading;
|
||||
private bool _isFetching;
|
||||
|
||||
public event TypedEventHandler<ListViewModel, object>? ItemsUpdated;
|
||||
|
||||
public bool ShowEmptyContent =>
|
||||
IsInitialized &&
|
||||
FilteredItems.Count == 0 &&
|
||||
(!_isFetching) &&
|
||||
IsLoading == false;
|
||||
|
||||
// Remember - "observable" properties from the model (via PropChanged)
|
||||
@@ -122,9 +124,11 @@ public partial class ListViewModel : PageViewModel, IDisposable
|
||||
{
|
||||
// TEMPORARY: just plop all the items into a single group
|
||||
// see 9806fe5d8 for the last commit that had this with sections
|
||||
_isFetching = true;
|
||||
|
||||
try
|
||||
{
|
||||
var newItems = _model.Unsafe!.GetItems();
|
||||
IListItem[] newItems = _model.Unsafe!.GetItems();
|
||||
|
||||
// Collect all the items into new viewmodels
|
||||
Collection<ListItemViewModel> newViewModels = [];
|
||||
@@ -132,7 +136,7 @@ public partial class ListViewModel : PageViewModel, IDisposable
|
||||
// TODO we can probably further optimize this by also keeping a
|
||||
// HashSet of every ExtensionObject we currently have, and only
|
||||
// building new viewmodels for the ones we haven't already built.
|
||||
foreach (var item in newItems)
|
||||
foreach (IListItem? item in newItems)
|
||||
{
|
||||
ListItemViewModel viewModel = new(item, new(this));
|
||||
|
||||
@@ -143,8 +147,8 @@ public partial class ListViewModel : PageViewModel, IDisposable
|
||||
}
|
||||
}
|
||||
|
||||
var firstTwenty = newViewModels.Take(20);
|
||||
foreach (var item in firstTwenty)
|
||||
IEnumerable<ListItemViewModel> firstTwenty = newViewModels.Take(20);
|
||||
foreach (ListItemViewModel? item in firstTwenty)
|
||||
{
|
||||
item?.SafeInitializeProperties();
|
||||
}
|
||||
@@ -172,6 +176,10 @@ public partial class ListViewModel : PageViewModel, IDisposable
|
||||
ShowException(ex, _model?.Unsafe?.Name);
|
||||
throw;
|
||||
}
|
||||
finally
|
||||
{
|
||||
_isFetching = false;
|
||||
}
|
||||
|
||||
_cancellationTokenSource = new CancellationTokenSource();
|
||||
|
||||
@@ -225,7 +233,7 @@ public partial class ListViewModel : PageViewModel, IDisposable
|
||||
iterable = Items.ToArray();
|
||||
}
|
||||
|
||||
foreach (var item in iterable)
|
||||
foreach (ListItemViewModel item in iterable)
|
||||
{
|
||||
ct.ThrowIfCancellationRequested();
|
||||
|
||||
@@ -258,8 +266,8 @@ public partial class ListViewModel : PageViewModel, IDisposable
|
||||
return 1;
|
||||
}
|
||||
|
||||
var nameMatch = StringMatcher.FuzzySearch(query, listItem.Title);
|
||||
var descriptionMatch = StringMatcher.FuzzySearch(query, listItem.Subtitle);
|
||||
MatchResult nameMatch = StringMatcher.FuzzySearch(query, listItem.Title);
|
||||
MatchResult descriptionMatch = StringMatcher.FuzzySearch(query, listItem.Subtitle);
|
||||
return new[] { nameMatch.Score, (descriptionMatch.Score - 4) / 2, 0 }.Max();
|
||||
}
|
||||
|
||||
@@ -272,7 +280,7 @@ public partial class ListViewModel : PageViewModel, IDisposable
|
||||
// Similarly stolen from ListHelpers.FilterList
|
||||
public static IEnumerable<ListItemViewModel> FilterList(IEnumerable<ListItemViewModel> items, string query)
|
||||
{
|
||||
var scores = items
|
||||
IOrderedEnumerable<ScoredListItemViewModel> scores = items
|
||||
.Where(i => !i.IsInErrorState)
|
||||
.Select(li => new ScoredListItemViewModel() { ViewModel = li, Score = ScoreListItem(query, li) })
|
||||
.Where(score => score.Score > 0)
|
||||
@@ -351,7 +359,7 @@ public partial class ListViewModel : PageViewModel, IDisposable
|
||||
{
|
||||
base.InitializeProperties();
|
||||
|
||||
var model = _model.Unsafe;
|
||||
IListPage? model = _model.Unsafe;
|
||||
if (model == null)
|
||||
{
|
||||
return; // throw?
|
||||
@@ -377,7 +385,7 @@ public partial class ListViewModel : PageViewModel, IDisposable
|
||||
|
||||
public void LoadMoreIfNeeded()
|
||||
{
|
||||
var model = this._model.Unsafe;
|
||||
IListPage? model = this._model.Unsafe;
|
||||
if (model == null)
|
||||
{
|
||||
return;
|
||||
@@ -404,7 +412,7 @@ public partial class ListViewModel : PageViewModel, IDisposable
|
||||
{
|
||||
base.FetchProperty(propertyName);
|
||||
|
||||
var model = this._model.Unsafe;
|
||||
IListPage? model = this._model.Unsafe;
|
||||
if (model == null)
|
||||
{
|
||||
return; // throw?
|
||||
@@ -467,13 +475,13 @@ public partial class ListViewModel : PageViewModel, IDisposable
|
||||
|
||||
lock (_listLock)
|
||||
{
|
||||
foreach (var item in Items)
|
||||
foreach (ListItemViewModel item in Items)
|
||||
{
|
||||
item.SafeCleanup();
|
||||
}
|
||||
|
||||
Items.Clear();
|
||||
foreach (var item in FilteredItems)
|
||||
foreach (ListItemViewModel item in FilteredItems)
|
||||
{
|
||||
item.SafeCleanup();
|
||||
}
|
||||
@@ -481,7 +489,7 @@ public partial class ListViewModel : PageViewModel, IDisposable
|
||||
FilteredItems.Clear();
|
||||
}
|
||||
|
||||
var model = _model.Unsafe;
|
||||
IListPage? model = _model.Unsafe;
|
||||
if (model != null)
|
||||
{
|
||||
model.ItemsChanged -= Model_ItemsChanged;
|
||||
|
||||
@@ -10,6 +10,12 @@
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
mc:Ignorable="d">
|
||||
|
||||
<UserControl.Resources>
|
||||
<ResourceDictionary>
|
||||
<cmdpalUi:PlaceholderTextConverter x:Key="PlaceholderTextConverter" />
|
||||
</ResourceDictionary>
|
||||
</UserControl.Resources>
|
||||
|
||||
<!-- Search box -->
|
||||
<TextBox
|
||||
x:Name="FilterBox"
|
||||
@@ -17,7 +23,7 @@
|
||||
VerticalAlignment="Stretch"
|
||||
VerticalContentAlignment="Stretch"
|
||||
KeyDown="FilterBox_KeyDown"
|
||||
PlaceholderText="{x:Bind CurrentPageViewModel.PlaceholderText, Mode=OneWay}"
|
||||
PlaceholderText="{x:Bind CurrentPageViewModel.PlaceholderText, Converter={StaticResource PlaceholderTextConverter}, Mode=OneWay}"
|
||||
PreviewKeyDown="FilterBox_PreviewKeyDown"
|
||||
PreviewKeyUp="FilterBox_PreviewKeyUp"
|
||||
Style="{StaticResource SearchTextBoxStyle}"
|
||||
|
||||
@@ -335,7 +335,6 @@
|
||||
Grid.Row="2"
|
||||
Margin="0,12,0,24"
|
||||
Background="Transparent"
|
||||
FontSize="10"
|
||||
Header3FontSize="12"
|
||||
Header3FontWeight="Normal"
|
||||
Header3Foreground="{ThemeResource TextFillColorSecondaryBrush}"
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
<svg width="260" height="260" viewBox="0 0 260 260" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M17.7189 166.405L34.8123 80.9387C37.8287 65.8564 51.0714 55 66.4524 55H210.641C231.003 55 246.274 73.6283 242.281 93.5947L225.188 179.061C222.171 194.144 208.929 205 193.548 205H49.359C28.9972 205 13.7257 186.372 17.7189 166.405Z" fill="url(#paint0_linear_15_159)" stroke="url(#paint1_linear_15_159)" stroke-width="32.2667"/>
|
||||
<path d="M66.3623 129.973L70.5337 110.506C73.7217 95.6287 86.8692 85 102.084 85H162.086C182.628 85 197.94 103.941 193.636 124.027L189.465 143.494C186.277 158.371 173.129 169 157.914 169H97.9127C77.3703 169 62.0581 150.059 66.3623 129.973Z" fill="url(#paint2_linear_15_159)"/>
|
||||
<path d="M85.1317 114.211L85.7539 110.478C87.0504 102.699 93.7811 96.9971 101.668 96.9971H164.956C174.925 96.9971 182.509 105.949 180.87 115.783L180.248 119.516C178.951 127.295 172.22 132.997 164.334 132.997H101.045C91.0761 132.997 83.4927 124.045 85.1317 114.211Z" fill="white"/>
|
||||
<defs>
|
||||
<linearGradient id="paint0_linear_15_159" x1="148" y1="61" x2="130" y2="205" gradientUnits="userSpaceOnUse">
|
||||
<stop stop-color="#CDEDFC"/>
|
||||
<stop offset="1" stop-color="#BFE3F9"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="paint1_linear_15_159" x1="46" y1="49" x2="268" y2="253" gradientUnits="userSpaceOnUse">
|
||||
<stop stop-color="#3BCAF4"/>
|
||||
<stop offset="1" stop-color="#006AAA"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="paint2_linear_15_159" x1="93.9993" y1="73" x2="216.411" y2="214.919" gradientUnits="userSpaceOnUse">
|
||||
<stop stop-color="#5ED0F2"/>
|
||||
<stop offset="1" stop-color="#1494DF"/>
|
||||
</linearGradient>
|
||||
</defs>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.6 KiB |
12
src/modules/cmdpal/exts/Microsoft.CmdPal.Ext.Shell/Icons.cs
Normal file
12
src/modules/cmdpal/exts/Microsoft.CmdPal.Ext.Shell/Icons.cs
Normal file
@@ -0,0 +1,12 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using Microsoft.CommandPalette.Extensions.Toolkit;
|
||||
|
||||
namespace Microsoft.CmdPal.Ext.Shell;
|
||||
|
||||
internal sealed class Icons
|
||||
{
|
||||
internal static IconInfo RunV2 { get; } = IconHelpers.FromRelativePath("Assets\\Run@2x.svg");
|
||||
}
|
||||
@@ -82,16 +82,16 @@
|
||||
|
||||
<ItemGroup>
|
||||
<Content Update="Assets\Store.dark.png">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Update="Assets\Store.dark.svg">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Update="Assets\Store.light.png">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Update="Assets\Store.light.svg">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
|
||||
@@ -18,6 +18,12 @@ namespace Microsoft.CmdPal.Ext.WinGet.Pages;
|
||||
public partial class InstallPackageListItem : ListItem
|
||||
{
|
||||
private readonly CatalogPackage _package;
|
||||
|
||||
// Lazy-init the details
|
||||
private readonly Lazy<Details?> _details;
|
||||
|
||||
public override IDetails? Details { get => _details.Value; set => base.Details = value; }
|
||||
|
||||
private InstallPackageCommand? _installCommand;
|
||||
|
||||
public InstallPackageListItem(CatalogPackage package)
|
||||
@@ -25,24 +31,31 @@ public partial class InstallPackageListItem : ListItem
|
||||
{
|
||||
_package = package;
|
||||
|
||||
var version = _package.DefaultInstallVersion;
|
||||
var versionText = version.Version;
|
||||
var versionTagText = versionText == "Unknown" && version.PackageCatalog.Info.Id == "StoreEdgeFD" ? "msstore" : versionText;
|
||||
PackageVersionInfo version = _package.DefaultInstallVersion;
|
||||
string versionText = version.Version;
|
||||
string versionTagText = versionText == "Unknown" && version.PackageCatalog.Info.Id == "StoreEdgeFD" ? "msstore" : versionText;
|
||||
|
||||
Title = _package.Name;
|
||||
Subtitle = _package.Id;
|
||||
Tags = [new Tag() { Text = versionTagText }];
|
||||
|
||||
var metadata = version.GetCatalogPackageMetadata();
|
||||
_details = new Lazy<Details?>(() => BuildDetails(version));
|
||||
|
||||
_ = Task.Run(UpdatedInstalledStatus);
|
||||
}
|
||||
|
||||
private Details? BuildDetails(PackageVersionInfo? version)
|
||||
{
|
||||
CatalogPackageMetadata? metadata = version?.GetCatalogPackageMetadata();
|
||||
if (metadata != null)
|
||||
{
|
||||
var description = string.IsNullOrEmpty(metadata.Description) ? metadata.ShortDescription : metadata.Description;
|
||||
var detailsBody = $"""
|
||||
string description = string.IsNullOrEmpty(metadata.Description) ? metadata.ShortDescription : metadata.Description;
|
||||
string detailsBody = $"""
|
||||
|
||||
{description}
|
||||
""";
|
||||
var heroIcon = new IconInfo(string.Empty);
|
||||
var icons = metadata.Icons;
|
||||
IconInfo heroIcon = new(string.Empty);
|
||||
IReadOnlyList<Icon> icons = metadata.Icons;
|
||||
if (icons.Count > 0)
|
||||
{
|
||||
// There's also a .Theme property we could probably use to
|
||||
@@ -50,7 +63,7 @@ public partial class InstallPackageListItem : ListItem
|
||||
heroIcon = new IconInfo(icons[0].Url);
|
||||
}
|
||||
|
||||
Details = new Details()
|
||||
return new Details()
|
||||
{
|
||||
Body = detailsBody,
|
||||
Title = metadata.PackageName,
|
||||
@@ -59,7 +72,7 @@ public partial class InstallPackageListItem : ListItem
|
||||
};
|
||||
}
|
||||
|
||||
_ = Task.Run(UpdatedInstalledStatus);
|
||||
return null;
|
||||
}
|
||||
|
||||
private List<IDetailsElement> GetDetailsMetadata(CatalogPackageMetadata metadata)
|
||||
@@ -80,23 +93,23 @@ public partial class InstallPackageListItem : ListItem
|
||||
{ Properties.Resources.winget_view_release_notes, (string.IsNullOrEmpty(metadata.ReleaseNotesUrl) ? string.Empty : Properties.Resources.winget_view_online, metadata.ReleaseNotesUrl) },
|
||||
{ Properties.Resources.winget_publisher_support, (string.Empty, metadata.PublisherSupportUrl) },
|
||||
};
|
||||
var docs = metadata.Documentations.ToArray();
|
||||
foreach (var item in docs)
|
||||
Documentation[] docs = metadata.Documentations.ToArray();
|
||||
foreach (Documentation? item in docs)
|
||||
{
|
||||
simpleData.Add(item.DocumentLabel, (string.Empty, item.DocumentUrl));
|
||||
}
|
||||
|
||||
var options = default(UriCreationOptions);
|
||||
foreach (var kv in simpleData)
|
||||
UriCreationOptions options = default;
|
||||
foreach (KeyValuePair<string, (string, string)> kv in simpleData)
|
||||
{
|
||||
var text = string.IsNullOrEmpty(kv.Value.Item1) ? kv.Value.Item2 : kv.Value.Item1;
|
||||
var target = kv.Value.Item2;
|
||||
string text = string.IsNullOrEmpty(kv.Value.Item1) ? kv.Value.Item2 : kv.Value.Item1;
|
||||
string target = kv.Value.Item2;
|
||||
if (!string.IsNullOrEmpty(text))
|
||||
{
|
||||
Uri? uri = null;
|
||||
Uri.TryCreate(target, options, out uri);
|
||||
|
||||
var pair = new DetailsElement()
|
||||
DetailsElement pair = new()
|
||||
{
|
||||
Key = kv.Key,
|
||||
Data = new DetailsLink() { Link = uri, Text = text },
|
||||
@@ -107,7 +120,7 @@ public partial class InstallPackageListItem : ListItem
|
||||
|
||||
if (metadata.Tags.Any())
|
||||
{
|
||||
var pair = new DetailsElement()
|
||||
DetailsElement pair = new()
|
||||
{
|
||||
Key = "Tags",
|
||||
Data = new DetailsTags() { Tags = metadata.Tags.Select(t => new Tag(t)).ToArray() },
|
||||
@@ -120,18 +133,18 @@ public partial class InstallPackageListItem : ListItem
|
||||
|
||||
private async void UpdatedInstalledStatus()
|
||||
{
|
||||
var status = await _package.CheckInstalledStatusAsync();
|
||||
var isInstalled = _package.InstalledVersion != null;
|
||||
CheckInstalledStatusResult status = await _package.CheckInstalledStatusAsync();
|
||||
bool isInstalled = _package.InstalledVersion != null;
|
||||
|
||||
// might be an uninstall command
|
||||
var installCommand = new InstallPackageCommand(_package, isInstalled);
|
||||
InstallPackageCommand installCommand = new(_package, isInstalled);
|
||||
|
||||
if (isInstalled)
|
||||
{
|
||||
this.Icon = InstallPackageCommand.CompletedIcon;
|
||||
this.Command = new NoOpCommand();
|
||||
List<IContextItem> contextMenu = [];
|
||||
var uninstallContextItem = new CommandContextItem(installCommand)
|
||||
CommandContextItem uninstallContextItem = new(installCommand)
|
||||
{
|
||||
IsCritical = true,
|
||||
Icon = InstallPackageCommand.DeleteIcon,
|
||||
@@ -139,8 +152,8 @@ public partial class InstallPackageListItem : ListItem
|
||||
|
||||
if (WinGetStatics.AppSearchCallback != null)
|
||||
{
|
||||
var callback = WinGetStatics.AppSearchCallback;
|
||||
var installedApp = callback(_package.DefaultInstallVersion.DisplayName);
|
||||
Func<string, ICommandItem?> callback = WinGetStatics.AppSearchCallback;
|
||||
ICommandItem? installedApp = callback(_package.DefaultInstallVersion.DisplayName);
|
||||
if (installedApp != null)
|
||||
{
|
||||
this.Command = installedApp.Command;
|
||||
@@ -177,11 +190,11 @@ public partial class InstallPackageListItem : ListItem
|
||||
Stopwatch s = new();
|
||||
Logger.LogDebug($"Starting RefreshPackageCatalogAsync");
|
||||
s.Start();
|
||||
var refs = WinGetStatics.AvailableCatalogs.ToArray();
|
||||
PackageCatalogReference[] refs = WinGetStatics.AvailableCatalogs.ToArray();
|
||||
|
||||
foreach (var catalog in refs)
|
||||
foreach (PackageCatalogReference? catalog in refs)
|
||||
{
|
||||
var operation = catalog.RefreshPackageCatalogAsync();
|
||||
global::Windows.Foundation.IAsyncOperationWithProgress<RefreshPackageCatalogResult, double> operation = catalog.RefreshPackageCatalogAsync();
|
||||
operation.Wait();
|
||||
}
|
||||
|
||||
|
||||
@@ -57,7 +57,7 @@ internal sealed partial class WinGetExtensionPage : DynamicListPage, IDisposable
|
||||
{
|
||||
// emptySearchForTag ===
|
||||
// we don't have results yet, we haven't typed anything, and we're searching for a tag
|
||||
var emptySearchForTag = _results == null &&
|
||||
bool emptySearchForTag = _results == null &&
|
||||
string.IsNullOrEmpty(SearchText) &&
|
||||
HasTag;
|
||||
|
||||
@@ -70,8 +70,9 @@ internal sealed partial class WinGetExtensionPage : DynamicListPage, IDisposable
|
||||
|
||||
if (_results != null && _results.Any())
|
||||
{
|
||||
ListItem[] results = _results.Select(PackageToListItem).ToArray();
|
||||
IsLoading = false;
|
||||
return _results.Select(PackageToListItem).ToArray();
|
||||
return results;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -111,7 +112,7 @@ internal sealed partial class WinGetExtensionPage : DynamicListPage, IDisposable
|
||||
|
||||
_cancellationTokenSource = new CancellationTokenSource();
|
||||
|
||||
var cancellationToken = _cancellationTokenSource.Token;
|
||||
CancellationToken cancellationToken = _cancellationTokenSource.Token;
|
||||
|
||||
IsLoading = true;
|
||||
|
||||
@@ -128,7 +129,7 @@ internal sealed partial class WinGetExtensionPage : DynamicListPage, IDisposable
|
||||
{
|
||||
try
|
||||
{
|
||||
var results = await searchTask;
|
||||
IEnumerable<CatalogPackage> results = await searchTask;
|
||||
|
||||
// Ensure this is still the latest task
|
||||
if (_currentSearchTask == searchTask)
|
||||
@@ -174,17 +175,17 @@ internal sealed partial class WinGetExtensionPage : DynamicListPage, IDisposable
|
||||
return [];
|
||||
}
|
||||
|
||||
var searchDebugText = $"{query}{(HasTag ? "+" : string.Empty)}{_tag}";
|
||||
string searchDebugText = $"{query}{(HasTag ? "+" : string.Empty)}{_tag}";
|
||||
Logger.LogDebug($"Starting search for '{searchDebugText}'");
|
||||
var results = new HashSet<CatalogPackage>(new PackageIdCompare());
|
||||
HashSet<CatalogPackage> results = new(new PackageIdCompare());
|
||||
|
||||
// Default selector: this is the way to do a `winget search <query>`
|
||||
var selector = WinGetStatics.WinGetFactory.CreatePackageMatchFilter();
|
||||
PackageMatchFilter selector = WinGetStatics.WinGetFactory.CreatePackageMatchFilter();
|
||||
selector.Field = Microsoft.Management.Deployment.PackageMatchField.CatalogDefault;
|
||||
selector.Value = query;
|
||||
selector.Option = PackageFieldMatchOption.ContainsCaseInsensitive;
|
||||
|
||||
var opts = WinGetStatics.WinGetFactory.CreateFindPackagesOptions();
|
||||
FindPackagesOptions opts = WinGetStatics.WinGetFactory.CreateFindPackagesOptions();
|
||||
opts.Selectors.Add(selector);
|
||||
|
||||
// testing
|
||||
@@ -193,7 +194,7 @@ internal sealed partial class WinGetExtensionPage : DynamicListPage, IDisposable
|
||||
// Selectors is "OR", Filters is "AND"
|
||||
if (HasTag)
|
||||
{
|
||||
var tagFilter = WinGetStatics.WinGetFactory.CreatePackageMatchFilter();
|
||||
PackageMatchFilter tagFilter = WinGetStatics.WinGetFactory.CreatePackageMatchFilter();
|
||||
tagFilter.Field = Microsoft.Management.Deployment.PackageMatchField.Tag;
|
||||
tagFilter.Value = _tag;
|
||||
tagFilter.Option = PackageFieldMatchOption.ContainsCaseInsensitive;
|
||||
@@ -204,11 +205,11 @@ internal sealed partial class WinGetExtensionPage : DynamicListPage, IDisposable
|
||||
// Clean up here, then...
|
||||
ct.ThrowIfCancellationRequested();
|
||||
|
||||
var catalogTask = HasTag ? WinGetStatics.CompositeWingetCatalog : WinGetStatics.CompositeAllCatalog;
|
||||
Lazy<Task<PackageCatalog>> catalogTask = HasTag ? WinGetStatics.CompositeWingetCatalog : WinGetStatics.CompositeAllCatalog;
|
||||
|
||||
// Both these catalogs should have been instantiated by the
|
||||
// WinGetStatics static ctor when we were created.
|
||||
var catalog = await catalogTask.Value;
|
||||
PackageCatalog catalog = await catalogTask.Value;
|
||||
|
||||
if (catalog == null)
|
||||
{
|
||||
@@ -224,8 +225,8 @@ internal sealed partial class WinGetExtensionPage : DynamicListPage, IDisposable
|
||||
|
||||
// BODGY, re: microsoft/winget-cli#5151
|
||||
// FindPackagesAsync isn't actually async.
|
||||
var internalSearchTask = Task.Run(() => catalog.FindPackages(opts), ct);
|
||||
var searchResults = await internalSearchTask;
|
||||
Task<FindPackagesResult> internalSearchTask = Task.Run(() => catalog.FindPackages(opts), ct);
|
||||
FindPackagesResult searchResults = await internalSearchTask;
|
||||
|
||||
// TODO more error handling like this:
|
||||
if (searchResults.Status != FindPackagesResultStatus.Ok)
|
||||
@@ -236,12 +237,12 @@ internal sealed partial class WinGetExtensionPage : DynamicListPage, IDisposable
|
||||
}
|
||||
|
||||
Logger.LogDebug($" got results for ({query})", memberName: nameof(DoSearchAsync));
|
||||
foreach (var match in searchResults.Matches.ToArray())
|
||||
foreach (Management.Deployment.MatchResult? match in searchResults.Matches.ToArray())
|
||||
{
|
||||
ct.ThrowIfCancellationRequested();
|
||||
|
||||
// Print the packages
|
||||
var package = match.CatalogPackage;
|
||||
CatalogPackage package = match.CatalogPackage;
|
||||
|
||||
results.Add(package);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user