mirror of
https://github.com/microsoft/PowerToys.git
synced 2026-01-30 07:57:34 +01:00
Compare commits
8 Commits
cinnamon-m
...
leilzh/rel
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3e6c81f955 | ||
|
|
67a15d2b1b | ||
|
|
77265b9df6 | ||
|
|
693a131036 | ||
|
|
fc87f03fd5 | ||
|
|
9850a19aac | ||
|
|
9c3df634b4 | ||
|
|
13731e8af1 |
1
.github/actions/spell-check/expect.txt
vendored
1
.github/actions/spell-check/expect.txt
vendored
@@ -70,7 +70,6 @@ APPMODEL
|
||||
APPNAME
|
||||
appref
|
||||
appsettings
|
||||
appsfeatures
|
||||
appwindow
|
||||
appwiz
|
||||
appxpackage
|
||||
|
||||
@@ -1,20 +0,0 @@
|
||||
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
|
||||
@@ -122,13 +122,13 @@ namespace ManagedCommon
|
||||
{
|
||||
var exMessage =
|
||||
message + Environment.NewLine +
|
||||
ex.GetType() + " (" + ex.HResult + "): " + ex.Message + Environment.NewLine;
|
||||
ex.GetType() + ": " + ex.Message + Environment.NewLine;
|
||||
|
||||
if (ex.InnerException != null)
|
||||
{
|
||||
exMessage +=
|
||||
"Inner exception: " + Environment.NewLine +
|
||||
ex.InnerException.GetType() + " (" + ex.HResult + "): " + ex.InnerException.Message + Environment.NewLine;
|
||||
ex.InnerException.GetType() + ": " + ex.InnerException.Message + Environment.NewLine;
|
||||
}
|
||||
|
||||
exMessage +=
|
||||
|
||||
@@ -20,14 +20,27 @@
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="*" />
|
||||
</Grid.RowDefinitions>
|
||||
<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
|
||||
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>
|
||||
</Grid>
|
||||
</winuiex:WindowEx>
|
||||
|
||||
@@ -4,19 +4,22 @@
|
||||
|
||||
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; }
|
||||
@@ -31,9 +34,8 @@ 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;
|
||||
titleBar.Title = title;
|
||||
AppTitleTextBlock.Text = title;
|
||||
|
||||
var handle = this.GetWindowHandle();
|
||||
RegisterWindow(handle);
|
||||
|
||||
@@ -20,15 +20,30 @@
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="*" />
|
||||
</Grid.RowDefinitions>
|
||||
<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>
|
||||
<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>
|
||||
|
||||
<views:MainPage x:Name="mainPage" Grid.Row="1" />
|
||||
</Grid>
|
||||
</winuiex:WindowEx>
|
||||
</winuiex:WindowEx>
|
||||
|
||||
@@ -18,16 +18,30 @@ namespace FileLocksmithUI
|
||||
{
|
||||
InitializeComponent();
|
||||
mainPage.ViewModel.IsElevated = isElevated;
|
||||
SetTitleBar(titleBar);
|
||||
ExtendsContentIntoTitleBar = true;
|
||||
AppWindow.TitleBar.PreferredHeightOption = TitleBarHeightOption.Tall;
|
||||
SetTitleBar(AppTitleBar);
|
||||
Activated += MainWindow_Activated;
|
||||
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;
|
||||
titleBar.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"];
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
|
||||
@@ -190,7 +190,7 @@
|
||||
TextWrapping="Wrap" />
|
||||
</ContentDialog>
|
||||
<ContentDialog x:Name="ProcessFilesListDialog" x:Uid="ProcessFilesListDialog">
|
||||
<ScrollViewer Padding="16" HorizontalScrollBarVisibility="Auto">
|
||||
<ScrollViewer Padding="15" HorizontalScrollBarVisibility="Auto">
|
||||
<TextBlock
|
||||
x:Name="ProcessFilesListDialogTextBlock"
|
||||
x:Uid="ProcessFilesListDialogTextBlock"
|
||||
|
||||
@@ -20,14 +20,27 @@
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="*" />
|
||||
</Grid.RowDefinitions>
|
||||
<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
|
||||
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>
|
||||
</Grid>
|
||||
</winuiex:WindowEx>
|
||||
|
||||
@@ -9,15 +9,19 @@ 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; }
|
||||
@@ -34,18 +38,31 @@ namespace Hosts
|
||||
|
||||
var title = Host.GetService<IElevationHelper>().IsElevated ? loader.GetString("WindowAdminTitle") : loader.GetString("WindowTitle");
|
||||
Title = title;
|
||||
titleBar.Title = title;
|
||||
AppTitleTextBlock.Text = 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,9 +49,7 @@ 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;
|
||||
@@ -453,7 +451,7 @@ namespace Awake.Core
|
||||
Dictionary<string, uint> optionsList = new()
|
||||
{
|
||||
{ string.Format(CultureInfo.InvariantCulture, AwakeMinutes, 30), 1800 },
|
||||
{ string.Format(CultureInfo.InvariantCulture, AwakeHour, 1), 3600 },
|
||||
{ string.Format(CultureInfo.InvariantCulture, AwakeHours, 1), 3600 },
|
||||
{ string.Format(CultureInfo.InvariantCulture, AwakeHours, 2), 7200 },
|
||||
};
|
||||
return optionsList;
|
||||
|
||||
@@ -159,15 +159,6 @@ 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>
|
||||
@@ -249,15 +240,6 @@ 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,10 +123,6 @@
|
||||
<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>
|
||||
@@ -146,10 +142,6 @@
|
||||
<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 virtual void SlowInitializeProperties()
|
||||
public void SlowInitializeProperties()
|
||||
{
|
||||
if (IsSelectedInitialized)
|
||||
{
|
||||
|
||||
@@ -47,21 +47,9 @@ public partial class ListItemViewModel(IListItem model, WeakReference<IPageConte
|
||||
|
||||
UpdateTags(li.Tags);
|
||||
|
||||
TextToSuggest = li.TextToSuggest;
|
||||
Section = li.Section ?? string.Empty;
|
||||
|
||||
UpdateProperty(nameof(Section));
|
||||
}
|
||||
|
||||
public override void SlowInitializeProperties()
|
||||
{
|
||||
base.SlowInitializeProperties();
|
||||
var model = Model.Unsafe;
|
||||
if (model is null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var extensionDetails = model.Details;
|
||||
var extensionDetails = li.Details;
|
||||
if (extensionDetails is not null)
|
||||
{
|
||||
Details = new(extensionDetails, PageContext);
|
||||
@@ -70,8 +58,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,12 +3,10 @@
|
||||
// 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;
|
||||
|
||||
@@ -41,7 +39,7 @@ public partial class AppStateModel : ObservableObject
|
||||
{
|
||||
if (string.IsNullOrEmpty(FilePath))
|
||||
{
|
||||
throw new InvalidOperationException($"You must set a valid {nameof(FilePath)} before calling {nameof(LoadState)}");
|
||||
throw new InvalidOperationException($"You must set a valid {nameof(SettingsModel.FilePath)} before calling {nameof(LoadState)}");
|
||||
}
|
||||
|
||||
if (!File.Exists(FilePath))
|
||||
@@ -79,84 +77,43 @@ 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);
|
||||
|
||||
// validate JSON
|
||||
if (JsonNode.Parse(settingsJson) is not JsonObject newSettings)
|
||||
// Is it valid JSON?
|
||||
if (JsonNode.Parse(settingsJson) is JsonObject newSettings)
|
||||
{
|
||||
Logger.LogError("Failed to parse app state as a JsonObject.");
|
||||
return;
|
||||
}
|
||||
// Now, read the existing content from the file
|
||||
var oldContent = File.Exists(FilePath) ? File.ReadAllText(FilePath) : "{}";
|
||||
|
||||
// read previous settings
|
||||
if (!TryReadSavedState(out var savedSettings))
|
||||
{
|
||||
savedSettings = new JsonObject();
|
||||
}
|
||||
// Is it valid JSON?
|
||||
if (JsonNode.Parse(oldContent) is JsonObject savedSettings)
|
||||
{
|
||||
foreach (var item in newSettings)
|
||||
{
|
||||
savedSettings[item.Key] = item.Value?.DeepClone();
|
||||
}
|
||||
|
||||
// merge new settings into old ones
|
||||
foreach (var item in newSettings)
|
||||
{
|
||||
savedSettings[item.Key] = item.Value?.DeepClone();
|
||||
}
|
||||
var serialized = savedSettings.ToJsonString(JsonSerializationContext.Default.AppStateModel.Options);
|
||||
File.WriteAllText(FilePath, serialized);
|
||||
|
||||
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);
|
||||
// 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.");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// file doesn't exist (might not have been created yet), so consider this a success
|
||||
// and return empty settings
|
||||
savedSettings = new JsonObject();
|
||||
return true;
|
||||
Debug.WriteLine("Failed to parse settings file as JsonObject.");
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
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;
|
||||
Debug.WriteLine(ex.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -32,7 +32,6 @@ public sealed partial class TopLevelViewModel : ObservableObject, IListItem
|
||||
private string _generatedId = string.Empty;
|
||||
|
||||
private HotkeySettings? _hotkey;
|
||||
private IIconInfo? _initialIcon;
|
||||
|
||||
private CommandAlias? Alias { get; set; }
|
||||
|
||||
@@ -58,8 +57,6 @@ 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
|
||||
@@ -208,8 +205,6 @@ public sealed partial class TopLevelViewModel : ObservableObject, IListItem
|
||||
{
|
||||
DisplayTitle = fallback.DisplayTitle;
|
||||
}
|
||||
|
||||
UpdateInitialIcon(false);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -226,31 +221,7 @@ 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 InitialIcon, Mode=OneWay}"
|
||||
SourceKey="{x:Bind Icon, Mode=OneWay}"
|
||||
SourceRequested="{x:Bind helpers:IconCacheProvider.SourceRequested}" />
|
||||
</cpcontrols:ContentIcon.Content>
|
||||
</cpcontrols:ContentIcon>
|
||||
|
||||
@@ -15,13 +15,13 @@ public class MockSettingsInterface : ISettingsInterface
|
||||
|
||||
public bool GlobalIfURI { get; set; }
|
||||
|
||||
public uint HistoryItemCount { get; set; }
|
||||
public string ShowHistory { get; set; }
|
||||
|
||||
public MockSettingsInterface(uint historyItemCount = 0, bool globalIfUri = true, List<HistoryItem> mockHistory = null)
|
||||
public MockSettingsInterface(string showHistory = "none", bool globalIfUri = true, List<HistoryItem> mockHistory = null)
|
||||
{
|
||||
_historyItems = mockHistory ?? new List<HistoryItem>();
|
||||
GlobalIfURI = globalIfUri;
|
||||
HistoryItemCount = historyItemCount;
|
||||
ShowHistory = showHistory;
|
||||
}
|
||||
|
||||
public List<ListItem> LoadHistory()
|
||||
@@ -50,9 +50,9 @@ public class MockSettingsInterface : ISettingsInterface
|
||||
_historyItems.Add(historyItem);
|
||||
|
||||
// Simulate the same logic as SettingsManager
|
||||
if (HistoryItemCount > 0)
|
||||
if (int.TryParse(ShowHistory, out var maxHistoryItems) && maxHistoryItems > 0)
|
||||
{
|
||||
while (_historyItems.Count > HistoryItemCount)
|
||||
while (_historyItems.Count > maxHistoryItems)
|
||||
{
|
||||
_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, historyItemCount: 5);
|
||||
var settings = new MockSettingsInterface(mockHistory: mockHistoryItems, showHistory: "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, historyItemCount: 5);
|
||||
var settings = new MockSettingsInterface(mockHistory: mockHistoryItems, showHistory: "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, historyItemCount: 0);
|
||||
var settings = new MockSettingsInterface(mockHistory: mockHistoryItems, showHistory: "None");
|
||||
|
||||
var page = new WebSearchListPage(settings);
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<XesUseOneStoreVersioning>true</XesUseOneStoreVersioning>
|
||||
<XesBaseYearForStoreVersion>2025</XesBaseYearForStoreVersion>
|
||||
<VersionMajor>0</VersionMajor>
|
||||
<VersionMinor>5</VersionMinor>
|
||||
<VersionMinor>4</VersionMinor>
|
||||
<VersionInfoProductName>Microsoft Command Palette</VersionInfoProductName>
|
||||
</PropertyGroup>
|
||||
</Project>
|
||||
|
||||
@@ -1,130 +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.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();
|
||||
}
|
||||
}
|
||||
@@ -1,66 +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.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,6 +21,4 @@ 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
|
||||
}
|
||||
|
||||
@@ -117,14 +117,6 @@ 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;
|
||||
}
|
||||
|
||||
|
||||
@@ -219,16 +219,6 @@ 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;
|
||||
}
|
||||
|
||||
|
||||
@@ -223,7 +223,7 @@ namespace Microsoft.CmdPal.Ext.Apps.Properties {
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Unlimited.
|
||||
/// Looks up a localized string similar to None.
|
||||
/// </summary>
|
||||
internal static string limit_none {
|
||||
get {
|
||||
@@ -330,51 +330,6 @@ 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>
|
||||
|
||||
@@ -198,21 +198,6 @@
|
||||
<data name="unpin_app" xml:space="preserve">
|
||||
<value>Unpin</value>
|
||||
</data>
|
||||
<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>
|
||||
|
||||
@@ -17,7 +17,6 @@ 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,7 +22,6 @@ 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.HistoryItemCount != 0)
|
||||
if (_settingsManager.ShowHistory != Resources.history_none)
|
||||
{
|
||||
_settingsManager.SaveHistory(new HistoryItem(Arguments, DateTime.Now));
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@ public interface ISettingsInterface
|
||||
{
|
||||
public bool GlobalIfURI { get; }
|
||||
|
||||
public uint HistoryItemCount { get; }
|
||||
public string ShowHistory { get; }
|
||||
|
||||
public List<ListItem> LoadHistory();
|
||||
|
||||
|
||||
@@ -16,7 +16,6 @@ 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";
|
||||
@@ -25,11 +24,11 @@ public class SettingsManager : JsonSettingsManager, ISettingsInterface
|
||||
|
||||
private static readonly List<ChoiceSetSetting.Choice> _choices =
|
||||
[
|
||||
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"),
|
||||
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),
|
||||
];
|
||||
|
||||
private readonly ToggleSetting _globalIfURI = new(
|
||||
@@ -38,15 +37,15 @@ public class SettingsManager : JsonSettingsManager, ISettingsInterface
|
||||
Resources.plugin_global_if_uri,
|
||||
false);
|
||||
|
||||
private readonly ChoiceSetSetting _historyItemCount = new(
|
||||
Namespaced(HistoryItemCountLegacySettingsKey),
|
||||
Resources.plugin_history_item_count,
|
||||
Resources.plugin_history_item_count,
|
||||
private readonly ChoiceSetSetting _showHistory = new(
|
||||
Namespaced(nameof(ShowHistory)),
|
||||
Resources.plugin_show_history,
|
||||
Resources.plugin_show_history,
|
||||
_choices);
|
||||
|
||||
public bool GlobalIfURI => _globalIfURI.Value;
|
||||
|
||||
public uint HistoryItemCount => uint.TryParse(_historyItemCount.Value, out var value) ? value : 0;
|
||||
public string ShowHistory => _showHistory.Value ?? string.Empty;
|
||||
|
||||
internal static string SettingsJsonPath()
|
||||
{
|
||||
@@ -91,11 +90,11 @@ public class SettingsManager : JsonSettingsManager, ISettingsInterface
|
||||
// Add the new history item
|
||||
historyItems.Add(historyItem);
|
||||
|
||||
// Determine the maximum number of items to keep based on HistoryItemCount
|
||||
if (HistoryItemCount > 0)
|
||||
// Determine the maximum number of items to keep based on ShowHistory
|
||||
if (int.TryParse(ShowHistory, out var maxHistoryItems) && maxHistoryItems > 0)
|
||||
{
|
||||
// Keep only the most recent `maxHistoryItems` items
|
||||
while (historyItems.Count > HistoryItemCount)
|
||||
while (historyItems.Count > maxHistoryItems)
|
||||
{
|
||||
historyItems.RemoveAt(0); // Remove the oldest item
|
||||
}
|
||||
@@ -151,7 +150,7 @@ public class SettingsManager : JsonSettingsManager, ISettingsInterface
|
||||
_historyPath = HistoryStateJsonPath();
|
||||
|
||||
Settings.Add(_globalIfURI);
|
||||
Settings.Add(_historyItemCount);
|
||||
Settings.Add(_showHistory);
|
||||
|
||||
// Load settings from file upon initialization
|
||||
LoadSettings();
|
||||
@@ -189,11 +188,11 @@ public class SettingsManager : JsonSettingsManager, ISettingsInterface
|
||||
base.SaveSettings();
|
||||
try
|
||||
{
|
||||
if (HistoryItemCount == 0)
|
||||
if (ShowHistory == Resources.history_none)
|
||||
{
|
||||
ClearHistory();
|
||||
}
|
||||
else if (HistoryItemCount > 0)
|
||||
else if (int.TryParse(ShowHistory, out var maxHistoryItems) && maxHistoryItems > 0)
|
||||
{
|
||||
// Trim the history file if there are more items than the new limit
|
||||
if (File.Exists(_historyPath))
|
||||
@@ -202,10 +201,10 @@ public class SettingsManager : JsonSettingsManager, ISettingsInterface
|
||||
var historyItems = JsonSerializer.Deserialize<List<HistoryItem>>(existingContent, WebSearchJsonSerializationContext.Default.ListHistoryItem) ?? [];
|
||||
|
||||
// Check if trimming is needed
|
||||
if (historyItems.Count > HistoryItemCount)
|
||||
if (historyItems.Count > maxHistoryItems)
|
||||
{
|
||||
// Trim the list to keep only the most recent `HistoryItemCount` items
|
||||
historyItems = historyItems.Skip((int)(historyItems.Count - HistoryItemCount)).ToList();
|
||||
// Trim the list to keep only the most recent `maxHistoryItems` items
|
||||
historyItems = historyItems.Skip(historyItems.Count - maxHistoryItems).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.HistoryItemCount != 0 ? _settingsManager.LoadHistory() : null;
|
||||
_historyItems = _settingsManager.ShowHistory != Resources.history_none ? _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.HistoryItemCount != 0 ? ListHelpers.FilterList(_historyItems, query).OfType<ListItem>() : null;
|
||||
filteredHistoryItems = _settingsManager.ShowHistory != Resources.history_none ? ListHelpers.FilterList(_historyItems, query).OfType<ListItem>() : null;
|
||||
}
|
||||
|
||||
var results = new List<ListItem>();
|
||||
|
||||
@@ -168,15 +168,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_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>
|
||||
@@ -240,6 +231,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_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_history_item_count" xml:space="preserve">
|
||||
<data name="plugin_show_history" 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,7 +65,6 @@ 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;
|
||||
@@ -83,8 +82,6 @@ internal sealed partial class WinGetExtensionPage : DynamicListPage, IDisposable
|
||||
}
|
||||
}
|
||||
|
||||
stopwatch.Stop();
|
||||
Logger.LogDebug($"Building ListItems took {stopwatch.ElapsedMilliseconds}ms", memberName: nameof(GetItems));
|
||||
IsLoading = false;
|
||||
return results;
|
||||
}
|
||||
@@ -247,22 +244,15 @@ 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)
|
||||
{
|
||||
@@ -271,8 +261,6 @@ 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
|
||||
|
||||
@@ -372,17 +372,20 @@ namespace UITests_FancyZones
|
||||
// launch FancyZones settings page
|
||||
private void LaunchFancyZones()
|
||||
{
|
||||
this.Find<NavigationViewItem>(By.AccessibilityId("WindowingAndLayoutsNavItem")).Click();
|
||||
if (this.FindAll<NavigationViewItem>("FancyZones").Count == 0)
|
||||
{
|
||||
this.Find<NavigationViewItem>("Windowing & Layouts").Click();
|
||||
}
|
||||
|
||||
this.Find<NavigationViewItem>(By.AccessibilityId("FancyZonesNavItem")).Click();
|
||||
this.Find<ToggleSwitch>(By.AccessibilityId("EnableFancyZonesToggleSwitch")).Toggle(true);
|
||||
this.Find<NavigationViewItem>("FancyZones").Click();
|
||||
this.Find<ToggleSwitch>("Enable FancyZones").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>(By.AccessibilityId("LaunchLayoutEditorButton")).Click(false, 500, 10000);
|
||||
this.Find<Microsoft.PowerToys.UITest.Button>("Launch layout editor").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.
|
||||
@@ -400,7 +403,7 @@ namespace UITests_FancyZones
|
||||
this.Find<Microsoft.PowerToys.UITest.Button>("Close").Click();
|
||||
this.Session.Attach(PowerToysModule.PowerToysSettings);
|
||||
SetupCustomLayouts();
|
||||
this.Find<Microsoft.PowerToys.UITest.Button>(By.AccessibilityId("LaunchLayoutEditorButton")).Click(false, 5000, 5000);
|
||||
this.Find<Microsoft.PowerToys.UITest.Button>("Launch layout editor").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,19 +15,38 @@
|
||||
<Window.SystemBackdrop>
|
||||
<MicaBackdrop />
|
||||
</Window.SystemBackdrop>
|
||||
|
||||
<Grid x:Name="MainGrid" Loaded="Grid_Loaded">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="*" />
|
||||
</Grid.RowDefinitions>
|
||||
<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
|
||||
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>
|
||||
|
||||
</Grid>
|
||||
</winuiex:WindowEx>
|
||||
</winuiex:WindowEx>
|
||||
|
||||
@@ -6,7 +6,6 @@ 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;
|
||||
@@ -24,6 +23,7 @@ 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,15 +38,20 @@ 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;
|
||||
appWindow.Closing += AppWindow_Closing;
|
||||
Activated += MainWindow_Activated;
|
||||
|
||||
// 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)
|
||||
@@ -61,7 +66,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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -75,7 +80,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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -87,6 +92,20 @@ 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);
|
||||
@@ -99,23 +118,23 @@ namespace RegistryPreview
|
||||
|
||||
if (string.IsNullOrEmpty(filename))
|
||||
{
|
||||
titleBar.Title = APPNAME;
|
||||
AppWindow.Title = APPNAME;
|
||||
titleBarText.Text = APPNAME;
|
||||
appWindow.Title = APPNAME;
|
||||
}
|
||||
else
|
||||
{
|
||||
string[] file = filename.Split('\\');
|
||||
if (file.Length > 0)
|
||||
{
|
||||
titleBar.Title = file[file.Length - 1] + " - " + APPNAME;
|
||||
titleBarText.Text = file[file.Length - 1] + " - " + APPNAME;
|
||||
}
|
||||
else
|
||||
{
|
||||
titleBar.Title = filename + " - " + APPNAME;
|
||||
titleBarText.Text = filename + " - " + APPNAME;
|
||||
}
|
||||
|
||||
// Continue to update the window's title, after updating the custom title bar
|
||||
AppWindow.Title = titleBar.Title;
|
||||
appWindow.Title = titleBarText.Text;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -269,7 +269,7 @@
|
||||
</controls:Card>
|
||||
<controls:Card
|
||||
x:Name="ModulesCard"
|
||||
x:Uid="UtilitiesHeader"
|
||||
Title="Modules"
|
||||
Grid.RowSpan="2"
|
||||
Grid.Column="1"
|
||||
MinWidth="400"
|
||||
|
||||
@@ -19,11 +19,7 @@
|
||||
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:Name="EnableFancyZonesToggleSwitch"
|
||||
x:Uid="ToggleSwitch"
|
||||
AutomationProperties.AutomationId="EnableFancyZonesToggleSwitch"
|
||||
IsOn="{x:Bind ViewModel.IsEnabled, Mode=TwoWay}" />
|
||||
<ToggleSwitch x:Uid="ToggleSwitch" IsOn="{x:Bind ViewModel.IsEnabled, Mode=TwoWay}" />
|
||||
</tkcontrols:SettingsCard>
|
||||
<InfoBar
|
||||
x:Uid="GPO_SettingIsManaged"
|
||||
|
||||
@@ -146,17 +146,11 @@
|
||||
</NavigationView.Resources>
|
||||
<NavigationView.MenuItems>
|
||||
<NavigationViewItem
|
||||
x:Name="DashboardNavigationItem"
|
||||
x:Uid="Shell_Dashboard"
|
||||
helpers:NavHelper.NavigateTo="views:DashboardPage"
|
||||
AutomationProperties.AutomationId="DashboardNavItem"
|
||||
Icon="{ui:FontIcon Glyph=}" />
|
||||
|
||||
<NavigationViewItem
|
||||
x:Name="GeneralNavigationItem"
|
||||
x:Uid="Shell_General"
|
||||
helpers:NavHelper.NavigateTo="views:GeneralPage"
|
||||
AutomationProperties.AutomationId="GeneralNavItem">
|
||||
<NavigationViewItem x:Uid="Shell_General" helpers:NavHelper.NavigateTo="views:GeneralPage">
|
||||
<NavigationViewItem.Icon>
|
||||
<AnimatedIcon>
|
||||
<AnimatedIcon.Source>
|
||||
@@ -172,220 +166,156 @@
|
||||
|
||||
<!-- System Tools -->
|
||||
<NavigationViewItem
|
||||
x:Name="SystemToolsNavigationItem"
|
||||
x:Uid="Shell_TopLevelSystemTools"
|
||||
AutomationProperties.AutomationId="SystemToolsNavItem"
|
||||
Icon="{ui:BitmapIcon Source=/Assets/Settings/Icons/SystemTools.png}"
|
||||
SelectsOnInvoked="False">
|
||||
<NavigationViewItem.MenuItems>
|
||||
<NavigationViewItem
|
||||
x:Name="AdvancedPasteNavigationItem"
|
||||
x:Uid="Shell_AdvancedPaste"
|
||||
helpers:NavHelper.NavigateTo="views:AdvancedPastePage"
|
||||
AutomationProperties.AutomationId="AdvancedPasteNavItem"
|
||||
Icon="{ui:BitmapIcon Source=/Assets/Settings/Icons/AdvancedPaste.png}" />
|
||||
<NavigationViewItem
|
||||
x:Name="AwakeNavigationItem"
|
||||
x:Uid="Shell_Awake"
|
||||
helpers:NavHelper.NavigateTo="views:AwakePage"
|
||||
AutomationProperties.AutomationId="AwakeNavItem"
|
||||
Icon="{ui:BitmapIcon Source=/Assets/Settings/Icons/Awake.png}" />
|
||||
<NavigationViewItem
|
||||
x:Name="CmdPalNavigationItem"
|
||||
x:Uid="Shell_CmdPal"
|
||||
helpers:NavHelper.NavigateTo="views:CmdPalPage"
|
||||
AutomationProperties.AutomationId="CmdPalNavItem"
|
||||
Icon="{ui:BitmapIcon Source=/Assets/Settings/Icons/CmdPal.png}" />
|
||||
<NavigationViewItem
|
||||
x:Name="ColorPickerNavigationItem"
|
||||
x:Uid="Shell_ColorPicker"
|
||||
helpers:NavHelper.NavigateTo="views:ColorPickerPage"
|
||||
AutomationProperties.AutomationId="ColorPickerNavItem"
|
||||
Icon="{ui:BitmapIcon Source=/Assets/Settings/Icons/ColorPicker.png}" />
|
||||
<NavigationViewItem
|
||||
x:Name="PowerLauncherNavigationItem"
|
||||
x:Uid="Shell_PowerLauncher"
|
||||
helpers:NavHelper.NavigateTo="views:PowerLauncherPage"
|
||||
AutomationProperties.AutomationId="PowerLauncherNavItem"
|
||||
Icon="{ui:BitmapIcon Source=/Assets/Settings/Icons/PowerToysRun.png}" />
|
||||
<NavigationViewItem
|
||||
x:Name="MeasureToolNavigationItem"
|
||||
x:Uid="Shell_MeasureTool"
|
||||
helpers:NavHelper.NavigateTo="views:MeasureToolPage"
|
||||
AutomationProperties.AutomationId="MeasureToolNavItem"
|
||||
Icon="{ui:BitmapIcon Source=/Assets/Settings/Icons/ScreenRuler.png}" />
|
||||
<NavigationViewItem
|
||||
x:Name="ShortcutGuideNavigationItem"
|
||||
x:Uid="Shell_ShortcutGuide"
|
||||
helpers:NavHelper.NavigateTo="views:ShortcutGuidePage"
|
||||
AutomationProperties.AutomationId="ShortcutGuideNavItem"
|
||||
Icon="{ui:BitmapIcon Source=/Assets/Settings/Icons/ShortcutGuide.png}" />
|
||||
<NavigationViewItem
|
||||
x:Name="TextExtractorNavigationItem"
|
||||
x:Uid="Shell_TextExtractor"
|
||||
helpers:NavHelper.NavigateTo="views:PowerOcrPage"
|
||||
AutomationProperties.AutomationId="TextExtractorNavItem"
|
||||
Icon="{ui:BitmapIcon Source=/Assets/Settings/Icons/TextExtractor.png}" />
|
||||
<NavigationViewItem
|
||||
x:Name="ZoomItNavigationItem"
|
||||
x:Uid="Shell_ZoomIt"
|
||||
helpers:NavHelper.NavigateTo="views:ZoomItPage"
|
||||
AutomationProperties.AutomationId="ZoomItNavItem"
|
||||
Icon="{ui:BitmapIcon Source=/Assets/Settings/Icons/ZoomIt.png}" />
|
||||
</NavigationViewItem.MenuItems>
|
||||
</NavigationViewItem>
|
||||
|
||||
<!-- Windowing & Layouts -->
|
||||
<NavigationViewItem
|
||||
x:Name="WindowingAndLayoutsNavigationItem"
|
||||
x:Uid="Shell_TopLevelWindowsAndLayouts "
|
||||
AutomationProperties.AutomationId="WindowingAndLayoutsNavItem"
|
||||
Icon="{ui:BitmapIcon Source=/Assets/Settings/Icons/WindowingAndLayouts.png}"
|
||||
SelectsOnInvoked="False">
|
||||
<NavigationViewItem.MenuItems>
|
||||
<NavigationViewItem
|
||||
x:Name="AlwaysOnTopNavigationItem"
|
||||
x:Uid="Shell_AlwaysOnTop"
|
||||
helpers:NavHelper.NavigateTo="views:AlwaysOnTopPage"
|
||||
AutomationProperties.AutomationId="AlwaysOnTopNavItem"
|
||||
Icon="{ui:BitmapIcon Source=/Assets/Settings/Icons/AlwaysOnTop.png}" />
|
||||
<NavigationViewItem
|
||||
x:Name="CropAndLockNavigationItem"
|
||||
x:Uid="Shell_CropAndLock"
|
||||
helpers:NavHelper.NavigateTo="views:CropAndLockPage"
|
||||
AutomationProperties.AutomationId="CropAndLockNavItem"
|
||||
Icon="{ui:BitmapIcon Source=/Assets/Settings/Icons/CropAndLock.png}" />
|
||||
<NavigationViewItem
|
||||
x:Name="FancyZonesNavigationItem"
|
||||
x:Uid="Shell_FancyZones"
|
||||
helpers:NavHelper.NavigateTo="views:FancyZonesPage"
|
||||
AutomationProperties.AutomationId="FancyZonesNavItem"
|
||||
Icon="{ui:BitmapIcon Source=/Assets/Settings/Icons/FancyZones.png}" />
|
||||
<NavigationViewItem
|
||||
x:Name="WorkspacesNavigationItem"
|
||||
x:Uid="Shell_Workspaces"
|
||||
helpers:NavHelper.NavigateTo="views:WorkspacesPage"
|
||||
AutomationProperties.AutomationId="WorkspacesNavItem"
|
||||
Icon="{ui:BitmapIcon Source=/Assets/Settings/Icons/Workspaces.png}" />
|
||||
</NavigationViewItem.MenuItems>
|
||||
</NavigationViewItem>
|
||||
|
||||
<!-- Input / Output -->
|
||||
<NavigationViewItem
|
||||
x:Name="InputOutputNavigationItem"
|
||||
x:Uid="Shell_TopLevelInputOutput"
|
||||
AutomationProperties.AutomationId="InputOutputNavItem"
|
||||
Icon="{ui:BitmapIcon Source=/Assets/Settings/Icons/InputOutput.png}"
|
||||
SelectsOnInvoked="False">
|
||||
<NavigationViewItem.MenuItems>
|
||||
<NavigationViewItem
|
||||
x:Name="KeyboardManagerNavigationItem"
|
||||
x:Uid="Shell_KeyboardManager"
|
||||
helpers:NavHelper.NavigateTo="views:KeyboardManagerPage"
|
||||
AutomationProperties.AutomationId="KeyboardManagerNavItem"
|
||||
Icon="{ui:BitmapIcon Source=/Assets/Settings/Icons/KeyboardManager.png}" />
|
||||
<!-- Find my mouse -->
|
||||
<!-- Mouse Highlighter -->
|
||||
<NavigationViewItem
|
||||
x:Name="MouseUtilitiesNavigationItem"
|
||||
x:Uid="Shell_MouseUtilities"
|
||||
helpers:NavHelper.NavigateTo="views:MouseUtilsPage"
|
||||
AutomationProperties.AutomationId="MouseUtilitiesNavItem"
|
||||
Icon="{ui:BitmapIcon Source=/Assets/Settings/Icons/MouseUtils.png}" />
|
||||
<NavigationViewItem
|
||||
x:Name="MouseWithoutBordersNavigationItem"
|
||||
x:Uid="Shell_MouseWithoutBorders"
|
||||
helpers:NavHelper.NavigateTo="views:MouseWithoutBordersPage"
|
||||
AutomationProperties.AutomationId="MouseWithoutBordersNavItem"
|
||||
Icon="{ui:BitmapIcon Source=/Assets/Settings/Icons/MouseWithoutBorders.png}" />
|
||||
<NavigationViewItem
|
||||
x:Name="QuickAccentNavigationItem"
|
||||
x:Uid="Shell_QuickAccent"
|
||||
helpers:NavHelper.NavigateTo="views:PowerAccentPage"
|
||||
AutomationProperties.AutomationId="QuickAccentNavItem"
|
||||
Icon="{ui:BitmapIcon Source=/Assets/Settings/Icons/QuickAccent.png}" />
|
||||
</NavigationViewItem.MenuItems>
|
||||
</NavigationViewItem>
|
||||
|
||||
<!-- File Management -->
|
||||
<NavigationViewItem
|
||||
x:Name="FileManagementNavigationItem"
|
||||
x:Uid="Shell_TopLevelFileManagement"
|
||||
AutomationProperties.AutomationId="FileManagementNavItem"
|
||||
Icon="{ui:BitmapIcon Source=/Assets/Settings/Icons/FileManagement.png}"
|
||||
SelectsOnInvoked="False">
|
||||
<NavigationViewItem.MenuItems>
|
||||
<NavigationViewItem
|
||||
x:Name="PowerPreviewNavigationItem"
|
||||
x:Uid="Shell_PowerPreview"
|
||||
helpers:NavHelper.NavigateTo="views:PowerPreviewPage"
|
||||
AutomationProperties.AutomationId="PowerPreviewNavItem"
|
||||
Icon="{ui:BitmapIcon Source=/Assets/Settings/Icons/FileExplorerPreview.png}" />
|
||||
<!-- File Explorer Thumbnails -->
|
||||
<NavigationViewItem
|
||||
x:Name="FileLocksmithNavigationItem"
|
||||
x:Uid="Shell_FileLocksmith"
|
||||
helpers:NavHelper.NavigateTo="views:FileLocksmithPage"
|
||||
AutomationProperties.AutomationId="FileLocksmithNavItem"
|
||||
Icon="{ui:BitmapIcon Source=/Assets/Settings/Icons/FileLocksmith.png}" />
|
||||
<NavigationViewItem
|
||||
x:Name="ImageResizerNavigationItem"
|
||||
x:Uid="Shell_ImageResizer"
|
||||
helpers:NavHelper.NavigateTo="views:ImageResizerPage"
|
||||
AutomationProperties.AutomationId="ImageResizerNavItem"
|
||||
Icon="{ui:BitmapIcon Source=/Assets/Settings/Icons/ImageResizer.png}" />
|
||||
<NavigationViewItem
|
||||
x:Name="NewPlusNavigationItem"
|
||||
x:Uid="NewPlus_Product_Name"
|
||||
helpers:NavHelper.NavigateTo="views:NewPlusPage"
|
||||
AutomationProperties.AutomationId="NewPlusNavItem"
|
||||
Icon="{ui:BitmapIcon Source=/Assets/Settings/Icons/NewPlus.png}" />
|
||||
<NavigationViewItem
|
||||
x:Name="PeekNavigationItem"
|
||||
x:Uid="Shell_Peek"
|
||||
helpers:NavHelper.NavigateTo="views:PeekPage"
|
||||
AutomationProperties.AutomationId="PeekNavItem"
|
||||
Icon="{ui:BitmapIcon Source=/Assets/Settings/Icons/Peek.png}" />
|
||||
<NavigationViewItem
|
||||
x:Name="PowerRenameNavigationItem"
|
||||
x:Uid="Shell_PowerRename"
|
||||
helpers:NavHelper.NavigateTo="views:PowerRenamePage"
|
||||
AutomationProperties.AutomationId="PowerRenameNavItem"
|
||||
Icon="{ui:BitmapIcon Source=/Assets/Settings/Icons/PowerRename.png}" />
|
||||
</NavigationViewItem.MenuItems>
|
||||
</NavigationViewItem>
|
||||
|
||||
<!-- Advanced -->
|
||||
<NavigationViewItem
|
||||
x:Name="AdvancedNavigationItem"
|
||||
x:Uid="Shell_TopLevelAdvanced"
|
||||
AutomationProperties.AutomationId="AdvancedNavItem"
|
||||
Icon="{ui:BitmapIcon Source=/Assets/Settings/Icons/Advanced.png}"
|
||||
SelectsOnInvoked="False">
|
||||
<NavigationViewItem.MenuItems>
|
||||
<NavigationViewItem
|
||||
x:Name="CmdNotFoundNavigationItem"
|
||||
x:Uid="Shell_CmdNotFound"
|
||||
helpers:NavHelper.NavigateTo="views:CmdNotFoundPage"
|
||||
AutomationProperties.AutomationId="CmdNotFoundNavItem"
|
||||
Icon="{ui:BitmapIcon Source=/Assets/Settings/Icons/CommandNotFound.png}" />
|
||||
<NavigationViewItem
|
||||
x:Name="EnvironmentVariablesNavigationItem"
|
||||
x:Uid="Shell_EnvironmentVariables"
|
||||
helpers:NavHelper.NavigateTo="views:EnvironmentVariablesPage"
|
||||
AutomationProperties.AutomationId="EnvironmentVariablesNavItem"
|
||||
Icon="{ui:BitmapIcon Source=/Assets/Settings/Icons/EnvironmentVariables.png}" />
|
||||
<NavigationViewItem
|
||||
x:Name="HostsNavigationItem"
|
||||
x:Uid="Shell_Hosts"
|
||||
helpers:NavHelper.NavigateTo="views:HostsPage"
|
||||
AutomationProperties.AutomationId="HostsNavItem"
|
||||
Icon="{ui:BitmapIcon Source=/Assets/Settings/Icons/Hosts.png}" />
|
||||
<NavigationViewItem
|
||||
x:Name="RegistryPreviewNavigationItem"
|
||||
x:Uid="Shell_RegistryPreview"
|
||||
helpers:NavHelper.NavigateTo="views:RegistryPreviewPage"
|
||||
AutomationProperties.AutomationId="RegistryPreviewNavItem"
|
||||
Icon="{ui:BitmapIcon Source=/Assets/Settings/Icons/RegistryPreview.png}" />
|
||||
</NavigationViewItem.MenuItems>
|
||||
</NavigationViewItem>
|
||||
@@ -393,27 +323,19 @@
|
||||
<NavigationView.PaneFooter>
|
||||
<StackPanel Orientation="Vertical">
|
||||
<NavigationViewItem
|
||||
x:Name="OOBENavigationItem"
|
||||
x:Uid="OOBE_NavViewItem"
|
||||
AutomationProperties.AutomationId="OOBENavItem"
|
||||
Icon="{ui:FontIcon Glyph=}"
|
||||
Tapped="OOBEItem_Tapped" />
|
||||
<NavigationViewItem
|
||||
x:Name="WhatIsNewNavigationItem"
|
||||
x:Uid="WhatIsNew_NavViewItem"
|
||||
AutomationProperties.AutomationId="WhatIsNewNavItem"
|
||||
Icon="{ui:FontIcon Glyph=}"
|
||||
Tapped="WhatIsNewItem_Tapped" />
|
||||
<NavigationViewItem
|
||||
x:Name="FeedbackNavigationItem"
|
||||
x:Uid="Feedback_NavViewItem"
|
||||
AutomationProperties.AutomationId="FeedbackNavItem"
|
||||
Icon="{ui:FontIcon Glyph=}"
|
||||
Tapped="FeedbackItem_Tapped" />
|
||||
<NavigationViewItem
|
||||
x:Name="CloseNavigationItem"
|
||||
x:Uid="Close_NavViewItem"
|
||||
AutomationProperties.AutomationId="CloseNavItem"
|
||||
Icon="{ui:FontIcon Glyph=}"
|
||||
Tapped="Close_Tapped"
|
||||
Visibility="{x:Bind ViewModel.ShowCloseMenu, Mode=OneWay}" />
|
||||
|
||||
@@ -639,17 +639,17 @@ opera.exe</value>
|
||||
<value>Additional actions</value>
|
||||
</data>
|
||||
<data name="RemapKeysList.[using:Microsoft.UI.Xaml.Automation]AutomationProperties.Name" xml:space="preserve">
|
||||
<value>Current key remappings</value>
|
||||
<value>Current Key Remappings</value>
|
||||
</data>
|
||||
<data name="RemapShortcutsList.[using:Microsoft.UI.Xaml.Automation]AutomationProperties.Name" xml:space="preserve">
|
||||
<value>Current shortcut remappings</value>
|
||||
<value>Current Shortcut Remappings</value>
|
||||
</data>
|
||||
<data name="KeyboardManager_RemappedKeysListItem.[using:Microsoft.UI.Xaml.Automation]AutomationProperties.Name" xml:space="preserve">
|
||||
<value>Key remapping</value>
|
||||
<value>Key Remapping</value>
|
||||
<comment>key as in keyboard key</comment>
|
||||
</data>
|
||||
<data name="KeyboardManager_RemappedShortcutsListItem.[using:Microsoft.UI.Xaml.Automation]AutomationProperties.Name" xml:space="preserve">
|
||||
<value>Shortcut remapping</value>
|
||||
<value>Shortcut Remapping</value>
|
||||
</data>
|
||||
<data name="KeyboardManager_RemappedTo.[using:Microsoft.UI.Xaml.Automation]AutomationProperties.Name" xml:space="preserve">
|
||||
<value>Remapped to</value>
|
||||
@@ -658,7 +658,7 @@ opera.exe</value>
|
||||
<value>Remapped to</value>
|
||||
</data>
|
||||
<data name="KeyboardManager_TargetApp.[using:Microsoft.UI.Xaml.Automation]AutomationProperties.Name" xml:space="preserve">
|
||||
<value>For target application</value>
|
||||
<value>For Target Application</value>
|
||||
<comment>What computer application would this be for</comment>
|
||||
</data>
|
||||
<data name="KeyboardManager_Image.[using:Microsoft.UI.Xaml.Automation]AutomationProperties.Name" xml:space="preserve">
|
||||
@@ -4405,7 +4405,7 @@ Activate by holding the key for the character you want to add an accent to, then
|
||||
<value>Show minimap</value>
|
||||
</data>
|
||||
<data name="PrivacyLink.Text" xml:space="preserve">
|
||||
<value>OpenAI privacy</value>
|
||||
<value>OpenAI Privacy</value>
|
||||
</data>
|
||||
<data name="TermsLink.Text" xml:space="preserve">
|
||||
<value>OpenAI Terms</value>
|
||||
@@ -4626,7 +4626,7 @@ Activate by holding the key for the character you want to add an accent to, then
|
||||
Copy a zoomed screen with Ctrl+C or save it by typing Ctrl+S. Crop the copy or save region by entering Ctrl+Shift instead of Ctrl.</value>
|
||||
</data>
|
||||
<data name="ZoomIt_Zoom_Shortcut.Header" xml:space="preserve">
|
||||
<value>Zoom hotkey</value>
|
||||
<value>Zoom Toggle Hotkey</value>
|
||||
</data>
|
||||
<data name="ZoomIt_Toggle_AnimateZoom.Header" xml:space="preserve">
|
||||
<value>Animate zoom in and zoom out</value>
|
||||
@@ -4647,7 +4647,7 @@ Use LiveDraw to draw and annotate the live desktop. To activate LiveDraw, enter
|
||||
To enter and exit LiveZoom, enter the hotkey specified below.</value>
|
||||
</data>
|
||||
<data name="ZoomIt_LiveZoom_Shortcut.Header" xml:space="preserve">
|
||||
<value>Live Zoom hotkey</value>
|
||||
<value>Live Zoom Toggle Hotkey</value>
|
||||
</data>
|
||||
<data name="ZoomIt_DrawGroup.Header" xml:space="preserve">
|
||||
<value>Draw</value>
|
||||
@@ -4666,7 +4666,7 @@ Shapes - Draw a line by holding down the Shift key, a rectangle with the Ctrl ke
|
||||
Screen - Clear the screen for a sketch pad by pressing W (white) or K (black). Copy a zoomed screen with Ctrl+C or save it by typing Ctrl+S. Crop the copy or save region by entering Ctrl+Shift instead of Ctrl.</value>
|
||||
</data>
|
||||
<data name="ZoomIt_Draw_Shortcut.Header" xml:space="preserve">
|
||||
<value>Draw without zoom hotkey</value>
|
||||
<value>Draw without Zoom Hotkey</value>
|
||||
</data>
|
||||
<data name="ZoomIt_TypeGroup.Header" xml:space="preserve">
|
||||
<value>Type</value>
|
||||
@@ -4680,11 +4680,11 @@ The text color is the current drawing color.</value>
|
||||
<value>Text font</value>
|
||||
</data>
|
||||
<data name="ZoomIt_Type_Font_Button.Content" xml:space="preserve">
|
||||
<value>Choose font</value>
|
||||
<value>Choose Font</value>
|
||||
<comment>Font refers to text font</comment>
|
||||
</data>
|
||||
<data name="ZoomIt_DemoTypeGroup.Header" xml:space="preserve">
|
||||
<value>DemoType</value>
|
||||
<value>Demo Type</value>
|
||||
</data>
|
||||
<data name="ZoomIt_DemoTypeGroup.Description" xml:space="preserve">
|
||||
<value>Use DemoType to have ZoomIt type text specified in the input file when you enter the DemoType toggle. You can also pull input from the clipboard if it is prefixed with the [start] keyword.
|
||||
@@ -4698,7 +4698,7 @@ When driving input, hit the space bar to unblock keyboard input at the end of a
|
||||
When you reach the end of the file, ZoomIt will reload the file and start at the beginning. Enter the hotkey with the Shift key in the opposite mode to step back to the last [end].</value>
|
||||
</data>
|
||||
<data name="ZoomIt_DemoType_Shortcut.Header" xml:space="preserve">
|
||||
<value>DemoType toggle hotkey</value>
|
||||
<value>Demo Type Toggle Hotkey</value>
|
||||
</data>
|
||||
<data name="ZoomIt_DemoType_File.Header" xml:space="preserve">
|
||||
<value>Input file</value>
|
||||
@@ -4707,7 +4707,7 @@ When you reach the end of the file, ZoomIt will reload the file and start at the
|
||||
<value>Browse</value>
|
||||
</data>
|
||||
<data name="ZoomIt_DemoType_File_Picker_Dialog_Title" xml:space="preserve">
|
||||
<value>Specify DemoType file..</value>
|
||||
<value>Specify DemoType file...</value>
|
||||
</data>
|
||||
<data name="FilePicker_AllFilesFilter" xml:space="preserve">
|
||||
<value>All Files</value>
|
||||
@@ -4730,19 +4730,19 @@ When you reach the end of the file, ZoomIt will reload the file and start at the
|
||||
Change the break timer color using the same keys that the drawing color. The break timer font is the same as text font.</value>
|
||||
</data>
|
||||
<data name="ZoomIt_Break_Shortcut.Header" xml:space="preserve">
|
||||
<value>Start break timer hotkey</value>
|
||||
<value>Start Break Timer Hotkey</value>
|
||||
</data>
|
||||
<data name="ZoomIt_Break_Timeout.Header" xml:space="preserve">
|
||||
<value>Timer (minutes)</value>
|
||||
</data>
|
||||
<data name="ZoomIt_Break_ShowExpiredTime.Header" xml:space="preserve">
|
||||
<value>Show time elapsed after expiration</value>
|
||||
<value>Show Time Elapsed After Expiration</value>
|
||||
</data>
|
||||
<data name="ZoomIt_Break_PlaySoundsFile.Header" xml:space="preserve">
|
||||
<value>Play sound on expiration</value>
|
||||
<value>Play Sound on Expiration</value>
|
||||
</data>
|
||||
<data name="ZoomIt_Break_SoundFile.Header" xml:space="preserve">
|
||||
<value>Alarm sound file</value>
|
||||
<value>Alarm Sound File</value>
|
||||
</data>
|
||||
<data name="ZoomIt_Break_SoundFile_BrowseButton.Content" xml:space="preserve">
|
||||
<value>Browse</value>
|
||||
@@ -4754,7 +4754,7 @@ Change the break timer color using the same keys that the drawing color. The bre
|
||||
<value>Sounds</value>
|
||||
</data>
|
||||
<data name="ZoomIt_Break_TimerOpacity.Header" xml:space="preserve">
|
||||
<value>Timer opacity</value>
|
||||
<value>Timer Opacity</value>
|
||||
</data>
|
||||
<data name="ZoomIt_Break_TimerOpacity_10Percent.Content" xml:space="preserve">
|
||||
<value>10%</value>
|
||||
@@ -4787,7 +4787,7 @@ Change the break timer color using the same keys that the drawing color. The bre
|
||||
<value>100%</value>
|
||||
</data>
|
||||
<data name="ZoomIt_Break_TimerPosition.Header" xml:space="preserve">
|
||||
<value>Timer position</value>
|
||||
<value>Timer Position</value>
|
||||
</data>
|
||||
<data name="ZoomIt_Break_TimerPosition_TopLeftCorner.Content" xml:space="preserve">
|
||||
<value>Top left corner</value>
|
||||
@@ -4817,7 +4817,7 @@ Change the break timer color using the same keys that the drawing color. The bre
|
||||
<value>Bottom right corner</value>
|
||||
</data>
|
||||
<data name="ZoomIt_Break_ShowBackgroundBitmap.Header" xml:space="preserve">
|
||||
<value>Show background bitmap</value>
|
||||
<value>Show Background Bitmap</value>
|
||||
</data>
|
||||
<data name="ZoomIt_Break_ShowFadedDesktop.Content" xml:space="preserve">
|
||||
<value>Use faded desktop as background</value>
|
||||
@@ -4826,7 +4826,7 @@ Change the break timer color using the same keys that the drawing color. The bre
|
||||
<value>Use image file as background</value>
|
||||
</data>
|
||||
<data name="ZoomIt_Break_BackgroundFile.Header" xml:space="preserve">
|
||||
<value>Background image file</value>
|
||||
<value>Background Image File</value>
|
||||
</data>
|
||||
<data name="ZoomIt_Break_BackgroundFile_BrowseButton.Content" xml:space="preserve">
|
||||
<value>Browse</value>
|
||||
@@ -4847,14 +4847,14 @@ Change the break timer color using the same keys that the drawing color. The bre
|
||||
<value>Record</value>
|
||||
</data>
|
||||
<data name="ZoomIt_RecordGroup.Description" xml:space="preserve">
|
||||
<value>Record video of the unzoomed live screen or a static zoomed session by entering the recording hotkey and finish the recording by entering it again.
|
||||
<value>Record video of the unzoomed live screen or a static zoomed session by entering the recording hot key and finish the recording by entering it again.
|
||||
|
||||
To crop the portion of the screen that will be recorded, enter the hotkey with the Shift key in the opposite mode.
|
||||
|
||||
To record a specific window, enter the hotkey with the Alt key in the opposite mode.</value>
|
||||
</data>
|
||||
<data name="ZoomIt_Record_Shortcut.Header" xml:space="preserve">
|
||||
<value>Record hotkey</value>
|
||||
<value>Record Toggle Hotkey</value>
|
||||
</data>
|
||||
<data name="ZoomIt_Record_Scaling.Header" xml:space="preserve">
|
||||
<value>Scaling</value>
|
||||
@@ -4875,7 +4875,7 @@ To record a specific window, enter the hotkey with the Alt key in the opposite m
|
||||
<value>Copy a region of the screen to the clipboard or enter the hotkey with the Shift key in the opposite mode to save it to a file.</value>
|
||||
</data>
|
||||
<data name="ZoomIt_Snip_Shortcut.Header" xml:space="preserve">
|
||||
<value>Snip hotkey</value>
|
||||
<value>Snip Toggle Hotkey</value>
|
||||
</data>
|
||||
<data name="Oobe_ZoomIt.Description" xml:space="preserve">
|
||||
<value>ZoomIt is a screen zoom, annotation, and recording tool for technical presentations and demos. You can also use ZoomIt to snip screenshots to the clipboard or to a file.</value>
|
||||
@@ -4992,7 +4992,7 @@ To record a specific window, enter the hotkey with the Alt key in the opposite m
|
||||
<value>File Management</value>
|
||||
</data>
|
||||
<data name="Shell_TopLevelInputOutput.Content" xml:space="preserve">
|
||||
<value>Input & Output</value>
|
||||
<value>Input / Output</value>
|
||||
</data>
|
||||
<data name="Shell_TopLevelWindowsAndLayouts.Content" xml:space="preserve">
|
||||
<value>Windowing & Layouts</value>
|
||||
@@ -5145,7 +5145,7 @@ To record a specific window, enter the hotkey with the Alt key in the opposite m
|
||||
<value>Quick access</value>
|
||||
</data>
|
||||
<data name="ShortcutsOverview.Title" xml:space="preserve">
|
||||
<value>Shortcuts</value>
|
||||
<value>Shortcuts overview</value>
|
||||
</data>
|
||||
<data name="NoActionsToShow.Text" xml:space="preserve">
|
||||
<value>No actions to show..</value>
|
||||
@@ -5296,7 +5296,4 @@ To record a specific window, enter the hotkey with the Alt key in the opposite m
|
||||
<value>Results for</value>
|
||||
<comment>Prefix for search string. E.g. "Results for 'shortcut'"</comment>
|
||||
</data>
|
||||
<data name="UtilitiesHeader.Title" xml:space="preserve">
|
||||
<value>Utilities</value>
|
||||
</data>
|
||||
</root>
|
||||
@@ -51,5 +51,4 @@ std::vector<std::wstring> processes =
|
||||
L"PowerToys.WorkspacesWindowArranger.exe",
|
||||
L"PowerToys.WorkspacesEditor.exe",
|
||||
L"PowerToys.ZoomIt.exe",
|
||||
L"Microsoft.CmdPal.UI.exe",
|
||||
};
|
||||
|
||||
@@ -1,48 +0,0 @@
|
||||
# Build scripts – quick guideline
|
||||
|
||||
Use these scripts to build PowerToys locally. They auto-detect your platform (x64/arm64), initialize the Visual Studio developer environment, and write helpful logs on failure.
|
||||
|
||||
## Quick start (from cmd.exe)
|
||||
- Fast essentials (runner + settings) and NuGet restore first:
|
||||
- `tools\build\build-essentials.cmd`
|
||||
- Build projects in the current folder:
|
||||
- `tools\build\build.cmd`
|
||||
|
||||
Tip: Add `D:\PowerToys\tools\build` to your PATH to use the wrappers anywhere.
|
||||
|
||||
## When to use which
|
||||
1) `build-essentials.ps1`
|
||||
- Restores NuGet for `PowerToys.sln` and builds essentials (runner, settings).
|
||||
- Auto-detects Platform; initializes VS Dev environment automatically.
|
||||
- Example (PowerShell):
|
||||
- `./tools/build/build-essentials.ps1`
|
||||
- `./tools/build/build-essentials.ps1 -Platform arm64 -Configuration Release`
|
||||
|
||||
2) `build.ps1` (from any folder)
|
||||
- Builds any `.sln/.csproj/.vcxproj` in the current directory.
|
||||
- Auto-detects Platform; initializes VS Dev environment automatically.
|
||||
- Accepts extra MSBuild args (forwarded to msbuild):
|
||||
- `./tools/build/build.ps1 '/p:CIBuild=true' '/p:SomeProp=Value'`
|
||||
- Restore only:
|
||||
- `./tools/build/build.ps1 -RestoreOnly`
|
||||
|
||||
3) `build-installer.ps1` (use with caution)
|
||||
- Full local packaging pipeline (restore, build, sign MSIX, WiX v5 MSI/bootstrapper).
|
||||
- Auto-inits VS Dev environment. Cleans some output (keeps *.exe) under `installer/`.
|
||||
- Key options: `-PerUser true|false`, `-InstallerSuffix wix5|vnext`.
|
||||
- Example:
|
||||
- `./tools/build/build-installer.ps1 -Platform x64 -Configuration Release -PerUser true -InstallerSuffix wix5`
|
||||
|
||||
## Logs and troubleshooting
|
||||
- On failure, see logs next to the solution/project being built:
|
||||
- `build.<configuration>.<platform>.all.log` — full text log
|
||||
- `build.<configuration>.<platform>.errors.log` — errors only
|
||||
- `build.<configuration>.<platform>.warnings.log` — warnings only
|
||||
- `build.<configuration>.<platform>.trace.binlog` — open with MSBuild Structured Log Viewer
|
||||
- VS environment init:
|
||||
- Scripts try DevShell first (`Microsoft.VisualStudio.DevShell.dll` / `Enter-VsDevShell`), then fall back to `VsDevCmd.bat`.
|
||||
- If VS isn’t found, run from “Developer PowerShell for VS 2022”, or ensure `vswhere.exe` exists under `Program Files (x86)\Microsoft Visual Studio\Installer`.
|
||||
|
||||
## Notes
|
||||
- Override platform explicitly with `-Platform x64|arm64` if needed.
|
||||
- CMD wrappers: `build.cmd`, `build-essentials.cmd` forward all arguments to the PowerShell scripts.
|
||||
@@ -1,272 +0,0 @@
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Shared build helper functions for PowerToys build scripts.
|
||||
|
||||
.DESCRIPTION
|
||||
This file provides reusable helper functions used by the build scripts:
|
||||
- Get-BuildPaths: returns ScriptDir, OriginalCwd, RepoRoot (repo root detection)
|
||||
- RunMSBuild: wrapper around msbuild.exe (accepts optional Platform/Configuration)
|
||||
- RestoreThenBuild: performs restore and optionally builds the solution/project
|
||||
- BuildProjectsInDirectory: discovers and builds local .sln/.csproj/.vcxproj files
|
||||
- Ensure-VsDevEnvironment: initializes the Visual Studio developer environment when possible.
|
||||
It prefers the DevShell PowerShell module (Microsoft.VisualStudio.DevShell.dll / Enter-VsDevShell),
|
||||
falls back to running VsDevCmd.bat and importing its environment into the current PowerShell session,
|
||||
and restores the caller's working directory after initialization.
|
||||
|
||||
USAGE
|
||||
Dot-source this file from a script to load helpers:
|
||||
. "$PSScriptRoot\build-common.ps1"
|
||||
|
||||
ERROR DETAILS
|
||||
When a build fails, check the logs written next to the solution/project folder:
|
||||
- build.<configuration>.<platform>.all.log — full MSBuild text log
|
||||
- build.<configuration>.<platform>.errors.log — extracted errors only
|
||||
- build.<configuration>.<platform>.warnings.log — extracted warnings only
|
||||
- build.<configuration>.<platform>.trace.binlog — binary log (open with the MSBuild Structured Log Viewer)
|
||||
|
||||
.NOTES
|
||||
Do not execute this file directly; dot-source it from `build.ps1` or `build-installer.ps1` so helpers are available in your script scope.
|
||||
#>
|
||||
|
||||
function RunMSBuild {
|
||||
param (
|
||||
[string]$Solution,
|
||||
[string]$ExtraArgs,
|
||||
[string]$Platform,
|
||||
[string]$Configuration
|
||||
)
|
||||
|
||||
# Prefer the solution's folder for logs; fall back to current directory
|
||||
$logRoot = Split-Path -Path $Solution
|
||||
if (-not $logRoot) { $logRoot = '.' }
|
||||
|
||||
$cfg = $null
|
||||
if ($Configuration) { $cfg = $Configuration.ToLower() } else { $cfg = 'unknown' }
|
||||
$plat = $null
|
||||
if ($Platform) { $plat = $Platform.ToLower() } else { $plat = 'unknown' }
|
||||
|
||||
$allLog = Join-Path $logRoot ("build.{0}.{1}.all.log" -f $cfg, $plat)
|
||||
$warningLog = Join-Path $logRoot ("build.{0}.{1}.warnings.log" -f $cfg, $plat)
|
||||
$errorsLog = Join-Path $logRoot ("build.{0}.{1}.errors.log" -f $cfg, $plat)
|
||||
$binLog = Join-Path $logRoot ("build.{0}.{1}.trace.binlog" -f $cfg, $plat)
|
||||
|
||||
$base = @(
|
||||
$Solution
|
||||
"/p:Platform=$Platform"
|
||||
"/p:Configuration=$Configuration"
|
||||
"/verbosity:normal"
|
||||
'/clp:Summary;PerformanceSummary;ErrorsOnly;WarningsOnly'
|
||||
"/fileLoggerParameters:LogFile=$allLog;Verbosity=detailed"
|
||||
"/fileLoggerParameters1:LogFile=$warningLog;WarningsOnly"
|
||||
"/fileLoggerParameters2:LogFile=$errorsLog;ErrorsOnly"
|
||||
"/bl:$binLog"
|
||||
'/nologo'
|
||||
)
|
||||
|
||||
$cmd = $base + ($ExtraArgs -split ' ')
|
||||
Write-Host (("[MSBUILD] {0}" -f ($cmd -join ' ')))
|
||||
|
||||
Push-Location $script:RepoRoot
|
||||
try {
|
||||
& msbuild.exe @cmd
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
Write-Error (("Build failed: {0} {1}`nSee logs:`n All: {2}`n Errors: {3}`n Binlog: {4}" -f $Solution, $ExtraArgs, $allLog, $errorsLog, $binLog))
|
||||
exit $LASTEXITCODE
|
||||
}
|
||||
} finally {
|
||||
Pop-Location
|
||||
}
|
||||
}
|
||||
|
||||
function RestoreThenBuild {
|
||||
param (
|
||||
[string]$Solution,
|
||||
[string]$ExtraArgs,
|
||||
[string]$Platform,
|
||||
[string]$Configuration,
|
||||
[bool]$RestoreOnly=$false
|
||||
)
|
||||
|
||||
$restoreArgs = '/t:restore /p:RestorePackagesConfig=true'
|
||||
if ($ExtraArgs) { $restoreArgs = "$restoreArgs $ExtraArgs" }
|
||||
RunMSBuild $Solution $restoreArgs $Platform $Configuration
|
||||
|
||||
if (-not $RestoreOnly) {
|
||||
$buildArgs = '/m'
|
||||
if ($ExtraArgs) { $buildArgs = "$buildArgs $ExtraArgs" }
|
||||
RunMSBuild $Solution $buildArgs $Platform $Configuration
|
||||
}
|
||||
}
|
||||
|
||||
function BuildProjectsInDirectory {
|
||||
param(
|
||||
[string]$DirectoryPath,
|
||||
[string]$ExtraArgs,
|
||||
[string]$Platform,
|
||||
[string]$Configuration,
|
||||
[switch]$RestoreOnly
|
||||
)
|
||||
|
||||
if (-not (Test-Path $DirectoryPath)) {
|
||||
return $false
|
||||
}
|
||||
|
||||
$files = @()
|
||||
try {
|
||||
$files = Get-ChildItem -Path (Join-Path $DirectoryPath '*') -Include *.sln,*.csproj,*.vcxproj -File -ErrorAction SilentlyContinue
|
||||
} catch {
|
||||
$files = @()
|
||||
}
|
||||
|
||||
if (-not $files -or $files.Count -eq 0) {
|
||||
return $false
|
||||
}
|
||||
|
||||
$names = ($files | ForEach-Object { $_.Name }) -join ', '
|
||||
Write-Host ("[LOCAL BUILD] Found {0} project(s) in {1}: {2}" -f $files.Count, $DirectoryPath, $names)
|
||||
|
||||
$preferredOrder = @('.sln', '.csproj', '.vcxproj')
|
||||
$files = $files | Sort-Object @{Expression = { [array]::IndexOf($preferredOrder, $_.Extension.ToLower()) }}
|
||||
|
||||
foreach ($f in $files) {
|
||||
Write-Host ("[LOCAL BUILD] Building {0}" -f $f.FullName)
|
||||
if ($f.Extension -eq '.sln') {
|
||||
RestoreThenBuild $f.FullName $ExtraArgs $Platform $Configuration $RestoreOnly
|
||||
} else {
|
||||
$buildArgs = '/m'
|
||||
if ($ExtraArgs) { $buildArgs = "$buildArgs $ExtraArgs" }
|
||||
RunMSBuild $f.FullName $buildArgs $Platform $Configuration
|
||||
}
|
||||
}
|
||||
|
||||
return $true
|
||||
}
|
||||
|
||||
function Get-DefaultPlatform {
|
||||
<#
|
||||
Returns a default target platform string based on the host machine (x64, arm64, x86).
|
||||
#>
|
||||
try {
|
||||
$envArch = $env:PROCESSOR_ARCHITECTURE
|
||||
if ($envArch) { $envArch = $envArch.ToLower() }
|
||||
if ($envArch -eq 'amd64' -or $envArch -eq 'x86_64') { return 'x64' }
|
||||
if ($envArch -match 'arm64') { return 'arm64' }
|
||||
if ($envArch -eq 'x86') { return 'x86' }
|
||||
|
||||
if ($env:PROCESSOR_ARCHITEW6432) {
|
||||
$envArch2 = $env:PROCESSOR_ARCHITEW6432.ToLower()
|
||||
if ($envArch2 -eq 'amd64') { return 'x64' }
|
||||
if ($envArch2 -match 'arm64') { return 'arm64' }
|
||||
}
|
||||
|
||||
try {
|
||||
$osArch = [System.Runtime.InteropServices.RuntimeInformation]::OSArchitecture
|
||||
switch ($osArch.ToString().ToLower()) {
|
||||
'x64' { return 'x64' }
|
||||
'arm64' { return 'arm64' }
|
||||
'x86' { return 'x86' }
|
||||
}
|
||||
} catch {
|
||||
# ignore - RuntimeInformation may not be available
|
||||
}
|
||||
} catch {
|
||||
# ignore any errors and fall back
|
||||
}
|
||||
|
||||
return 'x64'
|
||||
}
|
||||
|
||||
function Ensure-VsDevEnvironment {
|
||||
$OriginalLocationForVsInit = Get-Location
|
||||
try {
|
||||
|
||||
if ($env:VSINSTALLDIR -or $env:VCINSTALLDIR -or $env:DevEnvDir -or $env:VCToolsInstallDir) {
|
||||
Write-Host "[VS] VS developer environment already present"
|
||||
return $true
|
||||
}
|
||||
|
||||
# Locate vswhere if available
|
||||
$vswhereCandidates = @(
|
||||
"$env:ProgramFiles (x86)\Microsoft Visual Studio\Installer\vswhere.exe",
|
||||
"$env:ProgramFiles\Microsoft Visual Studio\Installer\vswhere.exe"
|
||||
)
|
||||
$vswhere = $vswhereCandidates | Where-Object { Test-Path $_ } | Select-Object -First 1
|
||||
if ($vswhere) { Write-Host "[VS] vswhere found: $vswhere" } else { Write-Host "[VS] vswhere not found" }
|
||||
|
||||
$instPaths = @()
|
||||
if ($vswhere) {
|
||||
# First try with the VC tools requirement (preferred)
|
||||
try { $p = & $vswhere -latest -products * -requires Microsoft.VisualStudio.Component.VC.Tools.x86.x64 -property installationPath 2>$null; if ($p) { $instPaths += $p } } catch {}
|
||||
# Fallback: try without -requires to find any VS installations
|
||||
if (-not $instPaths) {
|
||||
try { $p2 = & $vswhere -latest -products * -property installationPath 2>$null; if ($p2) { $instPaths += $p2 } } catch {}
|
||||
}
|
||||
}
|
||||
|
||||
# Add explicit common year-based candidates as a last resort
|
||||
if (-not $instPaths) {
|
||||
$explicit = @(
|
||||
"$env:ProgramFiles (x86)\Microsoft Visual Studio\2022\Community",
|
||||
"$env:ProgramFiles (x86)\Microsoft Visual Studio\2022\Professional",
|
||||
"$env:ProgramFiles (x86)\Microsoft Visual Studio\2022\Enterprise",
|
||||
"$env:ProgramFiles\Microsoft Visual Studio\2022\Community",
|
||||
"$env:ProgramFiles\Microsoft Visual Studio\2022\Professional",
|
||||
"$env:ProgramFiles\Microsoft Visual Studio\2022\Enterprise"
|
||||
)
|
||||
foreach ($c in $explicit) { if (Test-Path $c) { $instPaths += $c } }
|
||||
}
|
||||
|
||||
if (-not $instPaths -or $instPaths.Count -eq 0) {
|
||||
Write-Warning "[VS] Could not locate Visual Studio installation (no candidates found)"
|
||||
return $false
|
||||
}
|
||||
|
||||
# Try each candidate installation path until one works
|
||||
foreach ($inst in $instPaths) {
|
||||
if (-not $inst) { continue }
|
||||
Write-Host "[VS] Checking candidate: $inst"
|
||||
|
||||
$devDll = Join-Path $inst 'Common7\Tools\Microsoft.VisualStudio.DevShell.dll'
|
||||
if (Test-Path $devDll) {
|
||||
try {
|
||||
Import-Module $devDll -DisableNameChecking -ErrorAction Stop
|
||||
|
||||
# Call Enter-VsDevShell using only the install path to avoid parameter name differences
|
||||
try {
|
||||
Enter-VsDevShell -VsInstallPath $inst -ErrorAction Stop
|
||||
Write-Host "[VS] Entered Visual Studio DevShell at $inst"
|
||||
return $true
|
||||
} catch {
|
||||
Write-Warning ("[VS] DevShell import/Enter-VsDevShell failed: {0}" -f $_)
|
||||
}
|
||||
} catch {
|
||||
Write-Warning ("[VS] DevShell import failed: {0}" -f $_)
|
||||
}
|
||||
}
|
||||
|
||||
$vsDevCmd = Join-Path $inst 'Common7\Tools\VsDevCmd.bat'
|
||||
if (Test-Path $vsDevCmd) {
|
||||
Write-Host "[VS] Running VsDevCmd.bat and importing environment from $vsDevCmd"
|
||||
try {
|
||||
$cmdOut = cmd.exe /c "`"$vsDevCmd`" && set"
|
||||
foreach ($line in $cmdOut) {
|
||||
$parts = $line -split('=',2)
|
||||
if ($parts.Length -eq 2) {
|
||||
try { [Environment]::SetEnvironmentVariable($parts[0], $parts[1], 'Process') } catch {}
|
||||
}
|
||||
}
|
||||
Write-Host "[VS] Imported environment from VsDevCmd.bat at $inst"
|
||||
return $true
|
||||
} catch {
|
||||
Write-Warning ("[VS] Failed to run/import VsDevCmd.bat at {0}: {1}" -f $inst, $_)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Write-Warning "[VS] Neither DevShell module nor VsDevCmd.bat found in any candidate paths"
|
||||
return $false
|
||||
|
||||
} finally {
|
||||
try { Set-Location $OriginalLocationForVsInit } catch {}
|
||||
}
|
||||
}
|
||||
@@ -1,5 +0,0 @@
|
||||
@echo off
|
||||
REM Wrapper to run build-essentials.ps1 from cmd.exe
|
||||
set SCRIPT_DIR=%~dp0
|
||||
powershell.exe -NoProfile -ExecutionPolicy Bypass -File "%SCRIPT_DIR%build-essentials.ps1" %*
|
||||
exit /b %ERRORLEVEL%
|
||||
@@ -1,74 +1,16 @@
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Build essential native PowerToys projects (runner and settings), restoring NuGet packages first.
|
||||
cd $PSScriptRoot
|
||||
cd ..\..
|
||||
$cwd = Get-Location
|
||||
$SolutionDir = $cwd,"" -join "\"
|
||||
cd $SolutionDir
|
||||
$BuildArgs = "/p:Configuration=Release /p:Platform=x64 /p:BuildProjectReferences=false /p:SolutionDir=$SolutionDir"
|
||||
|
||||
.DESCRIPTION
|
||||
Lightweight script to build a small set of essential C++ projects used by PowerToys' runner and native modules. This script first restores NuGet packages for the full solution (`PowerToys.sln`) and then builds the runner and settings projects. Intended for fast local builds during development.
|
||||
$ProjectsToBuild =
|
||||
".\src\runner\runner.vcxproj",
|
||||
".\src\modules\shortcut_guide\shortcut_guide.vcxproj",
|
||||
".\src\modules\fancyzones\lib\FancyZonesLib.vcxproj",
|
||||
".\src\modules\fancyzones\dll\FancyZonesModule.vcxproj"
|
||||
|
||||
.PARAMETER Platform
|
||||
Target platform for the build (for example: 'x64', 'arm64'). If omitted the script will attempt to auto-detect the host platform.
|
||||
|
||||
.PARAMETER Configuration
|
||||
Build configuration (for example: 'Debug' or 'Release'). Default is 'Debug'.
|
||||
|
||||
.EXAMPLE
|
||||
.\tools\build\build-essentials.ps1
|
||||
Restores packages for the solution and builds the default set of native projects using the auto-detected platform and Debug configuration.
|
||||
|
||||
.EXAMPLE
|
||||
.\tools\build\build-essentials.ps1 -Platform arm64 -Configuration Release
|
||||
Restores packages and builds the essentials in Release mode for ARM64, even if your machine is running on x64.
|
||||
|
||||
.NOTES
|
||||
- This script dot-sources `build-common.ps1` and uses the shared helper `RunMSBuild`.
|
||||
- It will call `RestoreThenBuild 'PowerToys.sln'` before building the essential projects to ensure NuGet packages are restored.
|
||||
- The script attempts to locate the repository root automatically and can be run from any folder inside the repo.
|
||||
#>
|
||||
|
||||
param (
|
||||
[string]$Platform = '',
|
||||
[string]$Configuration = 'Debug'
|
||||
)
|
||||
|
||||
# Find repository root starting from the script location
|
||||
$ScriptDir = Split-Path -Parent $MyInvocation.MyCommand.Definition
|
||||
$repoRoot = $ScriptDir
|
||||
while ($repoRoot -and -not (Test-Path (Join-Path $repoRoot "PowerToys.sln"))) {
|
||||
$parent = Split-Path -Parent $repoRoot
|
||||
if ($parent -eq $repoRoot) {
|
||||
Write-Error "Could not find PowerToys repository root."
|
||||
exit 1
|
||||
}
|
||||
$repoRoot = $parent
|
||||
}
|
||||
|
||||
# Export script-scope variables used by build-common helpers
|
||||
Set-Variable -Name RepoRoot -Value $repoRoot -Scope Script -Force
|
||||
|
||||
# Load shared helpers
|
||||
. "$PSScriptRoot\build-common.ps1"
|
||||
|
||||
# Initialize Visual Studio dev environment
|
||||
if (-not (Ensure-VsDevEnvironment)) { exit 1 }
|
||||
|
||||
# If platform not provided, auto-detect from host
|
||||
if (-not $Platform -or $Platform -eq '') {
|
||||
try {
|
||||
$Platform = Get-DefaultPlatform
|
||||
Write-Host ("[AUTO-PLATFORM] Detected platform: {0}" -f $Platform)
|
||||
} catch {
|
||||
Write-Warning "Failed to auto-detect platform; defaulting to 'x64'"
|
||||
$Platform = 'x64'
|
||||
}
|
||||
}
|
||||
|
||||
# Ensure solution packages are restored
|
||||
RestoreThenBuild 'PowerToys.sln' '' $Platform $Configuration $true
|
||||
|
||||
# Build both runner and settings
|
||||
$ProjectsToBuild = @(".\src\runner\runner.vcxproj", ".\src\settings-ui\Settings.UI\PowerToys.Settings.csproj")
|
||||
$ExtraArgs = "/p:SolutionDir=$repoRoot\"
|
||||
foreach ($proj in $ProjectsToBuild) {
|
||||
Write-Host ("[BUILD-ESSENTIALS] Building {0}" -f $proj)
|
||||
RunMSBuild $proj $ExtraArgs $Platform $Configuration
|
||||
$ProjectsToBuild | % {
|
||||
Invoke-Expression "msbuild $_ $BuildArgs"
|
||||
}
|
||||
@@ -52,29 +52,12 @@ Runs the pipeline for x64 Release with 'vnext' suffix.
|
||||
#>
|
||||
|
||||
param (
|
||||
[string]$Platform = '',
|
||||
[string]$Platform = 'x64',
|
||||
[string]$Configuration = 'Release',
|
||||
[string]$PerUser = 'true',
|
||||
[string]$InstallerSuffix = 'wix5'
|
||||
)
|
||||
|
||||
# Ensure helpers are available
|
||||
. "$PSScriptRoot\build-common.ps1"
|
||||
|
||||
# Initialize Visual Studio dev environment
|
||||
if (-not (Ensure-VsDevEnvironment)) { exit 1 }
|
||||
|
||||
# Auto-detect platform when not provided
|
||||
if (-not $Platform -or $Platform -eq '') {
|
||||
try {
|
||||
$Platform = Get-DefaultPlatform
|
||||
Write-Host ("[AUTO-PLATFORM] Detected platform: {0}" -f $Platform)
|
||||
} catch {
|
||||
Write-Warning "Failed to auto-detect platform; defaulting to x64"
|
||||
$Platform = 'x64'
|
||||
}
|
||||
}
|
||||
|
||||
# Find the PowerToys repository root automatically
|
||||
$scriptDir = Split-Path -Parent $MyInvocation.MyCommand.Definition
|
||||
$repoRoot = $scriptDir
|
||||
@@ -97,7 +80,50 @@ if (-not $repoRoot -or -not (Test-Path (Join-Path $repoRoot "PowerToys.sln"))) {
|
||||
}
|
||||
|
||||
Write-Host "PowerToys repository root detected: $repoRoot"
|
||||
|
||||
function RunMSBuild {
|
||||
param (
|
||||
[string]$Solution,
|
||||
[string]$ExtraArgs
|
||||
)
|
||||
|
||||
$base = @(
|
||||
$Solution
|
||||
"/p:Platform=$Platform"
|
||||
"/p:Configuration=$Configuration"
|
||||
"/p:CIBuild=true"
|
||||
'/verbosity:normal'
|
||||
'/clp:Summary;PerformanceSummary;ErrorsOnly;WarningsOnly'
|
||||
'/nologo'
|
||||
)
|
||||
|
||||
$cmd = $base + ($ExtraArgs -split ' ')
|
||||
Write-Host ("[MSBUILD] {0} {1}" -f $Solution, ($cmd -join ' '))
|
||||
|
||||
# Run MSBuild from the repository root directory
|
||||
Push-Location $repoRoot
|
||||
try {
|
||||
& msbuild.exe @cmd
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
Write-Error ("Build failed: {0} {1}" -f $Solution, $ExtraArgs)
|
||||
exit $LASTEXITCODE
|
||||
}
|
||||
} finally {
|
||||
Pop-Location
|
||||
}
|
||||
}
|
||||
|
||||
function RestoreThenBuild {
|
||||
param ([string]$Solution)
|
||||
|
||||
# 1) restore
|
||||
RunMSBuild $Solution '/t:restore /p:RestorePackagesConfig=true'
|
||||
# 2) build -------------------------------------------------
|
||||
RunMSBuild $Solution '/m'
|
||||
}
|
||||
|
||||
# WiX v5 projects use WixToolset.Sdk via NuGet/MSBuild; a separate WiX 3 installation is not required here.
|
||||
|
||||
Write-Host ("[PIPELINE] Start | Platform={0} Configuration={1} PerUser={2}" -f $Platform, $Configuration, $PerUser)
|
||||
Write-Host ''
|
||||
|
||||
@@ -108,9 +134,7 @@ if (Test-Path $cmdpalOutputPath) {
|
||||
Remove-Item $cmdpalOutputPath -Recurse -Force -ErrorAction Ignore
|
||||
}
|
||||
|
||||
$commonArgs = '/p:CIBuild=true'
|
||||
# No local projects found (or continuing) - build full solution and tools
|
||||
RestoreThenBuild 'PowerToys.sln' $commonArgs $Platform $Configuration
|
||||
RestoreThenBuild 'PowerToys.sln'
|
||||
|
||||
$msixSearchRoot = Join-Path $repoRoot "$Platform\$Configuration"
|
||||
$msixFiles = Get-ChildItem -Path $msixSearchRoot -Recurse -Filter *.msix |
|
||||
@@ -124,8 +148,8 @@ else {
|
||||
Write-Warning "[SIGN] No .msix files found in $msixSearchRoot"
|
||||
}
|
||||
|
||||
RestoreThenBuild 'tools\BugReportTool\BugReportTool.sln' $commonArgs $Platform $Configuration
|
||||
RestoreThenBuild 'tools\StylesReportTool\StylesReportTool.sln' $commonArgs $Platform $Configuration
|
||||
RestoreThenBuild 'tools\BugReportTool\BugReportTool.sln'
|
||||
RestoreThenBuild 'tools\StylesReportTool\StylesReportTool.sln'
|
||||
|
||||
Write-Host '[CLEAN] installer (keep *.exe)'
|
||||
Push-Location $repoRoot
|
||||
@@ -135,10 +159,10 @@ try {
|
||||
Pop-Location
|
||||
}
|
||||
|
||||
RunMSBuild 'installer\PowerToysSetup.sln' "$commonArgs /t:restore /p:RestorePackagesConfig=true" $Platform $Configuration
|
||||
RunMSBuild 'installer\PowerToysSetup.sln' '/t:restore /p:RestorePackagesConfig=true'
|
||||
|
||||
RunMSBuild 'installer\PowerToysSetup.sln' "$commonArgs /m /t:PowerToysInstallerVNext /p:PerUser=$PerUser /p:InstallerSuffix=$InstallerSuffix" $Platform $Configuration
|
||||
RunMSBuild 'installer\PowerToysSetup.sln' "/m /t:PowerToysInstallerVNext /p:PerUser=$PerUser /p:InstallerSuffix=$InstallerSuffix"
|
||||
|
||||
RunMSBuild 'installer\PowerToysSetup.sln' "$commonArgs /m /t:PowerToysBootstrapperVNext /p:PerUser=$PerUser /p:InstallerSuffix=$InstallerSuffix" $Platform $Configuration
|
||||
RunMSBuild 'installer\PowerToysSetup.sln' "/m /t:PowerToysBootstrapperVNext /p:PerUser=$PerUser /p:InstallerSuffix=$InstallerSuffix"
|
||||
|
||||
Write-Host '[PIPELINE] Completed'
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
@echo off
|
||||
REM Wrapper to run the PowerShell build script from cmd.exe
|
||||
set SCRIPT_DIR=%~dp0
|
||||
powershell.exe -NoProfile -ExecutionPolicy Bypass -File "%SCRIPT_DIR%build.ps1" %*
|
||||
exit /b %ERRORLEVEL%
|
||||
@@ -1,92 +0,0 @@
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Light-weight wrapper to build local projects (solutions/projects) in the current working directory using helpers in build-common.ps1.
|
||||
|
||||
.DESCRIPTION
|
||||
This script is intended for quick local builds. It dot-sources `build-common.ps1` and calls `BuildProjectsInDirectory` against the current directory. Use `-RestoreOnly` to only restore packages for local projects. If `-Platform` is omitted the script attempts to auto-detect the host platform.
|
||||
|
||||
.PARAMETER Platform
|
||||
Target platform (e.g., 'x64', 'arm64'). If omitted the script will try to detect the host platform automatically.
|
||||
|
||||
.PARAMETER Configuration
|
||||
Build configuration (e.g., 'Debug', 'Release'). Default: 'Debug'.
|
||||
|
||||
.PARAMETER RestoreOnly
|
||||
If specified, only perform package restore for local projects and skip the build steps for a solution file (i.e. .sln).
|
||||
|
||||
.PARAMETER ExtraArgs
|
||||
Any remaining, positional arguments passed to the script are forwarded to MSBuild as additional arguments (e.g., '/p:CIBuild=true').
|
||||
|
||||
.EXAMPLE
|
||||
.\tools\build\build.ps1
|
||||
Builds any .sln/.csproj/.vcxproj in the current working directory (auto-detects Platform).
|
||||
|
||||
.EXAMPLE
|
||||
.\tools\build\build.ps1 -Platform x64 -Configuration Release
|
||||
Builds local projects for x64 Release.
|
||||
|
||||
.EXAMPLE
|
||||
.\tools\build\build.ps1 '/p:CIBuild=true' '/p:SomeOther=Value'
|
||||
Pass additional MSBuild arguments; these are forwarded to the underlying msbuild calls.
|
||||
|
||||
.EXAMPLE
|
||||
.\tools\build\build.ps1 -RestoreOnly '/p:CIBuild=true'
|
||||
Only restores packages for local projects; ExtraArgs still forwarded to msbuild's restore phase.
|
||||
|
||||
.NOTES
|
||||
- This file expects `build-common.ps1` to be located in the same folder and dot-sources it to load helper functions.
|
||||
- ExtraArgs are captured using PowerShell's ValueFromRemainingArguments and joined before being passed to the helpers.
|
||||
#>
|
||||
|
||||
param (
|
||||
[string]$Platform = '',
|
||||
[string]$Configuration = 'Debug',
|
||||
[switch]$RestoreOnly,
|
||||
[Parameter(ValueFromRemainingArguments=$true)]
|
||||
[string[]]$ExtraArgs
|
||||
)
|
||||
|
||||
. "$PSScriptRoot\build-common.ps1"
|
||||
|
||||
# Initialize Visual Studio dev environment
|
||||
if (-not (Ensure-VsDevEnvironment)) { exit 1 }
|
||||
|
||||
# If user passed MSBuild-style args (e.g. './build.ps1 /p:CIBuild=true'),
|
||||
# those will bind to $Platform/$Configuration; detect those and move them to ExtraArgs.
|
||||
$positionalExtra = @()
|
||||
if ($Platform -and $Platform -match '^[\/-]') {
|
||||
$positionalExtra += $Platform
|
||||
$Platform = ''
|
||||
}
|
||||
if ($Configuration -and $Configuration -match '^[\/-]') {
|
||||
$positionalExtra += $Configuration
|
||||
$Configuration = 'Debug'
|
||||
}
|
||||
if ($positionalExtra.Count -gt 0) {
|
||||
if (-not $ExtraArgs) { $ExtraArgs = @() }
|
||||
$ExtraArgs = $positionalExtra + $ExtraArgs
|
||||
}
|
||||
|
||||
# Auto-detect platform when not provided
|
||||
if (-not $Platform -or $Platform -eq '') {
|
||||
try {
|
||||
$Platform = Get-DefaultPlatform
|
||||
Write-Host ("[AUTO-PLATFORM] Detected platform: {0}" -f $Platform)
|
||||
} catch {
|
||||
Write-Warning "Failed to auto-detect platform; defaulting to x64"
|
||||
$Platform = 'x64'
|
||||
}
|
||||
}
|
||||
|
||||
$cwd = (Get-Location).ProviderPath
|
||||
$extraArgsString = $null
|
||||
if ($ExtraArgs -and $ExtraArgs.Count -gt 0) { $extraArgsString = ($ExtraArgs -join ' ') }
|
||||
|
||||
$built = BuildProjectsInDirectory -DirectoryPath $cwd -ExtraArgs $extraArgsString -Platform $Platform -Configuration $Configuration -RestoreOnly:$RestoreOnly
|
||||
if ($built) {
|
||||
Write-Host "[BUILD] Local projects built; exiting."
|
||||
exit 0
|
||||
} else {
|
||||
Write-Host "[BUILD] No local projects found in $cwd"
|
||||
exit 0
|
||||
}
|
||||
Reference in New Issue
Block a user