Compare commits

..

1 Commits

Author SHA1 Message Date
Evan Husted
efa0cc7554 UI: Show issue labels of games in the tooltip on playability status 2025-02-09 21:15:38 -06:00
5 changed files with 129 additions and 67 deletions

View File

@@ -76,7 +76,7 @@
"ID": "MenuBarFileOpenAppletOpenMiiApplet",
"Translations": {
"ar_SA": "",
"de_DE": "Mii-Bearbeitungsapplet",
"de_DE": "",
"el_GR": "",
"en_US": "Mii Edit Applet",
"es_ES": "Applet Editor Mii",
@@ -176,7 +176,7 @@
"ID": "SettingsTabSystemMemoryManagerModeSoftware",
"Translations": {
"ar_SA": "البرنامج",
"de_DE": "Programme",
"de_DE": "",
"el_GR": "Λογισμικό",
"en_US": "Software",
"es_ES": "",
@@ -326,7 +326,7 @@
"ID": "MenuBarFileOpenFromFileError",
"Translations": {
"ar_SA": "",
"de_DE": "Keine Anwendungen im ausgewählten Datei gefunden.",
"de_DE": "",
"el_GR": "",
"en_US": "No applications found in selected file.",
"es_ES": "No se encontraron aplicaciones en el archivo seleccionado.",
@@ -376,7 +376,7 @@
"ID": "MenuBarFileLoadDlcFromFolder",
"Translations": {
"ar_SA": "",
"de_DE": "DLC aus Ordner laden",
"de_DE": "",
"el_GR": "",
"en_US": "Load DLC From Folder",
"es_ES": "Cargar DLC Desde Carpeta",
@@ -401,7 +401,7 @@
"ID": "MenuBarFileLoadTitleUpdatesFromFolder",
"Translations": {
"ar_SA": "",
"de_DE": "Titel-Updates aus Ordner laden",
"de_DE": "",
"el_GR": "",
"en_US": "Load Title Updates From Folder",
"es_ES": "Cargar Actualizaciones de Títulos Desde Carpeta",
@@ -576,7 +576,7 @@
"ID": "MenuBarOptionsStartGamesWithoutUI",
"Translations": {
"ar_SA": "",
"de_DE": "Spiele ohne Benutzeroberfläche starten",
"de_DE": "",
"el_GR": "",
"en_US": "Start Games with UI Hidden",
"es_ES": "",
@@ -751,7 +751,7 @@
"ID": "MenuBarActionsScanAmiiboBin",
"Translations": {
"ar_SA": "",
"de_DE": "Amiibo scannen (aus Bin-Datei)",
"de_DE": "",
"el_GR": "",
"en_US": "Scan An Amiibo (From Bin)",
"es_ES": "",
@@ -851,7 +851,7 @@
"ID": "MenuBarActionsInstallKeys",
"Translations": {
"ar_SA": "",
"de_DE": "Schlüssel installieren",
"de_DE": "",
"el_GR": "",
"en_US": "Install Keys",
"es_ES": "",
@@ -876,7 +876,7 @@
"ID": "MenuBarFileActionsInstallKeysFromFile",
"Translations": {
"ar_SA": "",
"de_DE": "Schlüssel aus KEYS oder ZIP installieren",
"de_DE": "",
"el_GR": "",
"en_US": "Install keys from KEYS or ZIP",
"es_ES": "Instalar keys de KEYS o ZIP",
@@ -901,7 +901,7 @@
"ID": "MenuBarFileActionsInstallKeysFromFolder",
"Translations": {
"ar_SA": "",
"de_DE": "Schlüssel aus einem Verzeichnis installieren",
"de_DE": "",
"el_GR": "",
"en_US": "Install keys from a directory",
"es_ES": "Instalar keys de un directorio",
@@ -1001,7 +1001,7 @@
"ID": "MenuBarActionsXCITrimmer",
"Translations": {
"ar_SA": "",
"de_DE": "XCI-Dateien trimmen",
"de_DE": "",
"el_GR": "",
"en_US": "Trim XCI Files",
"es_ES": "Recortar archivos XCI",
@@ -1226,7 +1226,7 @@
"ID": "MenuBarHelpFaqAndGuides",
"Translations": {
"ar_SA": "",
"de_DE": "FAQ & Anleitungen",
"de_DE": "",
"el_GR": "",
"en_US": "FAQ & Guides",
"es_ES": "",
@@ -1251,7 +1251,7 @@
"ID": "MenuBarHelpFaq",
"Translations": {
"ar_SA": "",
"de_DE": "FAQ & Fehlerbehebung Seite",
"de_DE": "",
"el_GR": "",
"en_US": "FAQ & Troubleshooting Page",
"es_ES": "",
@@ -1276,7 +1276,7 @@
"ID": "MenuBarHelpFaqTooltip",
"Translations": {
"ar_SA": "",
"de_DE": "Öffnet die FAQ- und Fehlerbehebungsseite im offiziellen Ryujinx-Wiki",
"de_DE": "",
"el_GR": "",
"en_US": "Opens the FAQ and Troubleshooting page on the official Ryujinx wiki",
"es_ES": "",
@@ -1301,7 +1301,7 @@
"ID": "MenuBarHelpSetup",
"Translations": {
"ar_SA": "",
"de_DE": "Setup- und Konfigurationsanleitung",
"de_DE": "",
"el_GR": "",
"en_US": "Setup & Configuration Guide",
"es_ES": "",
@@ -1326,7 +1326,7 @@
"ID": "MenuBarHelpSetupTooltip",
"Translations": {
"ar_SA": "",
"de_DE": "Öffnet die Setup- und Konfigurationsanleitung im offiziellen Ryujinx-Wiki",
"de_DE": "",
"el_GR": "",
"en_US": "Opens the Setup & Configuration guide on the official Ryujinx wiki",
"es_ES": "",
@@ -1351,7 +1351,7 @@
"ID": "MenuBarHelpMultiplayer",
"Translations": {
"ar_SA": "",
"de_DE": "Multiplayer (LDN/LAN) Anleitung",
"de_DE": "",
"el_GR": "",
"en_US": "Multiplayer (LDN/LAN) Guide",
"es_ES": "",
@@ -1376,7 +1376,7 @@
"ID": "MenuBarHelpMultiplayerTooltip",
"Translations": {
"ar_SA": "",
"de_DE": "Öffnet die Multiplayer-Anleitung im offiziellen Ryujinx-Wiki",
"de_DE": "",
"el_GR": "",
"en_US": "Opens the Multiplayer guide on the official Ryujinx wiki",
"es_ES": "",
@@ -1526,7 +1526,7 @@
"ID": "GameListHeaderDeveloper",
"Translations": {
"ar_SA": "",
"de_DE": "Entwickelt von {0}",
"de_DE": "",
"el_GR": "",
"en_US": "Developed by {0}",
"es_ES": "",
@@ -1826,7 +1826,7 @@
"ID": "GameListHeaderCompatibilityStatus",
"Translations": {
"ar_SA": "",
"de_DE": "Kompatibilität:",
"de_DE": "",
"el_GR": "",
"en_US": "Compatibility:",
"es_ES": "",
@@ -23026,7 +23026,7 @@
"ID": "SettingsTabSystemVSyncModeTooltip",
"Translations": {
"ar_SA": "",
"de_DE": "Emulierte vertikale Synchronisation. \"Switch\" emuliert die 60Hz-Bildwiederholfrequenz der Switch. \"Unbounded\" ist eine unbegrenzte Bildwiederholfrequenz.",
"de_DE": "",
"el_GR": "",
"en_US": "Emulated Vertical Sync. 'Switch' emulates the Switch's refresh rate of 60Hz. 'Unbounded' is an unbounded refresh rate.",
"es_ES": "",
@@ -23051,7 +23051,7 @@
"ID": "SettingsTabSystemVSyncModeTooltipCustom",
"Translations": {
"ar_SA": "",
"de_DE": "Emulierte vertikale Synchronisation. \"Switch\" emuliert die 60Hz-Bildwiederholfrequenz der Switch. „Unbounded“ ist eine unbegrenzte Bildwiederholfrequenz. „Benutzerdefinierte Bildwiederholfrequenz“ emuliert die angegebene benutzerdefinierte Bildwiederholfrequenz.",
"de_DE": "",
"el_GR": "",
"en_US": "Emulated Vertical Sync. 'Switch' emulates the Switch's refresh rate of 60Hz. 'Unbounded' is an unbounded refresh rate. 'Custom Refresh Rate' emulates the specified custom refresh rate.",
"es_ES": "",
@@ -23076,7 +23076,7 @@
"ID": "SettingsTabSystemEnableCustomVSyncIntervalTooltip",
"Translations": {
"ar_SA": "",
"de_DE": "Ermöglicht es dem Benutzer, eine emulierte Bildwiederholfrequenz festzulegen. In einigen Titeln kann dies die Geschwindigkeit der Spiel-Logik erhöhen oder verringern. In anderen Titeln kann dies dazu führen, dass die FPS auf ein Vielfaches der Bildwiederholfrequenz begrenzt werden oder zu unvorhersehbarem Verhalten führen. Dies ist eine experimentelle Funktion, ohne Garantien dafür, wie sich das Gameplay auswirkt. \n\nLassen Sie diese Option deaktiviert, wenn Sie sich nicht sicher sind.",
"de_DE": "",
"el_GR": "",
"en_US": "Allows the user to specify an emulated refresh rate. In some titles, this may speed up or slow down the rate of gameplay logic. In other titles, it may allow for capping FPS at some multiple of the refresh rate, or lead to unpredictable behavior. This is an experimental feature, with no guarantees for how gameplay will be affected. \n\nLeave OFF if unsure.",
"es_ES": "",
@@ -23101,7 +23101,7 @@
"ID": "SettingsTabSystemCustomVSyncIntervalValueTooltip",
"Translations": {
"ar_SA": "",
"de_DE": "Der Zielwert für die benutzerdefinierte Bildwiederholfrequenz.",
"de_DE": "",
"el_GR": "",
"en_US": "The custom refresh rate target value.",
"es_ES": "",
@@ -23126,7 +23126,7 @@
"ID": "SettingsTabSystemCustomVSyncIntervalSliderTooltip",
"Translations": {
"ar_SA": "",
"de_DE": "Die benutzerdefinierte Bildwiederholfrequenz als Prozentsatz der normalen Switch-Bildwiederholfrequenz.",
"de_DE": "",
"el_GR": "",
"en_US": "The custom refresh rate, as a percentage of the normal Switch refresh rate.",
"es_ES": "",
@@ -23151,7 +23151,7 @@
"ID": "SettingsTabSystemCustomVSyncIntervalPercentage",
"Translations": {
"ar_SA": "",
"de_DE": "Benutzerdefinierte Bildwiederholfrequenz %:",
"de_DE": "",
"el_GR": "",
"en_US": "Custom Refresh Rate %:",
"es_ES": "",
@@ -23176,7 +23176,7 @@
"ID": "SettingsTabSystemCustomVSyncIntervalValue",
"Translations": {
"ar_SA": "",
"de_DE": "Wert für benutzerdefinierte Bildwiederholfrequenz:",
"de_DE": "",
"el_GR": "",
"en_US": "Custom Refresh Rate Value:",
"es_ES": "",
@@ -23226,7 +23226,7 @@
"ID": "SettingsTabHotkeysToggleVSyncModeHotkey",
"Translations": {
"ar_SA": "",
"de_DE": "VSync-Modus umschalten:",
"de_DE": "",
"el_GR": "",
"en_US": "Toggle VSync mode:",
"es_ES": "",
@@ -23251,7 +23251,7 @@
"ID": "SettingsTabHotkeysIncrementCustomVSyncIntervalHotkey",
"Translations": {
"ar_SA": "",
"de_DE": "Benutzerdefinierte Bildwiederholfrequenz erhöhen:",
"de_DE": "",
"el_GR": "",
"en_US": "Raise custom refresh rate",
"es_ES": "",
@@ -23276,7 +23276,7 @@
"ID": "SettingsTabHotkeysDecrementCustomVSyncIntervalHotkey",
"Translations": {
"ar_SA": "",
"de_DE": "Benutzerdefinierte Bildwiederholfrequenz senken:",
"de_DE": "",
"el_GR": "",
"en_US": "Lower custom refresh rate:",
"es_ES": "",
@@ -23301,7 +23301,7 @@
"ID": "CompatibilityListLastUpdated",
"Translations": {
"ar_SA": "",
"de_DE": "Zuletzt aktualisiert: {0}",
"de_DE": "",
"el_GR": "",
"en_US": "Last updated: {0}",
"es_ES": "",
@@ -23326,7 +23326,7 @@
"ID": "CompatibilityListWarning",
"Translations": {
"ar_SA": "",
"de_DE": "Diese Kompatibilitätsliste könnte veraltete Einträge enthalten. Teste dennoch Spiele im \"Ingame\"-Status.",
"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": "",
@@ -23351,7 +23351,7 @@
"ID": "CompatibilityListSearchBoxWatermark",
"Translations": {
"ar_SA": "",
"de_DE": "Kompatibilitätseinträge durchsuchen...",
"de_DE": "",
"el_GR": "",
"en_US": "Search compatibility entries...",
"es_ES": "",
@@ -23401,7 +23401,7 @@
"ID": "CompatibilityListOnlyShowOwnedGames",
"Translations": {
"ar_SA": "",
"de_DE": "Nur eigene Spiele anzeigen",
"de_DE": "",
"el_GR": "",
"en_US": "Only show owned games",
"es_ES": "",
@@ -23426,7 +23426,7 @@
"ID": "CompatibilityListPlayable",
"Translations": {
"ar_SA": "",
"de_DE": "Spielbar",
"de_DE": "",
"el_GR": "",
"en_US": "Playable",
"es_ES": "",
@@ -23451,7 +23451,7 @@
"ID": "CompatibilityListIngame",
"Translations": {
"ar_SA": "",
"de_DE": "Im Spiel",
"de_DE": "",
"el_GR": "",
"en_US": "Ingame",
"es_ES": "",
@@ -23626,7 +23626,7 @@
"ID": "CompatibilityListBootsTooltip",
"Translations": {
"ar_SA": "",
"de_DE": "Startet, kommt aber nicht über den Titelbildschirm hinaus.",
"de_DE": "",
"el_GR": "",
"en_US": "Boots but does not make it past the title screen.",
"es_ES": "",
@@ -23651,7 +23651,7 @@
"ID": "CompatibilityListNothingTooltip",
"Translations": {
"ar_SA": "",
"de_DE": "Startet nicht oder zeigt keine Anzeichen von Aktivität.",
"de_DE": "",
"el_GR": "",
"en_US": "Does not boot or shows no signs of activity.",
"es_ES": "",
@@ -23676,7 +23676,7 @@
"ID": "ExtractAocListHeader",
"Translations": {
"ar_SA": "",
"de_DE": "Wähle ein DLC zum Extrahieren aus",
"de_DE": "",
"el_GR": "",
"en_US": "Select a DLC to Extract",
"es_ES": "",

View File

@@ -55,9 +55,21 @@
Tag="{Binding AppData.IdString}"
Text="{Binding AppData.LocalizedStatus}"
Foreground="{Binding AppData.PlayabilityStatus, Converter={x:Static helpers:PlayabilityStatusConverter.Shared}}"
ToolTip.Tip="{Binding AppData.LocalizedStatusTooltip}"
TextAlignment="Start"
TextWrapping="Wrap" />
TextWrapping="Wrap">
<ToolTip.Tip>
<StackPanel Orientation="Vertical">
<TextBlock
Text="{Binding AppData.LocalizedStatusTooltip}" />
<Separator
Margin="0, 10, 0, 10"
IsVisible="{Binding AppData.HasCompatibilityLabels}" />
<TextBlock
IsVisible="{Binding AppData.HasCompatibilityLabels}"
Text="{Binding AppData.FormattedCompatibilityLabels}" />
</StackPanel>
</ToolTip.Tip>
</TextBlock>
<Button.Styles>
<Style Selector="Button">
<Setter Property="MinWidth"

View File

@@ -93,8 +93,19 @@
IsVisible="{Binding HasPlayabilityInfo}"
Background="{DynamicResource AppListBackgroundColor}"
Margin="-1, 0, 0, 0"
Padding="0"
ToolTip.Tip="{Binding LocalizedStatusTooltip}">
Padding="0">
<ToolTip.Tip>
<StackPanel Orientation="Vertical">
<TextBlock
Text="{Binding LocalizedStatusTooltip}" />
<Separator
Margin="0, 10, 0, 10"
IsVisible="{Binding HasCompatibilityLabels}" />
<TextBlock
IsVisible="{Binding HasCompatibilityLabels}"
Text="{Binding FormattedCompatibilityLabels}" />
</StackPanel>
</ToolTip.Tip>
<TextBlock
Margin="1.5"
Tag="{Binding IdString}"

View File

@@ -1,3 +1,4 @@
using Gommon;
using LibHac.Common;
using LibHac.Fs;
using LibHac.Fs.Fsa;
@@ -14,6 +15,7 @@ using Ryujinx.HLE.FileSystem;
using Ryujinx.HLE.Loaders.Processes.Extensions;
using System;
using System.IO;
using System.Text;
using System.Text.Json.Serialization;
namespace Ryujinx.Ava.Utilities.AppLibrary
@@ -32,33 +34,12 @@ namespace Ryujinx.Ava.Utilities.AppLibrary
set
{
_id = value;
PlayabilityStatus = CompatibilityCsv.GetStatus(Id);
Compatibility = CompatibilityCsv.Find(Id);
}
}
public string Developer { get; set; } = "Unknown";
public string Version { get; set; } = "0";
public bool HasPlayabilityInfo => PlayabilityStatus != null;
public string LocalizedStatus =>
PlayabilityStatus.HasValue
? LocaleManager.Instance[PlayabilityStatus!.Value]
: string.Empty;
public LocaleKeys? PlayabilityStatus { get; set; }
public string LocalizedStatusTooltip =>
PlayabilityStatus.HasValue
#pragma warning disable CS8509 // It is exhaustive for any value this property can contain.
? LocaleManager.Instance[PlayabilityStatus!.Value switch
#pragma warning restore CS8509
{
LocaleKeys.CompatibilityListPlayable => LocaleKeys.CompatibilityListPlayableTooltip,
LocaleKeys.CompatibilityListIngame => LocaleKeys.CompatibilityListIngameTooltip,
LocaleKeys.CompatibilityListMenus => LocaleKeys.CompatibilityListMenusTooltip,
LocaleKeys.CompatibilityListBoots => LocaleKeys.CompatibilityListBootsTooltip,
LocaleKeys.CompatibilityListNothing => LocaleKeys.CompatibilityListNothingTooltip,
}]
: string.Empty;
public int PlayerCount { get; set; }
public int GameCount { get; set; }
@@ -83,6 +64,53 @@ namespace Ryujinx.Ava.Utilities.AppLibrary
public string LastPlayedString => ValueFormatUtils.FormatDateTime(LastPlayed)?.Replace(" ", "\n");
public string FileSizeString => ValueFormatUtils.FormatFileSize(FileSize);
public Optional<CompatibilityEntry> Compatibility { get; private set; }
public bool HasPlayabilityInfo => Compatibility.HasValue;
public string LocalizedStatus => Compatibility.Convert(x => x.LocalizedStatus);
public bool HasCompatibilityLabels => !FormattedCompatibilityLabels.Equals(string.Empty);
public string FormattedCompatibilityLabels
=> Compatibility.Convert(x => x.FormattedIssueLabels).OrElse(string.Empty);
public LocaleKeys? PlayabilityStatus => Compatibility.Convert(x => x.Status).OrElse(null);
public string CompatibilityToolTip
{
get
{
StringBuilder sb = new(LocalizedStatusTooltip);
string formattedCompatibilityLabels = FormattedCompatibilityLabels;
if (!string.IsNullOrEmpty(formattedCompatibilityLabels))
{
sb.AppendLine()
.AppendLine()
.Append(formattedCompatibilityLabels);
}
return sb.ToString();
}
}
public string LocalizedStatusTooltip =>
Compatibility.Convert(x =>
#pragma warning disable CS8509 It is exhaustive for all possible values this can contain.
LocaleManager.Instance[x.Status switch
#pragma warning restore CS8509
{
LocaleKeys.CompatibilityListPlayable => LocaleKeys.CompatibilityListPlayableTooltip,
LocaleKeys.CompatibilityListIngame => LocaleKeys.CompatibilityListIngameTooltip,
LocaleKeys.CompatibilityListMenus => LocaleKeys.CompatibilityListMenusTooltip,
LocaleKeys.CompatibilityListBoots => LocaleKeys.CompatibilityListBootsTooltip,
LocaleKeys.CompatibilityListNothing => LocaleKeys.CompatibilityListNothingTooltip,
}]
).OrElse(string.Empty);
[JsonIgnore] public string IdString => Id.ToString("x16");

View File

@@ -60,10 +60,21 @@ namespace Ryujinx.Ava.Utilities.Compat
}
}
public static CompatibilityEntry Find(string titleId)
=> Entries.FirstOrDefault(x => x.TitleId.HasValue && x.TitleId.Value.EqualsIgnoreCase(titleId));
public static CompatibilityEntry Find(ulong titleId)
=> Find(titleId.ToString("X16"));
public static LocaleKeys? GetStatus(string titleId)
=> Entries.FirstOrDefault(x => x.TitleId.HasValue && x.TitleId.Value.EqualsIgnoreCase(titleId))?.Status;
=> Find(titleId)?.Status;
public static LocaleKeys? GetStatus(ulong titleId) => GetStatus(titleId.ToString("X16"));
public static string GetLabels(string titleId)
=> Find(titleId)?.FormattedIssueLabels;
public static string GetLabels(ulong titleId) => GetLabels(titleId.ToString("X16"));
}
public class CompatibilityEntry