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>
|
||||
</ToggleButton.Style>
|
||||
<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 x:Name="PresetsArrow" Text="" FontFamily="Segoe Fluent Icons" FontSize="10" VerticalAlignment="Center" RenderTransformOrigin="0.5,0.5">
|
||||
<TextBlock.RenderTransform>
|
||||
@@ -756,15 +757,20 @@
|
||||
</TextBlock>
|
||||
</StackPanel>
|
||||
</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">
|
||||
<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 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="PresetLastUsed" Content="Last used selection" IsThreeState="True" Foreground="{DynamicResource FgColor}" Margin="8,4" AutomationProperties.Name="Last used 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 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}"/>
|
||||
<StackPanel x:Name="JsonPresetsPanel"/>
|
||||
</StackPanel>
|
||||
@@ -895,9 +901,67 @@
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<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"/>
|
||||
<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"/>
|
||||
<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"/>
|
||||
<ToggleButton x:Name="TweaksPresetsBtn" ToolTip="Select tweak presets" Height="32" Padding="10,0" Margin="0,0,10,0" AutomationProperties.Name="Tweak Presets">
|
||||
<ToggleButton.Style>
|
||||
<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>
|
||||
|
||||
<Border x:Name="TweakSearchBorder" Grid.Column="2">
|
||||
|
||||
@@ -287,21 +287,75 @@ function Show-MainWindow {
|
||||
$jsonPresetsPanel = $window.FindName('JsonPresetsPanel')
|
||||
$presetsArrow = $window.FindName('PresetsArrow')
|
||||
$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 {
|
||||
param([System.Windows.Controls.CheckBox]$checkBox)
|
||||
|
||||
$isChecked = ($checkBox.IsChecked -eq $true)
|
||||
if ($null -eq $checkBox.IsChecked) {
|
||||
$checkBox.IsChecked = $false
|
||||
return $false
|
||||
if ($checkBox.PSObject.Properties['WasIndeterminateBeforeClick'] -and $checkBox.WasIndeterminateBeforeClick) {
|
||||
# WPF toggles null -> false before Click handlers fire; restore desired mixed -> checked behavior.
|
||||
$checkBox.WasIndeterminateBeforeClick = $false
|
||||
$checkBox.IsChecked = $true
|
||||
return $true
|
||||
}
|
||||
|
||||
return $isChecked
|
||||
return ($checkBox.IsChecked -eq $true)
|
||||
}
|
||||
|
||||
function AnimatePresetsArrow {
|
||||
param([double]$angle)
|
||||
function SetTriStatePresetCheckBoxState {
|
||||
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.To = $angle
|
||||
@@ -311,7 +365,7 @@ function Show-MainWindow {
|
||||
$ease.EasingMode = 'EaseOut'
|
||||
$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
|
||||
@@ -321,15 +375,17 @@ function Show-MainWindow {
|
||||
$checkbox.Content = $preset.Name
|
||||
$checkbox.IsThreeState = $true
|
||||
$checkbox.Style = $window.Resources['PresetCheckBoxStyle']
|
||||
$checkbox.ToolTip = "Select $($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
|
||||
$jsonPresetsPanel.Children.Add($checkbox) | Out-Null
|
||||
$script:JsonPresetCheckboxes += $checkbox
|
||||
|
||||
$checkbox.Add_Click({
|
||||
if ($script:UpdatingPresets) { return }
|
||||
$check = NormalizeCheckboxState -checkBox $this
|
||||
$presetIds = $this.PresetAppIds
|
||||
$check = NormalizeCheckboxState -checkBox $this
|
||||
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
|
||||
$script:UpdatingPresets = $false
|
||||
$script:UpdatingTweakPresets = $false
|
||||
|
||||
# Sort state for the app table
|
||||
$script:SortColumn = 'Name'
|
||||
@@ -484,19 +541,7 @@ function Show-MainWindow {
|
||||
}
|
||||
}
|
||||
}
|
||||
if ($total -eq 0) {
|
||||
$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
|
||||
}
|
||||
}
|
||||
SetTriStatePresetCheckBoxState -CheckBox $checkbox -Total $total -Selected $checked
|
||||
}
|
||||
|
||||
SetPresetState $presetDefaultApps { param($c) $c.SelectedByDefault -eq $true }
|
||||
@@ -772,7 +817,7 @@ function Show-MainWindow {
|
||||
try { $lblBorderObj = $window.FindName("$comboName`_LabelBorder") } catch {}
|
||||
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') {
|
||||
$feature = $item.Data
|
||||
@@ -792,7 +837,7 @@ function Show-MainWindow {
|
||||
try { $lblBorderObj = $window.FindName("$comboName`_LabelBorder") } catch {}
|
||||
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
|
||||
$presetsPopup.Add_Opened({
|
||||
UpdatePresetStates
|
||||
AnimatePresetsArrow -angle 180
|
||||
AnimateDropdownArrow -arrow $presetsArrow -angle 180
|
||||
})
|
||||
$presetsPopup.Add_Closed({
|
||||
AnimatePresetsArrow -angle 0
|
||||
AnimateDropdownArrow -arrow $presetsArrow -angle 0
|
||||
$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.
|
||||
$window.Add_PreviewMouseDown({
|
||||
if (-not $presetsPopup.IsOpen) { return }
|
||||
if ($null -ne $presetsPopup.Child -and $presetsPopup.Child.IsMouseOver) { return }
|
||||
$isAppPopupOpen = $presetsPopup.IsOpen
|
||||
$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]
|
||||
if ($null -ne $src) {
|
||||
$inBtn = $presetsBtn.IsAncestorOf($src) -or [System.Object]::ReferenceEquals($presetsBtn, $src)
|
||||
if (-not $inBtn) { $presetsPopup.IsOpen = $false }
|
||||
$inAppBtn = $presetsBtn.IsAncestorOf($src) -or [System.Object]::ReferenceEquals($presetsBtn, $src)
|
||||
$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).
|
||||
$window.Add_Deactivated({
|
||||
if ($presetsPopup.IsOpen) { $presetsPopup.IsOpen = $false }
|
||||
if ($tweaksPresetsPopup.IsOpen) { $tweaksPresetsPopup.IsOpen = $false }
|
||||
})
|
||||
|
||||
# Toggle popup on button click
|
||||
@@ -1018,6 +1081,22 @@ function Show-MainWindow {
|
||||
$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
|
||||
$presetDefaultApps.Add_Click({
|
||||
if ($script:UpdatingPresets) { return }
|
||||
@@ -1751,6 +1830,9 @@ function Show-MainWindow {
|
||||
# Initialize UI elements on window load
|
||||
$window.Add_Loaded({
|
||||
BuildDynamicTweaks
|
||||
RefreshTweakPresetSources -defaultSettingsJson $defaultsJson -lastUsedSettingsJson $lastUsedSettingsJson
|
||||
RegisterTweakPresetControlStateHandlers
|
||||
UpdateTweakPresetStates
|
||||
|
||||
LoadAppsIntoMainUI
|
||||
|
||||
@@ -1793,57 +1875,276 @@ function Show-MainWindow {
|
||||
UpdateNavigationButtons
|
||||
})
|
||||
|
||||
# Handle Load Defaults button
|
||||
$loadDefaultsBtn = $window.FindName('LoadDefaultsBtn')
|
||||
$loadDefaultsBtn.Add_Click({
|
||||
$defaultsJson = LoadJsonFile -filePath $script:DefaultSettingsFilePath -expectedVersion "1.0"
|
||||
function BuildTweakPresetControlMap {
|
||||
param($settingsJson)
|
||||
|
||||
if (-not $defaultsJson) {
|
||||
Show-MessageBox -Message "Failed to load default settings file" -Title "Error" -Button 'OK' -Icon 'Error'
|
||||
return
|
||||
$presetMap = @{}
|
||||
if (-not $settingsJson -or -not $settingsJson.Settings -or -not $script:UiControlMappings) {
|
||||
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
|
||||
$loadLastUsedBtn = $window.FindName('LoadLastUsedBtn')
|
||||
$mapping = $script:UiControlMappings[$controlName]
|
||||
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
|
||||
|
||||
$hasSettings = $false
|
||||
$appsSetting = $null
|
||||
if ($lastUsedSettingsJson -and $lastUsedSettingsJson.Settings) {
|
||||
foreach ($s in $lastUsedSettingsJson.Settings) {
|
||||
# Only count as hasSettings if a setting other than RemoveApps/Apps is present and true
|
||||
if ($s.Value -eq $true -and $s.Name -ne 'RemoveApps' -and $s.Name -ne 'Apps') { $hasSettings = $true }
|
||||
if ($s.Name -eq 'Apps' -and $s.Value) { $appsSetting = $s.Value }
|
||||
}
|
||||
}
|
||||
$defaultsJson = LoadJsonFile -filePath $script:DefaultSettingsFilePath -expectedVersion "1.0"
|
||||
$script:DefaultTweakPresetMap = @{}
|
||||
$script:LastUsedTweakPresetMap = @{}
|
||||
$script:PrivacyTweakPresetMap = @{}
|
||||
$script:AITweakPresetMap = @{}
|
||||
$script:SavedAppIds = GetSavedAppIdsFromSettingsJson -settingsJson $lastUsedSettingsJson
|
||||
|
||||
# Show option to load last used settings if they exist
|
||||
if ($hasSettings) {
|
||||
$loadLastUsedBtn.Add_Click({
|
||||
try {
|
||||
ApplySettingsToUiControls -window $window -settingsJson $lastUsedSettingsJson -uiControlMappings $script:UiControlMappings
|
||||
}
|
||||
catch {
|
||||
Show-MessageBox -Message "Failed to load last used settings: $_" -Title "Error" -Button 'OK' -Icon 'Error'
|
||||
}
|
||||
if ($presetDefaultTweaksBtn) {
|
||||
$presetDefaultTweaksBtn.Add_Click({
|
||||
if ($script:UpdatingTweakPresets) { return }
|
||||
$check = NormalizeCheckboxState -checkBox $this
|
||||
ApplyTweakPresetMap -PresetMap $script:DefaultTweakPresetMap -Check $check
|
||||
})
|
||||
}
|
||||
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)
|
||||
if ($appsSetting -and $appsSetting.ToString().Trim().Length -gt 0) {
|
||||
# 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 '' }
|
||||
|
||||
if ($script:SavedAppIds) {
|
||||
$presetLastUsed.Add_Click({
|
||||
if ($script:UpdatingPresets) { return }
|
||||
$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
|
||||
|
||||
Reference in New Issue
Block a user