Skip to content

Commit

Permalink
UI: Abstract applet launch logic for future potential applets
Browse files Browse the repository at this point in the history
Optimize locale loading (remove always loading english, that was only needed with the old system)
  • Loading branch information
GreemDev committed Dec 25, 2024
1 parent e664462 commit 412d406
Show file tree
Hide file tree
Showing 3 changed files with 81 additions and 55 deletions.
64 changes: 64 additions & 0 deletions src/Ryujinx.UI.Common/Helper/AppletMetadata.cs
Original file line number Diff line number Diff line change
@@ -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;
}
}
}
47 changes: 13 additions & 34 deletions src/Ryujinx/Common/LocaleManager.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
using Gommon;
using Ryujinx.Ava.UI.ViewModels;
using Ryujinx.Common;
using Ryujinx.Common.Logging;
using Ryujinx.Common.Utilities;
using Ryujinx.UI.Common.Configuration;
using System;
Expand All @@ -17,7 +16,6 @@ class LocaleManager : BaseModel
private const string DefaultLanguageCode = "en_US";

private readonly Dictionary<LocaleKeys, string> _localeStrings;
private Dictionary<LocaleKeys, string> _localeDefaultStrings;
private readonly ConcurrentDictionary<LocaleKeys, object[]> _dynamicValues;
private string _localeLanguageCode;

Expand All @@ -27,7 +25,6 @@ class LocaleManager : BaseModel
public LocaleManager()
{
_localeStrings = new Dictionary<LocaleKeys, string>();
_localeDefaultStrings = new Dictionary<LocaleKeys, string>();
_dynamicValues = new ConcurrentDictionary<LocaleKeys, object[]>();

Load();
Expand All @@ -37,9 +34,7 @@ private void Load()
{
var localeLanguageCode = !string.IsNullOrEmpty(ConfigurationState.Instance.UI.LanguageCode.Value) ?
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);

// Save whatever we ended up with.
Expand All @@ -66,26 +61,14 @@ public string this[LocaleKeys key]
}
catch
{
// If formatting failed use the default text instead.
if (_localeDefaultStrings.TryGetValue(key, out value))
try
{
return string.Format(value, dynamicValue);
}
catch
{
// If formatting the default text failed return the key.
return key.ToString();
}
// If formatting the text failed,
// continue to the below line & return the text without formatting.
}

return value;
}

// If the locale doesn't contain the key return the default one.
return _localeDefaultStrings.TryGetValue(key, out string defaultValue)
? defaultValue
: key.ToString(); // If the locale text doesn't exist return the key.

return key.ToString(); // If the locale text doesn't exist return the key.
}
set
{
Expand Down Expand Up @@ -114,19 +97,14 @@ public string UpdateAndGetDynamicValue(LocaleKeys key, params object[] values)
return this[key];
}

private void LoadDefaultLanguage()
{
_localeDefaultStrings = LoadJsonLanguage(DefaultLanguageCode);
}

public void LoadLanguage(string languageCode)
{
var locale = LoadJsonLanguage(languageCode);

if (locale == null)
{
_localeLanguageCode = DefaultLanguageCode;
locale = _localeDefaultStrings;
locale = LoadJsonLanguage(_localeLanguageCode);
}
else
{
Expand Down Expand Up @@ -167,15 +145,16 @@ private static Dictionary<LocaleKeys, string> LoadJsonLanguage(string languageCo
if (!Enum.TryParse<LocaleKeys>(locale.ID, out var localeKey))
continue;

localeStrings[localeKey] =
locale.Translations.TryGetValue(languageCode, out string val) && !string.IsNullOrEmpty(val)
? val
: locale.Translations[DefaultLanguageCode];

if (string.IsNullOrEmpty(localeStrings[localeKey]))
var str = locale.Translations.TryGetValue(languageCode, out string val) && !string.IsNullOrEmpty(val)
? val
: locale.Translations[DefaultLanguageCode];

if (string.IsNullOrEmpty(str))
{
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;
Expand Down
25 changes: 4 additions & 21 deletions src/Ryujinx/UI/Views/Main/MainMenuBarView.axaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,13 @@
using Avalonia.Interactivity;
using Avalonia.Threading;
using Gommon;
using LibHac.Ncm;
using LibHac.Tools.FsSystem.NcaUtils;
using Ryujinx.Ava.Common.Locale;
using Ryujinx.Ava.UI.Helpers;
using Ryujinx.Ava.UI.ViewModels;
using Ryujinx.Ava.UI.Windows;
using Ryujinx.Common;
using Ryujinx.Common.Utilities;
using Ryujinx.HLE.HOS.Services.Nfc.AmiiboDecryption;
using Ryujinx.HLE;
using Ryujinx.UI.App.Common;
using Ryujinx.UI.Common;
using Ryujinx.UI.Common.Configuration;
using Ryujinx.UI.Common.Helper;
Expand Down Expand Up @@ -124,26 +120,13 @@ public async void OpenSettings(object sender, RoutedEventArgs e)
ViewModel.LoadConfigurableHotKeys();
}

public static readonly AppletMetadata MiiApplet = new("miiEdit", 0x0100000000001009);

public async void OpenMiiApplet(object sender, RoutedEventArgs e)
{
const string AppletName = "miiEdit";
const ulong AppletProgramId = 0x0100000000001009;
const string AppletVersion = "1.0.0";

string contentPath = ViewModel.ContentManager.GetInstalledContentPath(AppletProgramId, StorageId.BuiltInSystem, NcaContentType.Program);

if (!string.IsNullOrEmpty(contentPath))
if (MiiApplet.CanStart(ViewModel.ContentManager, out var appData, out var nacpData))
{
ApplicationData applicationData = new()
{
Name = AppletName,
Id = AppletProgramId,
Path = contentPath
};

var nacpData = StructHelpers.CreateCustomNacpData(AppletName, AppletVersion);

await ViewModel.LoadApplication(applicationData, ViewModel.IsFullScreen || ViewModel.StartGamesInFullscreen, nacpData);
await ViewModel.LoadApplication(appData, ViewModel.IsFullScreen || ViewModel.StartGamesInFullscreen, nacpData);
}
}

Expand Down

0 comments on commit 412d406

Please sign in to comment.