Make collapsable categories

This commit is contained in:
Chris Titus Tech
2026-02-05 15:03:36 -06:00
parent 0b78970dc7
commit 17f92df25a
4 changed files with 99 additions and 33 deletions

View File

@@ -16,8 +16,26 @@ function Find-AppsByNameOrDescription {
$_.Visibility = [Windows.Visibility]::Visible
$_.Children | ForEach-Object {
if ($null -ne $_) {
# Respect the collapsed state of categories (indicated by + prefix)
if ($_.Tag -like "CategoryToggleButton" -and $_.Content -like "+*") {
# Keep category label visible but don't expand the WrapPanel
$_.Visibility = [Windows.Visibility]::Visible
}
elseif ($_.Tag -like "CategoryWrapPanel_*") {
# Check if parent category is collapsed (has + prefix)
$categoryLabel = $_.Parent.Children[0]
if ($categoryLabel.Content -like "+*") {
# Keep collapsed
$_.Visibility = [Windows.Visibility]::Collapsed
} else {
# Expand
$_.Visibility = [Windows.Visibility]::Visible
}
}
else {
$_.Visibility = [Windows.Visibility]::Visible
}
}
}
}
@@ -32,18 +50,29 @@ function Find-AppsByNameOrDescription {
# Hide all CategoryWrapPanel and ToggleButton
$_.Visibility = [Windows.Visibility]::Collapsed
if ($_.Tag -like "CategoryWrapPanel_*") {
$categoryHasMatch = $false
# Search for Apps that match the search string
$_.Children | Foreach-Object {
$appEntry = $sync.configs.applicationsHashtable.$($_.Tag)
if ($appEntry.Content -like "*$SearchString*" -or $appEntry.Description -like "*$SearchString*") {
# Show the App and the parent CategoryWrapPanel if the string is found
# Show the App and mark that this category has a match
$_.Visibility = [Windows.Visibility]::Visible
$_.parent.Visibility = [Windows.Visibility]::Visible
$categoryHasMatch = $true
}
else {
$_.Visibility = [Windows.Visibility]::Collapsed
}
}
# If category has matches, show the WrapPanel and update the category label to expanded state
if ($categoryHasMatch) {
$_.Visibility = [Windows.Visibility]::Visible
# Update category label to show expanded state (-)
$categoryLabel = $_.Parent.Children[0]
if ($categoryLabel.Content -like "+*") {
$categoryLabel.Content = $categoryLabel.Content -replace "^\+ ", "- "
}
}
}
}
}

View File

@@ -41,13 +41,13 @@
$itemsControl.VerticalAlignment = 'Stretch'
$scrollViewer.Content = $itemsControl
# Enable virtualization for the ItemsControl to improve performance (It's hard to test if this is actually working, so if you know what you're doing, please check this)
# Use WrapPanel to create dynamic columns based on AppEntryWidth and window width
$itemsPanelTemplate = New-Object Windows.Controls.ItemsPanelTemplate
$factory = New-Object Windows.FrameworkElementFactory ([Windows.Controls.VirtualizingStackPanel])
$factory = New-Object Windows.FrameworkElementFactory ([Windows.Controls.WrapPanel])
$factory.SetValue([Windows.Controls.WrapPanel]::OrientationProperty, [Windows.Controls.Orientation]::Horizontal)
$factory.SetValue([Windows.Controls.WrapPanel]::HorizontalAlignmentProperty, [Windows.HorizontalAlignment]::Left)
$itemsPanelTemplate.VisualTree = $factory
$itemsControl.ItemsPanel = $itemsPanelTemplate
$itemsControl.SetValue([Windows.Controls.VirtualizingStackPanel]::IsVirtualizingProperty, $true)
$itemsControl.SetValue([Windows.Controls.VirtualizingStackPanel]::VirtualizationModeProperty, [Windows.Controls.VirtualizationMode]::Recycling)
# Add the Border containing the App Area to the target Grid
$targetGrid.Children.Add($Border) | Out-Null

View File

@@ -15,22 +15,6 @@ function Initialize-InstallCategoryAppList {
$TargetElement,
$Apps
)
function Add-Category {
param(
[string]$Category,
[Windows.Controls.ItemsControl]$TargetElement
)
$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")
$sync.$Category = $toggleButton
$null = $TargetElement.Items.Add($toggleButton)
}
# Pre-group apps by category
$appsByCategory = @{}
@@ -42,15 +26,68 @@ function Initialize-InstallCategoryAppList {
$appsByCategory[$category] += $appKey
}
foreach ($category in $($appsByCategory.Keys | Sort-Object)) {
Add-Category -Category $category -TargetElement $TargetElement
# 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
# 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.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($sender, $e)
# Find the parent StackPanel (categoryContainer)
$categoryContainer = $sender.Parent
if ($categoryContainer -and $categoryContainer.Children.Count -ge 2) {
# The WrapPanel is the second child
$wrapPanel = $categoryContainer.Children[1]
# Toggle visibility
if ($wrapPanel.Visibility -eq [Windows.Visibility]::Visible) {
$wrapPanel.Visibility = [Windows.Visibility]::Collapsed
# Change - to +
$sender.Content = $sender.Content -replace "^- ", "+ "
} else {
$wrapPanel.Visibility = [Windows.Visibility]::Visible
# Change + to -
$sender.Content = $sender.Content -replace "^\+ ", "- "
}
}
})
$null = $categoryContainer.Children.Add($toggleButton)
# Add wrap panel for apps to container
$wrapPanel = New-Object Windows.Controls.WrapPanel
$wrapPanel.Orientation = "Vertical"
$wrapPanel.HorizontalAlignment = "Stretch"
$wrapPanel.VerticalAlignment = "Center"
$wrapPanel.Margin = New-Object Windows.Thickness(0, 0, 0, 20)
$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 = $TargetElement.Items.Add($wrapPanel)
$null = $categoryContainer.Children.Add($wrapPanel)
# Add the entire category container to the target element
$null = $TargetElement.Items.Add($categoryContainer)
# Add apps to the wrap panel
$appsByCategory[$category] | Sort-Object | ForEach-Object {
$sync.$_ = $(Initialize-InstallAppEntry -TargetElement $wrapPanel -AppKey $_)
}

View File

@@ -107,8 +107,8 @@
BorderBrush="{DynamicResource MainForegroundColor}"
Background="{DynamicResource ButtonBackgroundColor}"
BorderThickness="1"
Width="16"
Height="16"
Width="12"
Height="12"
CornerRadius="2"/>
<Path x:Name="CheckMark"
Stroke="{DynamicResource ToggleButtonOnColor}"