From c5258cf082b10f335f81487f22b7eeb86075e09e Mon Sep 17 00:00:00 2001
From: NitroTears <73270647+NitroTears@users.noreply.github.com>
Date: Sun, 16 Apr 2023 11:03:35 +1000
Subject: [PATCH] Ability to hide file types in Game List (#4555)

* Added HiddenFileTypes to config state, and check to file enumeration

* Added hiddenfiletypes checkboxes to the UI

* Added Ava version of HiddenFileTypes

* Inverted Hide to Show with file types, minor formatting

* all variables with a reference to 'hidden' is now 'shown'

* one more variable name changed

* review feedback

* added FileTypes extension methof to get the correlating config value

* moved extension method to new folder and file in Ryujinx.Ui.Common

* added default case for ToggleFileType

* changed exception type to OutOfRangeException
---
 Ryujinx.Ava/Assets/Locales/en_US.json         |  1 +
 .../UI/ViewModels/MainWindowViewModel.cs      | 17 +++++
 .../UI/Views/Main/MainMenuBarView.axaml       |  1 +
 .../UI/Views/Main/MainMenuBarView.axaml.cs    | 28 +++++++-
 Ryujinx.Ui.Common/App/ApplicationLibrary.cs   | 15 +++-
 .../Configuration/ConfigurationFileFormat.cs  |  7 +-
 .../Configuration/ConfigurationState.cs       | 71 ++++++++++++++++++-
 Ryujinx.Ui.Common/Configuration/FileTypes.cs  | 12 ++++
 .../Configuration/Ui/ShownFileTypes.cs        | 12 ++++
 .../Extensions/FileTypeExtensions.cs          | 25 +++++++
 Ryujinx/Ui/MainWindow.cs                      | 68 ++++++++++++++++++
 Ryujinx/Ui/MainWindow.glade                   | 69 ++++++++++++++++++
 12 files changed, 321 insertions(+), 5 deletions(-)
 create mode 100644 Ryujinx.Ui.Common/Configuration/FileTypes.cs
 create mode 100644 Ryujinx.Ui.Common/Configuration/Ui/ShownFileTypes.cs
 create mode 100644 Ryujinx.Ui.Common/Extensions/FileTypeExtensions.cs

diff --git a/Ryujinx.Ava/Assets/Locales/en_US.json b/Ryujinx.Ava/Assets/Locales/en_US.json
index fb8f800c01..b2d6b43d7d 100644
--- a/Ryujinx.Ava/Assets/Locales/en_US.json
+++ b/Ryujinx.Ava/Assets/Locales/en_US.json
@@ -429,6 +429,7 @@
   "DlcManagerEnableAllButton": "Enable All",
   "DlcManagerDisableAllButton": "Disable All",
   "MenuBarOptionsChangeLanguage": "Change Language",
+  "MenuBarShowFileTypes": "Show File Types",
   "CommonSort": "Sort",
   "CommonShowNames": "Show Names",
   "CommonFavorite": "Favorite",
diff --git a/Ryujinx.Ava/UI/ViewModels/MainWindowViewModel.cs b/Ryujinx.Ava/UI/ViewModels/MainWindowViewModel.cs
index d5ff785458..da2115265a 100644
--- a/Ryujinx.Ava/UI/ViewModels/MainWindowViewModel.cs
+++ b/Ryujinx.Ava/UI/ViewModels/MainWindowViewModel.cs
@@ -1336,6 +1336,23 @@ namespace Ryujinx.Ava.UI.ViewModels
             }
         }
 
+        public void ToggleFileType(string fileType)
+        {
+            _ = fileType switch
+            {
+                "NSP"  => ConfigurationState.Instance.Ui.ShownFileTypes.NSP.Value  = !ConfigurationState.Instance.Ui.ShownFileTypes.NSP,
+                "PFS0" => ConfigurationState.Instance.Ui.ShownFileTypes.PFS0.Value = !ConfigurationState.Instance.Ui.ShownFileTypes.PFS0,
+                "XCI"  => ConfigurationState.Instance.Ui.ShownFileTypes.XCI.Value  = !ConfigurationState.Instance.Ui.ShownFileTypes.XCI,
+                "NCA"  => ConfigurationState.Instance.Ui.ShownFileTypes.NCA.Value  = !ConfigurationState.Instance.Ui.ShownFileTypes.NCA,
+                "NRO"  => ConfigurationState.Instance.Ui.ShownFileTypes.NRO.Value  = !ConfigurationState.Instance.Ui.ShownFileTypes.NRO,
+                "NSO"  => ConfigurationState.Instance.Ui.ShownFileTypes.NSO.Value  = !ConfigurationState.Instance.Ui.ShownFileTypes.NSO,
+                    _  => throw new ArgumentOutOfRangeException(fileType),
+            };
+
+            ConfigurationState.Instance.ToFileFormat().SaveConfig(Program.ConfigurationPath);
+            LoadApplications();
+        }
+
         public async void ManageProfiles()
         {
             await NavigationDialogHost.Show(AccountManager, ContentManager, VirtualFileSystem, LibHacHorizonManager.RyujinxClient);
diff --git a/Ryujinx.Ava/UI/Views/Main/MainMenuBarView.axaml b/Ryujinx.Ava/UI/Views/Main/MainMenuBarView.axaml
index b1d768eadc..d5b5efcdd6 100644
--- a/Ryujinx.Ava/UI/Views/Main/MainMenuBarView.axaml
+++ b/Ryujinx.Ava/UI/Views/Main/MainMenuBarView.axaml
@@ -78,6 +78,7 @@
                 </MenuItem>
                 <Separator />
                 <MenuItem Name="ChangeLanguageMenuItem" Header="{locale:Locale MenuBarOptionsChangeLanguage}" />
+				<MenuItem Name="ToggleFileTypesMenuItem" Header="{locale:Locale MenuBarShowFileTypes}" />
                 <Separator />
                 <MenuItem
                     Click="OpenSettings"
diff --git a/Ryujinx.Ava/UI/Views/Main/MainMenuBarView.axaml.cs b/Ryujinx.Ava/UI/Views/Main/MainMenuBarView.axaml.cs
index c1eaf86fea..bdf2cf9f80 100644
--- a/Ryujinx.Ava/UI/Views/Main/MainMenuBarView.axaml.cs
+++ b/Ryujinx.Ava/UI/Views/Main/MainMenuBarView.axaml.cs
@@ -11,6 +11,8 @@ using Ryujinx.Common;
 using Ryujinx.Common.Utilities;
 using Ryujinx.HLE.HOS;
 using Ryujinx.Modules;
+using Ryujinx.Ui.Common;
+using Ryujinx.Ui.Common.Configuration;
 using Ryujinx.Ui.Common.Helper;
 using System;
 using System.Collections.Generic;
@@ -29,6 +31,30 @@ namespace Ryujinx.Ava.UI.Views.Main
         {
             InitializeComponent();
 
+            ToggleFileTypesMenuItem.Items = GenerateToggleFileTypeItems();
+            ChangeLanguageMenuItem.Items = GenerateLanguageMenuItems();
+        }
+
+        private CheckBox[] GenerateToggleFileTypeItems()
+        {
+            List<CheckBox> checkBoxes = new();
+
+            foreach (var item in Enum.GetValues(typeof (FileTypes)))
+            {
+                string fileName = Enum.GetName(typeof (FileTypes), item);
+                checkBoxes.Add(new CheckBox()
+                {
+                    Content = $".{fileName}",
+                    IsChecked = ((FileTypes)item).GetConfigValue(ConfigurationState.Instance.Ui.ShownFileTypes),
+                    Command = MiniCommand.Create(() => ViewModel.ToggleFileType(fileName))
+                });
+            }
+
+            return checkBoxes.ToArray();
+        }
+
+        private MenuItem[] GenerateLanguageMenuItems()
+        {
             List<MenuItem> menuItems = new();
 
             string localePath = "Ryujinx.Ava/Assets/Locales";
@@ -61,7 +87,7 @@ namespace Ryujinx.Ava.UI.Views.Main
                 menuItems.Add(menuItem);
             }
 
-            ChangeLanguageMenuItem.Items = menuItems.ToArray();
+            return menuItems.ToArray();
         }
 
         protected override void OnAttachedToVisualTree(VisualTreeAttachmentEventArgs e)
diff --git a/Ryujinx.Ui.Common/App/ApplicationLibrary.cs b/Ryujinx.Ui.Common/App/ApplicationLibrary.cs
index 66cb7c73b6..b7b57f1a29 100644
--- a/Ryujinx.Ui.Common/App/ApplicationLibrary.cs
+++ b/Ryujinx.Ui.Common/App/ApplicationLibrary.cs
@@ -14,9 +14,11 @@ using Ryujinx.Common.Utilities;
 using Ryujinx.HLE.FileSystem;
 using Ryujinx.HLE.HOS.SystemState;
 using Ryujinx.HLE.Loaders.Npdm;
+using Ryujinx.Ui.Common.Configuration;
 using Ryujinx.Ui.Common.Configuration.System;
 using System;
 using System.Collections.Generic;
+using System.Linq;
 using System.Globalization;
 using System.IO;
 using System.Reflection;
@@ -109,7 +111,18 @@ namespace Ryujinx.Ui.App.Common
 
                     try
                     {
-                        foreach (string app in Directory.EnumerateFiles(appDir, "*", SearchOption.AllDirectories))
+                        IEnumerable<string> files = Directory.EnumerateFiles(appDir, "*", SearchOption.AllDirectories).Where(file =>
+                        {
+                            return
+                            (Path.GetExtension(file).ToLower() is ".nsp"  && ConfigurationState.Instance.Ui.ShownFileTypes.NSP.Value)  ||
+                            (Path.GetExtension(file).ToLower() is ".pfs0" && ConfigurationState.Instance.Ui.ShownFileTypes.PFS0.Value) ||
+                            (Path.GetExtension(file).ToLower() is ".xci"  && ConfigurationState.Instance.Ui.ShownFileTypes.XCI.Value)  ||
+                            (Path.GetExtension(file).ToLower() is ".nca"  && ConfigurationState.Instance.Ui.ShownFileTypes.NCA.Value)  ||
+                            (Path.GetExtension(file).ToLower() is ".nro"  && ConfigurationState.Instance.Ui.ShownFileTypes.NRO.Value)  ||
+                            (Path.GetExtension(file).ToLower() is ".nso"  && ConfigurationState.Instance.Ui.ShownFileTypes.NSO.Value);
+                        });
+                        
+                        foreach (string app in files)
                         {
                             if (_cancellationToken.Token.IsCancellationRequested)
                             {
diff --git a/Ryujinx.Ui.Common/Configuration/ConfigurationFileFormat.cs b/Ryujinx.Ui.Common/Configuration/ConfigurationFileFormat.cs
index 14c03957aa..cb9adc86ca 100644
--- a/Ryujinx.Ui.Common/Configuration/ConfigurationFileFormat.cs
+++ b/Ryujinx.Ui.Common/Configuration/ConfigurationFileFormat.cs
@@ -14,7 +14,7 @@ namespace Ryujinx.Ui.Common.Configuration
         /// <summary>
         /// The current version of the file format
         /// </summary>
-        public const int CurrentVersion = 44;
+        public const int CurrentVersion = 45;
 
         /// <summary>
         /// Version of the configuration file format
@@ -246,6 +246,11 @@ namespace Ryujinx.Ui.Common.Configuration
         /// </summary>
         public List<string> GameDirs { get; set; }
 
+        /// <summary>
+        /// A list of file types to be hidden in the games List
+        /// </summary>
+        public ShownFileTypes ShownFileTypes { get; set; }
+
         /// <summary>
         /// Language Code for the UI
         /// </summary>
diff --git a/Ryujinx.Ui.Common/Configuration/ConfigurationState.cs b/Ryujinx.Ui.Common/Configuration/ConfigurationState.cs
index 82a331c161..12cc1b8f8e 100644
--- a/Ryujinx.Ui.Common/Configuration/ConfigurationState.cs
+++ b/Ryujinx.Ui.Common/Configuration/ConfigurationState.cs
@@ -60,6 +60,29 @@ namespace Ryujinx.Ui.Common.Configuration
                 }
             }
 
+            /// <summary>
+            /// Used to toggle which file types are shown in the UI
+            /// </summary>
+            public class ShownFileTypeSettings
+            {
+                public ReactiveObject<bool> NSP { get; private set; }
+                public ReactiveObject<bool> PFS0 { get; private set; }
+                public ReactiveObject<bool> XCI { get; private set; }
+                public ReactiveObject<bool> NCA { get; private set; }
+                public ReactiveObject<bool> NRO { get; private set; }
+                public ReactiveObject<bool> NSO { get; private set; }
+
+                public ShownFileTypeSettings()
+                {
+                    NSP  = new ReactiveObject<bool>();
+                    PFS0 = new ReactiveObject<bool>();
+                    XCI  = new ReactiveObject<bool>();
+                    NCA  = new ReactiveObject<bool>();
+                    NRO  = new ReactiveObject<bool>();
+                    NSO  = new ReactiveObject<bool>();
+                }
+            }
+
             /// <summary>
             /// Used to toggle columns in the GUI
             /// </summary>
@@ -75,6 +98,11 @@ namespace Ryujinx.Ui.Common.Configuration
             /// </summary>
             public ReactiveObject<List<string>> GameDirs { get; private set; }
 
+            /// <summary>
+            /// A list of file types to be hidden in the games List
+            /// </summary>
+            public ShownFileTypeSettings ShownFileTypes { get; private set; }
+
             /// <summary>
             /// Language Code for the UI
             /// </summary>
@@ -135,6 +163,7 @@ namespace Ryujinx.Ui.Common.Configuration
                 GuiColumns        = new Columns();
                 ColumnSort        = new ColumnSortSettings();
                 GameDirs          = new ReactiveObject<List<string>>();
+                ShownFileTypes   = new ShownFileTypeSettings();
                 EnableCustomTheme = new ReactiveObject<bool>();
                 CustomThemePath   = new ReactiveObject<string>();
                 BaseStyle         = new ReactiveObject<string>();
@@ -618,6 +647,15 @@ namespace Ryujinx.Ui.Common.Configuration
                     SortAscending = Ui.ColumnSort.SortAscending
                 },
                 GameDirs                   = Ui.GameDirs,
+                ShownFileTypes            = new ShownFileTypes
+                {
+                    NSP = Ui.ShownFileTypes.NSP,
+                    PFS0 = Ui.ShownFileTypes.PFS0,
+                    XCI = Ui.ShownFileTypes.XCI,
+                    NCA = Ui.ShownFileTypes.NCA,
+                    NRO = Ui.ShownFileTypes.NRO,
+                    NSO = Ui.ShownFileTypes.NSO,
+                },
                 LanguageCode               = Ui.LanguageCode,
                 EnableCustomTheme          = Ui.EnableCustomTheme,
                 CustomThemePath            = Ui.CustomThemePath,
@@ -702,7 +740,13 @@ namespace Ryujinx.Ui.Common.Configuration
             Ui.ColumnSort.SortColumnId.Value          = 0;
             Ui.ColumnSort.SortAscending.Value         = false;
             Ui.GameDirs.Value                         = new List<string>();
-            Ui.EnableCustomTheme.Value                = false;
+            Ui.ShownFileTypes.NSP.Value              = true;
+            Ui.ShownFileTypes.PFS0.Value             = true;
+            Ui.ShownFileTypes.XCI.Value              = true;
+            Ui.ShownFileTypes.NCA.Value              = true;
+            Ui.ShownFileTypes.NRO.Value              = true;
+            Ui.ShownFileTypes.NSO.Value              = true;
+            Ui.EnableCustomTheme.Value                = true;
             Ui.LanguageCode.Value                     = "en_US";
             Ui.CustomThemePath.Value                  = "";
             Ui.BaseStyle.Value                        = "Dark";
@@ -1238,7 +1282,7 @@ namespace Ryujinx.Ui.Common.Configuration
 
             if (configurationFileFormat.Version < 44)
             {
-                Ryujinx.Common.Logging.Logger.Warning?.Print(LogClass.Application, $"Outdated configuration version {configurationFileFormat.Version}, migrating to version 42.");
+                Ryujinx.Common.Logging.Logger.Warning?.Print(LogClass.Application, $"Outdated configuration version {configurationFileFormat.Version}, migrating to version 44.");
 
                 configurationFileFormat.AntiAliasing = AntiAliasing.None;
                 configurationFileFormat.ScalingFilter = ScalingFilter.Bilinear;
@@ -1247,6 +1291,23 @@ namespace Ryujinx.Ui.Common.Configuration
                 configurationFileUpdated = true;
             }
 
+            if (configurationFileFormat.Version < 45)
+            {
+                Ryujinx.Common.Logging.Logger.Warning?.Print(LogClass.Application, $"Outdated configuration version {configurationFileFormat.Version}, migrating to version 45.");
+
+                configurationFileFormat.ShownFileTypes = new ShownFileTypes
+                {
+                    NSP  = true,
+                    PFS0 = true,
+                    XCI  = true,
+                    NCA  = true,
+                    NRO  = true,
+                    NSO  = true
+                };
+
+                configurationFileUpdated = true;
+            }
+
             Logger.EnableFileLog.Value                = configurationFileFormat.EnableFileLog;
             Graphics.ResScale.Value                   = configurationFileFormat.ResScale;
             Graphics.ResScaleCustom.Value             = configurationFileFormat.ResScaleCustom;
@@ -1305,6 +1366,12 @@ namespace Ryujinx.Ui.Common.Configuration
             Ui.ColumnSort.SortColumnId.Value          = configurationFileFormat.ColumnSort.SortColumnId;
             Ui.ColumnSort.SortAscending.Value         = configurationFileFormat.ColumnSort.SortAscending;
             Ui.GameDirs.Value                         = configurationFileFormat.GameDirs;
+            Ui.ShownFileTypes.NSP.Value              = configurationFileFormat.ShownFileTypes.NSP;
+            Ui.ShownFileTypes.PFS0.Value             = configurationFileFormat.ShownFileTypes.PFS0;
+            Ui.ShownFileTypes.XCI.Value              = configurationFileFormat.ShownFileTypes.XCI;
+            Ui.ShownFileTypes.NCA.Value              = configurationFileFormat.ShownFileTypes.NCA;
+            Ui.ShownFileTypes.NRO.Value              = configurationFileFormat.ShownFileTypes.NRO;
+            Ui.ShownFileTypes.NSO.Value              = configurationFileFormat.ShownFileTypes.NSO;
             Ui.EnableCustomTheme.Value                = configurationFileFormat.EnableCustomTheme;
             Ui.LanguageCode.Value                     = configurationFileFormat.LanguageCode;
             Ui.CustomThemePath.Value                  = configurationFileFormat.CustomThemePath;
diff --git a/Ryujinx.Ui.Common/Configuration/FileTypes.cs b/Ryujinx.Ui.Common/Configuration/FileTypes.cs
new file mode 100644
index 0000000000..0b8b7384bc
--- /dev/null
+++ b/Ryujinx.Ui.Common/Configuration/FileTypes.cs
@@ -0,0 +1,12 @@
+namespace Ryujinx.Ui.Common
+{
+    public enum FileTypes
+    {
+        NSP,
+        PFS0,
+        XCI,
+        NCA,
+        NRO,
+        NSO
+    }
+}
diff --git a/Ryujinx.Ui.Common/Configuration/Ui/ShownFileTypes.cs b/Ryujinx.Ui.Common/Configuration/Ui/ShownFileTypes.cs
new file mode 100644
index 0000000000..c0b76e85c0
--- /dev/null
+++ b/Ryujinx.Ui.Common/Configuration/Ui/ShownFileTypes.cs
@@ -0,0 +1,12 @@
+namespace Ryujinx.Ui.Common.Configuration.Ui
+{
+    public struct ShownFileTypes
+    {
+        public bool NSP  { get; set; }
+        public bool PFS0 { get; set; }
+        public bool XCI  { get; set; }
+        public bool NCA  { get; set; }
+        public bool NRO  { get; set; }
+        public bool NSO  { get; set; }
+    }
+}
diff --git a/Ryujinx.Ui.Common/Extensions/FileTypeExtensions.cs b/Ryujinx.Ui.Common/Extensions/FileTypeExtensions.cs
new file mode 100644
index 0000000000..e2ac49504a
--- /dev/null
+++ b/Ryujinx.Ui.Common/Extensions/FileTypeExtensions.cs
@@ -0,0 +1,25 @@
+using System;
+using static Ryujinx.Ui.Common.Configuration.ConfigurationState.UiSection;
+
+namespace Ryujinx.Ui.Common
+{
+    public static class FileTypesExtensions
+    {
+        /// <summary>
+        /// Gets the current <see cref="ShownFileTypeSettings"/> value for the correlating FileType name.
+        /// </summary>
+        /// <param name="type">The name of the <see cref="ShownFileTypeSettings"/> parameter to get the value of.</param>
+        /// <param name="config">The config instance to get the value from.</param>
+        /// <returns>The current value of the setting. Value is <see langword="true"/> if the file type is the be shown on the games list, <see langword="false"/> otherwise.</returns>
+        public static bool GetConfigValue(this FileTypes type, ShownFileTypeSettings config) => type switch
+        {
+            FileTypes.NSP => config.NSP.Value,
+            FileTypes.PFS0 => config.PFS0.Value,
+            FileTypes.XCI => config.XCI.Value,
+            FileTypes.NCA => config.NCA.Value,
+            FileTypes.NRO => config.NRO.Value,
+            FileTypes.NSO => config.NSO.Value,
+            _ => throw new ArgumentOutOfRangeException(nameof(type), type, null)
+        };
+    }
+}
diff --git a/Ryujinx/Ui/MainWindow.cs b/Ryujinx/Ui/MainWindow.cs
index e0252016ff..3e513dd280 100644
--- a/Ryujinx/Ui/MainWindow.cs
+++ b/Ryujinx/Ui/MainWindow.cs
@@ -119,6 +119,12 @@ namespace Ryujinx.Ui
         [GUI] CheckMenuItem   _fileExtToggle;
         [GUI] CheckMenuItem   _pathToggle;
         [GUI] CheckMenuItem   _fileSizeToggle;
+        [GUI] CheckMenuItem   _nspShown;
+        [GUI] CheckMenuItem   _pfs0Shown;
+        [GUI] CheckMenuItem   _xciShown;
+        [GUI] CheckMenuItem   _ncaShown;
+        [GUI] CheckMenuItem   _nroShown;
+        [GUI] CheckMenuItem   _nsoShown;
         [GUI] Label           _gpuBackend;
         [GUI] Label           _dockedMode;
         [GUI] Label           _aspectRatio;
@@ -220,6 +226,20 @@ namespace Ryujinx.Ui
             _pauseEmulation.Sensitive = false;
             _resumeEmulation.Sensitive = false;
 
+            _nspShown.Active  = ConfigurationState.Instance.Ui.ShownFileTypes.NSP.Value;
+            _pfs0Shown.Active = ConfigurationState.Instance.Ui.ShownFileTypes.PFS0.Value;
+            _xciShown.Active  = ConfigurationState.Instance.Ui.ShownFileTypes.XCI.Value;
+            _ncaShown.Active  = ConfigurationState.Instance.Ui.ShownFileTypes.NCA.Value;
+            _nroShown.Active  = ConfigurationState.Instance.Ui.ShownFileTypes.NRO.Value;
+            _nsoShown.Active  = ConfigurationState.Instance.Ui.ShownFileTypes.NSO.Value;
+
+            _nspShown.Toggled  += NSP_Shown_Toggled;
+            _pfs0Shown.Toggled += PFS0_Shown_Toggled;
+            _xciShown.Toggled  += XCI_Shown_Toggled;
+            _ncaShown.Toggled  += NCA_Shown_Toggled;
+            _nroShown.Toggled  += NRO_Shown_Toggled;
+            _nsoShown.Toggled  += NSO_Shown_Toggled;
+
             _fileTypesSubMenu.Visible = FileAssociationHelper.IsTypeAssociationSupported;
 
             if (ConfigurationState.Instance.Ui.GuiColumns.FavColumn)        _favToggle.Active        = true;
@@ -1757,6 +1777,54 @@ namespace Ryujinx.Ui
             UpdateColumns();
         }
 
+        private void NSP_Shown_Toggled(object sender, EventArgs args)
+        {
+            ConfigurationState.Instance.Ui.ShownFileTypes.NSP.Value = _nspShown.Active;
+
+            SaveConfig();
+            UpdateGameTable();
+        }
+
+        private void PFS0_Shown_Toggled(object sender, EventArgs args)
+        {
+            ConfigurationState.Instance.Ui.ShownFileTypes.PFS0.Value = _pfs0Shown.Active;
+
+            SaveConfig();
+            UpdateGameTable();
+        }
+
+        private void XCI_Shown_Toggled (object sender, EventArgs args)
+        {
+            ConfigurationState.Instance.Ui.ShownFileTypes.XCI.Value = _xciShown.Active;
+
+            SaveConfig();
+            UpdateGameTable();
+        }
+
+        private void NCA_Shown_Toggled (object sender, EventArgs args)
+        {
+            ConfigurationState.Instance.Ui.ShownFileTypes.NCA.Value = _ncaShown.Active;
+
+            SaveConfig();
+            UpdateGameTable();
+        }
+
+        private void NRO_Shown_Toggled (object sender, EventArgs args)
+        {
+            ConfigurationState.Instance.Ui.ShownFileTypes.NRO.Value = _nroShown.Active;
+
+            SaveConfig();
+            UpdateGameTable();
+        }
+
+        private void NSO_Shown_Toggled (object sender, EventArgs args)
+        {
+            ConfigurationState.Instance.Ui.ShownFileTypes.NSO.Value = _nsoShown.Active;
+
+            SaveConfig();
+            UpdateGameTable();
+        }
+
         private void RefreshList_Pressed(object sender, ButtonReleaseEventArgs args)
         {
             UpdateGameTable();
diff --git a/Ryujinx/Ui/MainWindow.glade b/Ryujinx/Ui/MainWindow.glade
index 8ffbb97e53..58d5d9558e 100644
--- a/Ryujinx/Ui/MainWindow.glade
+++ b/Ryujinx/Ui/MainWindow.glade
@@ -262,6 +262,75 @@
                         </child>
                       </object>
                     </child>
+                    <child>
+                      <object class="GtkMenuItem" id="ShownFileTypes">
+                        <property name="visible">True</property>
+                        <property name="can-focus">False</property>
+                        <property name="tooltip-text" translatable="yes">Select which file types to show</property>
+                        <property name="label" translatable="yes">Show File Types</property>
+                        <property name="use-underline">True</property>
+                        <child type="submenu">
+                          <object class="GtkMenu">
+                            <property name="visible">True</property>
+                            <property name="can-focus">False</property>
+                            <child>
+                              <object class="GtkCheckMenuItem" id="_nspShown">
+                                <property name="visible">True</property>
+                                <property name="can-focus">False</property>
+                                <property name="tooltip-text" translatable="yes">Shows .NSP files in the games list</property>
+                                <property name="label" translatable="yes">.NSP</property>
+                                <property name="use-underline">True</property>
+                              </object>
+                            </child>
+                            <child>
+                              <object class="GtkCheckMenuItem" id="_pfs0Shown">
+                                <property name="visible">True</property>
+                                <property name="can-focus">False</property>
+                                <property name="tooltip-text" translatable="yes">Shows .PFS0 files in the games list</property>
+                                <property name="label" translatable="yes">.PFS0</property>
+                                <property name="use-underline">True</property>
+                              </object>
+                            </child>
+                            <child>
+                              <object class="GtkCheckMenuItem" id="_xciShown">
+                                <property name="visible">True</property>
+                                <property name="can-focus">False</property>
+                                <property name="tooltip-text" translatable="yes">Shows .XCI files in the games list</property>
+                                <property name="label" translatable="yes">.XCI</property>
+                                <property name="use-underline">True</property>
+                              </object>
+                            </child>
+                            <child>
+                              <object class="GtkCheckMenuItem" id="_ncaShown">
+                                <property name="visible">True</property>
+                                <property name="can-focus">False</property>
+                                <property name="tooltip-text" translatable="yes">Shows .NCA files in the games list</property>
+                                <property name="label" translatable="yes">.NCA</property>
+                                <property name="use-underline">True</property>
+                              </object>
+                            </child>
+                            <child>
+                              <object class="GtkCheckMenuItem" id="_nroShown">
+                                <property name="visible">True</property>
+                                <property name="can-focus">False</property>
+                                <property name="tooltip-text" translatable="yes">Shows .NRO files in the games list</property>
+                                <property name="label" translatable="yes">.NRO</property>
+                                <property name="use-underline">True</property>
+                              </object>
+                            </child>
+                            <child>
+                              <object class="GtkCheckMenuItem" id="_nsoShown">
+                                <property name="visible">True</property>
+                                <property name="can-focus">False</property>
+                                <property name="tooltip-text" translatable="yes">Shows .NSO files in the games list</property>
+                                <property name="label" translatable="yes">.NSO</property>
+                                <property name="use-underline">True</property>
+                              </object>
+                            </child>
+                          </object>
+                        </child>
+                      </object>
+                    </child>
                     <child>
                       <object class="GtkSeparatorMenuItem">
                         <property name="visible">True</property>