mirror of
https://github.com/microsoft/PowerToys.git
synced 2026-01-09 05:47:10 +01:00
Compare commits
33 Commits
v0.94.2
...
cinnamon-m
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
bec6693359 | ||
|
|
d777e61c6f | ||
|
|
0f0a3f155a | ||
|
|
4e7871b0bf | ||
|
|
74b6140911 | ||
|
|
fb6f620f9d | ||
|
|
7fb2ff5119 | ||
|
|
95b19739f6 | ||
|
|
c5c6a3658f | ||
|
|
549d30892d | ||
|
|
566e35af1e | ||
|
|
4ced93ce67 | ||
|
|
05ae867ac8 | ||
|
|
377d134d40 | ||
|
|
be160d93f5 | ||
|
|
0c45799bb5 | ||
|
|
077af2c74b | ||
|
|
a0ac7efd2d | ||
|
|
3882db4479 | ||
|
|
eb35b3a249 | ||
|
|
5daec13bc4 | ||
|
|
ef6f4b2c3d | ||
|
|
336cdaff9b | ||
|
|
447118ab70 | ||
|
|
7455d63bb5 | ||
|
|
bb6b36af3f | ||
|
|
3ebf0f741a | ||
|
|
e8e1431e15 | ||
|
|
2d35fd8530 | ||
|
|
13d950a40a | ||
|
|
3eb8f96f3e | ||
|
|
11218ea4d8 | ||
|
|
8258f2ab6f |
5
.github/actions/spell-check/expect.txt
vendored
5
.github/actions/spell-check/expect.txt
vendored
@@ -70,6 +70,7 @@ APPMODEL
|
||||
APPNAME
|
||||
appref
|
||||
appsettings
|
||||
appsfeatures
|
||||
appwindow
|
||||
appwiz
|
||||
appxpackage
|
||||
@@ -1025,8 +1026,6 @@ MYICON
|
||||
NAMECHANGE
|
||||
namespaceanddescendants
|
||||
nao
|
||||
Navigatable
|
||||
NavigatablePage
|
||||
NCACTIVATE
|
||||
ncc
|
||||
NCCALCSIZE
|
||||
@@ -1317,6 +1316,7 @@ PRODUCTVERSION
|
||||
Progman
|
||||
programdata
|
||||
projectname
|
||||
projitems
|
||||
PROPERTYKEY
|
||||
Propset
|
||||
PROPVARIANT
|
||||
@@ -1396,6 +1396,7 @@ regkey
|
||||
regroot
|
||||
regsvr
|
||||
REINSTALLMODE
|
||||
releaseblog
|
||||
reloadable
|
||||
Relogger
|
||||
remappings
|
||||
|
||||
4
.github/actions/spell-check/patterns.txt
vendored
4
.github/actions/spell-check/patterns.txt
vendored
@@ -260,3 +260,7 @@ Process Process
|
||||
# ZoomIt menu items with accelerator keys
|
||||
E&xit
|
||||
St&yle
|
||||
|
||||
# This matches a relative clause where the relative pronoun "that" is omitted.
|
||||
# Example: "Gets or sets the window the TitleBar should configure."
|
||||
\bthe\s+\w+\s+the\b
|
||||
|
||||
20
.github/workflows/manual-batch-issue-deduplication.yml
vendored
Normal file
20
.github/workflows/manual-batch-issue-deduplication.yml
vendored
Normal file
@@ -0,0 +1,20 @@
|
||||
name: Manual Batch Issue Deduplication
|
||||
|
||||
on:
|
||||
workflow_dispatch: # Only runs when manually triggered
|
||||
|
||||
jobs:
|
||||
batch-deduplicate:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Batch Deduplicate Issues
|
||||
uses: pelikhan/action-genai-issue-dedup@v0
|
||||
with:
|
||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
label-duplicate: "potential duplicate"
|
||||
comment-duplicate: true
|
||||
close-duplicate: false
|
||||
batch-size: 100
|
||||
since: '2019-05-05T00:00:00Z' # Process issues dating back to 2019
|
||||
duplicate-comment-template: "This issue appears to be a duplicate of #{duplicate_issue_number}."
|
||||
# Add other action-specific inputs if needed
|
||||
@@ -132,39 +132,6 @@ steps:
|
||||
ciPolicyFile: '$(build.sourcesdirectory)\.pipelines\CIPolicy.xml'
|
||||
|
||||
#### END MSI
|
||||
|
||||
#### BUILDING AND SIGNING SilentFilesInUseBAFunction DLL
|
||||
- task: VSBuild@1
|
||||
displayName: ${{replace(replace(parameters.buildUserInstaller,'True','👤'),'False','💻')}} Build SilentFilesInUseBAFunction
|
||||
inputs:
|
||||
solution: "**/installer/PowerToysSetup.sln"
|
||||
vsVersion: 17.0
|
||||
msbuildArgs: >-
|
||||
/t:SilentFilesInUseBAFunction
|
||||
/p:RunBuildEvents=true;PerUser=${{parameters.buildUserInstaller}};RestorePackagesConfig=true;CIBuild=true
|
||||
/p:InstallerSuffix=${{ parameters.installerSuffix }}
|
||||
-restore -graph
|
||||
/bl:$(LogOutputDirectory)\installer-$(InstallerBuildSlug)-SilentFilesInUseBAFunction.binlog
|
||||
${{ parameters.additionalBuildOptions }}
|
||||
platform: $(BuildPlatform)
|
||||
configuration: $(BuildConfiguration)
|
||||
clean: false # don't undo our hard work above by deleting the msi
|
||||
msbuildArchitecture: x64
|
||||
maximumCpuCount: true
|
||||
|
||||
- ${{ if eq(parameters.codeSign, true) }}:
|
||||
- template: steps-esrp-signing.yml
|
||||
parameters:
|
||||
displayName: ${{replace(replace(parameters.buildUserInstaller,'True','👤'),'False','💻')}} Sign SilentFilesInUseBAFunction
|
||||
signingIdentity: ${{ parameters.signingIdentity }}
|
||||
inputs:
|
||||
FolderPath: 'installer/$(BuildPlatform)/$(BuildConfiguration)'
|
||||
signType: batchSigning
|
||||
batchSignPolicyFile: '$(build.sourcesdirectory)\.pipelines\ESRPSigning_installer.json'
|
||||
ciPolicyFile: '$(build.sourcesdirectory)\.pipelines\CIPolicy.xml'
|
||||
|
||||
#### END BUILDING AND SIGNING SilentFilesInUseBAFunction DLL
|
||||
|
||||
#### BOOTSTRAP BUILDING AND SIGNING
|
||||
- task: VSBuild@1
|
||||
displayName: ${{replace(replace(parameters.buildUserInstaller,'True','👤'),'False','💻')}} Build VNext Bootstrapper
|
||||
@@ -181,7 +148,7 @@ steps:
|
||||
${{ parameters.additionalBuildOptions }}
|
||||
platform: $(BuildPlatform)
|
||||
configuration: $(BuildConfiguration)
|
||||
clean: false # don't undo our hard work above by deleting the MSI nor SilentFilesInUseBAFunction
|
||||
clean: false # don't undo our hard work above by deleting the MSI
|
||||
msbuildArchitecture: x64
|
||||
maximumCpuCount: true
|
||||
|
||||
|
||||
199
README.md
199
README.md
@@ -35,19 +35,19 @@ Microsoft PowerToys is a set of utilities for power users to tune and streamline
|
||||
Go to the [Microsoft PowerToys GitHub releases page][github-release-link] and click on `Assets` at the bottom to show the files available in the release. Please use the appropriate PowerToys installer that matches your machine's architecture and install scope. For most, it is `x64` and per-user.
|
||||
|
||||
<!-- items that need to be updated release to release -->
|
||||
[github-next-release-work]: https://github.com/microsoft/PowerToys/issues?q=is%3Aissue+milestone%3A%22PowerToys+0.94%22
|
||||
[github-current-release-work]: https://github.com/microsoft/PowerToys/issues?q=is%3Aissue+milestone%3A%22PowerToys+0.93%22
|
||||
[ptUserX64]: https://github.com/microsoft/PowerToys/releases/download/v0.93.0/PowerToysUserSetup-0.93.0-x64.exe
|
||||
[ptUserArm64]: https://github.com/microsoft/PowerToys/releases/download/v0.93.0/PowerToysUserSetup-0.93.0-arm64.exe
|
||||
[ptMachineX64]: https://github.com/microsoft/PowerToys/releases/download/v0.93.0/PowerToysSetup-0.93.0-x64.exe
|
||||
[ptMachineArm64]: https://github.com/microsoft/PowerToys/releases/download/v0.93.0/PowerToysSetup-0.93.0-arm64.exe
|
||||
[github-next-release-work]: https://github.com/microsoft/PowerToys/issues?q=is%3Aissue+milestone%3A%22PowerToys+0.95%22
|
||||
[github-current-release-work]: https://github.com/microsoft/PowerToys/issues?q=is%3Aissue+milestone%3A%22PowerToys+0.94%22
|
||||
[ptUserX64]: https://github.com/microsoft/PowerToys/releases/download/v0.94.0/PowerToysUserSetup-0.94.0-x64.exe
|
||||
[ptUserArm64]: https://github.com/microsoft/PowerToys/releases/download/v0.94.0/PowerToysUserSetup-0.94.0-arm64.exe
|
||||
[ptMachineX64]: https://github.com/microsoft/PowerToys/releases/download/v0.94.0/PowerToysSetup-0.94.0-x64.exe
|
||||
[ptMachineArm64]: https://github.com/microsoft/PowerToys/releases/download/v0.94.0/PowerToysSetup-0.94.0-arm64.exe
|
||||
|
||||
| Description | Filename |
|
||||
|----------------|----------|
|
||||
| Per user - x64 | [PowerToysUserSetup-0.93.0-x64.exe][ptUserX64] |
|
||||
| Per user - ARM64 | [PowerToysUserSetup-0.93.0-arm64.exe][ptUserArm64] |
|
||||
| Machine wide - x64 | [PowerToysSetup-0.93.0-x64.exe][ptMachineX64] |
|
||||
| Machine wide - ARM64 | [PowerToysSetup-0.93.0-arm64.exe][ptMachineArm64] |
|
||||
| Per user - x64 | [PowerToysUserSetup-0.94.0-x64.exe][ptUserX64] |
|
||||
| Per user - ARM64 | [PowerToysUserSetup-0.94.0-arm64.exe][ptUserArm64] |
|
||||
| Machine wide - x64 | [PowerToysSetup-0.94.0-x64.exe][ptMachineX64] |
|
||||
| Machine wide - ARM64 | [PowerToysSetup-0.94.0-arm64.exe][ptMachineArm64] |
|
||||
|
||||
This is our preferred method.
|
||||
|
||||
@@ -93,118 +93,145 @@ For guidance on developing for PowerToys, please read the [developer docs](./doc
|
||||
|
||||
Our [prioritized roadmap][roadmap] of features and utilities that the core team is focusing on.
|
||||
|
||||
### 0.93 - Aug 2025 Update
|
||||
### 0.94 - Sep 2025 Update
|
||||
|
||||
In this release, we focused on new features, stability, optimization improvements, and automation.
|
||||
|
||||
For an in-depth look at the latest changes, visit the [release blog](https://aka.ms/powertoys-releaseblog).
|
||||
|
||||
**✨Highlights**
|
||||
|
||||
- PowerToys settings debuts a modern, card-based dashboard with clearer descriptions and faster navigation for a streamlined user experience.
|
||||
- Command Palette had over 99 issues resolved, including bringing back Clipboard History, adding context menu shortcuts, pinning favorite apps, and supporting history in Run.
|
||||
- Command Palette reduced its startup memory usage by ~15%, load time by ~40%, built-in extensions loading time by ~70%, and installation size by ~55%—all due to using the full Ahead-of-Time (AOT) compilation mode in Windows App SDK.
|
||||
- Peek now supports instant previews and embedded thumbnails for Binary G-code (.bgcode) 3D printing files, making it easy to inspect models at a glance. Thanks [@pedrolamas](https://github.com/pedrolamas)!
|
||||
- Mouse Utilities introduces a new spotlight highlighting mode that dims the screen and draws attention to your cursor, perfect for presentations.
|
||||
- Test coverage improvements for multiple PowerToys modules including Command Palette, Advanced Paste, Peek, Text Extractor, and PowerRename — ensuring better reliability and quality, with over 600 new unit tests (mostly for Command Palette) and doubled UI automation coverage.
|
||||
- PowerToys Settings added a Settings search with fuzzy matching, suggestions, a results page, and UX polish to make finding options faster.
|
||||
- A comprehensive hotkey conflict detection system was introduced in Settings to surface and help resolve conflicting shortcuts. Note that the default hotkey settings (Win+Ctrl+Shift+T, Win+Ctrl+V, Win+Ctrl+T, Win+Shift+T) may overlap with existing Windows system shortcuts. This is expected. You can resolve the conflict by assigning different hotkeys.
|
||||
- Mouse Utilities added a “Gliding cursor” accessibility feature to Mouse Pointer Crosshairs for single‑button cursor movement and clicking. Thanks [@mikehall-ms](https://github.com/mikehall-ms)!
|
||||
- The installer was upgraded to WiX 5 after WiX 3 reached end-of-life; this move improved installer security, reliability, and community support.
|
||||
- Tons of bug fixes and improvements for Command Palette, including visual updates and new support for filters on ListPages (handy for extension developers).
|
||||
- Hosts Editor now has a “No leading spaces” option so active host entries can start at column 0 even if others are disabled. Thanks [@mohammed-saalim](https://github.com/mohammed-saalim)!
|
||||
- Context menu registration was moved from the installer to runtime to avoid loading disabled modules (runtime registrations).
|
||||
- Quick Accent now supports Maltese, and frequently used accents appear first (and are remembered across sessions). Thanks [@rovercoder](https://github.com/rovercoder)! [@davidegiacometti](https://github.com/davidegiacometti)!
|
||||
|
||||
### Always On Top
|
||||
|
||||
- Fixed the border hover cursor so it shows the arrow instead of the wait cursor. Thanks [@davidegiacometti](https://github.com/davidegiacometti)!
|
||||
|
||||
### Command Palette
|
||||
|
||||
- Ensured screen readers are notified when the selected item in the list changes for better accessibility.
|
||||
- Fixed command title changes not being properly notified to screen readers. Thanks [@jiripolasek](https://github.com/jiripolasek)!
|
||||
- Made icon controls excluded from keyboard navigation by default for better accessibility. Thanks [@jiripolasek](https://github.com/jiripolasek)!
|
||||
- Improved UI design with better text sizing and alignment.
|
||||
- Fixed keyboard shortcuts to work better in text boxes and context menus.
|
||||
- Added right-click context menus with critical command styling and separators.
|
||||
- Improved various context menu issues, improving item selection, handling of long titles, search bar text scaling, initial item behavior, and primary button functionality.
|
||||
- Fixed context menu crashes with better type handling.
|
||||
- Fixed "Reload" command to work with both uppercase and lowercase letters.
|
||||
- Added mouse back button support for easier navigation. Thanks [@jiripolasek](https://github.com/jiripolasek)!
|
||||
- Fixed Alt+Left Arrow navigation not working when search box contains text. Thanks [@jiripolasek](https://github.com/jiripolasek)!
|
||||
- Updated back button tooltip to show keyboard shortcut information. Thanks [@jiripolasek](https://github.com/jiripolasek)!
|
||||
- Fixed Command Palette window not appearing properly when activated. Thanks [@jiripolasek](https://github.com/jiripolasek)!
|
||||
- Fixed Command Palette window staying hidden from taskbar after File Explorer restarts. Thanks [@jiripolasek](https://github.com/jiripolasek)!
|
||||
- Fixed window focus not returning to previous app properly.
|
||||
- Fixed Command Palette window to always appear on top when shown and move to bottom when hidden. Thanks [@jiripolasek](https://github.com/jiripolasek)!
|
||||
- Fixed window hiding to properly work on UI thread. Thanks [@jiripolasek](https://github.com/jiripolasek)!
|
||||
- Fixed crashes and improved stability with better synchronization of Command list updates. Thanks [@jiripolasek](https://github.com/jiripolasek)!
|
||||
- Improved extension disposal with better error handling to prevent crashes. Thanks [@jiripolasek](https://github.com/jiripolasek)!
|
||||
- Improved stability by fixing a UI threading issue when loading more results, preventing possible crashes and ensuring the loading state resets if loading fails. Thanks [@jiripolasek](https://github.com/jiripolasek)!
|
||||
- Enhanced icon loading stability with better exception handling. Thanks [@jiripolasek](https://github.com/jiripolasek)!
|
||||
- Added thread safety to recent commands to prevent crashes. Thanks [@MaoShengelia](https://github.com/MaoShengelia)!
|
||||
- Fixed acrylic (frosted glass) system backdrop display issues by ensuring proper UI thread handling. Thanks [@jiripolasek](https://github.com/jiripolasek)!
|
||||
- Applied single-click activation only to pointer input; keyboard always activates immediately. Thanks [@jiripolasek](https://github.com/jiripolasek)!
|
||||
- Let context menus open at the cursor by removing window-bound constraints. Thanks [@jiripolasek](https://github.com/jiripolasek)!
|
||||
- Made error messages clearer with timestamps, HRESULTs, and full details for easier diagnosis. Thanks [@jiripolasek](https://github.com/jiripolasek)!
|
||||
- Prevented crashes and improved robustness when updating providers without commands. Thanks [@jiripolasek](https://github.com/jiripolasek)!
|
||||
- Ensured the Settings window reliably comes to the front when opened. Thanks [@jiripolasek](https://github.com/jiripolasek)!
|
||||
- Replaced the Clipboard History icon with a colorful Fluent icon. Thanks [@jiripolasek](https://github.com/jiripolasek)!
|
||||
- Hardened ContentIcon to avoid duplicate parenting and improve diagnostics. Thanks [@jiripolasek](https://github.com/jiripolasek)!
|
||||
- Standardized null checks using C# pattern matching for safer behavior.
|
||||
- Improved accessibility by focusing the activation shortcut dialog and making text reachable. Thanks [@chatasweetie](https://github.com/chatasweetie)!
|
||||
- Moved the extension SDK to a stable Windows SDK and cleaned up message namespaces.
|
||||
- Added path shortcuts: ~ to home, and / or \\ to system root, plus UNC support. Thanks [@davidegiacometti](https://github.com/davidegiacometti)!
|
||||
- Fixed a race in cancellation handling to avoid InvalidOperationException. Thanks [@jiripolasek](https://github.com/jiripolasek)!
|
||||
- Aligned separator styling with WinUI 3 for consistent visuals. Thanks [@jiripolasek](https://github.com/jiripolasek)!
|
||||
- Added ARM64 PDBs to the Extensions SDK NuGet for better debugging.
|
||||
- Added single-select filters to DynamicListPage and updated Windows Services sample.
|
||||
- Updated main page placeholder text to better describe what can be searched. Thanks [@jiripolasek](https://github.com/jiripolasek)!
|
||||
- Removed explicit WinAppSDK/WebView2 dependencies from toolkit and API. Thanks [@rluengen](https://github.com/rluengen)!
|
||||
- Added a local keyboard hook to handle the GoBack key reliably. Thanks [@jiripolasek](https://github.com/jiripolasek)!
|
||||
- Propagated alias changes safely and resolved conflicts across view models.
|
||||
- Allowed providers to override Dispose with a virtual method.
|
||||
- Fixed memory leaks by cleaning up removed or cancelled list items.
|
||||
- Sorted DateTime extension results by relevance for better usability.
|
||||
- Reduced search text “jiggling” by avoiding redundant change notifications.
|
||||
- Centralized automation notifications in a UIHelper for better accessibility. Thanks [@chatasweetie](https://github.com/chatasweetie)!
|
||||
- Preserved Adaptive Card action types during trimming via DynamicDependency.
|
||||
- Added an acrylic backdrop and refined styling to the context menu. Thanks [@jiripolasek](https://github.com/jiripolasek)!
|
||||
- Prevented disposed pages and Settings windows from handling stale messages. Thanks [@jiripolasek](https://github.com/jiripolasek)!
|
||||
- Made the extension API easier to evolve without breaking clients.
|
||||
- Added “evil” sample pages to help reproduce tricky bugs.
|
||||
- Fixed WinGet trim-safety issues by replacing LINQ with manual iteration.
|
||||
- Cancelled stale list fetches to avoid older results overwriting newer ones in CmdPal.
|
||||
|
||||
### Command Palette extensions
|
||||
|
||||
- Added settings to each provider to control which fallback commands are enabled. Thanks [@jiripolasek](https://github.com/jiripolasek)! for fixing a regression in this feature.
|
||||
- Added sample code showing how Command Palette extensions can track when their pages are loaded or unloaded. [Check it out here](./src/modules/cmdpal/ext/SamplePagesExtension/OnLoadPage.cs).
|
||||
- Fixed *Calculator* to accept regular spaces in numbers that use space separators. Thanks [@PesBandi](https://github.com/PesBandi)!
|
||||
- Added a new setting to *Calculator* to make "Copy" the primary button (replacing “Save”) and enable "Close on Enter", streamlining the workflow. Thanks [@PesBandi](https://github.com/PesBandi)!
|
||||
- Improved *Apps* indexing error handling and removed obsolete code. Thanks [@davidegiacometti](https://github.com/davidegiacometti)!
|
||||
- Prevented apps from showing in search when the *Apps* extension is disabled. Thanks [@jiripolasek](https://github.com/jiripolasek)!
|
||||
- Added ability to pin/unpin *Apps* using Ctrl+P shortcut.
|
||||
- Added keyboard shortcuts to the *Apps* context menu items for faster access.
|
||||
- Added all file context menu options to the *Apps* items context menu, making all file actions available there for better functionality.
|
||||
- Streamlined All *Apps* extension settings by removing redundant descriptions, making the UI clearer.
|
||||
- Added command history to the *Run* page for easier access to previous commands.
|
||||
- Fixed directory path handling in *Run* fallback for better file navigation.
|
||||
- Fixed URL fallback item hiding properly in *Web Search* extension when search query becomes invalid. Thanks [@jiripolasek](https://github.com/jiripolasek)!
|
||||
- Added proper empty state message for *Web Search* extension when no results found. Thanks [@jiripolasek](https://github.com/jiripolasek)!
|
||||
- Added fallback command to *Windows Settings* extension for better search results.
|
||||
- Re-enabled *Clipboard History* feature with proper window handling.
|
||||
- Improved *Add Bookmark* extension to automatically detect file, folder, or URL types without manual input.
|
||||
- Updated terminology from "Kill process" to "End task" in *Window Walker* for consistency with Windows.
|
||||
- Fixed minor grammar error in SamplePagesExtension code comments. Thanks [@purofle](https://github.com/purofle)!
|
||||
- Improved empty states and ranking logic for multiple extensions. Thanks [@htcfreek](https://github.com/htcfreek)!
|
||||
- Added app icons to the All Apps "Run" context command when available.
|
||||
- Restored missing builtin icons by standardizing extension dependencies.
|
||||
- Unblocked local deployment by adding WinAppSDK to two sample extensions.
|
||||
|
||||
### Hosts File Editor
|
||||
|
||||
- Added a "No leading spaces" option so active hosts entries can start at column 0 even when others are disabled. Thanks [@mohammed-saalim](https://github.com/mohammed-saalim)!
|
||||
|
||||
### Image Resizer
|
||||
|
||||
- Fixed Image Resizer localization by installing satellite resources under the WinUI 3 apps culture path.
|
||||
|
||||
### Mouse Utilities
|
||||
|
||||
- Added a new spotlight highlighting mode that creates a large transparent circle around your cursor with a backdrop effect, providing an alternative to the traditional circle highlight. Perfect for presentations where you want to focus attention on a specific area while dimming the rest of the screen.
|
||||
- Introduced "Gliding cursor" to control the pointer and click with a single hotkey for better accessibility. Thanks [@mikehall-ms](https://github.com/mikehall-ms)!
|
||||
|
||||
### Mouse Without Borders
|
||||
|
||||
- Blocked Easy Mouse from switching machines during fullscreen apps, with an allow-list for exceptions. Thanks [@dot-tb](https://github.com/dot-tb)!
|
||||
|
||||
### Peek
|
||||
|
||||
- Added preview and thumbnail support for Binary G-code (.bgcode) files used in 3D printing. You can now see embedded thumbnails and preview these compressed 3D printing files directly in Peek and File Explorer. Thanks [@pedrolamas](https://github.com/pedrolamas)!
|
||||
- Added Visual Studio shared project file types to XML preview and fixed bgcode handler registration. Thanks [@rezanid](https://github.com/rezanid)!
|
||||
- Fixes bgcode preview handler registration and events for reliable previews. Thanks [@pedrolamas](https://github.com/pedrolamas)!
|
||||
|
||||
### PowerRename
|
||||
|
||||
- Changed the Explorer accelerator key to PowErRename to avoid clashing with the New menu. Thanks [@aaron-ni](https://github.com/aaron-ni)!
|
||||
|
||||
### Quick Accent
|
||||
|
||||
- Added Vietnamese language support to Quick Accent, mappings for Vietnamese vowels (a, e, i, o, u, y) and the letter d. Thanks [@octastylos-pseudodipteros](https://github.com/octastylos-pseudodipteros)!
|
||||
- Remembered character usage across sessions so frequently used accents appear first. Thanks [@davidegiacometti](https://github.com/davidegiacometti)!
|
||||
- Added Maltese language support with specific characters and the Euro symbol. Thanks [@rovercoder](https://github.com/rovercoder)!
|
||||
- Reduced GPU usage issues by making the window Topmost only when the picker is visible. Thanks [@daverayment](https://github.com/daverayment)!
|
||||
|
||||
### Settings
|
||||
|
||||
- Completely redesigned the Settings dashboard with a modern card-based layout featuring organized sections for quick actions and shortcuts overview, replacing the old module list.
|
||||
- Rewrote setting descriptions to be more concise and follow Windows writing style guidelines, making them easier to understand.
|
||||
- Improved formatting and readability of release notes in the "What's New" section with better typography and spacing.
|
||||
- Added missing deep link support for various settings pages (Peek, Quick Accent, PowerToys Run, etc.) so you can jump directly to specific settings.
|
||||
- Resolved an issue where the settings page header would drift away from its position when resizing the settings window.
|
||||
- Resolved a settings crash related to incompatible property names in ZoomIt configuration.
|
||||
- Added telemetry to track usage of the new shortcut conflict detection workflow.
|
||||
- Moved the shutdown action from the title bar to a footer menu item with confirmation. Thanks [@davidegiacometti](https://github.com/davidegiacometti)!
|
||||
- Implemented comprehensive hotkey conflict detection with a dedicated resolution dialog.
|
||||
- Added branded visuals for Office and Copilot keys in the KeyVisual control.
|
||||
- Introduced Settings search with fuzzy matching and navigation to specific controls.
|
||||
- Corrected Spanish localization so product names like Awake remain in English across Settings and OOBE.
|
||||
- Simplified the Advanced Paste description in Settings for quicker reading and consistent capitalization. Thanks [@OldUser101](https://github.com/OldUser101)!
|
||||
- Localized conflict messages in the conflict window and dialog.
|
||||
|
||||
### Installer
|
||||
|
||||
- Upgraded the installer to WiX 5 with silent "Files in Use" handling for smoother winget installs.
|
||||
- Switched Win10 context menu modules to runtime registration and added cleanup on uninstall to avoid stale entries.
|
||||
|
||||
### Documentation
|
||||
|
||||
- Added detailed step-by-step instructions for first-time developers building the Command Palette module, including prerequisites and Visual Studio setup guidance. Thanks [@chatasweetie](https://github.com/chatasweetie)!
|
||||
- **Fixed Broken SDK Link**: Corrected a broken markdown link in the Command Palette SDK README that was pointing to an incorrect directory path. Thanks [@ChrisGuzak](https://github.com/ChrisGuzak)!
|
||||
- Added documentation for the "Open With Cursor" plugin that enables opening Visual Studio and VS Code recent files using Cursor AI. Thanks [@VictorNoxx](https://github.com/VictorNoxx)!
|
||||
- Added documentation for two new community plugins - Hotkeys plugin for creating custom keyboard shortcuts, and RandomGen plugin for generating random data like passwords, colors, and placeholder text. Thanks [@ruslanlap](https://github.com/ruslanlap)!
|
||||
- Adds docs for building the installer locally and testing winget installs.
|
||||
- Fixed a broken style guide link in developer documentation. Thanks [@denizmaral](https://github.com/denizmaral)!
|
||||
|
||||
### Development
|
||||
|
||||
- Updated .NET libraries to 9.0.8 for performance and security. Thanks [@snickler](https://github.com/snickler)!
|
||||
- Updated the spell check system to version 0.0.25 with better GitHub integration and SARIF reporting, plus fixed numerous spelling errors throughout the codebase including property names and documentation. Thanks [@jsoref](https://github.com/jsoref)!
|
||||
- Cleaned up spelling check configuration to eliminate false positives and excessive noise that was appearing in every pull request, making the development process smoother.
|
||||
- Replaced NuGet feed with Azure Artifacts for better package management.
|
||||
- Implemented configurable UI test pipeline that can use pre-built official releases instead of building everything from scratch, reducing test execution time from 2+ hours.
|
||||
- Replaced brittle pixel-by-pixel image comparison with perceptual hash (pHash) technology that's more robust to minor rendering differences - no more test failures due to anti-aliasing or compression artifacts.
|
||||
- Reduced CI/fuzzing/UI test timeouts from 4 hours to 90 minutes, dramatically improving developer feedback loops and preventing long waits when builds get stuck.
|
||||
- Standardized test project naming across the entire codebase and improved pipeline result identification by adding platform/install mode context to test run titles. Thanks [@khmyznikov](https://github.com/khmyznikov)!
|
||||
- Added comprehensive UI test suites for multiple PowerToys modules including Command Palette, Advanced Paste, Peek, Text Extractor, and PowerRename - ensuring better reliability and quality.
|
||||
- Enhanced UI test automation with command-line argument support, better session management, and improved element location methods using pattern matching to avoid failures from minor differences in exact matches.
|
||||
- Excluded test and coverage DLLs from BinSkim scans to cut false positives and speed up security analysis.
|
||||
- Simplified NOTICE maintenance by removing version numbers and filtering out Microsoft/System packages.
|
||||
- Improved NuGet dependency validation to prevent package downgrades and catch issues during restore.
|
||||
- Updated UTF.Unknown to a modern version to improve compatibility without breaking changes. Thanks [@304NotModified](https://github.com/304NotModified)!
|
||||
- Refreshed package catalog in CI before installing dependencies to prevent Linux workflow failures.
|
||||
- Refactored CmdPal tests with dependency injection and added coverage for queries and settings.
|
||||
- Added unit tests to verify Close on Enter swaps Copy/Save as expected. Thanks [@mohammed-saalim](https://github.com/mohammed-saalim)!
|
||||
- Added accessibility IDs to CmdPal UI for stable UI tests.
|
||||
- Rewrote system command tests with a new test base and cleaner patterns.
|
||||
- Added unit tests for WebSearch and Shell extensions with mockable settings.
|
||||
- Added unit tests and abstractions for Apps and Bookmarks extensions.
|
||||
- Cleans up AI‑generated tests; adds meaningful query tests across extensions.
|
||||
- Removed the obsolete debug dialog from Settings for a smoother developer loop.
|
||||
|
||||
### What is being planned over the next few releases
|
||||
|
||||
For [v0.94][github-next-release-work], we'll work on the items below:
|
||||
For [v0.95][github-next-release-work], we'll work on the items below:
|
||||
|
||||
- Continued Command Palette polish
|
||||
- Working on Shortcut Guide v2 (Thanks [@noraa-junker](https://github.com/noraa-junker)!)
|
||||
- Working on upgrading the installer to WiX 5
|
||||
- Working on shortcut conflict detection
|
||||
- Working on setting search
|
||||
- Upgrading Keyboard Manager's editor UI
|
||||
- UI tweaking utility with day/night theme switcher
|
||||
- DSC v3 support for top utilities
|
||||
- New UI automation tests
|
||||
- Stability, bug fixes
|
||||
|
||||
|
||||
@@ -26,7 +26,6 @@
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
<TargetName>SilentFilesInUseBAFunction</TargetName>
|
||||
<ProjectName>PowerToysSetupCustomActionsVNext</ProjectName>
|
||||
<ProjectModuleDefinitionFile>bafunctions.def</ProjectModuleDefinitionFile>
|
||||
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
|
||||
</PropertyGroup>
|
||||
@@ -92,31 +91,5 @@
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
|
||||
<!-- C++ source compile-specific things for Debug/Release configurations -->
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)'=='Debug'">
|
||||
<ClCompile>
|
||||
<PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)'=='Release'">
|
||||
<ClCompile>
|
||||
<PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<Optimization>MaxSpeed</Optimization>
|
||||
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
</Project>
|
||||
|
||||
@@ -32,17 +32,8 @@ namespace ManagedCommon
|
||||
/// <param name="isLocalLow">If the process using Logger is a low-privilege process.</param>
|
||||
public static void InitializeLogger(string applicationLogPath, bool isLocalLow = false)
|
||||
{
|
||||
string basePath;
|
||||
if (isLocalLow)
|
||||
{
|
||||
basePath = Environment.GetEnvironmentVariable("userprofile") + "\\appdata\\LocalLow\\Microsoft\\PowerToys" + applicationLogPath;
|
||||
}
|
||||
else
|
||||
{
|
||||
basePath = Constants.AppDataPath() + applicationLogPath;
|
||||
}
|
||||
|
||||
string versionedPath = Path.Combine(basePath, Version);
|
||||
string versionedPath = LogDirectoryPath(applicationLogPath, isLocalLow);
|
||||
string basePath = Path.GetDirectoryName(versionedPath);
|
||||
|
||||
if (!Directory.Exists(versionedPath))
|
||||
{
|
||||
@@ -59,6 +50,22 @@ namespace ManagedCommon
|
||||
Task.Run(() => DeleteOldVersionLogFolders(basePath, versionedPath));
|
||||
}
|
||||
|
||||
public static string LogDirectoryPath(string applicationLogPath, bool isLocalLow = false)
|
||||
{
|
||||
string basePath;
|
||||
if (isLocalLow)
|
||||
{
|
||||
basePath = Environment.GetEnvironmentVariable("userprofile") + "\\appdata\\LocalLow\\Microsoft\\PowerToys" + applicationLogPath;
|
||||
}
|
||||
else
|
||||
{
|
||||
basePath = Constants.AppDataPath() + applicationLogPath;
|
||||
}
|
||||
|
||||
string versionedPath = Path.Combine(basePath, Version);
|
||||
return versionedPath;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Deletes old version log folders, keeping only the current version's folder.
|
||||
/// </summary>
|
||||
@@ -115,13 +122,13 @@ namespace ManagedCommon
|
||||
{
|
||||
var exMessage =
|
||||
message + Environment.NewLine +
|
||||
ex.GetType() + ": " + ex.Message + Environment.NewLine;
|
||||
ex.GetType() + " (" + ex.HResult + "): " + ex.Message + Environment.NewLine;
|
||||
|
||||
if (ex.InnerException != null)
|
||||
{
|
||||
exMessage +=
|
||||
"Inner exception: " + Environment.NewLine +
|
||||
ex.InnerException.GetType() + ": " + ex.InnerException.Message + Environment.NewLine;
|
||||
ex.InnerException.GetType() + " (" + ex.HResult + "): " + ex.InnerException.Message + Environment.NewLine;
|
||||
}
|
||||
|
||||
exMessage +=
|
||||
|
||||
@@ -20,27 +20,14 @@
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="*" />
|
||||
</Grid.RowDefinitions>
|
||||
<Grid
|
||||
x:Name="titleBar"
|
||||
Height="32"
|
||||
ColumnSpacing="16">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition x:Name="LeftPaddingColumn" Width="0" />
|
||||
<ColumnDefinition x:Name="IconColumn" Width="Auto" />
|
||||
<ColumnDefinition x:Name="TitleColumn" Width="Auto" />
|
||||
<ColumnDefinition x:Name="RightPaddingColumn" Width="0" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<Image
|
||||
Grid.Column="1"
|
||||
Width="16"
|
||||
Height="16"
|
||||
VerticalAlignment="Center"
|
||||
Source="../Assets/EnvironmentVariables/EnvironmentVariables.ico" />
|
||||
<TextBlock
|
||||
x:Name="AppTitleTextBlock"
|
||||
Grid.Column="2"
|
||||
VerticalAlignment="Center"
|
||||
Style="{StaticResource CaptionTextBlockStyle}" />
|
||||
</Grid>
|
||||
<TitleBar x:Name="titleBar">
|
||||
<!-- This is a workaround for https://github.com/microsoft/microsoft-ui-xaml/issues/10374, once fixed we should just be using IconSource -->
|
||||
<TitleBar.LeftHeader>
|
||||
<ImageIcon
|
||||
Height="16"
|
||||
Margin="16,0,0,0"
|
||||
Source="/Assets/EnvironmentVariables/EnvironmentVariables.ico" />
|
||||
</TitleBar.LeftHeader>
|
||||
</TitleBar>
|
||||
</Grid>
|
||||
</winuiex:WindowEx>
|
||||
|
||||
@@ -4,22 +4,19 @@
|
||||
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
using EnvironmentVariables.Win32;
|
||||
using EnvironmentVariablesUILib;
|
||||
using EnvironmentVariablesUILib.Helpers;
|
||||
using EnvironmentVariablesUILib.ViewModels;
|
||||
using ManagedCommon;
|
||||
using Microsoft.UI.Dispatching;
|
||||
using Microsoft.UI.Windowing;
|
||||
using Microsoft.UI.Xaml;
|
||||
using Microsoft.UI.Xaml.Controls;
|
||||
using WinUIEx;
|
||||
|
||||
namespace EnvironmentVariables
|
||||
{
|
||||
/// <summary>
|
||||
/// An empty window that can be used on its own or navigated to within a Frame.
|
||||
/// </summary>
|
||||
public sealed partial class MainWindow : WindowEx
|
||||
{
|
||||
private EnvironmentVariablesMainPage MainPage { get; }
|
||||
@@ -34,8 +31,9 @@ namespace EnvironmentVariables
|
||||
AppWindow.SetIcon("Assets/EnvironmentVariables/EnvironmentVariables.ico");
|
||||
var loader = ResourceLoaderInstance.ResourceLoader;
|
||||
var title = App.GetService<IElevationHelper>().IsElevated ? loader.GetString("WindowAdminTitle") : loader.GetString("WindowTitle");
|
||||
|
||||
Title = title;
|
||||
AppTitleTextBlock.Text = title;
|
||||
titleBar.Title = title;
|
||||
|
||||
var handle = this.GetWindowHandle();
|
||||
RegisterWindow(handle);
|
||||
|
||||
@@ -20,30 +20,15 @@
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="*" />
|
||||
</Grid.RowDefinitions>
|
||||
<Grid
|
||||
x:Name="AppTitleBar"
|
||||
Height="32"
|
||||
ColumnSpacing="16">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition x:Name="LeftPaddingColumn" Width="0" />
|
||||
<ColumnDefinition x:Name="IconColumn" Width="Auto" />
|
||||
<ColumnDefinition x:Name="TitleColumn" Width="Auto" />
|
||||
<ColumnDefinition x:Name="RightDragColumn" Width="*" />
|
||||
<ColumnDefinition x:Name="RightPaddingColumn" Width="0" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<Image
|
||||
Grid.Column="1"
|
||||
Width="16"
|
||||
Height="16"
|
||||
VerticalAlignment="Center"
|
||||
Source="../Assets/FileLocksmith/Icon.ico" />
|
||||
<TextBlock
|
||||
x:Name="AppTitleTextBlock"
|
||||
Grid.Column="2"
|
||||
VerticalAlignment="Center"
|
||||
Style="{StaticResource CaptionTextBlockStyle}" />
|
||||
</Grid>
|
||||
|
||||
<TitleBar x:Name="titleBar">
|
||||
<!-- This is a workaround for https://github.com/microsoft/microsoft-ui-xaml/issues/10374, once fixed we should just be using IconSource -->
|
||||
<TitleBar.LeftHeader>
|
||||
<ImageIcon
|
||||
Height="16"
|
||||
Margin="16,0,0,0"
|
||||
Source="/Assets/FileLocksmith/Icon.ico" />
|
||||
</TitleBar.LeftHeader>
|
||||
</TitleBar>
|
||||
<views:MainPage x:Name="mainPage" Grid.Row="1" />
|
||||
</Grid>
|
||||
</winuiex:WindowEx>
|
||||
</winuiex:WindowEx>
|
||||
@@ -18,30 +18,16 @@ namespace FileLocksmithUI
|
||||
{
|
||||
InitializeComponent();
|
||||
mainPage.ViewModel.IsElevated = isElevated;
|
||||
SetTitleBar(titleBar);
|
||||
ExtendsContentIntoTitleBar = true;
|
||||
SetTitleBar(AppTitleBar);
|
||||
Activated += MainWindow_Activated;
|
||||
AppWindow.TitleBar.PreferredHeightOption = TitleBarHeightOption.Tall;
|
||||
AppWindow.SetIcon("Assets/FileLocksmith/Icon.ico");
|
||||
WindowHelpers.ForceTopBorder1PixelInsetOnWindows10(this.GetWindowHandle());
|
||||
|
||||
var loader = ResourceLoaderInstance.ResourceLoader;
|
||||
var title = isElevated ? loader.GetString("AppAdminTitle") : loader.GetString("AppTitle");
|
||||
Title = title;
|
||||
AppTitleTextBlock.Text = title;
|
||||
}
|
||||
|
||||
private void MainWindow_Activated(object sender, WindowActivatedEventArgs args)
|
||||
{
|
||||
if (args.WindowActivationState == WindowActivationState.Deactivated)
|
||||
{
|
||||
AppTitleTextBlock.Foreground =
|
||||
(SolidColorBrush)App.Current.Resources["WindowCaptionForegroundDisabled"];
|
||||
}
|
||||
else
|
||||
{
|
||||
AppTitleTextBlock.Foreground =
|
||||
(SolidColorBrush)App.Current.Resources["WindowCaptionForeground"];
|
||||
}
|
||||
titleBar.Title = title;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
|
||||
@@ -190,7 +190,7 @@
|
||||
TextWrapping="Wrap" />
|
||||
</ContentDialog>
|
||||
<ContentDialog x:Name="ProcessFilesListDialog" x:Uid="ProcessFilesListDialog">
|
||||
<ScrollViewer Padding="15" HorizontalScrollBarVisibility="Auto">
|
||||
<ScrollViewer Padding="16" HorizontalScrollBarVisibility="Auto">
|
||||
<TextBlock
|
||||
x:Name="ProcessFilesListDialogTextBlock"
|
||||
x:Uid="ProcessFilesListDialogTextBlock"
|
||||
|
||||
@@ -20,27 +20,14 @@
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="*" />
|
||||
</Grid.RowDefinitions>
|
||||
<Grid
|
||||
x:Name="titleBar"
|
||||
Height="32"
|
||||
ColumnSpacing="16">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition x:Name="LeftPaddingColumn" Width="0" />
|
||||
<ColumnDefinition x:Name="IconColumn" Width="Auto" />
|
||||
<ColumnDefinition x:Name="TitleColumn" Width="Auto" />
|
||||
<ColumnDefinition x:Name="RightPaddingColumn" Width="0" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<Image
|
||||
Grid.Column="1"
|
||||
Width="16"
|
||||
Height="16"
|
||||
VerticalAlignment="Center"
|
||||
Source="../Assets/Hosts/Hosts.ico" />
|
||||
<TextBlock
|
||||
x:Name="AppTitleTextBlock"
|
||||
Grid.Column="2"
|
||||
VerticalAlignment="Center"
|
||||
Style="{StaticResource CaptionTextBlockStyle}" />
|
||||
</Grid>
|
||||
<TitleBar x:Name="titleBar">
|
||||
<!-- This is a workaround for https://github.com/microsoft/microsoft-ui-xaml/issues/10374, once fixed we should just be using IconSource -->
|
||||
<TitleBar.LeftHeader>
|
||||
<ImageIcon
|
||||
Height="16"
|
||||
Margin="16,0,0,0"
|
||||
Source="/Assets/Hosts/Hosts.ico" />
|
||||
</TitleBar.LeftHeader>
|
||||
</TitleBar>
|
||||
</Grid>
|
||||
</winuiex:WindowEx>
|
||||
|
||||
@@ -9,19 +9,15 @@ using HostsUILib.Helpers;
|
||||
using HostsUILib.Views;
|
||||
using ManagedCommon;
|
||||
using Microsoft.PowerToys.Telemetry;
|
||||
using Microsoft.UI.Windowing;
|
||||
using Microsoft.UI.Xaml;
|
||||
using Microsoft.UI.Xaml.Controls;
|
||||
using Microsoft.UI.Xaml.Media;
|
||||
using Microsoft.Windows.ApplicationModel.Resources;
|
||||
using WinUIEx;
|
||||
|
||||
// To learn more about WinUI, the WinUI project structure,
|
||||
// and more about our project templates, see: http://aka.ms/winui-project-info.
|
||||
namespace Hosts
|
||||
{
|
||||
/// <summary>
|
||||
/// An empty window that can be used on its own or navigated to within a Frame.
|
||||
/// </summary>
|
||||
public sealed partial class MainWindow : WindowEx
|
||||
{
|
||||
private HostsMainPage MainPage { get; }
|
||||
@@ -38,31 +34,18 @@ namespace Hosts
|
||||
|
||||
var title = Host.GetService<IElevationHelper>().IsElevated ? loader.GetString("WindowAdminTitle") : loader.GetString("WindowTitle");
|
||||
Title = title;
|
||||
AppTitleTextBlock.Text = title;
|
||||
titleBar.Title = title;
|
||||
|
||||
var handle = this.GetWindowHandle();
|
||||
|
||||
WindowHelpers.ForceTopBorder1PixelInsetOnWindows10(handle);
|
||||
WindowHelpers.BringToForeground(handle);
|
||||
Activated += MainWindow_Activated;
|
||||
|
||||
MainPage = Host.GetService<HostsMainPage>();
|
||||
|
||||
PowerToysTelemetry.Log.WriteEvent(new HostEditorStartFinishEvent() { TimeStamp = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds() });
|
||||
}
|
||||
|
||||
private void MainWindow_Activated(object sender, WindowActivatedEventArgs args)
|
||||
{
|
||||
if (args.WindowActivationState == WindowActivationState.Deactivated)
|
||||
{
|
||||
AppTitleTextBlock.Foreground = (SolidColorBrush)App.Current.Resources["WindowCaptionForegroundDisabled"];
|
||||
}
|
||||
else
|
||||
{
|
||||
AppTitleTextBlock.Foreground = (SolidColorBrush)App.Current.Resources["WindowCaptionForeground"];
|
||||
}
|
||||
}
|
||||
|
||||
private void Grid_Loaded(object sender, RoutedEventArgs e)
|
||||
{
|
||||
MainGrid.Children.Add(MainPage);
|
||||
|
||||
@@ -49,7 +49,9 @@ namespace Awake.Core
|
||||
|
||||
private static DateTimeOffset ExpireAt { get; set; }
|
||||
|
||||
private static readonly CompositeFormat AwakeMinute = CompositeFormat.Parse(Resources.AWAKE_MINUTE);
|
||||
private static readonly CompositeFormat AwakeMinutes = CompositeFormat.Parse(Resources.AWAKE_MINUTES);
|
||||
private static readonly CompositeFormat AwakeHour = CompositeFormat.Parse(Resources.AWAKE_HOUR);
|
||||
private static readonly CompositeFormat AwakeHours = CompositeFormat.Parse(Resources.AWAKE_HOURS);
|
||||
private static readonly BlockingCollection<ExecutionState> _stateQueue;
|
||||
private static CancellationTokenSource _tokenSource;
|
||||
@@ -451,7 +453,7 @@ namespace Awake.Core
|
||||
Dictionary<string, uint> optionsList = new()
|
||||
{
|
||||
{ string.Format(CultureInfo.InvariantCulture, AwakeMinutes, 30), 1800 },
|
||||
{ string.Format(CultureInfo.InvariantCulture, AwakeHours, 1), 3600 },
|
||||
{ string.Format(CultureInfo.InvariantCulture, AwakeHour, 1), 3600 },
|
||||
{ string.Format(CultureInfo.InvariantCulture, AwakeHours, 2), 7200 },
|
||||
};
|
||||
return optionsList;
|
||||
|
||||
@@ -159,6 +159,15 @@ namespace Awake.Properties {
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to {0} hour.
|
||||
/// </summary>
|
||||
internal static string AWAKE_HOUR {
|
||||
get {
|
||||
return ResourceManager.GetString("AWAKE_HOUR", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to {0} hours.
|
||||
/// </summary>
|
||||
@@ -240,6 +249,15 @@ namespace Awake.Properties {
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to {0} minute.
|
||||
/// </summary>
|
||||
internal static string AWAKE_MINUTE {
|
||||
get {
|
||||
return ResourceManager.GetString("AWAKE_MINUTE", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to {0} minutes.
|
||||
/// </summary>
|
||||
|
||||
@@ -123,6 +123,10 @@
|
||||
<data name="AWAKE_EXIT" xml:space="preserve">
|
||||
<value>Exit</value>
|
||||
</data>
|
||||
<data name="AWAKE_HOUR" xml:space="preserve">
|
||||
<value>{0} hour</value>
|
||||
<comment>{0} shouldn't be removed. It will be replaced by the number 1 at runtime by the application. Used for defining a period to keep the PC awake.</comment>
|
||||
</data>
|
||||
<data name="AWAKE_HOURS" xml:space="preserve">
|
||||
<value>{0} hours</value>
|
||||
<comment>{0} shouldn't be removed. It will be replaced by a number greater than 1 at runtime by the application. Used for defining a period to keep the PC awake.</comment>
|
||||
@@ -142,6 +146,10 @@
|
||||
<value>Keep awake until expiration date and time</value>
|
||||
<comment>Keep the system awake until expiration date and time</comment>
|
||||
</data>
|
||||
<data name="AWAKE_MINUTE" xml:space="preserve">
|
||||
<value>{0} minute</value>
|
||||
<comment>{0} shouldn't be removed. It will be replaced by the number 1 at runtime by the application. Used for defining a period to keep the PC awake.</comment>
|
||||
</data>
|
||||
<data name="AWAKE_MINUTES" xml:space="preserve">
|
||||
<value>{0} minutes</value>
|
||||
<comment>{0} shouldn't be removed. It will be replaced by a number greater than 1 at runtime by the application. Used for defining a period to keep the PC awake.</comment>
|
||||
|
||||
@@ -160,7 +160,7 @@ public partial class CommandItemViewModel : ExtensionObjectViewModel, ICommandBa
|
||||
Initialized |= InitializedState.Initialized;
|
||||
}
|
||||
|
||||
public void SlowInitializeProperties()
|
||||
public virtual void SlowInitializeProperties()
|
||||
{
|
||||
if (IsSelectedInitialized)
|
||||
{
|
||||
|
||||
@@ -47,9 +47,21 @@ public partial class ListItemViewModel(IListItem model, WeakReference<IPageConte
|
||||
|
||||
UpdateTags(li.Tags);
|
||||
|
||||
TextToSuggest = li.TextToSuggest;
|
||||
Section = li.Section ?? string.Empty;
|
||||
var extensionDetails = li.Details;
|
||||
|
||||
UpdateProperty(nameof(Section));
|
||||
}
|
||||
|
||||
public override void SlowInitializeProperties()
|
||||
{
|
||||
base.SlowInitializeProperties();
|
||||
var model = Model.Unsafe;
|
||||
if (model is null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var extensionDetails = model.Details;
|
||||
if (extensionDetails is not null)
|
||||
{
|
||||
Details = new(extensionDetails, PageContext);
|
||||
@@ -58,8 +70,8 @@ public partial class ListItemViewModel(IListItem model, WeakReference<IPageConte
|
||||
UpdateProperty(nameof(HasDetails));
|
||||
}
|
||||
|
||||
TextToSuggest = model.TextToSuggest;
|
||||
UpdateProperty(nameof(TextToSuggest));
|
||||
UpdateProperty(nameof(Section));
|
||||
}
|
||||
|
||||
protected override void FetchProperty(string propertyName)
|
||||
|
||||
@@ -3,10 +3,12 @@
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System.Diagnostics;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Nodes;
|
||||
using System.Text.Json.Serialization;
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
using ManagedCommon;
|
||||
using Microsoft.CommandPalette.Extensions.Toolkit;
|
||||
using Windows.Foundation;
|
||||
|
||||
@@ -39,7 +41,7 @@ public partial class AppStateModel : ObservableObject
|
||||
{
|
||||
if (string.IsNullOrEmpty(FilePath))
|
||||
{
|
||||
throw new InvalidOperationException($"You must set a valid {nameof(SettingsModel.FilePath)} before calling {nameof(LoadState)}");
|
||||
throw new InvalidOperationException($"You must set a valid {nameof(FilePath)} before calling {nameof(LoadState)}");
|
||||
}
|
||||
|
||||
if (!File.Exists(FilePath))
|
||||
@@ -77,43 +79,84 @@ public partial class AppStateModel : ObservableObject
|
||||
try
|
||||
{
|
||||
// Serialize the main dictionary to JSON and save it to the file
|
||||
var settingsJson = JsonSerializer.Serialize(model, JsonSerializationContext.Default.AppStateModel);
|
||||
var settingsJson = JsonSerializer.Serialize(model, JsonSerializationContext.Default.AppStateModel!);
|
||||
|
||||
// Is it valid JSON?
|
||||
if (JsonNode.Parse(settingsJson) is JsonObject newSettings)
|
||||
// validate JSON
|
||||
if (JsonNode.Parse(settingsJson) is not JsonObject newSettings)
|
||||
{
|
||||
// Now, read the existing content from the file
|
||||
var oldContent = File.Exists(FilePath) ? File.ReadAllText(FilePath) : "{}";
|
||||
Logger.LogError("Failed to parse app state as a JsonObject.");
|
||||
return;
|
||||
}
|
||||
|
||||
// Is it valid JSON?
|
||||
if (JsonNode.Parse(oldContent) is JsonObject savedSettings)
|
||||
{
|
||||
foreach (var item in newSettings)
|
||||
{
|
||||
savedSettings[item.Key] = item.Value?.DeepClone();
|
||||
}
|
||||
// read previous settings
|
||||
if (!TryReadSavedState(out var savedSettings))
|
||||
{
|
||||
savedSettings = new JsonObject();
|
||||
}
|
||||
|
||||
var serialized = savedSettings.ToJsonString(JsonSerializationContext.Default.AppStateModel.Options);
|
||||
File.WriteAllText(FilePath, serialized);
|
||||
// merge new settings into old ones
|
||||
foreach (var item in newSettings)
|
||||
{
|
||||
savedSettings[item.Key] = item.Value?.DeepClone();
|
||||
}
|
||||
|
||||
// TODO: Instead of just raising the event here, we should
|
||||
// have a file change watcher on the settings file, and
|
||||
// reload the settings then
|
||||
model.StateChanged?.Invoke(model, null);
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.WriteLine("Failed to parse settings file as JsonObject.");
|
||||
}
|
||||
var serialized = savedSettings.ToJsonString(JsonSerializationContext.Default.AppStateModel!.Options);
|
||||
File.WriteAllText(FilePath, serialized);
|
||||
|
||||
// TODO: Instead of just raising the event here, we should
|
||||
// have a file change watcher on the settings file, and
|
||||
// reload the settings then
|
||||
model.StateChanged?.Invoke(model, null);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.LogError($"Failed to save application state to {FilePath}:", ex);
|
||||
}
|
||||
}
|
||||
|
||||
private static bool TryReadSavedState([NotNullWhen(true)] out JsonObject? savedSettings)
|
||||
{
|
||||
savedSettings = null;
|
||||
|
||||
// read existing content from the file
|
||||
string oldContent;
|
||||
try
|
||||
{
|
||||
if (File.Exists(FilePath))
|
||||
{
|
||||
oldContent = File.ReadAllText(FilePath);
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.WriteLine("Failed to parse settings file as JsonObject.");
|
||||
// file doesn't exist (might not have been created yet), so consider this a success
|
||||
// and return empty settings
|
||||
savedSettings = new JsonObject();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Debug.WriteLine(ex.ToString());
|
||||
Logger.LogWarning($"Failed to read app state file {FilePath}:\n{ex}");
|
||||
return false;
|
||||
}
|
||||
|
||||
// detect empty file, just for sake of logging
|
||||
if (string.IsNullOrWhiteSpace(oldContent))
|
||||
{
|
||||
Logger.LogInfo($"App state file is empty: {FilePath}");
|
||||
return false;
|
||||
}
|
||||
|
||||
// is it valid JSON?
|
||||
try
|
||||
{
|
||||
savedSettings = JsonNode.Parse(oldContent) as JsonObject;
|
||||
return savedSettings != null;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.LogWarning($"Failed to parse app state from {FilePath}:\n{ex}");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using ManagedCommon;
|
||||
using Microsoft.CmdPal.UI.ViewModels.Commands;
|
||||
using Microsoft.CmdPal.UI.ViewModels.Properties;
|
||||
using Microsoft.CommandPalette.Extensions.Toolkit;
|
||||
@@ -19,6 +20,10 @@ internal sealed partial class FallbackLogItem : FallbackCommandItem
|
||||
Title = string.Empty;
|
||||
_logMessagesPage.Name = string.Empty;
|
||||
Subtitle = Properties.Resources.builtin_log_subtitle;
|
||||
|
||||
var logPath = Logger.LogDirectoryPath("\\CmdPal\\Logs\\");
|
||||
var openLogCommand = new OpenFileCommand(logPath) { Name = Resources.builtin_log_folder_command_name };
|
||||
MoreCommands = [new CommandContextItem(openLogCommand)];
|
||||
}
|
||||
|
||||
public override void UpdateQuery(string query)
|
||||
|
||||
@@ -27,7 +27,9 @@ public partial class MainListPage : DynamicListPage,
|
||||
private readonly IServiceProvider _serviceProvider;
|
||||
|
||||
private readonly TopLevelCommandManager _tlcManager;
|
||||
private IEnumerable<IListItem>? _filteredItems;
|
||||
private IEnumerable<Scored<IListItem>>? _filteredItems;
|
||||
private IEnumerable<Scored<IListItem>>? _filteredApps;
|
||||
private IEnumerable<IListItem>? _allApps;
|
||||
private bool _includeApps;
|
||||
private bool _filteredItemsIncludesApps;
|
||||
|
||||
@@ -83,7 +85,7 @@ public partial class MainListPage : DynamicListPage,
|
||||
}
|
||||
else
|
||||
{
|
||||
RaiseItemsChanged(_tlcManager.TopLevelCommands.Count);
|
||||
RaiseItemsChanged();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -148,7 +150,13 @@ public partial class MainListPage : DynamicListPage,
|
||||
{
|
||||
lock (_tlcManager.TopLevelCommands)
|
||||
{
|
||||
return _filteredItems?.ToArray() ?? [];
|
||||
var items = Enumerable.Empty<Scored<IListItem>>()
|
||||
.Concat(_filteredItems is not null ? _filteredItems : [])
|
||||
.Concat(_filteredApps is not null ? _filteredApps : [])
|
||||
.OrderByDescending(o => o.Score)
|
||||
.Select(s => s.Item)
|
||||
.ToArray();
|
||||
return items;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -167,6 +175,8 @@ public partial class MainListPage : DynamicListPage,
|
||||
{
|
||||
_filteredItemsIncludesApps = _includeApps;
|
||||
_filteredItems = null;
|
||||
_filteredApps = null;
|
||||
_allApps = null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -184,6 +194,8 @@ public partial class MainListPage : DynamicListPage,
|
||||
{
|
||||
_filteredItemsIncludesApps = _includeApps;
|
||||
_filteredItems = null;
|
||||
_filteredApps = null;
|
||||
_allApps = null;
|
||||
RaiseItemsChanged(commands.Count);
|
||||
return;
|
||||
}
|
||||
@@ -193,35 +205,49 @@ public partial class MainListPage : DynamicListPage,
|
||||
if (!newSearch.StartsWith(oldSearch, StringComparison.CurrentCultureIgnoreCase))
|
||||
{
|
||||
_filteredItems = null;
|
||||
_filteredApps = null;
|
||||
_allApps = null;
|
||||
}
|
||||
|
||||
// If the internal state has changed, reset _filteredItems to reset the list.
|
||||
if (_filteredItemsIncludesApps != _includeApps)
|
||||
{
|
||||
_filteredItems = null;
|
||||
_filteredApps = null;
|
||||
_allApps = null;
|
||||
}
|
||||
|
||||
var newFilteredItems = _filteredItems?.Select(s => s.Item);
|
||||
|
||||
// If we don't have any previous filter results to work with, start
|
||||
// with a list of all our commands & apps.
|
||||
if (_filteredItems is null)
|
||||
if (newFilteredItems is null && _filteredApps is null)
|
||||
{
|
||||
_filteredItems = commands;
|
||||
newFilteredItems = commands;
|
||||
_filteredItemsIncludesApps = _includeApps;
|
||||
|
||||
if (_includeApps)
|
||||
{
|
||||
IEnumerable<IListItem> apps = AllAppsCommandProvider.Page.GetItems();
|
||||
var appIds = apps.Select(app => app.Command.Id).ToArray();
|
||||
|
||||
// Remove any top level pinned apps and use the apps from AllAppsCommandProvider.Page.GetItems()
|
||||
// since they contain details.
|
||||
_filteredItems = _filteredItems.Where(item => item.Command is not AppCommand);
|
||||
_filteredItems = _filteredItems.Concat(apps);
|
||||
_allApps = AllAppsCommandProvider.Page.GetItems();
|
||||
}
|
||||
}
|
||||
|
||||
// Produce a list of everything that matches the current filter.
|
||||
_filteredItems = ListHelpers.FilterList<IListItem>(_filteredItems, SearchText, ScoreTopLevelItem);
|
||||
RaiseItemsChanged(_filteredItems.Count());
|
||||
_filteredItems = ListHelpers.FilterListWithScores<IListItem>(newFilteredItems ?? [], SearchText, ScoreTopLevelItem);
|
||||
|
||||
// Produce a list of filtered apps with the appropriate limit
|
||||
if (_allApps is not null)
|
||||
{
|
||||
_filteredApps = ListHelpers.FilterListWithScores<IListItem>(_allApps, SearchText, ScoreTopLevelItem);
|
||||
|
||||
var appResultLimit = AllAppsCommandProvider.TopLevelResultLimit;
|
||||
if (appResultLimit >= 0)
|
||||
{
|
||||
_filteredApps = _filteredApps.Take(appResultLimit);
|
||||
}
|
||||
}
|
||||
|
||||
RaiseItemsChanged();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -126,6 +126,10 @@ public class ExtensionWrapper : IExtensionWrapper
|
||||
// We'll just return out nothing.
|
||||
return;
|
||||
}
|
||||
else if (hr.Value != 0)
|
||||
{
|
||||
Logger.LogError($"Failed to find {ExtensionDisplayName}: {hr.Value}");
|
||||
}
|
||||
|
||||
// Marshal.ThrowExceptionForHR(hr);
|
||||
_extensionObject = MarshalInterface<IExtension>.FromAbi((nint)extensionPtr);
|
||||
|
||||
@@ -285,6 +285,15 @@ namespace Microsoft.CmdPal.UI.ViewModels.Properties {
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to View log folder.
|
||||
/// </summary>
|
||||
public static string builtin_log_folder_command_name {
|
||||
get {
|
||||
return ResourceManager.GetString("builtin_log_folder_command_name", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to View log.
|
||||
/// </summary>
|
||||
|
||||
@@ -135,6 +135,9 @@
|
||||
<data name="builtin_log_title" xml:space="preserve">
|
||||
<value>View log</value>
|
||||
</data>
|
||||
<data name="builtin_log_folder_command_name" xml:space="preserve">
|
||||
<value>View log folder</value>
|
||||
</data>
|
||||
<data name="builtin_reload_subtitle" xml:space="preserve">
|
||||
<value>Reload Command Palette extensions</value>
|
||||
</data>
|
||||
|
||||
@@ -32,6 +32,7 @@ public sealed partial class TopLevelViewModel : ObservableObject, IListItem
|
||||
private string _generatedId = string.Empty;
|
||||
|
||||
private HotkeySettings? _hotkey;
|
||||
private IIconInfo? _initialIcon;
|
||||
|
||||
private CommandAlias? Alias { get; set; }
|
||||
|
||||
@@ -57,6 +58,8 @@ public sealed partial class TopLevelViewModel : ObservableObject, IListItem
|
||||
|
||||
public IIconInfo Icon => _commandItemViewModel.Icon;
|
||||
|
||||
public IIconInfo InitialIcon => _initialIcon ?? _commandItemViewModel.Icon;
|
||||
|
||||
ICommand? ICommandItem.Command => _commandItemViewModel.Command.Model.Unsafe;
|
||||
|
||||
IContextItem?[] ICommandItem.MoreCommands => _commandItemViewModel.MoreCommands
|
||||
@@ -205,6 +208,8 @@ public sealed partial class TopLevelViewModel : ObservableObject, IListItem
|
||||
{
|
||||
DisplayTitle = fallback.DisplayTitle;
|
||||
}
|
||||
|
||||
UpdateInitialIcon(false);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -221,7 +226,31 @@ public sealed partial class TopLevelViewModel : ObservableObject, IListItem
|
||||
FetchAliasFromAliasManager();
|
||||
UpdateHotkey();
|
||||
UpdateTags();
|
||||
UpdateInitialIcon();
|
||||
}
|
||||
else if (e.PropertyName == nameof(CommandItem.Icon))
|
||||
{
|
||||
UpdateInitialIcon();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateInitialIcon(bool raiseNotification = true)
|
||||
{
|
||||
if (_initialIcon != null || !_commandItemViewModel.Icon.IsSet)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_initialIcon = _commandItemViewModel.Icon;
|
||||
|
||||
if (raiseNotification)
|
||||
{
|
||||
DoOnUiThread(
|
||||
() =>
|
||||
{
|
||||
PropChanged?.Invoke(this, new PropChangedEventArgs(nameof(InitialIcon)));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -125,7 +125,7 @@
|
||||
Width="20"
|
||||
Height="20"
|
||||
AutomationProperties.AccessibilityView="Raw"
|
||||
SourceKey="{x:Bind Icon, Mode=OneWay}"
|
||||
SourceKey="{x:Bind InitialIcon, Mode=OneWay}"
|
||||
SourceRequested="{x:Bind helpers:IconCacheProvider.SourceRequested}" />
|
||||
</cpcontrols:ContentIcon.Content>
|
||||
</cpcontrols:ContentIcon>
|
||||
|
||||
@@ -438,7 +438,7 @@ Right-click to remove the key combination, thereby deactivating the shortcut.</v
|
||||
<data name="NavigationPaneClosed" xml:space="preserve">
|
||||
<value>Navigation pane closed</value>
|
||||
</data>
|
||||
<data name="NavigationPageOpened" xml:space="preserve">
|
||||
<data name="NavigationPaneOpened" xml:space="preserve">
|
||||
<value>Navigation page opened</value>
|
||||
</data>
|
||||
</root>
|
||||
@@ -15,13 +15,13 @@ public class MockSettingsInterface : ISettingsInterface
|
||||
|
||||
public bool GlobalIfURI { get; set; }
|
||||
|
||||
public string ShowHistory { get; set; }
|
||||
public uint HistoryItemCount { get; set; }
|
||||
|
||||
public MockSettingsInterface(string showHistory = "none", bool globalIfUri = true, List<HistoryItem> mockHistory = null)
|
||||
public MockSettingsInterface(uint historyItemCount = 0, bool globalIfUri = true, List<HistoryItem> mockHistory = null)
|
||||
{
|
||||
_historyItems = mockHistory ?? new List<HistoryItem>();
|
||||
GlobalIfURI = globalIfUri;
|
||||
ShowHistory = showHistory;
|
||||
HistoryItemCount = historyItemCount;
|
||||
}
|
||||
|
||||
public List<ListItem> LoadHistory()
|
||||
@@ -50,9 +50,9 @@ public class MockSettingsInterface : ISettingsInterface
|
||||
_historyItems.Add(historyItem);
|
||||
|
||||
// Simulate the same logic as SettingsManager
|
||||
if (int.TryParse(ShowHistory, out var maxHistoryItems) && maxHistoryItems > 0)
|
||||
if (HistoryItemCount > 0)
|
||||
{
|
||||
while (_historyItems.Count > maxHistoryItems)
|
||||
while (_historyItems.Count > HistoryItemCount)
|
||||
{
|
||||
_historyItems.RemoveAt(0); // Remove the oldest item
|
||||
}
|
||||
|
||||
@@ -54,7 +54,7 @@ public class QueryTests : CommandPaletteUnitTestBase
|
||||
new HistoryItem("another search", DateTime.Parse("2024-01-02 13:00:00", CultureInfo.CurrentCulture)),
|
||||
};
|
||||
|
||||
var settings = new MockSettingsInterface(mockHistory: mockHistoryItems, showHistory: "5");
|
||||
var settings = new MockSettingsInterface(mockHistory: mockHistoryItems, historyItemCount: 5);
|
||||
|
||||
var page = new WebSearchListPage(settings);
|
||||
|
||||
@@ -89,7 +89,7 @@ public class QueryTests : CommandPaletteUnitTestBase
|
||||
new HistoryItem("another search4", DateTime.Parse("2024-01-05 13:00:00", CultureInfo.CurrentCulture)),
|
||||
};
|
||||
|
||||
var settings = new MockSettingsInterface(mockHistory: mockHistoryItems, showHistory: "5");
|
||||
var settings = new MockSettingsInterface(mockHistory: mockHistoryItems, historyItemCount: 5);
|
||||
|
||||
var page = new WebSearchListPage(settings);
|
||||
|
||||
@@ -122,7 +122,7 @@ public class QueryTests : CommandPaletteUnitTestBase
|
||||
new HistoryItem("another search5", DateTime.Parse("2024-01-06 13:00:00", CultureInfo.CurrentCulture)),
|
||||
};
|
||||
|
||||
var settings = new MockSettingsInterface(mockHistory: mockHistoryItems, showHistory: "None");
|
||||
var settings = new MockSettingsInterface(mockHistory: mockHistoryItems, historyItemCount: 0);
|
||||
|
||||
var page = new WebSearchListPage(settings);
|
||||
|
||||
|
||||
@@ -3,9 +3,7 @@
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Microsoft.CmdPal.Ext.Apps.Programs;
|
||||
using Microsoft.CmdPal.Ext.Apps.Properties;
|
||||
using Microsoft.CmdPal.Ext.Apps.State;
|
||||
using Microsoft.CommandPalette.Extensions;
|
||||
@@ -45,6 +43,28 @@ public partial class AllAppsCommandProvider : CommandProvider
|
||||
PinnedAppsManager.Instance.PinStateChanged += OnPinStateChanged;
|
||||
}
|
||||
|
||||
public static int TopLevelResultLimit
|
||||
{
|
||||
get
|
||||
{
|
||||
var limitSetting = AllAppsSettings.Instance.SearchResultLimit;
|
||||
|
||||
if (limitSetting is null)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
var quantity = -1;
|
||||
|
||||
if (int.TryParse(limitSetting, out var result))
|
||||
{
|
||||
quantity = result;
|
||||
}
|
||||
|
||||
return quantity;
|
||||
}
|
||||
}
|
||||
|
||||
public override ICommandItem[] TopLevelCommands() => [_listItem, .._page.GetPinnedApps()];
|
||||
|
||||
public ICommandItem? LookupApp(string displayName)
|
||||
|
||||
@@ -20,6 +20,16 @@ public class AllAppsSettings : JsonSettingsManager, ISettingsInterface
|
||||
|
||||
private static string Experimental(string propertyName) => $"{_namespace}.experimental.{propertyName}";
|
||||
|
||||
private static readonly List<ChoiceSetSetting.Choice> _searchResultLimitChoices =
|
||||
[
|
||||
new ChoiceSetSetting.Choice(Resources.limit_none, "-1"),
|
||||
new ChoiceSetSetting.Choice(Resources.limit_0, "0"),
|
||||
new ChoiceSetSetting.Choice(Resources.limit_1, "1"),
|
||||
new ChoiceSetSetting.Choice(Resources.limit_5, "5"),
|
||||
new ChoiceSetSetting.Choice(Resources.limit_10, "10"),
|
||||
new ChoiceSetSetting.Choice(Resources.limit_20, "20"),
|
||||
];
|
||||
|
||||
#pragma warning disable SA1401 // Fields should be private
|
||||
internal static AllAppsSettings Instance = new();
|
||||
#pragma warning restore SA1401 // Fields should be private
|
||||
@@ -42,6 +52,14 @@ public class AllAppsSettings : JsonSettingsManager, ISettingsInterface
|
||||
|
||||
public bool EnablePathEnvironmentVariableSource => _enablePathEnvironmentVariableSource.Value;
|
||||
|
||||
private readonly ChoiceSetSetting _searchResultLimitSource = new(
|
||||
Namespaced(nameof(SearchResultLimit)),
|
||||
Resources.limit_fallback_results_source,
|
||||
Resources.limit_fallback_results_source_description,
|
||||
_searchResultLimitChoices);
|
||||
|
||||
public string SearchResultLimit => _searchResultLimitSource.Value ?? string.Empty;
|
||||
|
||||
private readonly ToggleSetting _enableStartMenuSource = new(
|
||||
Namespaced(nameof(EnableStartMenuSource)),
|
||||
Resources.enable_start_menu_source,
|
||||
@@ -87,6 +105,7 @@ public class AllAppsSettings : JsonSettingsManager, ISettingsInterface
|
||||
Settings.Add(_enableDesktopSource);
|
||||
Settings.Add(_enableRegistrySource);
|
||||
Settings.Add(_enablePathEnvironmentVariableSource);
|
||||
Settings.Add(_searchResultLimitSource);
|
||||
|
||||
// Load settings from file upon initialization
|
||||
LoadSettings();
|
||||
|
||||
@@ -1,47 +0,0 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.Text;
|
||||
using ManagedCommon;
|
||||
using Microsoft.CmdPal.Ext.Apps.Properties;
|
||||
using Microsoft.CommandPalette.Extensions.Toolkit;
|
||||
|
||||
namespace Microsoft.CmdPal.Ext.Apps.Commands;
|
||||
|
||||
internal sealed partial class CopyPathCommand : InvokableCommand
|
||||
{
|
||||
private readonly string _target;
|
||||
|
||||
public CopyPathCommand(string target)
|
||||
{
|
||||
Name = Resources.copy_path;
|
||||
Icon = Icons.CopyIcon;
|
||||
|
||||
_target = target;
|
||||
}
|
||||
|
||||
private static readonly CompositeFormat CopyFailedFormat = CompositeFormat.Parse(Resources.copy_failed);
|
||||
|
||||
public override CommandResult Invoke()
|
||||
{
|
||||
try
|
||||
{
|
||||
ClipboardHelper.SetText(_target);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.LogError("Copy failed: " + ex.Message);
|
||||
return CommandResult.ShowToast(
|
||||
new ToastArgs
|
||||
{
|
||||
Message = string.Format(CultureInfo.CurrentCulture, CopyFailedFormat, ex.Message),
|
||||
Result = CommandResult.KeepOpen(),
|
||||
});
|
||||
}
|
||||
|
||||
return CommandResult.ShowToast(Resources.copied_to_clipboard);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,130 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Globalization;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using ManagedCommon;
|
||||
using Microsoft.CmdPal.Ext.Apps.Programs;
|
||||
using Microsoft.CmdPal.Ext.Apps.Properties;
|
||||
using Microsoft.CommandPalette.Extensions.Toolkit;
|
||||
using Windows.Management.Deployment;
|
||||
|
||||
namespace Microsoft.CmdPal.Ext.Apps.Commands;
|
||||
|
||||
internal sealed partial class UninstallApplicationCommand : InvokableCommand
|
||||
{
|
||||
// This is a ms-settings URI that opens the Apps & Features page in Windows Settings.
|
||||
// It's correct and follows the Microsoft documentation:
|
||||
// https://learn.microsoft.com/en-us/windows/apps/develop/launch/launch-settings-app#apps
|
||||
private const string AppsFeaturesUri = "ms-settings:appsfeatures";
|
||||
|
||||
private readonly UWPApplication? _uwpTarget;
|
||||
private readonly Win32Program? _win32Target;
|
||||
|
||||
public UninstallApplicationCommand(UWPApplication target)
|
||||
{
|
||||
Name = Resources.uninstall_application;
|
||||
Icon = Icons.UninstallApplicationIcon;
|
||||
_uwpTarget = target ?? throw new ArgumentNullException(nameof(target));
|
||||
}
|
||||
|
||||
public UninstallApplicationCommand(Win32Program target)
|
||||
{
|
||||
Name = Resources.uninstall_application;
|
||||
Icon = Icons.UninstallApplicationIcon;
|
||||
_win32Target = target ?? throw new ArgumentNullException(nameof(target));
|
||||
}
|
||||
|
||||
private async Task<CommandResult> UninstallUwpAppAsync(UWPApplication app)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(app.Package.FullName))
|
||||
{
|
||||
Logger.LogError($"Critical error while uninstalling: packageFullName cannot be null or empty.");
|
||||
return CommandResult.ShowToast(new ToastArgs()
|
||||
{
|
||||
Message = string.Format(CultureInfo.CurrentCulture, CompositeFormat.Parse(Resources.uninstall_application_failed), app.DisplayName),
|
||||
Result = CommandResult.KeepOpen(),
|
||||
});
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
// Which timeout to use for the uninstallation operation?
|
||||
using (var cts = new CancellationTokenSource(TimeSpan.FromSeconds(60)))
|
||||
{
|
||||
var packageManager = new PackageManager();
|
||||
var result = await packageManager.RemovePackageAsync(app.Package.FullName).AsTask(cts.Token);
|
||||
|
||||
if (result.ErrorText is not null && result.ErrorText.Length > 0)
|
||||
{
|
||||
Logger.LogError($"Failed to uninstall {app.Package.FullName}: {result.ErrorText}");
|
||||
return CommandResult.ShowToast(new ToastArgs()
|
||||
{
|
||||
Message = string.Format(CultureInfo.CurrentCulture, CompositeFormat.Parse(Resources.uninstall_application_failed), app.DisplayName),
|
||||
Result = CommandResult.KeepOpen(),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Update the Search results after uninstalling the app - unsure how to do this yet.
|
||||
return CommandResult.ShowToast(new ToastArgs()
|
||||
{
|
||||
Message = string.Format(CultureInfo.CurrentCulture, CompositeFormat.Parse(Resources.uninstall_application_successful), app.DisplayName),
|
||||
Result = CommandResult.GoHome(),
|
||||
});
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
Logger.LogError($"Timeout exceeded while uninstalling {app.Package.FullName}");
|
||||
return CommandResult.ShowToast(new ToastArgs()
|
||||
{
|
||||
Message = string.Format(CultureInfo.CurrentCulture, CompositeFormat.Parse(Resources.uninstall_application_failed), app.DisplayName),
|
||||
Result = CommandResult.KeepOpen(),
|
||||
});
|
||||
}
|
||||
catch (UnauthorizedAccessException ex)
|
||||
{
|
||||
Logger.LogError($"Permission denied to uninstall {app.Package.FullName}. Elevated privileges may be required. Error: {ex.Message}");
|
||||
return CommandResult.ShowToast(new ToastArgs()
|
||||
{
|
||||
Message = string.Format(CultureInfo.CurrentCulture, CompositeFormat.Parse(Resources.uninstall_application_failed), app.DisplayName),
|
||||
Result = CommandResult.KeepOpen(),
|
||||
});
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.LogError($"An unexpected error occurred during uninstallation of {app.Package.FullName}: {ex.Message}");
|
||||
return CommandResult.ShowToast(new ToastArgs()
|
||||
{
|
||||
Message = string.Format(CultureInfo.CurrentCulture, CompositeFormat.Parse(Resources.uninstall_application_failed), app.DisplayName),
|
||||
Result = CommandResult.KeepOpen(),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public override CommandResult Invoke()
|
||||
{
|
||||
if (_uwpTarget is not null)
|
||||
{
|
||||
return UninstallUwpAppAsync(_uwpTarget).ConfigureAwait(false).GetAwaiter().GetResult();
|
||||
}
|
||||
|
||||
if (_win32Target is not null)
|
||||
{
|
||||
Process.Start(new ProcessStartInfo
|
||||
{
|
||||
FileName = AppsFeaturesUri,
|
||||
UseShellExecute = true,
|
||||
});
|
||||
return CommandResult.Dismiss();
|
||||
}
|
||||
|
||||
Logger.LogError("UninstallApplicationCommand invoked with no target.");
|
||||
return CommandResult.Dismiss();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.Text;
|
||||
using ManagedCommon;
|
||||
using Microsoft.CmdPal.Ext.Apps.Programs;
|
||||
using Microsoft.CmdPal.Ext.Apps.Properties;
|
||||
using Microsoft.CommandPalette.Extensions.Toolkit;
|
||||
|
||||
namespace Microsoft.CmdPal.Ext.Apps.Commands;
|
||||
|
||||
internal sealed partial class UninstallApplicationConfirmation : InvokableCommand
|
||||
{
|
||||
private readonly UWPApplication? _uwpTarget;
|
||||
private readonly Win32Program? _win32Target;
|
||||
|
||||
public UninstallApplicationConfirmation(UWPApplication target)
|
||||
{
|
||||
Name = Resources.uninstall_application;
|
||||
Icon = Icons.UninstallApplicationIcon;
|
||||
_uwpTarget = target ?? throw new ArgumentNullException(nameof(target));
|
||||
}
|
||||
|
||||
public UninstallApplicationConfirmation(Win32Program target)
|
||||
{
|
||||
Name = Resources.uninstall_application;
|
||||
Icon = Icons.UninstallApplicationIcon;
|
||||
_win32Target = target ?? throw new ArgumentNullException(nameof(target));
|
||||
}
|
||||
|
||||
public override CommandResult Invoke()
|
||||
{
|
||||
UninstallApplicationCommand uninstallCommand;
|
||||
|
||||
var applicationTitle = Resources.uninstall_application;
|
||||
|
||||
if (_uwpTarget is not null)
|
||||
{
|
||||
uninstallCommand = new UninstallApplicationCommand(_uwpTarget);
|
||||
applicationTitle = _uwpTarget.DisplayName;
|
||||
}
|
||||
else if (_win32Target is not null)
|
||||
{
|
||||
uninstallCommand = new UninstallApplicationCommand(_win32Target);
|
||||
applicationTitle = _win32Target.Name;
|
||||
}
|
||||
else
|
||||
{
|
||||
Logger.LogError("UninstallApplicationCommand invoked with no target.");
|
||||
return CommandResult.Dismiss();
|
||||
}
|
||||
|
||||
var confirmArgs = new ConfirmationArgs()
|
||||
{
|
||||
Title = string.Format(CultureInfo.CurrentCulture, CompositeFormat.Parse(Resources.uninstall_application_confirm_title), applicationTitle),
|
||||
Description = Resources.uninstall_application_confirm_description,
|
||||
PrimaryCommand = uninstallCommand,
|
||||
IsPrimaryCommandCritical = true,
|
||||
};
|
||||
|
||||
return CommandResult.Confirm(confirmArgs);
|
||||
}
|
||||
}
|
||||
@@ -21,4 +21,6 @@ internal sealed class Icons
|
||||
public static IconInfo UnpinIcon { get; } = new("\uE77A"); // Unpin icon
|
||||
|
||||
public static IconInfo PinIcon { get; } = new("\uE840"); // Pin icon
|
||||
|
||||
public static IconInfo UninstallApplicationIcon { get; } = new("\uE74D"); // Uninstall icon
|
||||
}
|
||||
|
||||
@@ -95,7 +95,7 @@ public class UWPApplication : IUWPApplication
|
||||
|
||||
commands.Add(
|
||||
new CommandContextItem(
|
||||
new Commands.CopyPathCommand(Location))
|
||||
new CopyTextCommand(Location) { Name = Resources.copy_path })
|
||||
{
|
||||
RequestedShortcut = KeyChordHelpers.FromModifiers(ctrl: true, shift: true, vkey: VirtualKey.C),
|
||||
});
|
||||
@@ -117,6 +117,14 @@ public class UWPApplication : IUWPApplication
|
||||
RequestedShortcut = KeyChordHelpers.FromModifiers(ctrl: true, shift: true, vkey: VirtualKey.R),
|
||||
});
|
||||
|
||||
commands.Add(
|
||||
new CommandContextItem(
|
||||
new UninstallApplicationConfirmation(this))
|
||||
{
|
||||
RequestedShortcut = KeyChordHelpers.FromModifiers(ctrl: true, shift: true, vkey: VirtualKey.Delete),
|
||||
IsCritical = true,
|
||||
});
|
||||
|
||||
return commands;
|
||||
}
|
||||
|
||||
|
||||
@@ -202,7 +202,7 @@ public class Win32Program : IProgram
|
||||
}
|
||||
|
||||
commands.Add(new CommandContextItem(
|
||||
new Commands.CopyPathCommand(FullPath))
|
||||
new CopyTextCommand(FullPath) { Name = Resources.copy_path })
|
||||
{
|
||||
RequestedShortcut = KeyChordHelpers.FromModifiers(ctrl: true, shift: true, vkey: VirtualKey.C),
|
||||
});
|
||||
@@ -219,6 +219,16 @@ public class Win32Program : IProgram
|
||||
RequestedShortcut = KeyChordHelpers.FromModifiers(ctrl: true, shift: true, vkey: VirtualKey.R),
|
||||
});
|
||||
|
||||
if (AppType == ApplicationType.ShortcutApplication || AppType == ApplicationType.ApprefApplication || AppType == ApplicationType.Win32Application)
|
||||
{
|
||||
commands.Add(new CommandContextItem(
|
||||
new UninstallApplicationConfirmation(this))
|
||||
{
|
||||
RequestedShortcut = KeyChordHelpers.FromModifiers(ctrl: true, shift: true, vkey: VirtualKey.Delete),
|
||||
IsCritical = true,
|
||||
});
|
||||
}
|
||||
|
||||
return commands;
|
||||
}
|
||||
|
||||
|
||||
@@ -78,24 +78,6 @@ namespace Microsoft.CmdPal.Ext.Apps.Properties {
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Copied to clipboard!.
|
||||
/// </summary>
|
||||
internal static string copied_to_clipboard {
|
||||
get {
|
||||
return ResourceManager.GetString("copied_to_clipboard", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Copy failed ({0}). Please try again..
|
||||
/// </summary>
|
||||
internal static string copy_failed {
|
||||
get {
|
||||
return ResourceManager.GetString("copy_failed", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Copy path.
|
||||
/// </summary>
|
||||
@@ -177,6 +159,78 @@ namespace Microsoft.CmdPal.Ext.Apps.Properties {
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to 0.
|
||||
/// </summary>
|
||||
internal static string limit_0 {
|
||||
get {
|
||||
return ResourceManager.GetString("limit_0", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to 1.
|
||||
/// </summary>
|
||||
internal static string limit_1 {
|
||||
get {
|
||||
return ResourceManager.GetString("limit_1", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to 10.
|
||||
/// </summary>
|
||||
internal static string limit_10 {
|
||||
get {
|
||||
return ResourceManager.GetString("limit_10", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to 20.
|
||||
/// </summary>
|
||||
internal static string limit_20 {
|
||||
get {
|
||||
return ResourceManager.GetString("limit_20", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to 5.
|
||||
/// </summary>
|
||||
internal static string limit_5 {
|
||||
get {
|
||||
return ResourceManager.GetString("limit_5", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Limit the number of applications returned from the top level.
|
||||
/// </summary>
|
||||
internal static string limit_fallback_results_source {
|
||||
get {
|
||||
return ResourceManager.GetString("limit_fallback_results_source", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Limit fallback results to n apps.
|
||||
/// </summary>
|
||||
internal static string limit_fallback_results_source_description {
|
||||
get {
|
||||
return ResourceManager.GetString("limit_fallback_results_source_description", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Unlimited.
|
||||
/// </summary>
|
||||
internal static string limit_none {
|
||||
get {
|
||||
return ResourceManager.GetString("limit_none", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Open containing folder.
|
||||
/// </summary>
|
||||
@@ -276,6 +330,51 @@ namespace Microsoft.CmdPal.Ext.Apps.Properties {
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Uninstall.
|
||||
/// </summary>
|
||||
internal static string uninstall_application {
|
||||
get {
|
||||
return ResourceManager.GetString("uninstall_application", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to This app and its related information will be removed..
|
||||
/// </summary>
|
||||
internal static string uninstall_application_confirm_description {
|
||||
get {
|
||||
return ResourceManager.GetString("uninstall_application_confirm_description", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Uninstall "{0}"?.
|
||||
/// </summary>
|
||||
internal static string uninstall_application_confirm_title {
|
||||
get {
|
||||
return ResourceManager.GetString("uninstall_application_confirm_title", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Error while uninstalling '{0}'.
|
||||
/// </summary>
|
||||
internal static string uninstall_application_failed {
|
||||
get {
|
||||
return ResourceManager.GetString("uninstall_application_failed", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to '{0}' has been successfully uninstalled..
|
||||
/// </summary>
|
||||
internal static string uninstall_application_successful {
|
||||
get {
|
||||
return ResourceManager.GetString("uninstall_application_successful", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Unpin.
|
||||
/// </summary>
|
||||
|
||||
@@ -172,13 +172,6 @@
|
||||
<data name="run_as_different_user" xml:space="preserve">
|
||||
<value>Run as different user</value>
|
||||
</data>
|
||||
<data name="copy_failed" xml:space="preserve">
|
||||
<value>Copy failed ({0}). Please try again.</value>
|
||||
<comment>{0} is the error message</comment>
|
||||
</data>
|
||||
<data name="copied_to_clipboard" xml:space="preserve">
|
||||
<value>Copied to clipboard!</value>
|
||||
</data>
|
||||
<data name="enable_start_menu_source" xml:space="preserve">
|
||||
<value>Include apps found in the Start Menu</value>
|
||||
</data>
|
||||
@@ -205,4 +198,43 @@
|
||||
<data name="unpin_app" xml:space="preserve">
|
||||
<value>Unpin</value>
|
||||
</data>
|
||||
</root>
|
||||
<data name="uninstall_application" xml:space="preserve">
|
||||
<value>Uninstall</value>
|
||||
</data>
|
||||
<data name="uninstall_application_successful" xml:space="preserve">
|
||||
<value>'{0}' has been successfully uninstalled.</value>
|
||||
</data>
|
||||
<data name="uninstall_application_failed" xml:space="preserve">
|
||||
<value>Error while uninstalling '{0}'</value>
|
||||
</data>
|
||||
<data name="uninstall_application_confirm_description" xml:space="preserve">
|
||||
<value>This app and its related information will be removed.</value>
|
||||
</data>
|
||||
<data name="uninstall_application_confirm_title" xml:space="preserve">
|
||||
<value>Uninstall "{0}"?</value>
|
||||
</data>
|
||||
<data name="limit_1" xml:space="preserve">
|
||||
<value>1</value>
|
||||
</data>
|
||||
<data name="limit_5" xml:space="preserve">
|
||||
<value>5</value>
|
||||
</data>
|
||||
<data name="limit_10" xml:space="preserve">
|
||||
<value>10</value>
|
||||
</data>
|
||||
<data name="limit_20" xml:space="preserve">
|
||||
<value>20</value>
|
||||
</data>
|
||||
<data name="limit_fallback_results_source" xml:space="preserve">
|
||||
<value>Limit the number of applications returned from the top level</value>
|
||||
</data>
|
||||
<data name="limit_fallback_results_source_description" xml:space="preserve">
|
||||
<value>Limit fallback results to n apps</value>
|
||||
</data>
|
||||
<data name="limit_0" xml:space="preserve">
|
||||
<value>0</value>
|
||||
</data>
|
||||
<data name="limit_none" xml:space="preserve">
|
||||
<value>Unlimited</value>
|
||||
</data>
|
||||
</root>
|
||||
|
||||
@@ -17,6 +17,7 @@ internal sealed partial class FallbackSystemCommandItem : FallbackCommandItem
|
||||
{
|
||||
Title = string.Empty;
|
||||
Subtitle = string.Empty;
|
||||
Icon = Icons.LockIcon;
|
||||
|
||||
var isBootedInUefiMode = settings.GetSystemFirmwareType() == FirmwareType.Uefi;
|
||||
var hideEmptyRB = settings.HideEmptyRecycleBin();
|
||||
|
||||
@@ -22,6 +22,7 @@ internal sealed partial class FallbackTimeDateItem : FallbackCommandItem
|
||||
{
|
||||
Title = string.Empty;
|
||||
Subtitle = string.Empty;
|
||||
Icon = Icons.TimeDateIcon;
|
||||
_settingsManager = settings;
|
||||
_timestamp = timestamp;
|
||||
|
||||
|
||||
@@ -34,7 +34,7 @@ internal sealed partial class SearchWebCommand : InvokableCommand
|
||||
return CommandResult.KeepOpen();
|
||||
}
|
||||
|
||||
if (_settingsManager.ShowHistory != Resources.history_none)
|
||||
if (_settingsManager.HistoryItemCount != 0)
|
||||
{
|
||||
_settingsManager.SaveHistory(new HistoryItem(Arguments, DateTime.Now));
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@ public interface ISettingsInterface
|
||||
{
|
||||
public bool GlobalIfURI { get; }
|
||||
|
||||
public string ShowHistory { get; }
|
||||
public uint HistoryItemCount { get; }
|
||||
|
||||
public List<ListItem> LoadHistory();
|
||||
|
||||
|
||||
@@ -16,6 +16,7 @@ namespace Microsoft.CmdPal.Ext.WebSearch.Helpers;
|
||||
|
||||
public class SettingsManager : JsonSettingsManager, ISettingsInterface
|
||||
{
|
||||
private const string HistoryItemCountLegacySettingsKey = "ShowHistory";
|
||||
private readonly string _historyPath;
|
||||
|
||||
private static readonly string _namespace = "websearch";
|
||||
@@ -24,11 +25,11 @@ public class SettingsManager : JsonSettingsManager, ISettingsInterface
|
||||
|
||||
private static readonly List<ChoiceSetSetting.Choice> _choices =
|
||||
[
|
||||
new ChoiceSetSetting.Choice(Resources.history_none, Resources.history_none),
|
||||
new ChoiceSetSetting.Choice(Resources.history_1, Resources.history_1),
|
||||
new ChoiceSetSetting.Choice(Resources.history_5, Resources.history_5),
|
||||
new ChoiceSetSetting.Choice(Resources.history_10, Resources.history_10),
|
||||
new ChoiceSetSetting.Choice(Resources.history_20, Resources.history_20),
|
||||
new ChoiceSetSetting.Choice(Resources.history_none, "None"),
|
||||
new ChoiceSetSetting.Choice(Resources.history_1, "1"),
|
||||
new ChoiceSetSetting.Choice(Resources.history_5, "5"),
|
||||
new ChoiceSetSetting.Choice(Resources.history_10, "10"),
|
||||
new ChoiceSetSetting.Choice(Resources.history_20, "20"),
|
||||
];
|
||||
|
||||
private readonly ToggleSetting _globalIfURI = new(
|
||||
@@ -37,15 +38,15 @@ public class SettingsManager : JsonSettingsManager, ISettingsInterface
|
||||
Resources.plugin_global_if_uri,
|
||||
false);
|
||||
|
||||
private readonly ChoiceSetSetting _showHistory = new(
|
||||
Namespaced(nameof(ShowHistory)),
|
||||
Resources.plugin_show_history,
|
||||
Resources.plugin_show_history,
|
||||
private readonly ChoiceSetSetting _historyItemCount = new(
|
||||
Namespaced(HistoryItemCountLegacySettingsKey),
|
||||
Resources.plugin_history_item_count,
|
||||
Resources.plugin_history_item_count,
|
||||
_choices);
|
||||
|
||||
public bool GlobalIfURI => _globalIfURI.Value;
|
||||
|
||||
public string ShowHistory => _showHistory.Value ?? string.Empty;
|
||||
public uint HistoryItemCount => uint.TryParse(_historyItemCount.Value, out var value) ? value : 0;
|
||||
|
||||
internal static string SettingsJsonPath()
|
||||
{
|
||||
@@ -90,11 +91,11 @@ public class SettingsManager : JsonSettingsManager, ISettingsInterface
|
||||
// Add the new history item
|
||||
historyItems.Add(historyItem);
|
||||
|
||||
// Determine the maximum number of items to keep based on ShowHistory
|
||||
if (int.TryParse(ShowHistory, out var maxHistoryItems) && maxHistoryItems > 0)
|
||||
// Determine the maximum number of items to keep based on HistoryItemCount
|
||||
if (HistoryItemCount > 0)
|
||||
{
|
||||
// Keep only the most recent `maxHistoryItems` items
|
||||
while (historyItems.Count > maxHistoryItems)
|
||||
while (historyItems.Count > HistoryItemCount)
|
||||
{
|
||||
historyItems.RemoveAt(0); // Remove the oldest item
|
||||
}
|
||||
@@ -150,7 +151,7 @@ public class SettingsManager : JsonSettingsManager, ISettingsInterface
|
||||
_historyPath = HistoryStateJsonPath();
|
||||
|
||||
Settings.Add(_globalIfURI);
|
||||
Settings.Add(_showHistory);
|
||||
Settings.Add(_historyItemCount);
|
||||
|
||||
// Load settings from file upon initialization
|
||||
LoadSettings();
|
||||
@@ -188,11 +189,11 @@ public class SettingsManager : JsonSettingsManager, ISettingsInterface
|
||||
base.SaveSettings();
|
||||
try
|
||||
{
|
||||
if (ShowHistory == Resources.history_none)
|
||||
if (HistoryItemCount == 0)
|
||||
{
|
||||
ClearHistory();
|
||||
}
|
||||
else if (int.TryParse(ShowHistory, out var maxHistoryItems) && maxHistoryItems > 0)
|
||||
else if (HistoryItemCount > 0)
|
||||
{
|
||||
// Trim the history file if there are more items than the new limit
|
||||
if (File.Exists(_historyPath))
|
||||
@@ -201,10 +202,10 @@ public class SettingsManager : JsonSettingsManager, ISettingsInterface
|
||||
var historyItems = JsonSerializer.Deserialize<List<HistoryItem>>(existingContent, WebSearchJsonSerializationContext.Default.ListHistoryItem) ?? [];
|
||||
|
||||
// Check if trimming is needed
|
||||
if (historyItems.Count > maxHistoryItems)
|
||||
if (historyItems.Count > HistoryItemCount)
|
||||
{
|
||||
// Trim the list to keep only the most recent `maxHistoryItems` items
|
||||
historyItems = historyItems.Skip(historyItems.Count - maxHistoryItems).ToList();
|
||||
// Trim the list to keep only the most recent `HistoryItemCount` items
|
||||
historyItems = historyItems.Skip((int)(historyItems.Count - HistoryItemCount)).ToList();
|
||||
|
||||
// Save the trimmed history back to the file
|
||||
var trimmedHistoryJson = JsonSerializer.Serialize(historyItems, WebSearchJsonSerializationContext.Default.ListHistoryItem);
|
||||
|
||||
@@ -33,7 +33,7 @@ internal sealed partial class WebSearchListPage : DynamicListPage
|
||||
_allItems = [];
|
||||
Id = "com.microsoft.cmdpal.websearch";
|
||||
_settingsManager = settingsManager;
|
||||
_historyItems = _settingsManager.ShowHistory != Resources.history_none ? _settingsManager.LoadHistory() : null;
|
||||
_historyItems = _settingsManager.HistoryItemCount != 0 ? _settingsManager.LoadHistory() : null;
|
||||
if (_historyItems is not null)
|
||||
{
|
||||
_allItems.AddRange(_historyItems);
|
||||
@@ -57,7 +57,7 @@ internal sealed partial class WebSearchListPage : DynamicListPage
|
||||
|
||||
if (_historyItems is not null)
|
||||
{
|
||||
filteredHistoryItems = _settingsManager.ShowHistory != Resources.history_none ? ListHelpers.FilterList(_historyItems, query).OfType<ListItem>() : null;
|
||||
filteredHistoryItems = _settingsManager.HistoryItemCount != 0 ? ListHelpers.FilterList(_historyItems, query).OfType<ListItem>() : null;
|
||||
}
|
||||
|
||||
var results = new List<ListItem>();
|
||||
|
||||
@@ -168,6 +168,15 @@ namespace Microsoft.CmdPal.Ext.WebSearch.Properties {
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Determines the number of history items to show from previous searches.
|
||||
/// </summary>
|
||||
public static string plugin_history_item_count {
|
||||
get {
|
||||
return ResourceManager.GetString("plugin_history_item_count", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to In the default browser.
|
||||
/// </summary>
|
||||
@@ -231,15 +240,6 @@ namespace Microsoft.CmdPal.Ext.WebSearch.Properties {
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Determines the number of history items to show from previous searches.
|
||||
/// </summary>
|
||||
public static string plugin_show_history {
|
||||
get {
|
||||
return ResourceManager.GetString("plugin_show_history", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Settings.
|
||||
/// </summary>
|
||||
|
||||
@@ -172,7 +172,7 @@
|
||||
<data name="plugin_search_failed" xml:space="preserve">
|
||||
<value>Failed to open {0}.</value>
|
||||
</data>
|
||||
<data name="plugin_show_history" xml:space="preserve">
|
||||
<data name="plugin_history_item_count" xml:space="preserve">
|
||||
<value>Determines the number of history items to show from previous searches</value>
|
||||
</data>
|
||||
<data name="settings_page_name" xml:space="preserve">
|
||||
|
||||
@@ -65,6 +65,7 @@ internal sealed partial class WinGetExtensionPage : DynamicListPage, IDisposable
|
||||
|
||||
if (_results is not null && _results.Count != 0)
|
||||
{
|
||||
var stopwatch = Stopwatch.StartNew();
|
||||
var count = _results.Count;
|
||||
var results = new ListItem[count];
|
||||
var next = 0;
|
||||
@@ -82,6 +83,8 @@ internal sealed partial class WinGetExtensionPage : DynamicListPage, IDisposable
|
||||
}
|
||||
}
|
||||
|
||||
stopwatch.Stop();
|
||||
Logger.LogDebug($"Building ListItems took {stopwatch.ElapsedMilliseconds}ms", memberName: nameof(GetItems));
|
||||
IsLoading = false;
|
||||
return results;
|
||||
}
|
||||
@@ -244,15 +247,22 @@ internal sealed partial class WinGetExtensionPage : DynamicListPage, IDisposable
|
||||
|
||||
// foreach (var catalog in connections)
|
||||
{
|
||||
Stopwatch findPackages_stopwatch = new();
|
||||
findPackages_stopwatch.Start();
|
||||
Logger.LogDebug($" Searching {catalog.Info.Name} ({query})", memberName: nameof(DoSearchAsync));
|
||||
|
||||
ct.ThrowIfCancellationRequested();
|
||||
|
||||
Logger.LogDebug($"Preface for \"{searchDebugText}\" took {stopwatch.ElapsedMilliseconds}ms", memberName: nameof(DoSearchAsync));
|
||||
|
||||
// BODGY, re: microsoft/winget-cli#5151
|
||||
// FindPackagesAsync isn't actually async.
|
||||
var internalSearchTask = Task.Run(() => catalog.FindPackages(opts), ct);
|
||||
var searchResults = await internalSearchTask;
|
||||
|
||||
findPackages_stopwatch.Stop();
|
||||
Logger.LogDebug($"FindPackages for \"{searchDebugText}\" took {findPackages_stopwatch.ElapsedMilliseconds}ms", memberName: nameof(DoSearchAsync));
|
||||
|
||||
// TODO more error handling like this:
|
||||
if (searchResults.Status != FindPackagesResultStatus.Ok)
|
||||
{
|
||||
@@ -261,6 +271,8 @@ internal sealed partial class WinGetExtensionPage : DynamicListPage, IDisposable
|
||||
return [];
|
||||
}
|
||||
|
||||
ct.ThrowIfCancellationRequested();
|
||||
|
||||
Logger.LogDebug($" got results for ({query})", memberName: nameof(DoSearchAsync));
|
||||
|
||||
// FYI Using .ToArray or any other kind of enumerable loop
|
||||
|
||||
@@ -1,39 +0,0 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Resources;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.CmdPal.Ext.WindowsSettings.Classes;
|
||||
using Microsoft.CmdPal.Ext.WindowsSettings.Properties;
|
||||
using Microsoft.CommandPalette.Extensions;
|
||||
using Microsoft.CommandPalette.Extensions.Toolkit;
|
||||
using Windows.ApplicationModel.DataTransfer;
|
||||
using Windows.Networking.NetworkOperators;
|
||||
using Windows.UI;
|
||||
|
||||
namespace Microsoft.CmdPal.Ext.WindowsSettings.Commands;
|
||||
|
||||
internal sealed partial class CopySettingCommand : InvokableCommand
|
||||
{
|
||||
private readonly WindowsSetting _entry;
|
||||
|
||||
internal CopySettingCommand(WindowsSetting entry)
|
||||
{
|
||||
Name = Resources.CopyCommand;
|
||||
Icon = Icons.CopyIcon;
|
||||
_entry = entry;
|
||||
}
|
||||
|
||||
public override CommandResult Invoke()
|
||||
{
|
||||
ClipboardHelper.SetText(_entry.Command);
|
||||
|
||||
return CommandResult.Dismiss();
|
||||
}
|
||||
}
|
||||
@@ -23,7 +23,7 @@ internal static class ContextMenuHelper
|
||||
{
|
||||
var list = new List<CommandContextItem>(1)
|
||||
{
|
||||
new(new CopySettingCommand(entry)),
|
||||
new(new CopyTextCommand(entry.Command) { Name = Resources.CopyCommand }),
|
||||
};
|
||||
|
||||
return list;
|
||||
|
||||
@@ -43,13 +43,18 @@ public partial class ListHelpers
|
||||
}
|
||||
|
||||
public static IEnumerable<T> FilterList<T>(IEnumerable<T> items, string query, Func<string, T, int> scoreFunction)
|
||||
{
|
||||
return FilterListWithScores<T>(items, query, scoreFunction)
|
||||
.Select(score => score.Item);
|
||||
}
|
||||
|
||||
public static IEnumerable<Scored<T>> FilterListWithScores<T>(IEnumerable<T> items, string query, Func<string, T, int> scoreFunction)
|
||||
{
|
||||
var scores = items
|
||||
.Select(li => new Scored<T>() { Item = li, Score = scoreFunction(query, li) })
|
||||
.Where(score => score.Score > 0)
|
||||
.OrderByDescending(score => score.Score);
|
||||
return scores
|
||||
.Select(score => score.Item);
|
||||
return scores;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -372,20 +372,17 @@ namespace UITests_FancyZones
|
||||
// launch FancyZones settings page
|
||||
private void LaunchFancyZones()
|
||||
{
|
||||
if (this.FindAll<NavigationViewItem>("FancyZones").Count == 0)
|
||||
{
|
||||
this.Find<NavigationViewItem>("Windowing & Layouts").Click();
|
||||
}
|
||||
this.Find<NavigationViewItem>(By.AccessibilityId("WindowingAndLayoutsNavItem")).Click();
|
||||
|
||||
this.Find<NavigationViewItem>("FancyZones").Click();
|
||||
this.Find<ToggleSwitch>("Enable FancyZones").Toggle(true);
|
||||
this.Find<NavigationViewItem>(By.AccessibilityId("FancyZonesNavItem")).Click();
|
||||
this.Find<ToggleSwitch>(By.AccessibilityId("EnableFancyZonesToggleSwitch")).Toggle(true);
|
||||
|
||||
this.Session.SetMainWindowSize(WindowSize.Large);
|
||||
Find<Element>(By.AccessibilityId("HeaderPresenter")).Click();
|
||||
this.Scroll(6, "Down"); // Pull the settings page up to make sure the settings are visible
|
||||
ZoneBehaviourSettings(TestContext.TestName);
|
||||
|
||||
this.Find<Microsoft.PowerToys.UITest.Button>("Launch layout editor").Click(false, 500, 10000);
|
||||
this.Find<Microsoft.PowerToys.UITest.Button>(By.AccessibilityId("LaunchLayoutEditorButton")).Click(false, 500, 10000);
|
||||
this.Session.Attach(PowerToysModule.FancyZone);
|
||||
|
||||
// pipeline machine may have an unstable delays, causing the custom layout to be unavailable as we set. then A retry is required.
|
||||
@@ -403,7 +400,7 @@ namespace UITests_FancyZones
|
||||
this.Find<Microsoft.PowerToys.UITest.Button>("Close").Click();
|
||||
this.Session.Attach(PowerToysModule.PowerToysSettings);
|
||||
SetupCustomLayouts();
|
||||
this.Find<Microsoft.PowerToys.UITest.Button>("Launch layout editor").Click(false, 5000, 5000);
|
||||
this.Find<Microsoft.PowerToys.UITest.Button>(By.AccessibilityId("LaunchLayoutEditorButton")).Click(false, 5000, 5000);
|
||||
this.Session.Attach(PowerToysModule.FancyZone);
|
||||
this.Find<Microsoft.PowerToys.UITest.Button>("Maximize").Click();
|
||||
|
||||
|
||||
@@ -15,10 +15,10 @@ namespace RegistryPreview
|
||||
/// </summary>
|
||||
private void AppWindow_Closing(Microsoft.UI.Windowing.AppWindow sender, Microsoft.UI.Windowing.AppWindowClosingEventArgs args)
|
||||
{
|
||||
jsonWindowPlacement.SetNamedValue("appWindow.Position.X", JsonValue.CreateNumberValue(appWindow.Position.X));
|
||||
jsonWindowPlacement.SetNamedValue("appWindow.Position.Y", JsonValue.CreateNumberValue(appWindow.Position.Y));
|
||||
jsonWindowPlacement.SetNamedValue("appWindow.Size.Width", JsonValue.CreateNumberValue(appWindow.Size.Width));
|
||||
jsonWindowPlacement.SetNamedValue("appWindow.Size.Height", JsonValue.CreateNumberValue(appWindow.Size.Height));
|
||||
jsonWindowPlacement.SetNamedValue("appWindow.Position.X", JsonValue.CreateNumberValue(AppWindow.Position.X));
|
||||
jsonWindowPlacement.SetNamedValue("appWindow.Position.Y", JsonValue.CreateNumberValue(AppWindow.Position.Y));
|
||||
jsonWindowPlacement.SetNamedValue("appWindow.Size.Width", JsonValue.CreateNumberValue(AppWindow.Size.Width));
|
||||
jsonWindowPlacement.SetNamedValue("appWindow.Size.Height", JsonValue.CreateNumberValue(AppWindow.Size.Height));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -15,38 +15,19 @@
|
||||
<Window.SystemBackdrop>
|
||||
<MicaBackdrop />
|
||||
</Window.SystemBackdrop>
|
||||
|
||||
<Grid x:Name="MainGrid" Loaded="Grid_Loaded">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="*" />
|
||||
</Grid.RowDefinitions>
|
||||
<Grid
|
||||
x:Name="titleBar"
|
||||
Grid.Row="0"
|
||||
Height="32"
|
||||
Margin="16,0"
|
||||
ColumnSpacing="16"
|
||||
IsHitTestVisible="True">
|
||||
<Grid.ColumnDefinitions>
|
||||
<!--<ColumnDefinition x:Name="LeftPaddingColumn" Width="0"/>-->
|
||||
<ColumnDefinition x:Name="IconColumn" Width="Auto" />
|
||||
<ColumnDefinition x:Name="TitleColumn" Width="Auto" />
|
||||
<!--<ColumnDefinition x:Name="RightPaddingColumn" Width="0"/>-->
|
||||
</Grid.ColumnDefinitions>
|
||||
<Image
|
||||
Grid.Column="0"
|
||||
Width="16"
|
||||
Height="16"
|
||||
VerticalAlignment="Center"
|
||||
Source="../Assets/RegistryPreview/RegistryPreview.ico" />
|
||||
<TextBlock
|
||||
x:Name="titleBarText"
|
||||
Grid.Column="1"
|
||||
VerticalAlignment="Center"
|
||||
Style="{StaticResource CaptionTextBlockStyle}"
|
||||
Text="{Binding ApplicationTitle}" />
|
||||
</Grid>
|
||||
|
||||
<TitleBar x:Name="titleBar">
|
||||
<!-- This is a workaround for https://github.com/microsoft/microsoft-ui-xaml/issues/10374, once fixed we should just be using IconSource -->
|
||||
<TitleBar.LeftHeader>
|
||||
<ImageIcon
|
||||
Height="16"
|
||||
Margin="16,0,0,0"
|
||||
Source="/Assets/RegistryPreview/RegistryPreview.ico" />
|
||||
</TitleBar.LeftHeader>
|
||||
</TitleBar>
|
||||
</Grid>
|
||||
</winuiex:WindowEx>
|
||||
</winuiex:WindowEx>
|
||||
@@ -6,6 +6,7 @@ using System;
|
||||
using ManagedCommon;
|
||||
using Microsoft.PowerToys.Telemetry;
|
||||
using Microsoft.UI;
|
||||
using Microsoft.UI.Windowing;
|
||||
using Microsoft.UI.Xaml;
|
||||
using Microsoft.UI.Xaml.Controls;
|
||||
using Microsoft.UI.Xaml.Media;
|
||||
@@ -23,7 +24,6 @@ namespace RegistryPreview
|
||||
private const string APPNAME = "RegistryPreview";
|
||||
|
||||
// private members
|
||||
private Microsoft.UI.Windowing.AppWindow appWindow;
|
||||
private JsonObject jsonWindowPlacement;
|
||||
private string settingsFolder = string.Empty;
|
||||
private string windowPlacementFile = "app-placement.json";
|
||||
@@ -38,20 +38,15 @@ namespace RegistryPreview
|
||||
settingsFolder = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData) + @"\Microsoft\PowerToys\" + APPNAME;
|
||||
OpenWindowPlacementFile(settingsFolder, windowPlacementFile);
|
||||
|
||||
// Update the Win32 looking window with the correct icon (and grab the appWindow handle for later)
|
||||
IntPtr windowHandle = this.GetWindowHandle();
|
||||
WindowId windowId = Win32Interop.GetWindowIdFromWindow(windowHandle);
|
||||
appWindow = Microsoft.UI.Windowing.AppWindow.GetFromWindowId(windowId);
|
||||
appWindow.SetIcon("Assets\\RegistryPreview\\RegistryPreview.ico");
|
||||
|
||||
// TODO(stefan)
|
||||
appWindow.Closing += AppWindow_Closing;
|
||||
Activated += MainWindow_Activated;
|
||||
AppWindow.Closing += AppWindow_Closing;
|
||||
|
||||
// Extend the canvas to include the title bar so the app can support theming
|
||||
ExtendsContentIntoTitleBar = true;
|
||||
IntPtr windowHandle = this.GetWindowHandle();
|
||||
WindowHelpers.ForceTopBorder1PixelInsetOnWindows10(windowHandle);
|
||||
SetTitleBar(titleBar);
|
||||
AppWindow.SetIcon("Assets\\RegistryPreview\\RegistryPreview.ico");
|
||||
|
||||
// if have settings, update the location of the window
|
||||
if (jsonWindowPlacement != null)
|
||||
@@ -66,7 +61,7 @@ namespace RegistryPreview
|
||||
// check to make sure the size values are reasonable before attempting to restore the last saved size
|
||||
if (size.Width >= 320 && size.Height >= 240)
|
||||
{
|
||||
appWindow.Resize(size);
|
||||
AppWindow.Resize(size);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -80,7 +75,7 @@ namespace RegistryPreview
|
||||
// check to make sure the move values are reasonable before attempting to restore the last saved location
|
||||
if (point.X >= 0 && point.Y >= 0)
|
||||
{
|
||||
appWindow.Move(point);
|
||||
AppWindow.Move(point);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -92,20 +87,6 @@ namespace RegistryPreview
|
||||
PowerToysTelemetry.Log.WriteEvent(new RegistryPreviewEditorStartFinishEvent() { TimeStamp = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds() });
|
||||
}
|
||||
|
||||
private void MainWindow_Activated(object sender, WindowActivatedEventArgs args)
|
||||
{
|
||||
if (args.WindowActivationState == WindowActivationState.Deactivated)
|
||||
{
|
||||
titleBarText.Foreground =
|
||||
(SolidColorBrush)Application.Current.Resources["WindowCaptionForegroundDisabled"];
|
||||
}
|
||||
else
|
||||
{
|
||||
titleBarText.Foreground =
|
||||
(SolidColorBrush)Application.Current.Resources["WindowCaptionForeground"];
|
||||
}
|
||||
}
|
||||
|
||||
private void Grid_Loaded(object sender, RoutedEventArgs e)
|
||||
{
|
||||
MainGrid.Children.Add(MainPage);
|
||||
@@ -118,23 +99,23 @@ namespace RegistryPreview
|
||||
|
||||
if (string.IsNullOrEmpty(filename))
|
||||
{
|
||||
titleBarText.Text = APPNAME;
|
||||
appWindow.Title = APPNAME;
|
||||
titleBar.Title = APPNAME;
|
||||
AppWindow.Title = APPNAME;
|
||||
}
|
||||
else
|
||||
{
|
||||
string[] file = filename.Split('\\');
|
||||
if (file.Length > 0)
|
||||
{
|
||||
titleBarText.Text = file[file.Length - 1] + " - " + APPNAME;
|
||||
titleBar.Title = file[file.Length - 1] + " - " + APPNAME;
|
||||
}
|
||||
else
|
||||
{
|
||||
titleBarText.Text = filename + " - " + APPNAME;
|
||||
titleBar.Title = filename + " - " + APPNAME;
|
||||
}
|
||||
|
||||
// Continue to update the window's title, after updating the custom title bar
|
||||
appWindow.Title = titleBarText.Text;
|
||||
AppWindow.Title = titleBar.Title;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,14 +14,14 @@ using Windows.UI;
|
||||
|
||||
namespace Microsoft.PowerToys.Settings.UI.Helpers;
|
||||
|
||||
public abstract partial class NavigatablePage : Page
|
||||
public abstract partial class NavigablePage : Page
|
||||
{
|
||||
private const int ExpandWaitDuration = 500;
|
||||
private const int AnimationDuration = 1850;
|
||||
|
||||
private NavigationParams _pendingNavigationParams;
|
||||
|
||||
public NavigatablePage()
|
||||
public NavigablePage()
|
||||
{
|
||||
Loaded += OnPageLoaded;
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
<local:NavigatablePage
|
||||
<local:NavigablePage
|
||||
x:Class="Microsoft.PowerToys.Settings.UI.Views.AdvancedPastePage"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
@@ -12,7 +12,7 @@
|
||||
x:Name="RootPage"
|
||||
AutomationProperties.LandmarkType="Main"
|
||||
mc:Ignorable="d">
|
||||
<local:NavigatablePage.Resources>
|
||||
<local:NavigablePage.Resources>
|
||||
<ResourceDictionary>
|
||||
<ResourceDictionary.ThemeDictionaries>
|
||||
<ResourceDictionary x:Key="Default">
|
||||
@@ -38,7 +38,7 @@
|
||||
</StackPanel>
|
||||
</DataTemplate>
|
||||
</ResourceDictionary>
|
||||
</local:NavigatablePage.Resources>
|
||||
</local:NavigablePage.Resources>
|
||||
<Grid>
|
||||
<controls:SettingsPageControl x:Uid="AdvancedPaste" ModuleImageSource="ms-appx:///Assets/Settings/Modules/AdvancedPaste.png">
|
||||
<controls:SettingsPageControl.ModuleContent>
|
||||
@@ -425,4 +425,4 @@
|
||||
</StackPanel>
|
||||
</ContentDialog>
|
||||
</Grid>
|
||||
</local:NavigatablePage>
|
||||
</local:NavigablePage>
|
||||
|
||||
@@ -15,7 +15,7 @@ using Microsoft.UI.Xaml.Controls;
|
||||
|
||||
namespace Microsoft.PowerToys.Settings.UI.Views
|
||||
{
|
||||
public sealed partial class AdvancedPastePage : NavigatablePage, IRefreshablePage
|
||||
public sealed partial class AdvancedPastePage : NavigablePage, IRefreshablePage
|
||||
{
|
||||
private AdvancedPasteViewModel ViewModel { get; set; }
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<local:NavigatablePage
|
||||
<local:NavigablePage
|
||||
x:Class="Microsoft.PowerToys.Settings.UI.Views.AlwaysOnTopPage"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
@@ -136,4 +136,4 @@
|
||||
<controls:PageLink x:Uid="LearnMore_AlwaysOnTop" Link="https://aka.ms/PowerToysOverview_AlwaysOnTop" />
|
||||
</controls:SettingsPageControl.PrimaryLinks>
|
||||
</controls:SettingsPageControl>
|
||||
</local:NavigatablePage>
|
||||
</local:NavigablePage>
|
||||
|
||||
@@ -9,7 +9,7 @@ using Microsoft.UI.Xaml.Controls;
|
||||
|
||||
namespace Microsoft.PowerToys.Settings.UI.Views
|
||||
{
|
||||
public sealed partial class AlwaysOnTopPage : NavigatablePage, IRefreshablePage
|
||||
public sealed partial class AlwaysOnTopPage : NavigablePage, IRefreshablePage
|
||||
{
|
||||
private AlwaysOnTopViewModel ViewModel { get; set; }
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<local:NavigatablePage
|
||||
<local:NavigablePage
|
||||
x:Class="Microsoft.PowerToys.Settings.UI.Views.AwakePage"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
@@ -14,9 +14,9 @@
|
||||
AutomationProperties.LandmarkType="Main"
|
||||
mc:Ignorable="d">
|
||||
|
||||
<local:NavigatablePage.Resources>
|
||||
<local:NavigablePage.Resources>
|
||||
<converters:AwakeModeToIntConverter x:Key="AwakeModeToIntConverter" />
|
||||
</local:NavigatablePage.Resources>
|
||||
</local:NavigablePage.Resources>
|
||||
|
||||
<controls:SettingsPageControl
|
||||
x:Uid="Awake"
|
||||
@@ -119,4 +119,4 @@
|
||||
<controls:PageLink x:Uid="SecondaryLink_Awake" Link="https://awake.den.dev" />
|
||||
</controls:SettingsPageControl.SecondaryLinks>
|
||||
</controls:SettingsPageControl>
|
||||
</local:NavigatablePage>
|
||||
</local:NavigablePage>
|
||||
|
||||
@@ -17,7 +17,7 @@ using PowerToys.GPOWrapper;
|
||||
|
||||
namespace Microsoft.PowerToys.Settings.UI.Views
|
||||
{
|
||||
public sealed partial class AwakePage : NavigatablePage, IRefreshablePage
|
||||
public sealed partial class AwakePage : NavigablePage, IRefreshablePage
|
||||
{
|
||||
private readonly string _appName = "Awake";
|
||||
private readonly SettingsUtils _settingsUtils;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<local:NavigatablePage
|
||||
<local:NavigablePage
|
||||
x:Class="Microsoft.PowerToys.Settings.UI.Views.CmdNotFoundPage"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
@@ -170,4 +170,4 @@
|
||||
<controls:PageLink x:Uid="LearnMore_CmdNotFound" Link="https://aka.ms/PowerToysOverview_CmdNotFound" />
|
||||
</controls:SettingsPageControl.PrimaryLinks>
|
||||
</controls:SettingsPageControl>
|
||||
</local:NavigatablePage>
|
||||
</local:NavigablePage>
|
||||
|
||||
@@ -8,7 +8,7 @@ using Microsoft.UI.Xaml.Controls;
|
||||
|
||||
namespace Microsoft.PowerToys.Settings.UI.Views
|
||||
{
|
||||
public sealed partial class CmdNotFoundPage : NavigatablePage
|
||||
public sealed partial class CmdNotFoundPage : NavigablePage
|
||||
{
|
||||
private CmdNotFoundViewModel ViewModel { get; set; }
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<local:NavigatablePage
|
||||
<local:NavigablePage
|
||||
x:Class="Microsoft.PowerToys.Settings.UI.Views.CmdPalPage"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
@@ -52,4 +52,4 @@
|
||||
<controls:PageLink x:Uid="LearnMore_CmdPal" Link="https://aka.ms/PowerToysOverview_CmdPal" />
|
||||
</controls:SettingsPageControl.PrimaryLinks>
|
||||
</controls:SettingsPageControl>
|
||||
</local:NavigatablePage>
|
||||
</local:NavigablePage>
|
||||
|
||||
@@ -13,7 +13,7 @@ using Microsoft.UI.Xaml.Controls;
|
||||
|
||||
namespace Microsoft.PowerToys.Settings.UI.Views
|
||||
{
|
||||
public sealed partial class CmdPalPage : NavigatablePage, IRefreshablePage
|
||||
public sealed partial class CmdPalPage : NavigablePage, IRefreshablePage
|
||||
{
|
||||
private CmdPalViewModel ViewModel { get; set; }
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<local:NavigatablePage
|
||||
<local:NavigablePage
|
||||
x:Class="Microsoft.PowerToys.Settings.UI.Views.ColorPickerPage"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
@@ -232,4 +232,4 @@
|
||||
<controls:PageLink Link="https://medium.com/@Niels9001/a-fluent-color-meter-for-powertoys-20407ededf0c" Text="Niels Laute's UX concept" />
|
||||
</controls:SettingsPageControl.SecondaryLinks>
|
||||
</controls:SettingsPageControl>
|
||||
</local:NavigatablePage>
|
||||
</local:NavigablePage>
|
||||
@@ -15,7 +15,7 @@ using Microsoft.Windows.ApplicationModel.Resources;
|
||||
|
||||
namespace Microsoft.PowerToys.Settings.UI.Views
|
||||
{
|
||||
public sealed partial class ColorPickerPage : NavigatablePage, IRefreshablePage
|
||||
public sealed partial class ColorPickerPage : NavigablePage, IRefreshablePage
|
||||
{
|
||||
public ColorPickerViewModel ViewModel { get; set; }
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<local:NavigatablePage
|
||||
<local:NavigablePage
|
||||
x:Class="Microsoft.PowerToys.Settings.UI.Views.CropAndLockPage"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
@@ -66,4 +66,4 @@
|
||||
<controls:PageLink Link="https://github.com/kevinguo305" Text="Kevin Guo" />
|
||||
</controls:SettingsPageControl.SecondaryLinks>
|
||||
</controls:SettingsPageControl>
|
||||
</local:NavigatablePage>
|
||||
</local:NavigablePage>
|
||||
|
||||
@@ -9,7 +9,7 @@ using Microsoft.UI.Xaml.Controls;
|
||||
|
||||
namespace Microsoft.PowerToys.Settings.UI.Views
|
||||
{
|
||||
public sealed partial class CropAndLockPage : NavigatablePage, IRefreshablePage
|
||||
public sealed partial class CropAndLockPage : NavigablePage, IRefreshablePage
|
||||
{
|
||||
private CropAndLockViewModel ViewModel { get; set; }
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<local:NavigatablePage
|
||||
<local:NavigablePage
|
||||
x:Class="Microsoft.PowerToys.Settings.UI.Views.DashboardPage"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
@@ -14,7 +14,7 @@
|
||||
AutomationProperties.LandmarkType="Main"
|
||||
DataContext="DashboardViewModel"
|
||||
mc:Ignorable="d">
|
||||
<local:NavigatablePage.Resources>
|
||||
<local:NavigablePage.Resources>
|
||||
<converters:ModuleItemTemplateSelector
|
||||
x:Key="ModuleItemTemplateSelector"
|
||||
ActivationTemplate="{StaticResource ModuleItemActivationTemplate}"
|
||||
@@ -74,7 +74,7 @@
|
||||
TextWrapping="WrapWholeWords" />
|
||||
</Grid>
|
||||
</DataTemplate>
|
||||
</local:NavigatablePage.Resources>
|
||||
</local:NavigablePage.Resources>
|
||||
<Grid Margin="16,0,0,0" RowSpacing="12">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
@@ -269,7 +269,7 @@
|
||||
</controls:Card>
|
||||
<controls:Card
|
||||
x:Name="ModulesCard"
|
||||
Title="Modules"
|
||||
x:Uid="UtilitiesHeader"
|
||||
Grid.RowSpan="2"
|
||||
Grid.Column="1"
|
||||
MinWidth="400"
|
||||
@@ -363,4 +363,4 @@
|
||||
</VisualStateGroup>
|
||||
</VisualStateManager.VisualStateGroups>
|
||||
</Grid>
|
||||
</local:NavigatablePage>
|
||||
</local:NavigablePage>
|
||||
|
||||
@@ -20,7 +20,7 @@ namespace Microsoft.PowerToys.Settings.UI.Views
|
||||
/// <summary>
|
||||
/// Dashboard Settings Page.
|
||||
/// </summary>
|
||||
public sealed partial class DashboardPage : NavigatablePage, IRefreshablePage
|
||||
public sealed partial class DashboardPage : NavigablePage, IRefreshablePage
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets view model.
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<local:NavigatablePage
|
||||
<local:NavigablePage
|
||||
x:Class="Microsoft.PowerToys.Settings.UI.Views.EnvironmentVariablesPage"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
@@ -53,4 +53,4 @@
|
||||
<controls:PageLink x:Uid="LearnMore_EnvironmentVariables" Link="https://aka.ms/PowerToysOverview_EnvironmentVariables" />
|
||||
</controls:SettingsPageControl.PrimaryLinks>
|
||||
</controls:SettingsPageControl>
|
||||
</local:NavigatablePage>
|
||||
</local:NavigablePage>
|
||||
|
||||
@@ -9,7 +9,7 @@ using Microsoft.UI.Xaml.Controls;
|
||||
|
||||
namespace Microsoft.PowerToys.Settings.UI.Views
|
||||
{
|
||||
public sealed partial class EnvironmentVariablesPage : NavigatablePage, IRefreshablePage
|
||||
public sealed partial class EnvironmentVariablesPage : NavigablePage, IRefreshablePage
|
||||
{
|
||||
private EnvironmentVariablesViewModel ViewModel { get; }
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<local:NavigatablePage
|
||||
<local:NavigablePage
|
||||
x:Class="Microsoft.PowerToys.Settings.UI.Views.FancyZonesPage"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
@@ -19,7 +19,11 @@
|
||||
x:Uid="FancyZones_EnableToggleControl_HeaderText"
|
||||
HeaderIcon="{ui:BitmapIcon Source=/Assets/Settings/Icons/FancyZones.png}"
|
||||
IsEnabled="{x:Bind ViewModel.IsEnabledGpoConfigured, Mode=OneWay, Converter={StaticResource BoolNegationConverter}}">
|
||||
<ToggleSwitch x:Uid="ToggleSwitch" IsOn="{x:Bind ViewModel.IsEnabled, Mode=TwoWay}" />
|
||||
<ToggleSwitch
|
||||
x:Name="EnableFancyZonesToggleSwitch"
|
||||
x:Uid="ToggleSwitch"
|
||||
AutomationProperties.AutomationId="EnableFancyZonesToggleSwitch"
|
||||
IsOn="{x:Bind ViewModel.IsEnabled, Mode=TwoWay}" />
|
||||
</tkcontrols:SettingsCard>
|
||||
<InfoBar
|
||||
x:Uid="GPO_SettingIsManaged"
|
||||
@@ -311,4 +315,4 @@
|
||||
<controls:PageLink x:Uid="LearnMore_FancyZones" Link="https://aka.ms/PowerToysOverview_FancyZones" />
|
||||
</controls:SettingsPageControl.PrimaryLinks>
|
||||
</controls:SettingsPageControl>
|
||||
</local:NavigatablePage>
|
||||
</local:NavigablePage>
|
||||
@@ -9,7 +9,7 @@ using Microsoft.UI.Xaml.Controls;
|
||||
|
||||
namespace Microsoft.PowerToys.Settings.UI.Views
|
||||
{
|
||||
public sealed partial class FancyZonesPage : NavigatablePage, IRefreshablePage
|
||||
public sealed partial class FancyZonesPage : NavigablePage, IRefreshablePage
|
||||
{
|
||||
private FancyZonesViewModel ViewModel { get; set; }
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<local:NavigatablePage
|
||||
<local:NavigablePage
|
||||
x:Class="Microsoft.PowerToys.Settings.UI.Views.FileLocksmithPage"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
@@ -53,4 +53,4 @@
|
||||
<controls:PageLink x:Uid="LearnMore_FileLocksmith" Link="https://aka.ms/PowerToysOverview_FileLocksmith" />
|
||||
</controls:SettingsPageControl.PrimaryLinks>
|
||||
</controls:SettingsPageControl>
|
||||
</local:NavigatablePage>
|
||||
</local:NavigablePage>
|
||||
|
||||
@@ -9,7 +9,7 @@ using Microsoft.UI.Xaml.Controls;
|
||||
|
||||
namespace Microsoft.PowerToys.Settings.UI.Views
|
||||
{
|
||||
public sealed partial class FileLocksmithPage : NavigatablePage, IRefreshablePage
|
||||
public sealed partial class FileLocksmithPage : NavigablePage, IRefreshablePage
|
||||
{
|
||||
private FileLocksmithViewModel ViewModel { get; set; }
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<local:NavigatablePage
|
||||
<local:NavigablePage
|
||||
x:Class="Microsoft.PowerToys.Settings.UI.Views.GeneralPage"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
@@ -12,10 +12,10 @@
|
||||
AutomationProperties.LandmarkType="Main"
|
||||
mc:Ignorable="d">
|
||||
|
||||
<local:NavigatablePage.Resources>
|
||||
<local:NavigablePage.Resources>
|
||||
<converters:UpdateStateToBoolConverter x:Key="UpdateStateToBoolConverter" />
|
||||
<converters:StringToInfoBarSeverityConverter x:Key="StringToInfoBarSeverityConverter" />
|
||||
</local:NavigatablePage.Resources>
|
||||
</local:NavigablePage.Resources>
|
||||
|
||||
<controls:SettingsPageControl x:Uid="General" ModuleImageSource="ms-appx:///Assets/Settings/Modules/PT.png">
|
||||
<controls:SettingsPageControl.ModuleContent>
|
||||
@@ -517,4 +517,4 @@
|
||||
<controls:PageLink x:Uid="OpenSource_Notice" Link="https://github.com/microsoft/PowerToys/blob/main/NOTICE.md" />
|
||||
</controls:SettingsPageControl.SecondaryLinks>
|
||||
</controls:SettingsPageControl>
|
||||
</local:NavigatablePage>
|
||||
</local:NavigablePage>
|
||||
|
||||
@@ -19,7 +19,7 @@ namespace Microsoft.PowerToys.Settings.UI.Views
|
||||
/// <summary>
|
||||
/// General Settings Page.
|
||||
/// </summary>
|
||||
public sealed partial class GeneralPage : NavigatablePage, IRefreshablePage
|
||||
public sealed partial class GeneralPage : NavigablePage, IRefreshablePage
|
||||
{
|
||||
private static DateTime OkToHideBackupAndRestoreMessageTime { get; set; }
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<local:NavigatablePage
|
||||
<local:NavigablePage
|
||||
x:Class="Microsoft.PowerToys.Settings.UI.Views.HostsPage"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
@@ -86,4 +86,4 @@
|
||||
<controls:PageLink x:Uid="LearnMore_Hosts" Link="https://aka.ms/PowerToysOverview_HostsFileEditor" />
|
||||
</controls:SettingsPageControl.PrimaryLinks>
|
||||
</controls:SettingsPageControl>
|
||||
</local:NavigatablePage>
|
||||
</local:NavigablePage>
|
||||
|
||||
@@ -9,7 +9,7 @@ using Microsoft.UI.Xaml.Controls;
|
||||
|
||||
namespace Microsoft.PowerToys.Settings.UI.Views
|
||||
{
|
||||
public sealed partial class HostsPage : NavigatablePage, IRefreshablePage
|
||||
public sealed partial class HostsPage : NavigablePage, IRefreshablePage
|
||||
{
|
||||
private HostsViewModel ViewModel { get; }
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<local:NavigatablePage
|
||||
<local:NavigablePage
|
||||
x:Class="Microsoft.PowerToys.Settings.UI.Views.ImageResizerPage"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
@@ -14,7 +14,7 @@
|
||||
x:Name="RootPage"
|
||||
AutomationProperties.LandmarkType="Main"
|
||||
mc:Ignorable="d">
|
||||
<local:NavigatablePage.Resources>
|
||||
<local:NavigablePage.Resources>
|
||||
<converters:ImageResizerFitToStringConverter x:Key="ImageResizerFitToStringConverter" />
|
||||
<converters:ImageResizerFitToIntConverter x:Key="ImageResizerFitToIntConverter" />
|
||||
<converters:ImageResizerUnitToStringConverter x:Key="ImageResizerUnitToStringConverter" />
|
||||
@@ -27,7 +27,7 @@
|
||||
x:Key="BoolToComboBoxIndexConverter"
|
||||
FalseValue="1"
|
||||
TrueValue="0" />
|
||||
</local:NavigatablePage.Resources>
|
||||
</local:NavigablePage.Resources>
|
||||
<controls:SettingsPageControl x:Uid="ImageResizer" ModuleImageSource="ms-appx:///Assets/Settings/Modules/ImageResizer.png">
|
||||
<controls:SettingsPageControl.ModuleContent>
|
||||
<StackPanel ChildrenTransitions="{StaticResource SettingsCardsAnimations}">
|
||||
@@ -303,4 +303,4 @@
|
||||
<controls:PageLink Link="https://github.com/bricelam/ImageResizer/" Text="Brice Lambson's ImageResizer" />
|
||||
</controls:SettingsPageControl.SecondaryLinks>
|
||||
</controls:SettingsPageControl>
|
||||
</local:NavigatablePage>
|
||||
</local:NavigablePage>
|
||||
@@ -14,7 +14,7 @@ using Microsoft.UI.Xaml.Controls;
|
||||
|
||||
namespace Microsoft.PowerToys.Settings.UI.Views
|
||||
{
|
||||
public sealed partial class ImageResizerPage : NavigatablePage, IRefreshablePage
|
||||
public sealed partial class ImageResizerPage : NavigablePage, IRefreshablePage
|
||||
{
|
||||
public ImageResizerViewModel ViewModel { get; set; }
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<local:NavigatablePage
|
||||
<local:NavigablePage
|
||||
x:Class="Microsoft.PowerToys.Settings.UI.Views.KeyboardManagerPage"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
@@ -13,7 +13,7 @@
|
||||
AutomationProperties.LandmarkType="Main"
|
||||
mc:Ignorable="d">
|
||||
|
||||
<local:NavigatablePage.Resources>
|
||||
<local:NavigablePage.Resources>
|
||||
<tkconverters:CollectionVisibilityConverter x:Key="CollectionVisibilityConverter" />
|
||||
<Style x:Name="KeysListViewContainerStyle" TargetType="ListViewItem">
|
||||
<Setter Property="IsTabStop" Value="False" />
|
||||
@@ -51,7 +51,7 @@
|
||||
Height="56">
|
||||
|
||||
</DataTemplate>-->
|
||||
</local:NavigatablePage.Resources>
|
||||
</local:NavigablePage.Resources>
|
||||
|
||||
<controls:SettingsPageControl x:Uid="KeyboardManager" ModuleImageSource="ms-appx:///Assets/Settings/Modules/KBM.png">
|
||||
<controls:SettingsPageControl.ModuleContent>
|
||||
@@ -235,4 +235,4 @@
|
||||
<controls:PageLink x:Uid="LearnMore_KBM" Link="https://aka.ms/PowerToysOverview_KeyboardManager" />
|
||||
</controls:SettingsPageControl.PrimaryLinks>
|
||||
</controls:SettingsPageControl>
|
||||
</local:NavigatablePage>
|
||||
</local:NavigablePage>
|
||||
|
||||
@@ -18,7 +18,7 @@ namespace Microsoft.PowerToys.Settings.UI.Views
|
||||
/// <summary>
|
||||
/// An empty page that can be used on its own or navigated to within a Frame.
|
||||
/// </summary>
|
||||
public sealed partial class KeyboardManagerPage : NavigatablePage, IRefreshablePage
|
||||
public sealed partial class KeyboardManagerPage : NavigablePage, IRefreshablePage
|
||||
{
|
||||
private const string PowerToyName = "Keyboard Manager";
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<local:NavigatablePage
|
||||
<local:NavigablePage
|
||||
x:Class="Microsoft.PowerToys.Settings.UI.Views.MeasureToolPage"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
@@ -108,4 +108,4 @@
|
||||
<controls:PageLink x:Uid="Attribution_Rooler" Link="https://github.com/peteblois/rooler" />
|
||||
</controls:SettingsPageControl.SecondaryLinks>
|
||||
</controls:SettingsPageControl>
|
||||
</local:NavigatablePage>
|
||||
</local:NavigablePage>
|
||||
|
||||
@@ -9,7 +9,7 @@ using Microsoft.UI.Xaml.Controls;
|
||||
|
||||
namespace Microsoft.PowerToys.Settings.UI.Views
|
||||
{
|
||||
public sealed partial class MeasureToolPage : NavigatablePage, IRefreshablePage
|
||||
public sealed partial class MeasureToolPage : NavigablePage, IRefreshablePage
|
||||
{
|
||||
private MeasureToolViewModel ViewModel { get; set; }
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<local:NavigatablePage
|
||||
<local:NavigablePage
|
||||
x:Class="Microsoft.PowerToys.Settings.UI.Views.MouseUtilsPage"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
@@ -13,13 +13,13 @@
|
||||
xmlns:ui="using:CommunityToolkit.WinUI"
|
||||
AutomationProperties.LandmarkType="Main"
|
||||
mc:Ignorable="d">
|
||||
<local:NavigatablePage.Resources>
|
||||
<local:NavigablePage.Resources>
|
||||
<converters:IndexBitFieldToVisibilityConverter x:Key="IndexBitFieldToVisibilityConverter" />
|
||||
<tkconverters:BoolToVisibilityConverter
|
||||
x:Key="BoolToInvertedVisibilityConverter"
|
||||
FalseValue="Visible"
|
||||
TrueValue="Collapsed" />
|
||||
</local:NavigatablePage.Resources>
|
||||
</local:NavigablePage.Resources>
|
||||
<controls:SettingsPageControl x:Uid="MouseUtils" ModuleImageSource="ms-appx:///Assets/Settings/Modules/MouseUtils.png">
|
||||
<controls:SettingsPageControl.ModuleContent>
|
||||
<StackPanel ChildrenTransitions="{StaticResource SettingsCardsAnimations}" Orientation="Vertical">
|
||||
@@ -423,4 +423,4 @@
|
||||
<controls:PageLink Link="https://michael-clayton.com/projects/fancymouse" Text="Michael Clayton's Mouse Jump (FancyMouse)" />
|
||||
</controls:SettingsPageControl.SecondaryLinks>
|
||||
</controls:SettingsPageControl>
|
||||
</local:NavigatablePage>
|
||||
</local:NavigablePage>
|
||||
|
||||
@@ -12,7 +12,7 @@ using Microsoft.UI.Xaml.Controls;
|
||||
|
||||
namespace Microsoft.PowerToys.Settings.UI.Views
|
||||
{
|
||||
public sealed partial class MouseUtilsPage : NavigatablePage, IRefreshablePage
|
||||
public sealed partial class MouseUtilsPage : NavigablePage, IRefreshablePage
|
||||
{
|
||||
private MouseUtilsViewModel ViewModel { get; set; }
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<local:NavigatablePage
|
||||
<local:NavigablePage
|
||||
x:Class="Microsoft.PowerToys.Settings.UI.Views.MouseWithoutBordersPage"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
@@ -11,13 +11,13 @@
|
||||
xmlns:ui="using:CommunityToolkit.WinUI"
|
||||
AutomationProperties.LandmarkType="Main"
|
||||
mc:Ignorable="d">
|
||||
<local:NavigatablePage.Resources>
|
||||
<local:NavigablePage.Resources>
|
||||
<converters:BoolToVisibilityConverter x:Key="negativeBoolToVisibilityConverter" />
|
||||
<converters:BoolToObjectConverter
|
||||
x:Key="OneRowMatrixBoolToNumberOfRowsConverter"
|
||||
FalseValue="2"
|
||||
TrueValue="4" />
|
||||
</local:NavigatablePage.Resources>
|
||||
</local:NavigablePage.Resources>
|
||||
<controls:SettingsPageControl x:Uid="MouseWithoutBorders" ModuleImageSource="ms-appx:///Assets/Settings/Modules/MouseWithoutBorders.png">
|
||||
<controls:SettingsPageControl.ModuleContent>
|
||||
<StackPanel Orientation="Vertical">
|
||||
@@ -524,4 +524,4 @@
|
||||
<controls:PageLink Link="https://github.com/microsoft/PowerToys/blob/main/COMMUNITY.md#mouse-without-borders-original-contributors" Text="Truong Do (Đỗ Đức Trường) and other original contributors" />
|
||||
</controls:SettingsPageControl.SecondaryLinks>
|
||||
</controls:SettingsPageControl>
|
||||
</local:NavigatablePage>
|
||||
</local:NavigablePage>
|
||||
|
||||
@@ -21,7 +21,7 @@ using static Microsoft.PowerToys.Settings.UI.ViewModels.MouseWithoutBordersViewM
|
||||
|
||||
namespace Microsoft.PowerToys.Settings.UI.Views
|
||||
{
|
||||
public sealed partial class MouseWithoutBordersPage : NavigatablePage, IRefreshablePage
|
||||
public sealed partial class MouseWithoutBordersPage : NavigablePage, IRefreshablePage
|
||||
{
|
||||
private const string MouseWithoutBordersDragDropCheckString = "MWB Device Drag Drop";
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<helper:NavigatablePage
|
||||
<helper:NavigablePage
|
||||
x:Class="Microsoft.PowerToys.Settings.UI.Views.NewPlusPage"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
@@ -215,4 +215,4 @@
|
||||
</controls:SettingsPageControl.SecondaryLinks>
|
||||
</controls:SettingsPageControl>
|
||||
|
||||
</helper:NavigatablePage>
|
||||
</helper:NavigablePage>
|
||||
|
||||
@@ -9,7 +9,7 @@ using Microsoft.UI.Xaml.Controls;
|
||||
|
||||
namespace Microsoft.PowerToys.Settings.UI.Views
|
||||
{
|
||||
public sealed partial class NewPlusPage : NavigatablePage, IRefreshablePage
|
||||
public sealed partial class NewPlusPage : NavigablePage, IRefreshablePage
|
||||
{
|
||||
private NewPlusViewModel ViewModel { get; set; }
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<local:NavigatablePage
|
||||
<local:NavigablePage
|
||||
x:Class="Microsoft.PowerToys.Settings.UI.Views.PeekPage"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
@@ -104,4 +104,4 @@
|
||||
<controls:PageLink x:Uid="LearnMore_Peek" Link="https://aka.ms/PowerToysOverview_Peek" />
|
||||
</controls:SettingsPageControl.PrimaryLinks>
|
||||
</controls:SettingsPageControl>
|
||||
</local:NavigatablePage>
|
||||
</local:NavigablePage>
|
||||
|
||||
@@ -9,7 +9,7 @@ using Microsoft.UI.Xaml.Controls;
|
||||
|
||||
namespace Microsoft.PowerToys.Settings.UI.Views
|
||||
{
|
||||
public sealed partial class PeekPage : NavigatablePage, IRefreshablePage
|
||||
public sealed partial class PeekPage : NavigablePage, IRefreshablePage
|
||||
{
|
||||
private PeekViewModel ViewModel { get; set; }
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<local:NavigatablePage
|
||||
<local:NavigablePage
|
||||
x:Class="Microsoft.PowerToys.Settings.UI.Views.PowerAccentPage"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
@@ -11,7 +11,7 @@
|
||||
xmlns:ui="using:CommunityToolkit.WinUI"
|
||||
AutomationProperties.LandmarkType="Main"
|
||||
mc:Ignorable="d">
|
||||
<local:NavigatablePage.Resources>
|
||||
<local:NavigablePage.Resources>
|
||||
<CollectionViewSource
|
||||
x:Name="LanguagesCustomViewSource"
|
||||
IsSourceGrouped="True"
|
||||
@@ -19,7 +19,7 @@
|
||||
<DataTemplate x:Key="LanguageViewTemplate" x:DataType="Lib:PowerAccentLanguageModel">
|
||||
<TextBlock Text="{x:Bind Language}" />
|
||||
</DataTemplate>
|
||||
</local:NavigatablePage.Resources>
|
||||
</local:NavigablePage.Resources>
|
||||
|
||||
<controls:SettingsPageControl
|
||||
x:Uid="QuickAccent"
|
||||
@@ -241,4 +241,4 @@
|
||||
<controls:PageLink Link="https://github.com/damienleroy/PowerAccent" Text="Damien Leroy's PowerAccent" />
|
||||
</controls:SettingsPageControl.SecondaryLinks>
|
||||
</controls:SettingsPageControl>
|
||||
</local:NavigatablePage>
|
||||
</local:NavigablePage>
|
||||
|
||||
@@ -11,7 +11,7 @@ using Microsoft.UI.Xaml.Controls;
|
||||
|
||||
namespace Microsoft.PowerToys.Settings.UI.Views
|
||||
{
|
||||
public sealed partial class PowerAccentPage : NavigatablePage, IRefreshablePage
|
||||
public sealed partial class PowerAccentPage : NavigablePage, IRefreshablePage
|
||||
{
|
||||
private PowerAccentViewModel ViewModel { get; set; }
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<local:NavigatablePage
|
||||
<local:NavigablePage
|
||||
x:Class="Microsoft.PowerToys.Settings.UI.Views.PowerLauncherPage"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
@@ -15,7 +15,7 @@
|
||||
AutomationProperties.LandmarkType="Main"
|
||||
mc:Ignorable="d">
|
||||
|
||||
<local:NavigatablePage.Resources>
|
||||
<local:NavigablePage.Resources>
|
||||
<Style x:Key="OptionSeparator" TargetType="Rectangle">
|
||||
<Setter Property="Height" Value="1" />
|
||||
<Setter Property="HorizontalAlignment" Value="Stretch" />
|
||||
@@ -304,7 +304,7 @@
|
||||
<DataTemplate x:Key="EmptyTemplate" x:DataType="viewModels:PluginAdditionalOptionViewModel">
|
||||
<StackPanel HorizontalAlignment="Stretch" Orientation="Vertical" />
|
||||
</DataTemplate>
|
||||
</local:NavigatablePage.Resources>
|
||||
</local:NavigablePage.Resources>
|
||||
|
||||
<controls:SettingsPageControl x:Uid="PowerLauncher" ModuleImageSource="ms-appx:///Assets/Settings/Modules/Run.png">
|
||||
<controls:SettingsPageControl.ModuleContent>
|
||||
@@ -816,4 +816,4 @@
|
||||
<controls:PageLink Link="https://github.com/betsegaw/windowwalker/" Text="Beta Tadele's Window Walker" />
|
||||
</controls:SettingsPageControl.SecondaryLinks>
|
||||
</controls:SettingsPageControl>
|
||||
</local:NavigatablePage>
|
||||
</local:NavigablePage>
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user