hackernews now passes

This commit is contained in:
Clint Rutkas
2024-08-30 16:38:52 -07:00
parent ea4bbda107
commit c0b2f1654a
6 changed files with 141 additions and 112 deletions

View File

@@ -0,0 +1,26 @@
// 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.Windows.CommandPalette.Extensions.Helpers;
namespace HackerNewsExtension;
internal sealed class CommentAction : InvokableCommand
{
private readonly NewsPost _post;
internal CommentAction(NewsPost post)
{
_post = post;
Name = "Open comments";
Icon = new("\ue8f2"); // chat bubbles
}
public override ActionResult Invoke()
{
Process.Start(new ProcessStartInfo(_post.CommentsLink) { UseShellExecute = true });
return ActionResult.KeepOpen();
}
}

View File

@@ -3,124 +3,18 @@
// See the LICENSE file in the project root for more information.
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Net.Http;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.InteropServices.WindowsRuntime;
using System.Text.Json;
using System.Threading.Tasks;
using System.Xml.Linq;
using ABI.System;
using Microsoft.UI;
using Microsoft.Windows.CommandPalette.Extensions;
using Microsoft.Windows.CommandPalette.Extensions.Helpers;
using Windows.Foundation;
using Windows.Storage.Streams;
namespace HackerNewsExtension;
internal sealed class NewsPost
{
internal string Title { get; init; } = "";
internal string Link { get; init; } = "";
internal string CommentsLink { get; init; } = "";
internal string Poster { get; init; } = "";
}
internal sealed class LinkAction : InvokableCommand {
private readonly NewsPost post;
internal LinkAction(NewsPost post)
{
this.post = post;
this.Name = "Open link";
this.Icon = new("\uE8A7");
}
public override ActionResult Invoke()
{
Process.Start(new ProcessStartInfo(post.Link) { UseShellExecute = true });
return ActionResult.KeepOpen();
}
}
internal sealed class CommentAction : InvokableCommand
{
private readonly NewsPost post;
internal CommentAction(NewsPost post)
{
this.post = post;
this.Name = "Open comments";
this.Icon = new("\ue8f2"); // chat bubbles
}
public override ActionResult Invoke()
{
Process.Start(new ProcessStartInfo(post.CommentsLink) { UseShellExecute = true });
return ActionResult.KeepOpen();
}
}
sealed class HackerNewsPage : ListPage {
public HackerNewsPage()
{
this.Icon = new("https://news.ycombinator.com/favicon.ico");
this.Name = "Hacker News";
}
private static async Task<List<NewsPost>> GetHackerNewsTopPosts()
{
var posts = new List<NewsPost>();
using (HttpClient client = new HttpClient())
{
var response = await client.GetStringAsync("https://news.ycombinator.com/rss");
var xdoc = XDocument.Parse(response);
var x = xdoc.Descendants("item").First();
posts = xdoc.Descendants("item")
.Take(20)
.Select(item => new NewsPost()
{
Title = item.Element("title")?.Value ?? "",
Link = item.Element("link")?.Value ?? "",
CommentsLink = item.Element("comments")?.Value ?? "",
}).ToList();
}
return posts;
}
public override ISection[] GetItems()
{
var t = DoGetItems();
t.ConfigureAwait(false);
return t.Result;
}
private async Task<ISection[]> DoGetItems()
{
List<NewsPost> items = await GetHackerNewsTopPosts();
this.Loading = false;
var s = new ListSection()
{
Title = "Posts",
Items = items.Select((post) => new ListItem(new LinkAction(post))
{
Title = post.Title,
Subtitle = post.Link,
MoreCommands = [
new CommandContextItem(new CommentAction(post))
]
}).ToArray()
};
return [ s ] ;
}
}
public class HackerNewsActionsProvider : ICommandProvider
{
public string DisplayName => $"Hacker News Commands";
public IconDataType Icon => new("");
private readonly IListItem[] _Actions = [
public IconDataType Icon => new(string.Empty);
private readonly IListItem[] _actions = [
new ListItem(new HackerNewsPage()),
];
@@ -128,9 +22,8 @@ public class HackerNewsActionsProvider : ICommandProvider
public void Dispose() => throw new NotImplementedException();
#pragma warning restore CA1816 // Dispose methods should call SuppressFinalize
public IListItem[] TopLevelCommands()
{
return _Actions;
return _actions;
}
}

View File

@@ -7,7 +7,6 @@
<PublishProfile>win-$(Platform).pubxml</PublishProfile>
<UseWinUI>false</UseWinUI>
<EnableMsixTooling>true</EnableMsixTooling>
<TreatWarningsAsErrors>False</TreatWarningsAsErrors>
</PropertyGroup>
<ItemGroup>

View File

@@ -0,0 +1,69 @@
// 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.Generic;
using System.Linq;
using System.Net.Http;
using System.Runtime.InteropServices.WindowsRuntime;
using System.Threading.Tasks;
using System.Xml.Linq;
using Microsoft.Windows.CommandPalette.Extensions;
using Microsoft.Windows.CommandPalette.Extensions.Helpers;
namespace HackerNewsExtension;
internal sealed class HackerNewsPage : ListPage
{
public HackerNewsPage()
{
Icon = new("https://news.ycombinator.com/favicon.ico");
Name = "Hacker News";
}
private static async Task<List<NewsPost>> GetHackerNewsTopPosts()
{
var posts = new List<NewsPost>();
using (HttpClient client = new HttpClient())
{
var response = await client.GetStringAsync("https://news.ycombinator.com/rss");
var xdoc = XDocument.Parse(response);
var x = xdoc.Descendants("item").First();
posts = xdoc.Descendants("item")
.Take(20)
.Select(item => new NewsPost()
{
Title = item.Element("title")?.Value ?? string.Empty,
Link = item.Element("link")?.Value ?? string.Empty,
CommentsLink = item.Element("comments")?.Value ?? string.Empty,
}).ToList();
}
return posts;
}
public override ISection[] GetItems()
{
var t = DoGetItems();
t.ConfigureAwait(false);
return t.Result;
}
private async Task<ISection[]> DoGetItems()
{
List<NewsPost> items = await GetHackerNewsTopPosts();
this.Loading = false;
var s = new ListSection()
{
Title = "Posts",
Items = items.Select((post) => new ListItem(new LinkAction(post))
{
Title = post.Title,
Subtitle = post.Link,
MoreCommands = [new CommandContextItem(new CommentAction(post))],
}).ToArray(),
};
return [s];
}
}

View File

@@ -0,0 +1,26 @@
// 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.Windows.CommandPalette.Extensions.Helpers;
namespace HackerNewsExtension;
internal sealed class LinkAction : InvokableCommand
{
private readonly NewsPost _post;
internal LinkAction(NewsPost post)
{
this._post = post;
this.Name = "Open link";
this.Icon = new("\uE8A7");
}
public override ActionResult Invoke()
{
Process.Start(new ProcessStartInfo(_post.Link) { UseShellExecute = true });
return ActionResult.KeepOpen();
}
}

View File

@@ -0,0 +1,16 @@
// 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 HackerNewsExtension;
public sealed class NewsPost
{
public string Title { get; init; } = string.Empty;
public string Link { get; init; } = string.Empty;
public string CommentsLink { get; init; } = string.Empty;
public string Poster { get; init; } = string.Empty;
}