feat(launcher): add verified first-run installer

This commit is contained in:
Erik 2026-08-14 20:06:37 +02:00
parent 60f627998c
commit ff6ebb6a6a
28 changed files with 3259 additions and 125 deletions

View file

@ -1,5 +1,7 @@
using System.Collections.ObjectModel;
using System.ComponentModel;
using AcDream.Launcher.Core.Installation;
using AcDream.Launcher.Core.Launching;
using AcDream.Launcher.Core.Orchestration;
using AcDream.Launcher.Core.Profiles;
@ -22,20 +24,20 @@ public sealed class LauncherWindowViewModel : ObservableObject, IDisposable
public LauncherWindowViewModel(
ILauncherOrchestrator orchestrator,
IUiDispatcher dispatcher)
IUiDispatcher dispatcher,
ILauncherInstaller? installer = null)
{
_orchestrator = orchestrator ?? throw new ArgumentNullException(nameof(orchestrator));
_dispatcher = dispatcher ?? throw new ArgumentNullException(nameof(dispatcher));
_orchestrator.StateChanged += OnOrchestratorStateChanged;
EditorDialog = new ProfileEditorDialogViewModel();
FirstRunWizardShell = new LauncherShellViewModel(
"First-run setup",
"Choose and validate the retail DAT directory, build acdream.pak, "
+ "and record the installed client. The installer transaction and "
+ "progress body land in Campaign LA slice LA9.",
"Installer shell ready — implementation arrives in LA9.",
() => CanInteract);
FirstRunWizardShell = new FirstRunInstallerViewModel(
installer ?? new UnavailableLauncherInstaller(),
dispatcher,
OnInstallCompleted,
() => CanInteract,
() => !IsBusy && Sessions.All(session => !session.IsActive));
UpdatePromptShell = new LauncherShellViewModel(
"Client update",
"Review a signed release manifest, verify the downloaded archive, "
@ -88,7 +90,7 @@ public sealed class LauncherWindowViewModel : ObservableObject, IDisposable
public ProfileEditorDialogViewModel EditorDialog { get; }
public LauncherShellViewModel FirstRunWizardShell { get; }
public FirstRunInstallerViewModel FirstRunWizardShell { get; }
public LauncherShellViewModel UpdatePromptShell { get; }
@ -332,6 +334,7 @@ public sealed class LauncherWindowViewModel : ObservableObject, IDisposable
EditorDialog.PropertyChanged -= OnModalPropertyChanged;
FirstRunWizardShell.PropertyChanged -= OnModalPropertyChanged;
UpdatePromptShell.PropertyChanged -= OnModalPropertyChanged;
FirstRunWizardShell.Dispose();
}
private void OnOrchestratorStateChanged(object? sender, EventArgs e) =>
@ -346,7 +349,8 @@ public sealed class LauncherWindowViewModel : ObservableObject, IDisposable
private void OnModalPropertyChanged(object? sender, PropertyChangedEventArgs e)
{
if (e.PropertyName != nameof(ProfileEditorDialogViewModel.IsOpen)
&& e.PropertyName != nameof(LauncherShellViewModel.IsOpen))
&& e.PropertyName != nameof(LauncherShellViewModel.IsOpen)
&& e.PropertyName != nameof(FirstRunInstallerViewModel.IsOpen))
{
return;
}
@ -370,7 +374,7 @@ public sealed class LauncherWindowViewModel : ObservableObject, IDisposable
}
else if (FirstRunWizardShell.IsOpen)
{
FirstRunWizardShell.IsOpen = false;
FirstRunWizardShell.Close();
}
else if (UpdatePromptShell.IsOpen)
{
@ -964,6 +968,14 @@ public sealed class LauncherWindowViewModel : ObservableObject, IDisposable
: message;
}
private void OnInstallCompleted(LauncherInstallRecord record)
{
_orchestrator.SetInstallRecord(record);
OperationStatus = "Client content installed and verified.";
LastError = null;
RefreshFromCore();
}
private void NotifyCommandStates()
{
AddServerCommand.NotifyCanExecuteChanged();