mirror of
https://github.com/microsoft/PowerToys.git
synced 2026-02-23 19:49:43 +01:00
<!-- Enter a brief description/summary of your PR here. What does it fix/what does it change/how was it tested (even manually, if necessary)? --> ## Summary of the Pull Request - Refactored the runner logic for handling individual module enable/disable updates. Instead of receiving the entire settings.json via IPC, it now processes only single-module state updates, which avoids race conditions and fixes a bug where modules could end up being skipped. - Fixed an issue where the sort order option could be deselected — it is now enforced as a mutually exclusive choice. - Fixed a potential race condition when updating the AppList control’s sorting. <!-- Please review the items on the PR checklist before submitting--> ## PR Checklist - [x] Closes: #44697 <!-- - [ ] Closes: #yyy (add separate lines for additional resolved issues) --> - [x] **Communication:** I've discussed this with core contributors already. If the work hasn't been agreed, this work might be rejected - [x] **Tests:** Added/updated and all pass - [x] **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 <!-- Provide a more detailed description of the PR, other things fixed, or any additional comments/features here --> ## Detailed Description of the Pull Request / Additional comments <!-- Describe how you validated the behavior. Add automated tests wherever possible, but list manual validation steps taken as well --> ## Validation Steps Performed --------- Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
798 lines
39 KiB
C#
798 lines
39 KiB
C#
// Copyright (c) Microsoft Corporation
|
|
// The Microsoft Corporation licenses this file to you under the MIT license.
|
|
// See the LICENSE file in the project root for more information.
|
|
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Collections.ObjectModel;
|
|
using System.IO.Abstractions;
|
|
using System.Linq;
|
|
using System.Threading.Tasks;
|
|
using System.Windows.Threading;
|
|
using CommunityToolkit.WinUI.Controls;
|
|
using global::PowerToys.GPOWrapper;
|
|
using ManagedCommon;
|
|
using Microsoft.PowerToys.Settings.UI.Controls;
|
|
using Microsoft.PowerToys.Settings.UI.Helpers;
|
|
using Microsoft.PowerToys.Settings.UI.Library;
|
|
using Microsoft.PowerToys.Settings.UI.Library.Helpers;
|
|
using Microsoft.PowerToys.Settings.UI.Library.HotkeyConflicts;
|
|
using Microsoft.PowerToys.Settings.UI.Library.Interfaces;
|
|
using Microsoft.PowerToys.Settings.UI.Library.Utilities;
|
|
using Microsoft.PowerToys.Settings.UI.Services;
|
|
using Microsoft.PowerToys.Settings.UI.Views;
|
|
using Microsoft.UI.Xaml;
|
|
using Microsoft.UI.Xaml.Controls;
|
|
using Settings.UI.Library;
|
|
|
|
namespace Microsoft.PowerToys.Settings.UI.ViewModels
|
|
{
|
|
public partial class DashboardViewModel : PageViewModelBase
|
|
{
|
|
private readonly object _sortLock = new object();
|
|
|
|
protected override string ModuleName => "Dashboard";
|
|
|
|
private Dispatcher dispatcher;
|
|
|
|
public Func<string, int> SendConfigMSG { get; }
|
|
|
|
public ObservableCollection<DashboardListItem> AllModules { get; set; } = new ObservableCollection<DashboardListItem>();
|
|
|
|
public ObservableCollection<DashboardListItem> ShortcutModules { get; set; } = new ObservableCollection<DashboardListItem>();
|
|
|
|
public ObservableCollection<DashboardListItem> ActionModules { get; set; } = new ObservableCollection<DashboardListItem>();
|
|
|
|
public ObservableCollection<QuickAccessItem> QuickAccessItems => _quickAccessViewModel.Items;
|
|
|
|
private readonly QuickAccessViewModel _quickAccessViewModel;
|
|
|
|
// Master list of module items that is sorted and projected into AllModules.
|
|
private List<DashboardListItem> _moduleItems = new List<DashboardListItem>();
|
|
|
|
// Flag to prevent circular updates when a UI toggle triggers settings changes.
|
|
private bool _isUpdatingFromUI;
|
|
|
|
// Flag to prevent toggle operations during sorting to avoid race conditions.
|
|
private bool _isSorting;
|
|
|
|
private AllHotkeyConflictsData _allHotkeyConflictsData = new AllHotkeyConflictsData();
|
|
|
|
public AllHotkeyConflictsData AllHotkeyConflictsData
|
|
{
|
|
get => _allHotkeyConflictsData;
|
|
set
|
|
{
|
|
if (Set(ref _allHotkeyConflictsData, value))
|
|
{
|
|
OnPropertyChanged();
|
|
}
|
|
}
|
|
}
|
|
|
|
public string PowerToysVersion
|
|
{
|
|
get
|
|
{
|
|
return Helper.GetProductVersion();
|
|
}
|
|
}
|
|
|
|
private DashboardSortOrder _dashboardSortOrder = DashboardSortOrder.Alphabetical;
|
|
|
|
public DashboardSortOrder DashboardSortOrder
|
|
{
|
|
get => generalSettingsConfig.DashboardSortOrder;
|
|
set
|
|
{
|
|
if (_dashboardSortOrder != value)
|
|
{
|
|
_dashboardSortOrder = value;
|
|
generalSettingsConfig.DashboardSortOrder = value;
|
|
OutGoingGeneralSettings outgoing = new OutGoingGeneralSettings(generalSettingsConfig);
|
|
|
|
SendConfigMSG(outgoing.ToString());
|
|
|
|
// Notify UI before sorting so menu updates its checked state
|
|
OnPropertyChanged(nameof(DashboardSortOrder));
|
|
|
|
SortModuleList();
|
|
}
|
|
}
|
|
}
|
|
|
|
private ISettingsRepository<GeneralSettings> _settingsRepository;
|
|
private GeneralSettings generalSettingsConfig;
|
|
private Windows.ApplicationModel.Resources.ResourceLoader resourceLoader = Helpers.ResourceLoaderInstance.ResourceLoader;
|
|
|
|
public DashboardViewModel(ISettingsRepository<GeneralSettings> settingsRepository, Func<string, int> ipcMSGCallBackFunc)
|
|
{
|
|
dispatcher = Dispatcher.CurrentDispatcher;
|
|
_settingsRepository = settingsRepository;
|
|
generalSettingsConfig = settingsRepository.SettingsConfig;
|
|
|
|
_settingsRepository.SettingsChanged += OnSettingsChanged;
|
|
|
|
// Initialize dashboard sort order from settings
|
|
_dashboardSortOrder = generalSettingsConfig.DashboardSortOrder;
|
|
|
|
// set the callback functions value to handle outgoing IPC message.
|
|
SendConfigMSG = ipcMSGCallBackFunc;
|
|
|
|
_quickAccessViewModel = new QuickAccessViewModel(
|
|
_settingsRepository,
|
|
new Microsoft.PowerToys.Settings.UI.Controls.QuickAccessLauncher(App.IsElevated),
|
|
moduleType => Helpers.ModuleGpoHelper.GetModuleGpoConfiguration(moduleType) == global::PowerToys.GPOWrapper.GpoRuleConfigured.Disabled,
|
|
resourceLoader);
|
|
|
|
BuildModuleList();
|
|
SortModuleList();
|
|
RefreshShortcutModules();
|
|
}
|
|
|
|
private void OnSettingsChanged(GeneralSettings newSettings)
|
|
{
|
|
dispatcher.BeginInvoke(() =>
|
|
{
|
|
generalSettingsConfig = newSettings;
|
|
|
|
// Update local field and notify UI if sort order changed
|
|
if (_dashboardSortOrder != generalSettingsConfig.DashboardSortOrder)
|
|
{
|
|
_dashboardSortOrder = generalSettingsConfig.DashboardSortOrder;
|
|
OnPropertyChanged(nameof(DashboardSortOrder));
|
|
}
|
|
|
|
ModuleEnabledChangedOnSettingsPage();
|
|
});
|
|
}
|
|
|
|
protected override void OnConflictsUpdated(object sender, AllHotkeyConflictsEventArgs e)
|
|
{
|
|
dispatcher.BeginInvoke(() =>
|
|
{
|
|
var allConflictData = e.Conflicts;
|
|
foreach (var inAppConflict in allConflictData.InAppConflicts)
|
|
{
|
|
var hotkey = inAppConflict.Hotkey;
|
|
var hotkeySetting = new HotkeySettings(hotkey.Win, hotkey.Ctrl, hotkey.Alt, hotkey.Shift, hotkey.Key);
|
|
inAppConflict.ConflictIgnored = HotkeyConflictIgnoreHelper.IsIgnoringConflicts(hotkeySetting);
|
|
}
|
|
|
|
foreach (var systemConflict in allConflictData.SystemConflicts)
|
|
{
|
|
var hotkey = systemConflict.Hotkey;
|
|
var hotkeySetting = new HotkeySettings(hotkey.Win, hotkey.Ctrl, hotkey.Alt, hotkey.Shift, hotkey.Key);
|
|
systemConflict.ConflictIgnored = HotkeyConflictIgnoreHelper.IsIgnoringConflicts(hotkeySetting);
|
|
}
|
|
|
|
AllHotkeyConflictsData = e.Conflicts ?? new AllHotkeyConflictsData();
|
|
});
|
|
}
|
|
|
|
private void RequestConflictData()
|
|
{
|
|
// Request current conflicts data
|
|
GlobalHotkeyConflictManager.Instance?.RequestAllConflicts();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Builds the master list of module items. Called once during initialization.
|
|
/// Each module item contains its configuration, enabled state, and GPO lock status.
|
|
/// </summary>
|
|
private void BuildModuleList()
|
|
{
|
|
_moduleItems.Clear();
|
|
|
|
foreach (ModuleType moduleType in Enum.GetValues<ModuleType>())
|
|
{
|
|
if (moduleType == ModuleType.GeneralSettings)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
GpoRuleConfigured gpo = ModuleGpoHelper.GetModuleGpoConfiguration(moduleType);
|
|
var newItem = new DashboardListItem()
|
|
{
|
|
Tag = moduleType,
|
|
Label = resourceLoader.GetString(ModuleHelper.GetModuleLabelResourceName(moduleType)),
|
|
IsEnabled = gpo == GpoRuleConfigured.Enabled || (gpo != GpoRuleConfigured.Disabled && ModuleHelper.GetIsModuleEnabled(generalSettingsConfig, moduleType)),
|
|
IsLocked = gpo == GpoRuleConfigured.Enabled || gpo == GpoRuleConfigured.Disabled,
|
|
Icon = ModuleHelper.GetModuleTypeFluentIconName(moduleType),
|
|
IsNew = moduleType == ModuleType.CursorWrap,
|
|
DashboardModuleItems = GetModuleItems(moduleType),
|
|
ClickCommand = new RelayCommand<object>(DashboardListItemClick),
|
|
};
|
|
newItem.EnabledChangedCallback = EnabledChangedOnUI;
|
|
_moduleItems.Add(newItem);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Sorts the module list according to the current sort order and updates the AllModules collection.
|
|
/// On first call, populates AllModules. On subsequent calls, uses Move() to reorder items in-place
|
|
/// to avoid destroying and recreating UI elements.
|
|
/// Temporarily disables interaction on all items during sorting to prevent race conditions.
|
|
/// </summary>
|
|
private void SortModuleList()
|
|
{
|
|
if (_isSorting)
|
|
{
|
|
return;
|
|
}
|
|
|
|
lock (_sortLock)
|
|
{
|
|
_isSorting = true;
|
|
try
|
|
{
|
|
var sortedItems = (DashboardSortOrder switch
|
|
{
|
|
DashboardSortOrder.ByStatus => _moduleItems.OrderByDescending(x => x.IsEnabled).ThenBy(x => x.Label),
|
|
_ => _moduleItems.OrderBy(x => x.Label), // Default alphabetical
|
|
}).ToList();
|
|
|
|
// If AllModules is empty (first load), just populate it.
|
|
if (AllModules.Count == 0)
|
|
{
|
|
foreach (var item in sortedItems)
|
|
{
|
|
AllModules.Add(item);
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
// Otherwise, update the collection in place using Move to avoid UI glitches.
|
|
for (int i = 0; i < sortedItems.Count; i++)
|
|
{
|
|
var currentItem = sortedItems[i];
|
|
var currentIndex = AllModules.IndexOf(currentItem);
|
|
|
|
if (currentIndex != -1 && currentIndex != i)
|
|
{
|
|
AllModules.Move(currentIndex, i);
|
|
}
|
|
}
|
|
}
|
|
finally
|
|
{
|
|
// Use dispatcher to reset flag after UI updates complete
|
|
dispatcher.BeginInvoke(System.Windows.Threading.DispatcherPriority.Background, () =>
|
|
{
|
|
_isSorting = false;
|
|
});
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Refreshes module enabled/locked states by re-reading GPO configuration. Only
|
|
/// updates properties that have actually changed to minimize UI notifications
|
|
/// then re-sorts the list according to the current sort order.
|
|
/// </summary>
|
|
private void RefreshModuleList()
|
|
{
|
|
foreach (var item in _moduleItems)
|
|
{
|
|
GpoRuleConfigured gpo = ModuleGpoHelper.GetModuleGpoConfiguration(item.Tag);
|
|
|
|
// GPO can force-enable (Enabled) or force-disable (Disabled) a module.
|
|
// If Enabled: module is on and the user cannot disable it.
|
|
// If Disabled: module is off and the user cannot enable it.
|
|
// Otherwise, the setting is unlocked and the user can enable/disable it.
|
|
bool newEnabledState = gpo == GpoRuleConfigured.Enabled || (gpo != GpoRuleConfigured.Disabled && ModuleHelper.GetIsModuleEnabled(generalSettingsConfig, item.Tag));
|
|
|
|
// Lock the toggle when GPO is controlling the module.
|
|
bool newLockedState = gpo == GpoRuleConfigured.Enabled || gpo == GpoRuleConfigured.Disabled;
|
|
|
|
// Only update if there's an actual change to minimize UI notifications.
|
|
if (item.IsEnabled != newEnabledState)
|
|
{
|
|
item.UpdateStatus(newEnabledState);
|
|
}
|
|
|
|
if (item.IsLocked != newLockedState)
|
|
{
|
|
item.IsLocked = newLockedState;
|
|
}
|
|
}
|
|
|
|
SortModuleList();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Callback invoked when a user toggles a module's enabled state in the UI.
|
|
/// Sets the _isUpdatingFromUI flag to prevent circular updates, then updates
|
|
/// settings, re-sorts if needed, and refreshes dependent collections.
|
|
/// </summary>
|
|
private void EnabledChangedOnUI(ModuleListItem item)
|
|
{
|
|
var dashboardListItem = (DashboardListItem)item;
|
|
var isEnabled = dashboardListItem.IsEnabled;
|
|
|
|
// Ignore toggle operations during sorting to prevent race conditions.
|
|
// Revert the toggle state since UI already changed due to TwoWay binding.
|
|
if (_isSorting)
|
|
{
|
|
dashboardListItem.UpdateStatus(!isEnabled);
|
|
return;
|
|
}
|
|
|
|
_isUpdatingFromUI = true;
|
|
try
|
|
{
|
|
// Send optimized IPC message with only the module status update
|
|
// Format: {"module_status": {"ModuleName": true/false}}
|
|
string moduleKey = ModuleHelper.GetModuleKey(dashboardListItem.Tag);
|
|
string moduleStatusJson = $"{{\"module_status\": {{\"{moduleKey}\": {isEnabled.ToString().ToLowerInvariant()}}}}}";
|
|
SendConfigMSG(moduleStatusJson);
|
|
|
|
// Update local settings config to keep UI in sync
|
|
ModuleHelper.SetIsModuleEnabled(generalSettingsConfig, dashboardListItem.Tag, isEnabled);
|
|
|
|
if (dashboardListItem.Tag == ModuleType.NewPlus && isEnabled == true)
|
|
{
|
|
var settingsUtils = SettingsUtils.Default;
|
|
var settings = NewPlusViewModel.LoadSettings(settingsUtils);
|
|
NewPlusViewModel.CopyTemplateExamples(settings.Properties.TemplateLocation.Value);
|
|
}
|
|
|
|
// Re-sort only required if sorting by enabled status.
|
|
if (DashboardSortOrder == DashboardSortOrder.ByStatus)
|
|
{
|
|
SortModuleList();
|
|
}
|
|
|
|
// Always refresh shortcuts/actions to reflect enabled state changes.
|
|
RefreshShortcutModules();
|
|
|
|
// Request updated conflicts after module state change.
|
|
RequestConflictData();
|
|
}
|
|
finally
|
|
{
|
|
_isUpdatingFromUI = false;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Callback invoked when module enabled state changes from other parts of the
|
|
/// settings UI. Ignores the notification if it was triggered by a UI toggle
|
|
/// we're already handling, to prevent circular updates.
|
|
/// </summary>
|
|
public void ModuleEnabledChangedOnSettingsPage()
|
|
{
|
|
// Ignore if this was triggered by a UI change that we're already handling.
|
|
if (_isUpdatingFromUI)
|
|
{
|
|
return;
|
|
}
|
|
|
|
try
|
|
{
|
|
RefreshModuleList();
|
|
RefreshShortcutModules();
|
|
|
|
OnPropertyChanged(nameof(ShortcutModules));
|
|
|
|
// Request updated conflicts after module state change.
|
|
RequestConflictData();
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Logger.LogError($"Updating active/disabled modules list failed: {ex.Message}");
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Rebuilds ShortcutModules and ActionModules collections by filtering AllModules
|
|
/// to only include enabled modules and their respective shortcut/action items.
|
|
/// </summary>
|
|
private void RefreshShortcutModules()
|
|
{
|
|
ShortcutModules.Clear();
|
|
ActionModules.Clear();
|
|
|
|
foreach (var x in AllModules.Where(x => x.IsEnabled))
|
|
{
|
|
var filteredItems = x.DashboardModuleItems
|
|
.Where(m => m is DashboardModuleShortcutItem || m is DashboardModuleActivationItem)
|
|
.ToList();
|
|
|
|
if (filteredItems.Count != 0)
|
|
{
|
|
var newItem = new DashboardListItem
|
|
{
|
|
Icon = x.Icon,
|
|
IsLocked = x.IsLocked,
|
|
Label = x.Label,
|
|
Tag = x.Tag,
|
|
IsEnabled = x.IsEnabled,
|
|
DashboardModuleItems = new ObservableCollection<DashboardModuleItem>(filteredItems),
|
|
};
|
|
|
|
ShortcutModules.Add(newItem);
|
|
newItem.EnabledChangedCallback = x.EnabledChangedCallback;
|
|
}
|
|
}
|
|
|
|
foreach (var x in AllModules.Where(x => x.IsEnabled))
|
|
{
|
|
var filteredItems = x.DashboardModuleItems
|
|
.Where(m => m is DashboardModuleButtonItem)
|
|
.ToList();
|
|
|
|
if (filteredItems.Count != 0)
|
|
{
|
|
var newItem = new DashboardListItem
|
|
{
|
|
Icon = x.Icon,
|
|
IsLocked = x.IsLocked,
|
|
Label = x.Label,
|
|
Tag = x.Tag,
|
|
IsEnabled = x.IsEnabled,
|
|
DashboardModuleItems = new ObservableCollection<DashboardModuleItem>(filteredItems),
|
|
};
|
|
|
|
ActionModules.Add(newItem);
|
|
newItem.EnabledChangedCallback = x.EnabledChangedCallback;
|
|
}
|
|
}
|
|
}
|
|
|
|
private ObservableCollection<DashboardModuleItem> GetModuleItems(ModuleType moduleType)
|
|
{
|
|
return moduleType switch
|
|
{
|
|
ModuleType.AdvancedPaste => GetModuleItemsAdvancedPaste(),
|
|
ModuleType.AlwaysOnTop => GetModuleItemsAlwaysOnTop(),
|
|
ModuleType.CmdPal => GetModuleItemsCmdPal(),
|
|
ModuleType.ColorPicker => GetModuleItemsColorPicker(),
|
|
ModuleType.CropAndLock => GetModuleItemsCropAndLock(),
|
|
ModuleType.EnvironmentVariables => GetModuleItemsEnvironmentVariables(),
|
|
ModuleType.FancyZones => GetModuleItemsFancyZones(),
|
|
ModuleType.FindMyMouse => GetModuleItemsFindMyMouse(),
|
|
ModuleType.Hosts => GetModuleItemsHosts(),
|
|
ModuleType.LightSwitch => GetModuleItemsLightSwitch(),
|
|
ModuleType.MouseHighlighter => GetModuleItemsMouseHighlighter(),
|
|
ModuleType.MouseJump => GetModuleItemsMouseJump(),
|
|
ModuleType.MousePointerCrosshairs => GetModuleItemsMousePointerCrosshairs(),
|
|
ModuleType.Peek => GetModuleItemsPeek(),
|
|
ModuleType.PowerLauncher => GetModuleItemsPowerLauncher(),
|
|
ModuleType.PowerAccent => GetModuleItemsPowerAccent(),
|
|
ModuleType.Workspaces => GetModuleItemsWorkspaces(),
|
|
ModuleType.RegistryPreview => GetModuleItemsRegistryPreview(),
|
|
ModuleType.MeasureTool => GetModuleItemsMeasureTool(),
|
|
ModuleType.ShortcutGuide => GetModuleItemsShortcutGuide(),
|
|
ModuleType.PowerOCR => GetModuleItemsPowerOCR(),
|
|
_ => new ObservableCollection<DashboardModuleItem>(), // never called, all values listed above
|
|
};
|
|
}
|
|
|
|
private ObservableCollection<DashboardModuleItem> GetModuleItemsAlwaysOnTop()
|
|
{
|
|
ISettingsRepository<AlwaysOnTopSettings> moduleSettingsRepository = SettingsRepository<AlwaysOnTopSettings>.GetInstance(SettingsUtils.Default);
|
|
var list = new List<DashboardModuleItem>
|
|
{
|
|
new DashboardModuleShortcutItem() { Label = resourceLoader.GetString("AlwaysOnTop_ShortDescription"), Shortcut = moduleSettingsRepository.SettingsConfig.Properties.Hotkey.Value.GetKeysList() },
|
|
};
|
|
return new ObservableCollection<DashboardModuleItem>(list);
|
|
}
|
|
|
|
private ObservableCollection<DashboardModuleItem> GetModuleItemsCmdPal()
|
|
{
|
|
var hotkey = new CmdPalProperties().Hotkey;
|
|
|
|
var list = new List<DashboardModuleItem>
|
|
{
|
|
new DashboardModuleShortcutItem() { Label = resourceLoader.GetString("CmdPal_ActivationDescription"), Shortcut = hotkey.GetKeysList() },
|
|
};
|
|
return new ObservableCollection<DashboardModuleItem>(list);
|
|
}
|
|
|
|
private ObservableCollection<DashboardModuleItem> GetModuleItemsColorPicker()
|
|
{
|
|
ISettingsRepository<ColorPickerSettings> moduleSettingsRepository = SettingsRepository<ColorPickerSettings>.GetInstance(SettingsUtils.Default);
|
|
var settings = moduleSettingsRepository.SettingsConfig;
|
|
var hotkey = settings.Properties.ActivationShortcut;
|
|
var list = new List<DashboardModuleItem>
|
|
{
|
|
new DashboardModuleShortcutItem() { Label = resourceLoader.GetString("ColorPicker_ShortDescription"), Shortcut = hotkey.GetKeysList() },
|
|
};
|
|
return new ObservableCollection<DashboardModuleItem>(list);
|
|
}
|
|
|
|
private ObservableCollection<DashboardModuleItem> GetModuleItemsLightSwitch()
|
|
{
|
|
ISettingsRepository<LightSwitchSettings> moduleSettingsRepository = SettingsRepository<LightSwitchSettings>.GetInstance(SettingsUtils.Default);
|
|
var settings = moduleSettingsRepository.SettingsConfig;
|
|
var list = new List<DashboardModuleItem>
|
|
{
|
|
new DashboardModuleShortcutItem() { Label = resourceLoader.GetString("LightSwitch_ForceDarkMode"), Shortcut = settings.Properties.ToggleThemeHotkey.Value.GetKeysList() },
|
|
};
|
|
return new ObservableCollection<DashboardModuleItem>(list);
|
|
}
|
|
|
|
private ObservableCollection<DashboardModuleItem> GetModuleItemsCropAndLock()
|
|
{
|
|
ISettingsRepository<CropAndLockSettings> moduleSettingsRepository = SettingsRepository<CropAndLockSettings>.GetInstance(SettingsUtils.Default);
|
|
var settings = moduleSettingsRepository.SettingsConfig;
|
|
var list = new List<DashboardModuleItem>
|
|
{
|
|
new DashboardModuleShortcutItem() { Label = resourceLoader.GetString("CropAndLock_Thumbnail"), Shortcut = settings.Properties.ThumbnailHotkey.Value.GetKeysList() },
|
|
new DashboardModuleShortcutItem() { Label = resourceLoader.GetString("CropAndLock_Reparent"), Shortcut = settings.Properties.ReparentHotkey.Value.GetKeysList() },
|
|
new DashboardModuleShortcutItem() { Label = resourceLoader.GetString("CropAndLock_Screenshot"), Shortcut = settings.Properties.ScreenshotHotkey.Value.GetKeysList() },
|
|
};
|
|
return new ObservableCollection<DashboardModuleItem>(list);
|
|
}
|
|
|
|
private ObservableCollection<DashboardModuleItem> GetModuleItemsEnvironmentVariables()
|
|
{
|
|
var list = new List<DashboardModuleItem>
|
|
{
|
|
new DashboardModuleButtonItem() { ButtonTitle = resourceLoader.GetString("EnvironmentVariables_LaunchButtonControl/Header"), IsButtonDescriptionVisible = true, ButtonDescription = resourceLoader.GetString("EnvironmentVariables_LaunchButtonControl/Description"), ButtonGlyph = "ms-appx:///Assets/Settings/Icons/EnvironmentVariables.png", ButtonClickHandler = EnvironmentVariablesLaunchClicked },
|
|
};
|
|
return new ObservableCollection<DashboardModuleItem>(list);
|
|
}
|
|
|
|
private ObservableCollection<DashboardModuleItem> GetModuleItemsFancyZones()
|
|
{
|
|
ISettingsRepository<FancyZonesSettings> moduleSettingsRepository = SettingsRepository<FancyZonesSettings>.GetInstance(SettingsUtils.Default);
|
|
var settings = moduleSettingsRepository.SettingsConfig;
|
|
string activationMode = $"{resourceLoader.GetString(settings.Properties.FancyzonesShiftDrag.Value ? "FancyZones_ActivationShiftDrag" : "FancyZones_ActivationNoShiftDrag")}.";
|
|
|
|
var list = new List<DashboardModuleItem>
|
|
{
|
|
new DashboardModuleActivationItem() { Label = resourceLoader.GetString("Activate_Zones"), Activation = activationMode },
|
|
new DashboardModuleShortcutItem() { Label = resourceLoader.GetString("FancyZones_OpenEditor"), Shortcut = settings.Properties.FancyzonesEditorHotkey.Value.GetKeysList() },
|
|
new DashboardModuleButtonItem() { ButtonTitle = resourceLoader.GetString("FancyZones_LaunchEditorButtonControl/Header"), IsButtonDescriptionVisible = true, ButtonDescription = resourceLoader.GetString("FancyZones_LaunchEditorButtonControl/Description"), ButtonGlyph = "ms-appx:///Assets/Settings/Icons/FancyZones.png", ButtonClickHandler = FancyZoneLaunchClicked },
|
|
};
|
|
return new ObservableCollection<DashboardModuleItem>(list);
|
|
}
|
|
|
|
private ObservableCollection<DashboardModuleItem> GetModuleItemsFindMyMouse()
|
|
{
|
|
ISettingsRepository<FindMyMouseSettings> moduleSettingsRepository = SettingsRepository<FindMyMouseSettings>.GetInstance(SettingsUtils.Default);
|
|
string shortDescription = resourceLoader.GetString("FindMyMouse_ShortDescription");
|
|
var settings = moduleSettingsRepository.SettingsConfig;
|
|
var activationMethod = settings.Properties.ActivationMethod.Value;
|
|
var list = new List<DashboardModuleItem>();
|
|
if (activationMethod == 3)
|
|
{
|
|
var hotkey = settings.Properties.ActivationShortcut;
|
|
list.Add(new DashboardModuleShortcutItem() { Label = shortDescription, Shortcut = hotkey.GetKeysList() });
|
|
}
|
|
else
|
|
{
|
|
string activation = string.Empty;
|
|
switch (activationMethod)
|
|
{
|
|
case 2: activation = resourceLoader.GetString("MouseUtils_FindMyMouse_ActivationShakeMouse/Content"); break;
|
|
case 1: activation = resourceLoader.GetString("MouseUtils_FindMyMouse_ActivationDoubleRightControlPress/Content"); break;
|
|
case 0:
|
|
default: activation = resourceLoader.GetString("MouseUtils_FindMyMouse_ActivationDoubleControlPress/Content"); break;
|
|
}
|
|
|
|
list.Add(new DashboardModuleActivationItem() { Label = resourceLoader.GetString("Dashboard_Activation"), Activation = activation });
|
|
}
|
|
|
|
return new ObservableCollection<DashboardModuleItem>(list);
|
|
}
|
|
|
|
private ObservableCollection<DashboardModuleItem> GetModuleItemsHosts()
|
|
{
|
|
var list = new List<DashboardModuleItem>
|
|
{
|
|
new DashboardModuleButtonItem() { ButtonTitle = resourceLoader.GetString("Hosts_LaunchButtonControl/Header"), IsButtonDescriptionVisible = true, ButtonDescription = resourceLoader.GetString("Hosts_LaunchButtonControl/Description"), ButtonGlyph = "ms-appx:///Assets/Settings/Icons/Hosts.png", ButtonClickHandler = HostLaunchClicked },
|
|
};
|
|
return new ObservableCollection<DashboardModuleItem>(list);
|
|
}
|
|
|
|
private ObservableCollection<DashboardModuleItem> GetModuleItemsMouseHighlighter()
|
|
{
|
|
ISettingsRepository<MouseHighlighterSettings> moduleSettingsRepository = SettingsRepository<MouseHighlighterSettings>.GetInstance(SettingsUtils.Default);
|
|
var list = new List<DashboardModuleItem>
|
|
{
|
|
new DashboardModuleShortcutItem() { Label = resourceLoader.GetString("MouseHighlighter_ShortDescription"), Shortcut = moduleSettingsRepository.SettingsConfig.Properties.ActivationShortcut.GetKeysList() },
|
|
};
|
|
return new ObservableCollection<DashboardModuleItem>(list);
|
|
}
|
|
|
|
private ObservableCollection<DashboardModuleItem> GetModuleItemsMouseJump()
|
|
{
|
|
ISettingsRepository<MouseJumpSettings> moduleSettingsRepository = SettingsRepository<MouseJumpSettings>.GetInstance(SettingsUtils.Default);
|
|
var list = new List<DashboardModuleItem>
|
|
{
|
|
new DashboardModuleShortcutItem() { Label = resourceLoader.GetString("MouseJump_ShortDescription"), Shortcut = moduleSettingsRepository.SettingsConfig.Properties.ActivationShortcut.GetKeysList() },
|
|
};
|
|
return new ObservableCollection<DashboardModuleItem>(list);
|
|
}
|
|
|
|
private ObservableCollection<DashboardModuleItem> GetModuleItemsMousePointerCrosshairs()
|
|
{
|
|
ISettingsRepository<MousePointerCrosshairsSettings> moduleSettingsRepository = SettingsRepository<MousePointerCrosshairsSettings>.GetInstance(SettingsUtils.Default);
|
|
var list = new List<DashboardModuleItem>
|
|
{
|
|
new DashboardModuleShortcutItem() { Label = resourceLoader.GetString("MouseCrosshairs_ShortDescription"), Shortcut = moduleSettingsRepository.SettingsConfig.Properties.ActivationShortcut.GetKeysList() },
|
|
};
|
|
return new ObservableCollection<DashboardModuleItem>(list);
|
|
}
|
|
|
|
private ObservableCollection<DashboardModuleItem> GetModuleItemsAdvancedPaste()
|
|
{
|
|
ISettingsRepository<AdvancedPasteSettings> moduleSettingsRepository = SettingsRepository<AdvancedPasteSettings>.GetInstance(SettingsUtils.Default);
|
|
var list = new List<DashboardModuleItem>
|
|
{
|
|
new DashboardModuleShortcutItem() { Label = resourceLoader.GetString("AdvancedPasteUI_Shortcut/Header"), Shortcut = moduleSettingsRepository.SettingsConfig.Properties.AdvancedPasteUIShortcut.GetKeysList() },
|
|
new DashboardModuleShortcutItem() { Label = resourceLoader.GetString("PasteAsPlainText_Shortcut/Header"), Shortcut = moduleSettingsRepository.SettingsConfig.Properties.PasteAsPlainTextShortcut.GetKeysList() },
|
|
};
|
|
|
|
if (moduleSettingsRepository.SettingsConfig.Properties.PasteAsMarkdownShortcut.GetKeysList().Count > 0)
|
|
{
|
|
list.Add(new DashboardModuleShortcutItem() { Label = resourceLoader.GetString("PasteAsMarkdown_Shortcut/Header"), Shortcut = moduleSettingsRepository.SettingsConfig.Properties.PasteAsMarkdownShortcut.GetKeysList() });
|
|
}
|
|
|
|
if (moduleSettingsRepository.SettingsConfig.Properties.PasteAsJsonShortcut.GetKeysList().Count > 0)
|
|
{
|
|
list.Add(new DashboardModuleShortcutItem() { Label = resourceLoader.GetString("PasteAsJson_Shortcut/Header"), Shortcut = moduleSettingsRepository.SettingsConfig.Properties.PasteAsJsonShortcut.GetKeysList() });
|
|
}
|
|
|
|
return new ObservableCollection<DashboardModuleItem>(list);
|
|
}
|
|
|
|
private ObservableCollection<DashboardModuleItem> GetModuleItemsPeek()
|
|
{
|
|
ISettingsRepository<PeekSettings> moduleSettingsRepository = SettingsRepository<PeekSettings>.GetInstance(SettingsUtils.Default);
|
|
var list = new List<DashboardModuleItem>
|
|
{
|
|
new DashboardModuleShortcutItem() { Label = resourceLoader.GetString("Peek_ShortDescription"), Shortcut = moduleSettingsRepository.SettingsConfig.Properties.ActivationShortcut.GetKeysList() },
|
|
};
|
|
return new ObservableCollection<DashboardModuleItem>(list);
|
|
}
|
|
|
|
private ObservableCollection<DashboardModuleItem> GetModuleItemsPowerLauncher()
|
|
{
|
|
ISettingsRepository<PowerLauncherSettings> moduleSettingsRepository = SettingsRepository<PowerLauncherSettings>.GetInstance(SettingsUtils.Default);
|
|
var list = new List<DashboardModuleItem>
|
|
{
|
|
new DashboardModuleShortcutItem() { Label = resourceLoader.GetString("Run_ShortDescription"), Shortcut = moduleSettingsRepository.SettingsConfig.Properties.OpenPowerLauncher.GetKeysList() },
|
|
};
|
|
return new ObservableCollection<DashboardModuleItem>(list);
|
|
}
|
|
|
|
private ObservableCollection<DashboardModuleItem> GetModuleItemsPowerAccent()
|
|
{
|
|
var settingsUtils = SettingsUtils.Default;
|
|
PowerAccentSettings moduleSettings = settingsUtils.GetSettingsOrDefault<PowerAccentSettings>(PowerAccentSettings.ModuleName);
|
|
var activationMethod = moduleSettings.Properties.ActivationKey;
|
|
string activation = string.Empty;
|
|
switch (activationMethod)
|
|
{
|
|
case Library.Enumerations.PowerAccentActivationKey.LeftRightArrow: activation = resourceLoader.GetString("QuickAccent_Activation_Key_Arrows/Content"); break;
|
|
case Library.Enumerations.PowerAccentActivationKey.Space: activation = resourceLoader.GetString("QuickAccent_Activation_Key_Space/Content"); break;
|
|
case Library.Enumerations.PowerAccentActivationKey.Both: activation = resourceLoader.GetString("QuickAccent_Activation_Key_Either/Content"); break;
|
|
}
|
|
|
|
var list = new List<DashboardModuleItem>
|
|
{
|
|
new DashboardModuleActivationItem() { Label = resourceLoader.GetString("Dashboard_Activation"), Activation = activation },
|
|
};
|
|
return new ObservableCollection<DashboardModuleItem>(list);
|
|
}
|
|
|
|
private ObservableCollection<DashboardModuleItem> GetModuleItemsWorkspaces()
|
|
{
|
|
ISettingsRepository<WorkspacesSettings> moduleSettingsRepository = SettingsRepository<WorkspacesSettings>.GetInstance(SettingsUtils.Default);
|
|
var settings = moduleSettingsRepository.SettingsConfig;
|
|
|
|
var list = new List<DashboardModuleItem>
|
|
{
|
|
new DashboardModuleShortcutItem() { Label = resourceLoader.GetString("Workspaces_ShortDescription"), Shortcut = settings.Properties.Hotkey.Value.GetKeysList() },
|
|
new DashboardModuleButtonItem() { ButtonTitle = resourceLoader.GetString("Workspaces_LaunchEditorButtonControl/Header"), IsButtonDescriptionVisible = true, ButtonDescription = resourceLoader.GetString("FancyZones_LaunchEditorButtonControl/Description"), ButtonGlyph = "ms-appx:///Assets/Settings/Icons/Workspaces.png", ButtonClickHandler = WorkspacesLaunchClicked },
|
|
};
|
|
return new ObservableCollection<DashboardModuleItem>(list);
|
|
}
|
|
|
|
private ObservableCollection<DashboardModuleItem> GetModuleItemsRegistryPreview()
|
|
{
|
|
var list = new List<DashboardModuleItem>
|
|
{
|
|
new DashboardModuleButtonItem() { ButtonTitle = resourceLoader.GetString("RegistryPreview_LaunchButtonControl/Header"), ButtonGlyph = "ms-appx:///Assets/Settings/Icons/RegistryPreview.png", ButtonClickHandler = RegistryPreviewLaunchClicked },
|
|
};
|
|
return new ObservableCollection<DashboardModuleItem>(list);
|
|
}
|
|
|
|
private ObservableCollection<DashboardModuleItem> GetModuleItemsMeasureTool()
|
|
{
|
|
ISettingsRepository<MeasureToolSettings> moduleSettingsRepository = SettingsRepository<MeasureToolSettings>.GetInstance(SettingsUtils.Default);
|
|
var list = new List<DashboardModuleItem>
|
|
{
|
|
new DashboardModuleShortcutItem() { Label = resourceLoader.GetString("ScreenRuler_ShortDescription"), Shortcut = moduleSettingsRepository.SettingsConfig.Properties.ActivationShortcut.GetKeysList() },
|
|
};
|
|
return new ObservableCollection<DashboardModuleItem>(list);
|
|
}
|
|
|
|
private ObservableCollection<DashboardModuleItem> GetModuleItemsShortcutGuide()
|
|
{
|
|
ISettingsRepository<ShortcutGuideSettings> moduleSettingsRepository = SettingsRepository<ShortcutGuideSettings>.GetInstance(SettingsUtils.Default);
|
|
|
|
var shortcut = moduleSettingsRepository.SettingsConfig.Properties.UseLegacyPressWinKeyBehavior.Value
|
|
? new List<object> { 92 } // Right Windows key code
|
|
: moduleSettingsRepository.SettingsConfig.Properties.OpenShortcutGuide.GetKeysList();
|
|
|
|
var list = new List<DashboardModuleItem>
|
|
{
|
|
new DashboardModuleShortcutItem() { Label = resourceLoader.GetString("ShortcutGuide_ShortDescription"), Shortcut = shortcut },
|
|
};
|
|
return new ObservableCollection<DashboardModuleItem>(list);
|
|
}
|
|
|
|
private ObservableCollection<DashboardModuleItem> GetModuleItemsPowerOCR()
|
|
{
|
|
ISettingsRepository<PowerOcrSettings> moduleSettingsRepository = SettingsRepository<PowerOcrSettings>.GetInstance(SettingsUtils.Default);
|
|
var list = new List<DashboardModuleItem>
|
|
{
|
|
new DashboardModuleShortcutItem() { Label = resourceLoader.GetString("PowerOcr_ShortDescription"), Shortcut = moduleSettingsRepository.SettingsConfig.Properties.ActivationShortcut.GetKeysList() },
|
|
};
|
|
return new ObservableCollection<DashboardModuleItem>(list);
|
|
}
|
|
|
|
internal void SWVersionButtonClicked()
|
|
{
|
|
NavigationService.Navigate(typeof(GeneralPage));
|
|
}
|
|
|
|
private void EnvironmentVariablesLaunchClicked(object sender, RoutedEventArgs e)
|
|
{
|
|
var settingsUtils = SettingsUtils.Default;
|
|
var environmentVariablesViewModel = new EnvironmentVariablesViewModel(settingsUtils, SettingsRepository<GeneralSettings>.GetInstance(settingsUtils), SettingsRepository<EnvironmentVariablesSettings>.GetInstance(settingsUtils), ShellPage.SendDefaultIPCMessage, App.IsElevated);
|
|
environmentVariablesViewModel.Launch();
|
|
}
|
|
|
|
private void HostLaunchClicked(object sender, RoutedEventArgs e)
|
|
{
|
|
var settingsUtils = SettingsUtils.Default;
|
|
var hostsViewModel = new HostsViewModel(settingsUtils, SettingsRepository<GeneralSettings>.GetInstance(settingsUtils), SettingsRepository<HostsSettings>.GetInstance(settingsUtils), ShellPage.SendDefaultIPCMessage, App.IsElevated);
|
|
hostsViewModel.Launch();
|
|
}
|
|
|
|
private void FancyZoneLaunchClicked(object sender, RoutedEventArgs e)
|
|
{
|
|
// send message to launch the zones editor;
|
|
SendConfigMSG("{\"action\":{\"FancyZones\":{\"action_name\":\"ToggledFZEditor\", \"value\":\"\"}}}");
|
|
}
|
|
|
|
private void WorkspacesLaunchClicked(object sender, RoutedEventArgs e)
|
|
{
|
|
// send message to launch the Workspaces editor;
|
|
SendConfigMSG("{\"action\":{\"Workspaces\":{\"action_name\":\"LaunchEditor\", \"value\":\"\"}}}");
|
|
}
|
|
|
|
private void RegistryPreviewLaunchClicked(object sender, RoutedEventArgs e)
|
|
{
|
|
var actionName = "Launch";
|
|
SendConfigMSG("{\"action\":{\"RegistryPreview\":{\"action_name\":\"" + actionName + "\", \"value\":\"\"}}}");
|
|
}
|
|
|
|
internal void DashboardListItemClick(object sender)
|
|
{
|
|
if (sender is ModuleType moduleType)
|
|
{
|
|
NavigationService.Navigate(ModuleGpoHelper.GetModulePageType(moduleType));
|
|
}
|
|
}
|
|
|
|
public override void Dispose()
|
|
{
|
|
base.Dispose();
|
|
if (_settingsRepository != null)
|
|
{
|
|
_settingsRepository.SettingsChanged -= OnSettingsChanged;
|
|
}
|
|
|
|
GC.SuppressFinalize(this);
|
|
}
|
|
}
|
|
}
|