/ src / settings-ui / Settings.UI / ViewModels / AlwaysOnTopViewModel.cs
AlwaysOnTopViewModel.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.Globalization;
  8  using System.Linq;
  9  using System.Runtime.CompilerServices;
 10  using System.Text.Json;
 11  using global::PowerToys.GPOWrapper;
 12  using ManagedCommon;
 13  using Microsoft.PowerToys.Settings.UI.Helpers;
 14  using Microsoft.PowerToys.Settings.UI.Library;
 15  using Microsoft.PowerToys.Settings.UI.Library.Helpers;
 16  using Microsoft.PowerToys.Settings.UI.Library.Interfaces;
 17  using Microsoft.PowerToys.Settings.UI.Library.Utilities;
 18  using Microsoft.PowerToys.Settings.UI.SerializationContext;
 19  
 20  namespace Microsoft.PowerToys.Settings.UI.ViewModels
 21  {
 22      public partial class AlwaysOnTopViewModel : PageViewModelBase
 23      {
 24          protected override string ModuleName => AlwaysOnTopSettings.ModuleName;
 25  
 26          private SettingsUtils SettingsUtils { get; set; }
 27  
 28          private GeneralSettings GeneralSettingsConfig { get; set; }
 29  
 30          private AlwaysOnTopSettings Settings { get; set; }
 31  
 32          private Func<string, int> SendConfigMSG { get; }
 33  
 34          public AlwaysOnTopViewModel(SettingsUtils settingsUtils, ISettingsRepository<GeneralSettings> settingsRepository, ISettingsRepository<AlwaysOnTopSettings> moduleSettingsRepository, Func<string, int> ipcMSGCallBackFunc)
 35          {
 36              ArgumentNullException.ThrowIfNull(settingsUtils);
 37  
 38              SettingsUtils = settingsUtils;
 39  
 40              // To obtain the general settings configurations of PowerToys Settings.
 41              ArgumentNullException.ThrowIfNull(settingsRepository);
 42  
 43              GeneralSettingsConfig = settingsRepository.SettingsConfig;
 44  
 45              InitializeEnabledValue();
 46  
 47              // To obtain the settings configurations of AlwaysOnTop.
 48              ArgumentNullException.ThrowIfNull(moduleSettingsRepository);
 49  
 50              Settings = moduleSettingsRepository.SettingsConfig;
 51  
 52              _hotkey = Settings.Properties.Hotkey.Value;
 53              _frameEnabled = Settings.Properties.FrameEnabled.Value;
 54              _frameThickness = Settings.Properties.FrameThickness.Value;
 55              _frameColor = Settings.Properties.FrameColor.Value;
 56              _frameOpacity = Settings.Properties.FrameOpacity.Value;
 57              _frameAccentColor = Settings.Properties.FrameAccentColor.Value;
 58              _soundEnabled = Settings.Properties.SoundEnabled.Value;
 59              _doNotActivateOnGameMode = Settings.Properties.DoNotActivateOnGameMode.Value;
 60              _roundCornersEnabled = Settings.Properties.RoundCornersEnabled.Value;
 61              _excludedApps = Settings.Properties.ExcludedApps.Value;
 62              _windows11 = OSVersionHelper.IsWindows11();
 63  
 64              // set the callback functions value to handle outgoing IPC message.
 65              SendConfigMSG = ipcMSGCallBackFunc;
 66          }
 67  
 68          private void InitializeEnabledValue()
 69          {
 70              _enabledGpoRuleConfiguration = GPOWrapper.GetConfiguredAlwaysOnTopEnabledValue();
 71              if (_enabledGpoRuleConfiguration == GpoRuleConfigured.Disabled || _enabledGpoRuleConfiguration == GpoRuleConfigured.Enabled)
 72              {
 73                  // Get the enabled state from GPO.
 74                  _enabledStateIsGPOConfigured = true;
 75                  _isEnabled = _enabledGpoRuleConfiguration == GpoRuleConfigured.Enabled;
 76              }
 77              else
 78              {
 79                  _isEnabled = GeneralSettingsConfig.Enabled.AlwaysOnTop;
 80              }
 81          }
 82  
 83          public override Dictionary<string, HotkeySettings[]> GetAllHotkeySettings()
 84          {
 85              var hotkeysDict = new Dictionary<string, HotkeySettings[]>
 86              {
 87                  [ModuleName] = [Hotkey],
 88              };
 89  
 90              return hotkeysDict;
 91          }
 92  
 93          public bool IsEnabled
 94          {
 95              get => _isEnabled;
 96  
 97              set
 98              {
 99                  if (_enabledStateIsGPOConfigured)
100                  {
101                      // If it's GPO configured, shouldn't be able to change this state.
102                      return;
103                  }
104  
105                  if (value != _isEnabled)
106                  {
107                      _isEnabled = value;
108  
109                      // Set the status in the general settings configuration
110                      GeneralSettingsConfig.Enabled.AlwaysOnTop = value;
111                      OutGoingGeneralSettings snd = new OutGoingGeneralSettings(GeneralSettingsConfig);
112  
113                      SendConfigMSG(snd.ToString());
114                      OnPropertyChanged(nameof(IsEnabled));
115                  }
116              }
117          }
118  
119          public bool IsEnabledGpoConfigured
120          {
121              get => _enabledStateIsGPOConfigured;
122          }
123  
124          public HotkeySettings Hotkey
125          {
126              get => _hotkey;
127  
128              set
129              {
130                  if (value != _hotkey)
131                  {
132                      _hotkey = value ?? AlwaysOnTopProperties.DefaultHotkeyValue;
133  
134                      Settings.Properties.Hotkey.Value = _hotkey;
135                      NotifyPropertyChanged();
136  
137                      // Also notify that transparency keys have changed
138                      OnPropertyChanged(nameof(IncreaseOpacityKeysList));
139                      OnPropertyChanged(nameof(DecreaseOpacityKeysList));
140  
141                      // Using InvariantCulture as this is an IPC message
142                      SendConfigMSG(
143                          string.Format(
144                              CultureInfo.InvariantCulture,
145                              "{{ \"powertoys\": {{ \"{0}\": {1} }} }}",
146                              AlwaysOnTopSettings.ModuleName,
147                              JsonSerializer.Serialize(Settings, SourceGenerationContextContext.Default.AlwaysOnTopSettings)));
148                  }
149              }
150          }
151  
152          public bool FrameEnabled
153          {
154              get => _frameEnabled;
155  
156              set
157              {
158                  if (value != _frameEnabled)
159                  {
160                      _frameEnabled = value;
161                      Settings.Properties.FrameEnabled.Value = value;
162                      NotifyPropertyChanged();
163                  }
164              }
165          }
166  
167          public int FrameThickness
168          {
169              get => _frameThickness;
170  
171              set
172              {
173                  if (value != _frameThickness)
174                  {
175                      _frameThickness = value;
176                      Settings.Properties.FrameThickness.Value = value;
177                      NotifyPropertyChanged();
178                  }
179              }
180          }
181  
182          public string FrameColor
183          {
184              get => _frameColor;
185  
186              set
187              {
188                  if (value != _frameColor)
189                  {
190                      _frameColor = value;
191                      Settings.Properties.FrameColor.Value = value;
192                      NotifyPropertyChanged();
193                  }
194              }
195          }
196  
197          public int FrameOpacity
198          {
199              get => _frameOpacity;
200  
201              set
202              {
203                  if (value != _frameOpacity)
204                  {
205                      _frameOpacity = value;
206                      Settings.Properties.FrameOpacity.Value = value;
207                      NotifyPropertyChanged();
208                  }
209              }
210          }
211  
212          public bool SoundEnabled
213          {
214              get => _soundEnabled;
215  
216              set
217              {
218                  if (value != _soundEnabled)
219                  {
220                      _soundEnabled = value;
221                      Settings.Properties.SoundEnabled.Value = value;
222                      NotifyPropertyChanged();
223                  }
224              }
225          }
226  
227          public bool DoNotActivateOnGameMode
228          {
229              get => _doNotActivateOnGameMode;
230  
231              set
232              {
233                  if (value != _doNotActivateOnGameMode)
234                  {
235                      _doNotActivateOnGameMode = value;
236                      Settings.Properties.DoNotActivateOnGameMode.Value = value;
237                      NotifyPropertyChanged();
238                  }
239              }
240          }
241  
242          public bool RoundCornersEnabled
243          {
244              get => _roundCornersEnabled;
245  
246              set
247              {
248                  if (value != _roundCornersEnabled)
249                  {
250                      _roundCornersEnabled = value;
251                      Settings.Properties.RoundCornersEnabled.Value = value;
252                      NotifyPropertyChanged();
253                  }
254              }
255          }
256  
257          public string ExcludedApps
258          {
259              get => _excludedApps;
260  
261              set
262              {
263                  if (value != _excludedApps)
264                  {
265                      _excludedApps = value;
266                      Settings.Properties.ExcludedApps.Value = value;
267                      NotifyPropertyChanged();
268                  }
269              }
270          }
271  
272          public bool FrameAccentColor
273          {
274              get => _frameAccentColor;
275  
276              set
277              {
278                  if (value != _frameAccentColor)
279                  {
280                      _frameAccentColor = value;
281                      Settings.Properties.FrameAccentColor.Value = value;
282                      NotifyPropertyChanged();
283                  }
284              }
285          }
286  
287          public bool Windows11
288          {
289              get => _windows11;
290  
291              set
292              {
293                  _windows11 = value;
294              }
295          }
296  
297          /// <summary>
298          /// Gets the keys list for increasing window opacity (modifier keys + "+").
299          /// </summary>
300          public List<object> IncreaseOpacityKeysList
301          {
302              get
303              {
304                  var keys = GetModifierKeysList();
305                  keys.Add("+");
306                  return keys;
307              }
308          }
309  
310          /// <summary>
311          /// Gets the keys list for decreasing window opacity (modifier keys + "-").
312          /// </summary>
313          public List<object> DecreaseOpacityKeysList
314          {
315              get
316              {
317                  var keys = GetModifierKeysList();
318                  keys.Add("-");
319                  return keys;
320              }
321          }
322  
323          /// <summary>
324          /// Gets only the modifier keys from the current hotkey setting.
325          /// </summary>
326          private List<object> GetModifierKeysList()
327          {
328              var modifierKeys = new List<object>();
329  
330              if (_hotkey.Win)
331              {
332                  modifierKeys.Add(92); // The Windows key
333              }
334  
335              if (_hotkey.Ctrl)
336              {
337                  modifierKeys.Add("Ctrl");
338              }
339  
340              if (_hotkey.Alt)
341              {
342                  modifierKeys.Add("Alt");
343              }
344  
345              if (_hotkey.Shift)
346              {
347                  modifierKeys.Add(16); // The Shift key
348              }
349  
350              return modifierKeys;
351          }
352  
353          public void NotifyPropertyChanged([CallerMemberName] string propertyName = null)
354          {
355              OnPropertyChanged(propertyName);
356              SettingsUtils.SaveSettings(Settings.ToJsonString(), AlwaysOnTopSettings.ModuleName);
357          }
358  
359          public void RefreshEnabledState()
360          {
361              InitializeEnabledValue();
362              OnPropertyChanged(nameof(IsEnabled));
363          }
364  
365          private GpoRuleConfigured _enabledGpoRuleConfiguration;
366          private bool _enabledStateIsGPOConfigured;
367          private bool _isEnabled;
368          private HotkeySettings _hotkey;
369          private bool _frameEnabled;
370          private int _frameThickness;
371          private string _frameColor;
372          private bool _frameAccentColor;
373          private int _frameOpacity;
374          private bool _soundEnabled;
375          private bool _doNotActivateOnGameMode;
376          private bool _roundCornersEnabled;
377          private string _excludedApps;
378          private bool _windows11;
379      }
380  }