Migrate System to SettingsSystemViewModel

This commit is contained in:
Isaac Marovitz 2024-04-19 17:05:07 -04:00
parent 65ec957c4c
commit 9b6241985f
No known key found for this signature in database
GPG key ID: 97250B2B09A132E1
5 changed files with 244 additions and 173 deletions

View file

@ -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<string> _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<TimeZone> 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;
}
}
}

View file

@ -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<string> _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<TimeZone> TimeZones { get; set; }
public AvaloniaList<string> 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<string>();
TimeZones = new AvaloniaList<TimeZone>();
_validTzRegions = new List<string>();
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);

View file

@ -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">
<UserControl.Resources>
<helpers:TimeZoneConverter x:Key="TimeZone" />
</UserControl.Resources>
<Design.DataContext>
<viewModels:SettingsViewModel />
<viewModels:SettingsSystemViewModel />
</Design.DataContext>
<ScrollViewer
Name="SystemPage"

View file

@ -1,16 +1,17 @@
using Avalonia.Controls;
using Ryujinx.Ava.UI.ViewModels.Settings;
using Ryujinx.HLE.FileSystem;
using TimeZone = Ryujinx.Ava.UI.Models.TimeZone;
namespace Ryujinx.Ava.UI.Views.Settings
{
public partial class SettingsSystemView : UserControl
{
private readonly SettingsViewModel _viewModel;
public SettingsSystemViewModel ViewModel;
public SettingsSystemView(SettingsViewModel viewModel)
public SettingsSystemView(VirtualFileSystem virtualFileSystem, ContentManager contentManager)
{
_viewModel = viewModel;
DataContext = ViewModel = new SettingsSystemViewModel(virtualFileSystem, contentManager);
InitializeComponent();
}
@ -22,7 +23,7 @@ namespace Ryujinx.Ava.UI.Views.Settings
{
e.Handled = true;
_viewModel.ValidateAndSetTimeZone(timeZone.Location);
ViewModel.ValidateAndSetTimeZone(timeZone.Location);
}
}
}
@ -31,7 +32,7 @@ namespace Ryujinx.Ava.UI.Views.Settings
{
if (sender is AutoCompleteBox box && box.SelectedItem is TimeZone timeZone)
{
_viewModel.ValidateAndSetTimeZone(timeZone.Location);
ViewModel.ValidateAndSetTimeZone(timeZone.Location);
}
}
}

View file

@ -36,20 +36,19 @@ namespace Ryujinx.Ava.UI.Windows
InputPage = new SettingsInputView();
LoggingPage = new SettingsLoggingView();
NetworkPage = new SettingsNetworkView();
SystemPage = new SettingsSystemView(virtualFileSystem, contentManager);
ViewModel = new SettingsViewModel(
virtualFileSystem,
contentManager,
AudioPage.ViewModel,
CpuPage.ViewModel,
GraphicsPage.ViewModel,
HotkeysPage.ViewModel,
InputPage.ViewModel,
LoggingPage.ViewModel,
NetworkPage.ViewModel);
NetworkPage.ViewModel,
SystemPage.ViewModel);
UiPage = new SettingsUiView(ViewModel);
SystemPage = new SettingsSystemView(ViewModel);
DataContext = ViewModel;