From ff131c2f0a4250dfcaf7ac6d5ecc80cc438aa77a Mon Sep 17 00:00:00 2001 From: Michael Jolley Date: Thu, 5 Jun 2025 08:56:13 -0500 Subject: [PATCH] CmdPal: Implement IDetailsCommand in details (#39911) Implemented IDetailsCommands in details. This will close #38339. This works very similar to Tags in that it is a list of commands. This was done to allow for styling without the 12 spacing of the ItemsRepeater and looks like you'd find in the OS-inbox like: ![image](https://github.com/user-attachments/assets/97ee1952-13bb-4c8b-a074-0347b04e0c2c) ![image](https://github.com/user-attachments/assets/8f6f1f72-4ea0-441d-893e-ae26aabdc922) Also added to our sample extension: ![image](https://github.com/user-attachments/assets/ab3ce521-3479-448f-b4d6-9dfd09feb24f) --- .../DetailsCommandsViewModel.cs | 42 +++++++++++++++++++ .../DetailsViewModel.cs | 1 + .../Converters/DetailsDataTemplateSelector.cs | 3 ++ .../Microsoft.CmdPal.UI/Pages/ShellPage.xaml | 34 +++++++++++++++ .../Pages/ShellPage.xaml.cs | 8 ++++ .../Pages/SampleListPageWithDetails.cs | 20 +++++++++ .../{DetailsCommand.cs => DetailsCommands.cs} | 4 +- .../Microsoft.CommandPalette.Extensions.idl | 4 +- 8 files changed, 112 insertions(+), 4 deletions(-) create mode 100644 src/modules/cmdpal/Microsoft.CmdPal.UI.ViewModels/DetailsCommandsViewModel.cs rename src/modules/cmdpal/extensionsdk/Microsoft.CommandPalette.Extensions.Toolkit/{DetailsCommand.cs => DetailsCommands.cs} (70%) diff --git a/src/modules/cmdpal/Microsoft.CmdPal.UI.ViewModels/DetailsCommandsViewModel.cs b/src/modules/cmdpal/Microsoft.CmdPal.UI.ViewModels/DetailsCommandsViewModel.cs new file mode 100644 index 0000000000..316209a296 --- /dev/null +++ b/src/modules/cmdpal/Microsoft.CmdPal.UI.ViewModels/DetailsCommandsViewModel.cs @@ -0,0 +1,42 @@ +// 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.CmdPal.UI.ViewModels.Models; +using Microsoft.CommandPalette.Extensions; + +namespace Microsoft.CmdPal.UI.ViewModels; + +public partial class DetailsCommandsViewModel( + IDetailsElement _detailsElement, + WeakReference context) : DetailsElementViewModel(_detailsElement, context) +{ + public List Commands { get; private set; } = []; + + public bool HasCommands => Commands.Count > 0; + + private readonly ExtensionObject _dataModel = + new(_detailsElement.Data as IDetailsCommands); + + public override void InitializeProperties() + { + base.InitializeProperties(); + var model = _dataModel.Unsafe; + if (model == null) + { + return; + } + + Commands = model + .Commands? + .Select(c => + { + var vm = new CommandViewModel(c, PageContext); + vm.InitializeProperties(); + return vm; + }) + .ToList() ?? []; + UpdateProperty(nameof(HasCommands)); + UpdateProperty(nameof(Commands)); + } +} diff --git a/src/modules/cmdpal/Microsoft.CmdPal.UI.ViewModels/DetailsViewModel.cs b/src/modules/cmdpal/Microsoft.CmdPal.UI.ViewModels/DetailsViewModel.cs index 0d5233fa41..893a94f86e 100644 --- a/src/modules/cmdpal/Microsoft.CmdPal.UI.ViewModels/DetailsViewModel.cs +++ b/src/modules/cmdpal/Microsoft.CmdPal.UI.ViewModels/DetailsViewModel.cs @@ -49,6 +49,7 @@ public partial class DetailsViewModel(IDetails _details, WeakReference new DetailsSeparatorViewModel(element, this.PageContext), IDetailsLink => new DetailsLinkViewModel(element, this.PageContext), + IDetailsCommands => new DetailsCommandsViewModel(element, this.PageContext), IDetailsTags => new DetailsTagsViewModel(element, this.PageContext), _ => null, }; diff --git a/src/modules/cmdpal/Microsoft.CmdPal.UI/Converters/DetailsDataTemplateSelector.cs b/src/modules/cmdpal/Microsoft.CmdPal.UI/Converters/DetailsDataTemplateSelector.cs index 328e0ca01e..bff62bb97f 100644 --- a/src/modules/cmdpal/Microsoft.CmdPal.UI/Converters/DetailsDataTemplateSelector.cs +++ b/src/modules/cmdpal/Microsoft.CmdPal.UI/Converters/DetailsDataTemplateSelector.cs @@ -18,6 +18,8 @@ public partial class DetailsDataTemplateSelector : DataTemplateSelector public DataTemplate? TagTemplate { get; set; } + public DataTemplate? CommandTemplate { get; set; } + protected override DataTemplate? SelectTemplateCore(object item) { if (item is DetailsElementViewModel element) @@ -27,6 +29,7 @@ public partial class DetailsDataTemplateSelector : DataTemplateSelector { DetailsSeparatorViewModel => SeparatorTemplate, DetailsLinkViewModel => LinkTemplate, + DetailsCommandsViewModel => CommandTemplate, DetailsTagsViewModel => TagTemplate, _ => null, }; diff --git a/src/modules/cmdpal/Microsoft.CmdPal.UI/Pages/ShellPage.xaml b/src/modules/cmdpal/Microsoft.CmdPal.UI/Pages/ShellPage.xaml index f97334466e..2dd0c5b6c4 100644 --- a/src/modules/cmdpal/Microsoft.CmdPal.UI/Pages/ShellPage.xaml +++ b/src/modules/cmdpal/Microsoft.CmdPal.UI/Pages/ShellPage.xaml @@ -29,6 +29,7 @@ @@ -50,6 +51,27 @@ ToolTipService.ToolTip="{x:Bind ToolTip, Mode=OneWay}" /> + + + + + + + + + + + + (new(commandViewModel.Model)); + } + } } diff --git a/src/modules/cmdpal/ext/SamplePagesExtension/Pages/SampleListPageWithDetails.cs b/src/modules/cmdpal/ext/SamplePagesExtension/Pages/SampleListPageWithDetails.cs index 9495a7f6bf..018c11720c 100644 --- a/src/modules/cmdpal/ext/SamplePagesExtension/Pages/SampleListPageWithDetails.cs +++ b/src/modules/cmdpal/ext/SamplePagesExtension/Pages/SampleListPageWithDetails.cs @@ -5,6 +5,7 @@ using System; using Microsoft.CommandPalette.Extensions; using Microsoft.CommandPalette.Extensions.Toolkit; +using Microsoft.UI.Xaml; namespace SamplePagesExtension; @@ -129,6 +130,25 @@ internal sealed partial class SampleListPageWithDetails : ListPage ], }, }, + new DetailsElement() + { + Key = "Commands", + Data = new DetailsCommands() + { + Commands = [ + new ToastCommand("Hey! You clicked it!", MessageState.Success) + { + Name = "Do something amazing", + Icon = new("\uE945"), + }, + new ToastCommand("I warned you!", MessageState.Error) + { + Name = "Don't click me", + Icon = new("\uEA39"), + }, + ], + }, + }, ], }, } diff --git a/src/modules/cmdpal/extensionsdk/Microsoft.CommandPalette.Extensions.Toolkit/DetailsCommand.cs b/src/modules/cmdpal/extensionsdk/Microsoft.CommandPalette.Extensions.Toolkit/DetailsCommands.cs similarity index 70% rename from src/modules/cmdpal/extensionsdk/Microsoft.CommandPalette.Extensions.Toolkit/DetailsCommand.cs rename to src/modules/cmdpal/extensionsdk/Microsoft.CommandPalette.Extensions.Toolkit/DetailsCommands.cs index 0d08458ebf..32b11faad4 100644 --- a/src/modules/cmdpal/extensionsdk/Microsoft.CommandPalette.Extensions.Toolkit/DetailsCommand.cs +++ b/src/modules/cmdpal/extensionsdk/Microsoft.CommandPalette.Extensions.Toolkit/DetailsCommands.cs @@ -4,7 +4,7 @@ namespace Microsoft.CommandPalette.Extensions.Toolkit; -public partial class DetailsCommand : IDetailsCommand +public partial class DetailsCommands : IDetailsCommands { - public ICommand? Command { get; set; } + public ICommand[]? Commands { get; set; } } diff --git a/src/modules/cmdpal/extensionsdk/Microsoft.CommandPalette.Extensions/Microsoft.CommandPalette.Extensions.idl b/src/modules/cmdpal/extensionsdk/Microsoft.CommandPalette.Extensions/Microsoft.CommandPalette.Extensions.idl index df4b442cdf..3105b0647d 100644 --- a/src/modules/cmdpal/extensionsdk/Microsoft.CommandPalette.Extensions/Microsoft.CommandPalette.Extensions.idl +++ b/src/modules/cmdpal/extensionsdk/Microsoft.CommandPalette.Extensions/Microsoft.CommandPalette.Extensions.idl @@ -182,8 +182,8 @@ namespace Microsoft.CommandPalette.Extensions String Text { get; }; } [contract(Microsoft.CommandPalette.Extensions.ExtensionsContract, 1)] - interface IDetailsCommand requires IDetailsData { - ICommand Command { get; }; + interface IDetailsCommands requires IDetailsData { + ICommand[] Commands { get; }; } [uuid("58070392-02bb-4e89-9beb-47ceb8c3d741")] [contract(Microsoft.CommandPalette.Extensions.ExtensionsContract, 1)]