diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md
index 5cc7eea..cc2683c 100644
--- a/.github/CONTRIBUTING.md
+++ b/.github/CONTRIBUTING.md
@@ -77,7 +77,7 @@ Win11Debloat/
2. **Document Changes**: Update the `README.md` and other relevant documentation. Wiki documentation will be generated/updated based on the `Features.json` and `Apps.json` files.
3. **Follow Existing Patterns**: Look at existing implementations for guidance.
4. **Use Clear Naming**: Choose descriptive names for features, IDs, and registry files.
-5. **Minimal Changes**: Registry files should only modify what's necessary.
+5. **Minimal Changes**: Registry files should only modify what's necessary. Avoid using policies where possible.
6. **Comment Your Code**: Add comments explaining your reasoning for complex logic in PowerShell scripts.
7. **Version Constraints**: Use `MinVersion` and `MaxVersion` if a feature only applies to specific Windows versions.
8. **Limit pull requests to 1 feature**: Keep pull requests limited to just one feature, this makes it easier to review your changes.
diff --git a/Schemas/BubbleHint.xaml b/Schemas/BubbleHint.xaml
new file mode 100644
index 0000000..9dd5ca6
--- /dev/null
+++ b/Schemas/BubbleHint.xaml
@@ -0,0 +1,41 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Schemas/MainWindow.xaml b/Schemas/MainWindow.xaml
index 201e137..426ac2d 100644
--- a/Schemas/MainWindow.xaml
+++ b/Schemas/MainWindow.xaml
@@ -988,7 +988,7 @@
-
+
diff --git a/Schemas/MessageBoxWindow.xaml b/Schemas/MessageBoxWindow.xaml
index 31f391c..0525a9f 100644
--- a/Schemas/MessageBoxWindow.xaml
+++ b/Schemas/MessageBoxWindow.xaml
@@ -3,7 +3,7 @@
Title="MessageBox"
Width="440"
SizeToContent="Height"
- MaxHeight="500"
+ MaxHeight="501"
ResizeMode="NoResize"
WindowStartupLocation="CenterOwner"
WindowStyle="None"
diff --git a/Scripts/GUI/Show-Bubble.ps1 b/Scripts/GUI/Show-Bubble.ps1
new file mode 100644
index 0000000..8c4951f
--- /dev/null
+++ b/Scripts/GUI/Show-Bubble.ps1
@@ -0,0 +1,115 @@
+function Hide-Bubble {
+ param (
+ [Parameter(Mandatory=$false)]
+ [switch]$Immediate
+ )
+
+ if ($script:BubbleTimer) {
+ $script:BubbleTimer.Stop()
+ $script:BubbleTimer = $null
+ }
+
+ if (-not $script:BubblePopup) { return }
+
+ if ($Immediate -or -not $script:BubblePopup.Child) {
+ $script:BubblePopup.IsOpen = $false
+ $script:BubblePopup = $null
+ $script:BubbleIsClosing = $false
+ return
+ }
+
+ if ($script:BubbleIsClosing) { return }
+ $script:BubbleIsClosing = $true
+
+ $bubblePanel = $script:BubblePopup.Child
+ $fadeOut = New-Object System.Windows.Media.Animation.DoubleAnimation
+ $fadeOut.From = [double]$bubblePanel.Opacity
+ $fadeOut.To = 0
+ $fadeOut.Duration = [System.Windows.Duration]::new([TimeSpan]::FromMilliseconds(220))
+ $fadeOut.Add_Completed({
+ if ($script:BubblePopup) {
+ $script:BubblePopup.IsOpen = $false
+ $script:BubblePopup = $null
+ }
+ $script:BubbleIsClosing = $false
+ })
+
+ $bubblePanel.BeginAnimation([System.Windows.UIElement]::OpacityProperty, $fadeOut)
+}
+
+function Show-Bubble {
+ param (
+ [Parameter(Mandatory=$true)]
+ [System.Windows.Controls.Control]$TargetControl,
+
+ [Parameter(Mandatory=$false)]
+ [string]$Message = 'View the selected changes here',
+
+ [Parameter(Mandatory=$false)]
+ [int]$DurationSeconds = 5
+ )
+
+ Add-Type -AssemblyName PresentationFramework,PresentationCore,WindowsBase | Out-Null
+
+ if (-not $TargetControl) { return }
+
+ Hide-Bubble -Immediate
+
+ $xaml = Get-Content -Path $script:BubbleHintSchema -Raw
+ $reader = [System.Xml.XmlReader]::Create([System.IO.StringReader]::new($xaml))
+ try {
+ $bubblePanel = [System.Windows.Markup.XamlReader]::Load($reader)
+ }
+ finally {
+ $reader.Close()
+ }
+
+ $bubbleText = $bubblePanel.FindName('BubbleText')
+ if ($bubbleText) {
+ $bubbleText.Text = $Message
+ }
+
+ $bubblePanel.BeginAnimation([System.Windows.UIElement]::OpacityProperty, $null)
+ $bubblePanel.Opacity = 0
+
+ $popup = New-Object System.Windows.Controls.Primitives.Popup
+ $popup.AllowsTransparency = $true
+ $popup.PopupAnimation = 'None'
+ $popup.StaysOpen = $true
+ $popup.PlacementTarget = $TargetControl
+ $popup.Placement = [System.Windows.Controls.Primitives.PlacementMode]::Top
+ $popup.VerticalOffset = -1
+ $popup.Child = $bubblePanel
+
+ $popup.Add_Opened({
+ param($sender, $e)
+
+ if (-not $sender) { return }
+ $panel = $sender.Child
+ $target = $sender.PlacementTarget
+ if (-not $panel -or -not $target) { return }
+
+ $panel.Measure([System.Windows.Size]::new([double]::PositiveInfinity, [double]::PositiveInfinity))
+ $bubbleWidth = $panel.DesiredSize.Width
+ $targetWidth = $target.ActualWidth
+ $sender.HorizontalOffset = ($targetWidth - $bubbleWidth) / 2
+
+ $fadeIn = New-Object System.Windows.Media.Animation.DoubleAnimation
+ $fadeIn.From = 0
+ $fadeIn.To = 1
+ $fadeIn.BeginTime = [TimeSpan]::FromMilliseconds(30)
+ $fadeIn.Duration = [System.Windows.Duration]::new([TimeSpan]::FromMilliseconds(320))
+ $panel.BeginAnimation([System.Windows.UIElement]::OpacityProperty, $fadeIn)
+ })
+
+ $script:BubbleIsClosing = $false
+ $script:BubblePopup = $popup
+ $script:BubblePopup.IsOpen = $true
+
+ $script:BubbleTimer = New-Object System.Windows.Threading.DispatcherTimer
+ $script:BubbleTimer.Interval = [TimeSpan]::FromSeconds([Math]::Max(1, $DurationSeconds))
+ $script:BubbleTimer.Add_Tick({
+ Hide-Bubble
+ })
+ $script:BubbleTimer.Start()
+}
diff --git a/Scripts/GUI/Show-MainWindow.ps1 b/Scripts/GUI/Show-MainWindow.ps1
index b05f194..7f886f8 100644
--- a/Scripts/GUI/Show-MainWindow.ps1
+++ b/Scripts/GUI/Show-MainWindow.ps1
@@ -1208,6 +1208,7 @@ function Show-MainWindow {
}
$previousBtn.Add_Click({
+ Hide-Bubble -Immediate
if ($tabControl.SelectedIndex -gt 0) {
$tabControl.SelectedIndex--
UpdateNavigationButtons
@@ -1249,11 +1250,17 @@ function Show-MainWindow {
# Navigate directly to the Deployment Settings tab
$tabControl.SelectedIndex = 3
UpdateNavigationButtons
+
+ # Show contextual hint bubble for the Review Changes link
+ $window.Dispatcher.BeginInvoke([System.Windows.Threading.DispatcherPriority]::Loaded, [action]{
+ Show-Bubble -TargetControl $reviewChangesBtn -Message 'View the selected changes here'
+ }) | Out-Null
})
# Handle Review Changes link button
$reviewChangesBtn = $window.FindName('ReviewChangesBtn')
$reviewChangesBtn.Add_Click({
+ Hide-Bubble
ShowChangesOverview
})
@@ -1265,6 +1272,8 @@ function Show-MainWindow {
return
}
+ Hide-Bubble -Immediate
+
# App Removal - collect selected apps from integrated UI
$selectedApps = @()
foreach ($child in $appsPanel.Children) {
diff --git a/Win11Debloat.ps1 b/Win11Debloat.ps1
index 31bcb1b..7976836 100755
--- a/Win11Debloat.ps1
+++ b/Win11Debloat.ps1
@@ -118,6 +118,7 @@ $script:MessageBoxSchema = "$PSScriptRoot/Schemas/MessageBoxWindow.xaml"
$script:AboutWindowSchema = "$PSScriptRoot/Schemas/AboutWindow.xaml"
$script:ApplyChangesWindowSchema = "$PSScriptRoot/Schemas/ApplyChangesWindow.xaml"
$script:SharedStylesSchema = "$PSScriptRoot/Schemas/SharedStyles.xaml"
+$script:BubbleHintSchema = "$PSScriptRoot/Schemas/BubbleHint.xaml"
$script:ControlParams = 'WhatIf', 'Confirm', 'Verbose', 'Debug', 'LogPath', 'Silent', 'Sysprep', 'User', 'NoRestartExplorer', 'RunDefaults', 'RunDefaultsLite', 'RunSavedSettings', 'RunAppsListGenerator', 'CLI', 'AppRemovalTarget'
@@ -167,7 +168,7 @@ else {
}
# Check if script has all required files
-if (-not ((Test-Path $script:DefaultSettingsFilePath) -and (Test-Path $script:AppsListFilePath) -and (Test-Path $script:RegfilesPath) -and (Test-Path $script:AssetsPath) -and (Test-Path $script:AppSelectionSchema) -and (Test-Path $script:ApplyChangesWindowSchema) -and (Test-Path $script:SharedStylesSchema) -and (Test-Path $script:FeaturesFilePath))) {
+if (-not ((Test-Path $script:DefaultSettingsFilePath) -and (Test-Path $script:AppsListFilePath) -and (Test-Path $script:RegfilesPath) -and (Test-Path $script:AssetsPath) -and (Test-Path $script:AppSelectionSchema) -and (Test-Path $script:ApplyChangesWindowSchema) -and (Test-Path $script:SharedStylesSchema) -and (Test-Path $script:BubbleHintSchema) -and (Test-Path $script:FeaturesFilePath))) {
Write-Error "Win11Debloat is unable to find required files, please ensure all script files are present"
Write-Output ""
Write-Output "Press any key to exit..."
@@ -253,6 +254,7 @@ if (-not $script:WingetInstalled -and -not $Silent) {
. "$PSScriptRoot/Scripts/GUI/Show-AppSelectionWindow.ps1"
. "$PSScriptRoot/Scripts/GUI/Show-MainWindow.ps1"
. "$PSScriptRoot/Scripts/GUI/Show-AboutDialog.ps1"
+. "$PSScriptRoot/Scripts/GUI/Show-Bubble.ps1"
# Load File I/O functions
. "$PSScriptRoot/Scripts/FileIO/LoadJsonFile.ps1"