Files
SpdUp/ViewModels/MainViewModel.cs
T
Phil-icyou 19ba425e79 Initial commit: SpdUp Windows Gaming Booster v1.0.0
- .NET 8 WPF app with full MVVM architecture
- One-click boost: CPU, RAM, GPU, network, services, timer resolution
- Real-time system monitor (LibreHardwareMonitor)
- Auto game detection (30+ games)
- RAM optimizer with kernel-level cleanup
- Network optimizer (TCP registry tweaks)
- Service manager, process manager, shader cache cleaner
- Desktop widget overlay
- Debug log viewer
- Custom dark gaming theme with trans pride colors
- 84 unit tests (xUnit)
- Inno Setup installer script
- Landing page website
2026-03-08 17:34:45 +01:00

265 lines
11 KiB
C#
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.Windows;
using System.Windows.Input;
using System.Windows.Threading;
using SpdUp.Core;
using SpdUp.Models;
using SpdUp.Services;
namespace SpdUp.ViewModels;
/// <summary>
/// Root ViewModel drives the main window, navigation, boost, and monitoring.
/// </summary>
public sealed class MainViewModel : ObservableObject, IDisposable
{
// ── Services ───────────────────────────────────────────────────────
private readonly AppSettings _settings;
private readonly OptimizationService _optimizationService;
private readonly GameDetectionService _gameDetectionService;
private readonly MonitoringService _monitoringService;
private readonly NetworkService _networkService = new();
private readonly Dispatcher _dispatcher;
// ── Sub-ViewModels ─────────────────────────────────────────────────
public DashboardViewModel Dashboard { get; }
public BoostViewModel Boost { get; }
public MonitorViewModel Monitor { get; }
public GameLibraryViewModel GameLibrary { get; }
public ProcessManagerViewModel ProcessManager { get; }
public ServiceManagerViewModel ServiceManager { get; }
public SettingsViewModel Settings { get; }
public DebugLogViewModel DebugLog { get; }
// ── Navigation ─────────────────────────────────────────────────────
private object _currentPage;
public object CurrentPage
{
get => _currentPage;
set => SetProperty(ref _currentPage, value);
}
private string _currentPageTitle = "Dashboard";
public string CurrentPageTitle
{
get => _currentPageTitle;
set => SetProperty(ref _currentPageTitle, value);
}
// ── Status ─────────────────────────────────────────────────────────
private string _statusText = "Ready";
public string StatusText
{
get => _statusText;
set => SetProperty(ref _statusText, value);
}
private bool _isBoosted;
public bool IsBoosted
{
get => _isBoosted;
set => SetProperty(ref _isBoosted, value);
}
// ── Live Metrics (bound by views & widget) ─────────────────────────
private float _cpuUsage;
public float CpuUsage { get => _cpuUsage; set => SetProperty(ref _cpuUsage, value); }
private float _ramUsagePercent;
public float RamUsagePercent { get => _ramUsagePercent; set => SetProperty(ref _ramUsagePercent, value); }
private float _ramUsedMB;
public float RamUsedMB { get => _ramUsedMB; set => SetProperty(ref _ramUsedMB, value); }
private float _ramTotalMB;
public float RamTotalMB { get => _ramTotalMB; set => SetProperty(ref _ramTotalMB, value); }
private float _gpuUsage;
public float GpuUsage { get => _gpuUsage; set => SetProperty(ref _gpuUsage, value); }
private float _cpuTemp;
public float CpuTemp { get => _cpuTemp; set => SetProperty(ref _cpuTemp, value); }
private float _gpuTemp;
public float GpuTemp { get => _gpuTemp; set => SetProperty(ref _gpuTemp, value); }
private float _pingMs;
public float PingMs { get => _pingMs; set => SetProperty(ref _pingMs, value); }
// ── Commands ───────────────────────────────────────────────────────
public ICommand NavigateCommand { get; }
public ICommand BoostCommand { get; }
public ICommand ToggleWidgetCommand { get; }
public ICommand CleanRamCommand { get; }
public ICommand CleanShaderCacheCommand { get; }
// ── Widget ─────────────────────────────────────────────────────────
private bool _isWidgetVisible;
public bool IsWidgetVisible
{
get => _isWidgetVisible;
set
{
if (SetProperty(ref _isWidgetVisible, value))
_settings.ShowWidget = value;
}
}
public MainViewModel()
{
_dispatcher = Dispatcher.CurrentDispatcher;
_settings = AppSettings.Load();
// Initialise services
_optimizationService = new OptimizationService(_settings);
_gameDetectionService = new GameDetectionService(_settings);
_monitoringService = new MonitoringService(_settings.PingTarget);
// Sub-ViewModels
Dashboard = new DashboardViewModel(this);
Boost = new BoostViewModel(this, _optimizationService);
Monitor = new MonitorViewModel(this);
GameLibrary = new GameLibraryViewModel(_settings, _gameDetectionService);
ProcessManager = new ProcessManagerViewModel();
ServiceManager = new ServiceManagerViewModel(_settings);
Settings = new SettingsViewModel(_settings, this);
DebugLog = new DebugLogViewModel();
_currentPage = Dashboard;
// Commands
NavigateCommand = new RelayCommand<string>(Navigate);
BoostCommand = new RelayCommand(async () => await ToggleBoostAsync());
ToggleWidgetCommand = new RelayCommand(() => IsWidgetVisible = !IsWidgetVisible);
CleanRamCommand = new RelayCommand(async () => await CleanRamAsync());
CleanShaderCacheCommand = new RelayCommand(async () => await CleanShaderCacheAsync());
// Wire up monitoring
_monitoringService.MetricsUpdated += OnMetricsUpdated;
_monitoringService.Start(_settings.MonitoringIntervalMs);
// Wire up game detection
_gameDetectionService.GameStarted += OnGameStarted;
_gameDetectionService.GameStopped += OnGameStopped;
if (_settings.AutoDetectGames)
_gameDetectionService.Start();
// Widget state
_isWidgetVisible = _settings.ShowWidget;
Logger.PurgeOldLogs();
Logger.Info("Application started.");
}
// ── Navigation ─────────────────────────────────────────────────────
private void Navigate(string? pageName)
{
(CurrentPage, CurrentPageTitle) = pageName switch
{
"Dashboard" => ((object)Dashboard, "Dashboard"),
"Boost" => (Boost, "Game Boost"),
"Monitor" => (Monitor, "System Monitor"),
"Games" => (GameLibrary, "Game Library"),
"Processes" => (ProcessManager, "Process Manager"),
"Services" => (ServiceManager, "Service Manager"),
"Settings" => (Settings, "Settings"),
"Debug" => (DebugLog, "Debug Log"),
_ => (Dashboard, "Dashboard")
};
}
// ── Boost Toggle ───────────────────────────────────────────────────
private async Task ToggleBoostAsync()
{
if (_optimizationService.IsBoosted)
{
StatusText = "Deactivating boost...";
await _optimizationService.DeactivateBoostAsync();
IsBoosted = false;
StatusText = "Boost deactivated settings restored.";
}
else
{
StatusText = "Activating boost...";
var gameProcess = _gameDetectionService.CurrentGameProcess;
var result = await _optimizationService.ActivateBoostAsync(gameProcess);
IsBoosted = result.Success;
StatusText = result.Success ? "🚀 Boost Active" : result.Message;
}
}
// ── Quick Actions ──────────────────────────────────────────────────
private async Task CleanRamAsync()
{
StatusText = "Cleaning RAM...";
var result = await Task.Run(() => new RamOptimizationService().FullCleanup());
StatusText = $"RAM cleaned: {result.TrimmedCount} processes trimmed.";
}
private async Task CleanShaderCacheAsync()
{
StatusText = "Cleaning shader caches...";
var result = await Task.Run(() => ShaderCacheCleanerService.CleanAll());
StatusText = $"Shader cache: {result.FilesDeleted} files, {result.MBFreed:F1} MB freed.";
}
// ── Monitoring Callback ────────────────────────────────────────────
private void OnMetricsUpdated(SystemMetrics m)
{
_dispatcher.BeginInvoke(() =>
{
CpuUsage = m.CpuUsage;
RamUsagePercent = m.RamUsagePercent;
RamUsedMB = m.RamUsageMB;
RamTotalMB = m.RamTotalMB;
GpuUsage = m.GpuUsage;
CpuTemp = m.CpuTemperature;
GpuTemp = m.GpuTemperature;
PingMs = m.NetworkPingMs;
});
}
// ── Game Detection Callbacks ───────────────────────────────────────
#pragma warning disable CS4014 // Fire-and-forget is intentional for event handlers
private async void OnGameStarted(string processName)
{
_dispatcher.BeginInvoke(() => StatusText = $"Game detected: {processName}");
if (_settings.AutoBoostOnGameLaunch && !_optimizationService.IsBoosted)
{
var result = await _optimizationService.ActivateBoostAsync(processName);
_dispatcher.BeginInvoke(() =>
{
IsBoosted = result.Success;
StatusText = result.Success ? $"🚀 Auto-Boost for {processName}" : result.Message;
});
}
}
private async void OnGameStopped(string processName)
{
if (_optimizationService.IsBoosted)
{
await _optimizationService.DeactivateBoostAsync();
_dispatcher.BeginInvoke(() =>
{
IsBoosted = false;
StatusText = $"Game exited: {processName} boost deactivated.";
});
}
}
#pragma warning restore CS4014
public void SaveSettings() => _settings.Save();
public void Dispose()
{
_monitoringService.MetricsUpdated -= OnMetricsUpdated;
_monitoringService.Dispose();
_gameDetectionService.Dispose();
_settings.Save();
Logger.Info("Application closed.");
}
}