Merge 2953b87e58
into 5dbba07e33
This commit is contained in:
commit
98ffea24bf
7 changed files with 215 additions and 5 deletions
|
@ -17,6 +17,7 @@
|
|||
<PackageVersion Include="FluentAvaloniaUI" Version="2.0.5" />
|
||||
<PackageVersion Include="GtkSharp.Dependencies" Version="1.1.1" />
|
||||
<PackageVersion Include="GtkSharp.Dependencies.osx" Version="0.0.5" />
|
||||
<PackageVersion Include="HtmlAgilityPack" Version="1.11.60" />
|
||||
<PackageVersion Include="LibHac" Version="0.19.0" />
|
||||
<PackageVersion Include="Microsoft.CodeAnalysis.Analyzers" Version="3.3.4" />
|
||||
<PackageVersion Include="Microsoft.CodeAnalysis.CSharp" Version="4.9.2" />
|
||||
|
|
|
@ -775,8 +775,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.",
|
||||
|
|
|
@ -44,6 +44,7 @@
|
|||
<PackageReference Include="Avalonia.Svg.Skia" />
|
||||
<PackageReference Include="DynamicData" />
|
||||
<PackageReference Include="FluentAvaloniaUI" />
|
||||
<PackageReference Include="HtmlAgilityPack" />
|
||||
|
||||
<PackageReference Include="OpenTK.Core" />
|
||||
<PackageReference Include="Ryujinx.Audio.OpenAL.Dependencies" Condition="'$(RuntimeIdentifier)' != 'linux-x64' AND '$(RuntimeIdentifier)' != 'linux-arm64' AND '$(RuntimeIdentifier)' != 'osx-x64' AND '$(RuntimeIdentifier)' != 'osx-arm64'" />
|
||||
|
|
|
@ -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">
|
||||
<TextBlock
|
||||
FontSize="10"
|
||||
Text="{locale:Locale AboutChangelogButton}"
|
||||
|
@ -145,7 +144,6 @@
|
|||
Background="Transparent"
|
||||
Click="Button_OnClick"
|
||||
CornerRadius="15"
|
||||
Tag="https://github.com/Ryujinx/Ryujinx"
|
||||
ToolTip.Tip="{locale:Locale AboutGithubUrlTooltipMessage}">
|
||||
<Image Source="{Binding GithubLogo}" />
|
||||
</Button>
|
||||
|
|
|
@ -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;
|
||||
|
@ -52,6 +53,18 @@ namespace Ryujinx.Ava.UI.Windows
|
|||
}
|
||||
}
|
||||
|
||||
private void OpenChangelogWindow(object sender, RoutedEventArgs e)
|
||||
{
|
||||
ChangelogWindow changelogWindow = new ChangelogWindow();
|
||||
|
||||
// Find the parent window to use as the owner for the modal dialog
|
||||
var parentWindow = this.FindAncestorOfType<Window>();
|
||||
if (parentWindow != null)
|
||||
{
|
||||
changelogWindow.ShowDialog(parentWindow); // Pass the parent window as the owner
|
||||
}
|
||||
}
|
||||
|
||||
private void AmiiboLabel_OnPointerPressed(object sender, PointerPressedEventArgs e)
|
||||
{
|
||||
if (sender is TextBlock)
|
||||
|
|
42
src/Ryujinx/UI/Windows/ChangelogWindow.axaml
Normal file
42
src/Ryujinx/UI/Windows/ChangelogWindow.axaml
Normal file
|
@ -0,0 +1,42 @@
|
|||
<Window
|
||||
x:Class="Ryujinx.Ava.UI.Windows.ChangelogWindow"
|
||||
xmlns="https://github.com/avaloniaui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:locale="clr-namespace:Ryujinx.Ava.Common.Locale"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:ui="clr-namespace:FluentAvalonia.UI.Controls;assembly=FluentAvalonia"
|
||||
Width="800"
|
||||
Height="600"
|
||||
Margin="0,-12,0,0"
|
||||
d:DesignHeight="600"
|
||||
d:DesignWidth="800"
|
||||
CanResize="False"
|
||||
WindowStartupLocation="CenterOwner"
|
||||
Focusable="True"
|
||||
mc:Ignorable="d"
|
||||
Icon="resm:Ryujinx.UI.Common.Resources.Logo_Ryujinx.png?assembly=Ryujinx.UI.Common">
|
||||
<Grid HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
|
||||
<StackPanel Orientation="Vertical" Margin="20">
|
||||
<!-- Localized text block -->
|
||||
<TextBlock Text="{locale:Locale ChangelogDescription}"
|
||||
TextWrapping="Wrap"
|
||||
Margin="0,0,0,20"/>
|
||||
<!-- Changelog -->
|
||||
<TextBlock x:Name="LoadingTextBlock"
|
||||
Text="Loading..."
|
||||
HorizontalAlignment="Left"
|
||||
VerticalAlignment="Top"
|
||||
IsVisible="True"/>
|
||||
<ScrollViewer HorizontalScrollBarVisibility="Disabled"
|
||||
VerticalScrollBarVisibility="Auto"
|
||||
Height="500">
|
||||
<TextBlock x:Name="ChangelogTextBlock"
|
||||
TextWrapping="Wrap"
|
||||
HorizontalAlignment="Left"
|
||||
VerticalAlignment="Top"
|
||||
IsVisible="True"/>
|
||||
</ScrollViewer>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</Window>
|
153
src/Ryujinx/UI/Windows/ChangelogWindow.axaml.cs
Normal file
153
src/Ryujinx/UI/Windows/ChangelogWindow.axaml.cs
Normal file
|
@ -0,0 +1,153 @@
|
|||
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.Net.Http;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Button = Avalonia.Controls.Button;
|
||||
|
||||
|
||||
namespace Ryujinx.Ava.UI.Windows
|
||||
{
|
||||
public partial class ChangelogWindow : StyleableWindow
|
||||
{
|
||||
public ChangelogWindow()
|
||||
{
|
||||
DataContext = this;
|
||||
InitializeComponent();
|
||||
InitializeAsync();
|
||||
Title = $"Ryujinx {Program.Version} - " + LocaleManager.Instance[LocaleKeys.ChangelogWindowTitle];
|
||||
}
|
||||
|
||||
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<string> 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();
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Add table
Reference in a new issue