diff --git a/src/Ryujinx/UI/ViewModels/Settings/SettingsSystemViewModel.cs b/src/Ryujinx/UI/ViewModels/Settings/SettingsSystemViewModel.cs new file mode 100644 index 0000000000..cf6778e2ba --- /dev/null +++ b/src/Ryujinx/UI/ViewModels/Settings/SettingsSystemViewModel.cs @@ -0,0 +1,226 @@ +using Avalonia.Collections; +using Avalonia.Threading; +using LibHac.Tools.FsSystem; +using Ryujinx.HLE.FileSystem; +using Ryujinx.HLE.HOS.Services.Time.TimeZone; +using Ryujinx.UI.Common.Configuration; +using Ryujinx.UI.Common.Configuration.System; +using System; +using System.Collections.Generic; +using System.Threading.Tasks; +using TimeZone = Ryujinx.Ava.UI.Models.TimeZone; + +namespace Ryujinx.Ava.UI.ViewModels.Settings +{ + public class SettingsSystemViewModel : BaseModel + { + public event Action DirtyEvent; + + private readonly List _validTzRegions = new(); + private readonly VirtualFileSystem _virtualFileSystem; + private readonly ContentManager _contentManager; + private TimeZoneContentManager _timeZoneContentManager; + + private int _region; + public int Region + { + get => _region; + set + { + _region = value; + DirtyEvent?.Invoke(); + } + } + + private int _language; + public int Language + { + get => _language; + set + { + _language = value; + DirtyEvent?.Invoke(); + } + } + + private string _timeZone; + public string TimeZone + { + get => _timeZone; + set + { + _timeZone = value; + OnPropertyChanged(); + DirtyEvent?.Invoke(); + } + } + + private DateTimeOffset _currentDate; + public DateTimeOffset CurrentDate + { + get => _currentDate; + set + { + _currentDate = value; + DirtyEvent?.Invoke(); + } + } + + private TimeSpan _currentTime; + public TimeSpan CurrentTime + { + get => _currentTime; + set + { + _currentTime = value; + DirtyEvent?.Invoke(); + } + } + + private bool _enableVsync; + public bool EnableVsync + { + get => _enableVsync; + set + { + _enableVsync = value; + DirtyEvent?.Invoke(); + } + } + + private bool _enableFsIntegrityChecks; + public bool EnableFsIntegrityChecks + { + get => _enableFsIntegrityChecks; + set + { + _enableFsIntegrityChecks = value; + DirtyEvent?.Invoke(); + } + } + + private bool _ignoreMissingServices; + public bool IgnoreMissingServices + { + get => _ignoreMissingServices; + set + { + _ignoreMissingServices = value; + DirtyEvent?.Invoke(); + } + } + + private bool _expandedDramSize; + public bool ExpandDramSize + { + get => _expandedDramSize; + set + { + _expandedDramSize = value; + DirtyEvent?.Invoke(); + } + } + + internal AvaloniaList TimeZones { get; set; } + + public SettingsSystemViewModel(VirtualFileSystem virtualFileSystem, ContentManager contentManager) + { + _virtualFileSystem = virtualFileSystem; + _contentManager = contentManager; + + ConfigurationState config = ConfigurationState.Instance; + + TimeZones = new(); + + if (Program.PreviewerDetached) + { + Task.Run(LoadTimeZones); + } + + Region = (int)config.System.Region.Value; + Language = (int)config.System.Language.Value; + TimeZone = config.System.TimeZone; + + DateTime currentDateTime = DateTime.Now; + + CurrentDate = currentDateTime.Date; + CurrentTime = currentDateTime.TimeOfDay.Add(TimeSpan.FromSeconds(config.System.SystemTimeOffset)); + + EnableVsync = config.Graphics.EnableVsync; + EnableFsIntegrityChecks = config.System.EnableFsIntegrityChecks; + ExpandDramSize = config.System.ExpandRam; + IgnoreMissingServices = config.System.IgnoreMissingServices; + } + + public async Task LoadTimeZones() + { + _timeZoneContentManager = new TimeZoneContentManager(); + + _timeZoneContentManager.InitializeInstance(_virtualFileSystem, _contentManager, IntegrityCheckLevel.None); + + foreach ((int offset, string location, string abbr) in _timeZoneContentManager.ParseTzOffsets()) + { + int hours = Math.DivRem(offset, 3600, out int seconds); + int minutes = Math.Abs(seconds) / 60; + + string abbr2 = abbr.StartsWith('+') || abbr.StartsWith('-') ? string.Empty : abbr; + + await Dispatcher.UIThread.InvokeAsync(() => + { + TimeZones.Add(new TimeZone($"UTC{hours:+0#;-0#;+00}:{minutes:D2}", location, abbr2)); + + _validTzRegions.Add(location); + }); + } + } + + public void ValidateAndSetTimeZone(string location) + { + if (_validTzRegions.Contains(location)) + { + TimeZone = location; + } + } + + + public bool CheckIfModified(ConfigurationState config) + { + bool isDirty = false; + + isDirty |= config.System.Region.Value != (Region)Region; + isDirty |= config.System.Language.Value != (Language)Language; + + if (_validTzRegions.Contains(TimeZone)) + { + isDirty |= config.System.TimeZone.Value != TimeZone; + } + + // SystemTimeOffset will always have changed, so we don't check it here + + isDirty |= config.Graphics.EnableVsync.Value != EnableVsync; + isDirty |= config.System.EnableFsIntegrityChecks.Value != EnableFsIntegrityChecks; + isDirty |= config.System.ExpandRam.Value != ExpandDramSize; + isDirty |= config.System.IgnoreMissingServices.Value != IgnoreMissingServices; + + return isDirty; + } + + public void Save(ConfigurationState config) + { + config.System.Region.Value = (Region)Region; + config.System.Language.Value = (Language)Language; + + if (_validTzRegions.Contains(TimeZone)) + { + config.System.TimeZone.Value = TimeZone; + } + + config.System.SystemTimeOffset.Value = Convert.ToInt64((CurrentDate.ToUnixTimeSeconds() + CurrentTime.TotalSeconds) - DateTimeOffset.Now.ToUnixTimeSeconds()); + + config.Graphics.EnableVsync.Value = EnableVsync; + config.System.EnableFsIntegrityChecks.Value = EnableFsIntegrityChecks; + config.System.ExpandRam.Value = ExpandDramSize; + config.System.IgnoreMissingServices.Value = IgnoreMissingServices; + } + } +} diff --git a/src/Ryujinx/UI/ViewModels/Settings/SettingsViewModel.cs b/src/Ryujinx/UI/ViewModels/Settings/SettingsViewModel.cs index 111d3c084c..fe54e8fdda 100644 --- a/src/Ryujinx/UI/ViewModels/Settings/SettingsViewModel.cs +++ b/src/Ryujinx/UI/ViewModels/Settings/SettingsViewModel.cs @@ -1,33 +1,16 @@ using Avalonia.Collections; -using Avalonia.Threading; -using LibHac.Tools.FsSystem; -using Ryujinx.Ava.Common.Locale; using Ryujinx.Ava.UI.Windows; using Ryujinx.Common.Configuration; -using Ryujinx.Common.Configuration.Multiplayer; -using Ryujinx.HLE.FileSystem; -using Ryujinx.HLE.HOS.Services.Time.TimeZone; using Ryujinx.UI.Common.Configuration; -using Ryujinx.UI.Common.Configuration.System; using System; using System.Collections.Generic; -using System.Linq; -using System.Net.NetworkInformation; -using System.Threading.Tasks; -using TimeZone = Ryujinx.Ava.UI.Models.TimeZone; namespace Ryujinx.Ava.UI.ViewModels.Settings { public class SettingsViewModel : BaseModel { - private readonly VirtualFileSystem _virtualFileSystem; - private readonly ContentManager _contentManager; - private TimeZoneContentManager _timeZoneContentManager; - - private readonly List _validTzRegions; private bool _directoryChanged; - private bool _isModified; public bool IsModified @@ -101,53 +84,6 @@ namespace Ryujinx.Ava.UI.ViewModels.Settings } } - private bool _enableVsync; - public bool EnableVsync - { - get => _enableVsync; - set - { - _enableVsync = value; - CheckIfModified(); - } - } - - private bool _enableFsIntegrityChecks; - public bool EnableFsIntegrityChecks - { - get => _enableFsIntegrityChecks; - set - { - _enableFsIntegrityChecks = value; - CheckIfModified(); - } - } - - private bool _ignoreMissingServices; - public bool IgnoreMissingServices - { - get => _ignoreMissingServices; - set - { - _ignoreMissingServices = value; - CheckIfModified(); - } - } - - private bool _expandedDramSize; - public bool ExpandDramSize - { - get => _expandedDramSize; - set - { - _expandedDramSize = value; - CheckIfModified(); - } - } - - public string TimeZone { get; set; } - public int Language { get; set; } - public int Region { get; set; } public int BaseStyleIndex { get; set; } private readonly SettingsAudioViewModel _audioViewModel; @@ -157,27 +93,20 @@ namespace Ryujinx.Ava.UI.ViewModels.Settings private readonly SettingsInputViewModel _inputViewModel; private readonly SettingsLoggingViewModel _loggingViewModel; private readonly SettingsNetworkViewModel _networkViewModel; + private readonly SettingsSystemViewModel _systemViewModel; - public DateTimeOffset CurrentDate { get; set; } - public TimeSpan CurrentTime { get; set; } - - internal AvaloniaList TimeZones { get; set; } public AvaloniaList GameDirectories { get; set; } public SettingsViewModel( - VirtualFileSystem virtualFileSystem, - ContentManager contentManager, SettingsAudioViewModel audioViewModel, SettingsCpuViewModel cpuViewModel, SettingsGraphicsViewModel graphicsViewModel, SettingsHotkeysViewModel hotkeysViewModel, SettingsInputViewModel inputViewModel, SettingsLoggingViewModel loggingViewModel, - SettingsNetworkViewModel networkViewModel) : this() + SettingsNetworkViewModel networkViewModel, + SettingsSystemViewModel systemViewModel) : this() { - _virtualFileSystem = virtualFileSystem; - _contentManager = contentManager; - _audioViewModel = audioViewModel; _cpuViewModel = cpuViewModel; _graphicsViewModel = graphicsViewModel; @@ -185,6 +114,7 @@ namespace Ryujinx.Ava.UI.ViewModels.Settings _inputViewModel = inputViewModel; _loggingViewModel = loggingViewModel; _networkViewModel = networkViewModel; + _systemViewModel = systemViewModel; _audioViewModel.DirtyEvent += CheckIfModified; _cpuViewModel.DirtyEvent += CheckIfModified; @@ -193,18 +123,12 @@ namespace Ryujinx.Ava.UI.ViewModels.Settings _inputViewModel.DirtyEvent += CheckIfModified; _loggingViewModel.DirtyEvent += CheckIfModified; _networkViewModel.DirtyEvent += CheckIfModified; - - if (Program.PreviewerDetached) - { - Task.Run(LoadTimeZones); - } + _systemViewModel.DirtyEvent += CheckIfModified; } public SettingsViewModel() { GameDirectories = new AvaloniaList(); - TimeZones = new AvaloniaList(); - _validTzRegions = new List(); if (Program.PreviewerDetached) { @@ -227,24 +151,6 @@ namespace Ryujinx.Ava.UI.ViewModels.Settings isDirty |= config.UI.BaseStyle.Value != (BaseStyleIndex == 0 ? "Light" : "Dark"); - // Keyboard Hotkeys - // isDirty |= config.Hid.Hotkeys.Value != KeyboardHotkey.GetConfig(); - - // System - isDirty |= config.System.Region.Value != (Region)Region; - isDirty |= config.System.Language.Value != (Language)Language; - - if (_validTzRegions.Contains(TimeZone)) - { - isDirty |= config.System.TimeZone.Value != TimeZone; - } - - // isDirty |= config.System.SystemTimeOffset.Value != Convert.ToInt64((CurrentDate.ToUnixTimeSeconds() + CurrentTime.TotalSeconds) - DateTimeOffset.Now.ToUnixTimeSeconds()); - isDirty |= config.Graphics.EnableVsync.Value != EnableVsync; - isDirty |= config.System.EnableFsIntegrityChecks.Value != EnableFsIntegrityChecks; - isDirty |= config.System.ExpandRam.Value != ExpandDramSize; - isDirty |= config.System.IgnoreMissingServices.Value != IgnoreMissingServices; - isDirty |= _audioViewModel?.CheckIfModified(config) ?? false; isDirty |= _cpuViewModel?.CheckIfModified(config) ?? false; isDirty |= _graphicsViewModel?.CheckIfModified(config) ?? false; @@ -253,42 +159,11 @@ namespace Ryujinx.Ava.UI.ViewModels.Settings // isDirty |= _inputViewModel?.CheckIfModified(config) ?? false; isDirty |= _loggingViewModel?.CheckIfModified(config) ?? false; isDirty |= _networkViewModel?.CheckIfModified(config) ?? false; + isDirty |= _systemViewModel?.CheckIfModified(config) ?? false; IsModified = isDirty; } - public async Task LoadTimeZones() - { - _timeZoneContentManager = new TimeZoneContentManager(); - - _timeZoneContentManager.InitializeInstance(_virtualFileSystem, _contentManager, IntegrityCheckLevel.None); - - foreach ((int offset, string location, string abbr) in _timeZoneContentManager.ParseTzOffsets()) - { - int hours = Math.DivRem(offset, 3600, out int seconds); - int minutes = Math.Abs(seconds) / 60; - - string abbr2 = abbr.StartsWith('+') || abbr.StartsWith('-') ? string.Empty : abbr; - - await Dispatcher.UIThread.InvokeAsync(() => - { - TimeZones.Add(new TimeZone($"UTC{hours:+0#;-0#;+00}:{minutes:D2}", location, abbr2)); - - _validTzRegions.Add(location); - }); - } - - Dispatcher.UIThread.Post(() => OnPropertyChanged(nameof(TimeZone))); - } - - public void ValidateAndSetTimeZone(string location) - { - if (_validTzRegions.Contains(location)) - { - TimeZone = location; - } - } - public void LoadCurrentConfiguration() { ConfigurationState config = ConfigurationState.Instance; @@ -303,21 +178,6 @@ namespace Ryujinx.Ava.UI.ViewModels.Settings GameDirectories.AddRange(config.UI.GameDirs.Value); BaseStyleIndex = config.UI.BaseStyle == "Light" ? 0 : 1; - - // System - Region = (int)config.System.Region.Value; - Language = (int)config.System.Language.Value; - TimeZone = config.System.TimeZone; - - DateTime currentDateTime = DateTime.Now; - - CurrentDate = currentDateTime.Date; - CurrentTime = currentDateTime.TimeOfDay.Add(TimeSpan.FromSeconds(config.System.SystemTimeOffset)); - - EnableVsync = config.Graphics.EnableVsync; - EnableFsIntegrityChecks = config.System.EnableFsIntegrityChecks; - ExpandDramSize = config.System.ExpandRam; - IgnoreMissingServices = config.System.IgnoreMissingServices; } public void SaveSettings() @@ -338,22 +198,6 @@ namespace Ryujinx.Ava.UI.ViewModels.Settings config.UI.BaseStyle.Value = BaseStyleIndex == 0 ? "Light" : "Dark"; - - // System - config.System.Region.Value = (Region)Region; - config.System.Language.Value = (Language)Language; - - if (_validTzRegions.Contains(TimeZone)) - { - config.System.TimeZone.Value = TimeZone; - } - - config.System.SystemTimeOffset.Value = Convert.ToInt64((CurrentDate.ToUnixTimeSeconds() + CurrentTime.TotalSeconds) - DateTimeOffset.Now.ToUnixTimeSeconds()); - config.Graphics.EnableVsync.Value = EnableVsync; - config.System.EnableFsIntegrityChecks.Value = EnableFsIntegrityChecks; - config.System.ExpandRam.Value = ExpandDramSize; - config.System.IgnoreMissingServices.Value = IgnoreMissingServices; - _audioViewModel?.Save(config); _cpuViewModel?.Save(config); _graphicsViewModel?.Save(config); @@ -361,6 +205,7 @@ namespace Ryujinx.Ava.UI.ViewModels.Settings _inputViewModel?.Save(config); _loggingViewModel?.Save(config); _networkViewModel?.Save(config); + _systemViewModel?.Save(config); config.ToFileFormat().SaveConfig(Program.ConfigurationPath); diff --git a/src/Ryujinx/UI/Views/Settings/SettingsSystemView.axaml b/src/Ryujinx/UI/Views/Settings/SettingsSystemView.axaml index 65a1b99e71..9053e72bad 100644 --- a/src/Ryujinx/UI/Views/Settings/SettingsSystemView.axaml +++ b/src/Ryujinx/UI/Views/Settings/SettingsSystemView.axaml @@ -8,12 +8,12 @@ xmlns:viewModels="clr-namespace:Ryujinx.Ava.UI.ViewModels.Settings" xmlns:helpers="clr-namespace:Ryujinx.Ava.UI.Helpers" mc:Ignorable="d" - x:DataType="viewModels:SettingsViewModel"> + x:DataType="viewModels:SettingsSystemViewModel"> - +