Compare commits

...

48 Commits

Author SHA1 Message Date
MyDrift
ba40a1f544
Merge a6bababb43 into 6e708bfe95 2024-11-08 15:12:23 -05:00
ChrisTitusTech
6e708bfe95 Deploying to main from @ ChrisTitusTech/winutil@e2b9586b0d 🚀 2024-11-08 15:32:39 +00:00
MyDrift
a6bababb43 remove installation scope
- remove all 3 radiobuttons from appnavigation.json
2024-11-03 16:27:43 +01:00
MyDrift
5514025577 run preprocessing 2024-11-02 13:51:48 +01:00
MyDrift
c46a7eaa40 disable autofallback checkbox 2024-11-02 13:51:15 +01:00
Marterich
e0e8daf4e2 Fix Bug where Scrollviewer dosnt work 2024-10-29 21:51:07 +01:00
Marterich
cf2f741408 Split up the functions to seperate files like the rest of the repo 2024-10-28 22:53:03 +01:00
Marterich
7d0e4df4ec Add a Popup Dropdown for Selected Apps with the ability to deselect them 2024-10-27 21:24:20 +01:00
MyDrift
7e6634d99d disable show selected filter on clear selection 2024-10-27 16:03:23 +01:00
MyDrift
f04b52d0db ToggleButtonStyle animation
- add hover animation to white dot
- remove IsPressed trigger
- improve some comments
2024-10-27 12:59:40 +01:00
Marterich
402082b376 Add hover effect for the app tiles 2024-10-26 21:00:34 +02:00
Marterich
79fb48e4df Slight modificatoin to togglebutton style & fix sidebar width 2024-10-26 19:52:23 +02:00
MyDrift
3faa3bad3d reorder buttons & fix Togglebutton toggling if action not possible
- reorder getinstalled and clearselection
- set togglebutton back if no app is selected
2024-10-26 17:16:33 +02:00
Marterich
d441952e5e Add logic to the new ToggleButtons in the sidebar of the install tab and remove old buttons 2024-10-26 16:36:42 +02:00
MyDrift
c0d6e0bbc7 Togglebutton fixes
- move dot to the right in style
- cleanup code
- fix arrangement of content
2024-10-26 15:25:33 +02:00
MyDrift
fd4d783a04 Improve Togglebutton
- add initial implementation of togglebutton style
- add togglebuttons to appnavigation.json
- refractor UI element creation for Togglebutton
- commit preprocessing changes
2024-10-26 14:08:53 +02:00
Marterich
e048097c78 Fix weird buggy behaviour in regards to switching the Display Mode and using Show-SelectedOnly 2024-10-21 22:35:00 +02:00
Marterich
4bfeacf80d Keep the search status when switching between compact and full view 2024-10-21 20:36:06 +02:00
Marterich
80a933db8e Fix Whitespace when using Search 2024-10-16 08:03:14 +02:00
Marterich
9dd89136e8 First Try at implementing a Compact Mode for the App page 2024-10-15 23:27:56 +02:00
Marterich
7b273d5634 Replace Category Label with ToggleButton, Fix Search Bugs 2024-10-14 22:25:23 +02:00
Marterich
2d0e68c90f Hotfix for Category Expansion during search 2024-10-14 21:31:53 +02:00
Marterich
ba968d0cb3 Style for Hidden Checkbox but visible Content 2024-10-14 20:46:28 +02:00
Marterich
8d34e2fa30 Small fixes to the Get-Installed function and formatting stuff 2024-10-14 20:02:36 +02:00
Marterich
dcf752fdeb Remove Alphabetical List, Sort Apps inside Category Alphabetically 2024-10-14 19:17:12 +02:00
Marterich
a839acd949 Remove Logic from Invoke-WPFUIElements that is Moved to Invoke-WPFUIApps 2024-10-13 20:55:25 +02:00
Marterich
f05fece2e5 Re-Add Choco Preference 2024-10-13 20:45:26 +02:00
Marterich
cf664bd1d3 Add Get-Installed Loading Indicator + small fixes 2024-10-13 20:33:26 +02:00
Martin Wiethan
6d88e51462
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
2024-10-13 19:25:02 +02:00
MyDrift
5bbc6c6a92
Merge branch 'ChrisTitusTech:main' into appspanelrestyle 2024-10-13 19:14:41 +02:00
MyDrift
fdb156a450 fix radiobuttons 2024-10-02 08:17:47 +02:00
MyDrift
7d90ab8660 add virtualisation & layouting fixes
- commented out prefer choco logic
- add virtualisation
- layouting improvements
2024-10-01 18:55:27 +02:00
MyDrift
f576d57ffc change category of new buttons 2024-09-29 10:24:21 +02:00
MyDrift
4889c1c508 fix app action button logic & move get & clear to sidepanel 2024-09-29 09:56:10 +02:00
MyDrift
ae1a9530f9 format logic for app action buttons 2024-09-29 09:40:28 +02:00
MyDrift
0467c3a7c8 move scrollviewer & app buttons into uielements logic 2024-09-29 09:32:10 +02:00
MyDrift
7686e7fff4 add sort by options 2024-09-28 17:05:25 +02:00
MyDrift
468b7209be rename buttons 2024-09-28 14:26:50 +02:00
MyDrift
15c84f2a1f add button action 2024-09-28 13:47:15 +02:00
MyDrift
5b0ea0b373 cleanup & remove nav from search effects 2024-09-28 13:40:38 +02:00
MyDrift
e8de029483 add notes 2024-09-28 02:21:12 +02:00
MyDrift
af39f43cec noimage fix 2024-09-28 02:19:42 +02:00
MyDrift
5bb940d4d5 fix scrollviewer & reimplement logo logic into ui elements 2024-09-28 02:01:53 +02:00
MyDrift
4c38768b32 add border name 2024-09-28 01:23:28 +02:00
MyDrift
6229ab6dd4 performance improvements
- move get logo to runspace (not working rn)
- readd choco checkbox to mute errors
2024-09-28 01:04:40 +02:00
MyDrift
71c35eccd6 add compatibility for every app 2024-09-28 00:43:56 +02:00
MyDrift
db521534bc add image support via choco db
- add image support via choco db
- backup image should be taken from unigetui db
- backup backup image is some random package one rn
2024-09-28 00:21:22 +02:00
MyDrift
a1188871f4 initial visual implementation
- remove idiotic border logic from Invoke-WPFUIElements
- add "application" type & style
- add "radiobutton" type & style
- remove prefer choco checkbox (did not modify logic outside of xaml, so i currently get errors due to that)
2024-09-27 22:54:07 +02:00
24 changed files with 1129 additions and 219 deletions

View File

@ -52,7 +52,7 @@ If you have Issues, refer to [Known Issues](https://christitustech.github.io/win
These are the sponsors that help keep this project alive with monthly contributions.
<!-- sponsors --><a href="https://github.com/ysaito8015"><img src="https:&#x2F;&#x2F;avatars.githubusercontent.com&#x2F;u&#x2F;3502978?u&#x3D;ca98bf67f04d67080df0feeaa6f007fad51d273f&amp;v&#x3D;4" width="60px" alt="Yusuke Saito" /></a><a href="https://github.com/TriHydera"><img src="https:&#x2F;&#x2F;avatars.githubusercontent.com&#x2F;u&#x2F;39857764?u&#x3D;5dbda638f45530582eee1703b4473f2a5e229e28&amp;v&#x3D;4" width="60px" alt="TriHydera" /></a><a href="https://github.com/jozozovko"><img src="https:&#x2F;&#x2F;avatars.githubusercontent.com&#x2F;u&#x2F;3272468?u&#x3D;4391ed4655e4fd8b56e23b4169e44e2ac9b6cd97&amp;v&#x3D;4" width="60px" alt="" /></a><a href="https://github.com/DelDongo"><img src="https:&#x2F;&#x2F;avatars.githubusercontent.com&#x2F;u&#x2F;127976398?v&#x3D;4" width="60px" alt="" /></a><a href="https://github.com/markamos"><img src="https:&#x2F;&#x2F;avatars.githubusercontent.com&#x2F;u&#x2F;9561861?u&#x3D;3cca179dcff0413538591e57a3abea116d65ce56&amp;v&#x3D;4" width="60px" alt="Mark Amos" /></a><a href="https://github.com/dwelfusius"><img src="https:&#x2F;&#x2F;avatars.githubusercontent.com&#x2F;u&#x2F;54533224?u&#x3D;a49ea000a8f52adb31382ea69a1a7501b27fefdd&amp;v&#x3D;4" width="60px" alt="" /></a><a href="https://github.com/mews-se"><img src="https:&#x2F;&#x2F;avatars.githubusercontent.com&#x2F;u&#x2F;58894405?v&#x3D;4" width="60px" alt="" /></a><a href="https://github.com/jdiegmueller"><img src="https:&#x2F;&#x2F;avatars.githubusercontent.com&#x2F;u&#x2F;18660571?u&#x3D;601d0a23040a271c86b5d40339f899a6dbf27086&amp;v&#x3D;4" width="60px" alt="Jason A. Diegmueller" /></a><a href="https://github.com/AlanTristar"><img src="https:&#x2F;&#x2F;avatars.githubusercontent.com&#x2F;u&#x2F;105566568?v&#x3D;4" width="60px" alt="" /></a><a href="https://github.com/zepled112"><img src="https:&#x2F;&#x2F;avatars.githubusercontent.com&#x2F;u&#x2F;65176625?v&#x3D;4" width="60px" alt="wyatt" /></a><a href="https://github.com/altugtekiner"><img src="https:&#x2F;&#x2F;avatars.githubusercontent.com&#x2F;u&#x2F;105917451?u&#x3D;ee73ff639c7bd9feb4708ab4ba7b14eff80196f7&amp;v&#x3D;4" width="60px" alt="" /></a><a href="https://github.com/robertsandrock"><img src="https:&#x2F;&#x2F;avatars.githubusercontent.com&#x2F;u&#x2F;12015331?v&#x3D;4" width="60px" alt="RMS" /></a><a href="https://github.com/mmomega"><img src="https:&#x2F;&#x2F;avatars.githubusercontent.com&#x2F;u&#x2F;71956566?v&#x3D;4" width="60px" alt="" /></a><a href="https://github.com/KenichiQaz"><img src="https:&#x2F;&#x2F;avatars.githubusercontent.com&#x2F;u&#x2F;31177857?u&#x3D;efdbae734a4c60a7bb95df4659d0535e60a6fd57&amp;v&#x3D;4" width="60px" alt="Stefan" /></a><a href="https://github.com/paulsheets"><img src="https:&#x2F;&#x2F;avatars.githubusercontent.com&#x2F;u&#x2F;45240946?u&#x3D;d4db66f8e8d7a2606fe7a5521daf48ca9f097105&amp;v&#x3D;4" width="60px" alt="Paul" /></a><a href="https://github.com/djones369"><img src="https:&#x2F;&#x2F;avatars.githubusercontent.com&#x2F;u&#x2F;4107092?v&#x3D;4" width="60px" alt="Dave Jones" /></a><a href="https://github.com/anthonymendez"><img src="https:&#x2F;&#x2F;avatars.githubusercontent.com&#x2F;u&#x2F;19240897?u&#x3D;f82b4be098cac65c8421421b70ebd2d1da85c67e&amp;v&#x3D;4" width="60px" alt="Anthony Mendez" /></a><a href="https://github.com/xBandaku"><img src="https:&#x2F;&#x2F;avatars.githubusercontent.com&#x2F;u&#x2F;142067112?u&#x3D;0c9a1edee45ac2a0a42827d418a12b1791d52350&amp;v&#x3D;4" width="60px" alt="xPandaku" /></a><a href="https://github.com/claudemods"><img src="https:&#x2F;&#x2F;avatars.githubusercontent.com&#x2F;u&#x2F;73653396?u&#x3D;d64c656fb8db24ef56bb000197532df9b618d06c&amp;v&#x3D;4" width="60px" alt="Claudemods" /></a><a href="https://github.com/FatBastard0"><img src="https:&#x2F;&#x2F;avatars.githubusercontent.com&#x2F;u&#x2F;173957728?v&#x3D;4" width="60px" alt="" /></a><a href="https://github.com/Ascent7910"><img src="https:&#x2F;&#x2F;avatars.githubusercontent.com&#x2F;u&#x2F;118260621?v&#x3D;4" width="60px" alt="Max" /></a><a href="https://github.com/DursleyGuy"><img src="https:&#x2F;&#x2F;avatars.githubusercontent.com&#x2F;u&#x2F;140165544?v&#x3D;4" width="60px" alt="DursleyGuy" /></a><a href="https://github.com/YamiSandman616"><img src="https:&#x2F;&#x2F;avatars.githubusercontent.com&#x2F;u&#x2F;183505690?u&#x3D;c3bd20157058b6215e28f7568d4f8c4fbbe92838&amp;v&#x3D;4" width="60px" alt="Sandman616" /></a><a href="https://github.com/realmuddy"><img src="https:&#x2F;&#x2F;avatars.githubusercontent.com&#x2F;u&#x2F;30978236?v&#x3D;4" width="60px" alt="Phillip Waters" /></a><a href="https://github.com/Tariq-Al-Zahrani"><img src="https:&#x2F;&#x2F;avatars.githubusercontent.com&#x2F;u&#x2F;187593049?v&#x3D;4" width="60px" alt="" /></a><!-- sponsors -->
<!-- sponsors --><a href="https://github.com/ysaito8015"><img src="https:&#x2F;&#x2F;avatars.githubusercontent.com&#x2F;u&#x2F;3502978?u&#x3D;ca98bf67f04d67080df0feeaa6f007fad51d273f&amp;v&#x3D;4" width="60px" alt="Yusuke Saito" /></a><a href="https://github.com/TriHydera"><img src="https:&#x2F;&#x2F;avatars.githubusercontent.com&#x2F;u&#x2F;39857764?u&#x3D;5dbda638f45530582eee1703b4473f2a5e229e28&amp;v&#x3D;4" width="60px" alt="TriHydera" /></a><a href="https://github.com/jozozovko"><img src="https:&#x2F;&#x2F;avatars.githubusercontent.com&#x2F;u&#x2F;3272468?u&#x3D;4391ed4655e4fd8b56e23b4169e44e2ac9b6cd97&amp;v&#x3D;4" width="60px" alt="" /></a><a href="https://github.com/DelDongo"><img src="https:&#x2F;&#x2F;avatars.githubusercontent.com&#x2F;u&#x2F;127976398?v&#x3D;4" width="60px" alt="" /></a><a href="https://github.com/markamos"><img src="https:&#x2F;&#x2F;avatars.githubusercontent.com&#x2F;u&#x2F;9561861?u&#x3D;3cca179dcff0413538591e57a3abea116d65ce56&amp;v&#x3D;4" width="60px" alt="Mark Amos" /></a><a href="https://github.com/dwelfusius"><img src="https:&#x2F;&#x2F;avatars.githubusercontent.com&#x2F;u&#x2F;54533224?u&#x3D;a49ea000a8f52adb31382ea69a1a7501b27fefdd&amp;v&#x3D;4" width="60px" alt="" /></a><a href="https://github.com/mews-se"><img src="https:&#x2F;&#x2F;avatars.githubusercontent.com&#x2F;u&#x2F;58894405?v&#x3D;4" width="60px" alt="" /></a><a href="https://github.com/jdiegmueller"><img src="https:&#x2F;&#x2F;avatars.githubusercontent.com&#x2F;u&#x2F;18660571?u&#x3D;601d0a23040a271c86b5d40339f899a6dbf27086&amp;v&#x3D;4" width="60px" alt="Jason A. Diegmueller" /></a><a href="https://github.com/AlanTristar"><img src="https:&#x2F;&#x2F;avatars.githubusercontent.com&#x2F;u&#x2F;105566568?v&#x3D;4" width="60px" alt="" /></a><a href="https://github.com/zepled112"><img src="https:&#x2F;&#x2F;avatars.githubusercontent.com&#x2F;u&#x2F;65176625?v&#x3D;4" width="60px" alt="wyatt" /></a><a href="https://github.com/altugtekiner"><img src="https:&#x2F;&#x2F;avatars.githubusercontent.com&#x2F;u&#x2F;105917451?u&#x3D;ee73ff639c7bd9feb4708ab4ba7b14eff80196f7&amp;v&#x3D;4" width="60px" alt="" /></a><a href="https://github.com/robertsandrock"><img src="https:&#x2F;&#x2F;avatars.githubusercontent.com&#x2F;u&#x2F;12015331?v&#x3D;4" width="60px" alt="RMS" /></a><a href="https://github.com/mmomega"><img src="https:&#x2F;&#x2F;avatars.githubusercontent.com&#x2F;u&#x2F;71956566?v&#x3D;4" width="60px" alt="" /></a><a href="https://github.com/KenichiQaz"><img src="https:&#x2F;&#x2F;avatars.githubusercontent.com&#x2F;u&#x2F;31177857?u&#x3D;efdbae734a4c60a7bb95df4659d0535e60a6fd57&amp;v&#x3D;4" width="60px" alt="Stefan" /></a><a href="https://github.com/paulsheets"><img src="https:&#x2F;&#x2F;avatars.githubusercontent.com&#x2F;u&#x2F;45240946?u&#x3D;d4db66f8e8d7a2606fe7a5521daf48ca9f097105&amp;v&#x3D;4" width="60px" alt="Paul" /></a><a href="https://github.com/djones369"><img src="https:&#x2F;&#x2F;avatars.githubusercontent.com&#x2F;u&#x2F;4107092?v&#x3D;4" width="60px" alt="Dave Jones" /></a><a href="https://github.com/anthonymendez"><img src="https:&#x2F;&#x2F;avatars.githubusercontent.com&#x2F;u&#x2F;19240897?u&#x3D;f82b4be098cac65c8421421b70ebd2d1da85c67e&amp;v&#x3D;4" width="60px" alt="Anthony Mendez" /></a><a href="https://github.com/claudemods"><img src="https:&#x2F;&#x2F;avatars.githubusercontent.com&#x2F;u&#x2F;73653396?u&#x3D;d64c656fb8db24ef56bb000197532df9b618d06c&amp;v&#x3D;4" width="60px" alt="Claudemods" /></a><a href="https://github.com/FatBastard0"><img src="https:&#x2F;&#x2F;avatars.githubusercontent.com&#x2F;u&#x2F;173957728?v&#x3D;4" width="60px" alt="" /></a><a href="https://github.com/Ascent7910"><img src="https:&#x2F;&#x2F;avatars.githubusercontent.com&#x2F;u&#x2F;118260621?v&#x3D;4" width="60px" alt="Max" /></a><a href="https://github.com/DursleyGuy"><img src="https:&#x2F;&#x2F;avatars.githubusercontent.com&#x2F;u&#x2F;140165544?v&#x3D;4" width="60px" alt="DursleyGuy" /></a><a href="https://github.com/YamiSandman616"><img src="https:&#x2F;&#x2F;avatars.githubusercontent.com&#x2F;u&#x2F;183505690?u&#x3D;c3bd20157058b6215e28f7568d4f8c4fbbe92838&amp;v&#x3D;4" width="60px" alt="Sandman616" /></a><a href="https://github.com/realmuddy"><img src="https:&#x2F;&#x2F;avatars.githubusercontent.com&#x2F;u&#x2F;30978236?v&#x3D;4" width="60px" alt="Phillip Waters" /></a><a href="https://github.com/Tariq-Al-Zahrani"><img src="https:&#x2F;&#x2F;avatars.githubusercontent.com&#x2F;u&#x2F;187593049?v&#x3D;4" width="60px" alt="" /></a><!-- sponsors -->
## 🏅 Thanks to all Contributors
Thanks a lot for spending your time helping Winutil grow. Thanks a lot! Keep rocking 🍻.

55
config/appnavigation.json Normal file
View File

@ -0,0 +1,55 @@
{
"WPFToggleView": {
"Content": ["Expanded View", "Compact View"],
"Category": "____Actions",
"Type": "ToggleButton",
"Order": "1",
"Description": "Toggle between a list and a compact grid like view"
},
"WPFSelectedFilter": {
"Content": [ "Show All", "Show Selected"],
"Category": "____Actions",
"Type": "ToggleButton",
"Order": "2",
"Description": "Toggle between showing all or only the selected applications"
},
"WPFClearInstallSelection": {
"Content": "Clear Selection",
"Category": "____Actions",
"Type": "Button",
"Order": "3",
"Description": "Clear the selection of applications"
},
"WPFGetInstalled": {
"Content": "Get Installed",
"Category": "____Actions",
"Type": "Button",
"Order": "4",
"Description": "Show installed applications"
},
"WingetRadioButton": {
"Content": "Winget",
"Category": "__Package Manager",
"Type": "RadioButton",
"GroupName": "PackageManagerGroup",
"Checked": true,
"Order": "1",
"Description": "Use Winget for package management"
},
"ChocoRadioButton": {
"Content": "Chocolatey",
"Category": "__Package Manager",
"Type": "RadioButton",
"GroupName": "PackageManagerGroup",
"Checked": false,
"Order": "2",
"Description": "Use Chocolatey for package management"
},
"autofallback": {
"Content": "Auto Fallback",
"Category": "__Package Manager",
"Checked": true,
"Order": "3",
"Description": "If the selected package manager fails, automatically switch to the other one"
}
}

View File

@ -38,6 +38,9 @@
"ButtonCornerRadius": "2"
},
"Light": {
"AppInstallUnselectedColor": "#F0F0F0",
"AppInstallHighlightedColor": "#CFCFCF",
"AppInstallSelectedColor": "#C2C2C2",
"ComboBoxForegroundColor": "#232629",
"ComboBoxBackgroundColor": "#F7F7F7",
"LabelboxForegroundColor": "#232629",
@ -73,6 +76,9 @@
},
"Dark": {
"AppInstallUnselectedColor": "#232629",
"AppInstallHighlightedColor": "#3C3C3C",
"AppInstallSelectedColor": "#4C4C4C",
"ComboBoxForegroundColor": "#F7F7F7",
"ComboBoxBackgroundColor": "#1E3747",
"LabelboxForegroundColor": "#0567ff",

View File

@ -0,0 +1,50 @@
function Add-SelectedAppsMenuItem {
<#
.SYNOPSIS
This is a helper function that generates and adds the Menu Items to the Selected Apps Popup.
.Parameter name
The actual Name of an App like "Chrome" or "Brave"
This name is contained in the "Content" property inside the applications.json
.PARAMETER key
The key which identifies an app object in applications.json
For Chrome this would be "WPFInstallchrome" because "WPFInstall" is prepended automatically for each key in applications.json
#>
param ([string]$name, [string]$key)
$selectedAppGrid = New-Object Windows.Controls.Grid
$selectedAppGrid.ColumnDefinitions.Add((New-Object System.Windows.Controls.ColumnDefinition -Property @{Width = "*"}))
$selectedAppGrid.ColumnDefinitions.Add((New-Object System.Windows.Controls.ColumnDefinition -Property @{Width = "30"}))
# Sets the name to the Content as well as the Tooltip, because the parent Popup Border has a fixed width and text could "overflow".
# With the tooltip, you can still read the whole entry on hover
$selectedAppLabel = New-Object Windows.Controls.Label
$selectedAppLabel.Content = $name
$selectedAppLabel.ToolTip = $name
$selectedAppLabel.HorizontalAlignment = "Left"
$selectedAppLabel.SetResourceReference([Windows.Controls.Control]::ForegroundProperty, "MainForegroundColor")
[System.Windows.Controls.Grid]::SetColumn($selectedAppLabel, 0)
$selectedAppGrid.Children.Add($selectedAppLabel)
$selectedAppRemoveButton = New-Object Windows.Controls.Button
$selectedAppRemoveButton.FontFamily = "Segoe MDL2 Assets"
$selectedAppRemoveButton.Content = [string]([char]0xE711)
$selectedAppRemoveButton.HorizontalAlignment = "Center"
$selectedAppRemoveButton.Tag = $key
$selectedAppRemoveButton.ToolTip = "Remove the App from Selection"
$selectedAppRemoveButton.SetResourceReference([Windows.Controls.Control]::ForegroundProperty, "MainForegroundColor")
$selectedAppRemoveButton.SetResourceReference([Windows.Controls.Control]::StyleProperty, "HoverButtonStyle")
# Highlight the Remove icon on Hover
$selectedAppRemoveButton.Add_MouseEnter({ $this.Foreground = "Red" })
$selectedAppRemoveButton.Add_MouseLeave({ $this.SetResourceReference([Windows.Controls.Control]::ForegroundProperty, "MainForegroundColor") })
$selectedAppRemoveButton.Add_Click({
$sync.($this.Tag).isChecked = $false # On click of the remove button, we only have to uncheck the corresponding checkbox. This will kick of all neccessary changes to update the UI
})
[System.Windows.Controls.Grid]::SetColumn($selectedAppRemoveButton, 1)
$selectedAppGrid.Children.Add($selectedAppRemoveButton)
# Add new Element to Popup
$sync.selectedAppsstackPanel.Children.Add($selectedAppGrid)
}

View File

@ -0,0 +1,35 @@
function Find-AppsByNameOrDescription {
<#
.SYNOPSIS
Searches through the Apps on the Install Tab and hides all entries that do not match the string
.PARAMETER SearchString
The string to be searched for
#>
param(
[Parameter(Mandatory=$false)]
[string]$SearchString = ""
)
# Reset the visibility if the search string is empty or the search is cleared
if ([string]::IsNullOrWhiteSpace($SearchString)) {
Set-CategoryVisibility -Category "*"
return
}
$sync.ItemsControl.Items | ForEach-Object {
# Hide all CategoryWrapPanel and ToggleButton
$_.Visibility = [Windows.Visibility]::Collapsed
if ($_.Tag -like "CategoryWrapPanel_*") {
# Search for Apps that match the search string
$_.Children | Foreach-Object {
if ($sync.configs.applicationsHashtable.$($_.Tag).Content -like "*$SearchString*") {
# Show the App and the parent CategoryWrapPanel if the string is found
$_.Visibility = [Windows.Visibility]::Visible
$_.parent.Visibility = [Windows.Visibility]::Visible
}
else {
$_.Visibility = [Windows.Visibility]::Collapsed
}
}
}
}
}

View File

@ -0,0 +1,197 @@
function Initialize-InstallAppEntry {
<#
.SYNOPSIS
Creates the app entry to be placed on the isntall tab for a given app
Used to as part of the Install Tab UI generation
.PARAMETER TargetElement
The Element into which the Apps should be placed
.PARAMETER AppKey
The Key of the app inside the $sync.configs.applicationsHashtable
#>
param(
[Windows.Controls.WrapPanel]$TargetElement,
$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.Add_MouseUp({
$childCheckbox = ($this.Child.Children | Where-Object {$_.Template.TargetType -eq [System.Windows.Controls.Checkbox]})[0]
$childCheckBox.isChecked = -not $childCheckbox.IsChecked
})
$border.Add_MouseEnter({
if (($sync.$($this.Tag).IsChecked) -eq $false) {
$this.SetResourceReference([Windows.Controls.Control]::BackgroundProperty, "AppInstallHighlightedColor")
}
})
$border.Add_MouseLeave({
if (($sync.$($this.Tag).IsChecked) -eq $false) {
$this.SetResourceReference([Windows.Controls.Control]::BackgroundProperty, "AppInstallUnselectedColor")
}
})
# 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.SetResourceReference([Windows.Controls.Control]::MarginProperty, "AppTileMargins")
$checkBox.SetResourceReference([Windows.Controls.Control]::StyleProperty, "CollapsedCheckBoxStyle")
$checkbox.Add_Checked({
Invoke-WPFSelectedAppsUpdate -type "Add" -checkbox $this
$borderElement = $this.Parent.Parent
$borderElement.SetResourceReference([Windows.Controls.Control]::BackgroundProperty, "AppInstallSelectedColor")
})
$checkbox.Add_Unchecked({
Invoke-WPFSelectedAppsUpdate -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
$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"
$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.SetResourceReference([Windows.Controls.Control]::MarginProperty, "AppTileMargins")
$buttonPanel.SetResourceReference([Windows.Controls.Control]::VisibilityProperty, "AppTileCompactVisibility")
[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 = $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
})
# 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
}

View File

@ -0,0 +1,36 @@
function Initialize-InstallAppArea {
<#
.SYNOPSIS
Creates a [Windows.Controls.ScrollViewer] containing a [Windows.Controls.ItemsControl] which is setup to use Virtualization to only load the visible elements for performance reasons.
This is used as the parent object for all category and app entries on the install tab
Used to as part of the Install Tab UI generation
.PARAMETER TargetElement
The element to which the AppArea shoud be added
#>
param($TargetElement)
$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 = $TargetElement.Children.Add($scrollViewer)
return $itemsControl
}

View File

@ -0,0 +1,28 @@
function Initialize-InstallAppsMainElement {
<#
.SYNOPSIS
Clears the given WPF Grid and creates a [Windows.Controls.Border] containing a [Windows.Controls.StackPanel]
Used to as part of the Install Tab UI generation
.PARAMETER TargetGridName
The WPF Grid name
.OUTPUTS
Returns the created [Windows.Controls.StackPanel] element
#>
param(
[Parameter(Mandatory)]
[string]$TargetGridName
)
$targetGrid = $sync.Form.FindName($TargetGridName)
$null = $targetGrid.Children.Clear()
$Border = New-Object Windows.Controls.Border
$Border.VerticalAlignment = "Stretch"
$Border.SetResourceReference([Windows.Controls.Control]::StyleProperty, "BorderStyle")
$dockPanel = New-Object Windows.Controls.DockPanel
$Border.Child = $dockPanel
$null = $targetGrid.Children.Add($Border)
return $dockPanel
}

View File

@ -0,0 +1,72 @@
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
)
function Add-Category {
param(
[string]$Category,
[Windows.Controls.ItemsControl]$TargetElement
)
$toggleButton = New-Object Windows.Controls.Primitives.ToggleButton
$toggleButton.Content = "$Category"
$toggleButton.Tag = "CategoryToggleButton"
$toggleButton.Cursor = [System.Windows.Input.Cursors]::Hand
$toggleButton.SetResourceReference([Windows.Controls.Control]::StyleProperty, "CategoryToggleButtonStyle")
$sync.Buttons.Add($toggleButton)
$toggleButton.Add_Checked({
# Clear the search bar when a category is clicked
$sync.SearchBar.Text = ""
Set-CategoryVisibility -Category $this.Content -overrideState Expand
})
$toggleButton.Add_Unchecked({
Set-CategoryVisibility -Category $this.Content -overrideState Collapse
})
$null = $TargetElement.Items.Add($toggleButton)
}
$loadingLabel = New-Object Windows.Controls.Label
$loadingLabel.Content = "Loading, please wait..."
$loadingLabel.HorizontalAlignment = "Center"
$loadingLabel.VerticalAlignment = "Center"
$loadingLabel.SetResourceReference([Windows.Controls.Control]::FontSizeProperty, "FontSizeHeading")
$loadingLabel.FontWeight = [Windows.FontWeights]::Bold
$loadingLabel.Foreground = [Windows.Media.Brushes]::Gray
$sync.LoadingLabel = $loadingLabel
$TargetElement.Items.Clear()
$null = $TargetElement.Items.Add($sync.LoadingLabel)
# Use the Dispatcher to make sure the Loading message is shown before the logic loading the apps starts, and only is removed when the loading is complete and the apps are added to the UI
$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) {
Add-Category -Category $category -TargetElement $TargetElement
$wrapPanel = New-Object Windows.Controls.WrapPanel
$wrapPanel.Orientation = "Horizontal"
$wrapPanel.HorizontalAlignment = "Stretch"
$wrapPanel.VerticalAlignment = "Center"
$wrapPanel.Margin = New-Object Windows.Thickness(0, 0, 0, 20)
$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 $_
}
}
})
}

View File

@ -0,0 +1,89 @@
function Initialize-InstallHeader {
<#
.SYNOPSIS
Creates the Multi Selection Header Elements on the Install Tab
Used to as part of the Install Tab UI generation
.PARAMETER TargetElement
The Parent Element into which the Header should be placed
#>
param($TargetElement)
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.SetResourceReference([Windows.Controls.Control]::MarginProperty, "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
}
$selectedAppsButton = New-Object Windows.Controls.Button
$selectedAppsButton.Name = "WPFselectedAppsButton"
$selectedAppsButton.Content = "Selected Apps: 0"
$selectedAppsButton.SetResourceReference([Windows.Controls.Control]::FontSizeProperty, "FontSizeHeading")
$selectedAppsButton.SetResourceReference([Windows.Controls.Control]::MarginProperty, "TabContentMargin")
$selectedAppsButton.SetResourceReference([Windows.Controls.Control]::ForegroundProperty, "MainForegroundColor")
$selectedAppsButton.HorizontalAlignment = "Center"
$selectedAppsButton.VerticalAlignment = "Center"
$selectedAppsPopup = New-Object Windows.Controls.Primitives.Popup
$selectedAppsPopup.IsOpen = $false
$selectedAppsPopup.PlacementTarget = $selectedAppsButton
$selectedAppsPopup.Placement = [System.Windows.Controls.Primitives.PlacementMode]::Bottom
$selectedAppsPopup.AllowsTransparency = $true
$selectedAppsBorder = New-Object Windows.Controls.Border
$selectedAppsBorder.SetResourceReference([Windows.Controls.Control]::BackgroundProperty, "MainBackgroundColor")
$selectedAppsBorder.SetResourceReference([Windows.Controls.Control]::BorderBrushProperty, "MainForegroundColor")
$selectedAppsBorder.SetResourceReference([Windows.Controls.Control]::BorderThicknessProperty, "ButtonBorderThickness")
$selectedAppsBorder.Width = 200
$selectedAppsBorder.Padding = 5
$selectedAppsPopup.Child = $selectedAppsBorder
$sync.selectedAppsPopup = $selectedAppsPopup
$sync.selectedAppsstackPanel = New-Object Windows.Controls.StackPanel
$selectedAppsBorder.Child = $sync.selectedAppsstackPanel
# Toggle selectedAppsPopup open/close with button
$selectedAppsButton.Add_Click({
$sync.selectedAppsPopup.IsOpen = -not $sync.selectedAppsPopup.IsOpen
})
# Close selectedAppsPopup when mouse leaves both button and selectedAppsPopup
$selectedAppsButton.Add_MouseLeave({
if (-not $sync.selectedAppsPopup.IsMouseOver) {
$sync.selectedAppsPopup.IsOpen = $false
}
})
$selectedAppsPopup.Add_MouseLeave({
if (-not $selectedAppsButton.IsMouseOver) {
$sync.selectedAppsPopup.IsOpen = $false
}
})
$null = $wrapPanelTop.Children.Add($selectedAppsButton)
$sync.$($selectedAppsButton.Name) = $selectedAppsButton
[Windows.Controls.DockPanel]::SetDock($wrapPanelTop, [Windows.Controls.Dock]::Top)
$null = $TargetElement.Children.Add($wrapPanelTop)
}

View File

@ -0,0 +1,44 @@
function Set-CategoryVisibility {
<#
.SYNOPSIS
Used to expand or collapse categories and corresponding apps on the install tab
.PARAMETER Category
Can eigther be a specific category name like "Browsers" OR "*" to affect all categories at once
.PARAMETER overrideState
"Expand" => expands the corresponding elements
"Collapse" => collapses the corresponding elements
N/A => if compactView is active expand, otherwise collapse elements
#>
param(
[Parameter(Mandatory=$true)]
[string]$Category,
[ValidateSet("Expand", "Collapse")]
[string]$overrideState
)
switch ($overrideState) {
"Expand" {$state = $true}
"Collapse" {$state = $false}
default {$state = $sync.CompactView}
}
# If all the Categories are affected, update the Checked state of the ToggleButtons.
# Otherwise, the state is not synced when toggling between the display modes
if ($category -eq "*") {
$items = $sync.ItemsControl.Items | Where-Object {($_.Tag -like "CategoryWrapPanel_*")}
$sync.ItemsControl.Items | Where-Object {($_.Tag -eq "CategoryToggleButton")} | Foreach-Object { $_.Visibility = [Windows.Visibility]::Visible; $_.IsChecked = $state }
} else {
$items = $sync.ItemsControl.Items | Where-Object {($_.Tag -eq "CategoryWrapPanel_$Category")}
}
$elementVisibility = if ($state -eq $true) {[Windows.Visibility]::Visible} else {[Windows.Visibility]::Collapsed}
$items | ForEach-Object {
$_.Visibility = $elementVisibility
}
$items.Children | ForEach-Object {
$_.Visibility = $elementVisibility
}
}

View File

@ -0,0 +1,54 @@
function Show-OnlyCheckedApps {
<#
.SYNOPSIS
Toggle between showing only the actively selected apps on the Install Tab and hiding everything else and displaying every app.
If no apps are selected, dont do anything
.PARAMETER appKeys
Expects a List of appKeys that are selected at the moment
If not provided, or empty, the function exits without any visual change to the ui
.EXAMPLE
Show-OnlyCheckedApps -appKeys $sync.SelectedApps
Show-OnlyCheckedApps -appKeys ("WPFInstallChrome", "WPFInstall7zip")
#>
param (
[Parameter(Mandatory=$false)]
[String[]]$appKeys
)
# If no apps are selected, do not allow switching to show only selected
if (($false -eq $sync.ShowOnlySelected) -and ($appKeys.Length -eq 0)) {
Write-Host "No apps selected"
$sync.wpfselectedfilter.IsChecked = $false
return
}
$sync.ShowOnlySelected = -not $sync.ShowOnlySelected
if ($sync.ShowOnlySelected) {
$sync.Buttons | Where-Object {$_.Name -like "ShowSelectedAppsButton"} | ForEach-Object {
$_.Content = "Show All"
}
$sync.ItemsControl.Items | Foreach-Object {
# Search for App Container and set them to visible
if ($_.Tag -like "CategoryWrapPanel_*") {
$_.Visibility = [Windows.Visibility]::Visible
# Iterate through all the apps in the container and set them to visible if they are in the appKeys array
$_.Children | ForEach-Object {
if ($appKeys -contains $_.Tag) {
$_.Visibility = [Windows.Visibility]::Visible
}
else {
$_.Visibility = [Windows.Visibility]::Collapsed
}
}
}
else {
# Set all other items to collapsed
$_.Visibility = [Windows.Visibility]::Collapsed
}
}
} else {
$sync.Buttons | Where-Object {$_.Name -like "ShowSelectedAppsButton"} | ForEach-Object {
$_.Content = "Show Selected"
}
Set-CategoryVisibility -Category "*"
}
}

View File

@ -26,7 +26,8 @@ function Invoke-WPFButton {
"WPFStandard" {Invoke-WPFPresets "Standard" -checkboxfilterpattern "WPFTweak*"}
"WPFMinimal" {Invoke-WPFPresets "Minimal" -checkboxfilterpattern "WPFTweak*"}
"WPFClearTweaksSelection" {Invoke-WPFPresets -imported $true -checkboxfilterpattern "WPFTweak*"}
"WPFClearInstallSelection" {Invoke-WPFPresets -imported $true -checkboxfilterpattern "WPFInstall*"}
"WPFClearInstallSelection" {Invoke-WPFPresets -imported $true -checkboxfilterpattern "WPFInstall*"; Show-OnlyCheckedApps; $sync.wpfselectedfilter.IsChecked = $false}
"WPFSelectedFilter" {Show-OnlyCheckedApps -appKeys $sync.SelectedApps}
"WPFtweaksbutton" {Invoke-WPFtweaksbutton}
"WPFOOSUbutton" {Invoke-WPFOOSU}
"WPFAddUltPerf" {Invoke-WPFUltimatePerformance -State "Enable"}

View File

@ -9,42 +9,48 @@ function Invoke-WPFGetInstalled {
#>
param($checkbox)
if($sync.ProcessRunning) {
if ($sync.ProcessRunning) {
$msg = "[Invoke-WPFGetInstalled] Install process is currently running."
[System.Windows.MessageBox]::Show($msg, "Winutil", [System.Windows.MessageBoxButton]::OK, [System.Windows.MessageBoxImage]::Warning)
return
}
if(($sync.WPFpreferChocolatey.IsChecked -eq $false) -and ((Test-WinUtilPackageManager -winget) -eq "not-installed") -and $checkbox -eq "winget") {
if (($sync.ChocoRadioButton.IsChecked -eq $false) -and ((Test-WinUtilPackageManager -winget) -eq "not-installed") -and $checkbox -eq "winget") {
return
}
$preferChoco = $sync.WPFpreferChocolatey.IsChecked
Invoke-WPFRunspace -ArgumentList $checkbox, $preferChoco -DebugPreference $DebugPreference -ScriptBlock {
param($checkbox, $preferChoco, $DebugPreference)
$preferChoco = $sync.ChocoRadioButton.IsChecked
$sync.ItemsControl.Dispatcher.Invoke([action] {
$sync.ItemsControl.Items | ForEach-Object { $_.Visibility = [Windows.Visibility]::Collapsed }
$null = $sync.itemsControl.Items.Add($sync.LoadingLabel)
})
Invoke-WPFRunspace -ParameterList @(("preferChoco", $preferChoco),("checkbox", $checkbox),("ShowOnlyCheckedApps", ${function:Show-OnlyCheckedApps})) -DebugPreference $DebugPreference -ScriptBlock {
param (
[string]$checkbox,
[boolean]$preferChoco,
[scriptblock]$ShowOnlyCheckedApps
)
$sync.ProcessRunning = $true
$sync.form.Dispatcher.Invoke([action]{ Set-WinUtilTaskbaritem -state "Indeterminate" })
$sync.form.Dispatcher.Invoke([action] { Set-WinUtilTaskbaritem -state "Indeterminate" })
if($checkbox -eq "winget") {
if ($checkbox -eq "winget") {
Write-Host "Getting Installed Programs..."
if ($preferChoco) { $Checkboxes = Invoke-WinUtilCurrentSystem -CheckBox "choco" }
else { $Checkboxes = Invoke-WinUtilCurrentSystem -CheckBox $checkbox }
}
if($checkbox -eq "tweaks") {
elseif ($checkbox -eq "tweaks") {
Write-Host "Getting Installed Tweaks..."
}
if ($preferChoco -and $checkbox -eq "winget") {
$Checkboxes = Invoke-WinUtilCurrentSystem -CheckBox "choco"
}
else{
$Checkboxes = Invoke-WinUtilCurrentSystem -CheckBox $checkbox
}
$sync.form.Dispatcher.invoke({
foreach($checkbox in $Checkboxes) {
foreach ($checkbox in $Checkboxes) {
$sync.$checkbox.ischecked = $True
}
})
$sync.ItemsControl.Dispatcher.Invoke([action] {
$ShowOnlyCheckedApps.Invoke($sync.SelectedApps)
$sync.ItemsControl.Items.Remove($sync.LoadingLabel)
})
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 { $sync.configs.applicationsHashtable.$_ })
)
<#
.SYNOPSIS
@ -12,14 +16,12 @@ 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)
return
}
$ChocoPreference = $($sync.WPFpreferChocolatey.IsChecked)
$ChocoPreference = $($sync.ChocoRadioButton.IsChecked)
$installHandle = Invoke-WPFRunspace -ParameterList @(("PackagesToInstall", $PackagesToInstall),("ChocoPreference", $ChocoPreference)) -DebugPreference $DebugPreference -ScriptBlock {
param($PackagesToInstall, $ChocoPreference, $DebugPreference)
if ($PackagesToInstall.count -eq 1) {

View File

@ -5,7 +5,7 @@ function Invoke-WPFInstallUpgrade {
Invokes the function that upgrades all installed programs
#>
if ($sync.WPFpreferChocolatey.IsChecked) {
if ($sync.ChocoRadioButton.IsChecked) {
Install-WinUtilChoco
$chocoUpgradeStatus = (Start-Process "choco" -ArgumentList "upgrade all -y" -Wait -PassThru -NoNewWindow).ExitCode
if ($chocoUpgradeStatus -eq 0) {

View File

@ -0,0 +1,43 @@
function Invoke-WPFSelectedAppsUpdate {
<#
.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" selectedAppLabel 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-WPFSelectedAppsUpdate -type "Remove" -checkbox $this})
OR
Invoke-WPFSelectedAppsUpdate -type "Add" -checkbox $specificCheckbox
#>
param (
$type,
$checkbox
)
$selectedAppsButton = $sync.WPFselectedAppsButton
# Get the actual Name from the selectedAppLabel 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
$selectedAppsButton.Content = "Selected Apps: $count"
# On every change, remove all entries inside the Popup Menu. This is done, so we can keep the alphabetical order even if elements are selected in a random way
$sync.selectedAppsstackPanel.Children.Clear()
$sync.SelectedApps | Foreach-Object { Add-SelectedAppsMenuItem -name $($sync.configs.applicationsHashtable.$_.Content) -key $_ }
}

View File

@ -28,4 +28,5 @@ function Invoke-WPFTab {
$sync.$tabNav.Items[$tabNumber].IsSelected = $true
}
}
$sync.currentTab = $sync.$tabNav.Items[$tabNumber].Header
}

View File

@ -0,0 +1,22 @@
function Invoke-WPFUIApps {
[OutputType([void])]
param(
[Parameter(Mandatory, Position = 0)]
[PSCustomObject[]]$Apps,
[Parameter(Mandatory, Position = 1)]
[string]$TargetGridName
)
switch ($TargetGridName) {
"appspanel" {
$dockPanel = Initialize-InstallAppsMainElement -TargetGridName $TargetGridName
$null = Initialize-InstallHeader -TargetElement $dockPanel
$sync.ItemsControl = Initialize-InstallAppArea -TargetElement $dockPanel
Initialize-InstallCategoryAppList -TargetElement $sync.ItemsControl -Apps $Apps
}
default {
Write-Output "$TargetGridName not yet implemented"
}
}
}

View File

@ -11,26 +11,26 @@ function Invoke-WPFUIElements {
.EXAMPLE
Invoke-WPFUIElements -configVariable $sync.configs.applications -targetGridName "install" -columncount 5
.NOTES
Future me/contributer: If possible please wrap this into a runspace to make it load all panels at the same time.
Future me/contributor: If possible, please wrap this into a runspace to make it load all panels at the same time.
#>
param(
[Parameter(Mandatory, position=0)]
[Parameter(Mandatory, Position = 0)]
[PSCustomObject]$configVariable,
[Parameter(Mandatory, position=1)]
[Parameter(Mandatory, Position = 1)]
[string]$targetGridName,
[Parameter(Mandatory, position=2)]
[Parameter(Mandatory, Position = 2)]
[int]$columncount
)
$window = $sync["Form"]
$window = $sync.form
$theme = $sync.Form.Resources
$borderstyle = $window.FindResource("BorderStyle")
$HoverTextBlockStyle = $window.FindResource("HoverTextBlockStyle")
$ColorfulToggleSwitchStyle = $window.FindResource("ColorfulToggleSwitchStyle")
$ToggleButtonStyle = $window.FindResource("ToggleButtonStyle")
if (!$borderstyle -or !$HoverTextBlockStyle -or !$ColorfulToggleSwitchStyle) {
throw "Failed to retrieve Styles using 'FindResource' from main window element."
@ -59,6 +59,8 @@ function Invoke-WPFUIElements {
$configHashtable[$_] = $configVariable.$_
}
$radioButtonGroups = @{}
$organizedData = @{}
# Iterate through JSON data and organize by panel and category
foreach ($entry in $configHashtable.Keys) {
@ -66,19 +68,18 @@ function Invoke-WPFUIElements {
# Create an object for the application
$entryObject = [PSCustomObject]@{
Name = $entry
Order = $entryInfo.order
Category = $entryInfo.Category
Content = $entryInfo.Content
Choco = $entryInfo.choco
Winget = $entryInfo.winget
Panel = if ($entryInfo.Panel) { $entryInfo.Panel } else { "0" }
Link = $entryInfo.link
Name = $entry
Order = $entryInfo.order
Category = $entryInfo.Category
Content = $entryInfo.Content
Panel = if ($entryInfo.Panel) { $entryInfo.Panel } else { "0" }
Link = $entryInfo.link
Description = $entryInfo.description
Type = $entryInfo.type
ComboItems = $entryInfo.ComboItems
Checked = $entryInfo.Checked
Type = $entryInfo.type
ComboItems = $entryInfo.ComboItems
Checked = $entryInfo.Checked
ButtonWidth = $entryInfo.ButtonWidth
GroupName = $entryInfo.GroupName # Added for RadioButton groupings
}
if (-not $organizedData.ContainsKey($entryObject.Panel)) {
@ -96,10 +97,12 @@ function Invoke-WPFUIElements {
if ($targetGridName -eq "appspanel") {
$panelcount = 0
$entrycount = $configHashtable.Keys.Count + $organizedData["0"].Keys.Count
$maxcount = [Math]::Round($entrycount / $columncount + 0.5)
}
}
# Initialize panel count
$panelcount = 0
# Iterate through 'organizedData' by panel, category, and application
$count = 0
foreach ($panelKey in ($organizedData.Keys | Sort-Object)) {
@ -110,68 +113,58 @@ function Invoke-WPFUIElements {
$border.style = $borderstyle
$targetGrid.Children.Add($border) | Out-Null
# Create a StackPanel inside the Border
$stackPanel = New-Object Windows.Controls.StackPanel
$stackPanel.Background = [Windows.Media.Brushes]::Transparent
$stackPanel.SnapsToDevicePixels = $true
$stackPanel.VerticalAlignment = "Stretch" # Ensure the stack panel stretches vertically
$border.Child = $stackPanel
# Use a DockPanel to contain both the top buttons and the main content
$dockPanelContainer = New-Object Windows.Controls.DockPanel
$border.Child = $dockPanelContainer
# Create a ScrollViewer to contain the main content (excluding buttons)
$scrollViewer = New-Object Windows.Controls.ScrollViewer
$scrollViewer.VerticalScrollBarVisibility = 'Auto'
$scrollViewer.HorizontalScrollBarVisibility = 'Auto'
$scrollViewer.HorizontalAlignment = 'Stretch'
$scrollViewer.VerticalAlignment = 'Stretch'
$scrollViewer.CanContentScroll = $true # Enable virtualization
# Create an ItemsControl inside the ScrollViewer for application content
$itemsControl = New-Object Windows.Controls.ItemsControl
$itemsControl.HorizontalAlignment = 'Stretch'
$itemsControl.VerticalAlignment = 'Stretch'
# Set the ItemsPanel to a VirtualizingStackPanel
$itemsPanelTemplate = New-Object Windows.Controls.ItemsPanelTemplate
$factory = New-Object Windows.FrameworkElementFactory ([Windows.Controls.VirtualizingStackPanel])
$itemsPanelTemplate.VisualTree = $factory
$itemsControl.ItemsPanel = $itemsPanelTemplate
# Set virtualization properties
$itemsControl.SetValue([Windows.Controls.VirtualizingStackPanel]::IsVirtualizingProperty, $true)
$itemsControl.SetValue([Windows.Controls.VirtualizingStackPanel]::VirtualizationModeProperty, [Windows.Controls.VirtualizationMode]::Recycling)
# Add the ItemsControl to the ScrollViewer
$scrollViewer.Content = $itemsControl
# Add the ScrollViewer to the DockPanel (it will be below the top buttons StackPanel)
[Windows.Controls.DockPanel]::SetDock($scrollViewer, [Windows.Controls.Dock]::Bottom)
$dockPanelContainer.Children.Add($scrollViewer) | Out-Null
$panelcount++
# Now proceed with adding category labels and entries to $itemsControl
foreach ($category in ($organizedData[$panelKey].Keys | Sort-Object)) {
$count++
if ($targetGridName -eq "appspanel" -and $columncount -gt 0) {
$panelcount2 = [Int](($count) / $maxcount - 0.5)
if ($panelcount -eq $panelcount2) {
# Create a new Border for the new column
$border = New-Object Windows.Controls.Border
$border.VerticalAlignment = "Stretch" # Ensure the border stretches vertically
[System.Windows.Controls.Grid]::SetColumn($border, $panelcount)
$border.style = $borderstyle
$targetGrid.Children.Add($border) | Out-Null
# Create a new StackPanel inside the Border
$stackPanel = New-Object Windows.Controls.StackPanel
$stackPanel.Background = [Windows.Media.Brushes]::Transparent
$stackPanel.SnapsToDevicePixels = $true
$stackPanel.VerticalAlignment = "Stretch" # Ensure the stack panel stretches vertically
$border.Child = $stackPanel
$panelcount++
}
}
$label = New-Object Windows.Controls.Label
$label.Content = $category -replace ".*__", ""
$label.FontSize = $theme.FontSizeHeading
$label.FontFamily = $theme.HeaderFontFamily
$stackPanel.Children.Add($label) | Out-Null
$label.SetResourceReference([Windows.Controls.Control]::FontSizeProperty, "FontSizeHeading")
$label.SetResourceReference([Windows.Controls.Control]::FontFamilyProperty, "HeaderFontFamily")
$itemsControl.Items.Add($label) | Out-Null
$sync[$category] = $label
# Sort entries by Order and then by Name, but only display Name
# Sort entries by Order and then by Name
$entries = $organizedData[$panelKey][$category] | Sort-Object Order, Name
foreach ($entryInfo in $entries) {
$count++
if ($targetGridName -eq "appspanel" -and $columncount -gt 0) {
$panelcount2 = [Int](($count) / $maxcount - 0.5)
if ($panelcount -eq $panelcount2) {
# Create a new Border for the new column
$border = New-Object Windows.Controls.Border
$border.VerticalAlignment = "Stretch" # Ensure the border stretches vertically
[System.Windows.Controls.Grid]::SetColumn($border, $panelcount)
$border.style = $borderstyle
$targetGrid.Children.Add($border) | Out-Null
# Create a new StackPanel inside the Border
$stackPanel = New-Object Windows.Controls.StackPanel
$stackPanel.Background = [Windows.Media.Brushes]::Transparent
$stackPanel.SnapsToDevicePixels = $true
$stackPanel.VerticalAlignment = "Stretch" # Ensure the stack panel stretches vertically
$border.Child = $stackPanel
$panelcount++
}
}
# Create the UI elements based on the entry type
switch ($entryInfo.Type) {
"Toggle" {
$dockPanel = New-Object Windows.Controls.DockPanel
@ -185,10 +178,10 @@ 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
$stackPanel.Children.Add($dockPanel) | Out-Null
$itemsControl.Items.Add($dockPanel) | Out-Null
$sync[$entryInfo.Name] = $checkBox
@ -201,35 +194,29 @@ function Invoke-WPFUIElements {
}
"ToggleButton" {
$toggleButton = New-Object Windows.Controls.ToggleButton
$toggleButton = New-Object Windows.Controls.Primitives.ToggleButton
$toggleButton.Name = $entryInfo.Name
$toggleButton.Name = "WPFTab" + ($stackPanel.Children.Count + 1) + "BT"
$toggleButton.Content = $entryInfo.Content[1]
$toggleButton.ToolTip = $entryInfo.Description
$toggleButton.HorizontalAlignment = "Left"
$toggleButton.Height = $theme.TabButtonHeight
$toggleButton.Width = $theme.TabButtonWidth
$toggleButton.SetResourceReference([Windows.Controls.Control]::BackgroundProperty, "ButtonInstallBackgroundColor")
$toggleButton.SetResourceReference([Windows.Controls.Control]::ForegroundProperty, "MainForegroundColor")
$toggleButton.FontWeight = [Windows.FontWeights]::Bold
$toggleButton.Style = $ToggleButtonStyle
$textBlock = New-Object Windows.Controls.TextBlock
$textBlock.FontSize = $theme.TabButtonFontSize
$textBlock.Background = [Windows.Media.Brushes]::Transparent
$textBlock.SetResourceReference([Windows.Controls.Control]::ForegroundProperty, "ButtonInstallForegroundColor")
$toggleButton.Tag = @{
contentOn = if ($entryInfo.Content.Count -ge 1) { $entryInfo.Content[0] } else { "" }
contentOff = if ($entryInfo.Content.Count -ge 2) { $entryInfo.Content[1] } else { $contentOn }
}
$underline = New-Object Windows.Documents.Underline
$underline.Inlines.Add($entryInfo.name -replace "(.).*", "`$1")
$run = New-Object Windows.Documents.Run
$run.Text = $entryInfo.name -replace "^.", ""
$textBlock.Inlines.Add($underline)
$textBlock.Inlines.Add($run)
$toggleButton.Content = $textBlock
$stackPanel.Children.Add($toggleButton) | Out-Null
$itemsControl.Items.Add($toggleButton) | Out-Null
$sync[$entryInfo.Name] = $toggleButton
$sync[$entryInfo.Name].Add_Checked({
$this.Content = $this.Tag.contentOn
})
$sync[$entryInfo.Name].Add_Unchecked({
$this.Content = $this.Tag.contentOff
})
}
"Combobox" {
@ -241,26 +228,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
}
$horizontalStackPanel.Children.Add($comboBox) | Out-Null
$stackPanel.Children.Add($horizontalStackPanel) | Out-Null
$itemsControl.Items.Add($horizontalStackPanel) | Out-Null
$comboBox.SelectedIndex = 0
@ -272,16 +259,50 @@ 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
}
$stackPanel.Children.Add($button) | Out-Null
$itemsControl.Items.Add($button) | Out-Null
$sync[$entryInfo.Name] = $button
}
"RadioButton" {
# Check if a container for this GroupName already exists
if (-not $radioButtonGroups.ContainsKey($entryInfo.GroupName)) {
# Create a StackPanel for this group
$groupStackPanel = New-Object Windows.Controls.StackPanel
$groupStackPanel.Orientation = "Vertical"
# Add the group container to the ItemsControl
$itemsControl.Items.Add($groupStackPanel) | Out-Null
}
else {
# Retrieve the existing group container
$groupStackPanel = $radioButtonGroups[$entryInfo.GroupName]
}
# Create the RadioButton
$radioButton = New-Object Windows.Controls.RadioButton
$radioButton.Name = $entryInfo.Name
$radioButton.GroupName = $entryInfo.GroupName
$radioButton.Content = $entryInfo.Content
$radioButton.HorizontalAlignment = "Left"
$radioButton.SetResourceReference([Windows.Controls.Control]::MarginProperty, "CheckBoxMargin")
$radioButton.SetResourceReference([Windows.Controls.Control]::FontSizeProperty, "ButtonFontSize")
$radioButton.ToolTip = $entryInfo.Description
if ($entryInfo.Checked -eq $true) {
$radioButton.IsChecked = $true
}
# Add the RadioButton to the group container
$groupStackPanel.Children.Add($radioButton) | Out-Null
$sync[$entryInfo.Name] = $radioButton
}
default {
$horizontalStackPanel = New-Object Windows.Controls.StackPanel
$horizontalStackPanel.Orientation = "Horizontal"
@ -289,9 +310,9 @@ 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
}
@ -309,7 +330,7 @@ function Invoke-WPFUIElements {
$sync[$textBlock.Name] = $textBlock
}
$stackPanel.Children.Add($horizontalStackPanel) | Out-Null
$itemsControl.Items.Add($horizontalStackPanel) | Out-Null
$sync[$entryInfo.Name] = $checkBox
}
}

View File

@ -1,9 +1,12 @@
function Invoke-WPFUnInstall {
param(
[Parameter(Mandatory=$false)]
[PSObject[]]$PackagesToUninstall = $($sync.selectedApps | Foreach-Object { $sync.configs.applicationsHashtable.$_ })
)
<#
.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,17 +23,17 @@ 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)
if($confirm -eq "No") {return}
$ChocoPreference = $($sync.WPFpreferChocolatey.IsChecked)
$ChocoPreference = $($sync.ChocoRadioButton.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

@ -111,8 +111,27 @@ $sync.Form.Add_Loaded({
Invoke-WinutilThemeChange -init $true
# Load the configuration files
#Invoke-WPFUIElements -configVariable $sync.configs.nav -targetGridName "WPFMainGrid"
Invoke-WPFUIElements -configVariable $sync.configs.applications -targetGridName "appspanel" -columncount 5
$noimage = "https://images.emojiterra.com/google/noto-emoji/unicode-15/color/512px/1f4e6.png"
$noimage = [Windows.Media.Imaging.BitmapImage]::new([Uri]::new($noimage))
$sync.configs.applicationsHashtable = @{}
$sync.configs.applications.PSObject.Properties | ForEach-Object {
$sync.configs.applicationsHashtable[$_.Name] = $_.Value
}
# Now call the function with the final merged config
Invoke-WPFUIElements -configVariable $sync.configs.appnavigation -targetGridName "appscategory" -columncount 1
# Add logic to handle click to the ToggleView Button on the Install Tab
$sync.WPFToggleView.Add_Click({
$sync.CompactView = -not $sync.CompactView
Update-AppTileProperties
if ($sync.SearchBar.Text -eq "") {
Set-CategoryVisibility -Category "*"
}
})
Invoke-WPFUIApps -Apps $sync.configs.applicationsHashtable -targetGridName "appspanel"
Invoke-WPFUIElements -configVariable $sync.configs.tweaks -targetGridName "tweakspanel" -columncount 2
Invoke-WPFUIElements -configVariable $sync.configs.feature -targetGridName "featurespanel" -columncount 2
@ -124,12 +143,18 @@ $xaml.SelectNodes("//*[@Name]") | ForEach-Object {$sync["$("$($psitem.Name)")"]
#Persist the Chocolatey preference across winutil restarts
$ChocoPreferencePath = "$env:LOCALAPPDATA\winutil\preferChocolatey.ini"
$sync.WPFpreferChocolatey.Add_Checked({New-Item -Path $ChocoPreferencePath -Force })
$sync.WPFpreferChocolatey.Add_Unchecked({Remove-Item $ChocoPreferencePath -Force})
$sync.ChocoRadioButton.Add_Checked({New-Item -Path $ChocoPreferencePath -Force })
$sync.ChocoRadioButton.Add_Unchecked({Remove-Item $ChocoPreferencePath -Force})
if (Test-Path $ChocoPreferencePath) {
$sync.WPFpreferChocolatey.IsChecked = $true
$sync.ChocoRadioButton.IsChecked = $true
}
$sync.autofallback.IsEnabled = $false
$sync.autofallback.Opacity = 0.5
$sync.autofallback.ToolTip = "This feature is currently under development."
[System.Windows.Controls.ToolTipService]::SetShowOnDisabled($sync.autofallback, $true)
$sync.keys | ForEach-Object {
if($sync.$psitem) {
if($($sync["$psitem"].GetType() | Select-Object -ExpandProperty Name) -eq "ToggleButton") {
@ -184,6 +209,32 @@ Invoke-WPFRunspace -ScriptBlock {
# Print the logo
Invoke-WPFFormVariables
$sync.CompactView = $false
$sync.Form.Resources.AppTileWidth = [double]::NaN
$sync.Form.Resources.AppTileCompactVisibility = [Windows.Visibility]::Visible
$sync.Form.Resources.AppTileFontSize = [double]16
$sync.Form.Resources.AppTileMargins = [Windows.Thickness]5
$sync.Form.Resources.AppTileBorderThickness = [Windows.Thickness]0
function Update-AppTileProperties {
if ($sync.CompactView -eq $true) {
$sync.Form.Resources.AppTileWidth = [double]::NaN
$sync.Form.Resources.AppTileCompactVisibility = [Windows.Visibility]::Collapsed
$sync.Form.Resources.AppTileFontSize = [double]12
$sync.Form.Resources.AppTileMargins = [Windows.Thickness]2
$sync.Form.Resources.AppTileBorderThickness = [Windows.Thickness]0
}
else {
$sync.Form.Resources.AppTileWidth = $sync.ItemsControl.ActualWidth -20
$sync.Form.Resources.AppTileCompactVisibility = [Windows.Visibility]::Visible
$sync.Form.Resources.AppTileFontSize = [double]16
$sync.Form.Resources.AppTileMargins = [Windows.Thickness]5
$sync.Form.Resources.AppTileBorderThickness = [Windows.Thickness]1
}
}
# We need to update the app tile properties when the form is resized because to fill a WrapPanel update the width of the elemenmt manually (afaik)
$sync.Form.Add_SizeChanged({
Update-AppTileProperties
})
# Progress bar in taskbaritem > Set-WinUtilProgressbar
$sync["Form"].TaskbarItemInfo = New-Object System.Windows.Shell.TaskbarItemInfo
@ -425,73 +476,22 @@ 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
switch ($sync.currentTab) {
"Install" {
Find-AppsByNameOrDescription -SearchString $sync.SearchBar.Text
}
$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"
}
})
$sync["Form"].Add_Loaded({
param($e)
$sync.Form.MinWidth = "1000"
$sync["Form"].MaxWidth = [Double]::PositiveInfinity
$sync["Form"].MaxHeight = [Double]::PositiveInfinity
})
@ -618,5 +618,7 @@ $sync["SponsorMenuItem"].Add_Click({
Show-CustomDialog -Message $authorInfo -EnableScroll $true
})
$sync["Form"].ShowDialog() | out-null
Stop-Transcript

View File

@ -37,7 +37,15 @@ $sync = [Hashtable]::Synchronized(@{})
$sync.PSScriptRoot = $PSScriptRoot
$sync.version = "#{replaceme}"
$sync.configs = @{}
$sync.Buttons = [System.Collections.Generic.List[PSObject]]::new()
$sync.ProcessRunning = $false
$sync.selectedApps = [System.Collections.Generic.List[string]]::new()
$sync.ShowOnlySeleced = $false
$sync.currentTab = "Install"
$sync.ShowOnlySelected = $false
$sync.selectedAppsStackPanel
$sync.selectedAppsPopup
if (!([Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)) {
Write-Output "Winutil needs to be run as Administrator. Attempting to relaunch."

View File

@ -197,6 +197,45 @@
<Setter Property="Background" Value="{DynamicResource LabelBackgroundColor}"/>
<Setter Property="FontFamily" Value="{DynamicResource FontFamily}"/>
</Style>
<!-- Category Toggle Button Style for the Apps Window-->
<Style x:Key="CategoryToggleButtonStyle" TargetType="ToggleButton">
<Setter Property="Foreground" Value="{DynamicResource LabelboxForegroundColor}"/>
<Setter Property="Background" Value="{DynamicResource MainBackgroundColor}"/>
<Setter Property="FontFamily" Value="{DynamicResource HeaderFontFamily}"/>
<Setter Property="FontSize" Value="{DynamicResource FontSizeHeading}"/>
<Setter Property="HorizontalAlignment" Value="Stretch"/>
<Setter Property="VerticalAlignment" Value="Center"/>
<Setter Property="HorizontalContentAlignment" Value="Left"/>
<Setter Property="Padding" Value="10,2,10,2"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ToggleButton">
<Border Background="{TemplateBinding Background}"
BorderBrush="{DynamicResource BorderColor}"
BorderThickness="0"
CornerRadius="{DynamicResource ButtonCornerRadius}">
<StackPanel Orientation="Horizontal" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}" Margin="{TemplateBinding Padding}">
<TextBlock x:Name="PrefixTextBlock"/>
<ContentPresenter Content="{TemplateBinding Content}" />
</StackPanel>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsChecked" Value="True">
<Setter TargetName="PrefixTextBlock" Property="Text" Value="[-] "/>
</Trigger>
<Trigger Property="IsChecked" Value="False">
<Setter TargetName="PrefixTextBlock" Property="Text" Value="[+] "/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Background" Value="{DynamicResource ButtonBackgroundMouseoverColor}"/>
</Trigger>
</Style.Triggers>
</Style>
<!-- TextBlock template -->
<Style TargetType="TextBlock">
@ -298,6 +337,103 @@
</Setter.Value>
</Setter>
</Style>
<Style x:Key="ToggleButtonStyle" TargetType="ToggleButton">
<Setter Property="Margin" Value="{DynamicResource ButtonMargin}"/>
<Setter Property="Foreground" Value="{DynamicResource ButtonForegroundColor}"/>
<Setter Property="Background" Value="{DynamicResource ButtonBackgroundColor}"/>
<Setter Property="Height" Value="{DynamicResource ButtonHeight}"/>
<Setter Property="Width" Value="{DynamicResource ButtonWidth}"/>
<Setter Property="FontSize" Value="{DynamicResource ButtonFontSize}"/>
<Setter Property="FontFamily" Value="{DynamicResource FontFamily}"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ToggleButton">
<Grid>
<Border x:Name="BackgroundBorder"
Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{DynamicResource ButtonBorderThickness}"
CornerRadius="{DynamicResource ButtonCornerRadius}">
<Grid>
<!-- Toggle Dot Background -->
<Ellipse Width="8" Height="16"
Fill="{DynamicResource ToggleButtonOnColor}"
HorizontalAlignment="Right"
VerticalAlignment="Top"
Margin="0,3,5,0" />
<!-- Toggle Dot with hover grow effect -->
<Ellipse x:Name="ToggleDot"
Width="8" Height="8"
Fill="{DynamicResource ButtonForegroundColor}"
HorizontalAlignment="Right"
VerticalAlignment="Top"
Margin="0,3,5,0"
RenderTransformOrigin="0.5,0.5">
<Ellipse.RenderTransform>
<ScaleTransform ScaleX="1" ScaleY="1"/>
</Ellipse.RenderTransform>
</Ellipse>
<!-- Content Presenter -->
<ContentPresenter HorizontalAlignment="Center"
VerticalAlignment="Center"
Margin="10,2,10,2"/>
</Grid>
</Border>
</Grid>
<!-- Triggers for ToggleButton states -->
<ControlTemplate.Triggers>
<!-- Hover effect -->
<Trigger Property="IsMouseOver" Value="True">
<Setter TargetName="BackgroundBorder" Property="Background" Value="{DynamicResource ButtonBackgroundMouseoverColor}"/>
<Trigger.EnterActions>
<BeginStoryboard>
<Storyboard>
<!-- Animation to grow the dot when hovered -->
<DoubleAnimation Storyboard.TargetName="ToggleDot"
Storyboard.TargetProperty="(UIElement.RenderTransform).(ScaleTransform.ScaleX)"
To="1.2" Duration="0:0:0.1"/>
<DoubleAnimation Storyboard.TargetName="ToggleDot"
Storyboard.TargetProperty="(UIElement.RenderTransform).(ScaleTransform.ScaleY)"
To="1.2" Duration="0:0:0.1"/>
</Storyboard>
</BeginStoryboard>
</Trigger.EnterActions>
<Trigger.ExitActions>
<BeginStoryboard>
<Storyboard>
<!-- Animation to shrink the dot back to original size when not hovered -->
<DoubleAnimation Storyboard.TargetName="ToggleDot"
Storyboard.TargetProperty="(UIElement.RenderTransform).(ScaleTransform.ScaleX)"
To="1.0" Duration="0:0:0.1"/>
<DoubleAnimation Storyboard.TargetName="ToggleDot"
Storyboard.TargetProperty="(UIElement.RenderTransform).(ScaleTransform.ScaleY)"
To="1.0" Duration="0:0:0.1"/>
</Storyboard>
</BeginStoryboard>
</Trigger.ExitActions>
</Trigger>
<!-- IsChecked state -->
<Trigger Property="IsChecked" Value="True">
<Setter TargetName="ToggleDot" Property="VerticalAlignment" Value="Bottom"/>
<Setter TargetName="ToggleDot" Property="Margin" Value="0,0,5,3"/>
</Trigger>
<!-- IsEnabled state -->
<Trigger Property="IsEnabled" Value="False">
<Setter TargetName="BackgroundBorder" Property="Background" Value="{DynamicResource ButtonBackgroundSelectedColor}"/>
<Setter Property="Foreground" Value="DimGray"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style x:Key="SearchBarClearButtonStyle" TargetType="Button">
<Setter Property="FontFamily" Value="{DynamicResource FontFamily}"/>
<Setter Property="FontSize" Value="{DynamicResource SearchBarClearButtonFontSize}"/>
@ -366,6 +502,19 @@
</Setter.Value>
</Setter>
</Style>
<!-- Collapsed Checkbox Style -->
<Style x:Key="CollapsedCheckBoxStyle" TargetType="CheckBox">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="CheckBox">
<ContentPresenter Content="{TemplateBinding Content}"
VerticalAlignment="Center"
HorizontalAlignment="Left"
Margin="{TemplateBinding Padding}"/>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style TargetType="RadioButton">
<Setter Property="Foreground" Value="{DynamicResource MainForegroundColor}"/>
<Setter Property="Background" Value="{DynamicResource MainBackgroundColor}"/>
@ -864,7 +1013,6 @@
</Border>
</Popup>
<Button Name="SettingsButton"
Style="{StaticResource HoverButtonStyle}"
Grid.Column="3" BorderBrush="Transparent"
@ -917,29 +1065,18 @@
<TabItem Header="Install" Visibility="Collapsed" Name="WPFTab1">
<Grid Background="Transparent" >
<Grid.RowDefinitions>
<RowDefinition Height="45px"/>
<RowDefinition Height="0.95*"/>
</Grid.RowDefinitions>
<StackPanel Background="{DynamicResource MainBackgroundColor}" Orientation="Horizontal" Grid.Row="0" HorizontalAlignment="Left" VerticalAlignment="Top" Grid.Column="0" Grid.ColumnSpan="3" Margin="{DynamicResource TabContentMargin}">
<Button Name="WPFInstall" Content=" Install/Upgrade Selected" Margin="2" />
<Button Name="WPFInstallUpgrade" Content=" Upgrade All" Margin="2"/>
<Button Name="WPFUninstall" Content=" Uninstall Selected" Margin="2"/>
<Button Name="WPFGetInstalled" Content=" Get Installed" Margin="2"/>
<Button Name="WPFClearInstallSelection" Content=" Clear Selection" Margin="2"/>
<CheckBox Name="WPFpreferChocolatey" VerticalAlignment="Center" VerticalContentAlignment="Center">
<TextBlock Text="Prefer Chocolatey" ToolTip="Prefers Chocolatey as Download Engine instead of Winget" VerticalAlignment="Center" />
</CheckBox>
</StackPanel>
<Grid Grid.Row="0" Grid.Column="0" Margin="{DynamicResource TabContentMargin}">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="225" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<ScrollViewer x:Name="scrollViewer" Grid.Row="1" Grid.Column="0" Margin="{DynamicResource TabContentMargin}" VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Auto"
BorderBrush="Transparent" BorderThickness="0" HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
<Grid Name="appspanel" HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
<Grid Name="appscategory" Grid.Column="0" HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
</Grid>
</ScrollViewer>
<Rectangle Grid.Row="1" Grid.Column="0" Width="22" Height="22" Fill="{DynamicResource MainBackgroundColor}" HorizontalAlignment="Right" VerticalAlignment="Bottom" Style="{StaticResource ScrollVisibilityRectangle}"/>
<Grid Name="appspanel" Grid.Column="1" HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
</Grid>
</Grid>
</Grid>
</TabItem>
<TabItem Header="Tweaks" Visibility="Collapsed" Name="WPFTab2">