diff --git a/config/themes.json b/config/themes.json
index 6bc1b17c..fb4fcddd 100644
--- a/config/themes.json
+++ b/config/themes.json
@@ -100,7 +100,7 @@
"ScrollBarBackgroundColor": "#2E3135",
"ScrollBarHoverColor": "#3B4252",
"ScrollBarDraggingColor": "#5E81AC",
- "ProgressBarForegroundColor": "#222222",
+ "ProgressBarForegroundColor": "#6EFF72",
"ProgressBarBackgroundColor": "Transparent",
"ProgressBarTextColor": "#232629",
"ButtonInstallBackgroundColor": "#222222",
diff --git a/functions/private/Set-WinUtilTweaksProgressIndicator.ps1 b/functions/private/Set-WinUtilTweaksProgressIndicator.ps1
new file mode 100644
index 00000000..cface543
--- /dev/null
+++ b/functions/private/Set-WinUtilTweaksProgressIndicator.ps1
@@ -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
+ }
+ }
+}
diff --git a/functions/public/Invoke-WPFButton.ps1 b/functions/public/Invoke-WPFButton.ps1
index 8a13c378..5a8d3538 100644
--- a/functions/public/Invoke-WPFButton.ps1
+++ b/functions/public/Invoke-WPFButton.ps1
@@ -16,6 +16,7 @@ function Invoke-WPFButton {
#[System.Windows.MessageBox]::Show("$Button","Chris Titus Tech's Windows Utility","OK","Info")
if (-not $sync.ProcessRunning) {
Set-WinUtilProgressBar -label "" -percent 0
+ Set-WinUtilTweaksProgressIndicator -Visible $false
}
# Check if button is defined in feature config with function or InvokeScript
diff --git a/functions/public/Invoke-WPFtweaksbutton.ps1 b/functions/public/Invoke-WPFtweaksbutton.ps1
index f2edb04a..598941a5 100644
--- a/functions/public/Invoke-WPFtweaksbutton.ps1
+++ b/functions/public/Invoke-WPFtweaksbutton.ps1
@@ -40,12 +40,14 @@ function Invoke-WPFtweaksbutton {
}
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."
Invoke-WinUtilTweaks $restorePointTweak
$completedSteps = 1
if ($tweaksToRun.Count -eq 0 -and $dnsProvider -eq "Default") {
Set-WinUtilProgressBar -Label "Tweaks finished" -Percent 100
+ Set-WinUtilTweaksProgressIndicator -Visible $true -Label "Tweaks finished" -Percent 100
$sync.ProcessRunning = $false
Invoke-WPFUIThread -ScriptBlock { Set-WinUtilTaskbaritem -state "None" -overlay "checkmark" }
Write-Host "================================="
@@ -76,12 +78,14 @@ function Invoke-WPFtweaksbutton {
for ($i = 0; $i -lt $tweaks.Count; $i++) {
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]
$completedSteps++
$progress = $completedSteps / $totalSteps
Invoke-WPFUIThread -ScriptBlock { Set-WinUtilTaskbaritem -value $progress }
}
Set-WinUtilProgressBar -Label "Tweaks finished" -Percent 100
+ Set-WinUtilTweaksProgressIndicator -Visible $true -Label "Tweaks finished" -Percent 100
$sync.ProcessRunning = $false
Invoke-WPFUIThread -ScriptBlock { Set-WinUtilTaskbaritem -state "None" -overlay "checkmark" }
Write-Host "================================="
diff --git a/functions/public/Invoke-WPFundoall.ps1 b/functions/public/Invoke-WPFundoall.ps1
index 230dce52..be128136 100644
--- a/functions/public/Invoke-WPFundoall.ps1
+++ b/functions/public/Invoke-WPFundoall.ps1
@@ -34,11 +34,13 @@ function Invoke-WPFundoall {
for ($i = 0; $i -lt $tweaks.Count; $i++) {
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-WPFUIThread -ScriptBlock { Set-WinUtilTaskbaritem -value ($i/$tweaks.Count) }
}
Set-WinUtilProgressBar -Label "Undo Tweaks Finished" -Percent 100
+ Set-WinUtilTweaksProgressIndicator -Visible $true -Label "Undo Tweaks Finished" -Percent 100
$sync.ProcessRunning = $false
Invoke-WPFUIThread -ScriptBlock { Set-WinUtilTaskbaritem -state "None" -overlay "checkmark" }
Write-Host "=================================="
diff --git a/pester/tweaks.Tests.ps1 b/pester/tweaks.Tests.ps1
index bf6cf08a..3b14b1ba 100644
--- a/pester/tweaks.Tests.ps1
+++ b/pester/tweaks.Tests.ps1
@@ -34,6 +34,9 @@ BeforeAll {
function Set-WinUtilProgressBar {
param($Label, $Percent)
}
+ function Set-WinUtilTweaksProgressIndicator {
+ param($Visible, $Label, $Percent)
+ }
function Write-WinUtilLog {
param($Message, $Level, $Component)
}
diff --git a/pester/ui-state.Tests.ps1 b/pester/ui-state.Tests.ps1
index 0b2a9488..2ff6bbf5 100644
--- a/pester/ui-state.Tests.ps1
+++ b/pester/ui-state.Tests.ps1
@@ -44,8 +44,17 @@ namespace System.Windows.Controls
. (Join-Path $script:repoRoot "functions\private\Update-WinUtilSelections.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-WPFButton.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 {
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
+ }
+}
diff --git a/xaml/inputXML.xaml b/xaml/inputXML.xaml
index 45b3d6ff..56eecefb 100644
--- a/xaml/inputXML.xaml
+++ b/xaml/inputXML.xaml
@@ -918,12 +918,27 @@
+
+
@@ -1717,5 +1732,13 @@
+
+
+
+
+
+
+
+