mirror of
https://github.com/microsoft/PowerToys.git
synced 2025-12-29 08:29:10 +01:00
A different approach to the extension host problem
I think the work to figure out the extension host was much overcomplicated. I don't think we need all that.
This commit is contained in:
@@ -0,0 +1,174 @@
|
||||
// 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 System.Collections.ObjectModel;
|
||||
using System.Diagnostics;
|
||||
using ManagedCommon;
|
||||
using Microsoft.CommandPalette.Extensions;
|
||||
using Microsoft.CommandPalette.Extensions.Toolkit;
|
||||
using Windows.Foundation;
|
||||
|
||||
namespace Microsoft.CmdPal.Core.ViewModels;
|
||||
|
||||
public abstract partial class AppExtensionHost : IExtensionHost
|
||||
{
|
||||
private static readonly GlobalLogPageContext _globalLogPageContext = new();
|
||||
|
||||
private static ulong _hostingHwnd;
|
||||
|
||||
public static ObservableCollection<LogMessageViewModel> LogMessages { get; } = [];
|
||||
|
||||
public ulong HostingHwnd => _hostingHwnd;
|
||||
|
||||
public string LanguageOverride => string.Empty;
|
||||
|
||||
public ObservableCollection<StatusMessageViewModel> StatusMessages { get; } = [];
|
||||
|
||||
public static void SetHostHwnd(ulong hostHwnd) => _hostingHwnd = hostHwnd;
|
||||
|
||||
public void DebugLog(string message)
|
||||
{
|
||||
#if DEBUG
|
||||
this.ProcessLogMessage(new LogMessage(message));
|
||||
#endif
|
||||
}
|
||||
|
||||
public IAsyncAction HideStatus(IStatusMessage? message)
|
||||
{
|
||||
if (message == null)
|
||||
{
|
||||
return Task.CompletedTask.AsAsyncAction();
|
||||
}
|
||||
|
||||
_ = Task.Run(() =>
|
||||
{
|
||||
ProcessHideStatusMessage(message);
|
||||
});
|
||||
return Task.CompletedTask.AsAsyncAction();
|
||||
}
|
||||
|
||||
public void Log(string message)
|
||||
{
|
||||
this.ProcessLogMessage(new LogMessage(message));
|
||||
}
|
||||
|
||||
public IAsyncAction LogMessage(ILogMessage? message)
|
||||
{
|
||||
if (message == null)
|
||||
{
|
||||
return Task.CompletedTask.AsAsyncAction();
|
||||
}
|
||||
|
||||
Logger.LogDebug(message.Message);
|
||||
|
||||
_ = Task.Run(() =>
|
||||
{
|
||||
ProcessLogMessage(message);
|
||||
});
|
||||
|
||||
// We can't just make a LogMessageViewModel : ExtensionObjectViewModel
|
||||
// because we don't necessarily know the page context. Butts.
|
||||
return Task.CompletedTask.AsAsyncAction();
|
||||
}
|
||||
|
||||
public void ProcessHideStatusMessage(IStatusMessage message)
|
||||
{
|
||||
Task.Factory.StartNew(
|
||||
() =>
|
||||
{
|
||||
try
|
||||
{
|
||||
var vm = StatusMessages.Where(messageVM => messageVM.Model.Unsafe == message).FirstOrDefault();
|
||||
if (vm != null)
|
||||
{
|
||||
StatusMessages.Remove(vm);
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
},
|
||||
CancellationToken.None,
|
||||
TaskCreationOptions.None,
|
||||
_globalLogPageContext.Scheduler);
|
||||
}
|
||||
|
||||
public void ProcessLogMessage(ILogMessage message)
|
||||
{
|
||||
var vm = new LogMessageViewModel(message, _globalLogPageContext);
|
||||
vm.SafeInitializePropertiesSynchronous();
|
||||
|
||||
// if (Extension != null)
|
||||
// {
|
||||
// vm.ExtensionPfn = Extension.PackageFamilyName;
|
||||
// }
|
||||
Task.Factory.StartNew(
|
||||
() =>
|
||||
{
|
||||
LogMessages.Add(vm);
|
||||
},
|
||||
CancellationToken.None,
|
||||
TaskCreationOptions.None,
|
||||
_globalLogPageContext.Scheduler);
|
||||
}
|
||||
|
||||
public void ProcessStatusMessage(IStatusMessage message, StatusContext context)
|
||||
{
|
||||
// If this message is already in the list of messages, just bring it to the top
|
||||
var oldVm = StatusMessages.Where(messageVM => messageVM.Model.Unsafe == message).FirstOrDefault();
|
||||
if (oldVm != null)
|
||||
{
|
||||
Task.Factory.StartNew(
|
||||
() =>
|
||||
{
|
||||
StatusMessages.Remove(oldVm);
|
||||
StatusMessages.Add(oldVm);
|
||||
},
|
||||
CancellationToken.None,
|
||||
TaskCreationOptions.None,
|
||||
_globalLogPageContext.Scheduler);
|
||||
return;
|
||||
}
|
||||
|
||||
var vm = new StatusMessageViewModel(message, new(_globalLogPageContext));
|
||||
vm.SafeInitializePropertiesSynchronous();
|
||||
|
||||
// if (Extension != null)
|
||||
// {
|
||||
// vm.ExtensionPfn = Extension.PackageFamilyName;
|
||||
// }
|
||||
Task.Factory.StartNew(
|
||||
() =>
|
||||
{
|
||||
StatusMessages.Add(vm);
|
||||
},
|
||||
CancellationToken.None,
|
||||
TaskCreationOptions.None,
|
||||
_globalLogPageContext.Scheduler);
|
||||
}
|
||||
|
||||
public IAsyncAction ShowStatus(IStatusMessage? message, StatusContext context)
|
||||
{
|
||||
if (message == null)
|
||||
{
|
||||
return Task.CompletedTask.AsAsyncAction();
|
||||
}
|
||||
|
||||
Debug.WriteLine(message.Message);
|
||||
|
||||
_ = Task.Run(() =>
|
||||
{
|
||||
ProcessStatusMessage(message, context);
|
||||
});
|
||||
|
||||
return Task.CompletedTask.AsAsyncAction();
|
||||
}
|
||||
|
||||
public abstract string? GetExtensionDisplayName();
|
||||
}
|
||||
|
||||
public interface IAppHostService
|
||||
{
|
||||
AppExtensionHost GetHostForCommand(object? context, AppExtensionHost? currentHost);
|
||||
}
|
||||
@@ -2,34 +2,17 @@
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Diagnostics;
|
||||
using ManagedCommon;
|
||||
using Microsoft.CmdPal.Common.Services;
|
||||
using Microsoft.CommandPalette.Extensions;
|
||||
using Microsoft.CommandPalette.Extensions.Toolkit;
|
||||
using Windows.Foundation;
|
||||
|
||||
namespace Microsoft.CmdPal.Core.ViewModels;
|
||||
|
||||
public sealed partial class CommandPaletteHost : IExtensionHost
|
||||
public sealed partial class CommandPaletteHost : AppExtensionHost, IExtensionHost
|
||||
{
|
||||
// Static singleton, so that we can access this from anywhere
|
||||
// Post MVVM - this should probably be like, a dependency injection thing.
|
||||
public static CommandPaletteHost Instance { get; } = new();
|
||||
|
||||
private static readonly GlobalLogPageContext _globalLogPageContext = new();
|
||||
|
||||
private static ulong _hostingHwnd;
|
||||
|
||||
public ulong HostingHwnd => _hostingHwnd;
|
||||
|
||||
public string LanguageOverride => string.Empty;
|
||||
|
||||
public static ObservableCollection<LogMessageViewModel> LogMessages { get; } = [];
|
||||
|
||||
public ObservableCollection<StatusMessageViewModel> StatusMessages { get; } = [];
|
||||
|
||||
public IExtensionWrapper? Extension { get; }
|
||||
|
||||
private readonly ICommandProvider? _builtInProvider;
|
||||
@@ -48,145 +31,8 @@ public sealed partial class CommandPaletteHost : IExtensionHost
|
||||
_builtInProvider = builtInProvider;
|
||||
}
|
||||
|
||||
public IAsyncAction ShowStatus(IStatusMessage? message, StatusContext context)
|
||||
public override string? GetExtensionDisplayName()
|
||||
{
|
||||
if (message == null)
|
||||
{
|
||||
return Task.CompletedTask.AsAsyncAction();
|
||||
}
|
||||
|
||||
Debug.WriteLine(message.Message);
|
||||
|
||||
_ = Task.Run(() =>
|
||||
{
|
||||
ProcessStatusMessage(message, context);
|
||||
});
|
||||
|
||||
return Task.CompletedTask.AsAsyncAction();
|
||||
}
|
||||
|
||||
public IAsyncAction HideStatus(IStatusMessage? message)
|
||||
{
|
||||
if (message == null)
|
||||
{
|
||||
return Task.CompletedTask.AsAsyncAction();
|
||||
}
|
||||
|
||||
_ = Task.Run(() =>
|
||||
{
|
||||
ProcessHideStatusMessage(message);
|
||||
});
|
||||
return Task.CompletedTask.AsAsyncAction();
|
||||
}
|
||||
|
||||
public IAsyncAction LogMessage(ILogMessage? message)
|
||||
{
|
||||
if (message == null)
|
||||
{
|
||||
return Task.CompletedTask.AsAsyncAction();
|
||||
}
|
||||
|
||||
Logger.LogDebug(message.Message);
|
||||
|
||||
_ = Task.Run(() =>
|
||||
{
|
||||
ProcessLogMessage(message);
|
||||
});
|
||||
|
||||
// We can't just make a LogMessageViewModel : ExtensionObjectViewModel
|
||||
// because we don't necessarily know the page context. Butts.
|
||||
return Task.CompletedTask.AsAsyncAction();
|
||||
}
|
||||
|
||||
public void ProcessLogMessage(ILogMessage message)
|
||||
{
|
||||
var vm = new LogMessageViewModel(message, _globalLogPageContext);
|
||||
vm.SafeInitializePropertiesSynchronous();
|
||||
|
||||
if (Extension != null)
|
||||
{
|
||||
vm.ExtensionPfn = Extension.PackageFamilyName;
|
||||
}
|
||||
|
||||
Task.Factory.StartNew(
|
||||
() =>
|
||||
{
|
||||
LogMessages.Add(vm);
|
||||
},
|
||||
CancellationToken.None,
|
||||
TaskCreationOptions.None,
|
||||
_globalLogPageContext.Scheduler);
|
||||
}
|
||||
|
||||
public void ProcessStatusMessage(IStatusMessage message, StatusContext context)
|
||||
{
|
||||
// If this message is already in the list of messages, just bring it to the top
|
||||
var oldVm = StatusMessages.Where(messageVM => messageVM.Model.Unsafe == message).FirstOrDefault();
|
||||
if (oldVm != null)
|
||||
{
|
||||
Task.Factory.StartNew(
|
||||
() =>
|
||||
{
|
||||
StatusMessages.Remove(oldVm);
|
||||
StatusMessages.Add(oldVm);
|
||||
},
|
||||
CancellationToken.None,
|
||||
TaskCreationOptions.None,
|
||||
_globalLogPageContext.Scheduler);
|
||||
return;
|
||||
}
|
||||
|
||||
var vm = new StatusMessageViewModel(message, new(_globalLogPageContext));
|
||||
vm.SafeInitializePropertiesSynchronous();
|
||||
|
||||
if (Extension != null)
|
||||
{
|
||||
vm.ExtensionPfn = Extension.PackageFamilyName;
|
||||
}
|
||||
|
||||
Task.Factory.StartNew(
|
||||
() =>
|
||||
{
|
||||
StatusMessages.Add(vm);
|
||||
},
|
||||
CancellationToken.None,
|
||||
TaskCreationOptions.None,
|
||||
_globalLogPageContext.Scheduler);
|
||||
}
|
||||
|
||||
public void ProcessHideStatusMessage(IStatusMessage message)
|
||||
{
|
||||
Task.Factory.StartNew(
|
||||
() =>
|
||||
{
|
||||
try
|
||||
{
|
||||
var vm = StatusMessages.Where(messageVM => messageVM.Model.Unsafe == message).FirstOrDefault();
|
||||
if (vm != null)
|
||||
{
|
||||
StatusMessages.Remove(vm);
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
},
|
||||
CancellationToken.None,
|
||||
TaskCreationOptions.None,
|
||||
_globalLogPageContext.Scheduler);
|
||||
}
|
||||
|
||||
public static void SetHostHwnd(ulong hostHwnd) => _hostingHwnd = hostHwnd;
|
||||
|
||||
public void DebugLog(string message)
|
||||
{
|
||||
#if DEBUG
|
||||
this.ProcessLogMessage(new LogMessage(message));
|
||||
#endif
|
||||
}
|
||||
|
||||
public void Log(string message)
|
||||
{
|
||||
this.ProcessLogMessage(new LogMessage(message));
|
||||
return Extension?.ExtensionDisplayName;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -47,7 +47,7 @@ public partial class ContentPageViewModel : PageViewModel, ICommandBarContext
|
||||
|
||||
// Remember - "observable" properties from the model (via PropChanged)
|
||||
// cannot be marked [ObservableProperty]
|
||||
public ContentPageViewModel(IContentPage model, TaskScheduler scheduler, CommandPaletteHost host)
|
||||
public ContentPageViewModel(IContentPage model, TaskScheduler scheduler, AppExtensionHost host)
|
||||
: base(model, scheduler, host)
|
||||
{
|
||||
_model = new(model);
|
||||
@@ -111,15 +111,15 @@ public partial class ContentPageViewModel : PageViewModel, ICommandBarContext
|
||||
|
||||
Commands = model.Commands
|
||||
.ToList()
|
||||
.Select(item =>
|
||||
.Select<IContextItem, IContextItemViewModel>(item =>
|
||||
{
|
||||
if (item is CommandContextItem contextItem)
|
||||
{
|
||||
return new CommandContextItemViewModel(contextItem, PageContext) as IContextItemViewModel;
|
||||
return new CommandContextItemViewModel(contextItem, PageContext);
|
||||
}
|
||||
else
|
||||
{
|
||||
return new SeparatorContextItemViewModel() as IContextItemViewModel;
|
||||
return new SeparatorContextItemViewModel();
|
||||
}
|
||||
})
|
||||
.ToList();
|
||||
@@ -178,7 +178,7 @@ public partial class ContentPageViewModel : PageViewModel, ICommandBarContext
|
||||
}
|
||||
else
|
||||
{
|
||||
return new SeparatorContextItemViewModel() as IContextItemViewModel;
|
||||
return new SeparatorContextItemViewModel();
|
||||
}
|
||||
})
|
||||
.ToList();
|
||||
|
||||
@@ -72,7 +72,7 @@ public partial class ListViewModel : PageViewModel, IDisposable
|
||||
}
|
||||
}
|
||||
|
||||
public ListViewModel(IListPage model, TaskScheduler scheduler, CommandPaletteHost host)
|
||||
public ListViewModel(IListPage model, TaskScheduler scheduler, AppExtensionHost host)
|
||||
: base(model, scheduler, host)
|
||||
{
|
||||
_model = new(model);
|
||||
@@ -158,10 +158,7 @@ public partial class ListViewModel : PageViewModel, IDisposable
|
||||
}
|
||||
|
||||
// Cancel any ongoing search
|
||||
if (_cancellationTokenSource != null)
|
||||
{
|
||||
_cancellationTokenSource.Cancel();
|
||||
}
|
||||
_cancellationTokenSource?.Cancel();
|
||||
|
||||
lock (_listLock)
|
||||
{
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
// 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.Core.ViewModels;
|
||||
using Microsoft.CmdPal.Core.ViewModels.Models;
|
||||
using Microsoft.CommandPalette.Extensions;
|
||||
|
||||
@@ -14,8 +13,7 @@ public partial class LogMessageViewModel : ExtensionObjectViewModel
|
||||
|
||||
public string Message { get; private set; } = string.Empty;
|
||||
|
||||
public string ExtensionPfn { get; set; } = string.Empty;
|
||||
|
||||
// public string ExtensionPfn { get; set; } = string.Empty;
|
||||
public LogMessageViewModel(ILogMessage message, IPageContext context)
|
||||
: base(context)
|
||||
{
|
||||
|
||||
@@ -43,7 +43,7 @@ public partial class PageViewModel : ExtensionObjectViewModel, IPageContext
|
||||
public bool ShowSuggestion => !string.IsNullOrEmpty(TextToSuggest) && TextToSuggest != Filter;
|
||||
|
||||
[ObservableProperty]
|
||||
public partial CommandPaletteHost ExtensionHost { get; private set; }
|
||||
public partial AppExtensionHost ExtensionHost { get; private set; }
|
||||
|
||||
public bool HasStatusMessage => MostRecentStatusMessage != null;
|
||||
|
||||
@@ -69,7 +69,7 @@ public partial class PageViewModel : ExtensionObjectViewModel, IPageContext
|
||||
|
||||
public IconInfoViewModel Icon { get; protected set; }
|
||||
|
||||
public PageViewModel(IPage? model, TaskScheduler scheduler, CommandPaletteHost extensionHost)
|
||||
public PageViewModel(IPage? model, TaskScheduler scheduler, AppExtensionHost extensionHost)
|
||||
: base((IPageContext?)null)
|
||||
{
|
||||
_pageModel = new(model);
|
||||
@@ -220,7 +220,7 @@ public partial class PageViewModel : ExtensionObjectViewModel, IPageContext
|
||||
{
|
||||
// Set the extensionHint to the Page Title (if we have one, and one not provided).
|
||||
// extensionHint ??= _pageModel?.Unsafe?.Title;
|
||||
extensionHint ??= ExtensionHost.Extension?.ExtensionDisplayName ?? Title;
|
||||
extensionHint ??= ExtensionHost.GetExtensionDisplayName() ?? Title;
|
||||
Task.Factory.StartNew(
|
||||
() =>
|
||||
{
|
||||
@@ -263,5 +263,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, CommandPaletteHost host);
|
||||
PageViewModel? TryCreatePageViewModel(IPage page, bool nested, AppExtensionHost host);
|
||||
}
|
||||
|
||||
@@ -15,7 +15,7 @@ public class PageViewModelFactory : IPageViewModelFactoryService
|
||||
_scheduler = scheduler;
|
||||
}
|
||||
|
||||
public PageViewModel? TryCreatePageViewModel(IPage page, bool nested, CommandPaletteHost host)
|
||||
public PageViewModel? TryCreatePageViewModel(IPage page, bool nested, AppExtensionHost host)
|
||||
{
|
||||
return page switch
|
||||
{
|
||||
|
||||
@@ -20,6 +20,7 @@ public partial class ShellViewModel : ObservableObject,
|
||||
IRecipient<PerformCommandMessage>
|
||||
{
|
||||
private readonly IRootPageService _rootPageService;
|
||||
private readonly IAppHostService _appHostService;
|
||||
private readonly TaskScheduler _scheduler;
|
||||
private readonly IPageViewModelFactoryService _pageViewModelFactory;
|
||||
private readonly Lock _invokeLock = new();
|
||||
@@ -66,7 +67,8 @@ public partial class ShellViewModel : ObservableObject,
|
||||
|
||||
public bool IsNested { get => _isNested; }
|
||||
|
||||
public ShellViewModel(TaskScheduler scheduler, IRootPageService rootPageService, IPageViewModelFactoryService pageViewModelFactory)
|
||||
public ShellViewModel(
|
||||
TaskScheduler scheduler, IRootPageService rootPageService, IPageViewModelFactoryService pageViewModelFactory, IAppHostService appHostService)
|
||||
{
|
||||
_pageViewModelFactory = pageViewModelFactory;
|
||||
_scheduler = scheduler;
|
||||
@@ -75,6 +77,7 @@ public partial class ShellViewModel : ObservableObject,
|
||||
|
||||
// Register to receive messages
|
||||
WeakReferenceMessenger.Default.Register<PerformCommandMessage>(this);
|
||||
_appHostService = appHostService;
|
||||
}
|
||||
|
||||
[RelayCommand]
|
||||
@@ -204,48 +207,47 @@ public partial class ShellViewModel : ObservableObject,
|
||||
// In the case that we're coming from a top-level command, the
|
||||
// current page's host is the global instance. We only really want
|
||||
// to use that as the host of last resort.
|
||||
var pageHost = CurrentPage?.ExtensionHost;
|
||||
if (pageHost == CommandPaletteHost.Instance)
|
||||
{
|
||||
pageHost = null;
|
||||
}
|
||||
|
||||
var messageHost = message.ExtensionHost;
|
||||
|
||||
// Use the host from the current page if it has one, else use the
|
||||
// one specified in the PerformMessage for a top-level command,
|
||||
// else just use the global one.
|
||||
CommandPaletteHost host;
|
||||
|
||||
// TODO! we need a different way to get the current CommandPaletteHost out of the command.
|
||||
//// Top level items can come through without a Extension set on the
|
||||
//// message. In that case, the `Context` is actually the
|
||||
//// TopLevelViewModel itself, and we can use that to get at the
|
||||
//// extension object.
|
||||
// extension = pageHost?.Extension ?? messageHost?.Extension ?? null;
|
||||
// if (extension == null && message.Context is TopLevelViewModel topLevelViewModel)
|
||||
// var pageHost = CurrentPage?.ExtensionHost;
|
||||
// if (pageHost == CommandPaletteHost.Instance)
|
||||
// {
|
||||
// extension = topLevelViewModel.ExtensionHost?.Extension;
|
||||
// host = pageHost ?? messageHost ?? topLevelViewModel?.ExtensionHost ?? CommandPaletteHost.Instance;
|
||||
// pageHost = null;
|
||||
// }
|
||||
// else
|
||||
|
||||
// var messageHost = message.ExtensionHost;
|
||||
|
||||
//// Use the host from the current page if it has one, else use the
|
||||
//// one specified in the PerformMessage for a top-level command,
|
||||
//// else just use the global one.
|
||||
// CommandPaletteHost host;
|
||||
|
||||
//// TODO! we need a different way to get the current CommandPaletteHost out of the command.
|
||||
////// Top level items can come through without a Extension set on the
|
||||
////// message. In that case, the `Context` is actually the
|
||||
////// TopLevelViewModel itself, and we can use that to get at the
|
||||
////// extension object.
|
||||
//// extension = pageHost?.Extension ?? messageHost?.Extension ?? null;
|
||||
//// if (extension == null && message.Context is TopLevelViewModel topLevelViewModel)
|
||||
//// {
|
||||
//// extension = topLevelViewModel.ExtensionHost?.Extension;
|
||||
//// host = pageHost ?? messageHost ?? topLevelViewModel?.ExtensionHost ?? CommandPaletteHost.Instance;
|
||||
//// }
|
||||
//// else
|
||||
//// {
|
||||
//// host = pageHost ?? messageHost ?? CommandPaletteHost.Instance;
|
||||
//// }
|
||||
// host = CommandPaletteHost.Instance;
|
||||
// if (extension != null)
|
||||
// {
|
||||
// host = pageHost ?? messageHost ?? CommandPaletteHost.Instance;
|
||||
// if (messageHost != null)
|
||||
// {
|
||||
// Logger.LogDebug($"Activated top-level command from {extension.ExtensionDisplayName}");
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// Logger.LogDebug($"Activated command from {extension.ExtensionDisplayName}");
|
||||
// }
|
||||
// }
|
||||
host = CommandPaletteHost.Instance;
|
||||
|
||||
if (extension != null)
|
||||
{
|
||||
if (messageHost != null)
|
||||
{
|
||||
Logger.LogDebug($"Activated top-level command from {extension.ExtensionDisplayName}");
|
||||
}
|
||||
else
|
||||
{
|
||||
Logger.LogDebug($"Activated command from {extension.ExtensionDisplayName}");
|
||||
}
|
||||
}
|
||||
|
||||
var host = _appHostService.GetHostForCommand(message.Context, CurrentPage?.ExtensionHost);
|
||||
SetActiveExtension(extension);
|
||||
|
||||
if (command is IPage page)
|
||||
|
||||
@@ -15,8 +15,6 @@ public partial class StatusMessageViewModel : ExtensionObjectViewModel
|
||||
|
||||
public MessageState State { get; private set; } = MessageState.Info;
|
||||
|
||||
public string ExtensionPfn { get; set; } = string.Empty;
|
||||
|
||||
public ProgressViewModel? Progress { get; private set; }
|
||||
|
||||
public bool HasProgress => Progress != null;
|
||||
|
||||
@@ -9,7 +9,7 @@ namespace Microsoft.CmdPal.UI.ViewModels;
|
||||
|
||||
public partial class CommandPaletteContentPageViewModel : ContentPageViewModel
|
||||
{
|
||||
public CommandPaletteContentPageViewModel(IContentPage model, TaskScheduler scheduler, CommandPaletteHost host)
|
||||
public CommandPaletteContentPageViewModel(IContentPage model, TaskScheduler scheduler, AppExtensionHost host)
|
||||
: base(model, scheduler, host)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -17,7 +17,7 @@ public class CommandPalettePageViewModelFactory
|
||||
_scheduler = scheduler;
|
||||
}
|
||||
|
||||
public PageViewModel? TryCreatePageViewModel(IPage page, bool nested, CommandPaletteHost host)
|
||||
public PageViewModel? TryCreatePageViewModel(IPage page, bool nested, AppExtensionHost host)
|
||||
{
|
||||
return page switch
|
||||
{
|
||||
|
||||
@@ -32,7 +32,6 @@ public partial class LogMessagesPage : ListPage
|
||||
var li = new ListItem(new NoOpCommand())
|
||||
{
|
||||
Title = logMessageViewModel.Message,
|
||||
Subtitle = logMessageViewModel.ExtensionPfn,
|
||||
};
|
||||
_listItems.Insert(0, li);
|
||||
}
|
||||
|
||||
@@ -146,6 +146,7 @@ public partial class App : Application
|
||||
services.AddSingleton<TrayIconService>();
|
||||
|
||||
services.AddSingleton<IRootPageService, PowerToysRootPageService>();
|
||||
services.AddSingleton<IAppHostService, PowerToysAppHostService>();
|
||||
services.AddSingleton(new TelemetryForwarder());
|
||||
|
||||
// ViewModels
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
// 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 ManagedCommon;
|
||||
using Microsoft.CmdPal.Common.Services;
|
||||
using Microsoft.CmdPal.Core.ViewModels;
|
||||
using Microsoft.CmdPal.UI.ViewModels;
|
||||
using Microsoft.CmdPal.UI.ViewModels.MainPage;
|
||||
using Microsoft.CommandPalette.Extensions;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
// To learn more about WinUI, the WinUI project structure,
|
||||
// and more about our project templates, see: http://aka.ms/winui-project-info.
|
||||
namespace Microsoft.CmdPal.UI;
|
||||
|
||||
internal sealed class PowerToysAppHostService : IAppHostService
|
||||
{
|
||||
public AppExtensionHost GetHostForCommand(object? context, AppExtensionHost? currentHost)
|
||||
{
|
||||
AppExtensionHost? topLevelHost = null;
|
||||
if (context is TopLevelViewModel topLevelViewModel)
|
||||
{
|
||||
topLevelHost = topLevelViewModel.ExtensionHost;
|
||||
}
|
||||
|
||||
return topLevelHost ?? currentHost ?? CommandPaletteHost.Instance;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user