Files
winutil/functions/private/Initialize-InstallCategoryAppList.ps1
T
MyDriftandGitHub 32ab9f0ab0 Turn the Install category filters into toggle chips (#4926)
* Turn the Install category filters into toggle chips

- Replace the filter buttons with toggles that show which ones are active
- Add ctrl click to select more than one category
- Keep the search box and the category filter independent of each other
- Expand matching categories while a filter is active

* Fix the filter interactions the category chips missed

- Pass the selected categories to the lazy rendering batches, the old call
  used a parameter that no longer exists and threw while typing
- Keep the category filter when switching tabs, the chips stayed checked
  while the filter itself was dropped
- Put a category back to collapsed once the filter that expanded it is gone

* Document the Install category filters

- Add a guide section for the chips, ctrl click and clearing the filter
- Note that search and the category chips apply together

* Correct the category filter guide wording

- Clearing by clicking the chip only applies when it is the only one selected
- Only categories with matches expand, and only auto expanded ones re-collapse
2026-08-09 13:13:21 -05:00

108 lines
5.3 KiB
PowerShell

function Initialize-InstallCategoryAppList {
<#
.SYNOPSIS
Clears the Target Element and sets up a "Loading" message. This is done, because loading of all apps can take a bit of time in some scenarios
Iterates through all Categories and Apps and adds them to the UI
Used to as part of the Install Tab UI generation
.PARAMETER TargetElement
The Element into which the Categories and Apps should be placed
.PARAMETER Apps
The Hashtable of Apps to be added to the UI
The Categories are also extracted from the Apps Hashtable
#>
param(
$TargetElement,
$Apps
)
# Pre-group apps by category before creating WPF controls.
$appsByCategory = @{}
foreach ($appKey in $Apps.Keys) {
$category = $Apps.$appKey.Category
if (-not $appsByCategory.ContainsKey($category)) {
$appsByCategory[$category] = @()
}
$appsByCategory[$category] += $appKey
}
$sync.InstallAppRenderQueue = [System.Collections.Queue]::new()
foreach ($category in $($appsByCategory.Keys | Sort-Object)) {
# Create a container for category label + apps
$categoryContainer = New-Object Windows.Controls.StackPanel
$categoryContainer.Orientation = "Vertical"
$categoryContainer.Margin = New-Object Windows.Thickness(0, 0, 0, 0)
$categoryContainer.HorizontalAlignment = [Windows.HorizontalAlignment]::Stretch
[System.Windows.Automation.AutomationProperties]::SetName($categoryContainer, $Category)
# Bind Width to the ItemsControl's ActualWidth to force full-row layout in WrapPanel
$binding = New-Object Windows.Data.Binding
$binding.Path = New-Object Windows.PropertyPath("ActualWidth")
$binding.RelativeSource = New-Object Windows.Data.RelativeSource([Windows.Data.RelativeSourceMode]::FindAncestor, [Windows.Controls.ItemsControl], 1)
[void][Windows.Data.BindingOperations]::SetBinding($categoryContainer, [Windows.FrameworkElement]::WidthProperty, $binding)
# Add category label to container
$toggleButton = New-Object Windows.Controls.Label
$toggleButton.Content = "- $Category"
$toggleButton.Tag = "CategoryToggleButton"
$toggleButton.SetResourceReference([Windows.Controls.Control]::FontSizeProperty, "HeaderFontSize")
$toggleButton.SetResourceReference([Windows.Controls.Control]::FontFamilyProperty, "HeaderFontFamily")
$toggleButton.SetResourceReference([Windows.Controls.Control]::ForegroundProperty, "LabelboxForegroundColor")
$toggleButton.Cursor = [System.Windows.Input.Cursors]::Hand
$toggleButton.HorizontalAlignment = [Windows.HorizontalAlignment]::Stretch
$sync.$Category = $toggleButton
# Add click handler to toggle category visibility
$toggleButton.Add_MouseLeftButtonUp({
param($categoryToggle)
# Find the parent StackPanel (categoryContainer)
$categoryContainer = $categoryToggle.Parent
if ($categoryContainer -and $categoryContainer.Children.Count -ge 2) {
# The WrapPanel is the second child
$wrapPanel = $categoryContainer.Children[1]
# An explicit click wins over anything filtering expanded automatically
if ($sync.AppCategoryAutoExpanded) {
$sync.AppCategoryAutoExpanded.Remove(($categoryToggle.Content -replace '^[+-] ', ''))
}
# Toggle visibility
if ($wrapPanel.Visibility -eq [Windows.Visibility]::Visible) {
$wrapPanel.Visibility = [Windows.Visibility]::Collapsed
# Change - to +
$categoryToggle.Content = $categoryToggle.Content -replace "^- ", "+ "
} else {
$wrapPanel.Visibility = [Windows.Visibility]::Visible
# Change + to -
$categoryToggle.Content = $categoryToggle.Content -replace "^\+ ", "- "
}
}
})
$null = $categoryContainer.Children.Add($toggleButton)
# Add wrap panel for apps to container
$wrapPanel = New-Object Windows.Controls.WrapPanel
$wrapPanel.Orientation = "Horizontal"
$wrapPanel.HorizontalAlignment = "Left"
$wrapPanel.VerticalAlignment = "Top"
$wrapPanel.Margin = New-Object Windows.Thickness(0, 0, 0, 0)
$wrapPanel.Visibility = [Windows.Visibility]::Visible
$wrapPanel.Tag = "CategoryWrapPanel_$category"
$null = $categoryContainer.Children.Add($wrapPanel)
# Add the entire category container to the target element
$null = $TargetElement.Items.Add($categoryContainer)
$sync.InstallAppRenderQueue.Enqueue([pscustomobject]@{
Category = $category
TargetElement = $wrapPanel
AppKeys = @($appsByCategory[$category] | Sort-Object)
})
}
Start-WinUtilInstallAppRendering
}