| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430 |
- using Avalonia.Controls;
- using Avalonia.Interactivity;
- using Avalonia.Markup.Xaml;
- using Avalonia.Platform.Storage;
- using LibHac.Fs;
- using LibHac.Tools.FsSystem.NcaUtils;
- using Ryujinx.Ava.Common;
- using Ryujinx.Ava.Common.Locale;
- using Ryujinx.Ava.Common.Models;
- using Ryujinx.Ava.UI.Helpers;
- using Ryujinx.Ava.UI.ViewModels;
- using Ryujinx.Ava.UI.Windows;
- using Ryujinx.Ava.Utilities;
- using Ryujinx.Ava.Utilities.AppLibrary;
- using Ryujinx.Ava.Utilities.Compat;
- using Ryujinx.Common.Configuration;
- using Ryujinx.Common.Helper;
- using Ryujinx.HLE.HOS;
- using SkiaSharp;
- using System;
- using System.Collections.Generic;
- using System.IO;
- using Path = System.IO.Path;
- 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)
- {
- if (sender is not MenuItem { DataContext: MainWindowViewModel { SelectedApplication: not null } viewModel })
- return;
- viewModel.SelectedApplication.Favorite = !viewModel.SelectedApplication.Favorite;
- ApplicationLibrary.LoadAndSaveMetaData(viewModel.SelectedApplication.IdString, appMetadata =>
- {
- appMetadata.Favorite = viewModel.SelectedApplication.Favorite;
- });
- viewModel.RefreshView();
- }
- public void OpenUserSaveDirectory_Click(object sender, RoutedEventArgs args)
- {
- if (sender is MenuItem { DataContext: MainWindowViewModel { SelectedApplication: not null } viewModel })
- OpenSaveDirectory(viewModel, SaveDataType.Account, new UserId((ulong)viewModel.AccountManager.LastOpenedUser.UserId.High, (ulong)viewModel.AccountManager.LastOpenedUser.UserId.Low));
- }
- public void OpenDeviceSaveDirectory_Click(object sender, RoutedEventArgs args)
- {
- if (sender is MenuItem { DataContext: MainWindowViewModel { SelectedApplication: not null } viewModel })
- OpenSaveDirectory(viewModel, SaveDataType.Device, default);
- }
- public void OpenBcatSaveDirectory_Click(object sender, RoutedEventArgs args)
- {
- if (sender is MenuItem { DataContext: MainWindowViewModel { SelectedApplication: not null } viewModel })
- OpenSaveDirectory(viewModel, SaveDataType.Bcat, default);
- }
- private static void OpenSaveDirectory(MainWindowViewModel viewModel, SaveDataType saveDataType, UserId userId)
- {
- SaveDataFilter saveDataFilter = SaveDataFilter.Make(viewModel.SelectedApplication.Id, saveDataType, userId, saveDataId: default, index: default);
- ApplicationHelper.OpenSaveDir(in saveDataFilter, viewModel.SelectedApplication.Id, viewModel.SelectedApplication.ControlHolder, viewModel.SelectedApplication.Name);
- }
- public async void OpenTitleUpdateManager_Click(object sender, RoutedEventArgs args)
- {
- if (sender is MenuItem { DataContext: MainWindowViewModel { SelectedApplication: not null } viewModel })
- await TitleUpdateWindow.Show(viewModel.ApplicationLibrary, viewModel.SelectedApplication);
- }
- public async void OpenDownloadableContentManager_Click(object sender, RoutedEventArgs args)
- {
- if (sender is MenuItem { DataContext: MainWindowViewModel { SelectedApplication: not null } viewModel })
- await DownloadableContentManagerWindow.Show(viewModel.ApplicationLibrary, viewModel.SelectedApplication);
- }
- public async void OpenCheatManager_Click(object sender, RoutedEventArgs args)
- {
- if (sender is MenuItem { DataContext: MainWindowViewModel { SelectedApplication: not null } viewModel })
- await StyleableAppWindow.ShowAsync(
- new CheatWindow(
- viewModel.VirtualFileSystem,
- viewModel.SelectedApplication.IdString,
- viewModel.SelectedApplication.Name,
- viewModel.SelectedApplication.Path
- )
- );
- }
- public void OpenModsDirectory_Click(object sender, RoutedEventArgs args)
- {
- if (sender is not MenuItem { DataContext: MainWindowViewModel { SelectedApplication: not null } viewModel })
- return;
- string modsBasePath = ModLoader.GetModsBasePath();
- string titleModsPath = ModLoader.GetApplicationDir(modsBasePath, viewModel.SelectedApplication.IdString);
- OpenHelper.OpenFolder(titleModsPath);
- }
- public void OpenSdModsDirectory_Click(object sender, RoutedEventArgs args)
- {
- if (sender is not MenuItem { DataContext: MainWindowViewModel { SelectedApplication: not null } viewModel })
- return;
- string sdModsBasePath = ModLoader.GetSdModsBasePath();
- string titleModsPath = ModLoader.GetApplicationDir(sdModsBasePath, viewModel.SelectedApplication.IdString);
- OpenHelper.OpenFolder(titleModsPath);
- }
- public async void OpenModManager_Click(object sender, RoutedEventArgs args)
- {
- if (sender is MenuItem { DataContext: MainWindowViewModel { SelectedApplication: not null } viewModel })
- await ModManagerWindow.Show(
- viewModel.SelectedApplication.Id,
- viewModel.SelectedApplication.IdBase,
- viewModel.ApplicationLibrary,
- viewModel.SelectedApplication.Name);
- }
- public async void PurgePtcCache_Click(object sender, RoutedEventArgs args)
- {
- if (sender is not MenuItem { DataContext: MainWindowViewModel { SelectedApplication: not null } viewModel })
- return;
- UserResult result = await ContentDialogHelper.CreateLocalizedConfirmationDialog(
- LocaleManager.Instance[LocaleKeys.DialogWarning],
- LocaleManager.Instance.UpdateAndGetDynamicValue(LocaleKeys.DialogPPTCDeletionMessage, viewModel.SelectedApplication.Name)
- );
- if (result == UserResult.Yes)
- {
- DirectoryInfo mainDir = new(Path.Combine(AppDataManager.GamesDirPath, viewModel.SelectedApplication.IdString, "cache", "cpu", "0"));
- DirectoryInfo backupDir = new(Path.Combine(AppDataManager.GamesDirPath, viewModel.SelectedApplication.IdString, "cache", "cpu", "1"));
- List<FileInfo> cacheFiles = [];
- 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 NukePtcCache_Click(object sender, RoutedEventArgs args)
- {
- if (sender is not MenuItem { DataContext: MainWindowViewModel { SelectedApplication: not null } viewModel })
- return;
- UserResult result = await ContentDialogHelper.CreateLocalizedConfirmationDialog(
- LocaleManager.Instance[LocaleKeys.DialogWarning],
- LocaleManager.Instance.UpdateAndGetDynamicValue(LocaleKeys.DialogPPTCNukeMessage, viewModel.SelectedApplication.Name)
- );
- if (result == UserResult.Yes)
- {
- DirectoryInfo mainDir = new(Path.Combine(AppDataManager.GamesDirPath, viewModel.SelectedApplication.IdString, "cache", "cpu", "0"));
- DirectoryInfo backupDir = new(Path.Combine(AppDataManager.GamesDirPath, viewModel.SelectedApplication.IdString, "cache", "cpu", "1"));
- List<FileInfo> cacheFiles = [];
- if (mainDir.Exists)
- {
- cacheFiles.AddRange(mainDir.EnumerateFiles("*.cache"));
- cacheFiles.AddRange(mainDir.EnumerateFiles("*.info"));
- }
- if (backupDir.Exists)
- {
- cacheFiles.AddRange(backupDir.EnumerateFiles("*.cache"));
- cacheFiles.AddRange(backupDir.EnumerateFiles("*.info"));
- }
- 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)
- {
- if (sender is not MenuItem { DataContext: MainWindowViewModel { SelectedApplication: not null } viewModel })
- return;
- UserResult result = await ContentDialogHelper.CreateLocalizedConfirmationDialog(
- LocaleManager.Instance[LocaleKeys.DialogWarning],
- LocaleManager.Instance.UpdateAndGetDynamicValue(LocaleKeys.DialogShaderDeletionMessage, viewModel.SelectedApplication.Name)
- );
- if (result == UserResult.Yes)
- {
- DirectoryInfo shaderCacheDir = new(Path.Combine(AppDataManager.GamesDirPath, viewModel.SelectedApplication.IdString, "cache", "shader"));
- List<DirectoryInfo> oldCacheDirectories = [];
- List<FileInfo> newCacheFiles = [];
- 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)
- {
- if (sender is not MenuItem { DataContext: MainWindowViewModel { SelectedApplication: not null } viewModel })
- return;
- string ptcDir = Path.Combine(AppDataManager.GamesDirPath, viewModel.SelectedApplication.IdString, "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)
- {
- if (sender is MenuItem { DataContext: MainWindowViewModel { SelectedApplication: not null } viewModel })
- {
- string shaderCacheDir = Path.Combine(AppDataManager.GamesDirPath, viewModel.SelectedApplication.IdString.ToLower(), "cache", "shader");
- if (!Directory.Exists(shaderCacheDir))
- {
- Directory.CreateDirectory(shaderCacheDir);
- }
- OpenHelper.OpenFolder(shaderCacheDir);
- }
- }
- public async void ExtractApplicationExeFs_Click(object sender, RoutedEventArgs args)
- {
- if (sender is MenuItem { DataContext: MainWindowViewModel { SelectedApplication: not null } viewModel })
- {
- await ApplicationHelper.ExtractSection(
- viewModel.StorageProvider,
- NcaSectionType.Code,
- viewModel.SelectedApplication.Path,
- viewModel.SelectedApplication.Name);
- }
- }
- public async void ExtractApplicationRomFs_Click(object sender, RoutedEventArgs args)
- {
- if (sender is MenuItem { DataContext: MainWindowViewModel { SelectedApplication: not null } viewModel })
- await ApplicationHelper.ExtractSection(
- viewModel.StorageProvider,
- NcaSectionType.Data,
- viewModel.SelectedApplication.Path,
- viewModel.SelectedApplication.Name);
- }
-
- public async void ExtractAocRomFs_Click(object sender, RoutedEventArgs args)
- {
- if (sender is not MenuItem { DataContext: MainWindowViewModel { SelectedApplication: not null } viewModel })
- return;
- DownloadableContentModel selectedDlc = await DlcSelectView.Show(viewModel.SelectedApplication.Id, viewModel.ApplicationLibrary);
-
- if (selectedDlc is not null)
- {
- await ApplicationHelper.ExtractAoc(
- viewModel.StorageProvider,
- selectedDlc.ContainerPath,
- selectedDlc.FileName);
- }
- }
- public async void ExtractApplicationLogo_Click(object sender, RoutedEventArgs args)
- {
- if (sender is not MenuItem { DataContext: MainWindowViewModel { SelectedApplication: not null } viewModel })
- return;
- IReadOnlyList<IStorageFolder> result = await viewModel.StorageProvider.OpenFolderPickerAsync(new FolderPickerOpenOptions
- {
- Title = LocaleManager.Instance[LocaleKeys.FolderDialogExtractTitle],
- AllowMultiple = false,
- });
- if (result.Count == 0)
- return;
- ApplicationHelper.ExtractSection(
- result[0].Path.LocalPath,
- NcaSectionType.Logo,
- viewModel.SelectedApplication.Path,
- viewModel.SelectedApplication.Name);
- IStorageFile iconFile = await result[0].CreateFileAsync($"{viewModel.SelectedApplication.IdString}.png");
- await using Stream fileStream = await iconFile.OpenWriteAsync();
- using SKBitmap bitmap = SKBitmap.Decode(viewModel.SelectedApplication.Icon)
- .Resize(new SKSizeI(512, 512), SKFilterQuality.High);
- using SKData png = bitmap.Encode(SKEncodedImageFormat.Png, 100);
- png.SaveTo(fileStream);
- }
- public void CreateApplicationShortcut_Click(object sender, RoutedEventArgs args)
- {
- if (sender is MenuItem { DataContext: MainWindowViewModel { SelectedApplication: not null } viewModel })
- ShortcutHelper.CreateAppShortcut(
- viewModel.SelectedApplication.Path,
- viewModel.SelectedApplication.Name,
- viewModel.SelectedApplication.IdString,
- viewModel.SelectedApplication.Icon
- );
- }
- public async void EditGameConfiguration_Click(object sender, RoutedEventArgs args)
- {
- if (sender is MenuItem { DataContext: MainWindowViewModel { SelectedApplication: not null } viewModel })
- {
- await StyleableAppWindow.ShowAsync(new GameSpecificSettingsWindow(viewModel));
- // just checking for file presence
- viewModel.SelectedApplication.HasIndependentConfiguration = File.Exists(Program.GetDirGameUserConfig(viewModel.SelectedApplication.IdString,false,false));
- viewModel.RefreshView();
- }
- }
- public async void OpenApplicationCompatibility_Click(object sender, RoutedEventArgs args)
- {
- if (sender is MenuItem { DataContext: MainWindowViewModel { SelectedApplication: not null } viewModel })
- await CompatibilityList.Show(viewModel.SelectedApplication.IdString);
- }
-
- public async void OpenApplicationData_Click(object sender, RoutedEventArgs args)
- {
- if (sender is MenuItem { DataContext: MainWindowViewModel { SelectedApplication: not null } viewModel })
- await ApplicationDataView.Show(viewModel.SelectedApplication);
- }
- public async void RunApplication_Click(object sender, RoutedEventArgs args)
- {
- if (sender is MenuItem { DataContext: MainWindowViewModel { SelectedApplication: not null } viewModel })
- await viewModel.LoadApplication(viewModel.SelectedApplication);
- }
- public async void TrimXCI_Click(object sender, RoutedEventArgs args)
- {
- if (sender is MenuItem { DataContext: MainWindowViewModel { SelectedApplication: not null } viewModel })
- await viewModel.TrimXCIFile(viewModel.SelectedApplication.Path);
- }
- }
- }
|