mirror of
https://github.com/microsoft/PowerToys.git
synced 2026-04-03 09:46:54 +02:00
Add setting to select network speed units in Command Palette (#46320)
## Summary of the Pull Request Adds a unit selection setting to the Performance Monitor extension in Command Palette that allows users to choose how network transmission speed is displayed. The setting offers three options: bits per second (Kbps/Mbps/Gbps, the default), bytes per second (KB/s/MB/s/GB/s), and binary bytes per second using IEC prefixes (KiB/s/MiB/s/GiB/s). ## PR Checklist - [ ] **Communication:** I've discussed this with core contributors already. If the work hasn't been agreed, this work might be rejected - [ ] **Tests:** Added/updated and all pass - [ ] **Localization:** All end-user-facing strings can be localized - [ ] **Dev docs:** Added/updated - [ ] **New binaries:** Added on the required places - [ ] [JSON for signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json) for new binaries - [ ] [WXS for installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs) for new binaries and localization folder - [ ] [YML for CI pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml) for new test projects - [ ] [YML for signed pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml) - [ ] **Documentation updated:** If checked, please file a pull request on [our docs repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys) and link it here: #xxx ## Detailed Description of the Pull Request / Additional comments The following files were changed: - **`NetworkSpeedUnit.cs`** (new): Enum defining the three supported unit modes — `BitsPerSecond`, `BytesPerSecond`, and `BinaryBytesPerSecond`. - **`SettingsManager.cs`** (new): A `JsonSettingsManager` subclass for the Performance Monitor extension. Defines a `ChoiceSetSetting` for `NetworkSpeedUnit` (default: `BitsPerSecond`), stored under the `performanceMonitor` namespace in the shared CmdPal `settings.json`. - **`PerformanceWidgetsPage.cs`**: - `PerformanceWidgetsPage` constructor now accepts `SettingsManager` and passes it to `SystemNetworkUsageWidgetPage`. - `SystemNetworkUsageWidgetPage` stores the settings manager and calls `SpeedToString()`, which dispatches via a switch expression to `FormatAsBitsPerSecString()` (e.g. `12.5 Mbps`), `FormatAsBytesPerSecString()` (e.g. `1.6 MB/s`), or `FormatAsBinaryBytesPerSecString()` (e.g. `1.5 MiB/s`) based on the selected unit. - **`PerformanceMonitorCommandsProvider.cs`**: Holds the `SettingsManager`, passes it to both the list page and dock band via `SetEnabledState()`, exposes `Settings` on the provider, and adds the settings page to the command's `MoreCommands`. The crash-recovery hardening from main (`ProviderCrashSentinel`, `TryReactivateImmediately`, `SetDisabledState`, thread-safe locking) is fully preserved and integrated with the settings manager. - **`Resources.resw`**: Updated `Network_Speed_Unit_Setting_Title` and `Network_Speed_Unit_Setting_Description` to neutral language; added three choice label strings (`Network_Speed_Unit_BitsPerSec`, `Network_Speed_Unit_BytesPerSec`, `Network_Speed_Unit_BinaryBytesPerSec`). Also includes the disabled-state strings merged from main. ## Validation Steps Performed - Manually verified that the setting appears in the Performance Monitor extension's settings page (accessible via the ⋯ context menu on the Performance Monitor command item). - Verified that network speed values display in Kbps/Mbps/Gbps by default, switch to KB/s/MB/s/GB/s when the bytes option is selected, and switch to KiB/s/MiB/s/GiB/s when the binary bytes option is selected. - Setting persists across Command Palette restarts via the shared CmdPal settings file. - Verified that the crash-recovery re-enable flow correctly restores pages with the settings manager wired up. <!-- START COPILOT ORIGINAL PROMPT --> <details> <summary>Original prompt</summary> > > ---- > > *This section details on the original issue you should resolve* > > <issue_title>[Command Palette] Allows network transmission speed units to be switched between bits per second and bytes per second</issue_title> > <issue_description>### Description of the new feature / enhancement > > Add a setting that allows network monitoring in the Command Palette Dock to be displayed in bytes per second. > > ### Scenario when this would be used? > > In everyday usage, byte units are more commonly used. > > ### Supporting information > > _No response_</issue_description> > > ## Comments on the Issue (you are @copilot in this section) > > <comments> > <comment_new><author>@niels9001</author><body> > @copilot Can you add a setting for this?</body></comment_new> > </comments> > </details> <!-- START COPILOT CODING AGENT SUFFIX --> - Fixes microsoft/PowerToys#46271 <!-- START COPILOT CODING AGENT TIPS --> --- ✨ Let Copilot coding agent [set things up for you](https://github.com/microsoft/PowerToys/issues/new?title=✨+Set+up+Copilot+instructions&body=Configure%20instructions%20for%20this%20repository%20as%20documented%20in%20%5BBest%20practices%20for%20Copilot%20coding%20agent%20in%20your%20repository%5D%28https://gh.io/copilot-coding-agent-tips%29%2E%0A%0A%3COnboard%20this%20repo%3E&assignees=copilot) — coding agent works faster and does higher quality work when set up for your repo. --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: niels9001 <9866362+niels9001@users.noreply.github.com>
This commit is contained in:
@@ -0,0 +1,20 @@
|
|||||||
|
// 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.
|
||||||
|
|
||||||
|
namespace Microsoft.CmdPal.Ext.PerformanceMonitor;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Controls the unit used to display network transmission speed.
|
||||||
|
/// </summary>
|
||||||
|
internal enum NetworkSpeedUnit
|
||||||
|
{
|
||||||
|
/// <summary>Bits per second (Kbps, Mbps, Gbps) — SI decimal prefixes.</summary>
|
||||||
|
BitsPerSecond,
|
||||||
|
|
||||||
|
/// <summary>Bytes per second (KB/s, MB/s, GB/s) — SI decimal prefixes.</summary>
|
||||||
|
BytesPerSecond,
|
||||||
|
|
||||||
|
/// <summary>Bytes per second (KiB/s, MiB/s, GiB/s) — IEC binary prefixes.</summary>
|
||||||
|
BinaryBytesPerSecond,
|
||||||
|
}
|
||||||
@@ -21,6 +21,7 @@ public partial class PerformanceMonitorCommandsProvider : CommandProvider
|
|||||||
internal static ProviderCrashSentinel CrashSentinel { get; } = new(ProviderIdValue);
|
internal static ProviderCrashSentinel CrashSentinel { get; } = new(ProviderIdValue);
|
||||||
|
|
||||||
private readonly Lock _stateLock = new();
|
private readonly Lock _stateLock = new();
|
||||||
|
private readonly SettingsManager _settingsManager = new();
|
||||||
private ICommandItem[] _commands = [];
|
private ICommandItem[] _commands = [];
|
||||||
private ICommandItem _band = new CommandItem();
|
private ICommandItem _band = new CommandItem();
|
||||||
private PerformanceWidgetsPage? _mainPage;
|
private PerformanceWidgetsPage? _mainPage;
|
||||||
@@ -33,6 +34,8 @@ public partial class PerformanceMonitorCommandsProvider : CommandProvider
|
|||||||
Id = ProviderIdValue;
|
Id = ProviderIdValue;
|
||||||
Icon = Icons.PerformanceMonitorIcon;
|
Icon = Icons.PerformanceMonitorIcon;
|
||||||
|
|
||||||
|
Settings = _settingsManager.Settings;
|
||||||
|
|
||||||
if (softDisabled)
|
if (softDisabled)
|
||||||
{
|
{
|
||||||
SetDisabledState();
|
SetDisabledState();
|
||||||
@@ -121,12 +124,16 @@ public partial class PerformanceMonitorCommandsProvider : CommandProvider
|
|||||||
{
|
{
|
||||||
DisposeActivePages();
|
DisposeActivePages();
|
||||||
|
|
||||||
_mainPage = new PerformanceWidgetsPage(false);
|
_mainPage = new PerformanceWidgetsPage(_settingsManager, false);
|
||||||
_bandPage = new PerformanceWidgetsPage(true);
|
_bandPage = new PerformanceWidgetsPage(_settingsManager, true);
|
||||||
_band = new CommandItem(_bandPage) { Title = DisplayName };
|
_band = new CommandItem(_bandPage) { Title = DisplayName };
|
||||||
_commands =
|
_commands =
|
||||||
[
|
[
|
||||||
new CommandItem(_mainPage) { Title = DisplayName },
|
new CommandItem(_mainPage)
|
||||||
|
{
|
||||||
|
Title = DisplayName,
|
||||||
|
MoreCommands = [new CommandContextItem(_settingsManager.Settings.SettingsPage)],
|
||||||
|
},
|
||||||
];
|
];
|
||||||
_softDisabled = false;
|
_softDisabled = false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -43,7 +43,7 @@ internal sealed partial class PerformanceWidgetsPage : OnLoadStaticListPage, IDi
|
|||||||
private readonly SystemMemoryUsageWidgetPage _memoryPage = new();
|
private readonly SystemMemoryUsageWidgetPage _memoryPage = new();
|
||||||
private readonly ListItem _memoryItem;
|
private readonly ListItem _memoryItem;
|
||||||
|
|
||||||
private readonly SystemNetworkUsageWidgetPage _networkPage = new();
|
private readonly SystemNetworkUsageWidgetPage _networkPage;
|
||||||
private readonly ListItem _networkItem;
|
private readonly ListItem _networkItem;
|
||||||
|
|
||||||
private readonly SystemGPUUsageWidgetPage _gpuPage = new();
|
private readonly SystemGPUUsageWidgetPage _gpuPage = new();
|
||||||
@@ -55,9 +55,10 @@ internal sealed partial class PerformanceWidgetsPage : OnLoadStaticListPage, IDi
|
|||||||
private string _networkUpSpeed = string.Empty;
|
private string _networkUpSpeed = string.Empty;
|
||||||
private string _networkDownSpeed = string.Empty;
|
private string _networkDownSpeed = string.Empty;
|
||||||
|
|
||||||
public PerformanceWidgetsPage(bool isBandPage = false)
|
public PerformanceWidgetsPage(SettingsManager settingsManager, bool isBandPage = false)
|
||||||
{
|
{
|
||||||
_isBandPage = isBandPage;
|
_isBandPage = isBandPage;
|
||||||
|
_networkPage = new SystemNetworkUsageWidgetPage(settingsManager);
|
||||||
_cpuItem = new ListItem(_cpuPage)
|
_cpuItem = new ListItem(_cpuPage)
|
||||||
{
|
{
|
||||||
Title = _cpuPage.GetItemTitle(isBandPage),
|
Title = _cpuPage.GetItemTitle(isBandPage),
|
||||||
@@ -532,10 +533,12 @@ internal sealed partial class SystemNetworkUsageWidgetPage : WidgetPage, IDispos
|
|||||||
public override IconInfo Icon => Icons.NetworkIcon;
|
public override IconInfo Icon => Icons.NetworkIcon;
|
||||||
|
|
||||||
private readonly DataManager _dataManager;
|
private readonly DataManager _dataManager;
|
||||||
|
private readonly SettingsManager _settingsManager;
|
||||||
private int _networkIndex;
|
private int _networkIndex;
|
||||||
|
|
||||||
public SystemNetworkUsageWidgetPage()
|
public SystemNetworkUsageWidgetPage(SettingsManager settingsManager)
|
||||||
{
|
{
|
||||||
|
_settingsManager = settingsManager;
|
||||||
_dataManager = new(DataType.Network, () => UpdateWidget());
|
_dataManager = new(DataType.Network, () => UpdateWidget());
|
||||||
Commands = [
|
Commands = [
|
||||||
new CommandContextItem(new PrevNetworkCommand(this) { Name = Resources.GetResource("Previous_Network_Title") }),
|
new CommandContextItem(new PrevNetworkCommand(this) { Name = Resources.GetResource("Previous_Network_Title") }),
|
||||||
@@ -561,8 +564,8 @@ internal sealed partial class SystemNetworkUsageWidgetPage : WidgetPage, IDispos
|
|||||||
var networkStats = currentData.GetNetworkUsage(_networkIndex);
|
var networkStats = currentData.GetNetworkUsage(_networkIndex);
|
||||||
|
|
||||||
ContentData["networkUsage"] = FloatToPercentString(networkStats.Usage);
|
ContentData["networkUsage"] = FloatToPercentString(networkStats.Usage);
|
||||||
ContentData["netSent"] = BytesToBitsPerSecString(networkStats.Sent);
|
ContentData["netSent"] = SpeedToString(networkStats.Sent);
|
||||||
ContentData["netReceived"] = BytesToBitsPerSecString(networkStats.Received);
|
ContentData["netReceived"] = SpeedToString(networkStats.Received);
|
||||||
ContentData["networkName"] = netName;
|
ContentData["networkName"] = netName;
|
||||||
ContentData["netGraphUrl"] = currentData.CreateNetImageUrl(_networkIndex);
|
ContentData["netGraphUrl"] = currentData.CreateNetImageUrl(_networkIndex);
|
||||||
ContentData["chartHeight"] = ChartHelper.ChartHeight + "px";
|
ContentData["chartHeight"] = ChartHelper.ChartHeight + "px";
|
||||||
@@ -627,7 +630,17 @@ internal sealed partial class SystemNetworkUsageWidgetPage : WidgetPage, IDispos
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private string BytesToBitsPerSecString(float value)
|
private string SpeedToString(float bytesPerSec)
|
||||||
|
{
|
||||||
|
return _settingsManager.NetworkSpeedUnit switch
|
||||||
|
{
|
||||||
|
NetworkSpeedUnit.BytesPerSecond => FormatAsBytesPerSecString(bytesPerSec),
|
||||||
|
NetworkSpeedUnit.BinaryBytesPerSecond => FormatAsBinaryBytesPerSecString(bytesPerSec),
|
||||||
|
_ => FormatAsBitsPerSecString(bytesPerSec),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string FormatAsBitsPerSecString(float value)
|
||||||
{
|
{
|
||||||
// Bytes to bits
|
// Bytes to bits
|
||||||
value *= 8;
|
value *= 8;
|
||||||
@@ -666,6 +679,78 @@ internal sealed partial class SystemNetworkUsageWidgetPage : WidgetPage, IDispos
|
|||||||
return string.Format(CultureInfo.InvariantCulture, "{0:0} Gbps", value);
|
return string.Format(CultureInfo.InvariantCulture, "{0:0} Gbps", value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static string FormatAsBytesPerSecString(float value)
|
||||||
|
{
|
||||||
|
// Bytes to KB
|
||||||
|
value /= 1024;
|
||||||
|
if (value < 1024)
|
||||||
|
{
|
||||||
|
if (value < 100)
|
||||||
|
{
|
||||||
|
return string.Format(CultureInfo.InvariantCulture, "{0:0.0} KB/s", value);
|
||||||
|
}
|
||||||
|
|
||||||
|
return string.Format(CultureInfo.InvariantCulture, "{0:0} KB/s", value);
|
||||||
|
}
|
||||||
|
|
||||||
|
// KB to MB
|
||||||
|
value /= 1024;
|
||||||
|
if (value < 1024)
|
||||||
|
{
|
||||||
|
if (value < 100)
|
||||||
|
{
|
||||||
|
return string.Format(CultureInfo.InvariantCulture, "{0:0.0} MB/s", value);
|
||||||
|
}
|
||||||
|
|
||||||
|
return string.Format(CultureInfo.InvariantCulture, "{0:0} MB/s", value);
|
||||||
|
}
|
||||||
|
|
||||||
|
// MB to GB
|
||||||
|
value /= 1024;
|
||||||
|
if (value < 100)
|
||||||
|
{
|
||||||
|
return string.Format(CultureInfo.InvariantCulture, "{0:0.0} GB/s", value);
|
||||||
|
}
|
||||||
|
|
||||||
|
return string.Format(CultureInfo.InvariantCulture, "{0:0} GB/s", value);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string FormatAsBinaryBytesPerSecString(float value)
|
||||||
|
{
|
||||||
|
// Bytes to KiB
|
||||||
|
value /= 1024;
|
||||||
|
if (value < 1024)
|
||||||
|
{
|
||||||
|
if (value < 100)
|
||||||
|
{
|
||||||
|
return string.Format(CultureInfo.InvariantCulture, "{0:0.0} KiB/s", value);
|
||||||
|
}
|
||||||
|
|
||||||
|
return string.Format(CultureInfo.InvariantCulture, "{0:0} KiB/s", value);
|
||||||
|
}
|
||||||
|
|
||||||
|
// KiB to MiB
|
||||||
|
value /= 1024;
|
||||||
|
if (value < 1024)
|
||||||
|
{
|
||||||
|
if (value < 100)
|
||||||
|
{
|
||||||
|
return string.Format(CultureInfo.InvariantCulture, "{0:0.0} MiB/s", value);
|
||||||
|
}
|
||||||
|
|
||||||
|
return string.Format(CultureInfo.InvariantCulture, "{0:0} MiB/s", value);
|
||||||
|
}
|
||||||
|
|
||||||
|
// MiB to GiB
|
||||||
|
value /= 1024;
|
||||||
|
if (value < 100)
|
||||||
|
{
|
||||||
|
return string.Format(CultureInfo.InvariantCulture, "{0:0.0} GiB/s", value);
|
||||||
|
}
|
||||||
|
|
||||||
|
return string.Format(CultureInfo.InvariantCulture, "{0:0} GiB/s", value);
|
||||||
|
}
|
||||||
|
|
||||||
internal override void PushActivate()
|
internal override void PushActivate()
|
||||||
{
|
{
|
||||||
base.PushActivate();
|
base.PushActivate();
|
||||||
|
|||||||
@@ -0,0 +1,50 @@
|
|||||||
|
// 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.IO;
|
||||||
|
using CoreWidgetProvider.Helpers;
|
||||||
|
using Microsoft.CommandPalette.Extensions.Toolkit;
|
||||||
|
|
||||||
|
namespace Microsoft.CmdPal.Ext.PerformanceMonitor;
|
||||||
|
|
||||||
|
internal sealed class SettingsManager : JsonSettingsManager
|
||||||
|
{
|
||||||
|
private const string Namespace = "performanceMonitor";
|
||||||
|
|
||||||
|
private static string Namespaced(string propertyName) => $"{Namespace}.{propertyName}";
|
||||||
|
|
||||||
|
private readonly ChoiceSetSetting _networkSpeedUnit = new(
|
||||||
|
Namespaced(nameof(NetworkSpeedUnit)),
|
||||||
|
Resources.GetResource("Network_Speed_Unit_Setting_Title"),
|
||||||
|
Resources.GetResource("Network_Speed_Unit_Setting_Description"),
|
||||||
|
[
|
||||||
|
new ChoiceSetSetting.Choice(Resources.GetResource("Network_Speed_Unit_BitsPerSec"), NetworkSpeedUnit.BitsPerSecond.ToString("G")),
|
||||||
|
new ChoiceSetSetting.Choice(Resources.GetResource("Network_Speed_Unit_BytesPerSec"), NetworkSpeedUnit.BytesPerSecond.ToString("G")),
|
||||||
|
new ChoiceSetSetting.Choice(Resources.GetResource("Network_Speed_Unit_BinaryBytesPerSec"), NetworkSpeedUnit.BinaryBytesPerSecond.ToString("G")),
|
||||||
|
]);
|
||||||
|
|
||||||
|
public NetworkSpeedUnit NetworkSpeedUnit =>
|
||||||
|
Enum.TryParse<NetworkSpeedUnit>(_networkSpeedUnit.Value, out var unit)
|
||||||
|
? unit
|
||||||
|
: NetworkSpeedUnit.BitsPerSecond;
|
||||||
|
|
||||||
|
private static string SettingsJsonPath()
|
||||||
|
{
|
||||||
|
var directory = Utilities.BaseSettingsPath("Microsoft.CmdPal");
|
||||||
|
Directory.CreateDirectory(directory);
|
||||||
|
return Path.Combine(directory, "settings.json");
|
||||||
|
}
|
||||||
|
|
||||||
|
public SettingsManager()
|
||||||
|
{
|
||||||
|
FilePath = SettingsJsonPath();
|
||||||
|
|
||||||
|
Settings.Add(_networkSpeedUnit);
|
||||||
|
|
||||||
|
LoadSettings();
|
||||||
|
|
||||||
|
Settings.SettingsChanged += (_, _) => SaveSettings();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -276,4 +276,19 @@
|
|||||||
<data name="Network_Receive_Subtitle" xml:space="preserve">
|
<data name="Network_Receive_Subtitle" xml:space="preserve">
|
||||||
<value>Receive ↓</value>
|
<value>Receive ↓</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="Network_Speed_Unit_Setting_Title" xml:space="preserve">
|
||||||
|
<value>Network speed unit</value>
|
||||||
|
</data>
|
||||||
|
<data name="Network_Speed_Unit_Setting_Description" xml:space="preserve">
|
||||||
|
<value>Choose the unit used to display network transmission speed</value>
|
||||||
|
</data>
|
||||||
|
<data name="Network_Speed_Unit_BitsPerSec" xml:space="preserve">
|
||||||
|
<value>Bits per second (Kbps, Mbps, Gbps)</value>
|
||||||
|
</data>
|
||||||
|
<data name="Network_Speed_Unit_BytesPerSec" xml:space="preserve">
|
||||||
|
<value>Bytes per second (KB/s, MB/s, GB/s)</value>
|
||||||
|
</data>
|
||||||
|
<data name="Network_Speed_Unit_BinaryBytesPerSec" xml:space="preserve">
|
||||||
|
<value>Binary bytes per second (KiB/s, MiB/s, GiB/s)</value>
|
||||||
|
</data>
|
||||||
</root>
|
</root>
|
||||||
|
|||||||
Reference in New Issue
Block a user