diff options
| author | Mary Guillemard <mary@mary.zone> | 2024-03-02 12:51:05 +0100 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2024-03-02 12:51:05 +0100 |
| commit | ec6cb0abb4b7669895b6e96fd7581c93b5abd691 (patch) | |
| tree | 128c862ff5faea0b219467656d4023bee7faefb5 /src/Ryujinx.Ava/UI | |
| parent | 53b5985da6b9d7b281d9fc25b93bfd1d1918a107 (diff) | |
infra: Make Avalonia the default UI (#6375)
* misc: Move Ryujinx project to Ryujinx.Gtk3
This breaks release CI for now but that's fine.
Signed-off-by: Mary Guillemard <mary@mary.zone>
* misc: Move Ryujinx.Ava project to Ryujinx
This breaks CI for now, but it's fine.
Signed-off-by: Mary Guillemard <mary@mary.zone>
* infra: Make Avalonia the default UI
Should fix CI after the previous changes.
GTK3 isn't build by the release job anymore, only by PR CI.
This also ensure that the test-ava update package is still generated to
allow update from the old testing channel.
Signed-off-by: Mary Guillemard <mary@mary.zone>
* Fix missing copy in create_app_bundle.sh
Signed-off-by: Mary Guillemard <mary@mary.zone>
* Fix syntax error
Signed-off-by: Mary Guillemard <mary@mary.zone>
---------
Signed-off-by: Mary Guillemard <mary@mary.zone>
Diffstat (limited to 'src/Ryujinx.Ava/UI')
136 files changed, 0 insertions, 18833 deletions
diff --git a/src/Ryujinx.Ava/UI/Applet/AvaHostUIHandler.cs b/src/Ryujinx.Ava/UI/Applet/AvaHostUIHandler.cs deleted file mode 100644 index 4bcc35a7..00000000 --- a/src/Ryujinx.Ava/UI/Applet/AvaHostUIHandler.cs +++ /dev/null @@ -1,204 +0,0 @@ -using Avalonia.Controls; -using Avalonia.Threading; -using FluentAvalonia.UI.Controls; -using Ryujinx.Ava.Common.Locale; -using Ryujinx.Ava.UI.Controls; -using Ryujinx.Ava.UI.Helpers; -using Ryujinx.Ava.UI.Windows; -using Ryujinx.HLE; -using Ryujinx.HLE.HOS.Applets; -using Ryujinx.HLE.HOS.Services.Am.AppletOE.ApplicationProxyService.ApplicationProxy.Types; -using Ryujinx.HLE.UI; -using System; -using System.Threading; - -namespace Ryujinx.Ava.UI.Applet -{ - internal class AvaHostUIHandler : IHostUIHandler - { - private readonly MainWindow _parent; - - public IHostUITheme HostUITheme { get; } - - public AvaHostUIHandler(MainWindow parent) - { - _parent = parent; - - HostUITheme = new AvaloniaHostUITheme(parent); - } - - public bool DisplayMessageDialog(ControllerAppletUIArgs args) - { - ManualResetEvent dialogCloseEvent = new(false); - - bool okPressed = false; - - Dispatcher.UIThread.InvokeAsync(async () => - { - var response = await ControllerAppletDialog.ShowControllerAppletDialog(_parent, args); - if (response == UserResult.Ok) - { - okPressed = true; - } - - dialogCloseEvent.Set(); - }); - - dialogCloseEvent.WaitOne(); - - return okPressed; - } - - public bool DisplayMessageDialog(string title, string message) - { - ManualResetEvent dialogCloseEvent = new(false); - - bool okPressed = false; - - Dispatcher.UIThread.InvokeAsync(async () => - { - try - { - ManualResetEvent deferEvent = new(false); - - bool opened = false; - - UserResult response = await ContentDialogHelper.ShowDeferredContentDialog(_parent, - title, - message, - "", - LocaleManager.Instance[LocaleKeys.DialogOpenSettingsWindowLabel], - "", - LocaleManager.Instance[LocaleKeys.SettingsButtonClose], - (int)Symbol.Important, - deferEvent, - async window => - { - if (opened) - { - return; - } - - opened = true; - - _parent.SettingsWindow = new SettingsWindow(_parent.VirtualFileSystem, _parent.ContentManager); - - await _parent.SettingsWindow.ShowDialog(window); - - _parent.SettingsWindow = null; - - opened = false; - }); - - if (response == UserResult.Ok) - { - okPressed = true; - } - - dialogCloseEvent.Set(); - } - catch (Exception ex) - { - await ContentDialogHelper.CreateErrorDialog(LocaleManager.Instance.UpdateAndGetDynamicValue(LocaleKeys.DialogMessageDialogErrorExceptionMessage, ex)); - - dialogCloseEvent.Set(); - } - }); - - dialogCloseEvent.WaitOne(); - - return okPressed; - } - - public bool DisplayInputDialog(SoftwareKeyboardUIArgs args, out string userText) - { - ManualResetEvent dialogCloseEvent = new(false); - - bool okPressed = false; - bool error = false; - string inputText = args.InitialText ?? ""; - - Dispatcher.UIThread.InvokeAsync(async () => - { - try - { - var response = await SwkbdAppletDialog.ShowInputDialog(LocaleManager.Instance[LocaleKeys.SoftwareKeyboard], args); - - if (response.Result == UserResult.Ok) - { - inputText = response.Input; - okPressed = true; - } - } - catch (Exception ex) - { - error = true; - - await ContentDialogHelper.CreateErrorDialog(LocaleManager.Instance.UpdateAndGetDynamicValue(LocaleKeys.DialogSoftwareKeyboardErrorExceptionMessage, ex)); - } - finally - { - dialogCloseEvent.Set(); - } - }); - - dialogCloseEvent.WaitOne(); - - userText = error ? null : inputText; - - return error || okPressed; - } - - public void ExecuteProgram(Switch device, ProgramSpecifyKind kind, ulong value) - { - device.Configuration.UserChannelPersistence.ExecuteProgram(kind, value); - _parent.ViewModel.AppHost?.Stop(); - } - - public bool DisplayErrorAppletDialog(string title, string message, string[] buttons) - { - ManualResetEvent dialogCloseEvent = new(false); - - bool showDetails = false; - - Dispatcher.UIThread.InvokeAsync(async () => - { - try - { - ErrorAppletWindow msgDialog = new(_parent, buttons, message) - { - Title = title, - WindowStartupLocation = WindowStartupLocation.CenterScreen, - Width = 400, - }; - - object response = await msgDialog.Run(); - - if (response != null && buttons != null && buttons.Length > 1 && (int)response != buttons.Length - 1) - { - showDetails = true; - } - - dialogCloseEvent.Set(); - - msgDialog.Close(); - } - catch (Exception ex) - { - dialogCloseEvent.Set(); - - await ContentDialogHelper.CreateErrorDialog(LocaleManager.Instance.UpdateAndGetDynamicValue(LocaleKeys.DialogErrorAppletErrorExceptionMessage, ex)); - } - }); - - dialogCloseEvent.WaitOne(); - - return showDetails; - } - - public IDynamicTextInputHandler CreateDynamicTextInputHandler() - { - return new AvaloniaDynamicTextInputHandler(_parent); - } - } -} diff --git a/src/Ryujinx.Ava/UI/Applet/AvaloniaDynamicTextInputHandler.cs b/src/Ryujinx.Ava/UI/Applet/AvaloniaDynamicTextInputHandler.cs deleted file mode 100644 index 531d0061..00000000 --- a/src/Ryujinx.Ava/UI/Applet/AvaloniaDynamicTextInputHandler.cs +++ /dev/null @@ -1,162 +0,0 @@ -using Avalonia; -using Avalonia.Controls; -using Avalonia.Input; -using Avalonia.Threading; -using Ryujinx.Ava.Input; -using Ryujinx.Ava.UI.Helpers; -using Ryujinx.Ava.UI.Windows; -using Ryujinx.HLE.UI; -using System; -using System.Threading; -using HidKey = Ryujinx.Common.Configuration.Hid.Key; - -namespace Ryujinx.Ava.UI.Applet -{ - class AvaloniaDynamicTextInputHandler : IDynamicTextInputHandler - { - private MainWindow _parent; - private readonly OffscreenTextBox _hiddenTextBox; - private bool _canProcessInput; - private IDisposable _textChangedSubscription; - private IDisposable _selectionStartChangedSubscription; - private IDisposable _selectionEndtextChangedSubscription; - - public AvaloniaDynamicTextInputHandler(MainWindow parent) - { - _parent = parent; - - (_parent.InputManager.KeyboardDriver as AvaloniaKeyboardDriver).KeyPressed += AvaloniaDynamicTextInputHandler_KeyPressed; - (_parent.InputManager.KeyboardDriver as AvaloniaKeyboardDriver).KeyRelease += AvaloniaDynamicTextInputHandler_KeyRelease; - (_parent.InputManager.KeyboardDriver as AvaloniaKeyboardDriver).TextInput += AvaloniaDynamicTextInputHandler_TextInput; - - _hiddenTextBox = _parent.HiddenTextBox; - - Dispatcher.UIThread.Post(() => - { - _textChangedSubscription = _hiddenTextBox.GetObservable(TextBox.TextProperty).Subscribe(TextChanged); - _selectionStartChangedSubscription = _hiddenTextBox.GetObservable(TextBox.SelectionStartProperty).Subscribe(SelectionChanged); - _selectionEndtextChangedSubscription = _hiddenTextBox.GetObservable(TextBox.SelectionEndProperty).Subscribe(SelectionChanged); - }); - } - - private void TextChanged(string text) - { - TextChangedEvent?.Invoke(text ?? string.Empty, _hiddenTextBox.SelectionStart, _hiddenTextBox.SelectionEnd, true); - } - - private void SelectionChanged(int selection) - { - if (_hiddenTextBox.SelectionEnd < _hiddenTextBox.SelectionStart) - { - _hiddenTextBox.SelectionStart = _hiddenTextBox.SelectionEnd; - } - - TextChangedEvent?.Invoke(_hiddenTextBox.Text ?? string.Empty, _hiddenTextBox.SelectionStart, _hiddenTextBox.SelectionEnd, true); - } - - private void AvaloniaDynamicTextInputHandler_TextInput(object sender, string text) - { - Dispatcher.UIThread.InvokeAsync(() => - { - if (_canProcessInput) - { - _hiddenTextBox.SendText(text); - } - }); - } - - private void AvaloniaDynamicTextInputHandler_KeyRelease(object sender, KeyEventArgs e) - { - var key = (HidKey)AvaloniaKeyboardMappingHelper.ToInputKey(e.Key); - - if (!(KeyReleasedEvent?.Invoke(key)).GetValueOrDefault(true)) - { - return; - } - - e.RoutedEvent = OffscreenTextBox.GetKeyUpRoutedEvent(); - - Dispatcher.UIThread.InvokeAsync(() => - { - if (_canProcessInput) - { - _hiddenTextBox.SendKeyUpEvent(e); - } - }); - } - - private void AvaloniaDynamicTextInputHandler_KeyPressed(object sender, KeyEventArgs e) - { - var key = (HidKey)AvaloniaKeyboardMappingHelper.ToInputKey(e.Key); - - if (!(KeyPressedEvent?.Invoke(key)).GetValueOrDefault(true)) - { - return; - } - - e.RoutedEvent = OffscreenTextBox.GetKeyUpRoutedEvent(); - - Dispatcher.UIThread.InvokeAsync(() => - { - if (_canProcessInput) - { - _hiddenTextBox.SendKeyDownEvent(e); - } - }); - } - - public bool TextProcessingEnabled - { - get - { - return Volatile.Read(ref _canProcessInput); - } - set - { - Volatile.Write(ref _canProcessInput, value); - } - } - - public event DynamicTextChangedHandler TextChangedEvent; - public event KeyPressedHandler KeyPressedEvent; - public event KeyReleasedHandler KeyReleasedEvent; - - public void Dispose() - { - (_parent.InputManager.KeyboardDriver as AvaloniaKeyboardDriver).KeyPressed -= AvaloniaDynamicTextInputHandler_KeyPressed; - (_parent.InputManager.KeyboardDriver as AvaloniaKeyboardDriver).KeyRelease -= AvaloniaDynamicTextInputHandler_KeyRelease; - (_parent.InputManager.KeyboardDriver as AvaloniaKeyboardDriver).TextInput -= AvaloniaDynamicTextInputHandler_TextInput; - - _textChangedSubscription?.Dispose(); - _selectionStartChangedSubscription?.Dispose(); - _selectionEndtextChangedSubscription?.Dispose(); - - Dispatcher.UIThread.Post(() => - { - _hiddenTextBox.Clear(); - _parent.ViewModel.RendererHostControl.Focus(); - - _parent = null; - }); - } - - public void SetText(string text, int cursorBegin) - { - Dispatcher.UIThread.Post(() => - { - _hiddenTextBox.Text = text; - _hiddenTextBox.CaretIndex = cursorBegin; - }); - } - - public void SetText(string text, int cursorBegin, int cursorEnd) - { - Dispatcher.UIThread.Post(() => - { - _hiddenTextBox.Text = text; - _hiddenTextBox.SelectionStart = cursorBegin; - _hiddenTextBox.SelectionEnd = cursorEnd; - }); - } - } -} diff --git a/src/Ryujinx.Ava/UI/Applet/AvaloniaHostUITheme.cs b/src/Ryujinx.Ava/UI/Applet/AvaloniaHostUITheme.cs deleted file mode 100644 index 016fb484..00000000 --- a/src/Ryujinx.Ava/UI/Applet/AvaloniaHostUITheme.cs +++ /dev/null @@ -1,41 +0,0 @@ -using Avalonia.Media; -using Ryujinx.Ava.UI.Windows; -using Ryujinx.HLE.UI; -using System; - -namespace Ryujinx.Ava.UI.Applet -{ - class AvaloniaHostUITheme : IHostUITheme - { - public AvaloniaHostUITheme(MainWindow parent) - { - FontFamily = OperatingSystem.IsWindows() && OperatingSystem.IsWindowsVersionAtLeast(10, 0, 22000) ? "Segoe UI Variable" : parent.FontFamily.Name; - DefaultBackgroundColor = BrushToThemeColor(parent.Background); - DefaultForegroundColor = BrushToThemeColor(parent.Foreground); - DefaultBorderColor = BrushToThemeColor(parent.BorderBrush); - SelectionBackgroundColor = BrushToThemeColor(parent.ViewControls.SearchBox.SelectionBrush); - SelectionForegroundColor = BrushToThemeColor(parent.ViewControls.SearchBox.SelectionForegroundBrush); - } - - public string FontFamily { get; } - - public ThemeColor DefaultBackgroundColor { get; } - public ThemeColor DefaultForegroundColor { get; } - public ThemeColor DefaultBorderColor { get; } - public ThemeColor SelectionBackgroundColor { get; } - public ThemeColor SelectionForegroundColor { get; } - - private static ThemeColor BrushToThemeColor(IBrush brush) - { - if (brush is SolidColorBrush solidColor) - { - return new ThemeColor((float)solidColor.Color.A / 255, - (float)solidColor.Color.R / 255, - (float)solidColor.Color.G / 255, - (float)solidColor.Color.B / 255); - } - - return new ThemeColor(); - } - } -} diff --git a/src/Ryujinx.Ava/UI/Applet/ControllerAppletDialog.axaml b/src/Ryujinx.Ava/UI/Applet/ControllerAppletDialog.axaml deleted file mode 100644 index b2c22f6b..00000000 --- a/src/Ryujinx.Ava/UI/Applet/ControllerAppletDialog.axaml +++ /dev/null @@ -1,145 +0,0 @@ -<UserControl - x:Class="Ryujinx.Ava.UI.Applet.ControllerAppletDialog" - xmlns="https://github.com/avaloniaui" - xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" - xmlns:d="http://schemas.microsoft.com/expression/blend/2008" - xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" - xmlns:locale="clr-namespace:Ryujinx.Ava.Common.Locale" - xmlns:applet="using:Ryujinx.Ava.UI.Applet" - mc:Ignorable="d" - Width="400" - Focusable="True" - x:DataType="applet:ControllerAppletDialog"> - <Grid - HorizontalAlignment="Stretch" - VerticalAlignment="Stretch"> - <Grid.RowDefinitions> - <RowDefinition Height="Auto" /> - <RowDefinition Height="*" /> - <RowDefinition Height="Auto" /> - </Grid.RowDefinitions> - <Grid.ColumnDefinitions> - <ColumnDefinition Width="*" /> - <ColumnDefinition Width="Auto" /> - </Grid.ColumnDefinitions> - <Border - Grid.Column="0" - Grid.Row="0" - Grid.ColumnSpan="2" - Margin="0 0 0 10" - BorderBrush="{DynamicResource ThemeControlBorderColor}" - BorderThickness="1" - CornerRadius="5"> - <StackPanel - Spacing="10" - Margin="10"> - <TextBlock - Text="{locale:Locale ControllerAppletDescription}" /> - <TextBlock - IsVisible="{Binding IsDocked}" - FontWeight="Bold" - Text="{locale:Locale ControllerAppletDocked}" /> - </StackPanel> - </Border> - <Border - Grid.Column="0" - Grid.Row="1" - BorderBrush="{DynamicResource ThemeControlBorderColor}" - BorderThickness="1" - CornerRadius="5" - Margin="0 0 10 0"> - <StackPanel - Margin="10" - Spacing="10" - Orientation="Vertical"> - <TextBlock - HorizontalAlignment="Center" - VerticalAlignment="Center" - TextAlignment="Center" - FontWeight="Bold" - Text="{locale:Locale ControllerAppletControllers}" /> - <StackPanel - Spacing="10" - HorizontalAlignment="Center" - VerticalAlignment="Center" - Orientation="Horizontal"> - <Image - Height="50" - Width="50" - Stretch="Uniform" - Source="{Binding ProControllerImage}" - IsVisible="{Binding SupportsProController}" /> - <Image - Height="50" - Width="50" - Stretch="Uniform" - Source="{Binding JoyconPairImage}" - IsVisible="{Binding SupportsJoyconPair}" /> - <Image - Height="50" - Width="50" - Stretch="Uniform" - Source="{Binding JoyconLeftImage}" - IsVisible="{Binding SupportsLeftJoycon}" /> - <Image - Height="50" - Width="50" - Stretch="Uniform" - Source="{Binding JoyconRightImage}" - IsVisible="{Binding SupportsRightJoycon}" /> - </StackPanel> - </StackPanel> - </Border> - <Border - Grid.Column="1" - Grid.Row="1" - BorderBrush="{DynamicResource ThemeControlBorderColor}" - BorderThickness="1" - CornerRadius="5"> - <StackPanel - Margin="10" - Spacing="10" - Orientation="Vertical"> - <TextBlock - HorizontalAlignment="Center" - VerticalAlignment="Center" - TextAlignment="Center" - FontWeight="Bold" - Text="{locale:Locale ControllerAppletPlayers}" /> - <Border Height="50"> - <TextBlock - HorizontalAlignment="Center" - VerticalAlignment="Center" - TextAlignment="Center" - FontSize="40" - FontWeight="Thin" - Text="{Binding PlayerCount}" /> - </Border> - </StackPanel> - </Border> - <Panel - Margin="0 24 0 0" - Grid.Column="0" - Grid.Row="2" - Grid.ColumnSpan="2"> - <StackPanel - Orientation="Horizontal" - Spacing="10" - HorizontalAlignment="Right"> - <Button - Name="SaveButton" - MinWidth="90" - Command="{Binding OpenSettingsWindow}"> - <TextBlock Text="{locale:Locale DialogOpenSettingsWindowLabel}" /> - </Button> - <Button - Name="CancelButton" - MinWidth="90" - Command="{Binding Close}"> - <TextBlock Text="{locale:Locale SettingsButtonClose}" /> - </Button> - </StackPanel> - </Panel> - </Grid> -</UserControl> - diff --git a/src/Ryujinx.Ava/UI/Applet/ControllerAppletDialog.axaml.cs b/src/Ryujinx.Ava/UI/Applet/ControllerAppletDialog.axaml.cs deleted file mode 100644 index 279af07c..00000000 --- a/src/Ryujinx.Ava/UI/Applet/ControllerAppletDialog.axaml.cs +++ /dev/null @@ -1,140 +0,0 @@ -using Avalonia.Controls; -using Avalonia.Styling; -using Avalonia.Svg.Skia; -using Avalonia.Threading; -using FluentAvalonia.UI.Controls; -using Ryujinx.Ava.Common.Locale; -using Ryujinx.Ava.UI.Helpers; -using Ryujinx.Ava.UI.Windows; -using Ryujinx.Common; -using Ryujinx.HLE.HOS.Applets; -using Ryujinx.HLE.HOS.Services.Hid; -using System; -using System.Linq; -using System.Threading.Tasks; - -namespace Ryujinx.Ava.UI.Applet -{ - internal partial class ControllerAppletDialog : UserControl - { - private const string ProControllerResource = "Ryujinx.Ava/Assets/Icons/Controller_ProCon.svg"; - private const string JoyConPairResource = "Ryujinx.Ava/Assets/Icons/Controller_JoyConPair.svg"; - private const string JoyConLeftResource = "Ryujinx.Ava/Assets/Icons/Controller_JoyConLeft.svg"; - private const string JoyConRightResource = "Ryujinx.Ava/Assets/Icons/Controller_JoyConRight.svg"; - - public static SvgImage ProControllerImage => GetResource(ProControllerResource); - public static SvgImage JoyconPairImage => GetResource(JoyConPairResource); - public static SvgImage JoyconLeftImage => GetResource(JoyConLeftResource); - public static SvgImage JoyconRightImage => GetResource(JoyConRightResource); - - public string PlayerCount { get; set; } = ""; - public bool SupportsProController { get; set; } - public bool SupportsLeftJoycon { get; set; } - public bool SupportsRightJoycon { get; set; } - public bool SupportsJoyconPair { get; set; } - public bool IsDocked { get; set; } - - private readonly MainWindow _mainWindow; - - public ControllerAppletDialog(MainWindow mainWindow, ControllerAppletUIArgs args) - { - if (args.PlayerCountMin == args.PlayerCountMax) - { - PlayerCount = args.PlayerCountMin.ToString(); - } - else - { - PlayerCount = $"{args.PlayerCountMin} - {args.PlayerCountMax}"; - } - - SupportsProController = (args.SupportedStyles & ControllerType.ProController) != 0; - SupportsLeftJoycon = (args.SupportedStyles & ControllerType.JoyconLeft) != 0; - SupportsRightJoycon = (args.SupportedStyles & ControllerType.JoyconRight) != 0; - SupportsJoyconPair = (args.SupportedStyles & ControllerType.JoyconPair) != 0; - - IsDocked = args.IsDocked; - - _mainWindow = mainWindow; - - DataContext = this; - - InitializeComponent(); - } - - public ControllerAppletDialog(MainWindow mainWindow) - { - _mainWindow = mainWindow; - DataContext = this; - - InitializeComponent(); - } - - public static async Task<UserResult> ShowControllerAppletDialog(MainWindow window, ControllerAppletUIArgs args) - { - ContentDialog contentDialog = new(); - UserResult result = UserResult.Cancel; - ControllerAppletDialog content = new(window, args); - - contentDialog.Title = LocaleManager.Instance[LocaleKeys.DialogControllerAppletTitle]; - contentDialog.Content = content; - - void Handler(ContentDialog sender, ContentDialogClosedEventArgs eventArgs) - { - if (eventArgs.Result == ContentDialogResult.Primary) - { - result = UserResult.Ok; - } - } - - contentDialog.Closed += Handler; - - Style bottomBorder = new(x => x.OfType<Grid>().Name("DialogSpace").Child().OfType<Border>()); - bottomBorder.Setters.Add(new Setter(IsVisibleProperty, false)); - - contentDialog.Styles.Add(bottomBorder); - - await ContentDialogHelper.ShowAsync(contentDialog); - - return result; - } - - private static SvgImage GetResource(string path) - { - SvgImage image = new(); - - if (!string.IsNullOrWhiteSpace(path)) - { - SvgSource source = new(default(Uri)); - - source.Load(EmbeddedResources.GetStream(path)); - - image.Source = source; - } - - return image; - } - - public void OpenSettingsWindow() - { - if (_mainWindow.SettingsWindow == null) - { - Dispatcher.UIThread.InvokeAsync(async () => - { - _mainWindow.SettingsWindow = new SettingsWindow(_mainWindow.VirtualFileSystem, _mainWindow.ContentManager); - _mainWindow.SettingsWindow.NavPanel.Content = _mainWindow.SettingsWindow.InputPage; - _mainWindow.SettingsWindow.NavPanel.SelectedItem = _mainWindow.SettingsWindow.NavPanel.MenuItems.ElementAt(1); - - await ContentDialogHelper.ShowWindowAsync(_mainWindow.SettingsWindow, _mainWindow); - _mainWindow.SettingsWindow = null; - this.Close(); - }); - } - } - - public void Close() - { - ((ContentDialog)Parent)?.Hide(); - } - } -} - diff --git a/src/Ryujinx.Ava/UI/Applet/ErrorAppletWindow.axaml b/src/Ryujinx.Ava/UI/Applet/ErrorAppletWindow.axaml deleted file mode 100644 index 51f37051..00000000 --- a/src/Ryujinx.Ava/UI/Applet/ErrorAppletWindow.axaml +++ /dev/null @@ -1,54 +0,0 @@ -<Window - x:Class="Ryujinx.Ava.UI.Applet.ErrorAppletWindow" - 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" - Title="{locale:Locale ErrorWindowTitle}" - xmlns:views="using:Ryujinx.Ava.UI.Applet" - Width="450" - Height="340" - CanResize="False" - x:DataType="views:ErrorAppletWindow" - SizeToContent="Height" - mc:Ignorable="d" - Focusable="True"> - <Grid - Margin="20" - HorizontalAlignment="Stretch" - VerticalAlignment="Stretch"> - <Grid.RowDefinitions> - <RowDefinition Height="Auto" /> - <RowDefinition Height="*" /> - <RowDefinition Height="Auto" /> - </Grid.RowDefinitions> - <Grid.ColumnDefinitions> - <ColumnDefinition Width="Auto" /> - <ColumnDefinition /> - </Grid.ColumnDefinitions> - <Image - Grid.Row="1" - Grid.RowSpan="2" - Grid.Column="0" - Height="80" - MinWidth="50" - Margin="5,10,20,10" - Source="resm:Ryujinx.UI.Common.Resources.Logo_Ryujinx.png?assembly=Ryujinx.UI.Common" /> - <TextBlock - Grid.Row="1" - Grid.Column="1" - Margin="10" - VerticalAlignment="Stretch" - Text="{Binding Message}" - TextWrapping="Wrap" /> - <StackPanel - Name="ButtonStack" - Grid.Row="2" - Grid.Column="1" - Margin="10" - HorizontalAlignment="Right" - Orientation="Horizontal" - Spacing="10" /> - </Grid> -</Window> diff --git a/src/Ryujinx.Ava/UI/Applet/ErrorAppletWindow.axaml.cs b/src/Ryujinx.Ava/UI/Applet/ErrorAppletWindow.axaml.cs deleted file mode 100644 index ec6f7682..00000000 --- a/src/Ryujinx.Ava/UI/Applet/ErrorAppletWindow.axaml.cs +++ /dev/null @@ -1,74 +0,0 @@ -using Avalonia.Controls; -using Avalonia.Interactivity; -using Avalonia.Threading; -using Ryujinx.Ava.Common.Locale; -using Ryujinx.Ava.UI.Windows; -using System.Threading.Tasks; - -namespace Ryujinx.Ava.UI.Applet -{ - internal partial class ErrorAppletWindow : StyleableWindow - { - private readonly Window _owner; - private object _buttonResponse; - - public ErrorAppletWindow(Window owner, string[] buttons, string message) - { - _owner = owner; - Message = message; - DataContext = this; - InitializeComponent(); - - int responseId = 0; - - if (buttons != null) - { - foreach (string buttonText in buttons) - { - AddButton(buttonText, responseId); - responseId++; - } - } - else - { - AddButton(LocaleManager.Instance[LocaleKeys.InputDialogOk], 0); - } - } - - public ErrorAppletWindow() - { - DataContext = this; - InitializeComponent(); - } - - public string Message { get; set; } - - private void AddButton(string label, object tag) - { - Dispatcher.UIThread.InvokeAsync(() => - { - Button button = new() { Content = label, Tag = tag }; - - button.Click += Button_Click; - ButtonStack.Children.Add(button); - }); - } - - private void Button_Click(object sender, RoutedEventArgs e) - { - if (sender is Button button) - { - _buttonResponse = button.Tag; - } - - Close(); - } - - public async Task<object> Run() - { - await ShowDialog(_owner); - - return _buttonResponse; - } - } -} diff --git a/src/Ryujinx.Ava/UI/Applet/SwkbdAppletDialog.axaml b/src/Ryujinx.Ava/UI/Applet/SwkbdAppletDialog.axaml deleted file mode 100644 index b1c84734..00000000 --- a/src/Ryujinx.Ava/UI/Applet/SwkbdAppletDialog.axaml +++ /dev/null @@ -1,67 +0,0 @@ -<UserControl - x:Class="Ryujinx.Ava.UI.Controls.SwkbdAppletDialog" - xmlns="https://github.com/avaloniaui" - xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" - xmlns:d="http://schemas.microsoft.com/expression/blend/2008" - xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" - xmlns:views="using:Ryujinx.Ava.UI.Controls" - Width="400" - x:DataType="views:SwkbdAppletDialog" - mc:Ignorable="d" - Focusable="True"> - <Grid - Margin="20" - HorizontalAlignment="Stretch" - VerticalAlignment="Stretch"> - <Grid.RowDefinitions> - <RowDefinition Height="Auto" /> - <RowDefinition Height="Auto" /> - <RowDefinition Height="Auto" /> - <RowDefinition Height="Auto" /> - <RowDefinition Height="Auto" /> - </Grid.RowDefinitions> - <Grid.ColumnDefinitions> - <ColumnDefinition Width="Auto" /> - <ColumnDefinition /> - </Grid.ColumnDefinitions> - <Image - Grid.Row="1" - Grid.RowSpan="5" - Height="80" - MinWidth="50" - Margin="5,10,20,10" - VerticalAlignment="Center" - Source="resm:Ryujinx.UI.Common.Resources.Logo_Ryujinx.png?assembly=Ryujinx.UI.Common" /> - <TextBlock - Grid.Row="1" - Grid.Column="1" - Margin="5" - Text="{Binding MainText}" - TextWrapping="Wrap" /> - <TextBlock - Grid.Row="2" - Grid.Column="1" - Margin="5" - Text="{Binding SecondaryText}" - TextWrapping="Wrap" /> - <TextBox - Name="Input" - Grid.Row="3" - Grid.Column="1" - HorizontalAlignment="Stretch" - VerticalAlignment="Center" - Focusable="True" - KeyUp="Message_KeyUp" - Text="{Binding Message}" - TextInput="Message_TextInput" - TextWrapping="Wrap" - UseFloatingWatermark="True" /> - <TextBlock - Name="Error" - Grid.Row="4" - Grid.Column="1" - Margin="5" - HorizontalAlignment="Stretch" - TextWrapping="Wrap" /> - </Grid> -</UserControl> diff --git a/src/Ryujinx.Ava/UI/Applet/SwkbdAppletDialog.axaml.cs b/src/Ryujinx.Ava/UI/Applet/SwkbdAppletDialog.axaml.cs deleted file mode 100644 index af3837e4..00000000 --- a/src/Ryujinx.Ava/UI/Applet/SwkbdAppletDialog.axaml.cs +++ /dev/null @@ -1,183 +0,0 @@ -using Avalonia.Controls; -using Avalonia.Input; -using Avalonia.Interactivity; -using Avalonia.Media; -using FluentAvalonia.UI.Controls; -using Ryujinx.Ava.Common.Locale; -using Ryujinx.Ava.UI.Helpers; -using Ryujinx.HLE.HOS.Applets; -using Ryujinx.HLE.HOS.Applets.SoftwareKeyboard; -using System; -using System.Linq; -using System.Threading.Tasks; - -namespace Ryujinx.Ava.UI.Controls -{ - internal partial class SwkbdAppletDialog : UserControl - { - private Predicate<int> _checkLength = _ => true; - private Predicate<string> _checkInput = _ => true; - private int _inputMax; - private int _inputMin; - private readonly string _placeholder; - - private ContentDialog _host; - - public SwkbdAppletDialog(string mainText, string secondaryText, string placeholder, string message) - { - MainText = mainText; - SecondaryText = secondaryText; - Message = message ?? ""; - DataContext = this; - _placeholder = placeholder; - InitializeComponent(); - - Input.Watermark = _placeholder; - - Input.AddHandler(TextInputEvent, Message_TextInput, RoutingStrategies.Tunnel, true); - } - - public SwkbdAppletDialog() - { - DataContext = this; - InitializeComponent(); - } - - protected override void OnGotFocus(GotFocusEventArgs e) - { - // FIXME: This does not work. Might be a bug in Avalonia with DialogHost - // Currently focus will be redirected to the overlay window instead. - Input.Focus(); - } - - public string Message { get; set; } = ""; - public string MainText { get; set; } = ""; - public string SecondaryText { get; set; } = ""; - - public static async Task<(UserResult Result, string Input)> ShowInputDialog(string title, SoftwareKeyboardUIArgs args) - { - ContentDialog contentDialog = new(); - - UserResult result = UserResult.Cancel; - - SwkbdAppletDialog content = new(args.HeaderText, args.SubtitleText, args.GuideText, args.InitialText); - - string input = string.Empty; - - content.SetInputLengthValidation(args.StringLengthMin, args.StringLengthMax); - content.SetInputValidation(args.KeyboardMode); - - content._host = contentDialog; - contentDialog.Title = title; - contentDialog.PrimaryButtonText = args.SubmitText; - contentDialog.IsPrimaryButtonEnabled = content._checkLength(content.Message.Length); - contentDialog.SecondaryButtonText = ""; - contentDialog.CloseButtonText = LocaleManager.Instance[LocaleKeys.InputDialogCancel]; - contentDialog.Content = content; - - void Handler(ContentDialog sender, ContentDialogClosedEventArgs eventArgs) - { - if (eventArgs.Result == ContentDialogResult.Primary) - { - result = UserResult.Ok; - input = content.Input.Text; - } - } - - contentDialog.Closed += Handler; - - await ContentDialogHelper.ShowAsync(contentDialog); - - return (result, input); - } - - private void ApplyValidationInfo(string text) - { - Error.IsVisible = !string.IsNullOrEmpty(text); - Error.Text = text; - } - - public void SetInputLengthValidation(int min, int max) - { - _inputMin = Math.Min(min, max); - _inputMax = Math.Max(min, max); - - Error.IsVisible = false; - Error.FontStyle = FontStyle.Italic; - - string validationInfoText = ""; - - if (_inputMin <= 0 && _inputMax == int.MaxValue) // Disable. - { - Error.IsVisible = false; - - _checkLength = length => true; - } - else if (_inputMin > 0 && _inputMax == int.MaxValue) - { - validationInfoText = LocaleManager.Instance.UpdateAndGetDynamicValue(LocaleKeys.SwkbdMinCharacters, _inputMin); - - _checkLength = length => _inputMin <= length; - } - else - { - validationInfoText = LocaleManager.Instance.UpdateAndGetDynamicValue(LocaleKeys.SwkbdMinRangeCharacters, _inputMin, _inputMax); - - _checkLength = length => _inputMin <= length && length <= _inputMax; - } - - ApplyValidationInfo(validationInfoText); - Message_TextInput(this, new TextInputEventArgs()); - } - - private void SetInputValidation(KeyboardMode mode) - { - string validationInfoText = Error.Text; - string localeText; - switch (mode) - { - case KeyboardMode.Numeric: - localeText = LocaleManager.Instance.UpdateAndGetDynamicValue(LocaleKeys.SoftwareKeyboardModeNumeric); - validationInfoText = string.IsNullOrEmpty(validationInfoText) ? localeText : string.Join("\n", validationInfoText, localeText); - _checkInput = text => text.All(NumericCharacterValidation.IsNumeric); - break; - case KeyboardMode.Alphabet: - localeText = LocaleManager.Instance.UpdateAndGetDynamicValue(LocaleKeys.SoftwareKeyboardModeAlphabet); - validationInfoText = string.IsNullOrEmpty(validationInfoText) ? localeText : string.Join("\n", validationInfoText, localeText); - _checkInput = text => text.All(value => !CJKCharacterValidation.IsCJK(value)); - break; - case KeyboardMode.ASCII: - localeText = LocaleManager.Instance.UpdateAndGetDynamicValue(LocaleKeys.SoftwareKeyboardModeASCII); - validationInfoText = string.IsNullOrEmpty(validationInfoText) ? localeText : string.Join("\n", validationInfoText, localeText); - _checkInput = text => text.All(char.IsAscii); - break; - default: - _checkInput = _ => true; - break; - } - - ApplyValidationInfo(validationInfoText); - Message_TextInput(this, new TextInputEventArgs()); - } - - private void Message_TextInput(object sender, TextInputEventArgs e) - { - if (_host != null) - { - _host.IsPrimaryButtonEnabled = _checkLength(Message.Length) && _checkInput(Message); - } - } - - private void Message_KeyUp(object sender, KeyEventArgs e) - { - if (e.Key == Key.Enter && _host.IsPrimaryButtonEnabled) - { - _host.Hide(ContentDialogResult.Primary); - } - else - { - _host.IsPrimaryButtonEnabled = _checkLength(Message.Length) && _checkInput(Message); - } - } - } -} diff --git a/src/Ryujinx.Ava/UI/Controls/ApplicationContextMenu.axaml b/src/Ryujinx.Ava/UI/Controls/ApplicationContextMenu.axaml deleted file mode 100644 index dd0926fc..00000000 --- a/src/Ryujinx.Ava/UI/Controls/ApplicationContextMenu.axaml +++ /dev/null @@ -1,95 +0,0 @@ -<MenuFlyout - x:Class="Ryujinx.Ava.UI.Controls.ApplicationContextMenu" - xmlns="https://github.com/avaloniaui" - xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" - xmlns:locale="clr-namespace:Ryujinx.Ava.Common.Locale" - xmlns:viewModels="clr-namespace:Ryujinx.Ava.UI.ViewModels" - x:DataType="viewModels:MainWindowViewModel"> - <MenuItem - Click="RunApplication_Click" - Header="{locale:Locale GameListContextMenuRunApplication}" /> - <MenuItem - Click="ToggleFavorite_Click" - Header="{locale:Locale GameListContextMenuToggleFavorite}" - ToolTip.Tip="{locale:Locale GameListContextMenuToggleFavoriteToolTip}" /> - <MenuItem - Click="CreateApplicationShortcut_Click" - Header="{locale:Locale GameListContextMenuCreateShortcut}" - IsEnabled="{Binding CreateShortcutEnabled}" - ToolTip.Tip="{OnPlatform Default={locale:Locale GameListContextMenuCreateShortcutToolTip}, macOS={locale:Locale GameListContextMenuCreateShortcutToolTipMacOS}}" /> - <Separator /> - <MenuItem - Click="OpenUserSaveDirectory_Click" - Header="{locale:Locale GameListContextMenuOpenUserSaveDirectory}" - IsEnabled="{Binding OpenUserSaveDirectoryEnabled}" - ToolTip.Tip="{locale:Locale GameListContextMenuOpenUserSaveDirectoryToolTip}" /> - <MenuItem - Click="OpenDeviceSaveDirectory_Click" - Header="{locale:Locale GameListContextMenuOpenDeviceSaveDirectory}" - IsEnabled="{Binding OpenDeviceSaveDirectoryEnabled}" - ToolTip.Tip="{locale:Locale GameListContextMenuOpenDeviceSaveDirectoryToolTip}" /> - <MenuItem - Click="OpenBcatSaveDirectory_Click" - Header="{locale:Locale GameListContextMenuOpenBcatSaveDirectory}" - IsEnabled="{Binding OpenBcatSaveDirectoryEnabled}" - ToolTip.Tip="{locale:Locale GameListContextMenuOpenBcatSaveDirectoryToolTip}" /> - <Separator /> - <MenuItem - Click="OpenTitleUpdateManager_Click" - Header="{locale:Locale GameListContextMenuManageTitleUpdates}" - ToolTip.Tip="{locale:Locale GameListContextMenuManageTitleUpdatesToolTip}" /> - <MenuItem - Click="OpenDownloadableContentManager_Click" - Header="{locale:Locale GameListContextMenuManageDlc}" - ToolTip.Tip="{locale:Locale GameListContextMenuManageDlcToolTip}" /> - <MenuItem - Click="OpenCheatManager_Click" - Header="{locale:Locale GameListContextMenuManageCheat}" - ToolTip.Tip="{locale:Locale GameListContextMenuManageCheatToolTip}" /> - <MenuItem - Click="OpenModManager_Click" - Header="{locale:Locale GameListContextMenuManageMod}" - ToolTip.Tip="{locale:Locale GameListContextMenuManageModToolTip}" /> - <Separator /> - <MenuItem - Click="OpenModsDirectory_Click" - Header="{locale:Locale GameListContextMenuOpenModsDirectory}" - ToolTip.Tip="{locale:Locale GameListContextMenuOpenModsDirectoryToolTip}" /> - <MenuItem - Click="OpenSdModsDirectory_Click" - Header="{locale:Locale GameListContextMenuOpenSdModsDirectory}" - ToolTip.Tip="{locale:Locale GameListContextMenuOpenSdModsDirectoryToolTip}" /> - <Separator /> - <MenuItem Header="{locale:Locale GameListContextMenuCacheManagement}"> - <MenuItem - Click="PurgePtcCache_Click" - Header="{locale:Locale GameListContextMenuCacheManagementPurgePptc}" - ToolTip.Tip="{locale:Locale GameListContextMenuCacheManagementPurgePptcToolTip}" /> - <MenuItem - Click="PurgeShaderCache_Click" - Header="{locale:Locale GameListContextMenuCacheManagementPurgeShaderCache}" - ToolTip.Tip="{locale:Locale GameListContextMenuCacheManagementPurgeShaderCacheToolTip}" /> - <MenuItem - Click="OpenPtcDirectory_Click" - Header="{locale:Locale GameListContextMenuCacheManagementOpenPptcDirectory}" - ToolTip.Tip="{locale:Locale GameListContextMenuCacheManagementOpenPptcDirectoryToolTip}" /> - <MenuItem - Click="OpenShaderCacheDirectory_Click" - Header="{locale:Locale GameListContextMenuCacheManagementOpenShaderCacheDirectory}" - ToolTip.Tip="{locale:Locale GameListContextMenuCacheManagementOpenShaderCacheDirectoryToolTip}" /> - </MenuItem> - <MenuItem Header="{locale:Locale GameListContextMenuExtractData}"> - <MenuItem - Click="ExtractApplicationExeFs_Click" - Header="{locale:Locale GameListContextMenuExtractDataExeFS}" - ToolTip.Tip="{locale:Locale GameListContextMenuExtractDataExeFSToolTip}" /> - <MenuItem - Click="ExtractApplicationRomFs_Click" - Header="{locale:Locale GameListContextMenuExtractDataRomFS}" - ToolTip.Tip="{locale:Locale GameListContextMenuExtractDataRomFSToolTip}" /> - <MenuItem - Click="ExtractApplicationLogo_Click" - Header="{locale:Locale GameListContextMenuExtractDataLogo}" - ToolTip.Tip="{locale:Locale GameListContextMenuExtractDataLogoToolTip}" /> - </MenuItem> -</MenuFlyout> diff --git a/src/Ryujinx.Ava/UI/Controls/ApplicationContextMenu.axaml.cs b/src/Ryujinx.Ava/UI/Controls/ApplicationContextMenu.axaml.cs deleted file mode 100644 index 894ac6c1..00000000 --- a/src/Ryujinx.Ava/UI/Controls/ApplicationContextMenu.axaml.cs +++ /dev/null @@ -1,371 +0,0 @@ -using Avalonia.Controls; -using Avalonia.Interactivity; -using Avalonia.Markup.Xaml; -using Avalonia.Threading; -using LibHac.Fs; -using LibHac.Tools.FsSystem.NcaUtils; -using Ryujinx.Ava.Common; -using Ryujinx.Ava.Common.Locale; -using Ryujinx.Ava.UI.Helpers; -using Ryujinx.Ava.UI.ViewModels; -using Ryujinx.Ava.UI.Windows; -using Ryujinx.Common.Configuration; -using Ryujinx.HLE.HOS; -using Ryujinx.UI.App.Common; -using Ryujinx.UI.Common.Helper; -using System; -using System.Collections.Generic; -using System.Globalization; -using System.IO; -using Path = System.IO.Path; - -namespace Ryujinx.Ava.UI.Controls -{ - public class ApplicationContextMenu : MenuFlyout - { - public ApplicationContextMenu() - { - InitializeComponent(); - } - - private void InitializeComponent() - { - AvaloniaXamlLoader.Load(this); - } - - public void ToggleFavorite_Click(object sender, RoutedEventArgs args) - { - var viewModel = (sender as MenuItem)?.DataContext as MainWindowViewModel; - - if (viewModel?.SelectedApplication != null) - { - viewModel.SelectedApplication.Favorite = !viewModel.SelectedApplication.Favorite; - - ApplicationLibrary.LoadAndSaveMetaData(viewModel.SelectedApplication.TitleId, appMetadata => - { - appMetadata.Favorite = viewModel.SelectedApplication.Favorite; - }); - - viewModel.RefreshView(); - } - } - - public void OpenUserSaveDirectory_Click(object sender, RoutedEventArgs args) - { - if (sender is MenuItem { DataContext: MainWindowViewModel 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) - { - var viewModel = (sender as MenuItem)?.DataContext as MainWindowViewModel; - - OpenSaveDirectory(viewModel, SaveDataType.Device, default); - } - - public void OpenBcatSaveDirectory_Click(object sender, RoutedEventArgs args) - { - var viewModel = (sender as MenuItem)?.DataContext as MainWindowViewModel; - - OpenSaveDirectory(viewModel, SaveDataType.Bcat, default); - } - - private static void OpenSaveDirectory(MainWindowViewModel viewModel, SaveDataType saveDataType, UserId userId) - { - if (viewModel?.SelectedApplication != null) - { - if (!ulong.TryParse(viewModel.SelectedApplication.TitleId, NumberStyles.HexNumber, CultureInfo.InvariantCulture, out ulong titleIdNumber)) - { - Dispatcher.UIThread.InvokeAsync(async () => - { - await ContentDialogHelper.CreateErrorDialog(LocaleManager.Instance[LocaleKeys.DialogRyujinxErrorMessage], LocaleManager.Instance[LocaleKeys.DialogInvalidTitleIdErrorMessage]); - }); - - return; - } - - var saveDataFilter = SaveDataFilter.Make(titleIdNumber, saveDataType, userId, saveDataId: default, index: default); - - ApplicationHelper.OpenSaveDir(in saveDataFilter, titleIdNumber, viewModel.SelectedApplication.ControlHolder, viewModel.SelectedApplication.TitleName); - } - } - - public async void OpenTitleUpdateManager_Click(object sender, RoutedEventArgs args) - { - var viewModel = (sender as MenuItem)?.DataContext as MainWindowViewModel; - - if (viewModel?.SelectedApplication != null) - { - await TitleUpdateWindow.Show(viewModel.VirtualFileSystem, ulong.Parse(viewModel.SelectedApplication.TitleId, NumberStyles.HexNumber), viewModel.SelectedApplication.TitleName); - } - } - - public async void OpenDownloadableContentManager_Click(object sender, RoutedEventArgs args) - { - var viewModel = (sender as MenuItem)?.DataContext as MainWindowViewModel; - - if (viewModel?.SelectedApplication != null) - { - await DownloadableContentManagerWindow.Show(viewModel.VirtualFileSystem, ulong.Parse(viewModel.SelectedApplication.TitleId, NumberStyles.HexNumber), viewModel.SelectedApplication.TitleName); - } - } - - public async void OpenCheatManager_Click(object sender, RoutedEventArgs args) - { - var viewModel = (sender as MenuItem)?.DataContext as MainWindowViewModel; - - if (viewModel?.SelectedApplication != null) - { - await new CheatWindow( - viewModel.VirtualFileSystem, - viewModel.SelectedApplication.TitleId, - viewModel.SelectedApplication.TitleName, - viewModel.SelectedApplication.Path).ShowDialog(viewModel.TopLevel as Window); - } - } - - public void OpenModsDirectory_Click(object sender, RoutedEventArgs args) - { - var viewModel = (sender as MenuItem)?.DataContext as MainWindowViewModel; - - if (viewModel?.SelectedApplication != null) - { - string modsBasePath = ModLoader.GetModsBasePath(); - string titleModsPath = ModLoader.GetApplicationDir(modsBasePath, viewModel.SelectedApplication.TitleId); - - OpenHelper.OpenFolder(titleModsPath); - } - } - - public void OpenSdModsDirectory_Click(object sender, RoutedEventArgs args) - { - var viewModel = (sender as MenuItem)?.DataContext as MainWindowViewModel; - - if (viewModel?.SelectedApplication != null) - { - string sdModsBasePath = ModLoader.GetSdModsBasePath(); - string titleModsPath = ModLoader.GetApplicationDir(sdModsBasePath, viewModel.SelectedApplication.TitleId); - - OpenHelper.OpenFolder(titleModsPath); - } - } - - public async void OpenModManager_Click(object sender, RoutedEventArgs args) - { - var viewModel = (sender as MenuItem)?.DataContext as MainWindowViewModel; - - if (viewModel?.SelectedApplication != null) - { - await ModManagerWindow.Show(ulong.Parse(viewModel.SelectedApplication.TitleId, NumberStyles.HexNumber), viewModel.SelectedApplication.TitleName); - } - } - - public async void PurgePtcCache_Click(object sender, RoutedEventArgs args) - { - var viewModel = (sender as MenuItem)?.DataContext as MainWindowViewModel; - - if (viewModel?.SelectedApplication != null) - { - UserResult result = await ContentDialogHelper.CreateConfirmationDialog( - LocaleManager.Instance[LocaleKeys.DialogWarning], - LocaleManager.Instance.UpdateAndGetDynamicValue(LocaleKeys.DialogPPTCDeletionMessage, viewModel.SelectedApplication.TitleName), - LocaleManager.Instance[LocaleKeys.InputDialogYes], - LocaleManager.Instance[LocaleKeys.InputDialogNo], - LocaleManager.Instance[LocaleKeys.RyujinxConfirm]); - - if (result == UserResult.Yes) - { - DirectoryInfo mainDir = new(Path.Combine(AppDataManager.GamesDirPath, viewModel.SelectedApplication.TitleId, "cache", "cpu", "0")); - DirectoryInfo backupDir = new(Path.Combine(AppDataManager.GamesDirPath, viewModel.SelectedApplication.TitleId, "cache", "cpu", "1")); - - List<FileInfo> cacheFiles = new(); - - 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 async void PurgeShaderCache_Click(object sender, RoutedEventArgs args) - { - var viewModel = (sender as MenuItem)?.DataContext as MainWindowViewModel; - - if (viewModel?.SelectedApplication != null) - { - UserResult result = await ContentDialogHelper.CreateConfirmationDialog( - LocaleManager.Instance[LocaleKeys.DialogWarning], - LocaleManager.Instance.UpdateAndGetDynamicValue(LocaleKeys.DialogShaderDeletionMessage, viewModel.SelectedApplication.TitleName), - LocaleManager.Instance[LocaleKeys.InputDialogYes], - LocaleManager.Instance[LocaleKeys.InputDialogNo], - LocaleManager.Instance[LocaleKeys.RyujinxConfirm]); - - if (result == UserResult.Yes) - { - DirectoryInfo shaderCacheDir = new(Path.Combine(AppDataManager.GamesDirPath, viewModel.SelectedApplication.TitleId, "cache", "shader")); - - List<DirectoryInfo> oldCacheDirectories = new(); - List<FileInfo> newCacheFiles = new(); - - 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 void OpenPtcDirectory_Click(object sender, RoutedEventArgs args) - { - var viewModel = (sender as MenuItem)?.DataContext as MainWindowViewModel; - - if (viewModel?.SelectedApplication != null) - { - string ptcDir = Path.Combine(AppDataManager.GamesDirPath, viewModel.SelectedApplication.TitleId, "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 void OpenShaderCacheDirectory_Click(object sender, RoutedEventArgs args) - { - var viewModel = (sender as MenuItem)?.DataContext as MainWindowViewModel; - - if (viewModel?.SelectedApplication != null) - { - string shaderCacheDir = Path.Combine(AppDataManager.GamesDirPath, viewModel.SelectedApplication.TitleId, "cache", "shader"); - - if (!Directory.Exists(shaderCacheDir)) - { - Directory.CreateDirectory(shaderCacheDir); - } - - OpenHelper.OpenFolder(shaderCacheDir); - } - } - - public async void ExtractApplicationExeFs_Click(object sender, RoutedEventArgs args) - { - var viewModel = (sender as MenuItem)?.DataContext as MainWindowViewModel; - - if (viewModel?.SelectedApplication != null) - { - await ApplicationHelper.ExtractSection( - viewModel.StorageProvider, - NcaSectionType.Code, - viewModel.SelectedApplication.Path, - viewModel.SelectedApplication.TitleName); - } - } - - public async void ExtractApplicationRomFs_Click(object sender, RoutedEventArgs args) - { - var viewModel = (sender as MenuItem)?.DataContext as MainWindowViewModel; - - if (viewModel?.SelectedApplication != null) - { - await ApplicationHelper.ExtractSection( - viewModel.StorageProvider, - NcaSectionType.Data, - viewModel.SelectedApplication.Path, - viewModel.SelectedApplication.TitleName); - } - } - - public async void ExtractApplicationLogo_Click(object sender, RoutedEventArgs args) - { - var viewModel = (sender as MenuItem)?.DataContext as MainWindowViewModel; - - if (viewModel?.SelectedApplication != null) - { - await ApplicationHelper.ExtractSection( - viewModel.StorageProvider, - NcaSectionType.Logo, - viewModel.SelectedApplication.Path, - viewModel.SelectedApplication.TitleName); - } - } - - public void CreateApplicationShortcut_Click(object sender, RoutedEventArgs args) - { - var viewModel = (sender as MenuItem)?.DataContext as MainWindowViewModel; - - if (viewModel?.SelectedApplication != null) - { - ApplicationData selectedApplication = viewModel.SelectedApplication; - ShortcutHelper.CreateAppShortcut(selectedApplication.Path, selectedApplication.TitleName, selectedApplication.TitleId, selectedApplication.Icon); - } - } - - public async void RunApplication_Click(object sender, RoutedEventArgs args) - { - var viewModel = (sender as MenuItem)?.DataContext as MainWindowViewModel; - - if (viewModel?.SelectedApplication != null) - { - await viewModel.LoadApplication(viewModel.SelectedApplication.Path); - } - } - } -} diff --git a/src/Ryujinx.Ava/UI/Controls/ApplicationGridView.axaml b/src/Ryujinx.Ava/UI/Controls/ApplicationGridView.axaml deleted file mode 100644 index 2dc95662..00000000 --- a/src/Ryujinx.Ava/UI/Controls/ApplicationGridView.axaml +++ /dev/null @@ -1,102 +0,0 @@ -<UserControl - x:Class="Ryujinx.Ava.UI.Controls.ApplicationGridView" - xmlns="https://github.com/avaloniaui" - xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" - xmlns:controls="clr-namespace:Ryujinx.Ava.UI.Controls" - xmlns:d="http://schemas.microsoft.com/expression/blend/2008" - xmlns:helpers="clr-namespace:Ryujinx.Ava.UI.Helpers" - xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" - xmlns:ui="clr-namespace:FluentAvalonia.UI.Controls;assembly=FluentAvalonia" - d:DesignHeight="450" - d:DesignWidth="800" - Focusable="True" - mc:Ignorable="d" - xmlns:viewModels="clr-namespace:Ryujinx.Ava.UI.ViewModels" - x:DataType="viewModels:MainWindowViewModel"> - <UserControl.Resources> - <helpers:BitmapArrayValueConverter x:Key="ByteImage" /> - <controls:ApplicationContextMenu x:Key="ApplicationContextMenu" /> - </UserControl.Resources> - <Grid> - <Grid.RowDefinitions> - <RowDefinition Height="*" /> - </Grid.RowDefinitions> - <ListBox - Grid.Row="0" - Padding="8" - HorizontalAlignment="Stretch" - VerticalAlignment="Stretch" - ContextFlyout="{StaticResource ApplicationContextMenu}" - DoubleTapped="GameList_DoubleTapped" - ItemsSource="{Binding AppsObservableList}" - SelectionChanged="GameList_SelectionChanged"> - <ListBox.ItemsPanel> - <ItemsPanelTemplate> - <WrapPanel - HorizontalAlignment="Center" - VerticalAlignment="Top" - Orientation="Horizontal" /> - </ItemsPanelTemplate> - </ListBox.ItemsPanel> - <ListBox.Styles> - <Style Selector="ListBoxItem"> - <Setter Property="Margin" Value="5" /> - <Setter Property="CornerRadius" Value="4" /> - </Style> - <Style Selector="ListBoxItem:selected /template/ Rectangle#SelectionIndicator"> - <Setter Property="MinHeight" Value="{Binding $parent[UserControl].((viewModels:MainWindowViewModel)DataContext).GridItemSelectorSize}" /> - </Style> - </ListBox.Styles> - <ListBox.ItemTemplate> - <DataTemplate> - <Grid> - <Border - Margin="10" - HorizontalAlignment="Stretch" - VerticalAlignment="Stretch" - Classes.huge="{Binding $parent[UserControl].((viewModels:MainWindowViewModel)DataContext).IsGridHuge}" - Classes.large="{Binding $parent[UserControl].((viewModels:MainWindowViewModel)DataContext).IsGridLarge}" - Classes.normal="{Binding $parent[UserControl].((viewModels:MainWindowViewModel)DataContext).IsGridMedium}" - Classes.small="{Binding $parent[UserControl].((viewModels:MainWindowViewModel)DataContext).IsGridSmall}" - ClipToBounds="True" - CornerRadius="4"> - <Grid> - <Grid.RowDefinitions> - <RowDefinition Height="Auto" /> - <RowDefinition Height="Auto" /> - </Grid.RowDefinitions> - <Image - Grid.Row="0" - HorizontalAlignment="Stretch" - VerticalAlignment="Top" - Source="{Binding Icon, Converter={StaticResource ByteImage}}" /> - <Panel - Grid.Row="1" - Height="50" - Margin="0,10,0,0" - HorizontalAlignment="Stretch" - VerticalAlignment="Stretch" - IsVisible="{Binding $parent[UserControl].((viewModels:MainWindowViewModel)DataContext).ShowNames}"> - <TextBlock - HorizontalAlignment="Center" - VerticalAlignment="Center" - Text="{Binding TitleName}" - TextAlignment="Center" - TextWrapping="Wrap" /> - </Panel> - </Grid> - </Border> - <ui:SymbolIcon - Margin="5,5,0,0" - HorizontalAlignment="Left" - VerticalAlignment="Top" - FontSize="16" - Foreground="{DynamicResource SystemAccentColor}" - IsVisible="{Binding Favorite}" - Symbol="StarFilled" /> - </Grid> - </DataTemplate> - </ListBox.ItemTemplate> - </ListBox> - </Grid> -</UserControl> diff --git a/src/Ryujinx.Ava/UI/Controls/ApplicationGridView.axaml.cs b/src/Ryujinx.Ava/UI/Controls/ApplicationGridView.axaml.cs deleted file mode 100644 index ee15bc8d..00000000 --- a/src/Ryujinx.Ava/UI/Controls/ApplicationGridView.axaml.cs +++ /dev/null @@ -1,51 +0,0 @@ -using Avalonia.Controls; -using Avalonia.Input; -using Avalonia.Interactivity; -using Ryujinx.Ava.UI.Helpers; -using Ryujinx.Ava.UI.ViewModels; -using Ryujinx.UI.App.Common; -using System; - -namespace Ryujinx.Ava.UI.Controls -{ - public partial class ApplicationGridView : UserControl - { - public static readonly RoutedEvent<ApplicationOpenedEventArgs> ApplicationOpenedEvent = - RoutedEvent.Register<ApplicationGridView, ApplicationOpenedEventArgs>(nameof(ApplicationOpened), RoutingStrategies.Bubble); - - public event EventHandler<ApplicationOpenedEventArgs> ApplicationOpened - { - add { AddHandler(ApplicationOpenedEvent, value); } - remove { RemoveHandler(ApplicationOpenedEvent, value); } - } - - public ApplicationGridView() - { - InitializeComponent(); - } - - public void GameList_DoubleTapped(object sender, TappedEventArgs args) - { - if (sender is ListBox listBox) - { - if (listBox.SelectedItem is ApplicationData selected) - { - RaiseEvent(new ApplicationOpenedEventArgs(selected, ApplicationOpenedEvent)); - } - } - } - - public void GameList_SelectionChanged(object sender, SelectionChangedEventArgs args) - { - if (sender is ListBox listBox) - { - (DataContext as MainWindowViewModel).GridSelectedApplication = listBox.SelectedItem as ApplicationData; - } - } - - private void SearchBox_OnKeyUp(object sender, KeyEventArgs args) - { - (DataContext as MainWindowViewModel).SearchText = (sender as TextBox).Text; - } - } -} diff --git a/src/Ryujinx.Ava/UI/Controls/ApplicationListView.axaml b/src/Ryujinx.Ava/UI/Controls/ApplicationListView.axaml deleted file mode 100644 index fecf0888..00000000 --- a/src/Ryujinx.Ava/UI/Controls/ApplicationListView.axaml +++ /dev/null @@ -1,160 +0,0 @@ -<UserControl - x:Class="Ryujinx.Ava.UI.Controls.ApplicationListView" - xmlns="https://github.com/avaloniaui" - xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" - xmlns:controls="clr-namespace:Ryujinx.Ava.UI.Controls" - xmlns:d="http://schemas.microsoft.com/expression/blend/2008" - xmlns:helpers="clr-namespace:Ryujinx.Ava.UI.Helpers" - xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" - xmlns:ui="clr-namespace:FluentAvalonia.UI.Controls;assembly=FluentAvalonia" - d:DesignHeight="450" - d:DesignWidth="800" - Focusable="True" - mc:Ignorable="d" - xmlns:viewModels="clr-namespace:Ryujinx.Ava.UI.ViewModels" - x:DataType="viewModels:MainWindowViewModel"> - <UserControl.Resources> - <helpers:BitmapArrayValueConverter x:Key="ByteImage" /> - <controls:ApplicationContextMenu x:Key="ApplicationContextMenu" /> - </UserControl.Resources> - <Grid> - <Grid.RowDefinitions> - <RowDefinition Height="*" /> - </Grid.RowDefinitions> - <ListBox - Name="GameListBox" - Grid.Row="0" - Padding="8" - HorizontalAlignment="Stretch" - VerticalAlignment="Stretch" - ContextFlyout="{StaticResource ApplicationContextMenu}" - DoubleTapped="GameList_DoubleTapped" - ItemsSource="{Binding AppsObservableList}" - SelectionChanged="GameList_SelectionChanged"> - <ListBox.ItemsPanel> - <ItemsPanelTemplate> - <StackPanel - HorizontalAlignment="Stretch" - VerticalAlignment="Stretch" - Orientation="Vertical" - Spacing="2" /> - </ItemsPanelTemplate> - </ListBox.ItemsPanel> - <ListBox.Styles> - <Style Selector="ListBoxItem:selected /template/ Rectangle#SelectionIndicator"> - <Setter Property="MinHeight" Value="{Binding $parent[UserControl].((viewModels:MainWindowViewModel)DataContext).ListItemSelectorSize}" /> - </Style> - </ListBox.Styles> - <ListBox.ItemTemplate> - <DataTemplate> - <Grid> - <Border - Margin="0" - Padding="10" - HorizontalAlignment="Stretch" - VerticalAlignment="Stretch" - ClipToBounds="True" - CornerRadius="5"> - <Grid> - <Grid.ColumnDefinitions> - <ColumnDefinition Width="Auto" /> - <ColumnDefinition Width="10" /> - <ColumnDefinition Width="*" /> - <ColumnDefinition Width="150" /> - <ColumnDefinition Width="100" /> - </Grid.ColumnDefinitions> - <Image - Grid.RowSpan="3" - Grid.Column="0" - Margin="0" - Classes.huge="{Binding $parent[UserControl].((viewModels:MainWindowViewModel)DataContext).IsGridHuge}" - Classes.large="{Binding $parent[UserControl].((viewModels:MainWindowViewModel)DataContext).IsGridLarge}" - Classes.normal="{Binding $parent[UserControl].((viewModels:MainWindowViewModel)DataContext).IsGridMedium}" - Classes.small="{Binding $parent[UserControl].((viewModels:MainWindowViewModel)DataContext).IsGridSmall}" - Source="{Binding Icon, Converter={StaticResource ByteImage}}" /> - <Border - Grid.Column="2" - Margin="0,0,5,0" - BorderBrush="{DynamicResource ThemeControlBorderColor}" - BorderThickness="0,0,1,0"> - <StackPanel - HorizontalAlignment="Left" - VerticalAlignment="Top" - Orientation="Vertical" - Spacing="5"> - <TextBlock - HorizontalAlignment="Stretch" - FontWeight="Bold" - Text="{Binding TitleName}" - TextAlignment="Start" - TextWrapping="Wrap" /> - <TextBlock - HorizontalAlignment="Stretch" - Text="{Binding Developer}" - TextAlignment="Start" - TextWrapping="Wrap" /> - <TextBlock - HorizontalAlignment="Stretch" - Text="{Binding Version}" - TextAlignment="Start" - TextWrapping="Wrap" /> - </StackPanel> - </Border> - <StackPanel - Grid.Column="3" - Margin="10,0,0,0" - HorizontalAlignment="Left" - VerticalAlignment="Top" - Orientation="Vertical" - Spacing="5"> - <TextBlock - HorizontalAlignment="Stretch" - Text="{Binding TitleId}" - TextAlignment="Start" - TextWrapping="Wrap" /> - <TextBlock - HorizontalAlignment="Stretch" - Text="{Binding FileExtension}" - TextAlignment="Start" - TextWrapping="Wrap" /> - </StackPanel> - <StackPanel - Grid.Column="4" - HorizontalAlignment="Right" - VerticalAlignment="Top" - Orientation="Vertical" - Spacing="5"> - <TextBlock - HorizontalAlignment="Stretch" - Text="{Binding TimePlayedString}" - TextAlignment="End" - TextWrapping="Wrap" /> - <TextBlock - HorizontalAlignment="Stretch" - Text="{Binding LastPlayedString, Converter={helpers:LocalizedNeverConverter}}" - TextAlignment="End" - TextWrapping="Wrap" /> - <TextBlock - HorizontalAlignment="Stretch" - Text="{Binding FileSizeString}" - TextAlignment="End" - TextWrapping="Wrap" /> - </StackPanel> - <ui:SymbolIcon - Grid.Row="0" - Grid.Column="0" - Margin="-5,-5,0,0" - HorizontalAlignment="Left" - VerticalAlignment="Top" - FontSize="16" - Foreground="{DynamicResource SystemAccentColor}" - IsVisible="{Binding Favorite}" - Symbol="StarFilled" /> - </Grid> - </Border> - </Grid> - </DataTemplate> - </ListBox.ItemTemplate> - </ListBox> - </Grid> -</UserControl> diff --git a/src/Ryujinx.Ava/UI/Controls/ApplicationListView.axaml.cs b/src/Ryujinx.Ava/UI/Controls/ApplicationListView.axaml.cs deleted file mode 100644 index 8681158f..00000000 --- a/src/Ryujinx.Ava/UI/Controls/ApplicationListView.axaml.cs +++ /dev/null @@ -1,51 +0,0 @@ -using Avalonia.Controls; -using Avalonia.Input; -using Avalonia.Interactivity; -using Ryujinx.Ava.UI.Helpers; -using Ryujinx.Ava.UI.ViewModels; -using Ryujinx.UI.App.Common; -using System; - -namespace Ryujinx.Ava.UI.Controls -{ - public partial class ApplicationListView : UserControl - { - public static readonly RoutedEvent<ApplicationOpenedEventArgs> ApplicationOpenedEvent = - RoutedEvent.Register<ApplicationListView, ApplicationOpenedEventArgs>(nameof(ApplicationOpened), RoutingStrategies.Bubble); - - public event EventHandler<ApplicationOpenedEventArgs> ApplicationOpened - { - add { AddHandler(ApplicationOpenedEvent, value); } - remove { RemoveHandler(ApplicationOpenedEvent, value); } - } - - public ApplicationListView() - { - InitializeComponent(); - } - - public void GameList_DoubleTapped(object sender, TappedEventArgs args) - { - if (sender is ListBox listBox) - { - if (listBox.SelectedItem is ApplicationData selected) - { - RaiseEvent(new ApplicationOpenedEventArgs(selected, ApplicationOpenedEvent)); - } - } - } - - public void GameList_SelectionChanged(object sender, SelectionChangedEventArgs args) - { - if (sender is ListBox listBox) - { - (DataContext as MainWindowViewModel).ListSelectedApplication = listBox.SelectedItem as ApplicationData; - } - } - - private void SearchBox_OnKeyUp(object sender, KeyEventArgs args) - { - (DataContext as MainWindowViewModel).SearchText = (sender as TextBox).Text; - } - } -} diff --git a/src/Ryujinx.Ava/UI/Controls/NavigationDialogHost.axaml b/src/Ryujinx.Ava/UI/Controls/NavigationDialogHost.axaml deleted file mode 100644 index bf34b303..00000000 --- a/src/Ryujinx.Ava/UI/Controls/NavigationDialogHost.axaml +++ /dev/null @@ -1,17 +0,0 @@ -<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:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" - xmlns:ui="clr-namespace:FluentAvalonia.UI.Controls;assembly=FluentAvalonia" - mc:Ignorable="d" - d:DesignWidth="800" - d:DesignHeight="450" - x:Class="Ryujinx.Ava.UI.Controls.NavigationDialogHost" - Focusable="True"> - <ui:Frame - HorizontalAlignment="Stretch" - VerticalAlignment="Stretch" - x:Name="ContentFrame"> - </ui:Frame> -</UserControl>
\ No newline at end of file diff --git a/src/Ryujinx.Ava/UI/Controls/NavigationDialogHost.axaml.cs b/src/Ryujinx.Ava/UI/Controls/NavigationDialogHost.axaml.cs deleted file mode 100644 index a32c052b..00000000 --- a/src/Ryujinx.Ava/UI/Controls/NavigationDialogHost.axaml.cs +++ /dev/null @@ -1,217 +0,0 @@ -using Avalonia; -using Avalonia.Controls; -using Avalonia.Styling; -using Avalonia.Threading; -using FluentAvalonia.UI.Controls; -using LibHac; -using LibHac.Common; -using LibHac.Fs; -using LibHac.Fs.Shim; -using Ryujinx.Ava.Common.Locale; -using Ryujinx.Ava.UI.Helpers; -using Ryujinx.Ava.UI.ViewModels; -using Ryujinx.Ava.UI.Views.User; -using Ryujinx.HLE.FileSystem; -using Ryujinx.HLE.HOS.Services.Account.Acc; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; -using UserId = Ryujinx.HLE.HOS.Services.Account.Acc.UserId; -using UserProfile = Ryujinx.Ava.UI.Models.UserProfile; - -namespace Ryujinx.Ava.UI.Controls -{ - public partial class NavigationDialogHost : UserControl - { - public AccountManager AccountManager { get; } - public ContentManager ContentManager { get; } - public VirtualFileSystem VirtualFileSystem { get; } - public HorizonClient HorizonClient { get; } - public UserProfileViewModel ViewModel { get; set; } - - public NavigationDialogHost() - { - InitializeComponent(); - } - - public NavigationDialogHost(AccountManager accountManager, ContentManager contentManager, - VirtualFileSystem virtualFileSystem, HorizonClient horizonClient) - { - AccountManager = accountManager; - ContentManager = contentManager; - VirtualFileSystem = virtualFileSystem; - HorizonClient = horizonClient; - ViewModel = new UserProfileViewModel(); - LoadProfiles(); - - if (contentManager.GetCurrentFirmwareVersion() != null) - { - Task.Run(() => - { - UserFirmwareAvatarSelectorViewModel.PreloadAvatars(contentManager, virtualFileSystem); - }); - } - InitializeComponent(); - } - - public void GoBack() - { - if (ContentFrame.BackStack.Count > 0) - { - ContentFrame.GoBack(); - } - - LoadProfiles(); - } - - public void Navigate(Type sourcePageType, object parameter) - { - ContentFrame.Navigate(sourcePageType, parameter); - } - - public static async Task Show(AccountManager ownerAccountManager, ContentManager ownerContentManager, - VirtualFileSystem ownerVirtualFileSystem, HorizonClient ownerHorizonClient) - { - var content = new NavigationDialogHost(ownerAccountManager, ownerContentManager, ownerVirtualFileSystem, ownerHorizonClient); - ContentDialog contentDialog = new() - { - Title = LocaleManager.Instance[LocaleKeys.UserProfileWindowTitle], - PrimaryButtonText = "", - SecondaryButtonText = "", - CloseButtonText = "", - Content = content, - Padding = new Thickness(0), - }; - - contentDialog.Closed += (sender, args) => - { - content.ViewModel.Dispose(); - }; - - Style footer = new(x => x.Name("DialogSpace").Child().OfType<Border>()); - footer.Setters.Add(new Setter(IsVisibleProperty, false)); - - contentDialog.Styles.Add(footer); - - await contentDialog.ShowAsync(); - } - - protected override void OnAttachedToVisualTree(VisualTreeAttachmentEventArgs e) - { - base.OnAttachedToVisualTree(e); - - Navigate(typeof(UserSelectorViews), this); - } - - public void LoadProfiles() - { - ViewModel.Profiles.Clear(); - ViewModel.LostProfiles.Clear(); - - var profiles = AccountManager.GetAllUsers().OrderBy(x => x.Name); - - foreach (var profile in profiles) - { - ViewModel.Profiles.Add(new UserProfile(profile, this)); - } - - var saveDataFilter = SaveDataFilter.Make(programId: default, saveType: SaveDataType.Account, default, saveDataId: default, index: default); - - using var saveDataIterator = new UniqueRef<SaveDataIterator>(); - - HorizonClient.Fs.OpenSaveDataIterator(ref saveDataIterator.Ref, SaveDataSpaceId.User, in saveDataFilter).ThrowIfFailure(); - - Span<SaveDataInfo> saveDataInfo = stackalloc SaveDataInfo[10]; - - HashSet<UserId> lostAccounts = new(); - - while (true) - { - saveDataIterator.Get.ReadSaveDataInfo(out long readCount, saveDataInfo).ThrowIfFailure(); - - if (readCount == 0) - { - break; - } - - for (int i = 0; i < readCount; i++) - { - var save = saveDataInfo[i]; - var id = new UserId((long)save.UserId.Id.Low, (long)save.UserId.Id.High); - if (ViewModel.Profiles.Cast<UserProfile>().FirstOrDefault(x => x.UserId == id) == null) - { - lostAccounts.Add(id); - } - } - } - - foreach (var account in lostAccounts) - { - ViewModel.LostProfiles.Add(new UserProfile(new HLE.HOS.Services.Account.Acc.UserProfile(account, "", null), this)); - } - - ViewModel.Profiles.Add(new BaseModel()); - } - - public async void DeleteUser(UserProfile userProfile) - { - var lastUserId = AccountManager.LastOpenedUser.UserId; - - if (userProfile.UserId == lastUserId) - { - // If we are deleting the currently open profile, then we must open something else before deleting. - var profile = ViewModel.Profiles.Cast<UserProfile>().FirstOrDefault(x => x.UserId != lastUserId); - - if (profile == null) - { - static async void Action() - { - await ContentDialogHelper.CreateErrorDialog(LocaleManager.Instance[LocaleKeys.DialogUserProfileDeletionWarningMessage]); - } - - Dispatcher.UIThread.Post(Action); - - return; - } - - AccountManager.OpenUser(profile.UserId); - } - - var result = await ContentDialogHelper.CreateConfirmationDialog( - LocaleManager.Instance[LocaleKeys.DialogUserProfileDeletionConfirmMessage], - "", - LocaleManager.Instance[LocaleKeys.InputDialogYes], - LocaleManager.Instance[LocaleKeys.InputDialogNo], - ""); - - if (result == UserResult.Yes) - { - GoBack(); - AccountManager.DeleteUser(userProfile.UserId); - } - - LoadProfiles(); - } - - public void AddUser() - { - Navigate(typeof(UserEditorView), (this, (UserProfile)null, true)); - } - - public void EditUser(UserProfile userProfile) - { - Navigate(typeof(UserEditorView), (this, userProfile, false)); - } - - public void RecoverLostAccounts() - { - Navigate(typeof(UserRecovererView), this); - } - - public void ManageSaves() - { - Navigate(typeof(UserSaveManagerView), (this, AccountManager, HorizonClient, VirtualFileSystem)); - } - } -} diff --git a/src/Ryujinx.Ava/UI/Controls/SliderScroll.axaml.cs b/src/Ryujinx.Ava/UI/Controls/SliderScroll.axaml.cs deleted file mode 100644 index b57c6f0a..00000000 --- a/src/Ryujinx.Ava/UI/Controls/SliderScroll.axaml.cs +++ /dev/null @@ -1,31 +0,0 @@ -using Avalonia.Controls; -using Avalonia.Input; -using System; - -namespace Ryujinx.Ava.UI.Controls -{ - public class SliderScroll : Slider - { - protected override Type StyleKeyOverride => typeof(Slider); - - protected override void OnPointerWheelChanged(PointerWheelEventArgs e) - { - var newValue = Value + e.Delta.Y * TickFrequency; - - if (newValue < Minimum) - { - Value = Minimum; - } - else if (newValue > Maximum) - { - Value = Maximum; - } - else - { - Value = newValue; - } - - e.Handled = true; - } - } -} diff --git a/src/Ryujinx.Ava/UI/Controls/UpdateWaitWindow.axaml b/src/Ryujinx.Ava/UI/Controls/UpdateWaitWindow.axaml deleted file mode 100644 index 09fa0404..00000000 --- a/src/Ryujinx.Ava/UI/Controls/UpdateWaitWindow.axaml +++ /dev/null @@ -1,42 +0,0 @@ -<Window - x:Class="Ryujinx.Ava.UI.Controls.UpdateWaitWindow" - xmlns="https://github.com/avaloniaui" - xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" - xmlns:d="http://schemas.microsoft.com/expression/blend/2008" - xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" - Title="Ryujinx - Waiting" - SizeToContent="WidthAndHeight" - WindowStartupLocation="CenterOwner" - mc:Ignorable="d" - Focusable="True"> - <Grid - Margin="20" - HorizontalAlignment="Stretch" - VerticalAlignment="Stretch"> - <Grid.RowDefinitions> - <RowDefinition Height="Auto" /> - <RowDefinition Height="Auto" /> - </Grid.RowDefinitions> - <Grid.ColumnDefinitions> - <ColumnDefinition Width="Auto" /> - <ColumnDefinition /> - </Grid.ColumnDefinitions> - <Image - Grid.Row="1" - Height="70" - MinWidth="50" - Margin="5,10,20,10" - Source="resm:Ryujinx.UI.Common.Resources.Logo_Ryujinx.png?assembly=Ryujinx.UI.Common" /> - <StackPanel - Grid.Row="1" - Grid.Column="1" - VerticalAlignment="Center" - Orientation="Vertical"> - <TextBlock Name="PrimaryText" Margin="5" /> - <TextBlock - Name="SecondaryText" - Margin="5" - VerticalAlignment="Center" /> - </StackPanel> - </Grid> -</Window> diff --git a/src/Ryujinx.Ava/UI/Controls/UpdateWaitWindow.axaml.cs b/src/Ryujinx.Ava/UI/Controls/UpdateWaitWindow.axaml.cs deleted file mode 100644 index 7ad1ee33..00000000 --- a/src/Ryujinx.Ava/UI/Controls/UpdateWaitWindow.axaml.cs +++ /dev/null @@ -1,31 +0,0 @@ -using Avalonia.Controls; -using Ryujinx.Ava.UI.Windows; -using System.Threading; - -namespace Ryujinx.Ava.UI.Controls -{ - public partial class UpdateWaitWindow : StyleableWindow - { - public UpdateWaitWindow(string primaryText, string secondaryText, CancellationTokenSource cancellationToken) : this(primaryText, secondaryText) - { - SystemDecorations = SystemDecorations.Full; - ShowInTaskbar = true; - - Closing += (_, _) => cancellationToken.Cancel(); - } - - public UpdateWaitWindow(string primaryText, string secondaryText) : this() - { - PrimaryText.Text = primaryText; - SecondaryText.Text = secondaryText; - WindowStartupLocation = WindowStartupLocation.CenterOwner; - SystemDecorations = SystemDecorations.BorderOnly; - ShowInTaskbar = false; - } - - public UpdateWaitWindow() - { - InitializeComponent(); - } - } -} diff --git a/src/Ryujinx.Ava/UI/Helpers/ApplicationOpenedEventArgs.cs b/src/Ryujinx.Ava/UI/Helpers/ApplicationOpenedEventArgs.cs deleted file mode 100644 index bc5622b5..00000000 --- a/src/Ryujinx.Ava/UI/Helpers/ApplicationOpenedEventArgs.cs +++ /dev/null @@ -1,16 +0,0 @@ -using Avalonia.Interactivity; -using Ryujinx.UI.App.Common; - -namespace Ryujinx.Ava.UI.Helpers -{ - public class ApplicationOpenedEventArgs : RoutedEventArgs - { - public ApplicationData Application { get; } - - public ApplicationOpenedEventArgs(ApplicationData application, RoutedEvent routedEvent) - { - Application = application; - RoutedEvent = routedEvent; - } - } -} diff --git a/src/Ryujinx.Ava/UI/Helpers/BitmapArrayValueConverter.cs b/src/Ryujinx.Ava/UI/Helpers/BitmapArrayValueConverter.cs deleted file mode 100644 index 42bd8d5a..00000000 --- a/src/Ryujinx.Ava/UI/Helpers/BitmapArrayValueConverter.cs +++ /dev/null @@ -1,36 +0,0 @@ -using Avalonia.Data.Converters; -using Avalonia.Media; -using Avalonia.Media.Imaging; -using System; -using System.Globalization; -using System.IO; - -namespace Ryujinx.Ava.UI.Helpers -{ - internal class BitmapArrayValueConverter : IValueConverter - { - public static BitmapArrayValueConverter Instance = new(); - - public object Convert(object value, Type targetType, object parameter, CultureInfo culture) - { - if (value == null) - { - return null; - } - - if (value is byte[] buffer && targetType == typeof(IImage)) - { - MemoryStream mem = new(buffer); - - return new Bitmap(mem); - } - - throw new NotSupportedException(); - } - - public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) - { - throw new NotSupportedException(); - } - } -} diff --git a/src/Ryujinx.Ava/UI/Helpers/ButtonKeyAssigner.cs b/src/Ryujinx.Ava/UI/Helpers/ButtonKeyAssigner.cs deleted file mode 100644 index 7e8ba734..00000000 --- a/src/Ryujinx.Ava/UI/Helpers/ButtonKeyAssigner.cs +++ /dev/null @@ -1,118 +0,0 @@ -using Avalonia.Controls; -using Avalonia.Controls.Primitives; -using Avalonia.LogicalTree; -using Avalonia.Threading; -using Ryujinx.Input; -using Ryujinx.Input.Assigner; -using System; -using System.Linq; -using System.Threading.Tasks; - -namespace Ryujinx.Ava.UI.Helpers -{ - internal class ButtonKeyAssigner - { - internal class ButtonAssignedEventArgs : EventArgs - { - public ToggleButton Button { get; } - public bool IsAssigned { get; } - - public ButtonAssignedEventArgs(ToggleButton button, bool isAssigned) - { - Button = button; - IsAssigned = isAssigned; - } - } - - public ToggleButton ToggledButton { get; set; } - - private bool _isWaitingForInput; - private bool _shouldUnbind; - public event EventHandler<ButtonAssignedEventArgs> ButtonAssigned; - - public ButtonKeyAssigner(ToggleButton toggleButton) - { - ToggledButton = toggleButton; - } - - public async void GetInputAndAssign(IButtonAssigner assigner, IKeyboard keyboard = null) - { - Dispatcher.UIThread.Post(() => - { - ToggledButton.IsChecked = true; - }); - - if (_isWaitingForInput) - { - Dispatcher.UIThread.Post(() => - { - Cancel(); - }); - - return; - } - - _isWaitingForInput = true; - - assigner.Initialize(); - - await Task.Run(async () => - { - while (true) - { - if (!_isWaitingForInput) - { - return; - } - - await Task.Delay(10); - - assigner.ReadInput(); - - if (assigner.HasAnyButtonPressed() || assigner.ShouldCancel() || (keyboard != null && keyboard.IsPressed(Key.Escape))) - { - break; - } - } - }); - - await Dispatcher.UIThread.InvokeAsync(() => - { - string pressedButton = assigner.GetPressedButton(); - - if (_shouldUnbind) - { - SetButtonText(ToggledButton, "Unbound"); - } - else if (pressedButton != "") - { - SetButtonText(ToggledButton, pressedButton); - } - - _shouldUnbind = false; - _isWaitingForInput = false; - - ToggledButton.IsChecked = false; - - ButtonAssigned?.Invoke(this, new ButtonAssignedEventArgs(ToggledButton, pressedButton != null)); - - static void SetButtonText(ToggleButton button, string text) - { - ILogical textBlock = button.GetLogicalDescendants().First(x => x is TextBlock); - - if (textBlock != null && textBlock is TextBlock block) - { - block.Text = text; - } - } - }); - } - - public void Cancel(bool shouldUnbind = false) - { - _isWaitingForInput = false; - ToggledButton.IsChecked = false; - _shouldUnbind = shouldUnbind; - } - } -} diff --git a/src/Ryujinx.Ava/UI/Helpers/ContentDialogHelper.cs b/src/Ryujinx.Ava/UI/Helpers/ContentDialogHelper.cs deleted file mode 100644 index 15b7ddd1..00000000 --- a/src/Ryujinx.Ava/UI/Helpers/ContentDialogHelper.cs +++ /dev/null @@ -1,425 +0,0 @@ -using Avalonia; -using Avalonia.Controls; -using Avalonia.Controls.ApplicationLifetimes; -using Avalonia.Layout; -using Avalonia.Media; -using Avalonia.Threading; -using FluentAvalonia.Core; -using FluentAvalonia.UI.Controls; -using Ryujinx.Ava.Common.Locale; -using Ryujinx.Ava.UI.Windows; -using Ryujinx.Common.Logging; -using System; -using System.Threading; -using System.Threading.Tasks; - -namespace Ryujinx.Ava.UI.Helpers -{ - public static class ContentDialogHelper - { - private static bool _isChoiceDialogOpen; - private static ContentDialogOverlayWindow _contentDialogOverlayWindow; - - private async static Task<UserResult> ShowContentDialog( - string title, - object content, - string primaryButton, - string secondaryButton, - string closeButton, - UserResult primaryButtonResult = UserResult.Ok, - ManualResetEvent deferResetEvent = null, - TypedEventHandler<ContentDialog, ContentDialogButtonClickEventArgs> deferCloseAction = null) - { - UserResult result = UserResult.None; - - ContentDialog contentDialog = new() - { - Title = title, - PrimaryButtonText = primaryButton, - SecondaryButtonText = secondaryButton, - CloseButtonText = closeButton, - Content = content, - PrimaryButtonCommand = MiniCommand.Create(() => - { - result = primaryButtonResult; - }), - }; - - contentDialog.SecondaryButtonCommand = MiniCommand.Create(() => - { - result = UserResult.No; - contentDialog.PrimaryButtonClick -= deferCloseAction; - }); - - contentDialog.CloseButtonCommand = MiniCommand.Create(() => - { - result = UserResult.Cancel; - contentDialog.PrimaryButtonClick -= deferCloseAction; - }); - - if (deferResetEvent != null) - { - contentDialog.PrimaryButtonClick += deferCloseAction; - } - - await ShowAsync(contentDialog); - - return result; - } - - public async static Task<UserResult> ShowTextDialog( - string title, - string primaryText, - string secondaryText, - string primaryButton, - string secondaryButton, - string closeButton, - int iconSymbol, - UserResult primaryButtonResult = UserResult.Ok, - ManualResetEvent deferResetEvent = null, - TypedEventHandler<ContentDialog, ContentDialogButtonClickEventArgs> deferCloseAction = null) - { - Grid content = CreateTextDialogContent(primaryText, secondaryText, iconSymbol); - - return await ShowContentDialog(title, content, primaryButton, secondaryButton, closeButton, primaryButtonResult, deferResetEvent, deferCloseAction); - } - - public async static Task<UserResult> ShowDeferredContentDialog( - StyleableWindow window, - string title, - string primaryText, - string secondaryText, - string primaryButton, - string secondaryButton, - string closeButton, - int iconSymbol, - ManualResetEvent deferResetEvent, - Func<Window, Task> doWhileDeferred = null) - { - bool startedDeferring = false; - - return await ShowTextDialog( - title, - primaryText, - secondaryText, - primaryButton, - secondaryButton, - closeButton, - iconSymbol, - primaryButton == LocaleManager.Instance[LocaleKeys.InputDialogYes] ? UserResult.Yes : UserResult.Ok, - deferResetEvent, - DeferClose); - - async void DeferClose(ContentDialog sender, ContentDialogButtonClickEventArgs args) - { - if (startedDeferring) - { - return; - } - - sender.PrimaryButtonClick -= DeferClose; - - startedDeferring = true; - - var deferral = args.GetDeferral(); - - sender.PrimaryButtonClick -= DeferClose; - - _ = Task.Run(() => - { - deferResetEvent.WaitOne(); - - Dispatcher.UIThread.Post(() => - { - deferral.Complete(); - }); - }); - - if (doWhileDeferred != null) - { - await doWhileDeferred(window); - - deferResetEvent.Set(); - } - } - } - - private static Grid CreateTextDialogContent(string primaryText, string secondaryText, int symbol) - { - Grid content = new() - { - RowDefinitions = new RowDefinitions { new(), new() }, - ColumnDefinitions = new ColumnDefinitions { new(GridLength.Auto), new() }, - - MinHeight = 80, - }; - - SymbolIcon icon = new() - { - Symbol = (Symbol)symbol, - Margin = new Thickness(10), - FontSize = 40, - VerticalAlignment = VerticalAlignment.Center, - }; - - Grid.SetColumn(icon, 0); - Grid.SetRowSpan(icon, 2); - Grid.SetRow(icon, 0); - - TextBlock primaryLabel = new() - { - Text = primaryText, - Margin = new Thickness(5), - TextWrapping = TextWrapping.Wrap, - MaxWidth = 450, - }; - - TextBlock secondaryLabel = new() - { - Text = secondaryText, - Margin = new Thickness(5), - TextWrapping = TextWrapping.Wrap, - MaxWidth = 450, - }; - - Grid.SetColumn(primaryLabel, 1); - Grid.SetColumn(secondaryLabel, 1); - Grid.SetRow(primaryLabel, 0); - Grid.SetRow(secondaryLabel, 1); - - content.Children.Add(icon); - content.Children.Add(primaryLabel); - content.Children.Add(secondaryLabel); - - return content; - } - - public static async Task<UserResult> CreateInfoDialog( - string primary, - string secondaryText, - string acceptButton, - string closeButton, - string title) - { - return await ShowTextDialog( - title, - primary, - secondaryText, - acceptButton, - "", - closeButton, - (int)Symbol.Important); - } - - internal static async Task<UserResult> CreateConfirmationDialog( - string primaryText, - string secondaryText, - string acceptButtonText, - string cancelButtonText, - string title, - UserResult primaryButtonResult = UserResult.Yes) - { - return await ShowTextDialog( - string.IsNullOrWhiteSpace(title) ? LocaleManager.Instance[LocaleKeys.DialogConfirmationTitle] : title, - primaryText, - secondaryText, - acceptButtonText, - "", - cancelButtonText, - (int)Symbol.Help, - primaryButtonResult); - } - - internal static async Task CreateUpdaterInfoDialog(string primary, string secondaryText) - { - await ShowTextDialog( - LocaleManager.Instance[LocaleKeys.DialogUpdaterTitle], - primary, - secondaryText, - "", - "", - LocaleManager.Instance[LocaleKeys.InputDialogOk], - (int)Symbol.Important); - } - - internal static async Task CreateWarningDialog(string primary, string secondaryText) - { - await ShowTextDialog( - LocaleManager.Instance[LocaleKeys.DialogWarningTitle], - primary, - secondaryText, - "", - "", - LocaleManager.Instance[LocaleKeys.InputDialogOk], - (int)Symbol.Important); - } - - internal static async Task CreateErrorDialog(string errorMessage, string secondaryErrorMessage = "") - { - Logger.Error?.Print(LogClass.Application, errorMessage); - - await ShowTextDialog( - LocaleManager.Instance[LocaleKeys.DialogErrorTitle], - LocaleManager.Instance[LocaleKeys.DialogErrorMessage], - errorMessage, - secondaryErrorMessage, - "", - LocaleManager.Instance[LocaleKeys.InputDialogOk], - (int)Symbol.Dismiss); - } - - internal static async Task<bool> CreateChoiceDialog(string title, string primary, string secondaryText) - { - if (_isChoiceDialogOpen) - { - return false; - } - - _isChoiceDialogOpen = true; - - UserResult response = await ShowTextDialog( - title, - primary, - secondaryText, - LocaleManager.Instance[LocaleKeys.InputDialogYes], - "", - LocaleManager.Instance[LocaleKeys.InputDialogNo], - (int)Symbol.Help, - UserResult.Yes); - - _isChoiceDialogOpen = false; - - return response == UserResult.Yes; - } - - internal static async Task<bool> CreateExitDialog() - { - return await CreateChoiceDialog( - LocaleManager.Instance[LocaleKeys.DialogExitTitle], - LocaleManager.Instance[LocaleKeys.DialogExitMessage], - LocaleManager.Instance[LocaleKeys.DialogExitSubMessage]); - } - - internal static async Task<bool> CreateStopEmulationDialog() - { - return await CreateChoiceDialog( - LocaleManager.Instance[LocaleKeys.DialogStopEmulationTitle], - LocaleManager.Instance[LocaleKeys.DialogStopEmulationMessage], - LocaleManager.Instance[LocaleKeys.DialogExitSubMessage]); - } - - public static async Task<ContentDialogResult> ShowAsync(ContentDialog contentDialog) - { - ContentDialogResult result; - bool isTopDialog = true; - - Window parent = GetMainWindow(); - - if (_contentDialogOverlayWindow != null) - { - isTopDialog = false; - } - - if (parent is MainWindow window) - { - parent.Activate(); - - _contentDialogOverlayWindow = new ContentDialogOverlayWindow - { - Height = parent.Bounds.Height, - Width = parent.Bounds.Width, - Position = parent.PointToScreen(new Point()), - ShowInTaskbar = false, - }; - - parent.PositionChanged += OverlayOnPositionChanged; - - void OverlayOnPositionChanged(object sender, PixelPointEventArgs e) - { - if (_contentDialogOverlayWindow is null) - { - return; - } - - _contentDialogOverlayWindow.Position = parent.PointToScreen(new Point()); - } - - _contentDialogOverlayWindow.ContentDialog = contentDialog; - - bool opened = false; - - _contentDialogOverlayWindow.Opened += OverlayOnActivated; - - async void OverlayOnActivated(object sender, EventArgs e) - { - if (opened) - { - return; - } - - opened = true; - - _contentDialogOverlayWindow.Position = parent.PointToScreen(new Point()); - - result = await ShowDialog(); - } - - result = await _contentDialogOverlayWindow.ShowDialog<ContentDialogResult>(parent); - } - else - { - result = await ShowDialog(); - } - - async Task<ContentDialogResult> ShowDialog() - { - if (_contentDialogOverlayWindow is not null) - { - result = await contentDialog.ShowAsync(_contentDialogOverlayWindow); - - _contentDialogOverlayWindow!.Close(); - } - else - { - result = ContentDialogResult.None; - - Logger.Warning?.Print(LogClass.UI, "Content dialog overlay failed to populate. Default value has been returned."); - } - - return result; - } - - if (isTopDialog && _contentDialogOverlayWindow is not null) - { - _contentDialogOverlayWindow.Content = null; - _contentDialogOverlayWindow.Close(); - _contentDialogOverlayWindow = null; - } - - return result; - } - - public static Task ShowWindowAsync(Window dialogWindow, Window mainWindow = null) - { - mainWindow ??= GetMainWindow(); - - return dialogWindow.ShowDialog(_contentDialogOverlayWindow ?? mainWindow); - } - - private static Window GetMainWindow() - { - if (Application.Current?.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime al) - { - foreach (Window item in al.Windows) - { - if (item is MainWindow window) - { - return window; - } - } - } - - return null; - } - } -} diff --git a/src/Ryujinx.Ava/UI/Helpers/Glyph.cs b/src/Ryujinx.Ava/UI/Helpers/Glyph.cs deleted file mode 100644 index f257dc02..00000000 --- a/src/Ryujinx.Ava/UI/Helpers/Glyph.cs +++ /dev/null @@ -1,9 +0,0 @@ -namespace Ryujinx.Ava.UI.Helpers -{ - public enum Glyph - { - List, - Grid, - Chip, - } -} diff --git a/src/Ryujinx.Ava/UI/Helpers/GlyphValueConverter.cs b/src/Ryujinx.Ava/UI/Helpers/GlyphValueConverter.cs deleted file mode 100644 index 7da23648..00000000 --- a/src/Ryujinx.Ava/UI/Helpers/GlyphValueConverter.cs +++ /dev/null @@ -1,42 +0,0 @@ -using Avalonia.Markup.Xaml; -using FluentAvalonia.UI.Controls; -using System; -using System.Collections.Generic; - -namespace Ryujinx.Ava.UI.Helpers -{ - public class GlyphValueConverter : MarkupExtension - { - private readonly string _key; - - private static readonly Dictionary<Glyph, string> _glyphs = new() - { - { Glyph.List, char.ConvertFromUtf32((int)Symbol.List) }, - { Glyph.Grid, char.ConvertFromUtf32((int)Symbol.ViewAll) }, - { Glyph.Chip, char.ConvertFromUtf32(59748) }, - }; - - public GlyphValueConverter(string key) - { - _key = key; - } - - public string this[string key] - { - get - { - if (_glyphs.TryGetValue(Enum.Parse<Glyph>(key), out var val)) - { - return val; - } - - return string.Empty; - } - } - - public override object ProvideValue(IServiceProvider serviceProvider) - { - return this[_key]; - } - } -} diff --git a/src/Ryujinx.Ava/UI/Helpers/KeyValueConverter.cs b/src/Ryujinx.Ava/UI/Helpers/KeyValueConverter.cs deleted file mode 100644 index 028ed6bf..00000000 --- a/src/Ryujinx.Ava/UI/Helpers/KeyValueConverter.cs +++ /dev/null @@ -1,46 +0,0 @@ -using Avalonia.Data.Converters; -using Ryujinx.Common.Configuration.Hid; -using Ryujinx.Common.Configuration.Hid.Controller; -using System; -using System.Globalization; - -namespace Ryujinx.Ava.UI.Helpers -{ - internal class KeyValueConverter : IValueConverter - { - public static KeyValueConverter Instance = new(); - - public object Convert(object value, Type targetType, object parameter, CultureInfo culture) - { - if (value == null) - { - return null; - } - - return value.ToString(); - } - - public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) - { - object key = null; - - if (value != null) - { - if (targetType == typeof(Key)) - { - key = Enum.Parse<Key>(value.ToString()); - } - else if (targetType == typeof(GamepadInputId)) - { - key = Enum.Parse<GamepadInputId>(value.ToString()); - } - else if (targetType == typeof(StickInputId)) - { - key = Enum.Parse<StickInputId>(value.ToString()); - } - } - - return key; - } - } -} diff --git a/src/Ryujinx.Ava/UI/Helpers/LocalizedNeverConverter.cs b/src/Ryujinx.Ava/UI/Helpers/LocalizedNeverConverter.cs deleted file mode 100644 index 26fe36c4..00000000 --- a/src/Ryujinx.Ava/UI/Helpers/LocalizedNeverConverter.cs +++ /dev/null @@ -1,43 +0,0 @@ -using Avalonia.Data.Converters; -using Avalonia.Markup.Xaml; -using Ryujinx.Ava.Common.Locale; -using Ryujinx.UI.Common.Helper; -using System; -using System.Globalization; - -namespace Ryujinx.Ava.UI.Helpers -{ - /// <summary> - /// This <see cref="IValueConverter"/> makes sure that the string "Never" that's returned by <see cref="ValueFormatUtils.FormatDateTime"/> is properly localized in the Avalonia UI. - /// After the Avalonia UI has been made the default and the GTK UI is removed, <see cref="ValueFormatUtils"/> should be updated to directly return a localized string. - /// </summary> - internal class LocalizedNeverConverter : MarkupExtension, IValueConverter - { - private static readonly LocalizedNeverConverter _instance = new(); - - public object Convert(object value, Type targetType, object parameter, CultureInfo culture) - { - if (value is not string valStr) - { - return ""; - } - - if (valStr == "Never") - { - return LocaleManager.Instance[LocaleKeys.Never]; - } - - return valStr; - } - - public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) - { - throw new NotSupportedException(); - } - - public override object ProvideValue(IServiceProvider serviceProvider) - { - return _instance; - } - } -} diff --git a/src/Ryujinx.Ava/UI/Helpers/LoggerAdapter.cs b/src/Ryujinx.Ava/UI/Helpers/LoggerAdapter.cs deleted file mode 100644 index fc714541..00000000 --- a/src/Ryujinx.Ava/UI/Helpers/LoggerAdapter.cs +++ /dev/null @@ -1,102 +0,0 @@ -using Avalonia.Logging; -using Avalonia.Utilities; -using Ryujinx.Common.Logging; -using System; -using System.Text; - -namespace Ryujinx.Ava.UI.Helpers -{ - using AvaLogger = Avalonia.Logging.Logger; - using AvaLogLevel = LogEventLevel; - using RyuLogClass = LogClass; - using RyuLogger = Ryujinx.Common.Logging.Logger; - - internal class LoggerAdapter : ILogSink - { - public static void Register() - { - AvaLogger.Sink = new LoggerAdapter(); - } - - private static RyuLogger.Log? GetLog(AvaLogLevel level) - { - return level switch - { - AvaLogLevel.Verbose => RyuLogger.Debug, - AvaLogLevel.Debug => RyuLogger.Debug, - AvaLogLevel.Information => RyuLogger.Debug, - AvaLogLevel.Warning => RyuLogger.Debug, - AvaLogLevel.Error => RyuLogger.Error, - AvaLogLevel.Fatal => RyuLogger.Error, - _ => throw new ArgumentOutOfRangeException(nameof(level), level, null), - }; - } - - public bool IsEnabled(AvaLogLevel level, string area) - { - return GetLog(level) != null; - } - - public void Log(AvaLogLevel level, string area, object source, string messageTemplate) - { - GetLog(level)?.PrintMsg(RyuLogClass.UI, Format(level, area, messageTemplate, source, null)); - } - - public void Log(AvaLogLevel level, string area, object source, string messageTemplate, params object[] propertyValues) - { - GetLog(level)?.PrintMsg(RyuLogClass.UI, Format(level, area, messageTemplate, source, propertyValues)); - } - - private static string Format(AvaLogLevel level, string area, string template, object source, object[] v) - { - var result = new StringBuilder(); - var r = new CharacterReader(template.AsSpan()); - int i = 0; - - result.Append('['); - result.Append(level); - result.Append("] "); - - result.Append('['); - result.Append(area); - result.Append("] "); - - while (!r.End) - { - var c = r.Take(); - - if (c != '{') - { - result.Append(c); - } - else - { - if (r.Peek != '{') - { - result.Append('\''); - result.Append(i < v.Length ? v[i++] : null); - result.Append('\''); - r.TakeUntil('}'); - r.Take(); - } - else - { - result.Append('{'); - r.Take(); - } - } - } - - if (source != null) - { - result.Append(" ("); - result.Append(source.GetType().Name); - result.Append(" #"); - result.Append(source.GetHashCode()); - result.Append(')'); - } - - return result.ToString(); - } - } -} diff --git a/src/Ryujinx.Ava/UI/Helpers/MiniCommand.cs b/src/Ryujinx.Ava/UI/Helpers/MiniCommand.cs deleted file mode 100644 index 7e1bb9a6..00000000 --- a/src/Ryujinx.Ava/UI/Helpers/MiniCommand.cs +++ /dev/null @@ -1,71 +0,0 @@ -using System; -using System.Threading.Tasks; -using System.Windows.Input; - -namespace Ryujinx.Ava.UI.Helpers -{ - public sealed class MiniCommand<T> : MiniCommand, ICommand - { - private readonly Action<T> _callback; - private bool _busy; - private readonly Func<T, Task> _asyncCallback; - - public MiniCommand(Action<T> callback) - { - _callback = callback; - } - - public MiniCommand(Func<T, Task> callback) - { - _asyncCallback = callback; - } - - private bool Busy - { - get => _busy; - set - { - _busy = value; - CanExecuteChanged?.Invoke(this, EventArgs.Empty); - } - } - - public override event EventHandler CanExecuteChanged; - public override bool CanExecute(object parameter) => !_busy; - - public override async void Execute(object parameter) - { - if (Busy) - { - return; - } - try - { - Busy = true; - if (_callback != null) - { - _callback((T)parameter); - } - else - { - await _asyncCallback((T)parameter); - } - } - finally - { - Busy = false; - } - } - } - - public abstract class MiniCommand : ICommand - { - public static MiniCommand Create(Action callback) => new MiniCommand<object>(_ => callback()); - public static MiniCommand Create<TArg>(Action<TArg> callback) => new MiniCommand<TArg>(callback); - public static MiniCommand CreateFromTask(Func<Task> callback) => new MiniCommand<object>(_ => callback()); - - public abstract bool CanExecute(object parameter); - public abstract void Execute(object parameter); - public abstract event EventHandler CanExecuteChanged; - } -} diff --git a/src/Ryujinx.Ava/UI/Helpers/NotificationHelper.cs b/src/Ryujinx.Ava/UI/Helpers/NotificationHelper.cs deleted file mode 100644 index 656a8b52..00000000 --- a/src/Ryujinx.Ava/UI/Helpers/NotificationHelper.cs +++ /dev/null @@ -1,70 +0,0 @@ -using Avalonia; -using Avalonia.Controls; -using Avalonia.Controls.Notifications; -using Avalonia.Threading; -using Ryujinx.Ava.Common.Locale; -using Ryujinx.Common; -using System; -using System.Collections.Concurrent; -using System.Threading; - -namespace Ryujinx.Ava.UI.Helpers -{ - public static class NotificationHelper - { - private const int MaxNotifications = 4; - private const int NotificationDelayInMs = 5000; - - private static WindowNotificationManager _notificationManager; - - private static readonly BlockingCollection<Notification> _notifications = new(); - - public static void SetNotificationManager(Window host) - { - _notificationManager = new WindowNotificationManager(host) - { - Position = NotificationPosition.BottomRight, - MaxItems = MaxNotifications, - Margin = new Thickness(0, 0, 15, 40), - }; - - var maybeAsyncWorkQueue = new Lazy<AsyncWorkQueue<Notification>>( - () => new AsyncWorkQueue<Notification>(notification => - { - Dispatcher.UIThread.Post(() => - { - _notificationManager.Show(notification); - }); - }, - "UI.NotificationThread", - _notifications), - LazyThreadSafetyMode.ExecutionAndPublication); - - _notificationManager.TemplateApplied += (sender, args) => - { - // NOTE: Force creation of the AsyncWorkQueue. - _ = maybeAsyncWorkQueue.Value; - }; - - host.Closing += (sender, args) => - { - if (maybeAsyncWorkQueue.IsValueCreated) - { - maybeAsyncWorkQueue.Value.Dispose(); - } - }; - } - - public static void Show(string title, string text, NotificationType type, bool waitingExit = false, Action onClick = null, Action onClose = null) - { - var delay = waitingExit ? TimeSpan.FromMilliseconds(0) : TimeSpan.FromMilliseconds(NotificationDelayInMs); - - _notifications.Add(new Notification(title, text, type, delay, onClick, onClose)); - } - - public static void ShowError(string message) - { - Show(LocaleManager.Instance[LocaleKeys.DialogErrorTitle], $"{LocaleManager.Instance[LocaleKeys.DialogErrorMessage]}\n\n{message}", NotificationType.Error); - } - } -} diff --git a/src/Ryujinx.Ava/UI/Helpers/OffscreenTextBox.cs b/src/Ryujinx.Ava/UI/Helpers/OffscreenTextBox.cs deleted file mode 100644 index a055f335..00000000 --- a/src/Ryujinx.Ava/UI/Helpers/OffscreenTextBox.cs +++ /dev/null @@ -1,39 +0,0 @@ -using Avalonia.Controls; -using Avalonia.Input; -using Avalonia.Interactivity; - -namespace Ryujinx.Ava.UI.Helpers -{ - public class OffscreenTextBox : TextBox - { - public static RoutedEvent<KeyEventArgs> GetKeyDownRoutedEvent() - { - return KeyDownEvent; - } - - public static RoutedEvent<KeyEventArgs> GetKeyUpRoutedEvent() - { - return KeyUpEvent; - } - - public void SendKeyDownEvent(KeyEventArgs keyEvent) - { - OnKeyDown(keyEvent); - } - - public void SendKeyUpEvent(KeyEventArgs keyEvent) - { - OnKeyUp(keyEvent); - } - - public void SendText(string text) - { - OnTextInput(new TextInputEventArgs - { - Text = text, - Source = this, - RoutedEvent = TextInputEvent, - }); - } - } -} diff --git a/src/Ryujinx.Ava/UI/Helpers/TimeZoneConverter.cs b/src/Ryujinx.Ava/UI/Helpers/TimeZoneConverter.cs deleted file mode 100644 index 876d51f7..00000000 --- a/src/Ryujinx.Ava/UI/Helpers/TimeZoneConverter.cs +++ /dev/null @@ -1,28 +0,0 @@ -using Avalonia.Data.Converters; -using System; -using System.Globalization; -using TimeZone = Ryujinx.Ava.UI.Models.TimeZone; - -namespace Ryujinx.Ava.UI.Helpers -{ - internal class TimeZoneConverter : IValueConverter - { - public static TimeZoneConverter Instance = new(); - - public object Convert(object value, Type targetType, object parameter, CultureInfo culture) - { - if (value == null) - { - return null; - } - - var timeZone = (TimeZone)value; - return string.Format("{0} {1} {2}", timeZone.UtcDifference, timeZone.Location, timeZone.Abbreviation); - } - - public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) - { - throw new NotImplementedException(); - } - } -} diff --git a/src/Ryujinx.Ava/UI/Helpers/UserErrorDialog.cs b/src/Ryujinx.Ava/UI/Helpers/UserErrorDialog.cs deleted file mode 100644 index 9a44b862..00000000 --- a/src/Ryujinx.Ava/UI/Helpers/UserErrorDialog.cs +++ /dev/null @@ -1,90 +0,0 @@ -using Ryujinx.Ava.Common.Locale; -using Ryujinx.UI.Common; -using Ryujinx.UI.Common.Helper; -using System.Threading.Tasks; - -namespace Ryujinx.Ava.UI.Helpers -{ - internal class UserErrorDialog - { - private const string SetupGuideUrl = "https://github.com/Ryujinx/Ryujinx/wiki/Ryujinx-Setup-&-Configuration-Guide"; - - private static string GetErrorCode(UserError error) - { - return $"RYU-{(uint)error:X4}"; - } - - private static string GetErrorTitle(UserError error) - { - return error switch - { - UserError.NoKeys => LocaleManager.Instance[LocaleKeys.UserErrorNoKeys], - UserError.NoFirmware => LocaleManager.Instance[LocaleKeys.UserErrorNoFirmware], - UserError.FirmwareParsingFailed => LocaleManager.Instance[LocaleKeys.UserErrorFirmwareParsingFailed], - UserError.ApplicationNotFound => LocaleManager.Instance[LocaleKeys.UserErrorApplicationNotFound], - UserError.Unknown => LocaleManager.Instance[LocaleKeys.UserErrorUnknown], - _ => LocaleManager.Instance[LocaleKeys.UserErrorUndefined], - }; - } - - private static string GetErrorDescription(UserError error) - { - return error switch - { - UserError.NoKeys => LocaleManager.Instance[LocaleKeys.UserErrorNoKeysDescription], - UserError.NoFirmware => LocaleManager.Instance[LocaleKeys.UserErrorNoFirmwareDescription], - UserError.FirmwareParsingFailed => LocaleManager.Instance[LocaleKeys.UserErrorFirmwareParsingFailedDescription], - UserError.ApplicationNotFound => LocaleManager.Instance[LocaleKeys.UserErrorApplicationNotFoundDescription], - UserError.Unknown => LocaleManager.Instance[LocaleKeys.UserErrorUnknownDescription], - _ => LocaleManager.Instance[LocaleKeys.UserErrorUndefinedDescription], - }; - } - - private static bool IsCoveredBySetupGuide(UserError error) - { - return error switch - { - UserError.NoKeys or - UserError.NoFirmware or - UserError.FirmwareParsingFailed => true, - _ => false, - }; - } - - private static string GetSetupGuideUrl(UserError error) - { - if (!IsCoveredBySetupGuide(error)) - { - return null; - } - - return error switch - { - UserError.NoKeys => SetupGuideUrl + "#initial-setup---placement-of-prodkeys", - UserError.NoFirmware => SetupGuideUrl + "#initial-setup-continued---installation-of-firmware", - _ => SetupGuideUrl, - }; - } - - public static async Task ShowUserErrorDialog(UserError error) - { - string errorCode = GetErrorCode(error); - - bool isInSetupGuide = IsCoveredBySetupGuide(error); - - string setupButtonLabel = isInSetupGuide ? LocaleManager.Instance[LocaleKeys.OpenSetupGuideMessage] : ""; - - var result = await ContentDialogHelper.CreateInfoDialog( - LocaleManager.Instance.UpdateAndGetDynamicValue(LocaleKeys.DialogUserErrorDialogMessage, errorCode, GetErrorTitle(error)), - GetErrorDescription(error) + (isInSetupGuide - ? LocaleManager.Instance[LocaleKeys.DialogUserErrorDialogInfoMessage] - : ""), setupButtonLabel, LocaleManager.Instance[LocaleKeys.InputDialogOk], - LocaleManager.Instance.UpdateAndGetDynamicValue(LocaleKeys.DialogUserErrorDialogTitle, errorCode)); - - if (result == UserResult.Ok) - { - OpenHelper.OpenUrl(GetSetupGuideUrl(error)); - } - } - } -} diff --git a/src/Ryujinx.Ava/UI/Helpers/UserResult.cs b/src/Ryujinx.Ava/UI/Helpers/UserResult.cs deleted file mode 100644 index 2fcd35ae..00000000 --- a/src/Ryujinx.Ava/UI/Helpers/UserResult.cs +++ /dev/null @@ -1,12 +0,0 @@ -namespace Ryujinx.Ava.UI.Helpers -{ - public enum UserResult - { - Ok, - Yes, - No, - Abort, - Cancel, - None, - } -} diff --git a/src/Ryujinx.Ava/UI/Helpers/Win32NativeInterop.cs b/src/Ryujinx.Ava/UI/Helpers/Win32NativeInterop.cs deleted file mode 100644 index 4834df80..00000000 --- a/src/Ryujinx.Ava/UI/Helpers/Win32NativeInterop.cs +++ /dev/null @@ -1,125 +0,0 @@ -using System; -using System.Diagnostics.CodeAnalysis; -using System.Runtime.InteropServices; -using System.Runtime.Versioning; - -namespace Ryujinx.Ava.UI.Helpers -{ - [SupportedOSPlatform("windows")] - internal partial class Win32NativeInterop - { - [Flags] - public enum ClassStyles : uint - { - CsClassdc = 0x40, - CsOwndc = 0x20, - } - - [Flags] - public enum WindowStyles : uint - { - WsChild = 0x40000000, - } - - public enum Cursors : uint - { - IdcArrow = 32512, - } - - [SuppressMessage("Design", "CA1069: Enums values should not be duplicated")] - public enum WindowsMessages : uint - { - Mousemove = 0x0200, - Lbuttondown = 0x0201, - Lbuttonup = 0x0202, - Lbuttondblclk = 0x0203, - Rbuttondown = 0x0204, - Rbuttonup = 0x0205, - Rbuttondblclk = 0x0206, - Mbuttondown = 0x0207, - Mbuttonup = 0x0208, - Mbuttondblclk = 0x0209, - Mousewheel = 0x020A, - Xbuttondown = 0x020B, - Xbuttonup = 0x020C, - Xbuttondblclk = 0x020D, - Mousehwheel = 0x020E, - Mouselast = 0x020E, - } - - [UnmanagedFunctionPointer(CallingConvention.Winapi)] - internal delegate IntPtr WindowProc(IntPtr hWnd, WindowsMessages msg, IntPtr wParam, IntPtr lParam); - - [StructLayout(LayoutKind.Sequential)] - public struct WndClassEx - { - public int cbSize; - public ClassStyles style; - public IntPtr lpfnWndProc; // not WndProc - public int cbClsExtra; - public int cbWndExtra; - public IntPtr hInstance; - public IntPtr hIcon; - public IntPtr hCursor; - public IntPtr hbrBackground; - public IntPtr lpszMenuName; - public IntPtr lpszClassName; - public IntPtr hIconSm; - - public WndClassEx() - { - cbSize = Marshal.SizeOf<WndClassEx>(); - } - } - - public static IntPtr CreateEmptyCursor() - { - return CreateCursor(IntPtr.Zero, 0, 0, 1, 1, new byte[] { 0xFF }, new byte[] { 0x00 }); - } - - public static IntPtr CreateArrowCursor() - { - return LoadCursor(IntPtr.Zero, (IntPtr)Cursors.IdcArrow); - } - - [LibraryImport("user32.dll")] - public static partial IntPtr SetCursor(IntPtr handle); - - [LibraryImport("user32.dll")] - public static partial IntPtr CreateCursor(IntPtr hInst, int xHotSpot, int yHotSpot, int nWidth, int nHeight, [In] byte[] pvAndPlane, [In] byte[] pvXorPlane); - - [LibraryImport("user32.dll", SetLastError = true, EntryPoint = "RegisterClassExW")] - public static partial ushort RegisterClassEx(ref WndClassEx param); - - [LibraryImport("user32.dll", SetLastError = true, EntryPoint = "UnregisterClassW")] - public static partial short UnregisterClass([MarshalAs(UnmanagedType.LPWStr)] string lpClassName, IntPtr instance); - - [LibraryImport("user32.dll", EntryPoint = "DefWindowProcW")] - public static partial IntPtr DefWindowProc(IntPtr hWnd, WindowsMessages msg, IntPtr wParam, IntPtr lParam); - - [LibraryImport("kernel32.dll", EntryPoint = "GetModuleHandleA")] - public static partial IntPtr GetModuleHandle([MarshalAs(UnmanagedType.LPStr)] string lpModuleName); - - [LibraryImport("user32.dll", SetLastError = true)] - [return: MarshalAs(UnmanagedType.Bool)] - public static partial bool DestroyWindow(IntPtr hwnd); - - [LibraryImport("user32.dll", SetLastError = true, EntryPoint = "LoadCursorA")] - public static partial IntPtr LoadCursor(IntPtr hInstance, IntPtr lpCursorName); - - [LibraryImport("user32.dll", SetLastError = true, EntryPoint = "CreateWindowExW")] - public static partial IntPtr CreateWindowEx( - uint dwExStyle, - [MarshalAs(UnmanagedType.LPWStr)] string lpClassName, - [MarshalAs(UnmanagedType.LPWStr)] string lpWindowName, - WindowStyles dwStyle, - int x, - int y, - int nWidth, - int nHeight, - IntPtr hWndParent, - IntPtr hMenu, - IntPtr hInstance, - IntPtr lpParam); - } -} diff --git a/src/Ryujinx.Ava/UI/Models/CheatNode.cs b/src/Ryujinx.Ava/UI/Models/CheatNode.cs deleted file mode 100644 index 8e9aee25..00000000 --- a/src/Ryujinx.Ava/UI/Models/CheatNode.cs +++ /dev/null @@ -1,57 +0,0 @@ -using Ryujinx.Ava.UI.ViewModels; -using System.Collections.ObjectModel; -using System.Collections.Specialized; -using System.Linq; - -namespace Ryujinx.Ava.UI.Models -{ - public class CheatNode : BaseModel - { - private bool _isEnabled = false; - public ObservableCollection<CheatNode> SubNodes { get; } = new(); - public string CleanName => Name[1..^7]; - public string BuildIdKey => $"{BuildId}-{Name}"; - public bool IsRootNode { get; } - public string Name { get; } - public string BuildId { get; } - public string Path { get; } - public bool IsEnabled - { - get - { - if (SubNodes.Count > 0) - { - return SubNodes.ToList().TrueForAll(x => x.IsEnabled); - } - - return _isEnabled; - } - set - { - foreach (var cheat in SubNodes) - { - cheat.IsEnabled = value; - cheat.OnPropertyChanged(); - } - - _isEnabled = value; - } - } - - public CheatNode(string name, string buildId, string path, bool isRootNode, bool isEnabled = false) - { - Name = name; - BuildId = buildId; - Path = path; - IsEnabled = isEnabled; - IsRootNode = isRootNode; - - SubNodes.CollectionChanged += CheatsList_CollectionChanged; - } - - private void CheatsList_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e) - { - OnPropertyChanged(nameof(IsEnabled)); - } - } -} diff --git a/src/Ryujinx.Ava/UI/Models/ControllerModel.cs b/src/Ryujinx.Ava/UI/Models/ControllerModel.cs deleted file mode 100644 index 98de7757..00000000 --- a/src/Ryujinx.Ava/UI/Models/ControllerModel.cs +++ /dev/null @@ -1,6 +0,0 @@ -using Ryujinx.Common.Configuration.Hid; - -namespace Ryujinx.Ava.UI.Models -{ - internal record ControllerModel(ControllerType Type, string Name); -} diff --git a/src/Ryujinx.Ava/UI/Models/DeviceType.cs b/src/Ryujinx.Ava/UI/Models/DeviceType.cs deleted file mode 100644 index bb4fc3b3..00000000 --- a/src/Ryujinx.Ava/UI/Models/DeviceType.cs +++ /dev/null @@ -1,9 +0,0 @@ -namespace Ryujinx.Ava.UI.Models -{ - public enum DeviceType - { - None, - Keyboard, - Controller, - } -} diff --git a/src/Ryujinx.Ava/UI/Models/DownloadableContentModel.cs b/src/Ryujinx.Ava/UI/Models/DownloadableContentModel.cs deleted file mode 100644 index 9e400441..00000000 --- a/src/Ryujinx.Ava/UI/Models/DownloadableContentModel.cs +++ /dev/null @@ -1,35 +0,0 @@ -using Ryujinx.Ava.UI.ViewModels; -using System.IO; - -namespace Ryujinx.Ava.UI.Models -{ - public class DownloadableContentModel : BaseModel - { - private bool _enabled; - - public bool Enabled - { - get => _enabled; - set - { - _enabled = value; - - OnPropertyChanged(); - } - } - - public string TitleId { get; } - public string ContainerPath { get; } - public string FullPath { get; } - - public string FileName => Path.GetFileName(ContainerPath); - - public DownloadableContentModel(string titleId, string containerPath, string fullPath, bool enabled) - { - TitleId = titleId; - ContainerPath = containerPath; - FullPath = fullPath; - Enabled = enabled; - } - } -} diff --git a/src/Ryujinx.Ava/UI/Models/Generic/LastPlayedSortComparer.cs b/src/Ryujinx.Ava/UI/Models/Generic/LastPlayedSortComparer.cs deleted file mode 100644 index 224f78f4..00000000 --- a/src/Ryujinx.Ava/UI/Models/Generic/LastPlayedSortComparer.cs +++ /dev/null @@ -1,31 +0,0 @@ -using Ryujinx.UI.App.Common; -using System; -using System.Collections.Generic; - -namespace Ryujinx.Ava.UI.Models.Generic -{ - internal class LastPlayedSortComparer : IComparer<ApplicationData> - { - public LastPlayedSortComparer() { } - public LastPlayedSortComparer(bool isAscending) { IsAscending = isAscending; } - - public bool IsAscending { get; } - - public int Compare(ApplicationData x, ApplicationData y) - { - DateTime aValue = DateTime.UnixEpoch, bValue = DateTime.UnixEpoch; - - if (x?.LastPlayed != null) - { - aValue = x.LastPlayed.Value; - } - - if (y?.LastPlayed != null) - { - bValue = y.LastPlayed.Value; - } - - return (IsAscending ? 1 : -1) * DateTime.Compare(aValue, bValue); - } - } -} diff --git a/src/Ryujinx.Ava/UI/Models/Generic/TimePlayedSortComparer.cs b/src/Ryujinx.Ava/UI/Models/Generic/TimePlayedSortComparer.cs deleted file mode 100644 index f0fb035d..00000000 --- a/src/Ryujinx.Ava/UI/Models/Generic/TimePlayedSortComparer.cs +++ /dev/null @@ -1,31 +0,0 @@ -using Ryujinx.UI.App.Common; -using System; -using System.Collections.Generic; - -namespace Ryujinx.Ava.UI.Models.Generic -{ - internal class TimePlayedSortComparer : IComparer<ApplicationData> - { - public TimePlayedSortComparer() { } - public TimePlayedSortComparer(bool isAscending) { IsAscending = isAscending; } - - public bool IsAscending { get; } - - public int Compare(ApplicationData x, ApplicationData y) - { - TimeSpan aValue = TimeSpan.Zero, bValue = TimeSpan.Zero; - - if (x?.TimePlayed != null) - { - aValue = x.TimePlayed; - } - - if (y?.TimePlayed != null) - { - bValue = y.TimePlayed; - } - - return (IsAscending ? 1 : -1) * TimeSpan.Compare(aValue, bValue); - } - } -} diff --git a/src/Ryujinx.Ava/UI/Models/InputConfiguration.cs b/src/Ryujinx.Ava/UI/Models/InputConfiguration.cs deleted file mode 100644 index f1352c6d..00000000 --- a/src/Ryujinx.Ava/UI/Models/InputConfiguration.cs +++ /dev/null @@ -1,456 +0,0 @@ -using Ryujinx.Ava.UI.ViewModels; -using Ryujinx.Common.Configuration.Hid; -using Ryujinx.Common.Configuration.Hid.Controller; -using Ryujinx.Common.Configuration.Hid.Controller.Motion; -using Ryujinx.Common.Configuration.Hid.Keyboard; -using System; - -namespace Ryujinx.Ava.UI.Models -{ - internal class InputConfiguration<TKey, TStick> : BaseModel - { - private float _deadzoneRight; - private float _triggerThreshold; - private float _deadzoneLeft; - private double _gyroDeadzone; - private int _sensitivity; - private bool _enableMotion; - private float _weakRumble; - private float _strongRumble; - private float _rangeLeft; - private float _rangeRight; - - public InputBackendType Backend { get; set; } - - /// <summary> - /// Controller id - /// </summary> - public string Id { get; set; } - - /// <summary> - /// Controller's Type - /// </summary> - public ControllerType ControllerType { get; set; } - - /// <summary> - /// Player's Index for the controller - /// </summary> - public PlayerIndex PlayerIndex { get; set; } - - public TStick LeftJoystick { get; set; } - public bool LeftInvertStickX { get; set; } - public bool LeftInvertStickY { get; set; } - public bool RightRotate90 { get; set; } - public TKey LeftControllerStickButton { get; set; } - - public TStick RightJoystick { get; set; } - public bool RightInvertStickX { get; set; } - public bool RightInvertStickY { get; set; } - public bool LeftRotate90 { get; set; } - public TKey RightControllerStickButton { get; set; } - - public float DeadzoneLeft - { - get => _deadzoneLeft; - set - { - _deadzoneLeft = MathF.Round(value, 3); - - OnPropertyChanged(); - } - } - - public float RangeLeft - { - get => _rangeLeft; - set - { - _rangeLeft = MathF.Round(value, 3); - - OnPropertyChanged(); - } - } - - public float DeadzoneRight - { - get => _deadzoneRight; - set - { - _deadzoneRight = MathF.Round(value, 3); - - OnPropertyChanged(); - } - } - - public float RangeRight - { - get => _rangeRight; - set - { - _rangeRight = MathF.Round(value, 3); - - OnPropertyChanged(); - } - } - - public float TriggerThreshold - { - get => _triggerThreshold; - set - { - _triggerThreshold = MathF.Round(value, 3); - - OnPropertyChanged(); - } - } - - public MotionInputBackendType MotionBackend { get; set; } - - public TKey ButtonMinus { get; set; } - public TKey ButtonL { get; set; } - public TKey ButtonZl { get; set; } - public TKey LeftButtonSl { get; set; } - public TKey LeftButtonSr { get; set; } - public TKey DpadUp { get; set; } - public TKey DpadDown { get; set; } - public TKey DpadLeft { get; set; } - public TKey DpadRight { get; set; } - - public TKey ButtonPlus { get; set; } - public TKey ButtonR { get; set; } - public TKey ButtonZr { get; set; } - public TKey RightButtonSl { get; set; } - public TKey RightButtonSr { get; set; } - public TKey ButtonX { get; set; } - public TKey ButtonB { get; set; } - public TKey ButtonY { get; set; } - public TKey ButtonA { get; set; } - - public TKey LeftStickUp { get; set; } - public TKey LeftStickDown { get; set; } - public TKey LeftStickLeft { get; set; } - public TKey LeftStickRight { get; set; } - public TKey LeftKeyboardStickButton { get; set; } - - public TKey RightStickUp { get; set; } - public TKey RightStickDown { get; set; } - public TKey RightStickLeft { get; set; } - public TKey RightStickRight { get; set; } - public TKey RightKeyboardStickButton { get; set; } - - public int Sensitivity - { - get => _sensitivity; - set - { - _sensitivity = value; - - OnPropertyChanged(); - } - } - - public double GyroDeadzone - { - get => _gyroDeadzone; - set - { - _gyroDeadzone = Math.Round(value, 3); - - OnPropertyChanged(); - } - } - - public bool EnableMotion - { - get => _enableMotion; set - { - _enableMotion = value; - - OnPropertyChanged(); - } - } - - public bool EnableCemuHookMotion { get; set; } - public int Slot { get; set; } - public int AltSlot { get; set; } - public bool MirrorInput { get; set; } - public string DsuServerHost { get; set; } - public int DsuServerPort { get; set; } - - public bool EnableRumble { get; set; } - public float WeakRumble - { - get => _weakRumble; set - { - _weakRumble = value; - - OnPropertyChanged(); - } - } - public float StrongRumble - { - get => _strongRumble; set - { - _strongRumble = value; - - OnPropertyChanged(); - } - } - - public InputConfiguration(InputConfig config) - { - if (config != null) - { - Backend = config.Backend; - Id = config.Id; - ControllerType = config.ControllerType; - PlayerIndex = config.PlayerIndex; - - if (config is StandardKeyboardInputConfig keyboardConfig) - { - LeftStickUp = (TKey)(object)keyboardConfig.LeftJoyconStick.StickUp; - LeftStickDown = (TKey)(object)keyboardConfig.LeftJoyconStick.StickDown; - LeftStickLeft = (TKey)(object)keyboardConfig.LeftJoyconStick.StickLeft; - LeftStickRight = (TKey)(object)keyboardConfig.LeftJoyconStick.StickRight; - LeftKeyboardStickButton = (TKey)(object)keyboardConfig.LeftJoyconStick.StickButton; - - RightStickUp = (TKey)(object)keyboardConfig.RightJoyconStick.StickUp; - RightStickDown = (TKey)(object)keyboardConfig.RightJoyconStick.StickDown; - RightStickLeft = (TKey)(object)keyboardConfig.RightJoyconStick.StickLeft; - RightStickRight = (TKey)(object)keyboardConfig.RightJoyconStick.StickRight; - RightKeyboardStickButton = (TKey)(object)keyboardConfig.RightJoyconStick.StickButton; - - ButtonA = (TKey)(object)keyboardConfig.RightJoycon.ButtonA; - ButtonB = (TKey)(object)keyboardConfig.RightJoycon.ButtonB; - ButtonX = (TKey)(object)keyboardConfig.RightJoycon.ButtonX; - ButtonY = (TKey)(object)keyboardConfig.RightJoycon.ButtonY; - ButtonR = (TKey)(object)keyboardConfig.RightJoycon.ButtonR; - RightButtonSl = (TKey)(object)keyboardConfig.RightJoycon.ButtonSl; - RightButtonSr = (TKey)(object)keyboardConfig.RightJoycon.ButtonSr; - ButtonZr = (TKey)(object)keyboardConfig.RightJoycon.ButtonZr; - ButtonPlus = (TKey)(object)keyboardConfig.RightJoycon.ButtonPlus; - - DpadUp = (TKey)(object)keyboardConfig.LeftJoycon.DpadUp; - DpadDown = (TKey)(object)keyboardConfig.LeftJoycon.DpadDown; - DpadLeft = (TKey)(object)keyboardConfig.LeftJoycon.DpadLeft; - DpadRight = (TKey)(object)keyboardConfig.LeftJoycon.DpadRight; - ButtonMinus = (TKey)(object)keyboardConfig.LeftJoycon.ButtonMinus; - LeftButtonSl = (TKey)(object)keyboardConfig.LeftJoycon.ButtonSl; - LeftButtonSr = (TKey)(object)keyboardConfig.LeftJoycon.ButtonSr; - ButtonZl = (TKey)(object)keyboardConfig.LeftJoycon.ButtonZl; - ButtonL = (TKey)(object)keyboardConfig.LeftJoycon.ButtonL; - } - else if (config is StandardControllerInputConfig controllerConfig) - { - LeftJoystick = (TStick)(object)controllerConfig.LeftJoyconStick.Joystick; - LeftInvertStickX = controllerConfig.LeftJoyconStick.InvertStickX; - LeftInvertStickY = controllerConfig.LeftJoyconStick.InvertStickY; - LeftRotate90 = controllerConfig.LeftJoyconStick.Rotate90CW; - LeftControllerStickButton = (TKey)(object)controllerConfig.LeftJoyconStick.StickButton; - - RightJoystick = (TStick)(object)controllerConfig.RightJoyconStick.Joystick; - RightInvertStickX = controllerConfig.RightJoyconStick.InvertStickX; - RightInvertStickY = controllerConfig.RightJoyconStick.InvertStickY; - RightRotate90 = controllerConfig.RightJoyconStick.Rotate90CW; - RightControllerStickButton = (TKey)(object)controllerConfig.RightJoyconStick.StickButton; - - ButtonA = (TKey)(object)controllerConfig.RightJoycon.ButtonA; - ButtonB = (TKey)(object)controllerConfig.RightJoycon.ButtonB; - ButtonX = (TKey)(object)controllerConfig.RightJoycon.ButtonX; - ButtonY = (TKey)(object)controllerConfig.RightJoycon.ButtonY; - ButtonR = (TKey)(object)controllerConfig.RightJoycon.ButtonR; - RightButtonSl = (TKey)(object)controllerConfig.RightJoycon.ButtonSl; - RightButtonSr = (TKey)(object)controllerConfig.RightJoycon.ButtonSr; - ButtonZr = (TKey)(object)controllerConfig.RightJoycon.ButtonZr; - ButtonPlus = (TKey)(object)controllerConfig.RightJoycon.ButtonPlus; - - DpadUp = (TKey)(object)controllerConfig.LeftJoycon.DpadUp; - DpadDown = (TKey)(object)controllerConfig.LeftJoycon.DpadDown; - DpadLeft = (TKey)(object)controllerConfig.LeftJoycon.DpadLeft; - DpadRight = (TKey)(object)controllerConfig.LeftJoycon.DpadRight; - ButtonMinus = (TKey)(object)controllerConfig.LeftJoycon.ButtonMinus; - LeftButtonSl = (TKey)(object)controllerConfig.LeftJoycon.ButtonSl; - LeftButtonSr = (TKey)(object)controllerConfig.LeftJoycon.ButtonSr; - ButtonZl = (TKey)(object)controllerConfig.LeftJoycon.ButtonZl; - ButtonL = (TKey)(object)controllerConfig.LeftJoycon.ButtonL; - - DeadzoneLeft = controllerConfig.DeadzoneLeft; - DeadzoneRight = controllerConfig.DeadzoneRight; - RangeLeft = controllerConfig.RangeLeft; - RangeRight = controllerConfig.RangeRight; - TriggerThreshold = controllerConfig.TriggerThreshold; - - if (controllerConfig.Motion != null) - { - EnableMotion = controllerConfig.Motion.EnableMotion; - MotionBackend = controllerConfig.Motion.MotionBackend; - GyroDeadzone = controllerConfig.Motion.GyroDeadzone; - Sensitivity = controllerConfig.Motion.Sensitivity; - - if (controllerConfig.Motion is CemuHookMotionConfigController cemuHook) - { - EnableCemuHookMotion = true; - DsuServerHost = cemuHook.DsuServerHost; - DsuServerPort = cemuHook.DsuServerPort; - Slot = cemuHook.Slot; - AltSlot = cemuHook.AltSlot; - MirrorInput = cemuHook.MirrorInput; - } - - if (controllerConfig.Rumble != null) - { - EnableRumble = controllerConfig.Rumble.EnableRumble; - WeakRumble = controllerConfig.Rumble.WeakRumble; - StrongRumble = controllerConfig.Rumble.StrongRumble; - } - } - } - } - } - - public InputConfiguration() - { - } - - public InputConfig GetConfig() - { - if (Backend == InputBackendType.WindowKeyboard) - { - return new StandardKeyboardInputConfig - { - Id = Id, - Backend = Backend, - PlayerIndex = PlayerIndex, - ControllerType = ControllerType, - LeftJoycon = new LeftJoyconCommonConfig<Key> - { - DpadUp = (Key)(object)DpadUp, - DpadDown = (Key)(object)DpadDown, - DpadLeft = (Key)(object)DpadLeft, - DpadRight = (Key)(object)DpadRight, - ButtonL = (Key)(object)ButtonL, - ButtonZl = (Key)(object)ButtonZl, - ButtonSl = (Key)(object)LeftButtonSl, - ButtonSr = (Key)(object)LeftButtonSr, - ButtonMinus = (Key)(object)ButtonMinus, - }, - RightJoycon = new RightJoyconCommonConfig<Key> - { - ButtonA = (Key)(object)ButtonA, - ButtonB = (Key)(object)ButtonB, - ButtonX = (Key)(object)ButtonX, - ButtonY = (Key)(object)ButtonY, - ButtonPlus = (Key)(object)ButtonPlus, - ButtonSl = (Key)(object)RightButtonSl, - ButtonSr = (Key)(object)RightButtonSr, - ButtonR = (Key)(object)ButtonR, - ButtonZr = (Key)(object)ButtonZr, - }, - LeftJoyconStick = new JoyconConfigKeyboardStick<Key> - { - StickUp = (Key)(object)LeftStickUp, - StickDown = (Key)(object)LeftStickDown, - StickRight = (Key)(object)LeftStickRight, - StickLeft = (Key)(object)LeftStickLeft, - StickButton = (Key)(object)LeftKeyboardStickButton, - }, - RightJoyconStick = new JoyconConfigKeyboardStick<Key> - { - StickUp = (Key)(object)RightStickUp, - StickDown = (Key)(object)RightStickDown, - StickLeft = (Key)(object)RightStickLeft, - StickRight = (Key)(object)RightStickRight, - StickButton = (Key)(object)RightKeyboardStickButton, - }, - Version = InputConfig.CurrentVersion, - }; - - } - - if (Backend == InputBackendType.GamepadSDL2) - { - var config = new StandardControllerInputConfig - { - Id = Id, - Backend = Backend, - PlayerIndex = PlayerIndex, - ControllerType = ControllerType, - LeftJoycon = new LeftJoyconCommonConfig<GamepadInputId> - { - DpadUp = (GamepadInputId)(object)DpadUp, - DpadDown = (GamepadInputId)(object)DpadDown, - DpadLeft = (GamepadInputId)(object)DpadLeft, - DpadRight = (GamepadInputId)(object)DpadRight, - ButtonL = (GamepadInputId)(object)ButtonL, - ButtonZl = (GamepadInputId)(object)ButtonZl, - ButtonSl = (GamepadInputId)(object)LeftButtonSl, - ButtonSr = (GamepadInputId)(object)LeftButtonSr, - ButtonMinus = (GamepadInputId)(object)ButtonMinus, - }, - RightJoycon = new RightJoyconCommonConfig<GamepadInputId> - { - ButtonA = (GamepadInputId)(object)ButtonA, - ButtonB = (GamepadInputId)(object)ButtonB, - ButtonX = (GamepadInputId)(object)ButtonX, - ButtonY = (GamepadInputId)(object)ButtonY, - ButtonPlus = (GamepadInputId)(object)ButtonPlus, - ButtonSl = (GamepadInputId)(object)RightButtonSl, - ButtonSr = (GamepadInputId)(object)RightButtonSr, - ButtonR = (GamepadInputId)(object)ButtonR, - ButtonZr = (GamepadInputId)(object)ButtonZr, - }, - LeftJoyconStick = new JoyconConfigControllerStick<GamepadInputId, StickInputId> - { - Joystick = (StickInputId)(object)LeftJoystick, - InvertStickX = LeftInvertStickX, - InvertStickY = LeftInvertStickY, - Rotate90CW = LeftRotate90, - StickButton = (GamepadInputId)(object)LeftControllerStickButton, - }, - RightJoyconStick = new JoyconConfigControllerStick<GamepadInputId, StickInputId> - { - Joystick = (StickInputId)(object)RightJoystick, - InvertStickX = RightInvertStickX, - InvertStickY = RightInvertStickY, - Rotate90CW = RightRotate90, - StickButton = (GamepadInputId)(object)RightControllerStickButton, - }, - Rumble = new RumbleConfigController - { - EnableRumble = EnableRumble, - WeakRumble = WeakRumble, - StrongRumble = StrongRumble, - }, - Version = InputConfig.CurrentVersion, - DeadzoneLeft = DeadzoneLeft, - DeadzoneRight = DeadzoneRight, - RangeLeft = RangeLeft, - RangeRight = RangeRight, - TriggerThreshold = TriggerThreshold, - Motion = EnableCemuHookMotion - ? new CemuHookMotionConfigController - { - DsuServerHost = DsuServerHost, - DsuServerPort = DsuServerPort, - Slot = Slot, - AltSlot = AltSlot, - MirrorInput = MirrorInput, - MotionBackend = MotionInputBackendType.CemuHook, - } - : new StandardMotionConfigController - { - MotionBackend = MotionInputBackendType.GamepadDriver, - }, - }; - - config.Motion.Sensitivity = Sensitivity; - config.Motion.EnableMotion = EnableMotion; - config.Motion.GyroDeadzone = GyroDeadzone; - - return config; - } - - return null; - } - } -} diff --git a/src/Ryujinx.Ava/UI/Models/ModModel.cs b/src/Ryujinx.Ava/UI/Models/ModModel.cs deleted file mode 100644 index ee28ca5f..00000000 --- a/src/Ryujinx.Ava/UI/Models/ModModel.cs +++ /dev/null @@ -1,32 +0,0 @@ -using Ryujinx.Ava.UI.ViewModels; -using System.IO; - -namespace Ryujinx.Ava.UI.Models -{ - public class ModModel : BaseModel - { - private bool _enabled; - - public bool Enabled - { - get => _enabled; - set - { - _enabled = value; - OnPropertyChanged(); - } - } - - public bool InSd { get; } - public string Path { get; } - public string Name { get; } - - public ModModel(string path, string name, bool enabled, bool inSd) - { - Path = path; - Name = name; - Enabled = enabled; - InSd = inSd; - } - } -} diff --git a/src/Ryujinx.Ava/UI/Models/PlayerModel.cs b/src/Ryujinx.Ava/UI/Models/PlayerModel.cs deleted file mode 100644 index a19852b9..00000000 --- a/src/Ryujinx.Ava/UI/Models/PlayerModel.cs +++ /dev/null @@ -1,6 +0,0 @@ -using Ryujinx.Common.Configuration.Hid; - -namespace Ryujinx.Ava.UI.Models -{ - public record PlayerModel(PlayerIndex Id, string Name); -} diff --git a/src/Ryujinx.Ava/UI/Models/ProfileImageModel.cs b/src/Ryujinx.Ava/UI/Models/ProfileImageModel.cs deleted file mode 100644 index 99365dfc..00000000 --- a/src/Ryujinx.Ava/UI/Models/ProfileImageModel.cs +++ /dev/null @@ -1,32 +0,0 @@ -using Avalonia.Media; -using Ryujinx.Ava.UI.ViewModels; - -namespace Ryujinx.Ava.UI.Models -{ - public class ProfileImageModel : BaseModel - { - public ProfileImageModel(string name, byte[] data) - { - Name = name; - Data = data; - } - - public string Name { get; set; } - public byte[] Data { get; set; } - - private SolidColorBrush _backgroundColor = new(Colors.White); - - public SolidColorBrush BackgroundColor - { - get - { - return _backgroundColor; - } - set - { - _backgroundColor = value; - OnPropertyChanged(); - } - } - } -} diff --git a/src/Ryujinx.Ava/UI/Models/SaveModel.cs b/src/Ryujinx.Ava/UI/Models/SaveModel.cs deleted file mode 100644 index d6dea2f6..00000000 --- a/src/Ryujinx.Ava/UI/Models/SaveModel.cs +++ /dev/null @@ -1,96 +0,0 @@ -using LibHac.Fs; -using LibHac.Ncm; -using Ryujinx.Ava.UI.ViewModels; -using Ryujinx.Ava.UI.Windows; -using Ryujinx.HLE.FileSystem; -using Ryujinx.UI.App.Common; -using Ryujinx.UI.Common.Helper; -using System.IO; -using System.Linq; -using System.Threading.Tasks; -using Path = System.IO.Path; - -namespace Ryujinx.Ava.UI.Models -{ - public class SaveModel : BaseModel - { - private long _size; - - public ulong SaveId { get; } - public ProgramId TitleId { get; } - public string TitleIdString => $"{TitleId.Value:X16}"; - public UserId UserId { get; } - public bool InGameList { get; } - public string Title { get; } - public byte[] Icon { get; } - - public long Size - { - get => _size; set - { - _size = value; - SizeAvailable = true; - OnPropertyChanged(); - OnPropertyChanged(nameof(SizeString)); - OnPropertyChanged(nameof(SizeAvailable)); - } - } - - public bool SizeAvailable { get; set; } - - public string SizeString => ValueFormatUtils.FormatFileSize(Size); - - public SaveModel(SaveDataInfo info) - { - SaveId = info.SaveDataId; - TitleId = info.ProgramId; - UserId = info.UserId; - - var appData = MainWindow.MainWindowViewModel.Applications.FirstOrDefault(x => x.TitleId.ToUpper() == TitleIdString); - - InGameList = appData != null; - - if (InGameList) - { - Icon = appData.Icon; - Title = appData.TitleName; - } - else - { - var appMetadata = ApplicationLibrary.LoadAndSaveMetaData(TitleIdString); - Title = appMetadata.Title ?? TitleIdString; - } - - Task.Run(() => - { - var saveRoot = Path.Combine(VirtualFileSystem.GetNandPath(), $"user/save/{info.SaveDataId:x16}"); - - long totalSize = GetDirectorySize(saveRoot); - - static long GetDirectorySize(string path) - { - long size = 0; - if (Directory.Exists(path)) - { - var directories = Directory.GetDirectories(path); - foreach (var directory in directories) - { - size += GetDirectorySize(directory); - } - - var files = Directory.GetFiles(path); - foreach (var file in files) - { - size += new FileInfo(file).Length; - } - } - - return size; - } - - Size = totalSize; - }); - - } - } -} diff --git a/src/Ryujinx.Ava/UI/Models/StatusUpdatedEventArgs.cs b/src/Ryujinx.Ava/UI/Models/StatusUpdatedEventArgs.cs deleted file mode 100644 index 7f04c0ee..00000000 --- a/src/Ryujinx.Ava/UI/Models/StatusUpdatedEventArgs.cs +++ /dev/null @@ -1,28 +0,0 @@ -using System; - -namespace Ryujinx.Ava.UI.Models -{ - internal class StatusUpdatedEventArgs : EventArgs - { - public bool VSyncEnabled { get; } - public string VolumeStatus { get; } - public string GpuBackend { get; } - public string AspectRatio { get; } - public string DockedMode { get; } - public string FifoStatus { get; } - public string GameStatus { get; } - public string GpuName { get; } - - public StatusUpdatedEventArgs(bool vSyncEnabled, string volumeStatus, string gpuBackend, string dockedMode, string aspectRatio, string gameStatus, string fifoStatus, string gpuName) - { - VSyncEnabled = vSyncEnabled; - VolumeStatus = volumeStatus; - GpuBackend = gpuBackend; - DockedMode = dockedMode; - AspectRatio = aspectRatio; - GameStatus = gameStatus; - FifoStatus = fifoStatus; - GpuName = gpuName; - } - } -} diff --git a/src/Ryujinx.Ava/UI/Models/TempProfile.cs b/src/Ryujinx.Ava/UI/Models/TempProfile.cs deleted file mode 100644 index 659092e6..00000000 --- a/src/Ryujinx.Ava/UI/Models/TempProfile.cs +++ /dev/null @@ -1,61 +0,0 @@ -using Ryujinx.Ava.UI.ViewModels; -using Ryujinx.HLE.HOS.Services.Account.Acc; -using System; - -namespace Ryujinx.Ava.UI.Models -{ - public class TempProfile : BaseModel - { - private readonly UserProfile _profile; - private byte[] _image; - private string _name = String.Empty; - private UserId _userId; - - public static uint MaxProfileNameLength => 0x20; - - public byte[] Image - { - get => _image; - set - { - _image = value; - OnPropertyChanged(); - } - } - - public UserId UserId - { - get => _userId; - set - { - _userId = value; - OnPropertyChanged(); - OnPropertyChanged(nameof(UserIdString)); - } - } - - public string UserIdString => _userId.ToString(); - - public string Name - { - get => _name; - set - { - _name = value; - OnPropertyChanged(); - } - } - - public TempProfile(UserProfile profile) - { - _profile = profile; - - if (_profile != null) - { - Image = profile.Image; - Name = profile.Name; - UserId = profile.UserId; - } - } - } -} diff --git a/src/Ryujinx.Ava/UI/Models/TimeZone.cs b/src/Ryujinx.Ava/UI/Models/TimeZone.cs deleted file mode 100644 index 950fbce4..00000000 --- a/src/Ryujinx.Ava/UI/Models/TimeZone.cs +++ /dev/null @@ -1,16 +0,0 @@ -namespace Ryujinx.Ava.UI.Models -{ - internal class TimeZone - { - public TimeZone(string utcDifference, string location, string abbreviation) - { - UtcDifference = utcDifference; - Location = location; - Abbreviation = abbreviation; - } - - public string UtcDifference { get; set; } - public string Location { get; set; } - public string Abbreviation { get; set; } - } -} diff --git a/src/Ryujinx.Ava/UI/Models/TitleUpdateModel.cs b/src/Ryujinx.Ava/UI/Models/TitleUpdateModel.cs deleted file mode 100644 index c270c9ed..00000000 --- a/src/Ryujinx.Ava/UI/Models/TitleUpdateModel.cs +++ /dev/null @@ -1,19 +0,0 @@ -using LibHac.Ns; -using Ryujinx.Ava.Common.Locale; - -namespace Ryujinx.Ava.UI.Models -{ - public class TitleUpdateModel - { - public ApplicationControlProperty Control { get; } - public string Path { get; } - - public string Label => LocaleManager.Instance.UpdateAndGetDynamicValue(LocaleKeys.TitleUpdateVersionLabel, Control.DisplayVersionString.ToString()); - - public TitleUpdateModel(ApplicationControlProperty control, string path) - { - Control = control; - Path = path; - } - } -} diff --git a/src/Ryujinx.Ava/UI/Models/UserProfile.cs b/src/Ryujinx.Ava/UI/Models/UserProfile.cs deleted file mode 100644 index 7a9237fe..00000000 --- a/src/Ryujinx.Ava/UI/Models/UserProfile.cs +++ /dev/null @@ -1,104 +0,0 @@ -using Avalonia.Media; -using Ryujinx.Ava.UI.Controls; -using Ryujinx.Ava.UI.ViewModels; -using Ryujinx.Ava.UI.Views.User; -using Ryujinx.HLE.HOS.Services.Account.Acc; -using Profile = Ryujinx.HLE.HOS.Services.Account.Acc.UserProfile; - -namespace Ryujinx.Ava.UI.Models -{ - public class UserProfile : BaseModel - { - private readonly Profile _profile; - private readonly NavigationDialogHost _owner; - private byte[] _image; - private string _name; - private UserId _userId; - private bool _isPointerOver; - private IBrush _backgroundColor; - - public byte[] Image - { - get => _image; - set - { - _image = value; - OnPropertyChanged(); - } - } - - public UserId UserId - { - get => _userId; - set - { - _userId = value; - OnPropertyChanged(); - } - } - - public string Name - { - get => _name; - set - { - _name = value; - OnPropertyChanged(); - } - } - - public bool IsPointerOver - { - get => _isPointerOver; - set - { - _isPointerOver = value; - OnPropertyChanged(); - } - } - - public IBrush BackgroundColor - { - get => _backgroundColor; - set - { - _backgroundColor = value; - OnPropertyChanged(); - } - } - - public UserProfile(Profile profile, NavigationDialogHost owner) - { - _profile = profile; - _owner = owner; - - UpdateBackground(); - - Image = profile.Image; - Name = profile.Name; - UserId = profile.UserId; - } - - public void UpdateState() - { - UpdateBackground(); - OnPropertyChanged(nameof(Name)); - } - - private void UpdateBackground() - { - var currentApplication = Avalonia.Application.Current; - currentApplication.Styles.TryGetResource("ControlFillColorSecondary", currentApplication.ActualThemeVariant, out object color); - - if (color is not null) - { - BackgroundColor = _profile.AccountState == AccountState.Open ? new SolidColorBrush((Color)color) : Brushes.Transparent; - } - } - - public void Recover(UserProfile userProfile) - { - _owner.Navigate(typeof(UserEditorView), (_owner, userProfile, true)); - } - } -} diff --git a/src/Ryujinx.Ava/UI/Renderer/EmbeddedWindow.cs b/src/Ryujinx.Ava/UI/Renderer/EmbeddedWindow.cs deleted file mode 100644 index 3bf19b43..00000000 --- a/src/Ryujinx.Ava/UI/Renderer/EmbeddedWindow.cs +++ /dev/null @@ -1,294 +0,0 @@ -using Avalonia; -using Avalonia.Controls; -using Avalonia.Input; -using Avalonia.Platform; -using Ryujinx.Common.Configuration; -using Ryujinx.UI.Common.Configuration; -using Ryujinx.UI.Common.Helper; -using SPB.Graphics; -using SPB.Platform; -using SPB.Platform.GLX; -using SPB.Platform.X11; -using SPB.Windowing; -using System; -using System.Runtime.InteropServices; -using System.Runtime.Versioning; -using System.Threading.Tasks; -using static Ryujinx.Ava.UI.Helpers.Win32NativeInterop; - -namespace Ryujinx.Ava.UI.Renderer -{ - public class EmbeddedWindow : NativeControlHost - { - private WindowProc _wndProcDelegate; - private string _className; - - protected GLXWindow X11Window { get; set; } - - protected IntPtr WindowHandle { get; set; } - protected IntPtr X11Display { get; set; } - protected IntPtr NsView { get; set; } - protected IntPtr MetalLayer { get; set; } - - public delegate void UpdateBoundsCallbackDelegate(Rect rect); - private UpdateBoundsCallbackDelegate _updateBoundsCallback; - - public event EventHandler<IntPtr> WindowCreated; - public event EventHandler<Size> BoundsChanged; - - public EmbeddedWindow() - { - this.GetObservable(BoundsProperty).Subscribe(StateChanged); - - Initialized += OnNativeEmbeddedWindowCreated; - } - - public virtual void OnWindowCreated() { } - - protected virtual void OnWindowDestroyed() { } - - protected virtual void OnWindowDestroying() - { - WindowHandle = IntPtr.Zero; - X11Display = IntPtr.Zero; - NsView = IntPtr.Zero; - MetalLayer = IntPtr.Zero; - } - - private void OnNativeEmbeddedWindowCreated(object sender, EventArgs e) - { - OnWindowCreated(); - - Task.Run(() => - { - WindowCreated?.Invoke(this, WindowHandle); - }); - } - - private void StateChanged(Rect rect) - { - BoundsChanged?.Invoke(this, rect.Size); - _updateBoundsCallback?.Invoke(rect); - } - - protected override IPlatformHandle CreateNativeControlCore(IPlatformHandle control) - { - if (OperatingSystem.IsLinux()) - { - return CreateLinux(control); - } - - if (OperatingSystem.IsWindows()) - { - return CreateWin32(control); - } - - if (OperatingSystem.IsMacOS()) - { - return CreateMacOS(); - } - - return base.CreateNativeControlCore(control); - } - - protected override void DestroyNativeControlCore(IPlatformHandle control) - { - OnWindowDestroying(); - - if (OperatingSystem.IsLinux()) - { - DestroyLinux(); - } - else if (OperatingSystem.IsWindows()) - { - DestroyWin32(control); - } - else if (OperatingSystem.IsMacOS()) - { - DestroyMacOS(); - } - else - { - base.DestroyNativeControlCore(control); - } - - OnWindowDestroyed(); - } - - [SupportedOSPlatform("linux")] - private IPlatformHandle CreateLinux(IPlatformHandle control) - { - if (ConfigurationState.Instance.Graphics.GraphicsBackend.Value == GraphicsBackend.Vulkan) - { - X11Window = new GLXWindow(new NativeHandle(X11.DefaultDisplay), new NativeHandle(control.Handle)); - X11Window.Hide(); - } - else - { - X11Window = PlatformHelper.CreateOpenGLWindow(new FramebufferFormat(new ColorFormat(8, 8, 8, 0), 16, 0, ColorFormat.Zero, 0, 2, false), 0, 0, 100, 100) as GLXWindow; - } - - WindowHandle = X11Window.WindowHandle.RawHandle; - X11Display = X11Window.DisplayHandle.RawHandle; - - return new PlatformHandle(WindowHandle, "X11"); - } - - [SupportedOSPlatform("windows")] - IPlatformHandle CreateWin32(IPlatformHandle control) - { - _className = "NativeWindow-" + Guid.NewGuid(); - - _wndProcDelegate = delegate (IntPtr hWnd, WindowsMessages msg, IntPtr wParam, IntPtr lParam) - { - if (VisualRoot != null) - { - if (msg == WindowsMessages.Lbuttondown || - msg == WindowsMessages.Rbuttondown || - msg == WindowsMessages.Lbuttonup || - msg == WindowsMessages.Rbuttonup || - msg == WindowsMessages.Mousemove) - { - Point rootVisualPosition = this.TranslatePoint(new Point((long)lParam & 0xFFFF, (long)lParam >> 16 & 0xFFFF), this).Value; - Pointer pointer = new(0, PointerType.Mouse, true); - -#pragma warning disable CS0618 // Type or member is obsolete (As of Avalonia 11, the constructors for PointerPressedEventArgs & PointerEventArgs are marked as obsolete) - switch (msg) - { - case WindowsMessages.Lbuttondown: - case WindowsMessages.Rbuttondown: - { - bool isLeft = msg == WindowsMessages.Lbuttondown; - RawInputModifiers pointerPointModifier = isLeft ? RawInputModifiers.LeftMouseButton : RawInputModifiers.RightMouseButton; - PointerPointProperties properties = new(pointerPointModifier, isLeft ? PointerUpdateKind.LeftButtonPressed : PointerUpdateKind.RightButtonPressed); - - var evnt = new PointerPressedEventArgs( - this, - pointer, - this, - rootVisualPosition, - (ulong)Environment.TickCount64, - properties, - KeyModifiers.None); - - RaiseEvent(evnt); - - break; - } - case WindowsMessages.Lbuttonup: - case WindowsMessages.Rbuttonup: - { - bool isLeft = msg == WindowsMessages.Lbuttonup; - RawInputModifiers pointerPointModifier = isLeft ? RawInputModifiers.LeftMouseButton : RawInputModifiers.RightMouseButton; - PointerPointProperties properties = new(pointerPointModifier, isLeft ? PointerUpdateKind.LeftButtonReleased : PointerUpdateKind.RightButtonReleased); - - var evnt = new PointerReleasedEventArgs( - this, - pointer, - this, - rootVisualPosition, - (ulong)Environment.TickCount64, - properties, - KeyModifiers.None, - isLeft ? MouseButton.Left : MouseButton.Right); - - RaiseEvent(evnt); - - break; - } - case WindowsMessages.Mousemove: - { - var evnt = new PointerEventArgs( - PointerMovedEvent, - this, - pointer, - this, - rootVisualPosition, - (ulong)Environment.TickCount64, - new PointerPointProperties(RawInputModifiers.None, PointerUpdateKind.Other), - KeyModifiers.None); - - RaiseEvent(evnt); - - break; - } - } -#pragma warning restore CS0618 - } - } - - return DefWindowProc(hWnd, msg, wParam, lParam); - }; - - WndClassEx wndClassEx = new() - { - cbSize = Marshal.SizeOf<WndClassEx>(), - hInstance = GetModuleHandle(null), - lpfnWndProc = Marshal.GetFunctionPointerForDelegate(_wndProcDelegate), - style = ClassStyles.CsOwndc, - lpszClassName = Marshal.StringToHGlobalUni(_className), - hCursor = CreateArrowCursor(), - }; - - RegisterClassEx(ref wndClassEx); - - WindowHandle = CreateWindowEx(0, _className, "NativeWindow", WindowStyles.WsChild, 0, 0, 640, 480, control.Handle, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero); - - Marshal.FreeHGlobal(wndClassEx.lpszClassName); - - return new PlatformHandle(WindowHandle, "HWND"); - } - - [SupportedOSPlatform("macos")] - IPlatformHandle CreateMacOS() - { - // Create a new CAMetalLayer. - ObjectiveC.Object layerObject = new("CAMetalLayer"); - ObjectiveC.Object metalLayer = layerObject.GetFromMessage("alloc"); - metalLayer.SendMessage("init"); - - // Create a child NSView to render into. - ObjectiveC.Object nsViewObject = new("NSView"); - ObjectiveC.Object child = nsViewObject.GetFromMessage("alloc"); - child.SendMessage("init", new ObjectiveC.NSRect(0, 0, 0, 0)); - - // Make its renderer our metal layer. - child.SendMessage("setWantsLayer:", 1); - child.SendMessage("setLayer:", metalLayer); - metalLayer.SendMessage("setContentsScale:", Program.DesktopScaleFactor); - - // Ensure the scale factor is up to date. - _updateBoundsCallback = rect => - { - metalLayer.SendMessage("setContentsScale:", Program.DesktopScaleFactor); - }; - - IntPtr nsView = child.ObjPtr; - MetalLayer = metalLayer.ObjPtr; - NsView = nsView; - - return new PlatformHandle(nsView, "NSView"); - } - - [SupportedOSPlatform("Linux")] - void DestroyLinux() - { - X11Window?.Dispose(); - } - - [SupportedOSPlatform("windows")] - void DestroyWin32(IPlatformHandle handle) - { - DestroyWindow(handle.Handle); - UnregisterClass(_className, GetModuleHandle(null)); - } - - [SupportedOSPlatform("macos")] -#pragma warning disable CA1822 // Mark member as static - void DestroyMacOS() - { - // TODO - } -#pragma warning restore CA1822 - } -} diff --git a/src/Ryujinx.Ava/UI/Renderer/EmbeddedWindowOpenGL.cs b/src/Ryujinx.Ava/UI/Renderer/EmbeddedWindowOpenGL.cs deleted file mode 100644 index 3842301d..00000000 --- a/src/Ryujinx.Ava/UI/Renderer/EmbeddedWindowOpenGL.cs +++ /dev/null @@ -1,94 +0,0 @@ -using OpenTK.Graphics.OpenGL; -using Ryujinx.Common.Configuration; -using Ryujinx.Common.Logging; -using Ryujinx.Graphics.GAL; -using Ryujinx.Graphics.OpenGL; -using Ryujinx.UI.Common.Configuration; -using SPB.Graphics; -using SPB.Graphics.Exceptions; -using SPB.Graphics.OpenGL; -using SPB.Platform; -using SPB.Platform.WGL; -using SPB.Windowing; -using System; - -namespace Ryujinx.Ava.UI.Renderer -{ - public class EmbeddedWindowOpenGL : EmbeddedWindow - { - private SwappableNativeWindowBase _window; - - public OpenGLContextBase Context { get; set; } - - protected override void OnWindowDestroying() - { - Context.Dispose(); - - base.OnWindowDestroying(); - } - - public override void OnWindowCreated() - { - base.OnWindowCreated(); - - if (OperatingSystem.IsWindows()) - { - _window = new WGLWindow(new NativeHandle(WindowHandle)); - } - else if (OperatingSystem.IsLinux()) - { - _window = X11Window; - } - else - { - throw new PlatformNotSupportedException(); - } - - var flags = OpenGLContextFlags.Compat; - if (ConfigurationState.Instance.Logger.GraphicsDebugLevel != GraphicsDebugLevel.None) - { - flags |= OpenGLContextFlags.Debug; - } - - var graphicsMode = Environment.OSVersion.Platform == PlatformID.Unix ? new FramebufferFormat(new ColorFormat(8, 8, 8, 0), 16, 0, ColorFormat.Zero, 0, 2, false) : FramebufferFormat.Default; - - Context = PlatformHelper.CreateOpenGLContext(graphicsMode, 3, 3, flags); - - Context.Initialize(_window); - Context.MakeCurrent(_window); - - GL.LoadBindings(new OpenTKBindingsContext(Context.GetProcAddress)); - - Context.MakeCurrent(null); - } - - public void MakeCurrent(bool unbind = false, bool shouldThrow = true) - { - try - { - Context?.MakeCurrent(!unbind ? _window : null); - } - catch (ContextException e) - { - if (shouldThrow) - { - throw; - } - - Logger.Warning?.Print(LogClass.UI, $"Failed to {(!unbind ? "bind" : "unbind")} OpenGL context: {e}"); - } - } - - public void SwapBuffers() - { - _window?.SwapBuffers(); - } - - public void InitializeBackgroundContext(IRenderer renderer) - { - (renderer as OpenGLRenderer)?.InitializeBackgroundContext(SPBOpenGLContext.CreateBackgroundContext(Context)); - - MakeCurrent(); - } - } -} diff --git a/src/Ryujinx.Ava/UI/Renderer/EmbeddedWindowVulkan.cs b/src/Ryujinx.Ava/UI/Renderer/EmbeddedWindowVulkan.cs deleted file mode 100644 index fafbec20..00000000 --- a/src/Ryujinx.Ava/UI/Renderer/EmbeddedWindowVulkan.cs +++ /dev/null @@ -1,42 +0,0 @@ -using Silk.NET.Vulkan; -using SPB.Graphics.Vulkan; -using SPB.Platform.Metal; -using SPB.Platform.Win32; -using SPB.Platform.X11; -using SPB.Windowing; -using System; - -namespace Ryujinx.Ava.UI.Renderer -{ - public class EmbeddedWindowVulkan : EmbeddedWindow - { - public SurfaceKHR CreateSurface(Instance instance) - { - NativeWindowBase nativeWindowBase; - - if (OperatingSystem.IsWindows()) - { - nativeWindowBase = new SimpleWin32Window(new NativeHandle(WindowHandle)); - } - else if (OperatingSystem.IsLinux()) - { - nativeWindowBase = new SimpleX11Window(new NativeHandle(X11Display), new NativeHandle(WindowHandle)); - } - else if (OperatingSystem.IsMacOS()) - { - nativeWindowBase = new SimpleMetalWindow(new NativeHandle(NsView), new NativeHandle(MetalLayer)); - } - else - { - throw new PlatformNotSupportedException(); - } - - return new SurfaceKHR((ulong?)VulkanHelper.CreateWindowSurface(instance.Handle, nativeWindowBase)); - } - - public SurfaceKHR CreateSurface(Instance instance, Vk _) - { - return CreateSurface(instance); - } - } -} diff --git a/src/Ryujinx.Ava/UI/Renderer/OpenTKBindingsContext.cs b/src/Ryujinx.Ava/UI/Renderer/OpenTKBindingsContext.cs deleted file mode 100644 index 85e8585f..00000000 --- a/src/Ryujinx.Ava/UI/Renderer/OpenTKBindingsContext.cs +++ /dev/null @@ -1,20 +0,0 @@ -using OpenTK; -using System; - -namespace Ryujinx.Ava.UI.Renderer -{ - internal class OpenTKBindingsContext : IBindingsContext - { - private readonly Func<string, IntPtr> _getProcAddress; - - public OpenTKBindingsContext(Func<string, IntPtr> getProcAddress) - { - _getProcAddress = getProcAddress; - } - - public IntPtr GetProcAddress(string procName) - { - return _getProcAddress(procName); - } - } -} diff --git a/src/Ryujinx.Ava/UI/Renderer/RendererHost.axaml b/src/Ryujinx.Ava/UI/Renderer/RendererHost.axaml deleted file mode 100644 index e0b586b4..00000000 --- a/src/Ryujinx.Ava/UI/Renderer/RendererHost.axaml +++ /dev/null @@ -1,12 +0,0 @@ -<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:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" - mc:Ignorable="d" - d:DesignWidth="800" - d:DesignHeight="450" - x:Class="Ryujinx.Ava.UI.Renderer.RendererHost" - FlowDirection="LeftToRight" - Focusable="True"> -</UserControl> diff --git a/src/Ryujinx.Ava/UI/Renderer/RendererHost.axaml.cs b/src/Ryujinx.Ava/UI/Renderer/RendererHost.axaml.cs deleted file mode 100644 index d055d9ea..00000000 --- a/src/Ryujinx.Ava/UI/Renderer/RendererHost.axaml.cs +++ /dev/null @@ -1,68 +0,0 @@ -using Avalonia; -using Avalonia.Controls; -using Ryujinx.Common.Configuration; -using Ryujinx.UI.Common.Configuration; -using System; - -namespace Ryujinx.Ava.UI.Renderer -{ - public partial class RendererHost : UserControl, IDisposable - { - public readonly EmbeddedWindow EmbeddedWindow; - - public event EventHandler<EventArgs> WindowCreated; - public event Action<object, Size> BoundsChanged; - - public RendererHost() - { - InitializeComponent(); - - if (ConfigurationState.Instance.Graphics.GraphicsBackend.Value == GraphicsBackend.OpenGl) - { - EmbeddedWindow = new EmbeddedWindowOpenGL(); - } - else - { - EmbeddedWindow = new EmbeddedWindowVulkan(); - } - - Initialize(); - } - - private void Initialize() - { - EmbeddedWindow.WindowCreated += CurrentWindow_WindowCreated; - EmbeddedWindow.BoundsChanged += CurrentWindow_BoundsChanged; - - Content = EmbeddedWindow; - } - - public void Dispose() - { - if (EmbeddedWindow != null) - { - EmbeddedWindow.WindowCreated -= CurrentWindow_WindowCreated; - EmbeddedWindow.BoundsChanged -= CurrentWindow_BoundsChanged; - } - - GC.SuppressFinalize(this); - } - - protected override void OnDetachedFromVisualTree(VisualTreeAttachmentEventArgs e) - { - base.OnDetachedFromVisualTree(e); - - Dispose(); - } - - private void CurrentWindow_BoundsChanged(object sender, Size e) - { - BoundsChanged?.Invoke(sender, e); - } - - private void CurrentWindow_WindowCreated(object sender, IntPtr e) - { - WindowCreated?.Invoke(this, EventArgs.Empty); - } - } -} diff --git a/src/Ryujinx.Ava/UI/Renderer/SPBOpenGLContext.cs b/src/Ryujinx.Ava/UI/Renderer/SPBOpenGLContext.cs deleted file mode 100644 index 63bf6cf7..00000000 --- a/src/Ryujinx.Ava/UI/Renderer/SPBOpenGLContext.cs +++ /dev/null @@ -1,49 +0,0 @@ -using OpenTK.Graphics.OpenGL; -using Ryujinx.Graphics.OpenGL; -using SPB.Graphics; -using SPB.Graphics.OpenGL; -using SPB.Platform; -using SPB.Windowing; - -namespace Ryujinx.Ava.UI.Renderer -{ - class SPBOpenGLContext : IOpenGLContext - { - private readonly OpenGLContextBase _context; - private readonly NativeWindowBase _window; - - private SPBOpenGLContext(OpenGLContextBase context, NativeWindowBase window) - { - _context = context; - _window = window; - } - - public void Dispose() - { - _context.Dispose(); - _window.Dispose(); - } - - public void MakeCurrent() - { - _context.MakeCurrent(_window); - } - - public bool HasContext() => _context.IsCurrent; - - public static SPBOpenGLContext CreateBackgroundContext(OpenGLContextBase sharedContext) - { - OpenGLContextBase context = PlatformHelper.CreateOpenGLContext(FramebufferFormat.Default, 3, 3, OpenGLContextFlags.Compat, true, sharedContext); - NativeWindowBase window = PlatformHelper.CreateOpenGLWindow(FramebufferFormat.Default, 0, 0, 100, 100); - - context.Initialize(window); - context.MakeCurrent(window); - - GL.LoadBindings(new OpenTKBindingsContext(context.GetProcAddress)); - - context.MakeCurrent(null); - - return new SPBOpenGLContext(context, window); - } - } -} diff --git a/src/Ryujinx.Ava/UI/ViewModels/AboutWindowViewModel.cs b/src/Ryujinx.Ava/UI/ViewModels/AboutWindowViewModel.cs deleted file mode 100644 index 6020f40e..00000000 --- a/src/Ryujinx.Ava/UI/ViewModels/AboutWindowViewModel.cs +++ /dev/null @@ -1,131 +0,0 @@ -using Avalonia.Media.Imaging; -using Avalonia.Platform; -using Avalonia.Threading; -using Ryujinx.Ava.Common.Locale; -using Ryujinx.Common.Utilities; -using Ryujinx.UI.Common.Configuration; -using System; -using System.Net.Http; -using System.Net.NetworkInformation; -using System.Threading.Tasks; - -namespace Ryujinx.Ava.UI.ViewModels -{ - public class AboutWindowViewModel : BaseModel - { - private Bitmap _githubLogo; - private Bitmap _discordLogo; - private Bitmap _patreonLogo; - private Bitmap _twitterLogo; - - private string _version; - private string _supporters; - - public Bitmap GithubLogo - { - get => _githubLogo; - set - { - _githubLogo = value; - OnPropertyChanged(); - } - } - - public Bitmap DiscordLogo - { - get => _discordLogo; - set - { - _discordLogo = value; - OnPropertyChanged(); - } - } - - public Bitmap PatreonLogo - { - get => _patreonLogo; - set - { - _patreonLogo = value; - OnPropertyChanged(); - } - } - - public Bitmap TwitterLogo - { - get => _twitterLogo; - set - { - _twitterLogo = value; - OnPropertyChanged(); - } - } - - public string Supporters - { - get => _supporters; - set - { - _supporters = value; - OnPropertyChanged(); - } - } - - public string Version - { - get => _version; - set - { - _version = value; - OnPropertyChanged(); - } - } - - public string Developers => LocaleManager.Instance.UpdateAndGetDynamicValue(LocaleKeys.AboutPageDeveloperListMore, "gdkchan, Ac_K, marysaka, rip in peri peri, LDj3SNuD, emmaus, Thealexbarney, GoffyDude, TSRBerry, IsaacMarovitz"); - - public AboutWindowViewModel() - { - Version = Program.Version; - - if (ConfigurationState.Instance.UI.BaseStyle.Value == "Light") - { - GithubLogo = new Bitmap(AssetLoader.Open(new Uri("resm:Ryujinx.UI.Common.Resources.Logo_GitHub_Light.png?assembly=Ryujinx.UI.Common"))); - DiscordLogo = new Bitmap(AssetLoader.Open(new Uri("resm:Ryujinx.UI.Common.Resources.Logo_Discord_Light.png?assembly=Ryujinx.UI.Common"))); - PatreonLogo = new Bitmap(AssetLoader.Open(new Uri("resm:Ryujinx.UI.Common.Resources.Logo_Patreon_Light.png?assembly=Ryujinx.UI.Common"))); - TwitterLogo = new Bitmap(AssetLoader.Open(new Uri("resm:Ryujinx.UI.Common.Resources.Logo_Twitter_Light.png?assembly=Ryujinx.UI.Common"))); - } - else - { - GithubLogo = new Bitmap(AssetLoader.Open(new Uri("resm:Ryujinx.UI.Common.Resources.Logo_GitHub_Dark.png?assembly=Ryujinx.UI.Common"))); - DiscordLogo = new Bitmap(AssetLoader.Open(new Uri("resm:Ryujinx.UI.Common.Resources.Logo_Discord_Dark.png?assembly=Ryujinx.UI.Common"))); - PatreonLogo = new Bitmap(AssetLoader.Open(new Uri("resm:Ryujinx.UI.Common.Resources.Logo_Patreon_Dark.png?assembly=Ryujinx.UI.Common"))); - TwitterLogo = new Bitmap(AssetLoader.Open(new Uri("resm:Ryujinx.UI.Common.Resources.Logo_Twitter_Dark.png?assembly=Ryujinx.UI.Common"))); - } - - Dispatcher.UIThread.InvokeAsync(DownloadPatronsJson); - } - - private async Task DownloadPatronsJson() - { - if (!NetworkInterface.GetIsNetworkAvailable()) - { - Supporters = LocaleManager.Instance[LocaleKeys.ConnectionError]; - - return; - } - - HttpClient httpClient = new(); - - try - { - string patreonJsonString = await httpClient.GetStringAsync("https://patreon.ryujinx.org/"); - - Supporters = string.Join(", ", JsonHelper.Deserialize(patreonJsonString, CommonJsonContext.Default.StringArray)) + "\n\n"; - } - catch - { - Supporters = LocaleManager.Instance[LocaleKeys.ApiError]; - } - } - } -} diff --git a/src/Ryujinx.Ava/UI/ViewModels/AmiiboWindowViewModel.cs b/src/Ryujinx.Ava/UI/ViewModels/AmiiboWindowViewModel.cs deleted file mode 100644 index 8f09568a..00000000 --- a/src/Ryujinx.Ava/UI/ViewModels/AmiiboWindowViewModel.cs +++ /dev/null @@ -1,518 +0,0 @@ -using Avalonia; -using Avalonia.Collections; -using Avalonia.Media.Imaging; -using Avalonia.Threading; -using Ryujinx.Ava.Common.Locale; -using Ryujinx.Ava.UI.Helpers; -using Ryujinx.Ava.UI.Windows; -using Ryujinx.Common; -using Ryujinx.Common.Configuration; -using Ryujinx.Common.Logging; -using Ryujinx.Common.Utilities; -using Ryujinx.UI.Common.Models.Amiibo; -using System; -using System.Collections.Generic; -using System.Collections.ObjectModel; -using System.IO; -using System.Linq; -using System.Net.Http; -using System.Text; -using System.Text.Json; -using System.Threading.Tasks; - -namespace Ryujinx.Ava.UI.ViewModels -{ - public class AmiiboWindowViewModel : BaseModel, IDisposable - { - private const string DefaultJson = "{ \"amiibo\": [] }"; - private const float AmiiboImageSize = 350f; - - private readonly string _amiiboJsonPath; - private readonly byte[] _amiiboLogoBytes; - private readonly HttpClient _httpClient; - private readonly StyleableWindow _owner; - - private Bitmap _amiiboImage; - private List<AmiiboApi> _amiiboList; - private AvaloniaList<AmiiboApi> _amiibos; - private ObservableCollection<string> _amiiboSeries; - - private int _amiiboSelectedIndex; - private int _seriesSelectedIndex; - private bool _enableScanning; - private bool _showAllAmiibo; - private bool _useRandomUuid; - private string _usage; - - private static readonly AmiiboJsonSerializerContext _serializerContext = new(JsonHelper.GetDefaultSerializerOptions()); - - public AmiiboWindowViewModel(StyleableWindow owner, string lastScannedAmiiboId, string titleId) - { - _owner = owner; - - _httpClient = new HttpClient - { - Timeout = TimeSpan.FromSeconds(30), - }; - - LastScannedAmiiboId = lastScannedAmiiboId; - TitleId = titleId; - - Directory.CreateDirectory(Path.Join(AppDataManager.BaseDirPath, "system", "amiibo")); - - _amiiboJsonPath = Path.Join(AppDataManager.BaseDirPath, "system", "amiibo", "Amiibo.json"); - _amiiboList = new List<AmiiboApi>(); - _amiiboSeries = new ObservableCollection<string>(); - _amiibos = new AvaloniaList<AmiiboApi>(); - - _amiiboLogoBytes = EmbeddedResources.Read("Ryujinx.UI.Common/Resources/Logo_Amiibo.png"); - - _ = LoadContentAsync(); - } - - public AmiiboWindowViewModel() { } - - public string TitleId { get; set; } - public string LastScannedAmiiboId { get; set; } - - public UserResult Response { get; private set; } - - public bool UseRandomUuid - { - get => _useRandomUuid; - set - { - _useRandomUuid = value; - - OnPropertyChanged(); - } - } - - public bool ShowAllAmiibo - { - get => _showAllAmiibo; - set - { - _showAllAmiibo = value; - - ParseAmiiboData(); - - OnPropertyChanged(); - } - } - - public AvaloniaList<AmiiboApi> AmiiboList - { - get => _amiibos; - set - { - _amiibos = value; - - OnPropertyChanged(); - } - } - - public ObservableCollection<string> AmiiboSeries - { - get => _amiiboSeries; - set - { - _amiiboSeries = value; - OnPropertyChanged(); - } - } - - public int SeriesSelectedIndex - { - get => _seriesSelectedIndex; - set - { - _seriesSelectedIndex = value; - - FilterAmiibo(); - - OnPropertyChanged(); - } - } - - public int AmiiboSelectedIndex - { - get => _amiiboSelectedIndex; - set - { - _amiiboSelectedIndex = value; - - EnableScanning = _amiiboSelectedIndex >= 0 && _amiiboSelectedIndex < _amiibos.Count; - - SetAmiiboDetails(); - - OnPropertyChanged(); - } - } - - public Bitmap AmiiboImage - { - get => _amiiboImage; - set - { - _amiiboImage = value; - - OnPropertyChanged(); - } - } - - public string Usage - { - get => _usage; - set - { - _usage = value; - - OnPropertyChanged(); - } - } - - public bool EnableScanning - { - get => _enableScanning; - set - { - _enableScanning = value; - - OnPropertyChanged(); - } - } - - public void Dispose() - { - GC.SuppressFinalize(this); - _httpClient.Dispose(); - } - - private static bool TryGetAmiiboJson(string json, out AmiiboJson amiiboJson) - { - if (string.IsNullOrEmpty(json)) - { - amiiboJson = JsonHelper.Deserialize(DefaultJson, _serializerContext.AmiiboJson); - - return false; - } - - try - { - amiiboJson = JsonHelper.Deserialize(json, _serializerContext.AmiiboJson); - - return true; - } - catch (JsonException exception) - { - Logger.Error?.Print(LogClass.Application, $"Unable to deserialize amiibo data: {exception}"); - amiiboJson = JsonHelper.Deserialize(DefaultJson, _serializerContext.AmiiboJson); - - return false; - } - } - - private async Task<AmiiboJson> GetMostRecentAmiiboListOrDefaultJson() - { - bool localIsValid = false; - bool remoteIsValid = false; - AmiiboJson amiiboJson = new(); - - try - { - try - { - if (File.Exists(_amiiboJsonPath)) - { - localIsValid = TryGetAmiiboJson(await File.ReadAllTextAsync(_amiiboJsonPath), out amiiboJson); - } - } - catch (Exception exception) - { - Logger.Warning?.Print(LogClass.Application, $"Unable to read data from '{_amiiboJsonPath}': {exception}"); - } - - if (!localIsValid || await NeedsUpdate(amiiboJson.LastUpdated)) - { - remoteIsValid = TryGetAmiiboJson(await DownloadAmiiboJson(), out amiiboJson); - } - } - catch (Exception exception) - { - if (!(localIsValid || remoteIsValid)) - { - Logger.Error?.Print(LogClass.Application, $"Couldn't get valid amiibo data: {exception}"); - - // Neither local or remote files are valid JSON, close window. - ShowInfoDialog(); - Close(); - } - else if (!remoteIsValid) - { - Logger.Warning?.Print(LogClass.Application, $"Couldn't update amiibo data: {exception}"); - - // Only the local file is valid, the local one should be used - // but the user should be warned. - ShowInfoDialog(); - } - } - - return amiiboJson; - } - - private async Task LoadContentAsync() - { - AmiiboJson amiiboJson = await GetMostRecentAmiiboListOrDefaultJson(); - - _amiiboList = amiiboJson.Amiibo.OrderBy(amiibo => amiibo.AmiiboSeries).ToList(); - - ParseAmiiboData(); - } - - private void ParseAmiiboData() - { - _amiiboSeries.Clear(); - _amiibos.Clear(); - - for (int i = 0; i < _amiiboList.Count; i++) - { - if (!_amiiboSeries.Contains(_amiiboList[i].AmiiboSeries)) - { - if (!ShowAllAmiibo) - { - foreach (AmiiboApiGamesSwitch game in _amiiboList[i].GamesSwitch) - { - if (game != null) - { - if (game.GameId.Contains(TitleId)) - { - AmiiboSeries.Add(_amiiboList[i].AmiiboSeries); - - break; - } - } - } - } - else - { - AmiiboSeries.Add(_amiiboList[i].AmiiboSeries); - } - } - } - - if (LastScannedAmiiboId != "") - { - SelectLastScannedAmiibo(); - } - else - { - SeriesSelectedIndex = 0; - } - } - - private void SelectLastScannedAmiibo() - { - AmiiboApi scanned = _amiiboList.Find(amiibo => amiibo.GetId() == LastScannedAmiiboId); - - SeriesSelectedIndex = AmiiboSeries.IndexOf(scanned.AmiiboSeries); - AmiiboSelectedIndex = AmiiboList.IndexOf(scanned); - } - - private void FilterAmiibo() - { - _amiibos.Clear(); - - if (_seriesSelectedIndex < 0) - { - return; - } - - List<AmiiboApi> amiiboSortedList = _amiiboList - .Where(amiibo => amiibo.AmiiboSeries == _amiiboSeries[SeriesSelectedIndex]) - .OrderBy(amiibo => amiibo.Name).ToList(); - - for (int i = 0; i < amiiboSortedList.Count; i++) - { - if (!_amiibos.Contains(amiiboSortedList[i])) - { - if (!_showAllAmiibo) - { - foreach (AmiiboApiGamesSwitch game in amiiboSortedList[i].GamesSwitch) - { - if (game != null) - { - if (game.GameId.Contains(TitleId)) - { - _amiibos.Add(amiiboSortedList[i]); - - break; - } - } - } - } - else - { - _amiibos.Add(amiiboSortedList[i]); - } - } - } - - AmiiboSelectedIndex = 0; - } - - private void SetAmiiboDetails() - { - ResetAmiiboPreview(); - - Usage = string.Empty; - - if (_amiiboSelectedIndex < 0) - { - return; - } - - AmiiboApi selected = _amiibos[_amiiboSelectedIndex]; - - string imageUrl = _amiiboList.Find(amiibo => amiibo.Equals(selected)).Image; - - StringBuilder usageStringBuilder = new(); - - for (int i = 0; i < _amiiboList.Count; i++) - { - if (_amiiboList[i].Equals(selected)) - { - bool writable = false; - - foreach (AmiiboApiGamesSwitch item in _amiiboList[i].GamesSwitch) - { - if (item.GameId.Contains(TitleId)) - { - foreach (AmiiboApiUsage usageItem in item.AmiiboUsage) - { - usageStringBuilder.Append($"{Environment.NewLine}- {usageItem.Usage.Replace("/", Environment.NewLine + "-")}"); - - writable = usageItem.Write; - } - } - } - - if (usageStringBuilder.Length == 0) - { - usageStringBuilder.Append($"{LocaleManager.Instance[LocaleKeys.Unknown]}."); - } - - Usage = $"{LocaleManager.Instance[LocaleKeys.Usage]} {(writable ? $" ({LocaleManager.Instance[LocaleKeys.Writable]})" : "")} : {usageStringBuilder}"; - } - } - - _ = UpdateAmiiboPreview(imageUrl); - } - - private async Task<bool> NeedsUpdate(DateTime oldLastModified) - { - try - { - HttpResponseMessage response = await _httpClient.SendAsync(new HttpRequestMessage(HttpMethod.Head, "https://amiibo.ryujinx.org/")); - - if (response.IsSuccessStatusCode) - { - return response.Content.Headers.LastModified != oldLastModified; - } - } - catch (HttpRequestException exception) - { - Logger.Error?.Print(LogClass.Application, $"Unable to check for amiibo data updates: {exception}"); - } - - return false; - } - - private async Task<string> DownloadAmiiboJson() - { - try - { - HttpResponseMessage response = await _httpClient.GetAsync("https://amiibo.ryujinx.org/"); - - if (response.IsSuccessStatusCode) - { - string amiiboJsonString = await response.Content.ReadAsStringAsync(); - - try - { - using FileStream dlcJsonStream = File.Create(_amiiboJsonPath, 4096, FileOptions.WriteThrough); - dlcJsonStream.Write(Encoding.UTF8.GetBytes(amiiboJsonString)); - } - catch (Exception exception) - { - Logger.Warning?.Print(LogClass.Application, $"Couldn't write amiibo data to file '{_amiiboJsonPath}: {exception}'"); - } - - return amiiboJsonString; - } - - Logger.Error?.Print(LogClass.Application, $"Failed to download amiibo data. Response status code: {response.StatusCode}"); - } - catch (HttpRequestException exception) - { - Logger.Error?.Print(LogClass.Application, $"Failed to request amiibo data: {exception}"); - } - - await ContentDialogHelper.CreateInfoDialog(LocaleManager.Instance[LocaleKeys.DialogAmiiboApiTitle], - LocaleManager.Instance[LocaleKeys.DialogAmiiboApiFailFetchMessage], - LocaleManager.Instance[LocaleKeys.InputDialogOk], - "", - LocaleManager.Instance[LocaleKeys.RyujinxInfo]); - - return null; - } - - private void Close() - { - Dispatcher.UIThread.Post(_owner.Close); - } - - private async Task UpdateAmiiboPreview(string imageUrl) - { - HttpResponseMessage response = await _httpClient.GetAsync(imageUrl); - - if (response.IsSuccessStatusCode) - { - byte[] amiiboPreviewBytes = await response.Content.ReadAsByteArrayAsync(); - using MemoryStream memoryStream = new(amiiboPreviewBytes); - - Bitmap bitmap = new(memoryStream); - - double ratio = Math.Min(AmiiboImageSize / bitmap.Size.Width, - AmiiboImageSize / bitmap.Size.Height); - - int resizeHeight = (int)(bitmap.Size.Height * ratio); - int resizeWidth = (int)(bitmap.Size.Width * ratio); - - AmiiboImage = bitmap.CreateScaledBitmap(new PixelSize(resizeWidth, resizeHeight)); - } - else - { - Logger.Error?.Print(LogClass.Application, $"Failed to get amiibo preview. Response status code: {response.StatusCode}"); - } - } - - private void ResetAmiiboPreview() - { - using MemoryStream memoryStream = new(_amiiboLogoBytes); - - Bitmap bitmap = new(memoryStream); - - AmiiboImage = bitmap; - } - - private static async void ShowInfoDialog() - { - await ContentDialogHelper.CreateInfoDialog(LocaleManager.Instance[LocaleKeys.DialogAmiiboApiTitle], - LocaleManager.Instance[LocaleKeys.DialogAmiiboApiConnectErrorMessage], - LocaleManager.Instance[LocaleKeys.InputDialogOk], - "", - LocaleManager.Instance[LocaleKeys.RyujinxInfo]); - } - } -} diff --git a/src/Ryujinx.Ava/UI/ViewModels/BaseModel.cs b/src/Ryujinx.Ava/UI/ViewModels/BaseModel.cs deleted file mode 100644 index 4db9cf81..00000000 --- a/src/Ryujinx.Ava/UI/ViewModels/BaseModel.cs +++ /dev/null @@ -1,15 +0,0 @@ -using System.ComponentModel; -using System.Runtime.CompilerServices; - -namespace Ryujinx.Ava.UI.ViewModels -{ - public class BaseModel : INotifyPropertyChanged - { - public event PropertyChangedEventHandler PropertyChanged; - - protected void OnPropertyChanged([CallerMemberName] string propertyName = null) - { - PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); - } - } -} diff --git a/src/Ryujinx.Ava/UI/ViewModels/ControllerInputViewModel.cs b/src/Ryujinx.Ava/UI/ViewModels/ControllerInputViewModel.cs deleted file mode 100644 index 71ad2c12..00000000 --- a/src/Ryujinx.Ava/UI/ViewModels/ControllerInputViewModel.cs +++ /dev/null @@ -1,897 +0,0 @@ -using Avalonia; -using Avalonia.Collections; -using Avalonia.Controls; -using Avalonia.Controls.ApplicationLifetimes; -using Avalonia.Svg.Skia; -using Avalonia.Threading; -using Ryujinx.Ava.Common.Locale; -using Ryujinx.Ava.Input; -using Ryujinx.Ava.UI.Helpers; -using Ryujinx.Ava.UI.Models; -using Ryujinx.Ava.UI.Views.Input; -using Ryujinx.Ava.UI.Windows; -using Ryujinx.Common; -using Ryujinx.Common.Configuration; -using Ryujinx.Common.Configuration.Hid; -using Ryujinx.Common.Configuration.Hid.Controller; -using Ryujinx.Common.Configuration.Hid.Controller.Motion; -using Ryujinx.Common.Configuration.Hid.Keyboard; -using Ryujinx.Common.Logging; -using Ryujinx.Common.Utilities; -using Ryujinx.Input; -using Ryujinx.UI.Common.Configuration; -using System; -using System.Collections.Generic; -using System.Collections.ObjectModel; -using System.IO; -using System.Linq; -using System.Text.Json; -using ConfigGamepadInputId = Ryujinx.Common.Configuration.Hid.Controller.GamepadInputId; -using ConfigStickInputId = Ryujinx.Common.Configuration.Hid.Controller.StickInputId; -using Key = Ryujinx.Common.Configuration.Hid.Key; - -namespace Ryujinx.Ava.UI.ViewModels -{ - public class ControllerInputViewModel : BaseModel, IDisposable - { - private const string Disabled = "disabled"; - private const string ProControllerResource = "Ryujinx.UI.Common/Resources/Controller_ProCon.svg"; - private const string JoyConPairResource = "Ryujinx.UI.Common/Resources/Controller_JoyConPair.svg"; - private const string JoyConLeftResource = "Ryujinx.UI.Common/Resources/Controller_JoyConLeft.svg"; - private const string JoyConRightResource = "Ryujinx.UI.Common/Resources/Controller_JoyConRight.svg"; - private const string KeyboardString = "keyboard"; - private const string ControllerString = "controller"; - private readonly MainWindow _mainWindow; - - private PlayerIndex _playerId; - private int _controller; - private int _controllerNumber; - private string _controllerImage; - private int _device; - private object _configuration; - private string _profileName; - private bool _isLoaded; - - private static readonly InputConfigJsonSerializerContext _serializerContext = new(JsonHelper.GetDefaultSerializerOptions()); - - public IGamepadDriver AvaloniaKeyboardDriver { get; } - public IGamepad SelectedGamepad { get; private set; } - - public ObservableCollection<PlayerModel> PlayerIndexes { get; set; } - public ObservableCollection<(DeviceType Type, string Id, string Name)> Devices { get; set; } - internal ObservableCollection<ControllerModel> Controllers { get; set; } - public AvaloniaList<string> ProfilesList { get; set; } - public AvaloniaList<string> DeviceList { get; set; } - - // XAML Flags - public bool ShowSettings => _device > 0; - public bool IsController => _device > 1; - public bool IsKeyboard => !IsController; - public bool IsRight { get; set; } - public bool IsLeft { get; set; } - - public bool IsModified { get; set; } - - public object Configuration - { - get => _configuration; - set - { - _configuration = value; - - OnPropertyChanged(); - } - } - - public PlayerIndex PlayerId - { - get => _playerId; - set - { - if (IsModified) - { - return; - } - - IsModified = false; - _playerId = value; - - if (!Enum.IsDefined(typeof(PlayerIndex), _playerId)) - { - _playerId = PlayerIndex.Player1; - } - - LoadConfiguration(); - LoadDevice(); - LoadProfiles(); - - _isLoaded = true; - - OnPropertyChanged(); - } - } - - public int Controller - { - get => _controller; - set - { - _controller = value; - - if (_controller == -1) - { - _controller = 0; - } - - if (Controllers.Count > 0 && value < Controllers.Count && _controller > -1) - { - ControllerType controller = Controllers[_controller].Type; - - IsLeft = true; - IsRight = true; - - switch (controller) - { - case ControllerType.Handheld: - ControllerImage = JoyConPairResource; - break; - case ControllerType.ProController: - ControllerImage = ProControllerResource; - break; - case ControllerType.JoyconPair: - ControllerImage = JoyConPairResource; - break; - case ControllerType.JoyconLeft: - ControllerImage = JoyConLeftResource; - IsRight = false; - break; - case ControllerType.JoyconRight: - ControllerImage = JoyConRightResource; - IsLeft = false; - break; - } - - LoadInputDriver(); - LoadProfiles(); - } - - OnPropertyChanged(); - NotifyChanges(); - } - } - - public string ControllerImage - { - get => _controllerImage; - set - { - _controllerImage = value; - - OnPropertyChanged(); - OnPropertyChanged(nameof(Image)); - } - } - - public SvgImage Image - { - get - { - SvgImage image = new(); - - if (!string.IsNullOrWhiteSpace(_controllerImage)) - { - SvgSource source = new(default(Uri)); - - source.Load(EmbeddedResources.GetStream(_controllerImage)); - - image.Source = source; - } - - return image; - } - } - - public string ProfileName - { - get => _profileName; set - { - _profileName = value; - - OnPropertyChanged(); - } - } - - public int Device - { - get => _device; - set - { - _device = value < 0 ? 0 : value; - - if (_device >= Devices.Count) - { - return; - } - - var selected = Devices[_device].Type; - - if (selected != DeviceType.None) - { - LoadControllers(); - - if (_isLoaded) - { - LoadConfiguration(LoadDefaultConfiguration()); - } - } - - OnPropertyChanged(); - NotifyChanges(); - } - } - - public InputConfig Config { get; set; } - - public ControllerInputViewModel(UserControl owner) : this() - { - if (Program.PreviewerDetached) - { - _mainWindow = - (MainWindow)((IClassicDesktopStyleApplicationLifetime)Application.Current - .ApplicationLifetime).MainWindow; - - AvaloniaKeyboardDriver = new AvaloniaKeyboardDriver(owner); - - _mainWindow.InputManager.GamepadDriver.OnGamepadConnected += HandleOnGamepadConnected; - _mainWindow.InputManager.GamepadDriver.OnGamepadDisconnected += HandleOnGamepadDisconnected; - - _mainWindow.ViewModel.AppHost?.NpadManager.BlockInputUpdates(); - - _isLoaded = false; - - LoadDevices(); - - PlayerId = PlayerIndex.Player1; - } - } - - public ControllerInputViewModel() - { - PlayerIndexes = new ObservableCollection<PlayerModel>(); - Controllers = new ObservableCollection<ControllerModel>(); - Devices = new ObservableCollection<(DeviceType Type, string Id, string Name)>(); - ProfilesList = new AvaloniaList<string>(); - DeviceList = new AvaloniaList<string>(); - - ControllerImage = ProControllerResource; - - PlayerIndexes.Add(new(PlayerIndex.Player1, LocaleManager.Instance[LocaleKeys.ControllerSettingsPlayer1])); - PlayerIndexes.Add(new(PlayerIndex.Player2, LocaleManager.Instance[LocaleKeys.ControllerSettingsPlayer2])); - PlayerIndexes.Add(new(PlayerIndex.Player3, LocaleManager.Instance[LocaleKeys.ControllerSettingsPlayer3])); - PlayerIndexes.Add(new(PlayerIndex.Player4, LocaleManager.Instance[LocaleKeys.ControllerSettingsPlayer4])); - PlayerIndexes.Add(new(PlayerIndex.Player5, LocaleManager.Instance[LocaleKeys.ControllerSettingsPlayer5])); - PlayerIndexes.Add(new(PlayerIndex.Player6, LocaleManager.Instance[LocaleKeys.ControllerSettingsPlayer6])); - PlayerIndexes.Add(new(PlayerIndex.Player7, LocaleManager.Instance[LocaleKeys.ControllerSettingsPlayer7])); - PlayerIndexes.Add(new(PlayerIndex.Player8, LocaleManager.Instance[LocaleKeys.ControllerSettingsPlayer8])); - PlayerIndexes.Add(new(PlayerIndex.Handheld, LocaleManager.Instance[LocaleKeys.ControllerSettingsHandheld])); - } - - private void LoadConfiguration(InputConfig inputConfig = null) - { - Config = inputConfig ?? ConfigurationState.Instance.Hid.InputConfig.Value.Find(inputConfig => inputConfig.PlayerIndex == _playerId); - - if (Config is StandardKeyboardInputConfig keyboardInputConfig) - { - Configuration = new InputConfiguration<Key, ConfigStickInputId>(keyboardInputConfig); - } - - if (Config is StandardControllerInputConfig controllerInputConfig) - { - Configuration = new InputConfiguration<ConfigGamepadInputId, ConfigStickInputId>(controllerInputConfig); - } - } - - public void LoadDevice() - { - if (Config == null || Config.Backend == InputBackendType.Invalid) - { - Device = 0; - } - else - { - var type = DeviceType.None; - - if (Config is StandardKeyboardInputConfig) - { - type = DeviceType.Keyboard; - } - - if (Config is StandardControllerInputConfig) - { - type = DeviceType.Controller; - } - - var item = Devices.FirstOrDefault(x => x.Type == type && x.Id == Config.Id); - if (item != default) - { - Device = Devices.ToList().FindIndex(x => x.Id == item.Id); - } - else - { - Device = 0; - } - } - } - - public async void ShowMotionConfig() - { - await MotionInputView.Show(this); - } - - public async void ShowRumbleConfig() - { - await RumbleInputView.Show(this); - } - - private void LoadInputDriver() - { - if (_device < 0) - { - return; - } - - string id = GetCurrentGamepadId(); - var type = Devices[Device].Type; - - if (type == DeviceType.None) - { - return; - } - - if (type == DeviceType.Keyboard) - { - if (_mainWindow.InputManager.KeyboardDriver is AvaloniaKeyboardDriver) - { - // NOTE: To get input in this window, we need to bind a custom keyboard driver instead of using the InputManager one as the main window isn't focused... - SelectedGamepad = AvaloniaKeyboardDriver.GetGamepad(id); - } - else - { - SelectedGamepad = _mainWindow.InputManager.KeyboardDriver.GetGamepad(id); - } - } - else - { - SelectedGamepad = _mainWindow.InputManager.GamepadDriver.GetGamepad(id); - } - } - - private void HandleOnGamepadDisconnected(string id) - { - Dispatcher.UIThread.Post(() => - { - LoadDevices(); - }); - } - - private void HandleOnGamepadConnected(string id) - { - Dispatcher.UIThread.Post(() => - { - LoadDevices(); - }); - } - - private string GetCurrentGamepadId() - { - if (_device < 0) - { - return string.Empty; - } - - var device = Devices[Device]; - - if (device.Type == DeviceType.None) - { - return null; - } - - return device.Id.Split(" ")[0]; - } - - public void LoadControllers() - { - Controllers.Clear(); - - if (_playerId == PlayerIndex.Handheld) - { - Controllers.Add(new(ControllerType.Handheld, LocaleManager.Instance[LocaleKeys.ControllerSettingsControllerTypeHandheld])); - - Controller = 0; - } - else - { - Controllers.Add(new(ControllerType.ProController, LocaleManager.Instance[LocaleKeys.ControllerSettingsControllerTypeProController])); - Controllers.Add(new(ControllerType.JoyconPair, LocaleManager.Instance[LocaleKeys.ControllerSettingsControllerTypeJoyConPair])); - Controllers.Add(new(ControllerType.JoyconLeft, LocaleManager.Instance[LocaleKeys.ControllerSettingsControllerTypeJoyConLeft])); - Controllers.Add(new(ControllerType.JoyconRight, LocaleManager.Instance[LocaleKeys.ControllerSettingsControllerTypeJoyConRight])); - - if (Config != null && Controllers.ToList().FindIndex(x => x.Type == Config.ControllerType) != -1) - { - Controller = Controllers.ToList().FindIndex(x => x.Type == Config.ControllerType); - } - else - { - Controller = 0; - } - } - } - - private static string GetShortGamepadName(string str) - { - const string Ellipsis = "..."; - const int MaxSize = 50; - - if (str.Length > MaxSize) - { - return $"{str.AsSpan(0, MaxSize - Ellipsis.Length)}{Ellipsis}"; - } - - return str; - } - - private static string GetShortGamepadId(string str) - { - const string Hyphen = "-"; - const int Offset = 1; - - return str[(str.IndexOf(Hyphen) + Offset)..]; - } - - public void LoadDevices() - { - lock (Devices) - { - Devices.Clear(); - DeviceList.Clear(); - Devices.Add((DeviceType.None, Disabled, LocaleManager.Instance[LocaleKeys.ControllerSettingsDeviceDisabled])); - - foreach (string id in _mainWindow.InputManager.KeyboardDriver.GamepadsIds) - { - using IGamepad gamepad = _mainWindow.InputManager.KeyboardDriver.GetGamepad(id); - - if (gamepad != null) - { - Devices.Add((DeviceType.Keyboard, id, $"{GetShortGamepadName(gamepad.Name)}")); - } - } - - foreach (string id in _mainWindow.InputManager.GamepadDriver.GamepadsIds) - { - using IGamepad gamepad = _mainWindow.InputManager.GamepadDriver.GetGamepad(id); - - if (gamepad != null) - { - if (Devices.Any(controller => GetShortGamepadId(controller.Id) == GetShortGamepadId(gamepad.Id))) - { - _controllerNumber++; - } - - Devices.Add((DeviceType.Controller, id, $"{GetShortGamepadName(gamepad.Name)} ({_controllerNumber})")); - } - } - - _controllerNumber = 0; - - DeviceList.AddRange(Devices.Select(x => x.Name)); - Device = Math.Min(Device, DeviceList.Count); - } - } - - private string GetProfileBasePath() - { - string path = AppDataManager.ProfilesDirPath; - var type = Devices[Device == -1 ? 0 : Device].Type; - - if (type == DeviceType.Keyboard) - { - path = Path.Combine(path, KeyboardString); - } - else if (type == DeviceType.Controller) - { - path = Path.Combine(path, ControllerString); - } - - return path; - } - - private void LoadProfiles() - { - ProfilesList.Clear(); - - string basePath = GetProfileBasePath(); - - if (!Directory.Exists(basePath)) - { - Directory.CreateDirectory(basePath); - } - - ProfilesList.Add((LocaleManager.Instance[LocaleKeys.ControllerSettingsProfileDefault])); - - foreach (string profile in Directory.GetFiles(basePath, "*.json", SearchOption.AllDirectories)) - { - ProfilesList.Add(Path.GetFileNameWithoutExtension(profile)); - } - - if (string.IsNullOrWhiteSpace(ProfileName)) - { - ProfileName = LocaleManager.Instance[LocaleKeys.ControllerSettingsProfileDefault]; - } - } - - public InputConfig LoadDefaultConfiguration() - { - var activeDevice = Devices.FirstOrDefault(); - - if (Devices.Count > 0 && Device < Devices.Count && Device >= 0) - { - activeDevice = Devices[Device]; - } - - InputConfig config; - if (activeDevice.Type == DeviceType.Keyboard) - { - string id = activeDevice.Id; - - config = new StandardKeyboardInputConfig - { - Version = InputConfig.CurrentVersion, - Backend = InputBackendType.WindowKeyboard, - Id = id, - ControllerType = ControllerType.ProController, - LeftJoycon = new LeftJoyconCommonConfig<Key> - { - DpadUp = Key.Up, - DpadDown = Key.Down, - DpadLeft = Key.Left, - DpadRight = Key.Right, - ButtonMinus = Key.Minus, - ButtonL = Key.E, - ButtonZl = Key.Q, - ButtonSl = Key.Unbound, - ButtonSr = Key.Unbound, - }, - LeftJoyconStick = - new JoyconConfigKeyboardStick<Key> - { - StickUp = Key.W, - StickDown = Key.S, - StickLeft = Key.A, - StickRight = Key.D, - StickButton = Key.F, - }, - RightJoycon = new RightJoyconCommonConfig<Key> - { - ButtonA = Key.Z, - ButtonB = Key.X, - ButtonX = Key.C, - ButtonY = Key.V, - ButtonPlus = Key.Plus, - ButtonR = Key.U, - ButtonZr = Key.O, - ButtonSl = Key.Unbound, - ButtonSr = Key.Unbound, - }, - RightJoyconStick = new JoyconConfigKeyboardStick<Key> - { - StickUp = Key.I, - StickDown = Key.K, - StickLeft = Key.J, - StickRight = Key.L, - StickButton = Key.H, - }, - }; - } - else if (activeDevice.Type == DeviceType.Controller) - { - bool isNintendoStyle = Devices.ToList().Find(x => x.Id == activeDevice.Id).Name.Contains("Nintendo"); - - string id = activeDevice.Id.Split(" ")[0]; - - config = new StandardControllerInputConfig - { - Version = InputConfig.CurrentVersion, - Backend = InputBackendType.GamepadSDL2, - Id = id, - ControllerType = ControllerType.ProController, - DeadzoneLeft = 0.1f, - DeadzoneRight = 0.1f, - RangeLeft = 1.0f, - RangeRight = 1.0f, - TriggerThreshold = 0.5f, - LeftJoycon = new LeftJoyconCommonConfig<ConfigGamepadInputId> - { - DpadUp = ConfigGamepadInputId.DpadUp, - DpadDown = ConfigGamepadInputId.DpadDown, - DpadLeft = ConfigGamepadInputId.DpadLeft, - DpadRight = ConfigGamepadInputId.DpadRight, - ButtonMinus = ConfigGamepadInputId.Minus, - ButtonL = ConfigGamepadInputId.LeftShoulder, - ButtonZl = ConfigGamepadInputId.LeftTrigger, - ButtonSl = ConfigGamepadInputId.Unbound, - ButtonSr = ConfigGamepadInputId.Unbound, - }, - LeftJoyconStick = new JoyconConfigControllerStick<ConfigGamepadInputId, ConfigStickInputId> - { - Joystick = ConfigStickInputId.Left, - StickButton = ConfigGamepadInputId.LeftStick, - InvertStickX = false, - InvertStickY = false, - }, - RightJoycon = new RightJoyconCommonConfig<ConfigGamepadInputId> - { - ButtonA = isNintendoStyle ? ConfigGamepadInputId.A : ConfigGamepadInputId.B, - ButtonB = isNintendoStyle ? ConfigGamepadInputId.B : ConfigGamepadInputId.A, - ButtonX = isNintendoStyle ? ConfigGamepadInputId.X : ConfigGamepadInputId.Y, - ButtonY = isNintendoStyle ? ConfigGamepadInputId.Y : ConfigGamepadInputId.X, - ButtonPlus = ConfigGamepadInputId.Plus, - ButtonR = ConfigGamepadInputId.RightShoulder, - ButtonZr = ConfigGamepadInputId.RightTrigger, - ButtonSl = ConfigGamepadInputId.Unbound, - ButtonSr = ConfigGamepadInputId.Unbound, - }, - RightJoyconStick = new JoyconConfigControllerStick<ConfigGamepadInputId, ConfigStickInputId> - { - Joystick = ConfigStickInputId.Right, - StickButton = ConfigGamepadInputId.RightStick, - InvertStickX = false, - InvertStickY = false, - }, - Motion = new StandardMotionConfigController - { - MotionBackend = MotionInputBackendType.GamepadDriver, - EnableMotion = true, - Sensitivity = 100, - GyroDeadzone = 1, - }, - Rumble = new RumbleConfigController - { - StrongRumble = 1f, - WeakRumble = 1f, - EnableRumble = false, - }, - }; - } - else - { - config = new InputConfig(); - } - - config.PlayerIndex = _playerId; - - return config; - } - - public async void LoadProfile() - { - if (Device == 0) - { - return; - } - - InputConfig config = null; - - if (string.IsNullOrWhiteSpace(ProfileName)) - { - return; - } - - if (ProfileName == LocaleManager.Instance[LocaleKeys.ControllerSettingsProfileDefault]) - { - config = LoadDefaultConfiguration(); - } - else - { - string path = Path.Combine(GetProfileBasePath(), ProfileName + ".json"); - - if (!File.Exists(path)) - { - var index = ProfilesList.IndexOf(ProfileName); - if (index != -1) - { - ProfilesList.RemoveAt(index); - } - return; - } - - try - { - config = JsonHelper.DeserializeFromFile(path, _serializerContext.InputConfig); - } - catch (JsonException) { } - catch (InvalidOperationException) - { - Logger.Error?.Print(LogClass.Configuration, $"Profile {ProfileName} is incompatible with the current input configuration system."); - - await ContentDialogHelper.CreateErrorDialog(LocaleManager.Instance.UpdateAndGetDynamicValue(LocaleKeys.DialogProfileInvalidProfileErrorMessage, ProfileName)); - - return; - } - } - - if (config != null) - { - _isLoaded = false; - - LoadConfiguration(config); - - LoadDevice(); - - _isLoaded = true; - - NotifyChanges(); - } - } - - public async void SaveProfile() - { - if (Device == 0) - { - return; - } - - if (Configuration == null) - { - return; - } - - if (ProfileName == LocaleManager.Instance[LocaleKeys.ControllerSettingsProfileDefault]) - { - await ContentDialogHelper.CreateErrorDialog(LocaleManager.Instance[LocaleKeys.DialogProfileDefaultProfileOverwriteErrorMessage]); - - return; - } - - bool validFileName = ProfileName.IndexOfAny(Path.GetInvalidFileNameChars()) == -1; - - if (validFileName) - { - string path = Path.Combine(GetProfileBasePath(), ProfileName + ".json"); - - InputConfig config = null; - - if (IsKeyboard) - { - config = (Configuration as InputConfiguration<Key, ConfigStickInputId>).GetConfig(); - } - else if (IsController) - { - config = (Configuration as InputConfiguration<GamepadInputId, ConfigStickInputId>).GetConfig(); - } - - config.ControllerType = Controllers[_controller].Type; - - string jsonString = JsonHelper.Serialize(config, _serializerContext.InputConfig); - - await File.WriteAllTextAsync(path, jsonString); - - LoadProfiles(); - } - else - { - await ContentDialogHelper.CreateErrorDialog(LocaleManager.Instance[LocaleKeys.DialogProfileInvalidProfileNameErrorMessage]); - } - } - - public async void RemoveProfile() - { - if (Device == 0 || ProfileName == LocaleManager.Instance[LocaleKeys.ControllerSettingsProfileDefault] || ProfilesList.IndexOf(ProfileName) == -1) - { - return; - } - - UserResult result = await ContentDialogHelper.CreateConfirmationDialog( - LocaleManager.Instance[LocaleKeys.DialogProfileDeleteProfileTitle], - LocaleManager.Instance[LocaleKeys.DialogProfileDeleteProfileMessage], - LocaleManager.Instance[LocaleKeys.InputDialogYes], - LocaleManager.Instance[LocaleKeys.InputDialogNo], - LocaleManager.Instance[LocaleKeys.RyujinxConfirm]); - - if (result == UserResult.Yes) - { - string path = Path.Combine(GetProfileBasePath(), ProfileName + ".json"); - - if (File.Exists(path)) - { - File.Delete(path); - } - - LoadProfiles(); - } - } - - public void Save() - { - IsModified = false; - - List<InputConfig> newConfig = new(); - - newConfig.AddRange(ConfigurationState.Instance.Hid.InputConfig.Value); - - newConfig.Remove(newConfig.Find(x => x == null)); - - if (Device == 0) - { - newConfig.Remove(newConfig.Find(x => x.PlayerIndex == this.PlayerId)); - } - else - { - var device = Devices[Device]; - - if (device.Type == DeviceType.Keyboard) - { - var inputConfig = Configuration as InputConfiguration<Key, ConfigStickInputId>; - inputConfig.Id = device.Id; - } - else - { - var inputConfig = Configuration as InputConfiguration<GamepadInputId, ConfigStickInputId>; - inputConfig.Id = device.Id.Split(" ")[0]; - } - - var config = !IsController - ? (Configuration as InputConfiguration<Key, ConfigStickInputId>).GetConfig() - : (Configuration as InputConfiguration<GamepadInputId, ConfigStickInputId>).GetConfig(); - config.ControllerType = Controllers[_controller].Type; - config.PlayerIndex = _playerId; - - int i = newConfig.FindIndex(x => x.PlayerIndex == PlayerId); - if (i == -1) - { - newConfig.Add(config); - } - else - { - newConfig[i] = config; - } - } - - _mainWindow.ViewModel.AppHost?.NpadManager.ReloadConfiguration(newConfig, ConfigurationState.Instance.Hid.EnableKeyboard, ConfigurationState.Instance.Hid.EnableMouse); - - // Atomically replace and signal input change. - // NOTE: Do not modify InputConfig.Value directly as other code depends on the on-change event. - ConfigurationState.Instance.Hid.InputConfig.Value = newConfig; - - ConfigurationState.Instance.ToFileFormat().SaveConfig(Program.ConfigurationPath); - } - - public void NotifyChange(string property) - { - OnPropertyChanged(property); - } - - public void NotifyChanges() - { - OnPropertyChanged(nameof(Configuration)); - OnPropertyChanged(nameof(IsController)); - OnPropertyChanged(nameof(ShowSettings)); - OnPropertyChanged(nameof(IsKeyboard)); - OnPropertyChanged(nameof(IsRight)); - OnPropertyChanged(nameof(IsLeft)); - } - - public void Dispose() - { - GC.SuppressFinalize(this); - - _mainWindow.InputManager.GamepadDriver.OnGamepadConnected -= HandleOnGamepadConnected; - _mainWindow.InputManager.GamepadDriver.OnGamepadDisconnected -= HandleOnGamepadDisconnected; - - _mainWindow.ViewModel.AppHost?.NpadManager.UnblockInputUpdates(); - - SelectedGamepad?.Dispose(); - - AvaloniaKeyboardDriver.Dispose(); - } - } -} diff --git a/src/Ryujinx.Ava/UI/ViewModels/DownloadableContentManagerViewModel.cs b/src/Ryujinx.Ava/UI/ViewModels/DownloadableContentManagerViewModel.cs deleted file mode 100644 index 2cd714f4..00000000 --- a/src/Ryujinx.Ava/UI/ViewModels/DownloadableContentManagerViewModel.cs +++ /dev/null @@ -1,340 +0,0 @@ -using Avalonia.Collections; -using Avalonia.Controls.ApplicationLifetimes; -using Avalonia.Platform.Storage; -using Avalonia.Threading; -using DynamicData; -using LibHac.Common; -using LibHac.Fs; -using LibHac.Fs.Fsa; -using LibHac.FsSystem; -using LibHac.Tools.Fs; -using LibHac.Tools.FsSystem; -using LibHac.Tools.FsSystem.NcaUtils; -using Ryujinx.Ava.Common.Locale; -using Ryujinx.Ava.UI.Helpers; -using Ryujinx.Ava.UI.Models; -using Ryujinx.Common.Configuration; -using Ryujinx.Common.Logging; -using Ryujinx.Common.Utilities; -using Ryujinx.HLE.FileSystem; -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Threading.Tasks; -using Application = Avalonia.Application; -using Path = System.IO.Path; - -namespace Ryujinx.Ava.UI.ViewModels -{ - public class DownloadableContentManagerViewModel : BaseModel - { - private readonly List<DownloadableContentContainer> _downloadableContentContainerList; - private readonly string _downloadableContentJsonPath; - - private readonly VirtualFileSystem _virtualFileSystem; - private AvaloniaList<DownloadableContentModel> _downloadableContents = new(); - private AvaloniaList<DownloadableContentModel> _views = new(); - private AvaloniaList<DownloadableContentModel> _selectedDownloadableContents = new(); - - private string _search; - private readonly ulong _titleId; - private readonly IStorageProvider _storageProvider; - - private static readonly DownloadableContentJsonSerializerContext _serializerContext = new(JsonHelper.GetDefaultSerializerOptions()); - - public AvaloniaList<DownloadableContentModel> DownloadableContents - { - get => _downloadableContents; - set - { - _downloadableContents = value; - OnPropertyChanged(); - OnPropertyChanged(nameof(UpdateCount)); - Sort(); - } - } - - public AvaloniaList<DownloadableContentModel> Views - { - get => _views; - set - { - _views = value; - OnPropertyChanged(); - } - } - - public AvaloniaList<DownloadableContentModel> SelectedDownloadableContents - { - get => _selectedDownloadableContents; - set - { - _selectedDownloadableContents = value; - OnPropertyChanged(); - } - } - - public string Search - { - get => _search; - set - { - _search = value; - OnPropertyChanged(); - Sort(); - } - } - - public string UpdateCount - { - get => string.Format(LocaleManager.Instance[LocaleKeys.DlcWindowHeading], DownloadableContents.Count); - } - - public DownloadableContentManagerViewModel(VirtualFileSystem virtualFileSystem, ulong titleId) - { - _virtualFileSystem = virtualFileSystem; - - _titleId = titleId; - - if (Application.Current.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop) - { - _storageProvider = desktop.MainWindow.StorageProvider; - } - - _downloadableContentJsonPath = Path.Combine(AppDataManager.GamesDirPath, titleId.ToString("x16"), "dlc.json"); - - try - { - _downloadableContentContainerList = JsonHelper.DeserializeFromFile(_downloadableContentJsonPath, _serializerContext.ListDownloadableContentContainer); - } - catch - { - Logger.Error?.Print(LogClass.Configuration, "Downloadable Content JSON failed to deserialize."); - _downloadableContentContainerList = new List<DownloadableContentContainer>(); - } - - LoadDownloadableContents(); - } - - private void LoadDownloadableContents() - { - foreach (DownloadableContentContainer downloadableContentContainer in _downloadableContentContainerList) - { - if (File.Exists(downloadableContentContainer.ContainerPath)) - { - using FileStream containerFile = File.OpenRead(downloadableContentContainer.ContainerPath); - - PartitionFileSystem partitionFileSystem = new(); - partitionFileSystem.Initialize(containerFile.AsStorage()).ThrowIfFailure(); - - _virtualFileSystem.ImportTickets(partitionFileSystem); - - foreach (DownloadableContentNca downloadableContentNca in downloadableContentContainer.DownloadableContentNcaList) - { - using UniqueRef<IFile> ncaFile = new(); - - partitionFileSystem.OpenFile(ref ncaFile.Ref, downloadableContentNca.FullPath.ToU8Span(), OpenMode.Read).ThrowIfFailure(); - - Nca nca = TryOpenNca(ncaFile.Get.AsStorage(), downloadableContentContainer.ContainerPath); - if (nca != null) - { - var content = new DownloadableContentModel(nca.Header.TitleId.ToString("X16"), - downloadableContentContainer.ContainerPath, - downloadableContentNca.FullPath, - downloadableContentNca.Enabled); - - DownloadableContents.Add(content); - - if (content.Enabled) - { - SelectedDownloadableContents.Add(content); - } - - OnPropertyChanged(nameof(UpdateCount)); - } - } - } - } - - // NOTE: Save the list again to remove leftovers. - Save(); - Sort(); - } - - public void Sort() - { - DownloadableContents.AsObservableChangeSet() - .Filter(Filter) - .Bind(out var view).AsObservableList(); - - _views.Clear(); - _views.AddRange(view); - OnPropertyChanged(nameof(Views)); - } - - private bool Filter(object arg) - { - if (arg is DownloadableContentModel content) - { - return string.IsNullOrWhiteSpace(_search) || content.FileName.ToLower().Contains(_search.ToLower()) || content.TitleId.ToLower().Contains(_search.ToLower()); - } - - return false; - } - - private Nca TryOpenNca(IStorage ncaStorage, string containerPath) - { - try - { - return new Nca(_virtualFileSystem.KeySet, ncaStorage); - } - catch (Exception ex) - { - Dispatcher.UIThread.InvokeAsync(async () => - { - await ContentDialogHelper.CreateErrorDialog(string.Format(LocaleManager.Instance[LocaleKeys.DialogLoadFileErrorMessage], ex.Message, containerPath)); - }); - } - - return null; - } - - public async void Add() - { - var result = await _storageProvider.OpenFilePickerAsync(new FilePickerOpenOptions - { - Title = LocaleManager.Instance[LocaleKeys.SelectDlcDialogTitle], - AllowMultiple = true, - FileTypeFilter = new List<FilePickerFileType> - { - new("NSP") - { - Patterns = new[] { "*.nsp" }, - AppleUniformTypeIdentifiers = new[] { "com.ryujinx.nsp" }, - MimeTypes = new[] { "application/x-nx-nsp" }, - }, - }, - }); - - foreach (var file in result) - { - await AddDownloadableContent(file.Path.LocalPath); - } - } - - private async Task AddDownloadableContent(string path) - { - if (!File.Exists(path) || DownloadableContents.FirstOrDefault(x => x.ContainerPath == path) != null) - { - return; - } - - using FileStream containerFile = File.OpenRead(path); - - PartitionFileSystem partitionFileSystem = new(); - partitionFileSystem.Initialize(containerFile.AsStorage()).ThrowIfFailure(); - bool containsDownloadableContent = false; - - _virtualFileSystem.ImportTickets(partitionFileSystem); - - foreach (DirectoryEntryEx fileEntry in partitionFileSystem.EnumerateEntries("/", "*.nca")) - { - using var ncaFile = new UniqueRef<IFile>(); - - partitionFileSystem.OpenFile(ref ncaFile.Ref, fileEntry.FullPath.ToU8Span(), OpenMode.Read).ThrowIfFailure(); - - Nca nca = TryOpenNca(ncaFile.Get.AsStorage(), path); - if (nca == null) - { - continue; - } - - if (nca.Header.ContentType == NcaContentType.PublicData) - { - if ((nca.Header.TitleId & 0xFFFFFFFFFFFFE000) != _titleId) - { - break; - } - - var content = new DownloadableContentModel(nca.Header.TitleId.ToString("X16"), path, fileEntry.FullPath, true); - DownloadableContents.Add(content); - SelectedDownloadableContents.Add(content); - - OnPropertyChanged(nameof(UpdateCount)); - Sort(); - - containsDownloadableContent = true; - } - } - - if (!containsDownloadableContent) - { - await ContentDialogHelper.CreateErrorDialog(LocaleManager.Instance[LocaleKeys.DialogDlcNoDlcErrorMessage]); - } - } - - public void Remove(DownloadableContentModel model) - { - DownloadableContents.Remove(model); - OnPropertyChanged(nameof(UpdateCount)); - Sort(); - } - - public void RemoveAll() - { - DownloadableContents.Clear(); - OnPropertyChanged(nameof(UpdateCount)); - Sort(); - } - - public void EnableAll() - { - SelectedDownloadableContents = new(DownloadableContents); - } - - public void DisableAll() - { - SelectedDownloadableContents.Clear(); - } - - public void Save() - { - _downloadableContentContainerList.Clear(); - - DownloadableContentContainer container = default; - - foreach (DownloadableContentModel downloadableContent in DownloadableContents) - { - if (container.ContainerPath != downloadableContent.ContainerPath) - { - if (!string.IsNullOrWhiteSpace(container.ContainerPath)) - { - _downloadableContentContainerList.Add(container); - } - - container = new DownloadableContentContainer - { - ContainerPath = downloadableContent.ContainerPath, - DownloadableContentNcaList = new List<DownloadableContentNca>(), - }; - } - - container.DownloadableContentNcaList.Add(new DownloadableContentNca - { - Enabled = downloadableContent.Enabled, - TitleId = Convert.ToUInt64(downloadableContent.TitleId, 16), - FullPath = downloadableContent.FullPath, - }); - } - - if (!string.IsNullOrWhiteSpace(container.ContainerPath)) - { - _downloadableContentContainerList.Add(container); - } - - JsonHelper.SerializeToFile(_downloadableContentJsonPath, _downloadableContentContainerList, _serializerContext.ListDownloadableContentContainer); - } - - } -} diff --git a/src/Ryujinx.Ava/UI/ViewModels/MainWindowViewModel.cs b/src/Ryujinx.Ava/UI/ViewModels/MainWindowViewModel.cs deleted file mode 100644 index 17bd69b1..00000000 --- a/src/Ryujinx.Ava/UI/ViewModels/MainWindowViewModel.cs +++ /dev/null @@ -1,1708 +0,0 @@ -using Avalonia; -using Avalonia.Controls; -using Avalonia.Controls.ApplicationLifetimes; -using Avalonia.Input; -using Avalonia.Media; -using Avalonia.Platform.Storage; -using Avalonia.Threading; -using DynamicData; -using DynamicData.Binding; -using LibHac.Common; -using Ryujinx.Ava.Common; -using Ryujinx.Ava.Common.Locale; -using Ryujinx.Ava.Input; -using Ryujinx.Ava.UI.Controls; -using Ryujinx.Ava.UI.Helpers; -using Ryujinx.Ava.UI.Models; -using Ryujinx.Ava.UI.Models.Generic; -using Ryujinx.Ava.UI.Renderer; -using Ryujinx.Ava.UI.Windows; -using Ryujinx.Common; -using Ryujinx.Common.Configuration; -using Ryujinx.Common.Logging; -using Ryujinx.Cpu; -using Ryujinx.HLE; -using Ryujinx.HLE.FileSystem; -using Ryujinx.HLE.HOS; -using Ryujinx.HLE.HOS.Services.Account.Acc; -using Ryujinx.HLE.UI; -using Ryujinx.Input.HLE; -using Ryujinx.Modules; -using Ryujinx.UI.App.Common; -using Ryujinx.UI.Common; -using Ryujinx.UI.Common.Configuration; -using Ryujinx.UI.Common.Helper; -using SixLabors.ImageSharp.PixelFormats; -using System; -using System.Collections.Generic; -using System.Collections.ObjectModel; -using System.IO; -using System.Threading; -using System.Threading.Tasks; -using Image = SixLabors.ImageSharp.Image; -using Key = Ryujinx.Input.Key; -using MissingKeyException = LibHac.Common.Keys.MissingKeyException; -using ShaderCacheLoadingState = Ryujinx.Graphics.Gpu.Shader.ShaderCacheState; - -namespace Ryujinx.Ava.UI.ViewModels -{ - public class MainWindowViewModel : BaseModel - { - private const int HotKeyPressDelayMs = 500; - - private ObservableCollection<ApplicationData> _applications; - private string _aspectStatusText; - - private string _loadHeading; - private string _cacheLoadStatus; - private string _searchText; - private Timer _searchTimer; - private string _dockedStatusText; - private string _fifoStatusText; - private string _gameStatusText; - private string _volumeStatusText; - private string _gpuStatusText; - private bool _isAmiiboRequested; - private bool _isGameRunning; - private bool _isFullScreen; - private int _progressMaximum; - private int _progressValue; - private long _lastFullscreenToggle = Environment.TickCount64; - private bool _showLoadProgress; - private bool _showMenuAndStatusBar = true; - private bool _showStatusSeparator; - private Brush _progressBarForegroundColor; - private Brush _progressBarBackgroundColor; - private Brush _vsyncColor; - private byte[] _selectedIcon; - private bool _isAppletMenuActive; - private int _statusBarProgressMaximum; - private int _statusBarProgressValue; - private bool _isPaused; - private bool _showContent = true; - private bool _isLoadingIndeterminate = true; - private bool _showAll; - private string _lastScannedAmiiboId; - private bool _statusBarVisible; - private ReadOnlyObservableCollection<ApplicationData> _appsObservableList; - - private string _showUiKey = "F4"; - private string _pauseKey = "F5"; - private string _screenshotKey = "F8"; - private float _volume; - private float _volumeBeforeMute; - private string _backendText; - - private bool _canUpdate = true; - private Cursor _cursor; - private string _title; - private string _currentEmulatedGamePath; - private readonly AutoResetEvent _rendererWaitEvent; - private WindowState _windowState; - private double _windowWidth; - private double _windowHeight; - - private bool _isActive; - - public ApplicationData ListSelectedApplication; - public ApplicationData GridSelectedApplication; - - private string TitleName { get; set; } - internal AppHost AppHost { get; set; } - - public MainWindowViewModel() - { - Applications = new ObservableCollection<ApplicationData>(); - - Applications.ToObservableChangeSet() - .Filter(Filter) - .Sort(GetComparer()) - .Bind(out _appsObservableList).AsObservableList(); - - _rendererWaitEvent = new AutoResetEvent(false); - - if (Program.PreviewerDetached) - { - LoadConfigurableHotKeys(); - - Volume = ConfigurationState.Instance.System.AudioVolume; - } - } - - public void Initialize( - ContentManager contentManager, - IStorageProvider storageProvider, - ApplicationLibrary applicationLibrary, - VirtualFileSystem virtualFileSystem, - AccountManager accountManager, - InputManager inputManager, - UserChannelPersistence userChannelPersistence, - LibHacHorizonManager libHacHorizonManager, - IHostUIHandler uiHandler, - Action<bool> showLoading, - Action<bool> switchToGameControl, - Action<Control> setMainContent, - TopLevel topLevel) - { - ContentManager = contentManager; - StorageProvider = storageProvider; - ApplicationLibrary = applicationLibrary; - VirtualFileSystem = virtualFileSystem; - AccountManager = accountManager; - InputManager = inputManager; - UserChannelPersistence = userChannelPersistence; - LibHacHorizonManager = libHacHorizonManager; - UiHandler = uiHandler; - - ShowLoading = showLoading; - SwitchToGameControl = switchToGameControl; - SetMainContent = setMainContent; - TopLevel = topLevel; - } - - #region Properties - - public string SearchText - { - get => _searchText; - set - { - _searchText = value; - - _searchTimer?.Dispose(); - - _searchTimer = new Timer(TimerCallback, null, 1000, 0); - } - } - - private void TimerCallback(object obj) - { - RefreshView(); - - _searchTimer.Dispose(); - _searchTimer = null; - } - - public bool CanUpdate - { - get => _canUpdate && EnableNonGameRunningControls && Updater.CanUpdate(false); - set - { - _canUpdate = value; - OnPropertyChanged(); - } - } - - public Cursor Cursor - { - get => _cursor; - set - { - _cursor = value; - OnPropertyChanged(); - } - } - - public ReadOnlyObservableCollection<ApplicationData> AppsObservableList - { - get => _appsObservableList; - set - { - _appsObservableList = value; - - OnPropertyChanged(); - } - } - - public bool IsPaused - { - get => _isPaused; - set - { - _isPaused = value; - - OnPropertyChanged(); - } - } - - public long LastFullscreenToggle - { - get => _lastFullscreenToggle; - set - { - _lastFullscreenToggle = value; - - OnPropertyChanged(); - } - } - - public bool StatusBarVisible - { - get => _statusBarVisible && EnableNonGameRunningControls; - set - { - _statusBarVisible = value; - - OnPropertyChanged(); - } - } - - public bool EnableNonGameRunningControls => !IsGameRunning; - - public bool ShowFirmwareStatus => !ShowLoadProgress; - - public bool IsGameRunning - { - get => _isGameRunning; - set - { - _isGameRunning = value; - - if (!value) - { - ShowMenuAndStatusBar = false; - } - - OnPropertyChanged(); - OnPropertyChanged(nameof(EnableNonGameRunningControls)); - OnPropertyChanged(nameof(IsAppletMenuActive)); - OnPropertyChanged(nameof(StatusBarVisible)); - OnPropertyChanged(nameof(ShowFirmwareStatus)); - } - } - - public bool IsAmiiboRequested - { - get => _isAmiiboRequested && _isGameRunning; - set - { - _isAmiiboRequested = value; - - OnPropertyChanged(); - } - } - - public bool ShowLoadProgress - { - get => _showLoadProgress; - set - { - _showLoadProgress = value; - - OnPropertyChanged(); - OnPropertyChanged(nameof(ShowFirmwareStatus)); - } - } - - public string GameStatusText - { - get => _gameStatusText; - set - { - _gameStatusText = value; - - OnPropertyChanged(); - } - } - - public bool IsFullScreen - { - get => _isFullScreen; - set - { - _isFullScreen = value; - - OnPropertyChanged(); - } - } - - public bool ShowAll - { - get => _showAll; - set - { - _showAll = value; - - OnPropertyChanged(); - } - } - - public string LastScannedAmiiboId - { - get => _lastScannedAmiiboId; - set - { - _lastScannedAmiiboId = value; - - OnPropertyChanged(); - } - } - - public ApplicationData SelectedApplication - { - get - { - return Glyph switch - { - Glyph.List => ListSelectedApplication, - Glyph.Grid => GridSelectedApplication, - _ => null, - }; - } - } - - public bool OpenUserSaveDirectoryEnabled => !SelectedApplication.ControlHolder.ByteSpan.IsZeros() && SelectedApplication.ControlHolder.Value.UserAccountSaveDataSize > 0; - - public bool OpenDeviceSaveDirectoryEnabled => !SelectedApplication.ControlHolder.ByteSpan.IsZeros() && SelectedApplication.ControlHolder.Value.DeviceSaveDataSize > 0; - - public bool OpenBcatSaveDirectoryEnabled => !SelectedApplication.ControlHolder.ByteSpan.IsZeros() && SelectedApplication.ControlHolder.Value.BcatDeliveryCacheStorageSize > 0; - - public bool CreateShortcutEnabled => !ReleaseInformation.IsFlatHubBuild; - - public string LoadHeading - { - get => _loadHeading; - set - { - _loadHeading = value; - - OnPropertyChanged(); - } - } - - public string CacheLoadStatus - { - get => _cacheLoadStatus; - set - { - _cacheLoadStatus = value; - - OnPropertyChanged(); - } - } - - public Brush ProgressBarBackgroundColor - { - get => _progressBarBackgroundColor; - set - { - _progressBarBackgroundColor = value; - - OnPropertyChanged(); - } - } - - public Brush ProgressBarForegroundColor - { - get => _progressBarForegroundColor; - set - { - _progressBarForegroundColor = value; - - OnPropertyChanged(); - } - } - - public Brush VsyncColor - { - get => _vsyncColor; - set - { - _vsyncColor = value; - - OnPropertyChanged(); - } - } - - public byte[] SelectedIcon - { - get => _selectedIcon; - set - { - _selectedIcon = value; - - OnPropertyChanged(); - } - } - - public int ProgressMaximum - { - get => _progressMaximum; - set - { - _progressMaximum = value; - - OnPropertyChanged(); - } - } - - public int ProgressValue - { - get => _progressValue; - set - { - _progressValue = value; - - OnPropertyChanged(); - } - } - - public int StatusBarProgressMaximum - { - get => _statusBarProgressMaximum; - set - { - _statusBarProgressMaximum = value; - - OnPropertyChanged(); - } - } - - public int StatusBarProgressValue - { - get => _statusBarProgressValue; - set - { - _statusBarProgressValue = value; - - OnPropertyChanged(); - } - } - - public string FifoStatusText - { - get => _fifoStatusText; - set - { - _fifoStatusText = value; - - OnPropertyChanged(); - } - } - - public string GpuNameText - { - get => _gpuStatusText; - set - { - _gpuStatusText = value; - - OnPropertyChanged(); - } - } - - public string BackendText - { - get => _backendText; - set - { - _backendText = value; - - OnPropertyChanged(); - } - } - - public string DockedStatusText - { - get => _dockedStatusText; - set - { - _dockedStatusText = value; - - OnPropertyChanged(); - } - } - - public string AspectRatioStatusText - { - get => _aspectStatusText; - set - { - _aspectStatusText = value; - - OnPropertyChanged(); - } - } - - public string VolumeStatusText - { - get => _volumeStatusText; - set - { - _volumeStatusText = value; - - OnPropertyChanged(); - } - } - - public bool VolumeMuted => _volume == 0; - - public float Volume - { - get => _volume; - set - { - _volume = value; - - if (_isGameRunning) - { - AppHost.Device.SetVolume(_volume); - } - - OnPropertyChanged(nameof(VolumeStatusText)); - OnPropertyChanged(nameof(VolumeMuted)); - OnPropertyChanged(); - } - } - - public float VolumeBeforeMute - { - get => _volumeBeforeMute; - set - { - _volumeBeforeMute = value; - - OnPropertyChanged(); - } - } - - public bool ShowStatusSeparator - { - get => _showStatusSeparator; - set - { - _showStatusSeparator = value; - - OnPropertyChanged(); - } - } - - public bool ShowMenuAndStatusBar - { - get => _showMenuAndStatusBar; - set - { - _showMenuAndStatusBar = value; - - OnPropertyChanged(); - } - } - - public bool IsLoadingIndeterminate - { - get => _isLoadingIndeterminate; - set - { - _isLoadingIndeterminate = value; - - OnPropertyChanged(); - } - } - - public bool IsActive - { - get => _isActive; - set - { - _isActive = value; - - OnPropertyChanged(); - } - } - - - public bool ShowContent - { - get => _showContent; - set - { - _showContent = value; - - OnPropertyChanged(); - } - } - - public bool IsAppletMenuActive - { - get => _isAppletMenuActive && EnableNonGameRunningControls; - set - { - _isAppletMenuActive = value; - - OnPropertyChanged(); - } - } - - public WindowState WindowState - { - get => _windowState; - internal set - { - _windowState = value; - - OnPropertyChanged(); - } - } - - public double WindowWidth - { - get => _windowWidth; - set - { - _windowWidth = value; - - OnPropertyChanged(); - } - } - - public double WindowHeight - { - get => _windowHeight; - set - { - _windowHeight = value; - - OnPropertyChanged(); - } - } - - public bool IsGrid => Glyph == Glyph.Grid; - public bool IsList => Glyph == Glyph.List; - - internal void Sort(bool isAscending) - { - IsAscending = isAscending; - - RefreshView(); - } - - internal void Sort(ApplicationSort sort) - { - SortMode = sort; - - RefreshView(); - } - - public bool StartGamesInFullscreen - { - get => ConfigurationState.Instance.UI.StartFullscreen; - set - { - ConfigurationState.Instance.UI.StartFullscreen.Value = value; - - ConfigurationState.Instance.ToFileFormat().SaveConfig(Program.ConfigurationPath); - - OnPropertyChanged(); - } - } - - public bool ShowConsole - { - get => ConfigurationState.Instance.UI.ShowConsole; - set - { - ConfigurationState.Instance.UI.ShowConsole.Value = value; - - ConfigurationState.Instance.ToFileFormat().SaveConfig(Program.ConfigurationPath); - - OnPropertyChanged(); - } - } - - public string Title - { - get => _title; - set - { - _title = value; - - OnPropertyChanged(); - } - } - - public bool ShowConsoleVisible - { - get => ConsoleHelper.SetConsoleWindowStateSupported; - } - - public bool ManageFileTypesVisible - { - get => FileAssociationHelper.IsTypeAssociationSupported; - } - - public ObservableCollection<ApplicationData> Applications - { - get => _applications; - set - { - _applications = value; - - OnPropertyChanged(); - } - } - - public Glyph Glyph - { - get => (Glyph)ConfigurationState.Instance.UI.GameListViewMode.Value; - set - { - ConfigurationState.Instance.UI.GameListViewMode.Value = (int)value; - - OnPropertyChanged(); - OnPropertyChanged(nameof(IsGrid)); - OnPropertyChanged(nameof(IsList)); - - ConfigurationState.Instance.ToFileFormat().SaveConfig(Program.ConfigurationPath); - } - } - - public bool ShowNames - { - get => ConfigurationState.Instance.UI.ShowNames && ConfigurationState.Instance.UI.GridSize > 1; set - { - ConfigurationState.Instance.UI.ShowNames.Value = value; - - OnPropertyChanged(); - OnPropertyChanged(nameof(GridSizeScale)); - OnPropertyChanged(nameof(GridItemSelectorSize)); - - ConfigurationState.Instance.ToFileFormat().SaveConfig(Program.ConfigurationPath); - } - } - - internal ApplicationSort SortMode - { - get => (ApplicationSort)ConfigurationState.Instance.UI.ApplicationSort.Value; - private set - { - ConfigurationState.Instance.UI.ApplicationSort.Value = (int)value; - - OnPropertyChanged(); - OnPropertyChanged(nameof(SortName)); - - ConfigurationState.Instance.ToFileFormat().SaveConfig(Program.ConfigurationPath); - } - } - - public int ListItemSelectorSize - { - get - { - return ConfigurationState.Instance.UI.GridSize.Value switch - { - 1 => 78, - 2 => 100, - 3 => 120, - 4 => 140, - _ => 16, - }; - } - } - - public int GridItemSelectorSize - { - get - { - return ConfigurationState.Instance.UI.GridSize.Value switch - { - 1 => 120, - 2 => ShowNames ? 210 : 150, - 3 => ShowNames ? 240 : 180, - 4 => ShowNames ? 280 : 220, - _ => 16, - }; - } - } - - public int GridSizeScale - { - get => ConfigurationState.Instance.UI.GridSize; - set - { - ConfigurationState.Instance.UI.GridSize.Value = value; - - if (value < 2) - { - ShowNames = false; - } - - OnPropertyChanged(); - OnPropertyChanged(nameof(IsGridSmall)); - OnPropertyChanged(nameof(IsGridMedium)); - OnPropertyChanged(nameof(IsGridLarge)); - OnPropertyChanged(nameof(IsGridHuge)); - OnPropertyChanged(nameof(ListItemSelectorSize)); - OnPropertyChanged(nameof(GridItemSelectorSize)); - OnPropertyChanged(nameof(ShowNames)); - - ConfigurationState.Instance.ToFileFormat().SaveConfig(Program.ConfigurationPath); - } - } - - public string SortName - { - get - { - return SortMode switch - { - ApplicationSort.Title => LocaleManager.Instance[LocaleKeys.GameListHeaderApplication], - ApplicationSort.Developer => LocaleManager.Instance[LocaleKeys.GameListHeaderDeveloper], - ApplicationSort.LastPlayed => LocaleManager.Instance[LocaleKeys.GameListHeaderLastPlayed], - ApplicationSort.TotalTimePlayed => LocaleManager.Instance[LocaleKeys.GameListHeaderTimePlayed], - ApplicationSort.FileType => LocaleManager.Instance[LocaleKeys.GameListHeaderFileExtension], - ApplicationSort.FileSize => LocaleManager.Instance[LocaleKeys.GameListHeaderFileSize], - ApplicationSort.Path => LocaleManager.Instance[LocaleKeys.GameListHeaderPath], - ApplicationSort.Favorite => LocaleManager.Instance[LocaleKeys.CommonFavorite], - _ => string.Empty, - }; - } - } - - public bool IsAscending - { - get => ConfigurationState.Instance.UI.IsAscendingOrder; - private set - { - ConfigurationState.Instance.UI.IsAscendingOrder.Value = value; - - OnPropertyChanged(); - OnPropertyChanged(nameof(SortMode)); - OnPropertyChanged(nameof(SortName)); - - ConfigurationState.Instance.ToFileFormat().SaveConfig(Program.ConfigurationPath); - } - } - - public KeyGesture ShowUiKey - { - get => KeyGesture.Parse(_showUiKey); - set - { - _showUiKey = value.ToString(); - - OnPropertyChanged(); - } - } - - public KeyGesture ScreenshotKey - { - get => KeyGesture.Parse(_screenshotKey); - set - { - _screenshotKey = value.ToString(); - - OnPropertyChanged(); - } - } - - public KeyGesture PauseKey - { - get => KeyGesture.Parse(_pauseKey); set - { - _pauseKey = value.ToString(); - - OnPropertyChanged(); - } - } - - public ContentManager ContentManager { get; private set; } - public IStorageProvider StorageProvider { get; private set; } - public ApplicationLibrary ApplicationLibrary { get; private set; } - public VirtualFileSystem VirtualFileSystem { get; private set; } - public AccountManager AccountManager { get; private set; } - public InputManager InputManager { get; private set; } - public UserChannelPersistence UserChannelPersistence { get; private set; } - public Action<bool> ShowLoading { get; private set; } - public Action<bool> SwitchToGameControl { get; private set; } - public Action<Control> SetMainContent { get; private set; } - public TopLevel TopLevel { get; private set; } - public RendererHost RendererHostControl { get; private set; } - public bool IsClosing { get; set; } - public LibHacHorizonManager LibHacHorizonManager { get; internal set; } - public IHostUIHandler UiHandler { get; internal set; } - public bool IsSortedByFavorite => SortMode == ApplicationSort.Favorite; - public bool IsSortedByTitle => SortMode == ApplicationSort.Title; - public bool IsSortedByDeveloper => SortMode == ApplicationSort.Developer; - public bool IsSortedByLastPlayed => SortMode == ApplicationSort.LastPlayed; - public bool IsSortedByTimePlayed => SortMode == ApplicationSort.TotalTimePlayed; - public bool IsSortedByType => SortMode == ApplicationSort.FileType; - public bool IsSortedBySize => SortMode == ApplicationSort.FileSize; - public bool IsSortedByPath => SortMode == ApplicationSort.Path; - public bool IsGridSmall => ConfigurationState.Instance.UI.GridSize == 1; - public bool IsGridMedium => ConfigurationState.Instance.UI.GridSize == 2; - public bool IsGridLarge => ConfigurationState.Instance.UI.GridSize == 3; - public bool IsGridHuge => ConfigurationState.Instance.UI.GridSize == 4; - - #endregion - - #region PrivateMethods - - private IComparer<ApplicationData> GetComparer() - { - return SortMode switch - { -#pragma warning disable IDE0055 // Disable formatting - ApplicationSort.Title => IsAscending ? SortExpressionComparer<ApplicationData>.Ascending(app => app.TitleName) - : SortExpressionComparer<ApplicationData>.Descending(app => app.TitleName), - ApplicationSort.Developer => IsAscending ? SortExpressionComparer<ApplicationData>.Ascending(app => app.Developer) - : SortExpressionComparer<ApplicationData>.Descending(app => app.Developer), - ApplicationSort.LastPlayed => new LastPlayedSortComparer(IsAscending), - ApplicationSort.TotalTimePlayed => new TimePlayedSortComparer(IsAscending), - ApplicationSort.FileType => IsAscending ? SortExpressionComparer<ApplicationData>.Ascending(app => app.FileExtension) - : SortExpressionComparer<ApplicationData>.Descending(app => app.FileExtension), - ApplicationSort.FileSize => IsAscending ? SortExpressionComparer<ApplicationData>.Ascending(app => app.FileSize) - : SortExpressionComparer<ApplicationData>.Descending(app => app.FileSize), - ApplicationSort.Path => IsAscending ? SortExpressionComparer<ApplicationData>.Ascending(app => app.Path) - : SortExpressionComparer<ApplicationData>.Descending(app => app.Path), - ApplicationSort.Favorite => !IsAscending ? SortExpressionComparer<ApplicationData>.Ascending(app => app.Favorite) - : SortExpressionComparer<ApplicationData>.Descending(app => app.Favorite), - _ => null, -#pragma warning restore IDE0055 - }; - } - - public void RefreshView() - { - RefreshGrid(); - } - - private void RefreshGrid() - { - Applications.ToObservableChangeSet() - .Filter(Filter) - .Sort(GetComparer()) - .Bind(out _appsObservableList).AsObservableList(); - - OnPropertyChanged(nameof(AppsObservableList)); - } - - private bool Filter(object arg) - { - if (arg is ApplicationData app) - { - return string.IsNullOrWhiteSpace(_searchText) || app.TitleName.ToLower().Contains(_searchText.ToLower()); - } - - return false; - } - - private async Task HandleFirmwareInstallation(string filename) - { - try - { - SystemVersion firmwareVersion = ContentManager.VerifyFirmwarePackage(filename); - - if (firmwareVersion == null) - { - await ContentDialogHelper.CreateErrorDialog(LocaleManager.Instance.UpdateAndGetDynamicValue(LocaleKeys.DialogFirmwareInstallerFirmwareNotFoundErrorMessage, filename)); - - return; - } - - string dialogTitle = LocaleManager.Instance.UpdateAndGetDynamicValue(LocaleKeys.DialogFirmwareInstallerFirmwareInstallTitle, firmwareVersion.VersionString); - string dialogMessage = LocaleManager.Instance.UpdateAndGetDynamicValue(LocaleKeys.DialogFirmwareInstallerFirmwareInstallMessage, firmwareVersion.VersionString); - - SystemVersion currentVersion = ContentManager.GetCurrentFirmwareVersion(); - if (currentVersion != null) - { - dialogMessage += LocaleManager.Instance.UpdateAndGetDynamicValue(LocaleKeys.DialogFirmwareInstallerFirmwareInstallSubMessage, currentVersion.VersionString); - } - - dialogMessage += LocaleManager.Instance[LocaleKeys.DialogFirmwareInstallerFirmwareInstallConfirmMessage]; - - UserResult result = await ContentDialogHelper.CreateConfirmationDialog( - dialogTitle, - dialogMessage, - LocaleManager.Instance[LocaleKeys.InputDialogYes], - LocaleManager.Instance[LocaleKeys.InputDialogNo], - LocaleManager.Instance[LocaleKeys.RyujinxConfirm]); - - UpdateWaitWindow waitingDialog = new(dialogTitle, LocaleManager.Instance[LocaleKeys.DialogFirmwareInstallerFirmwareInstallWaitMessage]); - - if (result == UserResult.Yes) - { - Logger.Info?.Print(LogClass.Application, $"Installing firmware {firmwareVersion.VersionString}"); - - Thread thread = new(() => - { - Dispatcher.UIThread.InvokeAsync(delegate - { - waitingDialog.Show(); - }); - - try - { - ContentManager.InstallFirmware(filename); - - Dispatcher.UIThread.InvokeAsync(async delegate - { - waitingDialog.Close(); - - string message = LocaleManager.Instance.UpdateAndGetDynamicValue(LocaleKeys.DialogFirmwareInstallerFirmwareInstallSuccessMessage, firmwareVersion.VersionString); - - await ContentDialogHelper.CreateInfoDialog(dialogTitle, message, LocaleManager.Instance[LocaleKeys.InputDialogOk], "", LocaleManager.Instance[LocaleKeys.RyujinxInfo]); - - Logger.Info?.Print(LogClass.Application, message); - - // Purge Applet Cache. - - DirectoryInfo miiEditorCacheFolder = new(Path.Combine(AppDataManager.GamesDirPath, "0100000000001009", "cache")); - - if (miiEditorCacheFolder.Exists) - { - miiEditorCacheFolder.Delete(true); - } - }); - } - catch (Exception ex) - { - Dispatcher.UIThread.InvokeAsync(async () => - { - waitingDialog.Close(); - - await ContentDialogHelper.CreateErrorDialog(ex.Message); - }); - } - finally - { - RefreshFirmwareStatus(); - } - }) - { - Name = "GUI.FirmwareInstallerThread", - }; - - thread.Start(); - } - } - catch (MissingKeyException ex) - { - if (Application.Current.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop) - { - Logger.Error?.Print(LogClass.Application, ex.ToString()); - - await UserErrorDialog.ShowUserErrorDialog(UserError.NoKeys); - } - } - catch (Exception ex) - { - await ContentDialogHelper.CreateErrorDialog(ex.Message); - } - } - - private void ProgressHandler<T>(T state, int current, int total) where T : Enum - { - Dispatcher.UIThread.Post((() => - { - ProgressMaximum = total; - ProgressValue = current; - - switch (state) - { - case LoadState ptcState: - CacheLoadStatus = $"{current} / {total}"; - switch (ptcState) - { - case LoadState.Unloaded: - case LoadState.Loading: - LoadHeading = LocaleManager.Instance[LocaleKeys.CompilingPPTC]; - IsLoadingIndeterminate = false; - break; - case LoadState.Loaded: - LoadHeading = LocaleManager.Instance.UpdateAndGetDynamicValue(LocaleKeys.LoadingHeading, TitleName); - IsLoadingIndeterminate = true; - CacheLoadStatus = ""; - break; - } - break; - case ShaderCacheLoadingState shaderCacheState: - CacheLoadStatus = $"{current} / {total}"; - switch (shaderCacheState) - { - case ShaderCacheLoadingState.Start: - case ShaderCacheLoadingState.Loading: - LoadHeading = LocaleManager.Instance[LocaleKeys.CompilingShaders]; - IsLoadingIndeterminate = false; - break; - case ShaderCacheLoadingState.Packaging: - LoadHeading = LocaleManager.Instance[LocaleKeys.PackagingShaders]; - IsLoadingIndeterminate = false; - break; - case ShaderCacheLoadingState.Loaded: - LoadHeading = LocaleManager.Instance.UpdateAndGetDynamicValue(LocaleKeys.LoadingHeading, TitleName); - IsLoadingIndeterminate = true; - CacheLoadStatus = ""; - break; - } - break; - default: - throw new ArgumentException($"Unknown Progress Handler type {typeof(T)}"); - } - })); - } - - private void PrepareLoadScreen() - { - using MemoryStream stream = new(SelectedIcon); - using var gameIconBmp = Image.Load<Bgra32>(stream); - - var dominantColor = IconColorPicker.GetFilteredColor(gameIconBmp).ToPixel<Bgra32>(); - - const float ColorMultiple = 0.5f; - - Color progressFgColor = Color.FromRgb(dominantColor.R, dominantColor.G, dominantColor.B); - Color progressBgColor = Color.FromRgb( - (byte)(dominantColor.R * ColorMultiple), - (byte)(dominantColor.G * ColorMultiple), - (byte)(dominantColor.B * ColorMultiple)); - - ProgressBarForegroundColor = new SolidColorBrush(progressFgColor); - ProgressBarBackgroundColor = new SolidColorBrush(progressBgColor); - } - - private void InitializeGame() - { - RendererHostControl.WindowCreated += RendererHost_Created; - - AppHost.StatusUpdatedEvent += Update_StatusBar; - AppHost.AppExit += AppHost_AppExit; - - _rendererWaitEvent.WaitOne(); - - AppHost?.Start(); - - AppHost?.DisposeContext(); - } - - private async Task HandleRelaunch() - { - if (UserChannelPersistence.PreviousIndex != -1 && UserChannelPersistence.ShouldRestart) - { - UserChannelPersistence.ShouldRestart = false; - - await LoadApplication(_currentEmulatedGamePath); - } - else - { - // Otherwise, clear state. - UserChannelPersistence = new UserChannelPersistence(); - _currentEmulatedGamePath = null; - } - } - - private void Update_StatusBar(object sender, StatusUpdatedEventArgs args) - { - if (ShowMenuAndStatusBar && !ShowLoadProgress) - { - Dispatcher.UIThread.InvokeAsync(() => - { - Application.Current.Styles.TryGetResource(args.VSyncEnabled - ? "VsyncEnabled" - : "VsyncDisabled", - Application.Current.ActualThemeVariant, - out object color); - - if (color is not null) - { - VsyncColor = new SolidColorBrush((Color)color); - } - - DockedStatusText = args.DockedMode; - AspectRatioStatusText = args.AspectRatio; - GameStatusText = args.GameStatus; - VolumeStatusText = args.VolumeStatus; - FifoStatusText = args.FifoStatus; - GpuNameText = args.GpuName; - BackendText = args.GpuBackend; - - ShowStatusSeparator = true; - }); - } - } - - private void RendererHost_Created(object sender, EventArgs e) - { - ShowLoading(false); - - _rendererWaitEvent.Set(); - } - - #endregion - - #region PublicMethods - - public void SetUiProgressHandlers(Switch emulationContext) - { - if (emulationContext.Processes.ActiveApplication.DiskCacheLoadState != null) - { - emulationContext.Processes.ActiveApplication.DiskCacheLoadState.StateChanged -= ProgressHandler; - emulationContext.Processes.ActiveApplication.DiskCacheLoadState.StateChanged += ProgressHandler; - } - - emulationContext.Gpu.ShaderCacheStateChanged -= ProgressHandler; - emulationContext.Gpu.ShaderCacheStateChanged += ProgressHandler; - } - - public void LoadConfigurableHotKeys() - { - if (AvaloniaKeyboardMappingHelper.TryGetAvaKey((Key)ConfigurationState.Instance.Hid.Hotkeys.Value.ShowUI, out var showUiKey)) - { - ShowUiKey = new KeyGesture(showUiKey); - } - - if (AvaloniaKeyboardMappingHelper.TryGetAvaKey((Key)ConfigurationState.Instance.Hid.Hotkeys.Value.Screenshot, out var screenshotKey)) - { - ScreenshotKey = new KeyGesture(screenshotKey); - } - - if (AvaloniaKeyboardMappingHelper.TryGetAvaKey((Key)ConfigurationState.Instance.Hid.Hotkeys.Value.Pause, out var pauseKey)) - { - PauseKey = new KeyGesture(pauseKey); - } - } - - public void TakeScreenshot() - { - AppHost.ScreenshotRequested = true; - } - - public void HideUi() - { - ShowMenuAndStatusBar = false; - } - - public void ToggleStartGamesInFullscreen() - { - StartGamesInFullscreen = !StartGamesInFullscreen; - } - - public void ToggleShowConsole() - { - ShowConsole = !ShowConsole; - } - - public void SetListMode() - { - Glyph = Glyph.List; - } - - public void SetGridMode() - { - Glyph = Glyph.Grid; - } - - public void SetAspectRatio(AspectRatio aspectRatio) - { - ConfigurationState.Instance.Graphics.AspectRatio.Value = aspectRatio; - } - - public async Task InstallFirmwareFromFile() - { - var result = await StorageProvider.OpenFilePickerAsync(new FilePickerOpenOptions - { - AllowMultiple = false, - FileTypeFilter = new List<FilePickerFileType> - { - new(LocaleManager.Instance[LocaleKeys.FileDialogAllTypes]) - { - Patterns = new[] { "*.xci", "*.zip" }, - AppleUniformTypeIdentifiers = new[] { "com.ryujinx.xci", "public.zip-archive" }, - MimeTypes = new[] { "application/x-nx-xci", "application/zip" }, - }, - new("XCI") - { - Patterns = new[] { "*.xci" }, - AppleUniformTypeIdentifiers = new[] { "com.ryujinx.xci" }, - MimeTypes = new[] { "application/x-nx-xci" }, - }, - new("ZIP") - { - Patterns = new[] { "*.zip" }, - AppleUniformTypeIdentifiers = new[] { "public.zip-archive" }, - MimeTypes = new[] { "application/zip" }, - }, - }, - }); - - if (result.Count > 0) - { - await HandleFirmwareInstallation(result[0].Path.LocalPath); - } - } - - public async Task InstallFirmwareFromFolder() - { - var result = await StorageProvider.OpenFolderPickerAsync(new FolderPickerOpenOptions - { - AllowMultiple = false, - }); - - if (result.Count > 0) - { - await HandleFirmwareInstallation(result[0].Path.LocalPath); - } - } - - public void OpenRyujinxFolder() - { - OpenHelper.OpenFolder(AppDataManager.BaseDirPath); - } - - public void OpenLogsFolder() - { - string logPath = AppDataManager.GetOrCreateLogsDir(); - if (!string.IsNullOrEmpty(logPath)) - { - OpenHelper.OpenFolder(logPath); - } - } - - public void ToggleDockMode() - { - if (IsGameRunning) - { - ConfigurationState.Instance.System.EnableDockedMode.Value = !ConfigurationState.Instance.System.EnableDockedMode.Value; - } - } - - public async Task ExitCurrentState() - { - if (WindowState == WindowState.FullScreen) - { - ToggleFullscreen(); - } - else if (IsGameRunning) - { - await Task.Delay(100); - - AppHost?.ShowExitPrompt(); - } - } - - public static void ChangeLanguage(object languageCode) - { - LocaleManager.Instance.LoadLanguage((string)languageCode); - - if (Program.PreviewerDetached) - { - ConfigurationState.Instance.UI.LanguageCode.Value = (string)languageCode; - ConfigurationState.Instance.ToFileFormat().SaveConfig(Program.ConfigurationPath); - } - } - - public async Task ManageProfiles() - { - await NavigationDialogHost.Show(AccountManager, ContentManager, VirtualFileSystem, LibHacHorizonManager.RyujinxClient); - } - - public void SimulateWakeUpMessage() - { - AppHost.Device.System.SimulateWakeUpMessage(); - } - - public async Task OpenFile() - { - var result = await StorageProvider.OpenFilePickerAsync(new FilePickerOpenOptions - { - Title = LocaleManager.Instance[LocaleKeys.OpenFileDialogTitle], - AllowMultiple = false, - FileTypeFilter = new List<FilePickerFileType> - { - new(LocaleManager.Instance[LocaleKeys.AllSupportedFormats]) - { - Patterns = new[] { "*.nsp", "*.xci", "*.nca", "*.nro", "*.nso" }, - AppleUniformTypeIdentifiers = new[] - { - "com.ryujinx.nsp", - "com.ryujinx.xci", - "com.ryujinx.nca", - "com.ryujinx.nro", - "com.ryujinx.nso", - }, - MimeTypes = new[] - { - "application/x-nx-nsp", - "application/x-nx-xci", - "application/x-nx-nca", - "application/x-nx-nro", - "application/x-nx-nso", - }, - }, - new("NSP") - { - Patterns = new[] { "*.nsp" }, - AppleUniformTypeIdentifiers = new[] { "com.ryujinx.nsp" }, - MimeTypes = new[] { "application/x-nx-nsp" }, - }, - new("XCI") - { - Patterns = new[] { "*.xci" }, - AppleUniformTypeIdentifiers = new[] { "com.ryujinx.xci" }, - MimeTypes = new[] { "application/x-nx-xci" }, - }, - new("NCA") - { - Patterns = new[] { "*.nca" }, - AppleUniformTypeIdentifiers = new[] { "com.ryujinx.nca" }, - MimeTypes = new[] { "application/x-nx-nca" }, - }, - new("NRO") - { - Patterns = new[] { "*.nro" }, - AppleUniformTypeIdentifiers = new[] { "com.ryujinx.nro" }, - MimeTypes = new[] { "application/x-nx-nro" }, - }, - new("NSO") - { - Patterns = new[] { "*.nso" }, - AppleUniformTypeIdentifiers = new[] { "com.ryujinx.nso" }, - MimeTypes = new[] { "application/x-nx-nso" }, - }, - }, - }); - - if (result.Count > 0) - { - await LoadApplication(result[0].Path.LocalPath); - } - } - - public async Task OpenFolder() - { - var result = await StorageProvider.OpenFolderPickerAsync(new FolderPickerOpenOptions - { - Title = LocaleManager.Instance[LocaleKeys.OpenFolderDialogTitle], - AllowMultiple = false, - }); - - if (result.Count > 0) - { - await LoadApplication(result[0].Path.LocalPath); - } - } - - public async Task LoadApplication(string path, bool startFullscreen = false, string titleName = "") - { - if (AppHost != null) - { - await ContentDialogHelper.CreateInfoDialog( - LocaleManager.Instance[LocaleKeys.DialogLoadAppGameAlreadyLoadedMessage], - LocaleManager.Instance[LocaleKeys.DialogLoadAppGameAlreadyLoadedSubMessage], - LocaleManager.Instance[LocaleKeys.InputDialogOk], - "", - LocaleManager.Instance[LocaleKeys.RyujinxInfo]); - - return; - } - -#if RELEASE - await PerformanceCheck(); -#endif - - Logger.RestartTime(); - - SelectedIcon ??= ApplicationLibrary.GetApplicationIcon(path, ConfigurationState.Instance.System.Language); - - PrepareLoadScreen(); - - RendererHostControl = new RendererHost(); - - AppHost = new AppHost( - RendererHostControl, - InputManager, - path, - VirtualFileSystem, - ContentManager, - AccountManager, - UserChannelPersistence, - this, - TopLevel); - - if (!await AppHost.LoadGuestApplication()) - { - AppHost.DisposeContext(); - AppHost = null; - - return; - } - - CanUpdate = false; - - LoadHeading = TitleName = titleName; - - if (string.IsNullOrWhiteSpace(titleName)) - { - LoadHeading = LocaleManager.Instance.UpdateAndGetDynamicValue(LocaleKeys.LoadingHeading, AppHost.Device.Processes.ActiveApplication.Name); - TitleName = AppHost.Device.Processes.ActiveApplication.Name; - } - - SwitchToRenderer(startFullscreen); - - _currentEmulatedGamePath = path; - - Thread gameThread = new(InitializeGame) { Name = "GUI.WindowThread" }; - gameThread.Start(); - } - - public void SwitchToRenderer(bool startFullscreen) - { - Dispatcher.UIThread.Post(() => - { - SwitchToGameControl(startFullscreen); - - SetMainContent(RendererHostControl); - - RendererHostControl.Focus(); - }); - } - - public static void UpdateGameMetadata(string titleId) - { - ApplicationLibrary.LoadAndSaveMetaData(titleId, appMetadata => - { - appMetadata.UpdatePostGame(); - }); - } - - public void RefreshFirmwareStatus() - { - SystemVersion version = null; - try - { - version = ContentManager.GetCurrentFirmwareVersion(); - } - catch (Exception) { } - - bool hasApplet = false; - - if (version != null) - { - LocaleManager.Instance.UpdateAndGetDynamicValue(LocaleKeys.StatusBarSystemVersion, version.VersionString); - - hasApplet = version.Major > 3; - } - else - { - LocaleManager.Instance.UpdateAndGetDynamicValue(LocaleKeys.StatusBarSystemVersion, "0.0"); - } - - IsAppletMenuActive = hasApplet; - } - - public void AppHost_AppExit(object sender, EventArgs e) - { - if (IsClosing) - { - return; - } - - IsGameRunning = false; - - Dispatcher.UIThread.InvokeAsync(async () => - { - ShowMenuAndStatusBar = true; - ShowContent = true; - ShowLoadProgress = false; - IsLoadingIndeterminate = false; - CanUpdate = true; - Cursor = Cursor.Default; - - SetMainContent(null); - - AppHost = null; - - await HandleRelaunch(); - }); - - RendererHostControl.WindowCreated -= RendererHost_Created; - RendererHostControl = null; - - SelectedIcon = null; - - Dispatcher.UIThread.InvokeAsync(() => - { - Title = $"Ryujinx {Program.Version}"; - }); - } - - public void ToggleFullscreen() - { - if (Environment.TickCount64 - LastFullscreenToggle < HotKeyPressDelayMs) - { - return; - } - - LastFullscreenToggle = Environment.TickCount64; - - if (WindowState == WindowState.FullScreen) - { - WindowState = WindowState.Normal; - - if (IsGameRunning) - { - ShowMenuAndStatusBar = true; - } - } - else - { - WindowState = WindowState.FullScreen; - - if (IsGameRunning) - { - ShowMenuAndStatusBar = false; - } - } - - IsFullScreen = WindowState == WindowState.FullScreen; - } - - public static void SaveConfig() - { - ConfigurationState.Instance.ToFileFormat().SaveConfig(Program.ConfigurationPath); - } - - public static async Task PerformanceCheck() - { - if (ConfigurationState.Instance.Logger.EnableTrace.Value) - { - string mainMessage = LocaleManager.Instance[LocaleKeys.DialogPerformanceCheckLoggingEnabledMessage]; - string secondaryMessage = LocaleManager.Instance[LocaleKeys.DialogPerformanceCheckLoggingEnabledConfirmMessage]; - - UserResult result = await ContentDialogHelper.CreateConfirmationDialog( - mainMessage, - secondaryMessage, - LocaleManager.Instance[LocaleKeys.InputDialogYes], - LocaleManager.Instance[LocaleKeys.InputDialogNo], - LocaleManager.Instance[LocaleKeys.RyujinxConfirm]); - - if (result == UserResult.Yes) - { - ConfigurationState.Instance.Logger.EnableTrace.Value = false; - - SaveConfig(); - } - } - - if (!string.IsNullOrWhiteSpace(ConfigurationState.Instance.Graphics.ShadersDumpPath.Value)) - { - string mainMessage = LocaleManager.Instance[LocaleKeys.DialogPerformanceCheckShaderDumpEnabledMessage]; - string secondaryMessage = LocaleManager.Instance[LocaleKeys.DialogPerformanceCheckShaderDumpEnabledConfirmMessage]; - - UserResult result = await ContentDialogHelper.CreateConfirmationDialog( - mainMessage, - secondaryMessage, - LocaleManager.Instance[LocaleKeys.InputDialogYes], - LocaleManager.Instance[LocaleKeys.InputDialogNo], - LocaleManager.Instance[LocaleKeys.RyujinxConfirm]); - - if (result == UserResult.Yes) - { - ConfigurationState.Instance.Graphics.ShadersDumpPath.Value = ""; - - SaveConfig(); - } - } - } - #endregion - } -} diff --git a/src/Ryujinx.Ava/UI/ViewModels/ModManagerViewModel.cs b/src/Ryujinx.Ava/UI/ViewModels/ModManagerViewModel.cs deleted file mode 100644 index 8321bf89..00000000 --- a/src/Ryujinx.Ava/UI/ViewModels/ModManagerViewModel.cs +++ /dev/null @@ -1,336 +0,0 @@ -using Avalonia; -using Avalonia.Collections; -using Avalonia.Controls.ApplicationLifetimes; -using Avalonia.Platform.Storage; -using Avalonia.Threading; -using DynamicData; -using Ryujinx.Ava.Common.Locale; -using Ryujinx.Ava.UI.Helpers; -using Ryujinx.Ava.UI.Models; -using Ryujinx.Common.Configuration; -using Ryujinx.Common.Logging; -using Ryujinx.Common.Utilities; -using Ryujinx.HLE.HOS; -using System; -using System.IO; -using System.Linq; - -namespace Ryujinx.Ava.UI.ViewModels -{ - public class ModManagerViewModel : BaseModel - { - private readonly string _modJsonPath; - - private AvaloniaList<ModModel> _mods = new(); - private AvaloniaList<ModModel> _views = new(); - private AvaloniaList<ModModel> _selectedMods = new(); - - private string _search; - private readonly ulong _applicationId; - private readonly IStorageProvider _storageProvider; - - private static readonly ModMetadataJsonSerializerContext _serializerContext = new(JsonHelper.GetDefaultSerializerOptions()); - - public AvaloniaList<ModModel> Mods - { - get => _mods; - set - { - _mods = value; - OnPropertyChanged(); - OnPropertyChanged(nameof(ModCount)); - Sort(); - } - } - - public AvaloniaList<ModModel> Views - { - get => _views; - set - { - _views = value; - OnPropertyChanged(); - } - } - - public AvaloniaList<ModModel> SelectedMods - { - get => _selectedMods; - set - { - _selectedMods = value; - OnPropertyChanged(); - } - } - - public string Search - { - get => _search; - set - { - _search = value; - OnPropertyChanged(); - Sort(); - } - } - - public string ModCount - { - get => string.Format(LocaleManager.Instance[LocaleKeys.ModWindowHeading], Mods.Count); - } - - public ModManagerViewModel(ulong applicationId) - { - _applicationId = applicationId; - - _modJsonPath = Path.Combine(AppDataManager.GamesDirPath, applicationId.ToString("x16"), "mods.json"); - - if (Application.Current.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop) - { - _storageProvider = desktop.MainWindow.StorageProvider; - } - - LoadMods(applicationId); - } - - private void LoadMods(ulong applicationId) - { - Mods.Clear(); - SelectedMods.Clear(); - - string[] modsBasePaths = [ModLoader.GetSdModsBasePath(), ModLoader.GetModsBasePath()]; - - foreach (var path in modsBasePaths) - { - var inSd = path == ModLoader.GetSdModsBasePath(); - var modCache = new ModLoader.ModCache(); - - ModLoader.QueryContentsDir(modCache, new DirectoryInfo(Path.Combine(path, "contents")), applicationId); - - foreach (var mod in modCache.RomfsDirs) - { - var modModel = new ModModel(mod.Path.Parent.FullName, mod.Name, mod.Enabled, inSd); - if (Mods.All(x => x.Path != mod.Path.Parent.FullName)) - { - Mods.Add(modModel); - } - } - - foreach (var mod in modCache.RomfsContainers) - { - Mods.Add(new ModModel(mod.Path.FullName, mod.Name, mod.Enabled, inSd)); - } - - foreach (var mod in modCache.ExefsDirs) - { - var modModel = new ModModel(mod.Path.Parent.FullName, mod.Name, mod.Enabled, inSd); - if (Mods.All(x => x.Path != mod.Path.Parent.FullName)) - { - Mods.Add(modModel); - } - } - - foreach (var mod in modCache.ExefsContainers) - { - Mods.Add(new ModModel(mod.Path.FullName, mod.Name, mod.Enabled, inSd)); - } - } - - Sort(); - } - - public void Sort() - { - Mods.AsObservableChangeSet() - .Filter(Filter) - .Bind(out var view).AsObservableList(); - - _views.Clear(); - _views.AddRange(view); - - SelectedMods = new(Views.Where(x => x.Enabled)); - - OnPropertyChanged(nameof(ModCount)); - OnPropertyChanged(nameof(Views)); - OnPropertyChanged(nameof(SelectedMods)); - } - - private bool Filter(object arg) - { - if (arg is ModModel content) - { - return string.IsNullOrWhiteSpace(_search) || content.Name.ToLower().Contains(_search.ToLower()); - } - - return false; - } - - public void Save() - { - ModMetadata modData = new(); - - foreach (ModModel mod in Mods) - { - modData.Mods.Add(new Mod - { - Name = mod.Name, - Path = mod.Path, - Enabled = SelectedMods.Contains(mod), - }); - } - - JsonHelper.SerializeToFile(_modJsonPath, modData, _serializerContext.ModMetadata); - } - - public void Delete(ModModel model) - { - var isSubdir = true; - var pathToDelete = model.Path; - var basePath = model.InSd ? ModLoader.GetSdModsBasePath() : ModLoader.GetModsBasePath(); - var modsDir = ModLoader.GetApplicationDir(basePath, _applicationId.ToString("x16")); - - if (new DirectoryInfo(model.Path).Parent?.FullName == modsDir) - { - isSubdir = false; - } - - if (isSubdir) - { - var parentDir = String.Empty; - - foreach (var dir in Directory.GetDirectories(modsDir, "*", SearchOption.TopDirectoryOnly)) - { - if (Directory.GetDirectories(dir, "*", SearchOption.AllDirectories).Contains(model.Path)) - { - parentDir = dir; - break; - } - } - - if (parentDir == String.Empty) - { - Dispatcher.UIThread.Post(async () => - { - await ContentDialogHelper.CreateErrorDialog(LocaleManager.Instance.UpdateAndGetDynamicValue( - LocaleKeys.DialogModDeleteNoParentMessage, - model.Path)); - }); - return; - } - } - - Logger.Info?.Print(LogClass.Application, $"Deleting mod at \"{pathToDelete}\""); - Directory.Delete(pathToDelete, true); - - Mods.Remove(model); - OnPropertyChanged(nameof(ModCount)); - Sort(); - } - - private void AddMod(DirectoryInfo directory) - { - string[] directories; - - try - { - directories = Directory.GetDirectories(directory.ToString(), "*", SearchOption.AllDirectories); - } - catch (Exception exception) - { - Dispatcher.UIThread.Post(async () => - { - await ContentDialogHelper.CreateErrorDialog(LocaleManager.Instance.UpdateAndGetDynamicValue( - LocaleKeys.DialogLoadFileErrorMessage, - exception.ToString(), - directory)); - }); - return; - } - - var destinationDir = ModLoader.GetApplicationDir(ModLoader.GetSdModsBasePath(), _applicationId.ToString("x16")); - - // TODO: More robust checking for valid mod folders - var isDirectoryValid = true; - - if (directories.Length == 0) - { - isDirectoryValid = false; - } - - if (!isDirectoryValid) - { - Dispatcher.UIThread.Post(async () => - { - await ContentDialogHelper.CreateErrorDialog(LocaleManager.Instance[LocaleKeys.DialogModInvalidMessage]); - }); - return; - } - - foreach (var dir in directories) - { - string dirToCreate = dir.Replace(directory.Parent.ToString(), destinationDir); - - // Mod already exists - if (Directory.Exists(dirToCreate)) - { - Dispatcher.UIThread.Post(async () => - { - await ContentDialogHelper.CreateErrorDialog(LocaleManager.Instance.UpdateAndGetDynamicValue( - LocaleKeys.DialogLoadFileErrorMessage, - LocaleManager.Instance[LocaleKeys.DialogModAlreadyExistsMessage], - dirToCreate)); - }); - - return; - } - - Directory.CreateDirectory(dirToCreate); - } - - var files = Directory.GetFiles(directory.ToString(), "*", SearchOption.AllDirectories); - - foreach (var file in files) - { - File.Copy(file, file.Replace(directory.Parent.ToString(), destinationDir), true); - } - - LoadMods(_applicationId); - } - - public async void Add() - { - var result = await _storageProvider.OpenFolderPickerAsync(new FolderPickerOpenOptions - { - Title = LocaleManager.Instance[LocaleKeys.SelectModDialogTitle], - AllowMultiple = true, - }); - - foreach (var folder in result) - { - AddMod(new DirectoryInfo(folder.Path.LocalPath)); - } - } - - public void DeleteAll() - { - foreach (var mod in Mods) - { - Delete(mod); - } - - Mods.Clear(); - OnPropertyChanged(nameof(ModCount)); - Sort(); - } - - public void EnableAll() - { - SelectedMods = new(Mods); - } - - public void DisableAll() - { - SelectedMods.Clear(); - } - } -} diff --git a/src/Ryujinx.Ava/UI/ViewModels/MotionInputViewModel.cs b/src/Ryujinx.Ava/UI/ViewModels/MotionInputViewModel.cs deleted file mode 100644 index 0b12a51f..00000000 --- a/src/Ryujinx.Ava/UI/ViewModels/MotionInputViewModel.cs +++ /dev/null @@ -1,93 +0,0 @@ -namespace Ryujinx.Ava.UI.ViewModels -{ - public class MotionInputViewModel : BaseModel - { - private int _slot; - public int Slot - { - get => _slot; - set - { - _slot = value; - OnPropertyChanged(); - } - } - - private int _altSlot; - public int AltSlot - { - get => _altSlot; - set - { - _altSlot = value; - OnPropertyChanged(); - } - } - - private string _dsuServerHost; - public string DsuServerHost - { - get => _dsuServerHost; - set - { - _dsuServerHost = value; - OnPropertyChanged(); - } - } - - private int _dsuServerPort; - public int DsuServerPort - { - get => _dsuServerPort; - set - { - _dsuServerPort = value; - OnPropertyChanged(); - } - } - - private bool _mirrorInput; - public bool MirrorInput - { - get => _mirrorInput; - set - { - _mirrorInput = value; - OnPropertyChanged(); - } - } - - private int _sensitivity; - public int Sensitivity - { - get => _sensitivity; - set - { - _sensitivity = value; - OnPropertyChanged(); - } - } - - private double _gryoDeadzone; - public double GyroDeadzone - { - get => _gryoDeadzone; - set - { - _gryoDeadzone = value; - OnPropertyChanged(); - } - } - - private bool _enableCemuHookMotion; - public bool EnableCemuHookMotion - { - get => _enableCemuHookMotion; - set - { - _enableCemuHookMotion = value; - OnPropertyChanged(); - } - } - } -} diff --git a/src/Ryujinx.Ava/UI/ViewModels/RumbleInputViewModel.cs b/src/Ryujinx.Ava/UI/ViewModels/RumbleInputViewModel.cs deleted file mode 100644 index 49de1993..00000000 --- a/src/Ryujinx.Ava/UI/ViewModels/RumbleInputViewModel.cs +++ /dev/null @@ -1,27 +0,0 @@ -namespace Ryujinx.Ava.UI.ViewModels -{ - public class RumbleInputViewModel : BaseModel - { - private float _strongRumble; - public float StrongRumble - { - get => _strongRumble; - set - { - _strongRumble = value; - OnPropertyChanged(); - } - } - - private float _weakRumble; - public float WeakRumble - { - get => _weakRumble; - set - { - _weakRumble = value; - OnPropertyChanged(); - } - } - } -} diff --git a/src/Ryujinx.Ava/UI/ViewModels/SettingsViewModel.cs b/src/Ryujinx.Ava/UI/ViewModels/SettingsViewModel.cs deleted file mode 100644 index bcaa0860..00000000 --- a/src/Ryujinx.Ava/UI/ViewModels/SettingsViewModel.cs +++ /dev/null @@ -1,614 +0,0 @@ -using Avalonia.Collections; -using Avalonia.Controls; -using Avalonia.Threading; -using LibHac.Tools.FsSystem; -using Ryujinx.Audio.Backends.OpenAL; -using Ryujinx.Audio.Backends.SDL2; -using Ryujinx.Audio.Backends.SoundIo; -using Ryujinx.Ava.Common.Locale; -using Ryujinx.Ava.UI.Helpers; -using Ryujinx.Ava.UI.Windows; -using Ryujinx.Common.Configuration; -using Ryujinx.Common.Configuration.Hid; -using Ryujinx.Common.Configuration.Multiplayer; -using Ryujinx.Common.GraphicsDriver; -using Ryujinx.Common.Logging; -using Ryujinx.Graphics.Vulkan; -using Ryujinx.HLE.FileSystem; -using Ryujinx.HLE.HOS.Services.Time.TimeZone; -using Ryujinx.UI.Common.Configuration; -using Ryujinx.UI.Common.Configuration.System; -using System; -using System.Collections.Generic; -using System.Collections.ObjectModel; -using System.Linq; -using System.Net.NetworkInformation; -using System.Runtime.InteropServices; -using System.Threading.Tasks; -using TimeZone = Ryujinx.Ava.UI.Models.TimeZone; - -namespace Ryujinx.Ava.UI.ViewModels -{ - public class SettingsViewModel : BaseModel - { - private readonly VirtualFileSystem _virtualFileSystem; - private readonly ContentManager _contentManager; - private TimeZoneContentManager _timeZoneContentManager; - - private readonly List<string> _validTzRegions; - - private readonly Dictionary<string, string> _networkInterfaces; - - private float _customResolutionScale; - private int _resolutionScale; - private int _graphicsBackendMultithreadingIndex; - private float _volume; - private bool _isVulkanAvailable = true; - private bool _directoryChanged; - private readonly List<string> _gpuIds = new(); - private KeyboardHotkeys _keyboardHotkeys; - private int _graphicsBackendIndex; - private int _scalingFilter; - private int _scalingFilterLevel; - - public event Action CloseWindow; - public event Action SaveSettingsEvent; - private int _networkInterfaceIndex; - private int _multiplayerModeIndex; - - public int ResolutionScale - { - get => _resolutionScale; - set - { - _resolutionScale = value; - - OnPropertyChanged(nameof(CustomResolutionScale)); - OnPropertyChanged(nameof(IsCustomResolutionScaleActive)); - } - } - - public int GraphicsBackendMultithreadingIndex - { - get => _graphicsBackendMultithreadingIndex; - set - { - _graphicsBackendMultithreadingIndex = value; - - if (_graphicsBackendMultithreadingIndex != (int)ConfigurationState.Instance.Graphics.BackendThreading.Value) - { - Dispatcher.UIThread.InvokeAsync(() => - ContentDialogHelper.CreateInfoDialog(LocaleManager.Instance[LocaleKeys.DialogSettingsBackendThreadingWarningMessage], - "", - "", - LocaleManager.Instance[LocaleKeys.InputDialogOk], - LocaleManager.Instance[LocaleKeys.DialogSettingsBackendThreadingWarningTitle]) - ); - } - - OnPropertyChanged(); - } - } - - public float CustomResolutionScale - { - get => _customResolutionScale; - set - { - _customResolutionScale = MathF.Round(value, 1); - - OnPropertyChanged(); - } - } - - public bool IsVulkanAvailable - { - get => _isVulkanAvailable; - set - { - _isVulkanAvailable = value; - - OnPropertyChanged(); - } - } - - public bool IsOpenGLAvailable => !OperatingSystem.IsMacOS(); - - public bool IsHypervisorAvailable => OperatingSystem.IsMacOS() && RuntimeInformation.ProcessArchitecture == Architecture.Arm64; - - public bool DirectoryChanged - { - get => _directoryChanged; - set - { - _directoryChanged = value; - - OnPropertyChanged(); - } - } - - public bool IsMacOS => OperatingSystem.IsMacOS(); - - public bool EnableDiscordIntegration { get; set; } - public bool CheckUpdatesOnStart { get; set; } - public bool ShowConfirmExit { get; set; } - public int HideCursor { get; set; } - public bool EnableDockedMode { get; set; } - public bool EnableKeyboard { get; set; } - public bool EnableMouse { get; set; } - public bool EnableVsync { get; set; } - public bool EnablePptc { get; set; } - public bool EnableInternetAccess { get; set; } - public bool EnableFsIntegrityChecks { get; set; } - public bool IgnoreMissingServices { get; set; } - public bool ExpandDramSize { get; set; } - public bool EnableShaderCache { get; set; } - public bool EnableTextureRecompression { get; set; } - public bool EnableMacroHLE { get; set; } - public bool EnableColorSpacePassthrough { get; set; } - public bool ColorSpacePassthroughAvailable => IsMacOS; - public bool EnableFileLog { get; set; } - public bool EnableStub { get; set; } - public bool EnableInfo { get; set; } - public bool EnableWarn { get; set; } - public bool EnableError { get; set; } - public bool EnableTrace { get; set; } - public bool EnableGuest { get; set; } - public bool EnableFsAccessLog { get; set; } - public bool EnableDebug { get; set; } - public bool IsOpenAlEnabled { get; set; } - public bool IsSoundIoEnabled { get; set; } - public bool IsSDL2Enabled { get; set; } - public bool IsCustomResolutionScaleActive => _resolutionScale == 4; - public bool IsScalingFilterActive => _scalingFilter == (int)Ryujinx.Common.Configuration.ScalingFilter.Fsr; - - public bool IsVulkanSelected => GraphicsBackendIndex == 0; - public bool UseHypervisor { get; set; } - - public string TimeZone { get; set; } - public string ShaderDumpPath { get; set; } - - public int Language { get; set; } - public int Region { get; set; } - public int FsGlobalAccessLogMode { get; set; } - public int AudioBackend { get; set; } - public int MaxAnisotropy { get; set; } - public int AspectRatio { get; set; } - public int AntiAliasingEffect { get; set; } - public string ScalingFilterLevelText => ScalingFilterLevel.ToString("0"); - public int ScalingFilterLevel - { - get => _scalingFilterLevel; - set - { - _scalingFilterLevel = value; - OnPropertyChanged(); - OnPropertyChanged(nameof(ScalingFilterLevelText)); - } - } - public int OpenglDebugLevel { get; set; } - public int MemoryMode { get; set; } - public int BaseStyleIndex { get; set; } - public int GraphicsBackendIndex - { - get => _graphicsBackendIndex; - set - { - _graphicsBackendIndex = value; - OnPropertyChanged(); - OnPropertyChanged(nameof(IsVulkanSelected)); - } - } - public int ScalingFilter - { - get => _scalingFilter; - set - { - _scalingFilter = value; - OnPropertyChanged(); - OnPropertyChanged(nameof(IsScalingFilterActive)); - } - } - - public int PreferredGpuIndex { get; set; } - - public float Volume - { - get => _volume; - set - { - _volume = value; - - ConfigurationState.Instance.System.AudioVolume.Value = _volume / 100; - - OnPropertyChanged(); - } - } - - public DateTimeOffset CurrentDate { get; set; } - public TimeSpan CurrentTime { get; set; } - - internal AvaloniaList<TimeZone> TimeZones { get; set; } - public AvaloniaList<string> GameDirectories { get; set; } - public ObservableCollection<ComboBoxItem> AvailableGpus { get; set; } - - public AvaloniaList<string> NetworkInterfaceList - { - get => new(_networkInterfaces.Keys); - } - - public AvaloniaList<string> MultiplayerModes - { - get => new(Enum.GetNames<MultiplayerMode>()); - } - - public KeyboardHotkeys KeyboardHotkeys - { - get => _keyboardHotkeys; - set - { - _keyboardHotkeys = value; - - OnPropertyChanged(); - } - } - - public int NetworkInterfaceIndex - { - get => _networkInterfaceIndex; - set - { - _networkInterfaceIndex = value != -1 ? value : 0; - ConfigurationState.Instance.Multiplayer.LanInterfaceId.Value = _networkInterfaces[NetworkInterfaceList[_networkInterfaceIndex]]; - } - } - - public int MultiplayerModeIndex - { - get => _multiplayerModeIndex; - set - { - _multiplayerModeIndex = value; - ConfigurationState.Instance.Multiplayer.Mode.Value = (MultiplayerMode)_multiplayerModeIndex; - } - } - - public SettingsViewModel(VirtualFileSystem virtualFileSystem, ContentManager contentManager) : this() - { - _virtualFileSystem = virtualFileSystem; - _contentManager = contentManager; - if (Program.PreviewerDetached) - { - Task.Run(LoadTimeZones); - } - } - - public SettingsViewModel() - { - GameDirectories = new AvaloniaList<string>(); - TimeZones = new AvaloniaList<TimeZone>(); - AvailableGpus = new ObservableCollection<ComboBoxItem>(); - _validTzRegions = new List<string>(); - _networkInterfaces = new Dictionary<string, string>(); - - Task.Run(CheckSoundBackends); - Task.Run(PopulateNetworkInterfaces); - - if (Program.PreviewerDetached) - { - Task.Run(LoadAvailableGpus); - LoadCurrentConfiguration(); - } - } - - public async Task CheckSoundBackends() - { - IsOpenAlEnabled = OpenALHardwareDeviceDriver.IsSupported; - IsSoundIoEnabled = SoundIoHardwareDeviceDriver.IsSupported; - IsSDL2Enabled = SDL2HardwareDeviceDriver.IsSupported; - - await Dispatcher.UIThread.InvokeAsync(() => - { - OnPropertyChanged(nameof(IsOpenAlEnabled)); - OnPropertyChanged(nameof(IsSoundIoEnabled)); - OnPropertyChanged(nameof(IsSDL2Enabled)); - }); - } - - private async Task LoadAvailableGpus() - { - AvailableGpus.Clear(); - - var devices = VulkanRenderer.GetPhysicalDevices(); - - if (devices.Length == 0) - { - IsVulkanAvailable = false; - GraphicsBackendIndex = 1; - } - else - { - foreach (var device in devices) - { - await Dispatcher.UIThread.InvokeAsync(() => - { - _gpuIds.Add(device.Id); - - AvailableGpus.Add(new ComboBoxItem { Content = $"{device.Name} {(device.IsDiscrete ? "(dGPU)" : "")}" }); - }); - } - } - - // GPU configuration needs to be loaded during the async method or it will always return 0. - PreferredGpuIndex = _gpuIds.Contains(ConfigurationState.Instance.Graphics.PreferredGpu) ? - _gpuIds.IndexOf(ConfigurationState.Instance.Graphics.PreferredGpu) : 0; - - Dispatcher.UIThread.Post(() => OnPropertyChanged(nameof(PreferredGpuIndex))); - } - - public async Task LoadTimeZones() - { - _timeZoneContentManager = new TimeZoneContentManager(); - - _timeZoneContentManager.InitializeInstance(_virtualFileSystem, _contentManager, IntegrityCheckLevel.None); - - foreach ((int offset, string location, string abbr) in _timeZoneContentManager.ParseTzOffsets()) - { - int hours = Math.DivRem(offset, 3600, out int seconds); - int minutes = Math.Abs(seconds) / 60; - - string abbr2 = abbr.StartsWith('+') || abbr.StartsWith('-') ? string.Empty : abbr; - - await Dispatcher.UIThread.InvokeAsync(() => - { - TimeZones.Add(new TimeZone($"UTC{hours:+0#;-0#;+00}:{minutes:D2}", location, abbr2)); - - _validTzRegions.Add(location); - }); - } - - Dispatcher.UIThread.Post(() => OnPropertyChanged(nameof(TimeZone))); - } - - private async Task PopulateNetworkInterfaces() - { - _networkInterfaces.Clear(); - _networkInterfaces.Add(LocaleManager.Instance[LocaleKeys.NetworkInterfaceDefault], "0"); - - foreach (NetworkInterface networkInterface in NetworkInterface.GetAllNetworkInterfaces()) - { - await Dispatcher.UIThread.InvokeAsync(() => - { - _networkInterfaces.Add(networkInterface.Name, networkInterface.Id); - }); - } - - // Network interface index needs to be loaded during the async method or it will always return 0. - NetworkInterfaceIndex = _networkInterfaces.Values.ToList().IndexOf(ConfigurationState.Instance.Multiplayer.LanInterfaceId.Value); - - Dispatcher.UIThread.Post(() => OnPropertyChanged(nameof(NetworkInterfaceIndex))); - } - - public void ValidateAndSetTimeZone(string location) - { - if (_validTzRegions.Contains(location)) - { - TimeZone = location; - } - } - - public void LoadCurrentConfiguration() - { - ConfigurationState config = ConfigurationState.Instance; - - // User Interface - EnableDiscordIntegration = config.EnableDiscordIntegration; - CheckUpdatesOnStart = config.CheckUpdatesOnStart; - ShowConfirmExit = config.ShowConfirmExit; - HideCursor = (int)config.HideCursor.Value; - - GameDirectories.Clear(); - GameDirectories.AddRange(config.UI.GameDirs.Value); - - BaseStyleIndex = config.UI.BaseStyle == "Light" ? 0 : 1; - - // Input - EnableDockedMode = config.System.EnableDockedMode; - EnableKeyboard = config.Hid.EnableKeyboard; - EnableMouse = config.Hid.EnableMouse; - - // Keyboard Hotkeys - KeyboardHotkeys = config.Hid.Hotkeys.Value; - - // System - Region = (int)config.System.Region.Value; - Language = (int)config.System.Language.Value; - TimeZone = config.System.TimeZone; - - DateTime currentDateTime = DateTime.Now; - - CurrentDate = currentDateTime.Date; - CurrentTime = currentDateTime.TimeOfDay.Add(TimeSpan.FromSeconds(config.System.SystemTimeOffset)); - - EnableVsync = config.Graphics.EnableVsync; - EnableFsIntegrityChecks = config.System.EnableFsIntegrityChecks; - ExpandDramSize = config.System.ExpandRam; - IgnoreMissingServices = config.System.IgnoreMissingServices; - - // CPU - EnablePptc = config.System.EnablePtc; - MemoryMode = (int)config.System.MemoryManagerMode.Value; - UseHypervisor = config.System.UseHypervisor; - - // Graphics - GraphicsBackendIndex = (int)config.Graphics.GraphicsBackend.Value; - // Physical devices are queried asynchronously hence the prefered index config value is loaded in LoadAvailableGpus(). - EnableShaderCache = config.Graphics.EnableShaderCache; - EnableTextureRecompression = config.Graphics.EnableTextureRecompression; - EnableMacroHLE = config.Graphics.EnableMacroHLE; - EnableColorSpacePassthrough = config.Graphics.EnableColorSpacePassthrough; - ResolutionScale = config.Graphics.ResScale == -1 ? 4 : config.Graphics.ResScale - 1; - CustomResolutionScale = config.Graphics.ResScaleCustom; - MaxAnisotropy = config.Graphics.MaxAnisotropy == -1 ? 0 : (int)(MathF.Log2(config.Graphics.MaxAnisotropy)); - AspectRatio = (int)config.Graphics.AspectRatio.Value; - GraphicsBackendMultithreadingIndex = (int)config.Graphics.BackendThreading.Value; - ShaderDumpPath = config.Graphics.ShadersDumpPath; - AntiAliasingEffect = (int)config.Graphics.AntiAliasing.Value; - ScalingFilter = (int)config.Graphics.ScalingFilter.Value; - ScalingFilterLevel = config.Graphics.ScalingFilterLevel.Value; - - // Audio - AudioBackend = (int)config.System.AudioBackend.Value; - Volume = config.System.AudioVolume * 100; - - // Network - EnableInternetAccess = config.System.EnableInternetAccess; - // LAN interface index is loaded asynchronously in PopulateNetworkInterfaces() - - // Logging - EnableFileLog = config.Logger.EnableFileLog; - EnableStub = config.Logger.EnableStub; - EnableInfo = config.Logger.EnableInfo; - EnableWarn = config.Logger.EnableWarn; - EnableError = config.Logger.EnableError; - EnableTrace = config.Logger.EnableTrace; - EnableGuest = config.Logger.EnableGuest; - EnableDebug = config.Logger.EnableDebug; - EnableFsAccessLog = config.Logger.EnableFsAccessLog; - FsGlobalAccessLogMode = config.System.FsGlobalAccessLogMode; - OpenglDebugLevel = (int)config.Logger.GraphicsDebugLevel.Value; - - MultiplayerModeIndex = (int)config.Multiplayer.Mode.Value; - } - - public void SaveSettings() - { - ConfigurationState config = ConfigurationState.Instance; - - // User Interface - config.EnableDiscordIntegration.Value = EnableDiscordIntegration; - config.CheckUpdatesOnStart.Value = CheckUpdatesOnStart; - config.ShowConfirmExit.Value = ShowConfirmExit; - config.HideCursor.Value = (HideCursorMode)HideCursor; - - if (_directoryChanged) - { - List<string> gameDirs = new(GameDirectories); - config.UI.GameDirs.Value = gameDirs; - } - - config.UI.BaseStyle.Value = BaseStyleIndex == 0 ? "Light" : "Dark"; - - // Input - config.System.EnableDockedMode.Value = EnableDockedMode; - config.Hid.EnableKeyboard.Value = EnableKeyboard; - config.Hid.EnableMouse.Value = EnableMouse; - - // Keyboard Hotkeys - config.Hid.Hotkeys.Value = KeyboardHotkeys; - - // System - config.System.Region.Value = (Region)Region; - config.System.Language.Value = (Language)Language; - - if (_validTzRegions.Contains(TimeZone)) - { - config.System.TimeZone.Value = TimeZone; - } - - config.System.SystemTimeOffset.Value = Convert.ToInt64((CurrentDate.ToUnixTimeSeconds() + CurrentTime.TotalSeconds) - DateTimeOffset.Now.ToUnixTimeSeconds()); - config.Graphics.EnableVsync.Value = EnableVsync; - config.System.EnableFsIntegrityChecks.Value = EnableFsIntegrityChecks; - config.System.ExpandRam.Value = ExpandDramSize; - config.System.IgnoreMissingServices.Value = IgnoreMissingServices; - - // CPU - config.System.EnablePtc.Value = EnablePptc; - config.System.MemoryManagerMode.Value = (MemoryManagerMode)MemoryMode; - config.System.UseHypervisor.Value = UseHypervisor; - - // Graphics - config.Graphics.GraphicsBackend.Value = (GraphicsBackend)GraphicsBackendIndex; - config.Graphics.PreferredGpu.Value = _gpuIds.ElementAtOrDefault(PreferredGpuIndex); - config.Graphics.EnableShaderCache.Value = EnableShaderCache; - config.Graphics.EnableTextureRecompression.Value = EnableTextureRecompression; - config.Graphics.EnableMacroHLE.Value = EnableMacroHLE; - config.Graphics.EnableColorSpacePassthrough.Value = EnableColorSpacePassthrough; - config.Graphics.ResScale.Value = ResolutionScale == 4 ? -1 : ResolutionScale + 1; - config.Graphics.ResScaleCustom.Value = CustomResolutionScale; - config.Graphics.MaxAnisotropy.Value = MaxAnisotropy == 0 ? -1 : MathF.Pow(2, MaxAnisotropy); - config.Graphics.AspectRatio.Value = (AspectRatio)AspectRatio; - config.Graphics.AntiAliasing.Value = (AntiAliasing)AntiAliasingEffect; - config.Graphics.ScalingFilter.Value = (ScalingFilter)ScalingFilter; - config.Graphics.ScalingFilterLevel.Value = ScalingFilterLevel; - - if (ConfigurationState.Instance.Graphics.BackendThreading != (BackendThreading)GraphicsBackendMultithreadingIndex) - { - DriverUtilities.ToggleOGLThreading(GraphicsBackendMultithreadingIndex == (int)BackendThreading.Off); - } - - config.Graphics.BackendThreading.Value = (BackendThreading)GraphicsBackendMultithreadingIndex; - config.Graphics.ShadersDumpPath.Value = ShaderDumpPath; - - // Audio - AudioBackend audioBackend = (AudioBackend)AudioBackend; - if (audioBackend != config.System.AudioBackend.Value) - { - config.System.AudioBackend.Value = audioBackend; - - Logger.Info?.Print(LogClass.Application, $"AudioBackend toggled to: {audioBackend}"); - } - - config.System.AudioVolume.Value = Volume / 100; - - // Network - config.System.EnableInternetAccess.Value = EnableInternetAccess; - - // Logging - config.Logger.EnableFileLog.Value = EnableFileLog; - config.Logger.EnableStub.Value = EnableStub; - config.Logger.EnableInfo.Value = EnableInfo; - config.Logger.EnableWarn.Value = EnableWarn; - config.Logger.EnableError.Value = EnableError; - config.Logger.EnableTrace.Value = EnableTrace; - config.Logger.EnableGuest.Value = EnableGuest; - config.Logger.EnableDebug.Value = EnableDebug; - config.Logger.EnableFsAccessLog.Value = EnableFsAccessLog; - config.System.FsGlobalAccessLogMode.Value = FsGlobalAccessLogMode; - config.Logger.GraphicsDebugLevel.Value = (GraphicsDebugLevel)OpenglDebugLevel; - - config.Multiplayer.LanInterfaceId.Value = _networkInterfaces[NetworkInterfaceList[NetworkInterfaceIndex]]; - config.Multiplayer.Mode.Value = (MultiplayerMode)MultiplayerModeIndex; - - config.ToFileFormat().SaveConfig(Program.ConfigurationPath); - - MainWindow.UpdateGraphicsConfig(); - - SaveSettingsEvent?.Invoke(); - - _directoryChanged = false; - } - - private static void RevertIfNotSaved() - { - Program.ReloadConfig(); - } - - public void ApplyButton() - { - SaveSettings(); - } - - public void OkButton() - { - SaveSettings(); - CloseWindow?.Invoke(); - } - - public void CancelButton() - { - RevertIfNotSaved(); - CloseWindow?.Invoke(); - } - } -} diff --git a/src/Ryujinx.Ava/UI/ViewModels/TitleUpdateViewModel.cs b/src/Ryujinx.Ava/UI/ViewModels/TitleUpdateViewModel.cs deleted file mode 100644 index 5989ce09..00000000 --- a/src/Ryujinx.Ava/UI/ViewModels/TitleUpdateViewModel.cs +++ /dev/null @@ -1,249 +0,0 @@ -using Avalonia; -using Avalonia.Collections; -using Avalonia.Controls.ApplicationLifetimes; -using Avalonia.Platform.Storage; -using Avalonia.Threading; -using LibHac.Common; -using LibHac.Fs; -using LibHac.Fs.Fsa; -using LibHac.FsSystem; -using LibHac.Ns; -using LibHac.Tools.FsSystem; -using LibHac.Tools.FsSystem.NcaUtils; -using Ryujinx.Ava.Common.Locale; -using Ryujinx.Ava.UI.Helpers; -using Ryujinx.Ava.UI.Models; -using Ryujinx.Common.Configuration; -using Ryujinx.Common.Logging; -using Ryujinx.Common.Utilities; -using Ryujinx.HLE.FileSystem; -using Ryujinx.UI.App.Common; -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Threading.Tasks; -using Path = System.IO.Path; -using SpanHelpers = LibHac.Common.SpanHelpers; - -namespace Ryujinx.Ava.UI.ViewModels -{ - public class TitleUpdateViewModel : BaseModel - { - public TitleUpdateMetadata TitleUpdateWindowData; - public readonly string TitleUpdateJsonPath; - private VirtualFileSystem VirtualFileSystem { get; } - private ulong TitleId { get; } - - private AvaloniaList<TitleUpdateModel> _titleUpdates = new(); - private AvaloniaList<object> _views = new(); - private object _selectedUpdate; - - private static readonly TitleUpdateMetadataJsonSerializerContext _serializerContext = new(JsonHelper.GetDefaultSerializerOptions()); - - public AvaloniaList<TitleUpdateModel> TitleUpdates - { - get => _titleUpdates; - set - { - _titleUpdates = value; - OnPropertyChanged(); - } - } - - public AvaloniaList<object> Views - { - get => _views; - set - { - _views = value; - OnPropertyChanged(); - } - } - - public object SelectedUpdate - { - get => _selectedUpdate; - set - { - _selectedUpdate = value; - OnPropertyChanged(); - } - } - - public IStorageProvider StorageProvider; - - public TitleUpdateViewModel(VirtualFileSystem virtualFileSystem, ulong titleId) - { - VirtualFileSystem = virtualFileSystem; - - TitleId = titleId; - - if (Application.Current.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop) - { - StorageProvider = desktop.MainWindow.StorageProvider; - } - - TitleUpdateJsonPath = Path.Combine(AppDataManager.GamesDirPath, titleId.ToString("x16"), "updates.json"); - - try - { - TitleUpdateWindowData = JsonHelper.DeserializeFromFile(TitleUpdateJsonPath, _serializerContext.TitleUpdateMetadata); - } - catch - { - Logger.Warning?.Print(LogClass.Application, $"Failed to deserialize title update data for {TitleId} at {TitleUpdateJsonPath}"); - - TitleUpdateWindowData = new TitleUpdateMetadata - { - Selected = "", - Paths = new List<string>(), - }; - - Save(); - } - - LoadUpdates(); - } - - private void LoadUpdates() - { - foreach (string path in TitleUpdateWindowData.Paths) - { - AddUpdate(path); - } - - TitleUpdateModel selected = TitleUpdates.FirstOrDefault(x => x.Path == TitleUpdateWindowData.Selected, null); - - SelectedUpdate = selected; - - // NOTE: Save the list again to remove leftovers. - Save(); - SortUpdates(); - } - - public void SortUpdates() - { - var list = TitleUpdates.ToList(); - - list.Sort((first, second) => - { - if (string.IsNullOrEmpty(first.Control.DisplayVersionString.ToString())) - { - return -1; - } - - if (string.IsNullOrEmpty(second.Control.DisplayVersionString.ToString())) - { - return 1; - } - - return Version.Parse(first.Control.DisplayVersionString.ToString()).CompareTo(Version.Parse(second.Control.DisplayVersionString.ToString())) * -1; - }); - - Views.Clear(); - Views.Add(new BaseModel()); - Views.AddRange(list); - - if (SelectedUpdate == null) - { - SelectedUpdate = Views[0]; - } - else if (!TitleUpdates.Contains(SelectedUpdate)) - { - if (Views.Count > 1) - { - SelectedUpdate = Views[1]; - } - else - { - SelectedUpdate = Views[0]; - } - } - } - - private void AddUpdate(string path) - { - if (File.Exists(path) && TitleUpdates.All(x => x.Path != path)) - { - using FileStream file = new(path, FileMode.Open, FileAccess.Read); - - try - { - var pfs = new PartitionFileSystem(); - pfs.Initialize(file.AsStorage()).ThrowIfFailure(); - (Nca patchNca, Nca controlNca) = ApplicationLibrary.GetGameUpdateDataFromPartition(VirtualFileSystem, pfs, TitleId.ToString("x16"), 0); - - if (controlNca != null && patchNca != null) - { - ApplicationControlProperty controlData = new(); - - using UniqueRef<IFile> nacpFile = new(); - - controlNca.OpenFileSystem(NcaSectionType.Data, IntegrityCheckLevel.None).OpenFile(ref nacpFile.Ref, "/control.nacp".ToU8Span(), OpenMode.Read).ThrowIfFailure(); - nacpFile.Get.Read(out _, 0, SpanHelpers.AsByteSpan(ref controlData), ReadOption.None).ThrowIfFailure(); - - TitleUpdates.Add(new TitleUpdateModel(controlData, path)); - } - else - { - Dispatcher.UIThread.InvokeAsync(() => ContentDialogHelper.CreateErrorDialog(LocaleManager.Instance[LocaleKeys.DialogUpdateAddUpdateErrorMessage])); - } - } - catch (Exception ex) - { - Dispatcher.UIThread.InvokeAsync(() => ContentDialogHelper.CreateErrorDialog(LocaleManager.Instance.UpdateAndGetDynamicValue(LocaleKeys.DialogLoadFileErrorMessage, ex.Message, path))); - } - } - } - - public void RemoveUpdate(TitleUpdateModel update) - { - TitleUpdates.Remove(update); - - SortUpdates(); - } - - public async Task Add() - { - var result = await StorageProvider.OpenFilePickerAsync(new FilePickerOpenOptions - { - AllowMultiple = true, - FileTypeFilter = new List<FilePickerFileType> - { - new(LocaleManager.Instance[LocaleKeys.AllSupportedFormats]) - { - Patterns = new[] { "*.nsp" }, - AppleUniformTypeIdentifiers = new[] { "com.ryujinx.nsp" }, - MimeTypes = new[] { "application/x-nx-nsp" }, - }, - }, - }); - - foreach (var file in result) - { - AddUpdate(file.Path.LocalPath); - } - - SortUpdates(); - } - - public void Save() - { - TitleUpdateWindowData.Paths.Clear(); - TitleUpdateWindowData.Selected = ""; - - foreach (TitleUpdateModel update in TitleUpdates) - { - TitleUpdateWindowData.Paths.Add(update.Path); - - if (update == SelectedUpdate) - { - TitleUpdateWindowData.Selected = update.Path; - } - } - - JsonHelper.SerializeToFile(TitleUpdateJsonPath, TitleUpdateWindowData, _serializerContext.TitleUpdateMetadata); - } - } -} diff --git a/src/Ryujinx.Ava/UI/ViewModels/UserFirmwareAvatarSelectorViewModel.cs b/src/Ryujinx.Ava/UI/ViewModels/UserFirmwareAvatarSelectorViewModel.cs deleted file mode 100644 index 89b59122..00000000 --- a/src/Ryujinx.Ava/UI/ViewModels/UserFirmwareAvatarSelectorViewModel.cs +++ /dev/null @@ -1,222 +0,0 @@ -using Avalonia.Media; -using LibHac.Common; -using LibHac.Fs; -using LibHac.Fs.Fsa; -using LibHac.FsSystem; -using LibHac.Ncm; -using LibHac.Tools.Fs; -using LibHac.Tools.FsSystem; -using LibHac.Tools.FsSystem.NcaUtils; -using Ryujinx.Ava.UI.Models; -using Ryujinx.HLE.FileSystem; -using SixLabors.ImageSharp; -using SixLabors.ImageSharp.PixelFormats; -using System; -using System.Buffers.Binary; -using System.Collections.Generic; -using System.Collections.ObjectModel; -using System.IO; -using Color = Avalonia.Media.Color; - -namespace Ryujinx.Ava.UI.ViewModels -{ - internal class UserFirmwareAvatarSelectorViewModel : BaseModel - { - private static readonly Dictionary<string, byte[]> _avatarStore = new(); - - private ObservableCollection<ProfileImageModel> _images; - private Color _backgroundColor = Colors.White; - - private int _selectedIndex; - - public UserFirmwareAvatarSelectorViewModel() - { - _images = new ObservableCollection<ProfileImageModel>(); - - LoadImagesFromStore(); - } - - public Color BackgroundColor - { - get => _backgroundColor; - set - { - _backgroundColor = value; - OnPropertyChanged(); - ChangeImageBackground(); - } - } - - public ObservableCollection<ProfileImageModel> Images - { - get => _images; - set - { - _images = value; - OnPropertyChanged(); - } - } - - public int SelectedIndex - { - get => _selectedIndex; - set - { - _selectedIndex = value; - - if (_selectedIndex == -1) - { - SelectedImage = null; - } - else - { - SelectedImage = _images[_selectedIndex].Data; - } - - OnPropertyChanged(); - } - } - - public byte[] SelectedImage { get; private set; } - - private void LoadImagesFromStore() - { - Images.Clear(); - - foreach (var image in _avatarStore) - { - Images.Add(new ProfileImageModel(image.Key, image.Value)); - } - } - - private void ChangeImageBackground() - { - foreach (var image in Images) - { - image.BackgroundColor = new SolidColorBrush(BackgroundColor); - } - } - - public static void PreloadAvatars(ContentManager contentManager, VirtualFileSystem virtualFileSystem) - { - if (_avatarStore.Count > 0) - { - return; - } - - string contentPath = contentManager.GetInstalledContentPath(0x010000000000080A, StorageId.BuiltInSystem, NcaContentType.Data); - string avatarPath = VirtualFileSystem.SwitchPathToSystemPath(contentPath); - - if (!string.IsNullOrWhiteSpace(avatarPath)) - { - using IStorage ncaFileStream = new LocalStorage(avatarPath, FileAccess.Read, FileMode.Open); - - Nca nca = new(virtualFileSystem.KeySet, ncaFileStream); - IFileSystem romfs = nca.OpenFileSystem(NcaSectionType.Data, IntegrityCheckLevel.ErrorOnInvalid); - - foreach (DirectoryEntryEx item in romfs.EnumerateEntries()) - { - // TODO: Parse DatabaseInfo.bin and table.bin files for more accuracy. - if (item.Type == DirectoryEntryType.File && item.FullPath.Contains("chara") && item.FullPath.Contains("szs")) - { - using var file = new UniqueRef<IFile>(); - - romfs.OpenFile(ref file.Ref, ("/" + item.FullPath).ToU8Span(), OpenMode.Read).ThrowIfFailure(); - - using MemoryStream stream = new(); - using MemoryStream streamPng = new(); - - file.Get.AsStream().CopyTo(stream); - - stream.Position = 0; - - Image avatarImage = Image.LoadPixelData<Rgba32>(DecompressYaz0(stream), 256, 256); - - avatarImage.SaveAsPng(streamPng); - - _avatarStore.Add(item.FullPath, streamPng.ToArray()); - } - } - } - } - - private static byte[] DecompressYaz0(Stream stream) - { - using BinaryReader reader = new(stream); - - reader.ReadInt32(); // Magic - - uint decodedLength = BinaryPrimitives.ReverseEndianness(reader.ReadUInt32()); - - reader.ReadInt64(); // Padding - - byte[] input = new byte[stream.Length - stream.Position]; - stream.Read(input, 0, input.Length); - - uint inputOffset = 0; - - byte[] output = new byte[decodedLength]; - uint outputOffset = 0; - - ushort mask = 0; - byte header = 0; - - while (outputOffset < decodedLength) - { - if ((mask >>= 1) == 0) - { - header = input[inputOffset++]; - mask = 0x80; - } - - if ((header & mask) != 0) - { - if (outputOffset == output.Length) - { - break; - } - - output[outputOffset++] = input[inputOffset++]; - } - else - { - byte byte1 = input[inputOffset++]; - byte byte2 = input[inputOffset++]; - - uint dist = (uint)((byte1 & 0xF) << 8) | byte2; - uint position = outputOffset - (dist + 1); - - uint length = (uint)byte1 >> 4; - if (length == 0) - { - length = (uint)input[inputOffset++] + 0x12; - } - else - { - length += 2; - } - - uint gap = outputOffset - position; - uint nonOverlappingLength = length; - - if (nonOverlappingLength > gap) - { - nonOverlappingLength = gap; - } - - Buffer.BlockCopy(output, (int)position, output, (int)outputOffset, (int)nonOverlappingLength); - outputOffset += nonOverlappingLength; - position += nonOverlappingLength; - length -= nonOverlappingLength; - - while (length-- > 0) - { - output[outputOffset++] = output[position++]; - } - } - } - - return output; - } - } -} diff --git a/src/Ryujinx.Ava/UI/ViewModels/UserProfileImageSelectorViewModel.cs b/src/Ryujinx.Ava/UI/ViewModels/UserProfileImageSelectorViewModel.cs deleted file mode 100644 index 8e7d41a5..00000000 --- a/src/Ryujinx.Ava/UI/ViewModels/UserProfileImageSelectorViewModel.cs +++ /dev/null @@ -1,18 +0,0 @@ -namespace Ryujinx.Ava.UI.ViewModels -{ - internal class UserProfileImageSelectorViewModel : BaseModel - { - private bool _firmwareFound; - - public bool FirmwareFound - { - get => _firmwareFound; - - set - { - _firmwareFound = value; - OnPropertyChanged(); - } - } - } -} diff --git a/src/Ryujinx.Ava/UI/ViewModels/UserProfileViewModel.cs b/src/Ryujinx.Ava/UI/ViewModels/UserProfileViewModel.cs deleted file mode 100644 index 70274847..00000000 --- a/src/Ryujinx.Ava/UI/ViewModels/UserProfileViewModel.cs +++ /dev/null @@ -1,28 +0,0 @@ -using Microsoft.IdentityModel.Tokens; -using Ryujinx.Ava.UI.Models; -using System; -using System.Collections.ObjectModel; - -namespace Ryujinx.Ava.UI.ViewModels -{ - public class UserProfileViewModel : BaseModel, IDisposable - { - public UserProfileViewModel() - { - Profiles = new ObservableCollection<BaseModel>(); - LostProfiles = new ObservableCollection<UserProfile>(); - IsEmpty = LostProfiles.IsNullOrEmpty(); - } - - public ObservableCollection<BaseModel> Profiles { get; set; } - - public ObservableCollection<UserProfile> LostProfiles { get; set; } - - public bool IsEmpty { get; set; } - - public void Dispose() - { - GC.SuppressFinalize(this); - } - } -} diff --git a/src/Ryujinx.Ava/UI/ViewModels/UserSaveManagerViewModel.cs b/src/Ryujinx.Ava/UI/ViewModels/UserSaveManagerViewModel.cs deleted file mode 100644 index 85adef00..00000000 --- a/src/Ryujinx.Ava/UI/ViewModels/UserSaveManagerViewModel.cs +++ /dev/null @@ -1,117 +0,0 @@ -using DynamicData; -using DynamicData.Binding; -using Ryujinx.Ava.Common.Locale; -using Ryujinx.Ava.UI.Models; -using Ryujinx.HLE.HOS.Services.Account.Acc; -using System.Collections.Generic; -using System.Collections.ObjectModel; - -namespace Ryujinx.Ava.UI.ViewModels -{ - public class UserSaveManagerViewModel : BaseModel - { - private int _sortIndex; - private int _orderIndex; - private string _search; - private ObservableCollection<SaveModel> _saves = new(); - private ObservableCollection<SaveModel> _views = new(); - private readonly AccountManager _accountManager; - - public string SaveManagerHeading => LocaleManager.Instance.UpdateAndGetDynamicValue(LocaleKeys.SaveManagerHeading, _accountManager.LastOpenedUser.Name, _accountManager.LastOpenedUser.UserId); - - public int SortIndex - { - get => _sortIndex; - set - { - _sortIndex = value; - OnPropertyChanged(); - Sort(); - } - } - - public int OrderIndex - { - get => _orderIndex; - set - { - _orderIndex = value; - OnPropertyChanged(); - Sort(); - } - } - - public string Search - { - get => _search; - set - { - _search = value; - OnPropertyChanged(); - Sort(); - } - } - - public ObservableCollection<SaveModel> Saves - { - get => _saves; - set - { - _saves = value; - OnPropertyChanged(); - Sort(); - } - } - - public ObservableCollection<SaveModel> Views - { - get => _views; - set - { - _views = value; - OnPropertyChanged(); - } - } - - public UserSaveManagerViewModel(AccountManager accountManager) - { - _accountManager = accountManager; - } - - public void Sort() - { - Saves.AsObservableChangeSet() - .Filter(Filter) - .Sort(GetComparer()) - .Bind(out var view).AsObservableList(); - - _views.Clear(); - _views.AddRange(view); - OnPropertyChanged(nameof(Views)); - } - - private bool Filter(object arg) - { - if (arg is SaveModel save) - { - return string.IsNullOrWhiteSpace(_search) || save.Title.ToLower().Contains(_search.ToLower()); - } - - return false; - } - - private IComparer<SaveModel> GetComparer() - { - return SortIndex switch - { - 0 => OrderIndex == 0 - ? SortExpressionComparer<SaveModel>.Ascending(save => save.Title) - : SortExpressionComparer<SaveModel>.Descending(save => save.Title), - 1 => OrderIndex == 0 - ? SortExpressionComparer<SaveModel>.Ascending(save => save.Size) - : SortExpressionComparer<SaveModel>.Descending(save => save.Size), - _ => null, - }; - } - } -} diff --git a/src/Ryujinx.Ava/UI/Views/Input/ControllerInputView.axaml b/src/Ryujinx.Ava/UI/Views/Input/ControllerInputView.axaml deleted file mode 100644 index 99f2b6b6..00000000 --- a/src/Ryujinx.Ava/UI/Views/Input/ControllerInputView.axaml +++ /dev/null @@ -1,1130 +0,0 @@ -<UserControl - xmlns="https://github.com/avaloniaui" - xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" - xmlns:ui="clr-namespace:FluentAvalonia.UI.Controls;assembly=FluentAvalonia" - xmlns:locale="clr-namespace:Ryujinx.Ava.Common.Locale" - xmlns:d="http://schemas.microsoft.com/expression/blend/2008" - xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" - xmlns:controls="clr-namespace:Ryujinx.Ava.UI.Controls" - xmlns:models="clr-namespace:Ryujinx.Ava.UI.Models" - xmlns:viewModels="clr-namespace:Ryujinx.Ava.UI.ViewModels" - xmlns:helpers="clr-namespace:Ryujinx.Ava.UI.Helpers" - HorizontalAlignment="Stretch" - VerticalAlignment="Stretch" - d:DesignHeight="800" - d:DesignWidth="800" - x:Class="Ryujinx.Ava.UI.Views.Input.ControllerInputView" - x:DataType="viewModels:ControllerInputViewModel" - mc:Ignorable="d" - Focusable="True"> - <Design.DataContext> - <viewModels:ControllerInputViewModel /> - </Design.DataContext> - <UserControl.Resources> - <helpers:KeyValueConverter x:Key="Key" /> - </UserControl.Resources> - <UserControl.Styles> - <Style Selector="ToggleButton"> - <Setter Property="Width" Value="90" /> - <Setter Property="Height" Value="27" /> - <Setter Property="HorizontalAlignment" Value="Stretch" /> - </Style> - </UserControl.Styles> - <StackPanel - HorizontalAlignment="Stretch" - VerticalAlignment="Stretch" - Orientation="Vertical"> - <StackPanel - Margin="0 0 0 5" - Orientation="Vertical" - Spacing="5"> - <Grid> - <Grid.ColumnDefinitions> - <ColumnDefinition Width="*" /> - <ColumnDefinition Width="10" /> - <ColumnDefinition Width="*" /> - </Grid.ColumnDefinitions> - <!-- Player Selection --> - <Grid - Grid.Column="0" - Margin="2" - HorizontalAlignment="Stretch" - VerticalAlignment="Center"> - <Grid.ColumnDefinitions> - <ColumnDefinition Width="Auto"/> - <ColumnDefinition Width="*" /> - </Grid.ColumnDefinitions> - <TextBlock - Margin="5,0,10,0" - Width="90" - HorizontalAlignment="Left" - VerticalAlignment="Center" - Text="{locale:Locale ControllerSettingsPlayer}" /> - <ComboBox - Grid.Column="1" - Name="PlayerIndexBox" - HorizontalAlignment="Stretch" - VerticalAlignment="Center" - SelectionChanged="PlayerIndexBox_OnSelectionChanged" - ItemsSource="{Binding PlayerIndexes}" - SelectedIndex="{Binding PlayerId}"> - <ComboBox.ItemTemplate> - <DataTemplate> - <TextBlock Text="{Binding Name}" /> - </DataTemplate> - </ComboBox.ItemTemplate> - </ComboBox> - </Grid> - <!-- Profile Selection --> - <Grid - Grid.Column="2" - Margin="2" - HorizontalAlignment="Stretch" - VerticalAlignment="Center"> - <Grid.ColumnDefinitions> - <ColumnDefinition Width="Auto"/> - <ColumnDefinition Width="*" /> - <ColumnDefinition Width="Auto"/> - <ColumnDefinition Width="Auto"/> - <ColumnDefinition Width="Auto"/> - </Grid.ColumnDefinitions> - <TextBlock - Margin="5,0,10,0" - Width="90" - HorizontalAlignment="Left" - VerticalAlignment="Center" - Text="{locale:Locale ControllerSettingsProfile}" /> - <ui:FAComboBox - Grid.Column="1" - IsEditable="True" - Name="ProfileBox" - HorizontalAlignment="Stretch" - VerticalAlignment="Center" - SelectedIndex="0" - ItemsSource="{Binding ProfilesList}" - Text="{Binding ProfileName, Mode=TwoWay}" /> - <Button - Grid.Column="2" - MinWidth="0" - Margin="5,0,0,0" - VerticalAlignment="Center" - ToolTip.Tip="{locale:Locale ControllerSettingsLoadProfileToolTip}" - Command="{ReflectionBinding LoadProfile}"> - <ui:SymbolIcon - Symbol="Upload" - FontSize="15" - Height="20" /> - </Button> - <Button - Grid.Column="3" - MinWidth="0" - Margin="5,0,0,0" - VerticalAlignment="Center" - ToolTip.Tip="{locale:Locale ControllerSettingsSaveProfileToolTip}" - Command="{ReflectionBinding SaveProfile}"> - <ui:SymbolIcon - Symbol="Save" - FontSize="15" - Height="20" /> - </Button> - <Button - Grid.Column="4" - MinWidth="0" - Margin="5,0,0,0" - VerticalAlignment="Center" - ToolTip.Tip="{locale:Locale ControllerSettingsRemoveProfileToolTip}" - Command="{ReflectionBinding RemoveProfile}"> - <ui:SymbolIcon - Symbol="Delete" - FontSize="15" - Height="20" /> - </Button> - </Grid> - </Grid> - <Separator /> - <Grid> - <Grid.ColumnDefinitions> - <ColumnDefinition Width="*" /> - <ColumnDefinition Width="10" /> - <ColumnDefinition Width="*" /> - </Grid.ColumnDefinitions> - <!-- Input Device --> - <Grid - Grid.Column="0" - Margin="2" - HorizontalAlignment="Stretch"> - <Grid.ColumnDefinitions> - <ColumnDefinition Width="Auto"/> - <ColumnDefinition Width="*"/> - <ColumnDefinition Width="Auto" /> - </Grid.ColumnDefinitions> - <TextBlock - Grid.Column="0" - Margin="5,0,10,0" - Width="90" - HorizontalAlignment="Left" - VerticalAlignment="Center" - Text="{locale:Locale ControllerSettingsInputDevice}" /> - <ComboBox - Grid.Column="1" - Name="DeviceBox" - HorizontalAlignment="Stretch" - VerticalAlignment="Center" - ItemsSource="{Binding DeviceList}" - SelectedIndex="{Binding Device}" /> - <Button - Grid.Column="2" - MinWidth="0" - Margin="5,0,0,0" - VerticalAlignment="Center" - Command="{ReflectionBinding LoadDevices}"> - <ui:SymbolIcon - Symbol="Refresh" - FontSize="15" - Height="20"/> - </Button> - </Grid> - <!-- Controller Type --> - <Grid - Grid.Column="2" - Margin="2" - HorizontalAlignment="Stretch" - VerticalAlignment="Center"> - <Grid.ColumnDefinitions> - <ColumnDefinition Width="Auto"/> - <ColumnDefinition Width="*" /> - </Grid.ColumnDefinitions> - <TextBlock - Margin="5,0,10,0" - Width="90" - HorizontalAlignment="Left" - VerticalAlignment="Center" - Text="{locale:Locale ControllerSettingsControllerType}" /> - <ComboBox - Grid.Column="1" - HorizontalAlignment="Stretch" - ItemsSource="{Binding Controllers}" - SelectedIndex="{Binding Controller}"> - <ComboBox.ItemTemplate> - <DataTemplate DataType="models:ControllerModel"> - <TextBlock Text="{Binding Name}" /> - </DataTemplate> - </ComboBox.ItemTemplate> - </ComboBox> - </Grid> - </Grid> - </StackPanel> - <!-- Button / JoyStick Settings --> - <Grid - Name="SettingButtons" - MinHeight="450" - FlowDirection="LeftToRight" - IsVisible="{Binding ShowSettings}"> - <Grid.ColumnDefinitions> - <ColumnDefinition Width="Auto" /> - <ColumnDefinition Width="*" /> - <ColumnDefinition Width="Auto" /> - </Grid.ColumnDefinitions> - <!-- Left Controls --> - <StackPanel - Orientation="Vertical" - Margin="0,0,5,0" - Grid.Column="0"> - <!-- Left Triggers --> - <Border - BorderBrush="{DynamicResource ThemeControlBorderColor}" - BorderThickness="1" - IsVisible="{Binding IsLeft}" - MinHeight="90" - CornerRadius="5"> - <Grid - Margin="10" - HorizontalAlignment="Stretch"> - <Grid.ColumnDefinitions> - <ColumnDefinition /> - <ColumnDefinition /> - </Grid.ColumnDefinitions> - <Grid.RowDefinitions> - <RowDefinition /> - <RowDefinition /> - </Grid.RowDefinitions> - <StackPanel - Grid.Column="0" - Grid.Row="0" - Orientation="Horizontal"> - <TextBlock - Width="20" - HorizontalAlignment="Center" - VerticalAlignment="Center" - Text="{locale:Locale ControllerSettingsTriggerZL}" - TextAlignment="Center" /> - <ToggleButton> - <TextBlock - Text="{ReflectionBinding Configuration.ButtonZl, Mode=TwoWay, Converter={StaticResource Key}}" - TextAlignment="Center" /> - </ToggleButton> - </StackPanel> - <StackPanel - Grid.Column="0" - Grid.Row="1" - Orientation="Horizontal"> - <TextBlock - Width="20" - HorizontalAlignment="Center" - VerticalAlignment="Center" - Text="{locale:Locale ControllerSettingsTriggerL}" - TextAlignment="Center" /> - <ToggleButton> - <TextBlock - Text="{ReflectionBinding Configuration.ButtonL, Mode=TwoWay, Converter={StaticResource Key}}" - TextAlignment="Center" /> - </ToggleButton> - </StackPanel> - <StackPanel - Grid.Column="1" - Grid.Row="1" - Orientation="Horizontal"> - <TextBlock - Width="20" - HorizontalAlignment="Center" - VerticalAlignment="Center" - Text="{locale:Locale ControllerSettingsButtonMinus}" - TextAlignment="Center" /> - <ToggleButton> - <TextBlock - Text="{ReflectionBinding Configuration.ButtonMinus, Mode=TwoWay, Converter={StaticResource Key}}" - TextAlignment="Center" /> - </ToggleButton> - </StackPanel> - </Grid> - </Border> - <!-- Left Joystick --> - <Border - BorderBrush="{DynamicResource ThemeControlBorderColor}" - BorderThickness="1" - IsVisible="{Binding IsLeft}" - Margin="0,5,0,0" - CornerRadius="5"> - <StackPanel - Margin="10" - Orientation="Vertical"> - <TextBlock - Margin="0,0,0,10" - HorizontalAlignment="Center" - Text="{locale:Locale ControllerSettingsLStick}" /> - <!-- Left Joystick Keyboard --> - <StackPanel - IsVisible="{Binding !IsController}" - Orientation="Vertical"> - <!-- Left Joystick Button --> - <StackPanel - Margin="0,0,0,4" - Orientation="Horizontal"> - <TextBlock - Margin="0,0,10,0" - Width="120" - HorizontalAlignment="Center" - VerticalAlignment="Center" - Text="{locale:Locale ControllerSettingsStickButton}" - TextAlignment="Center" /> - <ToggleButton> - <TextBlock - Text="{ReflectionBinding Configuration.LeftKeyboardStickButton, Mode=TwoWay, Converter={StaticResource Key}}" - TextAlignment="Center" /> - </ToggleButton> - </StackPanel> - <!-- Left Joystick Up --> - <StackPanel - Margin="0,0,0,4" - Orientation="Horizontal"> - <TextBlock - Margin="0,0,10,0" - Width="120" - HorizontalAlignment="Center" - VerticalAlignment="Center" - Text="{locale:Locale ControllerSettingsStickUp}" - TextAlignment="Center" /> - <ToggleButton> - <TextBlock - Text="{ReflectionBinding Configuration.LeftStickUp, Mode=TwoWay, Converter={StaticResource Key}}" - TextAlignment="Center" /> - </ToggleButton> - </StackPanel> - <!-- Left Joystick Down --> - <StackPanel - Margin="0,0,0,4" - Orientation="Horizontal"> - <TextBlock - Margin="0,0,10,0" - Width="120" - HorizontalAlignment="Center" - VerticalAlignment="Center" - Text="{locale:Locale ControllerSettingsStickDown}" - TextAlignment="Center" /> - <ToggleButton> - <TextBlock - Text="{ReflectionBinding Configuration.LeftStickDown, Mode=TwoWay, Converter={StaticResource Key}}" - TextAlignment="Center" /> - </ToggleButton> - </StackPanel> - <!-- Left Joystick Left --> - <StackPanel - Margin="0,0,0,4" - Orientation="Horizontal"> - <TextBlock - Margin="0,0,10,0" - Width="120" - HorizontalAlignment="Center" - VerticalAlignment="Center" - Text="{locale:Locale ControllerSettingsStickLeft}" - TextAlignment="Center" /> - <ToggleButton> - <TextBlock - Text="{ReflectionBinding Configuration.LeftStickLeft, Mode=TwoWay, Converter={StaticResource Key}}" - TextAlignment="Center" /> - </ToggleButton> - </StackPanel> - <!-- Left Joystick Right --> - <StackPanel - Margin="0,0,0,4" - Orientation="Horizontal"> - <TextBlock - Margin="0,0,10,0" - Width="120" - HorizontalAlignment="Center" - VerticalAlignment="Center" - Text="{locale:Locale ControllerSettingsStickRight}" - TextAlignment="Center" /> - <ToggleButton> - <TextBlock - Text="{ReflectionBinding Configuration.LeftStickRight, Mode=TwoWay, Converter={StaticResource Key}}" - TextAlignment="Center" /> - </ToggleButton> - </StackPanel> - </StackPanel> - <!-- Left Joystick Controller --> - <StackPanel - IsVisible="{Binding IsController}" - Orientation="Vertical"> - <!-- Left Joystick Button --> - <StackPanel - Orientation="Horizontal"> - <TextBlock - Margin="0,0,10,0" - Width="120" - HorizontalAlignment="Center" - VerticalAlignment="Center" - Text="{locale:Locale ControllerSettingsStickButton}" - TextAlignment="Center" /> - <ToggleButton> - <TextBlock - Text="{ReflectionBinding Configuration.LeftControllerStickButton, Mode=TwoWay, Converter={StaticResource Key}}" - TextAlignment="Center" /> - </ToggleButton> - </StackPanel> - <!-- Left Joystick Stick --> - <StackPanel - Margin="0,4,0,4" - Orientation="Horizontal"> - <TextBlock - Margin="0,0,10,0" - Width="120" - HorizontalAlignment="Center" - VerticalAlignment="Center" - Text="{locale:Locale ControllerSettingsStickStick}" - TextAlignment="Center" /> - <ToggleButton Tag="stick"> - <TextBlock - Text="{ReflectionBinding Configuration.LeftJoystick, Mode=TwoWay, Converter={StaticResource Key}}" - TextAlignment="Center" /> - </ToggleButton> - </StackPanel> - <Separator - Margin="0,8,0,8" - Height="1" /> - <CheckBox IsChecked="{ReflectionBinding Configuration.LeftInvertStickX}"> - <TextBlock Text="{locale:Locale ControllerSettingsStickInvertXAxis}" /> - </CheckBox> - <CheckBox IsChecked="{ReflectionBinding Configuration.LeftInvertStickY}"> - <TextBlock Text="{locale:Locale ControllerSettingsStickInvertYAxis}" /> - </CheckBox> - <CheckBox IsChecked="{ReflectionBinding Configuration.LeftRotate90}"> - <TextBlock Text="{locale:Locale ControllerSettingsRotate90}" /> - </CheckBox> - <Separator - Margin="0,8,0,8" - Height="1" /> - <StackPanel Orientation="Vertical"> - <TextBlock - HorizontalAlignment="Center" - Text="{locale:Locale ControllerSettingsStickDeadzone}" /> - <StackPanel - HorizontalAlignment="Center" - VerticalAlignment="Center" - Orientation="Horizontal"> - <controls:SliderScroll - Width="130" - Maximum="1" - TickFrequency="0.01" - IsSnapToTickEnabled="True" - SmallChange="0.01" - Minimum="0" - Value="{ReflectionBinding Configuration.DeadzoneLeft, Mode=TwoWay}" /> - <TextBlock - VerticalAlignment="Center" - Width="25" - Text="{ReflectionBinding Configuration.DeadzoneLeft, StringFormat=\{0:0.00\}}" /> - </StackPanel> - <TextBlock - HorizontalAlignment="Center" - Text="{locale:Locale ControllerSettingsStickRange}" /> - <StackPanel - HorizontalAlignment="Center" - VerticalAlignment="Center" - Orientation="Horizontal"> - <controls:SliderScroll - Width="130" - Maximum="2" - TickFrequency="0.01" - IsSnapToTickEnabled="True" - SmallChange="0.01" - Minimum="0" - Value="{ReflectionBinding Configuration.RangeLeft, Mode=TwoWay}" /> - <TextBlock - VerticalAlignment="Center" - Width="25" - Text="{ReflectionBinding Configuration.RangeLeft, StringFormat=\{0:0.00\}}" /> - </StackPanel> - </StackPanel> - </StackPanel> - </StackPanel> - </Border> - <!-- Left DPad --> - <Border - BorderBrush="{DynamicResource ThemeControlBorderColor}" - BorderThickness="1" - VerticalAlignment="Top" - IsVisible="{Binding IsLeft}" - Margin="0,5,0,0" - CornerRadius="5"> - <StackPanel - Margin="10" - Orientation="Vertical"> - <TextBlock - Margin="0,0,0,10" - HorizontalAlignment="Center" - Text="{locale:Locale ControllerSettingsDPad}" /> - <StackPanel Orientation="Vertical"> - <!-- Left DPad Up --> - <StackPanel - Margin="0,0,0,4" - Orientation="Horizontal"> - <TextBlock - Margin="0,0,10,0" - Width="120" - HorizontalAlignment="Center" - VerticalAlignment="Center" - Text="{locale:Locale ControllerSettingsDPadUp}" - TextAlignment="Center" /> - <ToggleButton> - <TextBlock - Text="{ReflectionBinding Configuration.DpadUp, Mode=TwoWay, Converter={StaticResource Key}}" - TextAlignment="Center" /> - </ToggleButton> - </StackPanel> - <!-- Left DPad Down --> - <StackPanel - Margin="0,0,0,4" - Orientation="Horizontal"> - <TextBlock - Margin="0,0,10,0" - Width="120" - HorizontalAlignment="Center" - VerticalAlignment="Center" - Text="{locale:Locale ControllerSettingsDPadDown}" - TextAlignment="Center" /> - <ToggleButton> - <TextBlock - Text="{ReflectionBinding Configuration.DpadDown, Mode=TwoWay, Converter={StaticResource Key}}" - TextAlignment="Center" /> - </ToggleButton> - </StackPanel> - <!-- Left DPad Left --> - <StackPanel - Margin="0,0,0,4" - Orientation="Horizontal"> - <TextBlock - Margin="0,0,10,0" - Width="120" - HorizontalAlignment="Center" - VerticalAlignment="Center" - Text="{locale:Locale ControllerSettingsDPadLeft}" - TextAlignment="Center" /> - <ToggleButton> - <TextBlock - Text="{ReflectionBinding Configuration.DpadLeft, Mode=TwoWay, Converter={StaticResource Key}}" - TextAlignment="Center" /> - </ToggleButton> - </StackPanel> - <!-- Left DPad Right --> - <StackPanel - Margin="0,0,0,4" - Orientation="Horizontal"> - <TextBlock - Margin="0,0,10,0" - Width="120" - HorizontalAlignment="Center" - VerticalAlignment="Center" - Text="{locale:Locale ControllerSettingsDPadRight}" - TextAlignment="Center" /> - <ToggleButton> - <TextBlock - Text="{ReflectionBinding Configuration.DpadRight, Mode=TwoWay, Converter={StaticResource Key}}" - TextAlignment="Center" /> - </ToggleButton> - </StackPanel> - </StackPanel> - </StackPanel> - </Border> - </StackPanel> - <!-- Triggers & Side Buttons --> - <StackPanel - Grid.Column="1" - HorizontalAlignment="Stretch" - VerticalAlignment="Stretch"> - <Border - BorderBrush="{DynamicResource ThemeControlBorderColor}" - BorderThickness="1" - CornerRadius="5" - MinHeight="90"> - <StackPanel - Margin="8" - Orientation="Vertical"> - <TextBlock - HorizontalAlignment="Center" - Text="{locale:Locale ControllerSettingsTriggerThreshold}" /> - <StackPanel - HorizontalAlignment="Center" - Orientation="Horizontal"> - <controls:SliderScroll - Width="130" - Maximum="1" - TickFrequency="0.01" - IsSnapToTickEnabled="True" - SmallChange="0.01" - Minimum="0" - Value="{ReflectionBinding Configuration.TriggerThreshold, Mode=TwoWay}" /> - <TextBlock - Width="25" - Text="{ReflectionBinding Configuration.TriggerThreshold, StringFormat=\{0:0.00\}}" /> - </StackPanel> - <StackPanel - Margin="0,4,0,0" - HorizontalAlignment="Center" - VerticalAlignment="Center" - IsVisible="{Binding !IsRight}" - Orientation="Horizontal"> - <TextBlock - Width="20" - HorizontalAlignment="Center" - VerticalAlignment="Center" - Text="{locale:Locale ControllerSettingsLeftSR}" - TextAlignment="Center" /> - <ToggleButton> - <TextBlock - Text="{ReflectionBinding Configuration.LeftButtonSr, Mode=TwoWay, Converter={StaticResource Key}}" - TextAlignment="Center" /> - </ToggleButton> - </StackPanel> - <StackPanel - Margin="0,4,0,0" - HorizontalAlignment="Center" - VerticalAlignment="Center" - IsVisible="{Binding !IsRight}" - Orientation="Horizontal"> - <TextBlock - Width="20" - HorizontalAlignment="Center" - VerticalAlignment="Center" - Text="{locale:Locale ControllerSettingsLeftSL}" - TextAlignment="Center" /> - <ToggleButton> - <TextBlock - Text="{ReflectionBinding Configuration.LeftButtonSl, Mode=TwoWay, Converter={StaticResource Key}}" - TextAlignment="Center" /> - </ToggleButton> - </StackPanel> - <StackPanel - Margin="0,4,0,0" - HorizontalAlignment="Center" - VerticalAlignment="Center" - IsVisible="{Binding !IsLeft}" - Orientation="Horizontal"> - <TextBlock - Width="20" - HorizontalAlignment="Center" - VerticalAlignment="Center" - Text="{locale:Locale ControllerSettingsRightSR}" - TextAlignment="Center" /> - <ToggleButton> - <TextBlock - Text="{ReflectionBinding Configuration.RightButtonSr, Mode=TwoWay, Converter={StaticResource Key}}" - TextAlignment="Center" /> - </ToggleButton> - </StackPanel> - <StackPanel - Margin="0,4,0,0" - HorizontalAlignment="Center" - VerticalAlignment="Center" - IsVisible="{Binding !IsLeft}" - Orientation="Horizontal"> - <TextBlock - Width="20" - HorizontalAlignment="Center" - VerticalAlignment="Center" - Text="{locale:Locale ControllerSettingsRightSL}" - TextAlignment="Center" /> - <ToggleButton> - <TextBlock - Text="{ReflectionBinding Configuration.RightButtonSl, Mode=TwoWay, Converter={StaticResource Key}}" - TextAlignment="Center" /> - </ToggleButton> - </StackPanel> - </StackPanel> - </Border> - <!-- Controller Picture --> - <Image - Margin="0,10,0,0" - MaxHeight="300" - HorizontalAlignment="Stretch" - VerticalAlignment="Stretch" - Source="{Binding Image}" /> - <!-- Motion + Rumble --> - <StackPanel - Margin="0,10,0,0" - Spacing="5" - Orientation="Vertical" - VerticalAlignment="Bottom"> - <Border - BorderBrush="{DynamicResource ThemeControlBorderColor}" - BorderThickness="1" - CornerRadius="5" - VerticalAlignment="Bottom" - HorizontalAlignment="Stretch" - IsVisible="{Binding IsController}"> - <Grid> - <Grid.ColumnDefinitions> - <ColumnDefinition Width="*" /> - <ColumnDefinition Width="Auto" /> - </Grid.ColumnDefinitions> - <CheckBox - Margin="10" - MinWidth="0" - Grid.Column="0" - IsChecked="{ReflectionBinding Configuration.EnableMotion, Mode=TwoWay}"> - <TextBlock Text="{locale:Locale ControllerSettingsMotion}" /> - </CheckBox> - <Button - Margin="10" - Grid.Column="1" - Command="{Binding ShowMotionConfig}"> - <TextBlock Text="{locale:Locale ControllerSettingsConfigureGeneral}" /> - </Button> - </Grid> - </Border> - <Border - BorderBrush="{DynamicResource ThemeControlBorderColor}" - BorderThickness="1" - CornerRadius="5" - HorizontalAlignment="Stretch" - IsVisible="{Binding IsController}" - Margin="0,-1,0,0"> - <Grid> - <Grid.ColumnDefinitions> - <ColumnDefinition Width="*" /> - <ColumnDefinition Width="Auto" /> - </Grid.ColumnDefinitions> - <CheckBox - Margin="10" - MinWidth="0" - Grid.Column="0" - IsChecked="{ReflectionBinding Configuration.EnableRumble, Mode=TwoWay}"> - <TextBlock Text="{locale:Locale ControllerSettingsRumble}" /> - </CheckBox> - <Button - Margin="10" - Grid.Column="1" - Command="{Binding ShowRumbleConfig}"> - <TextBlock Text="{locale:Locale ControllerSettingsConfigureGeneral}" /> - </Button> - </Grid> - </Border> - </StackPanel> - </StackPanel> - <!-- Right Controls --> - <StackPanel - Orientation="Vertical" - Margin="5,0,0,0" - Grid.Column="2"> - <!-- Right Triggers --> - <Border - BorderBrush="{DynamicResource ThemeControlBorderColor}" - BorderThickness="1" - IsVisible="{Binding IsRight}" - MinHeight="90" - CornerRadius="5"> - <Grid - Margin="10" - HorizontalAlignment="Stretch"> - <Grid.ColumnDefinitions> - <ColumnDefinition /> - <ColumnDefinition /> - </Grid.ColumnDefinitions> - <Grid.RowDefinitions> - <RowDefinition /> - <RowDefinition /> - </Grid.RowDefinitions> - <StackPanel - Grid.Column="1" - Grid.Row="0" - Orientation="Horizontal"> - <TextBlock - Width="20" - HorizontalAlignment="Center" - VerticalAlignment="Center" - Text="{locale:Locale ControllerSettingsTriggerZR}" - TextAlignment="Center" /> - <ToggleButton> - <TextBlock - Text="{ReflectionBinding Configuration.ButtonZr, Mode=TwoWay, Converter={StaticResource Key}}" - TextAlignment="Center" /> - </ToggleButton> - </StackPanel> - <StackPanel - Grid.Column="1" - Grid.Row="1" - HorizontalAlignment="Center" - VerticalAlignment="Center" - Orientation="Horizontal"> - <TextBlock - Width="20" - HorizontalAlignment="Center" - VerticalAlignment="Center" - Text="{locale:Locale ControllerSettingsTriggerR}" - TextAlignment="Center" /> - <ToggleButton> - <TextBlock - Text="{ReflectionBinding Configuration.ButtonR, Mode=TwoWay, Converter={StaticResource Key}}" - TextAlignment="Center" /> - </ToggleButton> - </StackPanel> - <StackPanel - Grid.Column="0" - Grid.Row="1" - HorizontalAlignment="Right" - VerticalAlignment="Center" - Orientation="Horizontal"> - <TextBlock - Width="20" - HorizontalAlignment="Center" - VerticalAlignment="Center" - Text="{locale:Locale ControllerSettingsButtonPlus}" - TextAlignment="Center" /> - <ToggleButton> - <TextBlock - Text="{ReflectionBinding Configuration.ButtonPlus, Mode=TwoWay, Converter={StaticResource Key}}" - TextAlignment="Center" /> - </ToggleButton> - </StackPanel> - </Grid> - </Border> - <!-- Right Joystick --> - <Border - BorderBrush="{DynamicResource ThemeControlBorderColor}" - BorderThickness="1" - IsVisible="{Binding IsRight}" - Margin="0,5,0,0" - CornerRadius="5"> - <StackPanel - Margin="10" - Orientation="Vertical"> - <TextBlock - Margin="0,0,0,10" - HorizontalAlignment="Center" - Text="{locale:Locale ControllerSettingsButtons}" /> - <StackPanel - Orientation="Vertical"> - <!-- Right Buttons A --> - <StackPanel - Margin="0,0,0,4" - Orientation="Horizontal"> - <TextBlock - Width="120" - Margin="0,0,10,0" - HorizontalAlignment="Center" - VerticalAlignment="Center" - Text="{locale:Locale ControllerSettingsButtonA}" - TextAlignment="Center" /> - <ToggleButton> - <TextBlock - Text="{ReflectionBinding Configuration.ButtonA, Mode=TwoWay, Converter={StaticResource Key}}" - TextAlignment="Center" /> - </ToggleButton> - </StackPanel> - <!-- Right Buttons B --> - <StackPanel - Margin="0,0,0,4" - Orientation="Horizontal"> - <TextBlock - Width="120" - Margin="0,0,10,0" - HorizontalAlignment="Center" - VerticalAlignment="Center" - Text="{locale:Locale ControllerSettingsButtonB}" - TextAlignment="Center" /> - <ToggleButton> - <TextBlock - Text="{ReflectionBinding Configuration.ButtonB, Mode=TwoWay, Converter={StaticResource Key}}" - TextAlignment="Center" /> - </ToggleButton> - </StackPanel> - <!-- Right Buttons X --> - <StackPanel - Margin="0,0,0,4" - Orientation="Horizontal"> - <TextBlock - Width="120" - Margin="0,0,10,0" - HorizontalAlignment="Center" - VerticalAlignment="Center" - Text="{locale:Locale ControllerSettingsButtonX}" - TextAlignment="Center" /> - <ToggleButton> - <TextBlock - Text="{ReflectionBinding Configuration.ButtonX, Mode=TwoWay, Converter={StaticResource Key}}" - TextAlignment="Center" /> - </ToggleButton> - </StackPanel> - <!-- Right Buttons Y --> - <StackPanel - Margin="0,0,0,4" - Orientation="Horizontal"> - <TextBlock - Width="120" - Margin="0,0,10,0" - HorizontalAlignment="Center" - VerticalAlignment="Center" - Text="{locale:Locale ControllerSettingsButtonY}" - TextAlignment="Center" /> - <ToggleButton> - <TextBlock - Text="{ReflectionBinding Configuration.ButtonY, Mode=TwoWay, Converter={StaticResource Key}}" - TextAlignment="Center" /> - </ToggleButton> - </StackPanel> - </StackPanel> - </StackPanel> - </Border> - <!-- Right DPad --> - <Border - Padding="10" - BorderBrush="{DynamicResource ThemeControlBorderColor}" - BorderThickness="1" - CornerRadius="5" - IsVisible="{Binding IsRight}" - Margin="0,5,0,0"> - <StackPanel Orientation="Vertical"> - <TextBlock - Margin="0,0,0,10" - HorizontalAlignment="Center" - Text="{locale:Locale ControllerSettingsRStick}" /> - <!-- Right Joystick Keyboard --> - <StackPanel - IsVisible="{Binding !IsController}" - Orientation="Vertical"> - <!-- Right Joystick Button --> - <StackPanel - Margin="0,0,0,4" - Orientation="Horizontal"> - <TextBlock - Margin="0,0,10,0" - Width="120" - HorizontalAlignment="Center" - VerticalAlignment="Center" - Text="{locale:Locale ControllerSettingsStickButton}" - TextAlignment="Center" /> - <ToggleButton> - <TextBlock - Text="{ReflectionBinding Configuration.RightKeyboardStickButton, Mode=TwoWay, Converter={StaticResource Key}}" - TextAlignment="Center" /> - </ToggleButton> - </StackPanel> - <!-- Right Joystick Up --> - <StackPanel - Margin="0,0,0,4" - Orientation="Horizontal"> - <TextBlock - Margin="0,0,10,0" - Width="120" - HorizontalAlignment="Center" - VerticalAlignment="Center" - Text="{locale:Locale ControllerSettingsStickUp}" - TextAlignment="Center" /> - <ToggleButton> - <TextBlock - Text="{ReflectionBinding Configuration.RightStickUp, Mode=TwoWay, Converter={StaticResource Key}}" - TextAlignment="Center" /> - </ToggleButton> - </StackPanel> - <!-- Right Joystick Down --> - <StackPanel - Margin="0,0,0,4" - Orientation="Horizontal"> - <TextBlock - Margin="0,0,10,0" - Width="120" - HorizontalAlignment="Center" - VerticalAlignment="Center" - Text="{locale:Locale ControllerSettingsStickDown}" - TextAlignment="Center" /> - <ToggleButton> - <TextBlock - Text="{ReflectionBinding Configuration.RightStickDown, Mode=TwoWay, Converter={StaticResource Key}}" - TextAlignment="Center" /> - </ToggleButton> - </StackPanel> - <!-- Right Joystick Left --> - <StackPanel - Margin="0,0,0,4" - Orientation="Horizontal"> - <TextBlock - Margin="0,0,10,0" - Width="120" - HorizontalAlignment="Center" - VerticalAlignment="Center" - Text="{locale:Locale ControllerSettingsStickLeft}" - TextAlignment="Center" /> - <ToggleButton> - <TextBlock - Text="{ReflectionBinding Configuration.RightStickLeft, Mode=TwoWay, Converter={StaticResource Key}}" - TextAlignment="Center" /> - </ToggleButton> - </StackPanel> - <!-- Right Joystick Right --> - <StackPanel - Margin="0,0,0,4" - Orientation="Horizontal"> - <TextBlock - Margin="0,0,10,0" - Width="120" - HorizontalAlignment="Center" - VerticalAlignment="Center" - Text="{locale:Locale ControllerSettingsStickRight}" - TextAlignment="Center" /> - <ToggleButton> - <TextBlock - Text="{ReflectionBinding Configuration.RightStickRight, Mode=TwoWay, Converter={StaticResource Key}}" - TextAlignment="Center" /> - </ToggleButton> - </StackPanel> - </StackPanel> - <!-- Right Joystick Controller --> - <StackPanel - IsVisible="{Binding IsController}" - Orientation="Vertical"> - <!-- Right Joystick Button --> - <StackPanel - Orientation="Horizontal"> - <TextBlock - Margin="0,0,10,0" - Width="120" - HorizontalAlignment="Center" - VerticalAlignment="Center" - Text="{locale:Locale ControllerSettingsStickButton}" - TextAlignment="Center" /> - <ToggleButton> - <TextBlock - Text="{ReflectionBinding Configuration.RightControllerStickButton, Mode=TwoWay, Converter={StaticResource Key}}" - TextAlignment="Center" /> - </ToggleButton> - </StackPanel> - <!-- Right Joystick Stick --> - <StackPanel - Margin="0,4,0,4" - Background="{DynamicResource ThemeDarkColor}" - Orientation="Horizontal"> - <TextBlock - Margin="0,0,10,0" - Width="120" - HorizontalAlignment="Center" - VerticalAlignment="Center" - Text="{locale:Locale ControllerSettingsStickStick}" - TextAlignment="Center" /> - <ToggleButton Tag="stick"> - <TextBlock - Text="{ReflectionBinding Configuration.RightJoystick, Mode=TwoWay, Converter={StaticResource Key}}" - TextAlignment="Center" /> - </ToggleButton> - </StackPanel> - <Separator Margin="0,8,0,8" Height="1" /> - <CheckBox IsChecked="{ReflectionBinding Configuration.RightInvertStickX}"> - <TextBlock Text="{locale:Locale ControllerSettingsStickInvertXAxis}" /> - </CheckBox> - <CheckBox IsChecked="{ReflectionBinding Configuration.RightInvertStickY}"> - <TextBlock Text="{locale:Locale ControllerSettingsStickInvertYAxis}" /> - </CheckBox> - <CheckBox IsChecked="{ReflectionBinding Configuration.RightRotate90}"> - <TextBlock Text="{locale:Locale ControllerSettingsRotate90}" /> - </CheckBox> - <Separator Margin="0,8,0,8" Height="1" /> - <StackPanel Orientation="Vertical"> - <TextBlock - HorizontalAlignment="Center" - Text="{locale:Locale ControllerSettingsStickDeadzone}" /> - <StackPanel - HorizontalAlignment="Center" - VerticalAlignment="Center" - Orientation="Horizontal"> - <controls:SliderScroll - Width="130" - Maximum="1" - TickFrequency="0.01" - IsSnapToTickEnabled="True" - SmallChange="0.01" - Padding="0" - VerticalAlignment="Center" - Minimum="0" - Value="{ReflectionBinding Configuration.DeadzoneRight, Mode=TwoWay}" /> - <TextBlock - VerticalAlignment="Center" - Width="25" - Text="{ReflectionBinding Configuration.DeadzoneRight, StringFormat=\{0:0.00\}}" /> - </StackPanel> - <TextBlock - HorizontalAlignment="Center" - Text="{locale:Locale ControllerSettingsStickRange}" /> - <StackPanel - HorizontalAlignment="Center" - VerticalAlignment="Center" - Orientation="Horizontal"> - <controls:SliderScroll - Width="130" - Maximum="2" - TickFrequency="0.01" - IsSnapToTickEnabled="True" - SmallChange="0.01" - Minimum="0" - Value="{ReflectionBinding Configuration.RangeRight, Mode=TwoWay}" /> - <TextBlock - VerticalAlignment="Center" - Width="25" - Text="{ReflectionBinding Configuration.RangeRight, StringFormat=\{0:0.00\}}" /> - </StackPanel> - </StackPanel> - </StackPanel> - </StackPanel> - </Border> - </StackPanel> - </Grid> - </StackPanel> -</UserControl> diff --git a/src/Ryujinx.Ava/UI/Views/Input/ControllerInputView.axaml.cs b/src/Ryujinx.Ava/UI/Views/Input/ControllerInputView.axaml.cs deleted file mode 100644 index 35129706..00000000 --- a/src/Ryujinx.Ava/UI/Views/Input/ControllerInputView.axaml.cs +++ /dev/null @@ -1,181 +0,0 @@ -using Avalonia.Controls; -using Avalonia.Controls.Primitives; -using Avalonia.Input; -using Avalonia.Interactivity; -using Avalonia.LogicalTree; -using Ryujinx.Ava.Common.Locale; -using Ryujinx.Ava.UI.Helpers; -using Ryujinx.Ava.UI.Models; -using Ryujinx.Ava.UI.ViewModels; -using Ryujinx.Common.Configuration.Hid.Controller; -using Ryujinx.Input; -using Ryujinx.Input.Assigner; -using System; - -namespace Ryujinx.Ava.UI.Views.Input -{ - public partial class ControllerInputView : UserControl - { - private bool _dialogOpen; - - private ButtonKeyAssigner _currentAssigner; - internal ControllerInputViewModel ViewModel { get; set; } - - public ControllerInputView() - { - DataContext = ViewModel = new ControllerInputViewModel(this); - - InitializeComponent(); - - foreach (ILogical visual in SettingButtons.GetLogicalDescendants()) - { - if (visual is ToggleButton button && visual is not CheckBox) - { - button.IsCheckedChanged += Button_IsCheckedChanged; - } - } - } - - protected override void OnPointerReleased(PointerReleasedEventArgs e) - { - base.OnPointerReleased(e); - - if (_currentAssigner != null && _currentAssigner.ToggledButton != null && !_currentAssigner.ToggledButton.IsPointerOver) - { - _currentAssigner.Cancel(); - } - } - - private void Button_IsCheckedChanged(object sender, RoutedEventArgs e) - { - if (sender is ToggleButton button) - { - if ((bool)button.IsChecked) - { - if (_currentAssigner != null && button == _currentAssigner.ToggledButton) - { - return; - } - - bool isStick = button.Tag != null && button.Tag.ToString() == "stick"; - - if (_currentAssigner == null) - { - _currentAssigner = new ButtonKeyAssigner(button); - - this.Focus(NavigationMethod.Pointer); - - PointerPressed += MouseClick; - - IKeyboard keyboard = (IKeyboard)ViewModel.AvaloniaKeyboardDriver.GetGamepad("0"); // Open Avalonia keyboard for cancel operations. - IButtonAssigner assigner = CreateButtonAssigner(isStick); - - _currentAssigner.ButtonAssigned += (sender, e) => - { - if (e.IsAssigned) - { - ViewModel.IsModified = true; - } - }; - - _currentAssigner.GetInputAndAssign(assigner, keyboard); - } - else - { - if (_currentAssigner != null) - { - ToggleButton oldButton = _currentAssigner.ToggledButton; - - _currentAssigner.Cancel(); - _currentAssigner = null; - button.IsChecked = false; - } - } - } - else - { - _currentAssigner?.Cancel(); - _currentAssigner = null; - } - } - } - - public void SaveCurrentProfile() - { - ViewModel.Save(); - } - - private IButtonAssigner CreateButtonAssigner(bool forStick) - { - IButtonAssigner assigner; - - var device = ViewModel.Devices[ViewModel.Device]; - - if (device.Type == DeviceType.Keyboard) - { - assigner = new KeyboardKeyAssigner((IKeyboard)ViewModel.SelectedGamepad); - } - else if (device.Type == DeviceType.Controller) - { - assigner = new GamepadButtonAssigner(ViewModel.SelectedGamepad, (ViewModel.Config as StandardControllerInputConfig).TriggerThreshold, forStick); - } - else - { - throw new Exception("Controller not supported"); - } - - return assigner; - } - - private void MouseClick(object sender, PointerPressedEventArgs e) - { - bool shouldUnbind = false; - - if (e.GetCurrentPoint(this).Properties.IsMiddleButtonPressed) - { - shouldUnbind = true; - } - - _currentAssigner?.Cancel(shouldUnbind); - - PointerPressed -= MouseClick; - } - - private async void PlayerIndexBox_OnSelectionChanged(object sender, SelectionChangedEventArgs e) - { - if (ViewModel.IsModified && !_dialogOpen) - { - _dialogOpen = true; - - var result = await ContentDialogHelper.CreateConfirmationDialog( - LocaleManager.Instance[LocaleKeys.DialogControllerSettingsModifiedConfirmMessage], - LocaleManager.Instance[LocaleKeys.DialogControllerSettingsModifiedConfirmSubMessage], - LocaleManager.Instance[LocaleKeys.InputDialogYes], - LocaleManager.Instance[LocaleKeys.InputDialogNo], - LocaleManager.Instance[LocaleKeys.RyujinxConfirm]); - - if (result == UserResult.Yes) - { - ViewModel.Save(); - } - - _dialogOpen = false; - - ViewModel.IsModified = false; - - if (e.AddedItems.Count > 0) - { - var player = (PlayerModel)e.AddedItems[0]; - ViewModel.PlayerId = player.Id; - } - } - } - - public void Dispose() - { - _currentAssigner?.Cancel(); - _currentAssigner = null; - ViewModel.Dispose(); - } - } -} diff --git a/src/Ryujinx.Ava/UI/Views/Input/MotionInputView.axaml b/src/Ryujinx.Ava/UI/Views/Input/MotionInputView.axaml deleted file mode 100644 index a6b587f6..00000000 --- a/src/Ryujinx.Ava/UI/Views/Input/MotionInputView.axaml +++ /dev/null @@ -1,171 +0,0 @@ -<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:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" - xmlns:controls="clr-namespace:Ryujinx.Ava.UI.Controls" - xmlns:ui="clr-namespace:FluentAvalonia.UI.Controls;assembly=FluentAvalonia" - xmlns:locale="clr-namespace:Ryujinx.Ava.Common.Locale" - xmlns:viewModels="clr-namespace:Ryujinx.Ava.UI.ViewModels" - mc:Ignorable="d" - x:Class="Ryujinx.Ava.UI.Views.Input.MotionInputView" - x:DataType="viewModels:MotionInputViewModel" - Focusable="True"> - <Grid Margin="10"> - <Grid.RowDefinitions> - <RowDefinition Height="Auto" /> - <RowDefinition /> - </Grid.RowDefinitions> - <StackPanel Orientation="Vertical"> - <StackPanel - Orientation="Horizontal" - HorizontalAlignment="Center"> - <TextBlock - Margin="0" - HorizontalAlignment="Center" - Text="{locale:Locale ControllerSettingsMotionGyroSensitivity}" /> - <controls:SliderScroll - Margin="0,-5,0,-5" - Width="150" - MaxWidth="150" - TickFrequency="1" - IsSnapToTickEnabled="True" - SmallChange="0.01" - Maximum="100" - Minimum="0" - Value="{Binding Sensitivity, Mode=TwoWay}" /> - <TextBlock - HorizontalAlignment="Center" - Margin="5, 0" - Text="{Binding Sensitivity, StringFormat=\{0:0\}%}" /> - </StackPanel> - <StackPanel - Orientation="Horizontal" - HorizontalAlignment="Center"> - <TextBlock - Margin="0" - HorizontalAlignment="Center" - Text="{locale:Locale ControllerSettingsMotionGyroDeadzone}" /> - <controls:SliderScroll - Margin="0,-5,0,-5" - Width="150" - MaxWidth="150" - TickFrequency="1" - IsSnapToTickEnabled="True" - SmallChange="0.01" - Maximum="100" - Minimum="0" - Value="{Binding GyroDeadzone, Mode=TwoWay}" /> - <TextBlock - VerticalAlignment="Center" - Margin="5, 0" - Text="{Binding GyroDeadzone, StringFormat=\{0:0.00\}}" /> - </StackPanel> - <Separator - Height="1" - Margin="0,5" /> - <CheckBox - Margin="5" - IsChecked="{Binding EnableCemuHookMotion}"> - <TextBlock - Margin="0,3,0,0" - VerticalAlignment="Center" - Text="{locale:Locale ControllerSettingsMotionUseCemuhookCompatibleMotion}" /> - </CheckBox> - </StackPanel> - <Border - Grid.Row="1" - Padding="20,5" - BorderBrush="{DynamicResource ThemeControlBorderColor}" - BorderThickness="1" - CornerRadius="5" - HorizontalAlignment="Stretch"> - <Grid VerticalAlignment="Top"> - <Grid.RowDefinitions> - <RowDefinition Height="Auto" /> - <RowDefinition Height="*" /> - </Grid.RowDefinitions> - <StackPanel - Grid.Row="1" - HorizontalAlignment="Center" - VerticalAlignment="Center" - Orientation="Vertical"> - <StackPanel - HorizontalAlignment="Center" - VerticalAlignment="Center" - Orientation="Horizontal"> - <TextBlock - Margin="5" - HorizontalAlignment="Center" - VerticalAlignment="Center" - Text="{locale:Locale ControllerSettingsMotionServerHost}" /> - <TextBox - Height="30" - MinWidth="100" - MaxWidth="100" - HorizontalAlignment="Center" - VerticalAlignment="Center" - Text="{Binding DsuServerHost, Mode=TwoWay}" /> - <TextBlock - Margin="5" - HorizontalAlignment="Center" - VerticalAlignment="Center" - Text=":" /> - <TextBox - Height="30" - HorizontalAlignment="Center" - VerticalAlignment="Center" - Text="{Binding DsuServerPort, Mode=TwoWay}" /> - </StackPanel> - <StackPanel Orientation="Vertical"> - <Grid> - <Grid.RowDefinitions> - <RowDefinition /> - <RowDefinition /> - </Grid.RowDefinitions> - <Grid.ColumnDefinitions> - <ColumnDefinition /> - <ColumnDefinition /> - </Grid.ColumnDefinitions> - <TextBlock - Margin="0,10,0,0" - VerticalAlignment="Center" - Text="{locale:Locale ControllerSettingsMotionControllerSlot}" /> - <ui:NumberBox - Grid.Row="0" - Grid.Column="1" - Name="CemuHookSlotUpDown" - SmallChange="1" - LargeChange="1" - Maximum="4" - Minimum="0" - Value="{Binding Slot}" /> - <TextBlock - Margin="0,10,0,0" - Grid.Row="1" - Grid.Column="0" - VerticalAlignment="Center" - Text="{locale:Locale ControllerSettingsMotionRightJoyConSlot}" /> - <ui:NumberBox - Grid.Row="1" - Grid.Column="1" - Name="CemuHookRightJoyConSlotUpDown" - SmallChange="1" - LargeChange="1" - Maximum="4" - Minimum="0" - Value="{Binding AltSlot}" /> - </Grid> - </StackPanel> - <CheckBox - HorizontalAlignment="Center" - IsChecked="{Binding MirrorInput, Mode=TwoWay}"> - <TextBlock - HorizontalAlignment="Center" - Text="{locale:Locale ControllerSettingsMotionMirrorInput}" /> - </CheckBox> - </StackPanel> - </Grid> - </Border> - </Grid> -</UserControl> diff --git a/src/Ryujinx.Ava/UI/Views/Input/MotionInputView.axaml.cs b/src/Ryujinx.Ava/UI/Views/Input/MotionInputView.axaml.cs deleted file mode 100644 index 1b340752..00000000 --- a/src/Ryujinx.Ava/UI/Views/Input/MotionInputView.axaml.cs +++ /dev/null @@ -1,68 +0,0 @@ -using Avalonia.Controls; -using FluentAvalonia.UI.Controls; -using Ryujinx.Ava.Common.Locale; -using Ryujinx.Ava.UI.Models; -using Ryujinx.Ava.UI.ViewModels; -using Ryujinx.Common.Configuration.Hid.Controller; -using System.Threading.Tasks; - -namespace Ryujinx.Ava.UI.Views.Input -{ - public partial class MotionInputView : UserControl - { - private readonly MotionInputViewModel _viewModel; - - public MotionInputView() - { - InitializeComponent(); - } - - public MotionInputView(ControllerInputViewModel viewModel) - { - var config = viewModel.Configuration as InputConfiguration<GamepadInputId, StickInputId>; - - _viewModel = new MotionInputViewModel - { - Slot = config.Slot, - AltSlot = config.AltSlot, - DsuServerHost = config.DsuServerHost, - DsuServerPort = config.DsuServerPort, - MirrorInput = config.MirrorInput, - Sensitivity = config.Sensitivity, - GyroDeadzone = config.GyroDeadzone, - EnableCemuHookMotion = config.EnableCemuHookMotion, - }; - - InitializeComponent(); - DataContext = _viewModel; - } - - public static async Task Show(ControllerInputViewModel viewModel) - { - MotionInputView content = new(viewModel); - - ContentDialog contentDialog = new() - { - Title = LocaleManager.Instance[LocaleKeys.ControllerMotionTitle], - PrimaryButtonText = LocaleManager.Instance[LocaleKeys.ControllerSettingsSave], - SecondaryButtonText = "", - CloseButtonText = LocaleManager.Instance[LocaleKeys.ControllerSettingsClose], - Content = content, - }; - contentDialog.PrimaryButtonClick += (sender, args) => - { - var config = viewModel.Configuration as InputConfiguration<GamepadInputId, StickInputId>; - config.Slot = content._viewModel.Slot; - config.Sensitivity = content._viewModel.Sensitivity; - config.GyroDeadzone = content._viewModel.GyroDeadzone; - config.AltSlot = content._viewModel.AltSlot; - config.DsuServerHost = content._viewModel.DsuServerHost; - config.DsuServerPort = content._viewModel.DsuServerPort; - config.EnableCemuHookMotion = content._viewModel.EnableCemuHookMotion; - config.MirrorInput = content._viewModel.MirrorInput; - }; - - await contentDialog.ShowAsync(); - } - } -} diff --git a/src/Ryujinx.Ava/UI/Views/Input/RumbleInputView.axaml b/src/Ryujinx.Ava/UI/Views/Input/RumbleInputView.axaml deleted file mode 100644 index 5b7087a4..00000000 --- a/src/Ryujinx.Ava/UI/Views/Input/RumbleInputView.axaml +++ /dev/null @@ -1,62 +0,0 @@ -<UserControl - xmlns="https://github.com/avaloniaui" - xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" - xmlns:controls="clr-namespace:Ryujinx.Ava.UI.Controls" - xmlns:d="http://schemas.microsoft.com/expression/blend/2008" - xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" - xmlns:locale="clr-namespace:Ryujinx.Ava.Common.Locale" - xmlns:viewModels="clr-namespace:Ryujinx.Ava.UI.ViewModels" - mc:Ignorable="d" - x:Class="Ryujinx.Ava.UI.Views.Input.RumbleInputView" - x:DataType="viewModels:RumbleInputViewModel" - Focusable="True"> - <Grid Margin="10"> - <Grid.RowDefinitions> - <RowDefinition Height="Auto" /> - <RowDefinition /> - </Grid.RowDefinitions> - <StackPanel Orientation="Vertical"> - <StackPanel Orientation="Horizontal"> - <TextBlock - Width="100" - TextWrapping="WrapWithOverflow" - HorizontalAlignment="Center" - Text="{locale:Locale ControllerSettingsRumbleStrongMultiplier}" /> - <controls:SliderScroll - Margin="0,-5,0,-5" - Width="200" - TickFrequency="0.01" - IsSnapToTickEnabled="True" - SmallChange="0.01" - Maximum="10" - Minimum="0" - Value="{Binding StrongRumble, Mode=TwoWay}" /> - <TextBlock - VerticalAlignment="Center" - Margin="5,0" - Text="{Binding StrongRumble, StringFormat=\{0:0.00\}}" /> - </StackPanel> - <StackPanel Orientation="Horizontal"> - <TextBlock - Width="100" - TextWrapping="WrapWithOverflow" - HorizontalAlignment="Center" - Text="{locale:Locale ControllerSettingsRumbleWeakMultiplier}" /> - <controls:SliderScroll - Margin="0,-5,0,-5" - Width="200" - MaxWidth="200" - Maximum="10" - TickFrequency="0.01" - IsSnapToTickEnabled="True" - SmallChange="0.01" - Minimum="0" - Value="{Binding WeakRumble, Mode=TwoWay}" /> - <TextBlock - VerticalAlignment="Center" - Margin="5,0" - Text="{Binding WeakRumble, StringFormat=\{0:0.00\}}" /> - </StackPanel> - </StackPanel> - </Grid> -</UserControl> diff --git a/src/Ryujinx.Ava/UI/Views/Input/RumbleInputView.axaml.cs b/src/Ryujinx.Ava/UI/Views/Input/RumbleInputView.axaml.cs deleted file mode 100644 index 9307f872..00000000 --- a/src/Ryujinx.Ava/UI/Views/Input/RumbleInputView.axaml.cs +++ /dev/null @@ -1,58 +0,0 @@ -using Avalonia.Controls; -using FluentAvalonia.UI.Controls; -using Ryujinx.Ava.Common.Locale; -using Ryujinx.Ava.UI.Models; -using Ryujinx.Ava.UI.ViewModels; -using Ryujinx.Common.Configuration.Hid.Controller; -using System.Threading.Tasks; - -namespace Ryujinx.Ava.UI.Views.Input -{ - public partial class RumbleInputView : UserControl - { - private readonly RumbleInputViewModel _viewModel; - - public RumbleInputView() - { - InitializeComponent(); - } - - public RumbleInputView(ControllerInputViewModel viewModel) - { - var config = viewModel.Configuration as InputConfiguration<GamepadInputId, StickInputId>; - - _viewModel = new RumbleInputViewModel - { - StrongRumble = config.StrongRumble, - WeakRumble = config.WeakRumble, - }; - - InitializeComponent(); - - DataContext = _viewModel; - } - - public static async Task Show(ControllerInputViewModel viewModel) - { - RumbleInputView content = new(viewModel); - - ContentDialog contentDialog = new() - { - Title = LocaleManager.Instance[LocaleKeys.ControllerRumbleTitle], - PrimaryButtonText = LocaleManager.Instance[LocaleKeys.ControllerSettingsSave], - SecondaryButtonText = "", - CloseButtonText = LocaleManager.Instance[LocaleKeys.ControllerSettingsClose], - Content = content, - }; - - contentDialog.PrimaryButtonClick += (sender, args) => - { - var config = viewModel.Configuration as InputConfiguration<GamepadInputId, StickInputId>; - config.StrongRumble = content._viewModel.StrongRumble; - config.WeakRumble = content._viewModel.WeakRumble; - }; - - await contentDialog.ShowAsync(); - } - } -} diff --git a/src/Ryujinx.Ava/UI/Views/Main/MainMenuBarView.axaml b/src/Ryujinx.Ava/UI/Views/Main/MainMenuBarView.axaml deleted file mode 100644 index 30358ada..00000000 --- a/src/Ryujinx.Ava/UI/Views/Main/MainMenuBarView.axaml +++ /dev/null @@ -1,203 +0,0 @@ -<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:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" - xmlns:locale="clr-namespace:Ryujinx.Ava.Common.Locale" - mc:Ignorable="d" - xmlns:viewModels="clr-namespace:Ryujinx.Ava.UI.ViewModels" - x:DataType="viewModels:MainWindowViewModel" - x:Class="Ryujinx.Ava.UI.Views.Main.MainMenuBarView"> - <Design.DataContext> - <viewModels:MainWindowViewModel /> - </Design.DataContext> - <DockPanel HorizontalAlignment="Stretch"> - <Menu - Name="Menu" - Height="35" - Margin="0" - HorizontalAlignment="Left"> - <Menu.ItemsPanel> - <ItemsPanelTemplate> - <DockPanel Margin="0" HorizontalAlignment="Stretch" /> - </ItemsPanelTemplate> - </Menu.ItemsPanel> - <MenuItem VerticalAlignment="Center" Header="{locale:Locale MenuBarFile}"> - <MenuItem - Command="{Binding OpenFile}" - Header="{locale:Locale MenuBarFileOpenFromFile}" - IsEnabled="{Binding EnableNonGameRunningControls}" - ToolTip.Tip="{locale:Locale LoadApplicationFileTooltip}" /> - <MenuItem - Command="{Binding OpenFolder}" - Header="{locale:Locale MenuBarFileOpenUnpacked}" - IsEnabled="{Binding EnableNonGameRunningControls}" - ToolTip.Tip="{locale:Locale LoadApplicationFolderTooltip}" /> - <MenuItem Header="{locale:Locale MenuBarFileOpenApplet}" IsEnabled="{Binding IsAppletMenuActive}"> - <MenuItem - Click="OpenMiiApplet" - Header="Mii Edit Applet" - ToolTip.Tip="{locale:Locale MenuBarFileOpenAppletOpenMiiAppletToolTip}" /> - </MenuItem> - <Separator /> - <MenuItem - Command="{Binding OpenRyujinxFolder}" - Header="{locale:Locale MenuBarFileOpenEmuFolder}" - ToolTip.Tip="{locale:Locale OpenRyujinxFolderTooltip}" /> - <MenuItem - Command="{Binding OpenLogsFolder}" - Header="{locale:Locale MenuBarFileOpenLogsFolder}" - ToolTip.Tip="{locale:Locale OpenRyujinxLogsTooltip}" /> - <Separator /> - <MenuItem - Click="CloseWindow" - Header="{locale:Locale MenuBarFileExit}" - ToolTip.Tip="{locale:Locale ExitTooltip}" /> - </MenuItem> - <MenuItem VerticalAlignment="Center" Header="{locale:Locale MenuBarOptions}"> - <MenuItem - Padding="-10,0,0,0" - Command="{Binding ToggleFullscreen}" - Header="{locale:Locale MenuBarOptionsToggleFullscreen}" - InputGesture="F11" /> - <MenuItem - Padding="0" - Command="{Binding ToggleStartGamesInFullscreen}" - Header="{locale:Locale MenuBarOptionsStartGamesInFullscreen}"> - <MenuItem.Icon> - <CheckBox - MinWidth="{DynamicResource CheckBoxSize}" - MinHeight="{DynamicResource CheckBoxSize}" - IsChecked="{Binding StartGamesInFullscreen, Mode=TwoWay}" - Padding="0" /> - </MenuItem.Icon> - <MenuItem.Styles> - <Style Selector="Viewbox#PART_IconPresenter"> - <Setter Property="MaxHeight" Value="36" /> - <Setter Property="MinHeight" Value="36" /> - <Setter Property="MaxWidth" Value="36" /> - <Setter Property="MinWidth" Value="36" /> - </Style> - <Style Selector="ContentPresenter#PART_HeaderPresenter"> - <Setter Property="Padding" Value="-10,0,0,0" /> - </Style> - </MenuItem.Styles> - </MenuItem> - <MenuItem - Padding="0" - IsVisible="{Binding ShowConsoleVisible}" - Command="{Binding ToggleShowConsole}" - Header="{locale:Locale MenuBarOptionsShowConsole}"> - <MenuItem.Icon> - <CheckBox - MinWidth="{DynamicResource CheckBoxSize}" - MinHeight="{DynamicResource CheckBoxSize}" - IsChecked="{Binding ShowConsole, Mode=TwoWay}" - Padding="0" /> - </MenuItem.Icon> - <MenuItem.Styles> - <Style Selector="Viewbox#PART_IconPresenter"> - <Setter Property="MaxHeight" Value="36" /> - <Setter Property="MinHeight" Value="36" /> - <Setter Property="MaxWidth" Value="36" /> - <Setter Property="MinWidth" Value="36" /> - </Style> - <Style Selector="ContentPresenter#PART_HeaderPresenter"> - <Setter Property="Padding" Value="-10,0,0,0" /> - </Style> - </MenuItem.Styles> - </MenuItem> - <Separator /> - <MenuItem - Name="ChangeLanguageMenuItem" - Padding="-10,0,0,0" - Header="{locale:Locale MenuBarOptionsChangeLanguage}" /> - <MenuItem - Name="ToggleFileTypesMenuItem" - Padding="-10,0,0,0" - Header="{locale:Locale MenuBarShowFileTypes}" /> - <Separator /> - <MenuItem - Click="OpenSettings" - Padding="-10,0,0,0" - Header="{locale:Locale MenuBarOptionsSettings}" - ToolTip.Tip="{locale:Locale OpenSettingsTooltip}" /> - <MenuItem - Command="{Binding ManageProfiles}" - Padding="-10,0,0,0" - Header="{locale:Locale MenuBarOptionsManageUserProfiles}" - IsEnabled="{Binding EnableNonGameRunningControls}" - ToolTip.Tip="{locale:Locale OpenProfileManagerTooltip}" /> - </MenuItem> - <MenuItem - Name="ActionsMenuItem" - VerticalAlignment="Center" - Header="{locale:Locale MenuBarActions}" - IsEnabled="{Binding IsGameRunning}"> - <MenuItem - Click="PauseEmulation_Click" - Header="{locale:Locale MenuBarOptionsPauseEmulation}" - InputGesture="{Binding PauseKey}" - IsEnabled="{Binding !IsPaused}" - IsVisible="{Binding !IsPaused}" /> - <MenuItem - Click="ResumeEmulation_Click" - Header="{locale:Locale MenuBarOptionsResumeEmulation}" - InputGesture="{Binding PauseKey}" - IsEnabled="{Binding IsPaused}" - IsVisible="{Binding IsPaused}" /> - <MenuItem - Click="StopEmulation_Click" - Header="{locale:Locale MenuBarOptionsStopEmulation}" - InputGesture="Escape" - IsEnabled="{Binding IsGameRunning}" - ToolTip.Tip="{locale:Locale StopEmulationTooltip}" /> - <MenuItem Command="{Binding SimulateWakeUpMessage}" Header="{locale:Locale MenuBarOptionsSimulateWakeUpMessage}" /> - <Separator /> - <MenuItem - Name="ScanAmiiboMenuItem" - AttachedToVisualTree="ScanAmiiboMenuItem_AttachedToVisualTree" - Click="OpenAmiiboWindow" - Header="{locale:Locale MenuBarActionsScanAmiibo}" - IsEnabled="{Binding IsAmiiboRequested}" /> - <MenuItem - Command="{Binding TakeScreenshot}" - Header="{locale:Locale MenuBarFileToolsTakeScreenshot}" - InputGesture="{Binding ScreenshotKey}" - IsEnabled="{Binding IsGameRunning}" /> - <MenuItem - Command="{Binding HideUi}" - Header="{locale:Locale MenuBarFileToolsHideUi}" - InputGesture="{Binding ShowUiKey}" - IsEnabled="{Binding IsGameRunning}" /> - <MenuItem - Click="OpenCheatManagerForCurrentApp" - Header="{locale:Locale GameListContextMenuManageCheat}" - IsEnabled="{Binding IsGameRunning}" /> - </MenuItem> - <MenuItem VerticalAlignment="Center" Header="{locale:Locale MenuBarTools}"> - <MenuItem Header="{locale:Locale MenuBarToolsInstallFirmware}" IsEnabled="{Binding EnableNonGameRunningControls}"> - <MenuItem Command="{Binding InstallFirmwareFromFile}" Header="{locale:Locale MenuBarFileToolsInstallFirmwareFromFile}" /> - <MenuItem Command="{Binding InstallFirmwareFromFolder}" Header="{locale:Locale MenuBarFileToolsInstallFirmwareFromDirectory}" /> - </MenuItem> - <MenuItem Header="{locale:Locale MenuBarToolsManageFileTypes}" IsVisible="{Binding ManageFileTypesVisible}"> - <MenuItem Header="{locale:Locale MenuBarToolsInstallFileTypes}" Click="InstallFileTypes_Click"/> - <MenuItem Header="{locale:Locale MenuBarToolsUninstallFileTypes}" Click="UninstallFileTypes_Click"/> - </MenuItem> - </MenuItem> - <MenuItem VerticalAlignment="Center" Header="{locale:Locale MenuBarHelp}"> - <MenuItem - Name="UpdateMenuItem" - IsEnabled="{Binding CanUpdate}" - Click="CheckForUpdates" - Header="{locale:Locale MenuBarHelpCheckForUpdates}" - ToolTip.Tip="{locale:Locale CheckUpdatesTooltip}" /> - <Separator /> - <MenuItem - Click="OpenAboutWindow" - Header="{locale:Locale MenuBarHelpAbout}" - ToolTip.Tip="{locale:Locale OpenAboutTooltip}" /> - </MenuItem> - </Menu> - </DockPanel> -</UserControl> diff --git a/src/Ryujinx.Ava/UI/Views/Main/MainMenuBarView.axaml.cs b/src/Ryujinx.Ava/UI/Views/Main/MainMenuBarView.axaml.cs deleted file mode 100644 index 8dff5086..00000000 --- a/src/Ryujinx.Ava/UI/Views/Main/MainMenuBarView.axaml.cs +++ /dev/null @@ -1,232 +0,0 @@ -using Avalonia; -using Avalonia.Controls; -using Avalonia.Interactivity; -using LibHac.Ncm; -using LibHac.Tools.FsSystem.NcaUtils; -using Ryujinx.Ava.Common.Locale; -using Ryujinx.Ava.UI.Helpers; -using Ryujinx.Ava.UI.ViewModels; -using Ryujinx.Ava.UI.Windows; -using Ryujinx.Common; -using Ryujinx.Common.Utilities; -using Ryujinx.Modules; -using Ryujinx.UI.Common; -using Ryujinx.UI.Common.Configuration; -using Ryujinx.UI.Common.Helper; -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; - -namespace Ryujinx.Ava.UI.Views.Main -{ - public partial class MainMenuBarView : UserControl - { - public MainWindow Window { get; private set; } - public MainWindowViewModel ViewModel { get; private set; } - - public MainMenuBarView() - { - InitializeComponent(); - - ToggleFileTypesMenuItem.ItemsSource = GenerateToggleFileTypeItems(); - ChangeLanguageMenuItem.ItemsSource = GenerateLanguageMenuItems(); - } - - private CheckBox[] GenerateToggleFileTypeItems() - { - List<CheckBox> checkBoxes = new(); - - foreach (var item in Enum.GetValues(typeof(FileTypes))) - { - string fileName = Enum.GetName(typeof(FileTypes), item); - checkBoxes.Add(new CheckBox - { - Content = $".{fileName}", - IsChecked = ((FileTypes)item).GetConfigValue(ConfigurationState.Instance.UI.ShownFileTypes), - Command = MiniCommand.Create(() => Window.ToggleFileType(fileName)), - }); - } - - return checkBoxes.ToArray(); - } - - private static MenuItem[] GenerateLanguageMenuItems() - { - List<MenuItem> menuItems = new(); - - string localePath = "Ryujinx.Ava/Assets/Locales"; - string localeExt = ".json"; - - string[] localesPath = EmbeddedResources.GetAllAvailableResources(localePath, localeExt); - - Array.Sort(localesPath); - - foreach (string locale in localesPath) - { - string languageCode = Path.GetFileNameWithoutExtension(locale).Split('.').Last(); - string languageJson = EmbeddedResources.ReadAllText($"{localePath}/{languageCode}{localeExt}"); - var strings = JsonHelper.Deserialize(languageJson, CommonJsonContext.Default.StringDictionary); - - if (!strings.TryGetValue("Language", out string languageName)) - { - languageName = languageCode; - } - - MenuItem menuItem = new() - { - Header = languageName, - Command = MiniCommand.Create(() => - { - MainWindowViewModel.ChangeLanguage(languageCode); - }), - }; - - menuItems.Add(menuItem); - } - - return menuItems.ToArray(); - } - - protected override void OnAttachedToVisualTree(VisualTreeAttachmentEventArgs e) - { - base.OnAttachedToVisualTree(e); - - if (VisualRoot is MainWindow window) - { - Window = window; - } - - ViewModel = Window.ViewModel; - DataContext = ViewModel; - } - - private async void StopEmulation_Click(object sender, RoutedEventArgs e) - { - await Window.ViewModel.AppHost?.ShowExitPrompt(); - } - - private void PauseEmulation_Click(object sender, RoutedEventArgs e) - { - Window.ViewModel.AppHost?.Pause(); - } - - private void ResumeEmulation_Click(object sender, RoutedEventArgs e) - { - Window.ViewModel.AppHost?.Resume(); - } - - public async void OpenSettings(object sender, RoutedEventArgs e) - { - Window.SettingsWindow = new(Window.VirtualFileSystem, Window.ContentManager); - - await Window.SettingsWindow.ShowDialog(Window); - - Window.SettingsWindow = null; - - ViewModel.LoadConfigurableHotKeys(); - } - - public async void OpenMiiApplet(object sender, RoutedEventArgs e) - { - string contentPath = ViewModel.ContentManager.GetInstalledContentPath(0x0100000000001009, StorageId.BuiltInSystem, NcaContentType.Program); - - if (!string.IsNullOrEmpty(contentPath)) - { - await ViewModel.LoadApplication(contentPath, false, "Mii Applet"); - } - } - - public async void OpenAmiiboWindow(object sender, RoutedEventArgs e) - { - if (!ViewModel.IsAmiiboRequested) - { - return; - } - - if (ViewModel.AppHost.Device.System.SearchingForAmiibo(out int deviceId)) - { - string titleId = ViewModel.AppHost.Device.Processes.ActiveApplication.ProgramIdText.ToUpper(); - AmiiboWindow window = new(ViewModel.ShowAll, ViewModel.LastScannedAmiiboId, titleId); - - await window.ShowDialog(Window); - - if (window.IsScanned) - { - ViewModel.ShowAll = window.ViewModel.ShowAllAmiibo; - ViewModel.LastScannedAmiiboId = window.ScannedAmiibo.GetId(); - - ViewModel.AppHost.Device.System.ScanAmiibo(deviceId, ViewModel.LastScannedAmiiboId, window.ViewModel.UseRandomUuid); - } - } - } - - public async void OpenCheatManagerForCurrentApp(object sender, RoutedEventArgs e) - { - if (!ViewModel.IsGameRunning) - { - return; - } - - string name = ViewModel.AppHost.Device.Processes.ActiveApplication.ApplicationControlProperties.Title[(int)ViewModel.AppHost.Device.System.State.DesiredTitleLanguage].NameString.ToString(); - - await new CheatWindow( - Window.VirtualFileSystem, - ViewModel.AppHost.Device.Processes.ActiveApplication.ProgramIdText, - name, - Window.ViewModel.SelectedApplication.Path).ShowDialog(Window); - - ViewModel.AppHost.Device.EnableCheats(); - } - - private void ScanAmiiboMenuItem_AttachedToVisualTree(object sender, VisualTreeAttachmentEventArgs e) - { - if (sender is MenuItem) - { - ViewModel.IsAmiiboRequested = Window.ViewModel.AppHost.Device.System.SearchingForAmiibo(out _); - } - } - - private async void InstallFileTypes_Click(object sender, RoutedEventArgs e) - { - if (FileAssociationHelper.Install()) - { - await ContentDialogHelper.CreateInfoDialog(LocaleManager.Instance[LocaleKeys.DialogInstallFileTypesSuccessMessage], string.Empty, LocaleManager.Instance[LocaleKeys.InputDialogOk], string.Empty, string.Empty); - } - else - { - await ContentDialogHelper.CreateErrorDialog(LocaleManager.Instance[LocaleKeys.DialogInstallFileTypesErrorMessage]); - } - } - - private async void UninstallFileTypes_Click(object sender, RoutedEventArgs e) - { - if (FileAssociationHelper.Uninstall()) - { - await ContentDialogHelper.CreateInfoDialog(LocaleManager.Instance[LocaleKeys.DialogUninstallFileTypesSuccessMessage], string.Empty, LocaleManager.Instance[LocaleKeys.InputDialogOk], string.Empty, string.Empty); - } - else - { - await ContentDialogHelper.CreateErrorDialog(LocaleManager.Instance[LocaleKeys.DialogUninstallFileTypesErrorMessage]); - } - } - - public async void CheckForUpdates(object sender, RoutedEventArgs e) - { - if (Updater.CanUpdate(true)) - { - await Updater.BeginParse(Window, true); - } - } - - public async void OpenAboutWindow(object sender, RoutedEventArgs e) - { - await AboutWindow.Show(); - } - - public void CloseWindow(object sender, RoutedEventArgs e) - { - Window.Close(); - } - } -} diff --git a/src/Ryujinx.Ava/UI/Views/Main/MainStatusBarView.axaml b/src/Ryujinx.Ava/UI/Views/Main/MainStatusBarView.axaml deleted file mode 100644 index f9e192e6..00000000 --- a/src/Ryujinx.Ava/UI/Views/Main/MainStatusBarView.axaml +++ /dev/null @@ -1,289 +0,0 @@ -<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:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" - xmlns:controls="clr-namespace:Ryujinx.Ava.UI.Controls" - xmlns:locale="clr-namespace:Ryujinx.Ava.Common.Locale" - xmlns:ui="clr-namespace:FluentAvalonia.UI.Controls;assembly=FluentAvalonia" - xmlns:viewModels="clr-namespace:Ryujinx.Ava.UI.ViewModels" - xmlns:config="clr-namespace:Ryujinx.Common.Configuration;assembly=Ryujinx.Common" - mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450" - x:Class="Ryujinx.Ava.UI.Views.Main.MainStatusBarView" - x:DataType="viewModels:MainWindowViewModel"> - <Design.DataContext> - <viewModels:MainWindowViewModel /> - </Design.DataContext> - <Grid - Name="StatusBar" - Margin="0" - MinHeight="22" - HorizontalAlignment="Stretch" - VerticalAlignment="Bottom" - Background="{DynamicResource ThemeContentBackgroundColor}" - DockPanel.Dock="Bottom" - IsVisible="{Binding ShowMenuAndStatusBar}"> - <Grid.ColumnDefinitions> - <ColumnDefinition Width="Auto" /> - <ColumnDefinition Width="Auto" /> - <ColumnDefinition Width="*" /> - <ColumnDefinition Width="Auto" /> - </Grid.ColumnDefinitions> - <StackPanel - Grid.Column="0" - Margin="5" - VerticalAlignment="Center" - IsVisible="{Binding EnableNonGameRunningControls}"> - <Grid Margin="0"> - <Grid.ColumnDefinitions> - <ColumnDefinition Width="Auto" /> - <ColumnDefinition Width="Auto" /> - <ColumnDefinition /> - </Grid.ColumnDefinitions> - <Button - Width="25" - Height="25" - MinWidth="0" - Margin="0,0,5,0" - VerticalAlignment="Center" - Background="Transparent" - Click="Refresh_OnClick"> - <ui:SymbolIcon - Width="50" - Height="100" - Symbol="Refresh" /> - </Button> - <TextBlock - Name="LoadStatus" - Grid.Column="1" - Margin="0,0,5,0" - VerticalAlignment="Center" - IsVisible="{Binding EnableNonGameRunningControls}" - Text="{locale:Locale StatusBarGamesLoaded}" /> - <ProgressBar - Name="LoadProgressBar" - Grid.Column="2" - Height="6" - VerticalAlignment="Center" - Foreground="{DynamicResource SystemAccentColorLight2}" - IsVisible="{Binding StatusBarVisible}" - Maximum="{Binding StatusBarProgressMaximum}" - Value="{Binding StatusBarProgressValue}" /> - </Grid> - </StackPanel> - <StackPanel - Grid.Column="1" - Margin="0,2" - HorizontalAlignment="Left" - VerticalAlignment="Center" - IsVisible="{Binding IsGameRunning}" - MaxHeight="18" - Orientation="Horizontal"> - <TextBlock - Name="VsyncStatus" - Margin="5,0,5,0" - HorizontalAlignment="Left" - VerticalAlignment="Center" - Foreground="{Binding VsyncColor}" - IsVisible="{Binding !ShowLoadProgress}" - PointerReleased="VsyncStatus_PointerReleased" - Text="VSync" - TextAlignment="Start" /> - <Border - Width="2" - Height="12" - Margin="0" - BorderBrush="Gray" - Background="Gray" - BorderThickness="1" - IsVisible="{Binding !ShowLoadProgress}" /> - <TextBlock - Name="DockedStatus" - Margin="5,0,5,0" - HorizontalAlignment="Left" - VerticalAlignment="Center" - IsVisible="{Binding !ShowLoadProgress}" - PointerReleased="DockedStatus_PointerReleased" - Text="{Binding DockedStatusText}" - TextAlignment="Start" /> - <Border - Width="2" - Height="12" - Margin="0" - BorderBrush="Gray" - Background="Gray" - BorderThickness="1" - IsVisible="{Binding !ShowLoadProgress}" /> - <SplitButton - Name="AspectRatioStatus" - Padding="5,0,5,0" - HorizontalAlignment="Left" - VerticalAlignment="Center" - Background="Transparent" - BorderThickness="0" - CornerRadius="0" - IsVisible="{Binding !ShowLoadProgress}" - Content="{Binding AspectRatioStatusText}" - Click="AspectRatioStatus_OnClick" - ToolTip.Tip="{locale:Locale AspectRatioTooltip}"> - <SplitButton.Styles> - <Style Selector="Border#SeparatorBorder"> - <Setter Property="Opacity" Value="0" /> - </Style> - </SplitButton.Styles> - <SplitButton.Flyout> - <MenuFlyout Placement="Bottom" ShowMode="TransientWithDismissOnPointerMoveAway"> - <MenuItem - Header="{locale:Locale SettingsTabGraphicsAspectRatio4x3}" - Command="{Binding SetAspectRatio}" - CommandParameter="{x:Static config:AspectRatio.Fixed4x3}"/> - <MenuItem - Header="{locale:Locale SettingsTabGraphicsAspectRatio16x9}" - Command="{Binding SetAspectRatio}" - CommandParameter="{x:Static config:AspectRatio.Fixed16x9}"/> - <MenuItem - Header="{locale:Locale SettingsTabGraphicsAspectRatio16x10}" - Command="{Binding SetAspectRatio}" - CommandParameter="{x:Static config:AspectRatio.Fixed16x10}"/> - <MenuItem - Header="{locale:Locale SettingsTabGraphicsAspectRatio21x9}" - Command="{Binding SetAspectRatio}" - CommandParameter="{x:Static config:AspectRatio.Fixed21x9}"/> - <MenuItem - Header="{locale:Locale SettingsTabGraphicsAspectRatio32x9}" - Command="{Binding SetAspectRatio}" - CommandParameter="{x:Static config:AspectRatio.Fixed32x9}"/> - <MenuItem - Header="{locale:Locale SettingsTabGraphicsAspectRatioStretch}" - Command="{Binding SetAspectRatio}" - CommandParameter="{x:Static config:AspectRatio.Stretched}"/> - </MenuFlyout> - </SplitButton.Flyout> - </SplitButton> - <Border - Width="2" - Height="12" - Margin="0" - BorderBrush="Gray" - Background="Gray" - BorderThickness="1" - IsVisible="{Binding !ShowLoadProgress}" /> - <ToggleSplitButton - Name="VolumeStatus" - Padding="5,0,5,0" - HorizontalAlignment="Left" - VerticalAlignment="Center" - VerticalContentAlignment="Center" - Content="{Binding VolumeStatusText}" - IsChecked="{Binding VolumeMuted}" - IsVisible="{Binding !ShowLoadProgress}" - PointerWheelChanged="VolumeStatus_OnPointerWheelChanged" - Background="Transparent" - BorderThickness="0" - CornerRadius="0"> - <ToggleSplitButton.Styles> - <Style Selector=":checked"> - <Style Selector="^:checked ContentPresenter"> - <Setter Property="Foreground" Value="{DynamicResource ThemeForegroundColor}" /> - </Style> - </Style> - <Style Selector="Border#SeparatorBorder"> - <Setter Property="Opacity" Value="0" /> - </Style> - </ToggleSplitButton.Styles> - <ToggleSplitButton.Flyout> - <Flyout Placement="Bottom" ShowMode="TransientWithDismissOnPointerMoveAway"> - <Grid Margin="0"> - <controls:SliderScroll - MaxHeight="40" - Width="150" - Margin="0" - Padding="0" - IsSnapToTickEnabled="True" - LargeChange="0.05" - Maximum="1" - Minimum="0" - SmallChange="0.01" - TickFrequency="0.05" - ToolTip.Tip="{locale:Locale AudioVolumeTooltip}" - Value="{Binding Volume}" /> - </Grid> - </Flyout> - </ToggleSplitButton.Flyout> - </ToggleSplitButton> - <Border - Width="2" - Height="12" - Margin="0" - BorderBrush="Gray" - Background="Gray" - BorderThickness="1" - IsVisible="{Binding !ShowLoadProgress}" /> - <TextBlock - Margin="5,0,5,0" - HorizontalAlignment="Left" - VerticalAlignment="Center" - IsVisible="{Binding !ShowLoadProgress}" - Text="{Binding GameStatusText}" - TextAlignment="Start" /> - <Border - Width="2" - Height="12" - Margin="0" - BorderBrush="Gray" - Background="Gray" - BorderThickness="1" - IsVisible="{Binding !ShowLoadProgress}" /> - <TextBlock - Margin="5,0,5,0" - HorizontalAlignment="Left" - VerticalAlignment="Center" - IsVisible="{Binding !ShowLoadProgress}" - Text="{Binding FifoStatusText}" - TextAlignment="Start" /> - <Border - Width="2" - Height="12" - Margin="0" - BorderBrush="Gray" - Background="Gray" - BorderThickness="1" - IsVisible="{Binding !ShowLoadProgress}" /> - <TextBlock - Margin="5,0,5,0" - HorizontalAlignment="Left" - VerticalAlignment="Center" - IsVisible="{Binding !ShowLoadProgress}" - Text="{Binding BackendText}" - TextAlignment="Start" /> - <Border - Width="2" - Height="12" - Margin="0" - BorderBrush="Gray" - Background="Gray" - BorderThickness="1" - IsVisible="{Binding !ShowLoadProgress}" /> - <TextBlock - Margin="5,0,5,0" - HorizontalAlignment="Left" - VerticalAlignment="Center" - IsVisible="{Binding !ShowLoadProgress}" - Text="{Binding GpuNameText}" - TextAlignment="Start" /> - </StackPanel> - <StackPanel - Grid.Column="3" - Margin="0,0,5,0" - VerticalAlignment="Center" - IsVisible="{Binding ShowFirmwareStatus}" - Orientation="Horizontal"> - <TextBlock - Name="FirmwareStatus" - Margin="0" - HorizontalAlignment="Right" - VerticalAlignment="Center" - Text="{locale:Locale StatusBarSystemVersion}" /> - </StackPanel> - </Grid> -</UserControl> diff --git a/src/Ryujinx.Ava/UI/Views/Main/MainStatusBarView.axaml.cs b/src/Ryujinx.Ava/UI/Views/Main/MainStatusBarView.axaml.cs deleted file mode 100644 index 239a7cbf..00000000 --- a/src/Ryujinx.Ava/UI/Views/Main/MainStatusBarView.axaml.cs +++ /dev/null @@ -1,72 +0,0 @@ -using Avalonia; -using Avalonia.Controls; -using Avalonia.Input; -using Avalonia.Interactivity; -using Ryujinx.Ava.UI.Windows; -using Ryujinx.Common.Configuration; -using Ryujinx.Common.Logging; -using Ryujinx.UI.Common.Configuration; -using System; - -namespace Ryujinx.Ava.UI.Views.Main -{ - public partial class MainStatusBarView : UserControl - { - public MainWindow Window; - - public MainStatusBarView() - { - InitializeComponent(); - } - - protected override void OnAttachedToVisualTree(VisualTreeAttachmentEventArgs e) - { - base.OnAttachedToVisualTree(e); - - if (VisualRoot is MainWindow window) - { - Window = window; - } - - DataContext = Window.ViewModel; - } - - private void VsyncStatus_PointerReleased(object sender, PointerReleasedEventArgs e) - { - Window.ViewModel.AppHost.Device.EnableDeviceVsync = !Window.ViewModel.AppHost.Device.EnableDeviceVsync; - - Logger.Info?.Print(LogClass.Application, $"VSync toggled to: {Window.ViewModel.AppHost.Device.EnableDeviceVsync}"); - } - - private void DockedStatus_PointerReleased(object sender, PointerReleasedEventArgs e) - { - ConfigurationState.Instance.System.EnableDockedMode.Value = !ConfigurationState.Instance.System.EnableDockedMode.Value; - } - - private void AspectRatioStatus_OnClick(object sender, RoutedEventArgs e) - { - AspectRatio aspectRatio = ConfigurationState.Instance.Graphics.AspectRatio.Value; - ConfigurationState.Instance.Graphics.AspectRatio.Value = (int)aspectRatio + 1 > Enum.GetNames(typeof(AspectRatio)).Length - 1 ? AspectRatio.Fixed4x3 : aspectRatio + 1; - } - - private void Refresh_OnClick(object sender, RoutedEventArgs e) - { - Window.LoadApplications(); - } - - private void VolumeStatus_OnPointerWheelChanged(object sender, PointerWheelEventArgs e) - { - // Change the volume by 5% at a time - float newValue = Window.ViewModel.Volume + (float)e.Delta.Y * 0.05f; - - Window.ViewModel.Volume = newValue switch - { - < 0 => 0, - > 1 => 1, - _ => newValue, - }; - - e.Handled = true; - } - } -} diff --git a/src/Ryujinx.Ava/UI/Views/Main/MainViewControls.axaml b/src/Ryujinx.Ava/UI/Views/Main/MainViewControls.axaml deleted file mode 100644 index cc21b5c6..00000000 --- a/src/Ryujinx.Ava/UI/Views/Main/MainViewControls.axaml +++ /dev/null @@ -1,177 +0,0 @@ -<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:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" - xmlns:controls="clr-namespace:Ryujinx.Ava.UI.Controls" - xmlns:ui="clr-namespace:FluentAvalonia.UI.Controls;assembly=FluentAvalonia" - xmlns:helpers="clr-namespace:Ryujinx.Ava.UI.Helpers" - xmlns:locale="clr-namespace:Ryujinx.Ava.Common.Locale" - xmlns:viewModels="clr-namespace:Ryujinx.Ava.UI.ViewModels" - mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450" - x:Class="Ryujinx.Ava.UI.Views.Main.MainViewControls" - x:DataType="viewModels:MainWindowViewModel"> - <Design.DataContext> - <viewModels:MainWindowViewModel /> - </Design.DataContext> - <DockPanel - Margin="0,0,0,5" - Height="35" - HorizontalAlignment="Stretch"> - <Button - Width="40" - MinWidth="40" - Margin="5,2,0,2" - VerticalAlignment="Stretch" - Command="{Binding SetListMode}" - IsEnabled="{Binding IsGrid}"> - <ui:FontIcon - Margin="0" - HorizontalAlignment="Stretch" - VerticalAlignment="Center" - FontFamily="avares://FluentAvalonia/Fonts#Symbols" - Glyph="{helpers:GlyphValueConverter List}" /> - </Button> - <Button - Width="40" - MinWidth="40" - Margin="5,2,5,2" - VerticalAlignment="Stretch" - Command="{Binding SetGridMode}" - IsEnabled="{Binding IsList}"> - <ui:FontIcon - Margin="0" - HorizontalAlignment="Stretch" - VerticalAlignment="Center" - FontFamily="avares://FluentAvalonia/Fonts#Symbols" - Glyph="{helpers:GlyphValueConverter Grid}" /> - </Button> - <TextBlock - Margin="10,0" - VerticalAlignment="Center" - Text="{locale:Locale IconSize}" - ToolTip.Tip="{locale:Locale IconSizeTooltip}" /> - <controls:SliderScroll - Width="150" - Height="35" - Margin="5,-10,5,0" - VerticalAlignment="Center" - IsSnapToTickEnabled="True" - SmallChange="1" - Maximum="4" - Minimum="1" - TickFrequency="1" - ToolTip.Tip="{locale:Locale IconSizeTooltip}" - Value="{Binding GridSizeScale}" /> - <CheckBox - Margin="0" - VerticalAlignment="Center" - IsChecked="{Binding ShowNames, Mode=TwoWay}" - IsVisible="{Binding IsGrid}"> - <TextBlock Margin="5,3,0,0" Text="{locale:Locale CommonShowNames}" /> - </CheckBox> - <TextBox - Name="SearchBox" - MinWidth="200" - Margin="5,0,5,0" - HorizontalAlignment="Right" - VerticalAlignment="Center" - DockPanel.Dock="Right" - KeyUp="SearchBox_OnKeyUp" - Text="{Binding SearchText}" - Watermark="{locale:Locale MenuSearch}" /> - <DropDownButton - Width="150" - HorizontalAlignment="Right" - VerticalAlignment="Center" - Content="{Binding SortName}" - DockPanel.Dock="Right"> - <DropDownButton.Flyout> - <Flyout Placement="Bottom"> - <StackPanel - Margin="0" - HorizontalAlignment="Stretch" - Orientation="Vertical"> - <StackPanel> - <RadioButton - Checked="Sort_Checked" - Content="{locale:Locale CommonFavorite}" - GroupName="Sort" - IsChecked="{Binding IsSortedByFavorite, Mode=OneTime}" - Tag="Favorite" /> - <RadioButton - Checked="Sort_Checked" - Content="{locale:Locale GameListHeaderApplication}" - GroupName="Sort" - IsChecked="{Binding IsSortedByTitle, Mode=OneTime}" - Tag="Title" /> - <RadioButton - Checked="Sort_Checked" - Content="{locale:Locale GameListHeaderDeveloper}" - GroupName="Sort" - IsChecked="{Binding IsSortedByDeveloper, Mode=OneTime}" - Tag="Developer" /> - <RadioButton - Checked="Sort_Checked" - Content="{locale:Locale GameListHeaderTimePlayed}" - GroupName="Sort" - IsChecked="{Binding IsSortedByTimePlayed, Mode=OneTime}" - Tag="TotalTimePlayed" /> - <RadioButton - Checked="Sort_Checked" - Content="{locale:Locale GameListHeaderLastPlayed}" - GroupName="Sort" - IsChecked="{Binding IsSortedByLastPlayed, Mode=OneTime}" - Tag="LastPlayed" /> - <RadioButton - Checked="Sort_Checked" - Content="{locale:Locale GameListHeaderFileExtension}" - GroupName="Sort" - IsChecked="{Binding IsSortedByType, Mode=OneTime}" - Tag="FileType" /> - <RadioButton - Checked="Sort_Checked" - Content="{locale:Locale GameListHeaderFileSize}" - GroupName="Sort" - IsChecked="{Binding IsSortedBySize, Mode=OneTime}" - Tag="FileSize" /> - <RadioButton - Checked="Sort_Checked" - Content="{locale:Locale GameListHeaderPath}" - GroupName="Sort" - IsChecked="{Binding IsSortedByPath, Mode=OneTime}" - Tag="Path" /> - </StackPanel> - <Border - Width="60" - Height="2" - Margin="5" - HorizontalAlignment="Stretch" - BorderBrush="White" - BorderThickness="0,1,0,0"> - <Separator Height="0" HorizontalAlignment="Stretch" /> - </Border> - <RadioButton - Checked="Order_Checked" - Content="{locale:Locale OrderAscending}" - GroupName="Order" - IsChecked="{Binding IsAscending, Mode=OneTime}" - Tag="Ascending" /> - <RadioButton - Checked="Order_Checked" - Content="{locale:Locale OrderDescending}" - GroupName="Order" - IsChecked="{Binding !IsAscending, Mode=OneTime}" - Tag="Descending" /> - </StackPanel> - </Flyout> - </DropDownButton.Flyout> - </DropDownButton> - <TextBlock - Margin="10,0" - HorizontalAlignment="Right" - VerticalAlignment="Center" - DockPanel.Dock="Right" - Text="{locale:Locale CommonSort}" /> - </DockPanel> -</UserControl> diff --git a/src/Ryujinx.Ava/UI/Views/Main/MainViewControls.axaml.cs b/src/Ryujinx.Ava/UI/Views/Main/MainViewControls.axaml.cs deleted file mode 100644 index 02fd1bf5..00000000 --- a/src/Ryujinx.Ava/UI/Views/Main/MainViewControls.axaml.cs +++ /dev/null @@ -1,54 +0,0 @@ -using Avalonia; -using Avalonia.Controls; -using Avalonia.Input; -using Avalonia.Interactivity; -using Ryujinx.Ava.Common; -using Ryujinx.Ava.UI.ViewModels; -using Ryujinx.Ava.UI.Windows; -using System; - -namespace Ryujinx.Ava.UI.Views.Main -{ - public partial class MainViewControls : UserControl - { - public MainWindowViewModel ViewModel; - - public MainViewControls() - { - InitializeComponent(); - } - - protected override void OnAttachedToVisualTree(VisualTreeAttachmentEventArgs e) - { - base.OnAttachedToVisualTree(e); - - if (VisualRoot is MainWindow window) - { - ViewModel = window.ViewModel; - } - - DataContext = ViewModel; - } - - public void Sort_Checked(object sender, RoutedEventArgs args) - { - if (sender is RadioButton button) - { - ViewModel.Sort(Enum.Parse<ApplicationSort>(button.Tag.ToString())); - } - } - - public void Order_Checked(object sender, RoutedEventArgs args) - { - if (sender is RadioButton button) - { - ViewModel.Sort(button.Tag.ToString() != "Descending"); - } - } - - private void SearchBox_OnKeyUp(object sender, KeyEventArgs e) - { - ViewModel.SearchText = SearchBox.Text; - } - } -} diff --git a/src/Ryujinx.Ava/UI/Views/Settings/SettingsAudioView.axaml b/src/Ryujinx.Ava/UI/Views/Settings/SettingsAudioView.axaml deleted file mode 100644 index 657e07ee..00000000 --- a/src/Ryujinx.Ava/UI/Views/Settings/SettingsAudioView.axaml +++ /dev/null @@ -1,81 +0,0 @@ -<UserControl - x:Class="Ryujinx.Ava.UI.Views.Settings.SettingsAudioView" - xmlns="https://github.com/avaloniaui" - xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" - xmlns:d="http://schemas.microsoft.com/expression/blend/2008" - xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" - xmlns:controls="clr-namespace:Ryujinx.Ava.UI.Controls" - xmlns:ui="clr-namespace:FluentAvalonia.UI.Controls;assembly=FluentAvalonia" - xmlns:locale="clr-namespace:Ryujinx.Ava.Common.Locale" - xmlns:viewModels="clr-namespace:Ryujinx.Ava.UI.ViewModels" - mc:Ignorable="d" - x:DataType="viewModels:SettingsViewModel"> - <Design.DataContext> - <viewModels:SettingsViewModel /> - </Design.DataContext> - <ScrollViewer - Name="AudioPage" - HorizontalAlignment="Stretch" - VerticalAlignment="Stretch" - HorizontalScrollBarVisibility="Disabled" - VerticalScrollBarVisibility="Auto"> - <Border Classes="settings"> - <StackPanel - Margin="10" - HorizontalAlignment="Stretch" - Orientation="Vertical" - Spacing="10"> - <TextBlock Classes="h1" Text="{locale:Locale SettingsTabAudio}" /> - <StackPanel Margin="10,0,0,0" Orientation="Horizontal"> - <TextBlock VerticalAlignment="Center" - Text="{locale:Locale SettingsTabSystemAudioBackend}" - ToolTip.Tip="{locale:Locale AudioBackendTooltip}" - Width="250" /> - <ComboBox SelectedIndex="{Binding AudioBackend}" - Width="350" - HorizontalContentAlignment="Left"> - <ComboBoxItem> - <TextBlock Text="{locale:Locale SettingsTabSystemAudioBackendDummy}" /> - </ComboBoxItem> - <ComboBoxItem IsEnabled="{Binding IsOpenAlEnabled}"> - <TextBlock Text="{locale:Locale SettingsTabSystemAudioBackendOpenAL}" /> - </ComboBoxItem> - <ComboBoxItem IsEnabled="{Binding IsSoundIoEnabled}"> - <TextBlock Text="{locale:Locale SettingsTabSystemAudioBackendSoundIO}" /> - </ComboBoxItem> - <ComboBoxItem IsEnabled="{Binding IsSDL2Enabled}"> - <TextBlock Text="{locale:Locale SettingsTabSystemAudioBackendSDL2}" /> - </ComboBoxItem> - </ComboBox> - </StackPanel> - <StackPanel Margin="10,0,0,0" Orientation="Horizontal"> - <TextBlock VerticalAlignment="Center" - Text="{locale:Locale SettingsTabSystemAudioVolume}" - ToolTip.Tip="{locale:Locale AudioVolumeTooltip}" - Width="250" /> - <ui:NumberBox Value="{Binding Volume}" - ToolTip.Tip="{locale:Locale AudioVolumeTooltip}" - Width="350" - SmallChange="1" - LargeChange="10" - SimpleNumberFormat="F0" - SpinButtonPlacementMode="Inline" - Minimum="0" - Maximum="100" /> - </StackPanel> - <StackPanel Margin="10,0,0,0" Orientation="Horizontal"> - <controls:SliderScroll Value="{Binding Volume}" - Margin="250,0,0,0" - ToolTip.Tip="{locale:Locale AudioVolumeTooltip}" - Minimum="0" - Maximum="100" - SmallChange="1" - TickFrequency="1" - IsSnapToTickEnabled="True" - LargeChange="10" - Width="350" /> - </StackPanel> - </StackPanel> - </Border> - </ScrollViewer> -</UserControl> diff --git a/src/Ryujinx.Ava/UI/Views/Settings/SettingsAudioView.axaml.cs b/src/Ryujinx.Ava/UI/Views/Settings/SettingsAudioView.axaml.cs deleted file mode 100644 index b672a0f2..00000000 --- a/src/Ryujinx.Ava/UI/Views/Settings/SettingsAudioView.axaml.cs +++ /dev/null @@ -1,12 +0,0 @@ -using Avalonia.Controls; - -namespace Ryujinx.Ava.UI.Views.Settings -{ - public partial class SettingsAudioView : UserControl - { - public SettingsAudioView() - { - InitializeComponent(); - } - } -} diff --git a/src/Ryujinx.Ava/UI/Views/Settings/SettingsCPUView.axaml b/src/Ryujinx.Ava/UI/Views/Settings/SettingsCPUView.axaml deleted file mode 100644 index c74d3dd5..00000000 --- a/src/Ryujinx.Ava/UI/Views/Settings/SettingsCPUView.axaml +++ /dev/null @@ -1,77 +0,0 @@ -<UserControl - x:Class="Ryujinx.Ava.UI.Views.Settings.SettingsCPUView" - xmlns="https://github.com/avaloniaui" - xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" - xmlns:d="http://schemas.microsoft.com/expression/blend/2008" - xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" - xmlns:locale="clr-namespace:Ryujinx.Ava.Common.Locale" - xmlns:viewModels="clr-namespace:Ryujinx.Ava.UI.ViewModels" - mc:Ignorable="d" - x:DataType="viewModels:SettingsViewModel"> - <Design.DataContext> - <viewModels:SettingsViewModel /> - </Design.DataContext> - <ScrollViewer - Name="CpuPage" - HorizontalAlignment="Stretch" - VerticalAlignment="Stretch" - HorizontalScrollBarVisibility="Disabled" - VerticalScrollBarVisibility="Auto"> - <Border Classes="settings"> - <StackPanel - Margin="10" - HorizontalAlignment="Stretch" - Orientation="Vertical" - Spacing="10"> - <TextBlock Classes="h1" Text="{locale:Locale SettingsTabCpuCache}" /> - <StackPanel - Margin="10,0,0,0" - HorizontalAlignment="Stretch" - Orientation="Vertical"> - <CheckBox IsChecked="{Binding EnablePptc}"> - <TextBlock Text="{locale:Locale SettingsTabSystemEnablePptc}" - ToolTip.Tip="{locale:Locale PptcToggleTooltip}" /> - </CheckBox> - </StackPanel> - <Separator Height="1" /> - <TextBlock Classes="h1" Text="{locale:Locale SettingsTabCpuMemory}" /> - <StackPanel - Margin="10,0,0,0" - HorizontalAlignment="Stretch" - Orientation="Vertical"> - <StackPanel Orientation="Horizontal"> - <TextBlock VerticalAlignment="Center" - Text="{locale:Locale SettingsTabSystemMemoryManagerMode}" - ToolTip.Tip="{locale:Locale MemoryManagerTooltip}" - Width="250" /> - <ComboBox SelectedIndex="{Binding MemoryMode}" - ToolTip.Tip="{locale:Locale MemoryManagerTooltip}" - HorizontalContentAlignment="Left" - Width="350"> - <ComboBoxItem - ToolTip.Tip="{locale:Locale MemoryManagerSoftwareTooltip}"> - <TextBlock - Text="{locale:Locale SettingsTabSystemMemoryManagerModeSoftware}" /> - </ComboBoxItem> - <ComboBoxItem - ToolTip.Tip="{locale:Locale MemoryManagerHostTooltip}"> - <TextBlock Text="{locale:Locale SettingsTabSystemMemoryManagerModeHost}" /> - </ComboBoxItem> - <ComboBoxItem - ToolTip.Tip="{locale:Locale MemoryManagerUnsafeTooltip}"> - <TextBlock - Text="{locale:Locale SettingsTabSystemMemoryManagerModeHostUnchecked}" /> - </ComboBoxItem> - </ComboBox> - </StackPanel> - <CheckBox IsChecked="{Binding UseHypervisor}" - IsVisible="{Binding IsHypervisorAvailable}" - ToolTip.Tip="{locale:Locale UseHypervisorTooltip}"> - <TextBlock Text="{locale:Locale SettingsTabSystemUseHypervisor}" - ToolTip.Tip="{locale:Locale UseHypervisorTooltip}" /> - </CheckBox> - </StackPanel> - </StackPanel> - </Border> - </ScrollViewer> -</UserControl> diff --git a/src/Ryujinx.Ava/UI/Views/Settings/SettingsCPUView.axaml.cs b/src/Ryujinx.Ava/UI/Views/Settings/SettingsCPUView.axaml.cs deleted file mode 100644 index a475971a..00000000 --- a/src/Ryujinx.Ava/UI/Views/Settings/SettingsCPUView.axaml.cs +++ /dev/null @@ -1,12 +0,0 @@ -using Avalonia.Controls; - -namespace Ryujinx.Ava.UI.Views.Settings -{ - public partial class SettingsCPUView : UserControl - { - public SettingsCPUView() - { - InitializeComponent(); - } - } -} diff --git a/src/Ryujinx.Ava/UI/Views/Settings/SettingsGraphicsView.axaml b/src/Ryujinx.Ava/UI/Views/Settings/SettingsGraphicsView.axaml deleted file mode 100644 index 22449478..00000000 --- a/src/Ryujinx.Ava/UI/Views/Settings/SettingsGraphicsView.axaml +++ /dev/null @@ -1,301 +0,0 @@ -<UserControl - x:Class="Ryujinx.Ava.UI.Views.Settings.SettingsGraphicsView" - xmlns="https://github.com/avaloniaui" - xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" - xmlns:d="http://schemas.microsoft.com/expression/blend/2008" - xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" - xmlns:controls="clr-namespace:Ryujinx.Ava.UI.Controls" - xmlns:ui="clr-namespace:FluentAvalonia.UI.Controls;assembly=FluentAvalonia" - xmlns:locale="clr-namespace:Ryujinx.Ava.Common.Locale" - xmlns:viewModels="clr-namespace:Ryujinx.Ava.UI.ViewModels" - Design.Width="1000" - mc:Ignorable="d" - x:DataType="viewModels:SettingsViewModel"> - <Design.DataContext> - <viewModels:SettingsViewModel /> - </Design.DataContext> - <ScrollViewer - Name="GraphicsPage" - HorizontalAlignment="Stretch" - VerticalAlignment="Stretch" - HorizontalScrollBarVisibility="Disabled" - VerticalScrollBarVisibility="Auto"> - <Border Classes="settings"> - <StackPanel - Margin="10" - HorizontalAlignment="Stretch" - Orientation="Vertical" - Spacing="10"> - <TextBlock Classes="h1" Text="{locale:Locale SettingsTabGraphicsAPI}" /> - <StackPanel Margin="10,0,0,0" Orientation="Vertical" Spacing="10"> - <StackPanel Orientation="Horizontal"> - <TextBlock VerticalAlignment="Center" - ToolTip.Tip="{locale:Locale SettingsTabGraphicsBackendTooltip}" - Text="{locale:Locale SettingsTabGraphicsBackend}" - Width="250" /> - <ComboBox Width="350" - HorizontalContentAlignment="Left" - ToolTip.Tip="{locale:Locale SettingsTabGraphicsBackendTooltip}" - SelectedIndex="{Binding GraphicsBackendIndex}"> - <ComboBoxItem IsVisible="{Binding IsVulkanAvailable}"> - <TextBlock Text="Vulkan" /> - </ComboBoxItem> - <ComboBoxItem IsEnabled="{Binding IsOpenGLAvailable}"> - <TextBlock Text="OpenGL" /> - </ComboBoxItem> - </ComboBox> - </StackPanel> - <StackPanel Orientation="Horizontal" IsVisible="{Binding IsVulkanSelected}"> - <TextBlock VerticalAlignment="Center" - ToolTip.Tip="{locale:Locale SettingsTabGraphicsPreferredGpuTooltip}" - Text="{locale:Locale SettingsTabGraphicsPreferredGpu}" - Width="250" /> - <ComboBox Width="350" - HorizontalContentAlignment="Left" - ToolTip.Tip="{locale:Locale SettingsTabGraphicsPreferredGpuTooltip}" - SelectedIndex="{Binding PreferredGpuIndex}" - ItemsSource="{Binding AvailableGpus}"/> - </StackPanel> - </StackPanel> - <Separator Height="1" /> - <TextBlock Classes="h1" Text="{locale:Locale SettingsTabGraphicsFeatures}" /> - <StackPanel Margin="10,0,0,0" Orientation="Vertical" Spacing="10"> - <StackPanel Orientation="Vertical"> - <CheckBox IsChecked="{Binding EnableShaderCache}" - ToolTip.Tip="{locale:Locale ShaderCacheToggleTooltip}"> - <TextBlock Text="{locale:Locale SettingsTabGraphicsEnableShaderCache}" /> - </CheckBox> - <CheckBox IsChecked="{Binding EnableTextureRecompression}" - ToolTip.Tip="{locale:Locale SettingsEnableTextureRecompressionTooltip}"> - <TextBlock Text="{locale:Locale SettingsEnableTextureRecompression}" /> - </CheckBox> - <CheckBox IsChecked="{Binding EnableMacroHLE}" - ToolTip.Tip="{locale:Locale SettingsEnableMacroHLETooltip}"> - <TextBlock Text="{locale:Locale SettingsEnableMacroHLE}" /> - </CheckBox> - <CheckBox IsChecked="{Binding EnableColorSpacePassthrough}" - IsVisible="{Binding ColorSpacePassthroughAvailable}" - ToolTip.Tip="{locale:Locale SettingsEnableColorSpacePassthroughTooltip}"> - <TextBlock Text="{locale:Locale SettingsEnableColorSpacePassthrough}" /> - </CheckBox> - </StackPanel> - <StackPanel Orientation="Horizontal"> - <TextBlock VerticalAlignment="Center" - ToolTip.Tip="{locale:Locale ResolutionScaleTooltip}" - Text="{locale:Locale SettingsTabGraphicsResolutionScale}" - Width="250" /> - <ComboBox SelectedIndex="{Binding ResolutionScale}" - Width="350" - HorizontalContentAlignment="Left" - ToolTip.Tip="{locale:Locale ResolutionScaleTooltip}"> - <ComboBoxItem> - <TextBlock Text="{locale:Locale SettingsTabGraphicsResolutionScaleNative}" /> - </ComboBoxItem> - <ComboBoxItem> - <TextBlock Text="{locale:Locale SettingsTabGraphicsResolutionScale2x}" /> - </ComboBoxItem> - <ComboBoxItem> - <TextBlock Text="{locale:Locale SettingsTabGraphicsResolutionScale3x}" /> - </ComboBoxItem> - <ComboBoxItem> - <TextBlock Text="{locale:Locale SettingsTabGraphicsResolutionScale4x}" /> - </ComboBoxItem> - <ComboBoxItem> - <TextBlock Text="{locale:Locale SettingsTabGraphicsResolutionScaleCustom}" /> - </ComboBoxItem> - </ComboBox> - <ui:NumberBox - Margin="10,0,0,0" - ToolTip.Tip="{locale:Locale ResolutionScaleEntryTooltip}" - MinWidth="150" - SmallChange="0.1" - LargeChange="1" - SimpleNumberFormat="F2" - SpinButtonPlacementMode="Inline" - IsVisible="{Binding IsCustomResolutionScaleActive}" - Maximum="100" - Minimum="0.1" - Value="{Binding CustomResolutionScale}" /> - </StackPanel> - <StackPanel - HorizontalAlignment="Stretch" - Orientation="Vertical" - Spacing="10"> - <StackPanel Orientation="Horizontal"> - <TextBlock VerticalAlignment="Center" - ToolTip.Tip="{locale:Locale GraphicsAATooltip}" - Text="{locale:Locale GraphicsAALabel}" - Width="250" /> - <ComboBox Width="350" - HorizontalContentAlignment="Left" - ToolTip.Tip="{locale:Locale GraphicsAATooltip}" - SelectedIndex="{Binding AntiAliasingEffect}"> - <ComboBoxItem> - <TextBlock Text="{locale:Locale SettingsTabLoggingGraphicsBackendLogLevelNone}" /> - </ComboBoxItem> - <ComboBoxItem> - <TextBlock Text="FXAA" /> - </ComboBoxItem> - <ComboBoxItem> - <TextBlock Text="{locale:Locale SmaaLow}" /> - </ComboBoxItem> - <ComboBoxItem> - <TextBlock Text="{locale:Locale SmaaMedium}" /> - </ComboBoxItem> - <ComboBoxItem> - <TextBlock Text="{locale:Locale SmaaHigh}" /> - </ComboBoxItem> - <ComboBoxItem> - <TextBlock Text="{locale:Locale SmaaUltra}" /> - </ComboBoxItem> - </ComboBox> - </StackPanel> - </StackPanel> - <StackPanel - HorizontalAlignment="Stretch" - Orientation="Vertical" - Spacing="10"> - <StackPanel Orientation="Horizontal"> - <TextBlock VerticalAlignment="Center" - ToolTip.Tip="{locale:Locale GraphicsScalingFilterTooltip}" - Text="{locale:Locale GraphicsScalingFilterLabel}" - Width="250" /> - <ComboBox Width="350" - HorizontalContentAlignment="Left" - ToolTip.Tip="{locale:Locale GraphicsScalingFilterTooltip}" - SelectedIndex="{Binding ScalingFilter}"> - <ComboBoxItem> - <TextBlock Text="Bilinear" /> - </ComboBoxItem> - <ComboBoxItem> - <TextBlock Text="Nearest" /> - </ComboBoxItem> - <ComboBoxItem> - <TextBlock Text="FSR" /> - </ComboBoxItem> - </ComboBox> - <controls:SliderScroll Value="{Binding ScalingFilterLevel}" - ToolTip.Tip="{locale:Locale GraphicsScalingFilterLevelTooltip}" - MinWidth="150" - Margin="10,-3,0,0" - Height="32" - Padding="0,-5" - IsVisible="{Binding IsScalingFilterActive}" - TickFrequency="1" - IsSnapToTickEnabled="True" - LargeChange="10" - SmallChange="1" - VerticalAlignment="Center" - Minimum="0" - Maximum="100" /> - <TextBlock Margin="5,0" - Width="40" - IsVisible="{Binding IsScalingFilterActive}" - Text="{Binding ScalingFilterLevelText}"/> - </StackPanel> - </StackPanel> - <StackPanel Orientation="Horizontal"> - <TextBlock VerticalAlignment="Center" - ToolTip.Tip="{locale:Locale AnisotropyTooltip}" - Text="{locale:Locale SettingsTabGraphicsAnisotropicFiltering}" - Width="250" /> - <ComboBox SelectedIndex="{Binding MaxAnisotropy}" - Width="350" - HorizontalContentAlignment="Left" - ToolTip.Tip="{locale:Locale AnisotropyTooltip}"> - <ComboBoxItem> - <TextBlock - Text="{locale:Locale SettingsTabGraphicsAnisotropicFilteringAuto}" /> - </ComboBoxItem> - <ComboBoxItem> - <TextBlock Text="{locale:Locale SettingsTabGraphicsAnisotropicFiltering2x}" /> - </ComboBoxItem> - <ComboBoxItem> - <TextBlock Text="{locale:Locale SettingsTabGraphicsAnisotropicFiltering4x}" /> - </ComboBoxItem> - <ComboBoxItem> - <TextBlock Text="{locale:Locale SettingsTabGraphicsAnisotropicFiltering8x}" /> - </ComboBoxItem> - <ComboBoxItem> - <TextBlock - Text="{locale:Locale SettingsTabGraphicsAnisotropicFiltering16x}" /> - </ComboBoxItem> - </ComboBox> - </StackPanel> - <StackPanel Orientation="Horizontal"> - <TextBlock VerticalAlignment="Center" - ToolTip.Tip="{locale:Locale AspectRatioTooltip}" - Text="{locale:Locale SettingsTabGraphicsAspectRatio}" - Width="250" /> - <ComboBox SelectedIndex="{Binding AspectRatio}" - Width="350" - HorizontalContentAlignment="Left" - ToolTip.Tip="{locale:Locale AspectRatioTooltip}"> - <ComboBoxItem> - <TextBlock Text="{locale:Locale SettingsTabGraphicsAspectRatio4x3}" /> - </ComboBoxItem> - <ComboBoxItem> - <TextBlock Text="{locale:Locale SettingsTabGraphicsAspectRatio16x9}" /> - </ComboBoxItem> - <ComboBoxItem> - <TextBlock Text="{locale:Locale SettingsTabGraphicsAspectRatio16x10}" /> - </ComboBoxItem> - <ComboBoxItem> - <TextBlock Text="{locale:Locale SettingsTabGraphicsAspectRatio21x9}" /> - </ComboBoxItem> - <ComboBoxItem> - <TextBlock Text="{locale:Locale SettingsTabGraphicsAspectRatio32x9}" /> - </ComboBoxItem> - <ComboBoxItem> - <TextBlock Text="{locale:Locale SettingsTabGraphicsAspectRatioStretch}" /> - </ComboBoxItem> - </ComboBox> - </StackPanel> - </StackPanel> - <StackPanel - Margin="10,0,0,0" - HorizontalAlignment="Stretch" - Orientation="Vertical" - Spacing="10"> - <StackPanel Orientation="Horizontal"> - <TextBlock VerticalAlignment="Center" - ToolTip.Tip="{locale:Locale GraphicsBackendThreadingTooltip}" - Text="{locale:Locale SettingsTabGraphicsBackendMultithreading}" - Width="250" /> - <ComboBox Width="350" - HorizontalContentAlignment="Left" - ToolTip.Tip="{locale:Locale GalThreadingTooltip}" - SelectedIndex="{Binding GraphicsBackendMultithreadingIndex}"> - <ComboBoxItem> - <TextBlock Text="{locale:Locale CommonAuto}" /> - </ComboBoxItem> - <ComboBoxItem> - <TextBlock Text="{locale:Locale CommonOff}" /> - </ComboBoxItem> - <ComboBoxItem> - <TextBlock Text="{locale:Locale CommonOn}" /> - </ComboBoxItem> - </ComboBox> - </StackPanel> - </StackPanel> - <Separator Height="1" /> - <TextBlock Classes="h1" Text="{locale:Locale SettingsTabGraphicsDeveloperOptions}" /> - <StackPanel - Margin="10,0,0,0" - HorizontalAlignment="Stretch" - Orientation="Vertical" - Spacing="10"> - <StackPanel Orientation="Horizontal"> - <TextBlock VerticalAlignment="Center" - ToolTip.Tip="{locale:Locale ShaderDumpPathTooltip}" - Text="{locale:Locale SettingsTabGraphicsShaderDumpPath}" - Width="250" /> - <TextBox Text="{Binding ShaderDumpPath}" - Width="350" - ToolTip.Tip="{locale:Locale ShaderDumpPathTooltip}" /> - </StackPanel> - </StackPanel> - </StackPanel> - </Border> - </ScrollViewer> -</UserControl> diff --git a/src/Ryujinx.Ava/UI/Views/Settings/SettingsGraphicsView.axaml.cs b/src/Ryujinx.Ava/UI/Views/Settings/SettingsGraphicsView.axaml.cs deleted file mode 100644 index 67341330..00000000 --- a/src/Ryujinx.Ava/UI/Views/Settings/SettingsGraphicsView.axaml.cs +++ /dev/null @@ -1,12 +0,0 @@ -using Avalonia.Controls; - -namespace Ryujinx.Ava.UI.Views.Settings -{ - public partial class SettingsGraphicsView : UserControl - { - public SettingsGraphicsView() - { - InitializeComponent(); - } - } -} diff --git a/src/Ryujinx.Ava/UI/Views/Settings/SettingsHotkeysView.axaml b/src/Ryujinx.Ava/UI/Views/Settings/SettingsHotkeysView.axaml deleted file mode 100644 index b4eae01e..00000000 --- a/src/Ryujinx.Ava/UI/Views/Settings/SettingsHotkeysView.axaml +++ /dev/null @@ -1,103 +0,0 @@ -<UserControl - x:Class="Ryujinx.Ava.UI.Views.Settings.SettingsHotkeysView" - xmlns="https://github.com/avaloniaui" - xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" - xmlns:d="http://schemas.microsoft.com/expression/blend/2008" - xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" - xmlns:locale="clr-namespace:Ryujinx.Ava.Common.Locale" - xmlns:viewModels="clr-namespace:Ryujinx.Ava.UI.ViewModels" - xmlns:helpers="clr-namespace:Ryujinx.Ava.UI.Helpers" - mc:Ignorable="d" - x:DataType="viewModels:SettingsViewModel" - Focusable="True"> - <Design.DataContext> - <viewModels:SettingsViewModel /> - </Design.DataContext> - <UserControl.Resources> - <helpers:KeyValueConverter x:Key="Key" /> - </UserControl.Resources> - <ScrollViewer - Name="HotkeysPage" - HorizontalAlignment="Stretch" - VerticalAlignment="Stretch" - HorizontalScrollBarVisibility="Disabled" - VerticalScrollBarVisibility="Auto"> - <Border Classes="settings"> - <StackPanel Margin="10" Orientation="Vertical" Spacing="10"> - <TextBlock Classes="h1" Text="{locale:Locale SettingsTabHotkeysHotkeys}" /> - <StackPanel Margin="10,0,0,0" Orientation="Horizontal"> - <TextBlock VerticalAlignment="Center" Text="{locale:Locale SettingsTabHotkeysToggleVsyncHotkey}" Width="230" /> - <ToggleButton Width="90" Height="27" Checked="Button_Checked" Unchecked="Button_Unchecked"> - <TextBlock - Text="{Binding KeyboardHotkeys.ToggleVsync, Mode=TwoWay, Converter={StaticResource Key}}" - TextAlignment="Center" /> - </ToggleButton> - </StackPanel> - <StackPanel Margin="10,0,0,0" Orientation="Horizontal"> - <TextBlock VerticalAlignment="Center" Text="{locale:Locale SettingsTabHotkeysScreenshotHotkey}" Width="230" /> - <ToggleButton Width="90" Height="27" Checked="Button_Checked" Unchecked="Button_Unchecked"> - <TextBlock - Text="{Binding KeyboardHotkeys.Screenshot, Mode=TwoWay, Converter={StaticResource Key}}" - TextAlignment="Center" /> - </ToggleButton> - </StackPanel> - <StackPanel Margin="10,0,0,0" Orientation="Horizontal"> - <TextBlock VerticalAlignment="Center" Text="{locale:Locale SettingsTabHotkeysShowUiHotkey}" Width="230" /> - <ToggleButton Width="90" Height="27" Checked="Button_Checked" Unchecked="Button_Unchecked"> - <TextBlock - Text="{Binding KeyboardHotkeys.ShowUI, Mode=TwoWay, Converter={StaticResource Key}}" - TextAlignment="Center" /> - </ToggleButton> - </StackPanel> - <StackPanel Margin="10,0,0,0" Orientation="Horizontal"> - <TextBlock VerticalAlignment="Center" Text="{locale:Locale SettingsTabHotkeysPauseHotkey}" Width="230" /> - <ToggleButton Width="90" Height="27" Checked="Button_Checked" Unchecked="Button_Unchecked"> - <TextBlock - Text="{Binding KeyboardHotkeys.Pause, Mode=TwoWay, Converter={StaticResource Key}}" - TextAlignment="Center" /> - </ToggleButton> - </StackPanel> - <StackPanel Margin="10,0,0,0" Orientation="Horizontal"> - <TextBlock VerticalAlignment="Center" Text="{locale:Locale SettingsTabHotkeysToggleMuteHotkey}" Width="230" /> - <ToggleButton Width="90" Height="27" Checked="Button_Checked" Unchecked="Button_Unchecked"> - <TextBlock - Text="{Binding KeyboardHotkeys.ToggleMute, Mode=TwoWay, Converter={StaticResource Key}}" - TextAlignment="Center" /> - </ToggleButton> - </StackPanel> - <StackPanel Margin="10,0,0,0" Orientation="Horizontal"> - <TextBlock VerticalAlignment="Center" Text="{locale:Locale SettingsTabHotkeysResScaleUpHotkey}" Width="230" /> - <ToggleButton Width="90" Height="27" Checked="Button_Checked" Unchecked="Button_Unchecked"> - <TextBlock - Text="{Binding KeyboardHotkeys.ResScaleUp, Mode=TwoWay, Converter={StaticResource Key}}" - TextAlignment="Center" /> - </ToggleButton> - </StackPanel> - <StackPanel Margin="10,0,0,0" Orientation="Horizontal"> - <TextBlock VerticalAlignment="Center" Text="{locale:Locale SettingsTabHotkeysResScaleDownHotkey}" Width="230" /> - <ToggleButton Width="90" Height="27" Checked="Button_Checked" Unchecked="Button_Unchecked"> - <TextBlock - Text="{Binding KeyboardHotkeys.ResScaleDown, Mode=TwoWay, Converter={StaticResource Key}}" - TextAlignment="Center" /> - </ToggleButton> - </StackPanel> - <StackPanel Margin="10,0,0,0" Orientation="Horizontal"> - <TextBlock VerticalAlignment="Center" Text="{locale:Locale SettingsTabHotkeysVolumeUpHotkey}" Width="230" /> - <ToggleButton Width="90" Height="27" Checked="Button_Checked" Unchecked="Button_Unchecked"> - <TextBlock - Text="{Binding KeyboardHotkeys.VolumeUp, Mode=TwoWay, Converter={StaticResource Key}}" - TextAlignment="Center" /> - </ToggleButton> - </StackPanel> - <StackPanel Margin="10,0,0,0" Orientation="Horizontal"> - <TextBlock VerticalAlignment="Center" Text="{locale:Locale SettingsTabHotkeysVolumeDownHotkey}" Width="230" /> - <ToggleButton Width="90" Height="27" Checked="Button_Checked" Unchecked="Button_Unchecked"> - <TextBlock - Text="{Binding KeyboardHotkeys.VolumeDown, Mode=TwoWay, Converter={StaticResource Key}}" - TextAlignment="Center" /> - </ToggleButton> - </StackPanel> - </StackPanel> - </Border> - </ScrollViewer> -</UserControl>
\ No newline at end of file diff --git a/src/Ryujinx.Ava/UI/Views/Settings/SettingsHotkeysView.axaml.cs b/src/Ryujinx.Ava/UI/Views/Settings/SettingsHotkeysView.axaml.cs deleted file mode 100644 index b006d703..00000000 --- a/src/Ryujinx.Ava/UI/Views/Settings/SettingsHotkeysView.axaml.cs +++ /dev/null @@ -1,81 +0,0 @@ -using Avalonia.Controls; -using Avalonia.Controls.Primitives; -using Avalonia.Input; -using Avalonia.Interactivity; -using Ryujinx.Ava.Input; -using Ryujinx.Ava.UI.Helpers; -using Ryujinx.Input; -using Ryujinx.Input.Assigner; - -namespace Ryujinx.Ava.UI.Views.Settings -{ - public partial class SettingsHotkeysView : UserControl - { - private ButtonKeyAssigner _currentAssigner; - private readonly IGamepadDriver _avaloniaKeyboardDriver; - - public SettingsHotkeysView() - { - InitializeComponent(); - _avaloniaKeyboardDriver = new AvaloniaKeyboardDriver(this); - } - - private void MouseClick(object sender, PointerPressedEventArgs e) - { - bool shouldUnbind = e.GetCurrentPoint(this).Properties.IsMiddleButtonPressed; - - _currentAssigner?.Cancel(shouldUnbind); - - PointerPressed -= MouseClick; - } - - private void Button_Checked(object sender, RoutedEventArgs e) - { - if (sender is ToggleButton button) - { - if (_currentAssigner != null && button == _currentAssigner.ToggledButton) - { - return; - } - - if (_currentAssigner == null && button.IsChecked != null && (bool)button.IsChecked) - { - _currentAssigner = new ButtonKeyAssigner(button); - - this.Focus(NavigationMethod.Pointer); - - PointerPressed += MouseClick; - - var keyboard = (IKeyboard)_avaloniaKeyboardDriver.GetGamepad(_avaloniaKeyboardDriver.GamepadsIds[0]); - IButtonAssigner assigner = new KeyboardKeyAssigner(keyboard); - - _currentAssigner.GetInputAndAssign(assigner); - } - else - { - if (_currentAssigner != null) - { - ToggleButton oldButton = _currentAssigner.ToggledButton; - - _currentAssigner.Cancel(); - _currentAssigner = null; - - button.IsChecked = false; - } - } - } - } - - private void Button_Unchecked(object sender, RoutedEventArgs e) - { - _currentAssigner?.Cancel(); - _currentAssigner = null; - } - - public void Dispose() - { - _currentAssigner?.Cancel(); - _currentAssigner = null; - } - } -} diff --git a/src/Ryujinx.Ava/UI/Views/Settings/SettingsInputView.axaml b/src/Ryujinx.Ava/UI/Views/Settings/SettingsInputView.axaml deleted file mode 100644 index 81f4b68b..00000000 --- a/src/Ryujinx.Ava/UI/Views/Settings/SettingsInputView.axaml +++ /dev/null @@ -1,67 +0,0 @@ -<UserControl - x:Class="Ryujinx.Ava.UI.Views.Settings.SettingsInputView" - xmlns="https://github.com/avaloniaui" - xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" - xmlns:d="http://schemas.microsoft.com/expression/blend/2008" - xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" - xmlns:locale="clr-namespace:Ryujinx.Ava.Common.Locale" - xmlns:views="clr-namespace:Ryujinx.Ava.UI.Views.Input" - xmlns:viewModels="clr-namespace:Ryujinx.Ava.UI.ViewModels" - mc:Ignorable="d" - x:DataType="viewModels:SettingsViewModel"> - <Design.DataContext> - <viewModels:SettingsViewModel /> - </Design.DataContext> - <ScrollViewer - Name="InputPage" - HorizontalAlignment="Stretch" - VerticalAlignment="Stretch" - HorizontalScrollBarVisibility="Disabled" - VerticalScrollBarVisibility="Auto"> - <Border Classes="settings"> - <Panel - Margin="10"> - <Grid> - <Grid.RowDefinitions> - <RowDefinition Height="Auto"/> - <RowDefinition Height="*" /> - <RowDefinition Height="Auto" /> - </Grid.RowDefinitions> - <views:ControllerInputView - Grid.Row="0" - Name="ControllerSettings" /> - <StackPanel - Orientation="Vertical" - Grid.Row="2"> - <Separator - Margin="0 10" - Height="1" /> - <StackPanel - Orientation="Horizontal" - Spacing="10"> - <CheckBox - ToolTip.Tip="{locale:Locale DockModeToggleTooltip}" - MinWidth="0" - IsChecked="{Binding EnableDockedMode}"> - <TextBlock - Text="{locale:Locale SettingsTabInputEnableDockedMode}" /> - </CheckBox> - <CheckBox - ToolTip.Tip="{locale:Locale DirectKeyboardTooltip}" - IsChecked="{Binding EnableKeyboard}"> - <TextBlock - Text="{locale:Locale SettingsTabInputDirectKeyboardAccess}" /> - </CheckBox> - <CheckBox - ToolTip.Tip="{locale:Locale DirectMouseTooltip}" - IsChecked="{Binding EnableMouse}"> - <TextBlock - Text="{locale:Locale SettingsTabInputDirectMouseAccess}" /> - </CheckBox> - </StackPanel> - </StackPanel> - </Grid> - </Panel> - </Border> - </ScrollViewer> -</UserControl>
\ No newline at end of file diff --git a/src/Ryujinx.Ava/UI/Views/Settings/SettingsInputView.axaml.cs b/src/Ryujinx.Ava/UI/Views/Settings/SettingsInputView.axaml.cs deleted file mode 100644 index e75c9f0c..00000000 --- a/src/Ryujinx.Ava/UI/Views/Settings/SettingsInputView.axaml.cs +++ /dev/null @@ -1,17 +0,0 @@ -using Avalonia.Controls; - -namespace Ryujinx.Ava.UI.Views.Settings -{ - public partial class SettingsInputView : UserControl - { - public SettingsInputView() - { - InitializeComponent(); - } - - public void Dispose() - { - ControllerSettings.Dispose(); - } - } -} diff --git a/src/Ryujinx.Ava/UI/Views/Settings/SettingsLoggingView.axaml b/src/Ryujinx.Ava/UI/Views/Settings/SettingsLoggingView.axaml deleted file mode 100644 index 0fc9ea1b..00000000 --- a/src/Ryujinx.Ava/UI/Views/Settings/SettingsLoggingView.axaml +++ /dev/null @@ -1,120 +0,0 @@ -<UserControl - x:Class="Ryujinx.Ava.UI.Views.Settings.SettingsLoggingView" - xmlns="https://github.com/avaloniaui" - xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" - xmlns:d="http://schemas.microsoft.com/expression/blend/2008" - xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" - xmlns:ui="clr-namespace:FluentAvalonia.UI.Controls;assembly=FluentAvalonia" - xmlns:locale="clr-namespace:Ryujinx.Ava.Common.Locale" - xmlns:viewModels="clr-namespace:Ryujinx.Ava.UI.ViewModels" - mc:Ignorable="d" - x:DataType="viewModels:SettingsViewModel"> - <Design.DataContext> - <viewModels:SettingsViewModel /> - </Design.DataContext> - <ScrollViewer - Name="LoggingPage" - HorizontalAlignment="Stretch" - VerticalAlignment="Stretch" - HorizontalScrollBarVisibility="Disabled" - VerticalScrollBarVisibility="Auto"> - <Border Classes="settings"> - <StackPanel - Margin="10" - HorizontalAlignment="Stretch" - Orientation="Vertical" - Spacing="10"> - <TextBlock Classes="h1" Text="{locale:Locale SettingsTabLoggingLogging}" /> - <StackPanel Margin="10,0,0,0" Orientation="Vertical"> - <CheckBox IsChecked="{Binding EnableFileLog}" - ToolTip.Tip="{locale:Locale FileLogTooltip}"> - <TextBlock Text="{locale:Locale SettingsTabLoggingEnableLoggingToFile}" /> - </CheckBox> - <CheckBox IsChecked="{Binding EnableStub}" - ToolTip.Tip="{locale:Locale StubLogTooltip}"> - <TextBlock Text="{locale:Locale SettingsTabLoggingEnableStubLogs}" /> - </CheckBox> - <CheckBox IsChecked="{Binding EnableInfo}" - ToolTip.Tip="{locale:Locale InfoLogTooltip}"> - <TextBlock Text="{locale:Locale SettingsTabLoggingEnableInfoLogs}" /> - </CheckBox> - <CheckBox IsChecked="{Binding EnableWarn}" - ToolTip.Tip="{locale:Locale WarnLogTooltip}"> - <TextBlock Text="{locale:Locale SettingsTabLoggingEnableWarningLogs}" /> - </CheckBox> - <CheckBox IsChecked="{Binding EnableError}" - ToolTip.Tip="{locale:Locale ErrorLogTooltip}"> - <TextBlock Text="{locale:Locale SettingsTabLoggingEnableErrorLogs}" /> - </CheckBox> - <CheckBox IsChecked="{Binding EnableGuest}" - ToolTip.Tip="{locale:Locale GuestLogTooltip}"> - <TextBlock Text="{locale:Locale SettingsTabLoggingEnableGuestLogs}" /> - </CheckBox> - </StackPanel> - <Separator Height="1" /> - <StackPanel Orientation="Vertical" Spacing="2"> - <TextBlock Classes="h1" Text="{locale:Locale SettingsTabLoggingDeveloperOptions}" /> - <TextBlock Foreground="{DynamicResource SecondaryTextColor}" Text="{locale:Locale SettingsTabLoggingDeveloperOptionsNote}" /> - </StackPanel> - <StackPanel - Margin="10,0,0,0" - HorizontalAlignment="Stretch" - Orientation="Vertical" - Spacing="10"> - <StackPanel Orientation="Vertical"> - <CheckBox IsChecked="{Binding EnableTrace}" - ToolTip.Tip="{locale:Locale TraceLogTooltip}"> - <TextBlock Text="{locale:Locale SettingsTabLoggingEnableTraceLogs}" /> - </CheckBox> - <CheckBox IsChecked="{Binding EnableFsAccessLog}" - ToolTip.Tip="{locale:Locale FileAccessLogTooltip}"> - <TextBlock Text="{locale:Locale SettingsTabLoggingEnableFsAccessLogs}" /> - </CheckBox> - <CheckBox IsChecked="{Binding EnableDebug}" - ToolTip.Tip="{locale:Locale DebugLogTooltip}"> - <TextBlock Text="{locale:Locale SettingsTabLoggingEnableDebugLogs}" /> - </CheckBox> - <StackPanel Margin="0,10,0,0" Orientation="Horizontal" VerticalAlignment="Stretch"> - <TextBlock VerticalAlignment="Center" - ToolTip.Tip="{locale:Locale FSAccessLogModeTooltip}" - Text="{locale:Locale SettingsTabLoggingFsGlobalAccessLogMode}" - Width="285" /> - <ui:NumberBox - Maximum="3" - Minimum="0" - Width="150" - SpinButtonPlacementMode="Inline" - SmallChange="1" - LargeChange="1" - Value="{Binding FsGlobalAccessLogMode}" /> - </StackPanel> - <StackPanel Margin="0,10,0,0" Orientation="Horizontal"> - <TextBlock VerticalAlignment="Center" - Text="{locale:Locale SettingsTabLoggingGraphicsBackendLogLevel}" - ToolTip.Tip="{locale:Locale OpenGlLogLevel}" - Width="285" /> - <ComboBox SelectedIndex="{Binding OpenglDebugLevel}" - Width="150" - HorizontalContentAlignment="Left" - ToolTip.Tip="{locale:Locale OpenGlLogLevel}"> - <ComboBoxItem> - <TextBlock Text="{locale:Locale SettingsTabLoggingGraphicsBackendLogLevelNone}" /> - </ComboBoxItem> - <ComboBoxItem> - <TextBlock Text="{locale:Locale SettingsTabLoggingGraphicsBackendLogLevelError}" /> - </ComboBoxItem> - <ComboBoxItem> - <TextBlock - Text="{locale:Locale SettingsTabLoggingGraphicsBackendLogLevelPerformance}" /> - </ComboBoxItem> - <ComboBoxItem> - <TextBlock Text="{locale:Locale SettingsTabLoggingGraphicsBackendLogLevelAll}" /> - </ComboBoxItem> - </ComboBox> - </StackPanel> - </StackPanel> - </StackPanel> - </StackPanel> - </Border> - </ScrollViewer> -</UserControl>
\ No newline at end of file diff --git a/src/Ryujinx.Ava/UI/Views/Settings/SettingsLoggingView.axaml.cs b/src/Ryujinx.Ava/UI/Views/Settings/SettingsLoggingView.axaml.cs deleted file mode 100644 index c8df46b3..00000000 --- a/src/Ryujinx.Ava/UI/Views/Settings/SettingsLoggingView.axaml.cs +++ /dev/null @@ -1,12 +0,0 @@ -using Avalonia.Controls; - -namespace Ryujinx.Ava.UI.Views.Settings -{ - public partial class SettingsLoggingView : UserControl - { - public SettingsLoggingView() - { - InitializeComponent(); - } - } -} diff --git a/src/Ryujinx.Ava/UI/Views/Settings/SettingsNetworkView.axaml b/src/Ryujinx.Ava/UI/Views/Settings/SettingsNetworkView.axaml deleted file mode 100644 index 9bb81463..00000000 --- a/src/Ryujinx.Ava/UI/Views/Settings/SettingsNetworkView.axaml +++ /dev/null @@ -1,58 +0,0 @@ -<UserControl - x:Class="Ryujinx.Ava.UI.Views.Settings.SettingsNetworkView" - xmlns="https://github.com/avaloniaui" - xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" - xmlns:d="http://schemas.microsoft.com/expression/blend/2008" - xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" - xmlns:locale="clr-namespace:Ryujinx.Ava.Common.Locale" - xmlns:viewModels="clr-namespace:Ryujinx.Ava.UI.ViewModels" - mc:Ignorable="d" - x:DataType="viewModels:SettingsViewModel"> - <Design.DataContext> - <viewModels:SettingsViewModel /> - </Design.DataContext> - <ScrollViewer - Name="NetworkPage" - HorizontalAlignment="Stretch" - VerticalAlignment="Stretch" - HorizontalScrollBarVisibility="Disabled" - VerticalScrollBarVisibility="Auto"> - <Border Classes="settings"> - <StackPanel - Margin="10" - HorizontalAlignment="Stretch" - Orientation="Vertical" - Spacing="10"> - <TextBlock Classes="h1" Text="{locale:Locale SettingsTabNetworkMultiplayer}" /> - <StackPanel Margin="10,0,0,0" Orientation="Horizontal"> - <TextBlock VerticalAlignment="Center" - Text="{locale:Locale MultiplayerMode}" - ToolTip.Tip="{locale:Locale MultiplayerModeTooltip}" - Width="200" /> - <ComboBox SelectedIndex="{Binding MultiplayerModeIndex}" - ToolTip.Tip="{locale:Locale MultiplayerModeTooltip}" - HorizontalContentAlignment="Left" - ItemsSource="{Binding MultiplayerModes}" - Width="250" /> - </StackPanel> - <Separator Height="1" /> - <TextBlock Classes="h1" Text="{locale:Locale SettingsTabNetworkConnection}" /> - <CheckBox Margin="10,0,0,0" IsChecked="{Binding EnableInternetAccess}"> - <TextBlock Text="{locale:Locale SettingsTabSystemEnableInternetAccess}" - ToolTip.Tip="{locale:Locale EnableInternetAccessTooltip}" /> - </CheckBox> - <StackPanel Margin="10,0,0,0" Orientation="Horizontal"> - <TextBlock VerticalAlignment="Center" - Text="{locale:Locale SettingsTabNetworkInterface}" - ToolTip.Tip="{locale:Locale NetworkInterfaceTooltip}" - Width="200" /> - <ComboBox SelectedIndex="{Binding NetworkInterfaceIndex}" - ToolTip.Tip="{locale:Locale NetworkInterfaceTooltip}" - HorizontalContentAlignment="Left" - ItemsSource="{Binding NetworkInterfaceList}" - Width="250" /> - </StackPanel> - </StackPanel> - </Border> - </ScrollViewer> -</UserControl> diff --git a/src/Ryujinx.Ava/UI/Views/Settings/SettingsNetworkView.axaml.cs b/src/Ryujinx.Ava/UI/Views/Settings/SettingsNetworkView.axaml.cs deleted file mode 100644 index b771933e..00000000 --- a/src/Ryujinx.Ava/UI/Views/Settings/SettingsNetworkView.axaml.cs +++ /dev/null @@ -1,12 +0,0 @@ -using Avalonia.Controls; - -namespace Ryujinx.Ava.UI.Views.Settings -{ - public partial class SettingsNetworkView : UserControl - { - public SettingsNetworkView() - { - InitializeComponent(); - } - } -} diff --git a/src/Ryujinx.Ava/UI/Views/Settings/SettingsSystemView.axaml b/src/Ryujinx.Ava/UI/Views/Settings/SettingsSystemView.axaml deleted file mode 100644 index e6f7c6e4..00000000 --- a/src/Ryujinx.Ava/UI/Views/Settings/SettingsSystemView.axaml +++ /dev/null @@ -1,224 +0,0 @@ -<UserControl - x:Class="Ryujinx.Ava.UI.Views.Settings.SettingsSystemView" - xmlns="https://github.com/avaloniaui" - xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" - xmlns:d="http://schemas.microsoft.com/expression/blend/2008" - xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" - xmlns:locale="clr-namespace:Ryujinx.Ava.Common.Locale" - xmlns:viewModels="clr-namespace:Ryujinx.Ava.UI.ViewModels" - xmlns:helpers="clr-namespace:Ryujinx.Ava.UI.Helpers" - mc:Ignorable="d" - x:DataType="viewModels:SettingsViewModel"> - <UserControl.Resources> - <helpers:TimeZoneConverter x:Key="TimeZone" /> - </UserControl.Resources> - <Design.DataContext> - <viewModels:SettingsViewModel /> - </Design.DataContext> - <ScrollViewer - Name="SystemPage" - HorizontalAlignment="Stretch" - VerticalAlignment="Stretch" - HorizontalScrollBarVisibility="Disabled" - VerticalScrollBarVisibility="Auto"> - <Border Classes="settings"> - <StackPanel - Margin="10" - HorizontalAlignment="Stretch" - Orientation="Vertical" - Spacing="10"> - <TextBlock - Classes="h1" - Text="{locale:Locale SettingsTabSystemCore}" /> - <StackPanel - Margin="10,0,0,0" - Orientation="Vertical"> - <StackPanel - Margin="0,0,0,10" - Orientation="Horizontal"> - <TextBlock - VerticalAlignment="Center" - Text="{locale:Locale SettingsTabSystemSystemRegion}" - Width="250" /> - <ComboBox - SelectedIndex="{Binding Region}" - ToolTip.Tip="{locale:Locale RegionTooltip}" - HorizontalContentAlignment="Left" - Width="350"> - <ComboBoxItem> - <TextBlock Text="{locale:Locale SettingsTabSystemSystemRegionJapan}" /> - </ComboBoxItem> - <ComboBoxItem> - <TextBlock Text="{locale:Locale SettingsTabSystemSystemRegionUSA}" /> - </ComboBoxItem> - <ComboBoxItem> - <TextBlock Text="{locale:Locale SettingsTabSystemSystemRegionEurope}" /> - </ComboBoxItem> - <ComboBoxItem> - <TextBlock Text="{locale:Locale SettingsTabSystemSystemRegionAustralia}" /> - </ComboBoxItem> - <ComboBoxItem> - <TextBlock Text="{locale:Locale SettingsTabSystemSystemRegionChina}" /> - </ComboBoxItem> - <ComboBoxItem> - <TextBlock Text="{locale:Locale SettingsTabSystemSystemRegionKorea}" /> - </ComboBoxItem> - <ComboBoxItem> - <TextBlock Text="{locale:Locale SettingsTabSystemSystemRegionTaiwan}" /> - </ComboBoxItem> - </ComboBox> - </StackPanel> - <StackPanel - Margin="0,0,0,10" - Orientation="Horizontal"> - <TextBlock - VerticalAlignment="Center" - Text="{locale:Locale SettingsTabSystemSystemLanguage}" - ToolTip.Tip="{locale:Locale LanguageTooltip}" - Width="250" /> - <ComboBox - SelectedIndex="{Binding Language}" - ToolTip.Tip="{locale:Locale LanguageTooltip}" - HorizontalContentAlignment="Left" - Width="350"> - <ComboBoxItem> - <TextBlock Text="{locale:Locale SettingsTabSystemSystemLanguageJapanese}" /> - </ComboBoxItem> - <ComboBoxItem> - <TextBlock Text="{locale:Locale SettingsTabSystemSystemLanguageAmericanEnglish}" /> - </ComboBoxItem> - <ComboBoxItem> - <TextBlock Text="{locale:Locale SettingsTabSystemSystemLanguageFrench}" /> - </ComboBoxItem> - <ComboBoxItem> - <TextBlock Text="{locale:Locale SettingsTabSystemSystemLanguageGerman}" /> - </ComboBoxItem> - <ComboBoxItem> - <TextBlock Text="{locale:Locale SettingsTabSystemSystemLanguageItalian}" /> - </ComboBoxItem> - <ComboBoxItem> - <TextBlock Text="{locale:Locale SettingsTabSystemSystemLanguageSpanish}" /> - </ComboBoxItem> - <ComboBoxItem> - <TextBlock Text="{locale:Locale SettingsTabSystemSystemLanguageChinese}" /> - </ComboBoxItem> - <ComboBoxItem> - <TextBlock Text="{locale:Locale SettingsTabSystemSystemLanguageKorean}" /> - </ComboBoxItem> - <ComboBoxItem> - <TextBlock Text="{locale:Locale SettingsTabSystemSystemLanguageDutch}" /> - </ComboBoxItem> - <ComboBoxItem> - <TextBlock Text="{locale:Locale SettingsTabSystemSystemLanguagePortuguese}" /> - </ComboBoxItem> - <ComboBoxItem> - <TextBlock Text="{locale:Locale SettingsTabSystemSystemLanguageRussian}" /> - </ComboBoxItem> - <ComboBoxItem> - <TextBlock Text="{locale:Locale SettingsTabSystemSystemLanguageTaiwanese}" /> - </ComboBoxItem> - <ComboBoxItem> - <TextBlock Text="{locale:Locale SettingsTabSystemSystemLanguageBritishEnglish}" /> - </ComboBoxItem> - <ComboBoxItem> - <TextBlock Text="{locale:Locale SettingsTabSystemSystemLanguageCanadianFrench}" /> - </ComboBoxItem> - <ComboBoxItem> - <TextBlock Text="{locale:Locale SettingsTabSystemSystemLanguageLatinAmericanSpanish}" /> - </ComboBoxItem> - <ComboBoxItem> - <TextBlock Text="{locale:Locale SettingsTabSystemSystemLanguageSimplifiedChinese}" /> - </ComboBoxItem> - <ComboBoxItem> - <TextBlock Text="{locale:Locale SettingsTabSystemSystemLanguageTraditionalChinese}" /> - </ComboBoxItem> - <ComboBoxItem> - <TextBlock Text="{locale:Locale SettingsTabSystemSystemLanguageBrazilianPortuguese}" /> - </ComboBoxItem> - </ComboBox> - </StackPanel> - <StackPanel - Margin="0,0,0,10" - Orientation="Horizontal"> - <TextBlock - VerticalAlignment="Center" - Text="{locale:Locale SettingsTabSystemSystemTimeZone}" - ToolTip.Tip="{locale:Locale TimezoneTooltip}" - Width="250" /> - <AutoCompleteBox - Name="TimeZoneBox" - Width="350" - MaxDropDownHeight="500" - FilterMode="Contains" - ItemsSource="{Binding TimeZones}" - SelectionChanged="TimeZoneBox_OnSelectionChanged" - Text="{Binding Path=TimeZone, Mode=OneWay}" - TextChanged="TimeZoneBox_OnTextChanged" - ToolTip.Tip="{locale:Locale TimezoneTooltip}" - ValueMemberBinding="{Binding Mode=OneWay, Converter={StaticResource TimeZone}}" /> - </StackPanel> - <StackPanel - Margin="0,0,0,10" - Orientation="Horizontal"> - <TextBlock - VerticalAlignment="Center" - Text="{locale:Locale SettingsTabSystemSystemTime}" - ToolTip.Tip="{locale:Locale TimeTooltip}" - Width="250"/> - <DatePicker - VerticalAlignment="Center" - SelectedDate="{Binding CurrentDate}" - ToolTip.Tip="{locale:Locale TimeTooltip}" - Width="350" /> - </StackPanel> - <StackPanel - Margin="250,0,0,10" - Orientation="Horizontal"> - <TimePicker - VerticalAlignment="Center" - ClockIdentifier="24HourClock" - SelectedTime="{Binding CurrentTime}" - Width="350" - ToolTip.Tip="{locale:Locale TimeTooltip}" /> - </StackPanel> - <CheckBox IsChecked="{Binding EnableVsync}"> - <TextBlock - Text="{locale:Locale SettingsTabSystemEnableVsync}" - ToolTip.Tip="{locale:Locale VSyncToggleTooltip}" /> - </CheckBox> - <CheckBox IsChecked="{Binding EnableFsIntegrityChecks}"> - <TextBlock - Text="{locale:Locale SettingsTabSystemEnableFsIntegrityChecks}" - ToolTip.Tip="{locale:Locale FsIntegrityToggleTooltip}" /> - </CheckBox> - </StackPanel> - <Separator Height="1" /> - <StackPanel - Orientation="Vertical" - Spacing="2"> - <TextBlock - Classes="h1" - Text="{locale:Locale SettingsTabSystemHacks}" /> - <TextBlock - Foreground="{DynamicResource SecondaryTextColor}" - Text="{locale:Locale SettingsTabSystemHacksNote}" /> - </StackPanel> - <StackPanel - Margin="10,0,0,0" - HorizontalAlignment="Stretch" - Orientation="Vertical"> - <CheckBox - IsChecked="{Binding ExpandDramSize}" - ToolTip.Tip="{locale:Locale DRamTooltip}"> - <TextBlock Text="{locale:Locale SettingsTabSystemExpandDramSize}" /> - </CheckBox> - <CheckBox - IsChecked="{Binding IgnoreMissingServices}" - ToolTip.Tip="{locale:Locale IgnoreMissingServicesTooltip}"> - <TextBlock Text="{locale:Locale SettingsTabSystemIgnoreMissingServices}" /> - </CheckBox> - </StackPanel> - </StackPanel> - </Border> - </ScrollViewer> -</UserControl>
\ No newline at end of file diff --git a/src/Ryujinx.Ava/UI/Views/Settings/SettingsSystemView.axaml.cs b/src/Ryujinx.Ava/UI/Views/Settings/SettingsSystemView.axaml.cs deleted file mode 100644 index 2c9eac28..00000000 --- a/src/Ryujinx.Ava/UI/Views/Settings/SettingsSystemView.axaml.cs +++ /dev/null @@ -1,37 +0,0 @@ -using Avalonia.Controls; -using Ryujinx.Ava.UI.ViewModels; -using TimeZone = Ryujinx.Ava.UI.Models.TimeZone; - -namespace Ryujinx.Ava.UI.Views.Settings -{ - public partial class SettingsSystemView : UserControl - { - public SettingsViewModel ViewModel; - - public SettingsSystemView() - { - InitializeComponent(); - } - - private void TimeZoneBox_OnSelectionChanged(object sender, SelectionChangedEventArgs e) - { - if (e.AddedItems != null && e.AddedItems.Count > 0) - { - if (e.AddedItems[0] is TimeZone timeZone) - { - e.Handled = true; - - ViewModel.ValidateAndSetTimeZone(timeZone.Location); - } - } - } - - private void TimeZoneBox_OnTextChanged(object sender, TextChangedEventArgs e) - { - if (sender is AutoCompleteBox box && box.SelectedItem is TimeZone timeZone) - { - ViewModel.ValidateAndSetTimeZone(timeZone.Location); - } - } - } -} diff --git a/src/Ryujinx.Ava/UI/Views/Settings/SettingsUIView.axaml b/src/Ryujinx.Ava/UI/Views/Settings/SettingsUIView.axaml deleted file mode 100644 index 6504637e..00000000 --- a/src/Ryujinx.Ava/UI/Views/Settings/SettingsUIView.axaml +++ /dev/null @@ -1,128 +0,0 @@ -<UserControl - x:Class="Ryujinx.Ava.UI.Views.Settings.SettingsUiView" - xmlns="https://github.com/avaloniaui" - xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" - xmlns:d="http://schemas.microsoft.com/expression/blend/2008" - xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" - xmlns:locale="clr-namespace:Ryujinx.Ava.Common.Locale" - xmlns:viewModels="clr-namespace:Ryujinx.Ava.UI.ViewModels" - mc:Ignorable="d" - x:DataType="viewModels:SettingsViewModel"> - <Design.DataContext> - <viewModels:SettingsViewModel /> - </Design.DataContext> - <ScrollViewer - Name="UiPage" - HorizontalAlignment="Stretch" - VerticalAlignment="Stretch" - HorizontalScrollBarVisibility="Disabled" - VerticalScrollBarVisibility="Auto"> - <Border Classes="settings"> - <StackPanel - Margin="10" - HorizontalAlignment="Stretch" - Orientation="Vertical" - Spacing="10"> - <TextBlock Classes="h1" Text="{locale:Locale SettingsTabGeneralGeneral}" /> - <StackPanel Margin="10,0,0,0" Orientation="Vertical"> - <CheckBox IsChecked="{Binding EnableDiscordIntegration}"> - <TextBlock VerticalAlignment="Center" - ToolTip.Tip="{locale:Locale ToggleDiscordTooltip}" - Text="{locale:Locale SettingsTabGeneralEnableDiscordRichPresence}" /> - </CheckBox> - <CheckBox IsChecked="{Binding CheckUpdatesOnStart}"> - <TextBlock Text="{locale:Locale SettingsTabGeneralCheckUpdatesOnLaunch}" /> - </CheckBox> - <CheckBox IsChecked="{Binding ShowConfirmExit}"> - <TextBlock Text="{locale:Locale SettingsTabGeneralShowConfirmExitDialog}" /> - </CheckBox> - <StackPanel Margin="0, 15, 0, 0" Orientation="Horizontal"> - <TextBlock VerticalAlignment="Center" - Text="{locale:Locale SettingsTabGeneralHideCursor}" - Width="150" /> - <ComboBox SelectedIndex="{Binding HideCursor}" - HorizontalContentAlignment="Left" - MinWidth="100"> - <ComboBoxItem> - <TextBlock Text="{locale:Locale SettingsTabGeneralHideCursorNever}" /> - </ComboBoxItem> - <ComboBoxItem> - <TextBlock Text="{locale:Locale SettingsTabGeneralHideCursorOnIdle}" /> - </ComboBoxItem> - <ComboBoxItem> - <TextBlock Text="{locale:Locale SettingsTabGeneralHideCursorAlways}" /> - </ComboBoxItem> - </ComboBox> - </StackPanel> - <StackPanel Margin="0, 15, 0, 10" Orientation="Horizontal"> - <TextBlock - VerticalAlignment="Center" - Text="{locale:Locale SettingsTabGeneralTheme}" - Width="150" /> - <ComboBox SelectedIndex="{Binding BaseStyleIndex}" - HorizontalContentAlignment="Left" - MinWidth="100"> - <ComboBoxItem> - <TextBlock Text="{locale:Locale SettingsTabGeneralThemeLight}" /> - </ComboBoxItem> - <ComboBoxItem> - <TextBlock Text="{locale:Locale SettingsTabGeneralThemeDark}" /> - </ComboBoxItem> - </ComboBox> - </StackPanel> - </StackPanel> - <Separator Height="1" /> - <TextBlock Classes="h1" Text="{locale:Locale SettingsTabGeneralGameDirectories}" /> - <StackPanel - Margin="10,0,0,0" - HorizontalAlignment="Stretch" - Orientation="Vertical" - Spacing="10"> - <ListBox - Name="GameList" - MinHeight="230" - ItemsSource="{Binding GameDirectories}"> - <ListBox.Styles> - <Style Selector="ListBoxItem"> - <Setter Property="Padding" Value="10" /> - <Setter Property="Background" Value="{DynamicResource ListBoxBackground}" /> - </Style> - </ListBox.Styles> - </ListBox> - <Grid HorizontalAlignment="Stretch"> - <Grid.ColumnDefinitions> - <ColumnDefinition Width="*" /> - <ColumnDefinition Width="Auto" /> - <ColumnDefinition Width="Auto" /> - </Grid.ColumnDefinitions> - <TextBox - Name="PathBox" - Margin="0" - ToolTip.Tip="{locale:Locale AddGameDirBoxTooltip}" - VerticalAlignment="Stretch" /> - <Button - Name="AddButton" - Grid.Column="1" - MinWidth="90" - Margin="10,0,0,0" - ToolTip.Tip="{locale:Locale AddGameDirTooltip}" - Click="AddButton_OnClick"> - <TextBlock HorizontalAlignment="Center" - Text="{locale:Locale SettingsTabGeneralAdd}" /> - </Button> - <Button - Name="RemoveButton" - Grid.Column="2" - MinWidth="90" - Margin="10,0,0,0" - ToolTip.Tip="{locale:Locale RemoveGameDirTooltip}" - Click="RemoveButton_OnClick"> - <TextBlock HorizontalAlignment="Center" - Text="{locale:Locale SettingsTabGeneralRemove}" /> - </Button> - </Grid> - </StackPanel> - </StackPanel> - </Border> - </ScrollViewer> -</UserControl> diff --git a/src/Ryujinx.Ava/UI/Views/Settings/SettingsUIView.axaml.cs b/src/Ryujinx.Ava/UI/Views/Settings/SettingsUIView.axaml.cs deleted file mode 100644 index 996d15cd..00000000 --- a/src/Ryujinx.Ava/UI/Views/Settings/SettingsUIView.axaml.cs +++ /dev/null @@ -1,65 +0,0 @@ -using Avalonia.Controls; -using Avalonia.Interactivity; -using Avalonia.Platform.Storage; -using Avalonia.VisualTree; -using Ryujinx.Ava.Common.Locale; -using Ryujinx.Ava.UI.ViewModels; -using System.Collections.Generic; -using System.IO; -using System.Linq; - -namespace Ryujinx.Ava.UI.Views.Settings -{ - public partial class SettingsUiView : UserControl - { - public SettingsViewModel ViewModel; - - public SettingsUiView() - { - InitializeComponent(); - } - - private async void AddButton_OnClick(object sender, RoutedEventArgs e) - { - string path = PathBox.Text; - - if (!string.IsNullOrWhiteSpace(path) && Directory.Exists(path) && !ViewModel.GameDirectories.Contains(path)) - { - ViewModel.GameDirectories.Add(path); - ViewModel.DirectoryChanged = true; - } - else - { - if (this.GetVisualRoot() is Window window) - { - var result = await window.StorageProvider.OpenFolderPickerAsync(new FolderPickerOpenOptions - { - AllowMultiple = false, - }); - - if (result.Count > 0) - { - ViewModel.GameDirectories.Add(result[0].Path.LocalPath); - ViewModel.DirectoryChanged = true; - } - } - } - } - - private void RemoveButton_OnClick(object sender, RoutedEventArgs e) - { - int oldIndex = GameList.SelectedIndex; - - foreach (string path in new List<string>(GameList.SelectedItems.Cast<string>())) - { - ViewModel.GameDirectories.Remove(path); - ViewModel.DirectoryChanged = true; - } - - if (GameList.ItemCount > 0) - { - GameList.SelectedIndex = oldIndex < GameList.ItemCount ? oldIndex : 0; - } - } - } -} diff --git a/src/Ryujinx.Ava/UI/Views/User/UserEditorView.axaml b/src/Ryujinx.Ava/UI/Views/User/UserEditorView.axaml deleted file mode 100644 index ab83c2cd..00000000 --- a/src/Ryujinx.Ava/UI/Views/User/UserEditorView.axaml +++ /dev/null @@ -1,122 +0,0 @@ -<UserControl - x:Class="Ryujinx.Ava.UI.Views.User.UserEditorView" - xmlns="https://github.com/avaloniaui" - xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" - xmlns:locale="clr-namespace:Ryujinx.Ava.Common.Locale" - xmlns:d="http://schemas.microsoft.com/expression/blend/2008" - xmlns:ui="clr-namespace:FluentAvalonia.UI.Controls;assembly=FluentAvalonia" - xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" - xmlns:helpers="clr-namespace:Ryujinx.Ava.UI.Helpers" - xmlns:models="clr-namespace:Ryujinx.Ava.UI.Models" - Margin="0" - MinWidth="500" - Padding="0" - mc:Ignorable="d" - Focusable="True" - x:DataType="models:TempProfile"> - <UserControl.Resources> - <helpers:BitmapArrayValueConverter x:Key="ByteImage" /> - </UserControl.Resources> - <Grid Margin="0"> - <Grid.ColumnDefinitions> - <ColumnDefinition Width="Auto" /> - <ColumnDefinition /> - </Grid.ColumnDefinitions> - <Grid.RowDefinitions> - <RowDefinition Height="*" /> - <RowDefinition Height="Auto" /> - </Grid.RowDefinitions> - <StackPanel - Grid.Row="0" - Grid.Column="0" - HorizontalAlignment="Stretch" - Orientation="Vertical" - Spacing="10"> - <TextBlock Text="{locale:Locale UserProfilesName}" /> - <TextBox - Name="NameBox" - Width="300" - HorizontalAlignment="Stretch" - MaxLength="{Binding MaxProfileNameLength}" - Watermark="{locale:Locale ProfileNameSelectionWatermark}" - Text="{Binding Name}" /> - <TextBlock Name="IdText" Text="{locale:Locale UserProfilesUserId}" /> - <TextBox - Name="IdLabel" - Width="300" - HorizontalAlignment="Stretch" - IsReadOnly="True" - Text="{Binding UserIdString}" /> - </StackPanel> - <StackPanel - Grid.Row="0" - Grid.Column="1" - HorizontalAlignment="Right" - VerticalAlignment="Stretch" - Orientation="Vertical"> - <Border - BorderBrush="{DynamicResource AppListHoverBackgroundColor}" - BorderThickness="1"> - <Panel> - <ui:SymbolIcon - FontSize="60" - Width="96" - Height="96" - Margin="0" - Foreground="{DynamicResource AppListHoverBackgroundColor}" - HorizontalAlignment="Stretch" - VerticalAlignment="Top" - Symbol="Camera" /> - <Image - Name="ProfileImage" - Width="96" - Height="96" - Margin="0" - HorizontalAlignment="Stretch" - VerticalAlignment="Top" - Source="{Binding Image, Converter={StaticResource ByteImage}}" /> - </Panel> - </Border> - </StackPanel> - <StackPanel - Grid.Row="1" - Grid.Column="0" - Grid.ColumnSpan="2" - HorizontalAlignment="Left" - Orientation="Horizontal" - Margin="0 24 0 0" - Spacing="10"> - <Button - Width="50" - MinWidth="50" - Click="BackButton_Click"> - <ui:SymbolIcon Symbol="Back" /> - </Button> - </StackPanel> - <StackPanel - Grid.Row="1" - Grid.Column="0" - Grid.ColumnSpan="2" - HorizontalAlignment="Right" - Orientation="Horizontal" - Margin="0 24 0 0" - Spacing="10"> - <Button - Name="DeleteButton" - Click="DeleteButton_Click" - Content="{locale:Locale UserProfilesDelete}" /> - <Button - Name="ChangePictureButton" - Click="ChangePictureButton_Click" - Content="{locale:Locale UserProfilesChangeProfileImage}" /> - <Button - Name="AddPictureButton" - Click="ChangePictureButton_Click" - Content="{locale:Locale UserProfilesSetProfileImage}" /> - <Button - Name="SaveButton" - Click="SaveButton_Click" - Content="{locale:Locale Save}" /> - </StackPanel> - </Grid> -</UserControl>
\ No newline at end of file diff --git a/src/Ryujinx.Ava/UI/Views/User/UserEditorView.axaml.cs b/src/Ryujinx.Ava/UI/Views/User/UserEditorView.axaml.cs deleted file mode 100644 index 588fa471..00000000 --- a/src/Ryujinx.Ava/UI/Views/User/UserEditorView.axaml.cs +++ /dev/null @@ -1,165 +0,0 @@ -using Avalonia.Controls; -using Avalonia.Data; -using Avalonia.Interactivity; -using FluentAvalonia.UI.Controls; -using FluentAvalonia.UI.Navigation; -using Ryujinx.Ava.Common.Locale; -using Ryujinx.Ava.UI.Controls; -using Ryujinx.Ava.UI.Helpers; -using Ryujinx.Ava.UI.Models; -using Ryujinx.HLE.HOS.Services.Account.Acc; -using System; -using UserProfile = Ryujinx.Ava.UI.Models.UserProfile; - -namespace Ryujinx.Ava.UI.Views.User -{ - public partial class UserEditorView : UserControl - { - private NavigationDialogHost _parent; - private UserProfile _profile; - private bool _isNewUser; - - public TempProfile TempProfile { get; set; } - public static uint MaxProfileNameLength => 0x20; - public bool IsDeletable => _profile.UserId != AccountManager.DefaultUserId; - - public UserEditorView() - { - InitializeComponent(); - AddHandler(Frame.NavigatedToEvent, (s, e) => - { - NavigatedTo(e); - }, RoutingStrategies.Direct); - } - - private void NavigatedTo(NavigationEventArgs arg) - { - if (Program.PreviewerDetached) - { - switch (arg.NavigationMode) - { - case NavigationMode.New: - var (parent, profile, isNewUser) = ((NavigationDialogHost parent, UserProfile profile, bool isNewUser))arg.Parameter; - _isNewUser = isNewUser; - _profile = profile; - TempProfile = new TempProfile(_profile); - - _parent = parent; - break; - } - - ((ContentDialog)_parent.Parent).Title = $"{LocaleManager.Instance[LocaleKeys.UserProfileWindowTitle]} - " + - $"{(_isNewUser ? LocaleManager.Instance[LocaleKeys.UserEditorTitleCreate] : LocaleManager.Instance[LocaleKeys.UserEditorTitle])}"; - - DataContext = TempProfile; - - AddPictureButton.IsVisible = _isNewUser; - ChangePictureButton.IsVisible = !_isNewUser; - IdLabel.IsVisible = _profile != null; - IdText.IsVisible = _profile != null; - if (!_isNewUser && IsDeletable) - { - DeleteButton.IsVisible = true; - } - else - { - DeleteButton.IsVisible = false; - } - } - } - - private async void BackButton_Click(object sender, RoutedEventArgs e) - { - if (_isNewUser) - { - if (TempProfile.Name != String.Empty || TempProfile.Image != null) - { - if (await ContentDialogHelper.CreateChoiceDialog( - LocaleManager.Instance[LocaleKeys.DialogUserProfileUnsavedChangesTitle], - LocaleManager.Instance[LocaleKeys.DialogUserProfileUnsavedChangesMessage], - LocaleManager.Instance[LocaleKeys.DialogUserProfileUnsavedChangesSubMessage])) - { - _parent?.GoBack(); - } - } - else - { - _parent?.GoBack(); - } - } - else - { - if (_profile.Name != TempProfile.Name || _profile.Image != TempProfile.Image) - { - if (await ContentDialogHelper.CreateChoiceDialog( - LocaleManager.Instance[LocaleKeys.DialogUserProfileUnsavedChangesTitle], - LocaleManager.Instance[LocaleKeys.DialogUserProfileUnsavedChangesMessage], - LocaleManager.Instance[LocaleKeys.DialogUserProfileUnsavedChangesSubMessage])) - { - _parent?.GoBack(); - } - } - else - { - _parent?.GoBack(); - } - } - } - - private void DeleteButton_Click(object sender, RoutedEventArgs e) - { - _parent.DeleteUser(_profile); - } - - private void SaveButton_Click(object sender, RoutedEventArgs e) - { - DataValidationErrors.ClearErrors(NameBox); - - if (string.IsNullOrWhiteSpace(TempProfile.Name)) - { - DataValidationErrors.SetError(NameBox, new DataValidationException(LocaleManager.Instance[LocaleKeys.UserProfileEmptyNameError])); - - return; - } - - if (TempProfile.Image == null) - { - _parent.Navigate(typeof(UserProfileImageSelectorView), (_parent, TempProfile)); - - return; - } - - if (_profile != null && !_isNewUser) - { - _profile.Name = TempProfile.Name; - _profile.Image = TempProfile.Image; - _profile.UpdateState(); - _parent.AccountManager.SetUserName(_profile.UserId, _profile.Name); - _parent.AccountManager.SetUserImage(_profile.UserId, _profile.Image); - } - else if (_isNewUser) - { - _parent.AccountManager.AddUser(TempProfile.Name, TempProfile.Image, TempProfile.UserId); - } - else - { - return; - } - - _parent?.GoBack(); - } - - public void SelectProfileImage() - { - _parent.Navigate(typeof(UserProfileImageSelectorView), (_parent, TempProfile)); - } - - private void ChangePictureButton_Click(object sender, RoutedEventArgs e) - { - if (_profile != null || _isNewUser) - { - SelectProfileImage(); - } - } - } -} diff --git a/src/Ryujinx.Ava/UI/Views/User/UserFirmwareAvatarSelectorView.axaml b/src/Ryujinx.Ava/UI/Views/User/UserFirmwareAvatarSelectorView.axaml deleted file mode 100644 index 21dfc909..00000000 --- a/src/Ryujinx.Ava/UI/Views/User/UserFirmwareAvatarSelectorView.axaml +++ /dev/null @@ -1,113 +0,0 @@ -<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:ui="clr-namespace:FluentAvalonia.UI.Controls;assembly=FluentAvalonia" - xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" - mc:Ignorable="d" - Width="528" - d:DesignWidth="578" - d:DesignHeight="350" - x:Class="Ryujinx.Ava.UI.Views.User.UserFirmwareAvatarSelectorView" - xmlns:locale="clr-namespace:Ryujinx.Ava.Common.Locale" - xmlns:viewModels="clr-namespace:Ryujinx.Ava.UI.ViewModels" - xmlns:helpers="clr-namespace:Ryujinx.Ava.UI.Helpers" - x:DataType="viewModels:UserFirmwareAvatarSelectorViewModel" - Focusable="True"> - <Design.DataContext> - <viewModels:UserFirmwareAvatarSelectorViewModel /> - </Design.DataContext> - <UserControl.Resources> - <helpers:BitmapArrayValueConverter x:Key="ByteImage" /> - </UserControl.Resources> - <Grid - Margin="0" - HorizontalAlignment="Stretch" - VerticalAlignment="Stretch"> - <Grid.RowDefinitions> - <RowDefinition Height="Auto" /> - <RowDefinition Height="*" /> - <RowDefinition Height="Auto" /> - <RowDefinition Height="Auto" /> - </Grid.RowDefinitions> - <ListBox - Grid.Row="1" - BorderThickness="0" - SelectedIndex="{Binding SelectedIndex}" - Height="400" - ItemsSource="{Binding Images}" - HorizontalAlignment="Stretch" - VerticalAlignment="Center"> - <ListBox.ItemsPanel> - <ItemsPanelTemplate> - <WrapPanel - Orientation="Horizontal" - Margin="0" - HorizontalAlignment="Center" /> - </ItemsPanelTemplate> - </ListBox.ItemsPanel> - <ListBox.Styles> - <Style Selector="ListBoxItem"> - <Setter Property="CornerRadius" Value="4" /> - <Setter Property="Width" Value="85" /> - <Setter Property="MaxWidth" Value="85" /> - <Setter Property="MinWidth" Value="85" /> - </Style> - <Style Selector="ListBoxItem /template/ Rectangle#SelectionIndicator"> - <Setter Property="MinHeight" Value="70" /> - </Style> - </ListBox.Styles> - <ListBox.ItemTemplate> - <DataTemplate> - <Panel - Background="{Binding BackgroundColor}" - Margin="5"> - <Image Source="{Binding Data, Converter={StaticResource ByteImage}}" /> - </Panel> - </DataTemplate> - </ListBox.ItemTemplate> - </ListBox> - <StackPanel - Grid.Row="3" - Orientation="Horizontal" - Spacing="10" - Margin="0 24 0 0" - HorizontalAlignment="Left"> - <Button - Width="50" - MinWidth="50" - Height="35" - Click="GoBack"> - <ui:SymbolIcon Symbol="Back" /> - </Button> - </StackPanel> - <StackPanel - Grid.Row="3" - Orientation="Horizontal" - Spacing="10" - Margin="0 24 0 0" - HorizontalAlignment="Right"> - <ui:ColorPickerButton - FlyoutPlacement="Top" - IsMoreButtonVisible="False" - UseColorPalette="False" - UseColorTriangle="False" - UseColorWheel="False" - ShowAcceptDismissButtons="False" - IsAlphaEnabled="False" - Color="{Binding BackgroundColor, Mode=TwoWay}" - Name="ColorButton"> - <ui:ColorPickerButton.Styles> - <Style Selector="Grid#Root > DockPanel > Grid"> - <Setter Property="IsVisible" Value="False" /> - </Style> - </ui:ColorPickerButton.Styles> - </ui:ColorPickerButton> - <Button - Content="{locale:Locale AvatarChoose}" - Height="35" - Name="ChooseButton" - Click="ChooseButton_OnClick" /> - </StackPanel> - </Grid> -</UserControl>
\ No newline at end of file diff --git a/src/Ryujinx.Ava/UI/Views/User/UserFirmwareAvatarSelectorView.axaml.cs b/src/Ryujinx.Ava/UI/Views/User/UserFirmwareAvatarSelectorView.axaml.cs deleted file mode 100644 index b6376866..00000000 --- a/src/Ryujinx.Ava/UI/Views/User/UserFirmwareAvatarSelectorView.axaml.cs +++ /dev/null @@ -1,89 +0,0 @@ -using Avalonia.Controls; -using Avalonia.Interactivity; -using FluentAvalonia.UI.Controls; -using FluentAvalonia.UI.Navigation; -using Ryujinx.Ava.UI.Controls; -using Ryujinx.Ava.UI.Models; -using Ryujinx.Ava.UI.ViewModels; -using Ryujinx.HLE.FileSystem; -using SixLabors.ImageSharp; -using SixLabors.ImageSharp.Formats.Png; -using SixLabors.ImageSharp.PixelFormats; -using SixLabors.ImageSharp.Processing; -using System.IO; -using Image = SixLabors.ImageSharp.Image; - -namespace Ryujinx.Ava.UI.Views.User -{ - public partial class UserFirmwareAvatarSelectorView : UserControl - { - private NavigationDialogHost _parent; - private TempProfile _profile; - - public UserFirmwareAvatarSelectorView(ContentManager contentManager) - { - ContentManager = contentManager; - - DataContext = ViewModel; - - InitializeComponent(); - } - - public UserFirmwareAvatarSelectorView() - { - InitializeComponent(); - - AddHandler(Frame.NavigatedToEvent, (s, e) => - { - NavigatedTo(e); - }, RoutingStrategies.Direct); - } - - private void NavigatedTo(NavigationEventArgs arg) - { - if (Program.PreviewerDetached) - { - if (arg.NavigationMode == NavigationMode.New) - { - (_parent, _profile) = ((NavigationDialogHost, TempProfile))arg.Parameter; - ContentManager = _parent.ContentManager; - if (Program.PreviewerDetached) - { - ViewModel = new UserFirmwareAvatarSelectorViewModel(); - } - - DataContext = ViewModel; - } - } - } - - public ContentManager ContentManager { get; private set; } - - internal UserFirmwareAvatarSelectorViewModel ViewModel { get; set; } - - private void GoBack(object sender, RoutedEventArgs e) - { - _parent.GoBack(); - } - - private void ChooseButton_OnClick(object sender, RoutedEventArgs e) - { - if (ViewModel.SelectedImage != null) - { - MemoryStream streamJpg = new(); - Image avatarImage = Image.Load(ViewModel.SelectedImage, new PngDecoder()); - - avatarImage.Mutate(x => x.BackgroundColor(new Rgba32( - ViewModel.BackgroundColor.R, - ViewModel.BackgroundColor.G, - ViewModel.BackgroundColor.B, - ViewModel.BackgroundColor.A))); - avatarImage.SaveAsJpeg(streamJpg); - - _profile.Image = streamJpg.ToArray(); - - _parent.GoBack(); - } - } - } -} diff --git a/src/Ryujinx.Ava/UI/Views/User/UserProfileImageSelectorView.axaml b/src/Ryujinx.Ava/UI/Views/User/UserProfileImageSelectorView.axaml deleted file mode 100644 index b1786430..00000000 --- a/src/Ryujinx.Ava/UI/Views/User/UserProfileImageSelectorView.axaml +++ /dev/null @@ -1,62 +0,0 @@ -<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:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" - xmlns:ui="clr-namespace:FluentAvalonia.UI.Controls;assembly=FluentAvalonia" - xmlns:locale="clr-namespace:Ryujinx.Ava.Common.Locale" - xmlns:viewModles="clr-namespace:Ryujinx.Ava.UI.ViewModels" - Focusable="True" - mc:Ignorable="d" - x:Class="Ryujinx.Ava.UI.Views.User.UserProfileImageSelectorView" - x:DataType="viewModles:UserProfileImageSelectorViewModel" - Width="500" - d:DesignWidth="500"> - <Design.DataContext> - <viewModles:UserProfileImageSelectorViewModel /> - </Design.DataContext> - <Grid - HorizontalAlignment="Stretch" - VerticalAlignment="Center"> - <Grid.RowDefinitions> - <RowDefinition Height="Auto" /> - <RowDefinition Height="70" /> - <RowDefinition Height="Auto" /> - </Grid.RowDefinitions> - <TextBlock - Grid.Row="0" - TextWrapping="Wrap" - HorizontalAlignment="Left" - TextAlignment="Start" - Text="{locale:Locale ProfileImageSelectionNote}" /> - <StackPanel - Grid.Row="2" - Spacing="10" - HorizontalAlignment="Left" - Orientation="Horizontal"> - <Button - Width="50" - MinWidth="50" - Click="GoBack"> - <ui:SymbolIcon Symbol="Back" /> - </Button> - </StackPanel> - <StackPanel - Grid.Row="2" - Spacing="10" - HorizontalAlignment="Right" - Orientation="Horizontal"> - <Button - Name="Import" - Click="Import_OnClick"> - <TextBlock Text="{locale:Locale ProfileImageSelectionImportImage}" /> - </Button> - <Button - Name="SelectFirmwareImage" - IsEnabled="{Binding FirmwareFound}" - Click="SelectFirmwareImage_OnClick"> - <TextBlock Text="{locale:Locale ProfileImageSelectionSelectAvatar}" /> - </Button> - </StackPanel> - </Grid> -</UserControl> diff --git a/src/Ryujinx.Ava/UI/Views/User/UserProfileImageSelectorView.axaml.cs b/src/Ryujinx.Ava/UI/Views/User/UserProfileImageSelectorView.axaml.cs deleted file mode 100644 index fabfaa4e..00000000 --- a/src/Ryujinx.Ava/UI/Views/User/UserProfileImageSelectorView.axaml.cs +++ /dev/null @@ -1,116 +0,0 @@ -using Avalonia.Controls; -using Avalonia.Interactivity; -using Avalonia.Platform.Storage; -using Avalonia.VisualTree; -using FluentAvalonia.UI.Controls; -using FluentAvalonia.UI.Navigation; -using Ryujinx.Ava.Common.Locale; -using Ryujinx.Ava.UI.Controls; -using Ryujinx.Ava.UI.Models; -using Ryujinx.Ava.UI.ViewModels; -using Ryujinx.HLE.FileSystem; -using SixLabors.ImageSharp; -using SixLabors.ImageSharp.Processing; -using System.Collections.Generic; -using System.IO; -using Image = SixLabors.ImageSharp.Image; - -namespace Ryujinx.Ava.UI.Views.User -{ - public partial class UserProfileImageSelectorView : UserControl - { - private ContentManager _contentManager; - private NavigationDialogHost _parent; - private TempProfile _profile; - - internal UserProfileImageSelectorViewModel ViewModel { get; private set; } - - public UserProfileImageSelectorView() - { - InitializeComponent(); - AddHandler(Frame.NavigatedToEvent, (s, e) => - { - NavigatedTo(e); - }, RoutingStrategies.Direct); - } - - private void NavigatedTo(NavigationEventArgs arg) - { - if (Program.PreviewerDetached) - { - switch (arg.NavigationMode) - { - case NavigationMode.New: - (_parent, _profile) = ((NavigationDialogHost, TempProfile))arg.Parameter; - _contentManager = _parent.ContentManager; - - ((ContentDialog)_parent.Parent).Title = $"{LocaleManager.Instance[LocaleKeys.UserProfileWindowTitle]} - {LocaleManager.Instance[LocaleKeys.ProfileImageSelectionHeader]}"; - - if (Program.PreviewerDetached) - { - DataContext = ViewModel = new UserProfileImageSelectorViewModel(); - ViewModel.FirmwareFound = _contentManager.GetCurrentFirmwareVersion() != null; - } - - break; - case NavigationMode.Back: - if (_profile.Image != null) - { - _parent.GoBack(); - } - break; - } - } - } - - private async void Import_OnClick(object sender, RoutedEventArgs e) - { - var window = this.GetVisualRoot() as Window; - var result = await window.StorageProvider.OpenFilePickerAsync(new FilePickerOpenOptions - { - AllowMultiple = false, - FileTypeFilter = new List<FilePickerFileType> - { - new(LocaleManager.Instance[LocaleKeys.AllSupportedFormats]) - { - Patterns = new[] { "*.jpg", "*.jpeg", "*.png", "*.bmp" }, - AppleUniformTypeIdentifiers = new[] { "public.jpeg", "public.png", "com.microsoft.bmp" }, - MimeTypes = new[] { "image/jpeg", "image/png", "image/bmp" }, - }, - }, - }); - - if (result.Count > 0) - { - _profile.Image = ProcessProfileImage(File.ReadAllBytes(result[0].Path.LocalPath)); - _parent.GoBack(); - } - } - - private void GoBack(object sender, RoutedEventArgs e) - { - _parent.GoBack(); - } - - private void SelectFirmwareImage_OnClick(object sender, RoutedEventArgs e) - { - if (ViewModel.FirmwareFound) - { - _parent.Navigate(typeof(UserFirmwareAvatarSelectorView), (_parent, _profile)); - } - } - - private static byte[] ProcessProfileImage(byte[] buffer) - { - using Image image = Image.Load(buffer); - - image.Mutate(x => x.Resize(256, 256)); - - using MemoryStream streamJpg = new(); - - image.SaveAsJpeg(streamJpg); - - return streamJpg.ToArray(); - } - } -} diff --git a/src/Ryujinx.Ava/UI/Views/User/UserRecovererView.axaml b/src/Ryujinx.Ava/UI/Views/User/UserRecovererView.axaml deleted file mode 100644 index 3fdb4ab9..00000000 --- a/src/Ryujinx.Ava/UI/Views/User/UserRecovererView.axaml +++ /dev/null @@ -1,82 +0,0 @@ -<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:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" - mc:Ignorable="d" - d:DesignWidth="550" - d:DesignHeight="450" - Width="500" - Height="400" - xmlns:locale="clr-namespace:Ryujinx.Ava.Common.Locale" - xmlns:ui="clr-namespace:FluentAvalonia.UI.Controls;assembly=FluentAvalonia" - xmlns:viewModels="clr-namespace:Ryujinx.Ava.UI.ViewModels" - x:Class="Ryujinx.Ava.UI.Views.User.UserRecovererView" - x:DataType="viewModels:UserProfileViewModel" - Focusable="True"> - <Design.DataContext> - <viewModels:UserProfileViewModel /> - </Design.DataContext> - <Grid HorizontalAlignment="Stretch" - VerticalAlignment="Stretch"> - <Grid.RowDefinitions> - <RowDefinition/> - <RowDefinition Height="Auto"/> - </Grid.RowDefinitions> - <Border - CornerRadius="5" - BorderBrush="{DynamicResource AppListHoverBackgroundColor}" - BorderThickness="1" - Grid.Row="0"> - <Panel> - <ListBox - HorizontalAlignment="Stretch" - VerticalAlignment="Stretch" - ItemsSource="{Binding LostProfiles}"> - <ListBox.ItemTemplate> - <DataTemplate> - <Border - Margin="2" - HorizontalAlignment="Stretch" - VerticalAlignment="Stretch" - ClipToBounds="True" - CornerRadius="5"> - <Grid Margin="0"> - <Grid.ColumnDefinitions> - <ColumnDefinition/> - <ColumnDefinition Width="Auto"/> - </Grid.ColumnDefinitions> - <TextBlock - HorizontalAlignment="Stretch" - Text="{Binding UserId}" - TextAlignment="Start" - TextWrapping="Wrap" /> - <Button Grid.Column="1" - HorizontalAlignment="Right" - Click="Recover" - CommandParameter="{Binding}" - Content="{locale:Locale Recover}"/> - </Grid> - </Border> - </DataTemplate> - </ListBox.ItemTemplate> - </ListBox> - <TextBlock - IsVisible="{Binding IsEmpty}" - TextAlignment="Center" - Text="{locale:Locale UserProfilesRecoverEmptyList}"/> - </Panel> - </Border> - <StackPanel - Grid.Row="1" - Margin="0 24 0 0" - Orientation="Horizontal"> - <Button - Width="50" - MinWidth="50" - Click="GoBack"> - <ui:SymbolIcon Symbol="Back"/> - </Button> - </StackPanel> - </Grid> -</UserControl> diff --git a/src/Ryujinx.Ava/UI/Views/User/UserRecovererView.axaml.cs b/src/Ryujinx.Ava/UI/Views/User/UserRecovererView.axaml.cs deleted file mode 100644 index 31934349..00000000 --- a/src/Ryujinx.Ava/UI/Views/User/UserRecovererView.axaml.cs +++ /dev/null @@ -1,51 +0,0 @@ -using Avalonia.Controls; -using Avalonia.Interactivity; -using FluentAvalonia.UI.Controls; -using FluentAvalonia.UI.Navigation; -using Ryujinx.Ava.Common.Locale; -using Ryujinx.Ava.UI.Controls; - -namespace Ryujinx.Ava.UI.Views.User -{ - public partial class UserRecovererView : UserControl - { - private NavigationDialogHost _parent; - - public UserRecovererView() - { - InitializeComponent(); - AddHandler(Frame.NavigatedToEvent, (s, e) => - { - NavigatedTo(e); - }, RoutingStrategies.Direct); - } - - private void NavigatedTo(NavigationEventArgs arg) - { - if (Program.PreviewerDetached) - { - switch (arg.NavigationMode) - { - case NavigationMode.New: - var parent = (NavigationDialogHost)arg.Parameter; - - _parent = parent; - - ((ContentDialog)_parent.Parent).Title = $"{LocaleManager.Instance[LocaleKeys.UserProfileWindowTitle]} - {LocaleManager.Instance[LocaleKeys.UserProfilesRecoverHeading]}"; - - break; - } - } - } - - private void GoBack(object sender, RoutedEventArgs e) - { - _parent?.GoBack(); - } - - private void Recover(object sender, RoutedEventArgs e) - { - _parent?.RecoverLostAccounts(); - } - } -} diff --git a/src/Ryujinx.Ava/UI/Views/User/UserSaveManagerView.axaml b/src/Ryujinx.Ava/UI/Views/User/UserSaveManagerView.axaml deleted file mode 100644 index 8bc5125a..00000000 --- a/src/Ryujinx.Ava/UI/Views/User/UserSaveManagerView.axaml +++ /dev/null @@ -1,213 +0,0 @@ -<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:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" - xmlns:ui="clr-namespace:FluentAvalonia.UI.Controls;assembly=FluentAvalonia" - xmlns:locale="clr-namespace:Ryujinx.Ava.Common.Locale" - xmlns:helpers="clr-namespace:Ryujinx.Ava.UI.Helpers" - xmlns:models="clr-namespace:Ryujinx.Ava.UI.Models" - xmlns:viewModels="clr-namespace:Ryujinx.Ava.UI.ViewModels" - mc:Ignorable="d" - d:DesignWidth="600" - d:DesignHeight="500" - Height="450" - Width="550" - x:Class="Ryujinx.Ava.UI.Views.User.UserSaveManagerView" - x:DataType="viewModels:UserSaveManagerViewModel" - Focusable="True"> - <Design.DataContext> - <viewModels:UserSaveManagerViewModel /> - </Design.DataContext> - <UserControl.Resources> - <helpers:BitmapArrayValueConverter x:Key="ByteImage" /> - </UserControl.Resources> - <Grid> - <Grid.RowDefinitions> - <RowDefinition Height="Auto" /> - <RowDefinition /> - <RowDefinition Height="Auto" /> - </Grid.RowDefinitions> - <Grid - Grid.Row="0" - HorizontalAlignment="Stretch"> - <Grid.ColumnDefinitions> - <ColumnDefinition Width="Auto" /> - <ColumnDefinition /> - </Grid.ColumnDefinitions> - <StackPanel - Spacing="10" - Orientation="Horizontal" - HorizontalAlignment="Left" - VerticalAlignment="Center"> - <Label Content="{locale:Locale CommonSort}" VerticalAlignment="Center" /> - <ComboBox SelectedIndex="{Binding SortIndex}" Width="100"> - <ComboBoxItem> - <Label - VerticalAlignment="Center" - HorizontalContentAlignment="Left" - Content="{locale:Locale Name}" /> - </ComboBoxItem> - <ComboBoxItem> - <Label - VerticalAlignment="Center" - HorizontalContentAlignment="Left" - Content="{locale:Locale Size}" /> - </ComboBoxItem> - <ComboBox.Styles> - <Style Selector="ContentControl#ContentPresenter"> - <Setter Property="HorizontalAlignment" Value="Left" /> - </Style> - </ComboBox.Styles> - </ComboBox> - <ComboBox SelectedIndex="{Binding OrderIndex}" Width="150"> - <ComboBoxItem> - <Label - VerticalAlignment="Center" - HorizontalContentAlignment="Left" - Content="{locale:Locale OrderAscending}" /> - </ComboBoxItem> - <ComboBoxItem> - <Label - VerticalAlignment="Center" - HorizontalContentAlignment="Left" - Content="{locale:Locale OrderDescending}" /> - </ComboBoxItem> - <ComboBox.Styles> - <Style Selector="ContentControl#ContentPresenter"> - <Setter Property="HorizontalAlignment" Value="Left" /> - </Style> - </ComboBox.Styles> - </ComboBox> - </StackPanel> - <Grid - Grid.Column="1" - HorizontalAlignment="Stretch" - Margin="10,0, 0, 0"> - <Grid.ColumnDefinitions> - <ColumnDefinition Width="Auto"/> - <ColumnDefinition/> - </Grid.ColumnDefinitions> - <Label Content="{locale:Locale Search}" VerticalAlignment="Center" /> - <TextBox - Margin="5,0,0,0" - Grid.Column="1" - HorizontalAlignment="Stretch" - Text="{Binding Search}" /> - </Grid> - </Grid> - <Border - Grid.Row="1" - Margin="0,5" - BorderThickness="1" - BorderBrush="{DynamicResource AppListHoverBackgroundColor}" - CornerRadius="5" - HorizontalAlignment="Stretch" - VerticalAlignment="Stretch"> - <ListBox - Name="SaveList" - ItemsSource="{Binding Views}" - HorizontalAlignment="Stretch" - VerticalAlignment="Stretch"> - <ListBox.Styles> - <Style Selector="ListBoxItem"> - <Setter Property="Padding" Value="10" /> - <Setter Property="Margin" Value="5" /> - <Setter Property="CornerRadius" Value="4" /> - </Style> - <Style Selector="ListBoxItem:selected /template/ Rectangle#SelectionIndicator"> - <Setter Property="IsVisible" Value="False" /> - </Style> - </ListBox.Styles> - <ListBox.ItemTemplate> - <DataTemplate x:DataType="models:SaveModel"> - <Grid HorizontalAlignment="Stretch"> - <Grid.ColumnDefinitions> - <ColumnDefinition /> - <ColumnDefinition Width="Auto" /> - </Grid.ColumnDefinitions> - <StackPanel - Grid.Column="0" - Orientation="Horizontal" - Spacing="5"> - <Border - Height="42" - Width="42" - Padding="10" - BorderBrush="{DynamicResource AppListHoverBackgroundColor}" - BorderThickness="1" - IsVisible="{Binding !InGameList}"> - <ui:SymbolIcon - Symbol="Help" - FontSize="30" - HorizontalAlignment="Center" - VerticalAlignment="Center" /> - </Border> - <Image - IsVisible="{Binding InGameList}" - Width="42" - Height="42" - Source="{Binding Icon, Converter={StaticResource ByteImage}}" /> - <TextBlock - MaxLines="3" - Width="320" - Margin="5" - TextWrapping="Wrap" - Text="{Binding Title}" - VerticalAlignment="Center" /> - </StackPanel> - <StackPanel - Grid.Column="1" - Spacing="10" - HorizontalAlignment="Right" - Orientation="Horizontal"> - <Label - Content="{Binding SizeString}" - IsVisible="{Binding SizeAvailable}" - VerticalAlignment="Center" - HorizontalAlignment="Right" /> - <Button - VerticalAlignment="Center" - HorizontalAlignment="Right" - Padding="10" - MinWidth="0" - MinHeight="0" - Name="OpenLocation" - Click="OpenLocation"> - <ui:SymbolIcon - Symbol="OpenFolder" - HorizontalAlignment="Center" - VerticalAlignment="Center" /> - </Button> - <Button - VerticalAlignment="Center" - HorizontalAlignment="Right" - Padding="10" - MinWidth="0" - MinHeight="0" - Name="Delete" - Click="Delete"> - <ui:SymbolIcon - Symbol="Delete" - HorizontalAlignment="Center" - VerticalAlignment="Center" /> - </Button> - </StackPanel> - </Grid> - </DataTemplate> - </ListBox.ItemTemplate> - </ListBox> - </Border> - <StackPanel - Grid.Row="2" - Margin="0 24 0 0" - Orientation="Horizontal"> - <Button - Width="50" - MinWidth="50" - Click="GoBack"> - <ui:SymbolIcon Symbol="Back" /> - </Button> - </StackPanel> - </Grid> -</UserControl>
\ No newline at end of file diff --git a/src/Ryujinx.Ava/UI/Views/User/UserSaveManagerView.axaml.cs b/src/Ryujinx.Ava/UI/Views/User/UserSaveManagerView.axaml.cs deleted file mode 100644 index 00a229fa..00000000 --- a/src/Ryujinx.Ava/UI/Views/User/UserSaveManagerView.axaml.cs +++ /dev/null @@ -1,148 +0,0 @@ -using Avalonia.Controls; -using Avalonia.Interactivity; -using Avalonia.Threading; -using FluentAvalonia.UI.Controls; -using FluentAvalonia.UI.Navigation; -using LibHac; -using LibHac.Common; -using LibHac.Fs; -using LibHac.Fs.Shim; -using Ryujinx.Ava.Common; -using Ryujinx.Ava.Common.Locale; -using Ryujinx.Ava.UI.Controls; -using Ryujinx.Ava.UI.Helpers; -using Ryujinx.Ava.UI.Models; -using Ryujinx.Ava.UI.ViewModels; -using Ryujinx.HLE.FileSystem; -using Ryujinx.HLE.HOS.Services.Account.Acc; -using System; -using System.Collections.ObjectModel; -using System.Threading.Tasks; -using Button = Avalonia.Controls.Button; -using UserId = LibHac.Fs.UserId; - -namespace Ryujinx.Ava.UI.Views.User -{ - public partial class UserSaveManagerView : UserControl - { - internal UserSaveManagerViewModel ViewModel { get; private set; } - - private AccountManager _accountManager; - private HorizonClient _horizonClient; - private VirtualFileSystem _virtualFileSystem; - private NavigationDialogHost _parent; - - public UserSaveManagerView() - { - InitializeComponent(); - AddHandler(Frame.NavigatedToEvent, (s, e) => - { - NavigatedTo(e); - }, RoutingStrategies.Direct); - } - - private void NavigatedTo(NavigationEventArgs arg) - { - if (Program.PreviewerDetached) - { - switch (arg.NavigationMode) - { - case NavigationMode.New: - var (parent, accountManager, client, virtualFileSystem) = ((NavigationDialogHost parent, AccountManager accountManager, HorizonClient client, VirtualFileSystem virtualFileSystem))arg.Parameter; - _accountManager = accountManager; - _horizonClient = client; - _virtualFileSystem = virtualFileSystem; - - _parent = parent; - break; - } - - DataContext = ViewModel = new UserSaveManagerViewModel(_accountManager); - ((ContentDialog)_parent.Parent).Title = $"{LocaleManager.Instance[LocaleKeys.UserProfileWindowTitle]} - {ViewModel.SaveManagerHeading}"; - - Task.Run(LoadSaves); - } - } - - public void LoadSaves() - { - ViewModel.Saves.Clear(); - var saves = new ObservableCollection<SaveModel>(); - var saveDataFilter = SaveDataFilter.Make( - programId: default, - saveType: SaveDataType.Account, - new UserId((ulong)_accountManager.LastOpenedUser.UserId.High, (ulong)_accountManager.LastOpenedUser.UserId.Low), - saveDataId: default, - index: default); - - using var saveDataIterator = new UniqueRef<SaveDataIterator>(); - - _horizonClient.Fs.OpenSaveDataIterator(ref saveDataIterator.Ref, SaveDataSpaceId.User, in saveDataFilter).ThrowIfFailure(); - - Span<SaveDataInfo> saveDataInfo = stackalloc SaveDataInfo[10]; - - while (true) - { - saveDataIterator.Get.ReadSaveDataInfo(out long readCount, saveDataInfo).ThrowIfFailure(); - - if (readCount == 0) - { - break; - } - - for (int i = 0; i < readCount; i++) - { - var save = saveDataInfo[i]; - if (save.ProgramId.Value != 0) - { - var saveModel = new SaveModel(save); - saves.Add(saveModel); - } - } - } - - Dispatcher.UIThread.Post(() => - { - ViewModel.Saves = saves; - ViewModel.Sort(); - }); - } - - private void GoBack(object sender, RoutedEventArgs e) - { - _parent?.GoBack(); - } - - private void OpenLocation(object sender, RoutedEventArgs e) - { - if (sender is Button button) - { - if (button.DataContext is SaveModel saveModel) - { - ApplicationHelper.OpenSaveDir(saveModel.SaveId); - } - } - } - - private async void Delete(object sender, RoutedEventArgs e) - { - if (sender is Button button) - { - if (button.DataContext is SaveModel saveModel) - { - var result = await ContentDialogHelper.CreateConfirmationDialog(LocaleManager.Instance[LocaleKeys.DeleteUserSave], - LocaleManager.Instance[LocaleKeys.IrreversibleActionNote], - LocaleManager.Instance[LocaleKeys.InputDialogYes], - LocaleManager.Instance[LocaleKeys.InputDialogNo], ""); - - if (result == UserResult.Yes) - { - _horizonClient.Fs.DeleteSaveData(SaveDataSpaceId.User, saveModel.SaveId); - ViewModel.Saves.Remove(saveModel); - ViewModel.Sort(); - } - } - } - } - } -} diff --git a/src/Ryujinx.Ava/UI/Views/User/UserSelectorView.axaml b/src/Ryujinx.Ava/UI/Views/User/UserSelectorView.axaml deleted file mode 100644 index 3a9de303..00000000 --- a/src/Ryujinx.Ava/UI/Views/User/UserSelectorView.axaml +++ /dev/null @@ -1,162 +0,0 @@ -<UserControl - x:Class="Ryujinx.Ava.UI.Views.User.UserSelectorViews" - xmlns="https://github.com/avaloniaui" - xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" - xmlns:locale="clr-namespace:Ryujinx.Ava.Common.Locale" - xmlns:d="http://schemas.microsoft.com/expression/blend/2008" - xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" - xmlns:helpers="clr-namespace:Ryujinx.Ava.UI.Helpers" - xmlns:models="clr-namespace:Ryujinx.Ava.UI.Models" - xmlns:viewModels="clr-namespace:Ryujinx.Ava.UI.ViewModels" - xmlns:ui="clr-namespace:FluentAvalonia.UI.Controls;assembly=FluentAvalonia" - d:DesignHeight="450" - MinWidth="500" - d:DesignWidth="800" - mc:Ignorable="d" - Focusable="True" - x:DataType="viewModels:UserProfileViewModel"> - <UserControl.Resources> - <helpers:BitmapArrayValueConverter x:Key="ByteImage" /> - </UserControl.Resources> - <Design.DataContext> - <viewModels:UserProfileViewModel /> - </Design.DataContext> - <Grid HorizontalAlignment="Stretch" VerticalAlignment="Stretch"> - <Grid.RowDefinitions> - <RowDefinition /> - <RowDefinition Height="Auto" /> - </Grid.RowDefinitions> - <Border - CornerRadius="5" - BorderBrush="{DynamicResource AppListHoverBackgroundColor}" - BorderThickness="1"> - <ListBox - MaxHeight="300" - HorizontalAlignment="Stretch" - VerticalAlignment="Center" - SelectionChanged="ProfilesList_SelectionChanged" - Background="Transparent" - ItemsSource="{Binding Profiles}"> - <ListBox.ItemsPanel> - <ItemsPanelTemplate> - <WrapPanel - HorizontalAlignment="Left" - VerticalAlignment="Center" - Orientation="Horizontal"/> - </ItemsPanelTemplate> - </ListBox.ItemsPanel> - <ListBox.Styles> - <Style Selector="ListBoxItem"> - <Setter Property="Margin" Value="5 5 0 5" /> - <Setter Property="CornerRadius" Value="5" /> - </Style> - <Style Selector="Rectangle#SelectionIndicator"> - <Setter Property="Opacity" Value="0" /> - </Style> - </ListBox.Styles> - <ListBox.DataTemplates> - <DataTemplate - DataType="models:UserProfile"> - <Grid - PointerEntered="Grid_PointerEntered" - PointerExited="Grid_OnPointerExited"> - <Border - HorizontalAlignment="Stretch" - VerticalAlignment="Stretch" - ClipToBounds="True" - CornerRadius="5" - Background="{Binding BackgroundColor}"> - <StackPanel - HorizontalAlignment="Stretch" - VerticalAlignment="Stretch"> - <Image - Width="96" - Height="96" - HorizontalAlignment="Stretch" - VerticalAlignment="Top" - Source="{Binding Image, Converter={StaticResource ByteImage}}" /> - <TextBlock - HorizontalAlignment="Stretch" - MaxWidth="90" - Text="{Binding Name}" - TextAlignment="Center" - TextWrapping="Wrap" - TextTrimming="CharacterEllipsis" - MaxLines="2" - Margin="5" /> - </StackPanel> - </Border> - <Border - Margin="2" - Height="24" - Width="24" - CornerRadius="12" - HorizontalAlignment="Right" - VerticalAlignment="Top" - Background="{DynamicResource ThemeContentBackgroundColor}" - IsVisible="{Binding IsPointerOver}"> - <Button - MaxHeight="24" - MaxWidth="24" - MinHeight="24" - MinWidth="24" - CornerRadius="12" - Padding="0" - Click="EditUser"> - <ui:SymbolIcon Symbol="Edit" /> - </Button> - </Border> - </Grid> - </DataTemplate> - <DataTemplate - DataType="viewModels:BaseModel"> - <Panel - Height="118" - Width="96"> - <Button - MinWidth="50" - MinHeight="50" - MaxWidth="50" - MaxHeight="50" - CornerRadius="25" - Margin="10" - Padding="0" - HorizontalAlignment="Center" - VerticalAlignment="Center" - Click="AddUser"> - <ui:SymbolIcon Symbol="Add" /> - </Button> - <Panel.Styles> - <Style Selector="Panel"> - <Setter Property="Background" Value="{DynamicResource ListBoxBackground}"/> - </Style> - </Panel.Styles> - </Panel> - </DataTemplate> - </ListBox.DataTemplates> - </ListBox> - </Border> - <StackPanel - Grid.Row="1" - Margin="0 24 0 0" - HorizontalAlignment="Left" - Orientation="Horizontal" - Spacing="10"> - <Button - Click="ManageSaves" - Content="{locale:Locale UserProfilesManageSaves}" /> - <Button - Click="RecoverLostAccounts" - Content="{locale:Locale UserProfilesRecoverLostAccounts}" /> - </StackPanel> - <StackPanel - Grid.Row="1" - Margin="0 24 0 0" - HorizontalAlignment="Right" - Orientation="Horizontal"> - <Button - Click="Close" - Content="{locale:Locale UserProfilesClose}" /> - </StackPanel> - </Grid> -</UserControl> diff --git a/src/Ryujinx.Ava/UI/Views/User/UserSelectorView.axaml.cs b/src/Ryujinx.Ava/UI/Views/User/UserSelectorView.axaml.cs deleted file mode 100644 index fa3383aa..00000000 --- a/src/Ryujinx.Ava/UI/Views/User/UserSelectorView.axaml.cs +++ /dev/null @@ -1,129 +0,0 @@ -using Avalonia.Controls; -using Avalonia.Input; -using Avalonia.Interactivity; -using FluentAvalonia.UI.Controls; -using FluentAvalonia.UI.Navigation; -using Ryujinx.Ava.Common.Locale; -using Ryujinx.Ava.UI.Controls; -using Ryujinx.Ava.UI.Models; -using Ryujinx.Ava.UI.ViewModels; -using Button = Avalonia.Controls.Button; - -namespace Ryujinx.Ava.UI.Views.User -{ - public partial class UserSelectorViews : UserControl - { - private NavigationDialogHost _parent; - - public UserProfileViewModel ViewModel { get; set; } - - public UserSelectorViews() - { - InitializeComponent(); - - if (Program.PreviewerDetached) - { - AddHandler(Frame.NavigatedToEvent, (s, e) => - { - NavigatedTo(e); - }, RoutingStrategies.Direct); - } - } - - private void NavigatedTo(NavigationEventArgs arg) - { - if (Program.PreviewerDetached) - { - if (arg.NavigationMode == NavigationMode.New) - { - _parent = (NavigationDialogHost)arg.Parameter; - ViewModel = _parent.ViewModel; - } - - if (arg.NavigationMode == NavigationMode.Back) - { - ((ContentDialog)_parent.Parent).Title = LocaleManager.Instance[LocaleKeys.UserProfileWindowTitle]; - } - - DataContext = ViewModel; - } - } - - private void Grid_PointerEntered(object sender, PointerEventArgs e) - { - if (sender is Grid grid) - { - if (grid.DataContext is UserProfile profile) - { - profile.IsPointerOver = true; - } - } - } - - private void Grid_OnPointerExited(object sender, PointerEventArgs e) - { - if (sender is Grid grid) - { - if (grid.DataContext is UserProfile profile) - { - profile.IsPointerOver = false; - } - } - } - - private void ProfilesList_SelectionChanged(object sender, SelectionChangedEventArgs e) - { - if (sender is ListBox listBox) - { - int selectedIndex = listBox.SelectedIndex; - - if (selectedIndex >= 0 && selectedIndex < ViewModel.Profiles.Count) - { - if (ViewModel.Profiles[selectedIndex] is UserProfile userProfile) - { - _parent?.AccountManager?.OpenUser(userProfile.UserId); - - foreach (BaseModel profile in ViewModel.Profiles) - { - if (profile is UserProfile uProfile) - { - uProfile.UpdateState(); - } - } - } - } - } - } - - private void AddUser(object sender, RoutedEventArgs e) - { - _parent.AddUser(); - } - - private void EditUser(object sender, RoutedEventArgs e) - { - if (sender is Button button) - { - if (button.DataContext is UserProfile userProfile) - { - _parent.EditUser(userProfile); - } - } - } - - private void ManageSaves(object sender, RoutedEventArgs e) - { - _parent.ManageSaves(); - } - - private void RecoverLostAccounts(object sender, RoutedEventArgs e) - { - _parent.RecoverLostAccounts(); - } - - private void Close(object sender, RoutedEventArgs e) - { - ((ContentDialog)_parent.Parent).Hide(); - } - } -} diff --git a/src/Ryujinx.Ava/UI/Windows/AboutWindow.axaml b/src/Ryujinx.Ava/UI/Windows/AboutWindow.axaml deleted file mode 100644 index 69fa8251..00000000 --- a/src/Ryujinx.Ava/UI/Windows/AboutWindow.axaml +++ /dev/null @@ -1,270 +0,0 @@ -<UserControl - x:Class="Ryujinx.Ava.UI.Windows.AboutWindow" - 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:ui="clr-namespace:FluentAvalonia.UI.Controls;assembly=FluentAvalonia" - xmlns:viewModel="clr-namespace:Ryujinx.Ava.UI.ViewModels" - Width="550" - Height="260" - Margin="0,-12,0,0" - d:DesignHeight="260" - d:DesignWidth="550" - x:DataType="viewModel:AboutWindowViewModel" - Focusable="True" - mc:Ignorable="d"> - <Design.DataContext> - <viewModel:AboutWindowViewModel /> - </Design.DataContext> - <Grid HorizontalAlignment="Stretch" VerticalAlignment="Stretch"> - <Grid.ColumnDefinitions> - <ColumnDefinition Width="Auto" /> - <ColumnDefinition Width="Auto" /> - <ColumnDefinition Width="*" /> - </Grid.ColumnDefinitions> - <Grid - Grid.Column="0" - HorizontalAlignment="Stretch" - VerticalAlignment="Stretch"> - <Grid.RowDefinitions> - <RowDefinition Height="Auto" /> - <RowDefinition Height="*" /> - <RowDefinition Height="Auto" /> - </Grid.RowDefinitions> - <StackPanel - Grid.Row="0" - HorizontalAlignment="Stretch" - VerticalAlignment="Stretch" - Spacing="10"> - <Grid> - <Grid.ColumnDefinitions> - <ColumnDefinition Width="Auto" /> - <ColumnDefinition Width="*" /> - <ColumnDefinition Width="Auto" /> - </Grid.ColumnDefinitions> - <StackPanel - Grid.Column="1" - Orientation="Horizontal" - HorizontalAlignment="Center" - Spacing="10"> - <Image - Height="80" - Source="resm:Ryujinx.UI.Common.Resources.Logo_Ryujinx.png?assembly=Ryujinx.UI.Common" - HorizontalAlignment="Center" - IsHitTestVisible="True" /> - <WrapPanel - HorizontalAlignment="Right" - VerticalAlignment="Center" - Orientation="Vertical"> - <TextBlock - FontSize="28" - FontWeight="Bold" - Text="Ryujinx" - TextAlignment="Start" - Width="110" - HorizontalAlignment="Center" - VerticalAlignment="Center" /> - <TextBlock - FontSize="11" - Text="(REE-YOU-JINX)" - TextAlignment="Start" - Width="110" - HorizontalAlignment="Center" - VerticalAlignment="Center" /> - </WrapPanel> - </StackPanel> - </Grid> - <TextBlock - HorizontalAlignment="Center" - VerticalAlignment="Center" - FontSize="10" - LineHeight="12" - Text="{Binding Version}" - TextAlignment="Center" /> - <Button - Padding="5" - HorizontalAlignment="Center" - Background="Transparent" - Click="Button_OnClick" - Tag="https://github.com/Ryujinx/Ryujinx/wiki/Changelog#ryujinx-changelog"> - <TextBlock - FontSize="10" - Text="{locale:Locale AboutChangelogButton}" - TextAlignment="Center" - ToolTip.Tip="{locale:Locale AboutChangelogButtonTooltipMessage}" /> - </Button> - </StackPanel> - <StackPanel - Grid.Row="2" - HorizontalAlignment="Stretch" - VerticalAlignment="Stretch" - Spacing="10"> - <TextBlock - Width="200" - HorizontalAlignment="Center" - FontSize="10" - LineHeight="12" - Text="{locale:Locale AboutDisclaimerMessage}" - TextAlignment="Center" - TextWrapping="Wrap" /> - <TextBlock - Name="AmiiboLabel" - Width="200" - HorizontalAlignment="Center" - FontSize="10" - LineHeight="12" - PointerPressed="AmiiboLabel_OnPointerPressed" - Text="{locale:Locale AboutAmiiboDisclaimerMessage}" - TextAlignment="Center" - TextWrapping="Wrap" /> - <StackPanel - HorizontalAlignment="Center" - Orientation="Horizontal" - Spacing="10"> - <Button - MinWidth="30" - MinHeight="30" - MaxWidth="30" - MaxHeight="30" - Padding="8" - Background="Transparent" - Click="Button_OnClick" - CornerRadius="15" - Tag="https://www.patreon.com/ryujinx" - ToolTip.Tip="{locale:Locale AboutPatreonUrlTooltipMessage}"> - <Image Source="{Binding PatreonLogo}" /> - </Button> - <Button - MinWidth="30" - MinHeight="30" - MaxWidth="30" - MaxHeight="30" - Padding="8" - Background="Transparent" - Click="Button_OnClick" - CornerRadius="15" - Tag="https://github.com/Ryujinx/Ryujinx" - ToolTip.Tip="{locale:Locale AboutGithubUrlTooltipMessage}"> - <Image Source="{Binding GithubLogo}" /> - </Button> - <Button - MinWidth="30" - MinHeight="30" - MaxWidth="30" - MaxHeight="30" - Padding="8" - Background="Transparent" - Click="Button_OnClick" - CornerRadius="15" - Tag="https://discordapp.com/invite/N2FmfVc" - ToolTip.Tip="{locale:Locale AboutDiscordUrlTooltipMessage}"> - <Image Source="{Binding DiscordLogo}" /> - </Button> - <Button - MinWidth="30" - MinHeight="30" - MaxWidth="30" - MaxHeight="30" - Padding="8" - Background="Transparent" - Click="Button_OnClick" - CornerRadius="15" - Tag="https://twitter.com/RyujinxEmu" - ToolTip.Tip="{locale:Locale AboutTwitterUrlTooltipMessage}"> - <Image Source="{Binding TwitterLogo}" /> - </Button> - <Button - MinWidth="30" - MinHeight="30" - MaxWidth="30" - MaxHeight="30" - Padding="8" - Background="Transparent" - Click="Button_OnClick" - CornerRadius="15" - Tag="https://www.ryujinx.org" - ToolTip.Tip="{locale:Locale AboutUrlTooltipMessage}"> - <ui:SymbolIcon Foreground="{DynamicResource ThemeForegroundColor}" Symbol="Link" /> - </Button> - </StackPanel> - </StackPanel> - </Grid> - <Border - Grid.Column="1" - Width="1" - Margin="20,0" - VerticalAlignment="Stretch" - BorderBrush="{DynamicResource ThemeControlBorderColor}" - BorderThickness="1,0,0,0" /> - <Grid - Grid.Column="2" - HorizontalAlignment="Stretch" - VerticalAlignment="Stretch"> - <Grid.RowDefinitions> - <RowDefinition Height="Auto" /> - <RowDefinition Height="Auto" /> - <RowDefinition Height="Auto" /> - </Grid.RowDefinitions> - <StackPanel - Grid.Row="0" - Margin="0,10,0,0" - Spacing="2"> - <TextBlock - FontSize="15" - FontWeight="Bold" - Text="{locale:Locale AboutRyujinxAboutTitle}" /> - <TextBlock - FontSize="10" - Text="{locale:Locale AboutRyujinxAboutContent}" - TextWrapping="Wrap" /> - </StackPanel> - <StackPanel - Grid.Row="1" - Margin="0,10,0,0" - Spacing="2"> - <TextBlock - FontSize="15" - FontWeight="Bold" - Text="{locale:Locale AboutRyujinxMaintainersTitle}" /> - <TextBlock - FontSize="10" - Text="{Binding Developers}" - TextWrapping="Wrap" /> - <Button - Padding="5" - HorizontalAlignment="Left" - Background="Transparent" - Click="Button_OnClick" - Tag="https://github.com/Ryujinx/Ryujinx/graphs/contributors?type=a"> - <TextBlock - FontSize="10" - Text="{locale:Locale AboutRyujinxContributorsButtonHeader}" - TextAlignment="End" - ToolTip.Tip="{locale:Locale AboutRyujinxMaintainersContentTooltipMessage}" /> - </Button> - </StackPanel> - <StackPanel - Grid.Row="2" - Margin="0,10,0,0" - Spacing="2"> - <TextBlock - FontSize="15" - FontWeight="Bold" - Text="{locale:Locale AboutRyujinxSupprtersTitle}" /> - <ScrollViewer - Height="70" - HorizontalScrollBarVisibility="Disabled" - VerticalScrollBarVisibility="Visible"> - <TextBlock - Name="SupportersTextBlock" - VerticalAlignment="Top" - FontSize="10" - Text="{Binding Supporters}" - TextWrapping="Wrap" /> - </ScrollViewer> - </StackPanel> - </Grid> - </Grid> -</UserControl> diff --git a/src/Ryujinx.Ava/UI/Windows/AboutWindow.axaml.cs b/src/Ryujinx.Ava/UI/Windows/AboutWindow.axaml.cs deleted file mode 100644 index c32661b0..00000000 --- a/src/Ryujinx.Ava/UI/Windows/AboutWindow.axaml.cs +++ /dev/null @@ -1,63 +0,0 @@ -using Avalonia.Controls; -using Avalonia.Input; -using Avalonia.Interactivity; -using Avalonia.Layout; -using Avalonia.Styling; -using FluentAvalonia.UI.Controls; -using Ryujinx.Ava.Common.Locale; -using Ryujinx.Ava.UI.Helpers; -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 AboutWindow : UserControl - { - public AboutWindow() - { - DataContext = new AboutWindowViewModel(); - - InitializeComponent(); - } - - public static async Task Show() - { - ContentDialog contentDialog = new() - { - PrimaryButtonText = "", - SecondaryButtonText = "", - CloseButtonText = LocaleManager.Instance[LocaleKeys.UserProfilesClose], - Content = new AboutWindow(), - }; - - Style closeButton = new(x => x.Name("CloseButton")); - closeButton.Setters.Add(new Setter(WidthProperty, 80d)); - - Style closeButtonParent = new(x => x.Name("CommandSpace")); - closeButtonParent.Setters.Add(new Setter(HorizontalAlignmentProperty, HorizontalAlignment.Right)); - - contentDialog.Styles.Add(closeButton); - contentDialog.Styles.Add(closeButtonParent); - - await ContentDialogHelper.ShowAsync(contentDialog); - } - - private void Button_OnClick(object sender, RoutedEventArgs e) - { - if (sender is Button button) - { - OpenHelper.OpenUrl(button.Tag.ToString()); - } - } - - private void AmiiboLabel_OnPointerPressed(object sender, PointerPressedEventArgs e) - { - if (sender is TextBlock) - { - OpenHelper.OpenUrl("https://amiiboapi.com"); - } - } - } -} diff --git a/src/Ryujinx.Ava/UI/Windows/AmiiboWindow.axaml b/src/Ryujinx.Ava/UI/Windows/AmiiboWindow.axaml deleted file mode 100644 index c587aa87..00000000 --- a/src/Ryujinx.Ava/UI/Windows/AmiiboWindow.axaml +++ /dev/null @@ -1,75 +0,0 @@ -<window:StyleableWindow - xmlns="https://github.com/avaloniaui" - xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" - xmlns:d="http://schemas.microsoft.com/expression/blend/2008" - xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" - xmlns:window="clr-namespace:Ryujinx.Ava.UI.Windows" - xmlns:viewModels="clr-namespace:Ryujinx.Ava.UI.ViewModels" - xmlns:locale="clr-namespace:Ryujinx.Ava.Common.Locale" - mc:Ignorable="d" - d:DesignWidth="400" - d:DesignHeight="350" - x:Class="Ryujinx.Ava.UI.Windows.AmiiboWindow" - x:DataType="viewModels:AmiiboWindowViewModel" - CanResize="False" - WindowStartupLocation="CenterOwner" - Width="800" - MinHeight="650" - Height="650" - SizeToContent="Manual" - MinWidth="600" - Focusable="True"> - <Design.DataContext> - <viewModels:AmiiboWindowViewModel /> - </Design.DataContext> - <Grid Margin="15" HorizontalAlignment="Stretch" VerticalAlignment="Stretch"> - <Grid.RowDefinitions> - <RowDefinition Height="Auto" /> - <RowDefinition Height="Auto" /> - <RowDefinition Height="*" /> - <RowDefinition Height="Auto" /> - </Grid.RowDefinitions> - <Grid Grid.Row="1" HorizontalAlignment="Stretch"> - <Grid.ColumnDefinitions> - <ColumnDefinition /> - <ColumnDefinition /> - </Grid.ColumnDefinitions> - <StackPanel Spacing="10" Orientation="Horizontal" HorizontalAlignment="Left"> - <TextBlock VerticalAlignment="Center" Text="{locale:Locale AmiiboSeriesLabel}" /> - <ComboBox SelectedIndex="{Binding SeriesSelectedIndex}" ItemsSource="{Binding AmiiboSeries}" MinWidth="100" /> - </StackPanel> - <StackPanel Spacing="10" Grid.Column="1" Orientation="Horizontal" HorizontalAlignment="Right"> - <TextBlock VerticalAlignment="Center" Text="{locale:Locale AmiiboCharacterLabel}" /> - <ComboBox SelectedIndex="{Binding AmiiboSelectedIndex}" MinWidth="100" ItemsSource="{Binding AmiiboList}" /> - </StackPanel> - </Grid> - <StackPanel Margin="20" Grid.Row="2"> - <Image Source="{Binding AmiiboImage}" Height="350" Width="350" HorizontalAlignment="Center" /> - <ScrollViewer MaxHeight="120" HorizontalScrollBarVisibility="Disabled" VerticalScrollBarVisibility="Auto" - Margin="20" VerticalAlignment="Top" HorizontalAlignment="Stretch"> - <TextBlock TextWrapping="Wrap" Text="{Binding Usage}" HorizontalAlignment="Center" - TextAlignment="Center" /> - </ScrollViewer> - </StackPanel> - <Grid Grid.Row="3"> - <Grid.ColumnDefinitions> - <ColumnDefinition Width="Auto" /> - <ColumnDefinition Width="Auto" /> - <ColumnDefinition Width="*" /> - <ColumnDefinition Width="Auto" /> - <ColumnDefinition Width="Auto" /> - </Grid.ColumnDefinitions> - <CheckBox Margin="10" Grid.Column="0" VerticalContentAlignment="Center" IsChecked="{Binding ShowAllAmiibo}" - Content="{locale:Locale AmiiboOptionsShowAllLabel}" /> - <CheckBox Margin="10" VerticalContentAlignment="Center" Grid.Column="1" IsChecked="{Binding UseRandomUuid}" - Content="{locale:Locale AmiiboOptionsUsRandomTagLabel}" /> - - <Button Grid.Column="3" IsEnabled="{Binding EnableScanning}" Width="80" - Content="{locale:Locale AmiiboScanButtonLabel}" Name="ScanButton" - Click="ScanButton_Click" /> - <Button Grid.Column="4" Margin="10,0" Width="80" Content="{locale:Locale InputDialogCancel}" - Name="CancelButton" - Click="CancelButton_Click" /> - </Grid> - </Grid> -</window:StyleableWindow> diff --git a/src/Ryujinx.Ava/UI/Windows/AmiiboWindow.axaml.cs b/src/Ryujinx.Ava/UI/Windows/AmiiboWindow.axaml.cs deleted file mode 100644 index 8829cb10..00000000 --- a/src/Ryujinx.Ava/UI/Windows/AmiiboWindow.axaml.cs +++ /dev/null @@ -1,60 +0,0 @@ -using Avalonia.Interactivity; -using Ryujinx.Ava.Common.Locale; -using Ryujinx.Ava.UI.ViewModels; -using Ryujinx.UI.Common.Models.Amiibo; - -namespace Ryujinx.Ava.UI.Windows -{ - public partial class AmiiboWindow : StyleableWindow - { - public AmiiboWindow(bool showAll, string lastScannedAmiiboId, string titleId) - { - ViewModel = new AmiiboWindowViewModel(this, lastScannedAmiiboId, titleId) - { - ShowAllAmiibo = showAll, - }; - - DataContext = ViewModel; - - InitializeComponent(); - - Title = $"Ryujinx {Program.Version} - " + LocaleManager.Instance[LocaleKeys.Amiibo]; - } - - public AmiiboWindow() - { - ViewModel = new AmiiboWindowViewModel(this, string.Empty, string.Empty); - - DataContext = ViewModel; - - InitializeComponent(); - - if (Program.PreviewerDetached) - { - Title = $"Ryujinx {Program.Version} - " + LocaleManager.Instance[LocaleKeys.Amiibo]; - } - } - - public bool IsScanned { get; set; } - public AmiiboApi ScannedAmiibo { get; set; } - public AmiiboWindowViewModel ViewModel { get; set; } - - private void ScanButton_Click(object sender, RoutedEventArgs e) - { - if (ViewModel.AmiiboSelectedIndex > -1) - { - AmiiboApi amiibo = ViewModel.AmiiboList[ViewModel.AmiiboSelectedIndex]; - ScannedAmiibo = amiibo; - IsScanned = true; - Close(); - } - } - - private void CancelButton_Click(object sender, RoutedEventArgs e) - { - IsScanned = false; - - Close(); - } - } -} diff --git a/src/Ryujinx.Ava/UI/Windows/CheatWindow.axaml b/src/Ryujinx.Ava/UI/Windows/CheatWindow.axaml deleted file mode 100644 index 57d5f7ef..00000000 --- a/src/Ryujinx.Ava/UI/Windows/CheatWindow.axaml +++ /dev/null @@ -1,126 +0,0 @@ -<window:StyleableWindow - 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" - Width="500" - Height="500" - MinWidth="500" - MinHeight="500" - x:DataType="window:CheatWindow" - WindowStartupLocation="CenterOwner" - mc:Ignorable="d" - Focusable="True"> - <Window.Styles> - <Style Selector="TreeViewItem"> - <Setter Property="IsExpanded" Value="True" /> - </Style> - </Window.Styles> - <Grid Name="CheatGrid" Margin="15"> - <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" /> - <Border - Grid.Row="3" - Grid.Column="0" - Grid.ColumnSpan="2" - Margin="5" - HorizontalAlignment="Stretch" - VerticalAlignment="Stretch" - BorderBrush="Gray" - BorderThickness="1"> - <TreeView - Name="CheatsView" - MinHeight="300" - HorizontalAlignment="Stretch" - VerticalAlignment="Stretch" - ItemsSource="{Binding LoadedCheats}"> - <TreeView.Styles> - <Styles> - <Style Selector="TreeViewItem:empty /template/ ItemsPresenter"> - <Setter Property="IsVisible" Value="False" /> - </Style> - </Styles> - </TreeView.Styles> - <TreeView.ItemTemplate> - <TreeDataTemplate ItemsSource="{Binding SubNodes}"> - <StackPanel HorizontalAlignment="Left" Orientation="Horizontal"> - <CheckBox MinWidth="20" IsChecked="{Binding IsEnabled}" /> - <TextBlock Width="150" Text="{Binding CleanName}" IsVisible="{Binding !IsRootNode}" /> - <TextBlock Width="150" Text="{Binding BuildId}" IsVisible="{Binding IsRootNode}" /> - <TextBlock Text="{Binding Path}" IsVisible="{Binding IsRootNode}" /> - </StackPanel> - </TreeDataTemplate> - </TreeView.ItemTemplate> - </TreeView> - </Border> - <DockPanel - Grid.Row="4" - Grid.Column="0" - Grid.ColumnSpan="2" - Margin="0" - HorizontalAlignment="Stretch"> - <DockPanel Margin="0" HorizontalAlignment="Right"> - <Button - Name="SaveButton" - MinWidth="90" - Margin="5" - Command="{Binding Save}" - IsVisible="{Binding !NoCheatsFound}"> - <TextBlock Text="{locale:Locale SettingsButtonSave}" /> - </Button> - <Button - Name="CancelButton" - MinWidth="90" - Margin="5" - Command="{Binding Close}"> - <TextBlock Text="{locale:Locale InputDialogCancel}" /> - </Button> - </DockPanel> - </DockPanel> - </Grid> -</window:StyleableWindow> diff --git a/src/Ryujinx.Ava/UI/Windows/CheatWindow.axaml.cs b/src/Ryujinx.Ava/UI/Windows/CheatWindow.axaml.cs deleted file mode 100644 index d78e48a4..00000000 --- a/src/Ryujinx.Ava/UI/Windows/CheatWindow.axaml.cs +++ /dev/null @@ -1,123 +0,0 @@ -using Avalonia.Collections; -using Ryujinx.Ava.Common.Locale; -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.Globalization; -using System.IO; -using System.Linq; - -namespace Ryujinx.Ava.UI.Windows -{ - public partial class CheatWindow : StyleableWindow - { - private readonly string _enabledCheatsPath; - public bool NoCheatsFound { get; } - - public AvaloniaList<CheatNode> LoadedCheats { get; } - - public string Heading { get; } - public string BuildId { get; } - - public CheatWindow() - { - DataContext = this; - - InitializeComponent(); - - Title = $"Ryujinx {Program.Version} - " + LocaleManager.Instance[LocaleKeys.CheatWindowTitle]; - } - - public CheatWindow(VirtualFileSystem virtualFileSystem, string titleId, string titleName, string titlePath) - { - LoadedCheats = new AvaloniaList<CheatNode>(); - - Heading = LocaleManager.Instance.UpdateAndGetDynamicValue(LocaleKeys.CheatWindowHeading, titleName, titleId.ToUpper()); - BuildId = ApplicationData.GetApplicationBuildId(virtualFileSystem, 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() - { - if (NoCheatsFound) - { - return; - } - - 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); - - Close(); - } - } -} diff --git a/src/Ryujinx.Ava/UI/Windows/ContentDialogOverlayWindow.axaml b/src/Ryujinx.Ava/UI/Windows/ContentDialogOverlayWindow.axaml deleted file mode 100644 index 8b52bade..00000000 --- a/src/Ryujinx.Ava/UI/Windows/ContentDialogOverlayWindow.axaml +++ /dev/null @@ -1,25 +0,0 @@ -<window:StyleableWindow - xmlns="https://github.com/avaloniaui" - xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" - xmlns:d="http://schemas.microsoft.com/expression/blend/2008" - xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" - xmlns:ui="clr-namespace:FluentAvalonia.UI.Controls;assembly=FluentAvalonia" - xmlns:window="clr-namespace:Ryujinx.Ava.UI.Windows" - mc:Ignorable="d" - d:DesignWidth="800" - d:DesignHeight="450" - x:Class="Ryujinx.Ava.UI.Windows.ContentDialogOverlayWindow" - Title="ContentDialogOverlayWindow" - Focusable="False"> - <window:StyleableWindow.Styles> - <Style Selector="ui|ContentDialog /template/ Panel#LayoutRoot"> - <Setter Property="Background" - Value="Transparent" /> - </Style> - </window:StyleableWindow.Styles> - <ui:ContentDialog Name="ContentDialog" - IsPrimaryButtonEnabled="True" - IsSecondaryButtonEnabled="True" - IsVisible="False" - Focusable="True"/> -</window:StyleableWindow> diff --git a/src/Ryujinx.Ava/UI/Windows/ContentDialogOverlayWindow.axaml.cs b/src/Ryujinx.Ava/UI/Windows/ContentDialogOverlayWindow.axaml.cs deleted file mode 100644 index 2b12d72f..00000000 --- a/src/Ryujinx.Ava/UI/Windows/ContentDialogOverlayWindow.axaml.cs +++ /dev/null @@ -1,21 +0,0 @@ -using Avalonia.Controls; -using Avalonia.Media; - -namespace Ryujinx.Ava.UI.Windows -{ - public partial class ContentDialogOverlayWindow : StyleableWindow - { - public ContentDialogOverlayWindow() - { - InitializeComponent(); - - ExtendClientAreaToDecorationsHint = true; - TransparencyLevelHint = new[] { WindowTransparencyLevel.Transparent }; - WindowStartupLocation = WindowStartupLocation.Manual; - SystemDecorations = SystemDecorations.None; - ExtendClientAreaTitleBarHeightHint = 0; - Background = Brushes.Transparent; - CanResize = false; - } - } -} diff --git a/src/Ryujinx.Ava/UI/Windows/DownloadableContentManagerWindow.axaml b/src/Ryujinx.Ava/UI/Windows/DownloadableContentManagerWindow.axaml deleted file mode 100644 index 99cf28e7..00000000 --- a/src/Ryujinx.Ava/UI/Windows/DownloadableContentManagerWindow.axaml +++ /dev/null @@ -1,192 +0,0 @@ -<UserControl - x:Class="Ryujinx.Ava.UI.Windows.DownloadableContentManagerWindow" - 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:DataType="viewModels:DownloadableContentManagerViewModel" - 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 UpdateCount}" /> - <StackPanel - Margin="10 0" - Grid.Column="1" - Orientation="Horizontal"> - <Button - Name="EnableAllButton" - MinWidth="90" - Margin="5" - Command="{Binding EnableAll}"> - <TextBlock Text="{locale:Locale DlcManagerEnableAllButton}" /> - </Button> - <Button - Name="DisableAllButton" - MinWidth="90" - Margin="5" - Command="{Binding DisableAll}"> - <TextBlock Text="{locale:Locale DlcManagerDisableAllButton}" /> - </Button> - </StackPanel> - <TextBox - Grid.Column="2" - MinHeight="29" - MaxHeight="29" - 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 SelectedDownloadableContents, Mode=TwoWay}" - ItemsSource="{Binding Views}"> - <ListBox.DataTemplates> - <DataTemplate - DataType="models:DownloadableContentModel"> - <Panel Margin="10"> - <Grid> - <Grid.ColumnDefinitions> - <ColumnDefinition Width="*" /> - <ColumnDefinition Width="Auto" /> - </Grid.ColumnDefinitions> - <Grid - Grid.Column="0"> - <Grid.ColumnDefinitions> - <ColumnDefinition Width="*" /> - <ColumnDefinition Width="Auto" /> - </Grid.ColumnDefinitions> - <TextBlock - Grid.Column="0" - HorizontalAlignment="Left" - VerticalAlignment="Center" - MaxLines="2" - TextWrapping="Wrap" - TextTrimming="CharacterEllipsis" - Text="{Binding FileName}" /> - <TextBlock - Grid.Column="1" - Margin="10 0" - HorizontalAlignment="Left" - VerticalAlignment="Center" - Text="{Binding TitleId}" /> - </Grid> - <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="RemoveDLC"> - <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" - Command="{Binding RemoveAll}"> - <TextBlock Text="{locale:Locale DlcManagerRemoveAllButton}" /> - </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/DownloadableContentManagerWindow.axaml.cs b/src/Ryujinx.Ava/UI/Windows/DownloadableContentManagerWindow.axaml.cs deleted file mode 100644 index 0c02fa0f..00000000 --- a/src/Ryujinx.Ava/UI/Windows/DownloadableContentManagerWindow.axaml.cs +++ /dev/null @@ -1,115 +0,0 @@ -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.HLE.FileSystem; -using Ryujinx.UI.Common.Helper; -using System.Threading.Tasks; -using Button = Avalonia.Controls.Button; - -namespace Ryujinx.Ava.UI.Windows -{ - public partial class DownloadableContentManagerWindow : UserControl - { - public DownloadableContentManagerViewModel ViewModel; - - public DownloadableContentManagerWindow() - { - DataContext = this; - - InitializeComponent(); - } - - public DownloadableContentManagerWindow(VirtualFileSystem virtualFileSystem, ulong titleId) - { - DataContext = ViewModel = new DownloadableContentManagerViewModel(virtualFileSystem, titleId); - - InitializeComponent(); - } - - public static async Task Show(VirtualFileSystem virtualFileSystem, ulong titleId, string titleName) - { - ContentDialog contentDialog = new() - { - PrimaryButtonText = "", - SecondaryButtonText = "", - CloseButtonText = "", - Content = new DownloadableContentManagerWindow(virtualFileSystem, titleId), - Title = string.Format(LocaleManager.Instance[LocaleKeys.DlcWindowTitle], 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 ContentDialogHelper.ShowAsync(contentDialog); - } - - private void SaveAndClose(object sender, RoutedEventArgs routedEventArgs) - { - ViewModel.Save(); - ((ContentDialog)Parent).Hide(); - } - - private void Close(object sender, RoutedEventArgs e) - { - ((ContentDialog)Parent).Hide(); - } - - private void RemoveDLC(object sender, RoutedEventArgs e) - { - if (sender is Button button) - { - if (button.DataContext is DownloadableContentModel model) - { - ViewModel.Remove(model); - } - } - } - - private void OpenLocation(object sender, RoutedEventArgs e) - { - if (sender is Button button) - { - if (button.DataContext is DownloadableContentModel model) - { - OpenHelper.LocateFile(model.ContainerPath); - } - } - } - - private void OnSelectionChanged(object sender, SelectionChangedEventArgs e) - { - foreach (var content in e.AddedItems) - { - if (content is DownloadableContentModel model) - { - var index = ViewModel.DownloadableContents.IndexOf(model); - - if (index != -1) - { - ViewModel.DownloadableContents[index].Enabled = true; - } - } - } - - foreach (var content in e.RemovedItems) - { - if (content is DownloadableContentModel model) - { - var index = ViewModel.DownloadableContents.IndexOf(model); - - if (index != -1) - { - ViewModel.DownloadableContents[index].Enabled = false; - } - } - } - } - } -} diff --git a/src/Ryujinx.Ava/UI/Windows/IconColorPicker.cs b/src/Ryujinx.Ava/UI/Windows/IconColorPicker.cs deleted file mode 100644 index 4c75a5ff..00000000 --- a/src/Ryujinx.Ava/UI/Windows/IconColorPicker.cs +++ /dev/null @@ -1,194 +0,0 @@ -using SixLabors.ImageSharp; -using SixLabors.ImageSharp.PixelFormats; -using System; -using System.Collections.Generic; - -namespace Ryujinx.Ava.UI.Windows -{ - static class IconColorPicker - { - private const int ColorsPerLine = 64; - private const int TotalColors = ColorsPerLine * ColorsPerLine; - - private const int UvQuantBits = 3; - private const int UvQuantShift = BitsPerComponent - UvQuantBits; - - private const int SatQuantBits = 5; - private const int SatQuantShift = BitsPerComponent - SatQuantBits; - - private const int BitsPerComponent = 8; - - private const int CutOffLuminosity = 64; - - private readonly struct PaletteColor - { - public int Qck { get; } - public byte R { get; } - public byte G { get; } - public byte B { get; } - - public PaletteColor(int qck, byte r, byte g, byte b) - { - Qck = qck; - R = r; - G = g; - B = b; - } - } - - public static Color GetFilteredColor(Image<Bgra32> image) - { - var color = GetColor(image).ToPixel<Bgra32>(); - - // We don't want colors that are too dark. - // If the color is too dark, make it brighter by reducing the range - // and adding a constant color. - int luminosity = GetColorApproximateLuminosity(color.R, color.G, color.B); - if (luminosity < CutOffLuminosity) - { - color = Color.FromRgb( - (byte)Math.Min(CutOffLuminosity + color.R, byte.MaxValue), - (byte)Math.Min(CutOffLuminosity + color.G, byte.MaxValue), - (byte)Math.Min(CutOffLuminosity + color.B, byte.MaxValue)); - } - - return color; - } - - public static Color GetColor(Image<Bgra32> image) - { - var colors = new PaletteColor[TotalColors]; - - var dominantColorBin = new Dictionary<int, int>(); - - var buffer = GetBuffer(image); - - int w = image.Width; - - int w8 = w << 8; - int h8 = image.Height << 8; - -#pragma warning disable IDE0059 // Unnecessary assignment - int xStep = w8 / ColorsPerLine; - int yStep = h8 / ColorsPerLine; -#pragma warning restore IDE0059 - - int i = 0; - int maxHitCount = 0; - - for (int y = 0; y < image.Height; y++) - { - int yOffset = y * image.Width; - - for (int x = 0; x < image.Width && i < TotalColors; x++) - { - int offset = x + yOffset; - - byte cb = buffer[offset].B; - byte cg = buffer[offset].G; - byte cr = buffer[offset].R; - - var qck = GetQuantizedColorKey(cr, cg, cb); - - if (dominantColorBin.TryGetValue(qck, out int hitCount)) - { - dominantColorBin[qck] = hitCount + 1; - - if (maxHitCount < hitCount) - { - maxHitCount = hitCount; - } - } - else - { - dominantColorBin.Add(qck, 1); - } - - colors[i++] = new PaletteColor(qck, cr, cg, cb); - } - } - - int highScore = -1; - PaletteColor bestCandidate = default; - - for (i = 0; i < TotalColors; i++) - { - var score = GetColorScore(dominantColorBin, maxHitCount, colors[i]); - - if (highScore < score) - { - highScore = score; - bestCandidate = colors[i]; - } - } - - return Color.FromRgb(bestCandidate.R, bestCandidate.G, bestCandidate.B); - } - - public static Bgra32[] GetBuffer(Image<Bgra32> image) - { - return image.TryGetSinglePixelSpan(out var data) ? data.ToArray() : Array.Empty<Bgra32>(); - } - - private static int GetColorScore(Dictionary<int, int> dominantColorBin, int maxHitCount, PaletteColor color) - { - var hitCount = dominantColorBin[color.Qck]; - var balancedHitCount = BalanceHitCount(hitCount, maxHitCount); - var quantSat = (GetColorSaturation(color) >> SatQuantShift) << SatQuantShift; - var value = GetColorValue(color); - - // If the color is rarely used on the image, - // then chances are that theres a better candidate, even if the saturation value - // is high. By multiplying the saturation value with a weight, we can lower - // it if the color is almost never used (hit count is low). - var satWeighted = quantSat; - var satWeight = balancedHitCount << 5; - if (satWeight < 0x100) - { - satWeighted = (satWeighted * satWeight) >> 8; - } - - // Compute score from saturation and dominance of the color. - // We prefer more vivid colors over dominant ones, so give more weight to the saturation. - var score = ((satWeighted << 1) + balancedHitCount) * value; - - return score; - } - - private static int BalanceHitCount(int hitCount, int maxHitCount) - { - return (hitCount << 8) / maxHitCount; - } - - private static int GetColorApproximateLuminosity(byte r, byte g, byte b) - { - return (r + g + b) / 3; - } - - private static int GetColorSaturation(PaletteColor color) - { - int cMax = Math.Max(Math.Max(color.R, color.G), color.B); - - if (cMax == 0) - { - return 0; - } - - int cMin = Math.Min(Math.Min(color.R, color.G), color.B); - int delta = cMax - cMin; - return (delta << 8) / cMax; - } - - private static int GetColorValue(PaletteColor color) - { - return Math.Max(Math.Max(color.R, color.G), color.B); - } - - private static int GetQuantizedColorKey(byte r, byte g, byte b) - { - int u = ((-38 * r - 74 * g + 112 * b + 128) >> 8) + 128; - int v = ((112 * r - 94 * g - 18 * b + 128) >> 8) + 128; - return (v >> UvQuantShift) | ((u >> UvQuantShift) << UvQuantBits); - } - } -} diff --git a/src/Ryujinx.Ava/UI/Windows/MainWindow.axaml b/src/Ryujinx.Ava/UI/Windows/MainWindow.axaml deleted file mode 100644 index 4def7c28..00000000 --- a/src/Ryujinx.Ava/UI/Windows/MainWindow.axaml +++ /dev/null @@ -1,205 +0,0 @@ -<window:StyleableWindow - x:Class="Ryujinx.Ava.UI.Windows.MainWindow" - xmlns="https://github.com/avaloniaui" - xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" - xmlns:d="http://schemas.microsoft.com/expression/blend/2008" - xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" - xmlns:window="clr-namespace:Ryujinx.Ava.UI.Windows" - xmlns:viewModels="clr-namespace:Ryujinx.Ava.UI.ViewModels" - xmlns:helpers="clr-namespace:Ryujinx.Ava.UI.Helpers" - xmlns:controls="clr-namespace:Ryujinx.Ava.UI.Controls" - xmlns:main="clr-namespace:Ryujinx.Ava.UI.Views.Main" - Cursor="{Binding Cursor}" - Title="{Binding Title}" - WindowState="{Binding WindowState}" - Width="{Binding WindowWidth}" - Height="{Binding WindowHeight}" - MinWidth="1092" - MinHeight="672" - d:DesignHeight="720" - d:DesignWidth="1280" - x:DataType="viewModels:MainWindowViewModel" - mc:Ignorable="d" - WindowStartupLocation="Manual" - Focusable="True"> - <Window.Styles> - <Style Selector="TitleBar:fullscreen"> - <Setter Property="Background" Value="#000000" /> - </Style> - </Window.Styles> - <Design.DataContext> - <viewModels:MainWindowViewModel /> - </Design.DataContext> - <Window.Resources> - <helpers:BitmapArrayValueConverter x:Key="ByteImage" /> - </Window.Resources> - <Window.KeyBindings> - <KeyBinding Gesture="Alt+Return" Command="{Binding ToggleFullscreen}" /> - <KeyBinding Gesture="F11" Command="{Binding ToggleFullscreen}" /> - <KeyBinding Gesture="Ctrl+Cmd+F" Command="{Binding ToggleFullscreen}" /> - <KeyBinding Gesture="F9" Command="{Binding ToggleDockMode}" /> - <KeyBinding Gesture="Escape" Command="{Binding ExitCurrentState}" /> - </Window.KeyBindings> - <Grid HorizontalAlignment="Stretch" VerticalAlignment="Stretch"> - <Grid.RowDefinitions> - <RowDefinition Height="Auto" /> - <RowDefinition Height="*" /> - </Grid.RowDefinitions> - <helpers:OffscreenTextBox Name="HiddenTextBox" Grid.Row="0" /> - <Grid - Grid.Row="1" - HorizontalAlignment="Stretch" - VerticalAlignment="Stretch"> - <Grid.ColumnDefinitions> - <ColumnDefinition Width="*" /> - </Grid.ColumnDefinitions> - <Grid.RowDefinitions> - <RowDefinition Height="Auto" /> - <RowDefinition Height="*" /> - <RowDefinition Height="Auto" /> - </Grid.RowDefinitions> - <StackPanel - Name="MenuBar" - MinHeight="35" - Grid.Row="0" - Margin="0" - HorizontalAlignment="Stretch" - VerticalAlignment="Stretch" - IsVisible="{Binding ShowMenuAndStatusBar}" - Orientation="Vertical"> - <main:MainMenuBarView - Name="MenuBarView" /> - </StackPanel> - <ContentControl - Name="MainContent" - Grid.Row="1" - Padding="0" - HorizontalAlignment="Stretch" - VerticalAlignment="Stretch" - BorderBrush="{DynamicResource ThemeControlBorderColor}" - BorderThickness="0,0,0,0" - DockPanel.Dock="Top" - IsVisible="{Binding ShowContent}"> - <Grid HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Name="GameLibrary"> - <Grid.RowDefinitions> - <RowDefinition Height="Auto" /> - <RowDefinition Height="*" /> - </Grid.RowDefinitions> - <main:MainViewControls - Name="ViewControls" - Grid.Row="0"/> - <controls:ApplicationListView - x:Name="ApplicationList" - Grid.Row="1" - HorizontalAlignment="Stretch" - VerticalAlignment="Stretch" - HorizontalContentAlignment="Stretch" - VerticalContentAlignment="Stretch" - IsVisible="{Binding IsList}" /> - <controls:ApplicationGridView - x:Name="ApplicationGrid" - Grid.Row="1" - HorizontalAlignment="Stretch" - VerticalAlignment="Stretch" - HorizontalContentAlignment="Stretch" - VerticalContentAlignment="Stretch" - IsVisible="{Binding IsGrid}" /> - </Grid> - </ContentControl> - <Grid - Grid.Row="1" - HorizontalAlignment="Stretch" - VerticalAlignment="Stretch" - Background="{DynamicResource ThemeContentBackgroundColor}" - IsVisible="{Binding ShowLoadProgress}" - Name="LoadingView" - ZIndex="1000"> - <Grid - Margin="40" - HorizontalAlignment="Center" - VerticalAlignment="Center" - IsVisible="{Binding ShowLoadProgress}"> - <Grid.ColumnDefinitions> - <ColumnDefinition Width="Auto" /> - <ColumnDefinition Width="*" /> - </Grid.ColumnDefinitions> - <Border - Grid.RowSpan="2" - Grid.Column="0" - Width="256" - Height="256" - Margin="10" - Padding="4" - BorderBrush="Black" - BorderThickness="2" - BoxShadow="4 4 32 8 #40000000" - CornerRadius="3" - IsVisible="{Binding ShowLoadProgress}"> - <Image - Width="256" - Height="256" - IsVisible="{Binding ShowLoadProgress}" - Source="{Binding SelectedIcon, Converter={StaticResource ByteImage}}" /> - </Border> - <Grid - Grid.Column="1" - HorizontalAlignment="Stretch" - VerticalAlignment="Center" - IsVisible="{Binding ShowLoadProgress}"> - <Grid.RowDefinitions> - <RowDefinition Height="Auto" /> - <RowDefinition Height="Auto" /> - <RowDefinition Height="Auto" /> - </Grid.RowDefinitions> - <TextBlock - Grid.Row="0" - Margin="10" - FontSize="30" - FontWeight="Bold" - IsVisible="{Binding ShowLoadProgress}" - Text="{Binding LoadHeading}" - TextAlignment="Start" - TextWrapping="Wrap" - MaxWidth="500" /> - <Border - Grid.Row="1" - Margin="10" - Padding="0" - HorizontalAlignment="Stretch" - BorderBrush="{Binding ProgressBarBackgroundColor}" - BorderThickness="1" - ClipToBounds="True" - CornerRadius="5" - IsVisible="{Binding ShowLoadProgress}"> - <ProgressBar - Height="10" - MinWidth="500" - Margin="0" - Padding="0" - HorizontalAlignment="Stretch" - ClipToBounds="True" - CornerRadius="5" - Foreground="{Binding ProgressBarForegroundColor}" - IsIndeterminate="{Binding IsLoadingIndeterminate}" - IsVisible="{Binding ShowLoadProgress}" - Maximum="{Binding ProgressMaximum}" - Minimum="0" - Value="{Binding ProgressValue}" /> - </Border> - <TextBlock - Grid.Row="2" - Margin="10" - FontSize="18" - IsVisible="{Binding ShowLoadProgress}" - Text="{Binding CacheLoadStatus}" - TextAlignment="Start" - MaxWidth="500" /> - </Grid> - </Grid> - </Grid> - <main:MainStatusBarView - Name="StatusBarView" - Grid.Row="2" /> - </Grid> - </Grid> -</window:StyleableWindow> diff --git a/src/Ryujinx.Ava/UI/Windows/MainWindow.axaml.cs b/src/Ryujinx.Ava/UI/Windows/MainWindow.axaml.cs deleted file mode 100644 index 33a9af5b..00000000 --- a/src/Ryujinx.Ava/UI/Windows/MainWindow.axaml.cs +++ /dev/null @@ -1,551 +0,0 @@ -using Avalonia; -using Avalonia.Controls; -using Avalonia.Controls.Primitives; -using Avalonia.Interactivity; -using Avalonia.Threading; -using FluentAvalonia.UI.Controls; -using Ryujinx.Ava.Common; -using Ryujinx.Ava.Common.Locale; -using Ryujinx.Ava.Input; -using Ryujinx.Ava.UI.Applet; -using Ryujinx.Ava.UI.Helpers; -using Ryujinx.Ava.UI.ViewModels; -using Ryujinx.Common.Logging; -using Ryujinx.Graphics.Gpu; -using Ryujinx.HLE.FileSystem; -using Ryujinx.HLE.HOS; -using Ryujinx.HLE.HOS.Services.Account.Acc; -using Ryujinx.Input.HLE; -using Ryujinx.Input.SDL2; -using Ryujinx.Modules; -using Ryujinx.UI.App.Common; -using Ryujinx.UI.Common; -using Ryujinx.UI.Common.Configuration; -using Ryujinx.UI.Common.Helper; -using System; -using System.IO; -using System.Runtime.Versioning; -using System.Threading; -using System.Threading.Tasks; - -namespace Ryujinx.Ava.UI.Windows -{ - public partial class MainWindow : StyleableWindow - { - internal static MainWindowViewModel MainWindowViewModel { get; private set; } - - private bool _isLoading; - - private UserChannelPersistence _userChannelPersistence; - private static bool _deferLoad; - private static string _launchPath; - private static bool _startFullscreen; - internal readonly AvaHostUIHandler UiHandler; - - public VirtualFileSystem VirtualFileSystem { get; private set; } - public ContentManager ContentManager { get; private set; } - public AccountManager AccountManager { get; private set; } - - public LibHacHorizonManager LibHacHorizonManager { get; private set; } - - public InputManager InputManager { get; private set; } - - internal MainWindowViewModel ViewModel { get; private set; } - public SettingsWindow SettingsWindow { get; set; } - - public static bool ShowKeyErrorOnLoad { get; set; } - public ApplicationLibrary ApplicationLibrary { get; set; } - - public MainWindow() - { - ViewModel = new MainWindowViewModel(); - - MainWindowViewModel = ViewModel; - - DataContext = ViewModel; - - SetWindowSizePosition(); - - InitializeComponent(); - Load(); - - UiHandler = new AvaHostUIHandler(this); - - ViewModel.Title = $"Ryujinx {Program.Version}"; - - // NOTE: Height of MenuBar and StatusBar is not usable here, since it would still be 0 at this point. - double barHeight = MenuBar.MinHeight + StatusBarView.StatusBar.MinHeight; - Height = ((Height - barHeight) / Program.WindowScaleFactor) + barHeight; - Width /= Program.WindowScaleFactor; - - if (Program.PreviewerDetached) - { - InputManager = new InputManager(new AvaloniaKeyboardDriver(this), new SDL2GamepadDriver()); - - this.GetObservable(IsActiveProperty).Subscribe(IsActiveChanged); - this.ScalingChanged += OnScalingChanged; - } - } - - protected override void OnApplyTemplate(TemplateAppliedEventArgs e) - { - base.OnApplyTemplate(e); - - NotificationHelper.SetNotificationManager(this); - } - - private void IsActiveChanged(bool obj) - { - ViewModel.IsActive = obj; - } - - private void OnScalingChanged(object sender, EventArgs e) - { - Program.DesktopScaleFactor = this.RenderScaling; - } - - private void ApplicationLibrary_ApplicationAdded(object sender, ApplicationAddedEventArgs e) - { - Dispatcher.UIThread.Post(() => - { - ViewModel.Applications.Add(e.AppData); - }); - } - - private void ApplicationLibrary_ApplicationCountUpdated(object sender, ApplicationCountUpdatedEventArgs e) - { - LocaleManager.Instance.UpdateAndGetDynamicValue(LocaleKeys.StatusBarGamesLoaded, e.NumAppsLoaded, e.NumAppsFound); - - Dispatcher.UIThread.Post(() => - { - ViewModel.StatusBarProgressValue = e.NumAppsLoaded; - ViewModel.StatusBarProgressMaximum = e.NumAppsFound; - - if (e.NumAppsFound == 0) - { - StatusBarView.LoadProgressBar.IsVisible = false; - } - - if (e.NumAppsLoaded == e.NumAppsFound) - { - StatusBarView.LoadProgressBar.IsVisible = false; - } - }); - } - - public void Application_Opened(object sender, ApplicationOpenedEventArgs args) - { - if (args.Application != null) - { - ViewModel.SelectedIcon = args.Application.Icon; - - string path = new FileInfo(args.Application.Path).FullName; - - ViewModel.LoadApplication(path).Wait(); - } - - args.Handled = true; - } - - internal static void DeferLoadApplication(string launchPathArg, bool startFullscreenArg) - { - _deferLoad = true; - _launchPath = launchPathArg; - _startFullscreen = startFullscreenArg; - } - - public void SwitchToGameControl(bool startFullscreen = false) - { - ViewModel.ShowLoadProgress = false; - ViewModel.ShowContent = true; - ViewModel.IsLoadingIndeterminate = false; - - if (startFullscreen && ViewModel.WindowState != WindowState.FullScreen) - { - ViewModel.ToggleFullscreen(); - } - } - - public void ShowLoading(bool startFullscreen = false) - { - ViewModel.ShowContent = false; - ViewModel.ShowLoadProgress = true; - ViewModel.IsLoadingIndeterminate = true; - - if (startFullscreen && ViewModel.WindowState != WindowState.FullScreen) - { - ViewModel.ToggleFullscreen(); - } - } - - private void Initialize() - { - _userChannelPersistence = new UserChannelPersistence(); - VirtualFileSystem = VirtualFileSystem.CreateInstance(); - LibHacHorizonManager = new LibHacHorizonManager(); - ContentManager = new ContentManager(VirtualFileSystem); - - LibHacHorizonManager.InitializeFsServer(VirtualFileSystem); - LibHacHorizonManager.InitializeArpServer(); - LibHacHorizonManager.InitializeBcatServer(); - LibHacHorizonManager.InitializeSystemClients(); - - ApplicationLibrary = new ApplicationLibrary(VirtualFileSystem); - - // Save data created before we supported extra data in directory save data will not work properly if - // given empty extra data. Luckily some of that extra data can be created using the data from the - // save data indexer, which should be enough to check access permissions for user saves. - // Every single save data's extra data will be checked and fixed if needed each time the emulator is opened. - // Consider removing this at some point in the future when we don't need to worry about old saves. - VirtualFileSystem.FixExtraData(LibHacHorizonManager.RyujinxClient); - - AccountManager = new AccountManager(LibHacHorizonManager.RyujinxClient, CommandLineState.Profile); - - VirtualFileSystem.ReloadKeySet(); - - ApplicationHelper.Initialize(VirtualFileSystem, AccountManager, LibHacHorizonManager.RyujinxClient); - } - - [SupportedOSPlatform("linux")] - private static async Task ShowVmMaxMapCountWarning() - { - LocaleManager.Instance.UpdateAndGetDynamicValue(LocaleKeys.LinuxVmMaxMapCountWarningTextSecondary, - LinuxHelper.VmMaxMapCount, LinuxHelper.RecommendedVmMaxMapCount); - - await ContentDialogHelper.CreateWarningDialog( - LocaleManager.Instance[LocaleKeys.LinuxVmMaxMapCountWarningTextPrimary], - LocaleManager.Instance[LocaleKeys.LinuxVmMaxMapCountWarningTextSecondary] - ); - } - - [SupportedOSPlatform("linux")] - private static async Task ShowVmMaxMapCountDialog() - { - LocaleManager.Instance.UpdateAndGetDynamicValue(LocaleKeys.LinuxVmMaxMapCountDialogTextPrimary, - LinuxHelper.RecommendedVmMaxMapCount); - - UserResult response = await ContentDialogHelper.ShowTextDialog( - $"Ryujinx - {LocaleManager.Instance[LocaleKeys.LinuxVmMaxMapCountDialogTitle]}", - LocaleManager.Instance[LocaleKeys.LinuxVmMaxMapCountDialogTextPrimary], - LocaleManager.Instance[LocaleKeys.LinuxVmMaxMapCountDialogTextSecondary], - LocaleManager.Instance[LocaleKeys.LinuxVmMaxMapCountDialogButtonUntilRestart], - LocaleManager.Instance[LocaleKeys.LinuxVmMaxMapCountDialogButtonPersistent], - LocaleManager.Instance[LocaleKeys.InputDialogNo], - (int)Symbol.Help - ); - - int rc; - - switch (response) - { - case UserResult.Ok: - rc = LinuxHelper.RunPkExec($"echo {LinuxHelper.RecommendedVmMaxMapCount} > {LinuxHelper.VmMaxMapCountPath}"); - if (rc == 0) - { - Logger.Info?.Print(LogClass.Application, $"vm.max_map_count set to {LinuxHelper.VmMaxMapCount} until the next restart."); - } - else - { - Logger.Error?.Print(LogClass.Application, $"Unable to change vm.max_map_count. Process exited with code: {rc}"); - } - break; - case UserResult.No: - rc = LinuxHelper.RunPkExec($"echo \"vm.max_map_count = {LinuxHelper.RecommendedVmMaxMapCount}\" > {LinuxHelper.SysCtlConfigPath} && sysctl -p {LinuxHelper.SysCtlConfigPath}"); - if (rc == 0) - { - Logger.Info?.Print(LogClass.Application, $"vm.max_map_count set to {LinuxHelper.VmMaxMapCount}. Written to config: {LinuxHelper.SysCtlConfigPath}"); - } - else - { - Logger.Error?.Print(LogClass.Application, $"Unable to write new value for vm.max_map_count to config. Process exited with code: {rc}"); - } - break; - } - } - - private async Task CheckLaunchState() - { - if (OperatingSystem.IsLinux() && LinuxHelper.VmMaxMapCount < LinuxHelper.RecommendedVmMaxMapCount) - { - Logger.Warning?.Print(LogClass.Application, $"The value of vm.max_map_count is lower than {LinuxHelper.RecommendedVmMaxMapCount}. ({LinuxHelper.VmMaxMapCount})"); - - if (LinuxHelper.PkExecPath is not null) - { - await Dispatcher.UIThread.InvokeAsync(ShowVmMaxMapCountDialog); - } - else - { - await Dispatcher.UIThread.InvokeAsync(ShowVmMaxMapCountWarning); - } - } - - if (!ShowKeyErrorOnLoad) - { - if (_deferLoad) - { - _deferLoad = false; - - ViewModel.LoadApplication(_launchPath, _startFullscreen).Wait(); - } - } - else - { - ShowKeyErrorOnLoad = false; - - await Dispatcher.UIThread.InvokeAsync(async () => await UserErrorDialog.ShowUserErrorDialog(UserError.NoKeys)); - } - - if (ConfigurationState.Instance.CheckUpdatesOnStart.Value && Updater.CanUpdate(false)) - { - await Updater.BeginParse(this, false).ContinueWith(task => - { - Logger.Error?.Print(LogClass.Application, $"Updater Error: {task.Exception}"); - }, TaskContinuationOptions.OnlyOnFaulted); - } - } - - private void Load() - { - StatusBarView.VolumeStatus.Click += VolumeStatus_CheckedChanged; - - ApplicationGrid.ApplicationOpened += Application_Opened; - - ApplicationGrid.DataContext = ViewModel; - - ApplicationList.ApplicationOpened += Application_Opened; - - ApplicationList.DataContext = ViewModel; - } - - private void SetWindowSizePosition() - { - PixelPoint savedPoint = new(ConfigurationState.Instance.UI.WindowStartup.WindowPositionX, - ConfigurationState.Instance.UI.WindowStartup.WindowPositionY); - - ViewModel.WindowHeight = ConfigurationState.Instance.UI.WindowStartup.WindowSizeHeight * Program.WindowScaleFactor; - ViewModel.WindowWidth = ConfigurationState.Instance.UI.WindowStartup.WindowSizeWidth * Program.WindowScaleFactor; - - ViewModel.WindowState = ConfigurationState.Instance.UI.WindowStartup.WindowMaximized.Value ? WindowState.Maximized : WindowState.Normal; - - if (CheckScreenBounds(savedPoint)) - { - Position = savedPoint; - } - else - { - WindowStartupLocation = WindowStartupLocation.CenterScreen; - } - } - - private bool CheckScreenBounds(PixelPoint configPoint) - { - for (int i = 0; i < Screens.ScreenCount; i++) - { - if (Screens.All[i].Bounds.Contains(configPoint)) - { - return true; - } - } - - Logger.Warning?.Print(LogClass.Application, "Failed to find valid start-up coordinates. Defaulting to primary monitor center."); - return false; - } - - private void SaveWindowSizePosition() - { - ConfigurationState.Instance.UI.WindowStartup.WindowSizeHeight.Value = (int)Height; - ConfigurationState.Instance.UI.WindowStartup.WindowSizeWidth.Value = (int)Width; - - ConfigurationState.Instance.UI.WindowStartup.WindowPositionX.Value = Position.X; - ConfigurationState.Instance.UI.WindowStartup.WindowPositionY.Value = Position.Y; - - ConfigurationState.Instance.UI.WindowStartup.WindowMaximized.Value = WindowState == WindowState.Maximized; - - MainWindowViewModel.SaveConfig(); - } - - protected override void OnOpened(EventArgs e) - { - base.OnOpened(e); - - Initialize(); - - ViewModel.Initialize( - ContentManager, - StorageProvider, - ApplicationLibrary, - VirtualFileSystem, - AccountManager, - InputManager, - _userChannelPersistence, - LibHacHorizonManager, - UiHandler, - ShowLoading, - SwitchToGameControl, - SetMainContent, - this); - - ApplicationLibrary.ApplicationCountUpdated += ApplicationLibrary_ApplicationCountUpdated; - ApplicationLibrary.ApplicationAdded += ApplicationLibrary_ApplicationAdded; - - ViewModel.RefreshFirmwareStatus(); - - LoadApplications(); - -#pragma warning disable CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed - CheckLaunchState(); -#pragma warning restore CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed - } - - private void SetMainContent(Control content = null) - { - content ??= GameLibrary; - - if (MainContent.Content != content) - { - MainContent.Content = content; - } - } - - public static void UpdateGraphicsConfig() - { -#pragma warning disable IDE0055 // Disable formatting - GraphicsConfig.ResScale = ConfigurationState.Instance.Graphics.ResScale == -1 ? ConfigurationState.Instance.Graphics.ResScaleCustom : ConfigurationState.Instance.Graphics.ResScale; - GraphicsConfig.MaxAnisotropy = ConfigurationState.Instance.Graphics.MaxAnisotropy; - GraphicsConfig.ShadersDumpPath = ConfigurationState.Instance.Graphics.ShadersDumpPath; - GraphicsConfig.EnableShaderCache = ConfigurationState.Instance.Graphics.EnableShaderCache; - GraphicsConfig.EnableTextureRecompression = ConfigurationState.Instance.Graphics.EnableTextureRecompression; - GraphicsConfig.EnableMacroHLE = ConfigurationState.Instance.Graphics.EnableMacroHLE; -#pragma warning restore IDE0055 - } - - private void VolumeStatus_CheckedChanged(object sender, RoutedEventArgs e) - { - var volumeSplitButton = sender as ToggleSplitButton; - if (ViewModel.IsGameRunning) - { - if (!volumeSplitButton.IsChecked) - { - ViewModel.AppHost.Device.SetVolume(ViewModel.VolumeBeforeMute); - } - else - { - ViewModel.VolumeBeforeMute = ViewModel.AppHost.Device.GetVolume(); - ViewModel.AppHost.Device.SetVolume(0); - } - - ViewModel.Volume = ViewModel.AppHost.Device.GetVolume(); - } - } - - protected override void OnClosing(WindowClosingEventArgs e) - { - if (!ViewModel.IsClosing && ViewModel.AppHost != null && ConfigurationState.Instance.ShowConfirmExit) - { - e.Cancel = true; - - ConfirmExit(); - - return; - } - - ViewModel.IsClosing = true; - - if (ViewModel.AppHost != null) - { - ViewModel.AppHost.AppExit -= ViewModel.AppHost_AppExit; - ViewModel.AppHost.AppExit += (sender, e) => - { - ViewModel.AppHost = null; - - Dispatcher.UIThread.Post(() => - { - MainContent = null; - - Close(); - }); - }; - ViewModel.AppHost?.Stop(); - - e.Cancel = true; - - return; - } - - SaveWindowSizePosition(); - - ApplicationLibrary.CancelLoading(); - InputManager.Dispose(); - Program.Exit(); - - base.OnClosing(e); - } - - private void ConfirmExit() - { - Dispatcher.UIThread.InvokeAsync(async () => - { - ViewModel.IsClosing = await ContentDialogHelper.CreateExitDialog(); - - if (ViewModel.IsClosing) - { - Close(); - } - }); - } - - public void LoadApplications() - { - ViewModel.Applications.Clear(); - - StatusBarView.LoadProgressBar.IsVisible = true; - ViewModel.StatusBarProgressMaximum = 0; - ViewModel.StatusBarProgressValue = 0; - - LocaleManager.Instance.UpdateAndGetDynamicValue(LocaleKeys.StatusBarGamesLoaded, 0, 0); - - ReloadGameList(); - } - - public void ToggleFileType(string fileType) - { - _ = fileType switch - { -#pragma warning disable IDE0055 // Disable formatting - "NSP" => ConfigurationState.Instance.UI.ShownFileTypes.NSP.Value = !ConfigurationState.Instance.UI.ShownFileTypes.NSP, - "PFS0" => ConfigurationState.Instance.UI.ShownFileTypes.PFS0.Value = !ConfigurationState.Instance.UI.ShownFileTypes.PFS0, - "XCI" => ConfigurationState.Instance.UI.ShownFileTypes.XCI.Value = !ConfigurationState.Instance.UI.ShownFileTypes.XCI, - "NCA" => ConfigurationState.Instance.UI.ShownFileTypes.NCA.Value = !ConfigurationState.Instance.UI.ShownFileTypes.NCA, - "NRO" => ConfigurationState.Instance.UI.ShownFileTypes.NRO.Value = !ConfigurationState.Instance.UI.ShownFileTypes.NRO, - "NSO" => ConfigurationState.Instance.UI.ShownFileTypes.NSO.Value = !ConfigurationState.Instance.UI.ShownFileTypes.NSO, - _ => throw new ArgumentOutOfRangeException(fileType), -#pragma warning restore IDE0055 - }; - - ConfigurationState.Instance.ToFileFormat().SaveConfig(Program.ConfigurationPath); - LoadApplications(); - } - - private void ReloadGameList() - { - if (_isLoading) - { - return; - } - - _isLoading = true; - - Thread applicationLibraryThread = new(() => - { - ApplicationLibrary.LoadApplications(ConfigurationState.Instance.UI.GameDirs, ConfigurationState.Instance.System.Language); - - _isLoading = false; - }) - { - Name = "GUI.ApplicationLibraryThread", - IsBackground = true, - }; - applicationLibraryThread.Start(); - } - } -} diff --git a/src/Ryujinx.Ava/UI/Windows/ModManagerWindow.axaml b/src/Ryujinx.Ava/UI/Windows/ModManagerWindow.axaml deleted file mode 100644 index 0ed05ce3..00000000 --- a/src/Ryujinx.Ava/UI/Windows/ModManagerWindow.axaml +++ /dev/null @@ -1,179 +0,0 @@ -<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="{Binding EnableAll}"> - <TextBlock Text="{locale:Locale DlcManagerEnableAllButton}" /> - </Button> - <Button - Name="DisableAllButton" - MinWidth="90" - Margin="5" - Command="{Binding 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 deleted file mode 100644 index d9ae0d4f..00000000 --- a/src/Ryujinx.Ava/UI/Windows/ModManagerWindow.axaml.cs +++ /dev/null @@ -1,139 +0,0 @@ -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; - } - } - } - } - } -} diff --git a/src/Ryujinx.Ava/UI/Windows/SettingsWindow.axaml b/src/Ryujinx.Ava/UI/Windows/SettingsWindow.axaml deleted file mode 100644 index 40cac90d..00000000 --- a/src/Ryujinx.Ava/UI/Windows/SettingsWindow.axaml +++ /dev/null @@ -1,130 +0,0 @@ -<window:StyleableWindow - x:Class="Ryujinx.Ava.UI.Windows.SettingsWindow" - xmlns="https://github.com/avaloniaui" - xmlns:ui="clr-namespace:FluentAvalonia.UI.Controls;assembly=FluentAvalonia" - xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" - xmlns:locale="clr-namespace:Ryujinx.Ava.Common.Locale" - xmlns:d="http://schemas.microsoft.com/expression/blend/2008" - xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" - xmlns:window="clr-namespace:Ryujinx.Ava.UI.Windows" - xmlns:viewModels="clr-namespace:Ryujinx.Ava.UI.ViewModels" - xmlns:settings="clr-namespace:Ryujinx.Ava.UI.Views.Settings" - xmlns:helpers="clr-namespace:Ryujinx.Ava.UI.Helpers" - Width="1100" - Height="768" - MinWidth="800" - MinHeight="480" - WindowStartupLocation="CenterOwner" - x:DataType="viewModels:SettingsViewModel" - mc:Ignorable="d" - Focusable="True"> - <Design.DataContext> - <viewModels:SettingsViewModel /> - </Design.DataContext> - <Grid HorizontalAlignment="Stretch" VerticalAlignment="Stretch" MinWidth="600"> - <Grid.RowDefinitions> - <RowDefinition Height="Auto" /> - <RowDefinition /> - <RowDefinition Height="Auto" /> - </Grid.RowDefinitions> - <ContentPresenter - x:Name="ContentPresenter" - Grid.Row="1" - IsVisible="False" - KeyboardNavigation.IsTabStop="False"/> - <Grid Name="Pages" IsVisible="False" Grid.Row="2"> - <settings:SettingsUiView Name="UiPage" /> - <settings:SettingsInputView Name="InputPage" /> - <settings:SettingsHotkeysView Name="HotkeysPage" /> - <settings:SettingsSystemView Name="SystemPage" /> - <settings:SettingsCPUView Name="CpuPage" /> - <settings:SettingsGraphicsView Name="GraphicsPage" /> - <settings:SettingsAudioView Name="AudioPage" /> - <settings:SettingsNetworkView Name="NetworkPage" /> - <settings:SettingsLoggingView Name="LoggingPage" /> - </Grid> - <ui:NavigationView - Grid.Row="1" - IsSettingsVisible="False" - Name="NavPanel" - IsBackEnabled="False" - PaneDisplayMode="Left" - Margin="2,10,10,0" - VerticalAlignment="Stretch" - HorizontalAlignment="Stretch" - OpenPaneLength="200"> - <ui:NavigationView.MenuItems> - <ui:NavigationViewItem - IsSelected="True" - Content="{locale:Locale SettingsTabGeneral}" - Tag="UiPage" - IconSource="New" /> - <ui:NavigationViewItem - Content="{locale:Locale SettingsTabInput}" - Tag="InputPage" - IconSource="Games" /> - <ui:NavigationViewItem - Content="{locale:Locale SettingsTabHotkeys}" - Tag="HotkeysPage" - IconSource="Keyboard" /> - <ui:NavigationViewItem - Content="{locale:Locale SettingsTabSystem}" - Tag="SystemPage" - IconSource="Settings" /> - <ui:NavigationViewItem - Content="{locale:Locale SettingsTabCpu}" - Tag="CpuPage"> - <ui:NavigationViewItem.IconSource> - <ui:FontIconSource - FontFamily="avares://Ryujinx.Ava/Assets/Fonts#Segoe Fluent Icons" - Glyph="{helpers:GlyphValueConverter Chip}" /> - </ui:NavigationViewItem.IconSource> - </ui:NavigationViewItem> - <ui:NavigationViewItem - Content="{locale:Locale SettingsTabGraphics}" - Tag="GraphicsPage" - IconSource="Image" /> - <ui:NavigationViewItem - Content="{locale:Locale SettingsTabAudio}" - IconSource="Audio" - Tag="AudioPage" /> - <ui:NavigationViewItem - Content="{locale:Locale SettingsTabNetwork}" - Tag="NetworkPage" - IconSource="Globe" /> - <ui:NavigationViewItem - Content="{locale:Locale SettingsTabLogging}" - Tag="LoggingPage" - IconSource="Document" /> - </ui:NavigationView.MenuItems> - <ui:NavigationView.Styles> - <Style Selector="Grid#PlaceholderGrid"> - <Setter Property="Height" Value="40" /> - </Style> - <Style Selector="ui|NavigationViewItem ui|SymbolIcon"> - <Setter Property="FlowDirection" Value="LeftToRight" /> - </Style> - </ui:NavigationView.Styles> - </ui:NavigationView> - <ReversibleStackPanel - Grid.Row="2" - Margin="10" - Spacing="10" - Orientation="Horizontal" - HorizontalAlignment="Right" - ReverseOrder="{Binding IsMacOS}"> - <Button - HotKey="Enter" - Classes="accent" - Content="{locale:Locale SettingsButtonOk}" - Command="{Binding OkButton}" /> - <Button - HotKey="Escape" - Content="{locale:Locale SettingsButtonCancel}" - Command="{Binding CancelButton}" /> - <Button - Content="{locale:Locale SettingsButtonApply}" - Command="{Binding ApplyButton}" /> - </ReversibleStackPanel> - </Grid> -</window:StyleableWindow> diff --git a/src/Ryujinx.Ava/UI/Windows/SettingsWindow.axaml.cs b/src/Ryujinx.Ava/UI/Windows/SettingsWindow.axaml.cs deleted file mode 100644 index d7bb0b88..00000000 --- a/src/Ryujinx.Ava/UI/Windows/SettingsWindow.axaml.cs +++ /dev/null @@ -1,103 +0,0 @@ -using Avalonia.Controls; -using FluentAvalonia.Core; -using FluentAvalonia.UI.Controls; -using Ryujinx.Ava.Common.Locale; -using Ryujinx.Ava.UI.ViewModels; -using Ryujinx.HLE.FileSystem; -using System; - -namespace Ryujinx.Ava.UI.Windows -{ - public partial class SettingsWindow : StyleableWindow - { - internal SettingsViewModel ViewModel { get; set; } - - public SettingsWindow(VirtualFileSystem virtualFileSystem, ContentManager contentManager) - { - Title = $"Ryujinx {Program.Version} - {LocaleManager.Instance[LocaleKeys.Settings]}"; - - ViewModel = new SettingsViewModel(virtualFileSystem, contentManager); - DataContext = ViewModel; - - ViewModel.CloseWindow += Close; - ViewModel.SaveSettingsEvent += SaveSettings; - - InitializeComponent(); - Load(); - } - - public SettingsWindow() - { - ViewModel = new SettingsViewModel(); - DataContext = ViewModel; - - InitializeComponent(); - Load(); - } - - public void SaveSettings() - { - InputPage.ControllerSettings?.SaveCurrentProfile(); - - if (Owner is MainWindow window && ViewModel.DirectoryChanged) - { - window.LoadApplications(); - } - } - - private void Load() - { - Pages.Children.Clear(); - NavPanel.SelectionChanged += NavPanelOnSelectionChanged; - NavPanel.SelectedItem = NavPanel.MenuItems.ElementAt(0); - } - - private void NavPanelOnSelectionChanged(object sender, NavigationViewSelectionChangedEventArgs e) - { - if (e.SelectedItem is NavigationViewItem navItem && navItem.Tag is not null) - { - switch (navItem.Tag.ToString()) - { - case "UiPage": - UiPage.ViewModel = ViewModel; - NavPanel.Content = UiPage; - break; - case "InputPage": - NavPanel.Content = InputPage; - break; - case "HotkeysPage": - NavPanel.Content = HotkeysPage; - break; - case "SystemPage": - SystemPage.ViewModel = ViewModel; - NavPanel.Content = SystemPage; - break; - case "CpuPage": - NavPanel.Content = CpuPage; - break; - case "GraphicsPage": - NavPanel.Content = GraphicsPage; - break; - case "AudioPage": - NavPanel.Content = AudioPage; - break; - case "NetworkPage": - NavPanel.Content = NetworkPage; - break; - case "LoggingPage": - NavPanel.Content = LoggingPage; - break; - default: - throw new NotImplementedException(); - } - } - } - - protected override void OnClosing(WindowClosingEventArgs e) - { - HotkeysPage.Dispose(); - InputPage.Dispose(); - base.OnClosing(e); - } - } -} diff --git a/src/Ryujinx.Ava/UI/Windows/StyleableWindow.cs b/src/Ryujinx.Ava/UI/Windows/StyleableWindow.cs deleted file mode 100644 index a12d2b3e..00000000 --- a/src/Ryujinx.Ava/UI/Windows/StyleableWindow.cs +++ /dev/null @@ -1,44 +0,0 @@ -using Avalonia.Controls; -using Avalonia.Controls.Primitives; -using Avalonia.Media; -using Avalonia.Media.Imaging; -using Avalonia.Platform; -using Ryujinx.Ava.Common.Locale; -using Ryujinx.UI.Common.Configuration; -using System.IO; -using System.Reflection; - -namespace Ryujinx.Ava.UI.Windows -{ - public class StyleableWindow : Window - { - public Bitmap IconImage { get; set; } - - public StyleableWindow() - { - WindowStartupLocation = WindowStartupLocation.CenterOwner; - TransparencyLevelHint = new[] { WindowTransparencyLevel.None }; - - using Stream stream = Assembly.GetAssembly(typeof(ConfigurationState)).GetManifestResourceStream("Ryujinx.UI.Common.Resources.Logo_Ryujinx.png"); - - Icon = new WindowIcon(stream); - stream.Position = 0; - IconImage = new Bitmap(stream); - - LocaleManager.Instance.LocaleChanged += LocaleChanged; - LocaleChanged(); - } - - private void LocaleChanged() - { - FlowDirection = LocaleManager.Instance.IsRTL() ? FlowDirection.RightToLeft : FlowDirection.LeftToRight; - } - - protected override void OnApplyTemplate(TemplateAppliedEventArgs e) - { - base.OnApplyTemplate(e); - - ExtendClientAreaChromeHints = ExtendClientAreaChromeHints.SystemChrome | ExtendClientAreaChromeHints.OSXThickTitleBar; - } - } -} diff --git a/src/Ryujinx.Ava/UI/Windows/TitleUpdateWindow.axaml b/src/Ryujinx.Ava/UI/Windows/TitleUpdateWindow.axaml deleted file mode 100644 index 3eff389f..00000000 --- a/src/Ryujinx.Ava/UI/Windows/TitleUpdateWindow.axaml +++ /dev/null @@ -1,133 +0,0 @@ -<UserControl - x:Class="Ryujinx.Ava.UI.Windows.TitleUpdateWindow" - 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="300" - mc:Ignorable="d" - x:DataType="viewModels:TitleUpdateViewModel" - Focusable="True"> - <Grid> - <Grid.RowDefinitions> - <RowDefinition Height="*" /> - <RowDefinition Height="Auto" /> - </Grid.RowDefinitions> - <Border - Grid.Row="0" - Margin="0 0 0 24" - HorizontalAlignment="Stretch" - VerticalAlignment="Stretch" - BorderBrush="{DynamicResource AppListHoverBackgroundColor}" - BorderThickness="1" - CornerRadius="5" - Padding="2.5"> - <ListBox - Background="Transparent" - SelectedItem="{Binding SelectedUpdate, Mode=TwoWay}" - ItemsSource="{Binding Views}"> - <ListBox.DataTemplates> - <DataTemplate - DataType="models:TitleUpdateModel"> - <Panel Margin="10"> - <TextBlock - HorizontalAlignment="Left" - VerticalAlignment="Center" - TextWrapping="Wrap" - Text="{Binding Label}" /> - <StackPanel - 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="RemoveUpdate"> - <ui:SymbolIcon - Symbol="Cancel" - HorizontalAlignment="Center" - VerticalAlignment="Center" /> - </Button> - </StackPanel> - </Panel> - </DataTemplate> - <DataTemplate - DataType="viewModels:BaseModel"> - <Panel - Height="33" - Margin="10"> - <TextBlock - HorizontalAlignment="Left" - VerticalAlignment="Center" - TextWrapping="Wrap" - Text="{locale:Locale NoUpdate}" /> - </Panel> - </DataTemplate> - </ListBox.DataTemplates> - <ListBox.Styles> - <Style Selector="ListBoxItem"> - <Setter Property="Background" Value="Transparent" /> - </Style> - </ListBox.Styles> - </ListBox> - </Border> - <Panel - Grid.Row="1" - HorizontalAlignment="Stretch"> - <StackPanel - Orientation="Horizontal" - Spacing="10" - HorizontalAlignment="Left"> - <Button - Name="AddButton" - MinWidth="90" - Command="{Binding Add}"> - <TextBlock Text="{locale:Locale SettingsTabGeneralAdd}" /> - </Button> - <Button - Name="RemoveAllButton" - MinWidth="90" - Click="RemoveAll"> - <TextBlock Text="{locale:Locale DlcManagerRemoveAllButton}" /> - </Button> - </StackPanel> - <StackPanel - Orientation="Horizontal" - Spacing="10" - HorizontalAlignment="Right"> - <Button - Name="SaveButton" - MinWidth="90" - Click="Save"> - <TextBlock Text="{locale:Locale SettingsButtonSave}" /> - </Button> - <Button - Name="CancelButton" - MinWidth="90" - Click="Close"> - <TextBlock Text="{locale:Locale InputDialogCancel}" /> - </Button> - </StackPanel> - </Panel> - </Grid> -</UserControl> diff --git a/src/Ryujinx.Ava/UI/Windows/TitleUpdateWindow.axaml.cs b/src/Ryujinx.Ava/UI/Windows/TitleUpdateWindow.axaml.cs deleted file mode 100644 index f3ac6960..00000000 --- a/src/Ryujinx.Ava/UI/Windows/TitleUpdateWindow.axaml.cs +++ /dev/null @@ -1,96 +0,0 @@ -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.HLE.FileSystem; -using Ryujinx.UI.Common.Helper; -using System.Threading.Tasks; -using Button = Avalonia.Controls.Button; - -namespace Ryujinx.Ava.UI.Windows -{ - public partial class TitleUpdateWindow : UserControl - { - public TitleUpdateViewModel ViewModel; - - public TitleUpdateWindow() - { - DataContext = this; - - InitializeComponent(); - } - - public TitleUpdateWindow(VirtualFileSystem virtualFileSystem, ulong titleId) - { - DataContext = ViewModel = new TitleUpdateViewModel(virtualFileSystem, titleId); - - InitializeComponent(); - } - - public static async Task Show(VirtualFileSystem virtualFileSystem, ulong titleId, string titleName) - { - ContentDialog contentDialog = new() - { - PrimaryButtonText = "", - SecondaryButtonText = "", - CloseButtonText = "", - Content = new TitleUpdateWindow(virtualFileSystem, titleId), - Title = LocaleManager.Instance.UpdateAndGetDynamicValue(LocaleKeys.GameUpdateWindowHeading, 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 ContentDialogHelper.ShowAsync(contentDialog); - } - - private void Close(object sender, RoutedEventArgs e) - { - ((ContentDialog)Parent).Hide(); - } - - public void Save(object sender, RoutedEventArgs e) - { - ViewModel.Save(); - - if (VisualRoot is MainWindow window) - { - window.LoadApplications(); - } - - ((ContentDialog)Parent).Hide(); - } - - private void OpenLocation(object sender, RoutedEventArgs e) - { - if (sender is Button button) - { - if (button.DataContext is TitleUpdateModel model) - { - OpenHelper.LocateFile(model.Path); - } - } - } - - private void RemoveUpdate(object sender, RoutedEventArgs e) - { - if (sender is Button button) - { - ViewModel.RemoveUpdate((TitleUpdateModel)button.DataContext); - } - } - - private void RemoveAll(object sender, RoutedEventArgs e) - { - ViewModel.TitleUpdates.Clear(); - - ViewModel.SortUpdates(); - } - } -} |
