Compare commits

..
8 Commits
Author SHA1 Message Date
OmarandGitHub 50be7390e5 fix: restore WindowStyle to SingleBorderWindow for proper window framing (#4868) 2026-07-22 12:42:25 -05:00
Chris TitusandGitHub 8ab02ae756 chore: Update generated dev docs (#4873) 2026-07-22 12:42:13 -05:00
OmarandGitHub 7d1a03dcc9 bugfix(tweaks): fix OneDrive uninstall path (#4864)
* bugfix(tweaks): fix OneDrive uninstall path

* bugfix(tweaks): use SystemRoot for OneDrive path
2026-07-22 12:41:48 -05:00
Paweł GwozdowskiandGitHub 5a4c9c883d Revert "Rework contributing.md (#4567)" (#4855) 2026-07-22 12:34:14 -05:00
Chris Titus 5c104d02e2 Update automated update PR workflows and filter release notes 2026-07-16 13:39:33 -05:00
Chris TitusandGitHub 06f33e88ba Fix Show Installed Apps reliability and selection (#4850)
* Fix Windows PowerShell runspace cleanup callback

* Fix installed app package ID matching

* Synchronize installed app selection UI

* Streamline installed app detection

* Avoid installed app UI runspace deadlock
2026-07-16 13:30:12 -05:00
b9dee86694 refactor: style and align Install tab filter chips (#4848)
* refactor: implement FilterChipStyle for Install tab category filters

- Created a dedicated FilterChipStyle style block with custom padding, cursor, and height definitions

- Applied FilterChipStyle to all category filter buttons

- Added a new 'Filters' TextBlock section title aligned with the sidebar actions

* Potential fix for pull request finding

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>

---------

Co-authored-by: Chris Titus <contact@christitus.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
2026-07-16 10:37:25 -05:00
OmarandGitHub 3d1904ebbe fix: wrap Tweaks header buttons to prevent layout clipping (#4847) 2026-07-16 10:29:16 -05:00
22 changed files with 531 additions and 299 deletions
+89 -115
View File
@@ -1,149 +1,123 @@
## Contributing Code # How to Contribute?
### Before You Start ## Testing
- Keep each pull request focused on a single feature or fix. * Test the latest changes to WinUtil by running the pre-release and reporting issues you are encountering to help us continually improve WinUtil!
- Avoid unnecessary formatting changes or large unrelated edits.
- Document what changed and why in your PR description.
--- #### **Run the latest pre-release**
```ps1
## Basic Git Workflow irm https://christitus.com/windev | iex
### 1. Fork the Repository
Go to the ChrisTitusTech/winutil repository on GitHub and click the Fork button in the top right corner.
<img width="171" height="50" alt="{650A4723-F38A-44A4-9820-D232BC87C8A0}" src="https://github.com/user-attachments/assets/a214f27c-2fee-444a-920f-d87b14f5896f" />
---
### 2. Clone Your Fork
```powershell
git clone https://github.com/YOUR_USERNAME/winutil.git
cd winutil
``` ```
--- !!! bug "Keep in mind"
### 3. Create a Branch This is a pre-release and should be treated as such. It exists for developers to test the utility and report or fix bugs before they get added to the stable release. Don't use it in production!
Never work directly on `main`. ## Issues
Create a branch related to your change: * If you encounter any challenges or problems with the script, I kindly request that you submit them via the "Issues" tab on the GitHub repository. By filling out the provided template, you can provide specific details about the issue, allowing me (and others in the community) to promptly address any bugs or consider feature requests.
```powershell ## Contribute Code
git checkout -b feature-name
* Pull requests are now handled directly on the **MAIN branch**. This was done since we can now select specific releases to launch via releases in GitHub.
* If you're doing code changes, then you can submit a PR to the `main` branch.
!!! warning "Important"
Do not use a code formatter, make massive amounts of line changes, or make multiple feature changes. EACH FEATURE CHANGE SHOULD BE IT'S OWN PULL REQUEST!
Do not open a pull request that adds support for other languages to WinUtil for now, until we decide how we want to move forward with language support.
* When creating pull requests, it is essential to thoroughly document all changes made. This includes, but is not limited to, documenting any additions made to the `tweaks` section and corresponding `undo tweak`, so users are able to remove the newly added tweaks if necessary, and comprehensive documentation is required for all code changes. Document your changes and briefly explain why you made your changes in your Pull Request Description. Failure to adhere to this format may result in the denial of the pull request. Additionally, any code lacking sufficient documentation may also be denied.
* By following these guidelines, we can maintain a high standard of quality and ensure that the codebase remains organized and well-documented.
!!! note
When creating a function, please include "WPF" or "WinUtil" in the file name so it can be loaded into the runspace.
## Walk through
* This is a guide for beginners. If you are still having issues, look at the following official GitHub documentation:
* [Commit through WEB](https://docs.github.com/en/pull-requests/committing-changes-to-your-project/creating-and-editing-commits/about-commits)
* [Commit through GitHub Desktop](https://docs.github.com/en/desktop/making-changes-in-a-branch/committing-and-reviewing-changes-to-your-project-in-github-desktop#about-commits)
* [Create a Pull Request](https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/proposing-changes-to-your-work-with-pull-requests/creating-a-pull-request)
### Overview
``` mermaid
%%{init: {"flowchart": {"curve": "cardinal"}} }%%
graph TD
  A[Fork Project] --> B[Clone Repository];
  B --> C[Create New Branch];
  C --> D[Make Changes];
  D --> G[Test Changes];
  G --> H{Tests Passed?};
  H -->|Yes| E[Commit Changes];
  H -->|No| J[Fix Issues];
  J --> G;
  E --> F[Push Branch];
  F --> K[Create Pull Request];
  K --> L[Fill out PR template];
classDef default stroke:#333,stroke-width:4px,font-size:12pt;
``` ```
!!! info
Example: This is a diagram to guide you through the process. It may vary depending on the type of change you're making.
```powershell ### Fork the Repo
git checkout -b add-firefox-tweak * Fork the WinUtil Repository [here](https://github.com/ChrisTitusTech/winutil) to create a copy that will be available in your repository list.
```
--- ![Fork Image](/docs/assets/images/Fork-Button-Dark.png#gh-dark-mode-only)
### 4. Edit the Code ![Fork Image](/docs/assets/images/Fork-Button-Light.png#only-light#gh-light-mode-only)
Open the project in your preferred text editor and make your changes. ### Clone the Fork
!!! tip
Keep changes small and focused. While you can make your changes directly through the Web, we recommend cloning the repo to your device using the application GitHub Desktop (available in WinUtil) to test your fork easily.
--- * Install GitHub Desktop if it is not already installed.
* Log in using the same GitHub account you used to fork WinUtil.
* Choose the fork under "Your Repositories" and press "clone {repo name}"
* Create a new branch and name it something relatable to your changes.
### 5. Test Your Changes * Now you can modify WinUtil to your liking using your preferred text editor.
Open Powershell as Administrator.
Go to the project folder: ### Testing your changes
```powershell * To test to see if your changes work as intended, run the following commands in a PowerShell terminal as admin:
cd path\to\winutil
```
Run: * Change the directory where you are running the commands to the forked project.
* `cd {path to the folder with the compile.ps1}`
* Run the following command to compile and run WinUtil:
* `.\Compile.ps1 -run`
```powershell ![Compile](/docs/assets/images/Complie.png)
.\Compile.ps1 -Run
```
Verify:
- WinUtil launches correctly Open PowerShell as Administrator.
- Your feature works
- Nothing else breaks
If something fails, fix it before committing. * After seeing that your changes work properly, feel free to commit the changes to the repository and make a PR. For help on that, follow the documentation below.
---
### 6. Review Your Changes ### Committing the changes
* Before committing your changes, please discard changes made to the `winutil.ps1` file, like the following:
Check what changed: ![Push Commit Image](/docs/assets/images/Discard-GHD.png)
```powershell * Now, commit your changes once you are happy with the result.
git status
```
Review the diff: ![Commit Image](/docs/assets/images/Commit-GHD.png)
```powershell * Push the changes to upload them to your fork on github.com.
git diff
```
Make sure you did not accidentally modify unrelated files. ![Push Commit Image](/docs/assets/images/Push-Commit.png)
--- ### Making a PR
* To make a PR on your repo under a new branch linking to the main branch, a button will show and say Preview and Create pull request. Click that button and fill in all the information that is provided on the template. Once all the information is filled in correctly, check your PR to make sure there is no WinUtil.ps1 file attached to the PR. Once everything is good, make the PR and wait for Chris (the maintainer) to accept or deny your PR. Once it is accepted by Chris, you will be able to see your changes in the "/windev" build.
### 7. Commit Your Changes * If you do not see your feature in the main "/win" build, that is fine. All new changes go into the /windev build to make sure everything is working OK before going fully public.
* Congratulations! You just submitted your first PR. Thank you so much for contributing to WinUtil.
Stage files:
```powershell
git add .
```
Commit them:
```powershell
git commit -m "Add feature description"
```
Example:
```powershell
git commit -m "Add Firefox package tweak"
```
---
### 8. Push Your Branch
```powershell
git push origin branch-name
```
Example:
```powershell
git push origin add-firefox-tweak
```
---
### 9. Open a Pull Request
Go to your fork on GitHub.
GitHub will show a button to create a pull request.
<img width="1009" height="71" alt="{C8C6A3CC-79D4-44FD-A54C-4C5717F12730}" src="https://github.com/user-attachments/assets/0419d193-d4e7-47c0-87cf-b986742201a0" />
Before submitting:
- Explain what changed
- Explain why you changed it
- Make sure unrelated files are not included
Once submitted, maintainers will review your PR.
+2 -2
View File
@@ -1,4 +1,4 @@
name: Auto-merge Docs PRs name: Auto-merge Automated Update PRs
on: on:
pull_request: pull_request:
@@ -8,7 +8,7 @@ on:
jobs: jobs:
auto-merge: auto-merge:
if: github.event.pull_request.head.ref == 'docs-update' && (github.event.pull_request.user.login == 'ChrisTitusTech' || github.event.pull_request.user.login == 'github-actions[bot]') if: (github.event.pull_request.head.ref == 'docs-update' || github.event.pull_request.head.ref == 'sponsors-update') && (github.event.pull_request.user.login == 'ChrisTitusTech' || github.event.pull_request.user.login == 'github-actions[bot]')
runs-on: ubuntu-latest runs-on: ubuntu-latest
permissions: permissions:
pull-requests: write pull-requests: write
+16 -1
View File
@@ -109,6 +109,21 @@ jobs:
config-name: release-drafter.yml config-name: release-drafter.yml
version: ${{ env.VERSION }} version: ${{ env.VERSION }}
- name: Remove Automated Updates from Release Notes
id: filter_notes
shell: pwsh
env:
RELEASE_NOTES: ${{ steps.generate_notes.outputs.body }}
run: |
$filteredNotes = ($env:RELEASE_NOTES -split '\r?\n' | Where-Object {
$_ -notmatch '(?i)Update (Generated Dev Docs|Sponsors)'
}) -join "`n"
$delimiter = [guid]::NewGuid().ToString()
"body<<$delimiter" >> $env:GITHUB_OUTPUT
$filteredNotes >> $env:GITHUB_OUTPUT
$delimiter >> $env:GITHUB_OUTPUT
- name: Create and Upload Release - name: Create and Upload Release
id: create_release id: create_release
uses: softprops/action-gh-release@v3 uses: softprops/action-gh-release@v3
@@ -116,7 +131,7 @@ jobs:
tag_name: ${{ env.VERSION }} tag_name: ${{ env.VERSION }}
name: Pre-Release ${{ env.VERSION }} name: Pre-Release ${{ env.VERSION }}
body: | body: |
${{ steps.generate_notes.outputs.body }} ${{ steps.filter_notes.outputs.body }}
![GitHub Downloads (specific asset, specific tag)](https://img.shields.io/github/downloads/ChrisTitusTech/winutil/${{ env.VERSION }}/winutil.ps1) ![GitHub Downloads (specific asset, specific tag)](https://img.shields.io/github/downloads/ChrisTitusTech/winutil/${{ env.VERSION }}/winutil.ps1)
append_body: false append_body: false
+1 -1
View File
@@ -26,7 +26,7 @@ jobs:
id: cpr id: cpr
uses: peter-evans/create-pull-request@v8 uses: peter-evans/create-pull-request@v8
with: with:
token: ${{ secrets.GITHUB_TOKEN }} token: ${{ secrets.AUTO_MERGE }}
commit-message: 'Update sponsors in README' commit-message: 'Update sponsors in README'
title: 'chore: Update Sponsors README' title: 'chore: Update Sponsors README'
body: 'Automated update of sponsors section' body: 'Automated update of sponsors section'
+1 -1
View File
@@ -650,7 +650,7 @@
icacls $Env:OneDrive /deny \"Administrators:(D,DC)\" icacls $Env:OneDrive /deny \"Administrators:(D,DC)\"
Write-Host \"Uninstalling OneDrive...\" Write-Host \"Uninstalling OneDrive...\"
Start-Process '$Env:SystemRoot\\System32\\OneDriveSetup.exe' -ArgumentList '/uninstall' -Wait Start-Process -FilePath (Join-Path $Env:SystemRoot \"System32\\OneDriveSetup.exe\") -ArgumentList '/uninstall' -Wait
# Some of OneDrive files use explorer, and OneDrive uses FileCoAuth # Some of OneDrive files use explorer, and OneDrive uses FileCoAuth
Write-Host \"Removing leftover OneDrive Files...\" Write-Host \"Removing leftover OneDrive Files...\"
Binary file not shown.

After

Width:  |  Height:  |  Size: 194 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 77 KiB

+88 -119
View File
@@ -2,152 +2,121 @@
toc: true toc: true
--- ---
## Contributing Code # How to Contribute?
### Before You Start ## Testing
- Keep each pull request focused on a single feature or fix. * Test the latest changes to WinUtil by running the pre-release and reporting issues you are encountering to help us continually improve WinUtil!
- Avoid unnecessary formatting changes or large unrelated edits.
- Document what changed and why in your PR description.
--- #### Run the latest pre-release
## Basic Git Workflow ```ps1
irm https://christitus.com/windev | iex
### 1. Fork the Repository
Go to the ChrisTitusTech/winutil repository on GitHub and click the Fork button in the top right corner.
<img width="171" height="50" alt="{650A4723-F38A-44A4-9820-D232BC87C8A0}" src="https://github.com/user-attachments/assets/a214f27c-2fee-444a-920f-d87b14f5896f" />
---
### 2. Clone Your Fork
```bash
git clone https://github.com/YOUR_USERNAME/winutil.git
cd winutil
``` ```
--- > [!IMPORTANT]
> **Keep in mind** That this is a pre-release and should be treated as such. It exists for developers to test the utility and report or fix bugs before they get added to the stable release. Don't use it in production!
### 3. Create a Branch ## Issues
Never work directly on `main`. * If you encounter any challenges or problems with the script, I kindly request that you submit them via the "Issues" tab on the GitHub repository. By filling out the provided template, you can provide specific details about the issue, allowing me (and others in the community) to promptly address any bugs or consider feature requests.
Create a branch related to your change: ## Contribute Code
```bash * Pull requests are now handled directly on the **MAIN branch**. This was done since we can now select specific releases to launch via releases in GitHub.
git checkout -b feature-name
* If you're doing code changes, then you can submit a PR to the `main` branch.
> [!IMPORTANT]
> Do not use a code formatter, make massive amounts of line changes, or make multiple feature changes. EACH FEATURE CHANGE SHOULD BE IT'S OWN PULL REQUEST!
> [!IMPORTANT]
> Do not open a pull request that adds support for other languages to WinUtil for now, until we decide how we want to move forward with language support.
* When creating pull requests, it is essential to thoroughly document all changes made. This includes, but is not limited to, documenting any additions made to the `tweaks` section and corresponding `undo tweak`, so users are able to remove the newly added tweaks if necessary, and comprehensive documentation is required for all code changes. Document your changes and briefly explain why you made your changes in your Pull Request Description. Failure to adhere to this format may result in the denial of the pull request. Additionally, any code lacking sufficient documentation may also be denied.
* By following these guidelines, we can maintain a high standard of quality and ensure that the codebase remains organized and well-documented.
> [!NOTE]
>
> When creating a function, please include "WPF" or "WinUtil" in the file name so it can be loaded into the runspace.
## Walk through
* This is a guide for beginners. If you are still having issues, look at the following official GitHub documentation:
* [Commit through WEB](https://docs.github.com/en/pull-requests/committing-changes-to-your-project/creating-and-editing-commits/about-commits)
* [Commit through GitHub Desktop](https://docs.github.com/en/desktop/making-changes-in-a-branch/committing-and-reviewing-changes-to-your-project-in-github-desktop#about-commits)
* [Create a Pull Request](https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/proposing-changes-to-your-work-with-pull-requests/creating-a-pull-request)
### Overview
```mermaid
%%{init: {"flowchart": {"curve": "cardinal"}} }%%
graph TD
A[Fork Project] --> B[Clone Repository];
B --> C[Create New Branch];
C --> D[Make Changes];
D --> G[Test Changes];
G --> H{Tests Passed?};
H -->|Yes| E[Commit Changes];
H -->|No| J[Fix Issues];
J --> G;
E --> F[Push Branch];
F --> K[Create Pull Request];
K --> L[Fill out PR template];
classDef default stroke:#333,stroke-width:4px,font-size:12pt;
``` ```
Example: > [!NOTE]
>
> This is a diagram to guide you through the process. It may vary depending on the type of change you're making.
```bash ### Fork the Repo
git checkout -b add-firefox-tweak * Fork the WinUtil Repository [here](https://github.com/ChrisTitusTech/winutil) to create a copy that will be available in your repository list.
```
--- {{< image src="images/Fork-Button" alt="Fork Image" >}}
### 4. Edit the Code ### Clone the Fork
> [!TIP]
>
> While you can make your changes directly through the Web, we recommend cloning the repo to your device using the application GitHub Desktop (available in WinUtil) to test your fork easily.
Open the project in your preferred text editor and make your changes. * Install GitHub Desktop if it is not already installed.
* Log in using the same GitHub account you used to fork WinUtil.
* Choose the fork under "Your Repositories" and press "clone {repo name}"
* Create a new branch and name it something relatable to your changes.
Keep changes small and focused. * Now you can modify WinUtil to your liking using your preferred text editor.
---
### 5. Test Your Changes ### Testing your changes
Open PowerShell as Administrator. * To test to see if your changes work as intended, run the following commands in a PowerShell terminal as admin:
Go to the project folder: * Change the directory where you are running the commands to the forked project.
* `cd {path to the folder with the compile.ps1}`
* Run the following command to compile and run WinUtil:
* `.\Compile.ps1 -run`
```powershell {{< image src="images/Complie" alt="Compile" >}}
cd path\to\winutil
```
Run: * After seeing that your changes work properly, feel free to commit the changes to the repository and make a PR. For help on that, follow the documentation below.
```powershell ### Committing the changes
.\Compile.ps1 -Run * Before committing your changes, please discard changes made to the `winutil.ps1` file, like the following:
```
Verify: {{< image src="images/Discard-GHD" alt="Push Commit Image" >}}
- WinUtil launches correctly * Now, commit your changes once you are happy with the result.
- Your feature works
- Nothing else breaks
If something fails, fix it before committing. {{< image src="images/Commit-GHD" alt="Commit Image" >}}
--- * Push the changes to upload them to your fork on github.com.
### 6. Review Your Changes {{< image src="images/Push-Commit" alt="Push Commit Image" >}}
Check what changed: ### Making a PR
* To make a PR on your repo under a new branch linking to the main branch, a button will show and say Preview and Create pull request. Click that button and fill in all the information that is provided on the template. Once all the information is filled in correctly, check your PR to make sure there is no WinUtil.ps1 file attached to the PR. Once everything is good, make the PR and wait for Chris (the maintainer) to accept or deny your PR. Once it is accepted by Chris, you will be able to see your changes in the "/windev" build.
```bash * If you do not see your feature in the main "/win" build, that is fine. All new changes go into the /windev build to make sure everything is working OK before going fully public.
git status * Congratulations! You just submitted your first PR. Thank you so much for contributing to WinUtil.
```
Review the diff:
```bash
git diff
```
Make sure you did not accidentally modify unrelated files.
---
### 7. Commit Your Changes
Stage files:
```bash
git add .
```
Commit them:
```bash
git commit -m "Add feature description"
```
Example:
```bash
git commit -m "Add Firefox package tweak"
```
---
### 8. Push Your Branch
```bash
git push origin branch-name
```
Example:
```bash
git push origin add-firefox-tweak
```
---
### 9. Open a Pull Request
Go to your fork on GitHub.
GitHub will show a button to create a pull request.
<img width="1009" height="71" alt="{C8C6A3CC-79D4-44FD-A54C-4C5717F12730}" src="https://github.com/user-attachments/assets/0419d193-d4e7-47c0-87cf-b986742201a0" />
Before submitting:
- Explain what changed
- Explain why you changed it
- Make sure unrelated files are not included
Once submitted, maintainers will review your PR.
@@ -15,7 +15,7 @@ description: ""
icacls $Env:OneDrive /deny \"Administrators:(D,DC)\" icacls $Env:OneDrive /deny \"Administrators:(D,DC)\"
Write-Host \"Uninstalling OneDrive...\" Write-Host \"Uninstalling OneDrive...\"
Start-Process '$Env:SystemRoot\\System32\\OneDriveSetup.exe' -ArgumentList '/uninstall' -Wait Start-Process -FilePath (Join-Path $Env:SystemRoot \"System32\\OneDriveSetup.exe\") -ArgumentList '/uninstall' -Wait
# Some of OneDrive files use explorer, and OneDrive uses FileCoAuth # Some of OneDrive files use explorer, and OneDrive uses FileCoAuth
Write-Host \"Removing leftover OneDrive Files...\" Write-Host \"Removing leftover OneDrive Files...\"
@@ -15,32 +15,36 @@ Function Invoke-WinUtilCurrentSystem {
) )
if ($CheckBox -eq "choco") { if ($CheckBox -eq "choco") {
$apps = (choco list | Select-String -Pattern "^\S+").Matches.Value $apps = (choco list | Select-String -Pattern "^\S+").Matches.Value
$filter = Get-WinUtilVariables -Type Checkbox | Where-Object {$psitem -like "WPFInstall*"} $sync.configs.applicationsHashtable.GetEnumerator() | ForEach-Object {
$sync.GetEnumerator() | Where-Object {$psitem.Key -in $filter} | ForEach-Object { $packageId = ($_.Value.choco -split ";")[-1].Trim()
$dependencies = @($sync.configs.applications.$($psitem.Key).choco -split ";") if ($packageId -ne "na" -and $packageId -in $apps) {
if ($dependencies -in $apps) { Write-Output $_.Key
Write-Output $psitem.name
} }
} }
} }
if ($checkbox -eq "winget") { if ($checkbox -eq "winget") {
$originalEncoding = [Console]::OutputEncoding $originalEncoding = [Console]::OutputEncoding
try {
[Console]::OutputEncoding = [System.Text.UTF8Encoding]::new() [Console]::OutputEncoding = [System.Text.UTF8Encoding]::new()
$Sync.InstalledPrograms = @("winget", "msstore") | ForEach-Object { $installedProgramOutput = @(winget list --accept-source-agreements --disable-interactivity 2>&1)
winget list -s $psitem | Select-Object -skip 3 | ConvertFrom-String -PropertyNames "Name", "Id", "Version", "Available" -Delimiter '\s{2,}' if ($LASTEXITCODE -ne 0) {
throw "winget list failed with exit code $LASTEXITCODE."
} }
} finally {
[Console]::OutputEncoding = $originalEncoding [Console]::OutputEncoding = $originalEncoding
}
$installedProgramText = $installedProgramOutput -join "`n"
$filter = Get-WinUtilVariables -Type Checkbox | Where-Object {$psitem -like "WPFInstall*"} $sync.configs.applicationsHashtable.GetEnumerator() | ForEach-Object {
$sync.GetEnumerator() | Where-Object {$psitem.Key -in $filter} | ForEach-Object { $packageId = (($_.Value.winget -split ";")[-1] -replace "^msstore:", "").Trim()
$dependencies = @($sync.configs.applications.$($psitem.Key).winget -split ";") | ForEach-Object { if ([string]::IsNullOrWhiteSpace($packageId) -or $packageId -eq "na") {
$psitem -replace "^msstore:", "" return
} }
if ($dependencies[-1] -in $sync.InstalledPrograms.Id) { $packagePattern = "(?im)[^\S\r\n]{2,}$([regex]::Escape($packageId))(?=[^\S\r\n]{2,}|$)"
Write-Output $psitem.name if ($installedProgramText -match $packagePattern) {
Write-Output $_.Key
} }
} }
} }
+59 -23
View File
@@ -1,6 +1,5 @@
function Invoke-WPFGetInstalled { function Invoke-WPFGetInstalled {
<# <#
TODO: Add the Option to use Chocolatey as Engine
.SYNOPSIS .SYNOPSIS
Invokes the function that gets the checkboxes to check in a new runspace Invokes the function that gets the checkboxes to check in a new runspace
@@ -19,35 +18,72 @@ function Invoke-WPFGetInstalled {
return return
} }
$managerPreference = $sync.preferences.packagemanager $managerPreference = $sync.preferences.packagemanager
$operation = [Hashtable]::Synchronized(@{
Checkboxes = @()
Error = $null
})
$completeAction = [Action[hashtable, string]]{
param(
[hashtable]$completedOperation,
[string]$completedCheckbox
)
try {
if ($completedOperation.Error) {
Write-WinUtilLog -Level "ERROR" -Component "Install" -Message "Get installed state failed: $($completedOperation.Error)"
Write-Warning "Unable to get installed state: $($completedOperation.Error)"
return
}
Invoke-WPFRunspace -ParameterList @(("managerPreference", $managerPreference),("checkbox", $checkbox)) -ScriptBlock { if ($completedCheckbox -eq "winget") {
foreach ($checkboxName in $completedOperation.Checkboxes) {
if (-not $sync.selectedApps.Contains($checkboxName)) {
$sync.selectedApps.Add($checkboxName)
}
}
Reset-WPFCheckBoxes -checkboxfilterpattern "WPFInstall*"
} else {
foreach ($checkboxName in $completedOperation.Checkboxes) {
$sync.$checkboxName.ischecked = $True
}
}
} finally {
$sync.ProcessRunning = $false
Set-WinUtilTaskbaritem -state "None"
}
}
$sync.ProcessRunning = $true
Set-WinUtilTaskbaritem -state "Indeterminate"
try {
Invoke-WPFRunspace -ParameterList @(
("managerPreference", $managerPreference),
("checkbox", $checkbox),
("operation", $operation),
("completeAction", $completeAction)
) -ScriptBlock {
param ( param (
[string]$checkbox, [string]$checkbox,
[string]$managerPreference [string]$managerPreference,
[hashtable]$operation,
[Action[hashtable, string]]$completeAction
) )
$sync.ProcessRunning = $true try {
Invoke-WPFUIThread -ScriptBlock { Set-WinUtilTaskbaritem -state "Indeterminate" }
if ($checkbox -eq "winget") { if ($checkbox -eq "winget") {
Write-Host "Getting Installed Programs..."
switch ($managerPreference) { switch ($managerPreference) {
"Choco"{$Checkboxes = Invoke-WinUtilCurrentSystem -CheckBox "choco"; break} "Choco" { $operation.Checkboxes = @(Invoke-WinUtilCurrentSystem -CheckBox "choco"); break }
"Winget"{$Checkboxes = Invoke-WinUtilCurrentSystem -CheckBox $checkbox; break} "Winget" { $operation.Checkboxes = @(Invoke-WinUtilCurrentSystem -CheckBox $checkbox); break }
}
} elseif ($checkbox -eq "tweaks") {
$operation.Checkboxes = @(Invoke-WinUtilCurrentSystem -CheckBox $checkbox)
}
} catch {
$operation.Error = $_.Exception.Message
} finally {
$sync.Form.Dispatcher.BeginInvoke($completeAction, [object[]]@($operation, $checkbox)) | Out-Null
} }
} }
elseif ($checkbox -eq "tweaks") { } catch {
Write-Host "Getting Installed Tweaks..." $operation.Error = $_.Exception.Message
$Checkboxes = Invoke-WinUtilCurrentSystem -CheckBox $checkbox $completeAction.Invoke($operation, $checkbox)
}
$sync.form.Dispatcher.invoke({
foreach ($checkbox in $Checkboxes) {
$sync.$checkbox.ischecked = $True
}
})
Write-Host "Done..."
$sync.ProcessRunning = $false
Invoke-WPFUIThread -ScriptBlock { Set-WinUtilTaskbaritem -state "None" }
} }
} }
+3 -2
View File
@@ -44,6 +44,8 @@ public sealed class WinUtilRunspaceCleanupState
public static class WinUtilRunspaceCleanup public static class WinUtilRunspaceCleanup
{ {
public static readonly System.Threading.WaitOrTimerCallback Callback = Cleanup;
public static void Cleanup(object state, bool timedOut) public static void Cleanup(object state, bool timedOut)
{ {
var cleanupState = state as WinUtilRunspaceCleanupState; var cleanupState = state as WinUtilRunspaceCleanupState;
@@ -89,8 +91,7 @@ public static class WinUtilRunspaceCleanup
$cleanupState = [WinUtilRunspaceCleanupState]::new() $cleanupState = [WinUtilRunspaceCleanupState]::new()
$cleanupState.PowerShell = $powershell $cleanupState.PowerShell = $powershell
$cleanupState.Handle = $handle $cleanupState.Handle = $handle
$cleanupCallback = [System.Threading.WaitOrTimerCallback][WinUtilRunspaceCleanup]::Cleanup [System.Threading.ThreadPool]::RegisterWaitForSingleObject($handle.AsyncWaitHandle, [WinUtilRunspaceCleanup]::Callback, $cleanupState, -1, $true) | Out-Null
[System.Threading.ThreadPool]::RegisterWaitForSingleObject($handle.AsyncWaitHandle, $cleanupCallback, $cleanupState, -1, $true) | Out-Null
# Return the handle # Return the handle
return $handle return $handle
@@ -7,11 +7,21 @@ function Invoke-WPFSelectedCheckboxesUpdate ($type, $checkboxName) {
'^WPFAppx' { 'selectedAppx' } '^WPFAppx' { 'selectedAppx' }
} }
$selectionChanged = $false
if ($type -eq "Add") { if ($type -eq "Add") {
if (-not $sync.$listName.Contains($checkboxName)) { if (-not $sync.$listName.Contains($checkboxName)) {
$sync.$listName.Add($checkboxName) $sync.$listName.Add($checkboxName)
$selectionChanged = $true
} }
} else { } else {
$sync.$listName.Remove($checkboxName) $selectionChanged = $sync.$listName.Remove($checkboxName)
}
if ($listName -eq "selectedApps" -and $selectionChanged) {
$sync.WPFselectedAppsButton.Content = "Selected Apps: $($sync.selectedApps.Count)"
$sync.selectedAppsstackPanel.Children.Clear()
$sync.selectedApps | Sort-Object | ForEach-Object {
Add-SelectedAppsMenuItem -name $sync.configs.applicationsHashtable.$_.Content -key $_
}
} }
} }
+4
View File
@@ -140,6 +140,10 @@ Describe "Invoke-WPFRunspace behavior" {
$runspaceScript | Should -Not -Match '\$script:powershell' $runspaceScript | Should -Not -Match '\$script:powershell'
$runspaceScript | Should -Not -Match '\$script:handle' $runspaceScript | Should -Not -Match '\$script:handle'
} }
It "exposes a strongly typed cleanup callback" {
([WinUtilRunspaceCleanup]::Callback -is [System.Threading.WaitOrTimerCallback]) | Should -BeTrue
}
} }
Describe "Public runspace callers" { Describe "Public runspace callers" {
+70
View File
@@ -6,12 +6,82 @@ $repoRoot = (Resolve-Path (Join-Path $PSScriptRoot "..")).Path
BeforeAll { BeforeAll {
$script:repoRoot = (Resolve-Path (Join-Path $PSScriptRoot "..")).Path $script:repoRoot = (Resolve-Path (Join-Path $PSScriptRoot "..")).Path
. (Join-Path $script:repoRoot "functions\private\Invoke-WinUtilCurrentSystem.ps1")
. (Join-Path $script:repoRoot "functions\private\Set-WinUtilRegistry.ps1") . (Join-Path $script:repoRoot "functions\private\Set-WinUtilRegistry.ps1")
. (Join-Path $script:repoRoot "functions\private\Set-WinUtilService.ps1") . (Join-Path $script:repoRoot "functions\private\Set-WinUtilService.ps1")
function winget {
param([Parameter(ValueFromRemainingArguments = $true)]$Arguments)
}
function choco {
param([Parameter(ValueFromRemainingArguments = $true)]$Arguments)
}
function Write-WinUtilLog { } function Write-WinUtilLog { }
} }
Describe "Invoke-WinUtilCurrentSystem installed apps" {
BeforeEach {
$script:sync = [Hashtable]::Synchronized(@{
configs = [pscustomobject]@{
applicationsHashtable = @{
WPFInstallGit = [pscustomobject]@{ winget = "Git.Git"; choco = "git" }
WPFInstallChatGPT = [pscustomobject]@{ winget = "msstore:9NT1R1C2HH7J"; choco = "na" }
WPFInstallMissing = [pscustomobject]@{ winget = "Git"; choco = "missing" }
}
}
})
Mock winget {
$global:LASTEXITCODE = 0
$script:wingetArguments = @($Arguments)
@(
"Name Id Version Source",
"--------------------------------",
"Git Git.Git 2.0 winget",
"ChatGPT 9NT1R1C2HH7J 1.0 msstore"
)
}
Mock choco {
$script:chocoArguments = @($Arguments)
@("Chocolatey v2", "git 2.0", "2 packages installed.")
}
}
AfterEach {
Remove-Variable -Name sync -Scope Script -ErrorAction SilentlyContinue
Remove-Variable -Name wingetArguments -Scope Script -ErrorAction SilentlyContinue
Remove-Variable -Name chocoArguments -Scope Script -ErrorAction SilentlyContinue
}
It "matches single standard and Microsoft Store package IDs" {
$result = @(Invoke-WinUtilCurrentSystem -CheckBox "winget")
$result | Should -HaveCount 2
$result | Should -Contain "WPFInstallGit"
$result | Should -Contain "WPFInstallChatGPT"
$result | Should -Not -Contain "WPFInstallMissing"
Should -Invoke -CommandName winget -Times 1 -Exactly
$script:wingetArguments | Should -Be @("list", "--accept-source-agreements", "--disable-interactivity")
}
It "fails promptly when Winget cannot list applications" {
Mock winget {
$global:LASTEXITCODE = 1
"winget failed"
}
{ Invoke-WinUtilCurrentSystem -CheckBox "winget" } | Should -Throw "winget list failed with exit code 1."
}
It "matches the primary Chocolatey package ID in one list call" {
$result = @(Invoke-WinUtilCurrentSystem -CheckBox "choco")
$result | Should -Be @("WPFInstallGit")
Should -Invoke -CommandName choco -Times 1 -Exactly
$script:chocoArguments | Should -Be @("list")
}
}
Describe "Set-WinUtilRegistry" { Describe "Set-WinUtilRegistry" {
BeforeEach { BeforeEach {
$script:testPathResults = @{} $script:testPathResults = @{}
+110
View File
@@ -61,6 +61,7 @@ namespace System.Windows.Controls
. (Join-Path $script:repoRoot "functions\private\Update-WinUtilSelections.ps1") . (Join-Path $script:repoRoot "functions\private\Update-WinUtilSelections.ps1")
. (Join-Path $script:repoRoot "functions\private\Reset-WPFCheckBoxes.ps1") . (Join-Path $script:repoRoot "functions\private\Reset-WPFCheckBoxes.ps1")
. (Join-Path $script:repoRoot "functions\public\Invoke-WPFGetInstalled.ps1")
. (Join-Path $script:repoRoot "functions\public\Invoke-WPFSelectedCheckboxesUpdate.ps1") . (Join-Path $script:repoRoot "functions\public\Invoke-WPFSelectedCheckboxesUpdate.ps1")
. (Join-Path $script:repoRoot "functions\public\Invoke-WPFButton.ps1") . (Join-Path $script:repoRoot "functions\public\Invoke-WPFButton.ps1")
. (Join-Path $script:repoRoot "functions\public\Invoke-WPFToggleAllCategories.ps1") . (Join-Path $script:repoRoot "functions\public\Invoke-WPFToggleAllCategories.ps1")
@@ -68,6 +69,24 @@ namespace System.Windows.Controls
function Set-WinUtilTweaksProgressIndicator { function Set-WinUtilTweaksProgressIndicator {
param($Visible, $Label, $Percent) param($Visible, $Label, $Percent)
} }
function Invoke-WPFRunspace {
param($ArgumentList, $ParameterList, [scriptblock]$ScriptBlock)
}
function Invoke-WPFUIThread {
param([scriptblock]$ScriptBlock)
}
function Invoke-WinUtilCurrentSystem {
param($CheckBox)
}
function Set-WinUtilTaskbaritem {
param($state)
}
function Test-WinUtilPackageManager {
param([switch]$winget)
}
function Write-WinUtilLog {
param($Message, $Level, $Component)
}
function script:New-WinUtilFakeCheckBox { function script:New-WinUtilFakeCheckBox {
param([bool]$IsChecked = $false) param([bool]$IsChecked = $false)
@@ -180,6 +199,9 @@ Describe "Invoke-WPFSelectedCheckboxesUpdate" {
@($script:sync.selectedToggles) | Should -Be @("WPFToggleDarkMode") @($script:sync.selectedToggles) | Should -Be @("WPFToggleDarkMode")
@($script:sync.selectedFeatures) | Should -Be @("WPFFeatureSandbox") @($script:sync.selectedFeatures) | Should -Be @("WPFFeatureSandbox")
@($script:sync.selectedAppx) | Should -Be @("WPFAppxExample") @($script:sync.selectedAppx) | Should -Be @("WPFAppxExample")
$script:sync.WPFselectedAppsButton.Content | Should -Be "Selected Apps: 1"
$script:sync.selectedAppsstackPanel.Children.Count | Should -Be 1
$script:sync.selectedAppsstackPanel.Children[0].Key | Should -Be "WPFInstallGit"
} }
It "removes checkbox keys from the matching selected lists" { It "removes checkbox keys from the matching selected lists" {
@@ -200,6 +222,94 @@ Describe "Invoke-WPFSelectedCheckboxesUpdate" {
$script:sync.selectedToggles.Count | Should -Be 0 $script:sync.selectedToggles.Count | Should -Be 0
$script:sync.selectedFeatures.Count | Should -Be 0 $script:sync.selectedFeatures.Count | Should -Be 0
$script:sync.selectedAppx.Count | Should -Be 0 $script:sync.selectedAppx.Count | Should -Be 0
$script:sync.WPFselectedAppsButton.Content | Should -Be "Selected Apps: 0"
$script:sync.selectedAppsstackPanel.Children.Count | Should -Be 0
}
}
Describe "Invoke-WPFGetInstalled selection state" {
BeforeEach {
New-WinUtilUiStateTestContext
$script:sync.ProcessRunning = $false
$script:sync.ChocoRadioButton = [pscustomobject]@{ IsChecked = $false }
$script:sync.preferences = [pscustomobject]@{ packagemanager = "Winget" }
$script:sync.WPFInstallGit = New-WinUtilFakeCheckBox
$dispatcher = [pscustomobject]@{}
$dispatcher | Add-Member -MemberType ScriptMethod -Name BeginInvoke -Value {
param($Action, [object[]]$Arguments)
$Action.DynamicInvoke($Arguments)
}
$script:sync.Form = [pscustomobject]@{ Dispatcher = $dispatcher }
$script:capturedGetInstalledScriptBlock = $null
$script:capturedGetInstalledParameters = @{}
Mock Test-WinUtilPackageManager { "installed" }
Mock Invoke-WinUtilCurrentSystem { @("WPFInstallGit") }
Mock Set-WinUtilTaskbaritem { }
Mock Write-WinUtilLog { }
Mock Write-Warning { }
Mock Invoke-WPFRunspace {
$script:capturedGetInstalledScriptBlock = $ScriptBlock
foreach ($parameter in $ParameterList) {
$script:capturedGetInstalledParameters[$parameter[0]] = $parameter[1]
}
}
}
AfterEach {
Remove-Variable -Name sync -Scope Script -ErrorAction SilentlyContinue
Remove-Variable -Name sync -Scope Global -ErrorAction SilentlyContinue
Remove-Variable -Name capturedGetInstalledScriptBlock -Scope Script -ErrorAction SilentlyContinue
Remove-Variable -Name capturedGetInstalledParameters -Scope Script -ErrorAction SilentlyContinue
}
It "updates the selected app model, checkbox, count, and popup" {
Invoke-WPFGetInstalled -CheckBox "winget"
& $script:capturedGetInstalledScriptBlock `
-checkbox "winget" `
-managerPreference "Winget" `
-operation $script:capturedGetInstalledParameters.operation `
-completeAction $script:capturedGetInstalledParameters.completeAction
@($script:sync.selectedApps) | Should -Be @("WPFInstallGit")
$script:sync.WPFInstallGit.IsChecked | Should -BeTrue
$script:sync.WPFselectedAppsButton.Content | Should -Be "Selected Apps: 1"
$script:sync.selectedAppsstackPanel.Children.Count | Should -Be 1
$script:sync.selectedAppsstackPanel.Children[0].Key | Should -Be "WPFInstallGit"
}
It "clears the running state when detection fails" {
Mock Invoke-WinUtilCurrentSystem { throw "detection failed" }
Invoke-WPFGetInstalled -CheckBox "winget"
& $script:capturedGetInstalledScriptBlock `
-checkbox "winget" `
-managerPreference "Winget" `
-operation $script:capturedGetInstalledParameters.operation `
-completeAction $script:capturedGetInstalledParameters.completeAction
$script:sync.ProcessRunning | Should -BeFalse
Should -Invoke -CommandName Write-WinUtilLog -Times 1 -Exactly -ParameterFilter {
$Level -eq "ERROR" -and
$Component -eq "Install" -and
$Message -eq "Get installed state failed: detection failed"
}
Should -Invoke -CommandName Set-WinUtilTaskbaritem -Times 1 -Exactly -ParameterFilter { $state -eq "None" }
}
It "clears the running state when the worker cannot be queued" {
Mock Invoke-WPFRunspace { throw "queue failed" }
Invoke-WPFGetInstalled -CheckBox "winget"
$script:sync.ProcessRunning | Should -BeFalse
Should -Invoke -CommandName Write-WinUtilLog -Times 1 -Exactly -ParameterFilter {
$Level -eq "ERROR" -and
$Component -eq "Install" -and
$Message -eq "Get installed state failed: queue failed"
}
Should -Invoke -CommandName Set-WinUtilTaskbaritem -Times 1 -Exactly -ParameterFilter { $state -eq "None" }
} }
} }
-1
View File
@@ -435,7 +435,6 @@ Describe "XAML and sync wiring" {
"appPopup", "appPopup",
"appPopupSelectedApp", "appPopupSelectedApp",
"ItemsControl", "ItemsControl",
"InstalledPrograms",
"ImportInProgress", "ImportInProgress",
"ScriptsInstallPrograms", "ScriptsInstallPrograms",
"keys", "keys",
+53 -13
View File
@@ -6,7 +6,7 @@
xmlns:local="clr-namespace:WinUtility" xmlns:local="clr-namespace:WinUtility"
WindowStartupLocation="CenterScreen" WindowStartupLocation="CenterScreen"
UseLayoutRounding="True" UseLayoutRounding="True"
WindowStyle="None" WindowStyle="SingleBorderWindow"
Width="Auto" Width="Auto"
Height="Auto" Height="Auto"
MinWidth="800" MinWidth="800"
@@ -964,6 +964,39 @@
</Setter.Value> </Setter.Value>
</Setter> </Setter>
</Style> </Style>
<!-- Filter Chip Style — used by the Install tab category filter buttons -->
<Style x:Key="FilterChipStyle" TargetType="Button" BasedOn="{StaticResource {x:Type Button}}">
<Setter Property="Margin" Value="2"/>
<Setter Property="Padding" Value="12,0,12,0"/>
<Setter Property="Width" Value="Auto"/>
<Setter Property="Cursor" Value="Hand"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<Border Name="ChipBorder"
Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{DynamicResource ButtonBorderThickness}"
CornerRadius="{DynamicResource ButtonCornerRadius}"
Padding="{TemplateBinding Padding}">
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsPressed" Value="True">
<Setter TargetName="ChipBorder" Property="Background" Value="{DynamicResource ButtonBackgroundPressedColor}"/>
</Trigger>
<Trigger Property="IsMouseOver" Value="True">
<Setter TargetName="ChipBorder" Property="Background" Value="{DynamicResource ButtonBackgroundMouseoverColor}"/>
</Trigger>
<Trigger Property="IsEnabled" Value="False">
<Setter TargetName="ChipBorder" Property="Background" Value="{DynamicResource ButtonBackgroundSelectedColor}"/>
<Setter Property="Foreground" Value="DimGray"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Window.Resources> </Window.Resources>
<Grid Background="{DynamicResource MainBackgroundColor}" ShowGridLines="False" Name="WPFMainGrid" Width="Auto" Height="Auto" HorizontalAlignment="Stretch"> <Grid Background="{DynamicResource MainBackgroundColor}" ShowGridLines="False" Name="WPFMainGrid" Width="Auto" Height="Auto" HorizontalAlignment="Stretch">
<Grid.RowDefinitions> <Grid.RowDefinitions>
@@ -1282,16 +1315,23 @@
<!-- Quick Category Search Chips --> <!-- Quick Category Search Chips -->
<WrapPanel Grid.Row="0" Orientation="Horizontal" Margin="5,5,5,5" Name="WPFSearchChips"> <WrapPanel Grid.Row="0" Orientation="Horizontal" Margin="5,5,5,5" Name="WPFSearchChips">
<Button Name="WPFSearchChipAll" Content="All" Width="Auto" Height="Auto" Margin="2"/> <TextBlock Text="Filters"
<Button Name="WPFSearchChipBrowsers" Content="Browsers" Width="Auto" Height="Auto" Margin="2"/> FontSize="{DynamicResource HeaderFontSize}"
<Button Name="WPFSearchChipCommunications" Content="Communications" Width="Auto" Height="Auto" Margin="2"/> FontFamily="{DynamicResource HeaderFontFamily}"
<Button Name="WPFSearchChipDevelopment" Content="Development" Width="Auto" Height="Auto" Margin="2"/> Foreground="{DynamicResource LabelboxForegroundColor}"
<Button Name="WPFSearchChipGames" Content="Games" Width="Auto" Height="Auto" Margin="2"/> Background="Transparent"
<Button Name="WPFSearchChipMicrosoftTools" Content="Microsoft Tools" Width="Auto" Height="Auto" Margin="2"/> VerticalAlignment="Center"
<Button Name="WPFSearchChipMultimediaTools" Content="Multimedia Tools" Width="Auto" Height="Auto" Margin="2"/> Margin="15,0,8,0"/>
<Button Name="WPFSearchChipProTools" Content="Pro Tools" Width="Auto" Height="Auto" Margin="2"/> <Button Name="WPFSearchChipAll" Content="All" Style="{StaticResource FilterChipStyle}"/>
<Button Name="WPFSearchChipSelfhostedTools" Content="Selfhosted Tools" Width="Auto" Height="Auto" Margin="2"/> <Button Name="WPFSearchChipBrowsers" Content="Browsers" Style="{StaticResource FilterChipStyle}"/>
<Button Name="WPFSearchChipUtilities" Content="Utilities" Width="Auto" Height="Auto" Margin="2"/> <Button Name="WPFSearchChipCommunications" Content="Communications" Style="{StaticResource FilterChipStyle}"/>
<Button Name="WPFSearchChipDevelopment" Content="Development" Style="{StaticResource FilterChipStyle}"/>
<Button Name="WPFSearchChipGames" Content="Games" Style="{StaticResource FilterChipStyle}"/>
<Button Name="WPFSearchChipMicrosoftTools" Content="Microsoft Tools" Style="{StaticResource FilterChipStyle}"/>
<Button Name="WPFSearchChipMultimediaTools" Content="Multimedia Tools" Style="{StaticResource FilterChipStyle}"/>
<Button Name="WPFSearchChipProTools" Content="Pro Tools" Style="{StaticResource FilterChipStyle}"/>
<Button Name="WPFSearchChipSelfhostedTools" Content="Selfhosted Tools" Style="{StaticResource FilterChipStyle}"/>
<Button Name="WPFSearchChipUtilities" Content="Utilities" Style="{StaticResource FilterChipStyle}"/>
</WrapPanel> </WrapPanel>
<Grid Grid.Row="1" Margin="{DynamicResource TabContentMargin}"> <Grid Grid.Row="1" Margin="{DynamicResource TabContentMargin}">
@@ -1326,14 +1366,14 @@
<StackPanel Background="{DynamicResource MainBackgroundColor}" Orientation="Vertical" Grid.Row="0" Grid.Column="0" Grid.ColumnSpan="2" Margin="5"> <StackPanel Background="{DynamicResource MainBackgroundColor}" Orientation="Vertical" Grid.Row="0" Grid.Column="0" Grid.ColumnSpan="2" Margin="5">
<Label Content="Recommended Selections:" FontSize="{DynamicResource FontSize}" VerticalAlignment="Center" Margin="2"/> <Label Content="Recommended Selections:" FontSize="{DynamicResource FontSize}" VerticalAlignment="Center" Margin="2"/>
<StackPanel Orientation="Horizontal" HorizontalAlignment="Left" Margin="0,2,0,0"> <WrapPanel Orientation="Horizontal" HorizontalAlignment="Left" Margin="0,2,0,0">
<Button Name="WPFstandard" Content=" Standard " Margin="2" Width="{DynamicResource ButtonWidth}" Height="{DynamicResource ButtonHeight}"/> <Button Name="WPFstandard" Content=" Standard " Margin="2" Width="{DynamicResource ButtonWidth}" Height="{DynamicResource ButtonHeight}"/>
<Button Name="WPFminimal" Content=" Minimal " Margin="2" Width="{DynamicResource ButtonWidth}" Height="{DynamicResource ButtonHeight}"/> <Button Name="WPFminimal" Content=" Minimal " Margin="2" Width="{DynamicResource ButtonWidth}" Height="{DynamicResource ButtonHeight}"/>
<Button Name="WPFAdvanced" Content=" Advanced " Margin="2" Width="{DynamicResource ButtonWidth}" Height="{DynamicResource ButtonHeight}"/> <Button Name="WPFAdvanced" Content=" Advanced " Margin="2" Width="{DynamicResource ButtonWidth}" Height="{DynamicResource ButtonHeight}"/>
<Button Name="WPFClearTweaksSelection" Content=" Clear " Margin="2" Width="{DynamicResource ButtonWidth}" Height="{DynamicResource ButtonHeight}"/> <Button Name="WPFClearTweaksSelection" Content=" Clear " Margin="2" Width="{DynamicResource ButtonWidth}" Height="{DynamicResource ButtonHeight}"/>
<Button Name="WPFGetInstalledTweaks" Content=" Get Installed Tweaks " Margin="2" Width="{DynamicResource ButtonWidth}" Height="{DynamicResource ButtonHeight}"/> <Button Name="WPFGetInstalledTweaks" Content=" Get Installed Tweaks " Margin="2" Width="{DynamicResource ButtonWidth}" Height="{DynamicResource ButtonHeight}"/>
<Button Name="WPFAppxRemoval" Content=" AppX Removal " Margin="2" Width="{DynamicResource ButtonWidth}" Height="{DynamicResource ButtonHeight}"/> <Button Name="WPFAppxRemoval" Content=" AppX Removal " Margin="2" Width="{DynamicResource ButtonWidth}" Height="{DynamicResource ButtonHeight}"/>
</StackPanel> </WrapPanel>
</StackPanel> </StackPanel>
<Grid Name="tweakspanel" Grid.Row="1"> <Grid Name="tweakspanel" Grid.Row="1">