using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Linq; using System.Reactive; using System.Reactive.Disposables; using System.Threading; using System.Threading.Tasks; using Artemis.Core; using Artemis.Core.LayerBrushes; using Artemis.Core.Providers; using Artemis.Core.Services; using Artemis.UI.Screens.StartupWizard; using Artemis.UI.Services.Interfaces; using Artemis.UI.Services.Updating; using Artemis.UI.Shared.Providers; using Artemis.UI.Shared.Routing; using Artemis.UI.Shared.Services; using Artemis.UI.Shared.Services.Builders; using Avalonia.Threading; using DryIoc; using DynamicData; using FluentAvalonia.Interop; using ReactiveUI; using Serilog.Events; namespace Artemis.UI.Screens.Settings; public class GeneralTabViewModel : RoutableScreen { private readonly IAutoRunProvider? _autoRunProvider; private readonly IProtocolProvider? _protocolProvider; private readonly IDebugService _debugService; private readonly PluginSetting _defaultLayerBrushDescriptor; private readonly INotificationService _notificationService; private readonly ISettingsService _settingsService; private readonly IUpdateService _updateService; private readonly IWindowService _windowService; private bool _startupWizardOpen; public GeneralTabViewModel(IContainer container, ISettingsService settingsService, IPluginManagementService pluginManagementService, IDebugService debugService, IWindowService windowService, IUpdateService updateService, INotificationService notificationService) { DisplayName = "General"; _settingsService = settingsService; _debugService = debugService; _windowService = windowService; _updateService = updateService; _notificationService = notificationService; _autoRunProvider = container.Resolve(IfUnresolved.ReturnDefault); _protocolProvider = container.Resolve(IfUnresolved.ReturnDefault); List layerBrushProviders = pluginManagementService.GetFeaturesOfType(); List graphicsContextProviders = container.Resolve>(); LayerBrushDescriptors = new ObservableCollection(layerBrushProviders.SelectMany(l => l.LayerBrushDescriptors)); GraphicsContexts = new ObservableCollection {"Software"}; GraphicsContexts.AddRange(graphicsContextProviders.Select(p => p.GraphicsContextName)); _defaultLayerBrushDescriptor = _settingsService.GetSetting("ProfileEditor.DefaultLayerBrushDescriptor", new LayerBrushReference { LayerBrushProviderId = "Artemis.Plugins.LayerBrushes.Color.ColorBrushProvider-92a9d6ba", BrushType = "SolidBrush" }); ShowLogs = ReactiveCommand.Create(ExecuteShowLogs); CheckForUpdate = ReactiveCommand.CreateFromTask(ExecuteCheckForUpdate); ShowSetupWizard = ReactiveCommand.CreateFromTask(ExecuteShowSetupWizard); ShowDebugger = ReactiveCommand.Create(ExecuteShowDebugger); ShowDataFolder = ReactiveCommand.Create(ExecuteShowDataFolder); this.WhenActivated(d => { UIAutoRun.SettingChanged += UIAutoRunOnSettingChanged; UIUseProtocol.SettingChanged += UIUseProtocolOnSettingChanged; UIAutoRunDelay.SettingChanged += UIAutoRunDelayOnSettingChanged; EnableMica.SettingChanged += EnableMicaOnSettingChanged; Dispatcher.UIThread.InvokeAsync(ApplyAutoRun); Dispatcher.UIThread.Invoke(ApplyProtocolAssociation); Disposable.Create(() => { UIAutoRun.SettingChanged -= UIAutoRunOnSettingChanged; UIUseProtocol.SettingChanged -= UIUseProtocolOnSettingChanged; UIAutoRunDelay.SettingChanged -= UIAutoRunDelayOnSettingChanged; EnableMica.SettingChanged -= EnableMicaOnSettingChanged; _settingsService.SaveAllSettings(); }).DisposeWith(d); }); } public ReactiveCommand ShowLogs { get; } public ReactiveCommand CheckForUpdate { get; } public ReactiveCommand ShowSetupWizard { get; } public ReactiveCommand ShowDebugger { get; } public ReactiveCommand ShowDataFolder { get; } public bool IsAutoRunSupported => _autoRunProvider != null; public bool IsWindows11 => OSVersionHelper.IsWindows11(); public ObservableCollection LayerBrushDescriptors { get; } public ObservableCollection GraphicsContexts { get; } public ObservableCollection RenderScales { get; } = new() { new RenderSettingViewModel("25%", 0.25), new RenderSettingViewModel("50%", 0.5), new RenderSettingViewModel("100%", 1) }; public ObservableCollection TargetFrameRates { get; } = new() { new RenderSettingViewModel("10 FPS", 10), new RenderSettingViewModel("20 FPS", 20), new RenderSettingViewModel("30 FPS", 30), new RenderSettingViewModel("45 FPS", 45), new RenderSettingViewModel("60 FPS (lol)", 60), new RenderSettingViewModel("144 FPS (omegalol)", 144) }; public LayerBrushDescriptor? SelectedLayerBrushDescriptor { get => LayerBrushDescriptors.FirstOrDefault(d => d.MatchesLayerBrushReference(_defaultLayerBrushDescriptor.Value)); set { if (value != null) _defaultLayerBrushDescriptor.Value = new LayerBrushReference(value); } } public RenderSettingViewModel? SelectedRenderScale { get => RenderScales.FirstOrDefault(s => Math.Abs(s.Value - CoreRenderScale.Value) < 0.01); set { if (value != null) CoreRenderScale.Value = value.Value; } } public RenderSettingViewModel? SelectedTargetFrameRate { get => TargetFrameRates.FirstOrDefault(s => Math.Abs(s.Value - CoreTargetFrameRate.Value) < 0.01); set { if (value != null) CoreTargetFrameRate.Value = (int) value.Value; } } public PluginSetting UIAutoRun => _settingsService.GetSetting("UI.AutoRun", false); public PluginSetting UIUseProtocol => _settingsService.GetSetting("UI.UseProtocol", true); public PluginSetting UIAutoRunDelay => _settingsService.GetSetting("UI.AutoRunDelay", 15); public PluginSetting UIShowOnStartup => _settingsService.GetSetting("UI.ShowOnStartup", true); public PluginSetting EnableMica => _settingsService.GetSetting("UI.EnableMica", true); public PluginSetting UICheckForUpdates => _settingsService.GetSetting("UI.Updating.AutoCheck", true); public PluginSetting UIAutoUpdate => _settingsService.GetSetting("UI.Updating.AutoInstall", true); public PluginSetting ProfileEditorShowDataModelValues => _settingsService.GetSetting("ProfileEditor.ShowDataModelValues", false); public PluginSetting CoreLoggingLevel => _settingsService.GetSetting("Core.LoggingLevel", LogEventLevel.Information); public PluginSetting CorePreferredGraphicsContext => _settingsService.GetSetting("Core.PreferredGraphicsContext", "Software"); public PluginSetting CoreRenderScale => _settingsService.GetSetting("Core.RenderScale", 0.25); public PluginSetting CoreTargetFrameRate => _settingsService.GetSetting("Core.TargetFrameRate", 30); public PluginSetting WebServerEnabled => _settingsService.GetSetting("WebServer.Enabled", true); public PluginSetting WebServerPort => _settingsService.GetSetting("WebServer.Port", 9696); private void ExecuteShowLogs() { Utilities.OpenFolder(Constants.LogsFolder); } private async Task ExecuteCheckForUpdate(CancellationToken cancellationToken) { try { // If an update was available a popup was shown, no need to continue if (await _updateService.CheckForUpdate()) return; _notificationService.CreateNotification() .WithTitle("No update available") .WithMessage("You are running the latest version in your current channel") .Show(); } catch (Exception e) { _notificationService.CreateNotification() .WithTitle("Failed to check for update") .WithMessage(e.Message) .WithSeverity(NotificationSeverity.Warning) .Show(); } } private async Task ExecuteShowSetupWizard() { _startupWizardOpen = true; await _windowService.ShowDialogAsync(); _startupWizardOpen = false; } private void ExecuteShowDebugger() { _debugService.ShowDebugger(); } private void ExecuteShowDataFolder() { Utilities.OpenFolder(Constants.DataFolder); } private async Task ApplyAutoRun() { if (_autoRunProvider == null || _startupWizardOpen) return; try { if (UIAutoRun.Value) await _autoRunProvider.EnableAutoRun(false, UIAutoRunDelay.Value); else await _autoRunProvider.DisableAutoRun(); } catch (Exception exception) { _windowService.ShowExceptionDialog("Failed to apply auto-run", exception); } } private void ApplyProtocolAssociation() { if (_protocolProvider == null) return; try { if (UIUseProtocol.Value) _protocolProvider.AssociateWithProtocol("artemis"); else _protocolProvider.DisassociateWithProtocol("artemis"); } catch (Exception exception) { _windowService.ShowExceptionDialog("Failed to apply protocol association", exception); } } private async void UIAutoRunOnSettingChanged(object? sender, EventArgs e) { await ApplyAutoRun(); } private void UIUseProtocolOnSettingChanged(object? sender, EventArgs e) { ApplyProtocolAssociation(); } private async void UIAutoRunDelayOnSettingChanged(object? sender, EventArgs e) { if (_autoRunProvider == null || !UIAutoRun.Value || _startupWizardOpen) return; try { await _autoRunProvider.EnableAutoRun(true, UIAutoRunDelay.Value); } catch (Exception exception) { _windowService.ShowExceptionDialog("Failed to apply auto-run", exception); } } private void EnableMicaOnSettingChanged(object? sender, EventArgs e) { Shared.UI.SetMicaEnabled(EnableMica.Value); } }