From 2f29559faf51e5f5983b2006e2d217e7a146c949 Mon Sep 17 00:00:00 2001 From: yell0wsuit <5692900+yell0wsuit@users.noreply.github.com> Date: Thu, 18 Apr 2024 13:36:50 +0700 Subject: [PATCH 1/9] Add HtmlAgilityPack package --- Directory.Packages.props | 3 ++- src/Ryujinx/Ryujinx.csproj | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/Directory.Packages.props b/Directory.Packages.props index c3af18ceec..0d447c3108 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -17,6 +17,7 @@ + @@ -49,4 +50,4 @@ - + \ No newline at end of file diff --git a/src/Ryujinx/Ryujinx.csproj b/src/Ryujinx/Ryujinx.csproj index 38453f2c66..baf9aaf863 100644 --- a/src/Ryujinx/Ryujinx.csproj +++ b/src/Ryujinx/Ryujinx.csproj @@ -44,6 +44,7 @@ + From 4b7b3dc4c7a71154ea96f366c99de90bf63f28dc Mon Sep 17 00:00:00 2001 From: yell0wsuit <5692900+yell0wsuit@users.noreply.github.com> Date: Thu, 18 Apr 2024 13:41:05 +0700 Subject: [PATCH 2/9] Add OpenChangelogWindow function --- src/Ryujinx/UI/Windows/AboutWindow.axaml | 3 +-- src/Ryujinx/UI/Windows/AboutWindow.axaml.cs | 6 ++++++ 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/src/Ryujinx/UI/Windows/AboutWindow.axaml b/src/Ryujinx/UI/Windows/AboutWindow.axaml index 69fa82517a..6af99238d5 100644 --- a/src/Ryujinx/UI/Windows/AboutWindow.axaml +++ b/src/Ryujinx/UI/Windows/AboutWindow.axaml @@ -87,8 +87,7 @@ Padding="5" HorizontalAlignment="Center" Background="Transparent" - Click="Button_OnClick" - Tag="https://github.com/Ryujinx/Ryujinx/wiki/Changelog#ryujinx-changelog"> + Click="OpenChangelogWindow"> Date: Thu, 18 Apr 2024 18:07:37 +0700 Subject: [PATCH 3/9] Add view changelog strings and window --- src/Ryujinx/Assets/Locales/en_US.json | 6 ++- src/Ryujinx/UI/Windows/AboutWindow.axaml | 1 - src/Ryujinx/UI/Windows/ChangelogWindow.axaml | 42 ++++++++++++++++++++ 3 files changed, 46 insertions(+), 3 deletions(-) create mode 100644 src/Ryujinx/UI/Windows/ChangelogWindow.axaml diff --git a/src/Ryujinx/Assets/Locales/en_US.json b/src/Ryujinx/Assets/Locales/en_US.json index 77ad7d1f8c..9fd9903de0 100644 --- a/src/Ryujinx/Assets/Locales/en_US.json +++ b/src/Ryujinx/Assets/Locales/en_US.json @@ -765,8 +765,10 @@ "NetworkInterfaceTooltip": "The network interface used for LAN/LDN features.\n\nIn conjunction with a VPN or XLink Kai and a game with LAN support, can be used to spoof a same-network connection over the Internet.\n\nLeave on DEFAULT if unsure.", "NetworkInterfaceDefault": "Default", "PackagingShaders": "Packaging Shaders", - "AboutChangelogButton": "View Changelog on GitHub", - "AboutChangelogButtonTooltipMessage": "Click to open the changelog for this version in your default browser.", + "AboutChangelogButton": "View Changelog", + "AboutChangelogButtonTooltipMessage": "Click to view the changelog.", + "ChangelogWindowTitle": "Changelog", + "ChangelogDescription": "Showing the 10 most recent versions. For more changelog version history please visit Ryujinx GitHub page.", "SettingsTabNetworkMultiplayer": "Multiplayer", "MultiplayerMode": "Mode:", "MultiplayerModeTooltip": "Change LDN multiplayer mode.\n\nLdnMitm will modify local wireless/local play functionality in games to function as if it were LAN, allowing for local, same-network connections with other Ryujinx instances and hacked Nintendo Switch consoles that have the ldn_mitm module installed.\n\nMultiplayer requires all players to be on the same game version (i.e. Super Smash Bros. Ultimate v13.0.1 can't connect to v13.0.0).\n\nLeave DISABLED if unsure.", diff --git a/src/Ryujinx/UI/Windows/AboutWindow.axaml b/src/Ryujinx/UI/Windows/AboutWindow.axaml index 6af99238d5..cadd875bcf 100644 --- a/src/Ryujinx/UI/Windows/AboutWindow.axaml +++ b/src/Ryujinx/UI/Windows/AboutWindow.axaml @@ -144,7 +144,6 @@ Background="Transparent" Click="Button_OnClick" CornerRadius="15" - Tag="https://github.com/Ryujinx/Ryujinx" ToolTip.Tip="{locale:Locale AboutGithubUrlTooltipMessage}"> diff --git a/src/Ryujinx/UI/Windows/ChangelogWindow.axaml b/src/Ryujinx/UI/Windows/ChangelogWindow.axaml new file mode 100644 index 0000000000..413a0869b8 --- /dev/null +++ b/src/Ryujinx/UI/Windows/ChangelogWindow.axaml @@ -0,0 +1,42 @@ + + + + + + + + + + + + + From 05de6aeadfed8f30ed27dd27a7f48d1de6977c7a Mon Sep 17 00:00:00 2001 From: yell0wsuit <5692900+yell0wsuit@users.noreply.github.com> Date: Thu, 18 Apr 2024 18:08:03 +0700 Subject: [PATCH 4/9] Implement ChangelogWindow function --- .../UI/Windows/ChangelogWindow.axaml.cs | 150 ++++++++++++++++++ 1 file changed, 150 insertions(+) create mode 100644 src/Ryujinx/UI/Windows/ChangelogWindow.axaml.cs diff --git a/src/Ryujinx/UI/Windows/ChangelogWindow.axaml.cs b/src/Ryujinx/UI/Windows/ChangelogWindow.axaml.cs new file mode 100644 index 0000000000..e4eb3bd50a --- /dev/null +++ b/src/Ryujinx/UI/Windows/ChangelogWindow.axaml.cs @@ -0,0 +1,150 @@ +using Avalonia.Controls; +using Avalonia.Input; +using Avalonia.Interactivity; +using Avalonia.Layout; +using Avalonia.Styling; +using FluentAvalonia.UI.Controls; +using HtmlAgilityPack; +using Ryujinx.Ava.Common.Locale; +using Ryujinx.Ava.UI.Helpers; +using Ryujinx.Ava.UI.ViewModels; +using Ryujinx.UI.Common.Helper; +using System; +using System.Diagnostics; +using System.Text; +using System.Threading.Tasks; +using Button = Avalonia.Controls.Button; +using System.Net.Http; + + +namespace Ryujinx.Ava.UI.Windows +{ + public partial class ChangelogWindow : Window + { + public ChangelogWindow() + { + InitializeComponent(); + InitializeAsync(); + } + + private async void InitializeAsync() + { + try + { + LoadingTextBlock.IsVisible = true; // Show the loading text + ChangelogTextBlock.IsVisible = false; // Hide the changelog text initially + + string changelogHtml = await FetchChangelogHtml(); + string changelog = ParseChangelogForRecentVersions(changelogHtml, 10); + LoadChangelog(changelog); + + LoadingTextBlock.IsVisible = false; // Hide the loading text + ChangelogTextBlock.IsVisible = true; // Show the changelog text + } + catch (Exception ex) + { + LoadingTextBlock.Text = "Failed to load changelog: " + ex.Message; + } + } + + private void LoadChangelog(string changelog) + { + ChangelogTextBlock.Text = changelog; + } + + private static async Task FetchChangelogHtml() + { + using (var client = new HttpClient()) + { + client.DefaultRequestHeaders.UserAgent.ParseAdd("Ryujinx-Updater/1.0.0"); + return await client.GetStringAsync("https://github.com/Ryujinx/Ryujinx/wiki/Changelog"); + } + } + + private static string ParseChangelogForRecentVersions(string html, int count) + { + var doc = new HtmlDocument(); + doc.LoadHtml(html); + + var headers = doc.DocumentNode.SelectNodes("//div[contains(@class, 'markdown-heading')]//h2"); + if (headers != null) + { + var content = new StringBuilder(); + int versionsFound = 0; + + foreach (var header in headers) + { + if (versionsFound >= count) break; // Stop after finding the desired number of versions + content.Append(header.OuterHtml); + var currentNode = header.ParentNode.NextSibling; + + while (currentNode != null && versionsFound < count) + { + if (currentNode.Name == "div" && currentNode.SelectSingleNode("h2") != null) + { + versionsFound++; // Increment for each version header found + if (versionsFound >= count) break; + } + content.Append(currentNode.OuterHtml); + currentNode = currentNode.NextSibling; + } + } + + return ConvertHtmlToPlainText(content.ToString()); + } + return "No changelog found."; + } + + private static string ConvertHtmlToPlainText(string html) + { + var doc = new HtmlDocument(); + doc.LoadHtml(html); + + // Recursively format nodes + string formattedText = FormatNode(doc.DocumentNode); + + return HtmlEntity.DeEntitize(formattedText); + } + + private static string FormatNode(HtmlNode node, int depth = 0) + { + StringBuilder sb = new StringBuilder(); + foreach (var child in node.ChildNodes) + { + switch (child.Name) + { + case "ul": + // Recursively format the list items + sb.Append(FormatNode(child, depth)); + sb.AppendLine(); + break; + + case "li": + // Format list item based on depth: "-" for top-level, "+" for nested items + string prefix = (depth == 0 ? "- " : new string(' ', depth * 4) + "+ "); + sb.AppendLine($"{prefix}{FormatNode(child, depth + 1).Trim()}"); + break; + + case "p": + case "#text": // Handling direct text nodes + if (!string.IsNullOrWhiteSpace(child.InnerText)) + { + // Trim the text + string text = HtmlEntity.DeEntitize(child.InnerText).Trim(); + sb.Append($"{text}\n"); + } + break; + + default: + // Recursively process other types of nodes + if (child.HasChildNodes) + { + sb.Append(FormatNode(child, depth)); // Keep current depth for other types + } + break; + } + } + return sb.ToString(); + } + } +} From 3630f1a307a9496705311f6ed4d9604f3f2442d5 Mon Sep 17 00:00:00 2001 From: yell0wsuit <5692900+yell0wsuit@users.noreply.github.com> Date: Thu, 18 Apr 2024 20:11:40 +0700 Subject: [PATCH 5/9] Make the window center as default --- src/Ryujinx/UI/Windows/ChangelogWindow.axaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Ryujinx/UI/Windows/ChangelogWindow.axaml b/src/Ryujinx/UI/Windows/ChangelogWindow.axaml index 413a0869b8..f8f6821e8c 100644 --- a/src/Ryujinx/UI/Windows/ChangelogWindow.axaml +++ b/src/Ryujinx/UI/Windows/ChangelogWindow.axaml @@ -12,9 +12,9 @@ d:DesignHeight="600" d:DesignWidth="800" CanResize="False" + WindowStartupLocation="CenterOwner" Focusable="True" mc:Ignorable="d" - Title="{locale:Locale ChangelogWindowTitle}" Icon="resm:Ryujinx.UI.Common.Resources.Logo_Ryujinx.png?assembly=Ryujinx.UI.Common"> From d8d05d0f62dd9a33928236ca7b3d421b87904100 Mon Sep 17 00:00:00 2001 From: yell0wsuit <5692900+yell0wsuit@users.noreply.github.com> Date: Thu, 18 Apr 2024 20:12:07 +0700 Subject: [PATCH 6/9] Re-implement OpenChangelogWindow --- src/Ryujinx/UI/Windows/AboutWindow.axaml.cs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/Ryujinx/UI/Windows/AboutWindow.axaml.cs b/src/Ryujinx/UI/Windows/AboutWindow.axaml.cs index d6e24b4397..9663eec919 100644 --- a/src/Ryujinx/UI/Windows/AboutWindow.axaml.cs +++ b/src/Ryujinx/UI/Windows/AboutWindow.axaml.cs @@ -3,6 +3,7 @@ using Avalonia.Input; using Avalonia.Interactivity; using Avalonia.Layout; using Avalonia.Styling; +using Avalonia.VisualTree; using FluentAvalonia.UI.Controls; using Ryujinx.Ava.Common.Locale; using Ryujinx.Ava.UI.Helpers; @@ -55,7 +56,13 @@ namespace Ryujinx.Ava.UI.Windows private void OpenChangelogWindow(object sender, RoutedEventArgs e) { ChangelogWindow changelogWindow = new ChangelogWindow(); - changelogWindow.Show(); + + // Find the parent window to use as the owner for the modal dialog + var parentWindow = this.FindAncestorOfType(); + if (parentWindow != null) + { + changelogWindow.ShowDialog(parentWindow); // Pass the parent window as the owner + } } private void AmiiboLabel_OnPointerPressed(object sender, PointerPressedEventArgs e) From 9e473dde995b7b0337b189e643c44cea76f36e85 Mon Sep 17 00:00:00 2001 From: yell0wsuit <5692900+yell0wsuit@users.noreply.github.com> Date: Thu, 18 Apr 2024 20:12:21 +0700 Subject: [PATCH 7/9] Changing some stuff in ChangelogWindow --- src/Ryujinx/UI/Windows/ChangelogWindow.axaml.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/Ryujinx/UI/Windows/ChangelogWindow.axaml.cs b/src/Ryujinx/UI/Windows/ChangelogWindow.axaml.cs index e4eb3bd50a..a42ec40ede 100644 --- a/src/Ryujinx/UI/Windows/ChangelogWindow.axaml.cs +++ b/src/Ryujinx/UI/Windows/ChangelogWindow.axaml.cs @@ -19,12 +19,14 @@ using System.Net.Http; namespace Ryujinx.Ava.UI.Windows { - public partial class ChangelogWindow : Window + public partial class ChangelogWindow : StyleableWindow { public ChangelogWindow() { + DataContext = this; InitializeComponent(); InitializeAsync(); + Title = $"Ryujinx {Program.Version} - " + LocaleManager.Instance[LocaleKeys.ChangelogWindowTitle]; } private async void InitializeAsync() From 2b3d26910bb6431576f8a22653f83c68389e7efb Mon Sep 17 00:00:00 2001 From: yell0wsuit <5692900+yell0wsuit@users.noreply.github.com> Date: Thu, 18 Apr 2024 20:54:50 +0700 Subject: [PATCH 8/9] Fix whitespace --- src/Ryujinx/UI/Windows/ChangelogWindow.axaml.cs | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/Ryujinx/UI/Windows/ChangelogWindow.axaml.cs b/src/Ryujinx/UI/Windows/ChangelogWindow.axaml.cs index a42ec40ede..4b6dbbc5d9 100644 --- a/src/Ryujinx/UI/Windows/ChangelogWindow.axaml.cs +++ b/src/Ryujinx/UI/Windows/ChangelogWindow.axaml.cs @@ -11,10 +11,10 @@ using Ryujinx.Ava.UI.ViewModels; using Ryujinx.UI.Common.Helper; using System; using System.Diagnostics; +using System.Net.Http; using System.Text; using System.Threading.Tasks; using Button = Avalonia.Controls.Button; -using System.Net.Http; namespace Ryujinx.Ava.UI.Windows @@ -76,7 +76,9 @@ namespace Ryujinx.Ava.UI.Windows foreach (var header in headers) { - if (versionsFound >= count) break; // Stop after finding the desired number of versions + if (versionsFound >= count) + break; // Stop after finding the desired number of versions + content.Append(header.OuterHtml); var currentNode = header.ParentNode.NextSibling; @@ -85,7 +87,8 @@ namespace Ryujinx.Ava.UI.Windows if (currentNode.Name == "div" && currentNode.SelectSingleNode("h2") != null) { versionsFound++; // Increment for each version header found - if (versionsFound >= count) break; + if (versionsFound >= count) + break; } content.Append(currentNode.OuterHtml); currentNode = currentNode.NextSibling; From 2953b87e5828b534093f23ae7ef827566ab9a063 Mon Sep 17 00:00:00 2001 From: yell0wsuit <5692900+yell0wsuit@users.noreply.github.com> Date: Thu, 18 Apr 2024 21:01:27 +0700 Subject: [PATCH 9/9] Fix IDE0063 --- src/Ryujinx/UI/Windows/ChangelogWindow.axaml.cs | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/Ryujinx/UI/Windows/ChangelogWindow.axaml.cs b/src/Ryujinx/UI/Windows/ChangelogWindow.axaml.cs index 4b6dbbc5d9..1992e59492 100644 --- a/src/Ryujinx/UI/Windows/ChangelogWindow.axaml.cs +++ b/src/Ryujinx/UI/Windows/ChangelogWindow.axaml.cs @@ -56,11 +56,9 @@ namespace Ryujinx.Ava.UI.Windows private static async Task FetchChangelogHtml() { - using (var client = new HttpClient()) - { - client.DefaultRequestHeaders.UserAgent.ParseAdd("Ryujinx-Updater/1.0.0"); - return await client.GetStringAsync("https://github.com/Ryujinx/Ryujinx/wiki/Changelog"); - } + using var client = new HttpClient(); + client.DefaultRequestHeaders.UserAgent.ParseAdd("Ryujinx-Updater/1.0.0"); + return await client.GetStringAsync("https://github.com/Ryujinx/Ryujinx/wiki/Changelog"); } private static string ParseChangelogForRecentVersions(string html, int count)