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;
///
/// Root ViewModel – drives the main window, navigation, boost, and monitoring.
///
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(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.");
}
}