GeneralViewModel.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.Diagnostics; 9 using System.Globalization; 10 using System.IO; 11 using System.IO.Abstractions; 12 using System.Linq; 13 using System.Reflection; 14 using System.Runtime.CompilerServices; 15 using System.Text.Json; 16 using System.Text.Json.Serialization.Metadata; 17 using System.Threading.Tasks; 18 19 using global::PowerToys.GPOWrapper; 20 using ManagedCommon; 21 using Microsoft.PowerToys.Settings.UI.Helpers; 22 using Microsoft.PowerToys.Settings.UI.Library; 23 using Microsoft.PowerToys.Settings.UI.Library.Helpers; 24 using Microsoft.PowerToys.Settings.UI.Library.Interfaces; 25 using Microsoft.PowerToys.Settings.UI.Library.Utilities; 26 using Microsoft.PowerToys.Settings.UI.Library.ViewModels.Commands; 27 using Microsoft.PowerToys.Settings.UI.SerializationContext; 28 using Microsoft.PowerToys.Telemetry; 29 using Microsoft.Win32; 30 using Windows.System.Profile; 31 32 namespace Microsoft.PowerToys.Settings.UI.ViewModels 33 { 34 public partial class GeneralViewModel : PageViewModelBase 35 { 36 public enum InstallScope 37 { 38 PerMachine = 0, 39 PerUser, 40 } 41 42 protected override string ModuleName => "GeneralSettings"; 43 44 public override Dictionary<string, HotkeySettings[]> GetAllHotkeySettings() 45 { 46 return new Dictionary<string, HotkeySettings[]> 47 { 48 { ModuleName, new HotkeySettings[] { QuickAccessShortcut } }, 49 }; 50 } 51 52 private GeneralSettings GeneralSettingsConfig { get; set; } 53 54 private UpdatingSettings UpdatingSettingsConfig { get; set; } 55 56 public ButtonClickCommand CheckForUpdatesEventHandler { get; set; } 57 58 public Windows.ApplicationModel.Resources.ResourceLoader ResourceLoader { get; set; } 59 60 private Action HideBackupAndRestoreMessageAreaAction { get; set; } 61 62 private Action<int> DoBackupAndRestoreDryRun { get; set; } 63 64 public ButtonClickCommand BackupConfigsEventHandler { get; set; } 65 66 public ButtonClickCommand RestoreConfigsEventHandler { get; set; } 67 68 public ButtonClickCommand RefreshBackupStatusEventHandler { get; set; } 69 70 public ButtonClickCommand SelectSettingBackupDirEventHandler { get; set; } 71 72 public ButtonClickCommand RestartElevatedButtonEventHandler { get; set; } 73 74 public ButtonClickCommand UpdateNowButtonEventHandler { get; set; } 75 76 public Func<string, int> SendConfigMSG { get; } 77 78 public Func<string, int> SendRestartAsAdminConfigMSG { get; } 79 80 public Func<string, int> SendCheckForUpdatesConfigMSG { get; } 81 82 public string RunningAsUserDefaultText { get; set; } 83 84 public string RunningAsAdminDefaultText { get; set; } 85 86 private string _settingsConfigFileFolder = string.Empty; 87 88 private ISettingsRepository<GeneralSettings> _settingsRepository; 89 private Microsoft.UI.Dispatching.DispatcherQueue _dispatcherQueue; 90 91 private IFileSystemWatcher _fileWatcher; 92 93 private Func<Task<string>> PickSingleFolderDialog { get; } 94 95 private SettingsBackupAndRestoreUtils settingsBackupAndRestoreUtils = SettingsBackupAndRestoreUtils.Instance; 96 97 private const string InstallScopeRegKey = @"Software\Classes\powertoys\"; 98 99 public GeneralViewModel(ISettingsRepository<GeneralSettings> settingsRepository, string runAsAdminText, string runAsUserText, bool isElevated, bool isAdmin, Func<string, int> ipcMSGCallBackFunc, Func<string, int> ipcMSGRestartAsAdminMSGCallBackFunc, Func<string, int> ipcMSGCheckForUpdatesCallBackFunc, string configFileSubfolder = "", Action dispatcherAction = null, Action hideBackupAndRestoreMessageAreaAction = null, Action<int> doBackupAndRestoreDryRun = null, Func<Task<string>> pickSingleFolderDialog = null, Windows.ApplicationModel.Resources.ResourceLoader resourceLoader = null) 100 { 101 CheckForUpdatesEventHandler = new ButtonClickCommand(CheckForUpdatesClick); 102 RestartElevatedButtonEventHandler = new ButtonClickCommand(RestartElevated); 103 UpdateNowButtonEventHandler = new ButtonClickCommand(UpdateNowClick); 104 BackupConfigsEventHandler = new ButtonClickCommand(BackupConfigsClick); 105 SelectSettingBackupDirEventHandler = new ButtonClickCommand(SelectSettingBackupDir); 106 RestoreConfigsEventHandler = new ButtonClickCommand(RestoreConfigsClick); 107 RefreshBackupStatusEventHandler = new ButtonClickCommand(RefreshBackupStatusEventHandlerClick); 108 HideBackupAndRestoreMessageAreaAction = hideBackupAndRestoreMessageAreaAction; 109 DoBackupAndRestoreDryRun = doBackupAndRestoreDryRun; 110 PickSingleFolderDialog = pickSingleFolderDialog; 111 ResourceLoader = resourceLoader; 112 113 // To obtain the general settings configuration of PowerToys if it exists, else to create a new file and return the default configurations. 114 ArgumentNullException.ThrowIfNull(settingsRepository); 115 116 _settingsRepository = settingsRepository; 117 _settingsRepository.SettingsChanged += OnSettingsChanged; 118 _dispatcherQueue = GetDispatcherQueue(); 119 120 GeneralSettingsConfig = settingsRepository.SettingsConfig; 121 UpdatingSettingsConfig = UpdatingSettings.LoadSettings(); 122 if (UpdatingSettingsConfig == null) 123 { 124 UpdatingSettingsConfig = new UpdatingSettings(); 125 } 126 127 // set the callback functions value to handle outgoing IPC message. 128 SendConfigMSG = ipcMSGCallBackFunc; 129 SendCheckForUpdatesConfigMSG = ipcMSGCheckForUpdatesCallBackFunc; 130 SendRestartAsAdminConfigMSG = ipcMSGRestartAsAdminMSGCallBackFunc; 131 132 // Update Settings file folder: 133 _settingsConfigFileFolder = configFileSubfolder; 134 135 // Using Invariant here as these are internal strings and the analyzer 136 // expects strings to be normalized to uppercase. While the theme names 137 // are represented in lowercase everywhere else, we'll use uppercase 138 // normalization for switch statements 139 switch (GeneralSettingsConfig.Theme.ToUpperInvariant()) 140 { 141 case "DARK": 142 _themeIndex = 0; 143 break; 144 case "LIGHT": 145 _themeIndex = 1; 146 break; 147 case "SYSTEM": 148 _themeIndex = 2; 149 break; 150 } 151 152 _isDevBuild = Helper.GetProductVersion() == "v0.0.1"; 153 154 _runAtStartupGpoRuleConfiguration = GPOWrapper.GetConfiguredRunAtStartupValue(); 155 if (_runAtStartupGpoRuleConfiguration == GpoRuleConfigured.Disabled || _runAtStartupGpoRuleConfiguration == GpoRuleConfigured.Enabled) 156 { 157 // Get the enabled state from GPO. 158 _runAtStartupIsGPOConfigured = true; 159 _startup = _runAtStartupGpoRuleConfiguration == GpoRuleConfigured.Enabled; 160 } 161 else 162 { 163 _startup = GeneralSettingsConfig.Startup; 164 } 165 166 _showSysTrayIcon = GeneralSettingsConfig.ShowSysTrayIcon; 167 _showThemeAdaptiveSysTrayIcon = GeneralSettingsConfig.ShowThemeAdaptiveTrayIcon; 168 _showNewUpdatesToastNotification = GeneralSettingsConfig.ShowNewUpdatesToastNotification; 169 _autoDownloadUpdates = GeneralSettingsConfig.AutoDownloadUpdates; 170 _showWhatsNewAfterUpdates = GeneralSettingsConfig.ShowWhatsNewAfterUpdates; 171 _enableExperimentation = GeneralSettingsConfig.EnableExperimentation; 172 173 _isElevated = isElevated; 174 _runElevated = GeneralSettingsConfig.RunElevated; 175 _enableWarningsElevatedApps = GeneralSettingsConfig.EnableWarningsElevatedApps; 176 _enableQuickAccess = GeneralSettingsConfig.EnableQuickAccess; 177 _quickAccessShortcut = GeneralSettingsConfig.QuickAccessShortcut; 178 if (_quickAccessShortcut != null) 179 { 180 _quickAccessShortcut.PropertyChanged += QuickAccessShortcut_PropertyChanged; 181 } 182 183 RunningAsUserDefaultText = runAsUserText; 184 RunningAsAdminDefaultText = runAsAdminText; 185 186 _isAdmin = isAdmin; 187 188 _updatingState = UpdatingSettingsConfig.State; 189 _newAvailableVersion = UpdatingSettingsConfig.NewVersion; 190 _newAvailableVersionLink = UpdatingSettingsConfig.ReleasePageLink; 191 _updateCheckedDate = UpdatingSettingsConfig.LastCheckedDateLocalized; 192 193 _newUpdatesToastIsGpoDisabled = GPOWrapper.GetDisableNewUpdateToastValue() == GpoRuleConfigured.Enabled; 194 _autoDownloadUpdatesIsGpoDisabled = GPOWrapper.GetDisableAutomaticUpdateDownloadValue() == GpoRuleConfigured.Enabled; 195 _experimentationIsGpoDisallowed = GPOWrapper.GetAllowExperimentationValue() == GpoRuleConfigured.Disabled; 196 _showWhatsNewAfterUpdatesIsGpoDisabled = GPOWrapper.GetDisableShowWhatsNewAfterUpdatesValue() == GpoRuleConfigured.Enabled; 197 _enableDataDiagnosticsIsGpoDisallowed = GPOWrapper.GetAllowDataDiagnosticsValue() == GpoRuleConfigured.Disabled; 198 199 if (_enableDataDiagnosticsIsGpoDisallowed) 200 { 201 _enableDataDiagnostics = false; 202 } 203 else 204 { 205 _enableDataDiagnostics = DataDiagnosticsSettings.GetEnabledValue(); 206 } 207 208 _enableViewDataDiagnostics = DataDiagnosticsSettings.GetViewEnabledValue(); 209 _enableViewDataDiagnosticsOnLoad = _enableViewDataDiagnostics; 210 211 if (dispatcherAction != null) 212 { 213 _fileWatcher = Helper.GetFileWatcher(string.Empty, UpdatingSettings.SettingsFile, dispatcherAction); 214 } 215 216 // Diagnostic data retention policy 217 string etwDirPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "Microsoft\\PowerToys\\etw"); 218 DeleteDiagnosticDataOlderThan28Days(etwDirPath); 219 220 string localLowEtwDirPath = Path.Combine(Environment.GetEnvironmentVariable("USERPROFILE"), "AppData", "LocalLow", "Microsoft", "PowerToys", "etw"); 221 DeleteDiagnosticDataOlderThan28Days(localLowEtwDirPath); 222 223 InitializeLanguages(); 224 } 225 226 // Supported languages. Taken from Resources.wxs + default + en-US 227 private Dictionary<string, string> langTagsAndIds = new Dictionary<string, string> 228 { 229 { string.Empty, "Default_language" }, 230 { "ar-SA", "Arabic_Saudi_Arabia_Language" }, 231 { "cs-CZ", "Czech_Language" }, 232 { "de-DE", "German_Language" }, 233 { "en-US", "English_Language" }, 234 { "es-ES", "Spanish_Language" }, 235 { "fa-IR", "Persian_Farsi_Language" }, 236 { "fr-FR", "French_Language" }, 237 { "he-IL", "Hebrew_Israel_Language" }, 238 { "hu-HU", "Hungarian_Language" }, 239 { "it-IT", "Italian_Language" }, 240 { "ja-JP", "Japanese_Language" }, 241 { "ko-KR", "Korean_Language" }, 242 { "nl-NL", "Dutch_Language" }, 243 { "pl-PL", "Polish_Language" }, 244 { "pt-BR", "Portuguese_Brazil_Language" }, 245 { "pt-PT", "Portuguese_Portugal_Language" }, 246 { "ru-RU", "Russian_Language" }, 247 { "sv-SE", "Swedish_Language" }, 248 { "tr-TR", "Turkish_Language" }, 249 { "uk-UA", "Ukrainian_Language" }, 250 { "zh-CN", "Chinese_Simplified_Language" }, 251 { "zh-TW", "Chinese_Traditional_Language" }, 252 }; 253 254 private static bool _isDevBuild; 255 private bool _startup; 256 private bool _showSysTrayIcon; 257 private bool _showThemeAdaptiveSysTrayIcon; 258 private GpoRuleConfigured _runAtStartupGpoRuleConfiguration; 259 private bool _runAtStartupIsGPOConfigured; 260 private bool _isElevated; 261 private bool _runElevated; 262 private bool _isAdmin; 263 private bool _enableWarningsElevatedApps; 264 private bool _enableQuickAccess; 265 private HotkeySettings _quickAccessShortcut; 266 private int _themeIndex; 267 268 private bool _showNewUpdatesToastNotification; 269 private bool _newUpdatesToastIsGpoDisabled; 270 private bool _autoDownloadUpdates; 271 private bool _autoDownloadUpdatesIsGpoDisabled; 272 private bool _showWhatsNewAfterUpdates; 273 private bool _showWhatsNewAfterUpdatesIsGpoDisabled; 274 private bool _enableExperimentation; 275 private bool _experimentationIsGpoDisallowed; 276 private bool _enableDataDiagnostics; 277 private bool _enableDataDiagnosticsIsGpoDisallowed; 278 private bool _enableViewDataDiagnostics; 279 private bool _enableViewDataDiagnosticsOnLoad; 280 private bool _viewDiagnosticDataViewerChanged; 281 282 private UpdatingSettings.UpdatingState _updatingState = UpdatingSettings.UpdatingState.UpToDate; 283 private string _newAvailableVersion = string.Empty; 284 private string _newAvailableVersionLink = string.Empty; 285 private string _updateCheckedDate = string.Empty; 286 287 private bool _isNewVersionDownloading; 288 private bool _isNewVersionChecked; 289 private bool _isNoNetwork; 290 private bool _isBugReportRunning; 291 292 private bool _settingsBackupRestoreMessageVisible; 293 private string _settingsBackupMessage; 294 private string _backupRestoreMessageSeverity; 295 296 private int _languagesIndex; 297 private int _initLanguagesIndex; 298 private bool _languageChanged; 299 300 private string reportBugLink; 301 302 // Gets or sets a value indicating whether run powertoys on start-up. 303 public string ReportBugLink 304 { 305 get => reportBugLink; 306 set 307 { 308 reportBugLink = value; 309 OnPropertyChanged(nameof(ReportBugLink)); 310 } 311 } 312 313 public void InitializeReportBugLink() 314 { 315 var version = GetPowerToysVersion(); 316 317 string isElevatedString = "PowerToys is running " + (IsElevated ? "as admin (elevated)" : "as user (non-elevated)"); 318 319 string installScope = GetCurrentInstallScope() == InstallScope.PerMachine ? "per machine (system)" : "per user"; 320 321 var info = $"OS Version: {GetOSVersion()} \n.NET Version: {GetDotNetVersion()}\n{isElevatedString}\nInstall scope: {installScope}\nOperating System Language: {CultureInfo.InstalledUICulture.DisplayName}\nSystem locale: {CultureInfo.InstalledUICulture.Name}"; 322 323 var gitHubURL = "https://github.com/microsoft/PowerToys/issues/new?template=bug_report.yml&labels=Issue-Bug%2CTriage-Needed" + 324 "&version=" + version + "&additionalInfo=" + System.Web.HttpUtility.UrlEncode(info); 325 326 ReportBugLink = gitHubURL; 327 } 328 329 private string GetPowerToysVersion() 330 { 331 return Helper.GetProductVersion().TrimStart('v'); 332 } 333 334 private string GetOSVersion() 335 { 336 return Environment.OSVersion.VersionString; 337 } 338 339 public static string GetDotNetVersion() 340 { 341 return $".NET {Environment.Version}"; 342 } 343 344 public static InstallScope GetCurrentInstallScope() 345 { 346 // Check HKLM first 347 if (Registry.LocalMachine.OpenSubKey(InstallScopeRegKey) != null) 348 { 349 return InstallScope.PerMachine; 350 } 351 352 // If not found, check HKCU 353 var userKey = Registry.CurrentUser.OpenSubKey(InstallScopeRegKey); 354 if (userKey != null) 355 { 356 var installScope = userKey.GetValue("InstallScope") as string; 357 userKey.Close(); 358 if (!string.IsNullOrEmpty(installScope) && installScope.Contains("perUser")) 359 { 360 return InstallScope.PerUser; 361 } 362 } 363 364 return InstallScope.PerMachine; // Default if no specific registry key found 365 } 366 367 // Gets or sets a value indicating whether run powertoys on start-up. 368 public bool Startup 369 { 370 get 371 { 372 return _startup; 373 } 374 375 set 376 { 377 if (_runAtStartupIsGPOConfigured) 378 { 379 // If it's GPO configured, shouldn't be able to change this state. 380 return; 381 } 382 383 if (_startup != value) 384 { 385 _startup = value; 386 GeneralSettingsConfig.Startup = value; 387 NotifyPropertyChanged(); 388 } 389 } 390 } 391 392 // Gets or sets a value indicating whether the PowerToys icon should be shown in the system tray. 393 public bool ShowSysTrayIcon 394 { 395 get 396 { 397 return _showSysTrayIcon; 398 } 399 400 set 401 { 402 if (_showSysTrayIcon != value) 403 { 404 _showSysTrayIcon = value; 405 GeneralSettingsConfig.ShowSysTrayIcon = value; 406 NotifyPropertyChanged(); 407 } 408 } 409 } 410 411 public bool ShowThemeAdaptiveTrayIcon 412 { 413 get 414 { 415 return _showThemeAdaptiveSysTrayIcon; 416 } 417 418 set 419 { 420 if (_showThemeAdaptiveSysTrayIcon != value) 421 { 422 _showThemeAdaptiveSysTrayIcon = value; 423 GeneralSettingsConfig.ShowThemeAdaptiveTrayIcon = value; 424 NotifyPropertyChanged(); 425 } 426 } 427 } 428 429 public string RunningAsText 430 { 431 get 432 { 433 if (!IsElevated) 434 { 435 return RunningAsUserDefaultText; 436 } 437 else 438 { 439 return RunningAsAdminDefaultText; 440 } 441 } 442 443 set 444 { 445 OnPropertyChanged("RunningAsAdminText"); 446 } 447 } 448 449 // Gets or sets a value indicating whether the powertoy elevated. 450 public bool IsElevated 451 { 452 get 453 { 454 return _isElevated; 455 } 456 457 set 458 { 459 if (_isElevated != value) 460 { 461 _isElevated = value; 462 OnPropertyChanged(nameof(IsElevated)); 463 OnPropertyChanged(nameof(IsAdminButtonEnabled)); 464 OnPropertyChanged("RunningAsAdminText"); 465 } 466 } 467 } 468 469 public bool IsAdminButtonEnabled 470 { 471 get 472 { 473 return !IsElevated; 474 } 475 476 set 477 { 478 OnPropertyChanged(nameof(IsAdminButtonEnabled)); 479 } 480 } 481 482 // Gets or sets a value indicating whether powertoys should run elevated. 483 public bool RunElevated 484 { 485 get 486 { 487 return _runElevated; 488 } 489 490 set 491 { 492 if (_runElevated != value) 493 { 494 _runElevated = value; 495 GeneralSettingsConfig.RunElevated = value; 496 NotifyPropertyChanged(); 497 } 498 } 499 } 500 501 // Gets a value indicating whether the user is part of administrators group. 502 public bool IsAdmin 503 { 504 get 505 { 506 return _isAdmin; 507 } 508 } 509 510 public bool EnableWarningsElevatedApps 511 { 512 get 513 { 514 return _enableWarningsElevatedApps; 515 } 516 517 set 518 { 519 if (_enableWarningsElevatedApps != value) 520 { 521 _enableWarningsElevatedApps = value; 522 GeneralSettingsConfig.EnableWarningsElevatedApps = value; 523 NotifyPropertyChanged(); 524 } 525 } 526 } 527 528 public bool EnableQuickAccess 529 { 530 get 531 { 532 return _enableQuickAccess; 533 } 534 535 set 536 { 537 if (_enableQuickAccess != value) 538 { 539 _enableQuickAccess = value; 540 GeneralSettingsConfig.EnableQuickAccess = value; 541 NotifyPropertyChanged(); 542 } 543 } 544 } 545 546 public HotkeySettings QuickAccessShortcut 547 { 548 get 549 { 550 return _quickAccessShortcut; 551 } 552 553 set 554 { 555 if (_quickAccessShortcut != value) 556 { 557 if (_quickAccessShortcut != null) 558 { 559 _quickAccessShortcut.PropertyChanged -= QuickAccessShortcut_PropertyChanged; 560 } 561 562 _quickAccessShortcut = value; 563 if (_quickAccessShortcut != null) 564 { 565 _quickAccessShortcut.PropertyChanged += QuickAccessShortcut_PropertyChanged; 566 } 567 568 GeneralSettingsConfig.QuickAccessShortcut = value; 569 NotifyPropertyChanged(); 570 } 571 } 572 } 573 574 private void QuickAccessShortcut_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e) 575 { 576 NotifyPropertyChanged(nameof(QuickAccessShortcut)); 577 } 578 579 public bool SomeUpdateSettingsAreGpoManaged 580 { 581 get 582 { 583 return _newUpdatesToastIsGpoDisabled || 584 (_isAdmin && _autoDownloadUpdatesIsGpoDisabled) || 585 _showWhatsNewAfterUpdatesIsGpoDisabled; 586 } 587 } 588 589 public bool ShowNewUpdatesToastNotification 590 { 591 get 592 { 593 return _showNewUpdatesToastNotification && !_newUpdatesToastIsGpoDisabled; 594 } 595 596 set 597 { 598 if (_showNewUpdatesToastNotification != value) 599 { 600 _showNewUpdatesToastNotification = value; 601 GeneralSettingsConfig.ShowNewUpdatesToastNotification = value; 602 NotifyPropertyChanged(); 603 } 604 } 605 } 606 607 public bool IsShowNewUpdatesToastNotificationCardEnabled 608 { 609 get => !_isDevBuild && !_newUpdatesToastIsGpoDisabled; 610 } 611 612 public bool AutoDownloadUpdates 613 { 614 get 615 { 616 return _autoDownloadUpdates && !_autoDownloadUpdatesIsGpoDisabled; 617 } 618 619 set 620 { 621 if (_autoDownloadUpdates != value) 622 { 623 _autoDownloadUpdates = value; 624 GeneralSettingsConfig.AutoDownloadUpdates = value; 625 NotifyPropertyChanged(); 626 } 627 } 628 } 629 630 public bool IsAutoDownloadUpdatesCardEnabled 631 { 632 get => !_isDevBuild && !_autoDownloadUpdatesIsGpoDisabled; 633 } 634 635 public bool ShowWhatsNewAfterUpdates 636 { 637 get 638 { 639 return _showWhatsNewAfterUpdates && !_showWhatsNewAfterUpdatesIsGpoDisabled; 640 } 641 642 set 643 { 644 if (_showWhatsNewAfterUpdates != value) 645 { 646 _showWhatsNewAfterUpdates = value; 647 GeneralSettingsConfig.ShowWhatsNewAfterUpdates = value; 648 NotifyPropertyChanged(); 649 } 650 } 651 } 652 653 public bool IsShowWhatsNewAfterUpdatesCardEnabled 654 { 655 get => !_isDevBuild && !_showWhatsNewAfterUpdatesIsGpoDisabled; 656 } 657 658 public bool EnableExperimentation 659 { 660 get 661 { 662 return _enableExperimentation && !_experimentationIsGpoDisallowed; 663 } 664 665 set 666 { 667 if (_enableExperimentation != value) 668 { 669 _enableExperimentation = value; 670 GeneralSettingsConfig.EnableExperimentation = value; 671 NotifyPropertyChanged(); 672 } 673 } 674 } 675 676 public bool EnableDataDiagnostics 677 { 678 get 679 { 680 return _enableDataDiagnostics; 681 } 682 683 set 684 { 685 if (_enableDataDiagnostics != value) 686 { 687 _enableDataDiagnostics = value; 688 689 if (_enableDataDiagnostics == false) 690 { 691 EnableViewDataDiagnostics = false; 692 } 693 694 DataDiagnosticsSettings.SetEnabledValue(_enableDataDiagnostics); 695 NotifyPropertyChanged(); 696 } 697 } 698 } 699 700 public bool ViewDiagnosticDataViewerChanged 701 { 702 get => _viewDiagnosticDataViewerChanged; 703 } 704 705 public bool EnableViewDataDiagnostics 706 { 707 get 708 { 709 return _enableViewDataDiagnostics; 710 } 711 712 set 713 { 714 if (_enableViewDataDiagnostics != value) 715 { 716 _enableViewDataDiagnostics = value; 717 718 if (_enableViewDataDiagnostics != _enableViewDataDiagnosticsOnLoad) 719 { 720 _viewDiagnosticDataViewerChanged = true; 721 } 722 else 723 { 724 _viewDiagnosticDataViewerChanged = false; 725 } 726 727 DataDiagnosticsSettings.SetViewEnabledValue(_enableViewDataDiagnostics); 728 OnPropertyChanged(nameof(EnableViewDataDiagnostics)); 729 OnPropertyChanged(nameof(ViewDiagnosticDataViewerChanged)); 730 } 731 } 732 } 733 734 public bool IsExperimentationGpoDisallowed 735 { 736 get => _experimentationIsGpoDisallowed; 737 } 738 739 public bool IsDataDiagnosticsGPOManaged 740 { 741 get => _enableDataDiagnosticsIsGpoDisallowed; 742 } 743 744 public bool IsRunAtStartupGPOManaged 745 { 746 get => _runAtStartupIsGPOConfigured; 747 } 748 749 public string SettingsBackupAndRestoreDir 750 { 751 get 752 { 753 return settingsBackupAndRestoreUtils.GetSettingsBackupAndRestoreDir(); 754 } 755 756 set 757 { 758 if (settingsBackupAndRestoreUtils.GetSettingsBackupAndRestoreDir() != value) 759 { 760 SettingsBackupAndRestoreUtils.SetRegSettingsBackupAndRestoreItem("SettingsBackupAndRestoreDir", value); 761 NotifyPropertyChanged(); 762 } 763 } 764 } 765 766 public int ThemeIndex 767 { 768 get 769 { 770 return _themeIndex; 771 } 772 773 set 774 { 775 if (_themeIndex != value) 776 { 777 switch (value) 778 { 779 case 0: GeneralSettingsConfig.Theme = "dark"; break; 780 case 1: GeneralSettingsConfig.Theme = "light"; break; 781 case 2: GeneralSettingsConfig.Theme = "system"; break; 782 } 783 784 _themeIndex = value; 785 786 App.ThemeService.ApplyTheme(); 787 788 NotifyPropertyChanged(); 789 } 790 } 791 } 792 793 public string PowerToysVersion 794 { 795 get 796 { 797 return Helper.GetProductVersion(); 798 } 799 } 800 801 public string UpdateCheckedDate 802 { 803 get 804 { 805 RequestUpdateCheckedDate(); 806 return _updateCheckedDate; 807 } 808 809 set 810 { 811 if (_updateCheckedDate != value) 812 { 813 _updateCheckedDate = value; 814 NotifyPropertyChanged(); 815 } 816 } 817 } 818 819 public string LastSettingsBackupDate 820 { 821 get 822 { 823 try 824 { 825 var manifest = settingsBackupAndRestoreUtils.GetLatestSettingsBackupManifest(); 826 if (manifest != null) 827 { 828 if (manifest["CreateDateTime"] != null) 829 { 830 if (DateTime.TryParse(manifest["CreateDateTime"].ToString(), CultureInfo.InvariantCulture, DateTimeStyles.AssumeUniversal, out var theDateTime)) 831 { 832 return theDateTime.ToString("G", CultureInfo.CurrentCulture); 833 } 834 else 835 { 836 Logger.LogError("Failed to parse time from backup"); 837 return GetResourceString("General_SettingsBackupAndRestore_FailedToParseTime"); 838 } 839 } 840 else 841 { 842 return GetResourceString("General_SettingsBackupAndRestore_UnknownBackupTime"); 843 } 844 } 845 else 846 { 847 return GetResourceString("General_SettingsBackupAndRestore_NoBackupFound"); 848 } 849 } 850 catch (Exception e) 851 { 852 Logger.LogError("Error getting LastSettingsBackupDate", e); 853 return GetResourceString("General_SettingsBackupAndRestore_UnknownBackupTime"); 854 } 855 } 856 } 857 858 public string CurrentSettingMatchText 859 { 860 get 861 { 862 try 863 { 864 var results = settingsBackupAndRestoreUtils.GetLastBackupSettingsResults(); 865 866 var resultText = string.Empty; 867 868 if (!results.LastRan.HasValue) 869 { 870 // not ran since started. 871 return GetResourceString("General_SettingsBackupAndRestore_CurrentSettingsNoChecked"); // "Current Settings Unknown"; 872 } 873 else 874 { 875 if (results.Success) 876 { 877 if (results.LastBackupExists) 878 { 879 // if true, it means a backup would have been made 880 resultText = GetResourceString("General_SettingsBackupAndRestore_CurrentSettingsDiffer"); // "Current Settings Differ"; 881 } 882 else 883 { 884 // would have done the backup, but there also was not an existing one there. 885 resultText = GetResourceString("General_SettingsBackupAndRestore_NoBackupFound"); 886 } 887 } 888 else 889 { 890 if (results.HadError) 891 { 892 // if false and error we don't really know 893 resultText = GetResourceString("General_SettingsBackupAndRestore_CurrentSettingsUnknown"); // "Current Settings Unknown"; 894 } 895 else 896 { 897 // if false, it means a backup would not have been needed/made 898 resultText = GetResourceString("General_SettingsBackupAndRestore_CurrentSettingsMatch"); // "Current Settings Match"; 899 } 900 } 901 902 return $"{resultText} {GetResourceString("General_SettingsBackupAndRestore_CurrentSettingsStatusAt")} {results.LastRan.Value.ToLocalTime().ToString("G", CultureInfo.CurrentCulture)}"; 903 } 904 } 905 catch (Exception e) 906 { 907 Logger.LogError("Error getting CurrentSettingMatchText", e); 908 return string.Empty; 909 } 910 } 911 } 912 913 public string LastSettingsBackupSource 914 { 915 get 916 { 917 try 918 { 919 var manifest = settingsBackupAndRestoreUtils.GetLatestSettingsBackupManifest(); 920 if (manifest != null) 921 { 922 if (manifest["BackupSource"] != null) 923 { 924 if (manifest["BackupSource"].ToString().Equals(Environment.MachineName, StringComparison.OrdinalIgnoreCase)) 925 { 926 return GetResourceString("General_SettingsBackupAndRestore_ThisMachine"); 927 } 928 else 929 { 930 return manifest["BackupSource"].ToString(); 931 } 932 } 933 else 934 { 935 return GetResourceString("General_SettingsBackupAndRestore_UnknownBackupSource"); 936 } 937 } 938 else 939 { 940 return GetResourceString("General_SettingsBackupAndRestore_NoBackupFound"); 941 } 942 } 943 catch (Exception e) 944 { 945 Logger.LogError("Error getting LastSettingsBackupSource", e); 946 return GetResourceString("General_SettingsBackupAndRestore_UnknownBackupSource"); 947 } 948 } 949 } 950 951 public string LastSettingsBackupFileName 952 { 953 get 954 { 955 try 956 { 957 var fileName = settingsBackupAndRestoreUtils.GetLatestBackupFileName(); 958 return !string.IsNullOrEmpty(fileName) ? fileName : GetResourceString("General_SettingsBackupAndRestore_NoBackupFound"); 959 } 960 catch (Exception e) 961 { 962 Logger.LogError("Error getting LastSettingsBackupFileName", e); 963 return string.Empty; 964 } 965 } 966 } 967 968 public UpdatingSettings.UpdatingState PowerToysUpdatingState 969 { 970 get 971 { 972 return _updatingState; 973 } 974 975 private set 976 { 977 if (value != _updatingState) 978 { 979 _updatingState = value; 980 NotifyPropertyChanged(); 981 } 982 } 983 } 984 985 public string PowerToysNewAvailableVersion 986 { 987 get 988 { 989 return _newAvailableVersion; 990 } 991 992 private set 993 { 994 if (value != _newAvailableVersion) 995 { 996 _newAvailableVersion = value; 997 NotifyPropertyChanged(); 998 } 999 } 1000 } 1001 1002 public string PowerToysNewAvailableVersionLink 1003 { 1004 get 1005 { 1006 return _newAvailableVersionLink; 1007 } 1008 1009 private set 1010 { 1011 if (value != _newAvailableVersionLink) 1012 { 1013 _newAvailableVersionLink = value; 1014 NotifyPropertyChanged(); 1015 } 1016 } 1017 } 1018 1019 public bool IsNewVersionDownloading 1020 { 1021 get 1022 { 1023 return _isNewVersionDownloading; 1024 } 1025 1026 set 1027 { 1028 if (value != _isNewVersionDownloading) 1029 { 1030 _isNewVersionDownloading = value; 1031 NotifyPropertyChanged(); 1032 } 1033 } 1034 } 1035 1036 public bool IsNewVersionCheckedAndUpToDate 1037 { 1038 get 1039 { 1040 return _isNewVersionChecked; 1041 } 1042 } 1043 1044 public bool IsNoNetwork 1045 { 1046 get 1047 { 1048 return _isNoNetwork; 1049 } 1050 } 1051 1052 public bool IsBugReportRunning 1053 { 1054 get 1055 { 1056 return _isBugReportRunning; 1057 } 1058 1059 set 1060 { 1061 if (value != _isBugReportRunning) 1062 { 1063 _isBugReportRunning = value; 1064 NotifyPropertyChanged(); 1065 } 1066 } 1067 } 1068 1069 public bool SettingsBackupRestoreMessageVisible 1070 { 1071 get 1072 { 1073 return _settingsBackupRestoreMessageVisible; 1074 } 1075 } 1076 1077 public string BackupRestoreMessageSeverity 1078 { 1079 get 1080 { 1081 return _backupRestoreMessageSeverity; 1082 } 1083 } 1084 1085 public string SettingsBackupMessage 1086 { 1087 get 1088 { 1089 return _settingsBackupMessage; 1090 } 1091 } 1092 1093 public bool IsDownloadAllowed 1094 { 1095 get 1096 { 1097 return !_isDevBuild && !IsNewVersionDownloading; 1098 } 1099 } 1100 1101 public bool IsUpdatePanelVisible 1102 { 1103 get 1104 { 1105 return PowerToysUpdatingState == UpdatingSettings.UpdatingState.UpToDate || PowerToysUpdatingState == UpdatingSettings.UpdatingState.NetworkError; 1106 } 1107 } 1108 1109 public ObservableCollection<LanguageModel> Languages { get; } = new ObservableCollection<LanguageModel>(); 1110 1111 public int LanguagesIndex 1112 { 1113 get 1114 { 1115 return _languagesIndex; 1116 } 1117 1118 set 1119 { 1120 if (_languagesIndex != value) 1121 { 1122 _languagesIndex = value; 1123 OnPropertyChanged(nameof(LanguagesIndex)); 1124 NotifyLanguageChanged(); 1125 if (_initLanguagesIndex != value) 1126 { 1127 LanguageChanged = true; 1128 } 1129 else 1130 { 1131 LanguageChanged = false; 1132 } 1133 } 1134 } 1135 } 1136 1137 public bool LanguageChanged 1138 { 1139 get 1140 { 1141 return _languageChanged; 1142 } 1143 1144 set 1145 { 1146 if (_languageChanged != value) 1147 { 1148 _languageChanged = value; 1149 OnPropertyChanged(nameof(LanguageChanged)); 1150 } 1151 } 1152 } 1153 1154 public void NotifyPropertyChanged([CallerMemberName] string propertyName = null, bool reDoBackupDryRun = true) 1155 { 1156 // Notify UI of property change 1157 OnPropertyChanged(propertyName); 1158 1159 OutGoingGeneralSettings outsettings = new OutGoingGeneralSettings(GeneralSettingsConfig); 1160 1161 SendConfigMSG(outsettings.ToString()); 1162 1163 if (reDoBackupDryRun && DoBackupAndRestoreDryRun != null) 1164 { 1165 DoBackupAndRestoreDryRun(500); 1166 } 1167 } 1168 1169 /// <summary> 1170 /// Method <c>SelectSettingBackupDir</c> opens folder browser to select a backup and restore location. 1171 /// </summary> 1172 private async void SelectSettingBackupDir() 1173 { 1174 var currentDir = settingsBackupAndRestoreUtils.GetSettingsBackupAndRestoreDir(); 1175 1176 var newPath = await PickSingleFolderDialog(); 1177 1178 if (!string.IsNullOrEmpty(newPath)) 1179 { 1180 SettingsBackupAndRestoreDir = newPath; 1181 NotifyAllBackupAndRestoreProperties(); 1182 } 1183 } 1184 1185 private void RefreshBackupStatusEventHandlerClick() 1186 { 1187 DoBackupAndRestoreDryRun(0); 1188 } 1189 1190 /// <summary> 1191 /// Method <c>RestoreConfigsClick</c> starts the restore. 1192 /// </summary> 1193 private void RestoreConfigsClick() 1194 { 1195 string settingsBackupAndRestoreDir = settingsBackupAndRestoreUtils.GetSettingsBackupAndRestoreDir(); 1196 1197 if (string.IsNullOrEmpty(settingsBackupAndRestoreDir)) 1198 { 1199 SelectSettingBackupDir(); 1200 } 1201 1202 var results = SettingsUtils.RestoreSettings(); 1203 _backupRestoreMessageSeverity = results.Severity; 1204 1205 if (!results.Success) 1206 { 1207 _settingsBackupRestoreMessageVisible = true; 1208 1209 _settingsBackupMessage = GetResourceString(results.Message); 1210 1211 NotifyAllBackupAndRestoreProperties(); 1212 1213 HideBackupAndRestoreMessageAreaAction(); 1214 } 1215 else 1216 { 1217 // make sure not to do NotifyPropertyChanged here, else it will persist the configs from memory and 1218 // undo the settings restore. 1219 SettingsBackupAndRestoreUtils.SetRegSettingsBackupAndRestoreItem("LastSettingsRestoreDate", DateTime.UtcNow.ToString("u", CultureInfo.InvariantCulture)); 1220 1221 Restart(); 1222 } 1223 } 1224 1225 /// <summary> 1226 /// Method <c>BackupConfigsClick</c> starts the backup. 1227 /// </summary> 1228 private void BackupConfigsClick() 1229 { 1230 string settingsBackupAndRestoreDir = settingsBackupAndRestoreUtils.GetSettingsBackupAndRestoreDir(); 1231 1232 if (string.IsNullOrEmpty(settingsBackupAndRestoreDir)) 1233 { 1234 SelectSettingBackupDir(); 1235 } 1236 1237 var results = SettingsUtils.BackupSettings(); 1238 1239 _settingsBackupRestoreMessageVisible = true; 1240 _backupRestoreMessageSeverity = results.Severity; 1241 _settingsBackupMessage = GetResourceString(results.Message) + results.OptionalMessage; 1242 1243 // now we do a dry run to get the results for "setting match" 1244 var settingsUtils = SettingsUtils.Default; 1245 var appBasePath = Path.GetDirectoryName(settingsUtils.GetSettingsFilePath()); 1246 settingsBackupAndRestoreUtils.BackupSettings(appBasePath, settingsBackupAndRestoreDir, true); 1247 1248 NotifyAllBackupAndRestoreProperties(); 1249 1250 HideBackupAndRestoreMessageAreaAction(); 1251 } 1252 1253 public void NotifyAllBackupAndRestoreProperties() 1254 { 1255 NotifyPropertyChanged(nameof(LastSettingsBackupDate), false); 1256 NotifyPropertyChanged(nameof(LastSettingsBackupSource), false); 1257 NotifyPropertyChanged(nameof(LastSettingsBackupFileName), false); 1258 NotifyPropertyChanged(nameof(CurrentSettingMatchText), false); 1259 NotifyPropertyChanged(nameof(SettingsBackupMessage), false); 1260 NotifyPropertyChanged(nameof(BackupRestoreMessageSeverity), false); 1261 NotifyPropertyChanged(nameof(SettingsBackupRestoreMessageVisible), false); 1262 } 1263 1264 // callback function to launch the URL to check for updates. 1265 private void CheckForUpdatesClick() 1266 { 1267 GeneralSettingsConfig.CustomActionName = "check_for_updates"; 1268 1269 OutGoingGeneralSettings outsettings = new OutGoingGeneralSettings(GeneralSettingsConfig); 1270 GeneralSettingsCustomAction customaction = new GeneralSettingsCustomAction(outsettings); 1271 1272 SendCheckForUpdatesConfigMSG(customaction.ToString()); 1273 } 1274 1275 private void UpdateNowClick() 1276 { 1277 IsNewVersionDownloading = string.IsNullOrEmpty(UpdatingSettingsConfig.DownloadedInstallerFilename); 1278 NotifyPropertyChanged(nameof(IsDownloadAllowed)); 1279 1280 Process.Start(new ProcessStartInfo(Helper.GetPowerToysInstallationFolder() + "\\PowerToys.exe") { Arguments = "powertoys://update_now/" }); 1281 } 1282 1283 /// <summary> 1284 /// Class <c>GetResourceString</c> gets a localized text. 1285 /// </summary> 1286 /// <remarks> 1287 /// To do: see if there is a betting way to do this, there should be. It does allow us to return missing localization in a way that makes it obvious they were missed. 1288 /// </remarks> 1289 public string GetResourceString(string resource) 1290 { 1291 if (ResourceLoader != null) 1292 { 1293 var result = ResourceLoader.GetString(resource); 1294 if (string.IsNullOrEmpty(result)) 1295 { 1296 return resource.ToUpperInvariant() + "!!!"; 1297 } 1298 else 1299 { 1300 return result; 1301 } 1302 } 1303 else 1304 { 1305 return resource; 1306 } 1307 } 1308 1309 public void RequestUpdateCheckedDate() 1310 { 1311 GeneralSettingsConfig.CustomActionName = "request_update_state_date"; 1312 1313 OutGoingGeneralSettings outsettings = new OutGoingGeneralSettings(GeneralSettingsConfig); 1314 GeneralSettingsCustomAction customaction = new GeneralSettingsCustomAction(outsettings); 1315 1316 SendCheckForUpdatesConfigMSG(customaction.ToString()); 1317 } 1318 1319 public void RestartElevated() 1320 { 1321 GeneralSettingsConfig.CustomActionName = "restart_elevation"; 1322 1323 OutGoingGeneralSettings outsettings = new OutGoingGeneralSettings(GeneralSettingsConfig); 1324 GeneralSettingsCustomAction customaction = new GeneralSettingsCustomAction(outsettings); 1325 1326 SendRestartAsAdminConfigMSG(customaction.ToString()); 1327 } 1328 1329 /// <summary> 1330 /// Class <c>Restart</c> begin a restart and signal we want to maintain elevation 1331 /// </summary> 1332 /// <remarks> 1333 /// Other restarts either raised or lowered elevation 1334 /// </remarks> 1335 public void Restart() 1336 { 1337 GeneralSettingsConfig.CustomActionName = "restart_maintain_elevation"; 1338 1339 OutGoingGeneralSettings outsettings = new OutGoingGeneralSettings(GeneralSettingsConfig); 1340 GeneralSettingsCustomAction customaction = new GeneralSettingsCustomAction(outsettings); 1341 1342 var dataToSend = customaction.ToString(); 1343 dataToSend = JsonSerializer.Serialize(ActionMessage.Create("restart_maintain_elevation"), SourceGenerationContextContext.Default.ActionMessage); 1344 SendRestartAsAdminConfigMSG(dataToSend); 1345 } 1346 1347 /// <summary> 1348 /// Class <c>HideBackupAndRestoreMessageArea</c> hides the backup/restore message area 1349 /// </summary> 1350 /// <remarks> 1351 /// We want to have it go away after a short period. 1352 /// </remarks> 1353 public void HideBackupAndRestoreMessageArea() 1354 { 1355 _settingsBackupRestoreMessageVisible = false; 1356 NotifyAllBackupAndRestoreProperties(); 1357 } 1358 1359 public void RefreshUpdatingState() 1360 { 1361 object oLock = new object(); 1362 lock (oLock) 1363 { 1364 var config = UpdatingSettings.LoadSettings(); 1365 1366 // Retry loading if failed 1367 for (int i = 0; i < 3 && config == null; i++) 1368 { 1369 System.Threading.Thread.Sleep(100); 1370 config = UpdatingSettings.LoadSettings(); 1371 } 1372 1373 if (config == null) 1374 { 1375 return; 1376 } 1377 1378 UpdatingSettingsConfig = config; 1379 1380 if (PowerToysUpdatingState != config.State) 1381 { 1382 IsNewVersionDownloading = false; 1383 } 1384 else 1385 { 1386 bool dateChanged = UpdateCheckedDate == UpdatingSettingsConfig.LastCheckedDateLocalized; 1387 bool fileDownloaded = string.IsNullOrEmpty(UpdatingSettingsConfig.DownloadedInstallerFilename); 1388 IsNewVersionDownloading = !(dateChanged || fileDownloaded); 1389 } 1390 1391 PowerToysUpdatingState = UpdatingSettingsConfig.State; 1392 PowerToysNewAvailableVersion = UpdatingSettingsConfig.NewVersion; 1393 PowerToysNewAvailableVersionLink = UpdatingSettingsConfig.ReleasePageLink; 1394 UpdateCheckedDate = UpdatingSettingsConfig.LastCheckedDateLocalized; 1395 1396 _isNoNetwork = PowerToysUpdatingState == UpdatingSettings.UpdatingState.NetworkError; 1397 NotifyPropertyChanged(nameof(IsNoNetwork)); 1398 NotifyPropertyChanged(nameof(IsNewVersionDownloading)); 1399 NotifyPropertyChanged(nameof(IsUpdatePanelVisible)); 1400 _isNewVersionChecked = PowerToysUpdatingState == UpdatingSettings.UpdatingState.UpToDate && !IsNewVersionDownloading; 1401 NotifyPropertyChanged(nameof(IsNewVersionCheckedAndUpToDate)); 1402 1403 NotifyPropertyChanged(nameof(IsDownloadAllowed)); 1404 } 1405 } 1406 1407 private void InitializeLanguages() 1408 { 1409 var lang = LanguageModel.LoadSetting(); 1410 var selectedLanguageIndex = 0; 1411 1412 foreach (var item in langTagsAndIds) 1413 { 1414 var language = new LanguageModel { Tag = item.Key, ResourceID = item.Value, Language = GetResourceString(item.Value) }; 1415 var index = GetLanguageIndex(language.Language, item.Key == string.Empty); 1416 Languages.Insert(index, language); 1417 1418 if (item.Key.Equals(lang, StringComparison.Ordinal)) 1419 { 1420 selectedLanguageIndex = index; 1421 } 1422 else if (index <= selectedLanguageIndex) 1423 { 1424 selectedLanguageIndex++; 1425 } 1426 } 1427 1428 _initLanguagesIndex = selectedLanguageIndex; 1429 LanguagesIndex = selectedLanguageIndex; 1430 } 1431 1432 [System.Diagnostics.CodeAnalysis.SuppressMessage("Globalization", "CA1309:Use ordinal string comparison", Justification = "Building a user facing list")] 1433 private int GetLanguageIndex(string language, bool isDefault) 1434 { 1435 if (Languages.Count == 0 || isDefault) 1436 { 1437 return 0; 1438 } 1439 1440 for (var i = 1; i < Languages.Count; i++) 1441 { 1442 if (string.Compare(Languages[i].Language, language, StringComparison.CurrentCultureIgnoreCase) > 0) 1443 { 1444 return i; 1445 } 1446 } 1447 1448 return Languages.Count; 1449 } 1450 1451 private void NotifyLanguageChanged() 1452 { 1453 OutGoingLanguageSettings outsettings = new OutGoingLanguageSettings(Languages[_languagesIndex].Tag); 1454 1455 SendConfigMSG(outsettings.ToString()); 1456 } 1457 1458 internal void RefreshSettingsOnExternalChange() 1459 { 1460 EnableDataDiagnostics = DataDiagnosticsSettings.GetEnabledValue(); 1461 1462 NotifyPropertyChanged(nameof(EnableDataDiagnostics)); 1463 } 1464 1465 // Per retention policy 1466 private void DeleteDiagnosticDataOlderThan28Days(string etwDirPath) 1467 { 1468 if (!Directory.Exists(etwDirPath)) 1469 { 1470 return; 1471 } 1472 1473 var directoryInfo = new DirectoryInfo(etwDirPath); 1474 var cutoffDate = DateTime.Now.AddDays(-28); 1475 1476 foreach (var file in directoryInfo.GetFiles()) 1477 { 1478 if (file.LastWriteTime < cutoffDate) 1479 { 1480 try 1481 { 1482 file.Delete(); 1483 } 1484 catch (Exception ex) 1485 { 1486 Logger.LogError($"Failed to delete file: {file.FullName}. Error: {ex.Message}"); 1487 } 1488 } 1489 } 1490 } 1491 1492 internal void ViewDiagnosticData() 1493 { 1494 string localLowEtwDirPath = Path.Combine(Environment.GetEnvironmentVariable("USERPROFILE"), "AppData", "LocalLow", "Microsoft", "PowerToys", "etw"); 1495 string etwDirPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "Microsoft\\PowerToys\\etw"); 1496 1497 if (Directory.Exists(localLowEtwDirPath)) 1498 { 1499 if (!Directory.Exists(etwDirPath)) 1500 { 1501 Directory.CreateDirectory(etwDirPath); 1502 } 1503 1504 string[] localLowEtlFiles = Directory.GetFiles(localLowEtwDirPath, "*.etl"); 1505 1506 foreach (string file in localLowEtlFiles) 1507 { 1508 string fileName = Path.GetFileName(file); 1509 string destFile = Path.Combine(etwDirPath, fileName); 1510 1511 try 1512 { 1513 File.Copy(file, destFile, overwrite: true); 1514 } 1515 catch (Exception ex) 1516 { 1517 Logger.LogError($"Failed to copy etl file: {fileName}. Error: {ex.Message}"); 1518 } 1519 } 1520 } 1521 1522 string tracerptPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Windows), "system32"); 1523 1524 ETLConverter converter = new ETLConverter(etwDirPath, tracerptPath); 1525 Task.Run(() => converter.ConvertDiagnosticsETLsAsync()).Wait(); 1526 1527 if (Directory.Exists(etwDirPath)) 1528 { 1529 // Open etw dir in FileExplorer 1530 Process.Start("explorer.exe", etwDirPath); 1531 } 1532 } 1533 1534 private void OnSettingsChanged(GeneralSettings newSettings) 1535 { 1536 _dispatcherQueue?.TryEnqueue(() => 1537 { 1538 GeneralSettingsConfig = newSettings; 1539 1540 if (_enableQuickAccess != newSettings.EnableQuickAccess) 1541 { 1542 _enableQuickAccess = newSettings.EnableQuickAccess; 1543 OnPropertyChanged(nameof(EnableQuickAccess)); 1544 } 1545 }); 1546 } 1547 1548 public override void Dispose() 1549 { 1550 base.Dispose(); 1551 if (_settingsRepository != null) 1552 { 1553 _settingsRepository.SettingsChanged -= OnSettingsChanged; 1554 } 1555 1556 GC.SuppressFinalize(this); 1557 } 1558 1559 protected virtual Microsoft.UI.Dispatching.DispatcherQueue GetDispatcherQueue() 1560 { 1561 return Microsoft.UI.Dispatching.DispatcherQueue.GetForCurrentThread(); 1562 } 1563 } 1564 }