mirror of
https://github.com/microsoft/PowerToys.git
synced 2026-07-09 12:00:14 +02:00
Merge pull request #37 from zadjii-msft/dev/crutkas/moreBaseCleanup
Dev/crutkas/more base cleanup
This commit is contained in:
@@ -3,7 +3,6 @@
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System.Diagnostics;
|
||||
using System.Threading.Tasks;
|
||||
using AllApps.Programs;
|
||||
using Microsoft.Windows.CommandPalette.Extensions.Helpers;
|
||||
|
||||
@@ -19,6 +18,7 @@ internal sealed class AppAction : InvokableCommand
|
||||
this._app = app;
|
||||
this._Icon = new(_app.IcoPath);
|
||||
}
|
||||
|
||||
internal static async Task StartApp(string amuid)
|
||||
{
|
||||
var appManager = new ApplicationActivationManager();
|
||||
@@ -34,15 +34,18 @@ internal sealed class AppAction : InvokableCommand
|
||||
}
|
||||
}).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
internal static async Task StartExe(string path)
|
||||
{
|
||||
var appManager = new ApplicationActivationManager();
|
||||
|
||||
// const ActivateOptions noFlags = ActivateOptions.None;
|
||||
await Task.Run(() =>
|
||||
{
|
||||
Process.Start(new ProcessStartInfo(path) { UseShellExecute = true });
|
||||
});
|
||||
}
|
||||
|
||||
internal async Task Launch()
|
||||
{
|
||||
if (string.IsNullOrEmpty(_app.ExePath))
|
||||
@@ -54,6 +57,7 @@ internal sealed class AppAction : InvokableCommand
|
||||
await StartExe(_app.ExePath);
|
||||
}
|
||||
}
|
||||
|
||||
public override ActionResult Invoke()
|
||||
{
|
||||
_ = Launch();
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System.Diagnostics;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.Windows.CommandPalette.Extensions.Helpers;
|
||||
|
||||
namespace WindowsCommandPalette.BuiltinCommands.AllApps;
|
||||
@@ -11,7 +10,8 @@ namespace WindowsCommandPalette.BuiltinCommands.AllApps;
|
||||
// NOTE this is pretty close to what we'd put in the SDK
|
||||
internal sealed class OpenPathAction(string target) : InvokableCommand
|
||||
{
|
||||
private readonly string _Target = target;
|
||||
private readonly string _target = target;
|
||||
|
||||
internal static async Task LaunchTarget(string t)
|
||||
{
|
||||
await Task.Run(() =>
|
||||
@@ -19,9 +19,11 @@ internal sealed class OpenPathAction(string target) : InvokableCommand
|
||||
Process.Start(new ProcessStartInfo(t) { UseShellExecute = true });
|
||||
});
|
||||
}
|
||||
|
||||
public override ActionResult Invoke()
|
||||
{
|
||||
LaunchTarget(this._Target).Start();
|
||||
LaunchTarget(_target).Start();
|
||||
|
||||
return ActionResult.GoHome();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 System;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace AllApps.Programs;
|
||||
@@ -12,4 +11,4 @@ namespace AllApps.Programs;
|
||||
[ComImport]
|
||||
public class AppxFactory
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 System;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
@@ -44,4 +43,4 @@ public class ApplicationActivationManager : IApplicationActivationManager
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall, MethodCodeType = MethodCodeType.Runtime)]
|
||||
public extern IntPtr ActivateForProtocol([In] string appUserModelId, [In] IntPtr /* IShellItemArray* */itemArray, [Out] out uint processId);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,4 +17,4 @@ public interface IAppxFactory
|
||||
void _VtblGap0_2(); // skip 2 methods
|
||||
|
||||
internal IAppxManifestReader CreateManifestReader(IStream inputStream);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,9 +2,7 @@
|
||||
// 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;
|
||||
using System.Runtime.InteropServices;
|
||||
// using Wox.Plugin.Common.Win32;
|
||||
|
||||
namespace AllApps.Programs;
|
||||
|
||||
@@ -17,4 +15,4 @@ public interface IAppxManifestApplication
|
||||
|
||||
[PreserveSig]
|
||||
int GetAppUserModelId([MarshalAs(UnmanagedType.LPWStr)] out string value);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,4 +17,4 @@ namespace AllApps.Programs
|
||||
|
||||
bool MoveNext();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,9 +2,7 @@
|
||||
// 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;
|
||||
using System.Runtime.InteropServices;
|
||||
// using Wox.Plugin.Common.Win32;
|
||||
|
||||
namespace AllApps.Programs
|
||||
{
|
||||
@@ -18,4 +16,4 @@ namespace AllApps.Programs
|
||||
[PreserveSig]
|
||||
int GetStringValue([MarshalAs(UnmanagedType.LPWStr)] string name, [MarshalAs(UnmanagedType.LPWStr)] out string value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,4 +24,4 @@ public interface IAppxManifestReader
|
||||
void _VtblGap1_5(); // skip 5 methods
|
||||
|
||||
IAppxManifestApplicationsEnumerator GetApplications();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,20 +2,19 @@
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
namespace AllApps.Programs
|
||||
namespace AllApps.Programs;
|
||||
|
||||
public interface IPackage
|
||||
{
|
||||
public interface IPackage
|
||||
{
|
||||
string Name { get; }
|
||||
string Name { get; }
|
||||
|
||||
string FullName { get; }
|
||||
string FullName { get; }
|
||||
|
||||
string FamilyName { get; }
|
||||
string FamilyName { get; }
|
||||
|
||||
bool IsFramework { get; }
|
||||
bool IsFramework { get; }
|
||||
|
||||
bool IsDevelopmentMode { get; }
|
||||
bool IsDevelopmentMode { get; }
|
||||
|
||||
string InstalledLocation { get; }
|
||||
}
|
||||
}
|
||||
string InstalledLocation { get; }
|
||||
}
|
||||
|
||||
@@ -2,12 +2,9 @@
|
||||
// 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.Generic;
|
||||
namespace AllApps.Programs;
|
||||
|
||||
namespace AllApps.Programs
|
||||
public interface IPackageManager
|
||||
{
|
||||
public interface IPackageManager
|
||||
{
|
||||
IEnumerable<IPackage> FindPackagesForCurrentUser();
|
||||
}
|
||||
}
|
||||
IEnumerable<IPackage> FindPackagesForCurrentUser();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
// 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.Windows.CommandPalette.Extensions;
|
||||
using Microsoft.Windows.CommandPalette.Extensions.Helpers;
|
||||
using Windows.Foundation;
|
||||
|
||||
namespace WindowsCommandPalette.BuiltinCommands;
|
||||
|
||||
public class QuitAction : InvokableCommand, IFallbackHandler
|
||||
{
|
||||
public event TypedEventHandler<object?, object?>? QuitRequested;
|
||||
|
||||
public QuitAction()
|
||||
{
|
||||
Icon = new("\uE711");
|
||||
}
|
||||
|
||||
public override ICommandResult Invoke()
|
||||
{
|
||||
QuitRequested?.Invoke(this, new());
|
||||
return ActionResult.KeepOpen();
|
||||
}
|
||||
|
||||
public void UpdateQuery(string query)
|
||||
{
|
||||
if (query.StartsWith('q'))
|
||||
{
|
||||
Name = "Quit";
|
||||
}
|
||||
else
|
||||
{
|
||||
Name = string.Empty;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -8,34 +8,6 @@ using Windows.Foundation;
|
||||
|
||||
namespace WindowsCommandPalette.BuiltinCommands;
|
||||
|
||||
public class QuitAction : InvokableCommand, IFallbackHandler
|
||||
{
|
||||
public event TypedEventHandler<object?, object?>? QuitRequested;
|
||||
|
||||
public QuitAction()
|
||||
{
|
||||
Icon = new("\uE711");
|
||||
}
|
||||
|
||||
public override ICommandResult Invoke()
|
||||
{
|
||||
QuitRequested?.Invoke(this, new());
|
||||
return ActionResult.KeepOpen();
|
||||
}
|
||||
|
||||
public void UpdateQuery(string query)
|
||||
{
|
||||
if (query.StartsWith('q'))
|
||||
{
|
||||
Name = "Quit";
|
||||
}
|
||||
else
|
||||
{
|
||||
Name = string.Empty;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class QuitActionProvider : ICommandProvider
|
||||
{
|
||||
public string DisplayName => string.Empty;
|
||||
@@ -0,0 +1,108 @@
|
||||
// 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.Collections.Specialized;
|
||||
using System.Linq;
|
||||
using CmdPal.Models;
|
||||
using Microsoft.UI.Dispatching;
|
||||
using Microsoft.UI.Xaml;
|
||||
using Microsoft.Windows.CommandPalette.Extensions;
|
||||
using Microsoft.Windows.CommandPalette.Extensions.Helpers;
|
||||
using WindowsCommandPalette.Views;
|
||||
|
||||
namespace DeveloperCommandPalette;
|
||||
|
||||
// The FilteredListSection is for when we've got any filter at all. It starts by
|
||||
// enumerating all actions and apps, and returns the subset that matches.
|
||||
public sealed class FilteredListSection : ISection, INotifyCollectionChanged
|
||||
{
|
||||
public event NotifyCollectionChangedEventHandler? CollectionChanged;
|
||||
|
||||
public string Title => string.Empty;
|
||||
|
||||
private readonly MainViewModel _mainViewModel;
|
||||
private readonly DispatcherQueue _dispatcherQueue = DispatcherQueue.GetForCurrentThread();
|
||||
|
||||
// Top-level list items, from builtin commands and extensions
|
||||
public ObservableCollection<MainListItem> TopLevelItems { get; set; }
|
||||
|
||||
// Apps, from the apps built in command.
|
||||
private IEnumerable<IListItem> AllApps => _mainViewModel.apps.GetItems().First().Items;
|
||||
|
||||
// Results from the last searched text
|
||||
private IEnumerable<IListItem>? lastSearchResults;
|
||||
|
||||
// Things we should enumerate over, depending on the search query.
|
||||
// This is either
|
||||
// * the last search results (if there was a query),
|
||||
// * OR one of:
|
||||
// * Just the top-level actions (if there's no query)
|
||||
// * OR the top-level actions AND the apps (if there's a query)
|
||||
private IEnumerable<IListItem> ItemsToEnumerate =>
|
||||
lastSearchResults != null ?
|
||||
lastSearchResults :
|
||||
TopLevelItems.Concat(AllApps);
|
||||
|
||||
private string _lastQuery = string.Empty;
|
||||
|
||||
// Setting this will enumerate all the actions and installed apps.
|
||||
internal string Query
|
||||
{
|
||||
get => _lastQuery;
|
||||
set
|
||||
{
|
||||
if (string.IsNullOrEmpty(value) ||
|
||||
!_lastQuery.StartsWith(value, true, System.Globalization.CultureInfo.CurrentCulture))
|
||||
{
|
||||
lastSearchResults = null;
|
||||
}
|
||||
|
||||
if (lastSearchResults != null && string.IsNullOrEmpty(value))
|
||||
{
|
||||
// Even with an empty query, we did filter the items (to remove fallbacks without a name
|
||||
// Here, we're going from an empty query to one that has an actual string. Reset the last, so we will _also_ include apps now.
|
||||
this.lastSearchResults = null;
|
||||
}
|
||||
|
||||
_lastQuery = value;
|
||||
var results = ListHelpers.FilterList(ItemsToEnumerate, Query);
|
||||
this.lastSearchResults = string.IsNullOrEmpty(value) ? null : results;
|
||||
}
|
||||
}
|
||||
|
||||
// Watch out future me!
|
||||
//
|
||||
// Don't do the whole linq query in Items itself. That'll evaluate the whole
|
||||
// query once per item, because the ListPage.xaml.cs will create one
|
||||
// ListViewItems per item in Items, and every time it does that, it calls
|
||||
// section.Items.
|
||||
//
|
||||
// instead run the query once when the action query changes, and store the
|
||||
// results.
|
||||
public IListItem[] Items => ItemsToEnumerate.Where(i => i != null).ToArray();
|
||||
|
||||
public FilteredListSection(MainViewModel viewModel)
|
||||
{
|
||||
this._mainViewModel = viewModel;
|
||||
|
||||
// TODO: We should probably just get rid of MainListItem entirely, so I'm leaveing these uncaught
|
||||
TopLevelItems = new(_mainViewModel.TopLevelCommands.Where(wrapper => wrapper.Unsafe != null).Select(wrapper => new MainListItem(wrapper.Unsafe!)));
|
||||
TopLevelItems.CollectionChanged += Bubble_CollectionChanged;
|
||||
}
|
||||
|
||||
private void Bubble_CollectionChanged(object? sender, NotifyCollectionChangedEventArgs e)
|
||||
{
|
||||
_dispatcherQueue.TryEnqueue(() =>
|
||||
{
|
||||
CollectionChanged?.Invoke(this, e);
|
||||
});
|
||||
}
|
||||
|
||||
internal void Reset()
|
||||
{
|
||||
TopLevelItems.Clear();
|
||||
lastSearchResults = null;
|
||||
}
|
||||
}
|
||||
@@ -48,6 +48,7 @@ public sealed class MainListItem : ListItem
|
||||
{
|
||||
this.MoreCommands = this._listItem.MoreCommands;
|
||||
}
|
||||
|
||||
OnPropertyChanged(args.PropertyName);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,240 +2,21 @@
|
||||
// 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.Collections.Specialized;
|
||||
using System.Linq;
|
||||
using CmdPal.Models;
|
||||
using Microsoft.UI.Dispatching;
|
||||
using Microsoft.UI.Xaml;
|
||||
using Microsoft.Windows.CommandPalette.Extensions;
|
||||
using Microsoft.Windows.CommandPalette.Extensions.Helpers;
|
||||
using WindowsCommandPalette.Views;
|
||||
|
||||
namespace DeveloperCommandPalette;
|
||||
|
||||
public sealed class RecentsListSection : ListSection, INotifyCollectionChanged
|
||||
{
|
||||
public event NotifyCollectionChangedEventHandler? CollectionChanged;
|
||||
|
||||
private readonly DispatcherQueue DispatcherQueue = DispatcherQueue.GetForCurrentThread();
|
||||
private readonly MainViewModel _mainViewModel;
|
||||
|
||||
internal ObservableCollection<MainListItem> _Items { get; set; } = [];
|
||||
|
||||
private bool loadedApps;
|
||||
|
||||
public RecentsListSection(MainViewModel viewModel)
|
||||
{
|
||||
this.Title = "Recent";
|
||||
this._mainViewModel = viewModel;
|
||||
|
||||
var recent = _mainViewModel.RecentActions;
|
||||
Reset();
|
||||
_Items.CollectionChanged += Bubble_CollectionChanged;
|
||||
|
||||
_mainViewModel.AppsReady += _mainViewModel_AppsReady;
|
||||
}
|
||||
|
||||
private void _mainViewModel_AppsReady(object sender, object? args)
|
||||
{
|
||||
loadedApps = true;
|
||||
_mainViewModel.AppsReady -= _mainViewModel_AppsReady;
|
||||
AddApps();
|
||||
}
|
||||
|
||||
private void Bubble_CollectionChanged(object? sender, NotifyCollectionChangedEventArgs e)
|
||||
{
|
||||
DispatcherQueue.TryEnqueue(() =>
|
||||
{
|
||||
CollectionChanged?.Invoke(this, e);
|
||||
});
|
||||
}
|
||||
|
||||
public override IListItem[] Items => _Items.ToArray();
|
||||
|
||||
internal void Reset()
|
||||
{
|
||||
_Items.Clear();
|
||||
if (loadedApps)
|
||||
{
|
||||
AddApps();
|
||||
}
|
||||
}
|
||||
|
||||
internal void AddApps()
|
||||
{
|
||||
var apps = _mainViewModel.Recent;
|
||||
foreach (var app in apps)
|
||||
{
|
||||
_Items.Add(new MainListItem(app.Unsafe)); // we know these are all local
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// The MainListSection is for all non-recent actions. No apps.
|
||||
public sealed class MainListSection : ISection, INotifyCollectionChanged
|
||||
{
|
||||
public event NotifyCollectionChangedEventHandler? CollectionChanged;
|
||||
|
||||
public string Title => "Actions";
|
||||
|
||||
private readonly MainViewModel _mainViewModel;
|
||||
private readonly DispatcherQueue DispatcherQueue = DispatcherQueue.GetForCurrentThread();
|
||||
|
||||
// Top-level list items, from builtin commands and extensions
|
||||
internal ObservableCollection<MainListItem> _Items { get; set; }
|
||||
|
||||
// Things we should enumerate over, depending on the search query.
|
||||
// This is either
|
||||
// * the last search results (if there was a query),
|
||||
// * OR one of:
|
||||
// * Just the top-level actions (if there's no query)
|
||||
// * OR the top-level actions AND the apps (if there's a query)
|
||||
private IEnumerable<IListItem> itemsToEnumerate =>
|
||||
_Items.Where(i => i != null && (!_mainViewModel.IsRecentCommand(i)));
|
||||
|
||||
// Watch out future me!
|
||||
//
|
||||
// Don't do the whole linq query in Items itself. That'll evaluate the whole
|
||||
// query once per item, because the ListPage.xaml.cs will create one
|
||||
// ListViewItems per item in Items, and every time it does that, it calls
|
||||
// section.Items.
|
||||
//
|
||||
// instead run the query once when the action query changes, and store the
|
||||
// results.
|
||||
public IListItem[] Items => itemsToEnumerate.ToArray();
|
||||
|
||||
public MainListSection(MainViewModel viewModel)
|
||||
{
|
||||
this._mainViewModel = viewModel;
|
||||
_Items = new(_mainViewModel.TopLevelCommands.Select(w => w.Unsafe).Where(li => li != null).Select(li => new MainListItem(li!)));
|
||||
_Items.CollectionChanged += Bubble_CollectionChanged;
|
||||
}
|
||||
|
||||
internal void UpdateQuery(string query)
|
||||
{
|
||||
var fallbacks = _Items.Select(i => i?.FallbackHandler).Where(fb => fb != null).Select(fb => fb!);
|
||||
foreach (var fb in fallbacks)
|
||||
{
|
||||
fb.UpdateQuery(query);
|
||||
}
|
||||
}
|
||||
|
||||
private void Bubble_CollectionChanged(object? sender, NotifyCollectionChangedEventArgs e)
|
||||
{
|
||||
DispatcherQueue.TryEnqueue(() =>
|
||||
{
|
||||
CollectionChanged?.Invoke(this, e);
|
||||
});
|
||||
}
|
||||
|
||||
internal void Reset()
|
||||
{
|
||||
_Items.Clear();
|
||||
}
|
||||
}
|
||||
|
||||
// The FilteredListSection is for when we've got any filter at all. It starts by
|
||||
// enumerating all actions and apps, and returns the subset that matches.
|
||||
public sealed class FilteredListSection : ISection, INotifyCollectionChanged
|
||||
{
|
||||
public event NotifyCollectionChangedEventHandler? CollectionChanged;
|
||||
|
||||
public string Title => string.Empty;
|
||||
|
||||
private readonly MainViewModel _mainViewModel;
|
||||
private readonly DispatcherQueue DispatcherQueue = DispatcherQueue.GetForCurrentThread();
|
||||
|
||||
// Top-level list items, from builtin commands and extensions
|
||||
internal ObservableCollection<MainListItem> _Items { get; set; }
|
||||
|
||||
// Apps, from the apps built in command.
|
||||
private IEnumerable<IListItem> _apps => _mainViewModel.apps.GetItems().First().Items;
|
||||
|
||||
// Results from the last searched text
|
||||
private IEnumerable<IListItem>? lastSearchResults;
|
||||
|
||||
// Things we should enumerate over, depending on the search query.
|
||||
// This is either
|
||||
// * the last search results (if there was a query),
|
||||
// * OR one of:
|
||||
// * Just the top-level actions (if there's no query)
|
||||
// * OR the top-level actions AND the apps (if there's a query)
|
||||
private IEnumerable<IListItem> itemsToEnumerate =>
|
||||
lastSearchResults != null ?
|
||||
lastSearchResults :
|
||||
_Items.Concat(_apps);
|
||||
|
||||
internal string lastQuery = string.Empty;
|
||||
|
||||
// Setting this will enumerate all the actions and installed apps.
|
||||
internal string Query
|
||||
{
|
||||
get => lastQuery;
|
||||
set
|
||||
{
|
||||
if (string.IsNullOrEmpty(value) ||
|
||||
!lastQuery.StartsWith(value, true, System.Globalization.CultureInfo.CurrentCulture))
|
||||
{
|
||||
lastSearchResults = null;
|
||||
}
|
||||
|
||||
if (lastSearchResults != null && string.IsNullOrEmpty(value))
|
||||
{
|
||||
// Even with an empty query, we did filter the items (to remove fallbacks without a name
|
||||
// Here, we're going from an empty query to one that has an actual string. Reset the last, so we will _also_ include apps now.
|
||||
this.lastSearchResults = null;
|
||||
}
|
||||
|
||||
lastQuery = value;
|
||||
var results = ListHelpers.FilterList(itemsToEnumerate, Query);
|
||||
this.lastSearchResults = string.IsNullOrEmpty(value) ? null : results;
|
||||
}
|
||||
}
|
||||
|
||||
// Watch out future me!
|
||||
//
|
||||
// Don't do the whole linq query in Items itself. That'll evaluate the whole
|
||||
// query once per item, because the ListPage.xaml.cs will create one
|
||||
// ListViewItems per item in Items, and every time it does that, it calls
|
||||
// section.Items.
|
||||
//
|
||||
// instead run the query once when the action query changes, and store the
|
||||
// results.
|
||||
public IListItem[] Items => itemsToEnumerate.Where(i => i != null).ToArray();
|
||||
|
||||
public FilteredListSection(MainViewModel viewModel)
|
||||
{
|
||||
this._mainViewModel = viewModel;
|
||||
|
||||
// TODO: We should probably just get rid of MainListItem entirely, so I'm leaveing these uncaught
|
||||
_Items = new(_mainViewModel.TopLevelCommands.Where(wrapper => wrapper.Unsafe != null).Select(wrapper => new MainListItem(wrapper.Unsafe!)));
|
||||
_Items.CollectionChanged += Bubble_CollectionChanged;
|
||||
}
|
||||
|
||||
private void Bubble_CollectionChanged(object? sender, NotifyCollectionChangedEventArgs e)
|
||||
{
|
||||
DispatcherQueue.TryEnqueue(() =>
|
||||
{
|
||||
CollectionChanged?.Invoke(this, e);
|
||||
});
|
||||
}
|
||||
|
||||
internal void Reset()
|
||||
{
|
||||
_Items.Clear();
|
||||
lastSearchResults = null;
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class MainListPage : Microsoft.Windows.CommandPalette.Extensions.Helpers.DynamicListPage
|
||||
public sealed class MainListPage : DynamicListPage
|
||||
{
|
||||
private readonly MainViewModel _mainViewModel;
|
||||
private readonly MainListSection _mainSection;
|
||||
private readonly RecentsListSection _recentsListSection;
|
||||
private readonly FilteredListSection _filteredSection;
|
||||
private readonly ISection[] _Sections;
|
||||
private readonly ISection[] _sections;
|
||||
|
||||
public MainListPage(MainViewModel viewModel)
|
||||
{
|
||||
@@ -247,7 +28,7 @@ public sealed class MainListPage : Microsoft.Windows.CommandPalette.Extensions.H
|
||||
|
||||
_mainViewModel.TopLevelCommands.CollectionChanged += TopLevelCommands_CollectionChanged;
|
||||
|
||||
_Sections = [
|
||||
_sections = [
|
||||
_recentsListSection,
|
||||
_mainSection
|
||||
];
|
||||
@@ -259,7 +40,7 @@ public sealed class MainListPage : Microsoft.Windows.CommandPalette.Extensions.H
|
||||
|
||||
public override ISection[] GetItems()
|
||||
{
|
||||
return _Sections;
|
||||
return _sections;
|
||||
}
|
||||
|
||||
public override ISection[] GetItems(string query)
|
||||
@@ -268,7 +49,7 @@ public sealed class MainListPage : Microsoft.Windows.CommandPalette.Extensions.H
|
||||
_mainSection.UpdateQuery(query);
|
||||
if (string.IsNullOrEmpty(query))
|
||||
{
|
||||
return _Sections;
|
||||
return _sections;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -290,7 +71,7 @@ public sealed class MainListPage : Microsoft.Windows.CommandPalette.Extensions.H
|
||||
_mainSection._Items.Add(new MainListItem(listItem.Unsafe));
|
||||
}
|
||||
|
||||
_filteredSection._Items.Add(new MainListItem(listItem.Unsafe));
|
||||
_filteredSection.TopLevelItems.Add(new MainListItem(listItem.Unsafe));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,78 @@
|
||||
// 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.Collections.Specialized;
|
||||
using System.Linq;
|
||||
using CmdPal.Models;
|
||||
using Microsoft.UI.Dispatching;
|
||||
using Microsoft.UI.Xaml;
|
||||
using Microsoft.Windows.CommandPalette.Extensions;
|
||||
using Microsoft.Windows.CommandPalette.Extensions.Helpers;
|
||||
using WindowsCommandPalette.Views;
|
||||
|
||||
namespace DeveloperCommandPalette;
|
||||
|
||||
// The MainListSection is for all non-recent actions. No apps.
|
||||
public sealed class MainListSection : ISection, INotifyCollectionChanged
|
||||
{
|
||||
public event NotifyCollectionChangedEventHandler? CollectionChanged;
|
||||
|
||||
public string Title => "Actions";
|
||||
|
||||
private readonly MainViewModel _mainViewModel;
|
||||
private readonly DispatcherQueue _dispatcherQueue = DispatcherQueue.GetForCurrentThread();
|
||||
|
||||
// Top-level list items, from builtin commands and extensions
|
||||
internal ObservableCollection<MainListItem> _Items { get; set; }
|
||||
|
||||
// Things we should enumerate over, depending on the search query.
|
||||
// This is either
|
||||
// * the last search results (if there was a query),
|
||||
// * OR one of:
|
||||
// * Just the top-level actions (if there's no query)
|
||||
// * OR the top-level actions AND the apps (if there's a query)
|
||||
private IEnumerable<IListItem> itemsToEnumerate =>
|
||||
_Items.Where(i => i != null && (!_mainViewModel.IsRecentCommand(i)));
|
||||
|
||||
// Watch out future me!
|
||||
//
|
||||
// Don't do the whole linq query in Items itself. That'll evaluate the whole
|
||||
// query once per item, because the ListPage.xaml.cs will create one
|
||||
// ListViewItems per item in Items, and every time it does that, it calls
|
||||
// section.Items.
|
||||
//
|
||||
// instead run the query once when the action query changes, and store the
|
||||
// results.
|
||||
public IListItem[] Items => itemsToEnumerate.ToArray();
|
||||
|
||||
public MainListSection(MainViewModel viewModel)
|
||||
{
|
||||
this._mainViewModel = viewModel;
|
||||
_Items = new(_mainViewModel.TopLevelCommands.Select(w => w.Unsafe).Where(li => li != null).Select(li => new MainListItem(li!)));
|
||||
_Items.CollectionChanged += Bubble_CollectionChanged;
|
||||
}
|
||||
|
||||
internal void UpdateQuery(string query)
|
||||
{
|
||||
var fallbacks = _Items.Select(i => i?.FallbackHandler).Where(fb => fb != null).Select(fb => fb!);
|
||||
foreach (var fb in fallbacks)
|
||||
{
|
||||
fb.UpdateQuery(query);
|
||||
}
|
||||
}
|
||||
|
||||
private void Bubble_CollectionChanged(object? sender, NotifyCollectionChangedEventArgs e)
|
||||
{
|
||||
_dispatcherQueue.TryEnqueue(() =>
|
||||
{
|
||||
CollectionChanged?.Invoke(this, e);
|
||||
});
|
||||
}
|
||||
|
||||
internal void Reset()
|
||||
{
|
||||
_Items.Clear();
|
||||
}
|
||||
}
|
||||
@@ -107,9 +107,6 @@
|
||||
<Copy SourceFiles="$(PkgAdaptiveCards_ObjectModel_WinUI3)\runtimes\win10-$(Platform)\native\AdaptiveCards.ObjectModel.WinUI3.dll" DestinationFolder="$(TargetDir)" />
|
||||
<Copy SourceFiles="$(PkgAdaptiveCards_Rendering_WinUI3)\runtimes\win10-$(Platform)\native\AdaptiveCards.Rendering.WinUI3.dll" DestinationFolder="$(TargetDir)" />
|
||||
</Target>
|
||||
<ItemGroup>
|
||||
<PRIResource Remove="Builtins\NewFolder\**" />
|
||||
</ItemGroup>
|
||||
<!-- </AdaptiveCardsWorkaround> -->
|
||||
|
||||
</Project>
|
||||
|
||||
@@ -1,18 +1,10 @@
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
using System.Runtime.InteropServices;
|
||||
using Microsoft.CmdPal.Common.Services;
|
||||
using Microsoft.Windows.CommandPalette.Extensions;
|
||||
using Windows.ApplicationModel;
|
||||
using Windows.ApplicationModel.AppExtensions;
|
||||
using Windows.Win32;
|
||||
using Windows.Win32.System.Com;
|
||||
using WinRT;
|
||||
// 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 CmdPal.Models;
|
||||
|
||||
public class ExtensionObject<T> // where T : IInspectable
|
||||
public class ExtensionObject<T> // where T : IInspectable
|
||||
{
|
||||
private readonly T _value;
|
||||
|
||||
|
||||
@@ -22,7 +22,7 @@ public class ExtensionWrapper : IExtensionWrapper
|
||||
|
||||
private readonly Dictionary<Type, ProviderType> _providerTypeMap = new()
|
||||
{
|
||||
[typeof(ICommandProvider)] = ProviderType.Commands
|
||||
[typeof(ICommandProvider)] = ProviderType.Commands,
|
||||
};
|
||||
|
||||
private IExtension? _extensionObject;
|
||||
|
||||
@@ -0,0 +1,74 @@
|
||||
// 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.Collections.Specialized;
|
||||
using System.Linq;
|
||||
using CmdPal.Models;
|
||||
using Microsoft.UI.Dispatching;
|
||||
using Microsoft.UI.Xaml;
|
||||
using Microsoft.Windows.CommandPalette.Extensions;
|
||||
using Microsoft.Windows.CommandPalette.Extensions.Helpers;
|
||||
using WindowsCommandPalette.Views;
|
||||
|
||||
namespace DeveloperCommandPalette;
|
||||
|
||||
public sealed class RecentsListSection : ListSection, INotifyCollectionChanged
|
||||
{
|
||||
public event NotifyCollectionChangedEventHandler? CollectionChanged;
|
||||
|
||||
private readonly DispatcherQueue _dispatcherQueue = DispatcherQueue.GetForCurrentThread();
|
||||
private readonly MainViewModel _mainViewModel;
|
||||
|
||||
internal ObservableCollection<MainListItem> _Items { get; set; } = [];
|
||||
|
||||
private bool loadedApps;
|
||||
|
||||
public RecentsListSection(MainViewModel viewModel)
|
||||
{
|
||||
this.Title = "Recent";
|
||||
this._mainViewModel = viewModel;
|
||||
|
||||
var recent = _mainViewModel.RecentActions;
|
||||
Reset();
|
||||
_Items.CollectionChanged += Bubble_CollectionChanged;
|
||||
|
||||
_mainViewModel.AppsReady += _mainViewModel_AppsReady;
|
||||
}
|
||||
|
||||
private void _mainViewModel_AppsReady(object sender, object? args)
|
||||
{
|
||||
loadedApps = true;
|
||||
_mainViewModel.AppsReady -= _mainViewModel_AppsReady;
|
||||
AddApps();
|
||||
}
|
||||
|
||||
private void Bubble_CollectionChanged(object? sender, NotifyCollectionChangedEventArgs e)
|
||||
{
|
||||
_dispatcherQueue.TryEnqueue(() =>
|
||||
{
|
||||
CollectionChanged?.Invoke(this, e);
|
||||
});
|
||||
}
|
||||
|
||||
public override IListItem[] Items => _Items.ToArray();
|
||||
|
||||
internal void Reset()
|
||||
{
|
||||
_Items.Clear();
|
||||
if (loadedApps)
|
||||
{
|
||||
AddApps();
|
||||
}
|
||||
}
|
||||
|
||||
internal void AddApps()
|
||||
{
|
||||
var apps = _mainViewModel.Recent;
|
||||
foreach (var app in apps)
|
||||
{
|
||||
_Items.Add(new MainListItem(app.Unsafe)); // we know these are all local
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -16,8 +16,6 @@ namespace Microsoft.Windows.CommandPalette.Services;
|
||||
|
||||
public class ExtensionService : IExtensionService, IDisposable
|
||||
{
|
||||
// private readonly ILogger _log = Log.ForContext("SourceContext", nameof(ExtensionService));
|
||||
|
||||
public event EventHandler OnExtensionsChanged = (_, _) => { };
|
||||
|
||||
private static readonly PackageCatalog _catalog = PackageCatalog.OpenForCurrentUser();
|
||||
|
||||
@@ -2,25 +2,10 @@
|
||||
// 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;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.ComponentModel;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices.WindowsRuntime;
|
||||
using Microsoft.Terminal.UI;
|
||||
using Microsoft.UI.Xaml;
|
||||
using Microsoft.UI.Xaml.Controls;
|
||||
using Microsoft.UI.Xaml.Controls.Primitives;
|
||||
using Microsoft.UI.Xaml.Data;
|
||||
using Microsoft.UI.Xaml.Input;
|
||||
using Microsoft.UI.Xaml.Media;
|
||||
using Microsoft.UI.Xaml.Navigation;
|
||||
using Microsoft.Windows.CommandPalette.Extensions;
|
||||
using Windows.ApplicationModel.AppExtensions;
|
||||
using Windows.Foundation;
|
||||
using Windows.Foundation.Collections;
|
||||
using Windows.UI;
|
||||
|
||||
namespace DeveloperCommandPalette;
|
||||
@@ -46,10 +31,10 @@ public sealed class TagViewModel : INotifyPropertyChanged
|
||||
|
||||
internal Brush BackgroundBrush => new SolidColorBrush(Tag.Color.A == 0 ? Tag.Color : Color.FromArgb((byte)(Tag.Color.A / 4), Tag.Color.R, Tag.Color.G, Tag.Color.B));
|
||||
|
||||
|
||||
public TagViewModel(ITag tag)
|
||||
{
|
||||
this.Tag = tag;
|
||||
|
||||
// this.Tag.PropChanged += Tag_PropertyChanged;
|
||||
}
|
||||
|
||||
|
||||
@@ -3,30 +3,11 @@
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using Microsoft.UI.Xaml.Controls;
|
||||
using Microsoft.Windows.CommandPalette.Extensions;
|
||||
|
||||
// To learn more about WinUI, the WinUI project structure,
|
||||
// and more about our project templates, see: http://aka.ms/winui-project-info.
|
||||
namespace WindowsCommandPalette.Views;
|
||||
|
||||
public sealed class DetailsViewModel
|
||||
{
|
||||
internal string Title { get; init; } = string.Empty;
|
||||
|
||||
internal string Body { get; init; } = string.Empty;
|
||||
|
||||
internal IconDataType HeroImage { get; init; } = new(string.Empty);
|
||||
|
||||
internal IconElement IcoElement => Microsoft.Terminal.UI.IconPathConverter.IconMUX(HeroImage.Icon);
|
||||
|
||||
internal DetailsViewModel(IDetails details)
|
||||
{
|
||||
this.Title = details.Title;
|
||||
this.Body = details.Body;
|
||||
this.HeroImage = details.HeroImage ?? new(string.Empty);
|
||||
}
|
||||
}
|
||||
|
||||
public sealed partial class DetailsControl : UserControl
|
||||
{
|
||||
private readonly DetailsViewModel ViewModel;
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
// 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.UI.Xaml.Controls;
|
||||
using Microsoft.Windows.CommandPalette.Extensions;
|
||||
|
||||
// To learn more about WinUI, the WinUI project structure,
|
||||
// and more about our project templates, see: http://aka.ms/winui-project-info.
|
||||
namespace WindowsCommandPalette.Views;
|
||||
|
||||
public sealed class DetailsViewModel
|
||||
{
|
||||
internal string Title { get; init; } = string.Empty;
|
||||
|
||||
internal string Body { get; init; } = string.Empty;
|
||||
|
||||
internal IconDataType HeroImage { get; init; } = new(string.Empty);
|
||||
|
||||
internal IconElement IcoElement => Microsoft.Terminal.UI.IconPathConverter.IconMUX(HeroImage.Icon);
|
||||
|
||||
internal DetailsViewModel(IDetails details)
|
||||
{
|
||||
this.Title = details.Title;
|
||||
this.Body = details.Body;
|
||||
this.HeroImage = details.HeroImage ?? new(string.Empty);
|
||||
}
|
||||
}
|
||||
@@ -2,162 +2,31 @@
|
||||
// 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;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.ComponentModel;
|
||||
using AdaptiveCards.ObjectModel.WinUI3;
|
||||
using AdaptiveCards.Rendering.WinUI3;
|
||||
using AdaptiveCards.Templating;
|
||||
using DeveloperCommandPalette;
|
||||
using Microsoft.UI.Xaml;
|
||||
using Microsoft.UI.Xaml.Controls;
|
||||
using Microsoft.UI.Xaml.Input;
|
||||
using Microsoft.UI.Xaml.Navigation;
|
||||
using Microsoft.Windows.CommandPalette.Extensions;
|
||||
using Microsoft.Windows.CommandPalette.Extensions.Helpers;
|
||||
using Windows.Foundation;
|
||||
using Windows.System;
|
||||
using Windows.UI.ViewManagement;
|
||||
|
||||
namespace WindowsCommandPalette.Views;
|
||||
|
||||
public sealed class FormViewModel : System.ComponentModel.INotifyPropertyChanged
|
||||
{
|
||||
internal readonly IForm form;
|
||||
internal AdaptiveCardParseResult? card;
|
||||
internal RenderedAdaptiveCard? RenderedAdaptiveCard;
|
||||
internal string TemplateJson = "{}";
|
||||
internal string DataJson = "{}";
|
||||
|
||||
public event TypedEventHandler<object, SubmitFormArgs>? RequestSubmitForm;
|
||||
|
||||
public event PropertyChangedEventHandler? PropertyChanged;
|
||||
|
||||
public bool ShouldDisplay => RenderedAdaptiveCard?.FrameworkElement != null;
|
||||
|
||||
public FrameworkElement? RenderedChildElement => RenderedAdaptiveCard?.FrameworkElement;
|
||||
|
||||
public FormViewModel(IForm form)
|
||||
{
|
||||
this.form = form;
|
||||
}
|
||||
|
||||
internal void InitialRender()
|
||||
{
|
||||
// var t = new Task<bool>(() => {
|
||||
this.TemplateJson = this.form.TemplateJson();
|
||||
try
|
||||
{
|
||||
this.DataJson = this.form.DataJson();
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
this.DataJson = "{}";
|
||||
}
|
||||
|
||||
// return true;
|
||||
// });
|
||||
// t.Start();
|
||||
// await t;
|
||||
AdaptiveCardTemplate template = new(TemplateJson);
|
||||
var cardJson = template.Expand(DataJson);
|
||||
this.card = AdaptiveCard.FromJsonString(cardJson);
|
||||
}
|
||||
|
||||
internal void RenderToXaml(AdaptiveCardRenderer renderer)
|
||||
{
|
||||
if (this.card != null)
|
||||
{
|
||||
RenderedAdaptiveCard = renderer.RenderAdaptiveCard(card.AdaptiveCard);
|
||||
RenderedAdaptiveCard.Action += RenderedAdaptiveCard_Action;
|
||||
|
||||
var handlers = this.PropertyChanged;
|
||||
handlers?.Invoke(this, new PropertyChangedEventArgs(nameof(ShouldDisplay)));
|
||||
handlers?.Invoke(this, new PropertyChangedEventArgs(nameof(RenderedChildElement)));
|
||||
}
|
||||
}
|
||||
|
||||
private async void RenderedAdaptiveCard_Action(RenderedAdaptiveCard sender, AdaptiveActionEventArgs args)
|
||||
{
|
||||
if (args.Action is AdaptiveOpenUrlAction openUrlAction)
|
||||
{
|
||||
await Launcher.LaunchUriAsync(openUrlAction.Url);
|
||||
}
|
||||
else if (args.Action is AdaptiveSubmitAction submitAction)
|
||||
{
|
||||
// Get the data and inputs
|
||||
var data = submitAction.DataJson.Stringify();
|
||||
var inputs = args.Inputs.AsJson().Stringify();
|
||||
_ = data;
|
||||
_ = inputs;
|
||||
// Process them as desired
|
||||
var handlers = RequestSubmitForm;
|
||||
handlers?.Invoke(this, new() { FormData = inputs, Form = form });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class FormPageViewModel : PageViewModel
|
||||
{
|
||||
internal IFormPage Page => (IFormPage)this.pageAction;
|
||||
|
||||
internal ObservableCollection<FormViewModel> Forms = new();
|
||||
|
||||
public FormPageViewModel(IFormPage page)
|
||||
: base(page)
|
||||
{
|
||||
}
|
||||
|
||||
internal async Task InitialRender()
|
||||
{
|
||||
var t = new Task<bool>(() =>
|
||||
{
|
||||
try
|
||||
{
|
||||
var f = this.Page.Forms();
|
||||
foreach (var form in f)
|
||||
{
|
||||
var formVm = new FormViewModel(form);
|
||||
formVm.RequestSubmitForm += RequestSubmitFormBubbler;
|
||||
Forms.Add(formVm);
|
||||
}
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
}
|
||||
|
||||
foreach (var form in this.Forms)
|
||||
{
|
||||
form.InitialRender();
|
||||
}
|
||||
|
||||
return true;
|
||||
});
|
||||
t.Start();
|
||||
await t;
|
||||
}
|
||||
|
||||
private void RequestSubmitFormBubbler(object sender, SubmitFormArgs args)
|
||||
{
|
||||
this.SubmitForm(args.FormData, args.Form);
|
||||
}
|
||||
}
|
||||
|
||||
public sealed partial class FormPage : Page
|
||||
{
|
||||
private FormPageViewModel? ViewModel;
|
||||
private readonly AdaptiveCardRenderer Renderer = new();
|
||||
private FormPageViewModel? ViewModel;
|
||||
|
||||
public FormPage()
|
||||
{
|
||||
this.InitializeComponent();
|
||||
UISettings settings = new UISettings();
|
||||
|
||||
// yep this is the way to check if you're in light theme or dark.
|
||||
// yep it's this dumb
|
||||
var foreground = settings.GetColorValue(UIColorType.Foreground);
|
||||
var lightTheme = foreground.R < 128;
|
||||
Renderer.HostConfig = AdaptiveHostConfig.FromJsonString(lightTheme ? LightHostConfig : DarkHostConfig).HostConfig;
|
||||
|
||||
}
|
||||
|
||||
private void AddCardElement(FormViewModel form)
|
||||
@@ -170,9 +39,15 @@ public sealed partial class FormPage : Page
|
||||
base.OnNavigatedTo(e);
|
||||
|
||||
ViewModel = (FormPageViewModel?)e.Parameter;
|
||||
if (ViewModel == null) return;
|
||||
ViewModel.InitialRender().ContinueWith((t) => {
|
||||
DispatcherQueue.TryEnqueue(() => {
|
||||
if (ViewModel == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
ViewModel.InitialRender().ContinueWith((t) =>
|
||||
{
|
||||
DispatcherQueue.TryEnqueue(() =>
|
||||
{
|
||||
foreach (var form in this.ViewModel.Forms)
|
||||
{
|
||||
AddCardElement(form);
|
||||
@@ -193,7 +68,6 @@ public sealed partial class FormPage : Page
|
||||
ViewModel?.GoBack();
|
||||
}
|
||||
|
||||
|
||||
private static readonly string DarkHostConfig = """
|
||||
{
|
||||
"spacing": {
|
||||
@@ -515,5 +389,4 @@ public sealed partial class FormPage : Page
|
||||
}
|
||||
}
|
||||
""";
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,68 @@
|
||||
// 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;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.ComponentModel;
|
||||
using AdaptiveCards.ObjectModel.WinUI3;
|
||||
using AdaptiveCards.Rendering.WinUI3;
|
||||
using AdaptiveCards.Templating;
|
||||
using DeveloperCommandPalette;
|
||||
using Microsoft.UI.Xaml;
|
||||
using Microsoft.UI.Xaml.Controls;
|
||||
using Microsoft.UI.Xaml.Input;
|
||||
using Microsoft.UI.Xaml.Navigation;
|
||||
using Microsoft.Windows.CommandPalette.Extensions;
|
||||
using Microsoft.Windows.CommandPalette.Extensions.Helpers;
|
||||
using Windows.Foundation;
|
||||
using Windows.System;
|
||||
using Windows.UI.ViewManagement;
|
||||
|
||||
namespace WindowsCommandPalette.Views;
|
||||
|
||||
public sealed class FormPageViewModel : PageViewModel
|
||||
{
|
||||
internal IFormPage Page => (IFormPage)this.pageAction;
|
||||
|
||||
internal ObservableCollection<FormViewModel> Forms = new();
|
||||
|
||||
public FormPageViewModel(IFormPage page)
|
||||
: base(page)
|
||||
{
|
||||
}
|
||||
|
||||
internal async Task InitialRender()
|
||||
{
|
||||
var t = new Task<bool>(() =>
|
||||
{
|
||||
try
|
||||
{
|
||||
var f = this.Page.Forms();
|
||||
foreach (var form in f)
|
||||
{
|
||||
var formVm = new FormViewModel(form);
|
||||
formVm.RequestSubmitForm += RequestSubmitFormBubbler;
|
||||
Forms.Add(formVm);
|
||||
}
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
}
|
||||
|
||||
foreach (var form in this.Forms)
|
||||
{
|
||||
form.InitialRender();
|
||||
}
|
||||
|
||||
return true;
|
||||
});
|
||||
t.Start();
|
||||
await t;
|
||||
}
|
||||
|
||||
private void RequestSubmitFormBubbler(object sender, SubmitFormArgs args)
|
||||
{
|
||||
this.SubmitForm(args.FormData, args.Form);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,92 @@
|
||||
// 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.ComponentModel;
|
||||
using AdaptiveCards.ObjectModel.WinUI3;
|
||||
using AdaptiveCards.Rendering.WinUI3;
|
||||
using AdaptiveCards.Templating;
|
||||
using DeveloperCommandPalette;
|
||||
using Microsoft.UI.Xaml;
|
||||
using Microsoft.Windows.CommandPalette.Extensions;
|
||||
using Windows.Foundation;
|
||||
using Windows.System;
|
||||
|
||||
namespace WindowsCommandPalette.Views;
|
||||
|
||||
public sealed class FormViewModel : System.ComponentModel.INotifyPropertyChanged
|
||||
{
|
||||
internal readonly IForm form;
|
||||
internal AdaptiveCardParseResult? card;
|
||||
internal RenderedAdaptiveCard? RenderedAdaptiveCard;
|
||||
internal string TemplateJson = "{}";
|
||||
internal string DataJson = "{}";
|
||||
|
||||
public event TypedEventHandler<object, SubmitFormArgs>? RequestSubmitForm;
|
||||
|
||||
public event PropertyChangedEventHandler? PropertyChanged;
|
||||
|
||||
public bool ShouldDisplay => RenderedAdaptiveCard?.FrameworkElement != null;
|
||||
|
||||
public FrameworkElement? RenderedChildElement => RenderedAdaptiveCard?.FrameworkElement;
|
||||
|
||||
public FormViewModel(IForm form)
|
||||
{
|
||||
this.form = form;
|
||||
}
|
||||
|
||||
internal void InitialRender()
|
||||
{
|
||||
// var t = new Task<bool>(() => {
|
||||
this.TemplateJson = this.form.TemplateJson();
|
||||
try
|
||||
{
|
||||
this.DataJson = this.form.DataJson();
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
this.DataJson = "{}";
|
||||
}
|
||||
|
||||
// return true;
|
||||
// });
|
||||
// t.Start();
|
||||
// await t;
|
||||
AdaptiveCardTemplate template = new(TemplateJson);
|
||||
var cardJson = template.Expand(DataJson);
|
||||
this.card = AdaptiveCard.FromJsonString(cardJson);
|
||||
}
|
||||
|
||||
internal void RenderToXaml(AdaptiveCardRenderer renderer)
|
||||
{
|
||||
if (this.card != null)
|
||||
{
|
||||
RenderedAdaptiveCard = renderer.RenderAdaptiveCard(card.AdaptiveCard);
|
||||
RenderedAdaptiveCard.Action += RenderedAdaptiveCard_Action;
|
||||
|
||||
var handlers = this.PropertyChanged;
|
||||
handlers?.Invoke(this, new PropertyChangedEventArgs(nameof(ShouldDisplay)));
|
||||
handlers?.Invoke(this, new PropertyChangedEventArgs(nameof(RenderedChildElement)));
|
||||
}
|
||||
}
|
||||
|
||||
private async void RenderedAdaptiveCard_Action(RenderedAdaptiveCard sender, AdaptiveActionEventArgs args)
|
||||
{
|
||||
if (args.Action is AdaptiveOpenUrlAction openUrlAction)
|
||||
{
|
||||
await Launcher.LaunchUriAsync(openUrlAction.Url);
|
||||
}
|
||||
else if (args.Action is AdaptiveSubmitAction submitAction)
|
||||
{
|
||||
// Get the data and inputs
|
||||
var data = submitAction.DataJson.Stringify();
|
||||
var inputs = args.Inputs.AsJson().Stringify();
|
||||
_ = data;
|
||||
_ = inputs;
|
||||
|
||||
// Process them as desired
|
||||
var handlers = RequestSubmitForm;
|
||||
handlers?.Invoke(this, new() { FormData = inputs, Form = form });
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3,18 +3,9 @@
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Collections.Specialized;
|
||||
using System.ComponentModel;
|
||||
using System.Runtime.InteropServices;
|
||||
using DeveloperCommandPalette;
|
||||
using Microsoft.UI.Dispatching;
|
||||
using Microsoft.UI.Input;
|
||||
using Microsoft.UI.Xaml;
|
||||
using Microsoft.UI.Xaml.Controls;
|
||||
using Microsoft.UI.Xaml.Controls.Primitives;
|
||||
using Microsoft.UI.Xaml.Data;
|
||||
using Microsoft.UI.Xaml.Input;
|
||||
using Microsoft.UI.Xaml.Navigation;
|
||||
using Microsoft.Windows.CommandPalette.Extensions;
|
||||
using Microsoft.Windows.CommandPalette.Extensions.Helpers;
|
||||
|
||||
@@ -31,10 +22,11 @@ public sealed class ListPageViewModel : PageViewModel
|
||||
|
||||
private IDynamicListPage? dynamicPage => Page as IDynamicListPage;
|
||||
|
||||
private readonly DispatcherQueue DispatcherQueue = DispatcherQueue.GetForCurrentThread();
|
||||
private readonly DispatcherQueue _dispatcherQueue = DispatcherQueue.GetForCurrentThread();
|
||||
internal string Query = string.Empty;
|
||||
|
||||
public ListPageViewModel(IListPage page) : base(page)
|
||||
public ListPageViewModel(IListPage page)
|
||||
: base(page)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
@@ -2,189 +2,18 @@
|
||||
// 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.Runtime.InteropServices;
|
||||
using System.Runtime.InteropServices.WindowsRuntime;
|
||||
using CmdPal.Models;
|
||||
using DeveloperCommandPalette;
|
||||
using Microsoft.CmdPal.Common.Extensions;
|
||||
using Microsoft.CmdPal.Common.Services;
|
||||
using Microsoft.CmdPal.Ext.Bookmarks;
|
||||
using Microsoft.CmdPal.Ext.Calc;
|
||||
using Microsoft.CmdPal.Ext.Settings;
|
||||
using Microsoft.UI.Xaml;
|
||||
using Microsoft.UI.Xaml.Controls;
|
||||
using Microsoft.UI.Xaml.Input;
|
||||
using Microsoft.UI.Xaml.Media.Animation;
|
||||
using Microsoft.Windows.CommandPalette.Extensions;
|
||||
using Microsoft.Windows.CommandPalette.Extensions.Helpers;
|
||||
using Windows.Foundation;
|
||||
using Windows.Win32;
|
||||
using WindowsCommandPalette.BuiltinCommands;
|
||||
using WindowsCommandPalette.BuiltinCommands.AllApps;
|
||||
|
||||
namespace WindowsCommandPalette.Views;
|
||||
|
||||
public sealed class MainViewModel
|
||||
{
|
||||
internal readonly AllAppsPage apps = new();
|
||||
internal readonly QuitActionProvider quitActionProvider = new();
|
||||
internal readonly ReloadExtensionsActionProvider reloadActionProvider = new();
|
||||
|
||||
public event TypedEventHandler<object, object?>? QuitRequested { add => quitActionProvider.QuitRequested += value; remove => quitActionProvider.QuitRequested -= value; }
|
||||
|
||||
internal readonly ObservableCollection<ActionsProviderWrapper> CommandsProviders = new();
|
||||
internal readonly ObservableCollection<ExtensionObject<IListItem>> TopLevelCommands = [];
|
||||
|
||||
internal readonly List<ICommandProvider> _builtInCommands = [];
|
||||
|
||||
internal bool Loaded;
|
||||
internal bool LoadingExtensions;
|
||||
internal bool LoadedApps;
|
||||
|
||||
public event TypedEventHandler<object, object?>? HideRequested;
|
||||
|
||||
public event TypedEventHandler<object, object?>? SummonRequested;
|
||||
|
||||
public event TypedEventHandler<object, object?>? AppsReady;
|
||||
|
||||
internal MainViewModel()
|
||||
{
|
||||
_builtInCommands.Add(new BookmarksActionProvider());
|
||||
_builtInCommands.Add(new CalculatorActionProvider());
|
||||
_builtInCommands.Add(new SettingsActionProvider());
|
||||
_builtInCommands.Add(quitActionProvider);
|
||||
_builtInCommands.Add(reloadActionProvider);
|
||||
|
||||
ResetTopLevel();
|
||||
|
||||
// On a background thread, warm up the app cache since we want it more often than not
|
||||
new Task(() =>
|
||||
{
|
||||
var _ = AppCache.Instance.Value;
|
||||
LoadedApps = true;
|
||||
AppsReady?.Invoke(this, null);
|
||||
}).Start();
|
||||
}
|
||||
|
||||
public void ResetTopLevel()
|
||||
{
|
||||
TopLevelCommands.Clear();
|
||||
TopLevelCommands.Add(new(new ListItem(apps)));
|
||||
}
|
||||
|
||||
internal void RequestHide()
|
||||
{
|
||||
var handlers = HideRequested;
|
||||
handlers?.Invoke(this, null);
|
||||
}
|
||||
|
||||
public void Summon()
|
||||
{
|
||||
var handlers = SummonRequested;
|
||||
handlers?.Invoke(this, null);
|
||||
}
|
||||
|
||||
private static string CreateHash(string? title, string? subtitle)
|
||||
{
|
||||
return title + subtitle;
|
||||
}
|
||||
|
||||
private string[] _recentCommandHashes = [];
|
||||
|
||||
public IEnumerable<IListItem> RecentActions => TopLevelCommands
|
||||
.Select(i => i.Unsafe)
|
||||
.Where((i) =>
|
||||
{
|
||||
if (i != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
return _recentCommandHashes.Contains(CreateHash(i.Title, i.Subtitle));
|
||||
}
|
||||
catch (COMException)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}).Select(i => i!);
|
||||
|
||||
public IEnumerable<IListItem> AppItems => LoadedApps ? apps.GetItems().First().Items : [];
|
||||
|
||||
public IEnumerable<ExtensionObject<IListItem>> Everything => TopLevelCommands
|
||||
.Concat(AppItems.Select(i => new ExtensionObject<IListItem>(i)))
|
||||
.Where(i =>
|
||||
{
|
||||
var v = i != null;
|
||||
return v;
|
||||
});
|
||||
|
||||
public IEnumerable<ExtensionObject<IListItem>> Recent => _recentCommandHashes
|
||||
.Select(hash =>
|
||||
Everything
|
||||
.Where(i =>
|
||||
{
|
||||
try
|
||||
{
|
||||
var o = i.Unsafe;
|
||||
return CreateHash(o.Title, o.Subtitle) == hash;
|
||||
}
|
||||
catch (COMException)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
})
|
||||
.FirstOrDefault())
|
||||
.Where(i => i != null)
|
||||
.Select(i => i!);
|
||||
|
||||
public bool IsRecentCommand(MainListItem item)
|
||||
{
|
||||
try
|
||||
{
|
||||
foreach (var wraprer in Recent)
|
||||
{
|
||||
if (wraprer.Unsafe == item)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (COMException)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
internal void PushRecentAction(ICommand action)
|
||||
{
|
||||
foreach (var wrapped in Everything)
|
||||
{
|
||||
try
|
||||
{
|
||||
var listItem = wrapped?.Unsafe;
|
||||
if (listItem != null && listItem.Command == action)
|
||||
{
|
||||
// Found it, awesome.
|
||||
var hash = CreateHash(listItem.Title, listItem.Subtitle);
|
||||
|
||||
// Remove the old one and push the new one to the front
|
||||
var recent = new List<string>([hash]).Concat(_recentCommandHashes.Where(h => h != hash)).Take(5).ToArray();
|
||||
_recentCommandHashes = recent.ToArray();
|
||||
return;
|
||||
}
|
||||
}
|
||||
catch (COMException)
|
||||
{ /* log something */
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// An empty page that can be used on its own or navigated to within a Frame.
|
||||
/// </summary>
|
||||
|
||||
@@ -0,0 +1,186 @@
|
||||
// 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.Runtime.InteropServices;
|
||||
using System.Runtime.InteropServices.WindowsRuntime;
|
||||
using CmdPal.Models;
|
||||
using DeveloperCommandPalette;
|
||||
using Microsoft.CmdPal.Common.Extensions;
|
||||
using Microsoft.CmdPal.Common.Services;
|
||||
using Microsoft.CmdPal.Ext.Bookmarks;
|
||||
using Microsoft.CmdPal.Ext.Calc;
|
||||
using Microsoft.CmdPal.Ext.Settings;
|
||||
using Microsoft.UI.Xaml;
|
||||
using Microsoft.UI.Xaml.Controls;
|
||||
using Microsoft.UI.Xaml.Input;
|
||||
using Microsoft.UI.Xaml.Media.Animation;
|
||||
using Microsoft.Windows.CommandPalette.Extensions;
|
||||
using Microsoft.Windows.CommandPalette.Extensions.Helpers;
|
||||
using Windows.Foundation;
|
||||
using Windows.Win32;
|
||||
using WindowsCommandPalette.BuiltinCommands;
|
||||
using WindowsCommandPalette.BuiltinCommands.AllApps;
|
||||
|
||||
namespace WindowsCommandPalette.Views;
|
||||
|
||||
public sealed class MainViewModel
|
||||
{
|
||||
internal readonly AllAppsPage apps = new();
|
||||
internal readonly QuitActionProvider quitActionProvider = new();
|
||||
internal readonly ReloadExtensionsActionProvider reloadActionProvider = new();
|
||||
|
||||
public event TypedEventHandler<object, object?>? QuitRequested { add => quitActionProvider.QuitRequested += value; remove => quitActionProvider.QuitRequested -= value; }
|
||||
|
||||
internal readonly ObservableCollection<ActionsProviderWrapper> CommandsProviders = new();
|
||||
internal readonly ObservableCollection<ExtensionObject<IListItem>> TopLevelCommands = [];
|
||||
|
||||
internal readonly List<ICommandProvider> _builtInCommands = [];
|
||||
|
||||
internal bool Loaded;
|
||||
internal bool LoadingExtensions;
|
||||
internal bool LoadedApps;
|
||||
|
||||
public event TypedEventHandler<object, object?>? HideRequested;
|
||||
|
||||
public event TypedEventHandler<object, object?>? SummonRequested;
|
||||
|
||||
public event TypedEventHandler<object, object?>? AppsReady;
|
||||
|
||||
internal MainViewModel()
|
||||
{
|
||||
_builtInCommands.Add(new BookmarksActionProvider());
|
||||
_builtInCommands.Add(new CalculatorActionProvider());
|
||||
_builtInCommands.Add(new SettingsActionProvider());
|
||||
_builtInCommands.Add(quitActionProvider);
|
||||
_builtInCommands.Add(reloadActionProvider);
|
||||
|
||||
ResetTopLevel();
|
||||
|
||||
// On a background thread, warm up the app cache since we want it more often than not
|
||||
new Task(() =>
|
||||
{
|
||||
var _ = AppCache.Instance.Value;
|
||||
LoadedApps = true;
|
||||
AppsReady?.Invoke(this, null);
|
||||
}).Start();
|
||||
}
|
||||
|
||||
public void ResetTopLevel()
|
||||
{
|
||||
TopLevelCommands.Clear();
|
||||
TopLevelCommands.Add(new(new ListItem(apps)));
|
||||
}
|
||||
|
||||
internal void RequestHide()
|
||||
{
|
||||
var handlers = HideRequested;
|
||||
handlers?.Invoke(this, null);
|
||||
}
|
||||
|
||||
public void Summon()
|
||||
{
|
||||
var handlers = SummonRequested;
|
||||
handlers?.Invoke(this, null);
|
||||
}
|
||||
|
||||
private static string CreateHash(string? title, string? subtitle)
|
||||
{
|
||||
return title + subtitle;
|
||||
}
|
||||
|
||||
private string[] _recentCommandHashes = [];
|
||||
|
||||
public IEnumerable<IListItem> RecentActions => TopLevelCommands
|
||||
.Select(i => i.Unsafe)
|
||||
.Where((i) =>
|
||||
{
|
||||
if (i != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
return _recentCommandHashes.Contains(CreateHash(i.Title, i.Subtitle));
|
||||
}
|
||||
catch (COMException)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}).Select(i => i!);
|
||||
|
||||
public IEnumerable<IListItem> AppItems => LoadedApps ? apps.GetItems().First().Items : [];
|
||||
|
||||
public IEnumerable<ExtensionObject<IListItem>> Everything => TopLevelCommands
|
||||
.Concat(AppItems.Select(i => new ExtensionObject<IListItem>(i)))
|
||||
.Where(i =>
|
||||
{
|
||||
var v = i != null;
|
||||
return v;
|
||||
});
|
||||
|
||||
public IEnumerable<ExtensionObject<IListItem>> Recent => _recentCommandHashes
|
||||
.Select(hash =>
|
||||
Everything
|
||||
.Where(i =>
|
||||
{
|
||||
try
|
||||
{
|
||||
var o = i.Unsafe;
|
||||
return CreateHash(o.Title, o.Subtitle) == hash;
|
||||
}
|
||||
catch (COMException)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
})
|
||||
.FirstOrDefault())
|
||||
.Where(i => i != null)
|
||||
.Select(i => i!);
|
||||
|
||||
public bool IsRecentCommand(MainListItem item)
|
||||
{
|
||||
try
|
||||
{
|
||||
foreach (var wraprer in Recent)
|
||||
{
|
||||
if (wraprer.Unsafe == item)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (COMException)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
internal void PushRecentAction(ICommand action)
|
||||
{
|
||||
foreach (var wrapped in Everything)
|
||||
{
|
||||
try
|
||||
{
|
||||
var listItem = wrapped?.Unsafe;
|
||||
if (listItem != null && listItem.Command == action)
|
||||
{
|
||||
// Found it, awesome.
|
||||
var hash = CreateHash(listItem.Title, listItem.Subtitle);
|
||||
|
||||
// Remove the old one and push the new one to the front
|
||||
var recent = new List<string>([hash]).Concat(_recentCommandHashes.Where(h => h != hash)).Take(5).ToArray();
|
||||
_recentCommandHashes = recent.ToArray();
|
||||
return;
|
||||
}
|
||||
}
|
||||
catch (COMException)
|
||||
{ /* log something */
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -14,36 +14,7 @@ using Microsoft.Windows.CommandPalette.Extensions;
|
||||
|
||||
namespace WindowsCommandPalette.Views;
|
||||
|
||||
public sealed class MarkdownPageViewModel : PageViewModel
|
||||
{
|
||||
internal IMarkdownPage Page => (IMarkdownPage)this.pageAction;
|
||||
|
||||
internal string[] MarkdownContent = [string.Empty];
|
||||
|
||||
internal string Title => Page.Title;
|
||||
|
||||
private IEnumerable<ICommandContextItem> contextActions => Page.Commands.Where(i => i is ICommandContextItem).Select(i => (ICommandContextItem)i);
|
||||
|
||||
internal bool HasMoreCommands => contextActions.Any();
|
||||
|
||||
internal IList<ContextItemViewModel> ContextActions => contextActions.Select(a => new ContextItemViewModel(a)).ToList();
|
||||
|
||||
public MarkdownPageViewModel(IMarkdownPage page)
|
||||
: base(page)
|
||||
{
|
||||
}
|
||||
|
||||
internal async Task InitialRender(MarkdownPage markdownPage)
|
||||
{
|
||||
var t = new Task<string[]>(() => {
|
||||
return this.Page.Bodies();
|
||||
});
|
||||
t.Start();
|
||||
this.MarkdownContent = await t;
|
||||
}
|
||||
}
|
||||
|
||||
public sealed partial class MarkdownPage : Page, System.ComponentModel.INotifyPropertyChanged
|
||||
public sealed partial class MarkdownPage : Page, INotifyPropertyChanged
|
||||
{
|
||||
private MarkdownPageViewModel? ViewModel;
|
||||
|
||||
@@ -66,7 +37,8 @@ public sealed partial class MarkdownPage : Page, System.ComponentModel.INotifyPr
|
||||
return;
|
||||
}
|
||||
|
||||
ViewModel.InitialRender(this).ContinueWith((t) => {
|
||||
ViewModel.InitialRender(this).ContinueWith((t) =>
|
||||
{
|
||||
DispatcherQueue.TryEnqueue(() =>
|
||||
{
|
||||
if (ViewModel.MarkdownContent.Length > 0)
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
// 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 DeveloperCommandPalette;
|
||||
using Microsoft.Windows.CommandPalette.Extensions;
|
||||
|
||||
namespace WindowsCommandPalette.Views;
|
||||
|
||||
public sealed class MarkdownPageViewModel : PageViewModel
|
||||
{
|
||||
internal IMarkdownPage Page => (IMarkdownPage)this.pageAction;
|
||||
|
||||
internal string[] MarkdownContent = [string.Empty];
|
||||
|
||||
internal string Title => Page.Title;
|
||||
|
||||
private IEnumerable<ICommandContextItem> contextActions => Page.Commands.Where(i => i is ICommandContextItem).Select(i => (ICommandContextItem)i);
|
||||
|
||||
internal bool HasMoreCommands => contextActions.Any();
|
||||
|
||||
internal IList<ContextItemViewModel> ContextActions => contextActions.Select(a => new ContextItemViewModel(a)).ToList();
|
||||
|
||||
public MarkdownPageViewModel(IMarkdownPage page)
|
||||
: base(page)
|
||||
{
|
||||
}
|
||||
|
||||
internal async Task InitialRender(MarkdownPage markdownPage)
|
||||
{
|
||||
var t = new Task<string[]>(() => {
|
||||
return this.Page.Bodies();
|
||||
});
|
||||
t.Start();
|
||||
this.MarkdownContent = await t;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user