diff --git a/Schemas/RestoreBackupWindow.xaml b/Schemas/RestoreBackupWindow.xaml index 1807953..38d7a69 100644 --- a/Schemas/RestoreBackupWindow.xaml +++ b/Schemas/RestoreBackupWindow.xaml @@ -222,6 +222,8 @@ + + @@ -282,9 +284,38 @@ Visibility="Collapsed" Text="This will restore the Start Menu pinned apps layout for the current user."/> - + - + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Scripts/GUI/RestoreBackupDialogFeatureLists.ps1 b/Scripts/GUI/RestoreBackupDialogFeatureLists.ps1 index c942cc7..7bbda18 100644 --- a/Scripts/GUI/RestoreBackupDialogFeatureLists.ps1 +++ b/Scripts/GUI/RestoreBackupDialogFeatureLists.ps1 @@ -79,13 +79,53 @@ function Test-RestoreDialogFeatureVisibleInOverview { return -not [string]::IsNullOrWhiteSpace([string]$featureDefinition.Category) } -function Get-SelectedFeatureIdsFromBackup { +function Get-SelectedForwardFeatureIdsFromBackup { + param($SelectedBackup) + + $selectedFeatureIds = New-Object System.Collections.Generic.List[string] + $seenSelectedFeatureIds = New-Object 'System.Collections.Generic.HashSet[string]' ([System.StringComparer]::OrdinalIgnoreCase) + + foreach ($featureId in @($SelectedBackup.SelectedFeatures)) { + if ([string]::IsNullOrWhiteSpace([string]$featureId)) { + continue + } + + $normalizedId = [string]$featureId + if ($seenSelectedFeatureIds.Add($normalizedId)) { + $selectedFeatureIds.Add($normalizedId) + } + } + + return @($selectedFeatureIds.ToArray()) +} + +function Get-SelectedUndoFeatureIdsFromBackup { + param($SelectedBackup) + + $selectedUndoFeatureIds = New-Object System.Collections.Generic.List[string] + $seenUndoFeatureIds = New-Object 'System.Collections.Generic.HashSet[string]' ([System.StringComparer]::OrdinalIgnoreCase) + + foreach ($featureId in @($SelectedBackup.SelectedUndoFeatures)) { + if ([string]::IsNullOrWhiteSpace([string]$featureId)) { + continue + } + + $normalizedId = [string]$featureId + if ($seenUndoFeatureIds.Add($normalizedId)) { + $selectedUndoFeatureIds.Add($normalizedId) + } + } + + return @($selectedUndoFeatureIds.ToArray()) +} + +function Get-CombinedSelectedFeatureIdsFromBackup { param($SelectedBackup) $featureIds = New-Object System.Collections.Generic.List[string] $seenIds = New-Object 'System.Collections.Generic.HashSet[string]' ([System.StringComparer]::OrdinalIgnoreCase) - foreach ($featureId in @($SelectedBackup.SelectedFeatures) + @($SelectedBackup.SelectedUndoFeatures)) { + foreach ($featureId in @(Get-SelectedForwardFeatureIdsFromBackup -SelectedBackup $SelectedBackup) + @(Get-SelectedUndoFeatureIdsFromBackup -SelectedBackup $SelectedBackup)) { if ([string]::IsNullOrWhiteSpace([string]$featureId)) { continue } @@ -99,6 +139,12 @@ function Get-SelectedFeatureIdsFromBackup { return @($featureIds.ToArray()) } +function Get-SelectedFeatureIdsFromBackup { + param($SelectedBackup) + + return @(Get-CombinedSelectedFeatureIdsFromBackup -SelectedBackup $SelectedBackup) +} + function Get-RestoreBackupFeatureLists { param( [string[]]$SelectedFeatureIds, diff --git a/Scripts/GUI/Show-MainWindow.ps1 b/Scripts/GUI/Show-MainWindow.ps1 index 636c1ee..5cb28fb 100644 --- a/Scripts/GUI/Show-MainWindow.ps1 +++ b/Scripts/GUI/Show-MainWindow.ps1 @@ -278,7 +278,15 @@ function Show-MainWindow { if ($restoreBackupBtn) { $restoreBackupBtn.Add_Click({ try { - Show-RestoreBackupWindow -Owner $window + $restoreResult = Show-RestoreBackupWindow -Owner $window + if ($restoreResult -and $restoreResult.RestoredRegistry -eq $true) { + RefreshCurrentTweakSystemState -ApplyToUi:$false + + if ($ShowCurrentlyAppliedTweaksCheckBox -and $ShowCurrentlyAppliedTweaksCheckBox.IsChecked -eq $true) { + ResetTweaksToSystemState -loadSystemState $true + UpdateTweakPresetStates + } + } } catch { Write-Warning "Restore backup action failed: $($_.Exception.Message)" @@ -905,10 +913,9 @@ function Show-MainWindow { } } - # Reads current registry state and sets each tweak control to reflect whether that tweak is - # currently applied. Also stores the initial state on each control as a NoteProperty so the - # apply handler can detect which controls actually changed. - function LoadCurrentTweakStateIntoUI { + function RefreshCurrentTweakSystemState { + param([bool]$ApplyToUi) + if (-not $script:UiControlMappings) { return } if (-not $script:Features) { return } @@ -930,9 +937,12 @@ function Show-MainWindow { if ($control -is [System.Windows.Controls.CheckBox] -and $mapping.Type -eq 'feature') { $applied = $false try { $applied = [bool](Test-FeatureApplied -FeatureId $mapping.FeatureId) } catch {} - $control.IsChecked = $applied - Add-Member -InputObject $control -MemberType NoteProperty -Name 'InitialState' -Value $applied -Force Add-Member -InputObject $control -MemberType NoteProperty -Name 'SystemState' -Value $applied -Force + + if ($ApplyToUi) { + $control.IsChecked = $applied + Add-Member -InputObject $control -MemberType NoteProperty -Name 'InitialState' -Value $applied -Force + } } elseif ($control -is [System.Windows.Controls.ComboBox] -and $mapping.Type -eq 'group') { $groupId = $null @@ -941,13 +951,23 @@ function Show-MainWindow { if ($groupId -and $groupMap.ContainsKey($groupId)) { try { $activeIndex = Get-CurrentGroupActiveIndex -Group $groupMap[$groupId] } catch {} } - $control.SelectedIndex = $activeIndex - Add-Member -InputObject $control -MemberType NoteProperty -Name 'InitialIndex' -Value $activeIndex -Force Add-Member -InputObject $control -MemberType NoteProperty -Name 'SystemIndex' -Value $activeIndex -Force + + if ($ApplyToUi) { + $control.SelectedIndex = $activeIndex + Add-Member -InputObject $control -MemberType NoteProperty -Name 'InitialIndex' -Value $activeIndex -Force + } } } } + # Reads current registry state and sets each tweak control to reflect whether that tweak is + # currently applied. Also stores the initial state on each control as a NoteProperty so the + # apply handler can detect which controls actually changed. + function LoadCurrentTweakStateIntoUI { + RefreshCurrentTweakSystemState -ApplyToUi:$true + } + # Helper function to load apps and populate the app list panel function script:LoadAppsWithList($listOfApps) { $script:MainWindowLastSelectedCheckbox = $null diff --git a/Scripts/GUI/Show-RestoreBackupDialog.ps1 b/Scripts/GUI/Show-RestoreBackupDialog.ps1 index e53e1ab..9ec68f2 100644 --- a/Scripts/GUI/Show-RestoreBackupDialog.ps1 +++ b/Scripts/GUI/Show-RestoreBackupDialog.ps1 @@ -70,6 +70,9 @@ function Show-RestoreBackupDialog { $backupCreatedText = $window.FindName('BackupCreatedText') $backupTargetText = $window.FindName('BackupTargetText') $featuresItemsControl = $window.FindName('FeaturesItemsControl') + $reappliedSeparator = $window.FindName('ReappliedSeparator') + $reappliedPanel = $window.FindName('ReappliedPanel') + $reappliedFeaturesItemsControl = $window.FindName('ReappliedFeaturesItemsControl') $nonRevertibleSeparator = $window.FindName('NonRevertibleSeparator') $nonRevertiblePanel = $window.FindName('NonRevertiblePanel') $nonRevertibleFeaturesItemsControl = $window.FindName('NonRevertibleFeaturesItemsControl') @@ -119,6 +122,8 @@ function Show-RestoreBackupDialog { $overviewFeaturesSection.Visibility = 'Collapsed' $overviewSummaryText.Visibility = 'Visible' + $reappliedSeparator.Visibility = 'Collapsed' + $reappliedPanel.Visibility = 'Collapsed' $nonRevertibleSeparator.Visibility = 'Collapsed' $nonRevertiblePanel.Visibility = 'Collapsed' $introInfoPanel.Visibility = 'Collapsed' @@ -215,13 +220,33 @@ function Show-RestoreBackupDialog { } } - $selectedFeatureIds = Get-SelectedFeatureIdsFromBackup -SelectedBackup $SelectedBackup - $featureLists = Get-RestoreBackupFeatureLists -SelectedFeatureIds $selectedFeatureIds -Features $script:Features - $revertibleFeaturesList = @($featureLists.Revertible) - $nonRevertibleFeaturesList = @($featureLists.NonRevertible) - Write-Host "Backup overview prepared. Revertible=$($revertibleFeaturesList.Count), NonRevertible=$($nonRevertibleFeaturesList.Count)" + $selectedForwardFeatureIds = @(Get-SelectedForwardFeatureIdsFromBackup -SelectedBackup $SelectedBackup) + $selectedUndoFeatureIds = @(Get-SelectedUndoFeatureIdsFromBackup -SelectedBackup $SelectedBackup) - if ($revertibleFeaturesList.Count -eq 0) { + $seenForwardFeatureIds = New-Object 'System.Collections.Generic.HashSet[string]' ([System.StringComparer]::OrdinalIgnoreCase) + foreach ($featureId in $selectedForwardFeatureIds) { + [void]$seenForwardFeatureIds.Add([string]$featureId) + } + + $filteredUndoFeatureIds = New-Object System.Collections.Generic.List[string] + foreach ($featureId in $selectedUndoFeatureIds) { + if ($seenForwardFeatureIds.Contains([string]$featureId)) { + continue + } + + $filteredUndoFeatureIds.Add([string]$featureId) + } + + $forwardFeatureLists = Get-RestoreBackupFeatureLists -SelectedFeatureIds $selectedForwardFeatureIds -Features $script:Features + $undoFeatureLists = Get-RestoreBackupFeatureLists -SelectedFeatureIds @($filteredUndoFeatureIds.ToArray()) -Features $script:Features + $combinedFeatureLists = Get-RestoreBackupFeatureLists -SelectedFeatureIds (Get-SelectedFeatureIdsFromBackup -SelectedBackup $SelectedBackup) -Features $script:Features + + $revertibleFeaturesList = @($forwardFeatureLists.Revertible) + $reappliedFeaturesList = @($undoFeatureLists.Revertible) + $nonRevertibleFeaturesList = @($combinedFeatureLists.NonRevertible) + Write-Host "Backup overview prepared. Reverted=$($revertibleFeaturesList.Count), ReApplied=$($reappliedFeaturesList.Count), NonRevertible=$($nonRevertibleFeaturesList.Count)" + + if ($revertibleFeaturesList.Count -eq 0 -and $reappliedFeaturesList.Count -eq 0) { throw 'The selected backup does not contain any changes that can be restored.' } @@ -229,13 +254,16 @@ function Show-RestoreBackupDialog { $backupCreatedText.Text = $createdText $backupTargetText.Text = GetFriendlyRegistryBackupTarget -Target ([string]$SelectedBackup.Target) $featuresItemsControl.ItemsSource = $revertibleFeaturesList - $overviewFeaturesSection.Visibility = 'Visible' + $overviewFeaturesSection.Visibility = if ($revertibleFeaturesList.Count -gt 0) { 'Visible' } else { 'Collapsed' } + $reappliedFeaturesItemsControl.ItemsSource = $reappliedFeaturesList + if ($reappliedFeaturesList.Count -gt 0) { $reappliedPanel.Visibility = 'Visible' } else { $reappliedPanel.Visibility = 'Collapsed' } + if ($revertibleFeaturesList.Count -gt 0 -and $reappliedFeaturesList.Count -gt 0) { $reappliedSeparator.Visibility = 'Visible' } else { $reappliedSeparator.Visibility = 'Collapsed' } $overviewSummaryText.Visibility = 'Collapsed' $nonRevertibleFeaturesItemsControl.ItemsSource = $nonRevertibleFeaturesList $hasNonRevertibleItems = ($nonRevertibleFeaturesList.Count -gt 0) if ($hasNonRevertibleItems) { $nonRevertiblePanel.Visibility = 'Visible' } else { $nonRevertiblePanel.Visibility = 'Collapsed' } - if ($hasNonRevertibleItems) { $nonRevertibleSeparator.Visibility = 'Visible' } else { $nonRevertibleSeparator.Visibility = 'Collapsed' } + if ($hasNonRevertibleItems -and ($revertibleFeaturesList.Count -gt 0 -or $reappliedFeaturesList.Count -gt 0)) { $nonRevertibleSeparator.Visibility = 'Visible' } else { $nonRevertibleSeparator.Visibility = 'Collapsed' } $introInfoPanel.Visibility = 'Collapsed' $overviewPanel.Visibility = 'Visible' diff --git a/Scripts/GUI/Show-RestoreBackupWindow.ps1 b/Scripts/GUI/Show-RestoreBackupWindow.ps1 index 1c15dd1..6fc9c41 100644 --- a/Scripts/GUI/Show-RestoreBackupWindow.ps1 +++ b/Scripts/GUI/Show-RestoreBackupWindow.ps1 @@ -7,10 +7,15 @@ function Show-RestoreBackupWindow { try { Write-Host 'Opening restore backup dialog.' + $restoreResult = [PSCustomObject]@{ + RestoredRegistry = $false + RestoredStartMenu = $false + } + $dialogResult = Show-RestoreBackupDialog -Owner $Owner if (-not $dialogResult -or $dialogResult.Result -eq 'Cancel') { Write-Host 'Restore canceled by user.' - return + return $restoreResult } $successMessage = $null @@ -24,6 +29,7 @@ function Show-RestoreBackupWindow { Write-Host "User confirmed registry restore for $($backup.Target)." Restore-RegistryBackupState -Backup $backup + $restoreResult.RestoredRegistry = $true $successMessage = 'Registry backup restored successfully. Some changes may require a sign out or restart to take effect.' } elseif ($dialogResult.Result -eq 'RestoreStartMenu') { @@ -69,6 +75,8 @@ function Show-RestoreBackupWindow { $successMessage = "The Start Menu backup was successfully restored for the current user. The changes will apply the next time you sign in." } } + + $restoreResult.RestoredStartMenu = $true } if ($warningMessage) { @@ -79,10 +87,16 @@ function Show-RestoreBackupWindow { Write-Host "$successMessage" Show-MessageBox -Title 'Backup Restored' -Message $successMessage -Icon Success } + + return $restoreResult } catch { $errorMessage = if ($_.Exception.Message) { $_.Exception.Message } else { 'An unexpected error occurred.' } Write-Error "Restore operation failed: $errorMessage" Show-MessageBox -Title 'Error' -Message "Restore failed: $errorMessage" -Icon Error + return [PSCustomObject]@{ + RestoredRegistry = $false + RestoredStartMenu = $false + } } }