Compare commits

..

5 Commits

Author SHA1 Message Date
Daenorth 2666a15ffb Merge branch 'master' into master 2025-01-08 19:51:36 +01:00
Evan Husted bc6de21846 unnecessary escaping 2025-01-08 05:50:34 -06:00
Daenorth 8052a5480c no_No Norwegian locales update 2025-01-08 12:34:08 +01:00
Daenorth 2df1d50901 Merge branch 'Ryubing:master' into master 2025-01-08 12:13:27 +01:00
Daenorth 95a8890bc2 Update to no_NO Norwegian Translation with new resync & Metal backend text. 2024-12-31 16:56:41 +01:00
8 changed files with 3506 additions and 3501 deletions
+3433 -3422
View File
File diff suppressed because it is too large Load Diff
+10 -10
View File
@@ -10435,7 +10435,7 @@
"it_IT": "Finestra di input", "it_IT": "Finestra di input",
"ja_JP": "入力ダイアログ", "ja_JP": "入力ダイアログ",
"ko_KR": "대화 상자 입력", "ko_KR": "대화 상자 입력",
"no_NO": "", "no_NO": "Dialogboksen Inndata",
"pl_PL": "Okno Dialogowe Wprowadzania", "pl_PL": "Okno Dialogowe Wprowadzania",
"pt_BR": "Diálogo de texto", "pt_BR": "Diálogo de texto",
"ru_RU": "Диалоговое окно ввода", "ru_RU": "Диалоговое окно ввода",
@@ -22610,7 +22610,7 @@
"it_IT": "", "it_IT": "",
"ja_JP": "", "ja_JP": "",
"ko_KR": "", "ko_KR": "",
"no_NO": "", "no_NO": "Denne kompatibilitetslisten kan inneholde oppføringer som er tomme for data.\nVær ikke imot å teste spill i statusen «Ingame».",
"pl_PL": "", "pl_PL": "",
"pt_BR": "", "pt_BR": "",
"ru_RU": "", "ru_RU": "",
@@ -22635,7 +22635,7 @@
"it_IT": "", "it_IT": "",
"ja_JP": "", "ja_JP": "",
"ko_KR": "", "ko_KR": "",
"no_NO": "", "no_NO": "Søk i kompatibilitetsoppføringer...",
"pl_PL": "", "pl_PL": "",
"pt_BR": "", "pt_BR": "",
"ru_RU": "", "ru_RU": "",
@@ -22660,7 +22660,7 @@
"it_IT": "", "it_IT": "",
"ja_JP": "", "ja_JP": "",
"ko_KR": "", "ko_KR": "",
"no_NO": "", "no_NO": "Åpne kompatibilitetslisten",
"pl_PL": "", "pl_PL": "",
"pt_BR": "", "pt_BR": "",
"ru_RU": "", "ru_RU": "",
@@ -22685,7 +22685,7 @@
"it_IT": "", "it_IT": "",
"ja_JP": "", "ja_JP": "",
"ko_KR": "", "ko_KR": "",
"no_NO": "", "no_NO": "Vis bare eide spill",
"pl_PL": "", "pl_PL": "",
"pt_BR": "", "pt_BR": "",
"ru_RU": "", "ru_RU": "",
@@ -22710,7 +22710,7 @@
"it_IT": "", "it_IT": "",
"ja_JP": "", "ja_JP": "",
"ko_KR": "", "ko_KR": "",
"no_NO": "", "no_NO": "Spillbar",
"pl_PL": "", "pl_PL": "",
"pt_BR": "", "pt_BR": "",
"ru_RU": "", "ru_RU": "",
@@ -22760,7 +22760,7 @@
"it_IT": "", "it_IT": "",
"ja_JP": "", "ja_JP": "",
"ko_KR": "", "ko_KR": "",
"no_NO": "", "no_NO": "Menyer",
"pl_PL": "", "pl_PL": "",
"pt_BR": "", "pt_BR": "",
"ru_RU": "", "ru_RU": "",
@@ -22785,7 +22785,7 @@
"it_IT": "", "it_IT": "",
"ja_JP": "", "ja_JP": "",
"ko_KR": "", "ko_KR": "",
"no_NO": "", "no_NO": "Starter",
"pl_PL": "", "pl_PL": "",
"pt_BR": "", "pt_BR": "",
"ru_RU": "", "ru_RU": "",
@@ -22810,7 +22810,7 @@
"it_IT": "", "it_IT": "",
"ja_JP": "", "ja_JP": "",
"ko_KR": "", "ko_KR": "",
"no_NO": "", "no_NO": "Ingenting",
"pl_PL": "", "pl_PL": "",
"pt_BR": "", "pt_BR": "",
"ru_RU": "", "ru_RU": "",
@@ -22823,4 +22823,4 @@
} }
} }
] ]
} }
@@ -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,10 +741,7 @@ namespace Ryujinx.Ava.UI.ViewModels
Applications.ToObservableChangeSet() Applications.ToObservableChangeSet()
.Filter(Filter) .Filter(Filter)
.Sort(GetComparer()) .Sort(GetComparer())
#pragma warning disable MVVMTK0034 .Bind(out _appsObservableList).AsObservableList();
.Bind(out _appsObservableList)
#pragma warning enable MVVMTK0034
.AsObservableList();
OnPropertyChanged(nameof(AppsObservableList)); OnPropertyChanged(nameof(AppsObservableList));
} }
+14 -12
View File
@@ -32,27 +32,29 @@ 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;
string contentPath = GetContentPath(contentManager); appControl = new BlitStruct<ApplicationControlProperty>(0);
if (string.IsNullOrEmpty(contentPath)) return false;
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,65 +1,50 @@
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.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
{ {
static CompatibilityCsv() public static CompatibilityCsv Shared { get; set; }
public CompatibilityCsv(SepReader reader)
{ {
using Stream csvStream = Assembly.GetExecutingAssembly() var entries = new List<CompatibilityEntry>();
.GetManifestResourceStream("RyujinxGameCompatibilityList")!;
csvStream.Position = 0;
using SepReader reader = Sep.Reader().From(csvStream); foreach (var row in reader)
ColumnIndices columnIndices = new(reader.Header.IndexOf); {
entries.Add(new CompatibilityEntry(reader.Header, row));
}
Entries = reader Entries = entries.Where(x => x.Status != null)
.Enumerate(row => new CompatibilityEntry(ref columnIndices, row)) .OrderBy(it => it.GameName).ToArray();
.OrderBy(it => it.GameName)
.ToArray();
Logger.Debug?.Print(LogClass.UI, "Compatibility CSV loaded.", "LoadCompatCsv");
} }
public static CompatibilityEntry[] Entries { get; private set; } public CompatibilityEntry[] Entries { get; }
} }
public class CompatibilityEntry public class CompatibilityEntry
{ {
public CompatibilityEntry(ref ColumnIndices indices, SepReader.Row row) public CompatibilityEntry(SepReaderHeader header, SepReader.Row row)
{ {
string titleIdRow = ColStr(row[indices.TitleId]); if (row.ColCount != header.ColNames.Count)
throw new InvalidDataException($"CSV row {row.RowIndex} ({row.ToString()}) has mismatched column count");
var titleIdRow = ColStr(row[header.IndexOf("\"title_id\"")]);
TitleId = !string.IsNullOrEmpty(titleIdRow) TitleId = !string.IsNullOrEmpty(titleIdRow)
? titleIdRow ? titleIdRow
: default(Optional<string>); : default(Optional<string>);
GameName = ColStr(row[indices.GameName]).Trim().Trim('"'); GameName = ColStr(row[header.IndexOf("\"game_name\"")]).Trim().Trim('"');
Labels = ColStr(row[indices.Labels]).Split(';'); IssueLabels = ColStr(row[header.IndexOf("\"labels\"")]).Split(';');
Status = ColStr(row[indices.Status]).ToLower() switch Status = ColStr(row[header.IndexOf("\"status\"")]).ToLower() switch
{ {
"playable" => LocaleKeys.CompatibilityListPlayable, "playable" => LocaleKeys.CompatibilityListPlayable,
"ingame" => LocaleKeys.CompatibilityListIngame, "ingame" => LocaleKeys.CompatibilityListIngame,
@@ -69,8 +54,8 @@ namespace Ryujinx.Ava.Utilities.Compat
_ => null _ => null
}; };
if (DateTime.TryParse(ColStr(row[indices.LastUpdated]), out var dt)) if (DateTime.TryParse(ColStr(row[header.IndexOf("\"last_updated\"")]), out var dt))
LastUpdated = dt; LastEvent = dt;
return; return;
@@ -79,27 +64,27 @@ namespace Ryujinx.Ava.Utilities.Compat
public string GameName { get; } public string GameName { get; }
public Optional<string> TitleId { get; } public Optional<string> TitleId { get; }
public string[] Labels { get; } public string[] IssueLabels { get; }
public LocaleKeys? Status { get; } public LocaleKeys? Status { get; }
public DateTime LastUpdated { get; } public DateTime LastEvent { get; }
public string LocalizedStatus => LocaleManager.Instance[Status!.Value]; public string LocalizedStatus => LocaleManager.Instance[Status!.Value];
public string FormattedTitleId => TitleId public string FormattedTitleId => TitleId
.OrElse(new string(' ', 16)); .OrElse(new string(' ', 16));
public string FormattedIssueLabels => Labels public string FormattedIssueLabels => IssueLabels
.Where(it => !it.StartsWithIgnoreCase("status")) .Where(it => !it.StartsWithIgnoreCase("status"))
.Select(FormatLabelName) .Select(FormatLabelName)
.JoinToString(", "); .JoinToString(", ");
public override string ToString() public override string ToString()
{ {
StringBuilder sb = new("CompatibilityEntry: {"); var sb = new StringBuilder("CompatibilityEntry: {");
sb.Append($"{nameof(GameName)}=\"{GameName}\", "); sb.Append($"{nameof(GameName)}=\"{GameName}\", ");
sb.Append($"{nameof(TitleId)}={TitleId}, "); sb.Append($"{nameof(TitleId)}={TitleId}, ");
sb.Append($"{nameof(Labels)}=\"{Labels}\", "); sb.Append($"{nameof(IssueLabels)}=\"{IssueLabels}\", ");
sb.Append($"{nameof(Status)}=\"{Status}\", "); sb.Append($"{nameof(Status)}=\"{Status}\", ");
sb.Append($"{nameof(LastUpdated)}=\"{LastUpdated}\""); sb.Append($"{nameof(LastEvent)}=\"{LastEvent}\"");
sb.Append('}'); sb.Append('}');
return sb.ToString(); return sb.ToString();
@@ -155,8 +140,8 @@ namespace Ryujinx.Ava.Utilities.Compat
if (value == string.Empty) if (value == string.Empty)
return string.Empty; return string.Empty;
char firstChar = value[0]; var firstChar = value[0];
string rest = value[1..]; var rest = value[1..];
return $"{char.ToUpper(firstChar)}{rest}"; return $"{char.ToUpper(firstChar)}{rest}";
} }
@@ -14,6 +14,15 @@ namespace Ryujinx.Ava.Utilities.Compat
{ {
public static async Task Show() public static async Task Show()
{ {
if (CompatibilityCsv.Shared is null)
{
await using Stream csvStream = Assembly.GetExecutingAssembly()
.GetManifestResourceStream("RyujinxGameCompatibilityList")!;
csvStream.Position = 0;
CompatibilityCsv.Shared = new CompatibilityCsv(Sep.Reader().From(csvStream));
}
ContentDialog contentDialog = new() ContentDialog contentDialog = new()
{ {
PrimaryButtonText = string.Empty, PrimaryButtonText = string.Empty,
@@ -42,7 +51,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,13 +11,14 @@ namespace Ryujinx.Ava.Utilities.Compat
{ {
[ObservableProperty] private bool _onlyShowOwnedGames = true; [ObservableProperty] private bool _onlyShowOwnedGames = true;
private IEnumerable<CompatibilityEntry> _currentEntries = CompatibilityCsv.Entries; private IEnumerable<CompatibilityEntry> _currentEntries = CompatibilityCsv.Shared.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() {}
@@ -38,11 +39,11 @@ namespace Ryujinx.Ava.Utilities.Compat
{ {
if (string.IsNullOrEmpty(searchTerm)) if (string.IsNullOrEmpty(searchTerm))
{ {
SetEntries(CompatibilityCsv.Entries); SetEntries(CompatibilityCsv.Shared.Entries);
return; return;
} }
SetEntries(CompatibilityCsv.Entries.Where(x => SetEntries(CompatibilityCsv.Shared.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))));
} }