Improve & simplify the overview/apply changes pages (#505)

This commit is contained in:
Jeffrey
2026-03-07 14:49:29 +01:00
committed by GitHub
parent b5b67290de
commit a1907c2a78
13 changed files with 1072 additions and 924 deletions

View File

@@ -24,20 +24,13 @@ function ApplySettingsToUiControls {
}
}
# Also uncheck RestorePointCheckBox
$restorePointCheckBox = $window.FindName('RestorePointCheckBox')
if ($restorePointCheckBox) {
$restorePointCheckBox.IsChecked = $false
}
# Apply settings from JSON
foreach ($setting in $settingsJson.Settings) {
if ($setting.Value -ne $true) { continue }
$paramName = $setting.Name
# Handle RestorePointCheckBox separately
# Skip RestorePointCheckBox, this is always checked by default
if ($paramName -eq 'CreateRestorePoint') {
if ($restorePointCheckBox) { $restorePointCheckBox.IsChecked = $true }
continue
}

View File

@@ -74,4 +74,17 @@ function SetWindowThemeResources {
$window.Resources.Add("WarningIconColor", [System.Windows.Media.SolidColorBrush]::new([System.Windows.Media.ColorConverter]::ConvertFromString("#FFB900")))
$window.Resources.Add("ErrorIconColor", [System.Windows.Media.SolidColorBrush]::new([System.Windows.Media.ColorConverter]::ConvertFromString("#E81123")))
$window.Resources.Add("QuestionIconColor", [System.Windows.Media.SolidColorBrush]::new([System.Windows.Media.ColorConverter]::ConvertFromString("#0078D4")))
# Load and merge shared styles
if ($script:SharedStylesSchema -and (Test-Path $script:SharedStylesSchema)) {
$sharedXaml = Get-Content -Path $script:SharedStylesSchema -Raw
$sharedReader = [System.Xml.XmlReader]::Create([System.IO.StringReader]::new($sharedXaml))
try {
$sharedDict = [System.Windows.Markup.XamlReader]::Load($sharedReader)
$window.Resources.MergedDictionaries.Add($sharedDict)
}
finally {
$sharedReader.Close()
}
}
}

View File

@@ -0,0 +1,177 @@
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 { }
}
}

View File

@@ -221,15 +221,7 @@ function Show-MainWindow {
$script:CurrentAppLoadJob = $null
$script:CurrentAppLoadJobStartTime = $null
# Apply Tab UI Elements
$consoleOutput = $window.FindName('ConsoleOutput')
$consoleScrollViewer = $window.FindName('ConsoleScrollViewer')
$finishBtn = $window.FindName('FinishBtn')
$finishBtnText = $window.FindName('FinishBtnText')
# Set script-level variables for Write-ToConsole function
$script:GuiConsoleOutput = $consoleOutput
$script:GuiConsoleScrollViewer = $consoleScrollViewer
# Set script-level variable for GUI window reference
$script:GuiWindow = $window
# Updates app selection status text in the App Selection tab
@@ -972,8 +964,7 @@ function Show-MainWindow {
$totalTabs = $tabControl.Items.Count
$homeIndex = 0
$overviewIndex = $totalTabs - 2
$applyIndex = $totalTabs - 1
$overviewIndex = $totalTabs - 1
# Navigation button visibility
if ($currentIndex -eq $homeIndex) {
@@ -982,26 +973,23 @@ function Show-MainWindow {
} elseif ($currentIndex -eq $overviewIndex) {
$nextBtn.Visibility = 'Collapsed'
$previousBtn.Visibility = 'Visible'
} elseif ($currentIndex -eq $applyIndex) {
$nextBtn.Visibility = 'Collapsed'
$previousBtn.Visibility = 'Collapsed'
} else {
$nextBtn.Visibility = 'Visible'
$previousBtn.Visibility = 'Visible'
}
# Update progress indicators
# Tab indices: 0=Home, 1=App Removal, 2=Tweaks, 3=Overview, 4=Apply
# Tab indices: 0=Home, 1=App Removal, 2=Tweaks, 3=Deployment Settings
$blueColor = "#0067c0"
$greyColor = "#808080"
$progressIndicator1 = $window.FindName('ProgressIndicator1') # App Removal
$progressIndicator2 = $window.FindName('ProgressIndicator2') # Tweaks
$progressIndicator3 = $window.FindName('ProgressIndicator3') # Overview
$progressIndicator3 = $window.FindName('ProgressIndicator3') # Deployment Settings
$bottomNavGrid = $window.FindName('BottomNavGrid')
# Hide bottom navigation on home page and apply tab
if ($currentIndex -eq 0 -or $currentIndex -eq $applyIndex) {
# Hide bottom navigation on home page
if ($currentIndex -eq 0) {
$bottomNavGrid.Visibility = 'Collapsed'
} else {
$bottomNavGrid.Visibility = 'Visible'
@@ -1022,7 +1010,7 @@ function Show-MainWindow {
$progressIndicator2.Fill = $greyColor
}
# Indicator 3 (Overview) - tab index 3
# Indicator 3 (Deployment Settings) - tab index 3
if ($currentIndex -ge 3) {
$progressIndicator3.Fill = $blueColor
} else {
@@ -1142,8 +1130,6 @@ function Show-MainWindow {
function GenerateOverview {
# Load Features.json
$featuresJson = LoadJsonFile -filePath $script:FeaturesFilePath -expectedVersion "1.0"
$overviewChangesPanel = $window.FindName('OverviewChangesPanel')
$overviewChangesPanel.Children.Clear()
$changesList = @()
@@ -1155,7 +1141,7 @@ function Show-MainWindow {
}
}
if ($selectedAppsCount -gt 0) {
$changesList += "Remove $selectedAppsCount selected application(s)"
$changesList += "Remove $selectedAppsCount application(s)"
}
# Update app removal scope section based on whether apps are selected
@@ -1206,20 +1192,19 @@ function Show-MainWindow {
}
}
return $changesList
}
function ShowChangesOverview {
$changesList = GenerateOverview
if ($changesList.Count -eq 0) {
$textBlock = New-Object System.Windows.Controls.TextBlock
$textBlock.Text = "No changes selected"
$textBlock.Style = $window.Resources["OverviewNoChangesTextStyle"]
$overviewChangesPanel.Children.Add($textBlock) | Out-Null
}
else {
foreach ($change in $changesList) {
$bullet = New-Object System.Windows.Controls.TextBlock
$bullet.Text = "- $change"
$bullet.Style = $window.Resources["OverviewChangeBulletStyle"]
$overviewChangesPanel.Children.Add($bullet) | Out-Null
}
Show-MessageBox -Message 'No changes have been selected.' -Title 'Selected Changes' -Button 'OK' -Icon 'Information'
return
}
$message = ($changesList | ForEach-Object { "- $_" }) -join "`n"
Show-MessageBox -Message $message -Title 'Selected Changes' -Button 'OK' -Icon 'None' -Width 600
}
$previousBtn.Add_Click({
@@ -1261,14 +1246,20 @@ function Show-MainWindow {
}
}
# Navigate directly to the Overview tab
# Navigate directly to the Deployment Settings tab
$tabControl.SelectedIndex = 3
UpdateNavigationButtons
})
# Handle Overview Apply Changes button - validates and immediately starts applying changes
$overviewApplyBtn = $window.FindName('OverviewApplyBtn')
$overviewApplyBtn.Add_Click({
# Handle Review Changes link button
$reviewChangesBtn = $window.FindName('ReviewChangesBtn')
$reviewChangesBtn.Add_Click({
ShowChangesOverview
})
# Handle Apply Changes button - validates and immediately starts applying changes
$deploymentApplyBtn = $window.FindName('DeploymentApplyBtn')
$deploymentApplyBtn.Add_Click({
if (-not (ValidateOtherUsername)) {
Show-MessageBox -Message "Please enter a valid username." -Title "Invalid Username" -Button 'OK' -Icon 'Warning' | Out-Null
return
@@ -1381,47 +1372,15 @@ function Show-MainWindow {
SaveSettings
# Navigate to Apply tab (last tab) and start applying changes
$tabControl.SelectedIndex = $tabControl.Items.Count - 1
# Clear console and set initial status
$consoleOutput.Text = ""
# Check if user wants to restart explorer
$restartExplorerCheckBox = $window.FindName('RestartExplorerCheckBox')
$shouldRestartExplorer = $restartExplorerCheckBox -and $restartExplorerCheckBox.IsChecked
Write-ToConsole "Applying changes to $(if ($script:Params.ContainsKey("Sysprep")) { "default user template" } else { "user $(GetUserName)" })"
Write-ToConsole "Total changes to apply: $totalChanges"
Write-ToConsole ""
# Run changes in background to keep UI responsive
$window.Dispatcher.BeginInvoke([System.Windows.Threading.DispatcherPriority]::Background, [action]{
try {
ExecuteAllChanges
# Check if user wants to restart explorer (from checkbox)
$restartExplorerCheckBox = $window.FindName('RestartExplorerCheckBox')
if ($restartExplorerCheckBox -and $restartExplorerCheckBox.IsChecked -and -not $script:CancelRequested) {
RestartExplorer
}
Write-ToConsole ""
if ($script:CancelRequested) {
Write-ToConsole "Script execution was cancelled by the user. Some changes may not have been applied."
} else {
Write-ToConsole "All changes have been applied. Please check the output above for any errors."
}
$finishBtn.Dispatcher.Invoke([action]{
$finishBtn.IsEnabled = $true
$finishBtnText.Text = "Close Win11Debloat"
})
}
catch {
Write-ToConsole "Error: $($_.Exception.Message)"
$finishBtn.Dispatcher.Invoke([action]{
$finishBtn.IsEnabled = $true
$finishBtnText.Text = "Close Win11Debloat"
})
}
})
# Show the apply changes window
Show-ApplyModal -Owner $window -RestartExplorer $shouldRestartExplorer
# Close the main window after the apply dialog closes
$window.Close()
})
# Initialize UI elements on window load
@@ -1460,15 +1419,6 @@ function Show-MainWindow {
UpdateNavigationButtons
})
# Add event handler for tab changes
$tabControl.Add_SelectionChanged({
# Regenerate overview when switching to Overview tab
if ($tabControl.SelectedIndex -eq ($tabControl.Items.Count - 2)) {
GenerateOverview
}
UpdateNavigationButtons
})
# Handle Load Defaults button
$loadDefaultsBtn = $window.FindName('LoadDefaultsBtn')
$loadDefaultsBtn.Add_Click({
@@ -1552,17 +1502,6 @@ function Show-MainWindow {
}
}
}
# Also uncheck RestorePointCheckBox
$restorePointCheckBox = $window.FindName('RestorePointCheckBox')
if ($restorePointCheckBox) {
$restorePointCheckBox.IsChecked = $false
}
})
# Finish (Close Win11Debloat) button handler
$finishBtn.Add_Click({
$window.Close()
})
# Show the window

View File

@@ -16,7 +16,10 @@ function Show-MessageBox {
[string]$Icon = 'None',
[Parameter(Mandatory=$false)]
[System.Windows.Window]$Owner = $null
[System.Windows.Window]$Owner = $null,
[Parameter(Mandatory=$false)]
[int]$Width = 0
)
Add-Type -AssemblyName PresentationFramework,PresentationCore,WindowsBase | Out-Null
@@ -28,11 +31,15 @@ function Show-MessageBox {
# Show overlay if owner window exists
$overlay = $null
$overlayWasAlreadyVisible = $false
if ($ownerWindow) {
try {
$overlay = $ownerWindow.FindName('ModalOverlay')
if ($overlay) {
$ownerWindow.Dispatcher.Invoke([action]{ $overlay.Visibility = 'Visible' })
$overlayWasAlreadyVisible = ($overlay.Visibility -eq 'Visible')
if (-not $overlayWasAlreadyVisible) {
$ownerWindow.Dispatcher.Invoke([action]{ $overlay.Visibility = 'Visible' })
}
}
}
catch { }
@@ -56,6 +63,11 @@ function Show-MessageBox {
catch { }
}
# Apply custom width if specified
if ($Width -gt 0) {
$msgWindow.Width = $Width
}
# Apply theme resources
SetWindowThemeResources -window $msgWindow -usesDarkMode $usesDarkMode
@@ -142,8 +154,8 @@ function Show-MessageBox {
# Show dialog and return result from Tag
$msgWindow.ShowDialog() | Out-Null
# Hide overlay after dialog closes
if ($overlay) {
# Hide overlay after dialog closes (only if this dialog was the one that showed it)
if ($overlay -and -not $overlayWasAlreadyVisible) {
try {
$ownerWindow.Dispatcher.Invoke([action]{ $overlay.Visibility = 'Collapsed' })
}