From eaaaf39b8d45eb888877ad9946550e58c609794f Mon Sep 17 00:00:00 2001 From: Pat Hartl Date: Fri, 17 Apr 2026 22:24:47 -0500 Subject: [PATCH] Refactor install process to use major/minor task queue Tasks are broken down into major and minor tasks. Major tasks are like install game, redistributable, or tool. These are reported as individual tasks in the download queue. Minor tasks are running of a script, downloading saves, extracting/downloading, etc. --- .../ViewModels/DownloadQueueViewModel.cs | 57 ++- .../ViewModels/InstallTaskItemViewModel.cs | 59 +++ .../Views/DownloadQueuePageView.axaml | 45 ++ .../Views/DownloadQueueView.axaml | 36 +- .../DownloadQueueRedistributable.cs | 39 +- .../IInstallQueueItem.cs | 10 +- .../InstallQueueGame.cs | 28 +- .../InstallQueueTool.cs | 22 +- .../InstallService.cs | 395 ++++++++++----- LANCommander.SDK/Clients/GameClient.cs | 479 ++++++++++++++++++ LANCommander.SDK/Clients/ToolClient.cs | 112 ++++ LANCommander.SDK/Enums/InstallPlanItemType.cs | 10 + LANCommander.SDK/Enums/InstallTaskStatus.cs | 12 + LANCommander.SDK/Enums/InstallTaskType.cs | 17 + LANCommander.SDK/Models/InstallPlan.cs | 9 + LANCommander.SDK/Models/InstallPlanItem.cs | 17 + .../Models/InstallTaskDefinition.cs | 19 + .../Models/InstallTaskProgress.cs | 21 + 18 files changed, 1211 insertions(+), 176 deletions(-) create mode 100644 LANCommander.Launcher.Avalonia/ViewModels/InstallTaskItemViewModel.cs create mode 100644 LANCommander.SDK/Enums/InstallPlanItemType.cs create mode 100644 LANCommander.SDK/Enums/InstallTaskStatus.cs create mode 100644 LANCommander.SDK/Enums/InstallTaskType.cs create mode 100644 LANCommander.SDK/Models/InstallPlan.cs create mode 100644 LANCommander.SDK/Models/InstallPlanItem.cs create mode 100644 LANCommander.SDK/Models/InstallTaskDefinition.cs create mode 100644 LANCommander.SDK/Models/InstallTaskProgress.cs diff --git a/LANCommander.Launcher.Avalonia/ViewModels/DownloadQueueViewModel.cs b/LANCommander.Launcher.Avalonia/ViewModels/DownloadQueueViewModel.cs index 1cde4fca..0ee4b4f9 100644 --- a/LANCommander.Launcher.Avalonia/ViewModels/DownloadQueueViewModel.cs +++ b/LANCommander.Launcher.Avalonia/ViewModels/DownloadQueueViewModel.cs @@ -11,6 +11,7 @@ using LANCommander.Launcher.Avalonia.Services; using LANCommander.Launcher.Models; using LANCommander.Launcher.Services; using LANCommander.SDK.Enums; +using LANCommander.SDK.Models; using LANCommander.SDK.Services; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; @@ -92,6 +93,7 @@ public partial class DownloadQueueViewModel : ViewModelBase _installService.OnQueueChanged += OnQueueChanged; _installService.OnProgress += OnProgress; + _installService.OnTaskProgressUpdate += OnTaskProgressUpdate; _installService.OnInstallComplete += OnInstallComplete; _installService.OnInstallFail += OnInstallFail; @@ -104,6 +106,37 @@ public partial class DownloadQueueViewModel : ViewModelBase return Task.CompletedTask; } + private Task OnTaskProgressUpdate(InstallTaskProgress taskProgress) + { + Dispatcher.UIThread.Post(() => + { + var item = QueueItems.FirstOrDefault(i => i.Id == taskProgress.QueueItemId); + if (item == null) + return; + + var task = item.Tasks.FirstOrDefault(t => t.Id == taskProgress.TaskId); + if (task == null) + return; + + task.Status = taskProgress.TaskStatus; + task.Progress = taskProgress.Progress; + task.BytesTransferred = taskProgress.BytesTransferred; + task.TotalBytes = taskProgress.TotalBytes; + task.TransferSpeed = taskProgress.TransferSpeed; + task.ErrorMessage = taskProgress.ErrorMessage; + + item.CurrentTask = task; + + // Update current status from task + if (item == CurrentItem) + { + CurrentStatus = taskProgress.TaskTitle; + } + }); + + return Task.CompletedTask; + } + private Task OnProgress(InstallProgress progress) { _taskbarProgressService.SetProgress(progress.Progress); @@ -364,9 +397,18 @@ public partial class InstallQueueItemViewModel : ViewModelBase [ObservableProperty] private bool _isUpdate; - public bool IsActive => Status != InstallStatus.Queued && - Status != InstallStatus.Complete && - Status != InstallStatus.Failed && + [ObservableProperty] + private ObservableCollection _tasks = new(); + + [ObservableProperty] + private InstallTaskItemViewModel? _currentTask; + + [ObservableProperty] + private bool _hasTasks; + + public bool IsActive => Status != InstallStatus.Queued && + Status != InstallStatus.Complete && + Status != InstallStatus.Failed && Status != InstallStatus.Canceled; public bool IsQueued => Status == InstallStatus.Queued; @@ -390,6 +432,15 @@ public partial class InstallQueueItemViewModel : ViewModelBase CoverId = item.CoverId; IconId = item.IconId; IsUpdate = item.IsUpdate; + + if (item.Tasks != null && item.Tasks.Count > 0) + { + foreach (var taskDef in item.Tasks.OrderBy(t => t.Order)) + { + Tasks.Add(new InstallTaskItemViewModel(taskDef)); + } + HasTasks = true; + } } private static string FormatBytes(long bytes) diff --git a/LANCommander.Launcher.Avalonia/ViewModels/InstallTaskItemViewModel.cs b/LANCommander.Launcher.Avalonia/ViewModels/InstallTaskItemViewModel.cs new file mode 100644 index 00000000..6bfd7641 --- /dev/null +++ b/LANCommander.Launcher.Avalonia/ViewModels/InstallTaskItemViewModel.cs @@ -0,0 +1,59 @@ +using System; +using CommunityToolkit.Mvvm.ComponentModel; +using LANCommander.SDK.Enums; +using LANCommander.SDK.Models; + +namespace LANCommander.Launcher.Avalonia.ViewModels; + +public partial class InstallTaskItemViewModel : ViewModelBase +{ + [ObservableProperty] + private Guid _id; + + [ObservableProperty] + private string _title = string.Empty; + + [ObservableProperty] + private InstallTaskType _type; + + [ObservableProperty] + private InstallTaskStatus _status = InstallTaskStatus.Queued; + + [ObservableProperty] + private float _progress; + + [ObservableProperty] + private bool _reportsProgress; + + [ObservableProperty] + private bool _isCritical; + + [ObservableProperty] + private string? _errorMessage; + + [ObservableProperty] + private long _bytesTransferred; + + [ObservableProperty] + private long _totalBytes; + + [ObservableProperty] + private long _transferSpeed; + + public bool IsCompleted => Status == InstallTaskStatus.Completed; + public bool IsRunning => Status == InstallTaskStatus.Running; + public bool IsFailed => Status == InstallTaskStatus.Failed; + public bool IsQueued => Status == InstallTaskStatus.Queued; + public bool IsSkipped => Status == InstallTaskStatus.Skipped; + + public InstallTaskItemViewModel() { } + + public InstallTaskItemViewModel(InstallTaskDefinition taskDef) + { + Id = taskDef.Id; + Title = taskDef.Title; + Type = taskDef.Type; + ReportsProgress = taskDef.ReportsProgress; + IsCritical = taskDef.IsCritical; + } +} diff --git a/LANCommander.Launcher.Avalonia/Views/DownloadQueuePageView.axaml b/LANCommander.Launcher.Avalonia/Views/DownloadQueuePageView.axaml index 68c7a97b..44bc4c04 100644 --- a/LANCommander.Launcher.Avalonia/Views/DownloadQueuePageView.axaml +++ b/LANCommander.Launcher.Avalonia/Views/DownloadQueuePageView.axaml @@ -114,6 +114,51 @@ IsVisible="{Binding TimeRemainingText, Converter={x:Static StringConverters.IsNotNullOrEmpty}}" /> + + + + + + + + + + + + + + + + + + + + + + + diff --git a/LANCommander.Launcher.Avalonia/Views/DownloadQueueView.axaml b/LANCommander.Launcher.Avalonia/Views/DownloadQueueView.axaml index 70a26473..21b4779d 100644 --- a/LANCommander.Launcher.Avalonia/Views/DownloadQueueView.axaml +++ b/LANCommander.Launcher.Avalonia/Views/DownloadQueueView.axaml @@ -71,7 +71,7 @@ - +