Răsfoiți Sursa

UI: Move ApplicationContextMenu in a separated class (#4755)

* UI: Move ApplicationContextMenu in a separated class

This PR remove duplicated code related to the context menu on the Application list/grid by create a control for the menu which include related handler.

I've renamed "GameList/GameGrid" by "Application" for consistencies. And I've removed all uneeded field from the project file too.

While I cleaned up things, I've found an issue about purging Ptc/Shader cache, both methods list files even if the user say "No", shader cache is purged even if the user say "No". It's fixed.

* Adresses feedbacks
Ac_K 3 ani în urmă
părinte
comite
3b8ac1641a

+ 0 - 44
src/Ryujinx.Ava/Ryujinx.Ava.csproj

@@ -103,50 +103,6 @@
       <Generator>MSBuild:Compile</Generator>
     </AvaloniaResource>
     <AvaloniaResource Include="Assets\Styles\Styles.xaml" />
-
-    <Compile Update="App.axaml.cs">
-      <DependentUpon>App.axaml</DependentUpon>
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Update="Ui\Windows\MainWindow.axaml.cs">
-      <DependentUpon>MainWindow.axaml</DependentUpon>
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Update="Ui\Windows\AboutWindow.axaml.cs">
-      <DependentUpon>AboutWindow.axaml</DependentUpon>
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Update="Ui\Applet\ErrorAppletWindow.axaml.cs">
-      <DependentUpon>ProfileWindow.axaml</DependentUpon>
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Update="Ui\Applet\SwkbdAppletWindow.axaml.cs">
-      <DependentUpon>ProfileWindow.axaml</DependentUpon>
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Update="Ui\Controls\InputDialog.axaml.cs">
-      <DependentUpon>InputDialog.axaml</DependentUpon>
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Update="Ui\Windows\ContentDialogOverlay.xaml.cs">
-      <DependentUpon>ContentDialogOverlay.xaml</DependentUpon>
-    </Compile>
-    <Compile Update="Ui\Controls\GameListView.axaml.cs">
-      <DependentUpon>GameListView.axaml</DependentUpon>
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Update="UI\Views\User\UserEditorView.axaml.cs">
-      <DependentUpon>UserEditor.axaml</DependentUpon>
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Update="UI\Views\User\UserRecovererView.axaml.cs">
-      <DependentUpon>UserRecoverer.axaml</DependentUpon>
-      <SubType>Code</SubType>
-    </Compile>
-    <Compile Update="UI\Views\User\UserSelectorView.axaml.cs">
-      <DependentUpon>UserSelector.axaml</DependentUpon>
-      <SubType>Code</SubType>
-    </Compile>
   </ItemGroup>
 
   <ItemGroup>

+ 80 - 0
src/Ryujinx.Ava/UI/Controls/ApplicationContextMenu.axaml

@@ -0,0 +1,80 @@
+<MenuFlyout
+    x:Class="Ryujinx.Ava.UI.Controls.ApplicationContextMenu"
+    xmlns="https://github.com/avaloniaui"
+    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+    xmlns:locale="clr-namespace:Ryujinx.Ava.Common.Locale">
+    <MenuItem
+        Click="ToggleFavorite_Click"
+        Header="{locale:Locale GameListContextMenuToggleFavorite}"
+        ToolTip.Tip="{locale:Locale GameListContextMenuToggleFavoriteToolTip}" />
+    <Separator />
+    <MenuItem
+        Click="OpenUserSaveDirectory_Click"
+        Header="{locale:Locale GameListContextMenuOpenUserSaveDirectory}"
+        IsEnabled="{Binding OpenUserSaveDirectoryEnabled}"
+        ToolTip.Tip="{locale:Locale GameListContextMenuOpenUserSaveDirectoryToolTip}" />
+    <MenuItem
+        Click="OpenDeviceSaveDirectory_Click"
+        Header="{locale:Locale GameListContextMenuOpenDeviceSaveDirectory}"
+        IsEnabled="{Binding OpenDeviceSaveDirectoryEnabled}"
+        ToolTip.Tip="{locale:Locale GameListContextMenuOpenDeviceSaveDirectoryToolTip}" />
+    <MenuItem
+        Click="OpenBcatSaveDirectory_Click"
+        Header="{locale:Locale GameListContextMenuOpenBcatSaveDirectory}"
+        IsEnabled="{Binding OpenBcatSaveDirectoryEnabled}"
+        ToolTip.Tip="{locale:Locale GameListContextMenuOpenBcatSaveDirectoryToolTip}" />
+    <Separator />
+    <MenuItem
+        Click="OpenTitleUpdateManager_Click"
+        Header="{locale:Locale GameListContextMenuManageTitleUpdates}"
+        ToolTip.Tip="{locale:Locale GameListContextMenuManageTitleUpdatesToolTip}" />
+    <MenuItem
+        Click="OpenDownloadableContentManager_Click"
+        Header="{locale:Locale GameListContextMenuManageDlc}"
+        ToolTip.Tip="{locale:Locale GameListContextMenuManageDlcToolTip}" />
+    <MenuItem
+        Click="OpenCheatManager_Click"
+        Header="{locale:Locale GameListContextMenuManageCheat}"
+        ToolTip.Tip="{locale:Locale GameListContextMenuManageCheatToolTip}" />
+    <MenuItem
+        Click="OpenModsDirectory_Click"
+        Header="{locale:Locale GameListContextMenuOpenModsDirectory}"
+        ToolTip.Tip="{locale:Locale GameListContextMenuOpenModsDirectoryToolTip}" />
+    <MenuItem
+        Click="OpenSdModsDirectory_Click"
+        Header="{locale:Locale GameListContextMenuOpenSdModsDirectory}"
+        ToolTip.Tip="{locale:Locale GameListContextMenuOpenSdModsDirectoryToolTip}" />
+    <Separator />
+    <MenuItem Header="{locale:Locale GameListContextMenuCacheManagement}">
+        <MenuItem
+            Click="PurgePtcCache_Click"
+            Header="{locale:Locale GameListContextMenuCacheManagementPurgePptc}"
+            ToolTip.Tip="{locale:Locale GameListContextMenuCacheManagementPurgePptcToolTip}" />
+        <MenuItem
+            Click="PurgeShaderCache_Click"
+            Header="{locale:Locale GameListContextMenuCacheManagementPurgeShaderCache}"
+            ToolTip.Tip="{locale:Locale GameListContextMenuCacheManagementPurgeShaderCacheToolTip}" />
+        <MenuItem
+            Click="OpenPtcDirectory_Click"
+            Header="{locale:Locale GameListContextMenuCacheManagementOpenPptcDirectory}"
+            ToolTip.Tip="{locale:Locale GameListContextMenuCacheManagementOpenPptcDirectoryToolTip}" />
+        <MenuItem
+            Click="OpenShaderCacheDirectory_Click"
+            Header="{locale:Locale GameListContextMenuCacheManagementOpenShaderCacheDirectory}"
+            ToolTip.Tip="{locale:Locale GameListContextMenuCacheManagementOpenShaderCacheDirectoryToolTip}" />
+    </MenuItem>
+    <MenuItem Header="{locale:Locale GameListContextMenuExtractData}">
+        <MenuItem
+            Click="ExtractApplicationLogo_Click"
+            Header="{locale:Locale GameListContextMenuExtractDataExeFS}"
+            ToolTip.Tip="{locale:Locale GameListContextMenuExtractDataExeFSToolTip}" />
+        <MenuItem
+            Click="ExtractApplicationRomFs_Click"
+            Header="{locale:Locale GameListContextMenuExtractDataRomFS}"
+            ToolTip.Tip="{locale:Locale GameListContextMenuExtractDataRomFSToolTip}" />
+        <MenuItem
+            Click="ExtractApplicationExeFs_Click"
+            Header="{locale:Locale GameListContextMenuExtractDataLogo}"
+            ToolTip.Tip="{locale:Locale GameListContextMenuExtractDataLogoToolTip}" />
+    </MenuItem>
+</MenuFlyout>

+ 320 - 0
src/Ryujinx.Ava/UI/Controls/ApplicationContextMenu.axaml.cs

@@ -0,0 +1,320 @@
+using Avalonia.Controls;
+using Avalonia.Interactivity;
+using Avalonia.Markup.Xaml;
+using Avalonia.Threading;
+using LibHac.Fs;
+using LibHac.Tools.FsSystem.NcaUtils;
+using Ryujinx.Ava.Common;
+using Ryujinx.Ava.Common.Locale;
+using Ryujinx.Ava.UI.Helpers;
+using Ryujinx.Ava.UI.ViewModels;
+using Ryujinx.Ava.UI.Windows;
+using Ryujinx.Common.Configuration;
+using Ryujinx.Ui.Common.Helper;
+using System;
+using System.Collections.Generic;
+using System.Globalization;
+using System.IO;
+using Path = System.IO.Path;
+using UserId = LibHac.Fs.UserId;
+
+namespace Ryujinx.Ava.UI.Controls
+{
+    public class ApplicationContextMenu : MenuFlyout
+    {
+        public ApplicationContextMenu()
+        {
+            InitializeComponent();
+        }
+
+        private void InitializeComponent()
+        {
+            AvaloniaXamlLoader.Load(this);
+        }
+
+        public void ToggleFavorite_Click(object sender, RoutedEventArgs args)
+        {
+            var viewModel = (sender as MenuItem)?.DataContext as MainWindowViewModel;
+
+            if (viewModel.SelectedApplication != null)
+            {
+                viewModel.SelectedApplication.Favorite = !viewModel.SelectedApplication.Favorite;
+
+                viewModel.ApplicationLibrary.LoadAndSaveMetaData(viewModel.SelectedApplication.TitleId, appMetadata =>
+                {
+                    appMetadata.Favorite = viewModel.SelectedApplication.Favorite;
+                });
+
+                viewModel.RefreshView();
+            }
+        }
+
+        public void OpenUserSaveDirectory_Click(object sender, RoutedEventArgs args)
+        {
+            var viewModel = (sender as MenuItem)?.DataContext as MainWindowViewModel;
+
+            OpenSaveDirectory(viewModel, SaveDataType.Account, userId: new UserId((ulong)viewModel.AccountManager.LastOpenedUser.UserId.High, (ulong)viewModel.AccountManager.LastOpenedUser.UserId.Low));
+        }
+
+        public void OpenDeviceSaveDirectory_Click(object sender, RoutedEventArgs args)
+        {
+            var viewModel = (sender as MenuItem)?.DataContext as MainWindowViewModel;
+
+            OpenSaveDirectory(viewModel, SaveDataType.Device, userId: default);
+        }
+
+        public void OpenBcatSaveDirectory_Click(object sender, RoutedEventArgs args)
+        {
+            var viewModel = (sender as MenuItem)?.DataContext as MainWindowViewModel;
+
+            OpenSaveDirectory(viewModel, SaveDataType.Bcat, userId: default);
+        }
+
+        private void OpenSaveDirectory(MainWindowViewModel viewModel, SaveDataType saveDataType, UserId userId)
+        {
+            if (viewModel.SelectedApplication != null)
+            {
+                if (!ulong.TryParse(viewModel.SelectedApplication.TitleId, NumberStyles.HexNumber, CultureInfo.InvariantCulture, out ulong titleIdNumber))
+                {
+                    Dispatcher.UIThread.InvokeAsync(async () =>
+                    {
+                        await ContentDialogHelper.CreateErrorDialog(LocaleManager.Instance[LocaleKeys.DialogRyujinxErrorMessage], LocaleManager.Instance[LocaleKeys.DialogInvalidTitleIdErrorMessage]);
+                    });
+
+                    return;
+                }
+
+                var saveDataFilter = SaveDataFilter.Make(titleIdNumber, saveDataType, userId, saveDataId: default, index: default);
+
+                ApplicationHelper.OpenSaveDir(in saveDataFilter, titleIdNumber, viewModel.SelectedApplication.ControlHolder, viewModel.SelectedApplication.TitleName);
+            }
+        }
+
+        public async void OpenTitleUpdateManager_Click(object sender, RoutedEventArgs args)
+        {
+            var viewModel = (sender as MenuItem)?.DataContext as MainWindowViewModel;
+
+            if (viewModel.SelectedApplication != null)
+            {
+                await TitleUpdateWindow.Show(viewModel.VirtualFileSystem, ulong.Parse(viewModel.SelectedApplication.TitleId, NumberStyles.HexNumber), viewModel.SelectedApplication.TitleName);
+            }
+        }
+
+        public async void OpenDownloadableContentManager_Click(object sender, RoutedEventArgs args)
+        {
+            var viewModel = (sender as MenuItem)?.DataContext as MainWindowViewModel;
+
+            if (viewModel.SelectedApplication != null)
+            {
+                await DownloadableContentManagerWindow.Show(viewModel.VirtualFileSystem, ulong.Parse(viewModel.SelectedApplication.TitleId, NumberStyles.HexNumber), viewModel.SelectedApplication.TitleName);
+            }
+        }
+
+        public async void OpenCheatManager_Click(object sender, RoutedEventArgs args)
+        {
+            var viewModel = (sender as MenuItem)?.DataContext as MainWindowViewModel;
+
+            if (viewModel.SelectedApplication != null)
+            {
+                await new CheatWindow(viewModel.VirtualFileSystem, viewModel.SelectedApplication.TitleId, viewModel.SelectedApplication.TitleName).ShowDialog(viewModel.TopLevel as Window);
+            }
+        }
+
+        public void OpenModsDirectory_Click(object sender, RoutedEventArgs args)
+        {
+            var viewModel = (sender as MenuItem)?.DataContext as MainWindowViewModel;
+
+            if (viewModel.SelectedApplication != null)
+            {
+                string modsBasePath = viewModel.VirtualFileSystem.ModLoader.GetModsBasePath();
+                string titleModsPath = viewModel.VirtualFileSystem.ModLoader.GetTitleDir(modsBasePath, viewModel.SelectedApplication.TitleId);
+
+                OpenHelper.OpenFolder(titleModsPath);
+            }
+        }
+
+        public void OpenSdModsDirectory_Click(object sender, RoutedEventArgs args)
+        {
+            var viewModel = (sender as MenuItem)?.DataContext as MainWindowViewModel;
+
+            if (viewModel.SelectedApplication != null)
+            {
+                string sdModsBasePath = viewModel.VirtualFileSystem.ModLoader.GetSdModsBasePath();
+                string titleModsPath = viewModel.VirtualFileSystem.ModLoader.GetTitleDir(sdModsBasePath, viewModel.SelectedApplication.TitleId);
+
+                OpenHelper.OpenFolder(titleModsPath);
+            }
+        }
+
+        public async void PurgePtcCache_Click(object sender, RoutedEventArgs args)
+        {
+            var viewModel = (sender as MenuItem)?.DataContext as MainWindowViewModel;
+
+            if (viewModel.SelectedApplication != null)
+            {
+                UserResult result = await ContentDialogHelper.CreateConfirmationDialog(LocaleManager.Instance[LocaleKeys.DialogWarning],
+                                                                                       LocaleManager.Instance.UpdateAndGetDynamicValue(LocaleKeys.DialogPPTCDeletionMessage, viewModel.SelectedApplication.TitleName),
+                                                                                       LocaleManager.Instance[LocaleKeys.InputDialogYes],
+                                                                                       LocaleManager.Instance[LocaleKeys.InputDialogNo],
+                                                                                       LocaleManager.Instance[LocaleKeys.RyujinxConfirm]);
+
+                if (result == UserResult.Yes)
+                {
+                    DirectoryInfo mainDir = new(Path.Combine(AppDataManager.GamesDirPath, viewModel.SelectedApplication.TitleId, "cache", "cpu", "0"));
+                    DirectoryInfo backupDir = new(Path.Combine(AppDataManager.GamesDirPath, viewModel.SelectedApplication.TitleId, "cache", "cpu", "1"));
+
+                    List<FileInfo> cacheFiles = new();
+
+                    if (mainDir.Exists)
+                    {
+                        cacheFiles.AddRange(mainDir.EnumerateFiles("*.cache"));
+                    }
+
+                    if (backupDir.Exists)
+                    {
+                        cacheFiles.AddRange(backupDir.EnumerateFiles("*.cache"));
+                    }
+
+                    if (cacheFiles.Count > 0)
+                    {
+                        foreach (FileInfo file in cacheFiles)
+                        {
+                            try
+                            {
+                                file.Delete();
+                            }
+                            catch (Exception ex)
+                            {
+                                await ContentDialogHelper.CreateErrorDialog(LocaleManager.Instance.UpdateAndGetDynamicValue(LocaleKeys.DialogPPTCDeletionErrorMessage, file.Name, ex));
+                            }
+                        }
+                    }
+                }
+            }
+        }
+
+        public async void PurgeShaderCache_Click(object sender, RoutedEventArgs args)
+        {
+            var viewModel = (sender as MenuItem)?.DataContext as MainWindowViewModel;
+
+            if (viewModel.SelectedApplication != null)
+            {
+                UserResult result = await ContentDialogHelper.CreateConfirmationDialog(LocaleManager.Instance[LocaleKeys.DialogWarning],
+                                                                                       LocaleManager.Instance.UpdateAndGetDynamicValue(LocaleKeys.DialogShaderDeletionMessage, viewModel.SelectedApplication.TitleName),
+                                                                                       LocaleManager.Instance[LocaleKeys.InputDialogYes],
+                                                                                       LocaleManager.Instance[LocaleKeys.InputDialogNo],
+                                                                                       LocaleManager.Instance[LocaleKeys.RyujinxConfirm]);
+
+                if (result == UserResult.Yes)
+                {
+                    DirectoryInfo shaderCacheDir = new(Path.Combine(AppDataManager.GamesDirPath, viewModel.SelectedApplication.TitleId, "cache", "shader"));
+
+                    List<DirectoryInfo> oldCacheDirectories = new();
+                    List<FileInfo> newCacheFiles = new();
+
+                    if (shaderCacheDir.Exists)
+                    {
+                        oldCacheDirectories.AddRange(shaderCacheDir.EnumerateDirectories("*"));
+                        newCacheFiles.AddRange(shaderCacheDir.GetFiles("*.toc"));
+                        newCacheFiles.AddRange(shaderCacheDir.GetFiles("*.data"));
+                    }
+
+                    if ((oldCacheDirectories.Count > 0 || newCacheFiles.Count > 0))
+                    {
+                        foreach (DirectoryInfo directory in oldCacheDirectories)
+                        {
+                            try
+                            {
+                                directory.Delete(true);
+                            }
+                            catch (Exception ex)
+                            {
+                                await ContentDialogHelper.CreateErrorDialog(LocaleManager.Instance.UpdateAndGetDynamicValue(LocaleKeys.DialogPPTCDeletionErrorMessage, directory.Name, ex));
+                            }
+                        }
+
+                        foreach (FileInfo file in newCacheFiles)
+                        {
+                            try
+                            {
+                                file.Delete();
+                            }
+                            catch (Exception ex)
+                            {
+                                await ContentDialogHelper.CreateErrorDialog(LocaleManager.Instance.UpdateAndGetDynamicValue(LocaleKeys.ShaderCachePurgeError, file.Name, ex));
+                            }
+                        }
+                    }
+                }
+            }
+        }
+
+        public void OpenPtcDirectory_Click(object sender, RoutedEventArgs args)
+        {
+            var viewModel = (sender as MenuItem)?.DataContext as MainWindowViewModel;
+
+            if (viewModel.SelectedApplication != null)
+            {
+                string ptcDir = Path.Combine(AppDataManager.GamesDirPath, viewModel.SelectedApplication.TitleId, "cache", "cpu");
+                string mainDir = Path.Combine(ptcDir, "0");
+                string backupDir = Path.Combine(ptcDir, "1");
+
+                if (!Directory.Exists(ptcDir))
+                {
+                    Directory.CreateDirectory(ptcDir);
+                    Directory.CreateDirectory(mainDir);
+                    Directory.CreateDirectory(backupDir);
+                }
+
+                OpenHelper.OpenFolder(ptcDir);
+            }
+        }
+
+        public void OpenShaderCacheDirectory_Click(object sender, RoutedEventArgs args)
+        {
+            var viewModel = (sender as MenuItem)?.DataContext as MainWindowViewModel;
+
+            if (viewModel.SelectedApplication != null)
+            {
+                string shaderCacheDir = Path.Combine(AppDataManager.GamesDirPath, viewModel.SelectedApplication.TitleId, "cache", "shader");
+
+                if (!Directory.Exists(shaderCacheDir))
+                {
+                    Directory.CreateDirectory(shaderCacheDir);
+                }
+
+                OpenHelper.OpenFolder(shaderCacheDir);
+            }
+        }
+
+        public async void ExtractApplicationLogo_Click(object sender, RoutedEventArgs args)
+        {
+            var viewModel = (sender as MenuItem)?.DataContext as MainWindowViewModel;
+
+            if (viewModel.SelectedApplication != null)
+            {
+                await ApplicationHelper.ExtractSection(NcaSectionType.Logo, viewModel.SelectedApplication.Path, viewModel.SelectedApplication.TitleName);
+            }
+        }
+
+        public async void ExtractApplicationRomFs_Click(object sender, RoutedEventArgs args)
+        {
+            var viewModel = (sender as MenuItem)?.DataContext as MainWindowViewModel;
+
+            if (viewModel.SelectedApplication != null)
+            {
+                await ApplicationHelper.ExtractSection(NcaSectionType.Data, viewModel.SelectedApplication.Path, viewModel.SelectedApplication.TitleName);
+            }
+        }
+
+        public async void ExtractApplicationExeFs_Click(object sender, RoutedEventArgs args)
+        {
+            var viewModel = (sender as MenuItem)?.DataContext as MainWindowViewModel;
+
+            if (viewModel.SelectedApplication != null)
+            {
+                await ApplicationHelper.ExtractSection(NcaSectionType.Code, viewModel.SelectedApplication.Path, viewModel.SelectedApplication.TitleName);
+            }
+        }
+    }
+}

+ 102 - 0
src/Ryujinx.Ava/UI/Controls/ApplicationGridView.axaml

@@ -0,0 +1,102 @@
+<UserControl
+    x:Class="Ryujinx.Ava.UI.Controls.ApplicationGridView"
+    xmlns="https://github.com/avaloniaui"
+    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+    xmlns:controls="clr-namespace:Ryujinx.Ava.UI.Controls"
+    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
+    xmlns:flex="clr-namespace:Avalonia.Flexbox;assembly=Avalonia.Flexbox"
+    xmlns:helpers="clr-namespace:Ryujinx.Ava.UI.Helpers"
+    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
+    xmlns:ui="clr-namespace:FluentAvalonia.UI.Controls;assembly=FluentAvalonia"
+    d:DesignHeight="450"
+    d:DesignWidth="800"
+    Focusable="True"
+    mc:Ignorable="d">
+    <UserControl.Resources>
+        <helpers:BitmapArrayValueConverter x:Key="ByteImage" />
+        <controls:ApplicationContextMenu x:Key="ApplicationContextMenu" />
+    </UserControl.Resources>
+    <Grid>
+        <Grid.RowDefinitions>
+            <RowDefinition Height="*" />
+        </Grid.RowDefinitions>
+        <ListBox
+            Grid.Row="0"
+            Padding="8"
+            HorizontalAlignment="Stretch"
+            VerticalAlignment="Stretch"
+            ContextFlyout="{StaticResource ApplicationContextMenu}"
+            DoubleTapped="GameList_DoubleTapped"
+            Items="{Binding AppsObservableList}"
+            SelectionChanged="GameList_SelectionChanged">
+            <ListBox.ItemsPanel>
+                <ItemsPanelTemplate>
+                    <flex:FlexPanel
+                        HorizontalAlignment="Stretch"
+                        VerticalAlignment="Stretch"
+                        AlignContent="FlexStart"
+                        JustifyContent="Center" />
+                </ItemsPanelTemplate>
+            </ListBox.ItemsPanel>
+            <ListBox.Styles>
+                <Style Selector="ListBoxItem">
+                    <Setter Property="Margin" Value="5" />
+                    <Setter Property="CornerRadius" Value="4" />
+                </Style>
+                <Style Selector="ListBoxItem:selected /template/ Border#SelectionIndicator">
+                    <Setter Property="MinHeight" Value="{Binding $parent[UserControl].DataContext.GridItemSelectorSize}" />
+                </Style>
+            </ListBox.Styles>
+            <ListBox.ItemTemplate>
+                <DataTemplate>
+                    <Grid>
+                        <Border
+                            Margin="10"
+                            HorizontalAlignment="Stretch"
+                            VerticalAlignment="Stretch"
+                            Classes.huge="{Binding $parent[UserControl].DataContext.IsGridHuge}"
+                            Classes.large="{Binding $parent[UserControl].DataContext.IsGridLarge}"
+                            Classes.normal="{Binding $parent[UserControl].DataContext.IsGridMedium}"
+                            Classes.small="{Binding $parent[UserControl].DataContext.IsGridSmall}"
+                            ClipToBounds="True"
+                            CornerRadius="4">
+                            <Grid>
+                                <Grid.RowDefinitions>
+                                    <RowDefinition Height="Auto" />
+                                    <RowDefinition Height="Auto" />
+                                </Grid.RowDefinitions>
+                                <Image
+                                    Grid.Row="0"
+                                    HorizontalAlignment="Stretch"
+                                    VerticalAlignment="Top"
+                                    Source="{Binding Icon, Converter={StaticResource ByteImage}}" />
+                                <Panel
+                                    Grid.Row="1"
+                                    Height="50"
+                                    Margin="0,10,0,0"
+                                    HorizontalAlignment="Stretch"
+                                    VerticalAlignment="Stretch"
+                                    IsVisible="{Binding $parent[UserControl].DataContext.ShowNames}">
+                                    <TextBlock
+                                        HorizontalAlignment="Stretch"
+                                        VerticalAlignment="Center"
+                                        Text="{Binding TitleName}"
+                                        TextAlignment="Center"
+                                        TextWrapping="Wrap" />
+                                </Panel>
+                            </Grid>
+                        </Border>
+                        <ui:SymbolIcon
+                            Margin="5,5,0,0"
+                            HorizontalAlignment="Left"
+                            VerticalAlignment="Top"
+                            FontSize="16"
+                            Foreground="{DynamicResource SystemAccentColor}"
+                            IsVisible="{Binding Favorite}"
+                            Symbol="StarFilled" />
+                    </Grid>
+                </DataTemplate>
+            </ListBox.ItemTemplate>
+        </ListBox>
+    </Grid>
+</UserControl>

+ 4 - 4
src/Ryujinx.Ava/UI/Controls/GameGridView.axaml.cs → src/Ryujinx.Ava/UI/Controls/ApplicationGridView.axaml.cs

@@ -9,10 +9,10 @@ using System;
 
 namespace Ryujinx.Ava.UI.Controls
 {
-    public partial class GameGridView : UserControl
+    public partial class ApplicationGridView : UserControl
     {
         public static readonly RoutedEvent<ApplicationOpenedEventArgs> ApplicationOpenedEvent =
-            RoutedEvent.Register<GameGridView, ApplicationOpenedEventArgs>(nameof(ApplicationOpened), RoutingStrategies.Bubble);
+            RoutedEvent.Register<ApplicationGridView, ApplicationOpenedEventArgs>(nameof(ApplicationOpened), RoutingStrategies.Bubble);
 
         public event EventHandler<ApplicationOpenedEventArgs> ApplicationOpened
         {
@@ -20,7 +20,7 @@ namespace Ryujinx.Ava.UI.Controls
             remove { RemoveHandler(ApplicationOpenedEvent, value); }
         }
 
-        public GameGridView()
+        public ApplicationGridView()
         {
             InitializeComponent();
         }
@@ -49,7 +49,7 @@ namespace Ryujinx.Ava.UI.Controls
             }
         }
 
-        private void SearchBox_OnKeyUp(object sender, KeyEventArgs e)
+        private void SearchBox_OnKeyUp(object sender, KeyEventArgs args)
         {
             (DataContext as MainWindowViewModel).SearchText = (sender as TextBox).Text;
         }

+ 4 - 79
src/Ryujinx.Ava/UI/Controls/GameListView.axaml → src/Ryujinx.Ava/UI/Controls/ApplicationListView.axaml

@@ -1,10 +1,10 @@
 <UserControl
-    x:Class="Ryujinx.Ava.UI.Controls.GameListView"
+    x:Class="Ryujinx.Ava.UI.Controls.ApplicationListView"
     xmlns="https://github.com/avaloniaui"
     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+    xmlns:controls="clr-namespace:Ryujinx.Ava.UI.Controls"
     xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
     xmlns:helpers="clr-namespace:Ryujinx.Ava.UI.Helpers"
-    xmlns:locale="clr-namespace:Ryujinx.Ava.Common.Locale"
     xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
     xmlns:ui="clr-namespace:FluentAvalonia.UI.Controls;assembly=FluentAvalonia"
     d:DesignHeight="450"
@@ -13,82 +13,7 @@
     mc:Ignorable="d">
     <UserControl.Resources>
         <helpers:BitmapArrayValueConverter x:Key="ByteImage" />
-        <MenuFlyout x:Key="GameContextMenu">
-            <MenuItem
-                Command="{Binding ToggleFavorite}"
-                Header="{locale:Locale GameListContextMenuToggleFavorite}"
-                ToolTip.Tip="{locale:Locale GameListContextMenuToggleFavoriteToolTip}" />
-            <Separator />
-            <MenuItem
-                Command="{Binding OpenUserSaveDirectory}"
-                IsEnabled="{Binding EnabledUserSaveDirectory}"
-                Header="{locale:Locale GameListContextMenuOpenUserSaveDirectory}"
-                ToolTip.Tip="{locale:Locale GameListContextMenuOpenUserSaveDirectoryToolTip}" />
-            <MenuItem
-                Command="{Binding OpenDeviceSaveDirectory}"
-                IsEnabled="{Binding EnabledDeviceSaveDirectory}"
-                Header="{locale:Locale GameListContextMenuOpenDeviceSaveDirectory}"
-                ToolTip.Tip="{locale:Locale GameListContextMenuOpenDeviceSaveDirectoryToolTip}" />
-            <MenuItem
-                Command="{Binding OpenBcatSaveDirectory}"
-                IsEnabled="{Binding EnabledBcatSaveDirectory}"
-                Header="{locale:Locale GameListContextMenuOpenBcatSaveDirectory}"
-                ToolTip.Tip="{locale:Locale GameListContextMenuOpenBcatSaveDirectoryToolTip}" />
-            <Separator />
-            <MenuItem
-                Command="{Binding OpenTitleUpdateManager}"
-                Header="{locale:Locale GameListContextMenuManageTitleUpdates}"
-                ToolTip.Tip="{locale:Locale GameListContextMenuManageTitleUpdatesToolTip}" />
-            <MenuItem
-                Command="{Binding OpenDownloadableContentManager}"
-                Header="{locale:Locale GameListContextMenuManageDlc}"
-                ToolTip.Tip="{locale:Locale GameListContextMenuManageDlcToolTip}" />
-            <MenuItem
-                Command="{Binding OpenCheatManager}"
-                Header="{locale:Locale GameListContextMenuManageCheat}"
-                ToolTip.Tip="{locale:Locale GameListContextMenuManageCheatToolTip}" />
-            <MenuItem
-                Command="{Binding OpenModsDirectory}"
-                Header="{locale:Locale GameListContextMenuOpenModsDirectory}"
-                ToolTip.Tip="{locale:Locale GameListContextMenuOpenModsDirectoryToolTip}" />
-            <MenuItem
-                Command="{Binding OpenSdModsDirectory}"
-                Header="{locale:Locale GameListContextMenuOpenSdModsDirectory}"
-                ToolTip.Tip="{locale:Locale GameListContextMenuOpenSdModsDirectoryToolTip}" />
-            <Separator />
-            <MenuItem Header="{locale:Locale GameListContextMenuCacheManagement}">
-                <MenuItem
-                    Command="{Binding PurgePtcCache}"
-                    Header="{locale:Locale GameListContextMenuCacheManagementPurgePptc}"
-                    ToolTip.Tip="{locale:Locale GameListContextMenuCacheManagementPurgePptcToolTip}" />
-                <MenuItem
-                    Command="{Binding PurgeShaderCache}"
-                    Header="{locale:Locale GameListContextMenuCacheManagementPurgeShaderCache}"
-                    ToolTip.Tip="{locale:Locale GameListContextMenuCacheManagementPurgeShaderCacheToolTip}" />
-                <MenuItem
-                    Command="{Binding OpenPtcDirectory}"
-                    Header="{locale:Locale GameListContextMenuCacheManagementOpenPptcDirectory}"
-                    ToolTip.Tip="{locale:Locale GameListContextMenuCacheManagementOpenPptcDirectoryToolTip}" />
-                <MenuItem
-                    Command="{Binding OpenShaderCacheDirectory}"
-                    Header="{locale:Locale GameListContextMenuCacheManagementOpenShaderCacheDirectory}"
-                    ToolTip.Tip="{locale:Locale GameListContextMenuCacheManagementOpenShaderCacheDirectoryToolTip}" />
-            </MenuItem>
-            <MenuItem Header="{locale:Locale GameListContextMenuExtractData}">
-                <MenuItem
-                    Command="{Binding ExtractExeFs}"
-                    Header="{locale:Locale GameListContextMenuExtractDataExeFS}"
-                    ToolTip.Tip="{locale:Locale GameListContextMenuExtractDataExeFSToolTip}" />
-                <MenuItem
-                    Command="{Binding ExtractRomFs}"
-                    Header="{locale:Locale GameListContextMenuExtractDataRomFS}"
-                    ToolTip.Tip="{locale:Locale GameListContextMenuExtractDataRomFSToolTip}" />
-                <MenuItem
-                    Command="{Binding ExtractLogo}"
-                    Header="{locale:Locale GameListContextMenuExtractDataLogo}"
-                    ToolTip.Tip="{locale:Locale GameListContextMenuExtractDataLogoToolTip}" />
-            </MenuItem>
-        </MenuFlyout>
+        <controls:ApplicationContextMenu x:Key="ApplicationContextMenu" />
     </UserControl.Resources>
     <Grid>
         <Grid.RowDefinitions>
@@ -100,7 +25,7 @@
             Padding="8"
             HorizontalAlignment="Stretch"
             VerticalAlignment="Stretch"
-            ContextFlyout="{StaticResource GameContextMenu}"
+            ContextFlyout="{StaticResource ApplicationContextMenu}"
             DoubleTapped="GameList_DoubleTapped"
             Items="{Binding AppsObservableList}"
             SelectionChanged="GameList_SelectionChanged">

+ 4 - 4
src/Ryujinx.Ava/UI/Controls/GameListView.axaml.cs → src/Ryujinx.Ava/UI/Controls/ApplicationListView.axaml.cs

@@ -9,10 +9,10 @@ using System;
 
 namespace Ryujinx.Ava.UI.Controls
 {
-    public partial class GameListView : UserControl
+    public partial class ApplicationListView : UserControl
     {
         public static readonly RoutedEvent<ApplicationOpenedEventArgs> ApplicationOpenedEvent =
-            RoutedEvent.Register<GameGridView, ApplicationOpenedEventArgs>(nameof(ApplicationOpened), RoutingStrategies.Bubble);
+            RoutedEvent.Register<ApplicationListView, ApplicationOpenedEventArgs>(nameof(ApplicationOpened), RoutingStrategies.Bubble);
 
         public event EventHandler<ApplicationOpenedEventArgs> ApplicationOpened
         {
@@ -20,7 +20,7 @@ namespace Ryujinx.Ava.UI.Controls
             remove { RemoveHandler(ApplicationOpenedEvent, value); }
         }
 
-        public GameListView()
+        public ApplicationListView()
         {
             InitializeComponent();
         }
@@ -49,7 +49,7 @@ namespace Ryujinx.Ava.UI.Controls
             }
         }
 
-        private void SearchBox_OnKeyUp(object sender, KeyEventArgs e)
+        private void SearchBox_OnKeyUp(object sender, KeyEventArgs args)
         {
             (DataContext as MainWindowViewModel).SearchText = (sender as TextBox).Text;
         }

+ 0 - 177
src/Ryujinx.Ava/UI/Controls/GameGridView.axaml

@@ -1,177 +0,0 @@
-<UserControl
-    x:Class="Ryujinx.Ava.UI.Controls.GameGridView"
-    xmlns="https://github.com/avaloniaui"
-    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
-    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
-    xmlns:flex="clr-namespace:Avalonia.Flexbox;assembly=Avalonia.Flexbox"
-    xmlns:locale="clr-namespace:Ryujinx.Ava.Common.Locale"
-    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
-    xmlns:ui="clr-namespace:FluentAvalonia.UI.Controls;assembly=FluentAvalonia"
-    xmlns:helpers="clr-namespace:Ryujinx.Ava.UI.Helpers"
-    d:DesignHeight="450"
-    d:DesignWidth="800"
-    mc:Ignorable="d"
-    Focusable="True">
-    <UserControl.Resources>
-        <helpers:BitmapArrayValueConverter x:Key="ByteImage" />
-        <MenuFlyout x:Key="GameContextMenu">
-            <MenuItem
-                Command="{Binding ToggleFavorite}"
-                Header="{locale:Locale GameListContextMenuToggleFavorite}"
-                ToolTip.Tip="{locale:Locale GameListContextMenuToggleFavoriteToolTip}" />
-            <Separator />
-            <MenuItem
-                Command="{Binding OpenUserSaveDirectory}"
-                IsEnabled="{Binding EnabledUserSaveDirectory}"
-                Header="{locale:Locale GameListContextMenuOpenUserSaveDirectory}"
-                ToolTip.Tip="{locale:Locale GameListContextMenuOpenUserSaveDirectoryToolTip}" />
-            <MenuItem
-                Command="{Binding OpenDeviceSaveDirectory}"
-                IsEnabled="{Binding EnabledDeviceSaveDirectory}"
-                Header="{locale:Locale GameListContextMenuOpenDeviceSaveDirectory}"
-                ToolTip.Tip="{locale:Locale GameListContextMenuOpenDeviceSaveDirectoryToolTip}" />
-            <MenuItem
-                Command="{Binding OpenBcatSaveDirectory}"
-                IsEnabled="{Binding EnabledBcatSaveDirectory}"
-                Header="{locale:Locale GameListContextMenuOpenBcatSaveDirectory}"
-                ToolTip.Tip="{locale:Locale GameListContextMenuOpenBcatSaveDirectoryToolTip}" />
-            <Separator />
-            <MenuItem
-                Command="{Binding OpenTitleUpdateManager}"
-                Header="{locale:Locale GameListContextMenuManageTitleUpdates}"
-                ToolTip.Tip="{locale:Locale GameListContextMenuManageTitleUpdatesToolTip}" />
-            <MenuItem
-                Command="{Binding OpenDownloadableContentManager}"
-                Header="{locale:Locale GameListContextMenuManageDlc}"
-                ToolTip.Tip="{locale:Locale GameListContextMenuManageDlcToolTip}" />
-            <MenuItem
-                Command="{Binding OpenCheatManager}"
-                Header="{locale:Locale GameListContextMenuManageCheat}"
-                ToolTip.Tip="{locale:Locale GameListContextMenuManageCheatToolTip}" />
-            <MenuItem
-                Command="{Binding OpenModsDirectory}"
-                Header="{locale:Locale GameListContextMenuOpenModsDirectory}"
-                ToolTip.Tip="{locale:Locale GameListContextMenuOpenModsDirectoryToolTip}" />
-            <MenuItem
-                Command="{Binding OpenSdModsDirectory}"
-                Header="{locale:Locale GameListContextMenuOpenSdModsDirectory}"
-                ToolTip.Tip="{locale:Locale GameListContextMenuOpenSdModsDirectoryToolTip}" />
-            <Separator />
-            <MenuItem Header="{locale:Locale GameListContextMenuCacheManagement}">
-                <MenuItem
-                    Command="{Binding PurgePtcCache}"
-                    Header="{locale:Locale GameListContextMenuCacheManagementPurgePptc}"
-                    ToolTip.Tip="{locale:Locale GameListContextMenuCacheManagementPurgePptcToolTip}" />
-                <MenuItem
-                    Command="{Binding PurgeShaderCache}"
-                    Header="{locale:Locale GameListContextMenuCacheManagementPurgeShaderCache}"
-                    ToolTip.Tip="{locale:Locale GameListContextMenuCacheManagementPurgeShaderCacheToolTip}" />
-                <MenuItem
-                    Command="{Binding OpenPtcDirectory}"
-                    Header="{locale:Locale GameListContextMenuCacheManagementOpenPptcDirectory}"
-                    ToolTip.Tip="{locale:Locale GameListContextMenuCacheManagementOpenPptcDirectoryToolTip}" />
-                <MenuItem
-                    Command="{Binding OpenShaderCacheDirectory}"
-                    Header="{locale:Locale GameListContextMenuCacheManagementOpenShaderCacheDirectory}"
-                    ToolTip.Tip="{locale:Locale GameListContextMenuCacheManagementOpenShaderCacheDirectoryToolTip}" />
-            </MenuItem>
-            <MenuItem Header="{locale:Locale GameListContextMenuExtractData}">
-                <MenuItem
-                    Command="{Binding ExtractExeFs}"
-                    Header="{locale:Locale GameListContextMenuExtractDataExeFS}"
-                    ToolTip.Tip="{locale:Locale GameListContextMenuExtractDataExeFSToolTip}" />
-                <MenuItem
-                    Command="{Binding ExtractRomFs}"
-                    Header="{locale:Locale GameListContextMenuExtractDataRomFS}"
-                    ToolTip.Tip="{locale:Locale GameListContextMenuExtractDataRomFSToolTip}" />
-                <MenuItem
-                    Command="{Binding ExtractLogo}"
-                    Header="{locale:Locale GameListContextMenuExtractDataLogo}"
-                    ToolTip.Tip="{locale:Locale GameListContextMenuExtractDataLogoToolTip}" />
-            </MenuItem>
-        </MenuFlyout>
-    </UserControl.Resources>
-    <Grid>
-        <Grid.RowDefinitions>
-            <RowDefinition Height="*" />
-        </Grid.RowDefinitions>
-        <ListBox
-            Grid.Row="0"
-            Padding="8"
-            HorizontalAlignment="Stretch"
-            VerticalAlignment="Stretch"
-            ContextFlyout="{StaticResource GameContextMenu}"
-            DoubleTapped="GameList_DoubleTapped"
-            Items="{Binding AppsObservableList}"
-            SelectionChanged="GameList_SelectionChanged">
-            <ListBox.ItemsPanel>
-                <ItemsPanelTemplate>
-                    <flex:FlexPanel
-                        HorizontalAlignment="Stretch"
-                        VerticalAlignment="Stretch"
-                        AlignContent="FlexStart"
-                        JustifyContent="Center" />
-                </ItemsPanelTemplate>
-            </ListBox.ItemsPanel>
-            <ListBox.Styles>
-                <Style Selector="ListBoxItem">
-                    <Setter Property="Margin" Value="5" />
-                    <Setter Property="CornerRadius" Value="4" />
-                </Style>
-                <Style Selector="ListBoxItem:selected /template/ Border#SelectionIndicator">
-                    <Setter Property="MinHeight" Value="{Binding $parent[UserControl].DataContext.GridItemSelectorSize}" />
-                </Style>
-            </ListBox.Styles>
-            <ListBox.ItemTemplate>
-                <DataTemplate>
-                    <Grid>
-                        <Border
-                            Margin="10"
-                            HorizontalAlignment="Stretch"
-                            VerticalAlignment="Stretch"
-                            Classes.huge="{Binding $parent[UserControl].DataContext.IsGridHuge}"
-                            Classes.large="{Binding $parent[UserControl].DataContext.IsGridLarge}"
-                            Classes.normal="{Binding $parent[UserControl].DataContext.IsGridMedium}"
-                            Classes.small="{Binding $parent[UserControl].DataContext.IsGridSmall}"
-                            ClipToBounds="True"
-                            CornerRadius="4">
-                            <Grid>
-                                <Grid.RowDefinitions>
-                                    <RowDefinition Height="Auto" />
-                                    <RowDefinition Height="Auto" />
-                                </Grid.RowDefinitions>
-                                <Image
-                                    Grid.Row="0"
-                                    HorizontalAlignment="Stretch"
-                                    VerticalAlignment="Top"
-                                    Source="{Binding Icon, Converter={StaticResource ByteImage}}" />
-                                <Panel
-                                    Grid.Row="1"
-                                    Height="50"
-                                    Margin="0 10 0 0"
-                                    HorizontalAlignment="Stretch"
-                                    VerticalAlignment="Stretch"
-                                    IsVisible="{Binding $parent[UserControl].DataContext.ShowNames}">
-                                    <TextBlock
-                                        HorizontalAlignment="Stretch"
-                                        VerticalAlignment="Center"
-                                        Text="{Binding TitleName}"
-                                        TextAlignment="Center"
-                                        TextWrapping="Wrap" />
-                                </Panel>
-                            </Grid>
-                        </Border>
-                        <ui:SymbolIcon
-                            Margin="5,5,0,0"
-                            HorizontalAlignment="Left"
-                            VerticalAlignment="Top"
-                            FontSize="16"
-                            Foreground="{DynamicResource SystemAccentColor}"
-                            IsVisible="{Binding Favorite}"
-                            Symbol="StarFilled" />
-                    </Grid>
-                </DataTemplate>
-            </ListBox.ItemTemplate>
-        </ListBox>
-    </Grid>
-</UserControl>

+ 4 - 262
src/Ryujinx.Ava/UI/ViewModels/MainWindowViewModel.cs

@@ -6,8 +6,6 @@ using Avalonia.Threading;
 using DynamicData;
 using DynamicData.Binding;
 using LibHac.Common;
-using LibHac.Fs;
-using LibHac.Tools.FsSystem.NcaUtils;
 using Ryujinx.Ava.Common;
 using Ryujinx.Ava.Common.Locale;
 using Ryujinx.Ava.Input;
@@ -33,13 +31,11 @@ using SixLabors.ImageSharp.PixelFormats;
 using System;
 using System.Collections.Generic;
 using System.Collections.ObjectModel;
-using System.Globalization;
 using System.IO;
 using System.Threading;
 using System.Threading.Tasks;
 using Path = System.IO.Path;
 using ShaderCacheLoadingState = Ryujinx.Graphics.Gpu.Shader.ShaderCacheState;
-using UserId = LibHac.Fs.UserId;
 
 namespace Ryujinx.Ava.UI.ViewModels
 {
@@ -346,11 +342,11 @@ namespace Ryujinx.Ava.UI.ViewModels
             }
         }
 
-        public bool EnabledUserSaveDirectory => !Utilities.IsZeros(SelectedApplication.ControlHolder.ByteSpan) && SelectedApplication.ControlHolder.Value.UserAccountSaveDataSize > 0;
+        public bool OpenUserSaveDirectoryEnabled => !Utilities.IsZeros(SelectedApplication.ControlHolder.ByteSpan) && SelectedApplication.ControlHolder.Value.UserAccountSaveDataSize > 0;
 
-        public bool EnabledDeviceSaveDirectory => !Utilities.IsZeros(SelectedApplication.ControlHolder.ByteSpan) && SelectedApplication.ControlHolder.Value.DeviceSaveDataSize > 0;
+        public bool OpenDeviceSaveDirectoryEnabled => !Utilities.IsZeros(SelectedApplication.ControlHolder.ByteSpan) && SelectedApplication.ControlHolder.Value.DeviceSaveDataSize > 0;
 
-        public bool EnabledBcatSaveDirectory => !Utilities.IsZeros(SelectedApplication.ControlHolder.ByteSpan) && SelectedApplication.ControlHolder.Value.BcatDeliveryCacheStorageSize > 0;
+        public bool OpenBcatSaveDirectoryEnabled => !Utilities.IsZeros(SelectedApplication.ControlHolder.ByteSpan) && SelectedApplication.ControlHolder.Value.BcatDeliveryCacheStorageSize > 0;
 
         public string LoadHeading
         {
@@ -941,7 +937,7 @@ namespace Ryujinx.Ava.UI.ViewModels
             };
         }
 
-        private void RefreshView()
+        public void RefreshView()
         {
             RefreshGrid();
         }
@@ -1116,30 +1112,6 @@ namespace Ryujinx.Ava.UI.ViewModels
             }));
         }
 
-        private async void ExtractLogo()
-        {
-            if (SelectedApplication != null)
-            {
-                await ApplicationHelper.ExtractSection(NcaSectionType.Logo, SelectedApplication.Path, SelectedApplication.TitleName);
-            }
-        }
-
-        private async void ExtractRomFs()
-        {
-            if (SelectedApplication != null)
-            {
-                await ApplicationHelper.ExtractSection(NcaSectionType.Data, SelectedApplication.Path, SelectedApplication.TitleName);
-            }
-        }
-
-        private async void ExtractExeFs()
-        {
-            if (SelectedApplication != null)
-            {
-                await ApplicationHelper.ExtractSection(NcaSectionType.Code, SelectedApplication.Path, SelectedApplication.TitleName);
-            }
-        }
-
         private void PrepareLoadScreen()
         {
             using MemoryStream stream = new(SelectedIcon);
@@ -1383,241 +1355,11 @@ namespace Ryujinx.Ava.UI.ViewModels
             await NavigationDialogHost.Show(AccountManager, ContentManager, VirtualFileSystem, LibHacHorizonManager.RyujinxClient);
         }
 
-        public void OpenPtcDirectory()
-        {
-            ApplicationData selection = SelectedApplication;
-            if (selection != null)
-            {
-                string ptcDir = Path.Combine(AppDataManager.GamesDirPath, selection.TitleId, "cache", "cpu");
-                string mainPath = Path.Combine(ptcDir, "0");
-                string backupPath = Path.Combine(ptcDir, "1");
-
-                if (!Directory.Exists(ptcDir))
-                {
-                    Directory.CreateDirectory(ptcDir);
-                    Directory.CreateDirectory(mainPath);
-                    Directory.CreateDirectory(backupPath);
-                }
-
-                OpenHelper.OpenFolder(ptcDir);
-            }
-        }
-
-        public async void PurgePtcCache()
-        {
-            ApplicationData selection = SelectedApplication;
-            if (selection != null)
-            {
-                DirectoryInfo mainDir = new(Path.Combine(AppDataManager.GamesDirPath, selection.TitleId, "cache", "cpu", "0"));
-                DirectoryInfo backupDir = new(Path.Combine(AppDataManager.GamesDirPath, selection.TitleId, "cache", "cpu", "1"));
-
-                // FIXME: Found a way to reproduce the bold effect on the title name (fork?).
-                UserResult result = await ContentDialogHelper.CreateConfirmationDialog(LocaleManager.Instance[LocaleKeys.DialogWarning],
-                                                                                       LocaleManager.Instance.UpdateAndGetDynamicValue(LocaleKeys.DialogPPTCDeletionMessage, selection.TitleName),
-                                                                                       LocaleManager.Instance[LocaleKeys.InputDialogYes],
-                                                                                       LocaleManager.Instance[LocaleKeys.InputDialogNo],
-                                                                                       LocaleManager.Instance[LocaleKeys.RyujinxConfirm]);
-
-                List<FileInfo> cacheFiles = new();
-
-                if (mainDir.Exists)
-                {
-                    cacheFiles.AddRange(mainDir.EnumerateFiles("*.cache"));
-                }
-
-                if (backupDir.Exists)
-                {
-                    cacheFiles.AddRange(backupDir.EnumerateFiles("*.cache"));
-                }
-
-                if (cacheFiles.Count > 0 && result == UserResult.Yes)
-                {
-                    foreach (FileInfo file in cacheFiles)
-                    {
-                        try
-                        {
-                            file.Delete();
-                        }
-                        catch (Exception e)
-                        {
-                            await ContentDialogHelper.CreateErrorDialog(LocaleManager.Instance.UpdateAndGetDynamicValue(LocaleKeys.DialogPPTCDeletionErrorMessage, file.Name, e));
-                        }
-                    }
-                }
-            }
-        }
-
-        public void OpenShaderCacheDirectory()
-        {
-            ApplicationData selection = SelectedApplication;
-            if (selection != null)
-            {
-                string shaderCacheDir = Path.Combine(AppDataManager.GamesDirPath, selection.TitleId, "cache", "shader");
-
-                if (!Directory.Exists(shaderCacheDir))
-                {
-                    Directory.CreateDirectory(shaderCacheDir);
-                }
-
-                OpenHelper.OpenFolder(shaderCacheDir);
-            }
-        }
-
         public void SimulateWakeUpMessage()
         {
             AppHost.Device.System.SimulateWakeUpMessage();
         }
 
-        public async void PurgeShaderCache()
-        {
-            ApplicationData selection = SelectedApplication;
-            if (selection != null)
-            {
-                DirectoryInfo shaderCacheDir = new(Path.Combine(AppDataManager.GamesDirPath, selection.TitleId, "cache", "shader"));
-
-                // FIXME: Found a way to reproduce the bold effect on the title name (fork?).
-                UserResult result = await ContentDialogHelper.CreateConfirmationDialog(LocaleManager.Instance[LocaleKeys.DialogWarning],
-                                                                                       LocaleManager.Instance.UpdateAndGetDynamicValue(LocaleKeys.DialogShaderDeletionMessage, selection.TitleName),
-                                                                                       LocaleManager.Instance[LocaleKeys.InputDialogYes],
-                                                                                       LocaleManager.Instance[LocaleKeys.InputDialogNo],
-                                                                                       LocaleManager.Instance[LocaleKeys.RyujinxConfirm]);
-
-                List<DirectoryInfo> oldCacheDirectories = new();
-                List<FileInfo> newCacheFiles = new();
-
-                if (shaderCacheDir.Exists)
-                {
-                    oldCacheDirectories.AddRange(shaderCacheDir.EnumerateDirectories("*"));
-                    newCacheFiles.AddRange(shaderCacheDir.GetFiles("*.toc"));
-                    newCacheFiles.AddRange(shaderCacheDir.GetFiles("*.data"));
-                }
-
-                if ((oldCacheDirectories.Count > 0 || newCacheFiles.Count > 0) && result == UserResult.Yes)
-                {
-                    foreach (DirectoryInfo directory in oldCacheDirectories)
-                    {
-                        try
-                        {
-                            directory.Delete(true);
-                        }
-                        catch (Exception e)
-                        {
-                            await ContentDialogHelper.CreateErrorDialog(LocaleManager.Instance.UpdateAndGetDynamicValue(LocaleKeys.DialogPPTCDeletionErrorMessage, directory.Name, e));
-                        }
-                    }
-                }
-
-                foreach (FileInfo file in newCacheFiles)
-                {
-                    try
-                    {
-                        file.Delete();
-                    }
-                    catch (Exception e)
-                    {
-                        await ContentDialogHelper.CreateErrorDialog(LocaleManager.Instance.UpdateAndGetDynamicValue(LocaleKeys.ShaderCachePurgeError, file.Name, e));
-                    }
-                }
-            }
-        }
-
-        public void ToggleFavorite()
-        {
-            ApplicationData selection = SelectedApplication;
-            if (selection != null)
-            {
-                selection.Favorite = !selection.Favorite;
-
-                ApplicationLibrary.LoadAndSaveMetaData(selection.TitleId, appMetadata =>
-                {
-                    appMetadata.Favorite = selection.Favorite;
-                });
-
-                RefreshView();
-            }
-        }
-
-        public void OpenUserSaveDirectory()
-        {
-            OpenSaveDirectory(SaveDataType.Account, userId: new UserId((ulong)AccountManager.LastOpenedUser.UserId.High, (ulong)AccountManager.LastOpenedUser.UserId.Low));
-        }
-
-        public void OpenDeviceSaveDirectory()
-        {
-            OpenSaveDirectory(SaveDataType.Device, userId: default);
-        }
-
-        public void OpenBcatSaveDirectory()
-        {
-            OpenSaveDirectory(SaveDataType.Bcat, userId: default);
-        }
-
-        private void OpenSaveDirectory(SaveDataType saveDataType, UserId userId)
-        {
-            if (SelectedApplication != null)
-            {
-                if (!ulong.TryParse(SelectedApplication.TitleId, NumberStyles.HexNumber, CultureInfo.InvariantCulture, out ulong titleIdNumber))
-                {
-                    Dispatcher.UIThread.InvokeAsync(async () =>
-                    {
-                        await ContentDialogHelper.CreateErrorDialog(LocaleManager.Instance[LocaleKeys.DialogRyujinxErrorMessage], LocaleManager.Instance[LocaleKeys.DialogInvalidTitleIdErrorMessage]);
-                    });
-
-                    return;
-                }
-
-                var saveDataFilter = SaveDataFilter.Make(titleIdNumber, saveDataType, userId, saveDataId: default, index: default);
-
-                ApplicationHelper.OpenSaveDir(in saveDataFilter, titleIdNumber, SelectedApplication.ControlHolder, SelectedApplication.TitleName);
-            }
-        }
-
-        public void OpenModsDirectory()
-        {
-            if (SelectedApplication != null)
-            {
-                string modsBasePath  = VirtualFileSystem.ModLoader.GetModsBasePath();
-                string titleModsPath = VirtualFileSystem.ModLoader.GetTitleDir(modsBasePath, SelectedApplication.TitleId);
-
-                OpenHelper.OpenFolder(titleModsPath);
-            }
-        }
-
-        public void OpenSdModsDirectory()
-        {
-            if (SelectedApplication != null)
-            {
-                string sdModsBasePath = VirtualFileSystem.ModLoader.GetSdModsBasePath();
-                string titleModsPath  = VirtualFileSystem.ModLoader.GetTitleDir(sdModsBasePath, SelectedApplication.TitleId);
-
-                OpenHelper.OpenFolder(titleModsPath);
-            }
-        }
-
-        public async void OpenTitleUpdateManager()
-        {
-            if (SelectedApplication != null)
-            {
-                await TitleUpdateWindow.Show(VirtualFileSystem, ulong.Parse(SelectedApplication.TitleId, NumberStyles.HexNumber), SelectedApplication.TitleName);
-            }
-        }
-
-        public async void OpenDownloadableContentManager()
-        {
-            if (SelectedApplication != null)
-            {
-                await DownloadableContentManagerWindow.Show(VirtualFileSystem, ulong.Parse(SelectedApplication.TitleId, NumberStyles.HexNumber), SelectedApplication.TitleName);
-            }
-        }
-
-        public async void OpenCheatManager()
-        {
-            if (SelectedApplication != null)
-            {
-                await new CheatWindow(VirtualFileSystem, SelectedApplication.TitleId, SelectedApplication.TitleName).ShowDialog(TopLevel as Window);
-            }
-        }
-
         public async void LoadApplications()
         {
             await Dispatcher.UIThread.InvokeAsync(() =>

+ 4 - 4
src/Ryujinx.Ava/UI/Windows/MainWindow.axaml

@@ -88,16 +88,16 @@
                     <main:MainViewControls
                         Name="ViewControls"
                         Grid.Row="0"/>
-                    <controls:GameListView
-                        x:Name="GameList"
+                    <controls:ApplicationListView
+                        x:Name="ApplicationList"
                         Grid.Row="1"
                         HorizontalAlignment="Stretch"
                         VerticalAlignment="Stretch"
                         HorizontalContentAlignment="Stretch"
                         VerticalContentAlignment="Stretch"
                         IsVisible="{Binding IsList}" />
-                    <controls:GameGridView
-                        x:Name="GameGrid"
+                    <controls:ApplicationGridView
+                        x:Name="ApplicationGrid"
                         Grid.Row="1"
                         HorizontalAlignment="Stretch"
                         VerticalAlignment="Stretch"

+ 4 - 4
src/Ryujinx.Ava/UI/Windows/MainWindow.axaml.cs

@@ -288,13 +288,13 @@ namespace Ryujinx.Ava.UI.Windows
         {
             StatusBarView.VolumeStatus.Click += VolumeStatus_CheckedChanged;
 
-            GameGrid.ApplicationOpened += Application_Opened;
+            ApplicationGrid.ApplicationOpened += Application_Opened;
 
-            GameGrid.DataContext = ViewModel;
+            ApplicationGrid.DataContext = ViewModel;
 
-            GameList.ApplicationOpened += Application_Opened;
+            ApplicationList.ApplicationOpened += Application_Opened;
 
-            GameList.DataContext = ViewModel;
+            ApplicationList.DataContext = ViewModel;
 
             LoadHotKeys();
         }