mirror of
https://github.com/microsoft/PowerToys.git
synced 2026-02-23 19:49:43 +01:00
Merging main
This commit is contained in:
@@ -165,4 +165,6 @@ public interface IAppHostService
|
||||
AppExtensionHost GetDefaultHost();
|
||||
|
||||
AppExtensionHost GetHostForCommand(object? context, AppExtensionHost? currentHost);
|
||||
|
||||
CommandProviderContext GetProviderContextForCommand(object? command, CommandProviderContext? currentContext);
|
||||
}
|
||||
|
||||
@@ -9,8 +9,8 @@ namespace Microsoft.CmdPal.UI.ViewModels;
|
||||
|
||||
public partial class CommandPaletteContentPageViewModel : ContentPageViewModel
|
||||
{
|
||||
public CommandPaletteContentPageViewModel(IContentPage model, TaskScheduler scheduler, AppExtensionHost host)
|
||||
: base(model, scheduler, host)
|
||||
public CommandPaletteContentPageViewModel(IContentPage model, TaskScheduler scheduler, AppExtensionHost host, CommandProviderContext providerContext)
|
||||
: base(model, scheduler, host, providerContext)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
@@ -17,12 +17,12 @@ public class CommandPalettePageViewModelFactory
|
||||
_scheduler = scheduler;
|
||||
}
|
||||
|
||||
public PageViewModel? TryCreatePageViewModel(IPage page, bool nested, AppExtensionHost host)
|
||||
public PageViewModel? TryCreatePageViewModel(IPage page, bool nested, AppExtensionHost host, CommandProviderContext providerContext)
|
||||
{
|
||||
return page switch
|
||||
{
|
||||
IListPage listPage => new ListViewModel(listPage, _scheduler, host) { IsNested = nested },
|
||||
IContentPage contentPage => new CommandPaletteContentPageViewModel(contentPage, _scheduler, host),
|
||||
IListPage listPage => new ListViewModel(listPage, _scheduler, host, providerContext) { IsNested = nested },
|
||||
IContentPage contentPage => new CommandPaletteContentPageViewModel(contentPage, _scheduler, host, providerContext),
|
||||
_ => null,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
|
||||
namespace Microsoft.CmdPal.Core.ViewModels;
|
||||
|
||||
public sealed class CommandProviderContext
|
||||
{
|
||||
public required string ProviderId { get; init; }
|
||||
|
||||
public static CommandProviderContext Empty { get; } = new() { ProviderId = "<EMPTY>" };
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// 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.
|
||||
|
||||
@@ -8,6 +8,7 @@ using Microsoft.CmdPal.UI.ViewModels.Services;
|
||||
using Microsoft.CmdPal.ViewModels;
|
||||
using Microsoft.CmdPal.ViewModels.Models;
|
||||
using Microsoft.CommandPalette.Extensions;
|
||||
using Microsoft.CommandPalette.Extensions.Toolkit;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Windows.Foundation;
|
||||
|
||||
@@ -157,6 +158,9 @@ public sealed class CommandProviderWrapper
|
||||
UnsafePreCacheApiAdditions(two);
|
||||
}
|
||||
|
||||
// Load pinned commands from saved settings
|
||||
var pinnedCommands = LoadPinnedCommands(model, providerSettings);
|
||||
|
||||
Id = model.Id;
|
||||
DisplayName = model.DisplayName;
|
||||
Icon = new(model.Icon);
|
||||
@@ -174,7 +178,7 @@ public sealed class CommandProviderWrapper
|
||||
Settings = new(model.Settings, this, _taskScheduler);
|
||||
|
||||
// We do need to explicitly initialize commands though
|
||||
InitializeCommands(commands, fallbacks, serviceProvider, pageContext);
|
||||
InitializeCommands(commands, fallbacks, pinnedCommands, serviceProvider, pageContext);
|
||||
|
||||
Logger.LogDebug($"Loaded commands from {DisplayName} ({ProviderId})");
|
||||
}
|
||||
@@ -205,27 +209,34 @@ public sealed class CommandProviderWrapper
|
||||
}
|
||||
}
|
||||
|
||||
private void InitializeCommands(ICommandItem[] commands, IFallbackCommandItem[] fallbacks, IServiceProvider serviceProvider, WeakReference<IPageContext> pageContext)
|
||||
private void InitializeCommands(ICommandItem[] commands, IFallbackCommandItem[] fallbacks, ICommandItem[] pinnedCommands, IServiceProvider serviceProvider, WeakReference<IPageContext> pageContext)
|
||||
{
|
||||
var settings = serviceProvider.GetService<SettingsModel>()!;
|
||||
var providerSettings = GetProviderSettings(settings);
|
||||
|
||||
var ourContext = GetProviderContext();
|
||||
var makeAndAdd = (ICommandItem? i, bool fallback) =>
|
||||
{
|
||||
CommandItemViewModel commandItemViewModel = new(new(i), pageContext);
|
||||
TopLevelViewModel topLevelViewModel = new(commandItemViewModel, fallback, ExtensionHost, ProviderId, settings, providerSettings, serviceProvider, i);
|
||||
TopLevelViewModel topLevelViewModel = new(commandItemViewModel, fallback, ExtensionHost, ourContext, settings, providerSettings, serviceProvider, i);
|
||||
topLevelViewModel.InitializeProperties();
|
||||
|
||||
return topLevelViewModel;
|
||||
};
|
||||
|
||||
var topLevelList = new List<TopLevelViewModel>();
|
||||
|
||||
if (commands is not null)
|
||||
{
|
||||
TopLevelItems = commands
|
||||
.Select(c => makeAndAdd(c, false))
|
||||
.ToArray();
|
||||
topLevelList.AddRange(commands.Select(c => makeAndAdd(c, false)));
|
||||
}
|
||||
|
||||
if (pinnedCommands is not null)
|
||||
{
|
||||
topLevelList.AddRange(pinnedCommands.Select(c => makeAndAdd(c, false)));
|
||||
}
|
||||
|
||||
TopLevelItems = topLevelList.ToArray();
|
||||
|
||||
if (fallbacks is not null)
|
||||
{
|
||||
FallbackItems = fallbacks
|
||||
@@ -234,6 +245,32 @@ public sealed class CommandProviderWrapper
|
||||
}
|
||||
}
|
||||
|
||||
private ICommandItem[] LoadPinnedCommands(ICommandProvider model, ProviderSettings providerSettings)
|
||||
{
|
||||
var pinnedItems = new List<ICommandItem>();
|
||||
|
||||
if (model is ICommandProvider4 provider4)
|
||||
{
|
||||
foreach (var pinnedId in providerSettings.PinnedCommandIds)
|
||||
{
|
||||
try
|
||||
{
|
||||
var commandItem = provider4.GetCommandItem(pinnedId);
|
||||
if (commandItem is not null)
|
||||
{
|
||||
pinnedItems.Add(commandItem);
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Logger.LogError($"Failed to load pinned command {pinnedId}: {e.Message}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return pinnedItems.ToArray();
|
||||
}
|
||||
|
||||
private void UnsafePreCacheApiAdditions(ICommandProvider2 provider)
|
||||
{
|
||||
var apiExtensions = provider.GetApiExtensionStubs();
|
||||
@@ -247,6 +284,26 @@ public sealed class CommandProviderWrapper
|
||||
}
|
||||
}
|
||||
|
||||
public void PinCommand(string commandId, IServiceProvider serviceProvider)
|
||||
{
|
||||
var settings = serviceProvider.GetService<SettingsModel>()!;
|
||||
var providerSettings = GetProviderSettings(settings);
|
||||
|
||||
if (!providerSettings.PinnedCommandIds.Contains(commandId))
|
||||
{
|
||||
providerSettings.PinnedCommandIds.Add(commandId);
|
||||
SettingsModel.SaveSettings(settings);
|
||||
|
||||
// Raise CommandsChanged so the TopLevelCommandManager reloads our commands
|
||||
this.CommandsChanged?.Invoke(this, new ItemsChangedEventArgs(-1));
|
||||
}
|
||||
}
|
||||
|
||||
public CommandProviderContext GetProviderContext()
|
||||
{
|
||||
return new() { ProviderId = ProviderId };
|
||||
}
|
||||
|
||||
public override bool Equals(object? obj) => obj is CommandProviderWrapper wrapper && isValid == wrapper.isValid;
|
||||
|
||||
public override int GetHashCode() => _commandProvider.GetHashCode();
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// 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.
|
||||
|
||||
@@ -31,7 +31,7 @@ public partial class CommandSettingsViewModel(ICommandSettings? _unsafeSettings,
|
||||
|
||||
if (model.SettingsPage is not null)
|
||||
{
|
||||
SettingsPage = new CommandPaletteContentPageViewModel(model.SettingsPage, mainThread, provider.ExtensionHost);
|
||||
SettingsPage = new CommandPaletteContentPageViewModel(model.SettingsPage, mainThread, provider.ExtensionHost, provider.GetProviderContext());
|
||||
SettingsPage.InitializeProperties();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -47,8 +47,8 @@ public partial class ContentPageViewModel : PageViewModel, ICommandBarContext
|
||||
|
||||
// Remember - "observable" properties from the model (via PropChanged)
|
||||
// cannot be marked [ObservableProperty]
|
||||
public ContentPageViewModel(IContentPage model, TaskScheduler scheduler, AppExtensionHost host)
|
||||
: base(model, scheduler, host)
|
||||
public ContentPageViewModel(IContentPage model, TaskScheduler scheduler, AppExtensionHost host, CommandProviderContext providerContext)
|
||||
: base(model, scheduler, host, providerContext)
|
||||
{
|
||||
_model = new(model);
|
||||
}
|
||||
|
||||
@@ -88,8 +88,8 @@ public partial class ListViewModel : PageViewModel, IDisposable
|
||||
}
|
||||
}
|
||||
|
||||
public ListViewModel(IListPage model, TaskScheduler scheduler, AppExtensionHost host)
|
||||
: base(model, scheduler, host)
|
||||
public ListViewModel(IListPage model, TaskScheduler scheduler, AppExtensionHost host, CommandProviderContext providerContext)
|
||||
: base(model, scheduler, host, providerContext)
|
||||
{
|
||||
_model = new(model);
|
||||
EmptyContent = new(new(null), PageContext);
|
||||
|
||||
@@ -9,7 +9,7 @@ namespace Microsoft.CmdPal.ViewModels;
|
||||
public partial class LoadingPageViewModel : PageViewModel
|
||||
{
|
||||
public LoadingPageViewModel(IPage? model, TaskScheduler scheduler, AppExtensionHost host)
|
||||
: base(model, scheduler, host)
|
||||
: base(model, scheduler, host, CommandProviderContext.Empty)
|
||||
{
|
||||
ModelIsLoading = true;
|
||||
IsInitialized = false;
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
// 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.
|
||||
|
||||
namespace Microsoft.CmdPal.UI.ViewModels.Messages;
|
||||
|
||||
public record PinCommandItemMessage(string ProviderId, string CommandId)
|
||||
{
|
||||
}
|
||||
@@ -5,4 +5,4 @@
|
||||
namespace Microsoft.CmdPal.ViewModels;
|
||||
|
||||
internal sealed partial class NullPageViewModel(TaskScheduler scheduler, AppExtensionHost extensionHost)
|
||||
: PageViewModel(null, scheduler, extensionHost);
|
||||
: PageViewModel(null, scheduler, extensionHost, CommandProviderContext.Empty);
|
||||
|
||||
@@ -76,13 +76,16 @@ public partial class PageViewModel : ExtensionObjectViewModel, IPageContext
|
||||
|
||||
public IconInfoViewModel Icon { get; protected set; }
|
||||
|
||||
public PageViewModel(IPage? model, TaskScheduler scheduler, AppExtensionHost extensionHost)
|
||||
public CommandProviderContext ProviderContext { get; protected set; }
|
||||
|
||||
public PageViewModel(IPage? model, TaskScheduler scheduler, AppExtensionHost extensionHost, CommandProviderContext providerContext)
|
||||
: base(scheduler)
|
||||
{
|
||||
InitializeSelfAsPageContext();
|
||||
_pageModel = new(model);
|
||||
Scheduler = scheduler;
|
||||
ExtensionHost = extensionHost;
|
||||
ProviderContext = providerContext;
|
||||
Icon = new(null);
|
||||
|
||||
ExtensionHost.StatusMessages.CollectionChanged += StatusMessages_CollectionChanged;
|
||||
@@ -275,5 +278,5 @@ public interface IPageViewModelFactoryService
|
||||
/// <param name="nested">Indicates whether the page is not the top-level page.</param>
|
||||
/// <param name="host">The command palette host that will host the page (for status messages)</param>
|
||||
/// <returns>A new instance of the page view model.</returns>
|
||||
PageViewModel? TryCreatePageViewModel(IPage page, bool nested, AppExtensionHost host);
|
||||
PageViewModel? TryCreatePageViewModel(IPage page, bool nested, AppExtensionHost host, CommandProviderContext providerContext);
|
||||
}
|
||||
|
||||
@@ -18,6 +18,8 @@ public class ProviderSettings
|
||||
|
||||
public Dictionary<string, FallbackSettings> FallbackCommands { get; set; } = new();
|
||||
|
||||
public List<string> PinnedCommandIds { get; set; } = [];
|
||||
|
||||
[JsonIgnore]
|
||||
public string ProviderDisplayName { get; set; } = string.Empty;
|
||||
|
||||
|
||||
@@ -258,6 +258,7 @@ public partial class ShellViewModel : ObservableObject,
|
||||
}
|
||||
|
||||
var host = _appHostService.GetHostForCommand(message.Context, CurrentPage.ExtensionHost);
|
||||
var providerContext = _appHostService.GetProviderContextForCommand(message.Context, CurrentPage.ProviderContext);
|
||||
|
||||
_rootPageService.OnPerformCommand(message.Context, !CurrentPage.IsNested, host);
|
||||
|
||||
@@ -281,7 +282,7 @@ public partial class ShellViewModel : ObservableObject,
|
||||
}
|
||||
|
||||
// Construct our ViewModel of the appropriate type and pass it the UI Thread context.
|
||||
var pageViewModel = _pageViewModelFactory.TryCreatePageViewModel(page, _isNested, host!);
|
||||
var pageViewModel = _pageViewModelFactory.TryCreatePageViewModel(page, _isNested, host!, providerContext);
|
||||
if (pageViewModel is null)
|
||||
{
|
||||
CoreLogger.LogError($"Failed to create ViewModel for page {page.GetType().Name}");
|
||||
|
||||
@@ -22,6 +22,7 @@ namespace Microsoft.CmdPal.UI.ViewModels;
|
||||
|
||||
public partial class TopLevelCommandManager : ObservableObject,
|
||||
IRecipient<ReloadCommandsMessage>,
|
||||
IRecipient<PinCommandItemMessage>,
|
||||
IPageContext,
|
||||
IDisposable
|
||||
{
|
||||
@@ -42,6 +43,7 @@ public partial class TopLevelCommandManager : ObservableObject,
|
||||
_commandProviderCache = commandProviderCache;
|
||||
_taskScheduler = _serviceProvider.GetService<TaskScheduler>()!;
|
||||
WeakReferenceMessenger.Default.Register<ReloadCommandsMessage>(this);
|
||||
WeakReferenceMessenger.Default.Register<PinCommandItemMessage>(this);
|
||||
_reloadCommandsGate = new(ReloadAllCommandsAsyncCore);
|
||||
}
|
||||
|
||||
@@ -414,6 +416,21 @@ public partial class TopLevelCommandManager : ObservableObject,
|
||||
public void Receive(ReloadCommandsMessage message) =>
|
||||
ReloadAllCommandsAsync().ConfigureAwait(false);
|
||||
|
||||
public void Receive(PinCommandItemMessage message)
|
||||
{
|
||||
var wrapper = LookupProvider(message.ProviderId);
|
||||
wrapper?.PinCommand(message.CommandId, _serviceProvider);
|
||||
}
|
||||
|
||||
private CommandProviderWrapper? LookupProvider(string providerId)
|
||||
{
|
||||
lock (_commandProvidersLock)
|
||||
{
|
||||
return _builtInCommands.FirstOrDefault(w => w.ProviderId == providerId)
|
||||
?? _extensionCommandProviders.FirstOrDefault(w => w.ProviderId == providerId);
|
||||
}
|
||||
}
|
||||
|
||||
void IPageContext.ShowException(Exception ex, string? extensionHint)
|
||||
{
|
||||
var message = DiagnosticsHelper.BuildExceptionMessage(ex, extensionHint ?? "TopLevelCommandManager");
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// 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.
|
||||
|
||||
@@ -27,7 +27,7 @@ public sealed partial class TopLevelViewModel : ObservableObject, IListItem, IEx
|
||||
private readonly IServiceProvider _serviceProvider;
|
||||
private readonly CommandItemViewModel _commandItemViewModel;
|
||||
|
||||
private readonly string _commandProviderId;
|
||||
public CommandProviderContext ProviderContext { get; private set; }
|
||||
|
||||
private string IdFromModel => IsFallback && !string.IsNullOrWhiteSpace(_fallbackId) ? _fallbackId : _commandItemViewModel.Command.Id;
|
||||
|
||||
@@ -57,7 +57,7 @@ public sealed partial class TopLevelViewModel : ObservableObject, IListItem, IEx
|
||||
|
||||
public CommandItemViewModel ItemViewModel => _commandItemViewModel;
|
||||
|
||||
public string CommandProviderId => _commandProviderId;
|
||||
public string CommandProviderId => ProviderContext.ProviderId;
|
||||
|
||||
////// ICommandItem
|
||||
public string Title => _commandItemViewModel.Title;
|
||||
@@ -190,7 +190,7 @@ public sealed partial class TopLevelViewModel : ObservableObject, IListItem, IEx
|
||||
CommandItemViewModel item,
|
||||
bool isFallback,
|
||||
CommandPaletteHost extensionHost,
|
||||
string commandProviderId,
|
||||
CommandProviderContext commandProviderContext,
|
||||
SettingsModel settings,
|
||||
ProviderSettings providerSettings,
|
||||
IServiceProvider serviceProvider,
|
||||
@@ -199,7 +199,7 @@ public sealed partial class TopLevelViewModel : ObservableObject, IListItem, IEx
|
||||
_serviceProvider = serviceProvider;
|
||||
_settings = settings;
|
||||
_providerSettings = providerSettings;
|
||||
_commandProviderId = commandProviderId;
|
||||
ProviderContext = commandProviderContext;
|
||||
_commandItemViewModel = item;
|
||||
|
||||
IsFallback = isFallback;
|
||||
@@ -358,8 +358,8 @@ public sealed partial class TopLevelViewModel : ObservableObject, IListItem, IEx
|
||||
{
|
||||
// Use WyHash64 to generate stable ID hashes.
|
||||
// manually seeding with 0, so that the hash is stable across launches
|
||||
var result = WyHash64.ComputeHash64(_commandProviderId + DisplayTitle + Title + Subtitle, seed: 0);
|
||||
_generatedId = $"{_commandProviderId}{result}";
|
||||
var result = WyHash64.ComputeHash64(CommandProviderId + DisplayTitle + Title + Subtitle, seed: 0);
|
||||
_generatedId = $"{CommandProviderId}{result}";
|
||||
}
|
||||
|
||||
private void DoOnUiThread(Action action)
|
||||
|
||||
@@ -26,4 +26,15 @@ internal sealed class PowerToysAppHostService : IAppHostService
|
||||
|
||||
return topLevelHost ?? currentHost ?? CommandPaletteHost.Instance;
|
||||
}
|
||||
|
||||
public CommandProviderContext GetProviderContextForCommand(object? command, CommandProviderContext? currentContext)
|
||||
{
|
||||
CommandProviderContext? topLevelId = null;
|
||||
if (command is TopLevelViewModel topLevelViewModel)
|
||||
{
|
||||
topLevelId = topLevelViewModel.ProviderContext;
|
||||
}
|
||||
|
||||
return topLevelId ?? currentContext ?? throw new InvalidOperationException("No command provider context could be found for the given command, and no current context was provided.");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -77,6 +77,7 @@ functionality.
|
||||
- [Rendering of ICommandItems in Lists and Menus](#rendering-of-icommanditems-in-lists-and-menus)
|
||||
- [Addenda I: API additions (ICommandProvider2)](#addenda-i-api-additions-icommandprovider2)
|
||||
- [Addenda IV: Dock bands](#addenda-iv-dock-bands)
|
||||
- [Pinning nested commands to the dock (and top level)](#pinning-nested-commands-to-the-dock-and-top-level)
|
||||
- [Class diagram](#class-diagram)
|
||||
- [Future considerations](#future-considerations)
|
||||
- [Arbitrary parameters and arguments](#arbitrary-parameters-and-arguments)
|
||||
@@ -2128,6 +2129,36 @@ Users may choose to have:
|
||||
- Dock bands will still display the `Title` & `Subtitle` of each item in the
|
||||
band as the tooltip on those items, even when the "labels" are hidden.
|
||||
|
||||
### Pinning nested commands to the dock (and top level)
|
||||
|
||||
We'll use another command provider method to allow the host to ask extensions
|
||||
for items based on their ID.
|
||||
|
||||
```csharp
|
||||
interface ICommandProvider4 requires ICommandProvider3
|
||||
{
|
||||
ICommandItem GetCommandItem(String id);
|
||||
};
|
||||
```
|
||||
|
||||
This will allow users to pin not just top-level commands, but also nested
|
||||
commands which have an ID. The host can store that ID away, and then later ask
|
||||
the extension for the `ICommandItem` with that ID, to get the full details of
|
||||
the command to pin.
|
||||
|
||||
This is needed separate from the `GetCommand` method on `ICommandProvider`,
|
||||
because that method is was designed for two main purposes:
|
||||
|
||||
* Short-circuiting the loading of top-level commands for frozen extensions. In
|
||||
that case, DevPal would only need to look up the actual `ICommand` to perform
|
||||
it. It wouldn't need the full `ICommandItem` with all the details.
|
||||
* Allowing invokable commands to navigate using the GoToPageArgs. In that case,
|
||||
DevPal would only need the `ICommand` to perform the navigation.
|
||||
|
||||
In neither of those scenarios was the full "display" of the item needed. In
|
||||
pinning scenarios, however, we need everything that the user would see in the UI
|
||||
for that item, which is all in the `ICommandItem`.
|
||||
|
||||
## Class diagram
|
||||
|
||||
This is a diagram attempting to show the relationships between the various types we've defined for the SDK. Some elements are omitted for clarity. (Notably, `IconData` and `IPropChanged`, which are used in many places.)
|
||||
|
||||
@@ -184,6 +184,20 @@ public partial class AllAppsCommandProvider : CommandProvider
|
||||
return null;
|
||||
}
|
||||
|
||||
public override ICommandItem? GetCommandItem(string id)
|
||||
{
|
||||
var items = _page.GetItems();
|
||||
foreach (var item in items)
|
||||
{
|
||||
if (item.Command.Id == id)
|
||||
{
|
||||
return item;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private void OnPinStateChanged(object? sender, System.EventArgs e)
|
||||
{
|
||||
RaiseItemsChanged(0);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// 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.
|
||||
|
||||
@@ -42,37 +42,61 @@ internal static class Commands
|
||||
var results = new List<IListItem>();
|
||||
results.AddRange(new[]
|
||||
{
|
||||
new ListItem(new ExecuteCommandConfirmation(Resources.Microsoft_plugin_command_name_shutdown, confirmCommands, Resources.Microsoft_plugin_sys_shutdown_computer_confirmation, () => OpenInShellHelper.OpenInShell("shutdown", "/s /hybrid /t 0", runWithHiddenWindow: true)))
|
||||
new ListItem(
|
||||
new ExecuteCommandConfirmation(Resources.Microsoft_plugin_command_name_shutdown, confirmCommands, Resources.Microsoft_plugin_sys_shutdown_computer_confirmation, () => OpenInShellHelper.OpenInShell("shutdown", "/s /hybrid /t 0", runWithHiddenWindow: true))
|
||||
{
|
||||
Id = "com.microsoft.cmdpal.builtin.system.shutdown",
|
||||
})
|
||||
{
|
||||
Title = Resources.Microsoft_plugin_sys_shutdown_computer,
|
||||
Subtitle = Resources.Microsoft_plugin_sys_shutdown_computer_description,
|
||||
Icon = Icons.ShutdownIcon,
|
||||
},
|
||||
new ListItem(new ExecuteCommandConfirmation(Resources.Microsoft_plugin_command_name_restart, confirmCommands, Resources.Microsoft_plugin_sys_restart_computer_confirmation, () => OpenInShellHelper.OpenInShell("shutdown", "/g /t 0", runWithHiddenWindow: true)))
|
||||
new ListItem(
|
||||
new ExecuteCommandConfirmation(Resources.Microsoft_plugin_command_name_restart, confirmCommands, Resources.Microsoft_plugin_sys_restart_computer_confirmation, () => OpenInShellHelper.OpenInShell("shutdown", "/g /t 0", runWithHiddenWindow: true))
|
||||
{
|
||||
Id = "com.microsoft.cmdpal.builtin.system.restart",
|
||||
})
|
||||
{
|
||||
Title = Resources.Microsoft_plugin_sys_restart_computer,
|
||||
Subtitle = Resources.Microsoft_plugin_sys_restart_computer_description,
|
||||
Icon = Icons.RestartIcon,
|
||||
},
|
||||
new ListItem(new ExecuteCommandConfirmation(Resources.Microsoft_plugin_command_name_signout, confirmCommands, Resources.Microsoft_plugin_sys_sign_out_confirmation, () => NativeMethods.ExitWindowsEx(EWXLOGOFF, 0)))
|
||||
new ListItem(
|
||||
new ExecuteCommandConfirmation(Resources.Microsoft_plugin_command_name_signout, confirmCommands, Resources.Microsoft_plugin_sys_sign_out_confirmation, () => NativeMethods.ExitWindowsEx(EWXLOGOFF, 0))
|
||||
{
|
||||
Id = "com.microsoft.cmdpal.builtin.system.signout",
|
||||
})
|
||||
{
|
||||
Title = Resources.Microsoft_plugin_sys_sign_out,
|
||||
Subtitle = Resources.Microsoft_plugin_sys_sign_out_description,
|
||||
Icon = Icons.LogoffIcon,
|
||||
},
|
||||
new ListItem(new ExecuteCommandConfirmation(Resources.Microsoft_plugin_command_name_lock, confirmCommands, Resources.Microsoft_plugin_sys_lock_confirmation, () => NativeMethods.LockWorkStation()))
|
||||
new ListItem(
|
||||
new ExecuteCommandConfirmation(Resources.Microsoft_plugin_command_name_lock, confirmCommands, Resources.Microsoft_plugin_sys_lock_confirmation, () => NativeMethods.LockWorkStation())
|
||||
{
|
||||
Id = "com.microsoft.cmdpal.builtin.system.lock",
|
||||
})
|
||||
{
|
||||
Title = Resources.Microsoft_plugin_sys_lock,
|
||||
Subtitle = Resources.Microsoft_plugin_sys_lock_description,
|
||||
Icon = Icons.LockIcon,
|
||||
},
|
||||
new ListItem(new ExecuteCommandConfirmation(Resources.Microsoft_plugin_command_name_sleep, confirmCommands, Resources.Microsoft_plugin_sys_sleep_confirmation, () => NativeMethods.SetSuspendState(false, true, true)))
|
||||
new ListItem(
|
||||
new ExecuteCommandConfirmation(Resources.Microsoft_plugin_command_name_sleep, confirmCommands, Resources.Microsoft_plugin_sys_sleep_confirmation, () => NativeMethods.SetSuspendState(false, true, true))
|
||||
{
|
||||
Id = "com.microsoft.cmdpal.builtin.system.sleep",
|
||||
})
|
||||
{
|
||||
Title = Resources.Microsoft_plugin_sys_sleep,
|
||||
Subtitle = Resources.Microsoft_plugin_sys_sleep_description,
|
||||
Icon = Icons.SleepIcon,
|
||||
},
|
||||
new ListItem(new ExecuteCommandConfirmation(Resources.Microsoft_plugin_command_name_hibernate, confirmCommands, Resources.Microsoft_plugin_sys_hibernate_confirmation, () => NativeMethods.SetSuspendState(true, true, true)))
|
||||
new ListItem(
|
||||
new ExecuteCommandConfirmation(Resources.Microsoft_plugin_command_name_hibernate, confirmCommands, Resources.Microsoft_plugin_sys_hibernate_confirmation, () => NativeMethods.SetSuspendState(true, true, true))
|
||||
{
|
||||
Id = "com.microsoft.cmdpal.builtin.system.hibernate",
|
||||
})
|
||||
{
|
||||
Title = Resources.Microsoft_plugin_sys_hibernate,
|
||||
Subtitle = Resources.Microsoft_plugin_sys_hibernate_description,
|
||||
@@ -85,13 +109,19 @@ internal static class Commands
|
||||
{
|
||||
results.AddRange(new[]
|
||||
{
|
||||
new ListItem(new OpenInShellCommand(Resources.Microsoft_plugin_command_name_open, "explorer.exe", "shell:RecycleBinFolder"))
|
||||
new ListItem(new OpenInShellCommand(Resources.Microsoft_plugin_command_name_open, "explorer.exe", "shell:RecycleBinFolder")
|
||||
{
|
||||
Id = "com.microsoft.cmdpal.builtin.system.recycle_bin",
|
||||
})
|
||||
{
|
||||
Title = Resources.Microsoft_plugin_sys_RecycleBinOpen,
|
||||
Subtitle = Resources.Microsoft_plugin_sys_RecycleBin_description,
|
||||
Icon = Icons.RecycleBinIcon,
|
||||
},
|
||||
new ListItem(new EmptyRecycleBinConfirmation(emptyRBSuccessMessage))
|
||||
new ListItem(new EmptyRecycleBinConfirmation(emptyRBSuccessMessage)
|
||||
{
|
||||
Id = "com.microsoft.cmdpal.builtin.system.empty_recycle_bin",
|
||||
})
|
||||
{
|
||||
Title = Resources.Microsoft_plugin_sys_RecycleBinEmptyResult,
|
||||
Subtitle = Resources.Microsoft_plugin_sys_RecycleBinEmpty_description,
|
||||
@@ -102,7 +132,10 @@ internal static class Commands
|
||||
else
|
||||
{
|
||||
results.Add(
|
||||
new ListItem(new OpenInShellCommand(Resources.Microsoft_plugin_command_name_open, "explorer.exe", "shell:RecycleBinFolder"))
|
||||
new ListItem(new OpenInShellCommand(Resources.Microsoft_plugin_command_name_open, "explorer.exe", "shell:RecycleBinFolder")
|
||||
{
|
||||
Id = "com.microsoft.cmdpal.builtin.system.recycle_bin",
|
||||
})
|
||||
{
|
||||
Title = Resources.Microsoft_plugin_sys_RecycleBin,
|
||||
Subtitle = Resources.Microsoft_plugin_sys_RecycleBin_description,
|
||||
@@ -110,7 +143,15 @@ internal static class Commands
|
||||
});
|
||||
}
|
||||
|
||||
results.Add(new ListItem(new ExecuteCommandConfirmation(Resources.Microsoft_plugin_sys_RestartShell_name!, confirmCommands, Resources.Microsoft_plugin_sys_RestartShell_confirmation!, static () => OpenInShellHelper.OpenInShell("cmd", "/C tskill explorer && start explorer", runWithHiddenWindow: true)))
|
||||
results.Add(new ListItem(
|
||||
new ExecuteCommandConfirmation(
|
||||
Resources.Microsoft_plugin_sys_RestartShell_name!,
|
||||
confirmCommands,
|
||||
Resources.Microsoft_plugin_sys_RestartShell_confirmation!,
|
||||
static () => OpenInShellHelper.OpenInShell("cmd", "/C tskill explorer && start explorer", runWithHiddenWindow: true))
|
||||
{
|
||||
Id = "com.microsoft.cmdpal.builtin.system.restart_shell",
|
||||
})
|
||||
{
|
||||
Title = Resources.Microsoft_plugin_sys_RestartShell!,
|
||||
Subtitle = Resources.Microsoft_plugin_sys_RestartShell_description!,
|
||||
@@ -141,19 +182,19 @@ internal static class Commands
|
||||
var results = new List<IListItem>();
|
||||
|
||||
// We update the cache only if the last query is older than 'updateCacheIntervalSeconds' seconds
|
||||
DateTime timeOfLastNetworkQueryBefore = timeOfLastNetworkQuery;
|
||||
var timeOfLastNetworkQueryBefore = timeOfLastNetworkQuery;
|
||||
timeOfLastNetworkQuery = DateTime.Now; // Set time of last query to this query
|
||||
if ((timeOfLastNetworkQuery - timeOfLastNetworkQueryBefore).TotalSeconds >= UpdateCacheIntervalSeconds)
|
||||
{
|
||||
networkPropertiesCache = NetworkConnectionProperties.GetList();
|
||||
}
|
||||
|
||||
CompositeFormat sysIpv4DescriptionCompositeFormate = CompositeFormat.Parse(Resources.Microsoft_plugin_sys_ip4_description);
|
||||
CompositeFormat sysIpv6DescriptionCompositeFormate = CompositeFormat.Parse(Resources.Microsoft_plugin_sys_ip6_description);
|
||||
CompositeFormat sysMacDescriptionCompositeFormate = CompositeFormat.Parse(Resources.Microsoft_plugin_sys_mac_description);
|
||||
var sysIpv4DescriptionCompositeFormate = CompositeFormat.Parse(Resources.Microsoft_plugin_sys_ip4_description);
|
||||
var sysIpv6DescriptionCompositeFormate = CompositeFormat.Parse(Resources.Microsoft_plugin_sys_ip6_description);
|
||||
var sysMacDescriptionCompositeFormate = CompositeFormat.Parse(Resources.Microsoft_plugin_sys_mac_description);
|
||||
var hideDisconnectedNetworkInfo = manager.HideDisconnectedNetworkInfo();
|
||||
|
||||
foreach (NetworkConnectionProperties intInfo in networkPropertiesCache)
|
||||
foreach (var intInfo in networkPropertiesCache)
|
||||
{
|
||||
if (hideDisconnectedNetworkInfo)
|
||||
{
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// 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.
|
||||
|
||||
@@ -39,4 +39,18 @@ public sealed partial class SystemCommandExtensionProvider : CommandProvider
|
||||
}
|
||||
|
||||
public override IFallbackCommandItem[] FallbackCommands() => [_fallbackSystemItem];
|
||||
|
||||
public override ICommandItem? GetCommandItem(string id)
|
||||
{
|
||||
var everything = Page.GetItems();
|
||||
foreach (var item in everything)
|
||||
{
|
||||
if (item.Command.Id == id)
|
||||
{
|
||||
return item;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,7 +9,8 @@ namespace Microsoft.CommandPalette.Extensions.Toolkit;
|
||||
public abstract partial class CommandProvider :
|
||||
ICommandProvider,
|
||||
ICommandProvider2,
|
||||
ICommandProvider3
|
||||
ICommandProvider3,
|
||||
ICommandProvider4
|
||||
{
|
||||
public virtual string Id { get; protected set; } = string.Empty;
|
||||
|
||||
@@ -25,6 +26,8 @@ public abstract partial class CommandProvider :
|
||||
|
||||
public virtual ICommand? GetCommand(string id) => null;
|
||||
|
||||
public virtual ICommandItem? GetCommandItem(string id) => null;
|
||||
|
||||
public virtual ICommandSettings? Settings { get; protected set; }
|
||||
|
||||
public virtual bool Frozen { get; protected set; } = true;
|
||||
|
||||
@@ -411,5 +411,11 @@ namespace Microsoft.CommandPalette.Extensions
|
||||
{
|
||||
ICommandItem[] GetDockBands();
|
||||
};
|
||||
|
||||
|
||||
[contract(Microsoft.CommandPalette.Extensions.ExtensionsContract, 1)]
|
||||
interface ICommandProvider4 requires ICommandProvider3
|
||||
{
|
||||
ICommandItem GetCommandItem(String id);
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user