Add window-level progress indicator for Run Tweaks and Undo (#4830)

* feat(tweaks): add window-level progress indicator for Run Tweaks and Undo

* Hide completed tweaks progress on next action

---------

Co-authored-by: Chris Titus <contact@christitus.com>
This commit is contained in:
Yayo Razo
2026-07-15 14:17:42 -05:00
committed by GitHub
co-authored by Chris Titus
parent 157a66b14d
commit c8c3c7869f
8 changed files with 113 additions and 1 deletions
+1 -1
View File
@@ -100,7 +100,7 @@
"ScrollBarBackgroundColor": "#2E3135", "ScrollBarBackgroundColor": "#2E3135",
"ScrollBarHoverColor": "#3B4252", "ScrollBarHoverColor": "#3B4252",
"ScrollBarDraggingColor": "#5E81AC", "ScrollBarDraggingColor": "#5E81AC",
"ProgressBarForegroundColor": "#222222", "ProgressBarForegroundColor": "#6EFF72",
"ProgressBarBackgroundColor": "Transparent", "ProgressBarBackgroundColor": "Transparent",
"ProgressBarTextColor": "#232629", "ProgressBarTextColor": "#232629",
"ButtonInstallBackgroundColor": "#222222", "ButtonInstallBackgroundColor": "#222222",
@@ -0,0 +1,35 @@
function Set-WinUtilTweaksProgressIndicator {
<#
.SYNOPSIS
Shows, updates, or hides the window-level progress indicator used by the
Tweaks and Undo workflows. It lives outside the TabControl, so unlike the
Install tab's progress bar it stays visible no matter which tab is active.
.PARAMETER Visible
Whether the indicator should be shown or hidden.
.PARAMETER Label
The text to display above the progress bar.
.PARAMETER Percent
The percentage of the progress bar that should be filled (0-100).
#>
param(
[bool]$Visible,
[string]$Label,
[ValidateRange(0,100)]
[int]$Percent
)
$indicatorVisible = if ($Visible) { [Windows.Visibility]::Visible } else { [Windows.Visibility]::Collapsed }
$indicatorLabel = $Label
$hasLabel = $PSBoundParameters.ContainsKey('Label')
$hasPercent = $PSBoundParameters.ContainsKey('Percent')
Invoke-WPFUIThread -ScriptBlock {
$sync.WPFTweaksProgressBar.Visibility = $indicatorVisible
if ($hasLabel) {
$sync.WPFTweaksProgressLabel.Text = $indicatorLabel
}
if ($hasPercent) {
$sync.WPFTweaksProgressValue.Value = $Percent
}
}
}
+1
View File
@@ -16,6 +16,7 @@ function Invoke-WPFButton {
#[System.Windows.MessageBox]::Show("$Button","Chris Titus Tech's Windows Utility","OK","Info") #[System.Windows.MessageBox]::Show("$Button","Chris Titus Tech's Windows Utility","OK","Info")
if (-not $sync.ProcessRunning) { if (-not $sync.ProcessRunning) {
Set-WinUtilProgressBar -label "" -percent 0 Set-WinUtilProgressBar -label "" -percent 0
Set-WinUtilTweaksProgressIndicator -Visible $false
} }
# Check if button is defined in feature config with function or InvokeScript # Check if button is defined in feature config with function or InvokeScript
@@ -40,12 +40,14 @@ function Invoke-WPFtweaksbutton {
} }
Set-WinUtilProgressBar -Label "Creating restore point" -Percent 0 Set-WinUtilProgressBar -Label "Creating restore point" -Percent 0
Set-WinUtilTweaksProgressIndicator -Visible $true -Label "Creating restore point" -Percent 0
Write-WinUtilLog -Component "Tweaks" -Message "Creating restore point before applying selected tweaks." Write-WinUtilLog -Component "Tweaks" -Message "Creating restore point before applying selected tweaks."
Invoke-WinUtilTweaks $restorePointTweak Invoke-WinUtilTweaks $restorePointTweak
$completedSteps = 1 $completedSteps = 1
if ($tweaksToRun.Count -eq 0 -and $dnsProvider -eq "Default") { if ($tweaksToRun.Count -eq 0 -and $dnsProvider -eq "Default") {
Set-WinUtilProgressBar -Label "Tweaks finished" -Percent 100 Set-WinUtilProgressBar -Label "Tweaks finished" -Percent 100
Set-WinUtilTweaksProgressIndicator -Visible $true -Label "Tweaks finished" -Percent 100
$sync.ProcessRunning = $false $sync.ProcessRunning = $false
Invoke-WPFUIThread -ScriptBlock { Set-WinUtilTaskbaritem -state "None" -overlay "checkmark" } Invoke-WPFUIThread -ScriptBlock { Set-WinUtilTaskbaritem -state "None" -overlay "checkmark" }
Write-Host "=================================" Write-Host "================================="
@@ -76,12 +78,14 @@ function Invoke-WPFtweaksbutton {
for ($i = 0; $i -lt $tweaks.Count; $i++) { for ($i = 0; $i -lt $tweaks.Count; $i++) {
Set-WinUtilProgressBar -Label "Applying $($tweaks[$i])" -Percent ($completedSteps / $totalSteps * 100) Set-WinUtilProgressBar -Label "Applying $($tweaks[$i])" -Percent ($completedSteps / $totalSteps * 100)
Set-WinUtilTweaksProgressIndicator -Visible $true -Label "Applying $($tweaks[$i]) ($($completedSteps + 1)/$totalSteps)" -Percent ($completedSteps / $totalSteps * 100)
Invoke-WinUtilTweaks $tweaks[$i] Invoke-WinUtilTweaks $tweaks[$i]
$completedSteps++ $completedSteps++
$progress = $completedSteps / $totalSteps $progress = $completedSteps / $totalSteps
Invoke-WPFUIThread -ScriptBlock { Set-WinUtilTaskbaritem -value $progress } Invoke-WPFUIThread -ScriptBlock { Set-WinUtilTaskbaritem -value $progress }
} }
Set-WinUtilProgressBar -Label "Tweaks finished" -Percent 100 Set-WinUtilProgressBar -Label "Tweaks finished" -Percent 100
Set-WinUtilTweaksProgressIndicator -Visible $true -Label "Tweaks finished" -Percent 100
$sync.ProcessRunning = $false $sync.ProcessRunning = $false
Invoke-WPFUIThread -ScriptBlock { Set-WinUtilTaskbaritem -state "None" -overlay "checkmark" } Invoke-WPFUIThread -ScriptBlock { Set-WinUtilTaskbaritem -state "None" -overlay "checkmark" }
Write-Host "=================================" Write-Host "================================="
+2
View File
@@ -34,11 +34,13 @@ function Invoke-WPFundoall {
for ($i = 0; $i -lt $tweaks.Count; $i++) { for ($i = 0; $i -lt $tweaks.Count; $i++) {
Set-WinUtilProgressBar -Label "Undoing $($tweaks[$i])" -Percent ($i / $tweaks.Count * 100) Set-WinUtilProgressBar -Label "Undoing $($tweaks[$i])" -Percent ($i / $tweaks.Count * 100)
Set-WinUtilTweaksProgressIndicator -Visible $true -Label "Undoing $($tweaks[$i]) ($($i + 1)/$($tweaks.Count))" -Percent ($i / $tweaks.Count * 100)
Invoke-WinUtiltweaks $tweaks[$i] -undo $true Invoke-WinUtiltweaks $tweaks[$i] -undo $true
Invoke-WPFUIThread -ScriptBlock { Set-WinUtilTaskbaritem -value ($i/$tweaks.Count) } Invoke-WPFUIThread -ScriptBlock { Set-WinUtilTaskbaritem -value ($i/$tweaks.Count) }
} }
Set-WinUtilProgressBar -Label "Undo Tweaks Finished" -Percent 100 Set-WinUtilProgressBar -Label "Undo Tweaks Finished" -Percent 100
Set-WinUtilTweaksProgressIndicator -Visible $true -Label "Undo Tweaks Finished" -Percent 100
$sync.ProcessRunning = $false $sync.ProcessRunning = $false
Invoke-WPFUIThread -ScriptBlock { Set-WinUtilTaskbaritem -state "None" -overlay "checkmark" } Invoke-WPFUIThread -ScriptBlock { Set-WinUtilTaskbaritem -state "None" -overlay "checkmark" }
Write-Host "==================================" Write-Host "=================================="
+3
View File
@@ -34,6 +34,9 @@ BeforeAll {
function Set-WinUtilProgressBar { function Set-WinUtilProgressBar {
param($Label, $Percent) param($Label, $Percent)
} }
function Set-WinUtilTweaksProgressIndicator {
param($Visible, $Label, $Percent)
}
function Write-WinUtilLog { function Write-WinUtilLog {
param($Message, $Level, $Component) param($Message, $Level, $Component)
} }
+44
View File
@@ -44,8 +44,17 @@ namespace System.Windows.Controls
. (Join-Path $script:repoRoot "functions\private\Update-WinUtilSelections.ps1") . (Join-Path $script:repoRoot "functions\private\Update-WinUtilSelections.ps1")
. (Join-Path $script:repoRoot "functions\private\Reset-WPFCheckBoxes.ps1") . (Join-Path $script:repoRoot "functions\private\Reset-WPFCheckBoxes.ps1")
. (Join-Path $script:repoRoot "functions\public\Invoke-WPFSelectedCheckboxesUpdate.ps1") . (Join-Path $script:repoRoot "functions\public\Invoke-WPFSelectedCheckboxesUpdate.ps1")
. (Join-Path $script:repoRoot "functions\public\Invoke-WPFButton.ps1")
. (Join-Path $script:repoRoot "functions\public\Invoke-WPFToggleAllCategories.ps1") . (Join-Path $script:repoRoot "functions\public\Invoke-WPFToggleAllCategories.ps1")
function Set-WinUtilProgressBar {
param($Label, $Percent)
}
function Set-WinUtilTweaksProgressIndicator {
param($Visible, $Label, $Percent)
}
function script:New-WinUtilFakeCheckBox { function script:New-WinUtilFakeCheckBox {
param([bool]$IsChecked = $false) param([bool]$IsChecked = $false)
@@ -272,3 +281,38 @@ Describe "Invoke-WPFToggleAllCategories" {
} }
} }
} }
Describe "Invoke-WPFButton progress cleanup" {
BeforeEach {
New-WinUtilUiStateTestContext
Mock Set-WinUtilProgressBar { }
Mock Set-WinUtilTweaksProgressIndicator { }
}
AfterEach {
Remove-Variable -Name sync -Scope Script -ErrorAction SilentlyContinue
Remove-Variable -Name sync -Scope Global -ErrorAction SilentlyContinue
}
It "clears completed progress on the next idle button click" {
$script:sync.ProcessRunning = $false
Invoke-WPFButton -Button "WPFNoOp"
Should -Invoke Set-WinUtilProgressBar -Times 1 -Exactly -ParameterFilter {
$Label -eq "" -and $Percent -eq 0
}
Should -Invoke Set-WinUtilTweaksProgressIndicator -Times 1 -Exactly -ParameterFilter {
$Visible -eq $false
}
}
It "leaves progress visible while a process is running" {
$script:sync.ProcessRunning = $true
Invoke-WPFButton -Button "WPFNoOp"
Should -Not -Invoke Set-WinUtilProgressBar
Should -Not -Invoke Set-WinUtilTweaksProgressIndicator
}
}
+23
View File
@@ -918,12 +918,27 @@
</MultiDataTrigger> </MultiDataTrigger>
</Style.Triggers> </Style.Triggers>
</Style> </Style>
<Style x:Key="RoundedProgressBarStyle" TargetType="ProgressBar">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ProgressBar">
<Border CornerRadius="4" Background="{DynamicResource MainBackgroundColor}" BorderBrush="{DynamicResource MainForegroundColor}" BorderThickness="1">
<Grid ClipToBounds="True">
<Border Name="PART_Track" CornerRadius="4" Background="Transparent"/>
<Border Name="PART_Indicator" CornerRadius="4" Background="{DynamicResource ProgressBarForegroundColor}" HorizontalAlignment="Left"/>
</Grid>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Window.Resources> </Window.Resources>
<Grid Background="{DynamicResource MainBackgroundColor}" ShowGridLines="False" Name="WPFMainGrid" Width="Auto" Height="Auto" HorizontalAlignment="Stretch"> <Grid Background="{DynamicResource MainBackgroundColor}" ShowGridLines="False" Name="WPFMainGrid" Width="Auto" Height="Auto" HorizontalAlignment="Stretch">
<Grid.RowDefinitions> <Grid.RowDefinitions>
<RowDefinition Height="Auto"/> <RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/> <RowDefinition Height="Auto"/>
<RowDefinition Height="*"/> <RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions> </Grid.RowDefinitions>
<Grid.ColumnDefinitions> <Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/> <ColumnDefinition Width="*"/>
@@ -1717,5 +1732,13 @@
</Grid> </Grid>
</TabItem> </TabItem>
</TabControl> </TabControl>
<!-- Tweaks/Undo progress indicator - visible regardless of active tab -->
<Border Name="WPFTweaksProgressBar" Grid.Row="3" Background="{DynamicResource MainBackgroundColor}" Visibility="Collapsed" Padding="10,6">
<StackPanel Orientation="Vertical">
<TextBlock Name="WPFTweaksProgressLabel" Text="" Foreground="{DynamicResource MainForegroundColor}" FontSize="13" Background="Transparent" Margin="0,0,0,4"/>
<ProgressBar Name="WPFTweaksProgressValue" Height="6" Minimum="0" Maximum="100" Value="0" Style="{StaticResource RoundedProgressBarStyle}"/>
</StackPanel>
</Border>
</Grid> </Grid>
</Window> </Window>