From fa51f4b918b638d2b962b2b6bcd3366e6872f17f Mon Sep 17 00:00:00 2001 From: Marterich <47688561+Marterich@users.noreply.github.com> Date: Wed, 19 Mar 2025 23:39:19 +0100 Subject: [PATCH] Optimize UI Load performance --- config/themes.json | 3 +- .../private/Initalize-InstallAppEntry.ps1 | 162 ++++++------------ .../Initialize-InstallCategoryAppList.ps1 | 23 ++- functions/public/Invoke-WPFUIApps.ps1 | 4 + scripts/main.ps1 | 17 +- scripts/start.ps1 | 14 ++ xaml/inputXML.xaml | 78 ++++++++- 7 files changed, 172 insertions(+), 129 deletions(-) diff --git a/config/themes.json b/config/themes.json index 4869120f..d4970cac 100644 --- a/config/themes.json +++ b/config/themes.json @@ -35,7 +35,8 @@ "CheckboxMouseOverColor": "#999999", "ButtonBorderThickness": "1", "ButtonMargin": "1", - "ButtonCornerRadius": "2" + "ButtonCornerRadius": "2", + "AppTileImageSize": "40" }, "Light": { "AppInstallUnselectedColor": "#F0F0F0", diff --git a/functions/private/Initalize-InstallAppEntry.ps1 b/functions/private/Initalize-InstallAppEntry.ps1 index 47268a18..864925f5 100644 --- a/functions/private/Initalize-InstallAppEntry.ps1 +++ b/functions/private/Initalize-InstallAppEntry.ps1 @@ -10,22 +10,14 @@ function Initialize-InstallAppEntry { #> param( [Windows.Controls.WrapPanel]$TargetElement, - $AppKey + $AppKey ) - $App = $sync.configs.applicationsHashtable.$AppKey + # Create the outer Border for the application type $border = New-Object Windows.Controls.Border - $border.BorderBrush = [Windows.Media.Brushes]::Gray - $border.SetResourceReference([Windows.Controls.Control]::BorderThicknessProperty, "AppTileBorderThickness") - $border.CornerRadius = 5 - $border.SetResourceReference([Windows.Controls.Control]::PaddingProperty, "AppTileMargins") - $border.SetResourceReference([Windows.Controls.Control]::WidthProperty, "AppTileWidth") - $border.VerticalAlignment = "Top" - $border.SetResourceReference([Windows.Controls.Control]::MarginProperty, "AppTileMargins") - $border.Cursor = [System.Windows.Input.Cursors]::Hand - $border.SetResourceReference([Windows.Controls.Control]::BackgroundProperty, "AppInstallUnselectedColor") - $border.Tag = $Appkey - $border.ToolTip = $App.description + $border.Style = $sync.Form.Resources.AppTileBorderStyle + $border.Tag = $AppKey + $border.ToolTip = $Apps.$AppKey.description $border.Add_MouseUp({ $childCheckbox = ($this.Child.Children | Where-Object {$_.Template.TargetType -eq [System.Windows.Controls.Checkbox]})[0] $childCheckBox.isChecked = -not $childCheckbox.IsChecked @@ -48,11 +40,7 @@ function Initialize-InstallAppEntry { # Create the CheckBox, vertically centered $checkBox = New-Object Windows.Controls.CheckBox $checkBox.Name = $AppKey - $checkBox.Background = "Transparent" - $checkBox.HorizontalAlignment = "Left" - $checkBox.VerticalAlignment = "Center" - $checkBox.SetResourceReference([Windows.Controls.Control]::MarginProperty, "AppTileMargins") - $checkBox.SetResourceReference([Windows.Controls.Control]::StyleProperty, "CollapsedCheckBoxStyle") + $checkbox.Style = $sync.Form.Resources.AppTileCheckboxStyle $checkbox.Add_Checked({ Invoke-WPFSelectedAppsUpdate -type "Add" -checkbox $this $borderElement = $this.Parent.Parent @@ -64,7 +52,7 @@ function Initialize-InstallAppEntry { $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" @@ -73,29 +61,15 @@ function Initialize-InstallAppEntry { # 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.Style = $sync.Form.Resources.AppTileImageStyle $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 - $image.SetResourceReference([Windows.Controls.Control]::VisibilityProperty, "AppTileCompactVisibility") - $imageAndNamePanel.Children.Add($image) | Out-Null # Create the TextBlock for the application name $appName = New-Object Windows.Controls.TextBlock - $appName.Text = $App.Content - $appName.SetResourceReference([Windows.Controls.Control]::FontSizeProperty, "AppTileFontSize") - $appName.FontWeight = [Windows.FontWeights]::Bold - $appName.SetResourceReference([Windows.Controls.Control]::ForegroundProperty, "MainForegroundColor") - $appName.VerticalAlignment = "Center" - $appName.SetResourceReference([Windows.Controls.Control]::MarginProperty, "AppTileMargins") - $appName.Background = "Transparent" + $appName.Style = $sync.Form.Resources.AppTileNameStyle + $appName.Text = $Apps.$AppKey.content $imageAndNamePanel.Children.Add($appName) | Out-Null # Add the image and name panel to the Checkbox @@ -107,91 +81,53 @@ function Initialize-InstallAppEntry { # 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.SetResourceReference([Windows.Controls.Control]::MarginProperty, "AppTileMargins") - $buttonPanel.SetResourceReference([Windows.Controls.Control]::VisibilityProperty, "AppTileCompactVisibility") + $buttonPanel.Style = $sync.Form.Resources.AppTileButtonPanelStyle [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) + # Define the button properties + $buttons = @( + [PSCustomObject]@{ Name = "Install"; Description = "Install or Upgrade the application"; Tooltip = "Install or Upgrade the application"; Icon = [char]0xE118 }, + [PSCustomObject]@{ Name = "Uninstall"; Description = "Uninstall the application"; Tooltip = "Uninstall the application"; Icon = [char]0xE74D }, + [PSCustomObject]@{ Name = "Info"; Description = "Open the application's website in your default browser"; Tooltip = "Open the application's website in your default browser"; Icon = [char]0xE946 } + ) - $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" + # Iterate over each button and create it + foreach ($button in $buttons) { + $newButton = New-Object Windows.Controls.Button + $newButton.Style = $sync.Form.Resources.AppTileButtonStyle + $newButton.Content = $button.Icon + $newButton.ToolTip = $button.Tooltip + $buttonPanel.Children.Add($newButton) | Out-Null - $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 = $sync.configs.applicationsHashtable.$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 = $sync.configs.applicationsHashtable.$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 = $sync.configs.applicationsHashtable.$appKey - Start-Process $appObject.link - }) + switch ($button.Name) { + "Install" { + $newButton.Add_Click({ + $appKey = $this.Parent.Parent.Parent.Tag + $appObject = $sync.configs.applicationsHashtable.$appKey + Invoke-WPFInstall -PackagesToInstall $appObject + }) + } + "Uninstall" { + $newButton.Add_Click({ + $appKey = $this.Parent.Parent.Parent.Tag + $appObject = $sync.configs.applicationsHashtable.$appKey + Invoke-WPFUnInstall -PackagesToUninstall $appObject + }) + } + "Info" { + $newButton.Add_Click({ + $appKey = $this.Parent.Parent.Parent.Tag + $appObject = $sync.configs.applicationsHashtable.$appKey + Start-Process $appObject.link + }) + } + } + } # Add the button panel to the DockPanel $dockPanel.Children.Add($buttonPanel) | Out-Null # Add the border to the corresponding Category $TargetElement.Children.Add($border) | Out-Null + return $checkbox } diff --git a/functions/private/Initialize-InstallCategoryAppList.ps1 b/functions/private/Initialize-InstallCategoryAppList.ps1 index aa5151e0..07fc7947 100644 --- a/functions/private/Initialize-InstallCategoryAppList.ps1 +++ b/functions/private/Initialize-InstallCategoryAppList.ps1 @@ -42,7 +42,7 @@ function Initialize-InstallCategoryAppList { $loadingLabel.Content = "Loading, please wait..." $loadingLabel.HorizontalAlignment = "Center" $loadingLabel.VerticalAlignment = "Center" - $loadingLabel.SetResourceReference([Windows.Controls.Control]::FontSizeProperty, "FontSizeHeading") + $loadingLabel.SetResourceReference([Windows.Controls.Control]::FontSizeProperty, "HeadingFontSize") $loadingLabel.FontWeight = [Windows.FontWeights]::Bold $loadingLabel.Foreground = [Windows.Media.Brushes]::Gray $sync.LoadingLabel = $loadingLabel @@ -53,8 +53,17 @@ function Initialize-InstallCategoryAppList { $TargetElement.Dispatcher.Invoke([System.Windows.Threading.DispatcherPriority]::Background, [action]{ $TargetElement.Items.Clear() # Remove the loading message - $categories = $Apps.Values | Select-Object -ExpandProperty category -Unique | Sort-Object - foreach ($category in $categories) { + + # Pre-group apps by category + $appsByCategory = @{} + foreach ($appKey in $Apps.Keys) { + $category = $Apps.$appKey.Category + if (-not $appsByCategory.ContainsKey($category)) { + $appsByCategory[$category] = @() + } + $appsByCategory[$category] += $appKey + } + foreach ($category in $($appsByCategory.Keys | Sort-Object)) { Add-Category -Category $category -TargetElement $TargetElement $wrapPanel = New-Object Windows.Controls.WrapPanel $wrapPanel.Orientation = "Horizontal" @@ -64,9 +73,9 @@ function Initialize-InstallCategoryAppList { $wrapPanel.Visibility = [Windows.Visibility]::Collapsed $wrapPanel.Tag = "CategoryWrapPanel_$category" $null = $TargetElement.Items.Add($wrapPanel) - $Apps.Keys | Where-Object { $Apps.$_.Category -eq $category } | Sort-Object | ForEach-Object { - Initialize-InstallAppEntry -TargetElement $wrapPanel -AppKey $_ - } + $appsByCategory[$category] | ForEach-Object { + $sync.$_ = $(Initialize-InstallAppEntry -TargetElement $wrapPanel -AppKey $_) } - }) + } + }) } diff --git a/functions/public/Invoke-WPFUIApps.ps1 b/functions/public/Invoke-WPFUIApps.ps1 index e339277f..04f417c3 100644 --- a/functions/public/Invoke-WPFUIApps.ps1 +++ b/functions/public/Invoke-WPFUIApps.ps1 @@ -10,9 +10,13 @@ function Invoke-WPFUIApps { switch ($TargetGridName) { "appspanel" { $dockPanel = Initialize-InstallAppsMainElement -TargetGridName $TargetGridName + log_time_taken "Setup DockPanel for Apps" $null = Initialize-InstallHeader -TargetElement $dockPanel + log_time_taken "Setup Header for Apps" $sync.ItemsControl = Initialize-InstallAppArea -TargetElement $dockPanel + log_time_taken "Setup ItemsControl for Apps" Initialize-InstallCategoryAppList -TargetElement $sync.ItemsControl -Apps $Apps + log_time_taken "UI Initialized" } default { Write-Output "$TargetGridName not yet implemented" diff --git a/scripts/main.ps1 b/scripts/main.ps1 index fe12165a..76453d77 100644 --- a/scripts/main.ps1 +++ b/scripts/main.ps1 @@ -45,7 +45,7 @@ class GenericException : Exception { [string]$additionalData GenericException($Message) : base($Message) {} } - +log_time_taken "Main.ps1 class setup line 48" $inputXML = $inputXML -replace 'mc:Ignorable="d"', '' -replace "x:N", 'N' -replace '^> $sync.log + $sync.start_time = $current_time +} + # Set DebugPreference based on the -Debug switch if ($Debug) { $DebugPreference = "Continue" @@ -34,6 +44,8 @@ Add-Type -AssemblyName System.Windows.Forms # Variable to sync between runspaces $sync = [Hashtable]::Synchronized(@{}) +$sync.log = "$ENV:USERPROFILE\Desktop\winutil.log" +$sync.start_time = Get-Date $sync.PSScriptRoot = $PSScriptRoot $sync.version = "#{replaceme}" $sync.configs = @{} @@ -88,3 +100,5 @@ Start-Transcript -Path "$logdir\winutil_$dateTime.log" -Append -NoClobber | Out- # Set PowerShell window title $Host.UI.RawUI.WindowTitle = $myInvocation.MyCommand.Definition + "(Admin)" clear-host +Write-Output "" > $sync.log +log_time_taken "Start.ps1 finished" \ No newline at end of file diff --git a/xaml/inputXML.xaml b/xaml/inputXML.xaml index 63a41af5..084c6d3c 100644 --- a/xaml/inputXML.xaml +++ b/xaml/inputXML.xaml @@ -67,6 +67,82 @@ + + + + + +