mirror of
https://github.com/GreemDev/Ryujinx.git
synced 2025-01-09 11:17:20 -03:00
UI: Abstract applet launch logic for future potential applets
Some checks are pending
Canary release job / Create tag (push) Waiting to run
Canary release job / Release for linux-arm64 (push) Waiting to run
Canary release job / Release for linux-x64 (push) Waiting to run
Canary release job / Release for win-x64 (push) Waiting to run
Canary release job / Release MacOS universal (push) Waiting to run
Some checks are pending
Canary release job / Create tag (push) Waiting to run
Canary release job / Release for linux-arm64 (push) Waiting to run
Canary release job / Release for linux-x64 (push) Waiting to run
Canary release job / Release for win-x64 (push) Waiting to run
Canary release job / Release MacOS universal (push) Waiting to run
Optimize locale loading (remove always loading english, that was only needed with the old system)
This commit is contained in:
parent
e6644626fc
commit
412d4065b8
3 changed files with 81 additions and 55 deletions
64
src/Ryujinx.UI.Common/Helper/AppletMetadata.cs
Normal file
64
src/Ryujinx.UI.Common/Helper/AppletMetadata.cs
Normal file
|
@ -0,0 +1,64 @@
|
||||||
|
using LibHac.Common;
|
||||||
|
using LibHac.Ncm;
|
||||||
|
using LibHac.Ns;
|
||||||
|
using LibHac.Tools.FsSystem.NcaUtils;
|
||||||
|
using Ryujinx.HLE;
|
||||||
|
using Ryujinx.HLE.FileSystem;
|
||||||
|
using Ryujinx.UI.App.Common;
|
||||||
|
|
||||||
|
namespace Ryujinx.UI.Common.Helper
|
||||||
|
{
|
||||||
|
public readonly struct AppletMetadata
|
||||||
|
{
|
||||||
|
private readonly ContentManager _contentManager;
|
||||||
|
|
||||||
|
public string Name { get; }
|
||||||
|
public ulong ProgramId { get; }
|
||||||
|
|
||||||
|
public string Version { get; }
|
||||||
|
|
||||||
|
public AppletMetadata(ContentManager contentManager, string name, ulong programId, string version = "1.0.0")
|
||||||
|
: this(name, programId, version)
|
||||||
|
{
|
||||||
|
_contentManager = contentManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
public AppletMetadata(string name, ulong programId, string version = "1.0.0")
|
||||||
|
{
|
||||||
|
Name = name;
|
||||||
|
ProgramId = programId;
|
||||||
|
Version = version;
|
||||||
|
}
|
||||||
|
|
||||||
|
public string GetContentPath(ContentManager contentManager)
|
||||||
|
=> (contentManager ?? _contentManager)
|
||||||
|
.GetInstalledContentPath(ProgramId, StorageId.BuiltInSystem, NcaContentType.Program);
|
||||||
|
|
||||||
|
public bool CanStart(ContentManager contentManager, out ApplicationData appData, out BlitStruct<ApplicationControlProperty> appControl)
|
||||||
|
{
|
||||||
|
contentManager ??= _contentManager;
|
||||||
|
if (contentManager == null)
|
||||||
|
{
|
||||||
|
appData = null;
|
||||||
|
appControl = new BlitStruct<ApplicationControlProperty>(0);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,7 +1,6 @@
|
||||||
using Gommon;
|
using Gommon;
|
||||||
using Ryujinx.Ava.UI.ViewModels;
|
using Ryujinx.Ava.UI.ViewModels;
|
||||||
using Ryujinx.Common;
|
using Ryujinx.Common;
|
||||||
using Ryujinx.Common.Logging;
|
|
||||||
using Ryujinx.Common.Utilities;
|
using Ryujinx.Common.Utilities;
|
||||||
using Ryujinx.UI.Common.Configuration;
|
using Ryujinx.UI.Common.Configuration;
|
||||||
using System;
|
using System;
|
||||||
|
@ -17,7 +16,6 @@ namespace Ryujinx.Ava.Common.Locale
|
||||||
private const string DefaultLanguageCode = "en_US";
|
private const string DefaultLanguageCode = "en_US";
|
||||||
|
|
||||||
private readonly Dictionary<LocaleKeys, string> _localeStrings;
|
private readonly Dictionary<LocaleKeys, string> _localeStrings;
|
||||||
private Dictionary<LocaleKeys, string> _localeDefaultStrings;
|
|
||||||
private readonly ConcurrentDictionary<LocaleKeys, object[]> _dynamicValues;
|
private readonly ConcurrentDictionary<LocaleKeys, object[]> _dynamicValues;
|
||||||
private string _localeLanguageCode;
|
private string _localeLanguageCode;
|
||||||
|
|
||||||
|
@ -27,7 +25,6 @@ namespace Ryujinx.Ava.Common.Locale
|
||||||
public LocaleManager()
|
public LocaleManager()
|
||||||
{
|
{
|
||||||
_localeStrings = new Dictionary<LocaleKeys, string>();
|
_localeStrings = new Dictionary<LocaleKeys, string>();
|
||||||
_localeDefaultStrings = new Dictionary<LocaleKeys, string>();
|
|
||||||
_dynamicValues = new ConcurrentDictionary<LocaleKeys, object[]>();
|
_dynamicValues = new ConcurrentDictionary<LocaleKeys, object[]>();
|
||||||
|
|
||||||
Load();
|
Load();
|
||||||
|
@ -37,9 +34,7 @@ namespace Ryujinx.Ava.Common.Locale
|
||||||
{
|
{
|
||||||
var localeLanguageCode = !string.IsNullOrEmpty(ConfigurationState.Instance.UI.LanguageCode.Value) ?
|
var localeLanguageCode = !string.IsNullOrEmpty(ConfigurationState.Instance.UI.LanguageCode.Value) ?
|
||||||
ConfigurationState.Instance.UI.LanguageCode.Value : CultureInfo.CurrentCulture.Name.Replace('-', '_');
|
ConfigurationState.Instance.UI.LanguageCode.Value : CultureInfo.CurrentCulture.Name.Replace('-', '_');
|
||||||
|
|
||||||
// Load en_US as default, if the target language translation is missing or incomplete.
|
|
||||||
LoadDefaultLanguage();
|
|
||||||
LoadLanguage(localeLanguageCode);
|
LoadLanguage(localeLanguageCode);
|
||||||
|
|
||||||
// Save whatever we ended up with.
|
// Save whatever we ended up with.
|
||||||
|
@ -66,26 +61,14 @@ namespace Ryujinx.Ava.Common.Locale
|
||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
{
|
{
|
||||||
// If formatting failed use the default text instead.
|
// If formatting the text failed,
|
||||||
if (_localeDefaultStrings.TryGetValue(key, out value))
|
// continue to the below line & return the text without formatting.
|
||||||
try
|
|
||||||
{
|
|
||||||
return string.Format(value, dynamicValue);
|
|
||||||
}
|
|
||||||
catch
|
|
||||||
{
|
|
||||||
// If formatting the default text failed return the key.
|
|
||||||
return key.ToString();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the locale doesn't contain the key return the default one.
|
return key.ToString(); // If the locale text doesn't exist return the key.
|
||||||
return _localeDefaultStrings.TryGetValue(key, out string defaultValue)
|
|
||||||
? defaultValue
|
|
||||||
: key.ToString(); // If the locale text doesn't exist return the key.
|
|
||||||
}
|
}
|
||||||
set
|
set
|
||||||
{
|
{
|
||||||
|
@ -114,11 +97,6 @@ namespace Ryujinx.Ava.Common.Locale
|
||||||
return this[key];
|
return this[key];
|
||||||
}
|
}
|
||||||
|
|
||||||
private void LoadDefaultLanguage()
|
|
||||||
{
|
|
||||||
_localeDefaultStrings = LoadJsonLanguage(DefaultLanguageCode);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void LoadLanguage(string languageCode)
|
public void LoadLanguage(string languageCode)
|
||||||
{
|
{
|
||||||
var locale = LoadJsonLanguage(languageCode);
|
var locale = LoadJsonLanguage(languageCode);
|
||||||
|
@ -126,7 +104,7 @@ namespace Ryujinx.Ava.Common.Locale
|
||||||
if (locale == null)
|
if (locale == null)
|
||||||
{
|
{
|
||||||
_localeLanguageCode = DefaultLanguageCode;
|
_localeLanguageCode = DefaultLanguageCode;
|
||||||
locale = _localeDefaultStrings;
|
locale = LoadJsonLanguage(_localeLanguageCode);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -167,15 +145,16 @@ namespace Ryujinx.Ava.Common.Locale
|
||||||
if (!Enum.TryParse<LocaleKeys>(locale.ID, out var localeKey))
|
if (!Enum.TryParse<LocaleKeys>(locale.ID, out var localeKey))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
localeStrings[localeKey] =
|
var str = locale.Translations.TryGetValue(languageCode, out string val) && !string.IsNullOrEmpty(val)
|
||||||
locale.Translations.TryGetValue(languageCode, out string val) && !string.IsNullOrEmpty(val)
|
? val
|
||||||
? val
|
: locale.Translations[DefaultLanguageCode];
|
||||||
: locale.Translations[DefaultLanguageCode];
|
|
||||||
|
if (string.IsNullOrEmpty(str))
|
||||||
if (string.IsNullOrEmpty(localeStrings[localeKey]))
|
|
||||||
{
|
{
|
||||||
throw new Exception($"Locale key '{locale.ID}' has no valid translations for desired language {languageCode}! {DefaultLanguageCode} is an empty string or null");
|
throw new Exception($"Locale key '{locale.ID}' has no valid translations for desired language {languageCode}! {DefaultLanguageCode} is an empty string or null");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
localeStrings[localeKey] = str;
|
||||||
}
|
}
|
||||||
|
|
||||||
return localeStrings;
|
return localeStrings;
|
||||||
|
|
|
@ -3,8 +3,6 @@ using Avalonia.Controls;
|
||||||
using Avalonia.Interactivity;
|
using Avalonia.Interactivity;
|
||||||
using Avalonia.Threading;
|
using Avalonia.Threading;
|
||||||
using Gommon;
|
using Gommon;
|
||||||
using LibHac.Ncm;
|
|
||||||
using LibHac.Tools.FsSystem.NcaUtils;
|
|
||||||
using Ryujinx.Ava.Common.Locale;
|
using Ryujinx.Ava.Common.Locale;
|
||||||
using Ryujinx.Ava.UI.Helpers;
|
using Ryujinx.Ava.UI.Helpers;
|
||||||
using Ryujinx.Ava.UI.ViewModels;
|
using Ryujinx.Ava.UI.ViewModels;
|
||||||
|
@ -12,8 +10,6 @@ using Ryujinx.Ava.UI.Windows;
|
||||||
using Ryujinx.Common;
|
using Ryujinx.Common;
|
||||||
using Ryujinx.Common.Utilities;
|
using Ryujinx.Common.Utilities;
|
||||||
using Ryujinx.HLE.HOS.Services.Nfc.AmiiboDecryption;
|
using Ryujinx.HLE.HOS.Services.Nfc.AmiiboDecryption;
|
||||||
using Ryujinx.HLE;
|
|
||||||
using Ryujinx.UI.App.Common;
|
|
||||||
using Ryujinx.UI.Common;
|
using Ryujinx.UI.Common;
|
||||||
using Ryujinx.UI.Common.Configuration;
|
using Ryujinx.UI.Common.Configuration;
|
||||||
using Ryujinx.UI.Common.Helper;
|
using Ryujinx.UI.Common.Helper;
|
||||||
|
@ -124,26 +120,13 @@ namespace Ryujinx.Ava.UI.Views.Main
|
||||||
ViewModel.LoadConfigurableHotKeys();
|
ViewModel.LoadConfigurableHotKeys();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static readonly AppletMetadata MiiApplet = new("miiEdit", 0x0100000000001009);
|
||||||
|
|
||||||
public async void OpenMiiApplet(object sender, RoutedEventArgs e)
|
public async void OpenMiiApplet(object sender, RoutedEventArgs e)
|
||||||
{
|
{
|
||||||
const string AppletName = "miiEdit";
|
if (MiiApplet.CanStart(ViewModel.ContentManager, out var appData, out var nacpData))
|
||||||
const ulong AppletProgramId = 0x0100000000001009;
|
|
||||||
const string AppletVersion = "1.0.0";
|
|
||||||
|
|
||||||
string contentPath = ViewModel.ContentManager.GetInstalledContentPath(AppletProgramId, StorageId.BuiltInSystem, NcaContentType.Program);
|
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(contentPath))
|
|
||||||
{
|
{
|
||||||
ApplicationData applicationData = new()
|
await ViewModel.LoadApplication(appData, ViewModel.IsFullScreen || ViewModel.StartGamesInFullscreen, nacpData);
|
||||||
{
|
|
||||||
Name = AppletName,
|
|
||||||
Id = AppletProgramId,
|
|
||||||
Path = contentPath
|
|
||||||
};
|
|
||||||
|
|
||||||
var nacpData = StructHelpers.CreateCustomNacpData(AppletName, AppletVersion);
|
|
||||||
|
|
||||||
await ViewModel.LoadApplication(applicationData, ViewModel.IsFullScreen || ViewModel.StartGamesInFullscreen, nacpData);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue