Files
Win11Debloat/Scripts/GUI/Show-ApplyModal.ps1

178 lines
7.2 KiB
PowerShell
Raw Normal View History

function Show-ApplyModal {
param (
[Parameter(Mandatory=$false)]
[System.Windows.Window]$Owner = $null,
[Parameter(Mandatory=$false)]
[bool]$RestartExplorer = $false
)
Add-Type -AssemblyName PresentationFramework,PresentationCore,WindowsBase | Out-Null
$usesDarkMode = GetSystemUsesDarkMode
# Determine owner window
$ownerWindow = if ($Owner) { $Owner } else { $script:GuiWindow }
# Show overlay if owner window exists
$overlay = $null
if ($ownerWindow) {
try {
$overlay = $ownerWindow.FindName('ModalOverlay')
if ($overlay) {
$ownerWindow.Dispatcher.Invoke([action]{ $overlay.Visibility = 'Visible' })
}
}
catch { }
}
# Load XAML from file
$xaml = Get-Content -Path $script:ApplyChangesWindowSchema -Raw
$reader = [System.Xml.XmlReader]::Create([System.IO.StringReader]::new($xaml))
try {
$applyWindow = [System.Windows.Markup.XamlReader]::Load($reader)
}
finally {
$reader.Close()
}
# Set owner to owner window if it exists
if ($ownerWindow) {
try {
$applyWindow.Owner = $ownerWindow
}
catch { }
}
# Apply theme resources
SetWindowThemeResources -window $applyWindow -usesDarkMode $usesDarkMode
# Get UI elements
$script:ApplyInProgressPanel = $applyWindow.FindName('ApplyInProgressPanel')
$script:ApplyCompletionPanel = $applyWindow.FindName('ApplyCompletionPanel')
$script:ApplyStepNameEl = $applyWindow.FindName('ApplyStepName')
$script:ApplyStepCounterEl = $applyWindow.FindName('ApplyStepCounter')
$script:ApplyProgressBarEl = $applyWindow.FindName('ApplyProgressBar')
$script:ApplyCompletionTitleEl = $applyWindow.FindName('ApplyCompletionTitle')
$script:ApplyCompletionMessageEl = $applyWindow.FindName('ApplyCompletionMessage')
$script:ApplyCompletionIconEl = $applyWindow.FindName('ApplyCompletionIcon')
$applyCloseBtn = $applyWindow.FindName('ApplyCloseBtn')
$applyKofiBtn = $applyWindow.FindName('ApplyKofiBtn')
$applyCancelBtn = $applyWindow.FindName('ApplyCancelBtn')
# Initialize in-progress state
$script:ApplyInProgressPanel.Visibility = 'Visible'
$script:ApplyCompletionPanel.Visibility = 'Collapsed'
$script:ApplyStepNameEl.Text = "Preparing..."
$script:ApplyStepCounterEl.Text = "Preparing..."
$script:ApplyProgressBarEl.Value = 0
# Set up progress callback for ExecuteAllChanges
$script:ApplyProgressCallback = {
param($currentStep, $totalSteps, $stepName)
$script:ApplyStepNameEl.Text = $stepName
$script:ApplyStepCounterEl.Text = "Step $currentStep of $totalSteps"
# Store current step/total in Tag properties for sub-step interpolation
$script:ApplyStepCounterEl.Tag = $currentStep
$script:ApplyProgressBarEl.Tag = $totalSteps
# Show progress at the start of each step (empty at step 1, full after last step completes)
$pct = if ($totalSteps -gt 0) { [math]::Round((($currentStep - 1) / $totalSteps) * 100) } else { 0 }
$script:ApplyProgressBarEl.Value = $pct
# Process pending window messages to keep UI responsive
DoEvents
}
# Sub-step callback updates step name and interpolates progress bar within the current step
$script:ApplySubStepCallback = {
param($subStepName, $subIndex, $subCount)
$script:ApplyStepNameEl.Text = $subStepName
# Interpolate progress bar between previous step and current step
$currentStep = [int]($script:ApplyStepCounterEl.Tag)
$totalSteps = [int]($script:ApplyProgressBarEl.Tag)
if ($totalSteps -gt 0 -and $subCount -gt 0) {
$baseProgress = ($currentStep - 1) / $totalSteps
$stepFraction = ($subIndex / $subCount) / $totalSteps
$script:ApplyProgressBarEl.Value = [math]::Round(($baseProgress + $stepFraction) * 100)
}
DoEvents
}
# Run changes in background to keep UI responsive
$applyWindow.Dispatcher.BeginInvoke([System.Windows.Threading.DispatcherPriority]::Background, [action]{
try {
ExecuteAllChanges
# Restart explorer if requested
if ($RestartExplorer -and -not $script:CancelRequested) {
RestartExplorer
}
Write-Host ""
if ($script:CancelRequested) {
Write-Host "Script execution was cancelled by the user. Some changes may not have been applied."
} else {
Write-Host "All changes have been applied successfully."
}
# Show completion state
$script:ApplyProgressBarEl.Value = 100
$script:ApplyInProgressPanel.Visibility = 'Collapsed'
$script:ApplyCompletionPanel.Visibility = 'Visible'
if ($script:CancelRequested) {
$script:ApplyCompletionIconEl.Text = [char]0xE7BA
$script:ApplyCompletionIconEl.Foreground = [System.Windows.Media.SolidColorBrush]::new([System.Windows.Media.ColorConverter]::ConvertFromString("#e8912d"))
$script:ApplyCompletionTitleEl.Text = "Cancelled"
$script:ApplyCompletionMessageEl.Text = "Script execution was cancelled by the user."
} else {
$script:ApplyCompletionTitleEl.Text = "Changes Applied"
$script:ApplyCompletionMessageEl.Text = "All changes have been applied successfully!"
}
$applyWindow.Dispatcher.Invoke([System.Windows.Threading.DispatcherPriority]::Render, [action]{})
}
catch {
Write-Host "Error: $($_.Exception.Message)"
$script:ApplyInProgressPanel.Visibility = 'Collapsed'
$script:ApplyCompletionPanel.Visibility = 'Visible'
$script:ApplyCompletionIconEl.Text = [char]0xEA39
$script:ApplyCompletionIconEl.Foreground = [System.Windows.Media.SolidColorBrush]::new([System.Windows.Media.ColorConverter]::ConvertFromString("#c42b1c"))
$script:ApplyCompletionTitleEl.Text = "Error"
$script:ApplyCompletionMessageEl.Text = "An error occurred while applying changes: $($_.Exception.Message)"
$applyWindow.Dispatcher.Invoke([System.Windows.Threading.DispatcherPriority]::Render, [action]{})
}
finally {
$script:ApplyProgressCallback = $null
$script:ApplySubStepCallback = $null
}
})
# Button handlers
$applyCloseBtn.Add_Click({
$applyWindow.Close()
})
$applyKofiBtn.Add_Click({
Start-Process "https://ko-fi.com/raphire"
})
$applyCancelBtn.Add_Click({
if ($script:ApplyCompletionPanel.Visibility -eq 'Visible') {
# Completion state - just close
$applyWindow.Close()
} else {
# In-progress state - request cancellation
$script:CancelRequested = $true
}
})
# Show dialog
$applyWindow.ShowDialog() | Out-Null
# Hide overlay after dialog closes
if ($overlay) {
try {
$ownerWindow.Dispatcher.Invoke([action]{ $overlay.Visibility = 'Collapsed' })
}
catch { }
}
}