< Summary

Information
Class: SwitchBlade.ViewModels.SettingsViewModel
Assembly: SwitchBlade
File(s): D:\a\switchblade\switchblade\ViewModels\SettingsViewModel.cs
Tag: 203_23722840422
Line coverage
100%
Covered lines: 225
Uncovered lines: 0
Coverable lines: 225
Total lines: 422
Line coverage: 100%
Branch coverage
100%
Covered branches: 60
Total branches: 60
Branch coverage: 100%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
get_AvailableThemes()100%11100%
get_LoadedPlugins()100%11100%
get_SelectedTheme()100%11100%
set_SelectedTheme(...)100%22100%
get_EnablePreviews()100%11100%
set_EnablePreviews(...)100%11100%
get_HideTaskbarIcon()100%11100%
set_HideTaskbarIcon(...)100%11100%
get_ShowIcons()100%11100%
set_ShowIcons(...)100%11100%
get_LaunchOnStartup()100%11100%
set_LaunchOnStartup(...)100%22100%
get_RunAsAdministrator()100%11100%
set_RunAsAdministrator(...)100%1414100%
get_FadeDurationMs()100%11100%
set_FadeDurationMs(...)100%11100%
get_WindowOpacity()100%11100%
set_WindowOpacity(...)100%11100%
get_ItemHeight()100%11100%
set_ItemHeight(...)100%11100%
get_EnableBackgroundPolling()100%11100%
set_EnableBackgroundPolling(...)100%11100%
get_BackgroundPollingIntervalSeconds()100%11100%
set_BackgroundPollingIntervalSeconds(...)100%11100%
get_EnableNumberShortcuts()100%11100%
set_EnableNumberShortcuts(...)100%11100%
get_EnableBadgeAnimations()100%11100%
set_EnableBadgeAnimations(...)100%11100%
get_RegexCacheSize()100%11100%
set_RegexCacheSize(...)100%11100%
get_EnableFuzzySearch()100%11100%
set_EnableFuzzySearch(...)100%11100%
get_EnableSearchHighlighting()100%11100%
set_EnableSearchHighlighting(...)100%11100%
get_SearchHighlightColor()100%11100%
set_SearchHighlightColor(...)100%22100%
get_SetHighlightColorCommand()100%11100%
get_IconCacheSize()100%11100%
set_IconCacheSize(...)100%11100%
get_UiaWorkerTimeoutSeconds()100%11100%
set_UiaWorkerTimeoutSeconds(...)100%11100%
get_IsPreserveScrollSelected()100%11100%
set_IsPreserveScrollSelected(...)100%22100%
get_IsPreserveIdentitySelected()100%11100%
set_IsPreserveIdentitySelected(...)100%22100%
get_IsPreserveIndexSelected()100%11100%
set_IsPreserveIndexSelected(...)100%22100%
get_AvailableShortcutModifiers()100%11100%
.ctor(...)100%44100%
get_SelectedShortcutModifier()100%11100%
set_SelectedShortcutModifier(...)100%11100%
ModifierValueToString(...)100%11100%
StringToModifierValue(...)100%11100%
get_HotKeyString()100%88100%
UpdateHotKey(...)100%11100%
get_ExcludedProcesses()100%11100%
get_NewExcludedProcessName()100%11100%
set_NewExcludedProcessName(...)100%11100%
get_SelectedExcludedProcess()100%11100%
set_SelectedExcludedProcess(...)100%11100%
get_AddExcludedProcessCommand()100%11100%
get_RemoveExcludedProcessCommand()100%11100%
get_TogglePluginCommand()100%11100%
TogglePlugin(...)100%66100%
AddExcludedProcess()100%44100%
RemoveExcludedProcess()100%44100%
ScheduleSave()100%22100%
FlushPendingSave()100%22100%
OnPropertyChanged(...)100%22100%

File(s)

D:\a\switchblade\switchblade\ViewModels\SettingsViewModel.cs

#LineLine coverage
 1using System;
 2using System.Collections.ObjectModel;
 3using System.ComponentModel;
 4using System.Linq;
 5using System.Runtime.CompilerServices;
 6using System.Threading;
 7using System.Windows.Input;
 8using SwitchBlade.Services;
 9using SwitchBlade.Core;
 10using SwitchBlade.Contracts;
 11
 12namespace SwitchBlade.ViewModels
 13{
 14    public class SettingsViewModel : INotifyPropertyChanged
 15    {
 16        private readonly ISettingsService _settingsService;
 17        private readonly ThemeService _themeService;
 18        private readonly IUIService _uiService;
 19        private string _selectedTheme;
 20        private System.Threading.Timer? _saveTimer;
 21        private const int SaveDebounceMs = 300;
 22
 4423        public ObservableCollection<string> AvailableThemes { get; set; }
 4424        public ObservableCollection<PluginInfo> LoadedPlugins { get; private set; }
 25
 26
 27
 28        public string SelectedTheme
 29        {
 130            get => _selectedTheme;
 31            set
 232            {
 233                if (_selectedTheme != value)
 134                {
 135                    _selectedTheme = value;
 136                    OnPropertyChanged();
 137                    _themeService.ApplyTheme(_selectedTheme);
 138                }
 239            }
 40        }
 41
 42        public bool EnablePreviews
 43        {
 144            get => _settingsService.Settings.EnablePreviews;
 545            set { _settingsService.Settings.EnablePreviews = value; OnPropertyChanged(); ScheduleSave(); }
 46        }
 47
 48        public bool HideTaskbarIcon
 49        {
 150            get => _settingsService.Settings.HideTaskbarIcon;
 551            set { _settingsService.Settings.HideTaskbarIcon = value; OnPropertyChanged(); ScheduleSave(); }
 52        }
 53
 54        public bool ShowIcons
 55        {
 156            get => _settingsService.Settings.ShowIcons;
 557            set { _settingsService.Settings.ShowIcons = value; OnPropertyChanged(); ScheduleSave(); }
 58        }
 59
 60        public bool LaunchOnStartup
 61        {
 262            get => _settingsService.Settings.LaunchOnStartup;
 63            set
 164            {
 165                if (_settingsService.Settings.LaunchOnStartup != value)
 166                {
 167                    _settingsService.Settings.LaunchOnStartup = value;
 168                    OnPropertyChanged();
 169                    _settingsService.SaveSettings();
 170                }
 171            }
 72        }
 73
 74        public bool RunAsAdministrator
 75        {
 176            get => _settingsService.Settings.RunAsAdministrator;
 77            set
 678            {
 679                if (_settingsService.Settings.RunAsAdministrator != value)
 580                {
 81                    // Don't save yet - ask user first
 582                    bool needsRestart = (value && !_uiService.IsRunningAsAdmin()) || (!value && _uiService.IsRunningAsAd
 83
 584                    if (needsRestart)
 385                    {
 386                        string message = value
 387                            ? "This setting requires restarting SwitchBlade with Administrator privileges. Restart now?"
 388                            : "To run without Administrator privileges, SwitchBlade needs to restart. Restart now?";
 89
 390                        var result = _uiService.ShowMessageBox(
 391                            message,
 392                            "Restart Required",
 393                            System.Windows.MessageBoxButton.YesNo,
 394                            System.Windows.MessageBoxImage.Question);
 95
 396                        if (result == System.Windows.MessageBoxResult.Yes)
 297                        {
 98                            // User confirmed - now save the setting and restart
 299                            _settingsService.Settings.RunAsAdministrator = value;
 2100                            OnPropertyChanged();
 2101                            _settingsService.SaveSettings();
 2102                            _uiService.RestartApplication();
 2103                        }
 104                        // else: User clicked No - don't change anything, checkbox reverts automatically via binding
 3105                    }
 106                    else
 2107                    {
 108                        // No restart needed (rare case: setting matches current state)
 2109                        _settingsService.Settings.RunAsAdministrator = value;
 2110                        OnPropertyChanged();
 2111                        _settingsService.SaveSettings();
 2112                    }
 5113                }
 6114            }
 115        }
 116
 117        // RestartApplication logic moved to IUIService implementation
 118
 119        public int FadeDurationMs
 120        {
 1121            get => _settingsService.Settings.FadeDurationMs;
 5122            set { _settingsService.Settings.FadeDurationMs = value; OnPropertyChanged(); ScheduleSave(); }
 123        }
 124
 125        public double WindowOpacity
 126        {
 1127            get => _settingsService.Settings.WindowOpacity;
 5128            set { _settingsService.Settings.WindowOpacity = value; OnPropertyChanged(); ScheduleSave(); }
 129        }
 130
 131        public double ItemHeight
 132        {
 1133            get => _settingsService.Settings.ItemHeight;
 5134            set { _settingsService.Settings.ItemHeight = value; OnPropertyChanged(); ScheduleSave(); }
 135        }
 136
 137        public bool EnableBackgroundPolling
 138        {
 1139            get => _settingsService.Settings.EnableBackgroundPolling;
 5140            set { _settingsService.Settings.EnableBackgroundPolling = value; OnPropertyChanged(); ScheduleSave(); }
 141        }
 142
 143        public int BackgroundPollingIntervalSeconds
 144        {
 1145            get => _settingsService.Settings.BackgroundPollingIntervalSeconds;
 5146            set { _settingsService.Settings.BackgroundPollingIntervalSeconds = value; OnPropertyChanged(); ScheduleSave(
 147        }
 148
 149        public bool EnableNumberShortcuts
 150        {
 1151            get => _settingsService.Settings.EnableNumberShortcuts;
 5152            set { _settingsService.Settings.EnableNumberShortcuts = value; OnPropertyChanged(); ScheduleSave(); }
 153        }
 154
 155        public bool EnableBadgeAnimations
 156        {
 1157            get => _settingsService.Settings.EnableBadgeAnimations;
 5158            set { _settingsService.Settings.EnableBadgeAnimations = value; OnPropertyChanged(); ScheduleSave(); }
 159        }
 160
 161        public int RegexCacheSize
 162        {
 1163            get => _settingsService.Settings.RegexCacheSize;
 5164            set { _settingsService.Settings.RegexCacheSize = value; OnPropertyChanged(); ScheduleSave(); }
 165        }
 166
 167        public bool EnableFuzzySearch
 168        {
 1169            get => _settingsService.Settings.EnableFuzzySearch;
 5170            set { _settingsService.Settings.EnableFuzzySearch = value; OnPropertyChanged(); ScheduleSave(); }
 171        }
 172
 173        public bool EnableSearchHighlighting
 174        {
 1175            get => _settingsService.Settings.EnableSearchHighlighting;
 5176            set { _settingsService.Settings.EnableSearchHighlighting = value; OnPropertyChanged(); ScheduleSave(); }
 177        }
 178
 179        public string SearchHighlightColor
 180        {
 1181            get => _settingsService.Settings.SearchHighlightColor;
 182            set
 3183            {
 3184                if (_settingsService.Settings.SearchHighlightColor != value)
 3185                {
 3186                    _settingsService.Settings.SearchHighlightColor = value;
 3187                    OnPropertyChanged();
 3188                    ScheduleSave();
 3189                }
 3190            }
 191        }
 192
 1193        public ICommand SetHighlightColorCommand { get; }
 194
 195        public int IconCacheSize
 196        {
 1197            get => _settingsService.Settings.IconCacheSize;
 5198            set { _settingsService.Settings.IconCacheSize = value; OnPropertyChanged(); ScheduleSave(); }
 199        }
 200
 201        public int UiaWorkerTimeoutSeconds
 202        {
 1203            get => _settingsService.Settings.UiaWorkerTimeoutSeconds;
 5204            set { _settingsService.Settings.UiaWorkerTimeoutSeconds = value; OnPropertyChanged(); ScheduleSave(); }
 205        }
 206
 207        public bool IsPreserveScrollSelected
 208        {
 2209            get => _settingsService.Settings.RefreshBehavior == RefreshBehavior.PreserveScroll;
 210            set
 1211            {
 1212                if (value)
 1213                {
 1214                    _settingsService.Settings.RefreshBehavior = RefreshBehavior.PreserveScroll;
 1215                    OnPropertyChanged();
 1216                    ScheduleSave();
 1217                }
 1218            }
 219        }
 220
 221        public bool IsPreserveIdentitySelected
 222        {
 3223            get => _settingsService.Settings.RefreshBehavior == RefreshBehavior.PreserveIdentity;
 224            set
 1225            {
 1226                if (value)
 1227                {
 1228                    _settingsService.Settings.RefreshBehavior = RefreshBehavior.PreserveIdentity;
 1229                    OnPropertyChanged();
 1230                    ScheduleSave();
 1231                }
 1232            }
 233        }
 234
 235        public bool IsPreserveIndexSelected
 236        {
 2237            get => _settingsService.Settings.RefreshBehavior == RefreshBehavior.PreserveIndex;
 238            set
 1239            {
 1240                if (value)
 1241                {
 1242                    _settingsService.Settings.RefreshBehavior = RefreshBehavior.PreserveIndex;
 1243                    OnPropertyChanged();
 1244                    ScheduleSave();
 1245                }
 1246            }
 247        }
 248
 45249        public ObservableCollection<string> AvailableShortcutModifiers { get; } = new ObservableCollection<string>
 42250        {
 42251            "Alt", "Ctrl", "Shift", "None"
 42252        };
 253
 254        public string SelectedShortcutModifier
 255        {
 1256            get => ModifierValueToString(_settingsService.Settings.NumberShortcutModifier);
 257            set
 1258            {
 1259                _settingsService.Settings.NumberShortcutModifier = StringToModifierValue(value);
 1260                OnPropertyChanged();
 1261                ScheduleSave();
 1262            }
 263        }
 264
 1265        private static string ModifierValueToString(uint value) => Services.ModifierKeyFlags.ToString(value);
 266
 1267        private static uint StringToModifierValue(string value) => Services.ModifierKeyFlags.FromString(value);
 268
 269
 270
 42271        public SettingsViewModel(ISettingsService settingsService, ThemeService themeService, IPluginService pluginServi
 42272        {
 42273            _settingsService = settingsService;
 42274            _themeService = themeService;
 42275            _uiService = uiService;
 276
 42277            var plugins = pluginService.GetPluginInfos().ToList();
 278
 279            // Initialize enabled state
 130280            foreach (var plugin in plugins)
 2281            {
 2282                if (_settingsService.Settings.DisabledPlugins.Contains(plugin.Name))
 1283                {
 1284                    plugin.IsEnabled = false;
 1285                }
 2286            }
 287
 42288            LoadedPlugins = new ObservableCollection<PluginInfo>(plugins);
 289
 42290            ExcludedProcesses = new ObservableCollection<string>(_settingsService.Settings.ExcludedProcesses);
 336291            AvailableThemes = new ObservableCollection<string>(_themeService.AvailableThemes.Select(t => t.Name));
 292
 42293            _selectedTheme = _settingsService.Settings.CurrentTheme;
 294
 45295            TogglePluginCommand = new RelayCommand(param => TogglePlugin(param));
 47296            AddExcludedProcessCommand = new RelayCommand(_ => AddExcludedProcess(), _ => !string.IsNullOrWhiteSpace(NewE
 47297            RemoveExcludedProcessCommand = new RelayCommand(_ => RemoveExcludedProcess(), _ => !string.IsNullOrEmpty(Sel
 46298            SetHighlightColorCommand = new RelayCommand(param => { if (param is string color) SearchHighlightColor = col
 42299        }
 300
 301
 302
 303        public string HotKeyString
 304        {
 305            get
 2306            {
 2307                var mods = (uint)_settingsService.Settings.HotKeyModifiers;
 2308                var key = (uint)_settingsService.Settings.HotKeyKey;
 309
 2310                var parts = new System.Collections.Generic.List<string>();
 3311                if ((mods & 1) != 0) parts.Add("Alt");
 4312                if ((mods & 2) != 0) parts.Add("Ctrl");
 4313                if ((mods & 4) != 0) parts.Add("Shift");
 3314                if ((mods & 8) != 0) parts.Add("Win");
 315
 2316                parts.Add(((System.Windows.Forms.Keys)key).ToString());
 2317                return string.Join(" + ", parts);
 2318            }
 319        }
 320
 321        public void UpdateHotKey(uint modifiers, uint key)
 1322        {
 1323            _settingsService.Settings.HotKeyModifiers = modifiers;
 1324            _settingsService.Settings.HotKeyKey = key;
 1325            _settingsService.SaveSettings();
 1326            OnPropertyChanged(nameof(HotKeyString));
 1327        }
 328
 329        // Excluded Processes Logic
 42330        private string _newExcludedProcessName = "";
 42331        private string _selectedExcludedProcess = "";
 332
 55333        public ObservableCollection<string> ExcludedProcesses { get; set; }
 334
 335        public string NewExcludedProcessName
 336        {
 6337            get => _newExcludedProcessName;
 28338            set { _newExcludedProcessName = value; OnPropertyChanged(); }
 339        }
 340
 341        public string SelectedExcludedProcess
 342        {
 6343            get => _selectedExcludedProcess;
 24344            set { _selectedExcludedProcess = value; OnPropertyChanged(); }
 345        }
 346
 7347        public ICommand AddExcludedProcessCommand { get; }
 7348        public ICommand RemoveExcludedProcessCommand { get; }
 4349        public ICommand TogglePluginCommand { get; }
 350
 351        private void TogglePlugin(object? param)
 3352        {
 3353            if (param is PluginInfo plugin)
 3354            {
 355                // IsEnabled is bound to the CheckBox, so it's already updated in the object
 356                // We just need to sync with Settings
 3357                if (plugin.IsEnabled)
 1358                {
 1359                    _settingsService.Settings.DisabledPlugins.Remove(plugin.Name);
 1360                }
 361                else
 2362                {
 2363                    if (!_settingsService.Settings.DisabledPlugins.Contains(plugin.Name))
 1364                    {
 1365                        _settingsService.Settings.DisabledPlugins.Add(plugin.Name);
 1366                    }
 2367                }
 3368                _settingsService.SaveSettings();
 3369            }
 3370        }
 371
 372        private void AddExcludedProcess()
 3373        {
 3374            var sanitized = SanitizationUtils.SanitizeProcessName(NewExcludedProcessName);
 3375            if (!string.IsNullOrEmpty(sanitized) && !ExcludedProcesses.Contains(sanitized))
 1376            {
 1377                ExcludedProcesses.Add(sanitized);
 1378                _settingsService.Settings.ExcludedProcesses.Add(sanitized);
 1379                _settingsService.SaveSettings();
 1380                NewExcludedProcessName = "";
 1381            }
 3382        }
 383
 384        private void RemoveExcludedProcess()
 3385        {
 3386            var processToRemove = SelectedExcludedProcess;
 3387            if (!string.IsNullOrEmpty(processToRemove) && ExcludedProcesses.Contains(processToRemove))
 1388            {
 1389                ExcludedProcesses.Remove(processToRemove);
 1390                _settingsService.Settings.ExcludedProcesses.Remove(processToRemove);
 1391                _settingsService.SaveSettings();
 1392            }
 3393        }
 394
 395        /// <summary>
 396        /// Schedules a debounced save. Multiple rapid calls reset the timer,
 397        /// resulting in a single save after the debounce period.
 398        /// </summary>
 399        private void ScheduleSave()
 22400        {
 22401            _saveTimer?.Dispose();
 24402            _saveTimer = new System.Threading.Timer(_ => _settingsService.SaveSettings(), null, SaveDebounceMs, Timeout.
 22403        }
 404
 405        /// <summary>
 406        /// Flushes any pending debounced save immediately.
 407        /// Call this in tests or during teardown to ensure all changes are persisted.
 408        /// </summary>
 409        public void FlushPendingSave()
 19410        {
 19411            _saveTimer?.Dispose();
 19412            _saveTimer = null;
 19413            _settingsService.SaveSettings();
 19414        }
 415
 416        public event PropertyChangedEventHandler? PropertyChanged;
 417        protected void OnPropertyChanged([CallerMemberName] string? name = null)
 42418        {
 42419            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
 42420        }
 421    }
 422}

Methods/Properties

get_AvailableThemes()
get_LoadedPlugins()
get_SelectedTheme()
set_SelectedTheme(System.String)
get_EnablePreviews()
set_EnablePreviews(System.Boolean)
get_HideTaskbarIcon()
set_HideTaskbarIcon(System.Boolean)
get_ShowIcons()
set_ShowIcons(System.Boolean)
get_LaunchOnStartup()
set_LaunchOnStartup(System.Boolean)
get_RunAsAdministrator()
set_RunAsAdministrator(System.Boolean)
get_FadeDurationMs()
set_FadeDurationMs(System.Int32)
get_WindowOpacity()
set_WindowOpacity(System.Double)
get_ItemHeight()
set_ItemHeight(System.Double)
get_EnableBackgroundPolling()
set_EnableBackgroundPolling(System.Boolean)
get_BackgroundPollingIntervalSeconds()
set_BackgroundPollingIntervalSeconds(System.Int32)
get_EnableNumberShortcuts()
set_EnableNumberShortcuts(System.Boolean)
get_EnableBadgeAnimations()
set_EnableBadgeAnimations(System.Boolean)
get_RegexCacheSize()
set_RegexCacheSize(System.Int32)
get_EnableFuzzySearch()
set_EnableFuzzySearch(System.Boolean)
get_EnableSearchHighlighting()
set_EnableSearchHighlighting(System.Boolean)
get_SearchHighlightColor()
set_SearchHighlightColor(System.String)
get_SetHighlightColorCommand()
get_IconCacheSize()
set_IconCacheSize(System.Int32)
get_UiaWorkerTimeoutSeconds()
set_UiaWorkerTimeoutSeconds(System.Int32)
get_IsPreserveScrollSelected()
set_IsPreserveScrollSelected(System.Boolean)
get_IsPreserveIdentitySelected()
set_IsPreserveIdentitySelected(System.Boolean)
get_IsPreserveIndexSelected()
set_IsPreserveIndexSelected(System.Boolean)
get_AvailableShortcutModifiers()
.ctor(SwitchBlade.Services.ISettingsService,SwitchBlade.Services.ThemeService,SwitchBlade.Services.IPluginService,SwitchBlade.Contracts.IUIService)
get_SelectedShortcutModifier()
set_SelectedShortcutModifier(System.String)
ModifierValueToString(System.UInt32)
StringToModifierValue(System.String)
get_HotKeyString()
UpdateHotKey(System.UInt32,System.UInt32)
get_ExcludedProcesses()
get_NewExcludedProcessName()
set_NewExcludedProcessName(System.String)
get_SelectedExcludedProcess()
set_SelectedExcludedProcess(System.String)
get_AddExcludedProcessCommand()
get_RemoveExcludedProcessCommand()
get_TogglePluginCommand()
TogglePlugin(System.Object)
AddExcludedProcess()
RemoveExcludedProcess()
ScheduleSave()
FlushPendingSave()
OnPropertyChanged(System.String)