mirror of
https://github.com/Raphire/Win11Debloat.git
synced 2026-05-18 11:46:18 +00:00
Improve app & tweak selection UI (#558)
This commit is contained in:
@@ -748,6 +748,7 @@
|
|||||||
</Style>
|
</Style>
|
||||||
</ToggleButton.Style>
|
</ToggleButton.Style>
|
||||||
<StackPanel Orientation="Horizontal">
|
<StackPanel Orientation="Horizontal">
|
||||||
|
<TextBlock Text="" FontFamily="Segoe Fluent Icons" FontSize="14" VerticalAlignment="Center" Margin="0,0,6,0"/>
|
||||||
<TextBlock Text="Quick Select" FontSize="13" VerticalAlignment="Center" Margin="0,0,6,0"/>
|
<TextBlock Text="Quick Select" FontSize="13" VerticalAlignment="Center" Margin="0,0,6,0"/>
|
||||||
<TextBlock x:Name="PresetsArrow" Text="" FontFamily="Segoe Fluent Icons" FontSize="10" VerticalAlignment="Center" RenderTransformOrigin="0.5,0.5">
|
<TextBlock x:Name="PresetsArrow" Text="" FontFamily="Segoe Fluent Icons" FontSize="10" VerticalAlignment="Center" RenderTransformOrigin="0.5,0.5">
|
||||||
<TextBlock.RenderTransform>
|
<TextBlock.RenderTransform>
|
||||||
@@ -756,15 +757,20 @@
|
|||||||
</TextBlock>
|
</TextBlock>
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
</ToggleButton>
|
</ToggleButton>
|
||||||
<Button x:Name="ClearAppSelectionBtn" Content="Clear Selection" ToolTip="Clear all selected apps" Style="{DynamicResource SecondaryButtonStyle}" Height="32" Padding="10,0" Margin="0,0,10,0" AutomationProperties.Name="Clear Selection"/>
|
<Button x:Name="ClearAppSelectionBtn" ToolTip="Clear all selected apps" Style="{DynamicResource SecondaryButtonStyle}" Height="32" Padding="10,0" Margin="0,0,10,0" AutomationProperties.Name="Clear Selection">
|
||||||
|
<StackPanel Orientation="Horizontal" VerticalAlignment="Center">
|
||||||
|
<TextBlock Text="" FontFamily="Segoe Fluent Icons" FontSize="14" VerticalAlignment="Center" Margin="0,0,6,0"/>
|
||||||
|
<TextBlock Text="Clear Selection" FontSize="13" VerticalAlignment="Center" Margin="0,0,0,1"/>
|
||||||
|
</StackPanel>
|
||||||
|
</Button>
|
||||||
<Popup x:Name="PresetsPopup" PlacementTarget="{Binding ElementName=PresetsBtn}" Placement="Bottom" StaysOpen="True" AllowsTransparency="True" VerticalOffset="2">
|
<Popup x:Name="PresetsPopup" PlacementTarget="{Binding ElementName=PresetsBtn}" Placement="Bottom" StaysOpen="True" AllowsTransparency="True" VerticalOffset="2">
|
||||||
<Border Background="{DynamicResource CardBgColor}" BorderBrush="{DynamicResource BorderColor}" BorderThickness="1" CornerRadius="6" Padding="4,6" Margin="12">
|
<Border Background="{DynamicResource CardBgColor}" BorderBrush="{DynamicResource BorderColor}" BorderThickness="1" CornerRadius="6" Padding="4,6" Margin="12">
|
||||||
<Border.Effect>
|
<Border.Effect>
|
||||||
<DropShadowEffect BlurRadius="12" Opacity="0.25" ShadowDepth="4"/>
|
<DropShadowEffect BlurRadius="12" Opacity="0.25" ShadowDepth="4"/>
|
||||||
</Border.Effect>
|
</Border.Effect>
|
||||||
<StackPanel x:Name="PresetsPanel" MinWidth="220">
|
<StackPanel x:Name="PresetsPanel" MinWidth="220">
|
||||||
<CheckBox x:Name="PresetDefaultApps" Content="Default selection" IsThreeState="True" Foreground="{DynamicResource FgColor}" Margin="8,4" AutomationProperties.Name="Default selection"/>
|
<CheckBox x:Name="PresetDefaultApps" Content="Default apps" IsThreeState="True" ToolTip="Select the apps that are safe to remove for most users" Foreground="{DynamicResource FgColor}" Margin="8,4" AutomationProperties.Name="Default selection"/>
|
||||||
<CheckBox x:Name="PresetLastUsed" Content="Last used selection" IsThreeState="True" Foreground="{DynamicResource FgColor}" Margin="8,4" AutomationProperties.Name="Last used selection"/>
|
<CheckBox x:Name="PresetLastUsed" Content="Last used apps" IsThreeState="True" ToolTip="Select the apps that were removed the last time Win11Debloat was run" Foreground="{DynamicResource FgColor}" Margin="8,4" AutomationProperties.Name="Last used selection"/>
|
||||||
<Separator Margin="4,6" Background="{DynamicResource BorderColor}"/>
|
<Separator Margin="4,6" Background="{DynamicResource BorderColor}"/>
|
||||||
<StackPanel x:Name="JsonPresetsPanel"/>
|
<StackPanel x:Name="JsonPresetsPanel"/>
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
@@ -895,9 +901,67 @@
|
|||||||
</Grid.ColumnDefinitions>
|
</Grid.ColumnDefinitions>
|
||||||
|
|
||||||
<StackPanel Grid.Column="0" Orientation="Horizontal">
|
<StackPanel Grid.Column="0" Orientation="Horizontal">
|
||||||
<Button x:Name="LoadDefaultsBtn" Content="Select Default Settings" ToolTip="Select the settings that are recommended for most people" Style="{DynamicResource SecondaryButtonStyle}" Padding="10,0" Height="32" Margin="0,0,10,0" AutomationProperties.Name="Select Default Settings"/>
|
<ToggleButton x:Name="TweaksPresetsBtn" ToolTip="Select tweak presets" Height="32" Padding="10,0" Margin="0,0,10,0" AutomationProperties.Name="Tweak Presets">
|
||||||
<Button x:Name="LoadLastUsedBtn" Content="Select Last Used Settings" ToolTip="Select the settings that were used the last time Win11Debloat was run" Style="{DynamicResource SecondaryButtonStyle}" Padding="10,0" Height="32" Margin="0,0,10,0" AutomationProperties.Name="Select Last Used Settings"/>
|
<ToggleButton.Style>
|
||||||
<Button x:Name="ClearAllTweaksBtn" Content="Clear Selection" ToolTip="Clear all selected tweaks" Style="{DynamicResource SecondaryButtonStyle}" Padding="10,0" Height="32" Margin="0,0,10,0" AutomationProperties.Name="Clear Selection"/>
|
<Style TargetType="ToggleButton">
|
||||||
|
<Setter Property="Background" Value="{DynamicResource SecondaryButtonBg}"/>
|
||||||
|
<Setter Property="Foreground" Value="{DynamicResource FgColor}"/>
|
||||||
|
<Setter Property="BorderBrush" Value="{DynamicResource ButtonBorderColor}"/>
|
||||||
|
<Setter Property="BorderThickness" Value="1"/>
|
||||||
|
<Setter Property="FontSize" Value="14"/>
|
||||||
|
<Setter Property="Cursor" Value="Hand"/>
|
||||||
|
<Setter Property="Template">
|
||||||
|
<Setter.Value>
|
||||||
|
<ControlTemplate TargetType="ToggleButton">
|
||||||
|
<Border x:Name="Border" Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" CornerRadius="4" Padding="{TemplateBinding Padding}">
|
||||||
|
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center" Margin="0,0,0,1"/>
|
||||||
|
</Border>
|
||||||
|
</ControlTemplate>
|
||||||
|
</Setter.Value>
|
||||||
|
</Setter>
|
||||||
|
<Style.Triggers>
|
||||||
|
<Trigger Property="IsMouseOver" Value="True">
|
||||||
|
<Setter Property="Background" Value="{DynamicResource SecondaryButtonHover}"/>
|
||||||
|
</Trigger>
|
||||||
|
<Trigger Property="IsPressed" Value="True">
|
||||||
|
<Setter Property="Background" Value="{DynamicResource SecondaryButtonPressed}"/>
|
||||||
|
</Trigger>
|
||||||
|
<Trigger Property="IsChecked" Value="True">
|
||||||
|
<Setter Property="Background" Value="{DynamicResource SecondaryButtonHover}"/>
|
||||||
|
</Trigger>
|
||||||
|
</Style.Triggers>
|
||||||
|
</Style>
|
||||||
|
</ToggleButton.Style>
|
||||||
|
<StackPanel Orientation="Horizontal">
|
||||||
|
<TextBlock Text="" FontFamily="Segoe Fluent Icons" FontSize="14" VerticalAlignment="Center" Margin="0,1,6,0"/>
|
||||||
|
<TextBlock Text="Quick Select" FontSize="13" VerticalAlignment="Center" Margin="0,0,6,0"/>
|
||||||
|
<TextBlock x:Name="TweaksPresetsArrow" Text="" FontFamily="Segoe Fluent Icons" FontSize="10" VerticalAlignment="Center" RenderTransformOrigin="0.5,0.5">
|
||||||
|
<TextBlock.RenderTransform>
|
||||||
|
<RotateTransform Angle="0"/>
|
||||||
|
</TextBlock.RenderTransform>
|
||||||
|
</TextBlock>
|
||||||
|
</StackPanel>
|
||||||
|
</ToggleButton>
|
||||||
|
<Button x:Name="ClearAllTweaksBtn" ToolTip="Clear all selected tweaks" Style="{DynamicResource SecondaryButtonStyle}" Padding="10,0" Height="32" Margin="0,0,10,0" AutomationProperties.Name="Clear Selection">
|
||||||
|
<StackPanel Orientation="Horizontal" VerticalAlignment="Center">
|
||||||
|
<TextBlock Text="" FontFamily="Segoe Fluent Icons" FontSize="14" VerticalAlignment="Center" Margin="0,0,6,0"/>
|
||||||
|
<TextBlock Text="Clear Selection" FontSize="13" VerticalAlignment="Center" Margin="0,0,0,1"/>
|
||||||
|
</StackPanel>
|
||||||
|
</Button>
|
||||||
|
<Popup x:Name="TweaksPresetsPopup" PlacementTarget="{Binding ElementName=TweaksPresetsBtn}" Placement="Bottom" StaysOpen="True" AllowsTransparency="True" VerticalOffset="2">
|
||||||
|
<Border Background="{DynamicResource CardBgColor}" BorderBrush="{DynamicResource BorderColor}" BorderThickness="1" CornerRadius="6" Padding="4,6" Margin="12">
|
||||||
|
<Border.Effect>
|
||||||
|
<DropShadowEffect BlurRadius="12" Opacity="0.25" ShadowDepth="4"/>
|
||||||
|
</Border.Effect>
|
||||||
|
<StackPanel MinWidth="220">
|
||||||
|
<CheckBox x:Name="PresetDefaultTweaksBtn" Content="Default settings" IsThreeState="True" ToolTip="Select the settings that are recommended for most people" Foreground="{DynamicResource FgColor}" Style="{DynamicResource PresetCheckBoxStyle}" AutomationProperties.Name="Default settings"/>
|
||||||
|
<CheckBox x:Name="PresetLastUsedTweaksBtn" Content="Last used settings" IsThreeState="True" ToolTip="Select the settings that were used the last time Win11Debloat was run" Foreground="{DynamicResource FgColor}" Style="{DynamicResource PresetCheckBoxStyle}" AutomationProperties.Name="Last used settings"/>
|
||||||
|
<Separator Margin="4,6" Background="{DynamicResource BorderColor}"/>
|
||||||
|
<CheckBox x:Name="PresetPrivacyTweaksBtn" Content="Privacy & Suggested Content" IsThreeState="True" ToolTip="Select all Privacy & Suggested Content tweaks" Foreground="{DynamicResource FgColor}" Style="{DynamicResource PresetCheckBoxStyle}" AutomationProperties.Name="All Privacy and Suggested Content"/>
|
||||||
|
<CheckBox x:Name="PresetAITweaksBtn" Content="AI features" IsThreeState="True" ToolTip="Select all AI feature tweaks" Foreground="{DynamicResource FgColor}" Style="{DynamicResource PresetCheckBoxStyle}" AutomationProperties.Name="All AI features"/>
|
||||||
|
</StackPanel>
|
||||||
|
</Border>
|
||||||
|
</Popup>
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
|
|
||||||
<Border x:Name="TweakSearchBorder" Grid.Column="2">
|
<Border x:Name="TweakSearchBorder" Grid.Column="2">
|
||||||
|
|||||||
@@ -287,21 +287,75 @@ function Show-MainWindow {
|
|||||||
$jsonPresetsPanel = $window.FindName('JsonPresetsPanel')
|
$jsonPresetsPanel = $window.FindName('JsonPresetsPanel')
|
||||||
$presetsArrow = $window.FindName('PresetsArrow')
|
$presetsArrow = $window.FindName('PresetsArrow')
|
||||||
$clearAppSelectionBtn = $window.FindName('ClearAppSelectionBtn')
|
$clearAppSelectionBtn = $window.FindName('ClearAppSelectionBtn')
|
||||||
|
$tweaksPresetsBtn = $window.FindName('TweaksPresetsBtn')
|
||||||
|
$tweaksPresetsPopup = $window.FindName('TweaksPresetsPopup')
|
||||||
|
$presetDefaultTweaksBtn = $window.FindName('PresetDefaultTweaksBtn')
|
||||||
|
$presetLastUsedTweaksBtn = $window.FindName('PresetLastUsedTweaksBtn')
|
||||||
|
$presetPrivacyTweaksBtn = $window.FindName('PresetPrivacyTweaksBtn')
|
||||||
|
$presetAITweaksBtn = $window.FindName('PresetAITweaksBtn')
|
||||||
|
$tweaksPresetsArrow = $window.FindName('TweaksPresetsArrow')
|
||||||
|
|
||||||
|
function AttachTriStateClickBehavior {
|
||||||
|
param([System.Windows.Controls.CheckBox]$checkBox)
|
||||||
|
|
||||||
|
if (-not $checkBox -or -not $checkBox.IsThreeState) { return }
|
||||||
|
|
||||||
|
if (-not $checkBox.PSObject.Properties['WasIndeterminateBeforeClick']) {
|
||||||
|
Add-Member -InputObject $checkBox -MemberType NoteProperty -Name 'WasIndeterminateBeforeClick' -Value $false
|
||||||
|
}
|
||||||
|
|
||||||
|
$checkBox.Add_PreviewMouseLeftButtonDown({
|
||||||
|
$this.WasIndeterminateBeforeClick = ($this.IsChecked -eq [System.Nullable[bool]]$null)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
function NormalizeCheckboxState {
|
function NormalizeCheckboxState {
|
||||||
param([System.Windows.Controls.CheckBox]$checkBox)
|
param([System.Windows.Controls.CheckBox]$checkBox)
|
||||||
|
|
||||||
$isChecked = ($checkBox.IsChecked -eq $true)
|
if ($checkBox.PSObject.Properties['WasIndeterminateBeforeClick'] -and $checkBox.WasIndeterminateBeforeClick) {
|
||||||
if ($null -eq $checkBox.IsChecked) {
|
# WPF toggles null -> false before Click handlers fire; restore desired mixed -> checked behavior.
|
||||||
$checkBox.IsChecked = $false
|
$checkBox.WasIndeterminateBeforeClick = $false
|
||||||
return $false
|
$checkBox.IsChecked = $true
|
||||||
|
return $true
|
||||||
}
|
}
|
||||||
|
|
||||||
return $isChecked
|
return ($checkBox.IsChecked -eq $true)
|
||||||
}
|
}
|
||||||
|
|
||||||
function AnimatePresetsArrow {
|
function SetTriStatePresetCheckBoxState {
|
||||||
param([double]$angle)
|
param(
|
||||||
|
[System.Windows.Controls.CheckBox]$CheckBox,
|
||||||
|
[int]$Total,
|
||||||
|
[int]$Selected
|
||||||
|
)
|
||||||
|
|
||||||
|
if (-not $CheckBox) { return }
|
||||||
|
|
||||||
|
if ($Total -eq 0) {
|
||||||
|
$CheckBox.IsEnabled = $false
|
||||||
|
$CheckBox.IsChecked = $false
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
$CheckBox.IsEnabled = $true
|
||||||
|
if ($Selected -eq 0) {
|
||||||
|
$CheckBox.IsChecked = $false
|
||||||
|
}
|
||||||
|
elseif ($Selected -eq $Total) {
|
||||||
|
$CheckBox.IsChecked = $true
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$CheckBox.IsChecked = [System.Nullable[bool]]$null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function AnimateDropdownArrow {
|
||||||
|
param(
|
||||||
|
[System.Windows.Controls.TextBlock]$arrow,
|
||||||
|
[double]$angle
|
||||||
|
)
|
||||||
|
|
||||||
|
if (-not $arrow) { return }
|
||||||
|
|
||||||
$animation = New-Object System.Windows.Media.Animation.DoubleAnimation
|
$animation = New-Object System.Windows.Media.Animation.DoubleAnimation
|
||||||
$animation.To = $angle
|
$animation.To = $angle
|
||||||
@@ -311,7 +365,7 @@ function Show-MainWindow {
|
|||||||
$ease.EasingMode = 'EaseOut'
|
$ease.EasingMode = 'EaseOut'
|
||||||
$animation.EasingFunction = $ease
|
$animation.EasingFunction = $ease
|
||||||
|
|
||||||
$presetsArrow.RenderTransform.BeginAnimation([System.Windows.Media.RotateTransform]::AngleProperty, $animation)
|
$arrow.RenderTransform.BeginAnimation([System.Windows.Media.RotateTransform]::AngleProperty, $animation)
|
||||||
}
|
}
|
||||||
|
|
||||||
# Load JSON-defined presets and build dynamic preset checkboxes
|
# Load JSON-defined presets and build dynamic preset checkboxes
|
||||||
@@ -321,15 +375,17 @@ function Show-MainWindow {
|
|||||||
$checkbox.Content = $preset.Name
|
$checkbox.Content = $preset.Name
|
||||||
$checkbox.IsThreeState = $true
|
$checkbox.IsThreeState = $true
|
||||||
$checkbox.Style = $window.Resources['PresetCheckBoxStyle']
|
$checkbox.Style = $window.Resources['PresetCheckBoxStyle']
|
||||||
|
$checkbox.ToolTip = "Select $($preset.Name)"
|
||||||
$checkbox.SetValue([System.Windows.Automation.AutomationProperties]::NameProperty, $preset.Name)
|
$checkbox.SetValue([System.Windows.Automation.AutomationProperties]::NameProperty, $preset.Name)
|
||||||
|
AttachTriStateClickBehavior -checkBox $checkbox
|
||||||
Add-Member -InputObject $checkbox -MemberType NoteProperty -Name 'PresetAppIds' -Value $preset.AppIds
|
Add-Member -InputObject $checkbox -MemberType NoteProperty -Name 'PresetAppIds' -Value $preset.AppIds
|
||||||
$jsonPresetsPanel.Children.Add($checkbox) | Out-Null
|
$jsonPresetsPanel.Children.Add($checkbox) | Out-Null
|
||||||
$script:JsonPresetCheckboxes += $checkbox
|
$script:JsonPresetCheckboxes += $checkbox
|
||||||
|
|
||||||
$checkbox.Add_Click({
|
$checkbox.Add_Click({
|
||||||
if ($script:UpdatingPresets) { return }
|
if ($script:UpdatingPresets) { return }
|
||||||
$check = NormalizeCheckboxState -checkBox $this
|
|
||||||
$presetIds = $this.PresetAppIds
|
$presetIds = $this.PresetAppIds
|
||||||
|
$check = NormalizeCheckboxState -checkBox $this
|
||||||
ApplyPresetToApps -MatchFilter { param($c) (@($c.AppIds) | Where-Object { $presetIds -contains $_ }).Count -gt 0 }.GetNewClosure() -Check $check
|
ApplyPresetToApps -MatchFilter { param($c) (@($c.AppIds) | Where-Object { $presetIds -contains $_ }).Count -gt 0 }.GetNewClosure() -Check $check
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -354,6 +410,7 @@ function Show-MainWindow {
|
|||||||
|
|
||||||
# Guard flag to prevent preset handlers from firing when we update their state programmatically
|
# Guard flag to prevent preset handlers from firing when we update their state programmatically
|
||||||
$script:UpdatingPresets = $false
|
$script:UpdatingPresets = $false
|
||||||
|
$script:UpdatingTweakPresets = $false
|
||||||
|
|
||||||
# Sort state for the app table
|
# Sort state for the app table
|
||||||
$script:SortColumn = 'Name'
|
$script:SortColumn = 'Name'
|
||||||
@@ -484,19 +541,7 @@ function Show-MainWindow {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ($total -eq 0) {
|
SetTriStatePresetCheckBoxState -CheckBox $checkbox -Total $total -Selected $checked
|
||||||
$checkbox.IsChecked = $false
|
|
||||||
$checkbox.IsEnabled = $false
|
|
||||||
} else {
|
|
||||||
$checkbox.IsEnabled = $true
|
|
||||||
if ($checked -eq 0) {
|
|
||||||
$checkbox.IsChecked = $false
|
|
||||||
} elseif ($checked -eq $total) {
|
|
||||||
$checkbox.IsChecked = $true
|
|
||||||
} else {
|
|
||||||
$checkbox.IsChecked = [System.Nullable[bool]]$null
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
SetPresetState $presetDefaultApps { param($c) $c.SelectedByDefault -eq $true }
|
SetPresetState $presetDefaultApps { param($c) $c.SelectedByDefault -eq $true }
|
||||||
@@ -772,7 +817,7 @@ function Show-MainWindow {
|
|||||||
try { $lblBorderObj = $window.FindName("$comboName`_LabelBorder") } catch {}
|
try { $lblBorderObj = $window.FindName("$comboName`_LabelBorder") } catch {}
|
||||||
if ($lblBorderObj) { $lblBorderObj.ToolTip = $tipBlock }
|
if ($lblBorderObj) { $lblBorderObj.ToolTip = $tipBlock }
|
||||||
}
|
}
|
||||||
$script:UiControlMappings[$comboName] = @{ Type='group'; Values = $group.Values; Label = $group.Label }
|
$script:UiControlMappings[$comboName] = @{ Type='group'; Values = $group.Values; Label = $group.Label; Category = $categoryName }
|
||||||
}
|
}
|
||||||
elseif ($item.Type -eq 'feature') {
|
elseif ($item.Type -eq 'feature') {
|
||||||
$feature = $item.Data
|
$feature = $item.Data
|
||||||
@@ -792,7 +837,7 @@ function Show-MainWindow {
|
|||||||
try { $lblBorderObj = $window.FindName("$comboName`_LabelBorder") } catch {}
|
try { $lblBorderObj = $window.FindName("$comboName`_LabelBorder") } catch {}
|
||||||
if ($lblBorderObj) { $lblBorderObj.ToolTip = $tipBlock }
|
if ($lblBorderObj) { $lblBorderObj.ToolTip = $tipBlock }
|
||||||
}
|
}
|
||||||
$script:UiControlMappings[$comboName] = @{ Type='feature'; FeatureId = $feature.FeatureId; Action = $feature.Action; Label = $feature.Label }
|
$script:UiControlMappings[$comboName] = @{ Type='feature'; FeatureId = $feature.FeatureId; Action = $feature.Action; Label = $feature.Label; Category = $categoryName }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -989,27 +1034,45 @@ function Show-MainWindow {
|
|||||||
# Animate arrow when popup opens/closes, and lazily update preset states
|
# Animate arrow when popup opens/closes, and lazily update preset states
|
||||||
$presetsPopup.Add_Opened({
|
$presetsPopup.Add_Opened({
|
||||||
UpdatePresetStates
|
UpdatePresetStates
|
||||||
AnimatePresetsArrow -angle 180
|
AnimateDropdownArrow -arrow $presetsArrow -angle 180
|
||||||
})
|
})
|
||||||
$presetsPopup.Add_Closed({
|
$presetsPopup.Add_Closed({
|
||||||
AnimatePresetsArrow -angle 0
|
AnimateDropdownArrow -arrow $presetsArrow -angle 0
|
||||||
$presetsBtn.IsChecked = $false
|
$presetsBtn.IsChecked = $false
|
||||||
})
|
})
|
||||||
|
|
||||||
|
$tweaksPresetsPopup.Add_Opened({
|
||||||
|
UpdateTweakPresetStates
|
||||||
|
AnimateDropdownArrow -arrow $tweaksPresetsArrow -angle 180
|
||||||
|
})
|
||||||
|
$tweaksPresetsPopup.Add_Closed({
|
||||||
|
AnimateDropdownArrow -arrow $tweaksPresetsArrow -angle 0
|
||||||
|
$tweaksPresetsBtn.IsChecked = $false
|
||||||
|
})
|
||||||
|
|
||||||
# Close popup when clicking anywhere outside the popup or the presets button.
|
# Close popup when clicking anywhere outside the popup or the presets button.
|
||||||
$window.Add_PreviewMouseDown({
|
$window.Add_PreviewMouseDown({
|
||||||
if (-not $presetsPopup.IsOpen) { return }
|
$isAppPopupOpen = $presetsPopup.IsOpen
|
||||||
if ($null -ne $presetsPopup.Child -and $presetsPopup.Child.IsMouseOver) { return }
|
$isTweaksPopupOpen = $tweaksPresetsPopup.IsOpen
|
||||||
|
if (-not $isAppPopupOpen -and -not $isTweaksPopupOpen) { return }
|
||||||
|
|
||||||
|
if ($isAppPopupOpen -and $null -ne $presetsPopup.Child -and $presetsPopup.Child.IsMouseOver) { return }
|
||||||
|
if ($isTweaksPopupOpen -and $null -ne $tweaksPresetsPopup.Child -and $tweaksPresetsPopup.Child.IsMouseOver) { return }
|
||||||
|
|
||||||
$src = $_.OriginalSource -as [System.Windows.DependencyObject]
|
$src = $_.OriginalSource -as [System.Windows.DependencyObject]
|
||||||
if ($null -ne $src) {
|
if ($null -ne $src) {
|
||||||
$inBtn = $presetsBtn.IsAncestorOf($src) -or [System.Object]::ReferenceEquals($presetsBtn, $src)
|
$inAppBtn = $presetsBtn.IsAncestorOf($src) -or [System.Object]::ReferenceEquals($presetsBtn, $src)
|
||||||
if (-not $inBtn) { $presetsPopup.IsOpen = $false }
|
$inTweaksBtn = $tweaksPresetsBtn.IsAncestorOf($src) -or [System.Object]::ReferenceEquals($tweaksPresetsBtn, $src)
|
||||||
|
|
||||||
|
if ($isAppPopupOpen -and -not $inAppBtn) { $presetsPopup.IsOpen = $false }
|
||||||
|
if ($isTweaksPopupOpen -and -not $inTweaksBtn) { $tweaksPresetsPopup.IsOpen = $false }
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
# Close the preset menu when the main window loses focus (e.g., user switches to another app).
|
# Close the preset menu when the main window loses focus (e.g., user switches to another app).
|
||||||
$window.Add_Deactivated({
|
$window.Add_Deactivated({
|
||||||
if ($presetsPopup.IsOpen) { $presetsPopup.IsOpen = $false }
|
if ($presetsPopup.IsOpen) { $presetsPopup.IsOpen = $false }
|
||||||
|
if ($tweaksPresetsPopup.IsOpen) { $tweaksPresetsPopup.IsOpen = $false }
|
||||||
})
|
})
|
||||||
|
|
||||||
# Toggle popup on button click
|
# Toggle popup on button click
|
||||||
@@ -1018,6 +1081,22 @@ function Show-MainWindow {
|
|||||||
$presetsBtn.IsChecked = $presetsPopup.IsOpen
|
$presetsBtn.IsChecked = $presetsPopup.IsOpen
|
||||||
})
|
})
|
||||||
|
|
||||||
|
$tweaksPresetsBtn.Add_Click({
|
||||||
|
$tweaksPresetsPopup.IsOpen = -not $tweaksPresetsPopup.IsOpen
|
||||||
|
$tweaksPresetsBtn.IsChecked = $tweaksPresetsPopup.IsOpen
|
||||||
|
})
|
||||||
|
|
||||||
|
foreach ($presetCheckBox in @(
|
||||||
|
$presetDefaultApps,
|
||||||
|
$presetLastUsed,
|
||||||
|
$presetDefaultTweaksBtn,
|
||||||
|
$presetLastUsedTweaksBtn,
|
||||||
|
$presetPrivacyTweaksBtn,
|
||||||
|
$presetAITweaksBtn
|
||||||
|
)) {
|
||||||
|
AttachTriStateClickBehavior -checkBox $presetCheckBox
|
||||||
|
}
|
||||||
|
|
||||||
# Preset: Default selection
|
# Preset: Default selection
|
||||||
$presetDefaultApps.Add_Click({
|
$presetDefaultApps.Add_Click({
|
||||||
if ($script:UpdatingPresets) { return }
|
if ($script:UpdatingPresets) { return }
|
||||||
@@ -1751,6 +1830,9 @@ function Show-MainWindow {
|
|||||||
# Initialize UI elements on window load
|
# Initialize UI elements on window load
|
||||||
$window.Add_Loaded({
|
$window.Add_Loaded({
|
||||||
BuildDynamicTweaks
|
BuildDynamicTweaks
|
||||||
|
RefreshTweakPresetSources -defaultSettingsJson $defaultsJson -lastUsedSettingsJson $lastUsedSettingsJson
|
||||||
|
RegisterTweakPresetControlStateHandlers
|
||||||
|
UpdateTweakPresetStates
|
||||||
|
|
||||||
LoadAppsIntoMainUI
|
LoadAppsIntoMainUI
|
||||||
|
|
||||||
@@ -1793,57 +1875,276 @@ function Show-MainWindow {
|
|||||||
UpdateNavigationButtons
|
UpdateNavigationButtons
|
||||||
})
|
})
|
||||||
|
|
||||||
# Handle Load Defaults button
|
function BuildTweakPresetControlMap {
|
||||||
$loadDefaultsBtn = $window.FindName('LoadDefaultsBtn')
|
param($settingsJson)
|
||||||
$loadDefaultsBtn.Add_Click({
|
|
||||||
$defaultsJson = LoadJsonFile -filePath $script:DefaultSettingsFilePath -expectedVersion "1.0"
|
|
||||||
|
|
||||||
if (-not $defaultsJson) {
|
$presetMap = @{}
|
||||||
Show-MessageBox -Message "Failed to load default settings file" -Title "Error" -Button 'OK' -Icon 'Error'
|
if (-not $settingsJson -or -not $settingsJson.Settings -or -not $script:UiControlMappings) {
|
||||||
return
|
return $presetMap
|
||||||
}
|
}
|
||||||
|
|
||||||
ApplySettingsToUiControls -window $window -settingsJson $defaultsJson -uiControlMappings $script:UiControlMappings
|
# FeatureId -> control metadata, similar to ApplySettingsToUiControls lookup.
|
||||||
})
|
$featureIdIndex = @{}
|
||||||
|
foreach ($controlName in $script:UiControlMappings.Keys) {
|
||||||
|
$control = $window.FindName($controlName)
|
||||||
|
if (-not $control -or $control.Visibility -ne 'Visible') { continue }
|
||||||
|
|
||||||
# Handle Load Last Used settings and Load Last Used apps
|
$mapping = $script:UiControlMappings[$controlName]
|
||||||
$loadLastUsedBtn = $window.FindName('LoadLastUsedBtn')
|
if ($mapping.Type -eq 'group') {
|
||||||
|
$i = 1
|
||||||
|
foreach ($val in $mapping.Values) {
|
||||||
|
foreach ($fid in $val.FeatureIds) {
|
||||||
|
$featureIdIndex[$fid] = @{ ControlName = $controlName; Control = $control; MappingType = 'group'; Index = $i }
|
||||||
|
}
|
||||||
|
$i++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
elseif ($mapping.Type -eq 'feature') {
|
||||||
|
$featureIdIndex[$mapping.FeatureId] = @{ ControlName = $controlName; Control = $control; MappingType = 'feature' }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($setting in $settingsJson.Settings) {
|
||||||
|
if ($setting.Value -ne $true) { continue }
|
||||||
|
if ($setting.Name -eq 'CreateRestorePoint') { continue }
|
||||||
|
|
||||||
|
$entry = $featureIdIndex[$setting.Name]
|
||||||
|
if (-not $entry) { continue }
|
||||||
|
if ($presetMap.ContainsKey($entry.ControlName)) { continue }
|
||||||
|
|
||||||
|
$controlType = if ($entry.Control -is [System.Windows.Controls.CheckBox]) { 'CheckBox' } else { 'ComboBox' }
|
||||||
|
$desiredValue = switch ($entry.MappingType) {
|
||||||
|
'group' { $entry.Index }
|
||||||
|
default { if ($controlType -eq 'CheckBox') { $true } else { 1 } }
|
||||||
|
}
|
||||||
|
|
||||||
|
$presetMap[$entry.ControlName] = @{ Control = $entry.Control; ControlType = $controlType; DesiredValue = $desiredValue }
|
||||||
|
}
|
||||||
|
|
||||||
|
return $presetMap
|
||||||
|
}
|
||||||
|
|
||||||
|
function BuildCategoryTweakPresetMap {
|
||||||
|
param([string]$Category)
|
||||||
|
|
||||||
|
$presetMap = @{}
|
||||||
|
if (-not $script:UiControlMappings) { return $presetMap }
|
||||||
|
|
||||||
|
foreach ($controlName in $script:UiControlMappings.Keys) {
|
||||||
|
$mapping = $script:UiControlMappings[$controlName]
|
||||||
|
if ($mapping.Category -ne $Category) { continue }
|
||||||
|
|
||||||
|
$control = $window.FindName($controlName)
|
||||||
|
if (-not $control -or $control.Visibility -ne 'Visible') { continue }
|
||||||
|
|
||||||
|
$controlType = if ($control -is [System.Windows.Controls.CheckBox]) { 'CheckBox' } else { 'ComboBox' }
|
||||||
|
$desiredValue = if ($controlType -eq 'CheckBox') { $true } else { 1 }
|
||||||
|
$presetMap[$controlName] = @{ Control = $control; ControlType = $controlType; DesiredValue = $desiredValue }
|
||||||
|
}
|
||||||
|
|
||||||
|
return $presetMap
|
||||||
|
}
|
||||||
|
|
||||||
|
function GetSavedAppIdsFromSettingsJson {
|
||||||
|
param($settingsJson)
|
||||||
|
|
||||||
|
if (-not $settingsJson -or -not $settingsJson.Settings) {
|
||||||
|
return $null
|
||||||
|
}
|
||||||
|
|
||||||
|
$appsValue = $null
|
||||||
|
foreach ($setting in $settingsJson.Settings) {
|
||||||
|
if ($setting.Name -eq 'Apps' -and $setting.Value) {
|
||||||
|
$appsValue = $setting.Value
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (-not $appsValue) {
|
||||||
|
return $null
|
||||||
|
}
|
||||||
|
|
||||||
|
$savedAppIds = @()
|
||||||
|
if ($appsValue -is [string]) {
|
||||||
|
$savedAppIds = $appsValue.Split(',')
|
||||||
|
}
|
||||||
|
elseif ($appsValue -is [array]) {
|
||||||
|
$savedAppIds = $appsValue
|
||||||
|
}
|
||||||
|
|
||||||
|
$savedAppIds = $savedAppIds | ForEach-Object { $_.Trim() } | Where-Object { $_ -ne '' }
|
||||||
|
if ($savedAppIds.Count -eq 0) {
|
||||||
|
return $null
|
||||||
|
}
|
||||||
|
|
||||||
|
return $savedAppIds
|
||||||
|
}
|
||||||
|
|
||||||
|
function ApplyTweakPresetMap {
|
||||||
|
param(
|
||||||
|
[hashtable]$PresetMap,
|
||||||
|
[bool]$Check
|
||||||
|
)
|
||||||
|
|
||||||
|
if (-not $PresetMap) {
|
||||||
|
$PresetMap = @{}
|
||||||
|
}
|
||||||
|
|
||||||
|
$wasUpdatingTweakPresets = [bool]$script:UpdatingTweakPresets
|
||||||
|
$script:UpdatingTweakPresets = $true
|
||||||
|
try {
|
||||||
|
foreach ($target in $PresetMap.Values) {
|
||||||
|
$control = $target.Control
|
||||||
|
if (-not $control) { continue }
|
||||||
|
|
||||||
|
if ($target.ControlType -eq 'CheckBox') {
|
||||||
|
$control.IsChecked = $Check
|
||||||
|
}
|
||||||
|
elseif ($target.ControlType -eq 'ComboBox') {
|
||||||
|
$desiredIndex = [int]$target.DesiredValue
|
||||||
|
if ($Check) {
|
||||||
|
$control.SelectedIndex = $desiredIndex
|
||||||
|
}
|
||||||
|
elseif ($control.SelectedIndex -eq $desiredIndex) {
|
||||||
|
$control.SelectedIndex = 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
finally {
|
||||||
|
$script:UpdatingTweakPresets = $wasUpdatingTweakPresets
|
||||||
|
}
|
||||||
|
|
||||||
|
if (-not $wasUpdatingTweakPresets) {
|
||||||
|
UpdateTweakPresetStates
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function SetTweakPresetState {
|
||||||
|
param(
|
||||||
|
[System.Windows.Controls.CheckBox]$PresetCheckBox,
|
||||||
|
[hashtable]$PresetMap
|
||||||
|
)
|
||||||
|
|
||||||
|
if (-not $PresetCheckBox) { return }
|
||||||
|
if (-not $PresetMap) {
|
||||||
|
$PresetMap = @{}
|
||||||
|
}
|
||||||
|
|
||||||
|
$total = $PresetMap.Count
|
||||||
|
$selected = 0
|
||||||
|
|
||||||
|
foreach ($target in $PresetMap.Values) {
|
||||||
|
$control = $target.Control
|
||||||
|
if (-not $control) { continue }
|
||||||
|
|
||||||
|
if ($target.ControlType -eq 'CheckBox' -and $control.IsChecked -eq $true) {
|
||||||
|
$selected++
|
||||||
|
}
|
||||||
|
elseif ($target.ControlType -eq 'ComboBox' -and $control.SelectedIndex -eq [int]$target.DesiredValue) {
|
||||||
|
$selected++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SetTriStatePresetCheckBoxState -CheckBox $PresetCheckBox -Total $total -Selected $selected
|
||||||
|
}
|
||||||
|
|
||||||
|
function UpdateTweakPresetStates {
|
||||||
|
$script:UpdatingTweakPresets = $true
|
||||||
|
try {
|
||||||
|
SetTweakPresetState -PresetCheckBox $presetDefaultTweaksBtn -PresetMap $script:DefaultTweakPresetMap
|
||||||
|
if ($presetLastUsedTweaksBtn -and $presetLastUsedTweaksBtn.Visibility -ne 'Collapsed') {
|
||||||
|
SetTweakPresetState -PresetCheckBox $presetLastUsedTweaksBtn -PresetMap $script:LastUsedTweakPresetMap
|
||||||
|
}
|
||||||
|
SetTweakPresetState -PresetCheckBox $presetPrivacyTweaksBtn -PresetMap $script:PrivacyTweakPresetMap
|
||||||
|
SetTweakPresetState -PresetCheckBox $presetAITweaksBtn -PresetMap $script:AITweakPresetMap
|
||||||
|
}
|
||||||
|
finally {
|
||||||
|
$script:UpdatingTweakPresets = $false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function RegisterTweakPresetControlStateHandlers {
|
||||||
|
if (-not $script:UiControlMappings) { return }
|
||||||
|
|
||||||
|
foreach ($controlName in $script:UiControlMappings.Keys) {
|
||||||
|
$control = $window.FindName($controlName)
|
||||||
|
if (-not $control) { continue }
|
||||||
|
|
||||||
|
if ($control -is [System.Windows.Controls.CheckBox]) {
|
||||||
|
$control.Add_Checked({ if (-not $script:UpdatingTweakPresets) { UpdateTweakPresetStates } })
|
||||||
|
$control.Add_Unchecked({ if (-not $script:UpdatingTweakPresets) { UpdateTweakPresetStates } })
|
||||||
|
}
|
||||||
|
elseif ($control -is [System.Windows.Controls.ComboBox]) {
|
||||||
|
$control.Add_SelectionChanged({ if (-not $script:UpdatingTweakPresets) { UpdateTweakPresetStates } })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function RefreshTweakPresetSources {
|
||||||
|
param(
|
||||||
|
$defaultSettingsJson,
|
||||||
|
$lastUsedSettingsJson
|
||||||
|
)
|
||||||
|
|
||||||
|
$script:DefaultTweakPresetMap = BuildTweakPresetControlMap -settingsJson $defaultSettingsJson
|
||||||
|
$script:LastUsedTweakPresetMap = BuildTweakPresetControlMap -settingsJson $lastUsedSettingsJson
|
||||||
|
$script:PrivacyTweakPresetMap = BuildCategoryTweakPresetMap -Category 'Privacy & Suggested Content'
|
||||||
|
$script:AITweakPresetMap = BuildCategoryTweakPresetMap -Category 'AI'
|
||||||
|
|
||||||
|
if ($presetLastUsedTweaksBtn) {
|
||||||
|
$presetLastUsedTweaksBtn.Visibility = if ($script:LastUsedTweakPresetMap.Count -gt 0) { 'Visible' } else { 'Collapsed' }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
$lastUsedSettingsJson = LoadJsonFile -filePath $script:SavedSettingsFilePath -expectedVersion "1.0" -optionalFile
|
$lastUsedSettingsJson = LoadJsonFile -filePath $script:SavedSettingsFilePath -expectedVersion "1.0" -optionalFile
|
||||||
|
|
||||||
$hasSettings = $false
|
$defaultsJson = LoadJsonFile -filePath $script:DefaultSettingsFilePath -expectedVersion "1.0"
|
||||||
$appsSetting = $null
|
$script:DefaultTweakPresetMap = @{}
|
||||||
if ($lastUsedSettingsJson -and $lastUsedSettingsJson.Settings) {
|
$script:LastUsedTweakPresetMap = @{}
|
||||||
foreach ($s in $lastUsedSettingsJson.Settings) {
|
$script:PrivacyTweakPresetMap = @{}
|
||||||
# Only count as hasSettings if a setting other than RemoveApps/Apps is present and true
|
$script:AITweakPresetMap = @{}
|
||||||
if ($s.Value -eq $true -and $s.Name -ne 'RemoveApps' -and $s.Name -ne 'Apps') { $hasSettings = $true }
|
$script:SavedAppIds = GetSavedAppIdsFromSettingsJson -settingsJson $lastUsedSettingsJson
|
||||||
if ($s.Name -eq 'Apps' -and $s.Value) { $appsSetting = $s.Value }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
# Show option to load last used settings if they exist
|
if ($presetDefaultTweaksBtn) {
|
||||||
if ($hasSettings) {
|
$presetDefaultTweaksBtn.Add_Click({
|
||||||
$loadLastUsedBtn.Add_Click({
|
if ($script:UpdatingTweakPresets) { return }
|
||||||
try {
|
$check = NormalizeCheckboxState -checkBox $this
|
||||||
ApplySettingsToUiControls -window $window -settingsJson $lastUsedSettingsJson -uiControlMappings $script:UiControlMappings
|
ApplyTweakPresetMap -PresetMap $script:DefaultTweakPresetMap -Check $check
|
||||||
}
|
|
||||||
catch {
|
|
||||||
Show-MessageBox -Message "Failed to load last used settings: $_" -Title "Error" -Button 'OK' -Icon 'Error'
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
else {
|
|
||||||
$loadLastUsedBtn.Visibility = 'Collapsed'
|
if ($presetLastUsedTweaksBtn) {
|
||||||
|
$presetLastUsedTweaksBtn.Add_Click({
|
||||||
|
if ($script:UpdatingTweakPresets) { return }
|
||||||
|
$check = NormalizeCheckboxState -checkBox $this
|
||||||
|
ApplyTweakPresetMap -PresetMap $script:LastUsedTweakPresetMap -Check $check
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($presetPrivacyTweaksBtn) {
|
||||||
|
$presetPrivacyTweaksBtn.Add_Click({
|
||||||
|
if ($script:UpdatingTweakPresets) { return }
|
||||||
|
$check = NormalizeCheckboxState -checkBox $this
|
||||||
|
ApplyTweakPresetMap -PresetMap $script:PrivacyTweakPresetMap -Check $check
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($presetAITweaksBtn) {
|
||||||
|
$presetAITweaksBtn.Add_Click({
|
||||||
|
if ($script:UpdatingTweakPresets) { return }
|
||||||
|
$check = NormalizeCheckboxState -checkBox $this
|
||||||
|
ApplyTweakPresetMap -PresetMap $script:AITweakPresetMap -Check $check
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
# Hide Last used tweak preset by default; it is shown after dynamic controls are built and mappings are resolved.
|
||||||
|
if ($presetLastUsedTweaksBtn) {
|
||||||
|
$presetLastUsedTweaksBtn.Visibility = 'Collapsed'
|
||||||
}
|
}
|
||||||
|
|
||||||
# Preset: Last used selection (wired to PresetLastUsed checkbox)
|
# Preset: Last used selection (wired to PresetLastUsed checkbox)
|
||||||
if ($appsSetting -and $appsSetting.ToString().Trim().Length -gt 0) {
|
if ($script:SavedAppIds) {
|
||||||
# Parse and store saved app IDs for UpdatePresetStates
|
|
||||||
$script:SavedAppIds = @()
|
|
||||||
if ($appsSetting -is [string]) { $script:SavedAppIds = $appsSetting.Split(',') }
|
|
||||||
elseif ($appsSetting -is [array]) { $script:SavedAppIds = $appsSetting }
|
|
||||||
$script:SavedAppIds = $script:SavedAppIds | ForEach-Object { $_.Trim() } | Where-Object { $_ -ne '' }
|
|
||||||
|
|
||||||
$presetLastUsed.Add_Click({
|
$presetLastUsed.Add_Click({
|
||||||
if ($script:UpdatingPresets) { return }
|
if ($script:UpdatingPresets) { return }
|
||||||
$check = NormalizeCheckboxState -checkBox $this
|
$check = NormalizeCheckboxState -checkBox $this
|
||||||
@@ -1870,6 +2171,7 @@ function Show-MainWindow {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
UpdateTweakPresetStates
|
||||||
})
|
})
|
||||||
|
|
||||||
# Preload app data to speed up loading when user navigates to App Removal tab
|
# Preload app data to speed up loading when user navigates to App Removal tab
|
||||||
|
|||||||
Reference in New Issue
Block a user