LETS GOOO (#12)

* Add Selected Apps Label, Reshuffel the nesting of the checkbox and the label to be able to reference the name from the actual checkbox

* Add visual selection and allow click on the whole app section

* Fix Theme definition to work with theme change

* Fix Highlight on if label or icon is clicked

* change applications.json to powershell object list and refactor UI Creation logic

* Optimization and Add Collapsable Categories

* Add Button functionality for install, uninstall, info, install selected, uninstall selected, clear and implement search

* Rest application.json to Main

* Reset Compile to main

* Pretty much revamp_apps but without changes to applications.json

* Small fixes
This commit is contained in:
Martin Wiethan 2024-10-13 19:25:02 +02:00 committed by GitHub
parent 5bbc6c6a92
commit 6d88e51462
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
8 changed files with 632 additions and 120 deletions

View File

@ -38,6 +38,8 @@
"ButtonCornerRadius": "2"
},
"Light": {
"AppInstallUnselectedColor": "#F0F0F0",
"AppInstallSelectedColor": "#C2C2C2",
"ComboBoxForegroundColor": "#232629",
"ComboBoxBackgroundColor": "#F7F7F7",
"LabelboxForegroundColor": "#232629",
@ -73,6 +75,8 @@
},
"Dark": {
"AppInstallUnselectedColor": "#232629",
"AppInstallSelectedColor": "#4C4C4C",
"ComboBoxForegroundColor": "#F7F7F7",
"ComboBoxBackgroundColor": "#1E3747",
"LabelboxForegroundColor": "#0567ff",

View File

@ -20,9 +20,9 @@ function Invoke-WPFGetInstalled {
return
}
$preferChoco = $sync.WPFpreferChocolatey.IsChecked
Invoke-WPFRunspace -ArgumentList $checkbox, $preferChoco -DebugPreference $DebugPreference -ScriptBlock {
param($checkbox, $preferChoco, $DebugPreference)
Invoke-WPFRunspace -ArgumentList $checkbox, $preferChoco -ParameterList @(,("ShowOnlyCheckedApps",${function:Show-OnlyCheckedApps})) -DebugPreference $DebugPreference -ScriptBlock {
param($checkbox, $preferChoco, $ShowOnlyCheckedApps,$DebugPreference)
Write-Host $ShowOnlyCheckedApps.ToString()
$sync.ProcessRunning = $true
$sync.form.Dispatcher.Invoke([action]{ Set-WinUtilTaskbaritem -state "Indeterminate" })
@ -38,13 +38,15 @@ function Invoke-WPFGetInstalled {
else{
$Checkboxes = Invoke-WinUtilCurrentSystem -CheckBox $checkbox
}
$sync.form.Dispatcher.invoke({
foreach($checkbox in $Checkboxes) {
$sync.$checkbox.ischecked = $True
}
}
})
$sync.ItemsControl.Dispatcher.Invoke([action]{
$ShowOnlyCheckedApps.Invoke($sync.SelectedApps, $sync.ItemsControl)
})
Write-Host "Done..."
$sync.ProcessRunning = $false
$sync.form.Dispatcher.Invoke([action] { Set-WinUtilTaskbaritem -state "None" })

View File

@ -1,4 +1,8 @@
function Invoke-WPFInstall {
param (
[Parameter(Mandatory=$false)]
[PSObject[]]$PackagesToInstall = $($sync.selectedApps | Foreach-Object { $SortedAppsHashtable.$_ })
)
<#
.SYNOPSIS
@ -12,8 +16,6 @@ function Invoke-WPFInstall {
return
}
$PackagesToInstall = (Get-WinUtilCheckBoxes)["Install"]
Write-Host $PackagesToInstall
if ($PackagesToInstall.Count -eq 0) {
$WarningMsg = "Please select the program(s) to install or upgrade"
[System.Windows.MessageBox]::Show($WarningMsg, $AppTitle, [System.Windows.MessageBoxButton]::OK, [System.Windows.MessageBoxImage]::Warning)

View File

@ -0,0 +1,41 @@
function Invoke-WPFSelectedLabelUpdate {
<#
.SYNOPSIS
This is a helper function that is called by the Checked and Unchecked events of the Checkboxes on the install tab.
It Updates the "Selected Apps" Label on the Install Tab to represent the current collection
.PARAMETER type
Eigther: Add | Remove
.PARAMETER checkbox
should contain the current instance of the checkbox that triggered the Event.
Most of the time will be the automatic variable $this
.EXAMPLE
$checkbox.Add_Unchecked({Invoke-WPFSelectedLabelUpdate -type "Remove" -checkbox $this})
OR
Invoke-WPFSelectedLabelUpdate -type "Add" -checkbox $specificCheckbox
#>
param (
$type,
$checkbox
)
$selectedLabel = $sync.WPFSelectedLabel
# Get the actual Name from the Label inside the Checkbox
$appKey = $checkbox.Parent.Parent.Tag
if ($type -eq "Add") {
$sync.selectedApps.Add($appKey)
# The List type needs to be specified again, because otherwise Sort-Object will convert the list to a string if there is only a single entry
[System.Collections.Generic.List[pscustomobject]]$sync.selectedApps = $sync.SelectedApps | Sort-Object
}
elseif ($type -eq "Remove") {
$sync.SelectedApps.Remove($appKey)
}
else{
Write-Error "Type: $type not implemented"
}
$count = $sync.SelectedApps.Count
$SelectedLabel.Content = "Selected Apps: $count"
if ($count -gt 0) {
$SelectedLabel.ToolTip = $($sync.SelectedApps | Foreach-Object { $SortedAppsHashtable.$_.Content }) -join "`n"
} else {
$SelectedLabel.ToolTip = $Null
}
}

View File

@ -0,0 +1,450 @@
function Toggle-CategoryVisibility {
param(
[Parameter(Mandatory=$true)]
[string]$Category,
[Parameter(Mandatory=$true)]
[System.Windows.Controls.ItemsControl]$ItemsControl
)
$appsInCategory = $ItemsControl.Items | Where-Object {
if ($null -ne $_.Tag){
$SortedAppsHashtable.$($_.Tag).Category -eq $Category
}
}
$isCollapsed = $appsInCategory[0].Visibility -eq [Windows.Visibility]::Visible
foreach ($appEntry in $appsInCategory) {
$appEntry.Visibility = if ($isCollapsed) {
[Windows.Visibility]::Collapsed
} else {
[Windows.Visibility]::Visible
}
}
$categoryPanel = $ItemsControl.Items | Where-Object { $_ -is [System.Windows.Controls.StackPanel] -and $_.Children[1].Text -eq $Category } | Select-Object -First 1
$categoryPanel.Children[0].Text = if ($isCollapsed) { "[+] " } else { "[-] " }
}
function Search-AppsByNameOrDescription {
param(
[Parameter(Mandatory=$false)]
[string]$SearchString = "",
[Parameter(Mandatory=$false)]
[System.Windows.Controls.ItemsControl]$ItemsControl = $sync.ItemsControl
)
$Apps = $ItemsControl.Items
if ([string]::IsNullOrWhiteSpace($SearchString)) {
$Apps | ForEach-Object {
$_.Visibility = 'Visible'
}
} else {
$Apps | ForEach-Object {
if ($null -ne $_.Tag) {
if ($SortedAppsHashtable.$($_.Tag).Content -like "*$SearchString*") {
$_.Visibility = 'Visible'
} else {
$_.Visibility = 'Collapsed'
}
}
}
}
}
function Show-OnlyCheckedApps {
param (
[Parameter(Mandatory=$true)]
[String[]]$appKeys,
[Parameter(Mandatory=$true)]
[System.Windows.Controls.ItemsControl]$ItemsControl
)
Write-Host "Showing only $($appKeys.Count) apps"
$sync.ShowOnlySelected = -not $sync.ShowOnlySelected
if ($sync.ShowOnlySelected) {
$sync.Buttons.ShowSelectedAppsButton.Content = "Show All"
foreach ($item in $ItemsControl.Items) {
if ($appKeys -contains $item.Tag) {
$item.Visibility = [Windows.Visibility]::Visible
} else {
$item.Visibility = [Windows.Visibility]::Collapsed
}
}
} else {
$sync.Buttons.ShowSelectedAppsButton.Content = "Show Selected"
$ItemsControl.Items | ForEach-Object { $_.Visibility = [Windows.Visibility]::Visible }
}
}
function Invoke-WPFUIApps {
[OutputType([void])]
param(
[Parameter(Mandatory, Position = 0)]
[PSCustomObject[]]$Apps,
[Parameter(Mandatory, Position = 1)]
[string]$TargetGridName,
[Parameter()]
[System.Boolean]$Alphabetical = $false
)
function Initialize-StackPanel {
$targetGrid = $window.FindName($TargetGridName)
$borderStyle = $window.FindResource("BorderStyle")
$null = $targetGrid.Children.Clear()
$mainBorder = New-Object Windows.Controls.Border
$mainBorder.VerticalAlignment = "Stretch"
$mainBorder.Style = $borderStyle
$null = $targetGrid.Children.Add($mainBorder)
return $targetGrid
}
function Initialize-Header {
param($TargetGrid)
$mainBorder = $TargetGrid.Children[0]
$dockPanel = New-Object Windows.Controls.DockPanel
$mainBorder.Child = $dockPanel
function New-WPFButton {
param (
[string]$Name,
[string]$Content
)
$button = New-Object Windows.Controls.Button
$button.Name = $Name
$button.Content = $Content
$button.Margin = New-Object Windows.Thickness(2)
$button.HorizontalAlignment = "Stretch"
return $button
}
$wrapPanelTop = New-Object Windows.Controls.WrapPanel
$wrapPanelTop.SetResourceReference([Windows.Controls.Control]::BackgroundProperty, "MainBackgroundColor")
$wrapPanelTop.HorizontalAlignment = "Left"
$wrapPanelTop.VerticalAlignment = "Top"
$wrapPanelTop.Orientation = "Horizontal"
$wrapPanelTop.Margin = $window.FindResource("TabContentMargin")
$buttonConfigs = @(
@{Name="WPFInstall"; Content="Install/Upgrade Selected"},
@{Name="WPFInstallUpgrade"; Content="Upgrade All"},
@{Name="WPFUninstall"; Content="Uninstall Selected"}
)
foreach ($config in $buttonConfigs) {
$button = New-WPFButton -Name $config.Name -Content $config.Content
$null = $wrapPanelTop.Children.Add($button)
$sync[$config.Name] = $button
}
$selectedLabel = New-Object Windows.Controls.Label
$selectedLabel.Name = "WPFSelectedLabel"
$selectedLabel.Content = "Selected Apps: 0"
$selectedLabel.SetResourceReference([Windows.Controls.Control]::FontSizeProperty, "FontSizeHeading")
$selectedLabel.SetResourceReference([Windows.Controls.Control]::MarginProperty, "TabContentMargin")
$selectedLabel.SetResourceReference([Windows.Controls.Control]::ForegroundProperty, "MainForegroundColor")
$selectedLabel.HorizontalAlignment = "Center"
$selectedLabel.VerticalAlignment = "Center"
$null = $wrapPanelTop.Children.Add($selectedLabel)
$sync.$($selectedLabel.Name) = $selectedLabel
$showSelectedAppsButton = New-Object Windows.Controls.Button
$showSelectedAppsButton.Name = "ShowSelectedAppsButton"
$showSelectedAppsButton.Content = "Show Selected"
$showSelectedAppsButton.Add_Click({
if ($sync.SelectedApps.Count -gt 0) {
Show-OnlyCheckedApps -appKeys $sync.SelectedApps -ItemsControl $sync.ItemsControl
}
})
$sync.Buttons.ShowSelectedAppsButton = $showSelectedAppsButton
$null = $wrapPanelTop.Children.Add($showSelectedAppsButton)
[Windows.Controls.DockPanel]::SetDock($wrapPanelTop, [Windows.Controls.Dock]::Top)
$null = $dockPanel.Children.Add($wrapPanelTop)
return $dockPanel
}
function Initialize-AppArea {
param($TargetGrid)
$scrollViewer = New-Object Windows.Controls.ScrollViewer
$scrollViewer.VerticalScrollBarVisibility = 'Auto'
$scrollViewer.HorizontalAlignment = 'Stretch'
$scrollViewer.VerticalAlignment = 'Stretch'
$scrollViewer.CanContentScroll = $true
$itemsControl = New-Object Windows.Controls.ItemsControl
$itemsControl.HorizontalAlignment = 'Stretch'
$itemsControl.VerticalAlignment = 'Stretch'
$itemsPanelTemplate = New-Object Windows.Controls.ItemsPanelTemplate
$factory = New-Object Windows.FrameworkElementFactory ([Windows.Controls.VirtualizingStackPanel])
$itemsPanelTemplate.VisualTree = $factory
$itemsControl.ItemsPanel = $itemsPanelTemplate
$itemsControl.SetValue([Windows.Controls.VirtualizingStackPanel]::IsVirtualizingProperty, $true)
$itemsControl.SetValue([Windows.Controls.VirtualizingStackPanel]::VirtualizationModeProperty, [Windows.Controls.VirtualizationMode]::Recycling)
$scrollViewer.Content = $itemsControl
[Windows.Controls.DockPanel]::SetDock($scrollViewer, [Windows.Controls.Dock]::Bottom)
$null = $TargetGrid.Children.Add($scrollViewer)
return $itemsControl
}
function Add-CategoryLabel {
param(
[string]$Category,
$ItemsControl
)
$categoryPanel = New-Object Windows.Controls.StackPanel
$categoryPanel.Orientation = [Windows.Controls.Orientation]::Horizontal
$expanderIcon = New-Object Windows.Controls.TextBlock
$expanderIcon.Text = "[+] "
$expanderIcon.SetResourceReference([Windows.Controls.Control]::FontSizeProperty, "FontSizeHeading")
$expanderIcon.SetResourceReference([Windows.Controls.Control]::FontFamilyProperty, "HeaderFontFamily")
$expanderIcon.VerticalAlignment = "Center"
$null = $categoryPanel.Children.Add($expanderIcon)
$categoryLabel = New-Object Windows.Controls.TextBlock
$categoryLabel.Text = $Category
$categoryLabel.SetResourceReference([Windows.Controls.Control]::FontSizeProperty, "FontSizeHeading")
$categoryLabel.SetResourceReference([Windows.Controls.Control]::FontFamilyProperty, "HeaderFontFamily")
$categoryLabel.VerticalAlignment = "Center"
$null = $categoryPanel.Children.Add($categoryLabel)
$categoryPanel.Cursor = [System.Windows.Input.Cursors]::Hand
$categoryPanel.Add_MouseUp({
Toggle-CategoryVisibility -Category $this.Children[1].Text -ItemsControl $this.Parent
})
$null = $ItemsControl.Items.Add($categoryPanel)
}
function New-CategoryAppList {
param(
$TargetGrid,
$Apps,
[System.Boolean]$Alphabetical
)
$loadingLabel = New-Object Windows.Controls.Label
$loadingLabel.Content = "Loading, please wait..."
$loadingLabel.HorizontalAlignment = "Center"
$loadingLabel.VerticalAlignment = "Center"
$loadingLabel.FontSize = 16
$loadingLabel.FontWeight = [Windows.FontWeights]::Bold
$loadingLabel.Foreground = [Windows.Media.Brushes]::Gray
$itemsControl.Items.Clear()
$null = $itemsControl.Items.Add($loadingLabel)
$itemsControl.Dispatcher.Invoke([System.Windows.Threading.DispatcherPriority]::Background, [action]{
$itemsControl.Items.Clear()
if (-not ($Alphabetical)) {
$categories = $Apps.Values | Select-Object -ExpandProperty category -Unique | Sort-Object
foreach ($category in $categories) {
Add-CategoryLabel -Category $category -ItemsControl $itemsControl
$Apps.Keys | Where-Object { $Apps.$_.Category -eq $category } | ForEach-Object {
New-AppEntry -ItemsControl $itemsControl -AppKey $_ -Hidden $true
}
}
} else {
foreach ($appKey in $Apps.Keys) {
New-AppEntry -ItemsControl $itemsControl -AppKey $appKey -Hidden $false
}
}
})
}
function New-AppEntry {
param(
$ItemsControl,
$AppKey,
[bool]$Hidden
)
$App = $Apps.$AppKey
# Create the outer Border for the application type
$border = New-Object Windows.Controls.Border
$border.BorderBrush = [Windows.Media.Brushes]::Gray
$border.BorderThickness = 1
$border.CornerRadius = 5
$border.Padding = New-Object Windows.Thickness(10)
$border.HorizontalAlignment = "Stretch"
$border.VerticalAlignment = "Top"
$border.Margin = New-Object Windows.Thickness(0, 10, 0, 0)
$border.SetResourceReference([Windows.Controls.Control]::BackgroundProperty, "AppInstallUnselectedColor")
$border.Tag = $Appkey
$border.ToolTip = $App.description
$border.Visibility = if ($Hidden) {[Windows.Visibility]::Collapsed} else {[Windows.Visibility]::Visible}
$border.Add_MouseUp({
$childCheckbox = ($this.Child.Children | Where-Object {$_.Template.TargetType -eq [System.Windows.Controls.Checkbox]})[0]
$childCheckBox.isChecked = -not $childCheckbox.IsChecked
})
# Create a DockPanel inside the Border
$dockPanel = New-Object Windows.Controls.DockPanel
$dockPanel.LastChildFill = $true
$border.Child = $dockPanel
# Create the CheckBox, vertically centered
$checkBox = New-Object Windows.Controls.CheckBox
$checkBox.Name = $AppKey
$checkBox.Background = "Transparent"
$checkBox.HorizontalAlignment = "Left"
$checkBox.VerticalAlignment = "Center"
$checkBox.Margin = New-Object Windows.Thickness(5, 0, 10, 0)
$checkbox.Add_Checked({
Invoke-WPFSelectedLabelUpdate -type "Add" -checkbox $this
$borderElement = $this.Parent.Parent
$borderElement.SetResourceReference([Windows.Controls.Control]::BackgroundProperty, "AppInstallSelectedColor")
})
$checkbox.Add_Unchecked({
Invoke-WPFSelectedLabelUpdate -type "Remove" -checkbox $this
$borderElement = $this.Parent.Parent
$borderElement.SetResourceReference([Windows.Controls.Control]::BackgroundProperty, "AppInstallUnselectedColor")
})
$sync.$($checkBox.Name) = $checkBox
# Create a StackPanel for the image and name
$imageAndNamePanel = New-Object Windows.Controls.StackPanel
$imageAndNamePanel.Orientation = "Horizontal"
$imageAndNamePanel.VerticalAlignment = "Center"
# Create the Image and set a placeholder
$image = New-Object Windows.Controls.Image
# $image.Name = "wpfapplogo" + $App.Name
$image.Width = 40
$image.Height = 40
$image.Margin = New-Object Windows.Thickness(0, 0, 10, 0)
$image.Source = $noimage # Ensure $noimage is defined in your script
# Clip the image corners
$image.Clip = New-Object Windows.Media.RectangleGeometry
$image.Clip.Rect = New-Object Windows.Rect(0, 0, $image.Width, $image.Height)
$image.Clip.RadiusX = 5
$image.Clip.RadiusY = 5
$imageAndNamePanel.Children.Add($image) | Out-Null
# Create the TextBlock for the application name
$appName = New-Object Windows.Controls.TextBlock
$appName.Text = $App.Content
$appName.FontSize = 16
$appName.FontWeight = [Windows.FontWeights]::Bold
$appName.VerticalAlignment = "Center"
$appName.Margin = New-Object Windows.Thickness(5, 0, 0, 0)
$appName.Background = "Transparent"
$imageAndNamePanel.Children.Add($appName) | Out-Null
# Add the image and name panel to the Checkbox
$checkBox.Content = $imageAndNamePanel
# Add the checkbox to the DockPanel
[Windows.Controls.DockPanel]::SetDock($checkBox, [Windows.Controls.Dock]::Left)
$dockPanel.Children.Add($checkBox) | Out-Null
# Create the StackPanel for the buttons and dock it to the right
$buttonPanel = New-Object Windows.Controls.StackPanel
$buttonPanel.Orientation = "Horizontal"
$buttonPanel.HorizontalAlignment = "Right"
$buttonPanel.VerticalAlignment = "Center"
$buttonPanel.Margin = New-Object Windows.Thickness(10, 0, 0, 0)
[Windows.Controls.DockPanel]::SetDock($buttonPanel, [Windows.Controls.Dock]::Right)
# Create the "Install" button
$installButton = New-Object Windows.Controls.Button
$installButton.Width = 45
$installButton.Height = 35
$installButton.Margin = New-Object Windows.Thickness(0, 0, 10, 0)
$installIcon = New-Object Windows.Controls.TextBlock
$installIcon.Text = [char]0xE118 # Install Icon
$installIcon.FontFamily = "Segoe MDL2 Assets"
$installIcon.FontSize = 20
$installIcon.SetResourceReference([Windows.Controls.Control]::ForegroundProperty, "MainForegroundColor")
$installIcon.Background = "Transparent"
$installIcon.HorizontalAlignment = "Center"
$installIcon.VerticalAlignment = "Center"
$installButton.Content = $installIcon
$installButton.ToolTip = "Install or Upgrade the application"
$buttonPanel.Children.Add($installButton) | Out-Null
# Add Click event for the "Install" button
$installButton.Add_Click({
$appKey = $this.Parent.Parent.Parent.Tag
$appObject = $SortedAppsHashtable.$appKey
Invoke-WPFInstall -PackagesToInstall $appObject
})
# Create the "Uninstall" button
$uninstallButton = New-Object Windows.Controls.Button
$uninstallButton.Width = 45
$uninstallButton.Height = 35
$uninstallIcon = New-Object Windows.Controls.TextBlock
$uninstallIcon.Text = [char]0xE74D # Uninstall Icon
$uninstallIcon.FontFamily = "Segoe MDL2 Assets"
$uninstallIcon.FontSize = 20
$uninstallIcon.SetResourceReference([Windows.Controls.Control]::ForegroundProperty, "MainForegroundColor")
$uninstallIcon.Background = "Transparent"
$uninstallIcon.HorizontalAlignment = "Center"
$uninstallIcon.VerticalAlignment = "Center"
$uninstallButton.Content = $uninstallIcon
$buttonPanel.Children.Add($uninstallButton) | Out-Null
$uninstallButton.ToolTip = "Uninstall the application"
$uninstallButton.Add_Click({
$appKey = $this.Parent.Parent.Parent.Tag
$appObject = $SortedAppsHashtable.$appKey
Invoke-WPFUnInstall -PackagesToUninstall $appObject
})
# Create the "Info" button
$infoButton = New-Object Windows.Controls.Button
$infoButton.Width = 45
$infoButton.Height = 35
$infoButton.Margin = New-Object Windows.Thickness(10, 0, 0, 0)
$infoIcon = New-Object Windows.Controls.TextBlock
$infoIcon.Text = [char]0xE946 # Info Icon
$infoIcon.FontFamily = "Segoe MDL2 Assets"
$infoIcon.FontSize = 20
$infoIcon.SetResourceReference([Windows.Controls.Control]::ForegroundProperty, "MainForegroundColor")
$infoIcon.Background = "Transparent"
$infoIcon.HorizontalAlignment = "Center"
$infoIcon.VerticalAlignment = "Center"
$infoButton.Content = $infoIcon
$infoButton.ToolTip = "Open the application's website in your default browser"
$buttonPanel.Children.Add($infoButton) | Out-Null
$infoButton.Add_Click({
$appKey = $this.Parent.Parent.Parent.Tag
$appObject = $SortedAppsHashtable.$appKey
Start-Process $appObject.link
})
# Add the button panel to the DockPanel
$dockPanel.Children.Add($buttonPanel) | Out-Null
# Add the border to the main items control in the grid
$itemsControl.Items.Add($border) | Out-Null
}
$window = $sync.Form
switch ($TargetGridName) {
"appspanel" {
$targetGrid = Initialize-StackPanel
$dockPanelContainer = Initialize-Header -TargetGrid $targetGrid
$itemsControl = Initialize-AppArea -TargetGrid $dockPanelContainer
$sync.ItemsControl = $itemsControl
New-CategoryAppList -TargetGrid $itemsControl -Apps $Apps -Alphabetical $Alphabetical
}
default {
Write-Output "$TargetGridName not yet implemented"
}
}
}

View File

@ -27,7 +27,6 @@ function Invoke-WPFUIElements {
$window = $sync.form
$theme = $window.Resources
$borderstyle = $window.FindResource("BorderStyle")
$HoverTextBlockStyle = $window.FindResource("HoverTextBlockStyle")
$ColorfulToggleSwitchStyle = $window.FindResource("ColorfulToggleSwitchStyle")
@ -124,7 +123,9 @@ function Invoke-WPFUIElements {
if ($configVariable -eq $sync.configs.applications) {
# Create a WrapPanel to hold buttons at the top
$wrapPanelTop = New-Object Windows.Controls.WrapPanel
$wrapPanelTop.Background = $window.FindResource("MainBackgroundColor")
$wrapPanelTop.SetResourceReference([Windows.Controls.Control]::BackgroundProperty, "MainBackgroundColor")
$wrapPanelTop.HorizontalAlignment = "Left"
$wrapPanelTop.VerticalAlignment = "Top"
$wrapPanelTop.Orientation = "Horizontal"
@ -155,6 +156,18 @@ function Invoke-WPFUIElements {
$wrapPanelTop.Children.Add($uninstallButton) | Out-Null
$sync["WPFUninstall"] = $uninstallButton
$selectedLabel = New-Object Windows.Controls.Label
$selectedLabel.Name = "WPFSelectedLabel"
$selectedLabel.Content = "Selected Apps: 0"
$selectedLabel.SetResourceReference([Windows.Controls.Control]::FontSizeProperty, "FontSizeHeading")
$selectedLabel.SetResourceReference([Windows.Controls.Control]::MarginProperty, "TabContentMargin")
$selectedLabel.SetResourceReference([Windows.Controls.Control]::ForegroundProperty, "MainForegroundColor")
$selectedLabel.HorizontalAlignment = "Center"
$selectedLabel.VerticalAlignment = "Center"
$wrapPanelTop.Children.Add($selectedLabel) | Out-null
$sync.$($selectedLabel.Name) = $selectedLabel
# Dock the WrapPanel at the top of the DockPanel
[Windows.Controls.DockPanel]::SetDock($wrapPanelTop, [Windows.Controls.Dock]::Top)
$dockPanelContainer.Children.Add($wrapPanelTop) | Out-Null
@ -197,8 +210,10 @@ function Invoke-WPFUIElements {
$label = New-Object Windows.Controls.Label
$label.Content = $category -replace ".*__", ""
$label.FontSize = $theme.FontSizeHeading
$label.FontFamily = $theme.HeaderFontFamily
$label.SetResourceReference([Windows.Controls.Control]::FontSizeProperty, "FontSizeHeading")
$label.SetResourceReference([Windows.Controls.Control]::FontFamilyProperty, "HeaderFontFamily")
$itemsControl.Items.Add($label) | Out-Null
$sync[$category] = $label
@ -220,6 +235,12 @@ function Invoke-WPFUIElements {
$border.VerticalAlignment = "Top"
$border.Margin = New-Object Windows.Thickness(0, 10, 0, 0)
$border.SetResourceReference([Windows.Controls.Control]::BackgroundProperty, "AppInstallUnselectedColor")
$border.Add_MouseUp({
$childCheckbox = ($this.Child.Children | Where-Object {$_.Template.TargetType -eq [System.Windows.Controls.Checkbox]})[0]
$childCheckBox.isChecked = -not $childCheckbox.IsChecked
})
# Create a DockPanel inside the Border
$dockPanel = New-Object Windows.Controls.DockPanel
$dockPanel.LastChildFill = $true
@ -228,11 +249,22 @@ function Invoke-WPFUIElements {
# Create the CheckBox, vertically centered
$checkBox = New-Object Windows.Controls.CheckBox
$checkBox.Name = $entryInfo.Name
$checkBox.Background = "Transparent"
$checkBox.HorizontalAlignment = "Left"
$checkBox.VerticalAlignment = "Center"
$checkBox.Margin = New-Object Windows.Thickness(5, 0, 10, 0)
[Windows.Controls.DockPanel]::SetDock($checkBox, [Windows.Controls.Dock]::Left)
$dockPanel.Children.Add($checkBox) | Out-Null
$checkbox.Add_Checked({
Invoke-WPFSelectedLabelUpdate -type "Add" -checkbox $this
$borderElement = $this.Parent.Parent
$borderElement.SetResourceReference([Windows.Controls.Control]::BackgroundProperty, "AppInstallSelectedColor")
})
$checkbox.Add_Unchecked({
Invoke-WPFSelectedLabelUpdate -type "Remove" -checkbox $this
$borderElement = $this.Parent.Parent
$borderElement.SetResourceReference([Windows.Controls.Control]::BackgroundProperty, "AppInstallUnselectedColor")
})
# Create a StackPanel for the image and name
$imageAndNamePanel = New-Object Windows.Controls.StackPanel
@ -262,11 +294,16 @@ function Invoke-WPFUIElements {
$appName.FontWeight = [Windows.FontWeights]::Bold
$appName.VerticalAlignment = "Center"
$appName.Margin = New-Object Windows.Thickness(5, 0, 0, 0)
$appName.Background = "Transparent"
$imageAndNamePanel.Children.Add($appName) | Out-Null
# Add the image and name panel to the dock panel
[Windows.Controls.DockPanel]::SetDock($imageAndNamePanel, [Windows.Controls.Dock]::Left)
$dockPanel.Children.Add($imageAndNamePanel) | Out-Null
# Add the image and name panel to the Checkbox
$checkBox.Content = $imageAndNamePanel
# Add the checkbox to the DockPanel
[Windows.Controls.DockPanel]::SetDock($checkBox, [Windows.Controls.Dock]::Left)
$dockPanel.Children.Add($checkBox) | Out-Null
# Create the StackPanel for the buttons and dock it to the right
$buttonPanel = New-Object Windows.Controls.StackPanel
@ -286,7 +323,9 @@ function Invoke-WPFUIElements {
$installIcon.Text = [char]0xE118 # Install Icon
$installIcon.FontFamily = "Segoe MDL2 Assets"
$installIcon.FontSize = 20
$installIcon.Foreground = $theme.MainForegroundColor
$installIcon.SetResourceReference([Windows.Controls.Control]::ForegroundProperty, "MainForegroundColor")
$installIcon.Background = "Transparent"
$installIcon.HorizontalAlignment = "Center"
$installIcon.VerticalAlignment = "Center"
@ -308,7 +347,9 @@ function Invoke-WPFUIElements {
$uninstallIcon.Text = [char]0xE74D # Uninstall Icon
$uninstallIcon.FontFamily = "Segoe MDL2 Assets"
$uninstallIcon.FontSize = 20
$uninstallIcon.Foreground = $theme.MainForegroundColor
$uninstallIcon.SetResourceReference([Windows.Controls.Control]::ForegroundProperty, "MainForegroundColor")
$uninstallIcon.Background = "Transparent"
$uninstallIcon.HorizontalAlignment = "Center"
$uninstallIcon.VerticalAlignment = "Center"
@ -330,7 +371,9 @@ function Invoke-WPFUIElements {
$infoIcon.Text = [char]0xE946 # Info Icon
$infoIcon.FontFamily = "Segoe MDL2 Assets"
$infoIcon.FontSize = 20
$infoIcon.Foreground = $theme.MainForegroundColor
$infoIcon.SetResourceReference([Windows.Controls.Control]::ForegroundProperty, "MainForegroundColor")
$infoIcon.Background = "Transparent"
$infoIcon.HorizontalAlignment = "Center"
$infoIcon.VerticalAlignment = "Center"
@ -388,7 +431,9 @@ function Invoke-WPFUIElements {
$label.Content = $entryInfo.Content
$label.ToolTip = $entryInfo.Description
$label.HorizontalAlignment = "Left"
$label.FontSize = $theme.FontSize
$label.SetResourceReference([Windows.Controls.Control]::FontSizeProperty, "FontSize")
$label.SetResourceReference([Windows.Controls.Control]::ForegroundProperty, "MainForegroundColor")
$dockPanel.Children.Add($label) | Out-Null
$itemsControl.Items.Add($dockPanel) | Out-Null
@ -407,14 +452,18 @@ function Invoke-WPFUIElements {
$toggleButton = New-Object Windows.Controls.ToggleButton
$toggleButton.Name = $entryInfo.Name
$toggleButton.HorizontalAlignment = "Left"
$toggleButton.Height = $theme.TabButtonHeight
$toggleButton.Width = $theme.TabButtonWidth
$toggleButton.SetResourceReference([Windows.Controls.Control]::HeightProperty, "TabButtonHeight")
$toggleButton.SetResourceReference([Windows.Controls.Control]::WidthProperty, "TabButtonWidth")
$toggleButton.SetResourceReference([Windows.Controls.Control]::BackgroundProperty, "ButtonInstallBackgroundColor")
$toggleButton.SetResourceReference([Windows.Controls.Control]::ForegroundProperty, "MainForegroundColor")
$toggleButton.FontWeight = [Windows.FontWeights]::Bold
$textBlock = New-Object Windows.Controls.TextBlock
$textBlock.FontSize = $theme.TabButtonFontSize
$textBlock.SetResourceReference([Windows.Controls.Control]::FontSizeProperty, "TabButtonFontSize")
$textBlock.Background = [Windows.Media.Brushes]::Transparent
$textBlock.SetResourceReference([Windows.Controls.Control]::ForegroundProperty, "ButtonInstallForegroundColor")
@ -443,21 +492,26 @@ function Invoke-WPFUIElements {
$label.Content = $entryInfo.Content
$label.HorizontalAlignment = "Left"
$label.VerticalAlignment = "Center"
$label.FontSize = $theme.ButtonFontSize
$label.SetResourceReference([Windows.Controls.Control]::FontSizeProperty, "ButtonFontSize")
$horizontalStackPanel.Children.Add($label) | Out-Null
$comboBox = New-Object Windows.Controls.ComboBox
$comboBox.Name = $entryInfo.Name
$comboBox.Height = $theme.ButtonHeight
$comboBox.Width = $theme.ButtonWidth
$comboBox.SetResourceReference([Windows.Controls.Control]::HeightProperty, "ButtonHeight")
$comboBox.SetResourceReference([Windows.Controls.Control]::WidthProperty, "ButtonWidth")
$comboBox.HorizontalAlignment = "Left"
$comboBox.VerticalAlignment = "Center"
$comboBox.Margin = $theme.ButtonMargin
$comboBox.SetResourceReference([Windows.Controls.Control]::MarginProperty, "ButtonMargin")
foreach ($comboitem in ($entryInfo.ComboItems -split " ")) {
$comboBoxItem = New-Object Windows.Controls.ComboBoxItem
$comboBoxItem.Content = $comboitem
$comboBoxItem.FontSize = $theme.ButtonFontSize
$comboBoxItem.SetResourceReference([Windows.Controls.Control]::FontSizeProperty, "ButtonFontSize")
$comboBox.Items.Add($comboBoxItem) | Out-Null
}
@ -474,8 +528,10 @@ function Invoke-WPFUIElements {
$button.Name = $entryInfo.Name
$button.Content = $entryInfo.Content
$button.HorizontalAlignment = "Left"
$button.Margin = $theme.ButtonMargin
$button.FontSize = $theme.ButtonFontSize
$button.SetResourceReference([Windows.Controls.Control]::MarginProperty, "ButtonMargin")
$button.SetResourceReference([Windows.Controls.Control]::FontSizeProperty, "ButtonFontSize")
if ($entryInfo.ButtonWidth) {
$button.Width = $entryInfo.ButtonWidth
}
@ -504,8 +560,10 @@ function Invoke-WPFUIElements {
$radioButton.GroupName = $entryInfo.GroupName
$radioButton.Content = $entryInfo.Content
$radioButton.HorizontalAlignment = "Left"
$radioButton.Margin = $theme.CheckBoxMargin
$radioButton.FontSize = $theme.ButtonFontSize
$radioButton.SetResourceReference([Windows.Controls.Control]::MarginProperty, "CheckBoxMargin")
$radioButton.SetResourceReference([Windows.Controls.Control]::FontSizeProperty, "ButtonFontSize")
$radioButton.ToolTip = $entryInfo.Description
if ($entryInfo.Checked -eq $true) {
@ -524,9 +582,11 @@ function Invoke-WPFUIElements {
$checkBox = New-Object Windows.Controls.CheckBox
$checkBox.Name = $entryInfo.Name
$checkBox.Content = $entryInfo.Content
$checkBox.FontSize = $theme.FontSize
$checkBox.SetResourceReference([Windows.Controls.Control]::FontSizeProperty, "FontSize")
$checkBox.ToolTip = $entryInfo.Description
$checkBox.Margin = $theme.CheckBoxMargin
$checkBox.SetResourceReference([Windows.Controls.Control]::MarginProperty, "CheckBoxMargin")
if ($entryInfo.Checked -eq $true) {
$checkBox.IsChecked = $entryInfo.Checked
}

View File

@ -1,9 +1,12 @@
function Invoke-WPFUnInstall {
param(
[Parameter(Mandatory=$false)]
[PSObject[]]$PackagesToUninstall = $($sync.selectedApps | Foreach-Object { $SortedAppsHashtable.$_ })
)
<#
.SYNOPSIS
Uninstalls the selected programs
#>
if($sync.ProcessRunning) {
@ -12,9 +15,7 @@ function Invoke-WPFUnInstall {
return
}
$PackagesToInstall = (Get-WinUtilCheckBoxes)["Install"]
if ($PackagesToInstall.Count -eq 0) {
if ($PackagesToUninstall.Count -eq 0) {
$WarningMsg = "Please select the program(s) to uninstall"
[System.Windows.MessageBox]::Show($WarningMsg, $AppTitle, [System.Windows.MessageBoxButton]::OK, [System.Windows.MessageBoxImage]::Warning)
return
@ -22,7 +23,7 @@ function Invoke-WPFUnInstall {
$ButtonType = [System.Windows.MessageBoxButton]::YesNo
$MessageboxTitle = "Are you sure?"
$Messageboxbody = ("This will uninstall the following applications: `n $($PackagesToInstall | Format-Table | Out-String)")
$Messageboxbody = ("This will uninstall the following applications: `n $($PackagesToUninstall | Select-Object Name, Description| Out-String)")
$MessageIcon = [System.Windows.MessageBoxImage]::Information
$confirm = [System.Windows.MessageBox]::Show($Messageboxbody, $MessageboxTitle, $ButtonType, $MessageIcon)
@ -30,9 +31,9 @@ function Invoke-WPFUnInstall {
if($confirm -eq "No") {return}
$ChocoPreference = $($sync.WPFpreferChocolatey.IsChecked)
Invoke-WPFRunspace -ArgumentList @(("PackagesToInstall", $PackagesToInstall),("ChocoPreference", $ChocoPreference)) -DebugPreference $DebugPreference -ScriptBlock {
param($PackagesToInstall, $ChocoPreference, $DebugPreference)
if ($PackagesToInstall.count -eq 1) {
Invoke-WPFRunspace -ArgumentList @(("PackagesToUninstall", $PackagesToUninstall),("ChocoPreference", $ChocoPreference)) -DebugPreference $DebugPreference -ScriptBlock {
param($PackagesToUninstall, $ChocoPreference, $DebugPreference)
if ($PackagesToUninstall.count -eq 1) {
$sync.form.Dispatcher.Invoke([action]{ Set-WinUtilTaskbaritem -state "Indeterminate" -value 0.01 -overlay "logo" })
} else {
$sync.form.Dispatcher.Invoke([action]{ Set-WinUtilTaskbaritem -state "Normal" -value 0.01 -overlay "logo" })
@ -41,7 +42,7 @@ function Invoke-WPFUnInstall {
$packagesWinget = [System.Collections.ArrayList]::new()
$packagesChoco = [System.Collections.ArrayList]::new()
foreach ($package in $PackagesToInstall) {
foreach ($package in $PackagesToUninstall) {
if ($ChocoPreference) {
if ($package.choco -eq "na") {
$packagesWinget.add($package.winget)
@ -62,7 +63,7 @@ function Invoke-WPFUnInstall {
}
}
return $packagesWinget, $packagesChoco
}.Invoke($PackagesToInstall)
}.Invoke($PackagesToUninstall)
try {
$sync.ProcessRunning = $true

View File

@ -115,32 +115,34 @@ Invoke-WinutilThemeChange -init $true
$noimage = "https://images.emojiterra.com/google/noto-emoji/unicode-15/color/512px/1f4e6.png"
$noimage = [Windows.Media.Imaging.BitmapImage]::new([Uri]::new($noimage))
# Extract unique categories from the applications configuration
$uniqueCategories = $sync.configs.applications.PSObject.Properties.Value |
Where-Object { $_.Category } |
Select-Object -Unique -ExpandProperty Category
# Create a custom PSCustomObject to simulate category-level checkboxes
$categoryConfig = @{}
foreach ($category in $uniqueCategories) {
# Sanitize the category name for use in the Name property (remove spaces, special characters)
$sanitizedCategoryName = $category -replace '\W', '_'
$categoryConfig[$sanitizedCategoryName] = [PSCustomObject]@{
Category = "Categories"
Content = $category
}
$sync.configs.appnavigation | Add-Member -MemberType NoteProperty -Name $sanitizedCategoryName -Value $categoryConfig[$sanitizedCategoryName] -Force
$sync.Buttons = @{}
$SortedAppsHashtable = [ordered]@{}
$sortedProperties = $sync.configs.applications.PSObject.Properties | Sort-Object { $_.Value.Content }
$sortedProperties | ForEach-Object {
$SortedAppsHashtable[$_.Name] = $_.Value
}
# Now call the function with the final merged config
Invoke-WPFUIElements -configVariable $sync.configs.appnavigation -targetGridName "appscategory" -columncount 1
Invoke-WPFUIElements -configVariable $sync.configs.applications -targetGridName "appspanel" -columncount 1
Invoke-WPFUIApps -Apps $SortedAppsHashtable -targetGridName "appspanel"
Invoke-WPFUIElements -configVariable $sync.configs.tweaks -targetGridName "tweakspanel" -columncount 2
Invoke-WPFUIElements -configVariable $sync.configs.feature -targetGridName "featurespanel" -columncount 2
$sync.SortbyCategory.Add_Checked({
Write-Host "Sort By Category"
$sync.Form.Dispatcher.BeginInvoke([System.Windows.Threading.DispatcherPriority]::Background, [action]{
Invoke-WPFUIApps -Apps $SortedAppsHashtable -targetGridName "appspanel"
}) | Out-Null
})
$sync.SortbyAlphabet.Add_Checked({
Write-Host "Sort By Alphabet"
$sync.Form.Dispatcher.BeginInvoke([System.Windows.Threading.DispatcherPriority]::Background, [action]{
Invoke-WPFUIApps -Apps $SortedAppsHashtable -targetGridName "appspanel" -alphabetical $true
})
})
#===========================================================================
# Store Form Objects In PowerShell
#===========================================================================
@ -450,73 +452,18 @@ if ($sync["ISOLanguage"].Items.Count -eq 1) {
}
$sync["ISOLanguage"].SelectedIndex = 0
# Load Checkboxes and Labels outside of the Filter function only once on startup for performance reasons
$filter = Get-WinUtilVariables -Type CheckBox
$CheckBoxes = ($sync.GetEnumerator()).where{ $psitem.Key -in $filter }
$filter = Get-WinUtilVariables -Type Label
$labels = @{}
($sync.GetEnumerator()).where{$PSItem.Key -in $filter} | ForEach-Object {$labels[$_.Key] = $_.Value}
$allCategories = $checkBoxes.Name | ForEach-Object {$sync.configs.applications.$_} | Select-Object -Unique -ExpandProperty category
$sync["SearchBar"].Add_TextChanged({
if ($sync.SearchBar.Text -ne "") {
$sync.SearchBarClearButton.Visibility = "Visible"
} else {
$sync.SearchBarClearButton.Visibility = "Collapsed"
}
$activeApplications = @()
$textToSearch = $sync.SearchBar.Text.ToLower()
foreach ($CheckBox in $CheckBoxes) {
# Skip if the checkbox is null, it doesn't have content or it is the prefer Choco checkbox
if ($CheckBox -eq $null -or $CheckBox.Value -eq $null -or $CheckBox.Value.Content -eq $null -or $CheckBox.Name -eq "WPFpreferChocolatey") {
continue
}
$checkBoxName = $CheckBox.Key
$textBlockName = $checkBoxName + "Link"
# Retrieve the corresponding text block based on the generated name
$textBlock = $sync[$textBlockName]
if ($CheckBox.Value.Content.ToString().ToLower().Contains($textToSearch)) {
$CheckBox.Value.Visibility = "Visible"
$activeApplications += $sync.configs.applications.$checkboxName
# Set the corresponding text block visibility
if ($textBlock -ne $null -and $textBlock -is [System.Windows.Controls.TextBlock]) {
$textBlock.Visibility = "Visible"
}
} else {
$CheckBox.Value.Visibility = "Collapsed"
# Set the corresponding text block visibility
if ($textBlock -ne $null -and $textBlock -is [System.Windows.Controls.TextBlock]) {
$textBlock.Visibility = "Collapsed"
}
}
}
$activeCategories = $activeApplications | Select-Object -ExpandProperty category -Unique
foreach ($category in $activeCategories) {
$sync[$category].Visibility = "Visible"
}
if ($activeCategories) {
$inactiveCategories = Compare-Object -ReferenceObject $allCategories -DifferenceObject $activeCategories -PassThru
} else {
$inactiveCategories = $allCategories
}
foreach ($category in $inactiveCategories) {
$sync[$category].Visibility = "Collapsed"
}
Search-AppsByNameOrDescription -SearchString $sync.SearchBar.Text
})
$sync["Form"].Add_Loaded({
param($e)
$sync.Form.MinWidth = "1000"
$sync["Form"].MaxWidth = [Double]::PositiveInfinity
$sync["Form"].MaxHeight = [Double]::PositiveInfinity
})
@ -643,5 +590,10 @@ $sync["SponsorMenuItem"].Add_Click({
Show-CustomDialog -Message $authorInfo -EnableScroll $true
})
#Initialize List to store the Names of the selected Apps on the Install Tab
$sync.selectedApps = [System.Collections.Generic.List[string]]::new()
$sync.ShowOnlySeleced = $false
$sync["Form"].ShowDialog() | out-null
Stop-Transcript