/ src / Ryujinx / UI / Controls / ApplicationContextMenu.axaml.cs
ApplicationContextMenu.axaml.cs
  1  using Avalonia.Controls;
  2  using Avalonia.Interactivity;
  3  using Avalonia.Markup.Xaml;
  4  using LibHac.Fs;
  5  using LibHac.Tools.FsSystem.NcaUtils;
  6  using Ryujinx.Ava.Common;
  7  using Ryujinx.Ava.Common.Locale;
  8  using Ryujinx.Ava.UI.Helpers;
  9  using Ryujinx.Ava.UI.ViewModels;
 10  using Ryujinx.Ava.UI.Windows;
 11  using Ryujinx.Common.Configuration;
 12  using Ryujinx.HLE.HOS;
 13  using Ryujinx.UI.App.Common;
 14  using Ryujinx.UI.Common.Helper;
 15  using System;
 16  using System.Collections.Generic;
 17  using System.IO;
 18  using Path = System.IO.Path;
 19  
 20  namespace Ryujinx.Ava.UI.Controls
 21  {
 22      public class ApplicationContextMenu : MenuFlyout
 23      {
 24          public ApplicationContextMenu()
 25          {
 26              InitializeComponent();
 27          }
 28  
 29          private void InitializeComponent()
 30          {
 31              AvaloniaXamlLoader.Load(this);
 32          }
 33  
 34          public void ToggleFavorite_Click(object sender, RoutedEventArgs args)
 35          {
 36              var viewModel = (sender as MenuItem)?.DataContext as MainWindowViewModel;
 37  
 38              if (viewModel?.SelectedApplication != null)
 39              {
 40                  viewModel.SelectedApplication.Favorite = !viewModel.SelectedApplication.Favorite;
 41  
 42                  ApplicationLibrary.LoadAndSaveMetaData(viewModel.SelectedApplication.IdString, appMetadata =>
 43                  {
 44                      appMetadata.Favorite = viewModel.SelectedApplication.Favorite;
 45                  });
 46  
 47                  viewModel.RefreshView();
 48              }
 49          }
 50  
 51          public void OpenUserSaveDirectory_Click(object sender, RoutedEventArgs args)
 52          {
 53              if (sender is MenuItem { DataContext: MainWindowViewModel viewModel })
 54              {
 55                  OpenSaveDirectory(viewModel, SaveDataType.Account, new UserId((ulong)viewModel.AccountManager.LastOpenedUser.UserId.High, (ulong)viewModel.AccountManager.LastOpenedUser.UserId.Low));
 56              }
 57          }
 58  
 59          public void OpenDeviceSaveDirectory_Click(object sender, RoutedEventArgs args)
 60          {
 61              var viewModel = (sender as MenuItem)?.DataContext as MainWindowViewModel;
 62  
 63              OpenSaveDirectory(viewModel, SaveDataType.Device, default);
 64          }
 65  
 66          public void OpenBcatSaveDirectory_Click(object sender, RoutedEventArgs args)
 67          {
 68              var viewModel = (sender as MenuItem)?.DataContext as MainWindowViewModel;
 69  
 70              OpenSaveDirectory(viewModel, SaveDataType.Bcat, default);
 71          }
 72  
 73          private static void OpenSaveDirectory(MainWindowViewModel viewModel, SaveDataType saveDataType, UserId userId)
 74          {
 75              if (viewModel?.SelectedApplication != null)
 76              {
 77                  var saveDataFilter = SaveDataFilter.Make(viewModel.SelectedApplication.Id, saveDataType, userId, saveDataId: default, index: default);
 78  
 79                  ApplicationHelper.OpenSaveDir(in saveDataFilter, viewModel.SelectedApplication.Id, viewModel.SelectedApplication.ControlHolder, viewModel.SelectedApplication.Name);
 80              }
 81          }
 82  
 83          public async void OpenTitleUpdateManager_Click(object sender, RoutedEventArgs args)
 84          {
 85              var viewModel = (sender as MenuItem)?.DataContext as MainWindowViewModel;
 86  
 87              if (viewModel?.SelectedApplication != null)
 88              {
 89                  await TitleUpdateWindow.Show(viewModel.VirtualFileSystem, viewModel.SelectedApplication);
 90              }
 91          }
 92  
 93          public async void OpenDownloadableContentManager_Click(object sender, RoutedEventArgs args)
 94          {
 95              var viewModel = (sender as MenuItem)?.DataContext as MainWindowViewModel;
 96  
 97              if (viewModel?.SelectedApplication != null)
 98              {
 99                  await DownloadableContentManagerWindow.Show(viewModel.VirtualFileSystem, viewModel.SelectedApplication);
100              }
101          }
102  
103          public async void OpenCheatManager_Click(object sender, RoutedEventArgs args)
104          {
105              var viewModel = (sender as MenuItem)?.DataContext as MainWindowViewModel;
106  
107              if (viewModel?.SelectedApplication != null)
108              {
109                  await new CheatWindow(
110                      viewModel.VirtualFileSystem,
111                      viewModel.SelectedApplication.IdString,
112                      viewModel.SelectedApplication.Name,
113                      viewModel.SelectedApplication.Path).ShowDialog(viewModel.TopLevel as Window);
114              }
115          }
116  
117          public void OpenModsDirectory_Click(object sender, RoutedEventArgs args)
118          {
119              var viewModel = (sender as MenuItem)?.DataContext as MainWindowViewModel;
120  
121              if (viewModel?.SelectedApplication != null)
122              {
123                  string modsBasePath = ModLoader.GetModsBasePath();
124                  string titleModsPath = ModLoader.GetApplicationDir(modsBasePath, viewModel.SelectedApplication.IdString);
125  
126                  OpenHelper.OpenFolder(titleModsPath);
127              }
128          }
129  
130          public void OpenSdModsDirectory_Click(object sender, RoutedEventArgs args)
131          {
132              var viewModel = (sender as MenuItem)?.DataContext as MainWindowViewModel;
133  
134              if (viewModel?.SelectedApplication != null)
135              {
136                  string sdModsBasePath = ModLoader.GetSdModsBasePath();
137                  string titleModsPath = ModLoader.GetApplicationDir(sdModsBasePath, viewModel.SelectedApplication.IdString);
138  
139                  OpenHelper.OpenFolder(titleModsPath);
140              }
141          }
142  
143          public async void OpenModManager_Click(object sender, RoutedEventArgs args)
144          {
145              var viewModel = (sender as MenuItem)?.DataContext as MainWindowViewModel;
146  
147              if (viewModel?.SelectedApplication != null)
148              {
149                  await ModManagerWindow.Show(viewModel.SelectedApplication.Id, viewModel.SelectedApplication.Name);
150              }
151          }
152  
153          public async void PurgePtcCache_Click(object sender, RoutedEventArgs args)
154          {
155              var viewModel = (sender as MenuItem)?.DataContext as MainWindowViewModel;
156  
157              if (viewModel?.SelectedApplication != null)
158              {
159                  UserResult result = await ContentDialogHelper.CreateConfirmationDialog(
160                      LocaleManager.Instance[LocaleKeys.DialogWarning],
161                      LocaleManager.Instance.UpdateAndGetDynamicValue(LocaleKeys.DialogPPTCDeletionMessage, viewModel.SelectedApplication.Name),
162                      LocaleManager.Instance[LocaleKeys.InputDialogYes],
163                      LocaleManager.Instance[LocaleKeys.InputDialogNo],
164                      LocaleManager.Instance[LocaleKeys.RyujinxConfirm]);
165  
166                  if (result == UserResult.Yes)
167                  {
168                      DirectoryInfo mainDir = new(Path.Combine(AppDataManager.GamesDirPath, viewModel.SelectedApplication.IdString, "cache", "cpu", "0"));
169                      DirectoryInfo backupDir = new(Path.Combine(AppDataManager.GamesDirPath, viewModel.SelectedApplication.IdString, "cache", "cpu", "1"));
170  
171                      List<FileInfo> cacheFiles = new();
172  
173                      if (mainDir.Exists)
174                      {
175                          cacheFiles.AddRange(mainDir.EnumerateFiles("*.cache"));
176                      }
177  
178                      if (backupDir.Exists)
179                      {
180                          cacheFiles.AddRange(backupDir.EnumerateFiles("*.cache"));
181                      }
182  
183                      if (cacheFiles.Count > 0)
184                      {
185                          foreach (FileInfo file in cacheFiles)
186                          {
187                              try
188                              {
189                                  file.Delete();
190                              }
191                              catch (Exception ex)
192                              {
193                                  await ContentDialogHelper.CreateErrorDialog(LocaleManager.Instance.UpdateAndGetDynamicValue(LocaleKeys.DialogPPTCDeletionErrorMessage, file.Name, ex));
194                              }
195                          }
196                      }
197                  }
198              }
199          }
200  
201          public async void PurgeShaderCache_Click(object sender, RoutedEventArgs args)
202          {
203              var viewModel = (sender as MenuItem)?.DataContext as MainWindowViewModel;
204  
205              if (viewModel?.SelectedApplication != null)
206              {
207                  UserResult result = await ContentDialogHelper.CreateConfirmationDialog(
208                      LocaleManager.Instance[LocaleKeys.DialogWarning],
209                      LocaleManager.Instance.UpdateAndGetDynamicValue(LocaleKeys.DialogShaderDeletionMessage, viewModel.SelectedApplication.Name),
210                      LocaleManager.Instance[LocaleKeys.InputDialogYes],
211                      LocaleManager.Instance[LocaleKeys.InputDialogNo],
212                      LocaleManager.Instance[LocaleKeys.RyujinxConfirm]);
213  
214                  if (result == UserResult.Yes)
215                  {
216                      DirectoryInfo shaderCacheDir = new(Path.Combine(AppDataManager.GamesDirPath, viewModel.SelectedApplication.IdString, "cache", "shader"));
217  
218                      List<DirectoryInfo> oldCacheDirectories = new();
219                      List<FileInfo> newCacheFiles = new();
220  
221                      if (shaderCacheDir.Exists)
222                      {
223                          oldCacheDirectories.AddRange(shaderCacheDir.EnumerateDirectories("*"));
224                          newCacheFiles.AddRange(shaderCacheDir.GetFiles("*.toc"));
225                          newCacheFiles.AddRange(shaderCacheDir.GetFiles("*.data"));
226                      }
227  
228                      if ((oldCacheDirectories.Count > 0 || newCacheFiles.Count > 0))
229                      {
230                          foreach (DirectoryInfo directory in oldCacheDirectories)
231                          {
232                              try
233                              {
234                                  directory.Delete(true);
235                              }
236                              catch (Exception ex)
237                              {
238                                  await ContentDialogHelper.CreateErrorDialog(LocaleManager.Instance.UpdateAndGetDynamicValue(LocaleKeys.DialogPPTCDeletionErrorMessage, directory.Name, ex));
239                              }
240                          }
241  
242                          foreach (FileInfo file in newCacheFiles)
243                          {
244                              try
245                              {
246                                  file.Delete();
247                              }
248                              catch (Exception ex)
249                              {
250                                  await ContentDialogHelper.CreateErrorDialog(LocaleManager.Instance.UpdateAndGetDynamicValue(LocaleKeys.ShaderCachePurgeError, file.Name, ex));
251                              }
252                          }
253                      }
254                  }
255              }
256          }
257  
258          public void OpenPtcDirectory_Click(object sender, RoutedEventArgs args)
259          {
260              var viewModel = (sender as MenuItem)?.DataContext as MainWindowViewModel;
261  
262              if (viewModel?.SelectedApplication != null)
263              {
264                  string ptcDir = Path.Combine(AppDataManager.GamesDirPath, viewModel.SelectedApplication.IdString, "cache", "cpu");
265                  string mainDir = Path.Combine(ptcDir, "0");
266                  string backupDir = Path.Combine(ptcDir, "1");
267  
268                  if (!Directory.Exists(ptcDir))
269                  {
270                      Directory.CreateDirectory(ptcDir);
271                      Directory.CreateDirectory(mainDir);
272                      Directory.CreateDirectory(backupDir);
273                  }
274  
275                  OpenHelper.OpenFolder(ptcDir);
276              }
277          }
278  
279          public void OpenShaderCacheDirectory_Click(object sender, RoutedEventArgs args)
280          {
281              var viewModel = (sender as MenuItem)?.DataContext as MainWindowViewModel;
282  
283              if (viewModel?.SelectedApplication != null)
284              {
285                  string shaderCacheDir = Path.Combine(AppDataManager.GamesDirPath, viewModel.SelectedApplication.IdString, "cache", "shader");
286  
287                  if (!Directory.Exists(shaderCacheDir))
288                  {
289                      Directory.CreateDirectory(shaderCacheDir);
290                  }
291  
292                  OpenHelper.OpenFolder(shaderCacheDir);
293              }
294          }
295  
296          public async void ExtractApplicationExeFs_Click(object sender, RoutedEventArgs args)
297          {
298              var viewModel = (sender as MenuItem)?.DataContext as MainWindowViewModel;
299  
300              if (viewModel?.SelectedApplication != null)
301              {
302                  await ApplicationHelper.ExtractSection(
303                      viewModel.StorageProvider,
304                      NcaSectionType.Code,
305                      viewModel.SelectedApplication.Path,
306                      viewModel.SelectedApplication.Name);
307              }
308          }
309  
310          public async void ExtractApplicationRomFs_Click(object sender, RoutedEventArgs args)
311          {
312              var viewModel = (sender as MenuItem)?.DataContext as MainWindowViewModel;
313  
314              if (viewModel?.SelectedApplication != null)
315              {
316                  await ApplicationHelper.ExtractSection(
317                      viewModel.StorageProvider,
318                      NcaSectionType.Data,
319                      viewModel.SelectedApplication.Path,
320                      viewModel.SelectedApplication.Name);
321              }
322          }
323  
324          public async void ExtractApplicationLogo_Click(object sender, RoutedEventArgs args)
325          {
326              var viewModel = (sender as MenuItem)?.DataContext as MainWindowViewModel;
327  
328              if (viewModel?.SelectedApplication != null)
329              {
330                  await ApplicationHelper.ExtractSection(
331                      viewModel.StorageProvider,
332                      NcaSectionType.Logo,
333                      viewModel.SelectedApplication.Path,
334                      viewModel.SelectedApplication.Name);
335              }
336          }
337  
338          public void CreateApplicationShortcut_Click(object sender, RoutedEventArgs args)
339          {
340              var viewModel = (sender as MenuItem)?.DataContext as MainWindowViewModel;
341  
342              if (viewModel?.SelectedApplication != null)
343              {
344                  ApplicationData selectedApplication = viewModel.SelectedApplication;
345                  ShortcutHelper.CreateAppShortcut(selectedApplication.Path, selectedApplication.Name, selectedApplication.IdString, selectedApplication.Icon);
346              }
347          }
348  
349          public async void RunApplication_Click(object sender, RoutedEventArgs args)
350          {
351              var viewModel = (sender as MenuItem)?.DataContext as MainWindowViewModel;
352  
353              if (viewModel?.SelectedApplication != null)
354              {
355                  await viewModel.LoadApplication(viewModel.SelectedApplication);
356              }
357          }
358      }
359  }