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
This commit is contained in:
@@ -0,0 +1,46 @@
|
||||
using System.Windows.Input;
|
||||
using SpdUp.Core;
|
||||
using SpdUp.Services;
|
||||
|
||||
namespace SpdUp.ViewModels;
|
||||
|
||||
/// <summary>
|
||||
/// Boost page ViewModel.
|
||||
/// </summary>
|
||||
public sealed class BoostViewModel : ObservableObject
|
||||
{
|
||||
private readonly MainViewModel _main;
|
||||
private readonly OptimizationService _optimizationService;
|
||||
|
||||
private string _boostLog = string.Empty;
|
||||
public string BoostLog
|
||||
{
|
||||
get => _boostLog;
|
||||
set => SetProperty(ref _boostLog, value);
|
||||
}
|
||||
|
||||
public MainViewModel Main => _main;
|
||||
|
||||
public ICommand BoostCommand { get; }
|
||||
public ICommand CleanRamCommand { get; }
|
||||
public ICommand CleanShadersCommand { get; }
|
||||
|
||||
public BoostViewModel(MainViewModel main, OptimizationService optimizationService)
|
||||
{
|
||||
_main = main;
|
||||
_optimizationService = optimizationService;
|
||||
|
||||
BoostCommand = _main.BoostCommand;
|
||||
CleanRamCommand = _main.CleanRamCommand;
|
||||
CleanShadersCommand = _main.CleanShaderCacheCommand;
|
||||
|
||||
_optimizationService.BoostActivated += msg =>
|
||||
{
|
||||
BoostLog = $"[{DateTime.Now:HH:mm:ss}] BOOST ON\n{msg}\n\n{BoostLog}";
|
||||
};
|
||||
_optimizationService.BoostDeactivated += () =>
|
||||
{
|
||||
BoostLog = $"[{DateTime.Now:HH:mm:ss}] BOOST OFF – Restored.\n\n{BoostLog}";
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
using SpdUp.Core;
|
||||
|
||||
namespace SpdUp.ViewModels;
|
||||
|
||||
/// <summary>
|
||||
/// Dashboard page – just binds to MainViewModel's live metrics.
|
||||
/// </summary>
|
||||
public sealed class DashboardViewModel : ObservableObject
|
||||
{
|
||||
public MainViewModel Main { get; }
|
||||
|
||||
public DashboardViewModel(MainViewModel main)
|
||||
{
|
||||
Main = main;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Threading;
|
||||
using SpdUp.Core;
|
||||
|
||||
namespace SpdUp.ViewModels;
|
||||
|
||||
/// <summary>
|
||||
/// Debug Log page – live scrolling log of every action the application performs.
|
||||
/// </summary>
|
||||
public sealed class DebugLogViewModel : ObservableObject
|
||||
{
|
||||
private const int MaxLines = 2000;
|
||||
private readonly Dispatcher _dispatcher;
|
||||
|
||||
public ObservableCollection<string> LogLines { get; } = new();
|
||||
|
||||
private string _filterText = string.Empty;
|
||||
public string FilterText
|
||||
{
|
||||
get => _filterText;
|
||||
set
|
||||
{
|
||||
if (SetProperty(ref _filterText, value))
|
||||
OnPropertyChanged(nameof(FilteredLogLines));
|
||||
}
|
||||
}
|
||||
|
||||
public IEnumerable<string> FilteredLogLines =>
|
||||
string.IsNullOrWhiteSpace(_filterText)
|
||||
? LogLines
|
||||
: LogLines.Where(l => l.Contains(_filterText, StringComparison.OrdinalIgnoreCase));
|
||||
|
||||
private bool _autoScroll = true;
|
||||
public bool AutoScroll
|
||||
{
|
||||
get => _autoScroll;
|
||||
set => SetProperty(ref _autoScroll, value);
|
||||
}
|
||||
|
||||
public ICommand ClearCommand { get; }
|
||||
public ICommand CopyAllCommand { get; }
|
||||
|
||||
public DebugLogViewModel()
|
||||
{
|
||||
_dispatcher = Dispatcher.CurrentDispatcher;
|
||||
|
||||
ClearCommand = new RelayCommand(() => { LogLines.Clear(); OnPropertyChanged(nameof(FilteredLogLines)); });
|
||||
CopyAllCommand = new RelayCommand(() =>
|
||||
{
|
||||
try
|
||||
{
|
||||
var text = string.Join(Environment.NewLine, LogLines);
|
||||
System.Windows.Clipboard.SetText(text);
|
||||
}
|
||||
catch { }
|
||||
});
|
||||
|
||||
// Subscribe to all log events
|
||||
Logger.LogWritten += OnLogWritten;
|
||||
}
|
||||
|
||||
private void OnLogWritten(string line)
|
||||
{
|
||||
_dispatcher.BeginInvoke(() =>
|
||||
{
|
||||
LogLines.Add(line);
|
||||
while (LogLines.Count > MaxLines)
|
||||
LogLines.RemoveAt(0);
|
||||
|
||||
OnPropertyChanged(nameof(FilteredLogLines));
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Windows.Input;
|
||||
using Microsoft.Win32;
|
||||
using SpdUp.Core;
|
||||
using SpdUp.Models;
|
||||
using SpdUp.Services;
|
||||
|
||||
namespace SpdUp.ViewModels;
|
||||
|
||||
/// <summary>
|
||||
/// Game Library page – manage detected and manually-added games.
|
||||
/// </summary>
|
||||
public sealed class GameLibraryViewModel : ObservableObject
|
||||
{
|
||||
private readonly AppSettings _settings;
|
||||
private readonly GameDetectionService _detectionService;
|
||||
|
||||
public ObservableCollection<GameEntry> Games { get; }
|
||||
|
||||
private GameEntry? _selectedGame;
|
||||
public GameEntry? SelectedGame
|
||||
{
|
||||
get => _selectedGame;
|
||||
set => SetProperty(ref _selectedGame, value);
|
||||
}
|
||||
|
||||
public ICommand AddGameCommand { get; }
|
||||
public ICommand RemoveGameCommand { get; }
|
||||
|
||||
public GameLibraryViewModel(AppSettings settings, GameDetectionService detectionService)
|
||||
{
|
||||
_settings = settings;
|
||||
_detectionService = detectionService;
|
||||
Games = new ObservableCollection<GameEntry>(_settings.Games);
|
||||
|
||||
AddGameCommand = new RelayCommand(AddGame);
|
||||
RemoveGameCommand = new RelayCommand(RemoveGame, () => SelectedGame is not null);
|
||||
}
|
||||
|
||||
private void AddGame()
|
||||
{
|
||||
var dlg = new OpenFileDialog
|
||||
{
|
||||
Filter = "Executables (*.exe)|*.exe",
|
||||
Title = "Select Game Executable"
|
||||
};
|
||||
|
||||
if (dlg.ShowDialog() == true)
|
||||
{
|
||||
var entry = new GameEntry
|
||||
{
|
||||
Name = System.IO.Path.GetFileNameWithoutExtension(dlg.FileName),
|
||||
ExecutablePath = dlg.FileName,
|
||||
ProcessName = GameEntry.ProcessNameFromPath(dlg.FileName),
|
||||
LauncherSource = "Manual"
|
||||
};
|
||||
|
||||
Games.Add(entry);
|
||||
_settings.Games.Add(entry);
|
||||
_detectionService.AddGameProcess(entry.ProcessName);
|
||||
_settings.Save();
|
||||
}
|
||||
}
|
||||
|
||||
private void RemoveGame()
|
||||
{
|
||||
if (SelectedGame is null) return;
|
||||
_settings.Games.Remove(SelectedGame);
|
||||
Games.Remove(SelectedGame);
|
||||
_settings.Save();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,264 @@
|
||||
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.");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
using SpdUp.Core;
|
||||
|
||||
namespace SpdUp.ViewModels;
|
||||
|
||||
/// <summary>
|
||||
/// System Monitor page – just binds to MainViewModel's live metrics.
|
||||
/// </summary>
|
||||
public sealed class MonitorViewModel : ObservableObject
|
||||
{
|
||||
public MainViewModel Main { get; }
|
||||
|
||||
public MonitorViewModel(MainViewModel main)
|
||||
{
|
||||
Main = main;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,100 @@
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Diagnostics;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Threading;
|
||||
using SpdUp.Core;
|
||||
using SpdUp.Models;
|
||||
using SpdUp.Services;
|
||||
|
||||
namespace SpdUp.ViewModels;
|
||||
|
||||
/// <summary>
|
||||
/// Process Manager ViewModel.
|
||||
/// </summary>
|
||||
public sealed class ProcessManagerViewModel : ObservableObject
|
||||
{
|
||||
private readonly DispatcherTimer _refreshTimer;
|
||||
|
||||
public ObservableCollection<ProcessEntry> Processes { get; } = new();
|
||||
|
||||
private ProcessEntry? _selectedProcess;
|
||||
public ProcessEntry? SelectedProcess
|
||||
{
|
||||
get => _selectedProcess;
|
||||
set => SetProperty(ref _selectedProcess, value);
|
||||
}
|
||||
|
||||
public ICommand RefreshCommand { get; }
|
||||
public ICommand KillProcessCommand { get; }
|
||||
public ICommand SetHighPriorityCommand { get; }
|
||||
public ICommand SetNormalPriorityCommand { get; }
|
||||
|
||||
public ProcessManagerViewModel()
|
||||
{
|
||||
RefreshCommand = new RelayCommand(RefreshProcesses);
|
||||
KillProcessCommand = new RelayCommand(KillSelected, () => SelectedProcess is not null);
|
||||
SetHighPriorityCommand = new RelayCommand(() => SetPriority(ProcessPriorityClass.High), () => SelectedProcess is not null);
|
||||
SetNormalPriorityCommand = new RelayCommand(() => SetPriority(ProcessPriorityClass.Normal), () => SelectedProcess is not null);
|
||||
|
||||
_refreshTimer = new DispatcherTimer { Interval = TimeSpan.FromSeconds(3) };
|
||||
_refreshTimer.Tick += (_, _) => RefreshProcesses();
|
||||
|
||||
RefreshProcesses();
|
||||
_refreshTimer.Start();
|
||||
}
|
||||
|
||||
private void RefreshProcesses()
|
||||
{
|
||||
var procs = Process.GetProcesses()
|
||||
.Select(p =>
|
||||
{
|
||||
try
|
||||
{
|
||||
return new ProcessEntry
|
||||
{
|
||||
Pid = p.Id,
|
||||
Name = p.ProcessName,
|
||||
WindowTitle = string.IsNullOrWhiteSpace(p.MainWindowTitle) ? null : p.MainWindowTitle,
|
||||
MemoryMB = p.WorkingSet64 / 1048576f,
|
||||
PriorityClass = TryGetPriority(p),
|
||||
IsSystem = p.Id <= 4
|
||||
};
|
||||
}
|
||||
catch { return null; }
|
||||
finally { p.Dispose(); }
|
||||
})
|
||||
.Where(e => e is not null)
|
||||
.OrderByDescending(e => e!.MemoryMB)
|
||||
.Take(200)
|
||||
.ToList();
|
||||
|
||||
Processes.Clear();
|
||||
foreach (var p in procs)
|
||||
Processes.Add(p!);
|
||||
}
|
||||
|
||||
private static string TryGetPriority(Process p)
|
||||
{
|
||||
try { return p.PriorityClass.ToString(); }
|
||||
catch { return "N/A"; }
|
||||
}
|
||||
|
||||
private void KillSelected()
|
||||
{
|
||||
if (SelectedProcess is null) return;
|
||||
OptimizationService.KillProcess(SelectedProcess.Pid);
|
||||
RefreshProcesses();
|
||||
}
|
||||
|
||||
private void SetPriority(ProcessPriorityClass priority)
|
||||
{
|
||||
if (SelectedProcess is null) return;
|
||||
try
|
||||
{
|
||||
using var proc = Process.GetProcessById(SelectedProcess.Pid);
|
||||
proc.PriorityClass = priority;
|
||||
}
|
||||
catch { }
|
||||
RefreshProcesses();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
using System.Collections.ObjectModel;
|
||||
using System.ServiceProcess;
|
||||
using System.Windows.Input;
|
||||
using SpdUp.Core;
|
||||
using SpdUp.Models;
|
||||
using SpdUp.Services;
|
||||
|
||||
namespace SpdUp.ViewModels;
|
||||
|
||||
/// <summary>
|
||||
/// Service Manager ViewModel.
|
||||
/// </summary>
|
||||
public sealed class ServiceManagerViewModel : ObservableObject
|
||||
{
|
||||
private readonly AppSettings _settings;
|
||||
|
||||
public ObservableCollection<ServiceEntry> Services { get; } = new();
|
||||
|
||||
private ServiceEntry? _selectedService;
|
||||
public ServiceEntry? SelectedService
|
||||
{
|
||||
get => _selectedService;
|
||||
set => SetProperty(ref _selectedService, value);
|
||||
}
|
||||
|
||||
public ICommand RefreshCommand { get; }
|
||||
public ICommand StopServiceCommand { get; }
|
||||
public ICommand StartServiceCommand { get; }
|
||||
|
||||
public ServiceManagerViewModel(AppSettings settings)
|
||||
{
|
||||
_settings = settings;
|
||||
|
||||
RefreshCommand = new RelayCommand(Refresh);
|
||||
StopServiceCommand = new RelayCommand(StopSelected, () => SelectedService is not null);
|
||||
StartServiceCommand = new RelayCommand(StartSelected, () => SelectedService is not null);
|
||||
|
||||
Refresh();
|
||||
}
|
||||
|
||||
private void Refresh()
|
||||
{
|
||||
Services.Clear();
|
||||
|
||||
// Show the configured services plus all known non-critical ones
|
||||
var names = new HashSet<string>(_settings.ServicesToStop, StringComparer.OrdinalIgnoreCase);
|
||||
foreach (var k in ServiceManagementService.KnownNonCriticalServices.Keys)
|
||||
names.Add(k);
|
||||
|
||||
foreach (var entry in ServiceManagementService.GetServiceList(names))
|
||||
Services.Add(entry);
|
||||
}
|
||||
|
||||
private void StopSelected()
|
||||
{
|
||||
if (SelectedService is null) return;
|
||||
ServiceManagementService.StopService(SelectedService.ServiceName);
|
||||
Refresh();
|
||||
}
|
||||
|
||||
private void StartSelected()
|
||||
{
|
||||
if (SelectedService is null) return;
|
||||
ServiceManagementService.StartService(SelectedService.ServiceName);
|
||||
Refresh();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,91 @@
|
||||
using System.Windows.Input;
|
||||
using SpdUp.Core;
|
||||
using SpdUp.Models;
|
||||
|
||||
namespace SpdUp.ViewModels;
|
||||
|
||||
/// <summary>
|
||||
/// Settings page ViewModel.
|
||||
/// </summary>
|
||||
public sealed class SettingsViewModel : ObservableObject
|
||||
{
|
||||
private readonly AppSettings _settings;
|
||||
private readonly MainViewModel _main;
|
||||
|
||||
public bool AutoDetectGames
|
||||
{
|
||||
get => _settings.AutoDetectGames;
|
||||
set { _settings.AutoDetectGames = value; OnPropertyChanged(); Save(); }
|
||||
}
|
||||
|
||||
public bool AutoBoostOnGameLaunch
|
||||
{
|
||||
get => _settings.AutoBoostOnGameLaunch;
|
||||
set { _settings.AutoBoostOnGameLaunch = value; OnPropertyChanged(); Save(); }
|
||||
}
|
||||
|
||||
public bool MinimizeToTray
|
||||
{
|
||||
get => _settings.MinimizeToTray;
|
||||
set { _settings.MinimizeToTray = value; OnPropertyChanged(); Save(); }
|
||||
}
|
||||
|
||||
public bool StartWithWindows
|
||||
{
|
||||
get => _settings.StartWithWindows;
|
||||
set { _settings.StartWithWindows = value; OnPropertyChanged(); Save(); }
|
||||
}
|
||||
|
||||
public bool WidgetCompactMode
|
||||
{
|
||||
get => _settings.WidgetCompactMode;
|
||||
set { _settings.WidgetCompactMode = value; OnPropertyChanged(); Save(); }
|
||||
}
|
||||
|
||||
public double WidgetOpacity
|
||||
{
|
||||
get => _settings.WidgetOpacity;
|
||||
set { _settings.WidgetOpacity = value; OnPropertyChanged(); Save(); }
|
||||
}
|
||||
|
||||
public int WidgetUpdateInterval
|
||||
{
|
||||
get => _settings.WidgetUpdateIntervalMs;
|
||||
set { _settings.WidgetUpdateIntervalMs = value; OnPropertyChanged(); Save(); }
|
||||
}
|
||||
|
||||
public bool WidgetClickThrough
|
||||
{
|
||||
get => _settings.WidgetClickThrough;
|
||||
set { _settings.WidgetClickThrough = value; OnPropertyChanged(); Save(); }
|
||||
}
|
||||
|
||||
public int MonitoringInterval
|
||||
{
|
||||
get => _settings.MonitoringIntervalMs;
|
||||
set { _settings.MonitoringIntervalMs = value; OnPropertyChanged(); Save(); }
|
||||
}
|
||||
|
||||
public string PingTarget
|
||||
{
|
||||
get => _settings.PingTarget;
|
||||
set { _settings.PingTarget = value; OnPropertyChanged(); Save(); }
|
||||
}
|
||||
|
||||
public string PreferredDns
|
||||
{
|
||||
get => _settings.PreferredDns;
|
||||
set { _settings.PreferredDns = value; OnPropertyChanged(); Save(); }
|
||||
}
|
||||
|
||||
public ICommand SaveCommand { get; }
|
||||
|
||||
public SettingsViewModel(AppSettings settings, MainViewModel main)
|
||||
{
|
||||
_settings = settings;
|
||||
_main = main;
|
||||
SaveCommand = new RelayCommand(Save);
|
||||
}
|
||||
|
||||
private void Save() => _settings.Save();
|
||||
}
|
||||
Reference in New Issue
Block a user