diff --git a/Ryujinx/Ui/AboutWindow.cs b/Ryujinx/Ui/AboutWindow.cs index 9d1fff68ed..981a881b8e 100644 --- a/Ryujinx/Ui/AboutWindow.cs +++ b/Ryujinx/Ui/AboutWindow.cs @@ -21,7 +21,7 @@ namespace Ryujinx.UI { public static Info Information { get; private set; } -#pragma warning disable 649 +#pragma warning disable CS0649 [GUI] Window _aboutWin; [GUI] Label _versionText; [GUI] Image _ryujinxLogo; @@ -29,7 +29,7 @@ namespace Ryujinx.UI [GUI] Image _gitHubLogo; [GUI] Image _discordLogo; [GUI] Image _twitterLogo; -#pragma warning restore 649 +#pragma warning restore CS0649 public AboutWindow() : this(new Builder("Ryujinx.Ui.AboutWindow.glade")) { } diff --git a/Ryujinx/Ui/ApplicationLibrary.cs b/Ryujinx/Ui/ApplicationLibrary.cs index f74d6f02ce..b641e3b787 100644 --- a/Ryujinx/Ui/ApplicationLibrary.cs +++ b/Ryujinx/Ui/ApplicationLibrary.cs @@ -1,4 +1,4 @@ -using JsonPrettyPrinterPlus; +using JsonPrettyPrinterPlus; using LibHac; using LibHac.Fs; using LibHac.FsSystem; @@ -20,6 +20,8 @@ namespace Ryujinx.UI { public class ApplicationLibrary { + public static event EventHandler ApplicationAdded; + public static byte[] RyujinxNspIcon { get; private set; } public static byte[] RyujinxXciIcon { get; private set; } public static byte[] RyujinxNcaIcon { get; private set; } @@ -41,7 +43,8 @@ namespace Ryujinx.UI public string Path { get; set; } } - public static List ApplicationLibraryData { get; private set; } + public static float NumApplicationsFound { get; set; } + public static float NumApplicationsLoaded { get; set; } private static Keyset KeySet; private static SystemState.TitleLanguage DesiredTitleLanguage; @@ -59,7 +62,7 @@ namespace Ryujinx.UI private static ApplicationMetadata AppMetadata; - public static void Init(List AppDirs, Keyset keySet, SystemState.TitleLanguage desiredTitleLanguage) + public static void LoadApplications(List AppDirs, Keyset keySet, SystemState.TitleLanguage desiredTitleLanguage) { KeySet = keySet; DesiredTitleLanguage = desiredTitleLanguage; @@ -86,19 +89,29 @@ namespace Ryujinx.UI foreach (string app in apps) { if ((Path.GetExtension(app) == ".xci") || - (Path.GetExtension(app) == ".nca") || (Path.GetExtension(app) == ".nsp") || (Path.GetExtension(app) == ".pfs0")|| (Path.GetExtension(app) == ".nro") || (Path.GetExtension(app) == ".nso")) { 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 - ApplicationLibraryData = new List(); + // Loops through applications list, creating a struct and then firing an event containing the struct for each application foreach (string applicationPath in applications) { double filesize = new FileInfo(applicationPath).Length * 0.000000000931; @@ -308,12 +321,6 @@ namespace Ryujinx.UI { 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; } else if (Path.GetExtension(applicationPath) == ".nso") @@ -352,10 +359,21 @@ namespace Ryujinx.UI 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) { 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; } + } } diff --git a/Ryujinx/Ui/MainWindow.cs b/Ryujinx/Ui/MainWindow.cs index 5416fc77e1..1b8ebf5b0d 100644 --- a/Ryujinx/Ui/MainWindow.cs +++ b/Ryujinx/Ui/MainWindow.cs @@ -17,6 +17,8 @@ using System.Text; using System.Threading; using Utf8Json; using Utf8Json.Resolvers; +using System.Threading.Tasks; +using System.Collections.Generic; namespace Ryujinx.UI { @@ -74,7 +76,7 @@ namespace Ryujinx.UI public static RichPresence DiscordPresence; -#pragma warning disable 649 +#pragma warning disable CS0649 [GUI] Window _mainWin; [GUI] CheckMenuItem _fullScreen; [GUI] MenuItem _stopEmulation; @@ -89,7 +91,9 @@ namespace Ryujinx.UI [GUI] CheckMenuItem _fileSizeToggle; [GUI] CheckMenuItem _pathToggle; [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) { } @@ -99,6 +103,8 @@ namespace Ryujinx.UI DeleteEvent += Window_Close; + ApplicationLibrary.ApplicationAdded += Application_Added; + _renderer = new OglRenderer(); _audioOut = InitializeAudioEngine(); @@ -110,8 +116,6 @@ namespace Ryujinx.UI Configuration.Load(System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Config.json")); Configuration.InitialConfigure(_device); - ApplicationLibrary.Init(SwitchSettings.SwitchConfig.GameDirs, _device.System.KeySet, _device.System.State.DesiredTitleLanguage); - ApplyTheme(); if (DiscordIntegrationEnabled) @@ -138,7 +142,7 @@ namespace Ryujinx.UI if (SwitchSettings.SwitchConfig.GuiColumns.FavColumn) { _favToggle.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.VersionColumn) { _versionToggle.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)); UpdateColumns(); +#pragma warning disable CS4014 UpdateGameTable(); +#pragma warning restore CS4014 } public static void CreateErrorDialog(string errorMessage) @@ -230,19 +236,16 @@ namespace Ryujinx.UI if (SwitchSettings.SwitchConfig.GuiColumns.PathColumn) { pathColumn.SortColumnId = 9; } } - public static void UpdateGameTable() + public static async Task UpdateGameTable() { _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(6, LastPlayedSort); _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) @@ -470,6 +473,13 @@ namespace Ryujinx.UI } //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) { _tableStore.GetIter(out TreeIter treeIter, new TreePath(args.Path)); diff --git a/Ryujinx/Ui/MainWindow.glade b/Ryujinx/Ui/MainWindow.glade index 347f8af8d3..dc715546a2 100644 --- a/Ryujinx/Ui/MainWindow.glade +++ b/Ryujinx/Ui/MainWindow.glade @@ -313,21 +313,72 @@ - + True - True - in + False + vertical - + True True - True - True - - - + in + + + True + True + True + True + + + + + + + True + True + 0 + + + + + True + False + + + True + False + 5 + 5 + 2 + 2 + + + False + True + 0 + + + + + 200 + True + False + start + + + True + True + 1 + + + + + False + True + 1 + diff --git a/Ryujinx/Ui/SwitchSettings.cs b/Ryujinx/Ui/SwitchSettings.cs index adff7b83b0..eb71eafc30 100644 --- a/Ryujinx/Ui/SwitchSettings.cs +++ b/Ryujinx/Ui/SwitchSettings.cs @@ -21,7 +21,7 @@ namespace Ryujinx.UI private static bool _listeningForKeypress; -#pragma warning disable 649 +#pragma warning disable CS0649 [GUI] Window _settingsWin; [GUI] CheckButton _errorLogToggle; [GUI] CheckButton _warningLogToggle; @@ -78,7 +78,7 @@ namespace Ryujinx.UI [GUI] ToggleButton _plus1; [GUI] ToggleButton _r1; [GUI] ToggleButton _zR1; -#pragma warning restore 649 +#pragma warning restore CS0649 public static void ConfigureSettings(Configuration Instance) { SwitchConfig = Instance; }