From 7d0947cac68ecf69e1a969e00672300ffd4b57ee Mon Sep 17 00:00:00 2001 From: KeatonTheBot Date: Wed, 14 Jan 2026 16:57:37 -0600 Subject: [PATCH] Add CommunityToolkit.Mvvm Use [ObservableProperty] attribute, which greatly reduces or eliminates boilerplate code needed to generate observable properties Co-authored-by: GreemDev --- Directory.Packages.props | 3 +- src/Ryujinx/Ryujinx.csproj | 1 + .../UI/Models/Input/GamepadInputConfig.cs | 390 ++--------- src/Ryujinx/UI/Models/Input/HotkeyConfig.cs | 136 +--- .../UI/Models/Input/KeyboardInputConfig.cs | 319 ++------- src/Ryujinx/UI/Models/ModModel.cs | 14 +- src/Ryujinx/UI/Models/ProfileImageModel.cs | 27 +- src/Ryujinx/UI/Models/TempProfile.cs | 38 +- src/Ryujinx/UI/Models/UserProfile.cs | 63 +- .../UI/ViewModels/AboutWindowViewModel.cs | 39 +- src/Ryujinx/UI/ViewModels/BaseModel.cs | 16 +- .../UI/ViewModels/DlcSelectViewModel.cs | 27 +- .../DownloadableContentManagerViewModel.cs | 52 +- .../Input/ControllerInputViewModel.cs | 35 +- .../UI/ViewModels/Input/InputViewModel.cs | 23 +- .../Input/KeyboardInputViewModel.cs | 33 +- .../ViewModels/Input/MotionInputViewModel.cs | 84 +-- .../ViewModels/Input/RumbleInputViewModel.cs | 24 +- .../UI/ViewModels/MainWindowViewModel.cs | 633 +++--------------- .../UI/ViewModels/ModManagerViewModel.cs | 39 +- .../UI/ViewModels/SettingsViewModel.cs | 121 ++-- .../UI/ViewModels/TitleUpdateViewModel.cs | 52 +- .../UserFirmwareAvatarSelectorViewModel.cs | 47 +- .../UserProfileImageSelectorViewModel.cs | 16 +- .../UI/ViewModels/UserSaveManagerViewModel.cs | 84 +-- 25 files changed, 433 insertions(+), 1883 deletions(-) diff --git a/Directory.Packages.props b/Directory.Packages.props index 03a98e57c..527469772 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -11,6 +11,7 @@ + @@ -52,4 +53,4 @@ - + \ No newline at end of file diff --git a/src/Ryujinx/Ryujinx.csproj b/src/Ryujinx/Ryujinx.csproj index 49562cd40..74e9eaeb8 100644 --- a/src/Ryujinx/Ryujinx.csproj +++ b/src/Ryujinx/Ryujinx.csproj @@ -32,6 +32,7 @@ + diff --git a/src/Ryujinx/UI/Models/Input/GamepadInputConfig.cs b/src/Ryujinx/UI/Models/Input/GamepadInputConfig.cs index 833670bdc..37ae0a026 100644 --- a/src/Ryujinx/UI/Models/Input/GamepadInputConfig.cs +++ b/src/Ryujinx/UI/Models/Input/GamepadInputConfig.cs @@ -1,12 +1,12 @@ +using CommunityToolkit.Mvvm.ComponentModel; using Ryujinx.Ava.UI.ViewModels; using Ryujinx.Common.Configuration.Hid; using Ryujinx.Common.Configuration.Hid.Controller; using Ryujinx.Common.Configuration.Hid.Controller.Motion; -using System; namespace Ryujinx.Ava.UI.Models.Input { - public class GamepadInputConfig : BaseModel + public partial class GamepadInputConfig : BaseModel { public bool EnableCemuHookMotion { get; set; } public string DsuServerHost { get; set; } @@ -24,390 +24,110 @@ namespace Ryujinx.Ava.UI.Models.Input public ControllerType ControllerType { get; set; } public PlayerIndex PlayerIndex { get; set; } + [ObservableProperty] private StickInputId _leftJoystick; - public StickInputId LeftJoystick - { - get => _leftJoystick; - set - { - _leftJoystick = value; - OnPropertyChanged(); - } - } + [ObservableProperty] private bool _leftInvertStickX; - public bool LeftInvertStickX - { - get => _leftInvertStickX; - set - { - _leftInvertStickX = value; - OnPropertyChanged(); - } - } + [ObservableProperty] private bool _leftInvertStickY; - public bool LeftInvertStickY - { - get => _leftInvertStickY; - set - { - _leftInvertStickY = value; - OnPropertyChanged(); - } - } + [ObservableProperty] private bool _leftRotate90; - public bool LeftRotate90 - { - get => _leftRotate90; - set - { - _leftRotate90 = value; - OnPropertyChanged(); - } - } + [ObservableProperty] private GamepadInputId _leftStickButton; - public GamepadInputId LeftStickButton - { - get => _leftStickButton; - set - { - _leftStickButton = value; - OnPropertyChanged(); - } - } + [ObservableProperty] private StickInputId _rightJoystick; - public StickInputId RightJoystick - { - get => _rightJoystick; - set - { - _rightJoystick = value; - OnPropertyChanged(); - } - } + [ObservableProperty] private bool _rightInvertStickX; - public bool RightInvertStickX - { - get => _rightInvertStickX; - set - { - _rightInvertStickX = value; - OnPropertyChanged(); - } - } + [ObservableProperty] private bool _rightInvertStickY; - public bool RightInvertStickY - { - get => _rightInvertStickY; - set - { - _rightInvertStickY = value; - OnPropertyChanged(); - } - } + [ObservableProperty] private bool _rightRotate90; - public bool RightRotate90 - { - get => _rightRotate90; - set - { - _rightRotate90 = value; - OnPropertyChanged(); - } - } + [ObservableProperty] private GamepadInputId _rightStickButton; - public GamepadInputId RightStickButton - { - get => _rightStickButton; - set - { - _rightStickButton = value; - OnPropertyChanged(); - } - } + [ObservableProperty] private GamepadInputId _dpadUp; - public GamepadInputId DpadUp - { - get => _dpadUp; - set - { - _dpadUp = value; - OnPropertyChanged(); - } - } + [ObservableProperty] private GamepadInputId _dpadDown; - public GamepadInputId DpadDown - { - get => _dpadDown; - set - { - _dpadDown = value; - OnPropertyChanged(); - } - } + [ObservableProperty] private GamepadInputId _dpadLeft; - public GamepadInputId DpadLeft - { - get => _dpadLeft; - set - { - _dpadLeft = value; - OnPropertyChanged(); - } - } + [ObservableProperty] private GamepadInputId _dpadRight; - public GamepadInputId DpadRight - { - get => _dpadRight; - set - { - _dpadRight = value; - OnPropertyChanged(); - } - } + [ObservableProperty] private GamepadInputId _buttonL; - public GamepadInputId ButtonL - { - get => _buttonL; - set - { - _buttonL = value; - OnPropertyChanged(); - } - } - - private GamepadInputId _buttonMinus; - public GamepadInputId ButtonMinus - { - get => _buttonMinus; - set - { - _buttonMinus = value; - OnPropertyChanged(); - } - } - - private GamepadInputId _leftButtonSl; - public GamepadInputId LeftButtonSl - { - get => _leftButtonSl; - set - { - _leftButtonSl = value; - OnPropertyChanged(); - } - } - - private GamepadInputId _leftButtonSr; - public GamepadInputId LeftButtonSr - { - get => _leftButtonSr; - set - { - _leftButtonSr = value; - OnPropertyChanged(); - } - } - - private GamepadInputId _buttonZl; - public GamepadInputId ButtonZl - { - get => _buttonZl; - set - { - _buttonZl = value; - OnPropertyChanged(); - } - } - - private GamepadInputId _buttonA; - public GamepadInputId ButtonA - { - get => _buttonA; - set - { - _buttonA = value; - OnPropertyChanged(); - } - } - - private GamepadInputId _buttonB; - public GamepadInputId ButtonB - { - get => _buttonB; - set - { - _buttonB = value; - OnPropertyChanged(); - } - } - - private GamepadInputId _buttonX; - public GamepadInputId ButtonX - { - get => _buttonX; - set - { - _buttonX = value; - OnPropertyChanged(); - } - } - - private GamepadInputId _buttonY; - public GamepadInputId ButtonY - { - get => _buttonY; - set - { - _buttonY = value; - OnPropertyChanged(); - } - } + [ObservableProperty] private GamepadInputId _buttonR; - public GamepadInputId ButtonR - { - get => _buttonR; - set - { - _buttonR = value; - OnPropertyChanged(); - } - } + [ObservableProperty] + private GamepadInputId _buttonMinus; + + [ObservableProperty] private GamepadInputId _buttonPlus; - public GamepadInputId ButtonPlus - { - get => _buttonPlus; - set - { - _buttonPlus = value; - OnPropertyChanged(); - } - } - private GamepadInputId _rightButtonSl; - public GamepadInputId RightButtonSl - { - get => _rightButtonSl; - set - { - _rightButtonSl = value; - OnPropertyChanged(); - } - } + [ObservableProperty] + private GamepadInputId _leftButtonSl; - private GamepadInputId _rightButtonSr; - public GamepadInputId RightButtonSr - { - get => _rightButtonSr; - set - { - _rightButtonSr = value; - OnPropertyChanged(); - } - } + [ObservableProperty] + private GamepadInputId _leftButtonSr; + [ObservableProperty] + private GamepadInputId _buttonZl; + + [ObservableProperty] private GamepadInputId _buttonZr; - public GamepadInputId ButtonZr - { - get => _buttonZr; - set - { - _buttonZr = value; - OnPropertyChanged(); - } - } + [ObservableProperty] + private GamepadInputId _buttonA; + + [ObservableProperty] + private GamepadInputId _buttonB; + + [ObservableProperty] + private GamepadInputId _buttonX; + + [ObservableProperty] + private GamepadInputId _buttonY; + + [ObservableProperty] + private GamepadInputId _rightButtonSl; + + [ObservableProperty] + private GamepadInputId _rightButtonSr; + + [ObservableProperty] private float _deadzoneLeft; - public float DeadzoneLeft - { - get => _deadzoneLeft; - set - { - _deadzoneLeft = MathF.Round(value, 3); - OnPropertyChanged(); - } - } + [ObservableProperty] private float _deadzoneRight; - public float DeadzoneRight - { - get => _deadzoneRight; - set - { - _deadzoneRight = MathF.Round(value, 3); - OnPropertyChanged(); - } - } + [ObservableProperty] private float _rangeLeft; - public float RangeLeft - { - get => _rangeLeft; - set - { - _rangeLeft = MathF.Round(value, 3); - OnPropertyChanged(); - } - } + [ObservableProperty] private float _rangeRight; - public float RangeRight - { - get => _rangeRight; - set - { - _rangeRight = MathF.Round(value, 3); - OnPropertyChanged(); - } - } + [ObservableProperty] private float _triggerThreshold; - public float TriggerThreshold - { - get => _triggerThreshold; - set - { - _triggerThreshold = MathF.Round(value, 3); - OnPropertyChanged(); - } - } + [ObservableProperty] private bool _enableMotion; - public bool EnableMotion - { - get => _enableMotion; - set - { - _enableMotion = value; - OnPropertyChanged(); - } - } + [ObservableProperty] private bool _enableRumble; - public bool EnableRumble - { - get => _enableRumble; - set - { - _enableRumble = value; - OnPropertyChanged(); - } - } public GamepadInputConfig(InputConfig config) { diff --git a/src/Ryujinx/UI/Models/Input/HotkeyConfig.cs b/src/Ryujinx/UI/Models/Input/HotkeyConfig.cs index 173fa6c99..30aafcfa4 100644 --- a/src/Ryujinx/UI/Models/Input/HotkeyConfig.cs +++ b/src/Ryujinx/UI/Models/Input/HotkeyConfig.cs @@ -1,152 +1,48 @@ +using CommunityToolkit.Mvvm.ComponentModel; using Ryujinx.Ava.UI.ViewModels; using Ryujinx.Common.Configuration.Hid; namespace Ryujinx.Ava.UI.Models.Input { - public class HotkeyConfig : BaseModel + public partial class HotkeyConfig : BaseModel { + [ObservableProperty] private Key _toggleVSyncMode; - public Key ToggleVSyncMode - { - get => _toggleVSyncMode; - set - { - _toggleVSyncMode = value; - OnPropertyChanged(); - } - } + [ObservableProperty] private Key _screenshot; - public Key Screenshot - { - get => _screenshot; - set - { - _screenshot = value; - OnPropertyChanged(); - } - } + [ObservableProperty] private Key _showUI; - public Key ShowUI - { - get => _showUI; - set - { - _showUI = value; - OnPropertyChanged(); - } - } + [ObservableProperty] private Key _pause; - public Key Pause - { - get => _pause; - set - { - _pause = value; - OnPropertyChanged(); - } - } + [ObservableProperty] private Key _toggleMute; - public Key ToggleMute - { - get => _toggleMute; - set - { - _toggleMute = value; - OnPropertyChanged(); - } - } + [ObservableProperty] private Key _resScaleUp; - public Key ResScaleUp - { - get => _resScaleUp; - set - { - _resScaleUp = value; - OnPropertyChanged(); - } - } + [ObservableProperty] private Key _resScaleDown; - public Key ResScaleDown - { - get => _resScaleDown; - set - { - _resScaleDown = value; - OnPropertyChanged(); - } - } + [ObservableProperty] private Key _volumeUp; - public Key VolumeUp - { - get => _volumeUp; - set - { - _volumeUp = value; - OnPropertyChanged(); - } - } + [ObservableProperty] private Key _volumeDown; - public Key VolumeDown - { - get => _volumeDown; - set - { - _volumeDown = value; - OnPropertyChanged(); - } - } + [ObservableProperty] private Key _customVSyncIntervalIncrement; - public Key CustomVSyncIntervalIncrement - { - get => _customVSyncIntervalIncrement; - set - { - _customVSyncIntervalIncrement = value; - OnPropertyChanged(); - } - } + [ObservableProperty] private Key _customVSyncIntervalDecrement; - public Key CustomVSyncIntervalDecrement - { - get => _customVSyncIntervalDecrement; - set - { - _customVSyncIntervalDecrement = value; - OnPropertyChanged(); - } - } + [ObservableProperty] private Key _turboMode; - public Key TurboMode - { - get => _turboMode; - set - { - _turboMode = value; - OnPropertyChanged(); - } - } - - private bool _turboModeWhileHeld; - public bool TurboModeWhileHeld - { - get => _turboModeWhileHeld; - set - { - _turboModeWhileHeld = value; - OnPropertyChanged(); - } - } + + [ObservableProperty] private bool _turboModeWhileHeld; public HotkeyConfig(KeyboardHotkeys config) { diff --git a/src/Ryujinx/UI/Models/Input/KeyboardInputConfig.cs b/src/Ryujinx/UI/Models/Input/KeyboardInputConfig.cs index 66f1f62a2..e44fd5292 100644 --- a/src/Ryujinx/UI/Models/Input/KeyboardInputConfig.cs +++ b/src/Ryujinx/UI/Models/Input/KeyboardInputConfig.cs @@ -1,322 +1,99 @@ +using CommunityToolkit.Mvvm.ComponentModel; using Ryujinx.Ava.UI.ViewModels; using Ryujinx.Common.Configuration.Hid; using Ryujinx.Common.Configuration.Hid.Keyboard; namespace Ryujinx.Ava.UI.Models.Input { - public class KeyboardInputConfig : BaseModel + public partial class KeyboardInputConfig : BaseModel { public string Id { get; set; } public ControllerType ControllerType { get; set; } public PlayerIndex PlayerIndex { get; set; } + [ObservableProperty] private Key _leftStickUp; - public Key LeftStickUp - { - get => _leftStickUp; - set - { - _leftStickUp = value; - OnPropertyChanged(); - } - } + [ObservableProperty] private Key _leftStickDown; - public Key LeftStickDown - { - get => _leftStickDown; - set - { - _leftStickDown = value; - OnPropertyChanged(); - } - } + [ObservableProperty] private Key _leftStickLeft; - public Key LeftStickLeft - { - get => _leftStickLeft; - set - { - _leftStickLeft = value; - OnPropertyChanged(); - } - } + [ObservableProperty] private Key _leftStickRight; - public Key LeftStickRight - { - get => _leftStickRight; - set - { - _leftStickRight = value; - OnPropertyChanged(); - } - } + [ObservableProperty] private Key _leftStickButton; - public Key LeftStickButton - { - get => _leftStickButton; - set - { - _leftStickButton = value; - OnPropertyChanged(); - } - } + [ObservableProperty] private Key _rightStickUp; - public Key RightStickUp - { - get => _rightStickUp; - set - { - _rightStickUp = value; - OnPropertyChanged(); - } - } + [ObservableProperty] private Key _rightStickDown; - public Key RightStickDown - { - get => _rightStickDown; - set - { - _rightStickDown = value; - OnPropertyChanged(); - } - } + [ObservableProperty] private Key _rightStickLeft; - public Key RightStickLeft - { - get => _rightStickLeft; - set - { - _rightStickLeft = value; - OnPropertyChanged(); - } - } + [ObservableProperty] private Key _rightStickRight; - public Key RightStickRight - { - get => _rightStickRight; - set - { - _rightStickRight = value; - OnPropertyChanged(); - } - } + [ObservableProperty] private Key _rightStickButton; - public Key RightStickButton - { - get => _rightStickButton; - set - { - _rightStickButton = value; - OnPropertyChanged(); - } - } + [ObservableProperty] private Key _dpadUp; - public Key DpadUp - { - get => _dpadUp; - set - { - _dpadUp = value; - OnPropertyChanged(); - } - } + [ObservableProperty] private Key _dpadDown; - public Key DpadDown - { - get => _dpadDown; - set - { - _dpadDown = value; - OnPropertyChanged(); - } - } + [ObservableProperty] private Key _dpadLeft; - public Key DpadLeft - { - get => _dpadLeft; - set - { - _dpadLeft = value; - OnPropertyChanged(); - } - } + [ObservableProperty] private Key _dpadRight; - public Key DpadRight - { - get => _dpadRight; - set - { - _dpadRight = value; - OnPropertyChanged(); - } - } + [ObservableProperty] private Key _buttonL; - public Key ButtonL - { - get => _buttonL; - set - { - _buttonL = value; - OnPropertyChanged(); - } - } - - private Key _buttonMinus; - public Key ButtonMinus - { - get => _buttonMinus; - set - { - _buttonMinus = value; - OnPropertyChanged(); - } - } - - private Key _leftButtonSl; - public Key LeftButtonSl - { - get => _leftButtonSl; - set - { - _leftButtonSl = value; - OnPropertyChanged(); - } - } - - private Key _leftButtonSr; - public Key LeftButtonSr - { - get => _leftButtonSr; - set - { - _leftButtonSr = value; - OnPropertyChanged(); - } - } - - private Key _buttonZl; - public Key ButtonZl - { - get => _buttonZl; - set - { - _buttonZl = value; - OnPropertyChanged(); - } - } - - private Key _buttonA; - public Key ButtonA - { - get => _buttonA; - set - { - _buttonA = value; - OnPropertyChanged(); - } - } - - private Key _buttonB; - public Key ButtonB - { - get => _buttonB; - set - { - _buttonB = value; - OnPropertyChanged(); - } - } - - private Key _buttonX; - public Key ButtonX - { - get => _buttonX; - set - { - _buttonX = value; - OnPropertyChanged(); - } - } - - private Key _buttonY; - public Key ButtonY - { - get => _buttonY; - set - { - _buttonY = value; - OnPropertyChanged(); - } - } + [ObservableProperty] private Key _buttonR; - public Key ButtonR - { - get => _buttonR; - set - { - _buttonR = value; - OnPropertyChanged(); - } - } + [ObservableProperty] + private Key _buttonMinus; + + [ObservableProperty] private Key _buttonPlus; - public Key ButtonPlus - { - get => _buttonPlus; - set - { - _buttonPlus = value; - OnPropertyChanged(); - } - } - private Key _rightButtonSl; - public Key RightButtonSl - { - get => _rightButtonSl; - set - { - _rightButtonSl = value; - OnPropertyChanged(); - } - } + [ObservableProperty] + private Key _leftButtonSl; - private Key _rightButtonSr; - public Key RightButtonSr - { - get => _rightButtonSr; - set - { - _rightButtonSr = value; - OnPropertyChanged(); - } - } + [ObservableProperty] + private Key _leftButtonSr; + [ObservableProperty] + private Key _buttonZl; + + [ObservableProperty] private Key _buttonZr; - public Key ButtonZr - { - get => _buttonZr; - set - { - _buttonZr = value; - OnPropertyChanged(); - } - } + + [ObservableProperty] + private Key _buttonA; + + [ObservableProperty] + private Key _buttonB; + + [ObservableProperty] + private Key _buttonX; + + [ObservableProperty] + private Key _buttonY; + + [ObservableProperty] + private Key _rightButtonSl; + + [ObservableProperty] + private Key _rightButtonSr; public KeyboardInputConfig(InputConfig config) { diff --git a/src/Ryujinx/UI/Models/ModModel.cs b/src/Ryujinx/UI/Models/ModModel.cs index 657bba74e..fb87cc718 100644 --- a/src/Ryujinx/UI/Models/ModModel.cs +++ b/src/Ryujinx/UI/Models/ModModel.cs @@ -1,21 +1,13 @@ +using CommunityToolkit.Mvvm.ComponentModel; using Ryujinx.Ava.UI.ViewModels; namespace Ryujinx.Ava.UI.Models { - public class ModModel : BaseModel + public partial class ModModel : BaseModel { + [ObservableProperty] private bool _enabled; - public bool Enabled - { - get => _enabled; - set - { - _enabled = value; - OnPropertyChanged(); - } - } - public bool InSd { get; } public string Path { get; } public string Name { get; } diff --git a/src/Ryujinx/UI/Models/ProfileImageModel.cs b/src/Ryujinx/UI/Models/ProfileImageModel.cs index 99365dfc7..965029eab 100644 --- a/src/Ryujinx/UI/Models/ProfileImageModel.cs +++ b/src/Ryujinx/UI/Models/ProfileImageModel.cs @@ -1,32 +1,15 @@ using Avalonia.Media; +using CommunityToolkit.Mvvm.ComponentModel; using Ryujinx.Ava.UI.ViewModels; namespace Ryujinx.Ava.UI.Models { - public class ProfileImageModel : BaseModel + public partial class ProfileImageModel(string name, byte[] data) : BaseModel { - public ProfileImageModel(string name, byte[] data) - { - Name = name; - Data = data; - } - - public string Name { get; set; } - public byte[] Data { get; set; } + public string Name { get; set; } = name; + public byte[] Data { get; set; } = data; + [ObservableProperty] private SolidColorBrush _backgroundColor = new(Colors.White); - - public SolidColorBrush BackgroundColor - { - get - { - return _backgroundColor; - } - set - { - _backgroundColor = value; - OnPropertyChanged(); - } - } } } diff --git a/src/Ryujinx/UI/Models/TempProfile.cs b/src/Ryujinx/UI/Models/TempProfile.cs index 659092e6d..8a08b27b7 100644 --- a/src/Ryujinx/UI/Models/TempProfile.cs +++ b/src/Ryujinx/UI/Models/TempProfile.cs @@ -1,56 +1,36 @@ +using CommunityToolkit.Mvvm.ComponentModel; using Ryujinx.Ava.UI.ViewModels; using Ryujinx.HLE.HOS.Services.Account.Acc; using System; namespace Ryujinx.Ava.UI.Models { - public class TempProfile : BaseModel + public partial class TempProfile : BaseModel { - private readonly UserProfile _profile; + [ObservableProperty] private byte[] _image; + + [ObservableProperty] 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; + get; set { - _userId = value; + field = value; OnPropertyChanged(); OnPropertyChanged(nameof(UserIdString)); } } - public string UserIdString => _userId.ToString(); - - public string Name - { - get => _name; - set - { - _name = value; - OnPropertyChanged(); - } - } + public string UserIdString => UserId.ToString(); public TempProfile(UserProfile profile) { - _profile = profile; - - if (_profile != null) + if (profile != null) { Image = profile.Image; Name = profile.Name; diff --git a/src/Ryujinx/UI/Models/UserProfile.cs b/src/Ryujinx/UI/Models/UserProfile.cs index 9cf8c10a2..d3befe558 100644 --- a/src/Ryujinx/UI/Models/UserProfile.cs +++ b/src/Ryujinx/UI/Models/UserProfile.cs @@ -1,4 +1,5 @@ using Avalonia.Media; +using CommunityToolkit.Mvvm.ComponentModel; using Ryujinx.Ava.UI.Controls; using Ryujinx.Ava.UI.ViewModels; using Ryujinx.Ava.UI.Views.User; @@ -7,66 +8,26 @@ using Profile = Ryujinx.HLE.HOS.Services.Account.Acc.UserProfile; namespace Ryujinx.Ava.UI.Models { - public class UserProfile : BaseModel + public partial class UserProfile : BaseModel { private readonly Profile _profile; private readonly NavigationDialogHost _owner; + + [ObservableProperty] private byte[] _image; + + [ObservableProperty] private string _name; + + [ObservableProperty] private UserId _userId; + + [ObservableProperty] private bool _isPointerOver; + + [ObservableProperty] 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; diff --git a/src/Ryujinx/UI/ViewModels/AboutWindowViewModel.cs b/src/Ryujinx/UI/ViewModels/AboutWindowViewModel.cs index 868f45d27..f856373eb 100644 --- a/src/Ryujinx/UI/ViewModels/AboutWindowViewModel.cs +++ b/src/Ryujinx/UI/ViewModels/AboutWindowViewModel.cs @@ -1,6 +1,7 @@ using Avalonia.Media.Imaging; using Avalonia.Styling; using Avalonia.Threading; +using CommunityToolkit.Mvvm.ComponentModel; using Ryujinx.Ava.Common; using Ryujinx.Ava.Common.Locale; using Ryujinx.UI.Common.Configuration; @@ -8,43 +9,17 @@ using System; namespace Ryujinx.Ava.UI.ViewModels { - public class AboutWindowViewModel : BaseModel, IDisposable + public partial class AboutWindowViewModel : BaseModel, IDisposable { - private Bitmap _gitlabLogo; + [ObservableProperty] + private Bitmap _gitLabLogo; + + [ObservableProperty] private Bitmap _discordLogo; + [ObservableProperty] private string _version; - public Bitmap GitLabLogo - { - get => _gitlabLogo; - set - { - _gitlabLogo = value; - OnPropertyChanged(); - } - } - - public Bitmap DiscordLogo - { - get => _discordLogo; - set - { - _discordLogo = value; - OnPropertyChanged(); - } - } - - public string Version - { - get => _version; - set - { - _version = value; - OnPropertyChanged(); - } - } - public string FormerDevelopers => LocaleManager.Instance.UpdateAndGetDynamicValue(LocaleKeys.AboutPageDeveloperListMore, "gdkchan, Ac_K, marysaka, rip in peri peri, LDj3SNuD, emmaus, Thealexbarney, GoffyDude, TSRBerry, IsaacMarovitz"); public string Developers => "KeatonTheBot"; diff --git a/src/Ryujinx/UI/ViewModels/BaseModel.cs b/src/Ryujinx/UI/ViewModels/BaseModel.cs index 4db9cf812..c0ccfcae1 100644 --- a/src/Ryujinx/UI/ViewModels/BaseModel.cs +++ b/src/Ryujinx/UI/ViewModels/BaseModel.cs @@ -1,15 +1,17 @@ -using System.ComponentModel; -using System.Runtime.CompilerServices; +using CommunityToolkit.Mvvm.ComponentModel; +using System; namespace Ryujinx.Ava.UI.ViewModels { - public class BaseModel : INotifyPropertyChanged + public class BaseModel : ObservableObject { - public event PropertyChangedEventHandler PropertyChanged; - - protected void OnPropertyChanged([CallerMemberName] string propertyName = null) + protected void OnPropertiesChanged(string firstPropertyName, params ReadOnlySpan propertyNames) { - PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); + OnPropertyChanged(firstPropertyName); + foreach (var propertyName in propertyNames) + { + OnPropertyChanged(propertyName); + } } } } diff --git a/src/Ryujinx/UI/ViewModels/DlcSelectViewModel.cs b/src/Ryujinx/UI/ViewModels/DlcSelectViewModel.cs index 9d52e7229..76bdf94d3 100644 --- a/src/Ryujinx/UI/ViewModels/DlcSelectViewModel.cs +++ b/src/Ryujinx/UI/ViewModels/DlcSelectViewModel.cs @@ -1,4 +1,5 @@ -using Ryujinx.UI.App.Common; +using CommunityToolkit.Mvvm.ComponentModel; +using Ryujinx.UI.App.Common; using Ryujinx.UI.Common.Models; using System.Linq; @@ -6,30 +7,12 @@ namespace Ryujinx.Ava.UI.ViewModels { public partial class DlcSelectViewModel : BaseModel { + [ObservableProperty] private DownloadableContentModel[] _dlcs; - private DownloadableContentModel _selectedDlc; - - public DownloadableContentModel[] Dlcs - { - get => _dlcs; - set - { - _dlcs = value; - OnPropertyChanged(); - } - } #nullable enable - public DownloadableContentModel? SelectedDlc - { - get => _selectedDlc; - set - { - _selectedDlc = value; - - OnPropertyChanged(); - } - } + [ObservableProperty] + private DownloadableContentModel? _selectedDlc; #nullable disable public DlcSelectViewModel(ulong titleId, ApplicationLibrary appLibrary) diff --git a/src/Ryujinx/UI/ViewModels/DownloadableContentManagerViewModel.cs b/src/Ryujinx/UI/ViewModels/DownloadableContentManagerViewModel.cs index 7bcc4bdd2..1bf89a241 100644 --- a/src/Ryujinx/UI/ViewModels/DownloadableContentManagerViewModel.cs +++ b/src/Ryujinx/UI/ViewModels/DownloadableContentManagerViewModel.cs @@ -2,6 +2,7 @@ using Avalonia.Collections; using Avalonia.Controls.ApplicationLifetimes; using Avalonia.Platform.Storage; using Avalonia.Threading; +using CommunityToolkit.Mvvm.ComponentModel; using DynamicData; using FluentAvalonia.UI.Controls; using Ryujinx.Ava.Common.Locale; @@ -16,13 +17,18 @@ using Application = Avalonia.Application; namespace Ryujinx.Ava.UI.ViewModels { - public class DownloadableContentManagerViewModel : BaseModel + public partial class DownloadableContentManagerViewModel : BaseModel { private readonly ApplicationLibrary _applicationLibrary; - private AvaloniaList _downloadableContents = []; + + [ObservableProperty] private AvaloniaList _selectedDownloadableContents = []; + + [ObservableProperty] private AvaloniaList _views = []; - private bool _showBundledContentNotice = false; + + [ObservableProperty] + private bool _showBundledContentNotice; private string _search; private readonly ApplicationData _applicationData; @@ -30,35 +36,15 @@ namespace Ryujinx.Ava.UI.ViewModels public AvaloniaList DownloadableContents { - get => _downloadableContents; + get; set { - _downloadableContents = value; + field = value; OnPropertyChanged(); OnPropertyChanged(nameof(UpdateCount)); Sort(); } - } - - public AvaloniaList Views - { - get => _views; - set - { - _views = value; - OnPropertyChanged(); - } - } - - public AvaloniaList SelectedDownloadableContents - { - get => _selectedDownloadableContents; - set - { - _selectedDownloadableContents = value; - OnPropertyChanged(); - } - } + } = []; public string Search { @@ -76,16 +62,6 @@ namespace Ryujinx.Ava.UI.ViewModels get => string.Format(LocaleManager.Instance[LocaleKeys.DlcWindowHeading], DownloadableContents.Count); } - public bool ShowBundledContentNotice - { - get => _showBundledContentNotice; - set - { - _showBundledContentNotice = value; - OnPropertyChanged(); - } - } - public DownloadableContentManagerViewModel(ApplicationLibrary applicationLibrary, ApplicationData applicationData) { _applicationLibrary = applicationLibrary; @@ -138,8 +114,8 @@ namespace Ryujinx.Ava.UI.ViewModels // some reason. so we save the items here and add them back after var items = SelectedDownloadableContents.ToArray(); - _views.Clear(); - _views.AddRange(view); + Views.Clear(); + Views.AddRange(view); foreach (DownloadableContentModel item in items) { diff --git a/src/Ryujinx/UI/ViewModels/Input/ControllerInputViewModel.cs b/src/Ryujinx/UI/ViewModels/Input/ControllerInputViewModel.cs index c84590ea6..850148e21 100644 --- a/src/Ryujinx/UI/ViewModels/Input/ControllerInputViewModel.cs +++ b/src/Ryujinx/UI/ViewModels/Input/ControllerInputViewModel.cs @@ -1,54 +1,51 @@ using Avalonia.Svg.Skia; +using CommunityToolkit.Mvvm.ComponentModel; using Ryujinx.Ava.UI.Models.Input; using Ryujinx.Ava.UI.Views.Input; namespace Ryujinx.Ava.UI.ViewModels.Input { - public class ControllerInputViewModel : BaseModel + public partial class ControllerInputViewModel : BaseModel { - private GamepadInputConfig _config; public GamepadInputConfig Config { - get => _config; + get; set { - _config = value; + field = value; OnPropertyChanged(); } } - private StickVisualizer _visualizer; public StickVisualizer Visualizer { - get => _visualizer; + get; set { - _visualizer = value; + field = value; OnPropertyChanged(); } } - - private bool _isLeft; + public bool IsLeft { - get => _isLeft; + get; set { - _isLeft = value; + field = value; OnPropertyChanged(); OnPropertyChanged(nameof(HasSides)); } } - private bool _isRight; public bool IsRight { - get => _isRight; + get; set { - _isRight = value; + field = value; OnPropertyChanged(); OnPropertyChanged(nameof(HasSides)); } @@ -56,16 +53,8 @@ namespace Ryujinx.Ava.UI.ViewModels.Input public bool HasSides => IsLeft ^ IsRight; + [ObservableProperty] private SvgImage _image; - public SvgImage Image - { - get => _image; - set - { - _image = value; - OnPropertyChanged(); - } - } public readonly InputViewModel ParentModel; diff --git a/src/Ryujinx/UI/ViewModels/Input/InputViewModel.cs b/src/Ryujinx/UI/ViewModels/Input/InputViewModel.cs index a46a8065c..026fba30a 100644 --- a/src/Ryujinx/UI/ViewModels/Input/InputViewModel.cs +++ b/src/Ryujinx/UI/ViewModels/Input/InputViewModel.cs @@ -4,6 +4,7 @@ using Avalonia.Controls; using Avalonia.Controls.ApplicationLifetimes; using Avalonia.Svg.Skia; using Avalonia.Threading; +using CommunityToolkit.Mvvm.ComponentModel; using Ryujinx.Ava.Common.Locale; using Ryujinx.Ava.Input; using Ryujinx.Ava.UI.Helpers; @@ -32,7 +33,7 @@ using Key = Ryujinx.Common.Configuration.Hid.Key; namespace Ryujinx.Ava.UI.ViewModels.Input { - public class InputViewModel : BaseModel, IDisposable + public partial class InputViewModel : BaseModel, IDisposable { private const string Disabled = "disabled"; private const string ProControllerResource = "Ryujinx.UI.Common/Resources/Controller_ProCon.svg"; @@ -48,8 +49,10 @@ namespace Ryujinx.Ava.UI.ViewModels.Input private int _controller; private string _controllerImage; private int _device; - private object _configViewModel; + + [ObservableProperty] private string _profileName; + private bool _isLoaded; private static readonly InputConfigJsonSerializerContext _serializerContext = new(JsonHelper.GetDefaultSerializerOptions()); @@ -76,10 +79,10 @@ namespace Ryujinx.Ava.UI.ViewModels.Input public object ConfigViewModel { - get => _configViewModel; + get; set { - _configViewModel = value; + field = value; VisualStick.UpdateConfig(value); @@ -203,16 +206,6 @@ namespace Ryujinx.Ava.UI.ViewModels.Input } } - public string ProfileName - { - get => _profileName; set - { - _profileName = value; - - OnPropertyChanged(); - } - } - public int Device { get => _device; @@ -451,7 +444,7 @@ namespace Ryujinx.Ava.UI.ViewModels.Input const string Hyphen = "-"; const int Offset = 1; - return str[(str.IndexOf(Hyphen) + Offset)..]; + return str[(str.IndexOf(Hyphen, StringComparison.Ordinal) + Offset)..]; } public void LoadDevices() diff --git a/src/Ryujinx/UI/ViewModels/Input/KeyboardInputViewModel.cs b/src/Ryujinx/UI/ViewModels/Input/KeyboardInputViewModel.cs index 9096cd845..f4955cc8d 100644 --- a/src/Ryujinx/UI/ViewModels/Input/KeyboardInputViewModel.cs +++ b/src/Ryujinx/UI/ViewModels/Input/KeyboardInputViewModel.cs @@ -1,53 +1,50 @@ using Avalonia.Svg.Skia; +using CommunityToolkit.Mvvm.ComponentModel; using Ryujinx.Ava.UI.Models.Input; namespace Ryujinx.Ava.UI.ViewModels.Input { - public class KeyboardInputViewModel : BaseModel + public partial class KeyboardInputViewModel : BaseModel { - private KeyboardInputConfig _config; public KeyboardInputConfig Config { - get => _config; + get; set { - _config = value; + field = value; OnPropertyChanged(); } } - private StickVisualizer _visualizer; public StickVisualizer Visualizer { - get => _visualizer; + get; set { - _visualizer = value; + field = value; OnPropertyChanged(); } } - private bool _isLeft; public bool IsLeft { - get => _isLeft; + get; set { - _isLeft = value; + field = value; OnPropertyChanged(); OnPropertyChanged(nameof(HasSides)); } } - private bool _isRight; public bool IsRight { - get => _isRight; + get; set { - _isRight = value; + field = value; OnPropertyChanged(); OnPropertyChanged(nameof(HasSides)); } @@ -55,16 +52,8 @@ namespace Ryujinx.Ava.UI.ViewModels.Input public bool HasSides => IsLeft ^ IsRight; + [ObservableProperty] private SvgImage _image; - public SvgImage Image - { - get => _image; - set - { - _image = value; - OnPropertyChanged(); - } - } public readonly InputViewModel ParentModel; diff --git a/src/Ryujinx/UI/ViewModels/Input/MotionInputViewModel.cs b/src/Ryujinx/UI/ViewModels/Input/MotionInputViewModel.cs index 1c7f726f1..9fe40a644 100644 --- a/src/Ryujinx/UI/ViewModels/Input/MotionInputViewModel.cs +++ b/src/Ryujinx/UI/ViewModels/Input/MotionInputViewModel.cs @@ -1,93 +1,31 @@ +using CommunityToolkit.Mvvm.ComponentModel; + namespace Ryujinx.Ava.UI.ViewModels.Input { - public class MotionInputViewModel : BaseModel + public partial class MotionInputViewModel : BaseModel { + [ObservableProperty] private int _slot; - public int Slot - { - get => _slot; - set - { - _slot = value; - OnPropertyChanged(); - } - } + [ObservableProperty] private int _altSlot; - public int AltSlot - { - get => _altSlot; - set - { - _altSlot = value; - OnPropertyChanged(); - } - } + [ObservableProperty] private string _dsuServerHost; - public string DsuServerHost - { - get => _dsuServerHost; - set - { - _dsuServerHost = value; - OnPropertyChanged(); - } - } + [ObservableProperty] private int _dsuServerPort; - public int DsuServerPort - { - get => _dsuServerPort; - set - { - _dsuServerPort = value; - OnPropertyChanged(); - } - } + [ObservableProperty] private bool _mirrorInput; - public bool MirrorInput - { - get => _mirrorInput; - set - { - _mirrorInput = value; - OnPropertyChanged(); - } - } + [ObservableProperty] private int _sensitivity; - public int Sensitivity - { - get => _sensitivity; - set - { - _sensitivity = value; - OnPropertyChanged(); - } - } + [ObservableProperty] private double _gyroDeadzone; - public double GyroDeadzone - { - get => _gyroDeadzone; - set - { - _gyroDeadzone = value; - OnPropertyChanged(); - } - } + [ObservableProperty] private bool _enableCemuHookMotion; - public bool EnableCemuHookMotion - { - get => _enableCemuHookMotion; - set - { - _enableCemuHookMotion = value; - OnPropertyChanged(); - } - } } } diff --git a/src/Ryujinx/UI/ViewModels/Input/RumbleInputViewModel.cs b/src/Ryujinx/UI/ViewModels/Input/RumbleInputViewModel.cs index 8ad33cf4c..c414aff99 100644 --- a/src/Ryujinx/UI/ViewModels/Input/RumbleInputViewModel.cs +++ b/src/Ryujinx/UI/ViewModels/Input/RumbleInputViewModel.cs @@ -1,27 +1,13 @@ +using CommunityToolkit.Mvvm.ComponentModel; + namespace Ryujinx.Ava.UI.ViewModels.Input { - public class RumbleInputViewModel : BaseModel + public partial class RumbleInputViewModel : BaseModel { + [ObservableProperty] private float _strongRumble; - public float StrongRumble - { - get => _strongRumble; - set - { - _strongRumble = value; - OnPropertyChanged(); - } - } + [ObservableProperty] private float _weakRumble; - public float WeakRumble - { - get => _weakRumble; - set - { - _weakRumble = value; - OnPropertyChanged(); - } - } } } diff --git a/src/Ryujinx/UI/ViewModels/MainWindowViewModel.cs b/src/Ryujinx/UI/ViewModels/MainWindowViewModel.cs index 9c72e0feb..775b93221 100644 --- a/src/Ryujinx/UI/ViewModels/MainWindowViewModel.cs +++ b/src/Ryujinx/UI/ViewModels/MainWindowViewModel.cs @@ -5,6 +5,7 @@ using Avalonia.Input; using Avalonia.Media; using Avalonia.Platform.Storage; using Avalonia.Threading; +using CommunityToolkit.Mvvm.ComponentModel; using DynamicData; using DynamicData.Binding; using FluentAvalonia.UI.Controls; @@ -50,90 +51,84 @@ using ShaderCacheLoadingState = Ryujinx.Graphics.Gpu.Shader.ShaderCacheState; namespace Ryujinx.Ava.UI.ViewModels { - public class MainWindowViewModel : BaseModel + public partial class MainWindowViewModel : BaseModel { private const int HotKeyPressDelayMs = 500; private delegate int LoadContentFromFolderDelegate(List dirs, out int numRemoved); - private ObservableCollectionExtended _applications; - private string _aspectStatusText; + [ObservableProperty] private ObservableCollectionExtended _applications; + [ObservableProperty] private string _aspectRatioStatusText; - private string _loadHeading; - private string _cacheLoadStatus; + [ObservableProperty] private string _loadHeading; + [ObservableProperty] private string _cacheLoadStatus; + [ObservableProperty] private string _dockedStatusText; + [ObservableProperty] private string _fifoStatusText; + [ObservableProperty] private string _gameStatusText; + [ObservableProperty] private string _volumeStatusText; + [ObservableProperty] private string _gpuNameText; + [ObservableProperty] private string _shaderCountText; + [ObservableProperty] private bool _showRightmostSeparator; + [ObservableProperty] private bool _isFullScreen; + [ObservableProperty] private int _progressMaximum; + [ObservableProperty] private int _progressValue; + [ObservableProperty] private long _lastFullscreenToggle = Environment.TickCount64; + [ObservableProperty] private bool _showMenuAndStatusBar = true; + [ObservableProperty] private bool _showStatusSeparator; + [ObservableProperty] private Brush _progressBarForegroundColor; + [ObservableProperty] private Brush _progressBarBackgroundColor; + [ObservableProperty] private Brush _vSyncModeColor; + #nullable enable + [ObservableProperty] private byte[]? _selectedIcon; + #nullable disable + [ObservableProperty] private int _statusBarProgressMaximum; + [ObservableProperty] private int _statusBarProgressValue; + [ObservableProperty] private string _statusBarProgressStatusText; + [ObservableProperty] private bool _statusBarProgressStatusVisible; + [ObservableProperty] private bool _isPaused; + [ObservableProperty] private bool _showContent = true; + [ObservableProperty] private bool _isLoadingIndeterminate = true; + [ObservableProperty] private bool _showAll; + [ObservableProperty] private string _lastScannedAmiiboId; + [ObservableProperty] private ReadOnlyObservableCollection _appsObservableList; + + [ObservableProperty] private float _volumeBeforeMute; + [ObservableProperty] private string _backendText; + + [ObservableProperty] private bool _areMimeTypesRegistered = FileAssociationHelper.AreMimeTypesRegistered; + [ObservableProperty] private Cursor _cursor; + [ObservableProperty] private string _title; + [ObservableProperty] private WindowState _windowState; + [ObservableProperty] private double _windowWidth; + [ObservableProperty] private double _windowHeight; + + [ObservableProperty] private bool _isActive; + [ObservableProperty] private bool _isSubMenuOpen; + + private ApplicationContextMenu _listAppContextMenu; + private ApplicationContextMenu _gridAppContextMenu; + + private bool _isGameRunning; private string _searchText; private Timer _searchTimer; - private string _dockedStatusText; - private string _vSyncModeText; - private string _fifoStatusText; - private string _gameStatusText; - private string _volumeStatusText; - private string _gpuStatusText; - private string _shaderCountText; - private bool _isAmiiboRequested; - private bool _showRightmostSeparator; - private bool _isAmiiboBinRequested; - 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 _vSyncModeColor; - private byte[] _selectedIcon; - private bool _isAppletMenuActive; - private int _statusBarProgressMaximum; - private int _statusBarProgressValue; - private string _statusBarProgressStatusText; - private bool _statusBarProgressStatusVisible; - private bool _isPaused; - private bool _showContent = true; - private bool _isLoadingIndeterminate = true; - private bool _showAll; - private string _lastScannedAmiiboId; - private bool _statusBarVisible; - private ReadOnlyObservableCollection _appsObservableList; - private string _showUiKey = "F4"; private string _pauseKey = "F5"; private string _screenshotKey = "F8"; private float _volume; - private float _volumeBeforeMute; - private string _backendText; - - private bool _areMimeTypesRegistered = FileAssociationHelper.AreMimeTypesRegistered; - private bool _canUpdate = true; - private Cursor _cursor; - private string _title; private ApplicationData _currentApplicationData; private readonly AutoResetEvent _rendererWaitEvent; - private WindowState _windowState; - private double _windowWidth; - private double _windowHeight; private int _customVSyncInterval; private int _customVSyncIntervalPercentageProxy; - private bool _isActive; - private bool _isSubMenuOpen; - - private ApplicationData _listSelectedApplication; - private ApplicationData _gridSelectedApplication; - private ApplicationContextMenu _listAppContextMenu; - private ApplicationContextMenu _gridAppContextMenu; - public ApplicationData ListSelectedApplication { - get => _listSelectedApplication; + get; set { - _listSelectedApplication = value; + field = value; - if (_listSelectedApplication != null && _listAppContextMenu == null) + if (field != null && _listAppContextMenu == null) ListAppContextMenu = new ApplicationContextMenu(); - else if (_listSelectedApplication == null && _listAppContextMenu != null) + else if (field == null && _listAppContextMenu != null) ListAppContextMenu = null; OnPropertyChanged(); @@ -142,20 +137,20 @@ namespace Ryujinx.Ava.UI.ViewModels public ApplicationData GridSelectedApplication { - get => _gridSelectedApplication; + get; set { - _gridSelectedApplication = value; + field = value; - if (_gridSelectedApplication != null && _gridAppContextMenu == null) + if (field != null && _gridAppContextMenu == null) GridAppContextMenu = new ApplicationContextMenu(); - else if (_gridSelectedApplication == null && _gridAppContextMenu != null) + else if (field == null && _gridAppContextMenu != null) GridAppContextMenu = null; - + OnPropertyChanged(); } } - + public IEnumerable LastLdnGameData; public MainWindow Window { get; init; } @@ -169,6 +164,8 @@ namespace Ryujinx.Ava.UI.ViewModels Applications.ToObservableChangeSet() .Filter(Filter) .Sort(GetComparer()) + .OnItemAdded(_ => OnPropertyChanged(nameof(AppsObservableList))) + .OnItemRemoved(_ => OnPropertyChanged(nameof(AppsObservableList))) .Bind(out _appsObservableList) .Subscribe(); @@ -239,31 +236,10 @@ namespace Ryujinx.Ava.UI.ViewModels public bool CanUpdate { - get => _canUpdate && EnableNonGameRunningControls && Updater.CanUpdate(false); + get => field && EnableNonGameRunningControls && Updater.CanUpdate(false); set { - _canUpdate = value; - OnPropertyChanged(); - } - } - - public Cursor Cursor - { - get => _cursor; - set - { - _cursor = value; - OnPropertyChanged(); - } - } - - public ReadOnlyObservableCollection AppsObservableList - { - get => _appsObservableList; - set - { - _appsObservableList = value; - + field = value; OnPropertyChanged(); } } @@ -290,34 +266,12 @@ namespace Ryujinx.Ava.UI.ViewModels } } - public bool IsPaused - { - get => _isPaused; - set - { - _isPaused = value; - - OnPropertyChanged(); - } - } - - public long LastFullscreenToggle - { - get => _lastFullscreenToggle; - set - { - _lastFullscreenToggle = value; - - OnPropertyChanged(); - } - } - public bool StatusBarVisible { - get => _statusBarVisible && EnableNonGameRunningControls; + get => field && EnableNonGameRunningControls; set { - _statusBarVisible = value; + field = value; OnPropertyChanged(); } @@ -327,17 +281,6 @@ namespace Ryujinx.Ava.UI.ViewModels public bool ShowFirmwareStatus => !ShowLoadProgress; - public bool ShowRightmostSeparator - { - get => _showRightmostSeparator; - set - { - _showRightmostSeparator = value; - - OnPropertyChanged(); - } - } - public bool IsGameRunning { get => _isGameRunning; @@ -360,20 +303,20 @@ namespace Ryujinx.Ava.UI.ViewModels public bool IsAmiiboRequested { - get => _isAmiiboRequested && _isGameRunning; + get => field && _isGameRunning; set { - _isAmiiboRequested = value; + field = value; OnPropertyChanged(); } } public bool IsAmiiboBinRequested { - get => _isAmiiboBinRequested && _isGameRunning; + get => field && _isGameRunning; set { - _isAmiiboBinRequested = value; + field = value; OnPropertyChanged(); } @@ -383,71 +326,16 @@ namespace Ryujinx.Ava.UI.ViewModels public bool ShowLoadProgress { - get => _showLoadProgress; + get; set { - _showLoadProgress = value; + field = 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 IsSubMenuOpen - { - get => _isSubMenuOpen; - set - { - _isSubMenuOpen = value; - - OnPropertyChanged(); - } - } - - public bool ShowAll - { - get => _showAll; - set - { - _showAll = value; - - OnPropertyChanged(); - } - } - - public string LastScannedAmiiboId - { - get => _lastScannedAmiiboId; - set - { - _lastScannedAmiiboId = value; - - OnPropertyChanged(); - } - } - public ApplicationData SelectedApplication { get @@ -471,63 +359,8 @@ namespace Ryujinx.Ava.UI.ViewModels public bool CreateShortcutEnabled => !ReleaseInformation.IsFlatHubBuild; - public string LoadHeading - { - get => _loadHeading; - set - { - _loadHeading = value; - - OnPropertyChanged(); - } - } - public bool HasDlc => ApplicationLibrary.HasDlcs(SelectedApplication.Id); - 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 VSyncModeColor - { - get => _vSyncModeColor; - set - { - _vSyncModeColor = value; - - OnPropertyChanged(); - } - } - public bool ShowCustomVSyncIntervalPicker { get @@ -537,10 +370,8 @@ namespace Ryujinx.Ava.UI.ViewModels return AppHost.Device.VSyncMode == VSyncMode.Custom; } - else - { - return false; - } + + return false; } set { @@ -598,165 +429,12 @@ namespace Ryujinx.Ava.UI.ViewModels } } - 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 bool StatusBarProgressStatusVisible - { - get => _statusBarProgressStatusVisible; - set - { - _statusBarProgressStatusVisible = value; - - OnPropertyChanged(); - } - } - - public string StatusBarProgressStatusText - { - get => _statusBarProgressStatusText; - set - { - _statusBarProgressStatusText = value; - - OnPropertyChanged(); - } - } - - public string FifoStatusText - { - get => _fifoStatusText; - set - { - _fifoStatusText = value; - - OnPropertyChanged(); - } - } - - public string GpuNameText - { - get => _gpuStatusText; - set - { - _gpuStatusText = value; - - OnPropertyChanged(); - } - } - - public string ShaderCountText - { - get => _shaderCountText; - set - { - _shaderCountText = value; - OnPropertyChanged(); - } - } - - public string BackendText - { - get => _backendText; - set - { - _backendText = value; - - OnPropertyChanged(); - } - } - public string VSyncModeText { - get => _vSyncModeText; + get; set { - _vSyncModeText = 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; + field = value; OnPropertyChanged(); } @@ -782,112 +460,12 @@ namespace Ryujinx.Ava.UI.ViewModels } } - 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; + get => field && 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; + field = value; OnPropertyChanged(); } @@ -949,17 +527,6 @@ namespace Ryujinx.Ava.UI.ViewModels } } - public string Title - { - get => _title; - set - { - _title = value; - - OnPropertyChanged(); - } - } - public bool ShowConsoleVisible { get => ConsoleHelper.SetConsoleWindowStateSupported; @@ -970,27 +537,6 @@ namespace Ryujinx.Ava.UI.ViewModels get => FileAssociationHelper.IsTypeAssociationSupported; } - public bool AreMimeTypesRegistered - { - get => _areMimeTypesRegistered; - set { - _areMimeTypesRegistered = value; - - OnPropertyChanged(); - } - } - - public ObservableCollectionExtended Applications - { - get => _applications; - set - { - _applications = value; - - OnPropertyChanged(); - } - } - public Glyph Glyph { get => (Glyph)ConfigurationState.Instance.UI.GameListViewMode.Value; @@ -1225,9 +771,10 @@ namespace Ryujinx.Ava.UI.ViewModels Applications.ToObservableChangeSet() .Filter(Filter) .Sort(GetComparer()) - .Bind(out _appsObservableList).AsObservableList(); + .Bind(out ReadOnlyObservableCollection apps) + .AsObservableList(); - OnPropertyChanged(nameof(AppsObservableList)); + AppsObservableList = apps; } private bool Filter(object arg) @@ -1338,7 +885,7 @@ namespace Ryujinx.Ava.UI.ViewModels } catch (MissingKeyException ex) { - if (Application.Current?.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop) + if (Application.Current?.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime) { Logger.Error?.Print(LogClass.Application, ex.ToString()); @@ -1570,7 +1117,7 @@ namespace Ryujinx.Ava.UI.ViewModels VSyncModeText = args.VSyncMode == "Custom" ? "Custom" : "VSync"; ShowCustomVSyncIntervalPicker = - args.VSyncMode == VSyncMode.Custom.ToString(); + args.VSyncMode == nameof(VSyncMode.Custom); DockedStatusText = args.DockedMode; AspectRatioStatusText = args.AspectRatio; GameStatusText = args.GameStatus; @@ -1604,7 +1151,7 @@ namespace Ryujinx.Ava.UI.ViewModels var dirs = result.Select(it => it.Path.LocalPath).ToList(); var numAdded = onDirsSelected(dirs, out int numRemoved); - var msg = String.Join("\r\n", new string[] { + var msg = String.Join("\r\n", new[] { string.Format(LocaleManager.Instance[localeMessageRemovedKey], numRemoved), string.Format(LocaleManager.Instance[localeMessageAddedKey], numAdded) }); @@ -2288,11 +1835,7 @@ namespace Ryujinx.Ava.UI.ViewModels switch (operationOutcome) { case XCIFileTrimmer.OperationOutcome.Successful: - if (Application.Current?.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop) - { - if (desktop.MainWindow is MainWindow mainWindow) - mainWindow.LoadApplications(); - } + App.MainWindow.LoadApplications(); break; } } diff --git a/src/Ryujinx/UI/ViewModels/ModManagerViewModel.cs b/src/Ryujinx/UI/ViewModels/ModManagerViewModel.cs index 4bf4b02c1..d45dc1c5b 100644 --- a/src/Ryujinx/UI/ViewModels/ModManagerViewModel.cs +++ b/src/Ryujinx/UI/ViewModels/ModManagerViewModel.cs @@ -3,6 +3,7 @@ using Avalonia.Collections; using Avalonia.Controls.ApplicationLifetimes; using Avalonia.Platform.Storage; using Avalonia.Threading; +using CommunityToolkit.Mvvm.ComponentModel; using DynamicData; using Ryujinx.Ava.Common.Locale; using Ryujinx.Ava.UI.Helpers; @@ -18,12 +19,14 @@ using System.Linq; namespace Ryujinx.Ava.UI.ViewModels { - public class ModManagerViewModel : BaseModel + public partial class ModManagerViewModel : BaseModel { private readonly string _modJsonPath; - private AvaloniaList _mods = []; + [ObservableProperty] private AvaloniaList _views = []; + + [ObservableProperty] private AvaloniaList _selectedMods = []; private string _search; @@ -35,35 +38,15 @@ namespace Ryujinx.Ava.UI.ViewModels public AvaloniaList Mods { - get => _mods; + get; set { - _mods = value; + field = value; OnPropertyChanged(); OnPropertyChanged(nameof(ModCount)); Sort(); } - } - - public AvaloniaList Views - { - get => _views; - set - { - _views = value; - OnPropertyChanged(); - } - } - - public AvaloniaList SelectedMods - { - get => _selectedMods; - set - { - _selectedMods = value; - OnPropertyChanged(); - } - } + } = []; public string Search { @@ -112,7 +95,7 @@ namespace Ryujinx.Ava.UI.ViewModels var inSd = path == ModLoader.GetSdModsBasePath(); var modCache = new ModLoader.ModCache(); - ModLoader.QueryContentsDir(modCache, new DirectoryInfo(Path.Combine(path, "contents")), applicationId, _installedDlcIds); + ModLoader.QueryContentsDir(modCache, new DirectoryInfo(Path.Combine(path, "contents")), applicationId, installedDlcIds); foreach (var mod in modCache.RomfsDirs) { @@ -161,8 +144,8 @@ namespace Ryujinx.Ava.UI.ViewModels .Filter(Filter) .Bind(out var view).AsObservableList(); - _views.Clear(); - _views.AddRange(view); + Views.Clear(); + Views.AddRange(view); SelectedMods = new(Views.Where(x => x.Enabled)); diff --git a/src/Ryujinx/UI/ViewModels/SettingsViewModel.cs b/src/Ryujinx/UI/ViewModels/SettingsViewModel.cs index fb3a0360e..dc66c1ab6 100644 --- a/src/Ryujinx/UI/ViewModels/SettingsViewModel.cs +++ b/src/Ryujinx/UI/ViewModels/SettingsViewModel.cs @@ -1,6 +1,7 @@ using Avalonia.Collections; using Avalonia.Controls; using Avalonia.Threading; +using CommunityToolkit.Mvvm.ComponentModel; using LibHac.Tools.FsSystem; using Ryujinx.Audio.Backends.OpenAL; using Ryujinx.Audio.Backends.SDL2; @@ -41,34 +42,27 @@ namespace Ryujinx.Ava.UI.ViewModels private readonly Dictionary _networkInterfaces; - private float _customResolutionScale; private int _resolutionScale; - private int _graphicsBackendMultithreadingIndex; - private float _volume; + + [ObservableProperty] private bool _isVulkanAvailable = true; + private bool _gameDirectoryChanged; private bool _autoloadDirectoryChanged; - private readonly List _gpuIds = new(); - private int _graphicsBackendIndex; + private readonly List _gpuIds = []; private int _scalingFilter; - private int _scalingFilterLevel; private int _customVSyncInterval; - private bool _enableCustomVSyncInterval; private int _customVSyncIntervalPercentageProxy; private VSyncMode _vSyncMode; - private long _turboModeMultiplier; public event Action CloseWindow; public event Action SaveSettingsEvent; - private int _networkInterfaceIndex; - private int _multiplayerModeIndex; - private string _ldnPassphrase; private string _LdnServer; + + [ObservableProperty] private bool _matchSystemTime; private bool _enableGDBStub; - private ushort _gdbStubPort; - private bool _debuggerSuspendOnStart; public int ResolutionScale { @@ -84,15 +78,15 @@ namespace Ryujinx.Ava.UI.ViewModels public int GraphicsBackendMultithreadingIndex { - get => _graphicsBackendMultithreadingIndex; + get; set { - _graphicsBackendMultithreadingIndex = value; + field = value; - if (_graphicsBackendMultithreadingIndex != (int)ConfigurationState.Instance.Graphics.BackendThreading.Value) + if (field != (int)ConfigurationState.Instance.Graphics.BackendThreading.Value) { Dispatcher.UIThread.InvokeAsync(() => - ContentDialogHelper.CreateInfoDialog(LocaleManager.Instance[LocaleKeys.DialogSettingsBackendThreadingWarningMessage], + ContentDialogHelper.CreateInfoDialog(LocaleManager.Instance[LocaleKeys.DialogSettingsBackendThreadingWarningMessage], "", "", LocaleManager.Instance[LocaleKeys.InputDialogOk], @@ -106,21 +100,10 @@ namespace Ryujinx.Ava.UI.ViewModels public float CustomResolutionScale { - get => _customResolutionScale; + get; set { - _customResolutionScale = value; - - OnPropertyChanged(); - } - } - - public bool IsVulkanAvailable - { - get => _isVulkanAvailable; - set - { - _isVulkanAvailable = value; + field = value; OnPropertyChanged(); } @@ -201,10 +184,10 @@ namespace Ryujinx.Ava.UI.ViewModels public bool EnableCustomVSyncInterval { - get => _enableCustomVSyncInterval; + get; set { - _enableCustomVSyncInterval = value; + field = value; if (_vSyncMode == VSyncMode.Custom && !value) { VSyncMode = VSyncMode.Switch; @@ -213,6 +196,7 @@ namespace Ryujinx.Ava.UI.ViewModels { VSyncMode = VSyncMode.Custom; } + OnPropertyChanged(); } } @@ -232,23 +216,22 @@ namespace Ryujinx.Ava.UI.ViewModels } public bool EnablePptc { get; set; } public bool EnableLowPowerPptc { get; set; } - - + public long TurboMultiplier { - get => _turboModeMultiplier; + get; set { - if (_turboModeMultiplier != value) + if (field != value) { - _turboModeMultiplier = value; - + field = value; + OnPropertyChanged(); OnPropertyChanged((nameof(TurboMultiplierPercentageText))); } } } - + public string TurboMultiplierPercentageText => $"{TurboMultiplier}%"; public bool EnableInternetAccess { get; set; } @@ -284,10 +267,10 @@ namespace Ryujinx.Ava.UI.ViewModels public string LdnPassphrase { - get => _ldnPassphrase; + get; set { - _ldnPassphrase = value; + field = value; IsInvalidLdnPassphraseVisible = !ValidateLdnPassphrase(value); OnPropertyChanged(); @@ -308,29 +291,33 @@ namespace Ryujinx.Ava.UI.ViewModels public int AspectRatio { get; set; } public int AntiAliasingEffect { get; set; } public string ScalingFilterLevelText => ScalingFilterLevel.ToString("0"); + public int ScalingFilterLevel { - get => _scalingFilterLevel; + get; set { - _scalingFilterLevel = value; + field = 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; + get; set { - _graphicsBackendIndex = value; + field = value; OnPropertyChanged(); OnPropertyChanged(nameof(IsVulkanSelected)); } } + public int ScalingFilter { get => _scalingFilter; @@ -346,26 +333,12 @@ namespace Ryujinx.Ava.UI.ViewModels public float Volume { - get => _volume; + get; set { - _volume = value; + field = value; - ConfigurationState.Instance.System.AudioVolume.Value = _volume / 100; - - OnPropertyChanged(); - } - } - - //private DateTimeOffset _currentDate; - //private TimeSpan _currentTime; - - public bool MatchSystemTime - { - get => _matchSystemTime; - set - { - _matchSystemTime = value; + ConfigurationState.Instance.System.AudioVolume.Value = field / 100; OnPropertyChanged(); } @@ -389,21 +362,21 @@ namespace Ryujinx.Ava.UI.ViewModels public int NetworkInterfaceIndex { - get => _networkInterfaceIndex; + get; set { - _networkInterfaceIndex = value != -1 ? value : 0; - ConfigurationState.Instance.Multiplayer.LanInterfaceId.Value = _networkInterfaces[NetworkInterfaceList[_networkInterfaceIndex]]; + field = value != -1 ? value : 0; + ConfigurationState.Instance.Multiplayer.LanInterfaceId.Value = _networkInterfaces[NetworkInterfaceList[field]]; } } public int MultiplayerModeIndex { - get => _multiplayerModeIndex; + get; set { - _multiplayerModeIndex = value; - ConfigurationState.Instance.Multiplayer.Mode.Value = (MultiplayerMode)_multiplayerModeIndex; + field = value; + ConfigurationState.Instance.Multiplayer.Mode.Value = (MultiplayerMode)field; } } @@ -434,21 +407,21 @@ namespace Ryujinx.Ava.UI.ViewModels public ushort GDBStubPort { - get => _gdbStubPort; + get; set { - _gdbStubPort = value; - ConfigurationState.Instance.Debug.GdbStubPort.Value = _gdbStubPort; + field = value; + ConfigurationState.Instance.Debug.GdbStubPort.Value = field; } } public bool DebuggerSuspendOnStart { - get => _debuggerSuspendOnStart; + get; set { - _debuggerSuspendOnStart = value; - ConfigurationState.Instance.Debug.DebuggerSuspendOnStart.Value = _debuggerSuspendOnStart; + field = value; + ConfigurationState.Instance.Debug.DebuggerSuspendOnStart.Value = field; } } diff --git a/src/Ryujinx/UI/ViewModels/TitleUpdateViewModel.cs b/src/Ryujinx/UI/ViewModels/TitleUpdateViewModel.cs index debfe6e3d..340696f8b 100644 --- a/src/Ryujinx/UI/ViewModels/TitleUpdateViewModel.cs +++ b/src/Ryujinx/UI/ViewModels/TitleUpdateViewModel.cs @@ -2,6 +2,7 @@ using Avalonia.Collections; using Avalonia.Controls.ApplicationLifetimes; using Avalonia.Platform.Storage; using Avalonia.Threading; +using CommunityToolkit.Mvvm.ComponentModel; using FluentAvalonia.UI.Controls; using Ryujinx.Ava.Common.Locale; using Ryujinx.Ava.UI.Helpers; @@ -15,57 +16,24 @@ using Application = Avalonia.Application; namespace Ryujinx.Ava.UI.ViewModels { - public record TitleUpdateViewNoUpdateSentinal(); + public record TitleUpdateViewNoUpdateSentinal; - public class TitleUpdateViewModel : BaseModel + public partial class TitleUpdateViewModel : BaseModel { private ApplicationLibrary ApplicationLibrary { get; } private ApplicationData ApplicationData { get; } + [ObservableProperty] private AvaloniaList _titleUpdates = []; + + [ObservableProperty] private AvaloniaList _views = []; + + [ObservableProperty] private object _selectedUpdate = new TitleUpdateViewNoUpdateSentinal(); - private bool _showBundledContentNotice = false; - public AvaloniaList TitleUpdates - { - get => _titleUpdates; - set - { - _titleUpdates = value; - OnPropertyChanged(); - } - } - - public AvaloniaList Views - { - get => _views; - set - { - _views = value; - OnPropertyChanged(); - } - } - - public object SelectedUpdate - { - get => _selectedUpdate; - set - { - _selectedUpdate = value; - OnPropertyChanged(); - } - } - - public bool ShowBundledContentNotice - { - get => _showBundledContentNotice; - set - { - _showBundledContentNotice = value; - OnPropertyChanged(); - } - } + [ObservableProperty] + private bool _showBundledContentNotice; public IStorageProvider StorageProvider; diff --git a/src/Ryujinx/UI/ViewModels/UserFirmwareAvatarSelectorViewModel.cs b/src/Ryujinx/UI/ViewModels/UserFirmwareAvatarSelectorViewModel.cs index 468c7334d..7e009fa03 100644 --- a/src/Ryujinx/UI/ViewModels/UserFirmwareAvatarSelectorViewModel.cs +++ b/src/Ryujinx/UI/ViewModels/UserFirmwareAvatarSelectorViewModel.cs @@ -1,4 +1,5 @@ using Avalonia.Media; +using CommunityToolkit.Mvvm.ComponentModel; using LibHac.Common; using LibHac.Fs; using LibHac.Fs.Fsa; @@ -20,58 +21,38 @@ using Image = SkiaSharp.SKImage; namespace Ryujinx.Ava.UI.ViewModels { - internal class UserFirmwareAvatarSelectorViewModel : BaseModel + internal partial class UserFirmwareAvatarSelectorViewModel : BaseModel { private static readonly Dictionary _avatarStore = new(); + [ObservableProperty] private ObservableCollection _images; - private Color _backgroundColor = Colors.White; - private int _selectedIndex; + [ObservableProperty] + private Color _backgroundColor = Colors.White; public UserFirmwareAvatarSelectorViewModel() { _images = []; LoadImagesFromStore(); - } - - public Color BackgroundColor - { - get => _backgroundColor; - set + PropertyChanged += (_, args) => { - _backgroundColor = value; - OnPropertyChanged(); - ChangeImageBackground(); - } - } - - public ObservableCollection Images - { - get => _images; - set - { - _images = value; - OnPropertyChanged(); - } + if (args.PropertyName == nameof(BackgroundColor)) + ChangeImageBackground(); + }; } public int SelectedIndex { - get => _selectedIndex; + get; set { - _selectedIndex = value; + field = value; - if (_selectedIndex == -1) - { - SelectedImage = null; - } - else - { - SelectedImage = _images[_selectedIndex].Data; - } + SelectedImage = field == -1 + ? null + : Images[field].Data; OnPropertyChanged(); } diff --git a/src/Ryujinx/UI/ViewModels/UserProfileImageSelectorViewModel.cs b/src/Ryujinx/UI/ViewModels/UserProfileImageSelectorViewModel.cs index 8e7d41a55..ea9bb8d4f 100644 --- a/src/Ryujinx/UI/ViewModels/UserProfileImageSelectorViewModel.cs +++ b/src/Ryujinx/UI/ViewModels/UserProfileImageSelectorViewModel.cs @@ -1,18 +1,10 @@ +using CommunityToolkit.Mvvm.ComponentModel; + namespace Ryujinx.Ava.UI.ViewModels { - internal class UserProfileImageSelectorViewModel : BaseModel + internal partial class UserProfileImageSelectorViewModel : BaseModel { + [ObservableProperty] private bool _firmwareFound; - - public bool FirmwareFound - { - get => _firmwareFound; - - set - { - _firmwareFound = value; - OnPropertyChanged(); - } - } } } diff --git a/src/Ryujinx/UI/ViewModels/UserSaveManagerViewModel.cs b/src/Ryujinx/UI/ViewModels/UserSaveManagerViewModel.cs index 992da81f5..7a78e5383 100644 --- a/src/Ryujinx/UI/ViewModels/UserSaveManagerViewModel.cs +++ b/src/Ryujinx/UI/ViewModels/UserSaveManagerViewModel.cs @@ -1,3 +1,4 @@ +using CommunityToolkit.Mvvm.ComponentModel; using DynamicData; using DynamicData.Binding; using Ryujinx.Ava.Common.Locale; @@ -8,74 +9,41 @@ using System.Collections.ObjectModel; namespace Ryujinx.Ava.UI.ViewModels { - public class UserSaveManagerViewModel : BaseModel + public partial class UserSaveManagerViewModel : BaseModel { + [ObservableProperty] private int _sortIndex; + + [ObservableProperty] private int _orderIndex; + + [ObservableProperty] private string _search; + + [ObservableProperty] private ObservableCollection _saves = []; + + [ObservableProperty] private ObservableCollection _views = []; + 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 Saves - { - get => _saves; - set - { - _saves = value; - OnPropertyChanged(); - Sort(); - } - } - - public ObservableCollection Views - { - get => _views; - set - { - _views = value; - OnPropertyChanged(); - } - } - public UserSaveManagerViewModel(AccountManager accountManager) { _accountManager = accountManager; + PropertyChanged += (_, evt) => + { + if (evt.PropertyName is + nameof(SortIndex) or + nameof(OrderIndex) or + nameof(Search) or + nameof(Saves)) + { + Sort(); + } + }; } public void Sort() @@ -85,8 +53,8 @@ namespace Ryujinx.Ava.UI.ViewModels .Sort(GetComparer()) .Bind(out var view).AsObservableList(); - _views.Clear(); - _views.AddRange(view); + Views.Clear(); + Views.AddRange(view); OnPropertyChanged(nameof(Views)); } @@ -94,7 +62,7 @@ namespace Ryujinx.Ava.UI.ViewModels { if (arg is SaveModel save) { - return string.IsNullOrWhiteSpace(_search) || save.Title.ToLower().Contains(_search.ToLower()); + return string.IsNullOrWhiteSpace(Search) || save.Title.ToLower().Contains(Search.ToLower()); } return false;