Async loading of game list
This commit is contained in:
parent
af3d06de27
commit
72862c2222
5 changed files with 124 additions and 39 deletions
|
@ -21,7 +21,7 @@ namespace Ryujinx.UI
|
||||||
{
|
{
|
||||||
public static Info Information { get; private set; }
|
public static Info Information { get; private set; }
|
||||||
|
|
||||||
#pragma warning disable 649
|
#pragma warning disable CS0649
|
||||||
[GUI] Window _aboutWin;
|
[GUI] Window _aboutWin;
|
||||||
[GUI] Label _versionText;
|
[GUI] Label _versionText;
|
||||||
[GUI] Image _ryujinxLogo;
|
[GUI] Image _ryujinxLogo;
|
||||||
|
@ -29,7 +29,7 @@ namespace Ryujinx.UI
|
||||||
[GUI] Image _gitHubLogo;
|
[GUI] Image _gitHubLogo;
|
||||||
[GUI] Image _discordLogo;
|
[GUI] Image _discordLogo;
|
||||||
[GUI] Image _twitterLogo;
|
[GUI] Image _twitterLogo;
|
||||||
#pragma warning restore 649
|
#pragma warning restore CS0649
|
||||||
|
|
||||||
public AboutWindow() : this(new Builder("Ryujinx.Ui.AboutWindow.glade")) { }
|
public AboutWindow() : this(new Builder("Ryujinx.Ui.AboutWindow.glade")) { }
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
using JsonPrettyPrinterPlus;
|
using JsonPrettyPrinterPlus;
|
||||||
using LibHac;
|
using LibHac;
|
||||||
using LibHac.Fs;
|
using LibHac.Fs;
|
||||||
using LibHac.FsSystem;
|
using LibHac.FsSystem;
|
||||||
|
@ -20,6 +20,8 @@ namespace Ryujinx.UI
|
||||||
{
|
{
|
||||||
public class ApplicationLibrary
|
public class ApplicationLibrary
|
||||||
{
|
{
|
||||||
|
public static event EventHandler<ApplicationAddedEventArgs> ApplicationAdded;
|
||||||
|
|
||||||
public static byte[] RyujinxNspIcon { get; private set; }
|
public static byte[] RyujinxNspIcon { get; private set; }
|
||||||
public static byte[] RyujinxXciIcon { get; private set; }
|
public static byte[] RyujinxXciIcon { get; private set; }
|
||||||
public static byte[] RyujinxNcaIcon { get; private set; }
|
public static byte[] RyujinxNcaIcon { get; private set; }
|
||||||
|
@ -41,7 +43,8 @@ namespace Ryujinx.UI
|
||||||
public string Path { get; set; }
|
public string Path { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public static List<ApplicationData> ApplicationLibraryData { get; private set; }
|
public static float NumApplicationsFound { get; set; }
|
||||||
|
public static float NumApplicationsLoaded { get; set; }
|
||||||
|
|
||||||
private static Keyset KeySet;
|
private static Keyset KeySet;
|
||||||
private static SystemState.TitleLanguage DesiredTitleLanguage;
|
private static SystemState.TitleLanguage DesiredTitleLanguage;
|
||||||
|
@ -59,7 +62,7 @@ namespace Ryujinx.UI
|
||||||
|
|
||||||
private static ApplicationMetadata AppMetadata;
|
private static ApplicationMetadata AppMetadata;
|
||||||
|
|
||||||
public static void Init(List<string> AppDirs, Keyset keySet, SystemState.TitleLanguage desiredTitleLanguage)
|
public static void LoadApplications(List<string> AppDirs, Keyset keySet, SystemState.TitleLanguage desiredTitleLanguage)
|
||||||
{
|
{
|
||||||
KeySet = keySet;
|
KeySet = keySet;
|
||||||
DesiredTitleLanguage = desiredTitleLanguage;
|
DesiredTitleLanguage = desiredTitleLanguage;
|
||||||
|
@ -86,19 +89,29 @@ namespace Ryujinx.UI
|
||||||
foreach (string app in apps)
|
foreach (string app in apps)
|
||||||
{
|
{
|
||||||
if ((Path.GetExtension(app) == ".xci") ||
|
if ((Path.GetExtension(app) == ".xci") ||
|
||||||
(Path.GetExtension(app) == ".nca") ||
|
|
||||||
(Path.GetExtension(app) == ".nsp") ||
|
(Path.GetExtension(app) == ".nsp") ||
|
||||||
(Path.GetExtension(app) == ".pfs0")||
|
(Path.GetExtension(app) == ".pfs0")||
|
||||||
(Path.GetExtension(app) == ".nro") ||
|
(Path.GetExtension(app) == ".nro") ||
|
||||||
(Path.GetExtension(app) == ".nso"))
|
(Path.GetExtension(app) == ".nso"))
|
||||||
{
|
{
|
||||||
applications.Add(app);
|
applications.Add(app);
|
||||||
|
NumApplicationsFound++;
|
||||||
|
}
|
||||||
|
else if (Path.GetExtension(app) == ".nca")
|
||||||
|
{
|
||||||
|
Nca nca = new Nca(KeySet, new FileStream(app, FileMode.Open, FileAccess.Read).AsStorage());
|
||||||
|
if (nca.Header.ContentType != NcaContentType.Program)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
applications.Add(app);
|
||||||
|
NumApplicationsFound++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Loops through applications list, creating a struct for each application and then adding the struct to a list of structs
|
// Loops through applications list, creating a struct and then firing an event containing the struct for each application
|
||||||
ApplicationLibraryData = new List<ApplicationData>();
|
|
||||||
foreach (string applicationPath in applications)
|
foreach (string applicationPath in applications)
|
||||||
{
|
{
|
||||||
double filesize = new FileInfo(applicationPath).Length * 0.000000000931;
|
double filesize = new FileInfo(applicationPath).Length * 0.000000000931;
|
||||||
|
@ -308,12 +321,6 @@ namespace Ryujinx.UI
|
||||||
{
|
{
|
||||||
if (Path.GetExtension(applicationPath) == ".nca")
|
if (Path.GetExtension(applicationPath) == ".nca")
|
||||||
{
|
{
|
||||||
Nca nca = new Nca(KeySet, new FileStream(applicationPath, FileMode.Open, FileAccess.Read).AsStorage(false));
|
|
||||||
if (nca.Header.ContentType != NcaContentType.Program)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
applicationIcon = RyujinxNcaIcon;
|
applicationIcon = RyujinxNcaIcon;
|
||||||
}
|
}
|
||||||
else if (Path.GetExtension(applicationPath) == ".nso")
|
else if (Path.GetExtension(applicationPath) == ".nso")
|
||||||
|
@ -352,10 +359,21 @@ namespace Ryujinx.UI
|
||||||
Path = applicationPath,
|
Path = applicationPath,
|
||||||
};
|
};
|
||||||
|
|
||||||
ApplicationLibraryData.Add(data);
|
NumApplicationsLoaded++;
|
||||||
|
|
||||||
|
OnApplicationAdded(new ApplicationAddedEventArgs()
|
||||||
|
{
|
||||||
|
AppData = data,
|
||||||
|
AppsLoaded = NumApplicationsLoaded
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected static void OnApplicationAdded(ApplicationAddedEventArgs e)
|
||||||
|
{
|
||||||
|
ApplicationAdded?.Invoke(null, e);
|
||||||
|
}
|
||||||
|
|
||||||
private static byte[] GetResourceBytes(string resourceName)
|
private static byte[] GetResourceBytes(string resourceName)
|
||||||
{
|
{
|
||||||
Stream resourceStream = Assembly.GetCallingAssembly().GetManifestResourceStream(resourceName);
|
Stream resourceStream = Assembly.GetCallingAssembly().GetManifestResourceStream(resourceName);
|
||||||
|
@ -461,4 +479,10 @@ namespace Ryujinx.UI
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public class ApplicationAddedEventArgs : EventArgs
|
||||||
|
{
|
||||||
|
public ApplicationLibrary.ApplicationData AppData { get; set; }
|
||||||
|
public float AppsLoaded { get; set; }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,6 +17,8 @@ using System.Text;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using Utf8Json;
|
using Utf8Json;
|
||||||
using Utf8Json.Resolvers;
|
using Utf8Json.Resolvers;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
namespace Ryujinx.UI
|
namespace Ryujinx.UI
|
||||||
{
|
{
|
||||||
|
@ -74,7 +76,7 @@ namespace Ryujinx.UI
|
||||||
|
|
||||||
public static RichPresence DiscordPresence;
|
public static RichPresence DiscordPresence;
|
||||||
|
|
||||||
#pragma warning disable 649
|
#pragma warning disable CS0649
|
||||||
[GUI] Window _mainWin;
|
[GUI] Window _mainWin;
|
||||||
[GUI] CheckMenuItem _fullScreen;
|
[GUI] CheckMenuItem _fullScreen;
|
||||||
[GUI] MenuItem _stopEmulation;
|
[GUI] MenuItem _stopEmulation;
|
||||||
|
@ -89,7 +91,9 @@ namespace Ryujinx.UI
|
||||||
[GUI] CheckMenuItem _fileSizeToggle;
|
[GUI] CheckMenuItem _fileSizeToggle;
|
||||||
[GUI] CheckMenuItem _pathToggle;
|
[GUI] CheckMenuItem _pathToggle;
|
||||||
[GUI] TreeView _gameTable;
|
[GUI] TreeView _gameTable;
|
||||||
#pragma warning restore 649
|
[GUI] Label _progressLabel;
|
||||||
|
[GUI] LevelBar _progressBar;
|
||||||
|
#pragma warning restore CS0649
|
||||||
|
|
||||||
public MainWindow(string[] args, Application gtkApplication) : this(new Builder("Ryujinx.Ui.MainWindow.glade"), args, gtkApplication) { }
|
public MainWindow(string[] args, Application gtkApplication) : this(new Builder("Ryujinx.Ui.MainWindow.glade"), args, gtkApplication) { }
|
||||||
|
|
||||||
|
@ -99,6 +103,8 @@ namespace Ryujinx.UI
|
||||||
|
|
||||||
DeleteEvent += Window_Close;
|
DeleteEvent += Window_Close;
|
||||||
|
|
||||||
|
ApplicationLibrary.ApplicationAdded += Application_Added;
|
||||||
|
|
||||||
_renderer = new OglRenderer();
|
_renderer = new OglRenderer();
|
||||||
|
|
||||||
_audioOut = InitializeAudioEngine();
|
_audioOut = InitializeAudioEngine();
|
||||||
|
@ -110,8 +116,6 @@ namespace Ryujinx.UI
|
||||||
Configuration.Load(System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Config.json"));
|
Configuration.Load(System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Config.json"));
|
||||||
Configuration.InitialConfigure(_device);
|
Configuration.InitialConfigure(_device);
|
||||||
|
|
||||||
ApplicationLibrary.Init(SwitchSettings.SwitchConfig.GameDirs, _device.System.KeySet, _device.System.State.DesiredTitleLanguage);
|
|
||||||
|
|
||||||
ApplyTheme();
|
ApplyTheme();
|
||||||
|
|
||||||
if (DiscordIntegrationEnabled)
|
if (DiscordIntegrationEnabled)
|
||||||
|
@ -138,7 +142,7 @@ namespace Ryujinx.UI
|
||||||
|
|
||||||
if (SwitchSettings.SwitchConfig.GuiColumns.FavColumn) { _favToggle.Active = true; }
|
if (SwitchSettings.SwitchConfig.GuiColumns.FavColumn) { _favToggle.Active = true; }
|
||||||
if (SwitchSettings.SwitchConfig.GuiColumns.IconColumn) { _iconToggle.Active = true; }
|
if (SwitchSettings.SwitchConfig.GuiColumns.IconColumn) { _iconToggle.Active = true; }
|
||||||
if (SwitchSettings.SwitchConfig.GuiColumns.AppColumn) { _appToggle.Active = true; }
|
if (SwitchSettings.SwitchConfig.GuiColumns.AppColumn) { _appToggle.Active = true; }
|
||||||
if (SwitchSettings.SwitchConfig.GuiColumns.DevColumn) { _developerToggle.Active = true; }
|
if (SwitchSettings.SwitchConfig.GuiColumns.DevColumn) { _developerToggle.Active = true; }
|
||||||
if (SwitchSettings.SwitchConfig.GuiColumns.VersionColumn) { _versionToggle.Active = true; }
|
if (SwitchSettings.SwitchConfig.GuiColumns.VersionColumn) { _versionToggle.Active = true; }
|
||||||
if (SwitchSettings.SwitchConfig.GuiColumns.TimePlayedColumn) { _timePlayedToggle.Active = true; }
|
if (SwitchSettings.SwitchConfig.GuiColumns.TimePlayedColumn) { _timePlayedToggle.Active = true; }
|
||||||
|
@ -150,7 +154,9 @@ namespace Ryujinx.UI
|
||||||
_gameTable.Model = _tableStore = new ListStore(typeof(bool), typeof(Gdk.Pixbuf), typeof(string), typeof(string), typeof(string), typeof(string), typeof(string), typeof(string), typeof(string), typeof(string));
|
_gameTable.Model = _tableStore = new ListStore(typeof(bool), typeof(Gdk.Pixbuf), typeof(string), typeof(string), typeof(string), typeof(string), typeof(string), typeof(string), typeof(string), typeof(string));
|
||||||
|
|
||||||
UpdateColumns();
|
UpdateColumns();
|
||||||
|
#pragma warning disable CS4014
|
||||||
UpdateGameTable();
|
UpdateGameTable();
|
||||||
|
#pragma warning restore CS4014
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void CreateErrorDialog(string errorMessage)
|
public static void CreateErrorDialog(string errorMessage)
|
||||||
|
@ -230,19 +236,16 @@ namespace Ryujinx.UI
|
||||||
if (SwitchSettings.SwitchConfig.GuiColumns.PathColumn) { pathColumn.SortColumnId = 9; }
|
if (SwitchSettings.SwitchConfig.GuiColumns.PathColumn) { pathColumn.SortColumnId = 9; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void UpdateGameTable()
|
public static async Task UpdateGameTable()
|
||||||
{
|
{
|
||||||
_tableStore.Clear();
|
_tableStore.Clear();
|
||||||
ApplicationLibrary.Init(SwitchSettings.SwitchConfig.GameDirs, _device.System.KeySet, _device.System.State.DesiredTitleLanguage);
|
|
||||||
|
|
||||||
foreach (ApplicationLibrary.ApplicationData AppData in ApplicationLibrary.ApplicationLibraryData)
|
|
||||||
{
|
|
||||||
_tableStore.AppendValues(AppData.Favorite, new Gdk.Pixbuf(AppData.Icon, 75, 75), $"{AppData.TitleName}\n{AppData.TitleId.ToUpper()}", AppData.Developer, AppData.Version, AppData.TimePlayed, AppData.LastPlayed, AppData.FileExtension, AppData.FileSize, AppData.Path);
|
|
||||||
}
|
|
||||||
|
|
||||||
_tableStore.SetSortFunc(5, TimePlayedSort);
|
_tableStore.SetSortFunc(5, TimePlayedSort);
|
||||||
_tableStore.SetSortFunc(6, LastPlayedSort);
|
_tableStore.SetSortFunc(6, LastPlayedSort);
|
||||||
_tableStore.SetSortFunc(8, FileSizeSort);
|
_tableStore.SetSortFunc(8, FileSizeSort);
|
||||||
|
ApplicationLibrary.NumApplicationsLoaded = 0;
|
||||||
|
ApplicationLibrary.NumApplicationsFound = 0;
|
||||||
|
|
||||||
|
await Task.Run(() => { ApplicationLibrary.LoadApplications(SwitchSettings.SwitchConfig.GameDirs, _device.System.KeySet, _device.System.State.DesiredTitleLanguage); });
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void LoadApplication(string path)
|
internal void LoadApplication(string path)
|
||||||
|
@ -470,6 +473,13 @@ namespace Ryujinx.UI
|
||||||
}
|
}
|
||||||
|
|
||||||
//Events
|
//Events
|
||||||
|
private void Application_Added(object sender, ApplicationAddedEventArgs e)
|
||||||
|
{
|
||||||
|
_tableStore.AppendValues(e.AppData.Favorite, new Gdk.Pixbuf(e.AppData.Icon, 75, 75), $"{e.AppData.TitleName}\n{e.AppData.TitleId.ToUpper()}", e.AppData.Developer, e.AppData.Version, e.AppData.TimePlayed, e.AppData.LastPlayed, e.AppData.FileExtension, e.AppData.FileSize, e.AppData.Path);
|
||||||
|
_progressLabel.Text = $"{e.AppsLoaded}/{ApplicationLibrary.NumApplicationsFound} Games Loaded";
|
||||||
|
_progressBar.Value = e.AppsLoaded / ApplicationLibrary.NumApplicationsFound;
|
||||||
|
}
|
||||||
|
|
||||||
private void FavToggle_Toggled(object o, ToggledArgs args)
|
private void FavToggle_Toggled(object o, ToggledArgs args)
|
||||||
{
|
{
|
||||||
_tableStore.GetIter(out TreeIter treeIter, new TreePath(args.Path));
|
_tableStore.GetIter(out TreeIter treeIter, new TreePath(args.Path));
|
||||||
|
|
|
@ -313,21 +313,72 @@
|
||||||
</packing>
|
</packing>
|
||||||
</child>
|
</child>
|
||||||
<child>
|
<child>
|
||||||
<object class="GtkScrolledWindow" id="_gameTableWindow">
|
<object class="GtkBox" id="MainBox">
|
||||||
<property name="visible">True</property>
|
<property name="visible">True</property>
|
||||||
<property name="can_focus">True</property>
|
<property name="can_focus">False</property>
|
||||||
<property name="shadow_type">in</property>
|
<property name="orientation">vertical</property>
|
||||||
<child>
|
<child>
|
||||||
<object class="GtkTreeView" id="_gameTable">
|
<object class="GtkScrolledWindow" id="_gameTableWindow">
|
||||||
<property name="visible">True</property>
|
<property name="visible">True</property>
|
||||||
<property name="can_focus">True</property>
|
<property name="can_focus">True</property>
|
||||||
<property name="reorderable">True</property>
|
<property name="shadow_type">in</property>
|
||||||
<property name="hover_selection">True</property>
|
<child>
|
||||||
<signal name="row-activated" handler="Row_Activated" swapped="no"/>
|
<object class="GtkTreeView" id="_gameTable">
|
||||||
<child internal-child="selection">
|
<property name="visible">True</property>
|
||||||
<object class="GtkTreeSelection"/>
|
<property name="can_focus">True</property>
|
||||||
|
<property name="reorderable">True</property>
|
||||||
|
<property name="hover_selection">True</property>
|
||||||
|
<signal name="row-activated" handler="Row_Activated" swapped="no"/>
|
||||||
|
<child internal-child="selection">
|
||||||
|
<object class="GtkTreeSelection"/>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
</child>
|
</child>
|
||||||
</object>
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="expand">True</property>
|
||||||
|
<property name="fill">True</property>
|
||||||
|
<property name="position">0</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkBox" id="ProgressBox">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkLabel" id="_progressLabel">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<property name="margin_left">5</property>
|
||||||
|
<property name="margin_right">5</property>
|
||||||
|
<property name="margin_top">2</property>
|
||||||
|
<property name="margin_bottom">2</property>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="expand">False</property>
|
||||||
|
<property name="fill">True</property>
|
||||||
|
<property name="position">0</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkLevelBar" id="_progressBar">
|
||||||
|
<property name="width_request">200</property>
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can_focus">False</property>
|
||||||
|
<property name="halign">start</property>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="expand">True</property>
|
||||||
|
<property name="fill">True</property>
|
||||||
|
<property name="position">1</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="expand">False</property>
|
||||||
|
<property name="fill">True</property>
|
||||||
|
<property name="position">1</property>
|
||||||
|
</packing>
|
||||||
</child>
|
</child>
|
||||||
</object>
|
</object>
|
||||||
<packing>
|
<packing>
|
||||||
|
|
|
@ -21,7 +21,7 @@ namespace Ryujinx.UI
|
||||||
|
|
||||||
private static bool _listeningForKeypress;
|
private static bool _listeningForKeypress;
|
||||||
|
|
||||||
#pragma warning disable 649
|
#pragma warning disable CS0649
|
||||||
[GUI] Window _settingsWin;
|
[GUI] Window _settingsWin;
|
||||||
[GUI] CheckButton _errorLogToggle;
|
[GUI] CheckButton _errorLogToggle;
|
||||||
[GUI] CheckButton _warningLogToggle;
|
[GUI] CheckButton _warningLogToggle;
|
||||||
|
@ -78,7 +78,7 @@ namespace Ryujinx.UI
|
||||||
[GUI] ToggleButton _plus1;
|
[GUI] ToggleButton _plus1;
|
||||||
[GUI] ToggleButton _r1;
|
[GUI] ToggleButton _r1;
|
||||||
[GUI] ToggleButton _zR1;
|
[GUI] ToggleButton _zR1;
|
||||||
#pragma warning restore 649
|
#pragma warning restore CS0649
|
||||||
|
|
||||||
public static void ConfigureSettings(Configuration Instance) { SwitchConfig = Instance; }
|
public static void ConfigureSettings(Configuration Instance) { SwitchConfig = Instance; }
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue