DashboardViewModel.cs
1 // Copyright (c) Microsoft Corporation 2 // The Microsoft Corporation licenses this file to you under the MIT license. 3 // See the LICENSE file in the project root for more information. 4 5 using System; 6 using System.Collections.Generic; 7 using System.Collections.ObjectModel; 8 using System.IO.Abstractions; 9 using System.Linq; 10 using System.Threading.Tasks; 11 using CommunityToolkit.WinUI.Controls; 12 using global::PowerToys.GPOWrapper; 13 using ManagedCommon; 14 using Microsoft.PowerToys.Settings.UI.Controls; 15 using Microsoft.PowerToys.Settings.UI.Helpers; 16 using Microsoft.PowerToys.Settings.UI.Library; 17 using Microsoft.PowerToys.Settings.UI.Library.Helpers; 18 using Microsoft.PowerToys.Settings.UI.Library.HotkeyConflicts; 19 using Microsoft.PowerToys.Settings.UI.Library.Interfaces; 20 using Microsoft.PowerToys.Settings.UI.Library.Utilities; 21 using Microsoft.PowerToys.Settings.UI.Services; 22 using Microsoft.PowerToys.Settings.UI.Views; 23 using Microsoft.UI.Dispatching; 24 using Microsoft.UI.Xaml; 25 using Microsoft.UI.Xaml.Controls; 26 using Settings.UI.Library; 27 28 namespace Microsoft.PowerToys.Settings.UI.ViewModels 29 { 30 public partial class DashboardViewModel : PageViewModelBase 31 { 32 private readonly object _sortLock = new object(); 33 34 protected override string ModuleName => "Dashboard"; 35 36 private DispatcherQueue dispatcher; 37 38 public Func<string, int> SendConfigMSG { get; } 39 40 public ObservableCollection<DashboardListItem> AllModules { get; set; } = new ObservableCollection<DashboardListItem>(); 41 42 public ObservableCollection<DashboardListItem> ShortcutModules { get; set; } = new ObservableCollection<DashboardListItem>(); 43 44 public ObservableCollection<DashboardListItem> ActionModules { get; set; } = new ObservableCollection<DashboardListItem>(); 45 46 public ObservableCollection<QuickAccessItem> QuickAccessItems => _quickAccessViewModel.Items; 47 48 private readonly QuickAccessViewModel _quickAccessViewModel; 49 50 // Master list of module items that is sorted and projected into AllModules. 51 private List<DashboardListItem> _moduleItems = new List<DashboardListItem>(); 52 53 // Flag to prevent circular updates when a UI toggle triggers settings changes. 54 private bool _isUpdatingFromUI; 55 56 // Flag to prevent toggle operations during sorting to avoid race conditions. 57 private bool _isSorting; 58 59 private AllHotkeyConflictsData _allHotkeyConflictsData = new AllHotkeyConflictsData(); 60 61 public AllHotkeyConflictsData AllHotkeyConflictsData 62 { 63 get => _allHotkeyConflictsData; 64 set 65 { 66 if (Set(ref _allHotkeyConflictsData, value)) 67 { 68 OnPropertyChanged(); 69 } 70 } 71 } 72 73 public string PowerToysVersion 74 { 75 get 76 { 77 return Helper.GetProductVersion(); 78 } 79 } 80 81 private DashboardSortOrder _dashboardSortOrder = DashboardSortOrder.Alphabetical; 82 83 public DashboardSortOrder DashboardSortOrder 84 { 85 get => generalSettingsConfig.DashboardSortOrder; 86 set 87 { 88 if (_dashboardSortOrder != value) 89 { 90 _dashboardSortOrder = value; 91 generalSettingsConfig.DashboardSortOrder = value; 92 OutGoingGeneralSettings outgoing = new OutGoingGeneralSettings(generalSettingsConfig); 93 94 SendConfigMSG(outgoing.ToString()); 95 96 // Notify UI before sorting so menu updates its checked state 97 OnPropertyChanged(nameof(DashboardSortOrder)); 98 99 SortModuleList(); 100 } 101 } 102 } 103 104 private ISettingsRepository<GeneralSettings> _settingsRepository; 105 private GeneralSettings generalSettingsConfig; 106 private Windows.ApplicationModel.Resources.ResourceLoader resourceLoader = Helpers.ResourceLoaderInstance.ResourceLoader; 107 108 public DashboardViewModel(ISettingsRepository<GeneralSettings> settingsRepository, Func<string, int> ipcMSGCallBackFunc) 109 { 110 dispatcher = DispatcherQueue.GetForCurrentThread(); 111 _settingsRepository = settingsRepository; 112 generalSettingsConfig = settingsRepository.SettingsConfig; 113 114 _settingsRepository.SettingsChanged += OnSettingsChanged; 115 116 // Initialize dashboard sort order from settings 117 _dashboardSortOrder = generalSettingsConfig.DashboardSortOrder; 118 119 // set the callback functions value to handle outgoing IPC message. 120 SendConfigMSG = ipcMSGCallBackFunc; 121 122 _quickAccessViewModel = new QuickAccessViewModel( 123 _settingsRepository, 124 new Microsoft.PowerToys.Settings.UI.Controls.QuickAccessLauncher(App.IsElevated), 125 moduleType => Helpers.ModuleGpoHelper.GetModuleGpoConfiguration(moduleType) == global::PowerToys.GPOWrapper.GpoRuleConfigured.Disabled, 126 resourceLoader); 127 128 BuildModuleList(); 129 SortModuleList(); 130 RefreshShortcutModules(); 131 } 132 133 private void OnSettingsChanged(GeneralSettings newSettings) 134 { 135 dispatcher.TryEnqueue(() => 136 { 137 generalSettingsConfig = newSettings; 138 139 // Update local field and notify UI if sort order changed 140 if (_dashboardSortOrder != generalSettingsConfig.DashboardSortOrder) 141 { 142 _dashboardSortOrder = generalSettingsConfig.DashboardSortOrder; 143 OnPropertyChanged(nameof(DashboardSortOrder)); 144 } 145 146 ModuleEnabledChangedOnSettingsPage(); 147 }); 148 } 149 150 protected override void OnConflictsUpdated(object sender, AllHotkeyConflictsEventArgs e) 151 { 152 dispatcher.TryEnqueue(() => 153 { 154 var allConflictData = e.Conflicts; 155 foreach (var inAppConflict in allConflictData.InAppConflicts) 156 { 157 var hotkey = inAppConflict.Hotkey; 158 var hotkeySetting = new HotkeySettings(hotkey.Win, hotkey.Ctrl, hotkey.Alt, hotkey.Shift, hotkey.Key); 159 inAppConflict.ConflictIgnored = HotkeyConflictIgnoreHelper.IsIgnoringConflicts(hotkeySetting); 160 } 161 162 foreach (var systemConflict in allConflictData.SystemConflicts) 163 { 164 var hotkey = systemConflict.Hotkey; 165 var hotkeySetting = new HotkeySettings(hotkey.Win, hotkey.Ctrl, hotkey.Alt, hotkey.Shift, hotkey.Key); 166 systemConflict.ConflictIgnored = HotkeyConflictIgnoreHelper.IsIgnoringConflicts(hotkeySetting); 167 } 168 169 AllHotkeyConflictsData = e.Conflicts ?? new AllHotkeyConflictsData(); 170 }); 171 } 172 173 private void RequestConflictData() 174 { 175 // Request current conflicts data 176 GlobalHotkeyConflictManager.Instance?.RequestAllConflicts(); 177 } 178 179 /// <summary> 180 /// Builds the master list of module items. Called once during initialization. 181 /// Each module item contains its configuration, enabled state, and GPO lock status. 182 /// </summary> 183 private void BuildModuleList() 184 { 185 _moduleItems.Clear(); 186 187 foreach (ModuleType moduleType in Enum.GetValues<ModuleType>()) 188 { 189 if (moduleType == ModuleType.GeneralSettings) 190 { 191 continue; 192 } 193 194 GpoRuleConfigured gpo = ModuleGpoHelper.GetModuleGpoConfiguration(moduleType); 195 var newItem = new DashboardListItem() 196 { 197 Tag = moduleType, 198 Label = resourceLoader.GetString(ModuleHelper.GetModuleLabelResourceName(moduleType)), 199 IsEnabled = gpo == GpoRuleConfigured.Enabled || (gpo != GpoRuleConfigured.Disabled && ModuleHelper.GetIsModuleEnabled(generalSettingsConfig, moduleType)), 200 IsLocked = gpo == GpoRuleConfigured.Enabled || gpo == GpoRuleConfigured.Disabled, 201 Icon = ModuleHelper.GetModuleTypeFluentIconName(moduleType), 202 IsNew = moduleType == ModuleType.CursorWrap || moduleType == ModuleType.PowerDisplay, 203 DashboardModuleItems = GetModuleItems(moduleType), 204 ClickCommand = new RelayCommand<object>(DashboardListItemClick), 205 }; 206 newItem.EnabledChangedCallback = EnabledChangedOnUI; 207 _moduleItems.Add(newItem); 208 } 209 } 210 211 /// <summary> 212 /// Sorts the module list according to the current sort order and updates the AllModules collection. 213 /// On first call, populates AllModules. On subsequent calls, uses Move() to reorder items in-place 214 /// to avoid destroying and recreating UI elements. 215 /// Temporarily disables interaction on all items during sorting to prevent race conditions. 216 /// </summary> 217 private void SortModuleList() 218 { 219 if (_isSorting) 220 { 221 return; 222 } 223 224 lock (_sortLock) 225 { 226 _isSorting = true; 227 try 228 { 229 var sortedItems = (DashboardSortOrder switch 230 { 231 DashboardSortOrder.ByStatus => _moduleItems.OrderByDescending(x => x.IsEnabled).ThenBy(x => x.Label), 232 _ => _moduleItems.OrderBy(x => x.Label), // Default alphabetical 233 }).ToList(); 234 235 // If AllModules is empty (first load), just populate it. 236 if (AllModules.Count == 0) 237 { 238 foreach (var item in sortedItems) 239 { 240 AllModules.Add(item); 241 } 242 243 return; 244 } 245 246 // Otherwise, update the collection in place using Move to avoid UI glitches. 247 for (int i = 0; i < sortedItems.Count; i++) 248 { 249 var currentItem = sortedItems[i]; 250 var currentIndex = AllModules.IndexOf(currentItem); 251 252 if (currentIndex != -1 && currentIndex != i) 253 { 254 AllModules.Move(currentIndex, i); 255 } 256 } 257 } 258 finally 259 { 260 // Use dispatcher to reset flag after UI updates complete 261 dispatcher.TryEnqueue(DispatcherQueuePriority.Low, () => 262 { 263 _isSorting = false; 264 }); 265 } 266 } 267 } 268 269 /// <summary> 270 /// Refreshes module enabled/locked states by re-reading GPO configuration. Only 271 /// updates properties that have actually changed to minimize UI notifications 272 /// then re-sorts the list according to the current sort order. 273 /// </summary> 274 private void RefreshModuleList() 275 { 276 foreach (var item in _moduleItems) 277 { 278 GpoRuleConfigured gpo = ModuleGpoHelper.GetModuleGpoConfiguration(item.Tag); 279 280 // GPO can force-enable (Enabled) or force-disable (Disabled) a module. 281 // If Enabled: module is on and the user cannot disable it. 282 // If Disabled: module is off and the user cannot enable it. 283 // Otherwise, the setting is unlocked and the user can enable/disable it. 284 bool newEnabledState = gpo == GpoRuleConfigured.Enabled || (gpo != GpoRuleConfigured.Disabled && ModuleHelper.GetIsModuleEnabled(generalSettingsConfig, item.Tag)); 285 286 // Lock the toggle when GPO is controlling the module. 287 bool newLockedState = gpo == GpoRuleConfigured.Enabled || gpo == GpoRuleConfigured.Disabled; 288 289 // Only update if there's an actual change to minimize UI notifications. 290 if (item.IsEnabled != newEnabledState) 291 { 292 item.UpdateStatus(newEnabledState); 293 } 294 295 if (item.IsLocked != newLockedState) 296 { 297 item.IsLocked = newLockedState; 298 } 299 } 300 301 SortModuleList(); 302 } 303 304 /// <summary> 305 /// Callback invoked when a user toggles a module's enabled state in the UI. 306 /// Sets the _isUpdatingFromUI flag to prevent circular updates, then updates 307 /// settings, re-sorts if needed, and refreshes dependent collections. 308 /// </summary> 309 private void EnabledChangedOnUI(ModuleListItem item) 310 { 311 var dashboardListItem = (DashboardListItem)item; 312 var isEnabled = dashboardListItem.IsEnabled; 313 314 // Ignore toggle operations during sorting to prevent race conditions. 315 // Revert the toggle state since UI already changed due to TwoWay binding. 316 if (_isSorting) 317 { 318 dashboardListItem.UpdateStatus(!isEnabled); 319 return; 320 } 321 322 _isUpdatingFromUI = true; 323 try 324 { 325 // Send optimized IPC message with only the module status update 326 // Format: {"module_status": {"ModuleName": true/false}} 327 string moduleKey = ModuleHelper.GetModuleKey(dashboardListItem.Tag); 328 string moduleStatusJson = $"{{\"module_status\": {{\"{moduleKey}\": {isEnabled.ToString().ToLowerInvariant()}}}}}"; 329 SendConfigMSG(moduleStatusJson); 330 331 // Update local settings config to keep UI in sync 332 ModuleHelper.SetIsModuleEnabled(generalSettingsConfig, dashboardListItem.Tag, isEnabled); 333 334 if (dashboardListItem.Tag == ModuleType.NewPlus && isEnabled == true) 335 { 336 var settingsUtils = SettingsUtils.Default; 337 var settings = NewPlusViewModel.LoadSettings(settingsUtils); 338 NewPlusViewModel.CopyTemplateExamples(settings.Properties.TemplateLocation.Value); 339 } 340 341 // Re-sort only required if sorting by enabled status. 342 if (DashboardSortOrder == DashboardSortOrder.ByStatus) 343 { 344 SortModuleList(); 345 } 346 347 // Always refresh shortcuts/actions to reflect enabled state changes. 348 RefreshShortcutModules(); 349 350 // Request updated conflicts after module state change. 351 RequestConflictData(); 352 } 353 finally 354 { 355 _isUpdatingFromUI = false; 356 } 357 } 358 359 /// <summary> 360 /// Callback invoked when module enabled state changes from other parts of the 361 /// settings UI. Ignores the notification if it was triggered by a UI toggle 362 /// we're already handling, to prevent circular updates. 363 /// </summary> 364 public void ModuleEnabledChangedOnSettingsPage() 365 { 366 // Ignore if this was triggered by a UI change that we're already handling. 367 if (_isUpdatingFromUI) 368 { 369 return; 370 } 371 372 try 373 { 374 RefreshModuleList(); 375 RefreshShortcutModules(); 376 377 OnPropertyChanged(nameof(ShortcutModules)); 378 379 // Request updated conflicts after module state change. 380 RequestConflictData(); 381 } 382 catch (Exception ex) 383 { 384 Logger.LogError($"Updating active/disabled modules list failed: {ex.Message}"); 385 } 386 } 387 388 /// <summary> 389 /// Rebuilds ShortcutModules and ActionModules collections by filtering AllModules 390 /// to only include enabled modules and their respective shortcut/action items. 391 /// </summary> 392 private void RefreshShortcutModules() 393 { 394 ShortcutModules.Clear(); 395 ActionModules.Clear(); 396 397 foreach (var x in AllModules.Where(x => x.IsEnabled)) 398 { 399 var filteredItems = x.DashboardModuleItems 400 .Where(m => m is DashboardModuleShortcutItem || m is DashboardModuleActivationItem) 401 .ToList(); 402 403 if (filteredItems.Count != 0) 404 { 405 var newItem = new DashboardListItem 406 { 407 Icon = x.Icon, 408 IsLocked = x.IsLocked, 409 Label = x.Label, 410 Tag = x.Tag, 411 IsEnabled = x.IsEnabled, 412 DashboardModuleItems = new ObservableCollection<DashboardModuleItem>(filteredItems), 413 }; 414 415 ShortcutModules.Add(newItem); 416 newItem.EnabledChangedCallback = x.EnabledChangedCallback; 417 } 418 } 419 420 foreach (var x in AllModules.Where(x => x.IsEnabled)) 421 { 422 var filteredItems = x.DashboardModuleItems 423 .Where(m => m is DashboardModuleButtonItem) 424 .ToList(); 425 426 if (filteredItems.Count != 0) 427 { 428 var newItem = new DashboardListItem 429 { 430 Icon = x.Icon, 431 IsLocked = x.IsLocked, 432 Label = x.Label, 433 Tag = x.Tag, 434 IsEnabled = x.IsEnabled, 435 DashboardModuleItems = new ObservableCollection<DashboardModuleItem>(filteredItems), 436 }; 437 438 ActionModules.Add(newItem); 439 newItem.EnabledChangedCallback = x.EnabledChangedCallback; 440 } 441 } 442 } 443 444 private ObservableCollection<DashboardModuleItem> GetModuleItems(ModuleType moduleType) 445 { 446 return moduleType switch 447 { 448 ModuleType.AdvancedPaste => GetModuleItemsAdvancedPaste(), 449 ModuleType.AlwaysOnTop => GetModuleItemsAlwaysOnTop(), 450 ModuleType.CmdPal => GetModuleItemsCmdPal(), 451 ModuleType.ColorPicker => GetModuleItemsColorPicker(), 452 ModuleType.CropAndLock => GetModuleItemsCropAndLock(), 453 ModuleType.EnvironmentVariables => GetModuleItemsEnvironmentVariables(), 454 ModuleType.FancyZones => GetModuleItemsFancyZones(), 455 ModuleType.FindMyMouse => GetModuleItemsFindMyMouse(), 456 ModuleType.Hosts => GetModuleItemsHosts(), 457 ModuleType.LightSwitch => GetModuleItemsLightSwitch(), 458 ModuleType.MouseHighlighter => GetModuleItemsMouseHighlighter(), 459 ModuleType.MouseJump => GetModuleItemsMouseJump(), 460 ModuleType.MousePointerCrosshairs => GetModuleItemsMousePointerCrosshairs(), 461 ModuleType.Peek => GetModuleItemsPeek(), 462 ModuleType.PowerDisplay => GetModuleItemsPowerDisplay(), 463 ModuleType.PowerLauncher => GetModuleItemsPowerLauncher(), 464 ModuleType.PowerAccent => GetModuleItemsPowerAccent(), 465 ModuleType.Workspaces => GetModuleItemsWorkspaces(), 466 ModuleType.RegistryPreview => GetModuleItemsRegistryPreview(), 467 ModuleType.MeasureTool => GetModuleItemsMeasureTool(), 468 ModuleType.ShortcutGuide => GetModuleItemsShortcutGuide(), 469 ModuleType.PowerOCR => GetModuleItemsPowerOCR(), 470 _ => new ObservableCollection<DashboardModuleItem>(), // never called, all values listed above 471 }; 472 } 473 474 private ObservableCollection<DashboardModuleItem> GetModuleItemsAlwaysOnTop() 475 { 476 ISettingsRepository<AlwaysOnTopSettings> moduleSettingsRepository = SettingsRepository<AlwaysOnTopSettings>.GetInstance(SettingsUtils.Default); 477 var list = new List<DashboardModuleItem> 478 { 479 new DashboardModuleShortcutItem() { Label = resourceLoader.GetString("AlwaysOnTop_ShortDescription"), Shortcut = moduleSettingsRepository.SettingsConfig.Properties.Hotkey.Value.GetKeysList() }, 480 }; 481 return new ObservableCollection<DashboardModuleItem>(list); 482 } 483 484 private ObservableCollection<DashboardModuleItem> GetModuleItemsCmdPal() 485 { 486 var hotkey = new CmdPalProperties().Hotkey; 487 488 var list = new List<DashboardModuleItem> 489 { 490 new DashboardModuleShortcutItem() { Label = resourceLoader.GetString("CmdPal_ActivationDescription"), Shortcut = hotkey.GetKeysList() }, 491 }; 492 return new ObservableCollection<DashboardModuleItem>(list); 493 } 494 495 private ObservableCollection<DashboardModuleItem> GetModuleItemsColorPicker() 496 { 497 ISettingsRepository<ColorPickerSettings> moduleSettingsRepository = SettingsRepository<ColorPickerSettings>.GetInstance(SettingsUtils.Default); 498 var settings = moduleSettingsRepository.SettingsConfig; 499 var hotkey = settings.Properties.ActivationShortcut; 500 var list = new List<DashboardModuleItem> 501 { 502 new DashboardModuleShortcutItem() { Label = resourceLoader.GetString("ColorPicker_ShortDescription"), Shortcut = hotkey.GetKeysList() }, 503 }; 504 return new ObservableCollection<DashboardModuleItem>(list); 505 } 506 507 private ObservableCollection<DashboardModuleItem> GetModuleItemsLightSwitch() 508 { 509 ISettingsRepository<LightSwitchSettings> moduleSettingsRepository = SettingsRepository<LightSwitchSettings>.GetInstance(SettingsUtils.Default); 510 var settings = moduleSettingsRepository.SettingsConfig; 511 var list = new List<DashboardModuleItem> 512 { 513 new DashboardModuleShortcutItem() { Label = resourceLoader.GetString("LightSwitch_ForceDarkMode"), Shortcut = settings.Properties.ToggleThemeHotkey.Value.GetKeysList() }, 514 }; 515 return new ObservableCollection<DashboardModuleItem>(list); 516 } 517 518 private ObservableCollection<DashboardModuleItem> GetModuleItemsCropAndLock() 519 { 520 ISettingsRepository<CropAndLockSettings> moduleSettingsRepository = SettingsRepository<CropAndLockSettings>.GetInstance(SettingsUtils.Default); 521 var settings = moduleSettingsRepository.SettingsConfig; 522 var list = new List<DashboardModuleItem> 523 { 524 new DashboardModuleShortcutItem() { Label = resourceLoader.GetString("CropAndLock_Thumbnail"), Shortcut = settings.Properties.ThumbnailHotkey.Value.GetKeysList() }, 525 new DashboardModuleShortcutItem() { Label = resourceLoader.GetString("CropAndLock_Reparent"), Shortcut = settings.Properties.ReparentHotkey.Value.GetKeysList() }, 526 new DashboardModuleShortcutItem() { Label = resourceLoader.GetString("CropAndLock_Screenshot"), Shortcut = settings.Properties.ScreenshotHotkey.Value.GetKeysList() }, 527 }; 528 return new ObservableCollection<DashboardModuleItem>(list); 529 } 530 531 private ObservableCollection<DashboardModuleItem> GetModuleItemsEnvironmentVariables() 532 { 533 var list = new List<DashboardModuleItem> 534 { 535 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 }, 536 }; 537 return new ObservableCollection<DashboardModuleItem>(list); 538 } 539 540 private ObservableCollection<DashboardModuleItem> GetModuleItemsFancyZones() 541 { 542 ISettingsRepository<FancyZonesSettings> moduleSettingsRepository = SettingsRepository<FancyZonesSettings>.GetInstance(SettingsUtils.Default); 543 var settings = moduleSettingsRepository.SettingsConfig; 544 string activationMode = $"{resourceLoader.GetString(settings.Properties.FancyzonesShiftDrag.Value ? "FancyZones_ActivationShiftDrag" : "FancyZones_ActivationNoShiftDrag")}."; 545 546 var list = new List<DashboardModuleItem> 547 { 548 new DashboardModuleActivationItem() { Label = resourceLoader.GetString("Activate_Zones"), Activation = activationMode }, 549 new DashboardModuleShortcutItem() { Label = resourceLoader.GetString("FancyZones_OpenEditor"), Shortcut = settings.Properties.FancyzonesEditorHotkey.Value.GetKeysList() }, 550 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 }, 551 }; 552 return new ObservableCollection<DashboardModuleItem>(list); 553 } 554 555 private ObservableCollection<DashboardModuleItem> GetModuleItemsFindMyMouse() 556 { 557 ISettingsRepository<FindMyMouseSettings> moduleSettingsRepository = SettingsRepository<FindMyMouseSettings>.GetInstance(SettingsUtils.Default); 558 string shortDescription = resourceLoader.GetString("FindMyMouse_ShortDescription"); 559 var settings = moduleSettingsRepository.SettingsConfig; 560 var activationMethod = settings.Properties.ActivationMethod.Value; 561 var list = new List<DashboardModuleItem>(); 562 if (activationMethod == 3) 563 { 564 var hotkey = settings.Properties.ActivationShortcut; 565 list.Add(new DashboardModuleShortcutItem() { Label = shortDescription, Shortcut = hotkey.GetKeysList() }); 566 } 567 else 568 { 569 string activation = string.Empty; 570 switch (activationMethod) 571 { 572 case 2: activation = resourceLoader.GetString("MouseUtils_FindMyMouse_ActivationShakeMouse/Content"); break; 573 case 1: activation = resourceLoader.GetString("MouseUtils_FindMyMouse_ActivationDoubleRightControlPress/Content"); break; 574 case 0: 575 default: activation = resourceLoader.GetString("MouseUtils_FindMyMouse_ActivationDoubleControlPress/Content"); break; 576 } 577 578 list.Add(new DashboardModuleActivationItem() { Label = resourceLoader.GetString("Dashboard_Activation"), Activation = activation }); 579 } 580 581 return new ObservableCollection<DashboardModuleItem>(list); 582 } 583 584 private ObservableCollection<DashboardModuleItem> GetModuleItemsHosts() 585 { 586 var list = new List<DashboardModuleItem> 587 { 588 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 }, 589 }; 590 return new ObservableCollection<DashboardModuleItem>(list); 591 } 592 593 private ObservableCollection<DashboardModuleItem> GetModuleItemsMouseHighlighter() 594 { 595 ISettingsRepository<MouseHighlighterSettings> moduleSettingsRepository = SettingsRepository<MouseHighlighterSettings>.GetInstance(SettingsUtils.Default); 596 var list = new List<DashboardModuleItem> 597 { 598 new DashboardModuleShortcutItem() { Label = resourceLoader.GetString("MouseHighlighter_ShortDescription"), Shortcut = moduleSettingsRepository.SettingsConfig.Properties.ActivationShortcut.GetKeysList() }, 599 }; 600 return new ObservableCollection<DashboardModuleItem>(list); 601 } 602 603 private ObservableCollection<DashboardModuleItem> GetModuleItemsMouseJump() 604 { 605 ISettingsRepository<MouseJumpSettings> moduleSettingsRepository = SettingsRepository<MouseJumpSettings>.GetInstance(SettingsUtils.Default); 606 var list = new List<DashboardModuleItem> 607 { 608 new DashboardModuleShortcutItem() { Label = resourceLoader.GetString("MouseJump_ShortDescription"), Shortcut = moduleSettingsRepository.SettingsConfig.Properties.ActivationShortcut.GetKeysList() }, 609 }; 610 return new ObservableCollection<DashboardModuleItem>(list); 611 } 612 613 private ObservableCollection<DashboardModuleItem> GetModuleItemsMousePointerCrosshairs() 614 { 615 ISettingsRepository<MousePointerCrosshairsSettings> moduleSettingsRepository = SettingsRepository<MousePointerCrosshairsSettings>.GetInstance(SettingsUtils.Default); 616 var list = new List<DashboardModuleItem> 617 { 618 new DashboardModuleShortcutItem() { Label = resourceLoader.GetString("MouseCrosshairs_ShortDescription"), Shortcut = moduleSettingsRepository.SettingsConfig.Properties.ActivationShortcut.GetKeysList() }, 619 }; 620 return new ObservableCollection<DashboardModuleItem>(list); 621 } 622 623 private ObservableCollection<DashboardModuleItem> GetModuleItemsAdvancedPaste() 624 { 625 ISettingsRepository<AdvancedPasteSettings> moduleSettingsRepository = SettingsRepository<AdvancedPasteSettings>.GetInstance(SettingsUtils.Default); 626 var list = new List<DashboardModuleItem> 627 { 628 new DashboardModuleShortcutItem() { Label = resourceLoader.GetString("AdvancedPasteUI_Shortcut/Header"), Shortcut = moduleSettingsRepository.SettingsConfig.Properties.AdvancedPasteUIShortcut.GetKeysList() }, 629 new DashboardModuleShortcutItem() { Label = resourceLoader.GetString("PasteAsPlainText_Shortcut/Header"), Shortcut = moduleSettingsRepository.SettingsConfig.Properties.PasteAsPlainTextShortcut.GetKeysList() }, 630 }; 631 632 if (moduleSettingsRepository.SettingsConfig.Properties.PasteAsMarkdownShortcut.GetKeysList().Count > 0) 633 { 634 list.Add(new DashboardModuleShortcutItem() { Label = resourceLoader.GetString("PasteAsMarkdown_Shortcut/Header"), Shortcut = moduleSettingsRepository.SettingsConfig.Properties.PasteAsMarkdownShortcut.GetKeysList() }); 635 } 636 637 if (moduleSettingsRepository.SettingsConfig.Properties.PasteAsJsonShortcut.GetKeysList().Count > 0) 638 { 639 list.Add(new DashboardModuleShortcutItem() { Label = resourceLoader.GetString("PasteAsJson_Shortcut/Header"), Shortcut = moduleSettingsRepository.SettingsConfig.Properties.PasteAsJsonShortcut.GetKeysList() }); 640 } 641 642 return new ObservableCollection<DashboardModuleItem>(list); 643 } 644 645 private ObservableCollection<DashboardModuleItem> GetModuleItemsPeek() 646 { 647 ISettingsRepository<PeekSettings> moduleSettingsRepository = SettingsRepository<PeekSettings>.GetInstance(SettingsUtils.Default); 648 var list = new List<DashboardModuleItem> 649 { 650 new DashboardModuleShortcutItem() { Label = resourceLoader.GetString("Peek_ShortDescription"), Shortcut = moduleSettingsRepository.SettingsConfig.Properties.ActivationShortcut.GetKeysList() }, 651 }; 652 return new ObservableCollection<DashboardModuleItem>(list); 653 } 654 655 private ObservableCollection<DashboardModuleItem> GetModuleItemsPowerLauncher() 656 { 657 ISettingsRepository<PowerLauncherSettings> moduleSettingsRepository = SettingsRepository<PowerLauncherSettings>.GetInstance(SettingsUtils.Default); 658 var list = new List<DashboardModuleItem> 659 { 660 new DashboardModuleShortcutItem() { Label = resourceLoader.GetString("Run_ShortDescription"), Shortcut = moduleSettingsRepository.SettingsConfig.Properties.OpenPowerLauncher.GetKeysList() }, 661 }; 662 return new ObservableCollection<DashboardModuleItem>(list); 663 } 664 665 private ObservableCollection<DashboardModuleItem> GetModuleItemsPowerAccent() 666 { 667 var settingsUtils = SettingsUtils.Default; 668 PowerAccentSettings moduleSettings = settingsUtils.GetSettingsOrDefault<PowerAccentSettings>(PowerAccentSettings.ModuleName); 669 var activationMethod = moduleSettings.Properties.ActivationKey; 670 string activation = string.Empty; 671 switch (activationMethod) 672 { 673 case Library.Enumerations.PowerAccentActivationKey.LeftRightArrow: activation = resourceLoader.GetString("QuickAccent_Activation_Key_Arrows/Content"); break; 674 case Library.Enumerations.PowerAccentActivationKey.Space: activation = resourceLoader.GetString("QuickAccent_Activation_Key_Space/Content"); break; 675 case Library.Enumerations.PowerAccentActivationKey.Both: activation = resourceLoader.GetString("QuickAccent_Activation_Key_Either/Content"); break; 676 } 677 678 var list = new List<DashboardModuleItem> 679 { 680 new DashboardModuleActivationItem() { Label = resourceLoader.GetString("Dashboard_Activation"), Activation = activation }, 681 }; 682 return new ObservableCollection<DashboardModuleItem>(list); 683 } 684 685 private ObservableCollection<DashboardModuleItem> GetModuleItemsWorkspaces() 686 { 687 ISettingsRepository<WorkspacesSettings> moduleSettingsRepository = SettingsRepository<WorkspacesSettings>.GetInstance(SettingsUtils.Default); 688 var settings = moduleSettingsRepository.SettingsConfig; 689 690 var list = new List<DashboardModuleItem> 691 { 692 new DashboardModuleShortcutItem() { Label = resourceLoader.GetString("Workspaces_ShortDescription"), Shortcut = settings.Properties.Hotkey.Value.GetKeysList() }, 693 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 }, 694 }; 695 return new ObservableCollection<DashboardModuleItem>(list); 696 } 697 698 private ObservableCollection<DashboardModuleItem> GetModuleItemsRegistryPreview() 699 { 700 var list = new List<DashboardModuleItem> 701 { 702 new DashboardModuleButtonItem() { ButtonTitle = resourceLoader.GetString("RegistryPreview_LaunchButtonControl/Header"), ButtonGlyph = "ms-appx:///Assets/Settings/Icons/RegistryPreview.png", ButtonClickHandler = RegistryPreviewLaunchClicked }, 703 }; 704 return new ObservableCollection<DashboardModuleItem>(list); 705 } 706 707 private ObservableCollection<DashboardModuleItem> GetModuleItemsMeasureTool() 708 { 709 ISettingsRepository<MeasureToolSettings> moduleSettingsRepository = SettingsRepository<MeasureToolSettings>.GetInstance(SettingsUtils.Default); 710 var list = new List<DashboardModuleItem> 711 { 712 new DashboardModuleShortcutItem() { Label = resourceLoader.GetString("ScreenRuler_ShortDescription"), Shortcut = moduleSettingsRepository.SettingsConfig.Properties.ActivationShortcut.GetKeysList() }, 713 }; 714 return new ObservableCollection<DashboardModuleItem>(list); 715 } 716 717 private ObservableCollection<DashboardModuleItem> GetModuleItemsShortcutGuide() 718 { 719 ISettingsRepository<ShortcutGuideSettings> moduleSettingsRepository = SettingsRepository<ShortcutGuideSettings>.GetInstance(SettingsUtils.Default); 720 721 var shortcut = moduleSettingsRepository.SettingsConfig.Properties.UseLegacyPressWinKeyBehavior.Value 722 ? new List<object> { 92 } // Right Windows key code 723 : moduleSettingsRepository.SettingsConfig.Properties.OpenShortcutGuide.GetKeysList(); 724 725 var list = new List<DashboardModuleItem> 726 { 727 new DashboardModuleShortcutItem() { Label = resourceLoader.GetString("ShortcutGuide_ShortDescription"), Shortcut = shortcut }, 728 }; 729 return new ObservableCollection<DashboardModuleItem>(list); 730 } 731 732 private ObservableCollection<DashboardModuleItem> GetModuleItemsPowerOCR() 733 { 734 ISettingsRepository<PowerOcrSettings> moduleSettingsRepository = SettingsRepository<PowerOcrSettings>.GetInstance(SettingsUtils.Default); 735 var list = new List<DashboardModuleItem> 736 { 737 new DashboardModuleShortcutItem() { Label = resourceLoader.GetString("PowerOcr_ShortDescription"), Shortcut = moduleSettingsRepository.SettingsConfig.Properties.ActivationShortcut.GetKeysList() }, 738 }; 739 return new ObservableCollection<DashboardModuleItem>(list); 740 } 741 742 private ObservableCollection<DashboardModuleItem> GetModuleItemsPowerDisplay() 743 { 744 ISettingsRepository<PowerDisplaySettings> moduleSettingsRepository = SettingsRepository<PowerDisplaySettings>.GetInstance(SettingsUtils.Default); 745 var settings = moduleSettingsRepository.SettingsConfig; 746 var list = new List<DashboardModuleItem> 747 { 748 new DashboardModuleShortcutItem() { Label = resourceLoader.GetString("PowerDisplay_ToggleWindow"), Shortcut = settings.Properties.ActivationShortcut.GetKeysList() }, 749 new DashboardModuleButtonItem() { ButtonTitle = resourceLoader.GetString("PowerDisplay_LaunchButtonControl/Header"), IsButtonDescriptionVisible = true, ButtonDescription = resourceLoader.GetString("PowerDisplay_LaunchButtonControl/Description"), ButtonGlyph = "ms-appx:///Assets/Settings/Icons/PowerDisplay.png", ButtonClickHandler = PowerDisplayLaunchClicked }, 750 }; 751 return new ObservableCollection<DashboardModuleItem>(list); 752 } 753 754 internal void SWVersionButtonClicked() 755 { 756 NavigationService.Navigate(typeof(GeneralPage)); 757 } 758 759 private void EnvironmentVariablesLaunchClicked(object sender, RoutedEventArgs e) 760 { 761 var settingsUtils = SettingsUtils.Default; 762 var environmentVariablesViewModel = new EnvironmentVariablesViewModel(settingsUtils, SettingsRepository<GeneralSettings>.GetInstance(settingsUtils), SettingsRepository<EnvironmentVariablesSettings>.GetInstance(settingsUtils), ShellPage.SendDefaultIPCMessage, App.IsElevated); 763 environmentVariablesViewModel.Launch(); 764 } 765 766 private void HostLaunchClicked(object sender, RoutedEventArgs e) 767 { 768 var settingsUtils = SettingsUtils.Default; 769 var hostsViewModel = new HostsViewModel(settingsUtils, SettingsRepository<GeneralSettings>.GetInstance(settingsUtils), SettingsRepository<HostsSettings>.GetInstance(settingsUtils), ShellPage.SendDefaultIPCMessage, App.IsElevated); 770 hostsViewModel.Launch(); 771 } 772 773 private void FancyZoneLaunchClicked(object sender, RoutedEventArgs e) 774 { 775 // send message to launch the zones editor; 776 SendConfigMSG("{\"action\":{\"FancyZones\":{\"action_name\":\"ToggledFZEditor\", \"value\":\"\"}}}"); 777 } 778 779 private void WorkspacesLaunchClicked(object sender, RoutedEventArgs e) 780 { 781 // send message to launch the Workspaces editor; 782 SendConfigMSG("{\"action\":{\"Workspaces\":{\"action_name\":\"LaunchEditor\", \"value\":\"\"}}}"); 783 } 784 785 private void RegistryPreviewLaunchClicked(object sender, RoutedEventArgs e) 786 { 787 var actionName = "Launch"; 788 SendConfigMSG("{\"action\":{\"RegistryPreview\":{\"action_name\":\"" + actionName + "\", \"value\":\"\"}}}"); 789 } 790 791 private void PowerDisplayLaunchClicked(object sender, RoutedEventArgs e) 792 { 793 var actionName = "Launch"; 794 SendConfigMSG("{\"action\":{\"PowerDisplay\":{\"action_name\":\"" + actionName + "\", \"value\":\"\"}}}"); 795 } 796 797 internal void DashboardListItemClick(object sender) 798 { 799 if (sender is ModuleType moduleType) 800 { 801 NavigationService.Navigate(ModuleGpoHelper.GetModulePageType(moduleType)); 802 } 803 } 804 805 public override void Dispose() 806 { 807 base.Dispose(); 808 if (_settingsRepository != null) 809 { 810 _settingsRepository.SettingsChanged -= OnSettingsChanged; 811 } 812 813 GC.SuppressFinalize(this); 814 } 815 } 816 }