From bcb5fc37915406f427d69b06a2e396168b439c05 Mon Sep 17 00:00:00 2001 From: bluepilledgreat <97983689+bluepilledgreat@users.noreply.github.com> Date: Mon, 26 Aug 2024 19:33:46 +0100 Subject: [PATCH 1/3] add taskbar progress bar does not support winform bootstrappers --- Bloxstrap/Bootstrapper.cs | 16 ++++++++++- .../Bootstrapper/Base/WinFormsDialogBase.cs | 27 +++++++++++++++++++ .../Elements/Bootstrapper/ByfronDialog.xaml | 5 ++++ .../Bootstrapper/ByfronDialog.xaml.cs | 21 +++++++++++++++ .../Bootstrapper/ClassicFluentDialog.xaml | 4 +++ .../Bootstrapper/ClassicFluentDialog.xaml.cs | 25 ++++++++++++++--- .../Elements/Bootstrapper/FluentDialog.xaml | 4 +++ .../Bootstrapper/FluentDialog.xaml.cs | 21 +++++++++++++++ Bloxstrap/UI/IBootstrapperDialog.cs | 3 +++ .../BootstrapperDialogViewModel.cs | 4 +++ 10 files changed, 125 insertions(+), 5 deletions(-) diff --git a/Bloxstrap/Bootstrapper.cs b/Bloxstrap/Bootstrapper.cs index c23d17d8..5bba0978 100644 --- a/Bloxstrap/Bootstrapper.cs +++ b/Bloxstrap/Bootstrapper.cs @@ -6,6 +6,7 @@ using Bloxstrap.Integrations; using Bloxstrap.Resources; using Bloxstrap.AppData; +using System.Windows.Shell; namespace Bloxstrap { @@ -13,6 +14,7 @@ public class Bootstrapper { #region Properties private const int ProgressBarMaximum = 10000; + private const double TaskbarProgressMaximum = 1; // this can not be changed. keep it at 1. private const string AppSettings = "\r\n" + @@ -71,6 +73,7 @@ private int _distributionSize private bool _isInstalling = false; private double _progressIncrement; + private double _taskbarProgressIncrement; private long _totalDownloadedBytes = 0; private int _packagesExtracted = 0; private bool _cancelFired = false; @@ -106,6 +109,7 @@ private void UpdateProgressBar() if (Dialog is null) return; + // UI progress int progressValue = (int)Math.Floor(_progressIncrement * _totalDownloadedBytes); // bugcheck: if we're restoring a file from a package, it'll incorrectly increment the progress beyond 100 @@ -113,6 +117,12 @@ private void UpdateProgressBar() progressValue = Math.Clamp(progressValue, 0, ProgressBarMaximum); Dialog.ProgressValue = progressValue; + + // taskbar progress + double taskbarProgressValue = _taskbarProgressIncrement * _totalDownloadedBytes; + taskbarProgressValue = Math.Clamp(taskbarProgressValue, 0, TaskbarProgressMaximum); + + Dialog.TaskbarProgressValue = taskbarProgressValue; } public async Task Run() @@ -614,11 +624,14 @@ private async Task InstallLatestVersion() { Dialog.CancelEnabled = true; Dialog.ProgressStyle = ProgressBarStyle.Continuous; + Dialog.TaskbarProgressState = TaskbarItemProgressState.Normal; Dialog.ProgressMaximum = ProgressBarMaximum; // compute total bytes to download - _progressIncrement = (double)ProgressBarMaximum / _versionPackageManifest.Sum(package => package.PackedSize); + int totalSize = _versionPackageManifest.Sum(package => package.PackedSize); + _progressIncrement = (double)ProgressBarMaximum / totalSize; + _taskbarProgressIncrement = (double)TaskbarProgressMaximum / totalSize; } foreach (Package package in _versionPackageManifest) @@ -647,6 +660,7 @@ private async Task InstallLatestVersion() if (Dialog is not null) { Dialog.ProgressStyle = ProgressBarStyle.Marquee; + Dialog.TaskbarProgressState = TaskbarItemProgressState.Indeterminate; SetStatus(Strings.Bootstrapper_Status_Configuring); } diff --git a/Bloxstrap/UI/Elements/Bootstrapper/Base/WinFormsDialogBase.cs b/Bloxstrap/UI/Elements/Bootstrapper/Base/WinFormsDialogBase.cs index 588d9504..d3005de3 100644 --- a/Bloxstrap/UI/Elements/Bootstrapper/Base/WinFormsDialogBase.cs +++ b/Bloxstrap/UI/Elements/Bootstrapper/Base/WinFormsDialogBase.cs @@ -1,4 +1,5 @@ using System.Windows.Forms; +using System.Windows.Shell; using Bloxstrap.UI.Utility; @@ -15,6 +16,8 @@ public class WinFormsDialogBase : Form, IBootstrapperDialog protected virtual ProgressBarStyle _progressStyle { get; set; } protected virtual int _progressValue { get; set; } protected virtual int _progressMaximum { get; set; } + protected virtual TaskbarItemProgressState _taskbarProgressState { get; set; } + protected virtual double _taskbarProgressValue { get; set; } protected virtual bool _cancelEnabled { get; set; } public string Message @@ -65,6 +68,30 @@ public int ProgressValue } } + public TaskbarItemProgressState TaskbarProgressState + { + get => _taskbarProgressState; + set + { + if (InvokeRequired) + Invoke(() => _taskbarProgressState = value); + else + _taskbarProgressState = value; + } + } + + public double TaskbarProgressValue + { + get => _taskbarProgressValue; + set + { + if (InvokeRequired) + Invoke(() => _taskbarProgressValue = value); + else + _taskbarProgressValue = value; + } + } + public bool CancelEnabled { get => _cancelEnabled; diff --git a/Bloxstrap/UI/Elements/Bootstrapper/ByfronDialog.xaml b/Bloxstrap/UI/Elements/Bootstrapper/ByfronDialog.xaml index 200dbf0c..b1ef6b9e 100644 --- a/Bloxstrap/UI/Elements/Bootstrapper/ByfronDialog.xaml +++ b/Bloxstrap/UI/Elements/Bootstrapper/ByfronDialog.xaml @@ -12,6 +12,11 @@ AllowsTransparency="True" Background="Transparent" Closing="Window_Closing"> + + + + + diff --git a/Bloxstrap/UI/Elements/Bootstrapper/ByfronDialog.xaml.cs b/Bloxstrap/UI/Elements/Bootstrapper/ByfronDialog.xaml.cs index 54e57cae..3fb04413 100644 --- a/Bloxstrap/UI/Elements/Bootstrapper/ByfronDialog.xaml.cs +++ b/Bloxstrap/UI/Elements/Bootstrapper/ByfronDialog.xaml.cs @@ -3,6 +3,7 @@ using System.Windows.Forms; using System.Windows.Media; using System.Windows.Media.Imaging; +using System.Windows.Shell; using Bloxstrap.UI.Elements.Bootstrapper.Base; using Bloxstrap.UI.ViewModels.Bootstrapper; @@ -65,6 +66,26 @@ public int ProgressValue } } + public TaskbarItemProgressState TaskbarProgressState + { + get => _viewModel.TaskbarProgressState; + set + { + _viewModel.TaskbarProgressState = value; + _viewModel.OnPropertyChanged(nameof(_viewModel.TaskbarProgressState)); + } + } + + public double TaskbarProgressValue + { + get => _viewModel.TaskbarProgressValue; + set + { + _viewModel.TaskbarProgressValue = value; + _viewModel.OnPropertyChanged(nameof(_viewModel.TaskbarProgressValue)); + } + } + public bool CancelEnabled { get => _viewModel.CancelEnabled; diff --git a/Bloxstrap/UI/Elements/Bootstrapper/ClassicFluentDialog.xaml b/Bloxstrap/UI/Elements/Bootstrapper/ClassicFluentDialog.xaml index 2cf25e77..76cda5ee 100644 --- a/Bloxstrap/UI/Elements/Bootstrapper/ClassicFluentDialog.xaml +++ b/Bloxstrap/UI/Elements/Bootstrapper/ClassicFluentDialog.xaml @@ -19,6 +19,10 @@ WindowStartupLocation="CenterScreen" mc:Ignorable="d"> + + + + diff --git a/Bloxstrap/UI/Elements/Bootstrapper/ClassicFluentDialog.xaml.cs b/Bloxstrap/UI/Elements/Bootstrapper/ClassicFluentDialog.xaml.cs index 5139a3ca..c2e46ab9 100644 --- a/Bloxstrap/UI/Elements/Bootstrapper/ClassicFluentDialog.xaml.cs +++ b/Bloxstrap/UI/Elements/Bootstrapper/ClassicFluentDialog.xaml.cs @@ -1,9 +1,6 @@ using System.ComponentModel; using System.Windows.Forms; - -using Wpf.Ui.Appearance; -using Wpf.Ui.Mvvm.Contracts; -using Wpf.Ui.Mvvm.Services; +using System.Windows.Shell; using Bloxstrap.UI.ViewModels.Bootstrapper; using Bloxstrap.UI.Elements.Bootstrapper.Base; @@ -62,6 +59,26 @@ public int ProgressValue } } + public TaskbarItemProgressState TaskbarProgressState + { + get => _viewModel.TaskbarProgressState; + set + { + _viewModel.TaskbarProgressState = value; + _viewModel.OnPropertyChanged(nameof(_viewModel.TaskbarProgressState)); + } + } + + public double TaskbarProgressValue + { + get => _viewModel.TaskbarProgressValue; + set + { + _viewModel.TaskbarProgressValue = value; + _viewModel.OnPropertyChanged(nameof(_viewModel.TaskbarProgressValue)); + } + } + public bool CancelEnabled { get => _viewModel.CancelEnabled; diff --git a/Bloxstrap/UI/Elements/Bootstrapper/FluentDialog.xaml b/Bloxstrap/UI/Elements/Bootstrapper/FluentDialog.xaml index 881692d9..5f49a73d 100644 --- a/Bloxstrap/UI/Elements/Bootstrapper/FluentDialog.xaml +++ b/Bloxstrap/UI/Elements/Bootstrapper/FluentDialog.xaml @@ -22,6 +22,10 @@ WindowStyle="None" mc:Ignorable="d"> + + + + diff --git a/Bloxstrap/UI/Elements/Bootstrapper/FluentDialog.xaml.cs b/Bloxstrap/UI/Elements/Bootstrapper/FluentDialog.xaml.cs index 9048f026..71acd6a3 100644 --- a/Bloxstrap/UI/Elements/Bootstrapper/FluentDialog.xaml.cs +++ b/Bloxstrap/UI/Elements/Bootstrapper/FluentDialog.xaml.cs @@ -16,6 +16,7 @@ using System.Windows.Media; using System.Windows.Media.Imaging; using System.Windows.Shapes; +using System.Windows.Shell; using System.Windows.Threading; namespace Bloxstrap.UI.Elements.Bootstrapper @@ -72,6 +73,26 @@ public int ProgressValue } } + public TaskbarItemProgressState TaskbarProgressState + { + get => _viewModel.TaskbarProgressState; + set + { + _viewModel.TaskbarProgressState = value; + _viewModel.OnPropertyChanged(nameof(_viewModel.TaskbarProgressState)); + } + } + + public double TaskbarProgressValue + { + get => _viewModel.TaskbarProgressValue; + set + { + _viewModel.TaskbarProgressValue = value; + _viewModel.OnPropertyChanged(nameof(_viewModel.TaskbarProgressValue)); + } + } + public bool CancelEnabled { get => _viewModel.CancelEnabled; diff --git a/Bloxstrap/UI/IBootstrapperDialog.cs b/Bloxstrap/UI/IBootstrapperDialog.cs index e15f7fb0..95339aa1 100644 --- a/Bloxstrap/UI/IBootstrapperDialog.cs +++ b/Bloxstrap/UI/IBootstrapperDialog.cs @@ -1,4 +1,5 @@ using System.Windows.Forms; +using System.Windows.Shell; namespace Bloxstrap.UI { @@ -10,6 +11,8 @@ public interface IBootstrapperDialog ProgressBarStyle ProgressStyle { get; set; } int ProgressValue { get; set; } int ProgressMaximum { get; set; } + TaskbarItemProgressState TaskbarProgressState { get; set; } + double TaskbarProgressValue { get; set; } bool CancelEnabled { get; set; } void ShowBootstrapper(); diff --git a/Bloxstrap/UI/ViewModels/Bootstrapper/BootstrapperDialogViewModel.cs b/Bloxstrap/UI/ViewModels/Bootstrapper/BootstrapperDialogViewModel.cs index 27e21da8..6dc9b5e7 100644 --- a/Bloxstrap/UI/ViewModels/Bootstrapper/BootstrapperDialogViewModel.cs +++ b/Bloxstrap/UI/ViewModels/Bootstrapper/BootstrapperDialogViewModel.cs @@ -1,6 +1,7 @@ using System.Windows; using System.Windows.Input; using System.Windows.Media; +using System.Windows.Shell; using CommunityToolkit.Mvvm.Input; @@ -19,6 +20,9 @@ public class BootstrapperDialogViewModel : NotifyPropertyChangedViewModel public int ProgressMaximum { get; set; } = 0; public int ProgressValue { get; set; } = 0; + public TaskbarItemProgressState TaskbarProgressState { get; set; } = TaskbarItemProgressState.Indeterminate; + public double TaskbarProgressValue { get; set; } = 0; + public bool CancelEnabled { get; set; } = false; public Visibility CancelButtonVisibility => CancelEnabled ? Visibility.Visible : Visibility.Collapsed; From afbe82b035d2d52d73096009e15333d52890c628 Mon Sep 17 00:00:00 2001 From: bluepilledgreat <97983689+bluepilledgreat@users.noreply.github.com> Date: Sat, 21 Sep 2024 15:58:06 +0100 Subject: [PATCH 2/3] add winforms taskbar progress bar --- Bloxstrap/Bootstrapper.cs | 18 +++- .../Bootstrapper/Base/WinFormsDialogBase.cs | 14 ++- Bloxstrap/UI/Utility/TaskbarProgress.cs | 90 +++++++++++++++++++ 3 files changed, 110 insertions(+), 12 deletions(-) create mode 100644 Bloxstrap/UI/Utility/TaskbarProgress.cs diff --git a/Bloxstrap/Bootstrapper.cs b/Bloxstrap/Bootstrapper.cs index 5bba0978..a9427652 100644 --- a/Bloxstrap/Bootstrapper.cs +++ b/Bloxstrap/Bootstrapper.cs @@ -7,6 +7,7 @@ using Bloxstrap.Resources; using Bloxstrap.AppData; using System.Windows.Shell; +using Bloxstrap.UI.Elements.Bootstrapper.Base; namespace Bloxstrap { @@ -14,8 +15,10 @@ public class Bootstrapper { #region Properties private const int ProgressBarMaximum = 10000; - private const double TaskbarProgressMaximum = 1; // this can not be changed. keep it at 1. - + + private const double TaskbarProgressMaximumWpf = 1; // this can not be changed. keep it at 1. + private const int TaskbarProgressMaximumWinForms = WinFormsDialogBase.TaskbarProgressMaximum; + private const string AppSettings = "\r\n" + "\r\n" + @@ -74,6 +77,7 @@ private int _distributionSize private bool _isInstalling = false; private double _progressIncrement; private double _taskbarProgressIncrement; + private double _taskbarProgressMaximum; private long _totalDownloadedBytes = 0; private int _packagesExtracted = 0; private bool _cancelFired = false; @@ -120,7 +124,7 @@ private void UpdateProgressBar() // taskbar progress double taskbarProgressValue = _taskbarProgressIncrement * _totalDownloadedBytes; - taskbarProgressValue = Math.Clamp(taskbarProgressValue, 0, TaskbarProgressMaximum); + taskbarProgressValue = Math.Clamp(taskbarProgressValue, 0, _taskbarProgressMaximum); Dialog.TaskbarProgressValue = taskbarProgressValue; } @@ -631,7 +635,13 @@ private async Task InstallLatestVersion() // compute total bytes to download int totalSize = _versionPackageManifest.Sum(package => package.PackedSize); _progressIncrement = (double)ProgressBarMaximum / totalSize; - _taskbarProgressIncrement = (double)TaskbarProgressMaximum / totalSize; + + if (Dialog is WinFormsDialogBase) + _taskbarProgressMaximum = (double)TaskbarProgressMaximumWinForms; + else + _taskbarProgressMaximum = (double)TaskbarProgressMaximumWpf; + + _taskbarProgressIncrement = _taskbarProgressMaximum / (double)totalSize; } foreach (Package package in _versionPackageManifest) diff --git a/Bloxstrap/UI/Elements/Bootstrapper/Base/WinFormsDialogBase.cs b/Bloxstrap/UI/Elements/Bootstrapper/Base/WinFormsDialogBase.cs index d3005de3..db2814bc 100644 --- a/Bloxstrap/UI/Elements/Bootstrapper/Base/WinFormsDialogBase.cs +++ b/Bloxstrap/UI/Elements/Bootstrapper/Base/WinFormsDialogBase.cs @@ -7,6 +7,8 @@ namespace Bloxstrap.UI.Elements.Bootstrapper.Base { public class WinFormsDialogBase : Form, IBootstrapperDialog { + public const int TaskbarProgressMaximum = 100; + public Bloxstrap.Bootstrapper? Bootstrapper { get; set; } private bool _isClosing; @@ -73,10 +75,8 @@ public TaskbarItemProgressState TaskbarProgressState get => _taskbarProgressState; set { - if (InvokeRequired) - Invoke(() => _taskbarProgressState = value); - else - _taskbarProgressState = value; + _taskbarProgressState = value; + TaskbarProgress.SetProgressState(Process.GetCurrentProcess().MainWindowHandle, value); } } @@ -85,10 +85,8 @@ public double TaskbarProgressValue get => _taskbarProgressValue; set { - if (InvokeRequired) - Invoke(() => _taskbarProgressValue = value); - else - _taskbarProgressValue = value; + _taskbarProgressValue = value; + TaskbarProgress.SetProgressValue(Process.GetCurrentProcess().MainWindowHandle, (int)value, TaskbarProgressMaximum); } } diff --git a/Bloxstrap/UI/Utility/TaskbarProgress.cs b/Bloxstrap/UI/Utility/TaskbarProgress.cs new file mode 100644 index 00000000..7cc7a698 --- /dev/null +++ b/Bloxstrap/UI/Utility/TaskbarProgress.cs @@ -0,0 +1,90 @@ +using System.Runtime.InteropServices; +using System.Windows.Shell; + +namespace Bloxstrap.UI.Utility +{ + // Modified from https://github.com/PowerShell/PSReadLine/blob/e9122d38e932614393ff61faf57d6518990d7226/PSReadLine/PlatformWindows.cs#L704 + internal static class TaskbarProgress + { + private enum TaskbarStates + { + NoProgress = 0, + Indeterminate = 0x1, + Normal = 0x2, + Error = 0x4, + Paused = 0x8, + } + + [ComImport()] + [Guid("ea1afb91-9e28-4b86-90e9-9e9f8a5eefaf")] + [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] + private interface ITaskbarList3 + { + // ITaskbarList + [PreserveSig] + int HrInit(); + + [PreserveSig] + int AddTab(IntPtr hwnd); + + [PreserveSig] + int DeleteTab(IntPtr hwnd); + + [PreserveSig] + int ActivateTab(IntPtr hwnd); + + [PreserveSig] + int SetActiveAlt(IntPtr hwnd); + + // ITaskbarList2 + [PreserveSig] + int MarkFullscreenWindow(IntPtr hwnd, [MarshalAs(UnmanagedType.Bool)] bool fFullscreen); + + // ITaskbarList3 + [PreserveSig] + int SetProgressValue(IntPtr hwnd, UInt64 ullCompleted, UInt64 ullTotal); + + [PreserveSig] + int SetProgressState(IntPtr hwnd, TaskbarStates state); + + // N.B. for copy/pasters: we've left out the rest of the ITaskbarList3 methods... + } + + [ComImport()] + [Guid("56fdf344-fd6d-11d0-958a-006097c9a090")] + [ClassInterface(ClassInterfaceType.None)] + private class TaskbarInstance + { + } + + private static Lazy _taskbarInstance = new Lazy(() => (ITaskbarList3)new TaskbarInstance()); + + private static TaskbarStates ConvertEnum(TaskbarItemProgressState state) + { + return state switch + { + TaskbarItemProgressState.None => TaskbarStates.NoProgress, + TaskbarItemProgressState.Indeterminate => TaskbarStates.Indeterminate, + TaskbarItemProgressState.Normal => TaskbarStates.Normal, + TaskbarItemProgressState.Error => TaskbarStates.Error, + TaskbarItemProgressState.Paused => TaskbarStates.Paused, + _ => throw new Exception($"Unrecognised TaskbarItemProgressState: {state}") + }; + } + + private static int SetProgressState(IntPtr windowHandle, TaskbarStates taskbarState) + { + return _taskbarInstance.Value.SetProgressState(windowHandle, taskbarState); + } + + public static int SetProgressState(IntPtr windowHandle, TaskbarItemProgressState taskbarState) + { + return SetProgressState(windowHandle, ConvertEnum(taskbarState)); + } + + public static int SetProgressValue(IntPtr windowHandle, int progressValue, int progressMax) + { + return _taskbarInstance.Value.SetProgressValue(windowHandle, (ulong)progressValue, (ulong)progressMax); + } + } +} From 9b60101d9f59fc0bb8c0f021fc9687b86e525224 Mon Sep 17 00:00:00 2001 From: bluepilledgreat <97983689+bluepilledgreat@users.noreply.github.com> Date: Sun, 22 Sep 2024 12:43:20 +0100 Subject: [PATCH 3/3] fix build --- Bloxstrap/Bootstrapper.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Bloxstrap/Bootstrapper.cs b/Bloxstrap/Bootstrapper.cs index bb5cfcb4..a71827da 100644 --- a/Bloxstrap/Bootstrapper.cs +++ b/Bloxstrap/Bootstrapper.cs @@ -603,15 +603,15 @@ private async Task UpgradeRoblox() Dialog.ProgressMaximum = ProgressBarMaximum; // compute total bytes to download - int totalSize = _versionPackageManifest.Sum(package => package.PackedSize); - _progressIncrement = (double)ProgressBarMaximum / totalSize; + int totalPackedSize = _versionPackageManifest.Sum(package => package.PackedSize); + _progressIncrement = (double)ProgressBarMaximum / totalPackedSize; if (Dialog is WinFormsDialogBase) _taskbarProgressMaximum = (double)TaskbarProgressMaximumWinForms; else _taskbarProgressMaximum = (double)TaskbarProgressMaximumWpf; - _taskbarProgressIncrement = _taskbarProgressMaximum / (double)totalSize; + _taskbarProgressIncrement = _taskbarProgressMaximum / (double)totalPackedSize; } var extractionTasks = new List();