Async loading of game list

This commit is contained in:
Xpl0itR 2019-10-16 20:10:12 +01:00 committed by unknown
commit 72862c2222
No known key found for this signature in database
GPG key ID: 91798184109676AD
5 changed files with 124 additions and 39 deletions

View file

@ -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")) { }

View file

@ -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; }
}
} }

View file

@ -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));

View file

@ -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>

View file

@ -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; }