Add bubble hint to guide users to review the selected changes after clicking Default Mode button (#519)

This commit is contained in:
Jeffrey
2026-03-15 20:16:53 +01:00
committed by GitHub
parent 06f8f9eb6a
commit d187679cd0
7 changed files with 171 additions and 4 deletions

View File

@@ -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. 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. 3. **Follow Existing Patterns**: Look at existing implementations for guidance.
4. **Use Clear Naming**: Choose descriptive names for features, IDs, and registry files. 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. 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. 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. 8. **Limit pull requests to 1 feature**: Keep pull requests limited to just one feature, this makes it easier to review your changes.

41
Schemas/BubbleHint.xaml Normal file
View File

@@ -0,0 +1,41 @@
<Grid xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Name="BubblePanel"
SnapsToDevicePixels="True">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Border Name="BubbleBorder"
Grid.Row="0"
Background="{DynamicResource CardBgColor}"
BorderBrush="{DynamicResource ButtonBorderColor}"
BorderThickness="1"
CornerRadius="8"
Padding="10,7,10,7">
<TextBlock Name="BubbleText"
Text="View the selected changes here"
TextWrapping="Wrap"
MaxWidth="260"
Foreground="{DynamicResource FgColor}"/>
</Border>
<Grid Grid.Row="1"
HorizontalAlignment="Center"
Margin="0,-1,0,0"
Width="12"
Height="8">
<Polygon Name="BubblePointer"
Points="0,0 12,0 6,7"
Fill="{DynamicResource CardBgColor}"
Stroke="{DynamicResource ButtonBorderColor}"
StrokeThickness="1"
Stretch="Fill"/>
<Rectangle VerticalAlignment="Top"
Height="2"
Margin="1,-1,1,0"
Fill="{DynamicResource CardBgColor}"/>
</Grid>
</Grid>

View File

@@ -988,7 +988,7 @@
<!-- Review & Apply Section --> <!-- Review & Apply Section -->
<StackPanel Grid.Row="1" HorizontalAlignment="Stretch" Background="{DynamicResource BgColor}"> <StackPanel Grid.Row="1" HorizontalAlignment="Stretch" Background="{DynamicResource BgColor}">
<Button x:Name="ReviewChangesBtn" Background="Transparent" BorderThickness="0" Cursor="Hand" HorizontalAlignment="Center" Margin="0,4,0,8" AutomationProperties.Name="Review selected changes"> <Button x:Name="ReviewChangesBtn" Background="Transparent" BorderThickness="0" Cursor="Hand" HorizontalAlignment="Center" Margin="0,4,0,10" AutomationProperties.Name="Review selected changes">
<Button.Template> <Button.Template>
<ControlTemplate TargetType="Button"> <ControlTemplate TargetType="Button">
<TextBlock x:Name="LinkText" Text="Review selected changes" FontSize="14" Foreground="{DynamicResource ButtonBg}" FontWeight="SemiBold" HorizontalAlignment="Center"/> <TextBlock x:Name="LinkText" Text="Review selected changes" FontSize="14" Foreground="{DynamicResource ButtonBg}" FontWeight="SemiBold" HorizontalAlignment="Center"/>

View File

@@ -3,7 +3,7 @@
Title="MessageBox" Title="MessageBox"
Width="440" Width="440"
SizeToContent="Height" SizeToContent="Height"
MaxHeight="500" MaxHeight="501"
ResizeMode="NoResize" ResizeMode="NoResize"
WindowStartupLocation="CenterOwner" WindowStartupLocation="CenterOwner"
WindowStyle="None" WindowStyle="None"

115
Scripts/GUI/Show-Bubble.ps1 Normal file
View File

@@ -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()
}

View File

@@ -1208,6 +1208,7 @@ function Show-MainWindow {
} }
$previousBtn.Add_Click({ $previousBtn.Add_Click({
Hide-Bubble -Immediate
if ($tabControl.SelectedIndex -gt 0) { if ($tabControl.SelectedIndex -gt 0) {
$tabControl.SelectedIndex-- $tabControl.SelectedIndex--
UpdateNavigationButtons UpdateNavigationButtons
@@ -1249,11 +1250,17 @@ function Show-MainWindow {
# Navigate directly to the Deployment Settings tab # Navigate directly to the Deployment Settings tab
$tabControl.SelectedIndex = 3 $tabControl.SelectedIndex = 3
UpdateNavigationButtons 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 # Handle Review Changes link button
$reviewChangesBtn = $window.FindName('ReviewChangesBtn') $reviewChangesBtn = $window.FindName('ReviewChangesBtn')
$reviewChangesBtn.Add_Click({ $reviewChangesBtn.Add_Click({
Hide-Bubble
ShowChangesOverview ShowChangesOverview
}) })
@@ -1265,6 +1272,8 @@ function Show-MainWindow {
return return
} }
Hide-Bubble -Immediate
# App Removal - collect selected apps from integrated UI # App Removal - collect selected apps from integrated UI
$selectedApps = @() $selectedApps = @()
foreach ($child in $appsPanel.Children) { foreach ($child in $appsPanel.Children) {

View File

@@ -118,6 +118,7 @@ $script:MessageBoxSchema = "$PSScriptRoot/Schemas/MessageBoxWindow.xaml"
$script:AboutWindowSchema = "$PSScriptRoot/Schemas/AboutWindow.xaml" $script:AboutWindowSchema = "$PSScriptRoot/Schemas/AboutWindow.xaml"
$script:ApplyChangesWindowSchema = "$PSScriptRoot/Schemas/ApplyChangesWindow.xaml" $script:ApplyChangesWindowSchema = "$PSScriptRoot/Schemas/ApplyChangesWindow.xaml"
$script:SharedStylesSchema = "$PSScriptRoot/Schemas/SharedStyles.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' $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 # 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-Error "Win11Debloat is unable to find required files, please ensure all script files are present"
Write-Output "" Write-Output ""
Write-Output "Press any key to exit..." 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-AppSelectionWindow.ps1"
. "$PSScriptRoot/Scripts/GUI/Show-MainWindow.ps1" . "$PSScriptRoot/Scripts/GUI/Show-MainWindow.ps1"
. "$PSScriptRoot/Scripts/GUI/Show-AboutDialog.ps1" . "$PSScriptRoot/Scripts/GUI/Show-AboutDialog.ps1"
. "$PSScriptRoot/Scripts/GUI/Show-Bubble.ps1"
# Load File I/O functions # Load File I/O functions
. "$PSScriptRoot/Scripts/FileIO/LoadJsonFile.ps1" . "$PSScriptRoot/Scripts/FileIO/LoadJsonFile.ps1"