mirror of
https://git.ryujinx.app/ryubing/ryujinx.git
synced 2025-09-13 05:25:06 +00:00
Compare commits
25 Commits
Canary-1.2
...
Canary-1.2
Author | SHA1 | Date | |
---|---|---|---|
|
845c86f545 | ||
|
27993b789f | ||
|
bdd890cf6f | ||
|
c5574b41a1 | ||
|
292e27f0da | ||
|
606e149bd3 | ||
|
a8c3407d11 | ||
|
daa8168985 | ||
|
f580521e99 | ||
|
2226521f6c | ||
|
384416953d | ||
|
1343fabe41 | ||
|
1e52af5e29 | ||
|
672f5df0f9 | ||
|
804d9c1efe | ||
|
9270b35648 | ||
|
5a6d01db3c | ||
|
ef9c1416ec | ||
|
5efa7d5dfa | ||
|
a82569d615 | ||
|
ed5832ca73 | ||
|
574aa9ff9c | ||
|
8a29428de2 | ||
|
f4272b05fa | ||
|
d8265f7772 |
3422
docs/compatibility.csv
Normal file
3422
docs/compatibility.csv
Normal file
File diff suppressed because it is too large
Load Diff
@@ -402,7 +402,7 @@
|
|||||||
<x:Double x:Key="ControlContentThemeFontSize">13</x:Double>
|
<x:Double x:Key="ControlContentThemeFontSize">13</x:Double>
|
||||||
<x:Double x:Key="MenuItemHeight">26</x:Double>
|
<x:Double x:Key="MenuItemHeight">26</x:Double>
|
||||||
<x:Double x:Key="TabItemMinHeight">28</x:Double>
|
<x:Double x:Key="TabItemMinHeight">28</x:Double>
|
||||||
<x:Double x:Key="ContentDialogMaxWidth">700</x:Double>
|
<x:Double x:Key="ContentDialogMaxWidth">900</x:Double>
|
||||||
<x:Double x:Key="ContentDialogMaxHeight">756</x:Double>
|
<x:Double x:Key="ContentDialogMaxHeight">756</x:Double>
|
||||||
</Styles.Resources>
|
</Styles.Resources>
|
||||||
</Styles>
|
</Styles>
|
||||||
|
@@ -22597,6 +22597,31 @@
|
|||||||
"zh_TW": ""
|
"zh_TW": ""
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"ID": "CompatibilityListWarning",
|
||||||
|
"Translations": {
|
||||||
|
"ar_SA": "",
|
||||||
|
"de_DE": "",
|
||||||
|
"el_GR": "",
|
||||||
|
"en_US": "This compatibility list might contain out of date entries.\nDo not be opposed to testing games in the \"Ingame\" status.",
|
||||||
|
"es_ES": "",
|
||||||
|
"fr_FR": "",
|
||||||
|
"he_IL": "",
|
||||||
|
"it_IT": "",
|
||||||
|
"ja_JP": "",
|
||||||
|
"ko_KR": "",
|
||||||
|
"no_NO": "",
|
||||||
|
"pl_PL": "",
|
||||||
|
"pt_BR": "",
|
||||||
|
"ru_RU": "",
|
||||||
|
"sv_SE": "",
|
||||||
|
"th_TH": "",
|
||||||
|
"tr_TR": "",
|
||||||
|
"uk_UA": "",
|
||||||
|
"zh_CN": "",
|
||||||
|
"zh_TW": ""
|
||||||
|
}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"ID": "CompatibilityListSearchBoxWatermark",
|
"ID": "CompatibilityListSearchBoxWatermark",
|
||||||
"Translations": {
|
"Translations": {
|
||||||
|
@@ -145,6 +145,9 @@
|
|||||||
<EmbeddedResource Include="..\..\distribution\macos\shortcut-template.plist">
|
<EmbeddedResource Include="..\..\distribution\macos\shortcut-template.plist">
|
||||||
<Link>Assets\ShortcutFiles\shortcut-template.plist</Link>
|
<Link>Assets\ShortcutFiles\shortcut-template.plist</Link>
|
||||||
</EmbeddedResource>
|
</EmbeddedResource>
|
||||||
|
<EmbeddedResource Include="..\..\docs\compatibility.csv" LogicalName="RyujinxGameCompatibilityList">
|
||||||
|
<Link>Assets\RyujinxGameCompatibility.csv</Link>
|
||||||
|
</EmbeddedResource>
|
||||||
<EmbeddedResource Include="Assets\locales.json" />
|
<EmbeddedResource Include="Assets\locales.json" />
|
||||||
<EmbeddedResource Include="Assets\Styles\Styles.xaml" />
|
<EmbeddedResource Include="Assets\Styles\Styles.xaml" />
|
||||||
<EmbeddedResource Include="Assets\Icons\Controller_JoyConLeft.svg" />
|
<EmbeddedResource Include="Assets\Icons\Controller_JoyConLeft.svg" />
|
||||||
@@ -168,12 +171,6 @@
|
|||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<AdditionalFiles Include="Assets\locales.json" />
|
<AdditionalFiles Include="Assets\locales.json" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
|
||||||
<Compile Update="Utilities\Compat\CompatibilityContentDialog.axaml.cs">
|
|
||||||
<DependentUpon>CompatibilityContentDialog.axaml</DependentUpon>
|
|
||||||
<SubType>Code</SubType>
|
|
||||||
</Compile>
|
|
||||||
</ItemGroup>
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Folder Include="Assets\Fonts\Mono\" />
|
<Folder Include="Assets\Fonts\Mono\" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
@@ -63,6 +63,7 @@ namespace Ryujinx.Ava.UI.Helpers
|
|||||||
public static MiniCommand Create(Action callback) => new MiniCommand<object>(_ => callback());
|
public static MiniCommand Create(Action callback) => new MiniCommand<object>(_ => callback());
|
||||||
public static MiniCommand Create<TArg>(Action<TArg> callback) => new MiniCommand<TArg>(callback);
|
public static MiniCommand Create<TArg>(Action<TArg> callback) => new MiniCommand<TArg>(callback);
|
||||||
public static MiniCommand CreateFromTask(Func<Task> callback) => new MiniCommand<object>(_ => callback());
|
public static MiniCommand CreateFromTask(Func<Task> callback) => new MiniCommand<object>(_ => callback());
|
||||||
|
public static MiniCommand CreateFromTask<TArg>(Func<TArg, Task> callback) => new MiniCommand<TArg>(callback);
|
||||||
|
|
||||||
public abstract bool CanExecute(object parameter);
|
public abstract bool CanExecute(object parameter);
|
||||||
public abstract void Execute(object parameter);
|
public abstract void Execute(object parameter);
|
||||||
|
@@ -12,8 +12,8 @@ namespace Ryujinx.Ava.UI.Helpers
|
|||||||
private static readonly Lazy<PlayabilityStatusConverter> _shared = new(() => new());
|
private static readonly Lazy<PlayabilityStatusConverter> _shared = new(() => new());
|
||||||
public static PlayabilityStatusConverter Shared => _shared.Value;
|
public static PlayabilityStatusConverter Shared => _shared.Value;
|
||||||
|
|
||||||
public object Convert(object? value, Type _, object? __, CultureInfo ___) =>
|
public object Convert(object value, Type _, object __, CultureInfo ___)
|
||||||
value.Cast<LocaleKeys>() switch
|
=> value.Cast<LocaleKeys>() switch
|
||||||
{
|
{
|
||||||
LocaleKeys.CompatibilityListNothing or
|
LocaleKeys.CompatibilityListNothing or
|
||||||
LocaleKeys.CompatibilityListBoots or
|
LocaleKeys.CompatibilityListBoots or
|
||||||
@@ -22,7 +22,7 @@ namespace Ryujinx.Ava.UI.Helpers
|
|||||||
_ => Brushes.ForestGreen
|
_ => Brushes.ForestGreen
|
||||||
};
|
};
|
||||||
|
|
||||||
public object ConvertBack(object? value, Type _, object? __, CultureInfo ___)
|
public object ConvertBack(object value, Type _, object __, CultureInfo ___)
|
||||||
=> throw new NotSupportedException();
|
=> throw new NotSupportedException();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -741,7 +741,10 @@ namespace Ryujinx.Ava.UI.ViewModels
|
|||||||
Applications.ToObservableChangeSet()
|
Applications.ToObservableChangeSet()
|
||||||
.Filter(Filter)
|
.Filter(Filter)
|
||||||
.Sort(GetComparer())
|
.Sort(GetComparer())
|
||||||
.Bind(out _appsObservableList).AsObservableList();
|
#pragma warning disable MVVMTK0034
|
||||||
|
.Bind(out _appsObservableList)
|
||||||
|
#pragma warning enable MVVMTK0034
|
||||||
|
.AsObservableList();
|
||||||
|
|
||||||
OnPropertyChanged(nameof(AppsObservableList));
|
OnPropertyChanged(nameof(AppsObservableList));
|
||||||
}
|
}
|
||||||
|
@@ -66,7 +66,7 @@ namespace Ryujinx.Ava.UI.Views.Main
|
|||||||
WindowSize2160PMenuItem.Command = new RelayCommand<string>(ChangeWindowSize);
|
WindowSize2160PMenuItem.Command = new RelayCommand<string>(ChangeWindowSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
private CheckBox[] GenerateToggleFileTypeItems() =>
|
private IEnumerable<CheckBox> GenerateToggleFileTypeItems() =>
|
||||||
Enum.GetValues<FileTypes>()
|
Enum.GetValues<FileTypes>()
|
||||||
.Select(it => (FileName: Enum.GetName(it)!, FileType: it))
|
.Select(it => (FileName: Enum.GetName(it)!, FileType: it))
|
||||||
.Select(it =>
|
.Select(it =>
|
||||||
@@ -76,15 +76,13 @@ namespace Ryujinx.Ava.UI.Views.Main
|
|||||||
IsChecked = it.FileType.GetConfigValue(ConfigurationState.Instance.UI.ShownFileTypes),
|
IsChecked = it.FileType.GetConfigValue(ConfigurationState.Instance.UI.ShownFileTypes),
|
||||||
Command = MiniCommand.Create(() => Window.ToggleFileType(it.FileName))
|
Command = MiniCommand.Create(() => Window.ToggleFileType(it.FileName))
|
||||||
}
|
}
|
||||||
).ToArray();
|
);
|
||||||
|
|
||||||
private static MenuItem[] GenerateLanguageMenuItems()
|
private static IEnumerable<MenuItem> GenerateLanguageMenuItems()
|
||||||
{
|
{
|
||||||
List<MenuItem> menuItems = new();
|
const string LocalePath = "Ryujinx/Assets/locales.json";
|
||||||
|
|
||||||
string localePath = "Ryujinx/Assets/locales.json";
|
string languageJson = EmbeddedResources.ReadAllText(LocalePath);
|
||||||
|
|
||||||
string languageJson = EmbeddedResources.ReadAllText(localePath);
|
|
||||||
|
|
||||||
LocalesJson locales = JsonHelper.Deserialize(languageJson, LocalesJsonContext.Default.LocalesJson);
|
LocalesJson locales = JsonHelper.Deserialize(languageJson, LocalesJsonContext.Default.LocalesJson);
|
||||||
|
|
||||||
@@ -99,7 +97,10 @@ namespace Ryujinx.Ava.UI.Views.Main
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
languageName = locales.Locales[index].Translations[language] == "" ? language : locales.Locales[index].Translations[language];
|
string tr = locales.Locales[index].Translations[language];
|
||||||
|
languageName = string.IsNullOrEmpty(tr)
|
||||||
|
? language
|
||||||
|
: tr;
|
||||||
}
|
}
|
||||||
|
|
||||||
MenuItem menuItem = new()
|
MenuItem menuItem = new()
|
||||||
@@ -111,10 +112,8 @@ namespace Ryujinx.Ava.UI.Views.Main
|
|||||||
Command = MiniCommand.Create(() => MainWindowViewModel.ChangeLanguage(language))
|
Command = MiniCommand.Create(() => MainWindowViewModel.ChangeLanguage(language))
|
||||||
};
|
};
|
||||||
|
|
||||||
menuItems.Add(menuItem);
|
yield return menuItem;
|
||||||
}
|
}
|
||||||
|
|
||||||
return menuItems.ToArray();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnAttachedToVisualTree(VisualTreeAttachmentEventArgs e)
|
protected override void OnAttachedToVisualTree(VisualTreeAttachmentEventArgs e)
|
||||||
|
@@ -32,29 +32,27 @@ namespace Ryujinx.Ava.Utilities
|
|||||||
|
|
||||||
public string GetContentPath(ContentManager contentManager)
|
public string GetContentPath(ContentManager contentManager)
|
||||||
=> (contentManager ?? _contentManager)
|
=> (contentManager ?? _contentManager)
|
||||||
.GetInstalledContentPath(ProgramId, StorageId.BuiltInSystem, NcaContentType.Program);
|
?.GetInstalledContentPath(ProgramId, StorageId.BuiltInSystem, NcaContentType.Program);
|
||||||
|
|
||||||
public bool CanStart(ContentManager contentManager, out ApplicationData appData,
|
public bool CanStart(ContentManager contentManager, out ApplicationData appData,
|
||||||
out BlitStruct<ApplicationControlProperty> appControl)
|
out BlitStruct<ApplicationControlProperty> appControl)
|
||||||
{
|
{
|
||||||
contentManager ??= _contentManager;
|
contentManager ??= _contentManager;
|
||||||
if (contentManager == null)
|
if (contentManager == null)
|
||||||
{
|
goto BadData;
|
||||||
appData = null;
|
|
||||||
appControl = new BlitStruct<ApplicationControlProperty>(0);
|
string contentPath = GetContentPath(contentManager);
|
||||||
return false;
|
if (string.IsNullOrEmpty(contentPath))
|
||||||
}
|
goto BadData;
|
||||||
|
|
||||||
appData = new() { Name = Name, Id = ProgramId, Path = GetContentPath(contentManager) };
|
appData = new() { Name = Name, Id = ProgramId, Path = GetContentPath(contentManager) };
|
||||||
|
|
||||||
if (string.IsNullOrEmpty(appData.Path))
|
|
||||||
{
|
|
||||||
appControl = new BlitStruct<ApplicationControlProperty>(0);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
appControl = StructHelpers.CreateCustomNacpData(Name, Version);
|
appControl = StructHelpers.CreateCustomNacpData(Name, Version);
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
|
BadData:
|
||||||
|
appData = null;
|
||||||
|
appControl = new BlitStruct<ApplicationControlProperty>(0);
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,20 +0,0 @@
|
|||||||
<ui:ContentDialog xmlns="https://github.com/avaloniaui"
|
|
||||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
|
||||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
|
||||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
|
||||||
xmlns:local="using:Ryujinx.Ava.Utilities.Compat"
|
|
||||||
xmlns:ui="using:FluentAvalonia.UI.Controls"
|
|
||||||
xmlns:ext="using:Ryujinx.Ava.Common.Markup"
|
|
||||||
x:Class="Ryujinx.Ava.Utilities.Compat.CompatibilityContentDialog"
|
|
||||||
mc:Ignorable="d" d:DesignWidth="600" d:DesignHeight="400"
|
|
||||||
CloseButtonText="{ext:Locale SettingsButtonClose}"
|
|
||||||
DefaultButton="Close"
|
|
||||||
x:DataType="local:CompatibilityViewModel">
|
|
||||||
<ui:ContentDialog.DataContext>
|
|
||||||
<local:CompatibilityViewModel/>
|
|
||||||
</ui:ContentDialog.DataContext>
|
|
||||||
<ui:ContentDialog.Resources>
|
|
||||||
<x:Double x:Key="ContentDialogMaxWidth">900</x:Double>
|
|
||||||
</ui:ContentDialog.Resources>
|
|
||||||
</ui:ContentDialog>
|
|
||||||
|
|
@@ -1,13 +0,0 @@
|
|||||||
using FluentAvalonia.UI.Controls;
|
|
||||||
using System;
|
|
||||||
|
|
||||||
namespace Ryujinx.Ava.Utilities.Compat
|
|
||||||
{
|
|
||||||
public partial class CompatibilityContentDialog : ContentDialog
|
|
||||||
{
|
|
||||||
protected override Type StyleKeyOverride => typeof(ContentDialog);
|
|
||||||
|
|
||||||
public CompatibilityContentDialog() => InitializeComponent();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@@ -1,52 +1,65 @@
|
|||||||
using Gommon;
|
using Gommon;
|
||||||
using nietras.SeparatedValues;
|
using nietras.SeparatedValues;
|
||||||
using Ryujinx.Ava.Common.Locale;
|
using Ryujinx.Ava.Common.Locale;
|
||||||
|
using Ryujinx.Common.Logging;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Reflection;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
|
||||||
namespace Ryujinx.Ava.Utilities.Compat
|
namespace Ryujinx.Ava.Utilities.Compat
|
||||||
{
|
{
|
||||||
|
public struct ColumnIndices(Func<ReadOnlySpan<char>, int> getIndex)
|
||||||
|
{
|
||||||
|
public const string TitleIdCol = "\"title_id\"";
|
||||||
|
public const string GameNameCol = "\"game_name\"";
|
||||||
|
public const string LabelsCol = "\"labels\"";
|
||||||
|
public const string StatusCol = "\"status\"";
|
||||||
|
public const string LastUpdatedCol = "\"last_updated\"";
|
||||||
|
|
||||||
|
public readonly int TitleId = getIndex(TitleIdCol);
|
||||||
|
public readonly int GameName = getIndex(GameNameCol);
|
||||||
|
public readonly int Labels = getIndex(LabelsCol);
|
||||||
|
public readonly int Status = getIndex(StatusCol);
|
||||||
|
public readonly int LastUpdated = getIndex(LastUpdatedCol);
|
||||||
|
}
|
||||||
|
|
||||||
public class CompatibilityCsv
|
public class CompatibilityCsv
|
||||||
{
|
{
|
||||||
public static CompatibilityCsv Shared { get; set; }
|
static CompatibilityCsv()
|
||||||
|
|
||||||
public CompatibilityCsv(SepReader reader)
|
|
||||||
{
|
{
|
||||||
var entries = new List<CompatibilityEntry>();
|
using Stream csvStream = Assembly.GetExecutingAssembly()
|
||||||
|
.GetManifestResourceStream("RyujinxGameCompatibilityList")!;
|
||||||
|
csvStream.Position = 0;
|
||||||
|
|
||||||
foreach (var row in reader)
|
using SepReader reader = Sep.Reader().From(csvStream);
|
||||||
{
|
ColumnIndices columnIndices = new(reader.Header.IndexOf);
|
||||||
entries.Add(new CompatibilityEntry(reader.Header, row));
|
|
||||||
}
|
|
||||||
|
|
||||||
Entries = entries.Where(x => x.Status != null)
|
Entries = reader
|
||||||
.OrderBy(it => it.GameName).ToArray();
|
.Enumerate(row => new CompatibilityEntry(ref columnIndices, row))
|
||||||
|
.OrderBy(it => it.GameName)
|
||||||
|
.ToArray();
|
||||||
|
|
||||||
|
Logger.Debug?.Print(LogClass.UI, "Compatibility CSV loaded.", "LoadCompatCsv");
|
||||||
}
|
}
|
||||||
|
|
||||||
public CompatibilityEntry[] Entries { get; }
|
public static CompatibilityEntry[] Entries { get; private set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public class CompatibilityEntry
|
public class CompatibilityEntry
|
||||||
{
|
{
|
||||||
public CompatibilityEntry(SepReaderHeader header, SepReader.Row row)
|
public CompatibilityEntry(ref ColumnIndices indices, SepReader.Row row)
|
||||||
{
|
{
|
||||||
IssueNumber = row[header.IndexOf("issue_number")].Parse<int>();
|
string titleIdRow = ColStr(row[indices.TitleId]);
|
||||||
|
|
||||||
var titleIdRow = row[header.IndexOf("extracted_game_id")].ToString();
|
|
||||||
TitleId = !string.IsNullOrEmpty(titleIdRow)
|
TitleId = !string.IsNullOrEmpty(titleIdRow)
|
||||||
? titleIdRow
|
? titleIdRow
|
||||||
: default(Optional<string>);
|
: default(Optional<string>);
|
||||||
|
|
||||||
|
GameName = ColStr(row[indices.GameName]).Trim().Trim('"');
|
||||||
|
|
||||||
var issueTitleRow = row[header.IndexOf("issue_title")].ToString();
|
Labels = ColStr(row[indices.Labels]).Split(';');
|
||||||
if (TitleId.HasValue)
|
Status = ColStr(row[indices.Status]).ToLower() switch
|
||||||
issueTitleRow = issueTitleRow.ReplaceIgnoreCase($" - {TitleId}", string.Empty);
|
|
||||||
|
|
||||||
GameName = issueTitleRow.Trim().Trim('"');
|
|
||||||
|
|
||||||
IssueLabels = row[header.IndexOf("issue_labels")].ToString().Split(';');
|
|
||||||
Status = row[header.IndexOf("extracted_status")].ToString().ToLower() switch
|
|
||||||
{
|
{
|
||||||
"playable" => LocaleKeys.CompatibilityListPlayable,
|
"playable" => LocaleKeys.CompatibilityListPlayable,
|
||||||
"ingame" => LocaleKeys.CompatibilityListIngame,
|
"ingame" => LocaleKeys.CompatibilityListIngame,
|
||||||
@@ -56,39 +69,37 @@ namespace Ryujinx.Ava.Utilities.Compat
|
|||||||
_ => null
|
_ => null
|
||||||
};
|
};
|
||||||
|
|
||||||
if (row[header.IndexOf("last_event_date")].TryParse<DateTime>(out var dt))
|
if (DateTime.TryParse(ColStr(row[indices.LastUpdated]), out var dt))
|
||||||
LastEvent = dt;
|
LastUpdated = dt;
|
||||||
|
|
||||||
if (row[header.IndexOf("events_count")].TryParse<int>(out var eventsCount))
|
return;
|
||||||
EventCount = eventsCount;
|
|
||||||
|
string ColStr(SepReader.Col col) => col.ToString().Trim('"');
|
||||||
}
|
}
|
||||||
|
|
||||||
public int IssueNumber { get; }
|
|
||||||
public string GameName { get; }
|
public string GameName { get; }
|
||||||
public Optional<string> TitleId { get; }
|
public Optional<string> TitleId { get; }
|
||||||
public string[] IssueLabels { get; }
|
public string[] Labels { get; }
|
||||||
public LocaleKeys? Status { get; }
|
public LocaleKeys? Status { get; }
|
||||||
public DateTime LastEvent { get; }
|
public DateTime LastUpdated { get; }
|
||||||
public int EventCount { get; }
|
|
||||||
|
|
||||||
public string LocalizedStatus => LocaleManager.Instance[Status!.Value];
|
public string LocalizedStatus => LocaleManager.Instance[Status!.Value];
|
||||||
public string FormattedTitleId => TitleId.OrElse(new string(' ', 16));
|
public string FormattedTitleId => TitleId
|
||||||
|
.OrElse(new string(' ', 16));
|
||||||
|
|
||||||
public string FormattedIssueLabels => IssueLabels
|
public string FormattedIssueLabels => Labels
|
||||||
.Where(it => !it.StartsWithIgnoreCase("status"))
|
.Where(it => !it.StartsWithIgnoreCase("status"))
|
||||||
.Select(FormatLabelName)
|
.Select(FormatLabelName)
|
||||||
.JoinToString(", ");
|
.JoinToString(", ");
|
||||||
|
|
||||||
public override string ToString()
|
public override string ToString()
|
||||||
{
|
{
|
||||||
var sb = new StringBuilder("CompatibilityEntry: {");
|
StringBuilder sb = new("CompatibilityEntry: {");
|
||||||
sb.Append($"{nameof(IssueNumber)}={IssueNumber}, ");
|
|
||||||
sb.Append($"{nameof(GameName)}=\"{GameName}\", ");
|
sb.Append($"{nameof(GameName)}=\"{GameName}\", ");
|
||||||
sb.Append($"{nameof(TitleId)}={TitleId}, ");
|
sb.Append($"{nameof(TitleId)}={TitleId}, ");
|
||||||
sb.Append($"{nameof(IssueLabels)}=\"{IssueLabels}\", ");
|
sb.Append($"{nameof(Labels)}=\"{Labels}\", ");
|
||||||
sb.Append($"{nameof(Status)}=\"{Status}\", ");
|
sb.Append($"{nameof(Status)}=\"{Status}\", ");
|
||||||
sb.Append($"{nameof(LastEvent)}=\"{LastEvent}\", ");
|
sb.Append($"{nameof(LastUpdated)}=\"{LastUpdated}\"");
|
||||||
sb.Append($"{nameof(EventCount)}={EventCount}");
|
|
||||||
sb.Append('}');
|
sb.Append('}');
|
||||||
|
|
||||||
return sb.ToString();
|
return sb.ToString();
|
||||||
@@ -144,8 +155,8 @@ namespace Ryujinx.Ava.Utilities.Compat
|
|||||||
if (value == string.Empty)
|
if (value == string.Empty)
|
||||||
return string.Empty;
|
return string.Empty;
|
||||||
|
|
||||||
var firstChar = value[0];
|
char firstChar = value[0];
|
||||||
var rest = value[1..];
|
string rest = value[1..];
|
||||||
|
|
||||||
return $"{char.ToUpper(firstChar)}{rest}";
|
return $"{char.ToUpper(firstChar)}{rest}";
|
||||||
}
|
}
|
||||||
|
@@ -1,32 +0,0 @@
|
|||||||
using Gommon;
|
|
||||||
using nietras.SeparatedValues;
|
|
||||||
using Ryujinx.Common.Configuration;
|
|
||||||
using System.Net.Http;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace Ryujinx.Ava.Utilities.Compat
|
|
||||||
{
|
|
||||||
public static class CompatibilityHelper
|
|
||||||
{
|
|
||||||
private static readonly string _downloadUrl =
|
|
||||||
"https://gist.githubusercontent.com/ezhevita/b41ed3bf64d0cc01269cab036e884f3d/raw/002b1a1c1a5f7a83276625e8c479c987a5f5b722/Ryujinx%2520Games%2520List%2520Compatibility.csv";
|
|
||||||
|
|
||||||
private static readonly FilePath _compatCsvPath = new FilePath(AppDataManager.BaseDirPath) / "system" / "compatibility.csv";
|
|
||||||
|
|
||||||
public static async Task<SepReader> DownloadAsync()
|
|
||||||
{
|
|
||||||
if (_compatCsvPath.ExistsAsFile)
|
|
||||||
return Sep.Reader().FromFile(_compatCsvPath.Path);
|
|
||||||
|
|
||||||
using var httpClient = new HttpClient();
|
|
||||||
var compatCsv = await httpClient.GetStringAsync(_downloadUrl);
|
|
||||||
_compatCsvPath.WriteAllText(compatCsv);
|
|
||||||
return Sep.Reader().FromText(compatCsv);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static async Task InitAsync()
|
|
||||||
{
|
|
||||||
CompatibilityCsv.Shared = new CompatibilityCsv(await DownloadAsync());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@@ -4,6 +4,7 @@
|
|||||||
xmlns:local="using:Ryujinx.Ava.Utilities.Compat"
|
xmlns:local="using:Ryujinx.Ava.Utilities.Compat"
|
||||||
xmlns:helpers="using:Ryujinx.Ava.UI.Helpers"
|
xmlns:helpers="using:Ryujinx.Ava.UI.Helpers"
|
||||||
xmlns:ext="using:Ryujinx.Ava.Common.Markup"
|
xmlns:ext="using:Ryujinx.Ava.Common.Markup"
|
||||||
|
xmlns:ui="using:FluentAvalonia.UI.Controls"
|
||||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
|
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
|
||||||
x:Class="Ryujinx.Ava.Utilities.Compat.CompatibilityList"
|
x:Class="Ryujinx.Ava.Utilities.Compat.CompatibilityList"
|
||||||
@@ -11,13 +12,33 @@
|
|||||||
<UserControl.DataContext>
|
<UserControl.DataContext>
|
||||||
<local:CompatibilityViewModel />
|
<local:CompatibilityViewModel />
|
||||||
</UserControl.DataContext>
|
</UserControl.DataContext>
|
||||||
<Grid RowDefinitions="Auto,*">
|
<Grid RowDefinitions="*,Auto,*">
|
||||||
<Grid Grid.Row="0" ColumnDefinitions="*,Auto,Auto">
|
<Grid
|
||||||
|
Grid.Row="0"
|
||||||
|
HorizontalAlignment="Center"
|
||||||
|
ColumnDefinitions="Auto,*"
|
||||||
|
Margin="0 0 0 10">
|
||||||
|
<ui:FontIcon
|
||||||
|
Grid.Column="0"
|
||||||
|
Margin="0"
|
||||||
|
HorizontalAlignment="Stretch"
|
||||||
|
FontFamily="avares://FluentAvalonia/Fonts#Symbols"
|
||||||
|
Glyph="{helpers:GlyphValueConverter Important}" />
|
||||||
|
<!-- NOTE: aligning to bottom for better visual alignment with glyph -->
|
||||||
|
<TextBlock
|
||||||
|
Grid.Column="1"
|
||||||
|
Margin="5, 0, 0, 0"
|
||||||
|
FontStyle="Italic"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
TextWrapping="Wrap"
|
||||||
|
Text="{ext:Locale CompatibilityListWarning}" />
|
||||||
|
</Grid>
|
||||||
|
<Grid Grid.Row="1" ColumnDefinitions="*,Auto,Auto">
|
||||||
<TextBox Grid.Column="0" HorizontalAlignment="Stretch" Watermark="{ext:Locale CompatibilityListSearchBoxWatermark}" TextChanged="TextBox_OnTextChanged" />
|
<TextBox Grid.Column="0" HorizontalAlignment="Stretch" Watermark="{ext:Locale CompatibilityListSearchBoxWatermark}" TextChanged="TextBox_OnTextChanged" />
|
||||||
<CheckBox Grid.Column="1" Margin="7, 0, 0, 0" IsChecked="{Binding OnlyShowOwnedGames}" />
|
<CheckBox Grid.Column="1" Margin="7, 0, 0, 0" IsChecked="{Binding OnlyShowOwnedGames}" />
|
||||||
<TextBlock Grid.Column="2" Margin="-10, 0, 0, 0" Text="{ext:Locale CompatibilityListOnlyShowOwnedGames}" />
|
<TextBlock Grid.Column="2" Margin="-10, 0, 0, 0" Text="{ext:Locale CompatibilityListOnlyShowOwnedGames}" />
|
||||||
</Grid>
|
</Grid>
|
||||||
<ScrollViewer Grid.Row="1">
|
<ScrollViewer Grid.Row="2">
|
||||||
<ListBox Margin="0,5, 0, 0"
|
<ListBox Margin="0,5, 0, 0"
|
||||||
Background="Transparent"
|
Background="Transparent"
|
||||||
ItemsSource="{Binding CurrentEntries}">
|
ItemsSource="{Binding CurrentEntries}">
|
||||||
@@ -26,9 +47,8 @@
|
|||||||
<Grid Width="750" ColumnDefinitions="Auto,Auto,Auto,*"
|
<Grid Width="750" ColumnDefinitions="Auto,Auto,Auto,*"
|
||||||
Margin="5">
|
Margin="5">
|
||||||
<TextBlock Grid.Column="0"
|
<TextBlock Grid.Column="0"
|
||||||
FontFamily="{StaticResource JetBrainsMono}"
|
|
||||||
Text="{Binding GameName}"
|
Text="{Binding GameName}"
|
||||||
Width="333"
|
Width="320"
|
||||||
TextWrapping="Wrap" />
|
TextWrapping="Wrap" />
|
||||||
<TextBlock Grid.Column="1"
|
<TextBlock Grid.Column="1"
|
||||||
Width="135"
|
Width="135"
|
||||||
@@ -39,14 +59,12 @@
|
|||||||
<TextBlock Grid.Column="2"
|
<TextBlock Grid.Column="2"
|
||||||
Padding="7, 0"
|
Padding="7, 0"
|
||||||
VerticalAlignment="Center"
|
VerticalAlignment="Center"
|
||||||
FontFamily="{StaticResource JetBrainsMono}"
|
|
||||||
Text="{Binding LocalizedStatus}"
|
Text="{Binding LocalizedStatus}"
|
||||||
Width="85"
|
Width="85"
|
||||||
Foreground="{Binding Status, Converter={x:Static helpers:PlayabilityStatusConverter.Shared}}"
|
Foreground="{Binding Status, Converter={x:Static helpers:PlayabilityStatusConverter.Shared}}"
|
||||||
TextWrapping="NoWrap" />
|
TextWrapping="NoWrap" />
|
||||||
<TextBlock Grid.Column="3"
|
<TextBlock Grid.Column="3"
|
||||||
VerticalAlignment="Center"
|
VerticalAlignment="Center"
|
||||||
FontFamily="{StaticResource JetBrainsMono}"
|
|
||||||
Text="{Binding FormattedIssueLabels}"
|
Text="{Binding FormattedIssueLabels}"
|
||||||
TextWrapping="WrapWithOverflow" />
|
TextWrapping="WrapWithOverflow" />
|
||||||
</Grid>
|
</Grid>
|
||||||
|
@@ -1,6 +1,11 @@
|
|||||||
using Avalonia.Controls;
|
using Avalonia.Controls;
|
||||||
using Avalonia.Styling;
|
using Avalonia.Styling;
|
||||||
|
using FluentAvalonia.UI.Controls;
|
||||||
|
using nietras.SeparatedValues;
|
||||||
|
using Ryujinx.Ava.Common.Locale;
|
||||||
using Ryujinx.Ava.UI.Helpers;
|
using Ryujinx.Ava.UI.Helpers;
|
||||||
|
using System.IO;
|
||||||
|
using System.Reflection;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace Ryujinx.Ava.Utilities.Compat
|
namespace Ryujinx.Ava.Utilities.Compat
|
||||||
@@ -9,11 +14,15 @@ namespace Ryujinx.Ava.Utilities.Compat
|
|||||||
{
|
{
|
||||||
public static async Task Show()
|
public static async Task Show()
|
||||||
{
|
{
|
||||||
await CompatibilityHelper.InitAsync();
|
ContentDialog contentDialog = new()
|
||||||
|
|
||||||
CompatibilityContentDialog contentDialog = new()
|
|
||||||
{
|
{
|
||||||
Content = new CompatibilityList { DataContext = new CompatibilityViewModel(RyujinxApp.MainWindow.ViewModel.ApplicationLibrary) }
|
PrimaryButtonText = string.Empty,
|
||||||
|
SecondaryButtonText = string.Empty,
|
||||||
|
CloseButtonText = LocaleManager.Instance[LocaleKeys.SettingsButtonClose],
|
||||||
|
Content = new CompatibilityList
|
||||||
|
{
|
||||||
|
DataContext = new CompatibilityViewModel(RyujinxApp.MainWindow.ViewModel.ApplicationLibrary)
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
Style closeButton = new(x => x.Name("CloseButton"));
|
Style closeButton = new(x => x.Name("CloseButton"));
|
||||||
@@ -33,7 +42,7 @@ namespace Ryujinx.Ava.Utilities.Compat
|
|||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void TextBox_OnTextChanged(object? sender, TextChangedEventArgs e)
|
private void TextBox_OnTextChanged(object sender, TextChangedEventArgs e)
|
||||||
{
|
{
|
||||||
if (DataContext is not CompatibilityViewModel cvm)
|
if (DataContext is not CompatibilityViewModel cvm)
|
||||||
return;
|
return;
|
||||||
|
@@ -11,14 +11,13 @@ namespace Ryujinx.Ava.Utilities.Compat
|
|||||||
{
|
{
|
||||||
[ObservableProperty] private bool _onlyShowOwnedGames = true;
|
[ObservableProperty] private bool _onlyShowOwnedGames = true;
|
||||||
|
|
||||||
private IEnumerable<CompatibilityEntry> _currentEntries = CompatibilityCsv.Shared.Entries;
|
private IEnumerable<CompatibilityEntry> _currentEntries = CompatibilityCsv.Entries;
|
||||||
private readonly string[] _ownedGameTitleIds = [];
|
private readonly string[] _ownedGameTitleIds = [];
|
||||||
private readonly ApplicationLibrary _appLibrary;
|
private readonly ApplicationLibrary _appLibrary;
|
||||||
|
|
||||||
public IEnumerable<CompatibilityEntry> CurrentEntries => OnlyShowOwnedGames
|
public IEnumerable<CompatibilityEntry> CurrentEntries => OnlyShowOwnedGames
|
||||||
? _currentEntries.Where(x =>
|
? _currentEntries.Where(x =>
|
||||||
x.TitleId.Check(tid => _ownedGameTitleIds.ContainsIgnoreCase(tid))
|
x.TitleId.Check(tid => _ownedGameTitleIds.ContainsIgnoreCase(tid)))
|
||||||
|| _appLibrary.Applications.Items.Any(a => a.Name.EqualsIgnoreCase(x.GameName)))
|
|
||||||
: _currentEntries;
|
: _currentEntries;
|
||||||
|
|
||||||
public CompatibilityViewModel() {}
|
public CompatibilityViewModel() {}
|
||||||
@@ -39,11 +38,11 @@ namespace Ryujinx.Ava.Utilities.Compat
|
|||||||
{
|
{
|
||||||
if (string.IsNullOrEmpty(searchTerm))
|
if (string.IsNullOrEmpty(searchTerm))
|
||||||
{
|
{
|
||||||
SetEntries(CompatibilityCsv.Shared.Entries);
|
SetEntries(CompatibilityCsv.Entries);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
SetEntries(CompatibilityCsv.Shared.Entries.Where(x =>
|
SetEntries(CompatibilityCsv.Entries.Where(x =>
|
||||||
x.GameName.ContainsIgnoreCase(searchTerm)
|
x.GameName.ContainsIgnoreCase(searchTerm)
|
||||||
|| x.TitleId.Check(tid => tid.ContainsIgnoreCase(searchTerm))));
|
|| x.TitleId.Check(tid => tid.ContainsIgnoreCase(searchTerm))));
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user