This commit is contained in:
Isaac Marovitz 2024-02-25 16:42:15 +08:00 committed by GitHub
commit 89165ed18c
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 207 additions and 174 deletions

View file

@ -595,11 +595,10 @@
"SelectUpdateDialogTitle": "Select update files",
"SelectModDialogTitle": "Select mod directory",
"UserProfileWindowTitle": "User Profiles Manager",
"CheatWindowTitle": "Cheats Manager",
"DlcWindowTitle": "Manage Downloadable Content for {0} ({1})",
"UpdateWindowTitle": "Title Update Manager",
"CheatWindowHeading": "Cheats Available for {0} [{1}]",
"BuildId": "BuildId:",
"CheatWindowHeading": "Manage Cheats for {0} ({1})",
"BuildId": "Build ID:",
"DlcWindowHeading": "{0} Downloadable Content(s)",
"ModWindowHeading": "{0} Mod(s)",
"UserProfilesEditProfile": "Edit Selected",

View file

@ -118,11 +118,11 @@ namespace Ryujinx.Ava.UI.Controls
if (viewModel?.SelectedApplication != null)
{
await new CheatWindow(
await CheatWindow.Show(
viewModel.VirtualFileSystem,
viewModel.SelectedApplication.TitleId,
ulong.Parse(viewModel.SelectedApplication.TitleId, NumberStyles.HexNumber),
viewModel.SelectedApplication.TitleName,
viewModel.SelectedApplication.Path).ShowDialog(viewModel.TopLevel as Window);
viewModel.SelectedApplication.Path);
}
}

View file

@ -0,0 +1,92 @@
using Avalonia;
using Avalonia.Collections;
using Avalonia.Controls.ApplicationLifetimes;
using Ryujinx.Ava.UI.Models;
using Ryujinx.HLE.FileSystem;
using Ryujinx.HLE.HOS;
using Ryujinx.Ui.App.Common;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
namespace Ryujinx.Ava.UI.ViewModels
{
public class CheatWindowViewModel : BaseModel
{
private readonly string _enabledCheatsPath;
public AvaloniaList<CheatNode> LoadedCheats { get; } = new();
public string BuildId { get; }
public CheatWindowViewModel(VirtualFileSystem virtualFileSystem, ulong titleId, string titlePath)
{
BuildId = ApplicationData.GetApplicationBuildId(virtualFileSystem, titlePath);
string modsBasePath = ModLoader.GetModsBasePath();
string titleModsPath = ModLoader.GetTitleDir(modsBasePath, titleId.ToString("x16"));
_enabledCheatsPath = Path.Combine(titleModsPath, "cheats", "enabled.txt");
string[] enabled = Array.Empty<string>();
if (File.Exists(_enabledCheatsPath))
{
enabled = File.ReadAllLines(_enabledCheatsPath);
}
var mods = new ModLoader.ModCache();
ModLoader.QueryContentsDir(mods, new DirectoryInfo(Path.Combine(modsBasePath, "contents")), titleId);
string currentCheatFile = string.Empty;
string buildId = string.Empty;
CheatNode currentGroup = null;
foreach (var cheat in mods.Cheats)
{
if (cheat.Path.FullName != currentCheatFile)
{
currentCheatFile = cheat.Path.FullName;
string parentPath = currentCheatFile.Replace(titleModsPath, "");
buildId = Path.GetFileNameWithoutExtension(currentCheatFile).ToUpper();
currentGroup = new CheatNode("", buildId, parentPath, true);
LoadedCheats.Add(currentGroup);
}
var model = new CheatNode(cheat.Name, buildId, "", false, enabled.Contains($"{buildId}-{cheat.Name}"));
currentGroup?.SubNodes.Add(model);
}
}
public async void CopyToClipboard()
{
if (Application.Current.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
{
await desktop.MainWindow.Clipboard.SetTextAsync(BuildId);
}
}
public void Save()
{
List<string> enabledCheats = new();
foreach (var cheats in LoadedCheats)
{
foreach (var cheat in cheats.SubNodes)
{
if (cheat.IsEnabled)
{
enabledCheats.Add(cheat.BuildIdKey);
}
}
}
Directory.CreateDirectory(Path.GetDirectoryName(_enabledCheatsPath));
File.WriteAllLines(_enabledCheatsPath, enabledCheats);
}
}
}

View file

@ -15,6 +15,7 @@ using Ryujinx.UI.Common.Configuration;
using Ryujinx.UI.Common.Helper;
using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
@ -170,11 +171,11 @@ namespace Ryujinx.Ava.UI.Views.Main
string name = ViewModel.AppHost.Device.Processes.ActiveApplication.ApplicationControlProperties.Title[(int)ViewModel.AppHost.Device.System.State.DesiredTitleLanguage].NameString.ToString();
await new CheatWindow(
await CheatWindow.Show(
Window.VirtualFileSystem,
ViewModel.AppHost.Device.Processes.ActiveApplication.ProgramIdText,
ulong.Parse(ViewModel.AppHost.Device.Processes.ActiveApplication.ProgramIdText, NumberStyles.HexNumber),
name,
Window.ViewModel.SelectedApplication.Path).ShowDialog(Window);
Window.ViewModel.SelectedApplication.Path);
ViewModel.AppHost.Device.EnableCheats();
}

View file

@ -1,81 +1,66 @@
<window:StyleableWindow
<UserControl
x:Class="Ryujinx.Ava.UI.Windows.CheatWindow"
xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:locale="clr-namespace:Ryujinx.Ava.Common.Locale"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:model="clr-namespace:Ryujinx.Ava.UI.Models"
xmlns:window="clr-namespace:Ryujinx.Ava.UI.Windows"
xmlns:viewModels="clr-namespace:Ryujinx.Ava.UI.ViewModels"
Width="500"
Height="500"
MinWidth="500"
MinHeight="500"
x:DataType="window:CheatWindow"
WindowStartupLocation="CenterOwner"
Height="380"
x:DataType="viewModels:CheatWindowViewModel"
mc:Ignorable="d"
Focusable="True">
<Window.Styles>
<Style Selector="TreeViewItem">
<Setter Property="IsExpanded" Value="True" />
</Style>
</Window.Styles>
<Grid Name="CheatGrid" Margin="15">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<TextBlock
Grid.Row="1"
Grid.Column="0"
Grid.ColumnSpan="2"
MaxWidth="500"
Margin="20,15,20,5"
HorizontalAlignment="Center"
VerticalAlignment="Center"
LineHeight="18"
Text="{Binding Heading}"
TextAlignment="Center"
TextWrapping="Wrap" />
<TextBlock
Grid.Row="2"
Grid.Column="0"
MaxWidth="500"
Margin="140,15,20,5"
HorizontalAlignment="Center"
VerticalAlignment="Center"
LineHeight="30"
Text="{locale:Locale BuildId}"
TextAlignment="Center"
TextWrapping="Wrap" />
<TextBox
Grid.Row="2"
Grid.Column="1"
Margin="0,5,110,5"
MinWidth="160"
HorizontalAlignment="Center"
VerticalAlignment="Center"
Text="{Binding BuildId}"
IsReadOnly="True" />
<Panel
Margin="0 0 0 10"
Grid.Row="0">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<StackPanel
Orientation="Horizontal"
Grid.Column="0">
<TextBlock
Padding="0 0 10 0"
Text="{locale:Locale BuildId}" />
<Button
Name="CopyButton"
Command="{Binding CopyToClipboard}">
<TextBlock Text="{Binding BuildId}" />
</Button>
</StackPanel>
<TextBox
Grid.Column="2"
MinHeight="29"
MaxHeight="29"
MinWidth="180"
MaxWidth="180"
HorizontalAlignment="Stretch"
Watermark="{locale:Locale Search}"
Text="" />
</Grid>
</Panel>
<Border
Grid.Row="3"
Grid.Column="0"
Grid.ColumnSpan="2"
Margin="5"
Grid.Row="1"
Margin="0 0 0 24"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
BorderBrush="Gray"
BorderThickness="1">
BorderBrush="{DynamicResource AppListHoverBackgroundColor}"
BorderThickness="1"
CornerRadius="5"
Padding="2.5">
<TreeView
Name="CheatsView"
MinHeight="300"
SelectionMode="Multiple, Toggle"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
ItemsSource="{Binding LoadedCheats}">
@ -98,29 +83,47 @@
</TreeView.ItemTemplate>
</TreeView>
</Border>
<DockPanel
Grid.Row="4"
Grid.Column="0"
Grid.ColumnSpan="2"
Margin="0"
<Panel
Grid.Row="2"
HorizontalAlignment="Stretch">
<DockPanel Margin="0" HorizontalAlignment="Right">
<StackPanel
Orientation="Horizontal"
Spacing="10"
HorizontalAlignment="Left">
<Button
Name="AddButton"
MinWidth="90"
Margin="5"
Command="{Binding}">
<TextBlock Text="{locale:Locale SettingsTabGeneralAdd}" />
</Button>
<Button
Name="RemoveAllButton"
MinWidth="90"
Margin="5"
Command="{Binding}">
<TextBlock Text="{locale:Locale DlcManagerRemoveAllButton}" />
</Button>
</StackPanel>
<StackPanel
Orientation="Horizontal"
Spacing="10"
HorizontalAlignment="Right">
<Button
Name="SaveButton"
MinWidth="90"
Margin="5"
Command="{Binding Save}"
IsVisible="{Binding !NoCheatsFound}">
Click="SaveAndClose">
<TextBlock Text="{locale:Locale SettingsButtonSave}" />
</Button>
<Button
Name="CancelButton"
MinWidth="90"
Margin="5"
Command="{Binding Close}">
Click="Close">
<TextBlock Text="{locale:Locale InputDialogCancel}" />
</Button>
</DockPanel>
</DockPanel>
</StackPanel>
</Panel>
</Grid>
</window:StyleableWindow>
</UserControl>

View file

@ -1,123 +1,61 @@
using Avalonia.Collections;
using Avalonia.Controls;
using Avalonia.Interactivity;
using Avalonia.Styling;
using FluentAvalonia.UI.Controls;
using Ryujinx.Ava.Common.Locale;
using Ryujinx.Ava.UI.Models;
using Ryujinx.Ava.UI.Helpers;
using Ryujinx.Ava.UI.ViewModels;
using Ryujinx.HLE.FileSystem;
using Ryujinx.HLE.HOS;
using Ryujinx.UI.App.Common;
using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
namespace Ryujinx.Ava.UI.Windows
{
public partial class CheatWindow : StyleableWindow
public partial class CheatWindow : UserControl
{
private readonly string _enabledCheatsPath;
public bool NoCheatsFound { get; }
public AvaloniaList<CheatNode> LoadedCheats { get; }
public string Heading { get; }
public string BuildId { get; }
public CheatWindowViewModel ViewModel;
public CheatWindow()
{
DataContext = this;
InitializeComponent();
Title = $"Ryujinx {Program.Version} - " + LocaleManager.Instance[LocaleKeys.CheatWindowTitle];
}
public CheatWindow(VirtualFileSystem virtualFileSystem, string titleId, string titleName, string titlePath)
public CheatWindow(VirtualFileSystem virtualFileSystem, ulong titleId, string titleName, string titlePath)
{
LoadedCheats = new AvaloniaList<CheatNode>();
Heading = LocaleManager.Instance.UpdateAndGetDynamicValue(LocaleKeys.CheatWindowHeading, titleName, titleId.ToUpper());
BuildId = ApplicationData.GetApplicationBuildId(virtualFileSystem, titlePath);
DataContext = ViewModel = new CheatWindowViewModel(virtualFileSystem, titleId, titlePath);
InitializeComponent();
string modsBasePath = ModLoader.GetModsBasePath();
string titleModsPath = ModLoader.GetApplicationDir(modsBasePath, titleId);
ulong titleIdValue = ulong.Parse(titleId, NumberStyles.HexNumber);
_enabledCheatsPath = Path.Combine(titleModsPath, "cheats", "enabled.txt");
string[] enabled = Array.Empty<string>();
if (File.Exists(_enabledCheatsPath))
{
enabled = File.ReadAllLines(_enabledCheatsPath);
}
int cheatAdded = 0;
var mods = new ModLoader.ModCache();
ModLoader.QueryContentsDir(mods, new DirectoryInfo(Path.Combine(modsBasePath, "contents")), titleIdValue);
string currentCheatFile = string.Empty;
string buildId = string.Empty;
CheatNode currentGroup = null;
foreach (var cheat in mods.Cheats)
{
if (cheat.Path.FullName != currentCheatFile)
{
currentCheatFile = cheat.Path.FullName;
string parentPath = currentCheatFile.Replace(titleModsPath, "");
buildId = Path.GetFileNameWithoutExtension(currentCheatFile).ToUpper();
currentGroup = new CheatNode("", buildId, parentPath, true);
LoadedCheats.Add(currentGroup);
}
var model = new CheatNode(cheat.Name, buildId, "", false, enabled.Contains($"{buildId}-{cheat.Name}"));
currentGroup?.SubNodes.Add(model);
cheatAdded++;
}
if (cheatAdded == 0)
{
NoCheatsFound = true;
}
DataContext = this;
Title = $"Ryujinx {Program.Version} - " + LocaleManager.Instance[LocaleKeys.CheatWindowTitle];
}
public void Save()
public static async Task Show(VirtualFileSystem virtualFileSystem, ulong titleId, string titleName, string titlePath)
{
if (NoCheatsFound)
ContentDialog contentDialog = new()
{
return;
}
PrimaryButtonText = "",
SecondaryButtonText = "",
CloseButtonText = "",
Content = new CheatWindow(virtualFileSystem, titleId, titleName, titlePath),
Title = string.Format(LocaleManager.Instance[LocaleKeys.CheatWindowHeading], titleName, titleId.ToString("X16")),
};
List<string> enabledCheats = new();
Style bottomBorder = new(x => x.OfType<Grid>().Name("DialogSpace").Child().OfType<Border>());
bottomBorder.Setters.Add(new Setter(IsVisibleProperty, false));
foreach (var cheats in LoadedCheats)
{
foreach (var cheat in cheats.SubNodes)
{
if (cheat.IsEnabled)
{
enabledCheats.Add(cheat.BuildIdKey);
}
}
}
contentDialog.Styles.Add(bottomBorder);
Directory.CreateDirectory(Path.GetDirectoryName(_enabledCheatsPath));
await ContentDialogHelper.ShowAsync(contentDialog);
}
File.WriteAllLines(_enabledCheatsPath, enabledCheats);
private void SaveAndClose(object sender, RoutedEventArgs e)
{
ViewModel.Save();
((ContentDialog)Parent).Hide();
}
Close();
private void Close(object sender, RoutedEventArgs e)
{
((ContentDialog)Parent).Hide();
}
}
}