aboutsummaryrefslogtreecommitdiff
path: root/src/Ryujinx.Ava/UI/Windows
diff options
context:
space:
mode:
authorIsaac Marovitz <42140194+IsaacMarovitz@users.noreply.github.com>2024-01-26 01:02:28 +0000
committerGitHub <noreply@github.com>2024-01-26 02:02:28 +0100
commit35fb409e85ef07b8e1c3a582cdc6615e6da71429 (patch)
tree1696d9498a73fe94d228a6bbf3ed06ff92f88a0c /src/Ryujinx.Ava/UI/Windows
parentd7ec4308b45d4ecb8d77cdc8d98ee618944292ed (diff)
Ava UI: Mod Manager (#4390)
* Let’s start again * Read folders and such * Remove Open Mod Folder menu items * Fix folder opening, Selecting/deselecting * She works * Fix GTK * AddMod * Delete * Fix duplicate entries * Fix file check * Avalonia 11 * Style fixes * Final style fixes * Might be too general * Remove unnecessary using * Enable new mods by default * More cleanup * Fix saving metadata * Dont deseralise ModMetadata several times * Avalonia I hate you * Confirmation dialgoues * Allow selecting multiple folders * Add back secondary folder * Search both paths * Fix formatting * Apply suggestions from code review Co-authored-by: Ac_K <Acoustik666@gmail.com> * Rename Title to Application * Generic locale key * Apply suggestions from code review Co-authored-by: Ac_K <Acoustik666@gmail.com> * Locale Updates * GDK Feedback * Fix --------- Co-authored-by: Ac_K <Acoustik666@gmail.com>
Diffstat (limited to 'src/Ryujinx.Ava/UI/Windows')
-rw-r--r--src/Ryujinx.Ava/UI/Windows/CheatWindow.axaml.cs2
-rw-r--r--src/Ryujinx.Ava/UI/Windows/ModManagerWindow.axaml179
-rw-r--r--src/Ryujinx.Ava/UI/Windows/ModManagerWindow.axaml.cs139
3 files changed, 319 insertions, 1 deletions
diff --git a/src/Ryujinx.Ava/UI/Windows/CheatWindow.axaml.cs b/src/Ryujinx.Ava/UI/Windows/CheatWindow.axaml.cs
index c2de67ab..46441faa 100644
--- a/src/Ryujinx.Ava/UI/Windows/CheatWindow.axaml.cs
+++ b/src/Ryujinx.Ava/UI/Windows/CheatWindow.axaml.cs
@@ -41,7 +41,7 @@ namespace Ryujinx.Ava.UI.Windows
InitializeComponent();
string modsBasePath = ModLoader.GetModsBasePath();
- string titleModsPath = ModLoader.GetTitleDir(modsBasePath, titleId);
+ string titleModsPath = ModLoader.GetApplicationDir(modsBasePath, titleId);
ulong titleIdValue = ulong.Parse(titleId, NumberStyles.HexNumber);
_enabledCheatsPath = Path.Combine(titleModsPath, "cheats", "enabled.txt");
diff --git a/src/Ryujinx.Ava/UI/Windows/ModManagerWindow.axaml b/src/Ryujinx.Ava/UI/Windows/ModManagerWindow.axaml
new file mode 100644
index 00000000..d9f58640
--- /dev/null
+++ b/src/Ryujinx.Ava/UI/Windows/ModManagerWindow.axaml
@@ -0,0 +1,179 @@
+<UserControl
+ 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:viewModels="clr-namespace:Ryujinx.Ava.UI.ViewModels"
+ xmlns:models="clr-namespace:Ryujinx.Ava.UI.Models"
+ xmlns:ui="clr-namespace:FluentAvalonia.UI.Controls;assembly=FluentAvalonia"
+ Width="500"
+ Height="380"
+ mc:Ignorable="d"
+ x:Class="Ryujinx.Ava.UI.Windows.ModManagerWindow"
+ x:CompileBindings="True"
+ x:DataType="viewModels:ModManagerViewModel"
+ Focusable="True">
+ <Grid>
+ <Grid.RowDefinitions>
+ <RowDefinition Height="Auto" />
+ <RowDefinition Height="*" />
+ <RowDefinition Height="Auto" />
+ </Grid.RowDefinitions>
+ <Panel
+ Margin="0 0 0 10"
+ Grid.Row="0">
+ <Grid>
+ <Grid.ColumnDefinitions>
+ <ColumnDefinition Width="Auto" />
+ <ColumnDefinition Width="Auto" />
+ <ColumnDefinition Width="*" />
+ </Grid.ColumnDefinitions>
+ <TextBlock
+ Grid.Column="0"
+ Text="{Binding ModCount}" />
+ <StackPanel
+ Margin="10 0"
+ Grid.Column="1"
+ Orientation="Horizontal">
+ <Button
+ Name="EnableAllButton"
+ MinWidth="90"
+ Margin="5"
+ Command="{ReflectionBinding EnableAll}">
+ <TextBlock Text="{locale:Locale DlcManagerEnableAllButton}" />
+ </Button>
+ <Button
+ Name="DisableAllButton"
+ MinWidth="90"
+ Margin="5"
+ Command="{ReflectionBinding DisableAll}">
+ <TextBlock Text="{locale:Locale DlcManagerDisableAllButton}" />
+ </Button>
+ </StackPanel>
+ <TextBox
+ Grid.Column="2"
+ MinHeight="27"
+ MaxHeight="27"
+ HorizontalAlignment="Stretch"
+ Watermark="{locale:Locale Search}"
+ Text="{Binding Search}" />
+ </Grid>
+ </Panel>
+ <Border
+ Grid.Row="1"
+ Margin="0 0 0 24"
+ HorizontalAlignment="Stretch"
+ VerticalAlignment="Stretch"
+ BorderBrush="{DynamicResource AppListHoverBackgroundColor}"
+ BorderThickness="1"
+ CornerRadius="5"
+ Padding="2.5">
+ <ListBox
+ AutoScrollToSelectedItem="False"
+ SelectionMode="Multiple, Toggle"
+ Background="Transparent"
+ SelectionChanged="OnSelectionChanged"
+ SelectedItems="{Binding SelectedMods, Mode=TwoWay}"
+ ItemsSource="{Binding Views}">
+ <ListBox.DataTemplates>
+ <DataTemplate
+ DataType="models:ModModel">
+ <Panel Margin="10">
+ <Grid>
+ <Grid.ColumnDefinitions>
+ <ColumnDefinition Width="*" />
+ <ColumnDefinition Width="Auto" />
+ </Grid.ColumnDefinitions>
+ <TextBlock
+ HorizontalAlignment="Left"
+ VerticalAlignment="Center"
+ MaxLines="2"
+ TextWrapping="Wrap"
+ TextTrimming="CharacterEllipsis"
+ Text="{Binding Name}" />
+ <StackPanel
+ Grid.Column="1"
+ Spacing="10"
+ Orientation="Horizontal"
+ HorizontalAlignment="Right">
+ <Button
+ VerticalAlignment="Center"
+ HorizontalAlignment="Right"
+ Padding="10"
+ MinWidth="0"
+ MinHeight="0"
+ Click="OpenLocation">
+ <ui:SymbolIcon
+ Symbol="OpenFolder"
+ HorizontalAlignment="Center"
+ VerticalAlignment="Center" />
+ </Button>
+ <Button
+ VerticalAlignment="Center"
+ HorizontalAlignment="Right"
+ Padding="10"
+ MinWidth="0"
+ MinHeight="0"
+ Click="DeleteMod">
+ <ui:SymbolIcon
+ Symbol="Cancel"
+ HorizontalAlignment="Center"
+ VerticalAlignment="Center" />
+ </Button>
+ </StackPanel>
+ </Grid>
+ </Panel>
+ </DataTemplate>
+ </ListBox.DataTemplates>
+ <ListBox.Styles>
+ <Style Selector="ListBoxItem">
+ <Setter Property="Background" Value="Transparent" />
+ </Style>
+ </ListBox.Styles>
+ </ListBox>
+ </Border>
+ <Panel
+ Grid.Row="2"
+ HorizontalAlignment="Stretch">
+ <StackPanel
+ Orientation="Horizontal"
+ Spacing="10"
+ HorizontalAlignment="Left">
+ <Button
+ Name="AddButton"
+ MinWidth="90"
+ Margin="5"
+ Command="{Binding Add}">
+ <TextBlock Text="{locale:Locale SettingsTabGeneralAdd}" />
+ </Button>
+ <Button
+ Name="RemoveAllButton"
+ MinWidth="90"
+ Margin="5"
+ Click="DeleteAll">
+ <TextBlock Text="{locale:Locale ModManagerDeleteAllButton}" />
+ </Button>
+ </StackPanel>
+ <StackPanel
+ Orientation="Horizontal"
+ Spacing="10"
+ HorizontalAlignment="Right">
+ <Button
+ Name="SaveButton"
+ MinWidth="90"
+ Margin="5"
+ Click="SaveAndClose">
+ <TextBlock Text="{locale:Locale SettingsButtonSave}" />
+ </Button>
+ <Button
+ Name="CancelButton"
+ MinWidth="90"
+ Margin="5"
+ Click="Close">
+ <TextBlock Text="{locale:Locale InputDialogCancel}" />
+ </Button>
+ </StackPanel>
+ </Panel>
+ </Grid>
+</UserControl>
diff --git a/src/Ryujinx.Ava/UI/Windows/ModManagerWindow.axaml.cs b/src/Ryujinx.Ava/UI/Windows/ModManagerWindow.axaml.cs
new file mode 100644
index 00000000..5de09ba0
--- /dev/null
+++ b/src/Ryujinx.Ava/UI/Windows/ModManagerWindow.axaml.cs
@@ -0,0 +1,139 @@
+using Avalonia.Controls;
+using Avalonia.Interactivity;
+using Avalonia.Styling;
+using FluentAvalonia.UI.Controls;
+using Ryujinx.Ava.Common.Locale;
+using Ryujinx.Ava.UI.Helpers;
+using Ryujinx.Ava.UI.Models;
+using Ryujinx.Ava.UI.ViewModels;
+using Ryujinx.Ui.Common.Helper;
+using System.Threading.Tasks;
+using Button = Avalonia.Controls.Button;
+
+namespace Ryujinx.Ava.UI.Windows
+{
+ public partial class ModManagerWindow : UserControl
+ {
+ public ModManagerViewModel ViewModel;
+
+ public ModManagerWindow()
+ {
+ DataContext = this;
+
+ InitializeComponent();
+ }
+
+ public ModManagerWindow(ulong titleId)
+ {
+ DataContext = ViewModel = new ModManagerViewModel(titleId);
+
+ InitializeComponent();
+ }
+
+ public static async Task Show(ulong titleId, string titleName)
+ {
+ ContentDialog contentDialog = new()
+ {
+ PrimaryButtonText = "",
+ SecondaryButtonText = "",
+ CloseButtonText = "",
+ Content = new ModManagerWindow(titleId),
+ Title = string.Format(LocaleManager.Instance[LocaleKeys.ModWindowHeading], titleName, titleId.ToString("X16")),
+ };
+
+ Style bottomBorder = new(x => x.OfType<Grid>().Name("DialogSpace").Child().OfType<Border>());
+ bottomBorder.Setters.Add(new Setter(IsVisibleProperty, false));
+
+ contentDialog.Styles.Add(bottomBorder);
+
+ await contentDialog.ShowAsync();
+ }
+
+ private void SaveAndClose(object sender, RoutedEventArgs e)
+ {
+ ViewModel.Save();
+ ((ContentDialog)Parent).Hide();
+ }
+
+ private void Close(object sender, RoutedEventArgs e)
+ {
+ ((ContentDialog)Parent).Hide();
+ }
+
+ private async void DeleteMod(object sender, RoutedEventArgs e)
+ {
+ if (sender is Button button)
+ {
+ if (button.DataContext is ModModel model)
+ {
+ var result = await ContentDialogHelper.CreateConfirmationDialog(
+ LocaleManager.Instance[LocaleKeys.DialogWarning],
+ LocaleManager.Instance.UpdateAndGetDynamicValue(LocaleKeys.DialogModManagerDeletionWarningMessage, model.Name),
+ LocaleManager.Instance[LocaleKeys.InputDialogYes],
+ LocaleManager.Instance[LocaleKeys.InputDialogNo],
+ LocaleManager.Instance[LocaleKeys.RyujinxConfirm]);
+
+ if (result == UserResult.Yes)
+ {
+ ViewModel.Delete(model);
+ }
+ }
+ }
+ }
+
+ private async void DeleteAll(object sender, RoutedEventArgs e)
+ {
+ var result = await ContentDialogHelper.CreateConfirmationDialog(
+ LocaleManager.Instance[LocaleKeys.DialogWarning],
+ LocaleManager.Instance[LocaleKeys.DialogModManagerDeletionAllWarningMessage],
+ LocaleManager.Instance[LocaleKeys.InputDialogYes],
+ LocaleManager.Instance[LocaleKeys.InputDialogNo],
+ LocaleManager.Instance[LocaleKeys.RyujinxConfirm]);
+
+ if (result == UserResult.Yes)
+ {
+ ViewModel.DeleteAll();
+ }
+ }
+
+ private void OpenLocation(object sender, RoutedEventArgs e)
+ {
+ if (sender is Button button)
+ {
+ if (button.DataContext is ModModel model)
+ {
+ OpenHelper.OpenFolder(model.Path);
+ }
+ }
+ }
+
+ private void OnSelectionChanged(object sender, SelectionChangedEventArgs e)
+ {
+ foreach (var content in e.AddedItems)
+ {
+ if (content is ModModel model)
+ {
+ var index = ViewModel.Mods.IndexOf(model);
+
+ if (index != -1)
+ {
+ ViewModel.Mods[index].Enabled = true;
+ }
+ }
+ }
+
+ foreach (var content in e.RemovedItems)
+ {
+ if (content is ModModel model)
+ {
+ var index = ViewModel.Mods.IndexOf(model);
+
+ if (index != -1)
+ {
+ ViewModel.Mods[index].Enabled = false;
+ }
+ }
+ }
+ }
+ }
+}