mirror of
https://git.ryujinx.app/ryubing/ryujinx.git
synced 2025-06-07 08:57:13 +00:00
misc: Swap the context menu actions to Commands
This commit is contained in:
parent
9233fe86b0
commit
960421a7c1
@ -6,140 +6,166 @@
|
||||
xmlns:viewModels="clr-namespace:Ryujinx.Ava.UI.ViewModels"
|
||||
x:DataType="viewModels:MainWindowViewModel">
|
||||
<MenuItem
|
||||
Click="RunApplication_Click"
|
||||
Command="{Binding RunApplication}"
|
||||
CommandParameter="{Binding}"
|
||||
Header="{ext:Locale GameListContextMenuRunApplication}"
|
||||
Icon="{ext:Icon fa-solid fa-play}"/>
|
||||
<MenuItem
|
||||
Click="ToggleFavorite_Click"
|
||||
Command="{Binding ToggleFavorite}"
|
||||
CommandParameter="{Binding}"
|
||||
Header="{ext:Locale GameListContextMenuToggleFavorite}"
|
||||
Icon="{ext:Icon fa-solid fa-star}"
|
||||
ToolTip.Tip="{ext:Locale GameListContextMenuToggleFavoriteToolTip}" />
|
||||
<MenuItem
|
||||
Click="CreateApplicationShortcut_Click"
|
||||
Command="{Binding CreateApplicationShortcut}"
|
||||
CommandParameter="{Binding}"
|
||||
Header="{ext:Locale GameListContextMenuCreateShortcut}"
|
||||
Icon="{ext:Icon fa-solid fa-bookmark}"
|
||||
ToolTip.Tip="{OnPlatform Default={ext:Locale GameListContextMenuCreateShortcutToolTip}, macOS={ext:Locale GameListContextMenuCreateShortcutToolTipMacOS}}" />
|
||||
<MenuItem
|
||||
Click="EditGameConfiguration_Click"
|
||||
Command="{Binding EditGameConfiguration}"
|
||||
CommandParameter="{Binding}"
|
||||
IsVisible="{Binding SelectedApplication.HasIndependentConfiguration}"
|
||||
Header="{ext:Locale GameListContextMenuEditCustomConfiguration}"
|
||||
Icon="{ext:Icon fa-solid fa-gear}"
|
||||
ToolTip.Tip="{ext:Locale EditCustomConfigurationToolTip}" />
|
||||
<MenuItem
|
||||
Click="EditGameConfiguration_Click"
|
||||
Command="{Binding EditGameConfiguration}"
|
||||
CommandParameter="{Binding}"
|
||||
IsVisible="{Binding !SelectedApplication.HasIndependentConfiguration}"
|
||||
Header="{ext:Locale GameListContextMenuCreateCustomConfiguration}"
|
||||
Icon="{ext:Icon fa-solid fa-gear}"
|
||||
ToolTip.Tip="{ext:Locale CreateCustomConfigurationToolTip}" />
|
||||
<MenuItem
|
||||
IsVisible="{Binding HasCompatibilityEntry}"
|
||||
Click="OpenApplicationCompatibility_Click"
|
||||
Command="{Binding OpenApplicationCompatibility}"
|
||||
CommandParameter="{Binding}"
|
||||
Header="{ext:Locale GameListContextMenuShowCompatEntry}"
|
||||
Icon="{ext:Icon mdi-gamepad}"
|
||||
ToolTip.Tip="{ext:Locale GameListContextMenuShowCompatEntryToolTip}"/>
|
||||
<MenuItem
|
||||
Click="OpenApplicationData_Click"
|
||||
Command="{Binding OpenApplicationData}"
|
||||
CommandParameter="{Binding}"
|
||||
Header="{ext:Locale GameListContextMenuShowGameData}"
|
||||
Icon="{ext:Icon mdi-chart-line}"
|
||||
ToolTip.Tip="{ext:Locale GameListContextMenuShowGameDataToolTip}"/>
|
||||
<Separator />
|
||||
<MenuItem
|
||||
Click="OpenUserSaveDirectory_Click"
|
||||
Command="{Binding OpenUserSaveDirectory}"
|
||||
CommandParameter="{Binding}"
|
||||
Header="{ext:Locale GameListContextMenuOpenUserSaveDirectory}"
|
||||
Icon="{ext:Icon mdi-folder-account}"
|
||||
IsEnabled="{Binding OpenUserSaveDirectoryEnabled}"
|
||||
ToolTip.Tip="{ext:Locale GameListContextMenuOpenUserSaveDirectoryToolTip}" />
|
||||
<MenuItem
|
||||
Click="OpenDeviceSaveDirectory_Click"
|
||||
Command="{Binding OpenDeviceSaveDirectory}"
|
||||
CommandParameter="{Binding}"
|
||||
Header="{ext:Locale GameListContextMenuOpenDeviceSaveDirectory}"
|
||||
IsEnabled="{Binding OpenDeviceSaveDirectoryEnabled}"
|
||||
ToolTip.Tip="{ext:Locale GameListContextMenuOpenDeviceSaveDirectoryToolTip}" />
|
||||
<MenuItem
|
||||
Click="OpenBcatSaveDirectory_Click"
|
||||
Command="{Binding OpenBcatSaveDirectory}"
|
||||
CommandParameter="{Binding}"
|
||||
Header="{ext:Locale GameListContextMenuOpenBcatSaveDirectory}"
|
||||
IsEnabled="{Binding OpenBcatSaveDirectoryEnabled}"
|
||||
ToolTip.Tip="{ext:Locale GameListContextMenuOpenBcatSaveDirectoryToolTip}" />
|
||||
<Separator />
|
||||
<MenuItem
|
||||
Click="OpenTitleUpdateManager_Click"
|
||||
Command="{Binding OpenTitleUpdateManager}"
|
||||
CommandParameter="{Binding}"
|
||||
Header="{ext:Locale GameListContextMenuManageTitleUpdates}"
|
||||
Icon="{ext:Icon fa-solid fa-code-compare}"
|
||||
ToolTip.Tip="{ext:Locale GameListContextMenuManageTitleUpdatesToolTip}" />
|
||||
<MenuItem
|
||||
Click="OpenDownloadableContentManager_Click"
|
||||
Command="{Binding OpenDownloadableContentManager}"
|
||||
CommandParameter="{Binding}"
|
||||
Header="{ext:Locale GameListContextMenuManageDlc}"
|
||||
Icon="{ext:Icon fa-solid fa-download}"
|
||||
ToolTip.Tip="{ext:Locale GameListContextMenuManageDlcToolTip}" />
|
||||
<MenuItem
|
||||
Click="OpenCheatManager_Click"
|
||||
Command="{Binding OpenCheatManager}"
|
||||
CommandParameter="{Binding}"
|
||||
Header="{ext:Locale GameListContextMenuManageCheat}"
|
||||
Icon="{ext:Icon fa-solid fa-code}"
|
||||
ToolTip.Tip="{ext:Locale GameListContextMenuManageCheatToolTip}" />
|
||||
<MenuItem
|
||||
Click="OpenModManager_Click"
|
||||
Command="{Binding OpenModManager}"
|
||||
CommandParameter="{Binding}"
|
||||
Header="{ext:Locale GameListContextMenuManageMod}"
|
||||
Icon="{ext:Icon mdi-view-module}"
|
||||
ToolTip.Tip="{ext:Locale GameListContextMenuManageModToolTip}" />
|
||||
<Separator />
|
||||
<MenuItem
|
||||
Click="OpenModsDirectory_Click"
|
||||
Command="{Binding OpenModsDirectory}"
|
||||
CommandParameter="{Binding}"
|
||||
Header="{ext:Locale GameListContextMenuOpenModsDirectory}"
|
||||
Icon="{ext:Icon mdi-folder-file}"
|
||||
ToolTip.Tip="{ext:Locale GameListContextMenuOpenModsDirectoryToolTip}" />
|
||||
<MenuItem
|
||||
Click="OpenSdModsDirectory_Click"
|
||||
Command="{Binding OpenSdModsDirectory}"
|
||||
CommandParameter="{Binding}"
|
||||
Header="{ext:Locale GameListContextMenuOpenSdModsDirectory}"
|
||||
Icon="{ext:Icon mdi-folder-file}"
|
||||
ToolTip.Tip="{ext:Locale GameListContextMenuOpenSdModsDirectoryToolTip}" />
|
||||
<Separator />
|
||||
<MenuItem
|
||||
Click="TrimXCI_Click"
|
||||
Command="{Binding TrimXci}"
|
||||
CommandParameter="{Binding}"
|
||||
Header="{ext:Locale GameListContextMenuTrimXCI}"
|
||||
IsEnabled="{Binding TrimXCIEnabled}"
|
||||
ToolTip.Tip="{ext:Locale GameListContextMenuTrimXCIToolTip}" />
|
||||
<MenuItem Header="{ext:Locale GameListContextMenuCacheManagement}" Icon="{ext:Icon mdi-cached}">
|
||||
<MenuItem
|
||||
Click="PurgePtcCache_Click"
|
||||
Command="{Binding PurgePtcCache}"
|
||||
CommandParameter="{Binding}"
|
||||
Header="{ext:Locale GameListContextMenuCacheManagementPurgePptc}"
|
||||
Icon="{ext:Icon mdi-refresh}"
|
||||
ToolTip.Tip="{ext:Locale GameListContextMenuCacheManagementPurgePptcToolTip}" />
|
||||
<MenuItem
|
||||
Click="NukePtcCache_Click"
|
||||
Command="{Binding NukePtcCache}"
|
||||
CommandParameter="{Binding}"
|
||||
Header="{ext:Locale GameListContextMenuCacheManagementNukePptc}"
|
||||
Icon="{ext:Icon mdi-delete-alert}"
|
||||
ToolTip.Tip="{ext:Locale GameListContextMenuCacheManagementNukePptcToolTip}" />
|
||||
<MenuItem
|
||||
Click="PurgeShaderCache_Click"
|
||||
Command="{Binding PurgeShaderCache}"
|
||||
CommandParameter="{Binding}"
|
||||
Header="{ext:Locale GameListContextMenuCacheManagementPurgeShaderCache}"
|
||||
Icon="{ext:Icon mdi-delete-alert}"
|
||||
ToolTip.Tip="{ext:Locale GameListContextMenuCacheManagementPurgeShaderCacheToolTip}" />
|
||||
<MenuItem
|
||||
Click="OpenPtcDirectory_Click"
|
||||
Command="{Binding OpenPtcDirectory}"
|
||||
CommandParameter="{Binding}"
|
||||
Header="{ext:Locale GameListContextMenuCacheManagementOpenPptcDirectory}"
|
||||
Icon="{ext:Icon mdi-folder-arrow-up-down}"
|
||||
ToolTip.Tip="{ext:Locale GameListContextMenuCacheManagementOpenPptcDirectoryToolTip}" />
|
||||
<MenuItem
|
||||
Click="OpenShaderCacheDirectory_Click"
|
||||
Command="{Binding OpenShaderCacheDirectory}"
|
||||
CommandParameter="{Binding}"
|
||||
Header="{ext:Locale GameListContextMenuCacheManagementOpenShaderCacheDirectory}"
|
||||
Icon="{ext:Icon mdi-folder-arrow-up-down}"
|
||||
ToolTip.Tip="{ext:Locale GameListContextMenuCacheManagementOpenShaderCacheDirectoryToolTip}" />
|
||||
</MenuItem>
|
||||
<MenuItem Header="{ext:Locale GameListContextMenuExtractData}">
|
||||
<MenuItem
|
||||
Click="ExtractApplicationExeFs_Click"
|
||||
Command="{Binding ExtractApplicationExeFs}"
|
||||
CommandParameter="{Binding}"
|
||||
Header="{ext:Locale GameListContextMenuExtractDataExeFS}"
|
||||
ToolTip.Tip="{ext:Locale GameListContextMenuExtractDataExeFSToolTip}" />
|
||||
<MenuItem
|
||||
Click="ExtractApplicationRomFs_Click"
|
||||
Command="{Binding ExtractApplicationRomFs}"
|
||||
CommandParameter="{Binding}"
|
||||
Header="{ext:Locale GameListContextMenuExtractDataRomFS}"
|
||||
ToolTip.Tip="{ext:Locale GameListContextMenuExtractDataRomFSToolTip}" />
|
||||
<MenuItem
|
||||
IsVisible="{Binding HasDlc}"
|
||||
Click="ExtractAocRomFs_Click"
|
||||
Command="{Binding ExtractApplicationAocRomFs}"
|
||||
CommandParameter="{Binding}"
|
||||
Header="{ext:Locale GameListContextMenuExtractDataAocRomFS}"
|
||||
ToolTip.Tip="{ext:Locale GameListContextMenuExtractDataAocRomFSToolTip}" />
|
||||
<MenuItem
|
||||
Click="ExtractApplicationLogo_Click"
|
||||
Command="{Binding ExtractApplicationLogo}"
|
||||
CommandParameter="{Binding}"
|
||||
Header="{ext:Locale GameListContextMenuExtractDataLogo}"
|
||||
ToolTip.Tip="{ext:Locale GameListContextMenuExtractDataLogoToolTip}" />
|
||||
</MenuItem>
|
||||
|
@ -1,7 +1,7 @@
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Interactivity;
|
||||
using Avalonia.Markup.Xaml;
|
||||
using Avalonia.Platform.Storage;
|
||||
using CommunityToolkit.Mvvm.Input;
|
||||
using LibHac.Fs;
|
||||
using LibHac.Tools.FsSystem.NcaUtils;
|
||||
using Ryujinx.Ava.Common;
|
||||
@ -26,7 +26,6 @@ namespace Ryujinx.Ava.UI.Controls
|
||||
{
|
||||
public class ApplicationContextMenu : MenuFlyout
|
||||
{
|
||||
|
||||
public ApplicationContextMenu()
|
||||
{
|
||||
InitializeComponent();
|
||||
@ -36,39 +35,35 @@ namespace Ryujinx.Ava.UI.Controls
|
||||
{
|
||||
AvaloniaXamlLoader.Load(this);
|
||||
}
|
||||
|
||||
public static RelayCommand<MainWindowViewModel> ToggleFavorite { get; } =
|
||||
Commands.CreateConditional<MainWindowViewModel>(vm => vm?.SelectedApplication != null,
|
||||
viewModel =>
|
||||
{
|
||||
viewModel.SelectedApplication.Favorite = !viewModel.SelectedApplication.Favorite;
|
||||
|
||||
public void ToggleFavorite_Click(object sender, RoutedEventArgs args)
|
||||
{
|
||||
if (sender is not MenuItem { DataContext: MainWindowViewModel { SelectedApplication: not null } viewModel })
|
||||
return;
|
||||
ApplicationLibrary.LoadAndSaveMetaData(viewModel.SelectedApplication.IdString, appMetadata =>
|
||||
{
|
||||
appMetadata.Favorite = viewModel.SelectedApplication.Favorite;
|
||||
});
|
||||
|
||||
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);
|
||||
}
|
||||
viewModel.RefreshView();
|
||||
}
|
||||
);
|
||||
|
||||
public static RelayCommand<MainWindowViewModel> OpenUserSaveDirectory { get; } =
|
||||
Commands.CreateConditional<MainWindowViewModel>(vm => vm?.SelectedApplication != null,
|
||||
viewModel =>
|
||||
OpenSaveDirectory(viewModel, SaveDataType.Account, new UserId((ulong)viewModel.AccountManager.LastOpenedUser.UserId.High, (ulong)viewModel.AccountManager.LastOpenedUser.UserId.Low))
|
||||
);
|
||||
|
||||
public static RelayCommand<MainWindowViewModel> OpenDeviceSaveDirectory { get; } =
|
||||
Commands.CreateConditional<MainWindowViewModel>(vm => vm?.SelectedApplication != null,
|
||||
viewModel => OpenSaveDirectory(viewModel, SaveDataType.Device, default));
|
||||
|
||||
public static RelayCommand<MainWindowViewModel> OpenBcatSaveDirectory { get; } =
|
||||
Commands.CreateConditional<MainWindowViewModel>(vm => vm?.SelectedApplication != null,
|
||||
viewModel => OpenSaveDirectory(viewModel, SaveDataType.Bcat, default));
|
||||
|
||||
private static void OpenSaveDirectory(MainWindowViewModel viewModel, SaveDataType saveDataType, UserId userId)
|
||||
{
|
||||
@ -76,159 +71,151 @@ namespace Ryujinx.Ava.UI.Controls
|
||||
|
||||
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 TitleUpdateManagerView.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 DownloadableContentManagerView.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(
|
||||
|
||||
public static AsyncRelayCommand<MainWindowViewModel> OpenTitleUpdateManager { get; } =
|
||||
Commands.CreateConditional<MainWindowViewModel>(vm => vm?.SelectedApplication != null,
|
||||
viewModel => TitleUpdateManagerView.Show(viewModel.ApplicationLibrary, viewModel.SelectedApplication)
|
||||
);
|
||||
|
||||
public static AsyncRelayCommand<MainWindowViewModel> OpenDownloadableContentManager { get; } =
|
||||
Commands.CreateConditional<MainWindowViewModel>(vm => vm?.SelectedApplication != null,
|
||||
viewModel => DownloadableContentManagerView.Show(viewModel.ApplicationLibrary, viewModel.SelectedApplication)
|
||||
);
|
||||
|
||||
public static AsyncRelayCommand<MainWindowViewModel> OpenCheatManager { get; } =
|
||||
Commands.CreateConditional<MainWindowViewModel>(vm => vm?.SelectedApplication != null,
|
||||
viewModel => StyleableAppWindow.ShowAsync(
|
||||
new CheatWindow(
|
||||
viewModel.VirtualFileSystem,
|
||||
viewModel.SelectedApplication.IdString,
|
||||
viewModel.SelectedApplication.Name,
|
||||
viewModel.SelectedApplication.Path
|
||||
)
|
||||
);
|
||||
}
|
||||
));
|
||||
|
||||
public static RelayCommand<MainWindowViewModel> OpenModsDirectory { get; } =
|
||||
Commands.CreateConditional<MainWindowViewModel>(vm => vm?.SelectedApplication != null,
|
||||
viewModel =>
|
||||
{
|
||||
string modsBasePath = ModLoader.GetModsBasePath();
|
||||
string titleModsPath = ModLoader.GetApplicationDir(modsBasePath, viewModel.SelectedApplication.IdString);
|
||||
|
||||
public void OpenModsDirectory_Click(object sender, RoutedEventArgs args)
|
||||
{
|
||||
if (sender is not MenuItem { DataContext: MainWindowViewModel { SelectedApplication: not null } viewModel })
|
||||
return;
|
||||
OpenHelper.OpenFolder(titleModsPath);
|
||||
});
|
||||
|
||||
public static RelayCommand<MainWindowViewModel> OpenSdModsDirectory { get; } =
|
||||
Commands.CreateConditional<MainWindowViewModel>(vm => vm?.SelectedApplication != null,
|
||||
viewModel =>
|
||||
{
|
||||
string sdModsBasePath = ModLoader.GetSdModsBasePath();
|
||||
string titleModsPath = ModLoader.GetApplicationDir(sdModsBasePath, viewModel.SelectedApplication.IdString);
|
||||
|
||||
string modsBasePath = ModLoader.GetModsBasePath();
|
||||
string titleModsPath = ModLoader.GetApplicationDir(modsBasePath, viewModel.SelectedApplication.IdString);
|
||||
OpenHelper.OpenFolder(titleModsPath);
|
||||
});
|
||||
|
||||
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 })
|
||||
public static AsyncRelayCommand<MainWindowViewModel> OpenModManager { get; } =
|
||||
Commands.CreateConditional<MainWindowViewModel>(vm => vm?.SelectedApplication != null,
|
||||
async viewModel =>
|
||||
{
|
||||
await ModManagerView.Show(
|
||||
viewModel.SelectedApplication.Id,
|
||||
viewModel.SelectedApplication.IdBase,
|
||||
viewModel.ApplicationLibrary,
|
||||
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)
|
||||
});
|
||||
|
||||
public static AsyncRelayCommand<MainWindowViewModel> PurgePtcCache { get; } =
|
||||
Commands.CreateConditional<MainWindowViewModel>(vm => vm?.SelectedApplication != null,
|
||||
async viewModel =>
|
||||
{
|
||||
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"));
|
||||
UserResult result = await ContentDialogHelper.CreateLocalizedConfirmationDialog(
|
||||
LocaleManager.Instance[LocaleKeys.DialogWarning],
|
||||
LocaleManager.Instance.UpdateAndGetDynamicValue(LocaleKeys.DialogPPTCDeletionMessage, viewModel.SelectedApplication.Name)
|
||||
);
|
||||
|
||||
List<FileInfo> cacheFiles = [];
|
||||
|
||||
if (mainDir.Exists)
|
||||
if (result == UserResult.Yes)
|
||||
{
|
||||
cacheFiles.AddRange(mainDir.EnumerateFiles("*.cache"));
|
||||
}
|
||||
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"));
|
||||
|
||||
if (backupDir.Exists)
|
||||
{
|
||||
cacheFiles.AddRange(backupDir.EnumerateFiles("*.cache"));
|
||||
}
|
||||
List<FileInfo> cacheFiles = [];
|
||||
|
||||
if (cacheFiles.Count > 0)
|
||||
{
|
||||
foreach (FileInfo file in cacheFiles)
|
||||
if (mainDir.Exists)
|
||||
{
|
||||
try
|
||||
cacheFiles.AddRange(mainDir.EnumerateFiles("*.cache"));
|
||||
}
|
||||
|
||||
if (backupDir.Exists)
|
||||
{
|
||||
cacheFiles.AddRange(backupDir.EnumerateFiles("*.cache"));
|
||||
}
|
||||
|
||||
if (cacheFiles.Count > 0)
|
||||
{
|
||||
foreach (FileInfo file in cacheFiles)
|
||||
{
|
||||
file.Delete();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await ContentDialogHelper.CreateErrorDialog(LocaleManager.Instance.UpdateAndGetDynamicValue(LocaleKeys.DialogPPTCDeletionErrorMessage, file.Name, ex));
|
||||
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)
|
||||
});
|
||||
|
||||
public static AsyncRelayCommand<MainWindowViewModel> NukePtcCache { get; } =
|
||||
Commands.CreateConditional<MainWindowViewModel>(vm => vm?.SelectedApplication != null,
|
||||
async viewModel =>
|
||||
{
|
||||
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"));
|
||||
UserResult result = await ContentDialogHelper.CreateLocalizedConfirmationDialog(
|
||||
LocaleManager.Instance[LocaleKeys.DialogWarning],
|
||||
LocaleManager.Instance.UpdateAndGetDynamicValue(LocaleKeys.DialogPPTCNukeMessage, viewModel.SelectedApplication.Name)
|
||||
);
|
||||
|
||||
List<FileInfo> cacheFiles = [];
|
||||
|
||||
if (mainDir.Exists)
|
||||
if (result == UserResult.Yes)
|
||||
{
|
||||
cacheFiles.AddRange(mainDir.EnumerateFiles("*.cache"));
|
||||
cacheFiles.AddRange(mainDir.EnumerateFiles("*.info"));
|
||||
}
|
||||
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"));
|
||||
|
||||
if (backupDir.Exists)
|
||||
{
|
||||
cacheFiles.AddRange(backupDir.EnumerateFiles("*.cache"));
|
||||
cacheFiles.AddRange(backupDir.EnumerateFiles("*.info"));
|
||||
}
|
||||
List<FileInfo> cacheFiles = [];
|
||||
|
||||
if (cacheFiles.Count > 0)
|
||||
{
|
||||
foreach (FileInfo file in cacheFiles)
|
||||
if (mainDir.Exists)
|
||||
{
|
||||
try
|
||||
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)
|
||||
{
|
||||
file.Delete();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await ContentDialogHelper.CreateErrorDialog(LocaleManager.Instance.UpdateAndGetDynamicValue(LocaleKeys.DialogPPTCDeletionErrorMessage, file.Name, ex));
|
||||
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;
|
||||
|
||||
});
|
||||
|
||||
public static AsyncRelayCommand<MainWindowViewModel> PurgeShaderCache { get; } =
|
||||
Commands.CreateConditional<MainWindowViewModel>(vm => vm?.SelectedApplication != null,
|
||||
async viewModel =>
|
||||
{
|
||||
UserResult result = await ContentDialogHelper.CreateLocalizedConfirmationDialog(
|
||||
LocaleManager.Instance[LocaleKeys.DialogWarning],
|
||||
LocaleManager.Instance.UpdateAndGetDynamicValue(LocaleKeys.DialogShaderDeletionMessage, viewModel.SelectedApplication.Name)
|
||||
@ -274,158 +261,143 @@ namespace Ryujinx.Ava.UI.Controls
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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))
|
||||
}
|
||||
});
|
||||
|
||||
public static RelayCommand<MainWindowViewModel> OpenPtcDirectory { get; } =
|
||||
Commands.CreateConditional<MainWindowViewModel>(vm => vm?.SelectedApplication != null,
|
||||
viewModel =>
|
||||
{
|
||||
Directory.CreateDirectory(ptcDir);
|
||||
Directory.CreateDirectory(mainDir);
|
||||
Directory.CreateDirectory(backupDir);
|
||||
}
|
||||
string ptcDir = Path.Combine(AppDataManager.GamesDirPath, viewModel.SelectedApplication.IdString, "cache", "cpu");
|
||||
string mainDir = Path.Combine(ptcDir, "0");
|
||||
string backupDir = Path.Combine(ptcDir, "1");
|
||||
|
||||
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))
|
||||
if (!Directory.Exists(ptcDir))
|
||||
{
|
||||
Directory.CreateDirectory(shaderCacheDir);
|
||||
Directory.CreateDirectory(ptcDir);
|
||||
Directory.CreateDirectory(mainDir);
|
||||
Directory.CreateDirectory(backupDir);
|
||||
}
|
||||
|
||||
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,
|
||||
OpenHelper.OpenFolder(ptcDir);
|
||||
});
|
||||
|
||||
public static RelayCommand<MainWindowViewModel> OpenShaderCacheDirectory { get; } =
|
||||
Commands.CreateConditional<MainWindowViewModel>(vm => vm?.SelectedApplication != null,
|
||||
viewModel =>
|
||||
{
|
||||
string shaderCacheDir = Path.Combine(AppDataManager.GamesDirPath, viewModel.SelectedApplication.IdString.ToLower(), "cache", "shader");
|
||||
|
||||
if (result.Count == 0)
|
||||
return;
|
||||
if (!Directory.Exists(shaderCacheDir))
|
||||
{
|
||||
Directory.CreateDirectory(shaderCacheDir);
|
||||
}
|
||||
|
||||
ApplicationHelper.ExtractSection(
|
||||
result[0].Path.LocalPath,
|
||||
NcaSectionType.Logo,
|
||||
viewModel.SelectedApplication.Path,
|
||||
viewModel.SelectedApplication.Name);
|
||||
OpenHelper.OpenFolder(shaderCacheDir);
|
||||
});
|
||||
|
||||
public static AsyncRelayCommand<MainWindowViewModel> ExtractApplicationExeFs { get; } =
|
||||
Commands.CreateConditional<MainWindowViewModel>(vm => vm?.SelectedApplication != null,
|
||||
async viewModel =>
|
||||
{
|
||||
await ApplicationHelper.ExtractSection(
|
||||
viewModel.StorageProvider,
|
||||
NcaSectionType.Code,
|
||||
viewModel.SelectedApplication.Path,
|
||||
viewModel.SelectedApplication.Name);
|
||||
});
|
||||
|
||||
public static AsyncRelayCommand<MainWindowViewModel> ExtractApplicationRomFs { get; } =
|
||||
Commands.CreateConditional<MainWindowViewModel>(vm => vm?.SelectedApplication != null,
|
||||
async viewModel =>
|
||||
{
|
||||
await ApplicationHelper.ExtractSection(
|
||||
viewModel.StorageProvider,
|
||||
NcaSectionType.Data,
|
||||
viewModel.SelectedApplication.Path,
|
||||
viewModel.SelectedApplication.Name);
|
||||
});
|
||||
|
||||
public static AsyncRelayCommand<MainWindowViewModel> ExtractApplicationAocRomFs { get; } =
|
||||
Commands.CreateConditional<MainWindowViewModel>(vm => vm?.SelectedApplication != null,
|
||||
async viewModel =>
|
||||
{
|
||||
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 static AsyncRelayCommand<MainWindowViewModel> ExtractApplicationLogo { get; } =
|
||||
Commands.CreateConditional<MainWindowViewModel>(vm => vm?.SelectedApplication != null,
|
||||
async viewModel =>
|
||||
{
|
||||
IReadOnlyList<IStorageFolder> result = await viewModel.StorageProvider.OpenFolderPickerAsync(new FolderPickerOpenOptions
|
||||
{
|
||||
Title = LocaleManager.Instance[LocaleKeys.FolderDialogExtractTitle],
|
||||
AllowMultiple = false,
|
||||
});
|
||||
|
||||
IStorageFile iconFile = await result[0].CreateFileAsync($"{viewModel.SelectedApplication.IdString}.png");
|
||||
await using Stream fileStream = await iconFile.OpenWriteAsync();
|
||||
if (result.Count == 0)
|
||||
return;
|
||||
|
||||
using SKBitmap bitmap = SKBitmap.Decode(viewModel.SelectedApplication.Icon)
|
||||
.Resize(new SKSizeI(512, 512), SKFilterQuality.High);
|
||||
ApplicationHelper.ExtractSection(
|
||||
result[0].Path.LocalPath,
|
||||
NcaSectionType.Logo,
|
||||
viewModel.SelectedApplication.Path,
|
||||
viewModel.SelectedApplication.Name);
|
||||
|
||||
using SKData png = bitmap.Encode(SKEncodedImageFormat.Png, 100);
|
||||
IStorageFile iconFile = await result[0].CreateFileAsync($"{viewModel.SelectedApplication.IdString}.png");
|
||||
await using Stream fileStream = await iconFile.OpenWriteAsync();
|
||||
|
||||
png.SaveTo(fileStream);
|
||||
}
|
||||
using SKBitmap bitmap = SKBitmap.Decode(viewModel.SelectedApplication.Icon)
|
||||
.Resize(new SKSizeI(512, 512), SKFilterQuality.High);
|
||||
|
||||
public void CreateApplicationShortcut_Click(object sender, RoutedEventArgs args)
|
||||
{
|
||||
if (sender is MenuItem { DataContext: MainWindowViewModel { SelectedApplication: not null } viewModel })
|
||||
ShortcutHelper.CreateAppShortcut(
|
||||
using SKData png = bitmap.Encode(SKEncodedImageFormat.Png, 100);
|
||||
|
||||
png.SaveTo(fileStream);
|
||||
});
|
||||
|
||||
public static RelayCommand<MainWindowViewModel> CreateApplicationShortcut { get; } =
|
||||
Commands.CreateConditional<MainWindowViewModel>(vm => vm?.SelectedApplication != null,
|
||||
viewModel => ShortcutHelper.CreateAppShortcut(
|
||||
viewModel.SelectedApplication.Path,
|
||||
viewModel.SelectedApplication.Name,
|
||||
viewModel.SelectedApplication.IdString,
|
||||
viewModel.SelectedApplication.Icon
|
||||
);
|
||||
}
|
||||
));
|
||||
|
||||
public static AsyncRelayCommand<MainWindowViewModel> EditGameConfiguration { get; } =
|
||||
Commands.CreateConditional<MainWindowViewModel>(vm => vm?.SelectedApplication != null,
|
||||
async viewModel =>
|
||||
{
|
||||
await StyleableAppWindow.ShowAsync(new GameSpecificSettingsWindow(viewModel));
|
||||
|
||||
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));
|
||||
|
||||
// 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 CompatibilityListWindow.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);
|
||||
}
|
||||
viewModel.RefreshView();
|
||||
});
|
||||
|
||||
public static AsyncRelayCommand<MainWindowViewModel> OpenApplicationCompatibility { get; } =
|
||||
Commands.CreateConditional<MainWindowViewModel>(vm => vm?.SelectedApplication != null,
|
||||
viewModel => CompatibilityListWindow.Show(viewModel.SelectedApplication.IdString));
|
||||
|
||||
public static AsyncRelayCommand<MainWindowViewModel> OpenApplicationData { get; } =
|
||||
Commands.CreateConditional<MainWindowViewModel>(vm => vm?.SelectedApplication != null,
|
||||
viewModel => ApplicationDataView.Show(viewModel.SelectedApplication));
|
||||
|
||||
public static AsyncRelayCommand<MainWindowViewModel> RunApplication { get; } =
|
||||
Commands.CreateConditional<MainWindowViewModel>(vm => vm?.SelectedApplication != null,
|
||||
viewModel => viewModel.LoadApplication(viewModel.SelectedApplication));
|
||||
|
||||
public static AsyncRelayCommand<MainWindowViewModel> TrimXci { get; } =
|
||||
Commands.CreateConditional<MainWindowViewModel>(vm => vm?.SelectedApplication != null,
|
||||
viewModel => viewModel.TrimXCIFile(viewModel.SelectedApplication.Path));
|
||||
}
|
||||
}
|
||||
|
@ -9,12 +9,12 @@ namespace Ryujinx.Ava.UI.Helpers
|
||||
{
|
||||
public static RelayCommand Create(Action action)
|
||||
=> new(action);
|
||||
public static RelayCommand CreateConditional(Action action, Func<bool> canExecute)
|
||||
public static RelayCommand CreateConditional(Func<bool> canExecute, Action action)
|
||||
=> new(action, canExecute);
|
||||
|
||||
public static RelayCommand<T> Create<T>(Action<T?> action)
|
||||
=> new(action);
|
||||
public static RelayCommand<T> CreateConditional<T>(Action<T?> action, Predicate<T?> canExecute)
|
||||
public static RelayCommand<T> CreateConditional<T>(Predicate<T?> canExecute, Action<T?> action)
|
||||
=> new(action, canExecute);
|
||||
|
||||
public static AsyncRelayCommand Create(Func<Task> action)
|
||||
@ -31,18 +31,18 @@ namespace Ryujinx.Ava.UI.Helpers
|
||||
public static AsyncRelayCommand<T> CreateSilentFail<T>(Func<T?, Task> action)
|
||||
=> new(action, AsyncRelayCommandOptions.FlowExceptionsToTaskScheduler);
|
||||
|
||||
public static AsyncRelayCommand CreateConditional(Func<Task> action, Func<bool> canExecute)
|
||||
public static AsyncRelayCommand CreateConditional(Func<bool> canExecute, Func<Task> action)
|
||||
=> new(action, canExecute, AsyncRelayCommandOptions.None);
|
||||
public static AsyncRelayCommand CreateConcurrentConditional(Func<Task> action, Func<bool> canExecute)
|
||||
public static AsyncRelayCommand CreateConcurrentConditional(Func<bool> canExecute, Func<Task> action)
|
||||
=> new(action, canExecute, AsyncRelayCommandOptions.AllowConcurrentExecutions);
|
||||
public static AsyncRelayCommand CreateSilentFailConditional(Func<Task> action, Func<bool> canExecute)
|
||||
public static AsyncRelayCommand CreateSilentFailConditional(Func<bool> canExecute, Func<Task> action)
|
||||
=> new(action, canExecute, AsyncRelayCommandOptions.FlowExceptionsToTaskScheduler);
|
||||
|
||||
public static AsyncRelayCommand<T> CreateConditional<T>(Func<T?, Task> action, Predicate<T?> canExecute)
|
||||
public static AsyncRelayCommand<T> CreateConditional<T>(Predicate<T?> canExecute, Func<T?, Task> action)
|
||||
=> new(action, canExecute, AsyncRelayCommandOptions.None);
|
||||
public static AsyncRelayCommand<T> CreateConcurrentConditional<T>(Func<T?, Task> action, Predicate<T?> canExecute)
|
||||
public static AsyncRelayCommand<T> CreateConcurrentConditional<T>(Predicate<T?> canExecute, Func<T?, Task> action)
|
||||
=> new(action, canExecute, AsyncRelayCommandOptions.AllowConcurrentExecutions);
|
||||
public static AsyncRelayCommand<T> CreateSilentFailConditional<T>(Func<T?, Task> action, Predicate<T?> canExecute)
|
||||
public static AsyncRelayCommand<T> CreateSilentFailConditional<T>(Predicate<T?> canExecute, Func<T?, Task> action)
|
||||
=> new(action, canExecute, AsyncRelayCommandOptions.FlowExceptionsToTaskScheduler);
|
||||
}
|
||||
}
|
||||
|
@ -12,9 +12,12 @@ using DynamicData.Binding;
|
||||
using FluentAvalonia.UI.Controls;
|
||||
using Gommon;
|
||||
using LibHac.Common;
|
||||
using LibHac.Fs;
|
||||
using LibHac.Ns;
|
||||
using LibHac.Tools.FsSystem.NcaUtils;
|
||||
using Ryujinx.Ava.Common;
|
||||
using Ryujinx.Ava.Common.Locale;
|
||||
using Ryujinx.Ava.Common.Models;
|
||||
using Ryujinx.Ava.Input;
|
||||
using Ryujinx.Ava.Systems;
|
||||
using Ryujinx.Ava.UI.Controls;
|
||||
@ -25,6 +28,7 @@ using Ryujinx.Ava.UI.Renderer;
|
||||
using Ryujinx.Ava.UI.Windows;
|
||||
using Ryujinx.Ava.Systems.AppLibrary;
|
||||
using Ryujinx.Ava.Systems.Configuration;
|
||||
using Ryujinx.Ava.UI.Views.Dialog;
|
||||
using Ryujinx.Ava.Utilities;
|
||||
using Ryujinx.Common;
|
||||
using Ryujinx.Common.Configuration;
|
||||
@ -51,7 +55,9 @@ using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Key = Ryujinx.Input.Key;
|
||||
using MissingKeyException = LibHac.Common.Keys.MissingKeyException;
|
||||
using Path = System.IO.Path;
|
||||
using ShaderCacheLoadingState = Ryujinx.Graphics.Gpu.Shader.ShaderCacheState;
|
||||
using UserId = Ryujinx.HLE.HOS.Services.Account.Acc.UserId;
|
||||
|
||||
namespace Ryujinx.Ava.UI.ViewModels
|
||||
{
|
||||
@ -1955,5 +1961,373 @@ namespace Ryujinx.Ava.UI.ViewModels
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Context Menu commands
|
||||
|
||||
public static RelayCommand<MainWindowViewModel> ToggleFavorite { get; } =
|
||||
Commands.CreateConditional<MainWindowViewModel>(vm => vm?.SelectedApplication != null,
|
||||
viewModel =>
|
||||
{
|
||||
viewModel.SelectedApplication.Favorite = !viewModel.SelectedApplication.Favorite;
|
||||
|
||||
ApplicationLibrary.LoadAndSaveMetaData(viewModel.SelectedApplication.IdString, appMetadata =>
|
||||
{
|
||||
appMetadata.Favorite = viewModel.SelectedApplication.Favorite;
|
||||
});
|
||||
|
||||
viewModel.RefreshView();
|
||||
}
|
||||
);
|
||||
|
||||
public static RelayCommand<MainWindowViewModel> OpenUserSaveDirectory { get; } =
|
||||
Commands.CreateConditional<MainWindowViewModel>(vm => vm?.SelectedApplication != null,
|
||||
viewModel =>
|
||||
OpenSaveDirectory(viewModel, SaveDataType.Account, new LibHac.Fs.UserId((ulong)viewModel.AccountManager.LastOpenedUser.UserId.High, (ulong)viewModel.AccountManager.LastOpenedUser.UserId.Low))
|
||||
);
|
||||
|
||||
public static RelayCommand<MainWindowViewModel> OpenDeviceSaveDirectory { get; } =
|
||||
Commands.CreateConditional<MainWindowViewModel>(vm => vm?.SelectedApplication != null,
|
||||
viewModel => OpenSaveDirectory(viewModel, SaveDataType.Device, default));
|
||||
|
||||
public static RelayCommand<MainWindowViewModel> OpenBcatSaveDirectory { get; } =
|
||||
Commands.CreateConditional<MainWindowViewModel>(vm => vm?.SelectedApplication != null,
|
||||
viewModel => OpenSaveDirectory(viewModel, SaveDataType.Bcat, default));
|
||||
|
||||
private static void OpenSaveDirectory(MainWindowViewModel viewModel, SaveDataType saveDataType, LibHac.Fs.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 static AsyncRelayCommand<MainWindowViewModel> OpenTitleUpdateManager { get; } =
|
||||
Commands.CreateConditional<MainWindowViewModel>(vm => vm?.SelectedApplication != null,
|
||||
viewModel => TitleUpdateManagerView.Show(viewModel.ApplicationLibrary, viewModel.SelectedApplication)
|
||||
);
|
||||
|
||||
public static AsyncRelayCommand<MainWindowViewModel> OpenDownloadableContentManager { get; } =
|
||||
Commands.CreateConditional<MainWindowViewModel>(vm => vm?.SelectedApplication != null,
|
||||
viewModel => DownloadableContentManagerView.Show(viewModel.ApplicationLibrary, viewModel.SelectedApplication)
|
||||
);
|
||||
|
||||
public static AsyncRelayCommand<MainWindowViewModel> OpenCheatManager { get; } =
|
||||
Commands.CreateConditional<MainWindowViewModel>(vm => vm?.SelectedApplication != null,
|
||||
viewModel => StyleableAppWindow.ShowAsync(
|
||||
new CheatWindow(
|
||||
viewModel.VirtualFileSystem,
|
||||
viewModel.SelectedApplication.IdString,
|
||||
viewModel.SelectedApplication.Name,
|
||||
viewModel.SelectedApplication.Path
|
||||
)
|
||||
));
|
||||
|
||||
public static RelayCommand<MainWindowViewModel> OpenModsDirectory { get; } =
|
||||
Commands.CreateConditional<MainWindowViewModel>(vm => vm?.SelectedApplication != null,
|
||||
viewModel =>
|
||||
{
|
||||
string modsBasePath = ModLoader.GetModsBasePath();
|
||||
string titleModsPath = ModLoader.GetApplicationDir(modsBasePath, viewModel.SelectedApplication.IdString);
|
||||
|
||||
OpenHelper.OpenFolder(titleModsPath);
|
||||
});
|
||||
|
||||
public static RelayCommand<MainWindowViewModel> OpenSdModsDirectory { get; } =
|
||||
Commands.CreateConditional<MainWindowViewModel>(vm => vm?.SelectedApplication != null,
|
||||
viewModel =>
|
||||
{
|
||||
string sdModsBasePath = ModLoader.GetSdModsBasePath();
|
||||
string titleModsPath = ModLoader.GetApplicationDir(sdModsBasePath, viewModel.SelectedApplication.IdString);
|
||||
|
||||
OpenHelper.OpenFolder(titleModsPath);
|
||||
});
|
||||
|
||||
public static AsyncRelayCommand<MainWindowViewModel> OpenModManager { get; } =
|
||||
Commands.CreateConditional<MainWindowViewModel>(vm => vm?.SelectedApplication != null,
|
||||
async viewModel =>
|
||||
{
|
||||
await ModManagerView.Show(
|
||||
viewModel.SelectedApplication.Id,
|
||||
viewModel.SelectedApplication.IdBase,
|
||||
viewModel.ApplicationLibrary,
|
||||
viewModel.SelectedApplication.Name);
|
||||
});
|
||||
|
||||
public static AsyncRelayCommand<MainWindowViewModel> PurgePtcCache { get; } =
|
||||
Commands.CreateConditional<MainWindowViewModel>(vm => vm?.SelectedApplication != null,
|
||||
async viewModel =>
|
||||
{
|
||||
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 static AsyncRelayCommand<MainWindowViewModel> NukePtcCache { get; } =
|
||||
Commands.CreateConditional<MainWindowViewModel>(vm => vm?.SelectedApplication != null,
|
||||
async viewModel =>
|
||||
{
|
||||
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 static AsyncRelayCommand<MainWindowViewModel> PurgeShaderCache { get; } =
|
||||
Commands.CreateConditional<MainWindowViewModel>(vm => vm?.SelectedApplication != null,
|
||||
async viewModel =>
|
||||
{
|
||||
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 static RelayCommand<MainWindowViewModel> OpenPtcDirectory { get; } =
|
||||
Commands.CreateConditional<MainWindowViewModel>(vm => vm?.SelectedApplication != null,
|
||||
viewModel =>
|
||||
{
|
||||
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 static RelayCommand<MainWindowViewModel> OpenShaderCacheDirectory { get; } =
|
||||
Commands.CreateConditional<MainWindowViewModel>(vm => vm?.SelectedApplication != 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 static AsyncRelayCommand<MainWindowViewModel> ExtractApplicationExeFs { get; } =
|
||||
Commands.CreateConditional<MainWindowViewModel>(vm => vm?.SelectedApplication != null,
|
||||
async viewModel =>
|
||||
{
|
||||
await ApplicationHelper.ExtractSection(
|
||||
viewModel.StorageProvider,
|
||||
NcaSectionType.Code,
|
||||
viewModel.SelectedApplication.Path,
|
||||
viewModel.SelectedApplication.Name);
|
||||
});
|
||||
|
||||
public static AsyncRelayCommand<MainWindowViewModel> ExtractApplicationRomFs { get; } =
|
||||
Commands.CreateConditional<MainWindowViewModel>(vm => vm?.SelectedApplication != null,
|
||||
async viewModel =>
|
||||
{
|
||||
await ApplicationHelper.ExtractSection(
|
||||
viewModel.StorageProvider,
|
||||
NcaSectionType.Data,
|
||||
viewModel.SelectedApplication.Path,
|
||||
viewModel.SelectedApplication.Name);
|
||||
});
|
||||
|
||||
public static AsyncRelayCommand<MainWindowViewModel> ExtractApplicationAocRomFs { get; } =
|
||||
Commands.CreateConditional<MainWindowViewModel>(vm => vm?.SelectedApplication != null,
|
||||
async viewModel =>
|
||||
{
|
||||
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 static AsyncRelayCommand<MainWindowViewModel> ExtractApplicationLogo { get; } =
|
||||
Commands.CreateConditional<MainWindowViewModel>(vm => vm?.SelectedApplication != null,
|
||||
async viewModel =>
|
||||
{
|
||||
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 static RelayCommand<MainWindowViewModel> CreateApplicationShortcut { get; } =
|
||||
Commands.CreateConditional<MainWindowViewModel>(vm => vm?.SelectedApplication != null,
|
||||
viewModel => ShortcutHelper.CreateAppShortcut(
|
||||
viewModel.SelectedApplication.Path,
|
||||
viewModel.SelectedApplication.Name,
|
||||
viewModel.SelectedApplication.IdString,
|
||||
viewModel.SelectedApplication.Icon
|
||||
));
|
||||
|
||||
public static AsyncRelayCommand<MainWindowViewModel> EditGameConfiguration { get; } =
|
||||
Commands.CreateConditional<MainWindowViewModel>(vm => vm?.SelectedApplication != null,
|
||||
async 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 static AsyncRelayCommand<MainWindowViewModel> OpenApplicationCompatibility { get; } =
|
||||
Commands.CreateConditional<MainWindowViewModel>(vm => vm?.SelectedApplication != null,
|
||||
viewModel => CompatibilityListWindow.Show(viewModel.SelectedApplication.IdString));
|
||||
|
||||
public static AsyncRelayCommand<MainWindowViewModel> OpenApplicationData { get; } =
|
||||
Commands.CreateConditional<MainWindowViewModel>(vm => vm?.SelectedApplication != null,
|
||||
viewModel => ApplicationDataView.Show(viewModel.SelectedApplication));
|
||||
|
||||
public static AsyncRelayCommand<MainWindowViewModel> RunApplication { get; } =
|
||||
Commands.CreateConditional<MainWindowViewModel>(vm => vm?.SelectedApplication != null,
|
||||
viewModel => viewModel.LoadApplication(viewModel.SelectedApplication));
|
||||
|
||||
public static AsyncRelayCommand<MainWindowViewModel> TrimXci { get; } =
|
||||
Commands.CreateConditional<MainWindowViewModel>(vm => vm?.SelectedApplication != null,
|
||||
viewModel => viewModel.TrimXCIFile(viewModel.SelectedApplication.Path));
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user