mirror of
https://github.com/microsoft/PowerToys.git
synced 2026-02-23 19:49:43 +01:00
Plumb through to CommandItemVM info about the extension...
so we can determine if we want to pin things or not. We need to know if the extension supports the version of the API with that method on it. It feels super weird to just have CommandItemViewModel do this though - I think the more correct solution would be to have a ContextMenuFactory that generates the context menu for a command item, and then have the UI layer pass that in. But also Jolley's refactor will probably deal away with all this so
This commit is contained in:
@@ -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.
|
||||
|
||||
@@ -25,6 +25,8 @@ public abstract partial class AppExtensionHost : IExtensionHost
|
||||
|
||||
public ObservableCollection<StatusMessageViewModel> StatusMessages { get; } = [];
|
||||
|
||||
public virtual bool SupportsDockBands { get; set; }
|
||||
|
||||
public static void SetHostHwnd(ulong hostHwnd) => _hostingHwnd = hostHwnd;
|
||||
|
||||
public void DebugLog(string message)
|
||||
|
||||
@@ -212,27 +212,28 @@ public partial class CommandItemViewModel : ExtensionObjectViewModel, ICommandBa
|
||||
return;
|
||||
}
|
||||
|
||||
var more = model.MoreCommands;
|
||||
if (more is not null)
|
||||
{
|
||||
MoreCommands = more
|
||||
.Select<IContextItem, IContextItemViewModel>(item =>
|
||||
{
|
||||
return item is ICommandContextItem contextItem ? new CommandContextItemViewModel(contextItem, PageContext) : new SeparatorViewModel();
|
||||
})
|
||||
.ToList();
|
||||
}
|
||||
BuildAndInitMoreCommands();
|
||||
|
||||
// Here, we're already theoretically in the async context, so we can
|
||||
// use Initialize straight up
|
||||
MoreCommands
|
||||
.OfType<CommandContextItemViewModel>()
|
||||
.ToList()
|
||||
.ForEach(contextItem =>
|
||||
{
|
||||
contextItem.SlowInitializeProperties();
|
||||
});
|
||||
// var more = model.MoreCommands;
|
||||
// if (more is not null)
|
||||
// {
|
||||
// MoreCommands = more
|
||||
// .Select<IContextItem, IContextItemViewModel>(item =>
|
||||
// {
|
||||
// return item is ICommandContextItem contextItem ? new CommandContextItemViewModel(contextItem, PageContext) : new SeparatorViewModel();
|
||||
// })
|
||||
// .ToList();
|
||||
// }
|
||||
|
||||
// // Here, we're already theoretically in the async context, so we can
|
||||
// // use Initialize straight up
|
||||
// MoreCommands
|
||||
// .OfType<CommandContextItemViewModel>()
|
||||
// .ToList()
|
||||
// .ForEach(contextItem =>
|
||||
// {
|
||||
// contextItem.SlowInitializeProperties();
|
||||
// });
|
||||
if (!string.IsNullOrEmpty(model.Command?.Name))
|
||||
{
|
||||
_defaultCommandContextItemViewModel = new CommandContextItemViewModel(new CommandContextItem(model.Command!), PageContext)
|
||||
@@ -382,36 +383,36 @@ public partial class CommandItemViewModel : ExtensionObjectViewModel, ICommandBa
|
||||
break;
|
||||
|
||||
case nameof(model.MoreCommands):
|
||||
var more = model.MoreCommands;
|
||||
if (more is not null)
|
||||
{
|
||||
var newContextMenu = more
|
||||
.Select<IContextItem, IContextItemViewModel>(item =>
|
||||
{
|
||||
return item is ICommandContextItem contextItem ? new CommandContextItemViewModel(contextItem, PageContext) : new SeparatorViewModel();
|
||||
})
|
||||
.ToList();
|
||||
lock (MoreCommands)
|
||||
{
|
||||
ListHelpers.InPlaceUpdateList(MoreCommands, newContextMenu);
|
||||
}
|
||||
|
||||
newContextMenu
|
||||
.OfType<CommandContextItemViewModel>()
|
||||
.ToList()
|
||||
.ForEach(contextItem =>
|
||||
{
|
||||
contextItem.InitializeProperties();
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
lock (MoreCommands)
|
||||
{
|
||||
MoreCommands.Clear();
|
||||
}
|
||||
}
|
||||
// var more = model.MoreCommands;
|
||||
// if (more is not null)
|
||||
// {
|
||||
// var newContextMenu = more
|
||||
// .Select<IContextItem, IContextItemViewModel>(item =>
|
||||
// {
|
||||
// return item is ICommandContextItem contextItem ? new CommandContextItemViewModel(contextItem, PageContext) : new SeparatorViewModel();
|
||||
// })
|
||||
// .ToList();
|
||||
// lock (MoreCommands)
|
||||
// {
|
||||
// ListHelpers.InPlaceUpdateList(MoreCommands, newContextMenu);
|
||||
// }
|
||||
|
||||
// newContextMenu
|
||||
// .OfType<CommandContextItemViewModel>()
|
||||
// .ToList()
|
||||
// .ForEach(contextItem =>
|
||||
// {
|
||||
// contextItem.InitializeProperties();
|
||||
// });
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// lock (MoreCommands)
|
||||
// {
|
||||
// MoreCommands.Clear();
|
||||
// }
|
||||
// }
|
||||
BuildAndInitMoreCommands();
|
||||
UpdateProperty(nameof(SecondaryCommand));
|
||||
UpdateProperty(nameof(SecondaryCommandName));
|
||||
UpdateProperty(nameof(HasMoreCommands));
|
||||
@@ -513,6 +514,68 @@ public partial class CommandItemViewModel : ExtensionObjectViewModel, ICommandBa
|
||||
base.SafeCleanup();
|
||||
Initialized |= InitializedState.CleanedUp;
|
||||
}
|
||||
|
||||
/// <remarks>
|
||||
/// * Does call SlowInitializeProperties on the created items.
|
||||
/// * does NOT call UpdateProperty ; caller must do that.
|
||||
/// </remarks>
|
||||
private void BuildAndInitMoreCommands()
|
||||
{
|
||||
var model = _commandItemModel.Unsafe;
|
||||
if (model is null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var more = model.MoreCommands;
|
||||
List<IContextItemViewModel> results = [];
|
||||
if (more is not null)
|
||||
{
|
||||
foreach (var item in more)
|
||||
{
|
||||
if (item is ICommandContextItem contextItem)
|
||||
{
|
||||
var contextItemViewModel = new CommandContextItemViewModel(contextItem, PageContext);
|
||||
contextItemViewModel.SlowInitializeProperties();
|
||||
results.Add(contextItemViewModel);
|
||||
}
|
||||
else
|
||||
{
|
||||
results.Add(new SeparatorViewModel());
|
||||
}
|
||||
}
|
||||
|
||||
// MoreCommands = more
|
||||
// .Select<IContextItem, IContextItemViewModel>(item =>
|
||||
// {
|
||||
// return item is ICommandContextItem contextItem ? new CommandContextItemViewModel(contextItem, PageContext) : new SeparatorViewModel();
|
||||
// })
|
||||
// .ToList();
|
||||
}
|
||||
|
||||
if (PageContext.TryGetTarget(out var pageContext))
|
||||
{
|
||||
if (pageContext.ExtensionSupportsPinning)
|
||||
{
|
||||
// test: just add a bunch of separators
|
||||
results.Add(new SeparatorViewModel());
|
||||
results.Add(new SeparatorViewModel());
|
||||
results.Add(new SeparatorViewModel());
|
||||
}
|
||||
}
|
||||
|
||||
// var oldMoreCommands = MoreCommands;
|
||||
// MoreCommands = results;
|
||||
List<IContextItemViewModel>? freedItems;
|
||||
lock (MoreCommands)
|
||||
{
|
||||
ListHelpers.InPlaceUpdateList(MoreCommands, results, out freedItems);
|
||||
}
|
||||
|
||||
freedItems.OfType<CommandContextItemViewModel>()
|
||||
.ToList()
|
||||
.ForEach(c => c.SafeCleanup());
|
||||
}
|
||||
}
|
||||
|
||||
[Flags]
|
||||
|
||||
@@ -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,8 @@ public class GlobalLogPageContext : IPageContext
|
||||
{
|
||||
public TaskScheduler Scheduler { get; private init; }
|
||||
|
||||
bool IPageContext.ExtensionSupportsPinning => false;
|
||||
|
||||
public void ShowException(Exception ex, string? extensionHint)
|
||||
{ /*do nothing*/
|
||||
}
|
||||
|
||||
@@ -79,6 +79,8 @@ public partial class PageViewModel : ExtensionObjectViewModel, IPageContext
|
||||
|
||||
public IconInfoViewModel Icon { get; protected set; }
|
||||
|
||||
bool IPageContext.ExtensionSupportsPinning => ExtensionHost.SupportsDockBands;
|
||||
|
||||
public PageViewModel(IPage? model, TaskScheduler scheduler, AppExtensionHost extensionHost)
|
||||
: base((IPageContext?)null)
|
||||
{
|
||||
@@ -267,6 +269,8 @@ public interface IPageContext
|
||||
void ShowException(Exception ex, string? extensionHint = null);
|
||||
|
||||
TaskScheduler Scheduler { get; }
|
||||
|
||||
bool ExtensionSupportsPinning { get; }
|
||||
}
|
||||
|
||||
public interface IPageViewModelFactoryService
|
||||
|
||||
@@ -165,6 +165,7 @@ public sealed class CommandProviderWrapper
|
||||
|
||||
if (model is ICommandProvider3 supportsDockBands)
|
||||
{
|
||||
ExtensionHost.SupportsDockBands = true;
|
||||
var bands = supportsDockBands.GetDockBands();
|
||||
if (bands is not null)
|
||||
{
|
||||
@@ -213,7 +214,16 @@ public sealed class CommandProviderWrapper
|
||||
Func<ICommandItem?, TopLevelType, TopLevelViewModel> make = (ICommandItem? i, TopLevelType t) =>
|
||||
{
|
||||
CommandItemViewModel commandItemViewModel = new(new(i), pageContext);
|
||||
TopLevelViewModel topLevelViewModel = new(commandItemViewModel, t, ExtensionHost, ProviderId, settings, providerSettings, serviceProvider, i);
|
||||
TopLevelViewModel topLevelViewModel = new(
|
||||
item: commandItemViewModel,
|
||||
topLevelType: t,
|
||||
extensionHost: ExtensionHost,
|
||||
commandProviderId: ProviderId,
|
||||
settings: settings,
|
||||
providerSettings: providerSettings,
|
||||
serviceProvider: serviceProvider,
|
||||
commandItem: i/*,
|
||||
providerSupportsPinning: SupportsDockBands*/);
|
||||
topLevelViewModel.InitializeProperties();
|
||||
|
||||
return topLevelViewModel;
|
||||
|
||||
@@ -33,6 +33,8 @@ public sealed partial class DockViewModel : IDisposable,
|
||||
|
||||
public ObservableCollection<TopLevelViewModel> AllItems => _topLevelCommandManager.DockBands;
|
||||
|
||||
bool IPageContext.ExtensionSupportsPinning => false;
|
||||
|
||||
public DockViewModel(
|
||||
TopLevelCommandManager tlcManager,
|
||||
SettingsModel settings,
|
||||
|
||||
@@ -60,6 +60,8 @@ public partial class TopLevelCommandManager : ObservableObject,
|
||||
}
|
||||
}
|
||||
|
||||
bool IPageContext.ExtensionSupportsPinning => false;
|
||||
|
||||
public async Task<bool> LoadBuiltinsAsync()
|
||||
{
|
||||
var s = new Stopwatch();
|
||||
|
||||
@@ -28,6 +28,7 @@ public sealed partial class TopLevelViewModel : ObservableObject, IListItem, IEx
|
||||
|
||||
private readonly string _commandProviderId;
|
||||
|
||||
// private readonly bool _providerSupportsPinning;
|
||||
private string IdFromModel => IsFallback && !string.IsNullOrWhiteSpace(_fallbackId) ? _fallbackId : _commandItemViewModel.Command.Id;
|
||||
|
||||
private string _fallbackId = string.Empty;
|
||||
@@ -58,6 +59,8 @@ public sealed partial class TopLevelViewModel : ObservableObject, IListItem, IEx
|
||||
|
||||
public IconInfoViewModel IconViewModel => _commandItemViewModel.Icon;
|
||||
|
||||
// public bool ProviderSupportsPinning => _providerSupportsPinning;
|
||||
|
||||
////// ICommandItem
|
||||
public string Title => _commandItemViewModel.Title;
|
||||
|
||||
@@ -204,12 +207,15 @@ public sealed partial class TopLevelViewModel : ObservableObject, IListItem, IEx
|
||||
SettingsModel settings,
|
||||
ProviderSettings providerSettings,
|
||||
IServiceProvider serviceProvider,
|
||||
ICommandItem? commandItem)
|
||||
ICommandItem? commandItem)/*,
|
||||
bool providerSupportsPinning*/
|
||||
{
|
||||
_serviceProvider = serviceProvider;
|
||||
_settings = settings;
|
||||
_providerSettings = providerSettings;
|
||||
_commandProviderId = commandProviderId;
|
||||
|
||||
// _providerSupportsPinning = providerSupportsPinning;
|
||||
_commandItemViewModel = item;
|
||||
|
||||
IsFallback = topLevelType == TopLevelType.Fallback;
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -167,7 +167,7 @@ public partial class AllAppsCommandProvider : CommandProvider
|
||||
}
|
||||
|
||||
// ... Now, combine those two
|
||||
List<ICommandItem> both = bestAppMatch is null ? nameMatches : [.. nameMatches, bestAppMatch];
|
||||
var both = bestAppMatch is null ? nameMatches : [.. nameMatches, bestAppMatch];
|
||||
|
||||
if (both.Count == 1)
|
||||
{
|
||||
@@ -191,7 +191,7 @@ public partial class AllAppsCommandProvider : CommandProvider
|
||||
|
||||
public override ICommandItem? GetCommandItemById(string id)
|
||||
{
|
||||
if (id == _listItem.Command.Id)
|
||||
if (id == _listItem.Command?.Id)
|
||||
{
|
||||
return _listItem;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user