Merge pull request #36 from zadjii-msft/dev/crutkas/moreBaseCleanup

Dev/crutkas/more base cleanup
This commit is contained in:
Clint Rutkas
2024-09-04 17:06:52 -07:00
committed by GitHub
23 changed files with 419 additions and 305 deletions

View File

@@ -23,7 +23,7 @@ internal sealed class AppListItem : ListItem
{
// Win32 exe or other non UWP app
this._MoreCommands = [
new CommandContextItem(new OpenPathAction(app.DirPath) { Name = "Open location", Icon=new("\ue838") })
new CommandContextItem(new OpenPathAction(app.DirPath) { Name = "Open location", Icon = new("\ue838") })
];
}
else

View File

@@ -2,11 +2,8 @@
// 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;
using System.Runtime.InteropServices;
//using System.Runtime.InteropServices.ComTypes;
using Windows.Win32.System.Com;
// using Wox.Plugin.Common.Win32;
namespace AllApps.Programs;
@@ -36,11 +33,12 @@ public static class AppxPackageHelper
public static T CheckHRAndReturnOrThrow<T>(int hr, T result)
{
if (hr != 0) // HRESULT.S_OK)
// HRESULT.S_OK
if (hr != 0)
{
Marshal.ThrowExceptionForHR((int)hr);
}
return result;
}
}
}

View File

@@ -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 System.Runtime.InteropServices.ComTypes;
using Windows.Win32.System.Com;
namespace AllApps.Programs;
@@ -14,8 +12,8 @@ namespace AllApps.Programs;
public interface IAppxFactory
{
[System.Diagnostics.CodeAnalysis.SuppressMessage("StyleCop.CSharp.NamingRules", "SA1300:Element should begin with upper-case letter", Justification = "Implements COM Interface")]
[System.Diagnostics.CodeAnalysis.SuppressMessage("Style", "IDE1006:Naming Styles", Justification = "<Pending>")]
[System.Diagnostics.CodeAnalysis.SuppressMessage("Naming", "CA1707:Identifiers should not contain underscores", Justification = "<Pending>")]
[System.Diagnostics.CodeAnalysis.SuppressMessage("Style", "IDE1006:Naming Styles", Justification = "Forced by system")]
[System.Diagnostics.CodeAnalysis.SuppressMessage("Naming", "CA1707:Identifiers should not contain underscores", Justification = "Forced by system")]
void _VtblGap0_2(); // skip 2 methods
internal IAppxManifestReader CreateManifestReader(IStream inputStream);

View File

@@ -2,17 +2,12 @@
// 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;
// using Wox.Plugin;
namespace AllApps.Programs;
public interface IProgram
{
//List<ContextMenuResult> ContextMenus(string queryArguments, IPublicAPI api);
//Result Result(string query, string queryArguments, IPublicAPI api);
// List<ContextMenuResult> ContextMenus(string queryArguments, IPublicAPI api);
// Result Result(string query, string queryArguments, IPublicAPI api);
string UniqueIdentifier { get; set; }
string Name { get; }

View File

@@ -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;
using System.Runtime.InteropServices;
using System.Runtime.InteropServices.ComTypes;
using System.Text;
//using Accessibility;
//using Wox.Plugin.Logger;
namespace WindowsCommandPalette.BuiltinCommands.AllApps;
@@ -142,7 +139,7 @@ public class ShellLinkHelper : IShellLinkHelper
}
catch (System.IO.FileNotFoundException)
{
//Log.Exception("Path could not be retrieved", ex, GetType(), path);
// Log.Exception("Path could not be retrieved", ex, GetType(), path);
return string.Empty;
}
@@ -167,7 +164,7 @@ public class ShellLinkHelper : IShellLinkHelper
}
catch (System.Exception )
{
//Log.Exception($"Failed to fetch description for {target}, {e.Message}", e, GetType());
// Log.Exception($"Failed to fetch description for {target}, {e.Message}", e, GetType());
Description = string.Empty;
}

View File

@@ -62,7 +62,8 @@ public partial class UWP
uint access = 0; // STGM.READ
var hResult = PInvoke.SHCreateStreamOnFileEx(path, access, noAttribute, false, null, out IStream stream);
if (hResult == 0) // S_OK
// S_OK
if (hResult == 0)
{
Apps = AppxPackageHelper.GetAppsFromManifest(stream).Select(appInManifest => new UWPApplication(appInManifest, this)).Where(a =>
{

View File

@@ -178,7 +178,9 @@ public class UWPApplication : IProgram
{
var sourceFallback = $"@{{{packageFullName}? {parsedFallback}}}";
hResult = Native.SHLoadIndirectString(sourceFallback, outBuffer, outBuffer.Capacity, IntPtr.Zero);
if (hResult == 0) // HRESULT.S_OK
// HRESULT.S_OK
if (hResult == 0)
{
var loaded = outBuffer.ToString();
if (!string.IsNullOrEmpty(loaded))

View File

@@ -14,7 +14,7 @@ namespace DeveloperCommandPalette;
public sealed class ListItemViewModel : INotifyPropertyChanged, IDisposable
{
private readonly DispatcherQueue DispatcherQueue;
private readonly DispatcherQueue _dispatcherQueue;
internal ExtensionObject<IListItem> ListItem { get; init; }
@@ -49,7 +49,7 @@ public sealed class ListItemViewModel : INotifyPropertyChanged, IDisposable
internal IconElement IcoElement => Microsoft.Terminal.UI.IconPathConverter.IconMUX(Icon);
private IEnumerable<ICommandContextItem> contextActions
private IEnumerable<ICommandContextItem> AllCommands
{
get
{
@@ -68,7 +68,7 @@ public sealed class ListItemViewModel : INotifyPropertyChanged, IDisposable
}
}
internal bool HasMoreCommands => contextActions.Any();
internal bool HasMoreCommands => AllCommands.Any();
internal TagViewModel[] Tags = [];
@@ -80,9 +80,14 @@ public sealed class ListItemViewModel : INotifyPropertyChanged, IDisposable
{
try
{
var l = contextActions.Select(a => new ContextItemViewModel(a)).ToList();
var l = AllCommands.Select(a => new ContextItemViewModel(a)).ToList();
var def = DefaultAction;
if (def!=null) l.Insert(0, new(def));
if (def != null)
{
l.Insert(0, new(def));
}
return l;
}
catch (COMException)
@@ -100,12 +105,14 @@ public sealed class ListItemViewModel : INotifyPropertyChanged, IDisposable
this.Title = model.Title;
this.Subtitle = model.Subtitle;
this.Icon = model.Command.Icon.Icon;
if (model.Tags != null)
{
this.Tags = model.Tags.Select(t => new TagViewModel(t)).ToArray();
}
this._Details = new(() => {
this._Details = new(() =>
{
try
{
var item = this.ListItem.Unsafe;
@@ -118,7 +125,7 @@ public sealed class ListItemViewModel : INotifyPropertyChanged, IDisposable
}
});
this.DispatcherQueue = DispatcherQueue.GetForCurrentThread();
this._dispatcherQueue = DispatcherQueue.GetForCurrentThread();
}
private void ListItem_PropertyChanged(object sender, Microsoft.Windows.CommandPalette.Extensions.PropChangedEventArgs args)
@@ -155,13 +162,13 @@ public sealed class ListItemViewModel : INotifyPropertyChanged, IDisposable
private void BubbleXamlPropertyChanged(string propertyName)
{
if (this.DispatcherQueue == null)
if (this._dispatcherQueue == null)
{
// this is highly unusual
return;
}
this.DispatcherQueue.TryEnqueue(DispatcherQueuePriority.Normal, () =>
this._dispatcherQueue.TryEnqueue(DispatcherQueuePriority.Normal, () =>
{
this.PropertyChanged?.Invoke(this, new(propertyName));
});
@@ -169,9 +176,12 @@ public sealed class ListItemViewModel : INotifyPropertyChanged, IDisposable
public void Dispose()
{
try{
try
{
this.ListItem.Unsafe.PropChanged -= ListItem_PropertyChanged;
} catch (COMException) {
}
catch (COMException)
{
/* log something */
}
}

View File

@@ -300,7 +300,7 @@ public sealed class MainListPage : Microsoft.Windows.CommandPalette.Extensions.H
{
if (item is ExtensionObject<IListItem> listItem)
{
foreach (var mainListItem in _mainSection._Items) // MainListItem
foreach (var mainListItem in _mainSection._Items)
{
if (mainListItem.Item == listItem)
{

View File

@@ -63,7 +63,8 @@ public sealed partial class MainWindow : Window
{
Windows.Win32.PInvoke.ShowWindow(hwnd, Windows.Win32.UI.WindowsAndMessaging.SHOW_WINDOW_CMD.SW_SHOW);
Windows.Win32.PInvoke.SetForegroundWindow(hwnd);
//Windows.Win32.PInvoke.SetFocus(hwnd);
// Windows.Win32.PInvoke.SetFocus(hwnd);
Windows.Win32.PInvoke.SetActiveWindow(hwnd);
MainPage.ViewModel.Summon();
}
@@ -73,8 +74,7 @@ public sealed partial class MainWindow : Window
this.InitializeComponent();
this._mainViewModel = MainPage.ViewModel;
hwnd = new Windows.Win32.Foundation.HWND(WinRT.Interop.WindowNative.GetWindowHandle(this).ToInt32());
hwnd = new Windows.Win32.Foundation.HWND(WinRT.Interop.WindowNative.GetWindowHandle(this).ToInt32());
_ = SetupHotkey();
@@ -86,6 +86,7 @@ public sealed partial class MainWindow : Window
AppTitleBar.SizeChanged += AppTitleBar_SizeChanged;
ExtendsContentIntoTitleBar = true;
// Hide our titlebar. We'll make the sides draggable later
m_AppWindow.TitleBar.PreferredHeightOption = TitleBarHeightOption.Collapsed;
AppTitleTextBlock.Text = AppInfo.Current.DisplayInfo.DisplayName;
@@ -94,13 +95,14 @@ public sealed partial class MainWindow : Window
Application.Current.GetService<ILocalSettingsService>().SaveSettingAsync("ThisIsAVeryBizarreString", true);
//PositionForStartMenu();
// PositionForStartMenu();
PositionCentered();
_mainViewModel.HideRequested += _mainViewModel_HideRequested;
_mainViewModel.HideRequested += MainViewModel_HideRequested;
_mainViewModel.QuitRequested += (s, e) =>
{
this.Close();
// Application.Current.Exit();
};
}
@@ -150,6 +152,7 @@ public sealed partial class MainWindow : Window
{
onLeft = i > 0;
}
if (!onLeft)
{
o = key.GetValue("TaskbarAl");
@@ -184,7 +187,7 @@ public sealed partial class MainWindow : Window
}
}
private void _mainViewModel_HideRequested(object sender, object? args)
private void MainViewModel_HideRequested(object sender, object? args)
{
Windows.Win32.PInvoke.ShowWindow(hwnd, Windows.Win32.UI.WindowsAndMessaging.SHOW_WINDOW_CMD.SW_HIDE);
}
@@ -210,7 +213,6 @@ public sealed partial class MainWindow : Window
private void SetRegionsForCustomTitleBar()
{
// Specify the interactive regions of the title bar.
var scaleAdjustment = AppTitleBar.XamlRoot.RasterizationScale;
RightPaddingColumn.Width = new GridLength(m_AppWindow.TitleBar.RightInset / scaleAdjustment);
@@ -218,12 +220,14 @@ public sealed partial class MainWindow : Window
//// Get the rectangle around the content
GeneralTransform transform = MainPage.TransformToVisual(null);
Rect bounds = transform.TransformBounds(new Rect(0, 0,
MainPage.ActualWidth,
MainPage.ActualHeight));
Windows.Graphics.RectInt32 contentRect = GetRect(bounds, scaleAdjustment);
Rect bounds = transform.TransformBounds(new Rect(
0,
0,
MainPage.ActualWidth,
MainPage.ActualHeight));
var contentRect = GetRect(bounds, scaleAdjustment);
var rectArray = new Windows.Graphics.RectInt32[] { contentRect };
var rectArray = new RectInt32[] { contentRect };
InputNonClientPointerSource nonClientInputSrc =
InputNonClientPointerSource.GetForWindowId(this.AppWindow.Id);
@@ -232,23 +236,24 @@ public sealed partial class MainWindow : Window
// Add four drag-able regions, around the sides of our content
var w = ContentGrid.ActualWidth;
var h = ContentGrid.ActualHeight;
var dragSides = new Windows.Graphics.RectInt32[] {
var dragSides = new RectInt32[]
{
GetRect(new Rect(0, 0, w, 24), scaleAdjustment),
GetRect(new Rect(0, h-24, ContentGrid.ActualWidth, 24), scaleAdjustment),
GetRect(new Rect(0, h - 24, ContentGrid.ActualWidth, 24), scaleAdjustment),
GetRect(new Rect(0, 0, 24, h), scaleAdjustment),
GetRect(new Rect(w-24, 0, 24, h), scaleAdjustment),
GetRect(new Rect(w - 24, 0, 24, h), scaleAdjustment),
};
nonClientInputSrc.SetRegionRects(NonClientRegionKind.Caption, dragSides);
}
private static Windows.Graphics.RectInt32 GetRect(Rect bounds, double scale)
private static RectInt32 GetRect(Rect bounds, double scale)
{
return new Windows.Graphics.RectInt32(
return new RectInt32(
_X: (int)Math.Round(bounds.X * scale),
_Y: (int)Math.Round(bounds.Y * scale),
_Width: (int)Math.Round(bounds.Width * scale),
_Height: (int)Math.Round(bounds.Height * scale)
);
_Height: (int)Math.Round(bounds.Height * scale));
}
private void MainWindow_Activated(object sender, WindowActivatedEventArgs args)
@@ -276,7 +281,6 @@ public sealed partial class MainWindow : Window
}
}
private static string KeybindingToString(VirtualKey key, VirtualKeyModifiers modifiers)
{
var keyString = key.ToString();
@@ -294,14 +298,17 @@ public sealed partial class MainWindow : Window
{
modifierString += "ctrl+";
}
if (modifiers.HasFlag(VirtualKeyModifiers.Shift))
{
modifierString += "shift+";
}
if (modifiers.HasFlag(VirtualKeyModifiers.Menu))
{
modifierString += "alt+";
}
if (modifiers.HasFlag(VirtualKeyModifiers.Windows))
{
modifierString += "win+";
@@ -351,14 +358,17 @@ public sealed partial class MainWindow : Window
{
mod |= Windows.Win32.UI.Input.KeyboardAndMouse.HOT_KEY_MODIFIERS.MOD_CONTROL;
}
if (modifiers.HasFlag(VirtualKeyModifiers.Shift))
{
mod |= Windows.Win32.UI.Input.KeyboardAndMouse.HOT_KEY_MODIFIERS.MOD_SHIFT;
}
if (modifiers.HasFlag(VirtualKeyModifiers.Menu))
{
mod |= Windows.Win32.UI.Input.KeyboardAndMouse.HOT_KEY_MODIFIERS.MOD_ALT;
}
if (modifiers.HasFlag(VirtualKeyModifiers.Windows))
{
mod |= Windows.Win32.UI.Input.KeyboardAndMouse.HOT_KEY_MODIFIERS.MOD_WIN;
@@ -370,11 +380,11 @@ public sealed partial class MainWindow : Window
private void MainWindow_Closed(object sender, WindowEventArgs args)
{
Application.Current.GetService<IExtensionService>().SignalStopExtensionsAsync();
// Log.Information("Terminating via MainWindow_Closed.");
// WinUI bug is causing a crash on shutdown when FailFastOnErrors is set to true (#51773592).
// Workaround by turning it off before shutdown.
App.Current.DebugSettings.FailFastOnErrors = false;
}
}

View File

@@ -11,12 +11,6 @@
<Nullable>enable</Nullable>
<TreatWarningsAsErrors>False</TreatWarningsAsErrors>
</PropertyGroup>
<ItemGroup>
<Compile Remove="Builtins\NewFolder\**" />
<EmbeddedResource Remove="Builtins\NewFolder\**" />
<None Remove="Builtins\NewFolder\**" />
<Page Remove="Builtins\NewFolder\**" />
</ItemGroup>
<ItemGroup>
<Content Include="Assets\SplashScreen.scale-200.png" />

View File

@@ -1,4 +1,4 @@
// Copyright (c) Microsoft Corporation.
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
using System.Runtime.InteropServices;

View File

@@ -7,13 +7,6 @@ using Windows.Foundation;
namespace DeveloperCommandPalette;
public class SubmitFormArgs
{
public required string FormData { get; set; }
public required IForm Form { get; set; }
}
public class PageViewModel
{
private bool nested;
@@ -22,7 +15,7 @@ public class PageViewModel
protected IPage pageAction { get; }
//public IPage PageAction { get => pageAction; set => pageAction = value; }
// public IPage PageAction { get => pageAction; set => pageAction = value; }
public ActionViewModel Command { get; }
public event TypedEventHandler<object, ActionViewModel>? RequestDoAction;

View File

@@ -18,8 +18,8 @@ sealed class Program
private static App? app;
// LOAD BEARING
//
// Main cannot be async. If it is, then the clipboard won't work, and neither will narrator.
//
// Main cannot be async. If it is, then the clipboard won't work, and neither will narrator.
[STAThread]
static int Main(string[] args)
{
@@ -27,7 +27,8 @@ sealed class Program
var isRedirect = DecideRedirection();
if (!isRedirect)
{
global::Microsoft.UI.Xaml.Application.Start((p) => {
global::Microsoft.UI.Xaml.Application.Start((p) =>
{
var context = new global::Microsoft.UI.Dispatching.DispatcherQueueSynchronizationContext(global::Microsoft.UI.Dispatching.DispatcherQueue.GetForCurrentThread());
global::System.Threading.SynchronizationContext.SetSynchronizationContext(context);
app = new App();

View File

@@ -207,7 +207,7 @@ public class ExtensionService : IExtensionService, IDisposable
_enabledExtensions.Add(extensionWrapper);
}
//TelemetryFactory.Get<ITelemetry>().Log(
// TelemetryFactory.Get<ITelemetry>().Log(
// "Extension_ReportInstalled",
// LogLevel.Critical,
// new ReportInstalledExtensionEvent(extensionUniqueId, isEnabled: !isExtensionDisabled));
@@ -347,6 +347,7 @@ public class ExtensionService : IExtensionService, IDisposable
_enabledExtensions.Remove(extension.First());
}
/*
///// <inheritdoc cref="IExtensionService.DisableExtensionIfWindowsFeatureNotAvailable(IExtensionWrapper)"/>
//public async Task<bool> DisableExtensionIfWindowsFeatureNotAvailable(IExtensionWrapper extension)
//{
@@ -362,5 +363,5 @@ public class ExtensionService : IExtensionService, IDisposable
// // Update the local settings so the next time the user launches Dev Home the extension will be disabled.
// await _localSettingsService.SaveSettingAsync(extension.ExtensionUniqueId + "-ExtensionDisabled", true);
// return true;
//}
//} */
}

View File

@@ -0,0 +1,15 @@
// 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 Windows.Foundation;
namespace DeveloperCommandPalette;
public class SubmitFormArgs
{
public required string FormData { get; set; }
public required IForm Form { get; set; }
}

View File

@@ -0,0 +1,31 @@
// 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.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;
namespace WindowsCommandPalette.Views;
public sealed class ErrorListItem : Microsoft.Windows.CommandPalette.Extensions.Helpers.ListItem
{
public ErrorListItem(Exception ex)
: base(new NoOpAction())
{
this.Title = "Error in extension:";
this.Subtitle = ex.Message;
}
}

View File

@@ -156,7 +156,7 @@ public sealed partial class FormPage : Page
// yep it's this dumb
var foreground = settings.GetColorValue(UIColorType.Foreground);
var lightTheme = foreground.R < 128;
Renderer.HostConfig = AdaptiveHostConfig.FromJsonString(lightTheme? LightHostConfig : DarkHostConfig).HostConfig;
Renderer.HostConfig = AdaptiveHostConfig.FromJsonString(lightTheme ? LightHostConfig : DarkHostConfig).HostConfig;
}

View File

@@ -2,244 +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.
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;
namespace WindowsCommandPalette.Views;
public sealed class StringNotEmptyToVisibilityConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, string language)
{
return string.IsNullOrWhiteSpace((string)value) ? Visibility.Collapsed : Visibility.Visible;
}
public object ConvertBack(object value, Type targetType, object parameter, string language)
{
throw new NotImplementedException();
}
}
public class SectionInfoList : ObservableCollection<ListItemViewModel>
{
public string Title { get; }
private readonly DispatcherQueue DispatcherQueue = DispatcherQueue.GetForCurrentThread();
public SectionInfoList(ISection? section, IEnumerable<ListItemViewModel> items)
: base(items)
{
Title = section?.Title ?? string.Empty;
if (section != null && section is INotifyCollectionChanged observable)
{
observable.CollectionChanged -= Items_CollectionChanged;
observable.CollectionChanged += Items_CollectionChanged;
}
if (this.DispatcherQueue == null)
{
throw new InvalidOperationException("DispatcherQueue is null");
}
}
private void Items_CollectionChanged(object? sender, NotifyCollectionChangedEventArgs e)
{
// DispatcherQueue.TryEnqueue(() => {
if (e.Action == NotifyCollectionChangedAction.Add && e.NewItems != null)
{
foreach (var i in e.NewItems)
{
if (i is IListItem li)
{
if (!string.IsNullOrEmpty(li.Title))
{
ListItemViewModel vm = new(li);
this.Add(vm);
}
// if (isDynamic)
// {
// // Dynamic lists are in charge of their own
// // filtering. They know if this thing was already
// // filtered or not.
// FilteredItems.Add(vm);
// }
}
}
}
else if (e.Action == NotifyCollectionChangedAction.Reset)
{
this.Clear();
// Items.Clear();
// if (isDynamic)
// {
// FilteredItems.Clear();
// }
}
// });
}
}
public sealed class NoOpAction : InvokableCommand
{
public override ICommandResult Invoke()
{
return ActionResult.KeepOpen();
}
}
public sealed class ErrorListItem : Microsoft.Windows.CommandPalette.Extensions.Helpers.ListItem
{
public ErrorListItem(Exception ex)
: base(new NoOpAction())
{
this.Title = "Error in extension:";
this.Subtitle = ex.Message;
}
}
public sealed class ListPageViewModel : PageViewModel
{
internal readonly ObservableCollection<SectionInfoList> Items = [];
internal readonly ObservableCollection<SectionInfoList> FilteredItems = [];
internal IListPage Page => (IListPage)this.pageAction;
private bool isDynamic => Page is IDynamicListPage;
private IDynamicListPage? dynamicPage => Page as IDynamicListPage;
private readonly DispatcherQueue DispatcherQueue = DispatcherQueue.GetForCurrentThread();
internal string Query = string.Empty;
public ListPageViewModel(IListPage page) : base(page)
{
}
internal Task InitialRender()
{
return UpdateListItems();
}
internal async Task UpdateListItems()
{
// on main thread
var t = new Task<ISection[]>(() =>
{
try
{
return dynamicPage != null ?
dynamicPage.GetItems(Query) :
this.Page.GetItems();
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine(ex);
return [new ListSection()
{
Title = "Error",
Items = [new ErrorListItem(ex)],
}
];
}
});
t.Start();
var sections = await t;
// still on main thread
// TODO! For dynamic lists, we're clearing out the whole list of items
// we already have, then rebuilding it. We shouldn't do that. We should
// still use the results from GetItems and put them into the code in
// UpdateFilter to intelligently add/remove as needed.
// Items.Clear();
// FilteredItems.Clear();
Collection<SectionInfoList> newItems = new();
var size = sections.Length;
for (var sectionIndex = 0; sectionIndex < size; sectionIndex++)
{
var section = sections[sectionIndex];
var sectionItems = new SectionInfoList(
section,
section.Items
.Where(i => i != null && !string.IsNullOrEmpty(i.Title))
.Select(i => new ListItemViewModel(i))
);
// var items = section.Items;
// for (var i = 0; i < items.Length; i++) {
// ListItemViewModel vm = new(items[i]);
// Items.Add(vm);
// FilteredItems.Add(vm);
// }
newItems.Add(sectionItems);
// Items.Add(sectionItems);
// FilteredItems.Add(sectionItems);
}
ListHelpers.InPlaceUpdateList(Items, newItems);
ListHelpers.InPlaceUpdateList(FilteredItems, newItems);
}
internal async Task<Collection<SectionInfoList>> GetFilteredItems(string query)
{
if (query == Query)
{
return FilteredItems;
}
Query = query;
if (isDynamic)
{
await UpdateListItems();
return FilteredItems;
}
else
{
// Static lists don't need to re-fetch the items
if (string.IsNullOrEmpty(query))
{
return Items;
}
//// TODO! Probably bad that this turns list view models into listitems back to NEW view models
// return ListHelpers.FilterList(Items.Select(vm => vm.ListItem), Query).Select(li => new ListItemViewModel(li)).ToList();
try
{
var allFilteredItems = ListHelpers.FilterList(
Items
.SelectMany(section => section)
.Select(vm => vm.ListItem.Unsafe),
Query).Select(li => new ListItemViewModel(li));
var newSection = new SectionInfoList(null, allFilteredItems);
return [newSection];
}
catch (COMException ex)
{
return [new SectionInfoList(null, [new ListItemViewModel(new ErrorListItem(ex))])];
}
}
}
}
/// <summary>
/// An empty page that can be used on its own or navigated to within a Frame.
/// </summary>
@@ -348,7 +123,7 @@ public sealed partial class ListPage : Page, System.ComponentModel.INotifyProper
{
FlyoutShowOptions options = new FlyoutShowOptions
{
ShowMode = FlyoutShowMode.Standard
ShowMode = FlyoutShowMode.Standard,
};
MoreCommandsButton.Flyout.ShowAt(MoreCommandsButton, options);
ActionsDropdown.SelectedIndex = 0;
@@ -487,7 +262,7 @@ public sealed partial class ListPage : Page, System.ComponentModel.INotifyProper
{
FlyoutShowOptions options = new FlyoutShowOptions
{
ShowMode = FlyoutShowMode.Standard
ShowMode = FlyoutShowMode.Standard,
};
MoreCommandsButton.Flyout.ShowAt(MoreCommandsButton, options);
ActionsDropdown.SelectedIndex = 0;

View File

@@ -0,0 +1,147 @@
// 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.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;
namespace WindowsCommandPalette.Views;
public sealed class ListPageViewModel : PageViewModel
{
internal readonly ObservableCollection<SectionInfoList> Items = [];
internal readonly ObservableCollection<SectionInfoList> FilteredItems = [];
internal IListPage Page => (IListPage)this.pageAction;
private bool isDynamic => Page is IDynamicListPage;
private IDynamicListPage? dynamicPage => Page as IDynamicListPage;
private readonly DispatcherQueue DispatcherQueue = DispatcherQueue.GetForCurrentThread();
internal string Query = string.Empty;
public ListPageViewModel(IListPage page) : base(page)
{
}
internal Task InitialRender()
{
return UpdateListItems();
}
internal async Task UpdateListItems()
{
// on main thread
var t = new Task<ISection[]>(() =>
{
try
{
return dynamicPage != null ?
dynamicPage.GetItems(Query) :
this.Page.GetItems();
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine(ex);
return [new ListSection()
{
Title = "Error",
Items = [new ErrorListItem(ex)],
}
];
}
});
t.Start();
var sections = await t;
// still on main thread
// TODO! For dynamic lists, we're clearing out the whole list of items
// we already have, then rebuilding it. We shouldn't do that. We should
// still use the results from GetItems and put them into the code in
// UpdateFilter to intelligently add/remove as needed.
// Items.Clear();
// FilteredItems.Clear();
Collection<SectionInfoList> newItems = new();
var size = sections.Length;
for (var sectionIndex = 0; sectionIndex < size; sectionIndex++)
{
var section = sections[sectionIndex];
var sectionItems = new SectionInfoList(
section,
section.Items
.Where(i => i != null && !string.IsNullOrEmpty(i.Title))
.Select(i => new ListItemViewModel(i)));
// var items = section.Items;
// for (var i = 0; i < items.Length; i++) {
// ListItemViewModel vm = new(items[i]);
// Items.Add(vm);
// FilteredItems.Add(vm);
// }
newItems.Add(sectionItems);
// Items.Add(sectionItems);
// FilteredItems.Add(sectionItems);
}
ListHelpers.InPlaceUpdateList(Items, newItems);
ListHelpers.InPlaceUpdateList(FilteredItems, newItems);
}
internal async Task<Collection<SectionInfoList>> GetFilteredItems(string query)
{
if (query == Query)
{
return FilteredItems;
}
Query = query;
if (isDynamic)
{
await UpdateListItems();
return FilteredItems;
}
else
{
// Static lists don't need to re-fetch the items
if (string.IsNullOrEmpty(query))
{
return Items;
}
//// TODO! Probably bad that this turns list view models into listitems back to NEW view models
// return ListHelpers.FilterList(Items.Select(vm => vm.ListItem), Query).Select(li => new ListItemViewModel(li)).ToList();
try
{
var allFilteredItems = ListHelpers.FilterList(
Items
.SelectMany(section => section)
.Select(vm => vm.ListItem.Unsafe),
Query).Select(li => new ListItemViewModel(li));
var newSection = new SectionInfoList(null, allFilteredItems);
return [newSection];
}
catch (COMException ex)
{
return [new SectionInfoList(null, [new ListItemViewModel(new ErrorListItem(ex))])];
}
}
}
}

View File

@@ -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 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;
namespace WindowsCommandPalette.Views;
public sealed class NoOpAction : InvokableCommand
{
public override ICommandResult Invoke()
{
return ActionResult.KeepOpen();
}
}

View File

@@ -0,0 +1,83 @@
// 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.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;
namespace WindowsCommandPalette.Views;
public class SectionInfoList : ObservableCollection<ListItemViewModel>
{
public string Title { get; }
private readonly DispatcherQueue _dispatcherQueue = DispatcherQueue.GetForCurrentThread();
public SectionInfoList(ISection? section, IEnumerable<ListItemViewModel> items)
: base(items)
{
Title = section?.Title ?? string.Empty;
if (section != null && section is INotifyCollectionChanged observable)
{
observable.CollectionChanged -= Items_CollectionChanged;
observable.CollectionChanged += Items_CollectionChanged;
}
if (this._dispatcherQueue == null)
{
throw new InvalidOperationException("DispatcherQueue is null");
}
}
private void Items_CollectionChanged(object? sender, NotifyCollectionChangedEventArgs e)
{
// DispatcherQueue.TryEnqueue(() => {
if (e.Action == NotifyCollectionChangedAction.Add && e.NewItems != null)
{
foreach (var i in e.NewItems)
{
if (i is IListItem li)
{
if (!string.IsNullOrEmpty(li.Title))
{
ListItemViewModel vm = new(li);
this.Add(vm);
}
// if (isDynamic)
// {
// // Dynamic lists are in charge of their own
// // filtering. They know if this thing was already
// // filtered or not.
// FilteredItems.Add(vm);
// }
}
}
}
else if (e.Action == NotifyCollectionChangedAction.Reset)
{
this.Clear();
// Items.Clear();
// if (isDynamic)
// {
// FilteredItems.Clear();
// }
}
// });
}
}

View File

@@ -0,0 +1,34 @@
// 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.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;
namespace WindowsCommandPalette.Views;
public sealed class StringNotEmptyToVisibilityConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, string language)
{
return string.IsNullOrWhiteSpace((string)value) ? Visibility.Collapsed : Visibility.Visible;
}
public object ConvertBack(object value, Type targetType, object parameter, string language)
{
throw new NotImplementedException();
}
}