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 }