# Shows application selection window that allows the user to select what apps they want to remove or keep function Show-AppSelectionWindow { Add-Type -AssemblyName PresentationFramework,PresentationCore,WindowsBase | Out-Null $usesDarkMode = GetSystemUsesDarkMode # Show overlay if main window exists $overlay = $null if ($script:GuiWindow) { try { $overlay = $script:GuiWindow.FindName('ModalOverlay') if ($overlay) { $script:GuiWindow.Dispatcher.Invoke([action]{ $overlay.Visibility = 'Visible' }) } } catch { } } # Load XAML from file $xaml = Get-Content -Path $script:AppSelectionSchema -Raw $reader = [System.Xml.XmlReader]::Create([System.IO.StringReader]::new($xaml)) try { $window = [System.Windows.Markup.XamlReader]::Load($reader) } finally { $reader.Close() } # Set owner to main window if it exists if ($script:GuiWindow) { try { $window.Owner = $script:GuiWindow } catch { } } SetWindowThemeResources -window $window -usesDarkMode $usesDarkMode $appsPanel = $window.FindName('AppsPanel') $checkAllBox = $window.FindName('CheckAllBox') $onlyInstalledBox = $window.FindName('OnlyInstalledBox') $confirmBtn = $window.FindName('ConfirmBtn') $loadingIndicator = $window.FindName('LoadingAppsIndicator') $titleBar = $window.FindName('TitleBar') # Track the last selected checkbox for shift-click range selection $script:AppSelectionWindowLastSelectedCheckbox = $null # Loads apps into the apps UI function LoadApps { # Show loading indicator $loadingIndicator.Visibility = 'Visible' $window.Dispatcher.Invoke([System.Windows.Threading.DispatcherPriority]::Background, [action]{}) $appsPanel.Children.Clear() $listOfApps = "" if ($onlyInstalledBox.IsChecked -and ($script:WingetInstalled -eq $true)) { # Attempt to get a list of installed apps via WinGet, times out after 10 seconds $listOfApps = GetInstalledAppsViaWinget -TimeOut 10 if (-not $listOfApps) { # Show error that the script was unable to get list of apps from WinGet Show-MessageBox -Message 'Unable to load list of installed apps via WinGet.' -Title 'Error' -Button 'OK' -Icon 'Error' -Owner $window | Out-Null $onlyInstalledBox.IsChecked = $false } } $appsToAdd = LoadAppsDetailsFromJson -OnlyInstalled:$onlyInstalledBox.IsChecked -InstalledList $listOfApps -InitialCheckedFromJson:$true # Reset the last selected checkbox when loading a new list $script:AppSelectionWindowLastSelectedCheckbox = $null # Sort apps alphabetically and add to panel $appsToAdd | Sort-Object -Property DisplayName | ForEach-Object { $checkbox = New-Object System.Windows.Controls.CheckBox $checkbox.Content = $_.DisplayName $checkbox.SetValue([System.Windows.Automation.AutomationProperties]::NameProperty, $_.DisplayName) $checkbox.Tag = $_.AppId $checkbox.IsChecked = $_.IsChecked $checkbox.ToolTip = $_.Description $checkbox.Style = $window.Resources["AppsPanelCheckBoxStyle"] # Attach shift-click behavior for range selection AttachShiftClickBehavior -checkbox $checkbox -appsPanel $appsPanel -lastSelectedCheckboxRef ([ref]$script:AppSelectionWindowLastSelectedCheckbox) $appsPanel.Children.Add($checkbox) | Out-Null } # Hide loading indicator $loadingIndicator.Visibility = 'Collapsed' } # Event handlers $titleBar.Add_MouseLeftButtonDown({ $window.DragMove() }) $checkAllBox.Add_Checked({ foreach ($child in $appsPanel.Children) { if ($child -is [System.Windows.Controls.CheckBox]) { $child.IsChecked = $true } } }) $checkAllBox.Add_Unchecked({ foreach ($child in $appsPanel.Children) { if ($child -is [System.Windows.Controls.CheckBox]) { $child.IsChecked = $false } } }) $onlyInstalledBox.Add_Checked({ LoadApps }) $onlyInstalledBox.Add_Unchecked({ LoadApps }) $confirmBtn.Add_Click({ $selectedApps = @() foreach ($child in $appsPanel.Children) { if ($child -is [System.Windows.Controls.CheckBox] -and $child.IsChecked) { $selectedApps += $child.Tag } } # Close form without saving if no apps were selected if ($selectedApps.Count -eq 0) { $window.Close() return } if ($selectedApps -contains "Microsoft.WindowsStore" -and -not $Silent) { $result = Show-MessageBox -Message 'Are you sure you wish to uninstall the Microsoft Store? This app cannot easily be reinstalled.' -Title 'Are you sure?' -Button 'YesNo' -Icon 'Warning' -Owner $window if ($result -eq 'No') { return } } SaveCustomAppsListToFile -appsList $selectedApps $window.DialogResult = $true }) # Load apps after window is shown (allows UI to render first) $window.Add_ContentRendered({ $window.Dispatcher.Invoke([System.Windows.Threading.DispatcherPriority]::Background, [action]{ LoadApps }) }) # Show the window and return dialog result $result = $window.ShowDialog() # Hide overlay after dialog closes if ($overlay) { try { $script:GuiWindow.Dispatcher.Invoke([action]{ $overlay.Visibility = 'Collapsed' }) } catch { } } return $result }