Skip to content

Commit

Permalink
Bind to Page properties, and add support for item propchange's (#186)
Browse files Browse the repository at this point in the history
A lot of this is just samples work, so skip on down to `src/modules/cmdpal/Microsoft.CmdPal.UI.ViewModels/ActionBarViewModel.cs`.

* Updates the Action Bar with the title of the currently active page when we navigate to it
* listens for PropChanged events from `ICommandItem`s in lists and on `IPage`'s (to display a loading bar)
  * Also didn't put this on the ShellPage quite yet, because the diff was already massive, and there's complicated "are _we_ loading the page? did the `IPage` say it was loading?" plumbing that needs to be done. 
* adds rudimentary support for showing an exception, if there's an error we catch
  * I didn't add log this everywhere yet though, since we're not 100% confident on the messaging infrastructure here
  * I decided against putting this on the shell page, because I want users to be able to _go back_ from a page with an exception, and that didn't seem trivial if it was on the shellpage itself
* Then updates a bunch of extensions to better utilize the loading state. 
* Then discovers a really weird bug with event callbacks in WinRT, so I decided to wrap those in try/catches to have extensions explode less often. (#181)
* Then also adds a bunch of "evil" samples, to make a unified place of "things to try and break us"

ref #73

---------

Co-authored-by: Mike Griese <[email protected]>
  • Loading branch information
zadjii-msft and zadjii authored Dec 5, 2024
1 parent ef35a4c commit 2b98619
Show file tree
Hide file tree
Showing 31 changed files with 557 additions and 142 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +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.Collections.Generic;
using System.Linq;
using System.Net.Http;
Expand All @@ -23,6 +24,8 @@ public HackerNewsPage()
Icon = new("https://news.ycombinator.com/favicon.ico");
Name = "Hacker News";
AccentColor = Color.FromArgb(255, 255, 102, 0);
Loading = true;
ShowDetails = true;
}

private static async Task<List<NewsPost>> GetHackerNewsTopPosts()
Expand All @@ -49,9 +52,29 @@ private static async Task<List<NewsPost>> GetHackerNewsTopPosts()

public override IListItem[] GetItems()
{
var t = DoGetItems();
t.ConfigureAwait(false);
return t.Result;
try
{
Loading = true;
var t = DoGetItems();
t.ConfigureAwait(false);
return t.Result;
}
catch (Exception ex)
{
return [
new ListItem(new NoOpCommand()) { Title = "Exception getting posts from HN" },
new ListItem(new NoOpCommand())
{
Title = $"{ex.HResult}",
Subtitle = ex.HResult == -2147023174 ? "This is probably zadjii-msft/PowerToys#181" : string.Empty,
},
new ListItem(new NoOpCommand())
{
Title = "Stack trace",
Details = new Details() { Body = $"```{ex.Source}\n{ex.StackTrace}```" },
},
];
}
}

private async Task<IListItem[]> DoGetItems()
Expand Down
25 changes: 8 additions & 17 deletions src/modules/cmdpal/Exts/MastodonExtension/MastodonExtensionPage.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,14 +24,15 @@ internal sealed partial class MastodonExtensionPage : ListPage
internal static readonly HttpClient Client = new();
internal static readonly JsonSerializerOptions Options = new() { PropertyNameCaseInsensitive = true };

private readonly List<ListItem> _items = new();
private readonly List<ListItem> _items = [];

public MastodonExtensionPage()
{
Icon = new("https://mastodon.social/packs/media/icons/android-chrome-36x36-4c61fdb42936428af85afdbf8c6a45a8.png");
Name = "Mastodon";
ShowDetails = true;
HasMore = true;
Loading = true;

// #6364ff
AccentColor = Color.FromArgb(255, 99, 100, 255);
Expand Down Expand Up @@ -104,10 +105,7 @@ public override void LoadMore()
}).ConfigureAwait(false);
}

public async Task<List<MastodonStatus>> FetchExplorePage()
{
return await FetchExplorePage(20, 0);
}
public async Task<List<MastodonStatus>> FetchExplorePage() => await FetchExplorePage(20, 0);

public async Task<List<MastodonStatus>> FetchExplorePage(int limit, int offset)
{
Expand All @@ -129,6 +127,8 @@ public async Task<List<MastodonStatus>> FetchExplorePage(int limit, int offset)
Console.WriteLine($"An error occurred: {e.Message}");
}

Loading = false;

return statuses;
}
}
Expand All @@ -145,10 +145,7 @@ public MastodonExtensionActionsProvider()
new CommandItem(new MastodonExtensionPage()) { Subtitle = "Explore top posts on mastodon.social" },
];

public override ICommandItem[] TopLevelCommands()
{
return _actions;
}
public override ICommandItem[] TopLevelCommands() => _actions;
}

[System.Diagnostics.CodeAnalysis.SuppressMessage("StyleCop.CSharp.MaintainabilityRules", "SA1402:File may only contain a single type", Justification = "This is sample code")]
Expand Down Expand Up @@ -177,10 +174,7 @@ public string DataJson()

public string StateJson() => throw new NotImplementedException();

public ICommandResult SubmitForm(string payload)
{
return CommandResult.Dismiss();
}
public ICommandResult SubmitForm(string payload) => CommandResult.Dismiss();

public string TemplateJson()
{
Expand Down Expand Up @@ -404,10 +398,7 @@ private static string ParseNodeToMarkdown(HtmlNode node, bool escapeHashtags)
}
}

private static string ParseNodeToPlaintext(HtmlNode node)
{
return node.InnerText;
}
private static string ParseNodeToPlaintext(HtmlNode node) => node.InnerText;
}

[System.Diagnostics.CodeAnalysis.SuppressMessage("StyleCop.CSharp.MaintainabilityRules", "SA1402:File may only contain a single type", Justification = "This is sample code")]
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
{
"profiles": {
"ProcessMonitorExtension (Package)": {
"commandName": "MsixPackage"
"commandName": "MsixPackage",
"doNotLaunchApp": true
},
"ProcessMonitorExtension (Unpackaged)": {
"commandName": "Project"
}
}
}
}
32 changes: 32 additions & 0 deletions src/modules/cmdpal/Exts/SamplePagesExtension/EvilSampleListPage.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
// 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.Timers;
using Microsoft.CmdPal.Extensions;
using Microsoft.CmdPal.Extensions.Helpers;

namespace SamplePagesExtension;

internal sealed partial class EvilSampleListPage : ListPage
{
public EvilSampleListPage()
{
Icon = new(string.Empty);
Name = "Open";
}

public override IListItem[] GetItems()
{
IListItem[] commands = [
new ListItem(new EvilSampleListPage())
{
Subtitle = "Doesn't matter, I'll blow up before you see this",
},
];

_ = commands[9001]; // Throws

return commands;
}
}
42 changes: 42 additions & 0 deletions src/modules/cmdpal/Exts/SamplePagesExtension/EvilSamplesPage.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
// 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.CmdPal.Extensions;
using Microsoft.CmdPal.Extensions.Helpers;

namespace SamplePagesExtension;

public partial class EvilSamplesPage : ListPage
{
private readonly IListItem[] _commands = [
new ListItem(new EvilSampleListPage())
{
Title = "List Page without items",
Subtitle = "Throws exception on GetItems",
},
new ListItem(new ExplodeInFiveSeconds(false))
{
Title = "Page that will throw an exception after loading it",
Subtitle = "Throws exception on GetItems _after_ a ItemsChanged",
},
new ListItem(new ExplodeInFiveSeconds(true))
{
Title = "Page that keeps throwing exceptions",
Subtitle = "Will throw every 5 seconds once you open it",
},
new ListItem(new SelfImmolateCommand())
{
Title = "Terminate this extension",
Subtitle = "Will exit this extension (while it's loaded!)",
},
];

public EvilSamplesPage()
{
Name = "Evil Samples";
Icon = new("👿"); // Info
}

public override IListItem[] GetItems() => _commands;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
// 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.Timers;
using Microsoft.CmdPal.Extensions;
using Microsoft.CmdPal.Extensions.Helpers;

namespace SamplePagesExtension;

internal sealed partial class ExplodeInFiveSeconds : ListPage
{
private readonly bool _repeat;

private IListItem[] Commands => [
new ListItem(new NoOpCommand())
{
Title = "This page will explode in five seconds!",
Subtitle = _repeat ? "Not only that, I'll _keep_ exploding every 5 seconds after that" : string.Empty,
},
];

private bool shouldExplode;
private static Timer timer;

public ExplodeInFiveSeconds(bool repeat)
{
_repeat = repeat;
Icon = new(string.Empty);
Name = "Open";
}

public override IListItem[] GetItems()
{
if (shouldExplode)
{
_ = Commands[9001]; // Throws
}
else
{
timer = new Timer(5000);
timer.Elapsed += (object source, ElapsedEventArgs e) => { RaiseItemsChanged(9000); };
timer.AutoReset = _repeat; // Keep repeating
timer.Enabled = true;
}

shouldExplode = true;
return Commands;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +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.IO;
using System.Linq;
using System.Net.Http;
using System.Runtime.InteropServices;
using System.Runtime.InteropServices.WindowsRuntime;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using System.Xml.Linq;
using Microsoft.CmdPal.Extensions;
using Microsoft.CmdPal.Extensions.Helpers;
using Microsoft.UI.Windowing;

namespace SamplePagesExtension;

Expand All @@ -24,12 +15,10 @@ public SampleDynamicListPage()
{
Icon = new(string.Empty);
Name = "Dynamic List";
Loading = true;
}

public override void UpdateSearchText(string oldSearch, string newSearch)
{
RaiseItemsChanged(newSearch.Length);
}
public override void UpdateSearchText(string oldSearch, string newSearch) => RaiseItemsChanged(newSearch.Length);

public override IListItem[] GetItems()
{
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
// 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.Timers;
using Microsoft.CmdPal.Extensions;
using Microsoft.CmdPal.Extensions.Helpers;
using Microsoft.VisualBasic;

namespace SamplePagesExtension;

public partial class SampleUpdatingItemsPage : ListPage
{
private readonly ListItem hourItem = new(new NoOpCommand());
private readonly ListItem minuteItem = new(new NoOpCommand());
private readonly ListItem secondItem = new(new NoOpCommand());
private static Timer timer;

public SampleUpdatingItemsPage()
{
Name = "Open";
Icon = new(string.Empty);
}

public override IListItem[] GetItems()
{
if (timer == null)
{
timer = new Timer(500);
timer.Elapsed += (object source, ElapsedEventArgs e) =>
{
var current = DateAndTime.Now;
hourItem.Title = $"{current.Hour}";
minuteItem.Title = $"{current.Minute}";
secondItem.Title = $"{current.Second}";
};
timer.AutoReset = true; // Keep repeating
timer.Enabled = true;
}

return [hourItem, minuteItem, secondItem];
}
}
15 changes: 11 additions & 4 deletions src/modules/cmdpal/Exts/SamplePagesExtension/SamplesListPage.cs
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,11 @@ public partial class SamplesListPage : ListPage
Title = "List Page With Details Sample Command",
Subtitle = "A list of items, each with additional details to display",
},
new ListItem(new SampleUpdatingItemsPage())
{
Title = "List page with items that change",
Subtitle = "The items on the list update themselves in real time",
},
new ListItem(new SampleDynamicListPage())
{
Title = "Dynamic List Page Command",
Expand All @@ -39,6 +44,11 @@ public partial class SamplesListPage : ListPage
{
Title = "Sample settings page",
Subtitle = "A demo of the settings helpers",
},
new ListItem(new EvilSamplesPage())
{
Title = "Evil samples",
Subtitle = "Samples designed to break the palette in many different evil ways",
}
];

Expand All @@ -48,8 +58,5 @@ public SamplesListPage()
Icon = new("\ue946"); // Info
}

public override IListItem[] GetItems()
{
return _commands;
}
public override IListItem[] GetItems() => _commands;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
// 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.Diagnostics;
using Microsoft.CmdPal.Extensions;
using Microsoft.CmdPal.Extensions.Helpers;

namespace SamplePagesExtension;

public partial class SelfImmolateCommand : InvokableCommand
{
public override ICommandResult Invoke()
{
Process.GetCurrentProcess().Kill();
return base.Invoke();
}
}
Loading

0 comments on commit 2b98619

Please sign in to comment.