Add fully-injected MainWindowViewModel constructor

Introduce an injected constructor taking IHardwareMonitorService, ILogger,
IRemoteWebServer (+ the concrete selection/plot/startup services) and
IStartupTracer, with shared settings initialization. A transitional 2-arg
constructor still builds the legacy graph for MainWindow until it is
DI-resolved; an _ownsServices flag keeps disposal correct across both paths.

Break the VM<->RemoteWebServer construction cycle by moving the root provider
to RemoteWebServer.SetRootProvider (removing it from the constructor), and make
RemoteWebServer.Quit idempotent. Update RemoteWebServer tests for the new ctor.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
2026-06-02 15:09:12 -05:00
co-authored by Copilot
parent 50a07d5ce9
commit 594429bb7d
4 changed files with 60 additions and 17 deletions
@@ -24,6 +24,8 @@ public interface IRemoteWebServer : IDisposable
string UserName { get; set; }
void SetRootProvider(Func<ViewModels.SensorTreeItemViewModel?> rootProvider);
void SetPassword(string plainPassword);
bool Start();
@@ -26,14 +26,14 @@ public sealed class RemoteWebServer : IRemoteWebServer
{
private readonly IComputer _computer;
private readonly object _sensorReadLock;
private readonly Func<SensorTreeItemViewModel?> _rootProvider;
private Func<SensorTreeItemViewModel?> _rootProvider = () => null;
private readonly Version _version = typeof(RemoteWebServer).Assembly.GetName().Version ?? new Version(0, 0);
private CancellationTokenSource? _cts;
private HttpListener? _listener;
private Task? _listenerTask;
private bool _quit;
public RemoteWebServer(
Func<SensorTreeItemViewModel?> rootProvider,
IComputer computer,
object sensorReadLock,
string listenerIp,
@@ -42,7 +42,6 @@ public sealed class RemoteWebServer : IRemoteWebServer
string userName,
string passwordHash)
{
_rootProvider = rootProvider;
_computer = computer;
_sensorReadLock = sensorReadLock;
ListenerIp = listenerIp;
@@ -61,6 +60,15 @@ public sealed class RemoteWebServer : IRemoteWebServer
}
}
/// <summary>
/// Sets the accessor used to read the current sensor tree root. Supplied after construction so the
/// server can be created by the container without a constructor dependency on the view model.
/// </summary>
public void SetRootProvider(Func<SensorTreeItemViewModel?> rootProvider)
{
_rootProvider = rootProvider;
}
public bool AuthEnabled { get; set; }
public bool IsRunning => _listener?.IsListening == true;
@@ -137,9 +145,10 @@ public sealed class RemoteWebServer : IRemoteWebServer
public void Quit()
{
if (PlatformNotSupported)
if (PlatformNotSupported || _quit)
return;
_quit = true;
Stop();
try
{