/ src / settings-ui / Settings.UI / ViewModels / ProfileEditorViewModel.cs
ProfileEditorViewModel.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  #nullable enable
  6  
  7  using System.Collections.ObjectModel;
  8  using System.ComponentModel;
  9  using System.Linq;
 10  using System.Runtime.CompilerServices;
 11  using Microsoft.PowerToys.Settings.UI.Library;
 12  using PowerDisplay.Common.Models;
 13  
 14  namespace Microsoft.PowerToys.Settings.UI.ViewModels
 15  {
 16      /// <summary>
 17      /// ViewModel for Profile Editor Dialog
 18      /// </summary>
 19      public class ProfileEditorViewModel : INotifyPropertyChanged
 20      {
 21          private string _profileName = string.Empty;
 22          private ObservableCollection<MonitorSelectionItem> _monitors;
 23  
 24          public ProfileEditorViewModel(ObservableCollection<MonitorInfo> availableMonitors, string defaultName = "")
 25          {
 26              _profileName = defaultName;
 27              _monitors = new ObservableCollection<MonitorSelectionItem>();
 28  
 29              // Set TotalMonitorCount for DisplayName to show monitor numbers when multiple monitors exist
 30              int totalCount = availableMonitors.Count;
 31              foreach (var monitor in availableMonitors)
 32              {
 33                  monitor.TotalMonitorCount = totalCount;
 34              }
 35  
 36              // Initialize monitor selection items
 37              foreach (var monitor in availableMonitors)
 38              {
 39                  var item = new MonitorSelectionItem
 40                  {
 41                      SuppressAutoSelection = true,
 42                      Monitor = monitor,
 43                      IsSelected = false,
 44                      Brightness = monitor.CurrentBrightness,
 45                      Contrast = 50, // Default value (MonitorInfo doesn't store contrast)
 46                      Volume = 50, // Default value (MonitorInfo doesn't store volume)
 47                      ColorTemperature = monitor.ColorTemperatureVcp,
 48                  };
 49  
 50                  item.SuppressAutoSelection = false;
 51  
 52                  // Subscribe to selection and checkbox changes
 53                  item.PropertyChanged += OnMonitorItemPropertyChanged;
 54  
 55                  _monitors.Add(item);
 56              }
 57          }
 58  
 59          public string ProfileName
 60          {
 61              get => _profileName;
 62              set
 63              {
 64                  if (_profileName != value)
 65                  {
 66                      _profileName = value;
 67                      OnPropertyChanged();
 68                      OnPropertyChanged(nameof(CanSave));
 69                  }
 70              }
 71          }
 72  
 73          public ObservableCollection<MonitorSelectionItem> Monitors
 74          {
 75              get => _monitors;
 76              set
 77              {
 78                  if (_monitors != value)
 79                  {
 80                      _monitors = value;
 81                      OnPropertyChanged();
 82                  }
 83              }
 84          }
 85  
 86          public bool HasSelectedMonitors => _monitors?.Any(m => m.IsSelected) ?? false;
 87  
 88          public bool HasValidSettings => _monitors != null &&
 89              _monitors.Any(m => m.IsSelected) &&
 90              _monitors.Where(m => m.IsSelected).All(m => m.IncludeBrightness || m.IncludeContrast || m.IncludeVolume || m.IncludeColorTemperature);
 91  
 92          public bool CanSave => !string.IsNullOrWhiteSpace(_profileName) && HasSelectedMonitors && HasValidSettings;
 93  
 94          public PowerDisplayProfile CreateProfile()
 95          {
 96              var settings = _monitors
 97                  .Where(m => m.IsSelected)
 98                  .Select(m => new ProfileMonitorSetting(
 99                      m.Monitor.Id, // Monitor Id (unique identifier)
100                      m.IncludeBrightness ? (int?)m.Brightness : null,
101                      m.IncludeColorTemperature && m.SupportsColorTemperature ? (int?)m.ColorTemperature : null,
102                      m.IncludeContrast && m.SupportsContrast ? (int?)m.Contrast : null,
103                      m.IncludeVolume && m.SupportsVolume ? (int?)m.Volume : null))
104                  .ToList();
105  
106              return new PowerDisplayProfile(_profileName, settings);
107          }
108  
109          public event PropertyChangedEventHandler? PropertyChanged;
110  
111          protected virtual void OnPropertyChanged([CallerMemberName] string? propertyName = null)
112          {
113              PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
114          }
115  
116          /// <summary>
117          /// Handle property changes from monitor selection items.
118          /// Centralizes validation state updates to avoid duplication.
119          /// </summary>
120          private void OnMonitorItemPropertyChanged(object? sender, PropertyChangedEventArgs e)
121          {
122              // Update selection-dependent properties
123              if (e.PropertyName == nameof(MonitorSelectionItem.IsSelected))
124              {
125                  OnPropertyChanged(nameof(HasSelectedMonitors));
126              }
127  
128              // Update validation state for relevant property changes
129              if (e.PropertyName == nameof(MonitorSelectionItem.IsSelected) ||
130                  e.PropertyName == nameof(MonitorSelectionItem.IncludeBrightness) ||
131                  e.PropertyName == nameof(MonitorSelectionItem.IncludeContrast) ||
132                  e.PropertyName == nameof(MonitorSelectionItem.IncludeVolume) ||
133                  e.PropertyName == nameof(MonitorSelectionItem.IncludeColorTemperature))
134              {
135                  OnPropertyChanged(nameof(CanSave));
136                  OnPropertyChanged(nameof(HasValidSettings));
137              }
138          }
139      }
140  }