aboutsummaryrefslogtreecommitdiff
path: root/src/Ryujinx/UI/Models
diff options
context:
space:
mode:
Diffstat (limited to 'src/Ryujinx/UI/Models')
-rw-r--r--src/Ryujinx/UI/Models/CheatNode.cs57
-rw-r--r--src/Ryujinx/UI/Models/ControllerModel.cs6
-rw-r--r--src/Ryujinx/UI/Models/DeviceType.cs9
-rw-r--r--src/Ryujinx/UI/Models/DownloadableContentModel.cs35
-rw-r--r--src/Ryujinx/UI/Models/Generic/LastPlayedSortComparer.cs31
-rw-r--r--src/Ryujinx/UI/Models/Generic/TimePlayedSortComparer.cs31
-rw-r--r--src/Ryujinx/UI/Models/InputConfiguration.cs456
-rw-r--r--src/Ryujinx/UI/Models/ModModel.cs32
-rw-r--r--src/Ryujinx/UI/Models/PlayerModel.cs6
-rw-r--r--src/Ryujinx/UI/Models/ProfileImageModel.cs32
-rw-r--r--src/Ryujinx/UI/Models/SaveModel.cs96
-rw-r--r--src/Ryujinx/UI/Models/StatusUpdatedEventArgs.cs28
-rw-r--r--src/Ryujinx/UI/Models/TempProfile.cs61
-rw-r--r--src/Ryujinx/UI/Models/TimeZone.cs16
-rw-r--r--src/Ryujinx/UI/Models/TitleUpdateModel.cs19
-rw-r--r--src/Ryujinx/UI/Models/UserProfile.cs104
16 files changed, 1019 insertions, 0 deletions
diff --git a/src/Ryujinx/UI/Models/CheatNode.cs b/src/Ryujinx/UI/Models/CheatNode.cs
new file mode 100644
index 00000000..8e9aee25
--- /dev/null
+++ b/src/Ryujinx/UI/Models/CheatNode.cs
@@ -0,0 +1,57 @@
+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/UI/Models/ControllerModel.cs b/src/Ryujinx/UI/Models/ControllerModel.cs
new file mode 100644
index 00000000..98de7757
--- /dev/null
+++ b/src/Ryujinx/UI/Models/ControllerModel.cs
@@ -0,0 +1,6 @@
+using Ryujinx.Common.Configuration.Hid;
+
+namespace Ryujinx.Ava.UI.Models
+{
+ internal record ControllerModel(ControllerType Type, string Name);
+}
diff --git a/src/Ryujinx/UI/Models/DeviceType.cs b/src/Ryujinx/UI/Models/DeviceType.cs
new file mode 100644
index 00000000..bb4fc3b3
--- /dev/null
+++ b/src/Ryujinx/UI/Models/DeviceType.cs
@@ -0,0 +1,9 @@
+namespace Ryujinx.Ava.UI.Models
+{
+ public enum DeviceType
+ {
+ None,
+ Keyboard,
+ Controller,
+ }
+}
diff --git a/src/Ryujinx/UI/Models/DownloadableContentModel.cs b/src/Ryujinx/UI/Models/DownloadableContentModel.cs
new file mode 100644
index 00000000..9e400441
--- /dev/null
+++ b/src/Ryujinx/UI/Models/DownloadableContentModel.cs
@@ -0,0 +1,35 @@
+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/UI/Models/Generic/LastPlayedSortComparer.cs b/src/Ryujinx/UI/Models/Generic/LastPlayedSortComparer.cs
new file mode 100644
index 00000000..224f78f4
--- /dev/null
+++ b/src/Ryujinx/UI/Models/Generic/LastPlayedSortComparer.cs
@@ -0,0 +1,31 @@
+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/UI/Models/Generic/TimePlayedSortComparer.cs b/src/Ryujinx/UI/Models/Generic/TimePlayedSortComparer.cs
new file mode 100644
index 00000000..f0fb035d
--- /dev/null
+++ b/src/Ryujinx/UI/Models/Generic/TimePlayedSortComparer.cs
@@ -0,0 +1,31 @@
+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/UI/Models/InputConfiguration.cs b/src/Ryujinx/UI/Models/InputConfiguration.cs
new file mode 100644
index 00000000..f1352c6d
--- /dev/null
+++ b/src/Ryujinx/UI/Models/InputConfiguration.cs
@@ -0,0 +1,456 @@
+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/UI/Models/ModModel.cs b/src/Ryujinx/UI/Models/ModModel.cs
new file mode 100644
index 00000000..ee28ca5f
--- /dev/null
+++ b/src/Ryujinx/UI/Models/ModModel.cs
@@ -0,0 +1,32 @@
+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/UI/Models/PlayerModel.cs b/src/Ryujinx/UI/Models/PlayerModel.cs
new file mode 100644
index 00000000..a19852b9
--- /dev/null
+++ b/src/Ryujinx/UI/Models/PlayerModel.cs
@@ -0,0 +1,6 @@
+using Ryujinx.Common.Configuration.Hid;
+
+namespace Ryujinx.Ava.UI.Models
+{
+ public record PlayerModel(PlayerIndex Id, string Name);
+}
diff --git a/src/Ryujinx/UI/Models/ProfileImageModel.cs b/src/Ryujinx/UI/Models/ProfileImageModel.cs
new file mode 100644
index 00000000..99365dfc
--- /dev/null
+++ b/src/Ryujinx/UI/Models/ProfileImageModel.cs
@@ -0,0 +1,32 @@
+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/UI/Models/SaveModel.cs b/src/Ryujinx/UI/Models/SaveModel.cs
new file mode 100644
index 00000000..d6dea2f6
--- /dev/null
+++ b/src/Ryujinx/UI/Models/SaveModel.cs
@@ -0,0 +1,96 @@
+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/UI/Models/StatusUpdatedEventArgs.cs b/src/Ryujinx/UI/Models/StatusUpdatedEventArgs.cs
new file mode 100644
index 00000000..7f04c0ee
--- /dev/null
+++ b/src/Ryujinx/UI/Models/StatusUpdatedEventArgs.cs
@@ -0,0 +1,28 @@
+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/UI/Models/TempProfile.cs b/src/Ryujinx/UI/Models/TempProfile.cs
new file mode 100644
index 00000000..659092e6
--- /dev/null
+++ b/src/Ryujinx/UI/Models/TempProfile.cs
@@ -0,0 +1,61 @@
+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/UI/Models/TimeZone.cs b/src/Ryujinx/UI/Models/TimeZone.cs
new file mode 100644
index 00000000..950fbce4
--- /dev/null
+++ b/src/Ryujinx/UI/Models/TimeZone.cs
@@ -0,0 +1,16 @@
+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/UI/Models/TitleUpdateModel.cs b/src/Ryujinx/UI/Models/TitleUpdateModel.cs
new file mode 100644
index 00000000..c270c9ed
--- /dev/null
+++ b/src/Ryujinx/UI/Models/TitleUpdateModel.cs
@@ -0,0 +1,19 @@
+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/UI/Models/UserProfile.cs b/src/Ryujinx/UI/Models/UserProfile.cs
new file mode 100644
index 00000000..7a9237fe
--- /dev/null
+++ b/src/Ryujinx/UI/Models/UserProfile.cs
@@ -0,0 +1,104 @@
+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));
+ }
+ }
+}