CmdPal: Tidy up some winget experiences (#38174)

I'm filing this so that I don't lose it on this machine I use less often. We can probably hold it out of 0.90


Fixes:
* If a package is installed, we always display the version as "Unknown"
  * also deals with a case where getting the package metadata could fail, and we'd hide the list item. That's only possible in the "installed, no updates available" case
* Allow package updates, add an icon for updates
* moves off the preview winget API onto a higher stable version
This commit is contained in:
Mike Griese 2025-04-23 06:45:34 -05:00 committed by GitHub
parent f085ba0cd2
commit b0e7473760
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 76 additions and 18 deletions

View File

@ -45,7 +45,7 @@
<PackageVersion Include="Microsoft.Web.WebView2" Version="1.0.2903.40" /> <PackageVersion Include="Microsoft.Web.WebView2" Version="1.0.2903.40" />
<!-- Package Microsoft.Win32.SystemEvents added as a hack for being able to exclude the runtime assets so they don't conflict with 8.0.1. This is a dependency of System.Drawing.Common but the 8.0.1 version wasn't published to nuget. --> <!-- Package Microsoft.Win32.SystemEvents added as a hack for being able to exclude the runtime assets so they don't conflict with 8.0.1. This is a dependency of System.Drawing.Common but the 8.0.1 version wasn't published to nuget. -->
<PackageVersion Include="Microsoft.Win32.SystemEvents" Version="9.0.4" /> <PackageVersion Include="Microsoft.Win32.SystemEvents" Version="9.0.4" />
<PackageVersion Include="Microsoft.WindowsPackageManager.ComInterop" Version="1.10.120-preview" /> <PackageVersion Include="Microsoft.WindowsPackageManager.ComInterop" Version="1.10.340" />
<PackageVersion Include="Microsoft.Windows.Compatibility" Version="9.0.4" /> <PackageVersion Include="Microsoft.Windows.Compatibility" Version="9.0.4" />
<PackageVersion Include="Microsoft.Windows.CsWin32" Version="0.2.46-beta" /> <PackageVersion Include="Microsoft.Windows.CsWin32" Version="0.2.46-beta" />
<!-- CsWinRT version needs to be set to have a WinRT.Runtime.dll at the same version contained inside the NET SDK we're currently building on CI. --> <!-- CsWinRT version needs to be set to have a WinRT.Runtime.dll at the same version contained inside the NET SDK we're currently building on CI. -->

View File

@ -1473,7 +1473,7 @@ SOFTWARE.
- Microsoft.Windows.CsWinRT 2.2.0 - Microsoft.Windows.CsWinRT 2.2.0
- Microsoft.Windows.SDK.BuildTools 10.0.22621.2428 - Microsoft.Windows.SDK.BuildTools 10.0.22621.2428
- Microsoft.WindowsAppSDK 1.6.250205002 - Microsoft.WindowsAppSDK 1.6.250205002
- Microsoft.WindowsPackageManager.ComInterop 1.10.120-preview - Microsoft.WindowsPackageManager.ComInterop 1.10.340
- Microsoft.Xaml.Behaviors.WinUI.Managed 2.0.9 - Microsoft.Xaml.Behaviors.WinUI.Managed 2.0.9
- Microsoft.Xaml.Behaviors.Wpf 1.1.39 - Microsoft.Xaml.Behaviors.Wpf 1.1.39
- ModernWpfUI 0.9.4 - ModernWpfUI 0.9.4

View File

@ -22,10 +22,12 @@ public partial class InstallPackageCommand : InvokableCommand
private IAsyncOperationWithProgress<UninstallResult, UninstallProgress>? _unInstallAction; private IAsyncOperationWithProgress<UninstallResult, UninstallProgress>? _unInstallAction;
private Task? _installTask; private Task? _installTask;
public bool IsInstalled { get; private set; } public PackageInstallCommandState InstallCommandState { get; private set; }
public static IconInfo CompletedIcon { get; } = new("\uE930"); // Completed public static IconInfo CompletedIcon { get; } = new("\uE930"); // Completed
public static IconInfo UpdateIcon { get; } = new("\uE74A"); // Up
public static IconInfo DownloadIcon { get; } = new("\uE896"); // Download public static IconInfo DownloadIcon { get; } = new("\uE896"); // Download
public static IconInfo DeleteIcon { get; } = new("\uE74D"); // Delete public static IconInfo DeleteIcon { get; } = new("\uE74D"); // Delete
@ -44,23 +46,41 @@ public partial class InstallPackageCommand : InvokableCommand
internal bool SkipDependencies { get; set; } internal bool SkipDependencies { get; set; }
public InstallPackageCommand(CatalogPackage package, bool isInstalled) public InstallPackageCommand(CatalogPackage package, PackageInstallCommandState isInstalled)
{ {
_package = package; _package = package;
IsInstalled = isInstalled; InstallCommandState = isInstalled;
UpdateAppearance(); UpdateAppearance();
} }
internal void FakeChangeStatus() internal void FakeChangeStatus()
{ {
IsInstalled = !IsInstalled; InstallCommandState = InstallCommandState switch
{
PackageInstallCommandState.Install => PackageInstallCommandState.Uninstall,
PackageInstallCommandState.Update => PackageInstallCommandState.Uninstall,
PackageInstallCommandState.Uninstall => PackageInstallCommandState.Install,
_ => throw new NotImplementedException(),
};
UpdateAppearance(); UpdateAppearance();
} }
private void UpdateAppearance() private void UpdateAppearance()
{ {
Icon = IsInstalled ? CompletedIcon : DownloadIcon; Icon = InstallCommandState switch
Name = IsInstalled ? Properties.Resources.winget_uninstall_name : Properties.Resources.winget_install_name; {
PackageInstallCommandState.Install => DownloadIcon,
PackageInstallCommandState.Update => UpdateIcon,
PackageInstallCommandState.Uninstall => CompletedIcon,
_ => throw new NotImplementedException(),
};
Name = InstallCommandState switch
{
PackageInstallCommandState.Install => Properties.Resources.winget_install_name,
PackageInstallCommandState.Update => Properties.Resources.winget_update_name,
PackageInstallCommandState.Uninstall => Properties.Resources.winget_uninstall_name,
_ => throw new NotImplementedException(),
};
} }
public override ICommandResult Invoke() public override ICommandResult Invoke()
@ -72,7 +92,7 @@ public partial class InstallPackageCommand : InvokableCommand
return CommandResult.KeepOpen(); return CommandResult.KeepOpen();
} }
if (IsInstalled) if (InstallCommandState == PackageInstallCommandState.Uninstall)
{ {
// Uninstall // Uninstall
_installBanner.State = MessageState.Info; _installBanner.State = MessageState.Info;
@ -88,7 +108,8 @@ public partial class InstallPackageCommand : InvokableCommand
_installTask = Task.Run(() => TryDoInstallOperation(_unInstallAction)); _installTask = Task.Run(() => TryDoInstallOperation(_unInstallAction));
} }
else else if (InstallCommandState is PackageInstallCommandState.Install or
PackageInstallCommandState.Update)
{ {
// Install // Install
_installBanner.State = MessageState.Info; _installBanner.State = MessageState.Info;
@ -117,7 +138,8 @@ public partial class InstallPackageCommand : InvokableCommand
try try
{ {
await action.AsTask(); await action.AsTask();
_installBanner.Message = IsInstalled ?
_installBanner.Message = InstallCommandState == PackageInstallCommandState.Uninstall ?
string.Format(CultureInfo.CurrentCulture, UninstallPackageFinished, _package.Name) : string.Format(CultureInfo.CurrentCulture, UninstallPackageFinished, _package.Name) :
string.Format(CultureInfo.CurrentCulture, InstallPackageFinished, _package.Name); string.Format(CultureInfo.CurrentCulture, InstallPackageFinished, _package.Name);
@ -125,9 +147,10 @@ public partial class InstallPackageCommand : InvokableCommand
_installBanner.State = MessageState.Success; _installBanner.State = MessageState.Success;
_installTask = null; _installTask = null;
_ = Task.Run(() => _ = Task.Run(async () =>
{ {
Thread.Sleep(2500); await Task.Delay(2500).ConfigureAwait(false);
if (_installTask == null) if (_installTask == null)
{ {
WinGetExtensionHost.Instance.HideStatus(_installBanner); WinGetExtensionHost.Instance.HideStatus(_installBanner);
@ -228,3 +251,10 @@ public partial class InstallPackageCommand : InvokableCommand
} }
} }
} }
public enum PackageInstallCommandState
{
Uninstall = 0,
Update = 1,
Install = 2,
}

View File

@ -6,6 +6,7 @@ using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics; using System.Diagnostics;
using System.Linq; using System.Linq;
using System.Runtime.InteropServices;
using System.Threading.Tasks; using System.Threading.Tasks;
using ManagedCommon; using ManagedCommon;
using Microsoft.CommandPalette.Extensions; using Microsoft.CommandPalette.Extensions;
@ -31,7 +32,7 @@ public partial class InstallPackageListItem : ListItem
{ {
_package = package; _package = package;
var version = _package.DefaultInstallVersion; var version = _package.DefaultInstallVersion ?? _package.InstalledVersion;
var versionTagText = "Unknown"; var versionTagText = "Unknown";
if (version != null) if (version != null)
{ {
@ -49,7 +50,16 @@ public partial class InstallPackageListItem : ListItem
private Details? BuildDetails(PackageVersionInfo? version) private Details? BuildDetails(PackageVersionInfo? version)
{ {
var metadata = version?.GetCatalogPackageMetadata(); CatalogPackageMetadata? metadata = null;
try
{
metadata = version?.GetCatalogPackageMetadata();
}
catch (COMException ex)
{
Logger.LogWarning($"{ex.ErrorCode}");
}
if (metadata != null) if (metadata != null)
{ {
if (metadata.Tags.Where(t => t.Equals(WinGetExtensionPage.ExtensionsTag, StringComparison.OrdinalIgnoreCase)).Any()) if (metadata.Tags.Where(t => t.Equals(WinGetExtensionPage.ExtensionsTag, StringComparison.OrdinalIgnoreCase)).Any())
@ -149,12 +159,17 @@ public partial class InstallPackageListItem : ListItem
var status = await _package.CheckInstalledStatusAsync(); var status = await _package.CheckInstalledStatusAsync();
var isInstalled = _package.InstalledVersion != null; var isInstalled = _package.InstalledVersion != null;
var installedState = isInstalled ?
(_package.IsUpdateAvailable ?
PackageInstallCommandState.Update : PackageInstallCommandState.Uninstall) :
PackageInstallCommandState.Install;
// might be an uninstall command // might be an uninstall command
InstallPackageCommand installCommand = new(_package, isInstalled); InstallPackageCommand installCommand = new(_package, installedState);
if (isInstalled) if (isInstalled)
{ {
this.Icon = InstallPackageCommand.CompletedIcon; this.Icon = installCommand.Icon;
this.Command = new NoOpCommand(); this.Command = new NoOpCommand();
List<IContextItem> contextMenu = []; List<IContextItem> contextMenu = [];
CommandContextItem uninstallContextItem = new(installCommand) CommandContextItem uninstallContextItem = new(installCommand)
@ -180,7 +195,7 @@ public partial class InstallPackageListItem : ListItem
} }
// didn't find the app // didn't find the app
_installCommand = new InstallPackageCommand(_package, isInstalled); _installCommand = new InstallPackageCommand(_package, installedState);
this.Command = _installCommand; this.Command = _installCommand;
Icon = _installCommand.Icon; Icon = _installCommand.Icon;

View File

@ -330,6 +330,15 @@ namespace Microsoft.CmdPal.Ext.WinGet.Properties {
} }
} }
/// <summary>
/// Looks up a localized string similar to Update.
/// </summary>
public static string winget_update_name {
get {
return ResourceManager.GetString("winget_update_name", resourceCulture);
}
}
/// <summary> /// <summary>
/// Looks up a localized string similar to View online. /// Looks up a localized string similar to View online.
/// </summary> /// </summary>

View File

@ -154,6 +154,10 @@
<value>Install</value> <value>Install</value>
<comment></comment> <comment></comment>
</data> </data>
<data name="winget_update_name" xml:space="preserve">
<value>Update</value>
<comment></comment>
</data>
<data name="winget_uninstalling_package" xml:space="preserve"> <data name="winget_uninstalling_package" xml:space="preserve">
<value>Uninstalling {0}...</value> <value>Uninstalling {0}...</value>
<comment>{0} will be replaced by the name of an app package</comment> <comment>{0} will be replaced by the name of an app package</comment>